source: CIVL/grammar/CivlCParser.g@ 844ebd8

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since 844ebd8 was d96afbd, checked in by Stephen Siegel <siegel@…>, 14 years ago

Debugging ANTLR to AST translation.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@19 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 34.1 KB
RevLine 
[d96fdd6d]1/* Grammar for programming CIVL-C.
2 * Based on C11 grammar.
3 *
4 * Author: Stephen F. Siegel
5 * Last modified:
6 *
7 * This grammar assumes the input token stream is the result of
8 * translation phase 7, as specified in the Standard.
9 * In particular, all the preprocessing has already been
10 * done.
11 *
12 * In addition to the Standard, I borrowed from the older
13 * C grammar included with the ANTLR distribution.
14 *
15 */
16parser grammar CivlCParser;
17
18options
19{
20 language=Java;
21 tokenVocab=PreprocessorParser;
22 output=AST;
23}
24
25tokens
26{
27 ABSENT; // represents missing syntactic element
28 GENERIC_ASSOC_LIST; // generic association list
29 GENERIC_ASSOCIATION; // a generic association
30 ENUMERATION_CONSTANT; // use of enumeration constant
31 COMPOUND_LITERAL; // literal for structs, etc.
[59b5362]32 CONTRACT; // procedure contracts
[d96fdd6d]33 CALL; // function call
34 INDEX; // array subscript operator
35 ARGUMENT_LIST; // list of arguments to an operator
36 POST_INCREMENT;
37 POST_DECREMENT;
38 PRE_INCREMENT;
39 PRE_DECREMENT;
40 OPERATOR; // symbol indicating an operator
41 TYPE; // symbol indicating "type"
42 EXPR; // symbol indicating "expression"
43 PARENTHESIZED_EXPRESSION;
44 CAST; // type cast operator
45 DECLARATION; // a declaration
46 DECLARATION_SPECIFIERS; // list of declaration specifiers
47 INIT_DECLARATOR_LIST; // list of initializer-declarator pairs
48 INIT_DECLARATOR; // initializer-declaration pair
49 STRUCT_DECLARATION_LIST; // list of field declarations
50 STRUCT_DECLARATION; // a field declaration
51 SPECIFIER_QUALIFIER_LIST; // list of type specifiers and qualifiers
52 STRUCT_DECLARATOR_LIST; // list of struct/union declarators
53 STRUCT_DECLARATOR; // a struct/union declarator
54 ENUMERATOR_LIST; // list of enumerators in enum type definition
55 ENUMERATOR; // identifier and optional int constant
56 DECLARATOR; // a declarator
57 DIRECT_DECLARATOR; // declarator after removing leading *s
58 TYPE_QUALIFIER_LIST; // list of type qualifiers
59 ARRAY_SUFFIX; // [..] used in declarator
60 FUNCTION_SUFFIX; // (..) used in declarator
61 POINTER; // * used in declarator
62 PARAMETER_TYPE_LIST; // parameter list and optional "..."
63 PARAMETER_LIST; // list of parameter decls in function decl
64 PARAMETER_DECLARATION;// parameter declaration in function decl
65 IDENTIFIER_LIST; // list of parameter names only in function decl
66 TYPE_NAME; // type specification without identifier
67 ABSTRACT_DECLARATOR; // declarator without identifier
68 DIRECT_ABSTRACT_DECLARATOR; // direct declarator sans identifier
69 SCALAR_INITIALIZER; //
70 INITIALIZER_LIST;
71 DESIGNATED_INITIALIZER;
72 DESIGNATION;
73 ARRAY_ELEMENT_DESIGNATOR;
74 FIELD_DESIGNATOR;
75 IDENTIFIER_LABELED_STATEMENT;
76 CASE_LABELED_STATEMENT;
77 DEFAULT_LABELED_STATEMENT;
78 COMPOUND_STATEMENT;
79 BLOCK_ITEM_LIST;
80 EXPRESSION_STATEMENT;
81 TRANSLATION_UNIT;
82 DECLARATION_LIST;
83 FUNCTION_DEFINITION;
84 TYPEDEF_NAME;
85 TOKEN_LIST;
86}
87
88scope Symbols {
89 Set<String> types; // to keep track of typedefs
90 Set<String> enumerationConstants; // to keep track of enum constants
91 boolean isFunctionDefinition; // "function scope": entire function definition
92}
93
94scope DeclarationScope {
95 boolean isTypedef; // is the current declaration a typedef
96}
97
98@header
99{
[af8a6cb]100package edu.udel.cis.vsl.civl.civlc.parse.common;
[d96fdd6d]101
102import java.util.Set;
103import java.util.HashSet;
[af8a6cb]104import edu.udel.cis.vsl.civl.civlc.parse.IF.RuntimeParseException;
[d96fdd6d]105}
106
107@members {
108 @Override
109 public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
110 String hdr = getErrorHeader(e);
111 String msg = getErrorMessage(e, tokenNames);
112
113 throw new RuntimeParseException(hdr+" "+msg, e.token);
114 }
115
116 @Override
117 public void emitErrorMessage(String msg) { // don't try to recover!
118 throw new RuntimeParseException(msg);
119 }
120
121 boolean isTypeName(String name) {
122 for (Object scope : Symbols_stack)
123 if (((Symbols_scope)scope).types.contains(name)) return true;
124 return false;
125 }
126
127 boolean isEnumerationConstant(String name) {
128 boolean answer = false;
129
130 // System.err.print("Is "+name+" an enumeration constant: ");
131 for (Object scope : Symbols_stack) {
132 if (((Symbols_scope)scope).enumerationConstants.contains(name)) {
133 answer=true;
134 break;
135 }
136 }
137 // System.err.println(answer);
138 // System.err.flush();
139 return answer;
140 }
141}
142
143
144/* ***** A.2.1: Expressions ***** */
145
146/* Constants from A.1.5 */
147
148constant
149 : enumerationConstant
150 | INTEGER_CONSTANT
151 | FLOATING_CONSTANT
152 | CHARACTER_CONSTANT
[59b5362]153 | SELF | TRUE | FALSE | RESULT
[d96fdd6d]154 ;
155
156enumerationConstant
157 : {isEnumerationConstant(input.LT(1).getText())}? IDENTIFIER ->
158 ^(ENUMERATION_CONSTANT IDENTIFIER)
159 ;
160
161/* 6.5.1 */
162primaryExpression
163 : constant
164 | // {!isEnumerationConstant(input.LT(1).getText())}?
165 IDENTIFIER
166 | STRING_LITERAL
167 | LPAREN expression RPAREN
168 -> ^(PARENTHESIZED_EXPRESSION LPAREN expression RPAREN)
169 | genericSelection
170 ;
171
172/* 6.5.1.1 */
173
174genericSelection
175 : GENERIC LPAREN assignmentExpression COMMA genericAssocList
176 RPAREN
177 -> ^(GENERIC assignmentExpression genericAssocList)
178 ;
179
180/* 6.5.1.1 */
181genericAssocList
182 : genericAssociation (COMMA genericAssociation)*
183 -> ^(GENERIC_ASSOC_LIST genericAssociation+)
184 ;
185
186/* 6.5.1.1 */
187genericAssociation
188 : typeName COLON assignmentExpression
189 -> ^(GENERIC_ASSOCIATION typeName assignmentExpression)
190 | DEFAULT COLON assignmentExpression
191 -> ^(GENERIC_ASSOCIATION DEFAULT assignmentExpression)
192 ;
193
194/* 6.5.2 */
195postfixExpression
196 : (postfixExpressionRoot -> postfixExpressionRoot)
197 ( l=LSQUARE expression RSQUARE
198 -> ^(OPERATOR
199 INDEX[$l]
200 ^(ARGUMENT_LIST $postfixExpression expression)
201 RSQUARE)
202 | LPAREN argumentExpressionList RPAREN
203 -> ^(CALL LPAREN $postfixExpression argumentExpressionList RPAREN)
204 | DOT IDENTIFIER
205 -> ^(DOT $postfixExpression IDENTIFIER)
206 | ARROW IDENTIFIER
207 -> ^(ARROW $postfixExpression IDENTIFIER)
208 | p=PLUSPLUS
209 -> ^(OPERATOR POST_INCREMENT[$p]
210 ^(ARGUMENT_LIST $postfixExpression))
211 | AT IDENTIFIER
212 -> ^(AT $postfixExpression IDENTIFIER)
213 | m=MINUSMINUS
214 -> ^(OPERATOR POST_DECREMENT[$m]
215 ^(ARGUMENT_LIST $postfixExpression))
216 )*
217 ;
218
219/*
220 * The "(typename) {...}" is a "compound literal".
221 * See C11 Sec. 6.5.2.5. I don't know what
222 * it means when it ends with an extra COMMA.
223 * I assume it doesn't mean anything and is just
224 * allowed as a convenience for the poor C programmer
225 * (but why?).
226 *
227 * Ambiguity: need to distinguish the compound literal
228 * "(typename) {...}" from the primaryExpression
229 * "(expression)". Presence of '{' implies it must
230 * be the compound literal.
231 */
232postfixExpressionRoot
233 : (LPAREN typeName RPAREN LCURLY)=>
234 LPAREN typeName RPAREN LCURLY initializerList
235 ( RCURLY
236 | COMMA RCURLY
237 )
238 -> ^(COMPOUND_LITERAL LPAREN typeName initializerList RCURLY)
239 | primaryExpression
240 ;
241
242/* 6.5.2 */
243argumentExpressionList
244 : -> ^(ARGUMENT_LIST)
245 | assignmentExpression (COMMA assignmentExpression)*
246 -> ^(ARGUMENT_LIST assignmentExpression+)
247 ;
248
249/* 6.5.3 */
250unaryExpression
251 : postfixExpression
252 | p=PLUSPLUS unaryExpression
253 -> ^(OPERATOR PRE_INCREMENT[$p]
254 ^(ARGUMENT_LIST unaryExpression))
255 | m=MINUSMINUS unaryExpression
256 -> ^(OPERATOR PRE_DECREMENT[$m]
257 ^(ARGUMENT_LIST unaryExpression))
258 | unaryOperator castExpression
259 -> ^(OPERATOR unaryOperator ^(ARGUMENT_LIST castExpression))
260 | (SIZEOF LPAREN typeName)=> SIZEOF LPAREN typeName RPAREN
261 -> ^(SIZEOF TYPE typeName)
262 | SIZEOF unaryExpression
263 -> ^(SIZEOF EXPR unaryExpression)
264 | ALIGNOF LPAREN typeName RPAREN
265 -> ^(ALIGNOF typeName)
266 | spawnExpression
267 ;
268
269
270spawnExpression
271 : SPAWN postfixExpressionRoot LPAREN
272 argumentExpressionList RPAREN
[d96afbd]273 -> ^(SPAWN LPAREN postfixExpressionRoot
274 argumentExpressionList RPAREN)
[d96fdd6d]275 ;
276
277
278/* 6.5.3 */
279unaryOperator
280 : AMPERSAND | STAR | PLUS | SUB | TILDE | NOT
281 ;
282
283/* 6.5.4 */
284// ambiguity: (expr) is a unary expression and looks
285// like (typeName).
286castExpression
287 : (LPAREN typeName RPAREN)=> l=LPAREN typeName RPAREN castExpression
288 -> ^(CAST typeName castExpression $l)
289 | unaryExpression
290 ;
291
292/* 6.5.5 */
293multiplicativeExpression
294 : (castExpression -> castExpression)
295 ( STAR y=castExpression
296 -> ^(OPERATOR STAR ^(ARGUMENT_LIST $multiplicativeExpression $y))
297 | DIV y=castExpression
298 -> ^(OPERATOR DIV ^(ARGUMENT_LIST $multiplicativeExpression $y))
299 | MOD y=castExpression
300 -> ^(OPERATOR MOD ^(ARGUMENT_LIST $multiplicativeExpression $y))
301 )*
302 ;
303
304/* 6.5.6 */
305additiveExpression
306 : (multiplicativeExpression -> multiplicativeExpression)
307 ( PLUS y=multiplicativeExpression
308 -> ^(OPERATOR PLUS ^(ARGUMENT_LIST $additiveExpression $y))
309 | SUB y=multiplicativeExpression
310 -> ^(OPERATOR SUB ^(ARGUMENT_LIST $additiveExpression $y))
311 )*
312 ;
313
314/* 6.5.7 */
315shiftExpression
316 : (additiveExpression -> additiveExpression)
317 ( SHIFTLEFT y=additiveExpression
318 -> ^(OPERATOR SHIFTLEFT ^(ARGUMENT_LIST $shiftExpression $y))
319 | SHIFTRIGHT y=additiveExpression
320 -> ^(OPERATOR SHIFTRIGHT ^(ARGUMENT_LIST $shiftExpression $y))
321 )*
322 ;
323
324/* 6.5.8 */
325relationalExpression
326 : ( shiftExpression -> shiftExpression )
327 ( relationalOperator y=shiftExpression
328 -> ^(OPERATOR relationalOperator ^(ARGUMENT_LIST $relationalExpression $y))
329 )*
330 ;
331
332relationalOperator
333 : LT | GT | LTE | GTE
334 ;
335
336/* 6.5.9 */
337equalityExpression
338 : ( relationalExpression -> relationalExpression )
339 ( equalityOperator y=relationalExpression
340 -> ^(OPERATOR equalityOperator ^(ARGUMENT_LIST $equalityExpression $y))
341 )*
342 ;
343
344equalityOperator
345 : EQUALS | NEQ
346 ;
347
348/* 6.5.10 */
349andExpression
350 : ( equalityExpression -> equalityExpression )
351 ( AMPERSAND y=equalityExpression
352 -> ^(OPERATOR AMPERSAND ^(ARGUMENT_LIST $andExpression $y))
353 )*
354 ;
355
356/* 6.5.11 */
357exclusiveOrExpression
358 : ( andExpression -> andExpression )
359 ( BITXOR y=andExpression
360 -> ^(OPERATOR BITXOR ^(ARGUMENT_LIST $exclusiveOrExpression $y))
361 )*
362 ;
363
364/* 6.5.12 */
365inclusiveOrExpression
366 : ( exclusiveOrExpression -> exclusiveOrExpression )
367 ( BITOR y=exclusiveOrExpression
368 -> ^(OPERATOR BITOR ^(ARGUMENT_LIST $inclusiveOrExpression $y))
369 )*
370 ;
371
372/* 6.5.13 */
373logicalAndExpression
374 : ( inclusiveOrExpression -> inclusiveOrExpression )
375 ( AND y=inclusiveOrExpression
376 -> ^(OPERATOR AND ^(ARGUMENT_LIST $logicalAndExpression $y))
377 )*
378 ;
379
380/* 6.5.14 */
381logicalOrExpression
382 : ( logicalAndExpression -> logicalAndExpression )
383 ( OR y=logicalAndExpression
384 -> ^(OPERATOR OR ^(ARGUMENT_LIST $logicalOrExpression $y))
385 )*
386 ;
387
388
389/* 6.5.15 */
390conditionalExpression
391 : logicalOrExpression
392 ( -> logicalOrExpression
393 | QMARK expression COLON conditionalExpression
394 -> ^(OPERATOR QMARK
395 ^(ARGUMENT_LIST
396 logicalOrExpression
397 expression
398 conditionalExpression))
399 )
400 ;
401
402/* 6.5.16
403 * conditionalExpression or
404 * Root: OPERATOR
405 * Child 0: assignmentOperator
406 * Child 1: ARGUMENT_LIST
407 * Child 1.0: unaryExpression
408 * Child 1.1: assignmentExpression
409 */
410assignmentExpression
411 : (unaryExpression assignmentOperator)=>
412 unaryExpression assignmentOperator assignmentExpression
413 -> ^(OPERATOR assignmentOperator
414 ^(ARGUMENT_LIST unaryExpression assignmentExpression))
415 | conditionalExpression
416 ;
417
418/* 6.5.16 */
419assignmentOperator
420 : ASSIGN | STAREQ | DIVEQ | MODEQ | PLUSEQ | SUBEQ
421 | SHIFTLEFTEQ | SHIFTRIGHTEQ | BITANDEQ | BITXOREQ | BITOREQ
422 ;
423
424/* 6.5.17
425 * assignmentExpression or
426 * Root: OPERATOR
427 * Child 0: COMMA
428 * Child 1: ARGUMENT_LIST
429 * Child 1.0: arg0
430 * Child 1.1: arg1
431 */
[34760dc]432commaExpression
[d96fdd6d]433 : ( x=assignmentExpression -> assignmentExpression)
434 ( COMMA y=assignmentExpression
435 -> ^(OPERATOR COMMA ^(ARGUMENT_LIST $x $y))
436 )*
437 ;
438
[34760dc]439expression
[a070b96]440 : COLLECTIVE LPAREN proc=conditionalExpression
441 COMMA intExpr=conditionalExpression RPAREN
442 body=conditionalExpression
443 -> ^(COLLECTIVE $proc $intExpr $body)
[34760dc]444 | commaExpression
445 ;
446
[d96fdd6d]447/* 6.6 */
448constantExpression
449 : conditionalExpression
450 ;
451
452/* ***** A.2.2: Declarations ***** */
453
454/* 6.7.
455 *
456 * This rule will construct either a DECLARATION or
457 * STATICASSERT tree:
458
459 * Root: DECLARATION
460 * Child 0: declarationSpecifiers
461 * Child 1: initDeclaratorList or ABSENT
462 *
463 * Root: STATICASSERT
464 * Child 0: constantExpression
465 * Child 1: stringLiteral
466 *
467 * The declarationSpecifiers rule returns a bit telling whether
468 * "typedef" occurred among the specifiers. This bit is passed
469 * to the initDeclaratorList rule, and down the call chain,
470 * where eventually an IDENTIFIER should be reached. At that point,
471 * if the bit is true, the IDENTIFIER is added to the set of typedef
472 * names.
473 *
474 */
475declaration
476scope DeclarationScope;
477@init {
478 $DeclarationScope::isTypedef = false;
479}
480 : d=declarationSpecifiers
481 (
[59b5362]482 i=initDeclaratorList contract_opt SEMI
483 -> ^(DECLARATION $d $i contract_opt)
484 | SEMI
[d96afbd]485 -> ^(DECLARATION $d ABSENT ABSENT)
[d96fdd6d]486 )
487 | staticAssertDeclaration
488 ;
489
490/* 6.7
491 * Root: DECLARATION_SPECIFIERS
492 * Children: declarationSpecifier (any number)
493 */
494declarationSpecifiers
495 : l=declarationSpecifierList
496 -> ^(DECLARATION_SPECIFIERS declarationSpecifierList)
497 ;
498
499/* Tree: flat list of declarationSpecifier
500 */
501declarationSpecifierList
502 : (
503 {!$DeclarationScope::isTypedef || input.LT(2).getType() != SEMI }?
504 s=declarationSpecifier
505 )+
506 ;
507
508declarationSpecifier
509 : s=storageClassSpecifier
510 | typeSpecifierOrQualifier
511 | functionSpecifier
512 | alignmentSpecifier
513 ;
514
515/*
516 * I factored this out of the declarationSpecifiers rule
517 * to deal with the ambiguity of "ATOMIC" in one place.
518 * "ATOMIC ( typeName )" matches atomicTypeSpecifier, which
519 * is a typeSpecifier. "ATOMIC" matches typeQualifier.
520 * When you see "ATOMIC" all you have to do is look at the
521 * next token. If it's '(', typeSpecifier is it.
522 */
523typeSpecifierOrQualifier
524 : (typeSpecifier)=> typeSpecifier
525 | typeQualifier
526 ;
527
528/* 6.7
529 * Root: INIT_DECLARATOR_LIST
530 * Children: initDeclarator
531 */
532initDeclaratorList
533 : i+=initDeclarator (COMMA i+=initDeclarator)*
534 -> ^(INIT_DECLARATOR_LIST $i+)
535 ;
536
537/* 6.7
538 * Root: INIT_DECLARATOR
539 * Child 0: declarator
540 * Child 1: initializer or ABSENT
541 */
542initDeclarator
543 : d=declarator
544 ( -> ^(INIT_DECLARATOR $d ABSENT)
545 | (ASSIGN i=initializer) -> ^(INIT_DECLARATOR $d $i)
546 )
547 ;
548
549/* 6.7.1 */
550storageClassSpecifier
551 : TYPEDEF {$DeclarationScope::isTypedef = true;}
552 | (EXTERN | STATIC | THREADLOCAL | AUTO | REGISTER)
553 ;
554
555/* 6.7.2 */
556typeSpecifier
557 : VOID | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE
558 | SIGNED | UNSIGNED | BOOL | COMPLEX
[34760dc]559 | PROC
[d96fdd6d]560 | atomicTypeSpecifier
561 | structOrUnionSpecifier
562 | enumSpecifier
563 | typedefName
564 ;
565
566/* 6.7.2.1
567 * Root: STRUCT or UNION
568 * Child 0: IDENTIFIER (the tag) or ABSENT
569 * Child 1: structDeclarationList or ABSENT
570 */
571structOrUnionSpecifier
572 : structOrUnion
573 ( IDENTIFIER LCURLY structDeclarationList RCURLY
574 -> ^(structOrUnion IDENTIFIER structDeclarationList RCURLY)
575 | LCURLY structDeclarationList RCURLY
576 -> ^(structOrUnion ABSENT structDeclarationList RCURLY)
577 | IDENTIFIER
578 -> ^(structOrUnion IDENTIFIER ABSENT)
579 )
580 ;
581
582/* 6.7.2.1 */
583structOrUnion
584 : STRUCT | UNION
585 ;
586
587/* 6.7.2.1
588 * Root: STRUCT_DECLARATION_LIST
589 * Children: structDeclaration
590 */
591structDeclarationList
592 : structDeclaration+
593 -> ^(STRUCT_DECLARATION_LIST structDeclaration+)
594 ;
595
596/* 6.7.2.1
597 * Two possible trees:
598 *
599 * Root: STRUCT_DECLARATION
600 * Child 0: specifierQualifierList
601 * Child 1: structDeclaratorList or ABSENT
602 *
603 * or
604 *
605 * staticAssertDeclaration (root: STATICASSERT)
606 */
607structDeclaration
608scope DeclarationScope;
609@init {
610 $DeclarationScope::isTypedef = false;
611}
612 : s=specifierQualifierList
613 ( -> ^(STRUCT_DECLARATION $s ABSENT)
614 | structDeclaratorList
615 -> ^(STRUCT_DECLARATION $s structDeclaratorList)
616 )
617 SEMI
618 | staticAssertDeclaration
619 ;
620
621/* 6.7.2.1
622 * Root: SPECIFIER_QUALIFIER_LIST
623 * Children: typeSpecifierOrQualifier
624 */
625specifierQualifierList
626 : typeSpecifierOrQualifier+
627 -> ^(SPECIFIER_QUALIFIER_LIST typeSpecifierOrQualifier+)
628 ;
629
630/* 6.7.2.1
631 * Root: STRUCT_DECLARATOR_LIST
632 * Children: structDeclarator (at least 1)
633 */
634structDeclaratorList
635 : s+=structDeclarator (COMMA s+=structDeclarator)*
636 -> ^(STRUCT_DECLARATOR_LIST $s+)
637 ;
638
639/* 6.7.2.1
640 * Root: STRUCT_DECLARATOR
641 * Child 0: declarator or ABSENT
642 * Child 1: constantExpression or ABSENT
643 */
644structDeclarator
645 : declarator
646 ( -> ^(STRUCT_DECLARATOR declarator ABSENT)
647 | COLON constantExpression
648 -> ^(STRUCT_DECLARATOR declarator constantExpression)
649 )
650 | COLON constantExpression
651 -> ^(STRUCT_DECLARATOR ABSENT constantExpression)
652 ;
653
654/* 6.7.2.2
655 * Root: ENUM
656 * Child 0: IDENTIFIER (tag) or ABSENT
657 * Child 1: enumeratorList
658 */
659enumSpecifier
660 : ENUM
661 ( IDENTIFIER
662 -> ^(ENUM IDENTIFIER ABSENT)
663 | IDENTIFIER LCURLY enumeratorList COMMA? RCURLY
664 -> ^(ENUM IDENTIFIER enumeratorList)
665 | LCURLY enumeratorList COMMA? RCURLY
666 -> ^(ENUM ABSENT enumeratorList)
667 )
668 ;
669
670/* 6.7.2.2
671 * Root: ENUMERATOR_LIST
672 * Children: enumerator
673 */
674enumeratorList
675 : enumerator (COMMA enumerator)*
676 -> ^(ENUMERATOR_LIST enumerator+)
677 ;
678
679/* 6.7.2.2
680 * Root: ENUMERATOR
681 * Child 0: IDENTIFIER
682 * Child 1: constantExpression or ABSENT
683 */
684enumerator
685 : IDENTIFIER
686 {
687 $Symbols::enumerationConstants.add($IDENTIFIER.text);
688 // System.err.println("define enum constant "+$IDENTIFIER.text);
689 }
690 ( -> ^(ENUMERATOR IDENTIFIER ABSENT)
691 | (ASSIGN constantExpression)
692 -> ^(ENUMERATOR IDENTIFIER constantExpression)
693 )
694 ;
695
696/* 6.7.2.4 */
697atomicTypeSpecifier
698 : ATOMIC LPAREN typeName RPAREN
699 -> ^(ATOMIC typeName)
700 ;
701
702/* 6.7.3 */
703typeQualifier
704 : CONST | RESTRICT | VOLATILE | ATOMIC
705 | INPUT | OUTPUT
706 ;
707
708/* 6.7.4 */
709functionSpecifier
710 : INLINE | NORETURN
711 ;
712
713/* 6.7.5
714 * Root: ALIGNAS
715 * Child 0: TYPE or EXPR
716 * Child 1: typeName (if Child 0 is TYPE) or constantExpression
717 * (if Child 0 is EXPR)
718 */
719alignmentSpecifier
720 : ALIGNAS LPAREN
721 ( typeName RPAREN
722 -> ^(ALIGNAS TYPE typeName)
723 | constantExpression RPAREN
724 -> ^(ALIGNAS EXPR constantExpression)
725 )
726 ;
727
728/* 6.7.6
729 * Root: DECLARATOR
730 * Child 0: pointer or ABSENT
731 * Child 1: directDeclarator
732 */
733declarator
734 : d=directDeclarator
735 -> ^(DECLARATOR ABSENT $d)
736 | pointer d=directDeclarator
737 -> ^(DECLARATOR pointer $d)
738 ;
739
740/* 6.7.6
741 * Root: DIRECT_DECLARATOR
742 * Child 0: directDeclaratorPrefix
743 * Children 1..: list of directDeclaratorSuffix (may be empty)
744 */
745directDeclarator
746 : p=directDeclaratorPrefix
747 ( -> ^(DIRECT_DECLARATOR $p)
748 | s+=directDeclaratorSuffix+ ->^(DIRECT_DECLARATOR $p $s+)
749 )
750 ;
751
752/*
753 * Tree: either an IDENTIFIER or a declarator.
754 */
755directDeclaratorPrefix
756 : IDENTIFIER
757 {
758 if ($DeclarationScope::isTypedef) {
759 $Symbols::types.add($IDENTIFIER.text);
760 //System.err.println("define type "+$IDENTIFIER.text);
761 }
762 }
763 | LPAREN! declarator RPAREN!
764 ;
765
766
767directDeclaratorSuffix
768 : directDeclaratorArraySuffix
769 | directDeclaratorFunctionSuffix
770 ;
771
772/*
773 * Root: ARRAY_SUFFIX
774 * child 0: LSQUARE (for source information)
775 * child 1: STATIC or ABSENT
776 * child 2: TYPE_QUALIFIER_LIST
777 * child 3: expression (array extent),
778 * "*" (unspecified variable length), or ABSENT
779 * child 4: RSQUARE (for source information)
780 */
781directDeclaratorArraySuffix
782 : LSQUARE
783 ( typeQualifierList_opt assignmentExpression_opt RSQUARE
784 -> ^(ARRAY_SUFFIX LSQUARE ABSENT typeQualifierList_opt
785 assignmentExpression_opt RSQUARE)
786 | STATIC typeQualifierList_opt assignmentExpression RSQUARE
787 -> ^(ARRAY_SUFFIX LSQUARE STATIC typeQualifierList_opt
788 assignmentExpression RSQUARE)
789 | typeQualifierList STATIC assignmentExpression RSQUARE
790 -> ^(ARRAY_SUFFIX LSQUARE STATIC typeQualifierList
791 assignmentExpression RSQUARE)
792 | typeQualifierList_opt STAR RSQUARE
793 -> ^(ARRAY_SUFFIX LSQUARE ABSENT typeQualifierList_opt
794 STAR RSQUARE)
795 )
796 ;
797
798/*
799 * Root: FUNCTION_SUFFIX
800 * child 0: LPAREN (for source information)
801 * child 1: either parameterTypeList or identifierList or ABSENT
802 * child 2: RPAREN (for source information)
803 */
804directDeclaratorFunctionSuffix
805 : LPAREN
806 ( parameterTypeList RPAREN
807 -> ^(FUNCTION_SUFFIX LPAREN parameterTypeList RPAREN)
808 | identifierList RPAREN
809 -> ^(FUNCTION_SUFFIX LPAREN identifierList RPAREN)
810 | RPAREN -> ^(FUNCTION_SUFFIX LPAREN ABSENT RPAREN)
811 )
812 ;
813
814/*
815 * Root: TYPE_QUALIFIER_LIST
816 * Children: typeQualifier
817 */
818typeQualifierList_opt
819 : typeQualifier* -> ^(TYPE_QUALIFIER_LIST typeQualifier*)
820 ;
821
822/*
823 * Tree: assignmentExpression or ABSENT
824 */
825assignmentExpression_opt
826 : -> ABSENT
827 | assignmentExpression
828 ;
829
830/* 6.7.6
831 * Root: POINTER
832 * chilren: STAR
833 */
834pointer
835 : pointer_part+ -> ^(POINTER pointer_part+)
836 ;
837
838/*
839 * Root: STAR
840 * child 0: TYPE_QUALIFIER_LIST
841 */
842pointer_part
843 : STAR typeQualifierList_opt -> ^(STAR typeQualifierList_opt)
844 ;
845
846/* 6.7.6
847 * Root: TYPE_QUALIFIER_LIST
848 * children: typeQualifier
849 */
850typeQualifierList
851 : typeQualifier+ -> ^(TYPE_QUALIFIER_LIST typeQualifier+)
852 ;
853
854/* 6.7.6
855 * Root: PARAMETER_TYPE_LIST
856 * child 0: parameterList (at least 1 parameter declaration)
857 * child 1: ELLIPSIS or ABSENT
858 *
859 * If the parameterTypeList occurs in a function prototype
860 * (that is not part of a function definition), it defines
861 * a new scope (a "function prototype scope"). If it occurs
862 * in a function definition, it does not define a new scope.
863 */
864
865parameterTypeList
866 : {$Symbols::isFunctionDefinition}? parameterTypeListWithoutScope
867 | parameterTypeListWithScope
868 ;
869
870parameterTypeListWithScope
871scope Symbols;
872@init {
873 $Symbols::types = new HashSet<String>();
874 $Symbols::enumerationConstants = new HashSet<String>();
875 $Symbols::isFunctionDefinition = false;
876}
877 : parameterTypeListWithoutScope
878 ;
879
880parameterTypeListWithoutScope
881 : parameterList
882 ( -> ^(PARAMETER_TYPE_LIST parameterList ABSENT)
883 | COMMA ELLIPSIS
884 -> ^(PARAMETER_TYPE_LIST parameterList ELLIPSIS)
885 )
886 ;
887
888/* 6.7.6
889 * Root: PARAMETER_LIST
890 * children: parameterDeclaration
891 */
892parameterList
893 : parameterDeclaration (COMMA parameterDeclaration)*
894 -> ^(PARAMETER_LIST parameterDeclaration+)
895 ;
896
897/* 6.7.6
898 * Root: PARAMETER_DECLARATION
899 * Child 0: declarationSpecifiers
900 * Child 1: declarator, or abstractDeclarator, or ABSENT
901 */
902parameterDeclaration
903scope DeclarationScope;
904@init {
905 $DeclarationScope::isTypedef = false;
906}
907 : declarationSpecifiers
908 ( -> ^(PARAMETER_DECLARATION declarationSpecifiers ABSENT)
909 | declaratorOrAbstractDeclarator
910 -> ^(PARAMETER_DECLARATION
911 declarationSpecifiers declaratorOrAbstractDeclarator)
912 )
913 ;
914
915
916// this has non-LL* decision due to recursive rule invocations
917// reachable from alts 1,2... E.g., both can start with pointer.
918
919declaratorOrAbstractDeclarator
920 : (declarator)=> declarator
921 | abstractDeclarator
922 ;
923
924
925/* 6.7.6
926 * Root: IDENTIFIER_LIST
927 * children: IDENTIFIER (at least 1)
928 */
929identifierList
930 : IDENTIFIER ( COMMA IDENTIFIER )*
931 -> ^(IDENTIFIER_LIST IDENTIFIER+)
932 ;
933
934/* 6.7.6. This is how a type is described without attaching
935 * it to an identifier.
936 * Root: TYPE_NAME
937 * child 0: specifierQualifierList
938 * child 1: abstractDeclarator or ABSENT
939 */
940typeName
941 : specifierQualifierList
942 ( -> ^(TYPE_NAME specifierQualifierList ABSENT)
943 | abstractDeclarator
944 -> ^(TYPE_NAME specifierQualifierList abstractDeclarator)
945 )
946 ;
947
948/* 6.7.7. Abstract declarators are like declarators without
949 * the IDENTIFIER.
950 *
951 * Root: ABSTRACT_DECLARATOR
952 * Child 0. pointer (may be ABSENT). Some number of *s with possible
953 * type qualifiers.
954 * Child 1. directAbstractDeclarator (may be ABSENT).
955 */
956abstractDeclarator
957 : pointer
958 -> ^(ABSTRACT_DECLARATOR pointer ABSENT)
959 | directAbstractDeclarator
960 -> ^(ABSTRACT_DECLARATOR ABSENT directAbstractDeclarator)
961 | pointer directAbstractDeclarator
962 -> ^(ABSTRACT_DECLARATOR pointer directAbstractDeclarator)
963 ;
964
965/* 6.7.7
966 *
967 * Root: DIRECT_ABSTRACT_DECLARATOR
968 * Child 0. abstract declarator or ABSENT.
969 * Children 1..: any number of direct abstract declarator suffixes
970 *
971 * Note that the difference between this and a directDeclarator
972 * is that Child 0 of a direct declarator would be either
973 * an IDENTIFIER or a declarator, but never ABSENT.
974 */
975directAbstractDeclarator
976 : LPAREN abstractDeclarator RPAREN directAbstractDeclaratorSuffix*
977 -> ^(DIRECT_ABSTRACT_DECLARATOR abstractDeclarator
978 directAbstractDeclaratorSuffix*)
979 | directAbstractDeclaratorSuffix+
980 -> ^(DIRECT_ABSTRACT_DECLARATOR ABSENT directAbstractDeclaratorSuffix+)
981 ;
982
983
984/* 6.7.8
985 * Root: TYPEDEF_NAME
986 * Child 0: IDENTIFIER
987 *
988 * Ambiguity: example:
989 * typedef int foo;
990 * typedef int foo;
991 *
992 * This is perfectly legal: you can define a typedef twice
993 * as long as both definitions are equivalent. However,
994 * the first definition causes foo to be entered into the type name
995 * table, so when parsing the second definition, foo is
996 * interpreted as a typedefName (a type specifier), and the
997 * declaration would have empty declarator. This is not
998 * what you want, so you have to forbid it somehow. I do this
999 * by requiring that if you are "in" a typedef, a typedef name
1000 * cannot be immediately followed by a semicolon. This is sound
1001 * because the C11 Standard requires at least one declarator
1002 * to be present in a typedef.
1003 */
1004typedefName
1005 : {isTypeName(input.LT(1).getText())}? IDENTIFIER
1006 -> ^(TYPEDEF_NAME IDENTIFIER)
1007 ;
1008
1009/* 6.7.7
1010 * Two possibilities:
1011 *
1012 * Root: ARRAY_SUFFIX
1013 * Child 0: STATIC or ABSENT
1014 * Child 1: typeQualifierList or ABSENT
1015 * Child 2: expression or STAR or ABSENT
1016 *
1017 * Root: FUNCTION_SUFFIX
1018 * Child 0: parameterTypeList or ABSENT
1019 */
1020directAbstractDeclaratorSuffix
1021 : LSQUARE
1022 ( typeQualifierList_opt assignmentExpression_opt RSQUARE
1023 -> ^(ARRAY_SUFFIX ABSENT typeQualifierList_opt
1024 assignmentExpression_opt)
1025 | STATIC typeQualifierList_opt assignmentExpression RSQUARE
1026 -> ^(ARRAY_SUFFIX STATIC typeQualifierList_opt
1027 assignmentExpression)
1028 | typeQualifierList STATIC assignmentExpression RSQUARE
1029 -> ^(ARRAY_SUFFIX STATIC typeQualifierList assignmentExpression)
1030 | STAR RSQUARE
1031 -> ^(ARRAY_SUFFIX ABSENT ABSENT STAR)
1032 )
1033 | LPAREN
1034 ( parameterTypeList RPAREN
1035 -> ^(FUNCTION_SUFFIX parameterTypeList)
1036 | RPAREN
1037 -> ^(FUNCTION_SUFFIX ABSENT)
1038 )
1039 ;
1040
1041/* 6.7.9 */
1042initializer
1043 : assignmentExpression -> ^(SCALAR_INITIALIZER assignmentExpression)
1044 | LCURLY initializerList
1045 ( RCURLY
1046 | COMMA RCURLY
1047 )
1048 -> initializerList
1049 ;
1050
1051/* 6.7.9 */
1052initializerList
1053 : designatedInitializer (COMMA designatedInitializer)*
1054 -> ^(INITIALIZER_LIST designatedInitializer+)
1055 ;
1056
1057designatedInitializer
1058 : initializer
1059 -> ^(DESIGNATED_INITIALIZER ABSENT initializer)
1060 | designation initializer
1061 -> ^(DESIGNATED_INITIALIZER designation initializer)
1062 ;
1063
1064/* 6.7.9 */
1065designation
1066 : designatorList ASSIGN -> ^(DESIGNATION designatorList)
1067 ;
1068
1069/* 6.7.9 */
1070designatorList
1071 : designator+
1072 ;
1073
1074/* 6.7.9 */
1075designator
1076 : LSQUARE constantExpression RSQUARE
1077 -> ^(ARRAY_ELEMENT_DESIGNATOR constantExpression)
1078 | DOT IDENTIFIER
1079 -> ^(FIELD_DESIGNATOR IDENTIFIER)
1080 ;
1081
1082/* 6.7.10 */
1083staticAssertDeclaration
1084 : STATICASSERT LPAREN constantExpression COMMA STRING_LITERAL
1085 RPAREN SEMI
1086 -> ^(STATICASSERT constantExpression STRING_LITERAL)
1087 ;
1088
1089
1090/* ***** A.2.3: Statements ***** */
1091
1092/* 6.8 */
1093statement
1094 : labeledStatement
1095 | compoundStatement
1096 | expressionStatement
1097 | selectionStatement
1098 | iterationStatement
1099 | jumpStatement
1100 | pragma
1101 | assertStatement
1102 | assumeStatement
1103 | waitStatement
1104 | whenStatement
1105 | chooseStatement
1106 ;
1107
1108statementWithScope
1109scope Symbols;
1110@init {
1111 $Symbols::types = new HashSet<String>();
1112 $Symbols::enumerationConstants = new HashSet<String>();
1113 $Symbols::isFunctionDefinition = false;
1114}
1115 : statement
1116 ;
1117
1118/* 6.8.1
1119 * Three possible trees:
1120 *
1121 * Root: IDENTIFIER_LABELED_STATEMENT
1122 * Child 0: IDENTIFIER
1123 * Child 1: statement
1124 *
1125 * Root: CASE_LABELED_STATEMENT
1126 * Child 0: CASE
1127 * Child 1: constantExpression
1128 * Child 2: statement
1129 *
1130 * Root: DEFAULT_LABELED_STATEMENT
1131 * Child 0: DEFAULT
1132 * Child 1: statement
1133 */
1134labeledStatement
1135 : IDENTIFIER COLON statement
1136 -> ^(IDENTIFIER_LABELED_STATEMENT IDENTIFIER statement)
1137 | CASE constantExpression COLON statement
1138 -> ^(CASE_LABELED_STATEMENT CASE constantExpression statement)
1139 | DEFAULT COLON statement
1140 -> ^(DEFAULT_LABELED_STATEMENT DEFAULT statement)
1141 ;
1142
1143/* 6.8.2
1144 * Root: BLOCK
1145 * Child 0: LCURLY (for source information)
1146 * Child 1: blockItemList or ABSENT
1147 * Child 2: RCURLY (for source information)
1148 */
1149compoundStatement
1150scope Symbols;
1151@init {
1152 $Symbols::types = new HashSet<String>();
1153 $Symbols::enumerationConstants = new HashSet<String>();
1154 $Symbols::isFunctionDefinition = false;
1155}
1156 : LCURLY
1157 ( RCURLY
1158 -> ^(COMPOUND_STATEMENT LCURLY ABSENT RCURLY)
1159 | blockItemList RCURLY
1160 -> ^(COMPOUND_STATEMENT LCURLY blockItemList RCURLY)
1161 )
1162 ;
1163
1164/* 6.8.2 */
1165blockItemList
1166 : blockItem+ -> ^(BLOCK_ITEM_LIST blockItem+)
1167 ;
1168
1169/* 6.8.2 */
1170blockItem
[34760dc]1171 : (declarationSpecifiers declarator declarationList_opt LCURLY)=>
1172 functionDefinition
1173 | declaration
[d96fdd6d]1174 | statement
1175 ;
1176
1177/* 6.8.3
1178 * Root: EXPRESSION_STATEMENT
1179 * Child 0: expression or ABSENT
1180 * Child 1: SEMI (for source information)
1181 */
1182expressionStatement
1183 : expression SEMI -> ^(EXPRESSION_STATEMENT expression SEMI)
1184 | SEMI -> ^(EXPRESSION_STATEMENT ABSENT SEMI)
1185 ;
1186
1187/* 6.8.4
1188 * Two possible trees:
1189 *
1190 * Root: IF
1191 * Child 0: expression
1192 * Child 1: statement (true branch)
1193 * Child 2: statement or ABSENT (false branch)
1194 *
1195 * Root: SWITCH
1196 * Child 0: expression
1197 * Child 1: statement
1198 */
1199selectionStatement
1200scope Symbols;
1201@init {
1202 $Symbols::types = new HashSet<String>();
1203 $Symbols::enumerationConstants = new HashSet<String>();
1204 $Symbols::isFunctionDefinition = false;
1205}
1206 : IF LPAREN expression RPAREN s1=statementWithScope
1207 ( (ELSE)=> ELSE s2=statementWithScope
1208 -> ^(IF expression $s1 $s2)
1209 | -> ^(IF expression $s1 ABSENT)
1210 )
1211 | SWITCH LPAREN expression RPAREN s=statementWithScope
1212 -> ^(SWITCH expression $s)
1213 ;
1214
1215/* 6.8.5
1216 * Three possible trees:
1217 *
1218 * Root: WHILE
1219 * Child 0: expression
1220 * Child 1: statement
1221 *
1222 * Root: DO
1223 * Child 0: statement
1224 * Child 1: expression
1225 *
1226 * Root: FOR
1227 * Child 0: clause-1: declaration, expression, or ABSENT
1228 * (for loop initializer)
1229 * Child 1: expression or ABSENT (condition)
1230 * Child 2: expression or ABSENT (incrementer)
1231 * Child 3: statement (body)
1232 *
1233 */
1234iterationStatement
1235scope Symbols;
1236@init {
1237 $Symbols::types = new HashSet<String>();
1238 $Symbols::enumerationConstants = new HashSet<String>();
1239 $Symbols::isFunctionDefinition = false;
1240}
1241 : WHILE LPAREN expression RPAREN invariant_opt
1242 s=statementWithScope
1243 -> ^(WHILE expression $s invariant_opt)
1244 | DO s=statementWithScope WHILE LPAREN expression RPAREN
1245 invariant_opt SEMI
1246 -> ^(DO $s expression invariant_opt)
1247 | FOR LPAREN
1248 ( d=declaration e1=expression_opt SEMI e2=expression_opt
1249 RPAREN i=invariant_opt s=statementWithScope
1250 -> ^(FOR $d $e1 $e2 $s $i)
1251 | e0=expression_opt SEMI e1=expression_opt SEMI
1252 e2=expression_opt RPAREN s=statementWithScope
1253 -> ^(FOR $e0 $e1 $e2 $s $i)
1254 )
1255 ;
1256
1257expression_opt
1258 : expression
1259 | -> ABSENT
1260 ;
1261
1262invariant_opt
1263 : -> ABSENT
1264 | INVARIANT LPAREN expression RPAREN
1265 -> ^(INVARIANT expression)
1266 ;
1267
1268
1269/* 6.8.6
1270 * Four possible trees:
1271 *
1272 * Root: GOTO
1273 * Child 0: IDENTIFIER
1274 * Child 1: SEMI (for source information)
1275 *
1276 * Root: CONTINUE
1277 * Child 0: SEMI (for source information)
1278 *
1279 * Root: BREAK
1280 * Child 0: SEMI (for source information)
1281 *
1282 * Root: RETURN
1283 * Child 0: expression or ABSENT
1284 * Child 1: SEMI (for source information)
1285 */
1286jumpStatement
1287 : GOTO IDENTIFIER SEMI -> ^(GOTO IDENTIFIER SEMI)
1288 | CONTINUE SEMI -> ^(CONTINUE SEMI)
1289 | BREAK SEMI -> ^(BREAK SEMI)
1290 | RETURN expression_opt SEMI -> ^(RETURN expression_opt SEMI)
1291 ;
1292
1293/*
1294 * Root: PRAGMA
1295 * child 0: IDENTIFIER (first token following # pragma)
1296 * child 1: TOKEN_LIST (chilren are list of tokens following identifier)
1297 * child 2: NEWLINE (character which ends the pragma)
1298 */
1299pragma : PRAGMA IDENTIFIER pragmaBody NEWLINE
1300 -> ^(PRAGMA IDENTIFIER ^(TOKEN_LIST pragmaBody) NEWLINE)
1301 ;
1302
1303pragmaBody
1304 : (~ NEWLINE)*
1305 ;
1306
1307assertStatement
1308 : ASSERT expression SEMI -> ^(ASSERT expression)
1309 ;
1310
1311assumeStatement
1312 : ASSUME expression SEMI -> ^(ASSUME expression)
1313 ;
1314
1315waitStatement
1316 : WAIT expression SEMI -> ^(WAIT expression)
1317 ;
1318
1319whenStatement
1320 : WHEN LPAREN expression RPAREN statement
1321 -> ^(WHEN expression statement)
1322 ;
1323
1324chooseStatement
1325 : CHOOSE LCURLY statement+ RCURLY
1326 -> ^(CHOOSE statement+)
1327 ;
1328
1329/* ***** A.2.4: External Definitions ***** */
1330
1331/* 6.9
1332 * Root: TRANSLATION_UNIT
1333 * Children: externalDeclaration
1334 */
1335translationUnit
1336scope Symbols; // the global scope
1337scope DeclarationScope; // just to have an outermost one with isTypedef false
1338@init {
1339 $Symbols::types = new HashSet<String>();
1340 $Symbols::enumerationConstants = new HashSet<String>();
1341 $Symbols::isFunctionDefinition = false;
1342 $DeclarationScope::isTypedef = false;
1343}
1344 : externalDeclaration* EOF
1345 -> ^(TRANSLATION_UNIT externalDeclaration*)
1346 ;
1347
1348/* 6.9
1349 * Need to look ahead to distinguish function definition from
1350 * a declaration. As soon as you see the "{", you know you
1351 * are in a function definition.
1352 */
1353externalDeclaration
[59b5362]1354 : (declarationSpecifiers declarator
1355 contract_opt declarationList_opt LCURLY)=>
[d96fdd6d]1356 functionDefinition
1357 | declaration
1358 | pragma
1359 ;
1360
1361/* 6.9.1 */
1362functionDefinition
1363scope Symbols; // "function scope"
1364@init {
1365 $Symbols::types = new HashSet<String>();
1366 $Symbols::enumerationConstants = new HashSet<String>();
1367 $Symbols::isFunctionDefinition = true;
1368}
[59b5362]1369 : declarationSpecifiers declarator contract_opt
[d96fdd6d]1370 declarationList_opt compoundStatement
1371 -> ^(FUNCTION_DEFINITION declarationSpecifiers declarator
[59b5362]1372 declarationList_opt compoundStatement contract_opt)
[d96fdd6d]1373 ;
1374
1375
1376/* 6.9.1
1377 * Root: DECLARATION_LIST
1378 * Children: declaration (any number)
1379 */
1380declarationList_opt
1381 : declaration* -> ^(DECLARATION_LIST declaration*)
1382 ;
[59b5362]1383
1384contractItem
1385 : REQUIRES expression SEMI -> ^(REQUIRES expression)
1386 | ENSURES expression SEMI -> ^(ENSURES expression)
1387 ;
1388
1389contract_opt
1390 : contractItem* -> ^(CONTRACT contractItem*)
1391 ;
Note: See TracBrowser for help on using the repository browser.