| parser grammar CTFParser; |
| |
| options { |
| language = Java; |
| output = AST; |
| ASTLabelType = CommonTree; |
| tokenVocab = CTFLexer; |
| } |
| |
| tokens { |
| ROOT; |
| |
| EVENT; |
| STREAM; |
| TRACE; |
| ENV; |
| CLOCK; |
| CALLSITE; |
| |
| DECLARATION; |
| SV_DECLARATION; |
| TYPE_SPECIFIER_LIST; |
| TYPE_DECLARATOR_LIST; |
| TYPE_DECLARATOR; |
| |
| STRUCT; |
| STRUCT_NAME; |
| STRUCT_BODY; |
| ALIGN; |
| |
| CTF_EXPRESSION_TYPE; |
| CTF_EXPRESSION_VAL; |
| CTF_LEFT; |
| CTF_RIGHT; |
| |
| UNARY_EXPRESSION_STRING; |
| UNARY_EXPRESSION_STRING_QUOTES; |
| UNARY_EXPRESSION_DEC; |
| UNARY_EXPRESSION_HEX; |
| UNARY_EXPRESSION_OCT; |
| LENGTH; |
| |
| TYPEDEF; |
| |
| TYPEALIAS; |
| TYPEALIAS_TARGET; |
| TYPEALIAS_ALIAS; |
| |
| INTEGER; |
| STRING; |
| FLOATING_POINT; |
| |
| ENUM; |
| ENUM_CONTAINER_TYPE; |
| ENUM_ENUMERATOR; |
| ENUM_NAME; |
| ENUM_VALUE; |
| ENUM_VALUE_RANGE; |
| ENUM_BODY; |
| |
| VARIANT; |
| VARIANT_NAME; |
| VARIANT_TAG; |
| VARIANT_BODY; |
| |
| DECLARATOR; |
| LENGTH; |
| } |
| |
| /* |
| * Scope for the tracking of types. |
| * For now we just track the names (it's a simple Set), but |
| * later we will have to track the info about the target type. |
| */ |
| scope Symbols { |
| Set<String> types; |
| } |
| |
| @header { |
| /******************************************************************************* |
| * Copyright (c) 2010, 2015 Ericsson, Ecole Polytechnique de Montréal and others |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Matthew Khouzam - Initial API and implementation |
| * Simon Marchi - Initial API and implementation |
| * Etienne Bergeron - Update to Antlr 3.5 syntax |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.ctf.parser; |
| |
| import java.util.Set; |
| import java.util.HashSet; |
| } |
| |
| @members { |
| public CTFParser(TokenStream input, boolean verbose) { |
| this(input); |
| this.verbose = verbose; |
| } |
| |
| /** |
| * This method is overriden to disable automatic error recovery. |
| * On a mismatched token, it simply re-throw an exception. |
| */ |
| @Override |
| protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException { |
| throw new MismatchedTokenException(ttype, input); |
| } |
| |
| /** |
| * Checks if a given name has been defined has a type. |
| * From: http://www.antlr.org/grammar/1153358328744/C.g |
| * |
| * @param name The name to check. |
| * @return True if is is a type, false otherwise. |
| */ |
| boolean isTypeName(String name) { |
| for (int i = Symbols_stack.size() - 1; i >= 0; i--) { |
| Symbols_scope scope = (Symbols_scope) Symbols_stack.get(i); |
| if (scope.types.contains(name)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void addTypeName(String name) { |
| $Symbols::types.add(name); |
| if (verbose) { |
| debug_print("New type: " + name + " " + $declaration); |
| } |
| } |
| |
| void typedefOn() { |
| debug_print("typedefOn" + $declaration); |
| $declaration::isTypedef=true; |
| } |
| |
| void typedefOff() { |
| debug_print("typedefOff" + $declaration); |
| $declaration::isTypedef=false; |
| } |
| |
| boolean inTypedef() { |
| return $declaration::isTypedef; |
| } |
| |
| boolean _inTypealiasAlias = false; |
| |
| void typealiasAliasOn() { |
| debug_print("typealiasAliasOn"); |
| _inTypealiasAlias = true; |
| } |
| |
| void typealiasAliasOff() { |
| debug_print("typealiasAliasOff"); |
| _inTypealiasAlias = false; |
| } |
| |
| boolean inTypealiasAlias() { |
| return _inTypealiasAlias; |
| } |
| |
| void debug_print(String str) { |
| if (verbose) { |
| System.out.println(str); |
| } |
| } |
| |
| /* Prints rule entry and exit while parsing */ |
| boolean verbose = false; |
| } |
| |
| /* |
| * Override the catch clause to disable automatic error recovery. |
| * By default, the catch block of every rule simple rethrows the error. |
| */ |
| @rulecatch { |
| catch (RecognitionException e) { |
| throw e; |
| } |
| } |
| |
| /* The top-level rule. */ |
| parse |
| scope Symbols; |
| @init { |
| $Symbols::types = new HashSet<String>(); |
| } |
| : declaration+ EOF -> ^(ROOT declaration+) |
| ; |
| |
| numberLiteral |
| : SIGN* |
| ( HEX_LITERAL -> ^(UNARY_EXPRESSION_HEX HEX_LITERAL SIGN*) |
| | DECIMAL_LITERAL -> ^(UNARY_EXPRESSION_DEC DECIMAL_LITERAL SIGN*) |
| | OCTAL_LITERAL -> ^(UNARY_EXPRESSION_OCT OCTAL_LITERAL SIGN*) |
| ) |
| ; |
| |
| primaryExpression |
| : (IDENTIFIER) => IDENTIFIER |
| -> ^(UNARY_EXPRESSION_STRING IDENTIFIER) |
| | (ctfKeyword) => ctfKeyword -> ^(UNARY_EXPRESSION_STRING ctfKeyword) |
| | (STRING_LITERAL) => STRING_LITERAL |
| -> ^(UNARY_EXPRESSION_STRING_QUOTES STRING_LITERAL) |
| /*| (LPAREN unaryExpression RPAREN)*/ // Not supported yet |
| | numberLiteral |
| | enumConstant |
| | CHARACTER_LITERAL |
| ; |
| |
| postfixExpressionSuffix |
| : OPENBRAC unaryExpression CLOSEBRAC! |
| | (ref=DOT | ref=ARROW) IDENTIFIER |
| -> ^($ref ^(UNARY_EXPRESSION_STRING IDENTIFIER)) |
| ; |
| |
| postfixCtfExpression |
| : (ref=DOT) ctfSpecifierHead |
| -> ^($ref ^(UNARY_EXPRESSION_STRING ctfSpecifierHead)) |
| ; |
| |
| postfixExpression |
| : (primaryExpression postfixExpressionSuffix*) |
| | (ctfSpecifierHead postfixCtfExpression* postfixExpressionSuffix+) // added for ctf-v1.8 |
| ; |
| |
| unaryExpression |
| : postfixExpression |
| /* | ((SIGN postfixExpression[true]) | postfixExpression[false]) */ |
| ; |
| |
| enumConstant |
| : STRING_LITERAL -> ^(UNARY_EXPRESSION_STRING_QUOTES STRING_LITERAL) |
| | IDENTIFIER -> ^(UNARY_EXPRESSION_STRING IDENTIFIER) |
| | ctfKeyword -> ^(UNARY_EXPRESSION_STRING ctfKeyword) |
| ; |
| |
| // 2.2 |
| |
| declaration |
| scope{ |
| boolean isTypedef; |
| } |
| @init { |
| typedefOff(); |
| } |
| : declarationSpecifiers declaratorList? TERM |
| // When the declaration is completely parsed and was a typedef, |
| // we add the declarators to the symbol table. |
| -> {inTypedef()}? |
| ^(DECLARATION ^(TYPEDEF declaratorList declarationSpecifiers)) |
| -> ^(DECLARATION declarationSpecifiers declaratorList?) |
| | ctfSpecifier TERM! |
| ; |
| |
| declarationSpecifiers |
| : ( |
| // We don't want to keep the typedef keyword in the specifier list. |
| // Instead, we keep track that we encountered a typedef in the declaration. |
| storageClassSpecifier |
| | typeQualifier |
| | typeSpecifier |
| )+ -> ^(TYPE_SPECIFIER_LIST typeQualifier* typeSpecifier*) |
| ; |
| |
| declaratorList |
| : declarator (SEPARATOR declarator)* |
| -> ^(TYPE_DECLARATOR_LIST declarator+) |
| ; |
| |
| abstractDeclaratorList |
| : abstractDeclarator (SEPARATOR abstractDeclarator)* |
| -> ^(TYPE_DECLARATOR_LIST abstractDeclarator+) |
| ; |
| |
| storageClassSpecifier |
| : TYPEDEFTOK { typedefOn(); } |
| ; |
| |
| typeSpecifier |
| : FLOATTOK |
| | INTTOK |
| | LONGTOK |
| | SHORTTOK |
| | SIGNEDTOK |
| | UNSIGNEDTOK |
| | CHARTOK |
| | DOUBLETOK |
| | VOIDTOK |
| | BOOLTOK |
| | COMPLEXTOK |
| | IMAGINARYTOK |
| | structSpecifier |
| | variantSpecifier |
| | enumSpecifier |
| | ctfTypeSpecifier |
| | { inTypealiasAlias() || isTypeName(input.LT(1).getText()) }? => typedefName |
| ; |
| |
| typeQualifier |
| : CONSTTOK |
| ; |
| |
| alignAttribute |
| : ALIGNTOK LPAREN unaryExpression RPAREN -> ^(ALIGN unaryExpression) |
| ; |
| |
| // you can have an empty struct but not an empty variant |
| structBody |
| scope Symbols; |
| @init { |
| $Symbols::types = new HashSet<String>(); |
| } |
| : LCURL structOrVariantDeclarationList? RCURL |
| -> ^(STRUCT_BODY structOrVariantDeclarationList?) |
| ; |
| |
| structSpecifier |
| : STRUCTTOK |
| ( |
| // We have an IDENTIFIER after 'struct' |
| ( |
| structName |
| ( |
| alignAttribute |
| | |
| ( |
| structBody |
| ( /* structBody can return an empty tree, so we need those ? */ |
| alignAttribute |
| | |
| /* empty */ |
| ) |
| ) |
| | |
| /* empty */ |
| ) |
| ) |
| | |
| // We have a body after 'struct' |
| ( |
| structBody |
| ( |
| alignAttribute |
| | |
| /* empty */ |
| ) |
| ) |
| ) -> ^(STRUCT structName? structBody? alignAttribute?) |
| ; |
| |
| structName |
| : IDENTIFIER -> ^(STRUCT_NAME IDENTIFIER) |
| ; |
| |
| structOrVariantDeclarationList |
| : structOrVariantDeclaration+ |
| ; |
| |
| structOrVariantDeclaration |
| : |
| ( |
| ( |
| declarationSpecifiers |
| ( |
| /* If we met a "typedef" */ |
| {inTypedef()}? => declaratorList |
| -> ^(TYPEDEF declaratorList declarationSpecifiers) |
| | structOrVariantDeclaratorList |
| -> ^(SV_DECLARATION declarationSpecifiers structOrVariantDeclaratorList) |
| ) |
| ) |
| | |
| // Lines 3 and 4 |
| typealiasDecl -> typealiasDecl |
| ) |
| TERM |
| ; |
| |
| specifierQualifierList |
| : (typeQualifier | typeSpecifier)+ |
| -> ^(TYPE_SPECIFIER_LIST typeQualifier* typeSpecifier*) |
| ; |
| |
| structOrVariantDeclaratorList |
| : structOrVariantDeclarator (SEPARATOR structOrVariantDeclarator)* |
| -> ^(TYPE_DECLARATOR_LIST structOrVariantDeclarator+) |
| ; |
| |
| structOrVariantDeclarator |
| : |
| /* Bitfields not supported yet */ |
| (declarator (COLON numberLiteral)?) -> declarator |
| /*| (COLON numberLiteral)*/ |
| ; |
| |
| variantSpecifier |
| : VARIANTTOK |
| ( |
| ( |
| variantName |
| ( |
| ( |
| variantTag |
| ( |
| variantBody |
| | |
| /* empty */ |
| ) |
| ) |
| | |
| variantBody |
| ) |
| ) |
| | (variantTag variantBody) |
| | variantBody |
| ) -> ^(VARIANT variantName? variantTag? variantBody?) |
| ; |
| |
| variantName |
| : IDENTIFIER -> ^(VARIANT_NAME IDENTIFIER) |
| ; |
| |
| variantBody |
| scope Symbols; |
| @init { |
| $Symbols::types = new HashSet<String>(); |
| } |
| : LCURL structOrVariantDeclarationList RCURL |
| -> ^(VARIANT_BODY structOrVariantDeclarationList) |
| ; |
| |
| variantTag |
| : LT IDENTIFIER GT -> ^(VARIANT_TAG IDENTIFIER) |
| ; |
| |
| enumSpecifier |
| : ENUMTOK |
| ( |
| // Lines 1 to 5, when we have "ENUMTOK IDENTIFIER". |
| ( |
| enumName |
| ( |
| enumContainerType enumBody |
| | |
| enumBody |
| | |
| // no enumDeclarator or enumBodym |
| ) |
| ) |
| | |
| // Lines 1, 2, 4, 5, when we have no IDENTIFIER. |
| ( |
| enumContainerType enumBody |
| | |
| enumBody |
| ) |
| ) -> ^(ENUM enumName? enumContainerType? enumBody?) |
| ; |
| |
| enumName |
| : IDENTIFIER -> ^(ENUM_NAME IDENTIFIER) |
| ; |
| |
| enumBody |
| : LCURL enumeratorList SEPARATOR? RCURL -> ^(ENUM_BODY enumeratorList) |
| ; |
| |
| enumContainerType |
| : COLON declarationSpecifiers -> ^(ENUM_CONTAINER_TYPE declarationSpecifiers) |
| ; |
| |
| enumeratorList |
| : enumerator (SEPARATOR enumerator)* -> (^(ENUM_ENUMERATOR enumerator))+ |
| ; |
| |
| enumerator |
| : enumConstant enumeratorValue? |
| ; |
| |
| enumeratorValue |
| : ASSIGNMENT e1=unaryExpression |
| ( /* empty */ |
| -> ^(ENUM_VALUE $e1) |
| | ELIPSES e2=unaryExpression |
| -> ^(ENUM_VALUE_RANGE $e1 $e2) |
| ) |
| ; |
| |
| declarator |
| : pointer* directDeclarator |
| -> ^(TYPE_DECLARATOR pointer* directDeclarator) |
| ; |
| |
| directDeclarator |
| : ( |
| IDENTIFIER |
| { if (inTypedef()) addTypeName($IDENTIFIER.text); } |
| { debug_print($IDENTIFIER.text); } |
| /*| LPAREN declarator RPAREN*/ /* Not supported yet */ |
| ) |
| directDeclaratorSuffix* |
| ; |
| |
| directDeclaratorSuffix |
| : OPENBRAC directDeclaratorLength CLOSEBRAC |
| -> ^(LENGTH directDeclaratorLength) |
| ; |
| |
| directDeclaratorLength |
| : unaryExpression |
| ; |
| |
| abstractDeclarator |
| : pointer+ directAbstractDeclarator? |
| -> ^(TYPE_DECLARATOR pointer+ directAbstractDeclarator?) |
| | directAbstractDeclarator |
| -> ^(TYPE_DECLARATOR directAbstractDeclarator) |
| ; |
| |
| /** |
| * In the CTF grammar, direct-abstract-declarator can be empty (because of |
| * identifier-opt). We take care of that by appending a '?' to each use of |
| * "abstractDeclaratorList". |
| */ |
| directAbstractDeclarator |
| : ( |
| IDENTIFIER |
| | (LPAREN abstractDeclarator RPAREN) |
| ) ( |
| OPENBRAC unaryExpression? CLOSEBRAC |
| )? |
| ; |
| |
| pointer |
| : POINTER typeQualifierList? -> ^(POINTER typeQualifierList?) |
| ; |
| |
| typeQualifierList |
| : typeQualifier+ |
| ; |
| |
| typedefName |
| : {inTypealiasAlias() || isTypeName(input.LT(1).getText())}? IDENTIFIER { if ((inTypedef() || inTypealiasAlias()) && !isTypeName($IDENTIFIER.text)) { addTypeName($IDENTIFIER.text); } } |
| ; |
| |
| /** |
| * What goes in the target part of a typealias. |
| * |
| * For example, the integer part in: |
| * typealias integer {...} := my_new_integer; |
| */ |
| typealiasTarget |
| : declarationSpecifiers abstractDeclaratorList? |
| ; |
| |
| /** |
| * What goes in the alias part of a typealias. |
| * |
| * For example, the my_new_integer part in: |
| * typealias integer {...} := my_new_integer; |
| */ |
| typealiasAlias |
| @init { |
| typealiasAliasOn(); |
| } |
| @after { |
| typealiasAliasOff(); |
| } |
| : abstractDeclaratorList |
| | declarationSpecifiers abstractDeclaratorList? |
| ; |
| |
| typealiasDecl |
| : TYPEALIASTOK typealiasTarget TYPE_ASSIGNMENT typealiasAlias |
| -> ^(TYPEALIAS |
| ^(TYPEALIAS_TARGET typealiasTarget) |
| ^(TYPEALIAS_ALIAS typealiasAlias)) |
| ; |
| |
| // 2.3 CTF stuff |
| |
| // TODO: Ajouter ceux qui manquent |
| ctfKeyword |
| : ALIGNTOK |
| | EVENTTOK |
| | SIGNEDTOK |
| | STRINGTOK |
| ; |
| |
| ctfSpecifier |
| // event {...}, stream {...}, trace {...} |
| : ctfSpecifierHead ctfBody -> ^(ctfSpecifierHead ctfBody) |
| // typealias |
| | typealiasDecl -> ^(DECLARATION typealiasDecl) |
| ; |
| |
| ctfSpecifierHead |
| : EVENTTOK -> EVENT |
| | STREAMTOK -> STREAM |
| | TRACETOK -> TRACE |
| | ENVTOK -> ENV |
| | CLOCKTOK -> CLOCK |
| | CALLSITETOK -> CALLSITE |
| ; |
| |
| ctfTypeSpecifier |
| /* ctfBody can return an empty tree if the body is empty */ |
| : FLOATINGPOINTTOK ctfBody -> ^(FLOATING_POINT ctfBody?) |
| | INTEGERTOK ctfBody -> ^(INTEGER ctfBody?) |
| | STRINGTOK ctfBody? -> ^(STRING ctfBody?) |
| ; |
| |
| ctfBody |
| scope Symbols; |
| @init { |
| $Symbols::types = new HashSet<String>(); |
| } |
| : LCURL ctfAssignmentExpressionList? RCURL -> ctfAssignmentExpressionList? |
| ; |
| |
| ctfAssignmentExpressionList |
| : (ctfAssignmentExpression TERM!)+ |
| ; |
| |
| ctfAssignmentExpression |
| @after { |
| if (inTypedef()) { |
| typedefOff(); |
| } |
| } |
| : left=unaryExpression |
| ( assignment=ASSIGNMENT right1=unaryExpression |
| -> ^(CTF_EXPRESSION_VAL |
| ^(CTF_LEFT $left) |
| ^(CTF_RIGHT $right1)) |
| | type_assignment=TYPE_ASSIGNMENT right2=typeSpecifier |
| -> ^(CTF_EXPRESSION_TYPE |
| ^(CTF_LEFT $left) |
| ^(CTF_RIGHT ^(TYPE_SPECIFIER_LIST $right2))) |
| ) |
| | (declarationSpecifiers {inTypedef()}? declaratorList) |
| -> ^(TYPEDEF declaratorList declarationSpecifiers) |
| | typealiasDecl |
| ; |