blob: 9e9dc2839f840aaa318f11ff968b4500a8ef36c8 [file] [log] [blame]
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
;