]> git.saurik.com Git - bison.git/blob - tests/existing.at
* NEWS: Reword %destructor vs YYABORT etc.
[bison.git] / tests / existing.at
1 # Exercising Bison on actual grammars. -*- Autotest -*-
2
3 # Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004
4 # Free Software Foundation, Inc.
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
9 # any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21 AT_BANNER([[Existing Grammars.]])
22 ## ----------------- ##
23 ## GNU AWK Grammar. ##
24 ## ----------------- ##
25
26 AT_SETUP([GNU AWK Grammar])
27
28 # We have been careful to strip all the actions excepts the
29 # mid-rule actions. We rely on %expect to check that there are
30 # indeed 65 SR conflicts.
31 #
32 # Bison was once wrong, due to an incorrect computation of nullable.
33 # It reported 485 SR conflicts!
34
35 AT_DATA([[input.y]],
36 [[%expect 65
37
38 %token FUNC_CALL NAME REGEXP
39 %token ERROR
40 %token YNUMBER YSTRING
41 %token RELOP APPEND_OP
42 %token ASSIGNOP MATCHOP NEWLINE CONCAT_OP
43 %token LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
44 %token LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
45 %token LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
46 %token LEX_GETLINE LEX_NEXTFILE
47 %token LEX_IN
48 %token LEX_AND LEX_OR INCREMENT DECREMENT
49 %token LEX_BUILTIN LEX_LENGTH
50
51 /* Lowest to highest */
52 %right ASSIGNOP
53 %right '?' ':'
54 %left LEX_OR
55 %left LEX_AND
56 %left LEX_GETLINE
57 %nonassoc LEX_IN
58 %left FUNC_CALL LEX_BUILTIN LEX_LENGTH
59 %nonassoc ','
60 %nonassoc MATCHOP
61 %nonassoc RELOP '<' '>' '|' APPEND_OP TWOWAYIO
62 %left CONCAT_OP
63 %left YSTRING YNUMBER
64 %left '+' '-'
65 %left '*' '/' '%'
66 %right '!' UNARY
67 %right '^'
68 %left INCREMENT DECREMENT
69 %left '$'
70 %left '(' ')'
71 %%
72
73 start
74 : opt_nls program opt_nls
75 ;
76
77 program
78 : rule
79 | program rule
80 | error
81 | program error
82 | /* empty */
83 ;
84
85 rule
86 : LEX_BEGIN {} action
87 | LEX_END {} action
88 | LEX_BEGIN statement_term
89 | LEX_END statement_term
90 | pattern action
91 | action
92 | pattern statement_term
93 | function_prologue function_body
94 ;
95
96 func_name
97 : NAME
98 | FUNC_CALL
99 | lex_builtin
100 ;
101
102 lex_builtin
103 : LEX_BUILTIN
104 | LEX_LENGTH
105 ;
106
107 function_prologue
108 : LEX_FUNCTION {} func_name '(' opt_param_list r_paren opt_nls
109 ;
110
111 function_body
112 : l_brace statements r_brace opt_semi opt_nls
113 | l_brace r_brace opt_semi opt_nls
114 ;
115
116
117 pattern
118 : exp
119 | exp ',' exp
120 ;
121
122 regexp
123 /*
124 * In this rule, want_regexp tells yylex that the next thing
125 * is a regexp so it should read up to the closing slash.
126 */
127 : '/' {} REGEXP '/'
128 ;
129
130 action
131 : l_brace statements r_brace opt_semi opt_nls
132 | l_brace r_brace opt_semi opt_nls
133 ;
134
135 statements
136 : statement
137 | statements statement
138 | error
139 | statements error
140 ;
141
142 statement_term
143 : nls
144 | semi opt_nls
145 ;
146
147 statement
148 : semi opt_nls
149 | l_brace r_brace
150 | l_brace statements r_brace
151 | if_statement
152 | LEX_WHILE '(' exp r_paren opt_nls statement
153 | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
154 | LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
155 | LEX_FOR '(' opt_exp semi opt_nls exp semi opt_nls opt_exp r_paren opt_nls statement
156 | LEX_FOR '(' opt_exp semi opt_nls semi opt_nls opt_exp r_paren opt_nls statement
157 | LEX_BREAK statement_term
158 | LEX_CONTINUE statement_term
159 | print '(' expression_list r_paren output_redir statement_term
160 | print opt_rexpression_list output_redir statement_term
161 | LEX_NEXT statement_term
162 | LEX_NEXTFILE statement_term
163 | LEX_EXIT opt_exp statement_term
164 | LEX_RETURN {} opt_exp statement_term
165 | LEX_DELETE NAME '[' expression_list ']' statement_term
166 | LEX_DELETE NAME statement_term
167 | exp statement_term
168 ;
169
170 print
171 : LEX_PRINT
172 | LEX_PRINTF
173 ;
174
175 if_statement
176 : LEX_IF '(' exp r_paren opt_nls statement
177 | LEX_IF '(' exp r_paren opt_nls statement
178 LEX_ELSE opt_nls statement
179 ;
180
181 nls
182 : NEWLINE
183 | nls NEWLINE
184 ;
185
186 opt_nls
187 : /* empty */
188 | nls
189 ;
190
191 input_redir
192 : /* empty */
193 | '<' simp_exp
194 ;
195
196 output_redir
197 : /* empty */
198 | '>' exp
199 | APPEND_OP exp
200 | '|' exp
201 | TWOWAYIO exp
202 ;
203
204 opt_param_list
205 : /* empty */
206 | param_list
207 ;
208
209 param_list
210 : NAME
211 | param_list comma NAME
212 | error
213 | param_list error
214 | param_list comma error
215 ;
216
217 /* optional expression, as in for loop */
218 opt_exp
219 : /* empty */
220 | exp
221 ;
222
223 opt_rexpression_list
224 : /* empty */
225 | rexpression_list
226 ;
227
228 rexpression_list
229 : rexp
230 | rexpression_list comma rexp
231 | error
232 | rexpression_list error
233 | rexpression_list error rexp
234 | rexpression_list comma error
235 ;
236
237 opt_expression_list
238 : /* empty */
239 | expression_list
240 ;
241
242 expression_list
243 : exp
244 | expression_list comma exp
245 | error
246 | expression_list error
247 | expression_list error exp
248 | expression_list comma error
249 ;
250
251 /* Expressions, not including the comma operator. */
252 exp : variable ASSIGNOP {} exp
253 | '(' expression_list r_paren LEX_IN NAME
254 | exp '|' LEX_GETLINE opt_variable
255 | exp TWOWAYIO LEX_GETLINE opt_variable
256 | LEX_GETLINE opt_variable input_redir
257 | exp LEX_AND exp
258 | exp LEX_OR exp
259 | exp MATCHOP exp
260 | regexp
261 | '!' regexp %prec UNARY
262 | exp LEX_IN NAME
263 | exp RELOP exp
264 | exp '<' exp
265 | exp '>' exp
266 | exp '?' exp ':' exp
267 | simp_exp
268 | exp simp_exp %prec CONCAT_OP
269 ;
270
271 rexp
272 : variable ASSIGNOP {} rexp
273 | rexp LEX_AND rexp
274 | rexp LEX_OR rexp
275 | LEX_GETLINE opt_variable input_redir
276 | regexp
277 | '!' regexp %prec UNARY
278 | rexp MATCHOP rexp
279 | rexp LEX_IN NAME
280 | rexp RELOP rexp
281 | rexp '?' rexp ':' rexp
282 | simp_exp
283 | rexp simp_exp %prec CONCAT_OP
284 ;
285
286 simp_exp
287 : non_post_simp_exp
288 /* Binary operators in order of decreasing precedence. */
289 | simp_exp '^' simp_exp
290 | simp_exp '*' simp_exp
291 | simp_exp '/' simp_exp
292 | simp_exp '%' simp_exp
293 | simp_exp '+' simp_exp
294 | simp_exp '-' simp_exp
295 | variable INCREMENT
296 | variable DECREMENT
297 ;
298
299 non_post_simp_exp
300 : '!' simp_exp %prec UNARY
301 | '(' exp r_paren
302 | LEX_BUILTIN
303 '(' opt_expression_list r_paren
304 | LEX_LENGTH '(' opt_expression_list r_paren
305 | LEX_LENGTH
306 | FUNC_CALL '(' opt_expression_list r_paren
307 | variable
308 | INCREMENT variable
309 | DECREMENT variable
310 | YNUMBER
311 | YSTRING
312 | '-' simp_exp %prec UNARY
313 | '+' simp_exp %prec UNARY
314 ;
315
316 opt_variable
317 : /* empty */
318 | variable
319 ;
320
321 variable
322 : NAME
323 | NAME '[' expression_list ']'
324 | '$' non_post_simp_exp
325 ;
326
327 l_brace
328 : '{' opt_nls
329 ;
330
331 r_brace
332 : '}' opt_nls
333 ;
334
335 r_paren
336 : ')'
337 ;
338
339 opt_semi
340 : /* empty */
341 | semi
342 ;
343
344 semi
345 : ';'
346 ;
347
348 comma : ',' opt_nls
349 ;
350
351 %%
352 ]])
353
354 # Pass plenty of options, to exercise plenty of code, even if we
355 # don't actually check the output. But SEGV is watching us, and
356 # so might do dmalloc.
357 AT_CHECK([[bison --verbose --defines input.y]])
358
359 AT_CLEANUP
360
361
362 ## ----------------- ##
363 ## GNU Cim Grammar. ##
364 ## ----------------- ##
365
366 AT_SETUP([GNU Cim Grammar])
367
368 # GNU Cim, the GNU Simula 87 Compiler.
369
370 # Bison was once wrong, due to an incorrect computation of the RR conflicts.
371 # It reported 80 SR && 99 RR conflicts instead of 78/10!!!
372
373 AT_DATA([[input.y]],
374 [[%union {
375 long int token;
376 long int ival;
377 long int arrdim;
378 double rval;
379 char *ident;
380 char *tval;
381 char stat_decl;
382 }
383
384 %token
385 HACTIVATE HAFTER /*HAND*/ HARRAY HAT
386 HBEFORE HBEGIN HBOOLEAN
387 HCHARACTER HCLASS /*HCOMMENT*/ HCONC
388 HDELAY HDO
389 HELSE HEND HEQ /*HEQV*/ HEXTERNAL
390 HFOR
391 HGE HGO HGOTO HGT
392 HHIDDEN
393 HIF /*HIMP*/ HIN HINNER HINSPECT HINTEGER HIS
394 HLABEL HLE HLONG HLT
395 HNAME HNE HNEW HNONE /*HNOT*/ HNOTEXT
396 /*HOR*/ HOTHERWISE
397 HPRIOR HPROCEDURE HPROTECTED
398 HQUA
399 HREACTIVATE HREAL HREF
400 HSHORT HSTEP HSWITCH
401 HTEXT HTHEN HTHIS HTO
402 HUNTIL
403 HVALUE HVAR HVIRTUAL
404 HWHEN HWHILE
405
406 HASSIGNVALUE HASSIGNREF
407 /*HDOT*/ HPAREXPSEPARATOR HLABELSEPARATOR HSTATEMENTSEPARATOR
408 HBEGPAR HENDPAR
409 HEQR HNER
410 HADD HSUB HMUL HDIV HINTDIV HEXP
411 HDOTDOTDOT
412
413 %token <ident> HIDENTIFIER
414 %token <ival> HBOOLEANKONST HINTEGERKONST HCHARACTERKONST
415 %token <rval> HREALKONST
416 %token <tval> HTEXTKONST
417
418 %type <tval> EXT_IDENT
419 %type <stat_decl> DECLSTATEMENT MODULSTATEMENT MBEE_DECLSTMS MBEE_DECLSTMSU
420 %type <stat_decl> MODULS
421 %type <ident> EXPRESSION_SIMP MBEE_ARG_R_PT
422 %type <arrdim> BAUND_PAIR_LIST
423
424 %right <token> HASSIGN
425 %left HORELSE
426 %left HANDTHEN
427 %left HEQV
428 %left HIMP
429 %left HOR
430 %left HAND
431
432 %left HNOT
433
434 %left <token> HVALRELOPERATOR HREFRELOPERATOR HOBJRELOPERATOR
435
436 %left HCONC
437
438 %left <token> HTERMOPERATOR
439 %left <token> UNEAR
440 %left <token> HFACTOROPERATOR
441 %left HPRIMARYOPERATOR
442
443 %left HQUA
444
445 %left HDOT
446
447 %start MAIN_MODULE
448 %%
449 /* GRAMATIKK FOR PROGRAM MODULES */
450 MAIN_MODULE : { categ=CLOCAL; mout(MBLOCK);
451 beginBlock(KBLOKK);separat_comp=FALSE;}
452 MODULS { endBlock(NULL,CCNO); mout(MENDBLOCK);}
453 | error HSTATEMENTSEPARATOR MBEE_DECLSTMS
454 ;
455 EXT_DECLARATION : HEXTERNAL
456 MBEE_TYPE
457 HPROCEDURE
458 { MBEENEWBLOCK();
459 kind=KPROC;}
460 EXT_LIST
461 |
462 HEXTERNAL
463 HIDENTIFIER
464 HPROCEDURE
465 { MBEENEWBLOCK();
466 type=TNOTY;
467 kind=KPROC;
468 if($2==Ckind)categ=CCPROC;else
469 yerror (1);
470 ysensitive=sensitive;
471 sensitive=ON;}
472 HIDENTIFIER { $<ident>$=$5;
473 sensitive=ysensitive;}
474 EXTERNAL_KIND_ITEM
475 { categ=CLOCAL;}
476 | HEXTERNAL
477 HCLASS
478 { MBEENEWBLOCK();
479 kind=KCLASS;}
480 EXT_LIST
481
482 ;
483 EXTERNAL_KIND_ITEM: EXT_IDENT
484 HOBJRELOPERATOR
485 { if($2!=HIS)yerror (2);}
486 MBEE_TYPE HPROCEDURE
487 HIDENTIFIER
488 { regDecl($6, type, KPROC, CCPROC);
489 beginBlock(kind);}
490 HEADING EMPTY_BLOCK
491 { categ=CLOCAL;
492 endBlock($1==NULL?$<ident>0:tag($1),CCCPROC);}
493 /* |
494 EXT_IDENT
495 { if($1!=NULL)yerror (3);
496 regDecl($0, type, kind, categ);}
497 MBEE_REST_EXT_LIST
498 { endBlock(NULL,CCNO);}
499 ;
500 MBEE_REST_EXT_LIST: /* EMPTY
501 | HPAREXPSEPARATOR EXT_KIND_LIST
502 ;
503 EXT_KIND_LIST : EXT_KIND_ITEM
504 | EXT_KIND_LIST HPAREXPSEPARATOR EXT_KIND_ITEM
505 ;
506 EXT_KIND_ITEM : HIDENTIFIER
507 EXT_IDENT
508 { if($2!=NULL)yerror (3);
509 regDecl($1, type, kind, categ);}*/
510 ;
511 EMPTY_BLOCK : /*EMPT*/
512 | HBEGIN HEND
513 ;
514 EXT_LIST : EXT_ITEM
515 | EXT_LIST HPAREXPSEPARATOR EXT_ITEM
516 ;
517 EXT_ITEM : HIDENTIFIER
518 EXT_IDENT
519 { lesinn_external_spec($1,$2, kind);}
520 ;
521 EXT_IDENT : /* EMPTY */ { $$=NULL;}
522 | HVALRELOPERATOR { if($1!=HEQ)yerror (9);
523 external=TRUE;}
524 HTEXTKONST { $$=$3;external=FALSE;}
525 ;
526 /* GRAMATIKK FOR TYPER */
527 NO_TYPE : /*EMPT*/ { type=TNOTY;}
528 ;
529 MBEE_TYPE : NO_TYPE
530 | TYPE
531 ;
532 TYPE : HREF HBEGPAR
533 HIDENTIFIER
534 { prefquantident=$3;
535 type=TREF;}
536 HENDPAR
537 | HTEXT { type=TTEXT;}
538 | HBOOLEAN { type=TBOOL;}
539 | HCHARACTER { type=TCHAR;}
540 | HSHORT HINTEGER { type=TSHORT;}
541 | HINTEGER { type=TINTG;}
542 | HREAL { type=TREAL;}
543 | HLONG HREAL { type=TLONG;}
544 ;
545
546 /* GRAMATIKK FOR DEL AV SETNINGER */
547 MBEE_ELSE_PART : /*EMPT*/
548 /* | HELSE
549 HIF
550 EXPRESSION
551 HTHEN { mout(MELSE);
552 mout(MIF);
553 OBSBLOCK();}
554 BLOCK { MBEEENDBLOCK();}
555 MBEE_ELSE_PART { mout(MENDIF);}*/
556 | HELSE { OBSBLOCK(); mout(MELSE);}
557 BLOCK { MBEEENDBLOCK();}
558 ;
559 FOR_LIST : FOR_LIST_ELEMENT { mout(MENDSEP);
560 mout(MLISTSEP);}
561 | FOR_LIST_ELEMENT
562 HPAREXPSEPARATOR
563 FOR_LIST { mout(MLISTSEP);}
564 ;
565 FOR_LIST_ELEMENT: EXPRESSION
566 MBEE_F_L_EL_R_PT
567 ;
568 MBEE_F_L_EL_R_PT: /*EMPT*/
569 | HWHILE
570 EXPRESSION { mout(MFORWHILE);}
571 | HSTEP
572 EXPRESSION
573 HUNTIL
574 EXPRESSION { mout(MUNTIL);
575 mout(MSTEP);}
576 ;
577 GOTO : HGO
578 HTO
579 | HGOTO
580 ;
581 CONN_STATE_R_PT : WHEN_CLAUSE_LIST
582 | HDO { beginBlock(KCON); mout(MDO);
583 OBSBLOCK(); }
584 BLOCK { endBlock(NULL,CCNO);
585 MBEEENDBLOCK(); mout(MENDDO);}
586 ;
587 WHEN_CLAUSE_LIST: HWHEN
588 HIDENTIFIER
589 HDO { beginBlock(KCON); mout(MIDENTIFIER);
590 OBSBLOCK(); moutId($2);
591 mout(MWHEN);}
592 BLOCK { endBlock(NULL,CCNO);
593 MBEEENDBLOCK(); mout(MENDWHEN);}
594 | WHEN_CLAUSE_LIST
595 HWHEN
596 HIDENTIFIER
597 HDO { beginBlock(KCON); mout(MIDENTIFIER);
598 OBSBLOCK(); moutId($3);
599 mout(MWHEN);}
600 BLOCK { endBlock(NULL,CCNO);
601 MBEEENDBLOCK(); mout(MENDWHEN);}
602 ;
603 MBEE_OTWI_CLAUS : /*EMPT*/
604 | HOTHERWISE {OBSBLOCK(); mout(MOTHERWISE);}
605
606 BLOCK {MBEEENDBLOCK();mout(MENDOTHERWISE);}
607 ;
608 ACTIVATOR : HACTIVATE { mout(MBOOLEANKONST);
609 moutIval(FALSE);}
610 | HREACTIVATE { mout(MBOOLEANKONST);
611 moutIval(TRUE);}
612 ;
613 SCHEDULE : /*EMPT*/ { mout(MCHARACTERKONST);
614 moutIval(DIRECT);
615 mout(MINTEGERKONST);
616 moutIval(0);
617 mout(MNONE);
618 mout(MBOOLEANKONST);
619 moutIval(FALSE);}
620 | ATDELAY EXPRESSION { mout(MNONE);}
621 PRIOR
622 | BEFOREAFTER { mout(MINTEGERKONST);
623 moutIval(0);}
624 EXPRESSION { mout(MBOOLEANKONST);
625 moutIval(FALSE);}
626 ;
627 ATDELAY : HAT { mout(MCHARACTERKONST);
628 moutIval(AT);}
629 | HDELAY { mout(MCHARACTERKONST);
630 moutIval(DELAYS);}
631 ;
632 BEFOREAFTER : HBEFORE { mout(MCHARACTERKONST);
633 moutIval(BEFORE);}
634 | HAFTER { mout(MCHARACTERKONST);
635 moutIval(AFTER);}
636 ;
637 PRIOR : /*EMPT*/ { mout(MBOOLEANKONST);
638 moutIval(FALSE);}
639 | HPRIOR { mout(MBOOLEANKONST);
640 moutIval(TRUE);}
641 ;
642 /* GRAMATIKK FOR SETNINGER OG DEKLARASJONER */
643 MODULSTATEMENT : HWHILE
644 EXPRESSION
645 HDO { STOPOBSBLOCK(); mout(MWHILE);
646 OBSBLOCK();}
647 BLOCK { MBEEENDBLOCK(); mout(MENDWHILE);
648 $$=STATEMENT;}
649 | HIF
650 EXPRESSION
651 HTHEN { STOPOBSBLOCK(); mout(MIF);
652 OBSBLOCK();}
653 BLOCK { MBEEENDBLOCK();}
654 MBEE_ELSE_PART { mout(MENDIF);
655 $$=STATEMENT;}
656 | HFOR
657 HIDENTIFIER
658 HASSIGN { STOPOBSBLOCK(); mout(MIDENTIFIER);
659 moutId($2);}
660 FOR_LIST
661 HDO { beginBlock(KFOR);
662 if($3==HASSIGNVALUE) mout(MFOR);
663 else mout(MFORR);
664 OBSBLOCK(); mout(MFORDO);}
665 BLOCK { MBEEENDBLOCK();
666 endBlock(NULL,CCNO); mout(MENDFOR);
667 $$=STATEMENT;}
668 | GOTO
669 EXPRESSION { mout(MGOTO);
670 STOPOBSBLOCK(); $$=STATEMENT;}
671 | HINSPECT
672 EXPRESSION { mout(MINSPECT);
673 STOPOBSBLOCK();
674 beginBlock(KINSP);}
675 CONN_STATE_R_PT
676 { endBlock(NULL,CCNO);}
677 MBEE_OTWI_CLAUS { mout(MENDINSPECT);
678 $$=STATEMENT;}
679 | HINNER { STOPOBSBLOCK(); mout(MINNER);
680 regInner(); $$=STATEMENT;}
681 | HIDENTIFIER
682 HLABELSEPARATOR
683 { STOPOBSBLOCK();
684 regDecl($1, TLABEL, KSIMPLE, categ); mout(MLABEL);
685 moutId($1);
686 mout(MENDLABEL);}
687 DECLSTATEMENT { if($4<=DECLARATION)
688 { yerror (27);
689 $$=DECLARATION;}
690 else $$=$4;}
691 | EXPRESSION_SIMP
692 HBEGIN
693 { $<ident>$=$1; }
694 IMPORT_SPEC_MODULE
695 { mout(MPRBLOCK);
696 prefquantident=$1;
697 beginBlock(KPRBLK);}
698 MBEE_DECLSTMS
699 HEND { endBlock(NULL,CCNO); mout(MENDPRBLOCK);
700 $$=STATEMENT;}
701 | EXPRESSION_SIMP HBEGIN error HSTATEMENTSEPARATOR
702 MBEE_DECLSTMS HEND { $$=STATEMENT;
703 endBlock(NULL,CCNO); mout(MENDPRBLOCK);}
704 | EXPRESSION_SIMP HBEGIN error HEND
705 { $$=STATEMENT;
706 endBlock(NULL,CCNO); mout(MENDPRBLOCK);}
707
708 | EXPRESSION_SIMP
709 { STOPOBSBLOCK(); $$=STATEMENT;
710 mout(MENDASSIGN);}
711 | ACTIVATOR EXPRESSION SCHEDULE
712 { $$=STATEMENT;
713 mout(MENDSEP);
714 mout(MARGUMENTSEP);
715 mout(MARGUMENTSEP);
716 mout(MARGUMENTSEP);
717 mout(MARGUMENTSEP);
718 mout(MARGUMENTSEP);
719 mout(MARGUMENTSEP);
720 mout(MARGUMENT);
721 moutId(activateid);
722 mout(MENDASSIGN);}
723 | HBEGIN
724 { STOPOBSBLOCK();
725 OBSBLOCK();}
726 MBEE_DECLSTMS
727 HEND { MBEEENDBLOCK(); $$=STATEMENT;}
728 | MBEE_TYPE HPROCEDURE
729 HIDENTIFIER
730 { MBEENEWBLOCK(); mout(MPROCEDURE);
731 regDecl($3, type, KPROC, categ);
732 beginBlock(KPROC);}
733 HEADING BLOCK { endBlock(NULL,CCNO); $$=DECLARATION;
734 mout(MENDPROCEDURE);}
735 | HIDENTIFIER
736 HCLASS
737 NO_TYPE
738 { $<ident>$=$1; }
739 IMPORT_SPEC_MODULE
740 HIDENTIFIER
741 { prefquantident=$1;
742 mout(MCLASS);
743 regDecl($6, TNOTY, KCLASS, categ);
744 beginBlock(KCLASS);}
745 HEADING
746 BLOCK { endBlock(NULL,CCNO); $$=DECLARATION;
747 mout(MENDCLASS);}
748 | HCLASS
749 NO_TYPE
750 HIDENTIFIER
751 { prefquantident=0;
752 MBEENEWBLOCK(); mout(MCLASS);
753 regDecl($3, TNOTY, KCLASS, categ);
754 beginBlock(KCLASS);}
755 HEADING
756 BLOCK { endBlock(NULL,CCNO); $$=DECLARATION;
757 mout(MENDCLASS);}
758 | EXT_DECLARATION { $$=EXTDECLARATION;}
759 | /*EMPT*/{ STOPOBSBLOCK(); $$=EMPTYSTATEMENT;}
760 ;
761 IMPORT_SPEC_MODULE: { MBEENEWBLOCK();
762 kind=KCLASS;
763 if($<ident>0==simsetident &&
764 findDecl(simsetident,cblock,FALSE)==NULL)
765 lesinn_external_spec(simsetident,
766 SIMSETATRFILE, kind);
767 if($<ident>0==simulationident && findDecl(
768 simulationident,cblock,FALSE)==NULL)
769 lesinn_external_spec(simulationident,
770 SIMULATIONATRFILE, kind);
771 if(($<ident>0==fileident && findDecl(
772 fileident,cblock,FALSE)==NULL) ||
773 ($<ident>0==outfileident && findDecl(
774 outfileident,cblock,FALSE)==NULL) ||
775 ($<ident>0==infileident && findDecl(
776 infileident,cblock,FALSE)==NULL) ||
777 ($<ident>0==directfileident && findDecl(
778 directfileident,cblock,FALSE)==NULL) ||
779 ($<ident>0==printfileident && findDecl(
780 printfileident,cblock,FALSE)==NULL) ||
781 ($<ident>0==bytefileident && findDecl(
782 bytefileident,cblock,FALSE)==NULL) ||
783 ($<ident>0==inbytefileident && findDecl(
784 inbytefileident,cblock,FALSE)==NULL) ||
785 ($<ident>0==outbytefileident && findDecl(
786 outbytefileident,cblock,FALSE)==NULL) ||
787 ($<ident>0==directbytefileident && findDecl(
788 directbytefileident,cblock,FALSE)==NULL))
789 lesinn_external_spec(fileident,
790 FILEATRFILE, kind);}
791 ;
792 DECLSTATEMENT : MODULSTATEMENT
793 | TYPE
794 HIDENTIFIER
795 MBEE_CONSTANT
796 HPAREXPSEPARATOR
797 { MBEENEWBLOCK();
798 kind=KSIMPLE;
799 regDecl($2, type, KSIMPLE, categ);
800 categ=CLOCAL;}
801 IDENTIFIER_LISTC { $$=DECLARATION;}
802 | TYPE
803 HIDENTIFIER
804 MBEE_CONSTANT
805 { MBEENEWBLOCK();
806 regDecl($2, type, KSIMPLE, categ);
807 categ=CLOCAL; $$=DECLARATION;}
808 | MBEE_TYPE
809 HARRAY { MBEENEWBLOCK();
810 kind=KARRAY;}
811 ARR_SEGMENT_LIST { $$=DECLARATION;}
812 | HSWITCH
813 HIDENTIFIER
814 HASSIGN { MBEENEWBLOCK(); mout(MIDENTIFIER);
815 moutId($2);
816 regDecl($2, TLABEL, KARRAY, categ);}
817 SWITCH_LIST { $$=DECLARATION;
818 mout(MSWITCH);
819 mout(MENDSWITCH);}
820 ;
821 BLOCK : DECLSTATEMENT { if($1<=DECLARATION)yerror (29);}
822 | HBEGIN MBEE_DECLSTMS HEND
823 | HBEGIN error HSTATEMENTSEPARATOR MBEE_DECLSTMS HEND
824 | HBEGIN error HEND
825 ;
826 MBEE_DECLSTMS : MBEE_DECLSTMSU { if($1<=DECLARATION)yerror (28);
827 $$=$1;}
828 ;
829 MBEE_DECLSTMSU : DECLSTATEMENT { $$=$1;}
830 | MBEE_DECLSTMSU
831 HSTATEMENTSEPARATOR
832 DECLSTATEMENT { if($1>=STATEMENT && $3<=DECLARATION)
833 yerror (26);
834 $$=$3;}
835 ;
836 MODULS : MODULSTATEMENT { if($1==DECLARATION)
837 {separat_comp=TRUE;gettimestamp();}
838 $$=$1;}
839 | MODULS HSTATEMENTSEPARATOR MODULSTATEMENT
840 { if($1>=STATEMENT && $3<=DECLARATION)
841 yerror (26);else
842 if($1>=STATEMENT
843 && $3!=EMPTYSTATEMENT)yerror (25);
844 if(separat_comp && $3==STATEMENT)
845 yerror (25);
846 if($3==DECLARATION && !separat_comp)
847 {separat_comp=TRUE;gettimestamp();}
848 $$=$3;}
849 ;
850 /* GRAMATIKK FOR DEL AV DEKLARASJONER */
851 ARR_SEGMENT_LIST: ARR_SEGMENT
852 | ARR_SEGMENT_LIST
853 HPAREXPSEPARATOR
854 ARR_SEGMENT
855 ;
856 ARR_SEGMENT : ARRAY_SEGMENT
857 HBEGPAR
858 BAUND_PAIR_LIST HENDPAR { mout(MARRAY);
859 mout(MENDARRAY);
860 setArrayDim($3);}
861 ;
862 ARRAY_SEGMENT : ARRAY_SEGMENT_EL { mout(MENDSEP);
863 mout(MARRAYSEP);}
864
865 | ARRAY_SEGMENT_EL
866 HPAREXPSEPARATOR
867 ARRAY_SEGMENT { mout(MARRAYSEP);}
868 ;
869 ARRAY_SEGMENT_EL: HIDENTIFIER { mout(MIDENTIFIER);
870 moutId($1);
871 regDecl($1, type, kind, categ);
872 if(lastArray==NULL)
873 lastArray=cblock->lastparloc;}
874 ;
875 BAUND_PAIR_LIST : BAUND_PAIR { mout(MENDSEP);
876 mout(MBOUNDSEP);
877 $$=1;}
878 | BAUND_PAIR
879 HPAREXPSEPARATOR
880 BAUND_PAIR_LIST { mout(MBOUNDSEP);
881 $$=$3+1;}
882 ;
883 BAUND_PAIR : EXPRESSION
884 HLABELSEPARATOR
885 EXPRESSION { mout(MBOUNDPARSEP);}
886 ;
887 SWITCH_LIST : EXPRESSION { mout(MENDSEP);
888 mout(MSWITCHSEP);}
889 | EXPRESSION
890 HPAREXPSEPARATOR
891 SWITCH_LIST { mout(MSWITCHSEP);}
892 ;
893 HEADING : MBEE_FMAL_PAR_P HSTATEMENTSEPARATOR { kind=KNOKD;}
894 MBEE_MODE_PART { categ=CSPEC;}
895 MBEE_SPEC_PART { kind=KNOKD;}
896 MBEE_PROT_PART { categ=CVIRT;}
897 MBEE_VIRT_PART
898 { categ=CLOCAL;}
899 ;
900 MBEE_FMAL_PAR_P : /*EMPT*/
901 | FMAL_PAR_PART
902 ;
903 FMAL_PAR_PART : HBEGPAR NO_TYPE
904 MBEE_LISTV HENDPAR
905 ;
906 MBEE_LISTV : /*EMPT*/
907 | LISTV
908 ;
909 LISTV : HIDENTIFIER { regDecl($1, type, KNOKD, CDEFLT);}
910 | FPP_CATEG HDOTDOTDOT { regDecl(varargsid, TVARARGS, KNOKD, categ);}
911 | HIDENTIFIER { regDecl($1, type, KNOKD, CDEFLT);}
912 HPAREXPSEPARATOR LISTV {}
913 | FPP_SPEC
914 | FPP_SPEC
915 HPAREXPSEPARATOR LISTV
916 ;
917 FPP_HEADING : HBEGPAR NO_TYPE
918 FPP_MBEE_LISTV HENDPAR
919 ;
920 FPP_MBEE_LISTV : /*EMPT*/
921 | FPP_LISTV
922 ;
923 FPP_LISTV : FPP_CATEG HDOTDOTDOT { regDecl(varargsid, TVARARGS, KNOKD, categ);}
924 | FPP_SPEC
925 | FPP_SPEC
926 HPAREXPSEPARATOR LISTV
927 ;
928 FPP_SPEC : FPP_CATEG SPECIFIER HIDENTIFIER
929 { regDecl($3, type, kind, categ);}
930 | FPP_CATEG FPP_PROC_DECL_IN_SPEC
931 ;
932 FPP_CATEG : HNAME HLABELSEPARATOR
933 { categ=CNAME;}
934 | HVALUE HLABELSEPARATOR
935 { categ=CVALUE;}
936 | HVAR HLABELSEPARATOR
937 { categ=CVAR;}
938 | /*EMPT*/ { categ=CDEFLT;}
939 ;
940 FPP_PROC_DECL_IN_SPEC: MBEE_TYPE HPROCEDURE
941 HIDENTIFIER
942 { $<ival>$=categ;
943 regDecl($3, type, KPROC, categ);
944 beginBlock(KPROC);}
945 FPP_HEADING
946 { categ=$<ival>4; /* M} settes tilbake*/}
947 { endBlock(NULL,CCNO);}
948 ;
949 IDENTIFIER_LISTV: HIDENTIFIER { regDecl($1, type, kind, categ);}
950 | HDOTDOTDOT { regDecl(varargsid, TVARARGS, kind, categ);}
951 | HIDENTIFIER { regDecl($1, type, kind, categ);}
952 HPAREXPSEPARATOR IDENTIFIER_LISTV {}
953 ;
954 MBEE_MODE_PART : /*EMPT*/
955 | MODE_PART
956 ;
957 MODE_PART : NAME_PART
958 | VALUE_PART
959 | VAR_PART
960 | NAME_PART VALUE_PART
961 | VALUE_PART NAME_PART
962 | NAME_PART VAR_PART
963 | VAR_PART NAME_PART
964 | VALUE_PART VAR_PART
965 | VAR_PART VALUE_PART
966 | VAR_PART NAME_PART VALUE_PART
967 | NAME_PART VAR_PART VALUE_PART
968 | NAME_PART VALUE_PART VAR_PART
969 | VAR_PART VALUE_PART NAME_PART
970 | VALUE_PART VAR_PART NAME_PART
971 | VALUE_PART NAME_PART VAR_PART
972 ;
973 NAME_PART : HNAME { categ=CNAME;}
974 IDENTIFIER_LISTV
975 HSTATEMENTSEPARATOR
976 ;
977 VAR_PART : HVAR { categ=CVAR;}
978 IDENTIFIER_LISTV
979 HSTATEMENTSEPARATOR
980 ;
981 VALUE_PART : HVALUE { categ=CVALUE;}
982 IDENTIFIER_LISTV HSTATEMENTSEPARATOR
983 ;
984 MBEE_SPEC_PART : /*EMPT*/
985 | SPEC_PART
986 ;
987 SPEC_PART : ONE_SPEC
988 | SPEC_PART ONE_SPEC
989 ;
990 ONE_SPEC : SPECIFIER IDENTIFIER_LIST HSTATEMENTSEPARATOR
991 | NO_TYPE HPROCEDURE HIDENTIFIER HOBJRELOPERATOR
992 { if($4!=HIS) yerror (8);}
993 PROC_DECL_IN_SPEC HSTATEMENTSEPARATOR
994 | FPP_PROC_DECL_IN_SPEC HSTATEMENTSEPARATOR
995 | MBEE_TYPE HPROCEDURE HIDENTIFIER HSTATEMENTSEPARATOR
996 { yerror (45);}
997 | MBEE_TYPE HPROCEDURE HIDENTIFIER HPAREXPSEPARATOR
998 IDENTIFIER_LIST HSTATEMENTSEPARATOR
999 { yerror (45);}
1000 ;
1001 SPECIFIER : TYPE { kind=KSIMPLE;}
1002 | MBEE_TYPE
1003 HARRAY { kind=KARRAY;}
1004 | HLABEL { type=TLABEL;
1005 kind=KSIMPLE;}
1006 | HSWITCH { type=TLABEL;
1007 kind=KARRAY;}
1008 ;
1009 PROC_DECL_IN_SPEC: MBEE_TYPE HPROCEDURE
1010 HIDENTIFIER
1011 { $<ival>$=categ;
1012 regDecl($3, type, KPROC, categ);
1013 beginBlock(KPROC);}
1014 HEADING
1015 { categ=$<ival>4; /* M} settes tilbake*/}
1016 MBEE_BEGIN_END
1017 { endBlock(NULL,CCNO);}
1018 ;
1019 MBEE_BEGIN_END : /* EMPTY */
1020 | HBEGIN HEND
1021 ;
1022 MBEE_PROT_PART : /*EMPT*/
1023 | PROTECTION_PART
1024 ;
1025 PROTECTION_PART : PROT_SPECIFIER IDENTIFIER_LIST
1026 HSTATEMENTSEPARATOR
1027 | PROTECTION_PART PROT_SPECIFIER
1028 IDENTIFIER_LIST HSTATEMENTSEPARATOR
1029 ;
1030 PROT_SPECIFIER : HHIDDEN { categ=CHIDEN;}
1031 | HPROTECTED { categ=CPROT;}
1032 | HHIDDEN
1033 HPROTECTED { categ=CHIPRO;}
1034 | HPROTECTED
1035 HHIDDEN { categ=CHIPRO;}
1036 ;
1037 MBEE_VIRT_PART : /*EMPT*/
1038 | VIRTUAL_PART
1039 ;
1040 VIRTUAL_PART : HVIRTUAL
1041 HLABELSEPARATOR
1042 MBEE_SPEC_PART
1043 ;
1044 IDENTIFIER_LIST : HIDENTIFIER { regDecl($1, type, kind, categ);}
1045 | IDENTIFIER_LIST HPAREXPSEPARATOR
1046 HIDENTIFIER { regDecl($3, type, kind, categ);}
1047 ;
1048 IDENTIFIER_LISTC: HIDENTIFIER
1049 MBEE_CONSTANT { regDecl($1, type, kind, categ);
1050 categ=CLOCAL;}
1051 | IDENTIFIER_LISTC HPAREXPSEPARATOR
1052 HIDENTIFIER
1053 MBEE_CONSTANT { regDecl($3, type, kind, categ);
1054 categ=CLOCAL;}
1055 ;
1056 MBEE_CONSTANT : /* EMPTY */
1057 | HVALRELOPERATOR
1058 { MBEENEWBLOCK();
1059 if($1!=HEQ) yerror (8);
1060 if(type==TREF)yerror (7);
1061 categ=CCONSTU;
1062 mout(MIDENTIFIER);
1063 moutId($<token>0);}
1064 EXPRESSION { mout(MASSIGN);
1065 mout(MCONST);}
1066 ;
1067
1068 /* GRAMATIKK FOR UTTRYKK */
1069 EXPRESSION : EXPRESSION_SIMP {}
1070 | HIF
1071 EXPRESSION
1072 HTHEN
1073 EXPRESSION
1074 HELSE
1075 EXPRESSION { mout(MELSEE);
1076 mout(MIFE);}
1077 ;
1078 EXPRESSION_SIMP : EXPRESSION_SIMP
1079 HASSIGN
1080 EXPRESSION { if($2==HASSIGNREF)mout(MASSIGNR);
1081 else mout(MASSIGN);$$=NULL;}
1082 |
1083
1084 EXPRESSION_SIMP
1085 HCONC
1086 EXPRESSION_SIMP { mout(MCONC);$$=NULL;}
1087 | EXPRESSION_SIMP HOR
1088 HELSE
1089 EXPRESSION_SIMP
1090 %prec HORELSE { mout(MORELSEE);$$=NULL;}
1091 | EXPRESSION_SIMP HAND
1092 HTHEN
1093 EXPRESSION_SIMP
1094 %prec HANDTHEN { mout(MANDTHENE);$$=NULL;}
1095 | EXPRESSION_SIMP
1096 HEQV EXPRESSION_SIMP { mout(MEQV);$$=NULL;}
1097 | EXPRESSION_SIMP
1098 HIMP EXPRESSION_SIMP { mout(MIMP);$$=NULL;}
1099 | EXPRESSION_SIMP
1100 HOR EXPRESSION_SIMP { mout(MOR);$$=NULL;}
1101 | EXPRESSION_SIMP
1102 HAND EXPRESSION_SIMP { mout(MAND);$$=NULL;}
1103 | HNOT EXPRESSION_SIMP { mout(MNOT);$$=NULL;}
1104 | EXPRESSION_SIMP
1105 HVALRELOPERATOR
1106 EXPRESSION_SIMP
1107 { switch($2)
1108 { case HEQ: mout(MEQ);break;
1109 case HNE: mout(MNE);break;
1110 case HLT: mout(MLT);break;
1111 case HLE: mout(MLE);break;
1112 case HGT: mout(MGT);break;
1113 case HGE: mout(MGE);break;
1114 }$$=NULL;}
1115 | EXPRESSION_SIMP
1116 HREFRELOPERATOR
1117 EXPRESSION_SIMP
1118 { if($2==HNER) mout(MNER);
1119 else mout(MEQR);$$=NULL;}
1120 | EXPRESSION_SIMP
1121 HOBJRELOPERATOR
1122 EXPRESSION_SIMP
1123 { if($2==HIS) mout(MIS);
1124 else mout(MINS);$$=NULL;}
1125 | HTERMOPERATOR
1126 EXPRESSION_SIMP %prec UNEAR
1127 { if($1==HADD) mout(MUADD);
1128 else mout(MUSUB);$$=NULL;}
1129 | EXPRESSION_SIMP
1130 HTERMOPERATOR
1131 EXPRESSION_SIMP
1132 { if($2==HADD) mout(MADD);
1133 else mout(MSUB);$$=NULL;}
1134 | EXPRESSION_SIMP
1135 HFACTOROPERATOR
1136 EXPRESSION_SIMP
1137 { if($2==HMUL) mout(MMUL); else
1138 if($2==HDIV) mout(MDIV);
1139 else mout(MINTDIV);$$=NULL;}
1140 | EXPRESSION_SIMP
1141 HPRIMARYOPERATOR
1142 EXPRESSION_SIMP { mout(MPRIMARY);$$=NULL;}
1143 | HBEGPAR
1144 EXPRESSION HENDPAR { mout(MNOOP);$$=NULL;}
1145 | HTEXTKONST { mout(MTEXTKONST);
1146 moutTval($1);$$=NULL;}
1147 | HCHARACTERKONST { mout(MCHARACTERKONST);
1148 moutIval($1);$$=NULL;}
1149 | HREALKONST { mout(MREALKONST);
1150 moutRval($1);$$=NULL;}
1151 | HINTEGERKONST { mout(MINTEGERKONST);
1152 moutIval($1);$$=NULL;}
1153 | HBOOLEANKONST { mout(MBOOLEANKONST);
1154 moutIval($1);$$=NULL;}
1155 | HNONE { mout(MNONE);$$=NULL;}
1156 | HIDENTIFIER
1157 { $<ident>$=$1;}
1158 MBEE_ARG_R_PT {}
1159 | HTHIS HIDENTIFIER { mout(MTHIS);
1160 moutId($2);$$=NULL;}
1161 | HNEW
1162 HIDENTIFIER
1163 ARG_R_PT { mout(MNEWARG);
1164 moutId($2);$$=NULL;}
1165 | EXPRESSION_SIMP
1166 HDOT
1167 EXPRESSION_SIMP { mout(MDOT);$$=NULL;}
1168 | EXPRESSION_SIMP
1169 HQUA HIDENTIFIER { mout(MQUA);
1170 moutId($3);$$=NULL;}
1171 ;
1172 ARG_R_PT : /*EMPTY*/ { mout(MENDSEP);}
1173 | HBEGPAR
1174 ARGUMENT_LIST HENDPAR
1175 ;
1176 MBEE_ARG_R_PT : /*EMPTY*/ { mout(MIDENTIFIER);
1177 moutId($<ident>0);
1178 $$=$<ident>0;}
1179 | HBEGPAR
1180 ARGUMENT_LIST HENDPAR { mout(MARGUMENT);
1181 moutId($<ident>0);}
1182 ;
1183 ARGUMENT_LIST : EXPRESSION { mout(MENDSEP);
1184 mout(MARGUMENTSEP);}
1185 | EXPRESSION
1186 HPAREXPSEPARATOR
1187 ARGUMENT_LIST { mout(MARGUMENTSEP);}
1188 ;
1189 %%
1190 ]])
1191
1192 # Pass plenty of options, to exercise plenty of code, even if we
1193 # don't actually check the output. But SEGV is watching us, and
1194 # so might do dmalloc.
1195 AT_CHECK([[bison --verbose --defines input.y]], 0, [],
1196 [[input.y: conflicts: 78 shift/reduce, 10 reduce/reduce
1197 ]])
1198
1199 AT_CHECK([[grep '^State.*conflicts:' input.output]], 0,
1200 [[State 64 conflicts: 14 shift/reduce
1201 State 164 conflicts: 1 shift/reduce
1202 State 201 conflicts: 33 shift/reduce, 4 reduce/reduce
1203 State 206 conflicts: 1 shift/reduce
1204 State 240 conflicts: 1 shift/reduce
1205 State 335 conflicts: 9 shift/reduce, 2 reduce/reduce
1206 State 356 conflicts: 1 shift/reduce
1207 State 360 conflicts: 9 shift/reduce, 2 reduce/reduce
1208 State 427 conflicts: 9 shift/reduce, 2 reduce/reduce
1209 ]])
1210
1211 AT_CLEANUP
1212
1213
1214 ## ----------------- ##
1215 ## GNU pic Grammar. ##
1216 ## ----------------- ##
1217
1218 AT_SETUP([GNU pic Grammar])
1219
1220 # GNU pic, part of groff.
1221
1222 # Bison once reported shift/reduce conflicts that it shouldn't have.
1223
1224 AT_DATA([[input.y]],
1225 [[%union {
1226 char *str;
1227 int n;
1228 double x;
1229 struct { double x, y; } pair;
1230 struct { double x; char *body; } if_data;
1231 struct { char *str; const char *filename; int lineno; } lstr;
1232 struct { double *v; int nv; int maxv; } dv;
1233 struct { double val; int is_multiplicative; } by;
1234 place pl;
1235 object *obj;
1236 corner crn;
1237 path *pth;
1238 object_spec *spec;
1239 saved_state *pstate;
1240 graphics_state state;
1241 object_type obtype;
1242 }
1243
1244 %token <str> LABEL
1245 %token <str> VARIABLE
1246 %token <x> NUMBER
1247 %token <lstr> TEXT
1248 %token <lstr> COMMAND_LINE
1249 %token <str> DELIMITED
1250 %token <n> ORDINAL
1251 %token TH
1252 %token LEFT_ARROW_HEAD
1253 %token RIGHT_ARROW_HEAD
1254 %token DOUBLE_ARROW_HEAD
1255 %token LAST
1256 %token UP
1257 %token DOWN
1258 %token LEFT
1259 %token RIGHT
1260 %token BOX
1261 %token CIRCLE
1262 %token ELLIPSE
1263 %token ARC
1264 %token LINE
1265 %token ARROW
1266 %token MOVE
1267 %token SPLINE
1268 %token HEIGHT
1269 %token RADIUS
1270 %token WIDTH
1271 %token DIAMETER
1272 %token FROM
1273 %token TO
1274 %token AT
1275 %token WITH
1276 %token BY
1277 %token THEN
1278 %token SOLID
1279 %token DOTTED
1280 %token DASHED
1281 %token CHOP
1282 %token SAME
1283 %token INVISIBLE
1284 %token LJUST
1285 %token RJUST
1286 %token ABOVE
1287 %token BELOW
1288 %token OF
1289 %token THE
1290 %token WAY
1291 %token BETWEEN
1292 %token AND
1293 %token HERE
1294 %token DOT_N
1295 %token DOT_E
1296 %token DOT_W
1297 %token DOT_S
1298 %token DOT_NE
1299 %token DOT_SE
1300 %token DOT_NW
1301 %token DOT_SW
1302 %token DOT_C
1303 %token DOT_START
1304 %token DOT_END
1305 %token DOT_X
1306 %token DOT_Y
1307 %token DOT_HT
1308 %token DOT_WID
1309 %token DOT_RAD
1310 %token SIN
1311 %token COS
1312 %token ATAN2
1313 %token LOG
1314 %token EXP
1315 %token SQRT
1316 %token K_MAX
1317 %token K_MIN
1318 %token INT
1319 %token RAND
1320 %token SRAND
1321 %token COPY
1322 %token THRU
1323 %token TOP
1324 %token BOTTOM
1325 %token UPPER
1326 %token LOWER
1327 %token SH
1328 %token PRINT
1329 %token CW
1330 %token CCW
1331 %token FOR
1332 %token DO
1333 %token IF
1334 %token ELSE
1335 %token ANDAND
1336 %token OROR
1337 %token NOTEQUAL
1338 %token EQUALEQUAL
1339 %token LESSEQUAL
1340 %token GREATEREQUAL
1341 %token LEFT_CORNER
1342 %token RIGHT_CORNER
1343 %token NORTH
1344 %token SOUTH
1345 %token EAST
1346 %token WEST
1347 %token CENTER
1348 %token END
1349 %token START
1350 %token RESET
1351 %token UNTIL
1352 %token PLOT
1353 %token THICKNESS
1354 %token FILL
1355 %token COLORED
1356 %token OUTLINED
1357 %token SHADED
1358 %token ALIGNED
1359 %token SPRINTF
1360 %token COMMAND
1361
1362 %left '.'
1363
1364 /* this ensures that plot 17 "%g" parses as (plot 17 "%g") */
1365 %left PLOT
1366 %left TEXT SPRINTF
1367
1368 /* give text adjustments higher precedence than TEXT, so that
1369 box "foo" above ljust == box ("foo" above ljust)
1370 */
1371
1372 %left LJUST RJUST ABOVE BELOW
1373
1374 %left LEFT RIGHT
1375 /* Give attributes that take an optional expression a higher
1376 precedence than left and right, so that eg `line chop left'
1377 parses properly. */
1378 %left CHOP SOLID DASHED DOTTED UP DOWN FILL COLORED OUTLINED
1379 %left LABEL
1380
1381 %left VARIABLE NUMBER '(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND SRAND LAST
1382 %left ORDINAL HERE '`'
1383
1384 %left BOX CIRCLE ELLIPSE ARC LINE ARROW SPLINE '[' /* ] */
1385
1386 /* these need to be lower than '-' */
1387 %left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS
1388
1389 /* these must have higher precedence than CHOP so that `label %prec CHOP'
1390 works */
1391 %left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C
1392 %left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER
1393 %left UPPER LOWER NORTH SOUTH EAST WEST CENTER START END
1394
1395 %left ','
1396 %left OROR
1397 %left ANDAND
1398 %left EQUALEQUAL NOTEQUAL
1399 %left '<' '>' LESSEQUAL GREATEREQUAL
1400
1401 %left BETWEEN OF
1402 %left AND
1403
1404 %left '+' '-'
1405 %left '*' '/' '%'
1406 %right '!'
1407 %right '^'
1408
1409 %type <x> expr any_expr text_expr
1410 %type <by> optional_by
1411 %type <pair> expr_pair position_not_place
1412 %type <if_data> simple_if
1413 %type <obj> nth_primitive
1414 %type <crn> corner
1415 %type <pth> path label_path relative_path
1416 %type <pl> place label element element_list middle_element_list
1417 %type <spec> object_spec
1418 %type <pair> position
1419 %type <obtype> object_type
1420 %type <n> optional_ordinal_last ordinal
1421 %type <str> until
1422 %type <dv> sprintf_args
1423 %type <lstr> text print_args print_arg
1424
1425 %%
1426
1427 top:
1428 optional_separator
1429 | element_list
1430 {
1431 if (olist.head)
1432 print_picture(olist.head);
1433 }
1434 ;
1435
1436
1437 element_list:
1438 optional_separator middle_element_list optional_separator
1439 { $$ = $2; }
1440 ;
1441
1442 middle_element_list:
1443 element
1444 { $$ = $1; }
1445 | middle_element_list separator element
1446 { $$ = $1; }
1447 ;
1448
1449 optional_separator:
1450 /* empty */
1451 | separator
1452 ;
1453
1454 separator:
1455 ';'
1456 | separator ';'
1457 ;
1458
1459 placeless_element:
1460 VARIABLE '=' any_expr
1461 {
1462 define_variable($1, $3);
1463 a_delete $1;
1464 }
1465 | VARIABLE ':' '=' any_expr
1466 {
1467 place *p = lookup_label($1);
1468 if (!p) {
1469 lex_error("variable `%1' not defined", $1);
1470 YYABORT;
1471 }
1472 p->obj = 0;
1473 p->x = $4;
1474 p->y = 0.0;
1475 a_delete $1;
1476 }
1477 | UP
1478 { current_direction = UP_DIRECTION; }
1479 | DOWN
1480 { current_direction = DOWN_DIRECTION; }
1481 | LEFT
1482 { current_direction = LEFT_DIRECTION; }
1483 | RIGHT
1484 { current_direction = RIGHT_DIRECTION; }
1485 | COMMAND_LINE
1486 {
1487 olist.append(make_command_object($1.str, $1.filename,
1488 $1.lineno));
1489 }
1490 | COMMAND print_args
1491 {
1492 olist.append(make_command_object($2.str, $2.filename,
1493 $2.lineno));
1494 }
1495 | PRINT print_args
1496 {
1497 fprintf(stderr, "%s\n", $2.str);
1498 a_delete $2.str;
1499 fflush(stderr);
1500 }
1501 | SH
1502 { delim_flag = 1; }
1503 DELIMITED
1504 {
1505 delim_flag = 0;
1506 if (safer_flag)
1507 lex_error("unsafe to run command `%1'", $3);
1508 else
1509 system($3);
1510 a_delete $3;
1511 }
1512 | COPY TEXT
1513 {
1514 if (yychar < 0)
1515 do_lookahead();
1516 do_copy($2.str);
1517 // do not delete the filename
1518 }
1519 | COPY TEXT THRU
1520 { delim_flag = 2; }
1521 DELIMITED
1522 { delim_flag = 0; }
1523 until
1524 {
1525 if (yychar < 0)
1526 do_lookahead();
1527 copy_file_thru($2.str, $5, $7);
1528 // do not delete the filename
1529 a_delete $5;
1530 a_delete $7;
1531 }
1532 | COPY THRU
1533 { delim_flag = 2; }
1534 DELIMITED
1535 { delim_flag = 0; }
1536 until
1537 {
1538 if (yychar < 0)
1539 do_lookahead();
1540 copy_rest_thru($4, $6);
1541 a_delete $4;
1542 a_delete $6;
1543 }
1544 | FOR VARIABLE '=' expr TO expr optional_by DO
1545 { delim_flag = 1; }
1546 DELIMITED
1547 {
1548 delim_flag = 0;
1549 if (yychar < 0)
1550 do_lookahead();
1551 do_for($2, $4, $6, $7.is_multiplicative, $7.val, $10);
1552 }
1553 | simple_if
1554 {
1555 if (yychar < 0)
1556 do_lookahead();
1557 if ($1.x != 0.0)
1558 push_body($1.body);
1559 a_delete $1.body;
1560 }
1561 | simple_if ELSE
1562 { delim_flag = 1; }
1563 DELIMITED
1564 {
1565 delim_flag = 0;
1566 if (yychar < 0)
1567 do_lookahead();
1568 if ($1.x != 0.0)
1569 push_body($1.body);
1570 else
1571 push_body($4);
1572 a_delete $1.body;
1573 a_delete $4;
1574 }
1575 | reset_variables
1576 | RESET
1577 { define_variable("scale", 1.0); }
1578 ;
1579
1580 reset_variables:
1581 RESET VARIABLE
1582 {
1583 reset($2);
1584 a_delete $2;
1585 }
1586 | reset_variables VARIABLE
1587 {
1588 reset($2);
1589 a_delete $2;
1590 }
1591 | reset_variables ',' VARIABLE
1592 {
1593 reset($3);
1594 a_delete $3;
1595 }
1596 ;
1597
1598 print_args:
1599 print_arg
1600 { $$ = $1; }
1601 | print_args print_arg
1602 {
1603 $$.str = new char[strlen($1.str) + strlen($2.str) + 1];
1604 strcpy($$.str, $1.str);
1605 strcat($$.str, $2.str);
1606 a_delete $1.str;
1607 a_delete $2.str;
1608 if ($1.filename) {
1609 $$.filename = $1.filename;
1610 $$.lineno = $1.lineno;
1611 }
1612 else if ($2.filename) {
1613 $$.filename = $2.filename;
1614 $$.lineno = $2.lineno;
1615 }
1616 }
1617 ;
1618
1619 print_arg:
1620 expr %prec ','
1621 {
1622 $$.str = new char[GDIGITS + 1];
1623 sprintf($$.str, "%g", $1);
1624 $$.filename = 0;
1625 $$.lineno = 0;
1626 }
1627 | text
1628 { $$ = $1; }
1629 | position %prec ','
1630 {
1631 $$.str = new char[GDIGITS + 2 + GDIGITS + 1];
1632 sprintf($$.str, "%g, %g", $1.x, $1.y);
1633 $$.filename = 0;
1634 $$.lineno = 0;
1635 }
1636 ;
1637
1638 simple_if:
1639 IF any_expr THEN
1640 { delim_flag = 1; }
1641 DELIMITED
1642 {
1643 delim_flag = 0;
1644 $$.x = $2;
1645 $$.body = $5;
1646 }
1647 ;
1648
1649 until:
1650 /* empty */
1651 { $$ = 0; }
1652 | UNTIL TEXT
1653 { $$ = $2.str; }
1654 ;
1655
1656 any_expr:
1657 expr
1658 { $$ = $1; }
1659 | text_expr
1660 { $$ = $1; }
1661 ;
1662
1663 text_expr:
1664 text EQUALEQUAL text
1665 {
1666 $$ = strcmp($1.str, $3.str) == 0;
1667 a_delete $1.str;
1668 a_delete $3.str;
1669 }
1670 | text NOTEQUAL text
1671 {
1672 $$ = strcmp($1.str, $3.str) != 0;
1673 a_delete $1.str;
1674 a_delete $3.str;
1675 }
1676 | text_expr ANDAND text_expr
1677 { $$ = ($1 != 0.0 && $3 != 0.0); }
1678 | text_expr ANDAND expr
1679 { $$ = ($1 != 0.0 && $3 != 0.0); }
1680 | expr ANDAND text_expr
1681 { $$ = ($1 != 0.0 && $3 != 0.0); }
1682 | text_expr OROR text_expr
1683 { $$ = ($1 != 0.0 || $3 != 0.0); }
1684 | text_expr OROR expr
1685 { $$ = ($1 != 0.0 || $3 != 0.0); }
1686 | expr OROR text_expr
1687 { $$ = ($1 != 0.0 || $3 != 0.0); }
1688 | '!' text_expr
1689 { $$ = ($2 == 0.0); }
1690 ;
1691
1692
1693 optional_by:
1694 /* empty */
1695 {
1696 $$.val = 1.0;
1697 $$.is_multiplicative = 0;
1698 }
1699 | BY expr
1700 {
1701 $$.val = $2;
1702 $$.is_multiplicative = 0;
1703 }
1704 | BY '*' expr
1705 {
1706 $$.val = $3;
1707 $$.is_multiplicative = 1;
1708 }
1709 ;
1710
1711 element:
1712 object_spec
1713 {
1714 $$.obj = $1->make_object(&current_position,
1715 &current_direction);
1716 if ($$.obj == 0)
1717 YYABORT;
1718 delete $1;
1719 if ($$.obj)
1720 olist.append($$.obj);
1721 else {
1722 $$.x = current_position.x;
1723 $$.y = current_position.y;
1724 }
1725 }
1726 | LABEL ':' optional_separator element
1727 {
1728 $$ = $4;
1729 define_label($1, & $$);
1730 a_delete $1;
1731 }
1732 | LABEL ':' optional_separator position_not_place
1733 {
1734 $$.obj = 0;
1735 $$.x = $4.x;
1736 $$.y = $4.y;
1737 define_label($1, & $$);
1738 a_delete $1;
1739 }
1740 | LABEL ':' optional_separator place
1741 {
1742 $$ = $4;
1743 define_label($1, & $$);
1744 a_delete $1;
1745 }
1746 | '{'
1747 {
1748 $<state>$.x = current_position.x;
1749 $<state>$.y = current_position.y;
1750 $<state>$.dir = current_direction;
1751 }
1752 element_list '}'
1753 {
1754 current_position.x = $<state>2.x;
1755 current_position.y = $<state>2.y;
1756 current_direction = $<state>2.dir;
1757 }
1758 optional_element
1759 {
1760 $$ = $3;
1761 }
1762 | placeless_element
1763 {
1764 $$.obj = 0;
1765 $$.x = current_position.x;
1766 $$.y = current_position.y;
1767 }
1768 ;
1769
1770 optional_element:
1771 /* empty */
1772 {}
1773 | element
1774 {}
1775 ;
1776
1777 object_spec:
1778 BOX
1779 { $$ = new object_spec(BOX_OBJECT); }
1780 | CIRCLE
1781 { $$ = new object_spec(CIRCLE_OBJECT); }
1782 | ELLIPSE
1783 { $$ = new object_spec(ELLIPSE_OBJECT); }
1784 | ARC
1785 {
1786 $$ = new object_spec(ARC_OBJECT);
1787 $$->dir = current_direction;
1788 }
1789 | LINE
1790 {
1791 $$ = new object_spec(LINE_OBJECT);
1792 lookup_variable("lineht", & $$->segment_height);
1793 lookup_variable("linewid", & $$->segment_width);
1794 $$->dir = current_direction;
1795 }
1796 | ARROW
1797 {
1798 $$ = new object_spec(ARROW_OBJECT);
1799 lookup_variable("lineht", & $$->segment_height);
1800 lookup_variable("linewid", & $$->segment_width);
1801 $$->dir = current_direction;
1802 }
1803 | MOVE
1804 {
1805 $$ = new object_spec(MOVE_OBJECT);
1806 lookup_variable("moveht", & $$->segment_height);
1807 lookup_variable("movewid", & $$->segment_width);
1808 $$->dir = current_direction;
1809 }
1810 | SPLINE
1811 {
1812 $$ = new object_spec(SPLINE_OBJECT);
1813 lookup_variable("lineht", & $$->segment_height);
1814 lookup_variable("linewid", & $$->segment_width);
1815 $$->dir = current_direction;
1816 }
1817 | text %prec TEXT
1818 {
1819 $$ = new object_spec(TEXT_OBJECT);
1820 $$->text = new text_item($1.str, $1.filename, $1.lineno);
1821 }
1822 | PLOT expr
1823 {
1824 $$ = new object_spec(TEXT_OBJECT);
1825 $$->text = new text_item(format_number(0, $2), 0, -1);
1826 }
1827 | PLOT expr text
1828 {
1829 $$ = new object_spec(TEXT_OBJECT);
1830 $$->text = new text_item(format_number($3.str, $2),
1831 $3.filename, $3.lineno);
1832 a_delete $3.str;
1833 }
1834 | '['
1835 {
1836 saved_state *p = new saved_state;
1837 $<pstate>$ = p;
1838 p->x = current_position.x;
1839 p->y = current_position.y;
1840 p->dir = current_direction;
1841 p->tbl = current_table;
1842 p->prev = current_saved_state;
1843 current_position.x = 0.0;
1844 current_position.y = 0.0;
1845 current_table = new PTABLE(place);
1846 current_saved_state = p;
1847 olist.append(make_mark_object());
1848 }
1849 element_list ']'
1850 {
1851 current_position.x = $<pstate>2->x;
1852 current_position.y = $<pstate>2->y;
1853 current_direction = $<pstate>2->dir;
1854 $$ = new object_spec(BLOCK_OBJECT);
1855 olist.wrap_up_block(& $$->oblist);
1856 $$->tbl = current_table;
1857 current_table = $<pstate>2->tbl;
1858 current_saved_state = $<pstate>2->prev;
1859 delete $<pstate>2;
1860 }
1861 | object_spec HEIGHT expr
1862 {
1863 $$ = $1;
1864 $$->height = $3;
1865 $$->flags |= HAS_HEIGHT;
1866 }
1867 | object_spec RADIUS expr
1868 {
1869 $$ = $1;
1870 $$->radius = $3;
1871 $$->flags |= HAS_RADIUS;
1872 }
1873 | object_spec WIDTH expr
1874 {
1875 $$ = $1;
1876 $$->width = $3;
1877 $$->flags |= HAS_WIDTH;
1878 }
1879 | object_spec DIAMETER expr
1880 {
1881 $$ = $1;
1882 $$->radius = $3/2.0;
1883 $$->flags |= HAS_RADIUS;
1884 }
1885 | object_spec expr %prec HEIGHT
1886 {
1887 $$ = $1;
1888 $$->flags |= HAS_SEGMENT;
1889 switch ($$->dir) {
1890 case UP_DIRECTION:
1891 $$->segment_pos.y += $2;
1892 break;
1893 case DOWN_DIRECTION:
1894 $$->segment_pos.y -= $2;
1895 break;
1896 case RIGHT_DIRECTION:
1897 $$->segment_pos.x += $2;
1898 break;
1899 case LEFT_DIRECTION:
1900 $$->segment_pos.x -= $2;
1901 break;
1902 }
1903 }
1904 | object_spec UP
1905 {
1906 $$ = $1;
1907 $$->dir = UP_DIRECTION;
1908 $$->flags |= HAS_SEGMENT;
1909 $$->segment_pos.y += $$->segment_height;
1910 }
1911 | object_spec UP expr
1912 {
1913 $$ = $1;
1914 $$->dir = UP_DIRECTION;
1915 $$->flags |= HAS_SEGMENT;
1916 $$->segment_pos.y += $3;
1917 }
1918 | object_spec DOWN
1919 {
1920 $$ = $1;
1921 $$->dir = DOWN_DIRECTION;
1922 $$->flags |= HAS_SEGMENT;
1923 $$->segment_pos.y -= $$->segment_height;
1924 }
1925 | object_spec DOWN expr
1926 {
1927 $$ = $1;
1928 $$->dir = DOWN_DIRECTION;
1929 $$->flags |= HAS_SEGMENT;
1930 $$->segment_pos.y -= $3;
1931 }
1932 | object_spec RIGHT
1933 {
1934 $$ = $1;
1935 $$->dir = RIGHT_DIRECTION;
1936 $$->flags |= HAS_SEGMENT;
1937 $$->segment_pos.x += $$->segment_width;
1938 }
1939 | object_spec RIGHT expr
1940 {
1941 $$ = $1;
1942 $$->dir = RIGHT_DIRECTION;
1943 $$->flags |= HAS_SEGMENT;
1944 $$->segment_pos.x += $3;
1945 }
1946 | object_spec LEFT
1947 {
1948 $$ = $1;
1949 $$->dir = LEFT_DIRECTION;
1950 $$->flags |= HAS_SEGMENT;
1951 $$->segment_pos.x -= $$->segment_width;
1952 }
1953 | object_spec LEFT expr
1954 {
1955 $$ = $1;
1956 $$->dir = LEFT_DIRECTION;
1957 $$->flags |= HAS_SEGMENT;
1958 $$->segment_pos.x -= $3;
1959 }
1960 | object_spec FROM position
1961 {
1962 $$ = $1;
1963 $$->flags |= HAS_FROM;
1964 $$->from.x = $3.x;
1965 $$->from.y = $3.y;
1966 }
1967 | object_spec TO position
1968 {
1969 $$ = $1;
1970 if ($$->flags & HAS_SEGMENT)
1971 $$->segment_list = new segment($$->segment_pos,
1972 $$->segment_is_absolute,
1973 $$->segment_list);
1974 $$->flags |= HAS_SEGMENT;
1975 $$->segment_pos.x = $3.x;
1976 $$->segment_pos.y = $3.y;
1977 $$->segment_is_absolute = 1;
1978 $$->flags |= HAS_TO;
1979 $$->to.x = $3.x;
1980 $$->to.y = $3.y;
1981 }
1982 | object_spec AT position
1983 {
1984 $$ = $1;
1985 $$->flags |= HAS_AT;
1986 $$->at.x = $3.x;
1987 $$->at.y = $3.y;
1988 if ($$->type != ARC_OBJECT) {
1989 $$->flags |= HAS_FROM;
1990 $$->from.x = $3.x;
1991 $$->from.y = $3.y;
1992 }
1993 }
1994 | object_spec WITH path
1995 {
1996 $$ = $1;
1997 $$->flags |= HAS_WITH;
1998 $$->with = $3;
1999 }
2000 | object_spec WITH position %prec ','
2001 {
2002 $$ = $1;
2003 $$->flags |= HAS_WITH;
2004 position pos;
2005 pos.x = $3.x;
2006 pos.y = $3.y;
2007 $$->with = new path(pos);
2008 }
2009 | object_spec BY expr_pair
2010 {
2011 $$ = $1;
2012 $$->flags |= HAS_SEGMENT;
2013 $$->segment_pos.x += $3.x;
2014 $$->segment_pos.y += $3.y;
2015 }
2016 | object_spec THEN
2017 {
2018 $$ = $1;
2019 if ($$->flags & HAS_SEGMENT) {
2020 $$->segment_list = new segment($$->segment_pos,
2021 $$->segment_is_absolute,
2022 $$->segment_list);
2023 $$->flags &= ~HAS_SEGMENT;
2024 $$->segment_pos.x = $$->segment_pos.y = 0.0;
2025 $$->segment_is_absolute = 0;
2026 }
2027 }
2028 | object_spec SOLID
2029 {
2030 $$ = $1; // nothing
2031 }
2032 | object_spec DOTTED
2033 {
2034 $$ = $1;
2035 $$->flags |= IS_DOTTED;
2036 lookup_variable("dashwid", & $$->dash_width);
2037 }
2038 | object_spec DOTTED expr
2039 {
2040 $$ = $1;
2041 $$->flags |= IS_DOTTED;
2042 $$->dash_width = $3;
2043 }
2044 | object_spec DASHED
2045 {
2046 $$ = $1;
2047 $$->flags |= IS_DASHED;
2048 lookup_variable("dashwid", & $$->dash_width);
2049 }
2050 | object_spec DASHED expr
2051 {
2052 $$ = $1;
2053 $$->flags |= IS_DASHED;
2054 $$->dash_width = $3;
2055 }
2056 | object_spec FILL
2057 {
2058 $$ = $1;
2059 $$->flags |= IS_DEFAULT_FILLED;
2060 }
2061 | object_spec FILL expr
2062 {
2063 $$ = $1;
2064 $$->flags |= IS_FILLED;
2065 $$->fill = $3;
2066 }
2067 | object_spec SHADED text
2068 {
2069 $$ = $1;
2070 $$->flags |= (IS_SHADED | IS_FILLED);
2071 $$->shaded = new char[strlen($3.str)+1];
2072 strcpy($$->shaded, $3.str);
2073 }
2074 | object_spec COLORED text
2075 {
2076 $$ = $1;
2077 $$->flags |= (IS_SHADED | IS_OUTLINED | IS_FILLED);
2078 $$->shaded = new char[strlen($3.str)+1];
2079 strcpy($$->shaded, $3.str);
2080 $$->outlined = new char[strlen($3.str)+1];
2081 strcpy($$->outlined, $3.str);
2082 }
2083 | object_spec OUTLINED text
2084 {
2085 $$ = $1;
2086 $$->flags |= IS_OUTLINED;
2087 $$->outlined = new char[strlen($3.str)+1];
2088 strcpy($$->outlined, $3.str);
2089 }
2090 | object_spec CHOP
2091 {
2092 $$ = $1;
2093 // line chop chop means line chop 0 chop 0
2094 if ($$->flags & IS_DEFAULT_CHOPPED) {
2095 $$->flags |= IS_CHOPPED;
2096 $$->flags &= ~IS_DEFAULT_CHOPPED;
2097 $$->start_chop = $$->end_chop = 0.0;
2098 }
2099 else if ($$->flags & IS_CHOPPED) {
2100 $$->end_chop = 0.0;
2101 }
2102 else {
2103 $$->flags |= IS_DEFAULT_CHOPPED;
2104 }
2105 }
2106 | object_spec CHOP expr
2107 {
2108 $$ = $1;
2109 if ($$->flags & IS_DEFAULT_CHOPPED) {
2110 $$->flags |= IS_CHOPPED;
2111 $$->flags &= ~IS_DEFAULT_CHOPPED;
2112 $$->start_chop = 0.0;
2113 $$->end_chop = $3;
2114 }
2115 else if ($$->flags & IS_CHOPPED) {
2116 $$->end_chop = $3;
2117 }
2118 else {
2119 $$->start_chop = $$->end_chop = $3;
2120 $$->flags |= IS_CHOPPED;
2121 }
2122 }
2123 | object_spec SAME
2124 {
2125 $$ = $1;
2126 $$->flags |= IS_SAME;
2127 }
2128 | object_spec INVISIBLE
2129 {
2130 $$ = $1;
2131 $$->flags |= IS_INVISIBLE;
2132 }
2133 | object_spec LEFT_ARROW_HEAD
2134 {
2135 $$ = $1;
2136 $$->flags |= HAS_LEFT_ARROW_HEAD;
2137 }
2138 | object_spec RIGHT_ARROW_HEAD
2139 {
2140 $$ = $1;
2141 $$->flags |= HAS_RIGHT_ARROW_HEAD;
2142 }
2143 | object_spec DOUBLE_ARROW_HEAD
2144 {
2145 $$ = $1;
2146 $$->flags |= (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD);
2147 }
2148 | object_spec CW
2149 {
2150 $$ = $1;
2151 $$->flags |= IS_CLOCKWISE;
2152 }
2153 | object_spec CCW
2154 {
2155 $$ = $1;
2156 $$->flags &= ~IS_CLOCKWISE;
2157 }
2158 | object_spec text %prec TEXT
2159 {
2160 $$ = $1;
2161 text_item **p;
2162 for (p = & $$->text; *p; p = &(*p)->next)
2163 ;
2164 *p = new text_item($2.str, $2.filename, $2.lineno);
2165 }
2166 | object_spec LJUST
2167 {
2168 $$ = $1;
2169 if ($$->text) {
2170 text_item *p;
2171 for (p = $$->text; p->next; p = p->next)
2172 ;
2173 p->adj.h = LEFT_ADJUST;
2174 }
2175 }
2176 | object_spec RJUST
2177 {
2178 $$ = $1;
2179 if ($$->text) {
2180 text_item *p;
2181 for (p = $$->text; p->next; p = p->next)
2182 ;
2183 p->adj.h = RIGHT_ADJUST;
2184 }
2185 }
2186 | object_spec ABOVE
2187 {
2188 $$ = $1;
2189 if ($$->text) {
2190 text_item *p;
2191 for (p = $$->text; p->next; p = p->next)
2192 ;
2193 p->adj.v = ABOVE_ADJUST;
2194 }
2195 }
2196 | object_spec BELOW
2197 {
2198 $$ = $1;
2199 if ($$->text) {
2200 text_item *p;
2201 for (p = $$->text; p->next; p = p->next)
2202 ;
2203 p->adj.v = BELOW_ADJUST;
2204 }
2205 }
2206 | object_spec THICKNESS expr
2207 {
2208 $$ = $1;
2209 $$->flags |= HAS_THICKNESS;
2210 $$->thickness = $3;
2211 }
2212 | object_spec ALIGNED
2213 {
2214 $$ = $1;
2215 $$->flags |= IS_ALIGNED;
2216 }
2217 ;
2218
2219 text:
2220 TEXT
2221 { $$ = $1; }
2222 | SPRINTF '(' TEXT sprintf_args ')'
2223 {
2224 $$.filename = $3.filename;
2225 $$.lineno = $3.lineno;
2226 $$.str = do_sprintf($3.str, $4.v, $4.nv);
2227 a_delete $4.v;
2228 a_delete $3.str;
2229 }
2230 ;
2231
2232 sprintf_args:
2233 /* empty */
2234 {
2235 $$.v = 0;
2236 $$.nv = 0;
2237 $$.maxv = 0;
2238 }
2239 | sprintf_args ',' expr
2240 {
2241 $$ = $1;
2242 if ($$.nv >= $$.maxv) {
2243 if ($$.nv == 0) {
2244 $$.v = new double[4];
2245 $$.maxv = 4;
2246 }
2247 else {
2248 double *oldv = $$.v;
2249 $$.maxv *= 2;
2250 $$.v = new double[$$.maxv];
2251 memcpy($$.v, oldv, $$.nv*sizeof(double));
2252 a_delete oldv;
2253 }
2254 }
2255 $$.v[$$.nv] = $3;
2256 $$.nv += 1;
2257 }
2258 ;
2259
2260 position:
2261 position_not_place
2262 { $$ = $1; }
2263 | place
2264 {
2265 position pos = $1;
2266 $$.x = pos.x;
2267 $$.y = pos.y;
2268 }
2269 ;
2270
2271 position_not_place:
2272 expr_pair
2273 { $$ = $1; }
2274 | position '+' expr_pair
2275 {
2276 $$.x = $1.x + $3.x;
2277 $$.y = $1.y + $3.y;
2278 }
2279 | position '-' expr_pair
2280 {
2281 $$.x = $1.x - $3.x;
2282 $$.y = $1.y - $3.y;
2283 }
2284 | '(' position ',' position ')'
2285 {
2286 $$.x = $2.x;
2287 $$.y = $4.y;
2288 }
2289 | expr between position AND position
2290 {
2291 $$.x = (1.0 - $1)*$3.x + $1*$5.x;
2292 $$.y = (1.0 - $1)*$3.y + $1*$5.y;
2293 }
2294 | expr '<' position ',' position '>'
2295 {
2296 $$.x = (1.0 - $1)*$3.x + $1*$5.x;
2297 $$.y = (1.0 - $1)*$3.y + $1*$5.y;
2298 }
2299 ;
2300
2301 between:
2302 BETWEEN
2303 | OF THE WAY BETWEEN
2304 ;
2305
2306 expr_pair:
2307 expr ',' expr
2308 {
2309 $$.x = $1;
2310 $$.y = $3;
2311 }
2312 | '(' expr_pair ')'
2313 { $$ = $2; }
2314 ;
2315
2316 place:
2317 /* line at A left == line (at A) left */
2318 label %prec CHOP
2319 { $$ = $1; }
2320 | label corner
2321 {
2322 path pth($2);
2323 if (!pth.follow($1, & $$))
2324 YYABORT;
2325 }
2326 | corner label
2327 {
2328 path pth($1);
2329 if (!pth.follow($2, & $$))
2330 YYABORT;
2331 }
2332 | corner OF label
2333 {
2334 path pth($1);
2335 if (!pth.follow($3, & $$))
2336 YYABORT;
2337 }
2338 | HERE
2339 {
2340 $$.x = current_position.x;
2341 $$.y = current_position.y;
2342 $$.obj = 0;
2343 }
2344 ;
2345
2346 label:
2347 LABEL
2348 {
2349 place *p = lookup_label($1);
2350 if (!p) {
2351 lex_error("there is no place `%1'", $1);
2352 YYABORT;
2353 }
2354 $$ = *p;
2355 a_delete $1;
2356 }
2357 | nth_primitive
2358 { $$.obj = $1; }
2359 | label '.' LABEL
2360 {
2361 path pth($3);
2362 if (!pth.follow($1, & $$))
2363 YYABORT;
2364 }
2365 ;
2366
2367 ordinal:
2368 ORDINAL
2369 { $$ = $1; }
2370 | '`' any_expr TH
2371 {
2372 // XXX Check for overflow (and non-integers?).
2373 $$ = (int)$2;
2374 }
2375 ;
2376
2377 optional_ordinal_last:
2378 LAST
2379 { $$ = 1; }
2380 | ordinal LAST
2381 { $$ = $1; }
2382 ;
2383
2384 nth_primitive:
2385 ordinal object_type
2386 {
2387 int count = 0;
2388 object *p;
2389 for (p = olist.head; p != 0; p = p->next)
2390 if (p->type() == $2 && ++count == $1) {
2391 $$ = p;
2392 break;
2393 }
2394 if (p == 0) {
2395 lex_error("there is no %1%2 %3", $1, ordinal_postfix($1),
2396 object_type_name($2));
2397 YYABORT;
2398 }
2399 }
2400 | optional_ordinal_last object_type
2401 {
2402 int count = 0;
2403 object *p;
2404 for (p = olist.tail; p != 0; p = p->prev)
2405 if (p->type() == $2 && ++count == $1) {
2406 $$ = p;
2407 break;
2408 }
2409 if (p == 0) {
2410 lex_error("there is no %1%2 last %3", $1,
2411 ordinal_postfix($1), object_type_name($2));
2412 YYABORT;
2413 }
2414 }
2415 ;
2416
2417 object_type:
2418 BOX
2419 { $$ = BOX_OBJECT; }
2420 | CIRCLE
2421 { $$ = CIRCLE_OBJECT; }
2422 | ELLIPSE
2423 { $$ = ELLIPSE_OBJECT; }
2424 | ARC
2425 { $$ = ARC_OBJECT; }
2426 | LINE
2427 { $$ = LINE_OBJECT; }
2428 | ARROW
2429 { $$ = ARROW_OBJECT; }
2430 | SPLINE
2431 { $$ = SPLINE_OBJECT; }
2432 | '[' ']'
2433 { $$ = BLOCK_OBJECT; }
2434 | TEXT
2435 { $$ = TEXT_OBJECT; }
2436 ;
2437
2438 label_path:
2439 '.' LABEL
2440 { $$ = new path($2); }
2441 | label_path '.' LABEL
2442 {
2443 $$ = $1;
2444 $$->append($3);
2445 }
2446 ;
2447
2448 relative_path:
2449 corner %prec CHOP
2450 { $$ = new path($1); }
2451 /* give this a lower precedence than LEFT and RIGHT so that
2452 [A: box] with .A left == [A: box] with (.A left) */
2453 | label_path %prec TEXT
2454 { $$ = $1; }
2455 | label_path corner
2456 {
2457 $$ = $1;
2458 $$->append($2);
2459 }
2460 ;
2461
2462 path:
2463 relative_path
2464 { $$ = $1; }
2465 | '(' relative_path ',' relative_path ')'
2466 {
2467 $$ = $2;
2468 $$->set_ypath($4);
2469 }
2470 /* The rest of these rules are a compatibility sop. */
2471 | ORDINAL LAST object_type relative_path
2472 {
2473 lex_warning("`%1%2 last %3' in `with' argument ignored",
2474 $1, ordinal_postfix($1), object_type_name($3));
2475 $$ = $4;
2476 }
2477 | LAST object_type relative_path
2478 {
2479 lex_warning("`last %1' in `with' argument ignored",
2480 object_type_name($2));
2481 $$ = $3;
2482 }
2483 | ORDINAL object_type relative_path
2484 {
2485 lex_warning("`%1%2 %3' in `with' argument ignored",
2486 $1, ordinal_postfix($1), object_type_name($2));
2487 $$ = $3;
2488 }
2489 | LABEL relative_path
2490 {
2491 lex_warning("initial `%1' in `with' argument ignored", $1);
2492 a_delete $1;
2493 $$ = $2;
2494 }
2495 ;
2496
2497 corner:
2498 DOT_N
2499 { $$ = &object::north; }
2500 | DOT_E
2501 { $$ = &object::east; }
2502 | DOT_W
2503 { $$ = &object::west; }
2504 | DOT_S
2505 { $$ = &object::south; }
2506 | DOT_NE
2507 { $$ = &object::north_east; }
2508 | DOT_SE
2509 { $$ = &object:: south_east; }
2510 | DOT_NW
2511 { $$ = &object::north_west; }
2512 | DOT_SW
2513 { $$ = &object::south_west; }
2514 | DOT_C
2515 { $$ = &object::center; }
2516 | DOT_START
2517 { $$ = &object::start; }
2518 | DOT_END
2519 { $$ = &object::end; }
2520 | TOP
2521 { $$ = &object::north; }
2522 | BOTTOM
2523 { $$ = &object::south; }
2524 | LEFT
2525 { $$ = &object::west; }
2526 | RIGHT
2527 { $$ = &object::east; }
2528 | UPPER LEFT
2529 { $$ = &object::north_west; }
2530 | LOWER LEFT
2531 { $$ = &object::south_west; }
2532 | UPPER RIGHT
2533 { $$ = &object::north_east; }
2534 | LOWER RIGHT
2535 { $$ = &object::south_east; }
2536 | LEFT_CORNER
2537 { $$ = &object::west; }
2538 | RIGHT_CORNER
2539 { $$ = &object::east; }
2540 | UPPER LEFT_CORNER
2541 { $$ = &object::north_west; }
2542 | LOWER LEFT_CORNER
2543 { $$ = &object::south_west; }
2544 | UPPER RIGHT_CORNER
2545 { $$ = &object::north_east; }
2546 | LOWER RIGHT_CORNER
2547 { $$ = &object::south_east; }
2548 | NORTH
2549 { $$ = &object::north; }
2550 | SOUTH
2551 { $$ = &object::south; }
2552 | EAST
2553 { $$ = &object::east; }
2554 | WEST
2555 { $$ = &object::west; }
2556 | CENTER
2557 { $$ = &object::center; }
2558 | START
2559 { $$ = &object::start; }
2560 | END
2561 { $$ = &object::end; }
2562 ;
2563
2564 expr:
2565 VARIABLE
2566 {
2567 if (!lookup_variable($1, & $$)) {
2568 lex_error("there is no variable `%1'", $1);
2569 YYABORT;
2570 }
2571 a_delete $1;
2572 }
2573 | NUMBER
2574 { $$ = $1; }
2575 | place DOT_X
2576 {
2577 if ($1.obj != 0)
2578 $$ = $1.obj->origin().x;
2579 else
2580 $$ = $1.x;
2581 }
2582 | place DOT_Y
2583 {
2584 if ($1.obj != 0)
2585 $$ = $1.obj->origin().y;
2586 else
2587 $$ = $1.y;
2588 }
2589 | place DOT_HT
2590 {
2591 if ($1.obj != 0)
2592 $$ = $1.obj->height();
2593 else
2594 $$ = 0.0;
2595 }
2596 | place DOT_WID
2597 {
2598 if ($1.obj != 0)
2599 $$ = $1.obj->width();
2600 else
2601 $$ = 0.0;
2602 }
2603 | place DOT_RAD
2604 {
2605 if ($1.obj != 0)
2606 $$ = $1.obj->radius();
2607 else
2608 $$ = 0.0;
2609 }
2610 | expr '+' expr
2611 { $$ = $1 + $3; }
2612 | expr '-' expr
2613 { $$ = $1 - $3; }
2614 | expr '*' expr
2615 { $$ = $1 * $3; }
2616 | expr '/' expr
2617 {
2618 if ($3 == 0.0) {
2619 lex_error("division by zero");
2620 YYABORT;
2621 }
2622 $$ = $1/$3;
2623 }
2624 | expr '%' expr
2625 {
2626 if ($3 == 0.0) {
2627 lex_error("modulus by zero");
2628 YYABORT;
2629 }
2630 $$ = fmod($1, $3);
2631 }
2632 | expr '^' expr
2633 {
2634 errno = 0;
2635 $$ = pow($1, $3);
2636 if (errno == EDOM) {
2637 lex_error("arguments to `^' operator out of domain");
2638 YYABORT;
2639 }
2640 if (errno == ERANGE) {
2641 lex_error("result of `^' operator out of range");
2642 YYABORT;
2643 }
2644 }
2645 | '-' expr %prec '!'
2646 { $$ = -$2; }
2647 | '(' any_expr ')'
2648 { $$ = $2; }
2649 | SIN '(' any_expr ')'
2650 {
2651 errno = 0;
2652 $$ = sin($3);
2653 if (errno == ERANGE) {
2654 lex_error("sin result out of range");
2655 YYABORT;
2656 }
2657 }
2658 | COS '(' any_expr ')'
2659 {
2660 errno = 0;
2661 $$ = cos($3);
2662 if (errno == ERANGE) {
2663 lex_error("cos result out of range");
2664 YYABORT;
2665 }
2666 }
2667 | ATAN2 '(' any_expr ',' any_expr ')'
2668 {
2669 errno = 0;
2670 $$ = atan2($3, $5);
2671 if (errno == EDOM) {
2672 lex_error("atan2 argument out of domain");
2673 YYABORT;
2674 }
2675 if (errno == ERANGE) {
2676 lex_error("atan2 result out of range");
2677 YYABORT;
2678 }
2679 }
2680 | LOG '(' any_expr ')'
2681 {
2682 errno = 0;
2683 $$ = log10($3);
2684 if (errno == ERANGE) {
2685 lex_error("log result out of range");
2686 YYABORT;
2687 }
2688 }
2689 | EXP '(' any_expr ')'
2690 {
2691 errno = 0;
2692 $$ = pow(10.0, $3);
2693 if (errno == ERANGE) {
2694 lex_error("exp result out of range");
2695 YYABORT;
2696 }
2697 }
2698 | SQRT '(' any_expr ')'
2699 {
2700 errno = 0;
2701 $$ = sqrt($3);
2702 if (errno == EDOM) {
2703 lex_error("sqrt argument out of domain");
2704 YYABORT;
2705 }
2706 }
2707 | K_MAX '(' any_expr ',' any_expr ')'
2708 { $$ = $3 > $5 ? $3 : $5; }
2709 | K_MIN '(' any_expr ',' any_expr ')'
2710 { $$ = $3 < $5 ? $3 : $5; }
2711 | INT '(' any_expr ')'
2712 { $$ = floor($3); }
2713 | RAND '(' any_expr ')'
2714 { $$ = 1.0 + floor(((rand()&0x7fff)/double(0x7fff))*$3); }
2715 | RAND '(' ')'
2716 {
2717 /* return a random number in the range >=0, <1 */
2718 /* portable, but not very random */
2719 $$ = (rand() & 0x7fff) / double(0x8000);
2720 }
2721 | SRAND '(' any_expr ')'
2722 {
2723 $$ = 0;
2724 srand((unsigned int)$3);
2725 }
2726 | expr '<' expr
2727 { $$ = ($1 < $3); }
2728 | expr LESSEQUAL expr
2729 { $$ = ($1 <= $3); }
2730 | expr '>' expr
2731 { $$ = ($1 > $3); }
2732 | expr GREATEREQUAL expr
2733 { $$ = ($1 >= $3); }
2734 | expr EQUALEQUAL expr
2735 { $$ = ($1 == $3); }
2736 | expr NOTEQUAL expr
2737 { $$ = ($1 != $3); }
2738 | expr ANDAND expr
2739 { $$ = ($1 != 0.0 && $3 != 0.0); }
2740 | expr OROR expr
2741 { $$ = ($1 != 0.0 || $3 != 0.0); }
2742 | '!' expr
2743 { $$ = ($2 == 0.0); }
2744
2745 ;
2746 ]])
2747
2748 # Pass plenty of options, to exercise plenty of code, even if we
2749 # don't actually check the output. But SEGV is watching us, and
2750 # so might do dmalloc.
2751 AT_CHECK([[bison --verbose --defines input.y]], 0, [], [])
2752
2753 AT_CLEANUP