Update Grammar and Add support for callsites
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.parser / Grammar / CTFParser.g
CommitLineData
866e5b51
FC
1parser grammar CTFParser;
2
3options {
4 language = Java;
5 output = AST;
6 ASTLabelType = CommonTree;
7 tokenVocab = CTFLexer;
8}
9
10tokens {
11 ROOT;
12
13 EVENT;
14 STREAM;
15 TRACE;
16 ENV;
17 CLOCK;
4c9d2941 18 CALLSITE;
866e5b51
FC
19
20 DECLARATION;
21 SV_DECLARATION;
22 TYPE_SPECIFIER_LIST;
23 TYPE_DECLARATOR_LIST;
24 TYPE_DECLARATOR;
25
26 STRUCT;
27 STRUCT_NAME;
28 STRUCT_BODY;
29 ALIGN;
30
31 CTF_EXPRESSION_TYPE;
32 CTF_EXPRESSION_VAL;
33 CTF_LEFT;
34 CTF_RIGHT;
35
36 UNARY_EXPRESSION_STRING;
37 UNARY_EXPRESSION_STRING_QUOTES;
38 UNARY_EXPRESSION_DEC;
39 UNARY_EXPRESSION_HEX;
40 UNARY_EXPRESSION_OCT;
41 LENGTH;
42
43 TYPEDEF;
44
45 TYPEALIAS;
46 TYPEALIAS_TARGET;
47 TYPEALIAS_ALIAS;
48
49 INTEGER;
50 STRING;
51 FLOATING_POINT;
52
53 ENUM;
54 ENUM_CONTAINER_TYPE;
55 ENUM_ENUMERATOR;
56 ENUM_NAME;
57 ENUM_VALUE;
58 ENUM_VALUE_RANGE;
59 ENUM_BODY;
60
61 VARIANT;
62 VARIANT_NAME;
63 VARIANT_TAG;
64 VARIANT_BODY;
65
66 DECLARATOR;
67 LENGTH;
68}
69
70/*
71 * Scope for the tracking of types.
72 * For now we just track the names (it's a simple Set), but
73 * later we will have to track the info about the target type.
74 */
75scope Symbols {
76 Set<String> types;
77}
78
79@header {
80package org.eclipse.linuxtools.ctf.parser;
81import java.util.Set;
82import java.util.HashSet;
83}
84
85@members {
86 public CTFParser(TokenStream input, boolean verbose) {
87 this(input);
88 this.verbose = verbose;
89 }
90
91 /* To disable automatic error recovery. When we have a mismatched token, simply throw an exception. */
92 @Override
93 protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException
94 {
95 throw new MismatchedTokenException(ttype, input);
96 }
97
98 /**
99 * Checks if a given name has been defined has a type.
100 * From: http://www.antlr.org/grammar/1153358328744/C.g
101 *
102 * @param name The name to check.
103 * @return True if is is a type, false otherwise.
104 */
105 boolean isTypeName(String name) {
106 for (int i = Symbols_stack.size() - 1; i >= 0; i--) {
107 Symbols_scope scope = (Symbols_scope)Symbols_stack.get(i);
108 if (scope.types.contains(name)) {
109 return true;
110 }
111 }
112 return false;
113 }
114
115 void addTypeName(String name) {
116 $Symbols::types.add(name);
117 if (verbose) {
118 debug_print("New type: " + name);
119 }
120 }
121
122 boolean _inTypedef = false;
123
124 void typedefOn() {
125 debug_print("typedefOn");
126 _inTypedef = true;
127 }
128
129 void typedefOff() {
130 debug_print("typedefOff");
131 _inTypedef = false;
132 }
133
134 boolean inTypedef() {
135 return _inTypedef;
136 }
137
138 boolean _inTypealiasAlias = false;
139
140 void typealiasAliasOn() {
141 debug_print("typealiasAliasOn");
142 _inTypealiasAlias = true;
143 }
144
145 void typealiasAliasOff() {
146 debug_print("typealiasAliasOff");
147 _inTypealiasAlias = false;
148 }
149
150 boolean inTypealiasAlias() {
151 return _inTypealiasAlias;
152 }
153
154 void print_tabs(int n) {
155 for (int i = 0; i < n; i++) {
156 System.out.print(" ");
157 }
158 }
159
160 void enter(String name) {
161 if (verbose) {
162 if (state.backtracking == 0) {
163 print_tabs(depth);
164 debug_print("+ " + name);
165 depth++;
166 }
167 }
168 }
169
170 void exit(String name) {
171 if (verbose) {
172 depth--;
173 print_tabs(depth);
174 debug_print("- " + name);
175 }
176 }
177
178 void debug_print(String str) {
179 if (verbose) {
180 System.out.println(str);
181 }
182 }
183
184 int depth = 0;
185
186 /* Prints rule entry and exit while parsing */
187 boolean verbose = false;
188}
189
190/* To disable automatic error recovery. By default, the catch block of every rule simple rethrows the error. */
191@rulecatch {
192 catch (RecognitionException e)
193 {
194 throw e;
195 }
196}
197
198/* The top-level rule. */
199parse
200scope Symbols;
201@init {
202 enter("parse");
203 debug_print("Scope push " + Symbols_stack.size());
204 $Symbols::types = new HashSet<String>();
205}
206@after {
207 debug_print("Scope pop " + Symbols_stack.size());
208 exit("parse");
209
210 debug_print("Final depth, should be 0: " + depth);
211}
212:
213 declaration+ EOF -> ^(ROOT declaration+)
214 ;
215
216numberLiteral
217@init {
218 enter("numberLiteral");
219}
220@after {
221 debug_print($numberLiteral.text);
222 exit("numberLiteral");
223}
224:
225 SIGN* (HEX_LITERAL -> ^(UNARY_EXPRESSION_HEX HEX_LITERAL SIGN*)
226 | DECIMAL_LITERAL -> ^(UNARY_EXPRESSION_DEC DECIMAL_LITERAL SIGN*)
227 | OCTAL_LITERAL -> ^(UNARY_EXPRESSION_OCT OCTAL_LITERAL SIGN*))
228 ;
229
230constant
231@init {
232 enter("constant");
233}
234@after {
235 exit("constant");
236}
237:
238 numberLiteral
239 | enumConstant
240 | CHARACTER_LITERAL
241 ;
242
243primaryExpression
244@init {
245 enter("primaryExpression");
246}
247@after {
248 exit("primaryExpression");
249}
250:
251 (IDENTIFIER) => IDENTIFIER { debug_print("IDENTIFIER: " + $IDENTIFIER.text);} -> ^(UNARY_EXPRESSION_STRING IDENTIFIER)
252 | (ctfKeyword) => ctfKeyword -> ^(UNARY_EXPRESSION_STRING ctfKeyword)
253 | (STRING_LITERAL) => STRING_LITERAL { debug_print("STRING_LITERAL: " + $STRING_LITERAL.text);} -> ^(UNARY_EXPRESSION_STRING_QUOTES STRING_LITERAL)
254 /*| (LPAREN unaryExpression RPAREN)*/ // Not supported yet
255 | constant
256 ;
257
258reference
259@init {
260 enter("reference");
261}
262@after {
263 debug_print($reference.text);
264 exit("reference");
265}
266:
267 (ref=DOT | ref=ARROW) IDENTIFIER -> ^($ref ^(UNARY_EXPRESSION_STRING IDENTIFIER))
268 ;
269
270postfixExpressionSuffix
271@init {
272 enter("postfixExpressionSuffix");
273}
274@after {
275 exit("postfixExpressionSuffix");
276}
277:
278 (OPENBRAC unaryExpression CLOSEBRAC!)
279 | reference
280 ;
281
282postfixExpression
283@init {
284 enter("postfixExpression");
285}
286@after {
287 exit("postfixExpression");
288}
289:
290 (primaryExpression) (postfixExpressionSuffix)*|
291 ((ctfSpecifierHead) (postfixExpressionSuffix)+)// added for ctfV1.8
292 ;
293
294unaryExpression
295@init {
296 enter("unaryExpression");
297}
298@after {
299 exit("unaryExpression");
300}
301:
302 /*((SIGN postfixExpression[true])
303 | postfixExpression[false])*/
304 postfixExpression
305 ;
306
307enumConstant
308@init {
309 enter("enumConstant");
310}
311@after {
312 debug_print($enumConstant.text);
313 exit("enumConstant");
314}
315:
316 STRING_LITERAL -> ^(UNARY_EXPRESSION_STRING_QUOTES STRING_LITERAL)
317 | IDENTIFIER -> ^(UNARY_EXPRESSION_STRING IDENTIFIER)
318 | ctfKeyword -> ^(UNARY_EXPRESSION_STRING ctfKeyword)
319 ;
320// 2.2
321
322declaration
323@init {
324 enter("declaration");
325}
326@after {
327 exit("declaration");
328 if (inTypedef())
329 typedefOff();
330}
331:
332 (declarationSpecifiers declaratorList? TERM)
333
334 // When the declaration is completely parsed and was a typedef, we add the declarators to the symbol table.
335 -> {inTypedef()}? ^(DECLARATION ^(TYPEDEF declaratorList declarationSpecifiers))
336 -> ^(DECLARATION declarationSpecifiers declaratorList?)
337
338 | (ctfSpecifier TERM!)
339 ;
340
341declarationSpecifiers
342@init {
343 enter("declarationSpecifiers");
344}
345@after {
346 debug_print($declarationSpecifiers.text);
347 exit("declarationSpecifiers");
348}
349:
350 (
351 // We don't want to keep the typedef keyword in the specifier list.
352 // Instead, we keep track that we encountered a typedef in the declaration.
353 storageClassSpecifier
354 | typeQualifier
355 | typeSpecifier
356 )+ -> ^(TYPE_SPECIFIER_LIST typeQualifier* typeSpecifier*)
357 ;
358
359declaratorList
360@init {
361 enter("declaratorList");
362}
363@after {
364 exit("declaratorList");
365}
366:
367 declarator (SEPARATOR declarator)* -> ^(TYPE_DECLARATOR_LIST declarator+)
368 ;
369
370abstractDeclaratorList
371@init {
372 enter("abstractDeclaratorList");
373}
374@after {
375 exit("abstractDeclaratorList");
376}
377:
378 abstractDeclarator (SEPARATOR abstractDeclarator)* -> ^(TYPE_DECLARATOR_LIST abstractDeclarator+)
379 ;
380
381storageClassSpecifier :
382 TYPEDEFTOK {typedefOn();}
383 ;
384
385typeSpecifier
386@init {
387 enter("typeSpecifier");
388}
389@after {
390 debug_print($typeSpecifier.text);
391 exit("typeSpecifier");
392}
393:
394 FLOATTOK
395 | INTTOK
396 | LONGTOK
397 | SHORTTOK
398 | SIGNEDTOK
399 | UNSIGNEDTOK
400 | CHARTOK
401 | DOUBLETOK
402 | VOIDTOK
403 | BOOLTOK
404 | COMPLEXTOK
405 | IMAGINARYTOK
406 | structSpecifier
407 | variantSpecifier
408 | enumSpecifier
409 | ctfTypeSpecifier
410 | {inTypealiasAlias() || isTypeName(input.LT(1).getText())}? => typedefName
411 ;
412
413typeQualifier
414@init {
415 enter("typeQualifier");
416}
417@after {
418 debug_print($typeQualifier.text);
419 exit("typeQualifier");
420}
421:
422 CONSTTOK
423 ;
424
425alignAttribute :
426 ALIGNTOK LPAREN unaryExpression RPAREN -> ^(ALIGN unaryExpression)
427 ;
428
429 // you can have an empty struct but not an empty variant
430structBody
431scope Symbols;
432@init {
433 enter("structBody");
434 debug_print("Scope push " + Symbols_stack.size());
435 $Symbols::types = new HashSet<String>();
436}
437@after {
438 debug_print("Scope pop " + Symbols_stack.size());
439 exit("structBody");
440}
441:
442 LCURL structOrVariantDeclarationList? RCURL -> ^(STRUCT_BODY structOrVariantDeclarationList?)
443 ;
444
445
446
447structSpecifier
448@init {
449 enter("structSpecifier");
450}
451@after {
452 exit("structSpecifier");
453}
454:
455 STRUCTTOK
456 (
457 // We have an IDENTIFIER after 'struct'
458 (
459 structName
460 (
461 alignAttribute
462 |
463 (
464 structBody
465 ( /* structBody can return an empty tree, so we need those ? */
466 alignAttribute
467 |
468 /* empty */
469 )
470 )
471 |
472 /* empty */
473 )
474 )
475 |
476 // We have a body after 'struct'
477 (
478 structBody
479 (
480 alignAttribute
481 |
482 /* empty */
483 )
484 )
485 ) -> ^(STRUCT structName? structBody? alignAttribute?)
486 ;
487
488structName
489@init {
490 enter("structName");
491}
492@after {
493 debug_print($structName.text);
494 exit("structName");
495}
496:
497 IDENTIFIER -> ^(STRUCT_NAME IDENTIFIER)
498 ;
499
500structOrVariantDeclarationList
501@init {
502 enter("structOrVariantDeclarationList");
503}
504@after {
505 exit("structOrVariantDeclarationList");
506}
507:
508 structOrVariantDeclaration+
509 ;
510
511structOrVariantDeclaration
512@init {
513 enter("structOrVariantDeclaration");
514}
515@after {
516 exit("structOrVariantDeclaration");
517}
518:
519 (
520 (
521 declarationSpecifiers
522 (
523 /* If we met a "typedef" */
524 {inTypedef()}? => declaratorList {typedefOff();}
525 -> ^(TYPEDEF declaratorList declarationSpecifiers)
526 | structOrVariantDeclaratorList
527 -> ^(SV_DECLARATION declarationSpecifiers structOrVariantDeclaratorList)
528 )
529 )
530 |
531 // Lines 3 and 4
532 typealiasDecl -> typealiasDecl
533 )
534 TERM
535 ;
536
537specifierQualifierList
538@init {
539 enter("specifierQualifierList");
540}
541@after {
542 exit("specifierQualifierList");
543}
544:
545 (typeQualifier | typeSpecifier)+ -> ^(TYPE_SPECIFIER_LIST typeQualifier* typeSpecifier*)
546 ;
547
548structOrVariantDeclaratorList
549@init {
550 enter("structOrVariantDeclaratorList");
551}
552@after {
553 exit("structOrVariantDeclaratorList");
554}
555:
556 structOrVariantDeclarator (SEPARATOR structOrVariantDeclarator)* -> ^(TYPE_DECLARATOR_LIST structOrVariantDeclarator+)
557 ;
558
559structOrVariantDeclarator
560@init {
561 enter("structOrVariantDeclarator");
562}
563@after {
564 exit("structOrVariantDeclarator");
565}
566:
567 /* Bitfields not supported yet */
568 (declarator (COLON numberLiteral)?) -> declarator
569 /*| (COLON numberLiteral)*/
570 ;
571
572variantSpecifier
573@init {
574 enter("variantSpecifier");
575}
576@after {
577 exit("variantSpecifier");
578}
579:
580 VARIANTTOK
581 (
582 (
583 variantName
584 (
585 (
586 variantTag
587 (
588 variantBody
589 |
590 /* empty */
591 )
592 )
593 |
594 variantBody
595 )
596 )
597 |
598 (variantTag variantBody)
599 |
600 variantBody
601 ) -> ^(VARIANT variantName? variantTag? variantBody?)
602 ;
603
604variantName
605@init {
606 enter("variantName");
607}
608@after {
609 debug_print($variantName.text);
610 exit("variantName");
611}
612:
613 IDENTIFIER -> ^(VARIANT_NAME IDENTIFIER)
614 ;
615
616variantBody
617scope Symbols;
618@init {
619 enter("variantBody");
620 debug_print("Scope push " + Symbols_stack.size());
621 $Symbols::types = new HashSet<String>();
622}
623@after {
624 debug_print("Scope pop " + Symbols_stack.size());
625 exit("variantBody");
626}
627:
628 LCURL structOrVariantDeclarationList RCURL -> ^(VARIANT_BODY structOrVariantDeclarationList)
629 ;
630
631variantTag
632@init {
633 enter("variantTag");
634}
635@after {
636 debug_print($variantTag.text);
637 exit("variantTag");
638}
639:
640 LT IDENTIFIER GT -> ^(VARIANT_TAG IDENTIFIER)
641 ;
642
643enumSpecifier
644@init {
645 enter("enumSpecifier");
646}
647@after {
648 exit("enumSpecifier");
649}
650:
651 ENUMTOK
652 (
653 // Lines 1 to 5, when we have "ENUMTOK IDENTIFIER".
654 (
655 enumName
656 (
657 enumContainerType enumBody
658 |
659 enumBody
660 |
661 // no enumDeclarator or enumBodym
662 )
663 )
664 |
665 // Lines 1, 2, 4, 5, when we have no IDENTIFIER.
666 (
667 enumContainerType enumBody
668 |
669 enumBody
670 )
671 ) -> ^(ENUM enumName? enumContainerType? enumBody?)
672 ;
673
674enumName
675@init {
676 enter("enumName");
677}
678@after {
679 debug_print($enumName.text);
680 exit("enumName");
681}
682:
683 IDENTIFIER -> ^(ENUM_NAME IDENTIFIER)
684 ;
685
686enumBody
687@init {
688 enter("enumBody");
689}
690@after {
691 exit("enumBody");
692}
693:
694 LCURL enumeratorList (SEPARATOR RCURL | RCURL) -> ^(ENUM_BODY enumeratorList)
695 ;
696
697enumContainerType
698@init {
699 enter("enumContainerType");
700}
701@after {
702 exit("enumContainerType");
703}
704:
705 COLON declarationSpecifiers -> ^(ENUM_CONTAINER_TYPE declarationSpecifiers)
706 ;
707
708enumeratorList
709@init {
710 enter("enumeratorList");
711}
712@after {
713 exit("enumeratorList");
714}
715:
716 enumerator (SEPARATOR enumerator)* -> (^(ENUM_ENUMERATOR enumerator))+
717 ;
718
719enumerator
720@init {
721 enter("enumerator");
722}
723@after {
724 exit("enumerator");
725}
726:
727 enumConstant enumeratorValue?
728 ;
729
730enumeratorValue
731@init {
732 enter("enumeratorValue");
733}
734@after {
735 exit("enumeratorValue");
736}
737:
738 ASSIGNMENT e1=unaryExpression
739 (
740 -> ^(ENUM_VALUE $e1)
741 | ELIPSES e2=unaryExpression -> ^(ENUM_VALUE_RANGE $e1 $e2)
742 )
743 ;
744
745
746declarator
747@init {
748 enter("declarator");
749}
750@after {
751 exit("declarator");
752}
753:
754 pointer* directDeclarator -> ^(TYPE_DECLARATOR pointer* directDeclarator)
755 ;
756
757directDeclarator
758@init {
759 enter("directDeclarator");
760}
761@after {
762 exit("directDeclarator");
763}
764:
765 (
766 IDENTIFIER { if (inTypedef()) addTypeName($IDENTIFIER.text); } {debug_print($IDENTIFIER.text);}
767 /*| LPAREN declarator RPAREN*/ /* Not supported yet */
768 )
769 directDeclaratorSuffix*
770 ;
771
772directDeclaratorSuffix:
773 OPENBRAC directDeclaratorLength CLOSEBRAC -> ^(LENGTH directDeclaratorLength)
774 ;
775
776directDeclaratorLength :
777 unaryExpression
778 ;
779
780
781abstractDeclarator
782@init {
783 enter("abstractDeclarator");
784}
785@after {
786 exit("abstractDeclarator");
787}
788:
789 (pointer+ directAbstractDeclarator?) -> ^(TYPE_DECLARATOR pointer+ directAbstractDeclarator?)
790 | directAbstractDeclarator -> ^(TYPE_DECLARATOR directAbstractDeclarator)
791 ;
792
793/*
794 In the CTF grammar, direct-abstract-declarator can be empty (because of identifier-opt).
795 We take care of that by appending a '?' to each use of "abstractDeclaratorList".
796*/
797directAbstractDeclarator
798@init {
799 enter("directAbstractDeclarator");
800}
801@after {
802 debug_print($directAbstractDeclarator.text);
803 exit("directAbstractDeclarator");
804}
805:
806 (
807 IDENTIFIER
808 | (LPAREN abstractDeclarator RPAREN)
809 )
810 (
811 OPENBRAC unaryExpression? CLOSEBRAC
812 )?
813 ;
814
815pointer
816@init {
817 enter("pointer");
818}
819@after {
820 debug_print($pointer.text);
821 exit("pointer");
822}
823:
824 POINTER typeQualifierList? -> ^(POINTER typeQualifierList?)
825 ;
826
827typeQualifierList :
828 typeQualifier+
829 ;
830
831typedefName
832@init {
833 enter("typedefName");
834}
835@after {
836 debug_print("typedefName: " + $typedefName.text);
837 exit("typedefName");
838}
839:
840 {inTypealiasAlias() || isTypeName(input.LT(1).getText())}? IDENTIFIER { if ((inTypedef() || inTypealiasAlias()) && !isTypeName($IDENTIFIER.text)) { addTypeName($IDENTIFIER.text); } }
841 ;
842
843/**
844 * What goes in the target part of a typealias.
845 *
846 * For example, the integer part in:
847 * typealias integer {...} := my_new_integer;
848 */
849typealiasTarget
850@init {
851 enter("typealiasTarget");
852}
853@after {
854 exit("typealiasTarget");
855}
856:
857 declarationSpecifiers abstractDeclaratorList?
858 ;
859
860/**
861 * What goes in the alias part of a typealias.
862 *
863 * For example, the my_new_integer part in:
864 * typealias integer {...} := my_new_integer;
865 */
866typealiasAlias
867@init {
868 enter("typealiasAlias");
869 typealiasAliasOn();
870}
871@after {
872 exit("typealiasAlias");
873 typealiasAliasOff();
874}
875:
876 (
877 abstractDeclaratorList
878 |
879 (declarationSpecifiers abstractDeclaratorList?)
880 )
881 ;
882
883typealiasDecl
884@init {
885 enter("typealiasDecl");
886}
887@after {
888 exit("typealiasDecl");
889}
890:
891 TYPEALIASTOK typealiasTarget TYPE_ASSIGNMENT typealiasAlias
892 -> ^(TYPEALIAS ^(TYPEALIAS_TARGET typealiasTarget) ^(TYPEALIAS_ALIAS typealiasAlias))
893 ;
894
895// 2.3 CTF stuff
896
897// TODO: Ajouter ceux qui manquent
898ctfKeyword
899@init {
900 enter("ctfKeyword");
901}
902@after {
903 debug_print($ctfKeyword.text);
904 exit("ctfKeyword");
905}
906:
907 ALIGNTOK
908 | EVENTTOK
909 | SIGNEDTOK
910 | STRINGTOK
911 ;
912
913ctfSpecifier
914@init {
915 enter("ctfSpecifier");
916}
917@after {
918 exit("ctfSpecifier");
919}
920 :
921 // event {...}, stream {...}, trace {...}
922 ctfSpecifierHead ctfBody -> ^(ctfSpecifierHead ctfBody)
923 |
924 // typealias
925 typealiasDecl -> ^(DECLARATION typealiasDecl)
926 ;
927
928ctfSpecifierHead
929@init {
930 enter("ctfSpecifierHead");
931}
932@after {
933 debug_print($ctfSpecifierHead.text);
934 exit("ctfSpecifierHead");
935}
936:
937 EVENTTOK -> EVENT
938 | STREAMTOK -> STREAM
939 | TRACETOK -> TRACE
940 | ENVTOK -> ENV
941 | CLOCKTOK -> CLOCK
4c9d2941 942 | CALLSITETOK -> CALLSITE
866e5b51
FC
943 ;
944
945ctfTypeSpecifier
946@init {
947 enter("ctfTypeSpecifier");
948}
949@after {
950 exit("ctfTypeSpecifier");
951}
952:
953 /* ctfBody can return an empty tree if the body is empty */
954 FLOATINGPOINTTOK ctfBody -> ^(FLOATING_POINT ctfBody?)
955 | INTEGERTOK ctfBody -> ^(INTEGER ctfBody?)
956 | STRINGTOK ctfBody? -> ^(STRING ctfBody?)
957 ;
958
959ctfBody
960scope Symbols;
961@init {
962 enter("ctfBody");
963 debug_print("Scope push " + + Symbols_stack.size());
964 $Symbols::types = new HashSet<String>();
965}
966@after {
967 debug_print("Scope pop " + + Symbols_stack.size());
968 exit("ctfBody");
969}
970:
971 LCURL ctfAssignmentExpressionList? RCURL -> ctfAssignmentExpressionList?
972 ;
973
974ctfAssignmentExpressionList :
975 (ctfAssignmentExpression TERM!)+
976 ;
977
978
979ctfAssignmentExpression
980@init {
981 enter("ctfAssignmentExpression");
982}
983@after {
984 if (inTypedef()) {
985 typedefOff();
986 }
987 exit("ctfAssignmentExpression");
988}
989:
990 (
991 left=unaryExpression
992 (
993 (assignment=ASSIGNMENT right1=unaryExpression) -> ^(CTF_EXPRESSION_VAL ^(CTF_LEFT $left) ^(CTF_RIGHT $right1))
994 | (type_assignment=TYPE_ASSIGNMENT right2=typeSpecifier) -> ^(CTF_EXPRESSION_TYPE ^(CTF_LEFT $left) ^(CTF_RIGHT ^(TYPE_SPECIFIER_LIST $right2)))
995 )
996 )
997
998 |
999
1000 (declarationSpecifiers {inTypedef()}? declaratorList)
1001 -> ^(TYPEDEF declaratorList declarationSpecifiers)
1002 |
1003
1004 typealiasDecl
1005 ;
This page took 0.061682 seconds and 5 git commands to generate.