mirror of
https://github.com/arduino/Arduino.git
synced 2024-12-12 23:08:52 +01:00
1359 lines
38 KiB
Plaintext
1359 lines
38 KiB
Plaintext
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
|
||
|
Copyright (c) Non, Inc. 1997 -- All Rights Reserved
|
||
|
|
||
|
PROJECT: C Compiler
|
||
|
MODULE: Parser
|
||
|
FILE: stdc.g
|
||
|
|
||
|
AUTHOR: John D. Mitchell (john@non.net), Jul 12, 1997
|
||
|
|
||
|
REVISION HISTORY:
|
||
|
|
||
|
Name Date Description
|
||
|
---- ---- -----------
|
||
|
JDM 97.07.12 Initial version.
|
||
|
JTC 97.11.18 Declaration vs declarator & misc. hacking.
|
||
|
JDM 97.11.20 Fixed: declaration vs funcDef,
|
||
|
parenthesized expressions,
|
||
|
declarator iteration,
|
||
|
varargs recognition,
|
||
|
empty source file recognition,
|
||
|
and some typos.
|
||
|
|
||
|
|
||
|
DESCRIPTION:
|
||
|
|
||
|
This grammar supports the Standard C language.
|
||
|
|
||
|
Note clearly that this grammar does *NOT* deal with
|
||
|
preprocessor functionality (including things like trigraphs)
|
||
|
Nor does this grammar deal with multi-byte characters nor strings
|
||
|
containing multi-byte characters [these constructs are "exercises
|
||
|
for the reader" as it were :-)].
|
||
|
|
||
|
Please refer to the ISO/ANSI C Language Standard if you believe
|
||
|
this grammar to be in error. Please cite chapter and verse in any
|
||
|
correspondence to the author to back up your claim.
|
||
|
|
||
|
TODO:
|
||
|
|
||
|
- typedefName is commented out, needs a symbol table to resolve
|
||
|
ambiguity.
|
||
|
|
||
|
- trees
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||
|
|
||
|
|
||
|
header{
|
||
|
package processing.app.preproc;
|
||
|
import java.io.*;
|
||
|
|
||
|
import antlr.CommonAST;
|
||
|
import antlr.DumpASTVisitor;
|
||
|
}
|
||
|
|
||
|
|
||
|
class StdCParser extends Parser;
|
||
|
|
||
|
options
|
||
|
{
|
||
|
k = 2;
|
||
|
exportVocab = STDC;
|
||
|
buildAST = true;
|
||
|
ASTLabelType = "TNode";
|
||
|
|
||
|
// Copied following options from java grammar.
|
||
|
codeGenMakeSwitchThreshold = 2;
|
||
|
codeGenBitsetTestThreshold = 3;
|
||
|
}
|
||
|
|
||
|
|
||
|
{
|
||
|
// Suppport C++-style single-line comments?
|
||
|
public static boolean CPPComments = true;
|
||
|
|
||
|
// access to symbol table
|
||
|
public CSymbolTable symbolTable = new CSymbolTable();
|
||
|
|
||
|
// source for names to unnamed scopes
|
||
|
protected int unnamedScopeCounter = 0;
|
||
|
|
||
|
public boolean isTypedefName(String name) {
|
||
|
boolean returnValue = false;
|
||
|
TNode node = symbolTable.lookupNameInCurrentScope(name);
|
||
|
for (; node != null; node = (TNode) node.getNextSibling() ) {
|
||
|
if(node.getType() == LITERAL_typedef) {
|
||
|
returnValue = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return returnValue;
|
||
|
}
|
||
|
|
||
|
|
||
|
public String getAScopeName() {
|
||
|
return "" + (unnamedScopeCounter++);
|
||
|
}
|
||
|
|
||
|
public void pushScope(String scopeName) {
|
||
|
symbolTable.pushScope(scopeName);
|
||
|
}
|
||
|
|
||
|
public void popScope() {
|
||
|
symbolTable.popScope();
|
||
|
}
|
||
|
|
||
|
int traceDepth = 0;
|
||
|
public void reportError(RecognitionException ex) {
|
||
|
try {
|
||
|
System.err.println("ANTLR Parsing Error: "+ex + " token name:" + tokenNames[LA(1)]);
|
||
|
ex.printStackTrace(System.err);
|
||
|
}
|
||
|
catch (TokenStreamException e) {
|
||
|
System.err.println("ANTLR Parsing Error: "+ex);
|
||
|
ex.printStackTrace(System.err);
|
||
|
}
|
||
|
}
|
||
|
public void reportError(String s) {
|
||
|
System.err.println("ANTLR Parsing Error from String: " + s);
|
||
|
}
|
||
|
public void reportWarning(String s) {
|
||
|
System.err.println("ANTLR Parsing Warning from String: " + s);
|
||
|
}
|
||
|
public void match(int t) throws MismatchedTokenException {
|
||
|
boolean debugging = false;
|
||
|
|
||
|
if ( debugging ) {
|
||
|
for (int x=0; x<traceDepth; x++) System.out.print(" ");
|
||
|
try {
|
||
|
System.out.println("Match("+tokenNames[t]+") with LA(1)="+
|
||
|
tokenNames[LA(1)] + ((inputState.guessing>0)?" [inputState.guessing "+ inputState.guessing + "]":""));
|
||
|
}
|
||
|
catch (TokenStreamException e) {
|
||
|
System.out.println("Match("+tokenNames[t]+") " + ((inputState.guessing>0)?" [inputState.guessing "+ inputState.guessing + "]":""));
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
try {
|
||
|
if ( LA(1)!=t ) {
|
||
|
if ( debugging ){
|
||
|
for (int x=0; x<traceDepth; x++) System.out.print(" ");
|
||
|
System.out.println("token mismatch: "+tokenNames[LA(1)]
|
||
|
+ "!="+tokenNames[t]);
|
||
|
}
|
||
|
throw new MismatchedTokenException(tokenNames, LT(1), t, false, getFilename());
|
||
|
|
||
|
} else {
|
||
|
// mark token as consumed -- fetch next token deferred until LA/LT
|
||
|
consume();
|
||
|
}
|
||
|
}
|
||
|
catch (TokenStreamException e) {
|
||
|
}
|
||
|
|
||
|
}
|
||
|
public void traceIn(String rname) {
|
||
|
traceDepth += 1;
|
||
|
for (int x=0; x<traceDepth; x++) System.out.print(" ");
|
||
|
try {
|
||
|
System.out.println("> "+rname+"; LA(1)==("+ tokenNames[LT(1).getType()]
|
||
|
+ ") " + LT(1).getText() + " [inputState.guessing "+ inputState.guessing + "]");
|
||
|
}
|
||
|
catch (TokenStreamException e) {
|
||
|
}
|
||
|
}
|
||
|
public void traceOut(String rname) {
|
||
|
for (int x=0; x<traceDepth; x++) System.out.print(" ");
|
||
|
try {
|
||
|
System.out.println("< "+rname+"; LA(1)==("+ tokenNames[LT(1).getType()]
|
||
|
+ ") "+LT(1).getText() + " [inputState.guessing "+ inputState.guessing + "]");
|
||
|
}
|
||
|
catch (TokenStreamException e) {
|
||
|
}
|
||
|
traceDepth -= 1;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
translationUnit
|
||
|
: externalList
|
||
|
|
||
|
| /* Empty source files are *not* allowed. */
|
||
|
{
|
||
|
System.err.println ( "Empty source file!" );
|
||
|
}
|
||
|
;
|
||
|
|
||
|
|
||
|
externalList
|
||
|
: ( externalDef )+
|
||
|
;
|
||
|
|
||
|
|
||
|
externalDef
|
||
|
: ( "typedef" | declaration )=> declaration
|
||
|
| functionDef
|
||
|
| asm_expr
|
||
|
;
|
||
|
|
||
|
|
||
|
asm_expr
|
||
|
: "asm"^
|
||
|
("volatile")? LCURLY! expr RCURLY! SEMI!
|
||
|
;
|
||
|
|
||
|
|
||
|
declaration
|
||
|
{ AST ds1 = null; }
|
||
|
: ds:declSpecifiers { ds1 = astFactory.dupList(#ds); }
|
||
|
(
|
||
|
initDeclList[ds1]
|
||
|
)?
|
||
|
SEMI!
|
||
|
{ ## = #( #[NDeclaration], ##); }
|
||
|
|
||
|
;
|
||
|
|
||
|
|
||
|
declSpecifiers
|
||
|
{ int specCount=0; }
|
||
|
: ( options { // this loop properly aborts when
|
||
|
// it finds a non-typedefName ID MBZ
|
||
|
warnWhenFollowAmbig = false;
|
||
|
} :
|
||
|
s:storageClassSpecifier
|
||
|
| typeQualifier
|
||
|
| ( "struct" | "union" | "enum" | typeSpecifier[specCount] )=>
|
||
|
specCount = typeSpecifier[specCount]
|
||
|
)+
|
||
|
;
|
||
|
|
||
|
storageClassSpecifier
|
||
|
: "auto"
|
||
|
| "register"
|
||
|
| "typedef"
|
||
|
| functionStorageClassSpecifier
|
||
|
;
|
||
|
|
||
|
|
||
|
functionStorageClassSpecifier
|
||
|
: "extern"
|
||
|
| "static"
|
||
|
;
|
||
|
|
||
|
|
||
|
typeQualifier
|
||
|
: "const"
|
||
|
| "volatile"
|
||
|
;
|
||
|
|
||
|
typeSpecifier [int specCount] returns [int retSpecCount]
|
||
|
{ retSpecCount = specCount + 1; }
|
||
|
:
|
||
|
( "void"
|
||
|
| "char"
|
||
|
| "short"
|
||
|
| "int"
|
||
|
| "long"
|
||
|
| "float"
|
||
|
| "double"
|
||
|
| "signed"
|
||
|
| "unsigned"
|
||
|
| structOrUnionSpecifier
|
||
|
| enumSpecifier
|
||
|
| { specCount == 0 }? typedefName
|
||
|
)
|
||
|
;
|
||
|
|
||
|
|
||
|
typedefName
|
||
|
: { isTypedefName ( LT(1).getText() ) }?
|
||
|
i:ID { ## = #(#[NTypedefName], #i); }
|
||
|
;
|
||
|
|
||
|
structOrUnionSpecifier
|
||
|
{ String scopeName; }
|
||
|
: sou:structOrUnion!
|
||
|
( ( ID LCURLY )=> i:ID l:LCURLY
|
||
|
{
|
||
|
scopeName = #sou.getText() + " " + #i.getText();
|
||
|
#l.setText(scopeName);
|
||
|
pushScope(scopeName);
|
||
|
}
|
||
|
structDeclarationList
|
||
|
{ popScope();}
|
||
|
RCURLY!
|
||
|
| l1:LCURLY
|
||
|
{
|
||
|
scopeName = getAScopeName();
|
||
|
#l1.setText(scopeName);
|
||
|
pushScope(scopeName);
|
||
|
}
|
||
|
structDeclarationList
|
||
|
{ popScope(); }
|
||
|
RCURLY!
|
||
|
| ID
|
||
|
)
|
||
|
{
|
||
|
## = #( #sou, ## );
|
||
|
}
|
||
|
;
|
||
|
|
||
|
|
||
|
structOrUnion
|
||
|
: "struct"
|
||
|
| "union"
|
||
|
;
|
||
|
|
||
|
|
||
|
structDeclarationList
|
||
|
: ( structDeclaration )+
|
||
|
;
|
||
|
|
||
|
|
||
|
structDeclaration
|
||
|
: specifierQualifierList structDeclaratorList ( SEMI! )+
|
||
|
;
|
||
|
|
||
|
|
||
|
specifierQualifierList
|
||
|
{ int specCount = 0; }
|
||
|
: ( options { // this loop properly aborts when
|
||
|
// it finds a non-typedefName ID MBZ
|
||
|
warnWhenFollowAmbig = false;
|
||
|
} :
|
||
|
( "struct" | "union" | "enum" | typeSpecifier[specCount] )=>
|
||
|
specCount = typeSpecifier[specCount]
|
||
|
| typeQualifier
|
||
|
)+
|
||
|
;
|
||
|
|
||
|
|
||
|
structDeclaratorList
|
||
|
: structDeclarator ( COMMA! structDeclarator )*
|
||
|
;
|
||
|
|
||
|
|
||
|
structDeclarator
|
||
|
:
|
||
|
( COLON constExpr
|
||
|
| declarator[false] ( COLON constExpr )?
|
||
|
)
|
||
|
{ ## = #( #[NStructDeclarator], ##); }
|
||
|
;
|
||
|
|
||
|
|
||
|
enumSpecifier
|
||
|
: "enum"^
|
||
|
( ( ID LCURLY )=> i:ID LCURLY enumList[i.getText()] RCURLY!
|
||
|
| LCURLY enumList["anonymous"] RCURLY!
|
||
|
| ID
|
||
|
)
|
||
|
;
|
||
|
|
||
|
|
||
|
enumList[String enumName]
|
||
|
: enumerator[enumName] ( COMMA! enumerator[enumName] )*
|
||
|
;
|
||
|
|
||
|
enumerator[String enumName]
|
||
|
: i:ID { symbolTable.add( i.getText(),
|
||
|
#( null,
|
||
|
#[LITERAL_enum, "enum"],
|
||
|
#[ ID, enumName]
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
(ASSIGN constExpr)?
|
||
|
;
|
||
|
|
||
|
|
||
|
initDeclList[AST declarationSpecifiers]
|
||
|
: initDecl[declarationSpecifiers]
|
||
|
( COMMA! initDecl[declarationSpecifiers] )*
|
||
|
;
|
||
|
|
||
|
|
||
|
initDecl[AST declarationSpecifiers]
|
||
|
{ String declName = ""; }
|
||
|
: declName = d:declarator[false]
|
||
|
{ AST ds1, d1;
|
||
|
ds1 = astFactory.dupList(declarationSpecifiers);
|
||
|
d1 = astFactory.dupList(#d);
|
||
|
symbolTable.add(declName, #(null, ds1, d1) );
|
||
|
}
|
||
|
( ASSIGN initializer
|
||
|
| COLON expr
|
||
|
)?
|
||
|
{ ## = #( #[NInitDecl], ## ); }
|
||
|
|
||
|
;
|
||
|
|
||
|
pointerGroup
|
||
|
: ( STAR ( typeQualifier )* )+ { ## = #( #[NPointerGroup], ##); }
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
idList
|
||
|
: ID ( COMMA! ID )*
|
||
|
;
|
||
|
|
||
|
|
||
|
initializer
|
||
|
: ( assignExpr
|
||
|
| LCURLY initializerList ( COMMA! )? RCURLY!
|
||
|
)
|
||
|
{ ## = #( #[NInitializer], ## ); }
|
||
|
;
|
||
|
|
||
|
|
||
|
initializerList
|
||
|
: initializer ( COMMA! initializer )*
|
||
|
;
|
||
|
|
||
|
|
||
|
declarator[boolean isFunctionDefinition] returns [String declName]
|
||
|
{ declName = ""; }
|
||
|
:
|
||
|
( pointerGroup )?
|
||
|
|
||
|
( id:ID { declName = id.getText(); }
|
||
|
| LPAREN declName = declarator[false] RPAREN
|
||
|
)
|
||
|
|
||
|
( ! LPAREN
|
||
|
{
|
||
|
if (isFunctionDefinition) {
|
||
|
pushScope(declName);
|
||
|
}
|
||
|
else {
|
||
|
pushScope("!"+declName);
|
||
|
}
|
||
|
}
|
||
|
(
|
||
|
(declSpecifiers)=> p:parameterTypeList
|
||
|
{
|
||
|
## = #( null, ##, #( #[NParameterTypeList], #p ) );
|
||
|
}
|
||
|
|
||
|
| (i:idList)?
|
||
|
{
|
||
|
## = #( null, ##, #( #[NParameterTypeList], #i ) );
|
||
|
}
|
||
|
)
|
||
|
{
|
||
|
popScope();
|
||
|
}
|
||
|
RPAREN
|
||
|
| LBRACKET ( constExpr )? RBRACKET
|
||
|
)*
|
||
|
{ ## = #( #[NDeclarator], ## ); }
|
||
|
;
|
||
|
|
||
|
parameterTypeList
|
||
|
: parameterDeclaration
|
||
|
( options {
|
||
|
warnWhenFollowAmbig = false;
|
||
|
} :
|
||
|
COMMA!
|
||
|
parameterDeclaration
|
||
|
)*
|
||
|
( COMMA!
|
||
|
VARARGS
|
||
|
)?
|
||
|
;
|
||
|
|
||
|
|
||
|
parameterDeclaration
|
||
|
{ String declName; }
|
||
|
: ds:declSpecifiers
|
||
|
( ( declarator[false] )=> declName = d:declarator[false]
|
||
|
{
|
||
|
AST d2, ds2;
|
||
|
d2 = astFactory.dupList(#d);
|
||
|
ds2 = astFactory.dupList(#ds);
|
||
|
symbolTable.add(declName, #(null, ds2, d2));
|
||
|
}
|
||
|
| nonemptyAbstractDeclarator
|
||
|
)?
|
||
|
{
|
||
|
## = #( #[NParameterDeclaration], ## );
|
||
|
}
|
||
|
;
|
||
|
|
||
|
/* JTC:
|
||
|
* This handles both new and old style functions.
|
||
|
* see declarator rule to see differences in parameters
|
||
|
* and here (declaration SEMI)* is the param type decls for the
|
||
|
* old style. may want to do some checking to check for illegal
|
||
|
* combinations (but I assume all parsed code will be legal?)
|
||
|
*/
|
||
|
|
||
|
functionDef
|
||
|
{ String declName; }
|
||
|
: ( (functionDeclSpecifiers)=> ds:functionDeclSpecifiers
|
||
|
| //epsilon
|
||
|
)
|
||
|
declName = d:declarator[true]
|
||
|
{
|
||
|
AST d2, ds2;
|
||
|
d2 = astFactory.dupList(#d);
|
||
|
ds2 = astFactory.dupList(#ds);
|
||
|
symbolTable.add(declName, #(null, ds2, d2));
|
||
|
pushScope(declName);
|
||
|
}
|
||
|
( declaration )* (VARARGS)? ( SEMI! )*
|
||
|
{ popScope(); }
|
||
|
compoundStatement[declName]
|
||
|
{ ## = #( #[NFunctionDef], ## );}
|
||
|
;
|
||
|
|
||
|
functionDeclSpecifiers
|
||
|
{ int specCount = 0; }
|
||
|
: ( options { // this loop properly aborts when
|
||
|
// it finds a non-typedefName ID MBZ
|
||
|
warnWhenFollowAmbig = false;
|
||
|
} :
|
||
|
functionStorageClassSpecifier
|
||
|
| typeQualifier
|
||
|
| ( "struct" | "union" | "enum" | typeSpecifier[specCount] )=>
|
||
|
specCount = typeSpecifier[specCount]
|
||
|
)+
|
||
|
;
|
||
|
|
||
|
declarationList
|
||
|
: ( options { // this loop properly aborts when
|
||
|
// it finds a non-typedefName ID MBZ
|
||
|
warnWhenFollowAmbig = false;
|
||
|
} :
|
||
|
( declarationPredictor )=> declaration
|
||
|
)+
|
||
|
;
|
||
|
|
||
|
declarationPredictor
|
||
|
: (options { //only want to look at declaration if I don't see typedef
|
||
|
warnWhenFollowAmbig = false;
|
||
|
}:
|
||
|
"typedef"
|
||
|
| declaration
|
||
|
)
|
||
|
;
|
||
|
|
||
|
|
||
|
compoundStatement[String scopeName]
|
||
|
: LCURLY!
|
||
|
{
|
||
|
pushScope(scopeName);
|
||
|
}
|
||
|
( ( declarationPredictor)=> declarationList )?
|
||
|
( statementList )?
|
||
|
{ popScope(); }
|
||
|
RCURLY!
|
||
|
{ ## = #( #[NCompoundStatement, scopeName], ##); }
|
||
|
;
|
||
|
|
||
|
|
||
|
statementList
|
||
|
: ( statement )+
|
||
|
;
|
||
|
statement
|
||
|
: SEMI // Empty statements
|
||
|
|
||
|
| compoundStatement[getAScopeName()] // Group of statements
|
||
|
|
||
|
| expr SEMI! { ## = #( #[NStatementExpr], ## ); } // Expressions
|
||
|
|
||
|
// Iteration statements:
|
||
|
|
||
|
| "while"^ LPAREN! expr RPAREN! statement
|
||
|
| "do"^ statement "while"! LPAREN! expr RPAREN! SEMI!
|
||
|
|! "for"
|
||
|
LPAREN ( e1:expr )? SEMI ( e2:expr )? SEMI ( e3:expr )? RPAREN
|
||
|
s:statement
|
||
|
{
|
||
|
if ( #e1 == null) { #e1 = #[ NEmptyExpression ]; }
|
||
|
if ( #e2 == null) { #e2 = #[ NEmptyExpression ]; }
|
||
|
if ( #e3 == null) { #e3 = #[ NEmptyExpression ]; }
|
||
|
## = #( #[LITERAL_for, "for"], #e1, #e2, #e3, #s );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Jump statements:
|
||
|
|
||
|
| "goto"^ ID SEMI!
|
||
|
| "continue" SEMI!
|
||
|
| "break" SEMI!
|
||
|
| "return"^ ( expr )? SEMI!
|
||
|
|
||
|
|
||
|
// Labeled statements:
|
||
|
| ID COLON! (options {warnWhenFollowAmbig=false;}:statement)? { ## = #( #[NLabel], ## ); }
|
||
|
| "case"^ constExpr COLON! statement
|
||
|
| "default"^ COLON! statement
|
||
|
|
||
|
|
||
|
|
||
|
// Selection statements:
|
||
|
|
||
|
| "if"^
|
||
|
LPAREN! expr RPAREN! statement
|
||
|
( //standard if-else ambiguity
|
||
|
options {
|
||
|
warnWhenFollowAmbig = false;
|
||
|
} :
|
||
|
"else" statement )?
|
||
|
| "switch"^ LPAREN! expr RPAREN! statement
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
expr
|
||
|
: assignExpr (options {
|
||
|
/* MBZ:
|
||
|
COMMA is ambiguous between comma expressions and
|
||
|
argument lists. argExprList should get priority,
|
||
|
and it does by being deeper in the expr rule tree
|
||
|
and using (COMMA assignExpr)*
|
||
|
*/
|
||
|
warnWhenFollowAmbig = false;
|
||
|
} :
|
||
|
c:COMMA^ { #c.setType(NCommaExpr); } assignExpr
|
||
|
)*
|
||
|
;
|
||
|
|
||
|
|
||
|
assignExpr
|
||
|
: conditionalExpr ( a:assignOperator! assignExpr { ## = #( #a, ## );} )?
|
||
|
;
|
||
|
|
||
|
assignOperator
|
||
|
: ASSIGN
|
||
|
| DIV_ASSIGN
|
||
|
| PLUS_ASSIGN
|
||
|
| MINUS_ASSIGN
|
||
|
| STAR_ASSIGN
|
||
|
| MOD_ASSIGN
|
||
|
| RSHIFT_ASSIGN
|
||
|
| LSHIFT_ASSIGN
|
||
|
| BAND_ASSIGN
|
||
|
| BOR_ASSIGN
|
||
|
| BXOR_ASSIGN
|
||
|
;
|
||
|
|
||
|
|
||
|
conditionalExpr
|
||
|
: logicalOrExpr
|
||
|
( QUESTION^ expr COLON! conditionalExpr )?
|
||
|
;
|
||
|
|
||
|
|
||
|
constExpr
|
||
|
: conditionalExpr
|
||
|
;
|
||
|
|
||
|
logicalOrExpr
|
||
|
: logicalAndExpr ( LOR^ logicalAndExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
logicalAndExpr
|
||
|
: inclusiveOrExpr ( LAND^ inclusiveOrExpr )*
|
||
|
;
|
||
|
|
||
|
inclusiveOrExpr
|
||
|
: exclusiveOrExpr ( BOR^ exclusiveOrExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
exclusiveOrExpr
|
||
|
: bitAndExpr ( BXOR^ bitAndExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
bitAndExpr
|
||
|
: equalityExpr ( BAND^ equalityExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
equalityExpr
|
||
|
: relationalExpr
|
||
|
( ( EQUAL^ | NOT_EQUAL^ ) relationalExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
relationalExpr
|
||
|
: shiftExpr
|
||
|
( ( LT^ | LTE^ | GT^ | GTE^ ) shiftExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
shiftExpr
|
||
|
: additiveExpr
|
||
|
( ( LSHIFT^ | RSHIFT^ ) additiveExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
additiveExpr
|
||
|
: multExpr
|
||
|
( ( PLUS^ | MINUS^ ) multExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
multExpr
|
||
|
: castExpr
|
||
|
( ( STAR^ | DIV^ | MOD^ ) castExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
castExpr
|
||
|
: ( LPAREN typeName RPAREN )=>
|
||
|
LPAREN! typeName RPAREN! ( castExpr )
|
||
|
{ ## = #( #[NCast, "("], ## ); }
|
||
|
|
||
|
| unaryExpr
|
||
|
;
|
||
|
|
||
|
|
||
|
typeName
|
||
|
: specifierQualifierList (nonemptyAbstractDeclarator)?
|
||
|
;
|
||
|
|
||
|
nonemptyAbstractDeclarator
|
||
|
: (
|
||
|
pointerGroup
|
||
|
( (LPAREN
|
||
|
( nonemptyAbstractDeclarator
|
||
|
| parameterTypeList
|
||
|
)?
|
||
|
RPAREN)
|
||
|
| (LBRACKET (expr)? RBRACKET)
|
||
|
)*
|
||
|
|
||
|
| ( (LPAREN
|
||
|
( nonemptyAbstractDeclarator
|
||
|
| parameterTypeList
|
||
|
)?
|
||
|
RPAREN)
|
||
|
| (LBRACKET (expr)? RBRACKET)
|
||
|
)+
|
||
|
)
|
||
|
{ ## = #( #[NNonemptyAbstractDeclarator], ## ); }
|
||
|
|
||
|
;
|
||
|
|
||
|
/* JTC:
|
||
|
|
||
|
LR rules:
|
||
|
|
||
|
abstractDeclarator
|
||
|
: nonemptyAbstractDeclarator
|
||
|
| // null
|
||
|
;
|
||
|
|
||
|
nonemptyAbstractDeclarator
|
||
|
: LPAREN nonemptyAbstractDeclarator RPAREN
|
||
|
| abstractDeclarator LPAREN RPAREN
|
||
|
| abstractDeclarator (LBRACKET (expr)? RBRACKET)
|
||
|
| STAR abstractDeclarator
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
unaryExpr
|
||
|
: postfixExpr
|
||
|
| INC^ unaryExpr
|
||
|
| DEC^ unaryExpr
|
||
|
| u:unaryOperator castExpr { ## = #( #[NUnaryExpr], ## ); }
|
||
|
|
||
|
| "sizeof"^
|
||
|
( ( LPAREN typeName )=> LPAREN typeName RPAREN
|
||
|
| unaryExpr
|
||
|
)
|
||
|
;
|
||
|
|
||
|
|
||
|
unaryOperator
|
||
|
: BAND
|
||
|
| STAR
|
||
|
| PLUS
|
||
|
| MINUS
|
||
|
| BNOT
|
||
|
| LNOT
|
||
|
;
|
||
|
|
||
|
postfixExpr
|
||
|
: primaryExpr
|
||
|
(
|
||
|
postfixSuffix {## = #( #[NPostfixExpr], ## );}
|
||
|
)?
|
||
|
;
|
||
|
postfixSuffix
|
||
|
:
|
||
|
( PTR ID
|
||
|
| DOT ID
|
||
|
| functionCall
|
||
|
| LBRACKET expr RBRACKET
|
||
|
| INC
|
||
|
| DEC
|
||
|
)+
|
||
|
;
|
||
|
|
||
|
functionCall
|
||
|
:
|
||
|
LPAREN^ (a:argExprList)? RPAREN
|
||
|
{
|
||
|
##.setType( NFunctionCallArgs );
|
||
|
}
|
||
|
;
|
||
|
|
||
|
|
||
|
primaryExpr
|
||
|
: ID
|
||
|
| charConst
|
||
|
| intConst
|
||
|
| floatConst
|
||
|
| stringConst
|
||
|
|
||
|
// JTC:
|
||
|
// ID should catch the enumerator
|
||
|
// leaving it in gives ambiguous err
|
||
|
// | enumerator
|
||
|
| LPAREN! expr RPAREN! { ## = #( #[NExpressionGroup, "("], ## ); }
|
||
|
;
|
||
|
|
||
|
argExprList
|
||
|
: assignExpr ( COMMA! assignExpr )*
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
protected
|
||
|
charConst
|
||
|
: CharLiteral
|
||
|
;
|
||
|
|
||
|
|
||
|
protected
|
||
|
stringConst
|
||
|
: (StringLiteral)+ { ## = #(#[NStringSeq], ##); }
|
||
|
;
|
||
|
|
||
|
|
||
|
protected
|
||
|
intConst
|
||
|
: IntOctalConst
|
||
|
| LongOctalConst
|
||
|
| UnsignedOctalConst
|
||
|
| IntIntConst
|
||
|
| LongIntConst
|
||
|
| UnsignedIntConst
|
||
|
| IntHexConst
|
||
|
| LongHexConst
|
||
|
| UnsignedHexConst
|
||
|
;
|
||
|
|
||
|
|
||
|
protected
|
||
|
floatConst
|
||
|
: FloatDoubleConst
|
||
|
| DoubleDoubleConst
|
||
|
| LongDoubleConst
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
dummy
|
||
|
: NTypedefName
|
||
|
| NInitDecl
|
||
|
| NDeclarator
|
||
|
| NStructDeclarator
|
||
|
| NDeclaration
|
||
|
| NCast
|
||
|
| NPointerGroup
|
||
|
| NExpressionGroup
|
||
|
| NFunctionCallArgs
|
||
|
| NNonemptyAbstractDeclarator
|
||
|
| NInitializer
|
||
|
| NStatementExpr
|
||
|
| NEmptyExpression
|
||
|
| NParameterTypeList
|
||
|
| NFunctionDef
|
||
|
| NCompoundStatement
|
||
|
| NParameterDeclaration
|
||
|
| NCommaExpr
|
||
|
| NUnaryExpr
|
||
|
| NLabel
|
||
|
| NPostfixExpr
|
||
|
| NRangeExpr
|
||
|
| NStringSeq
|
||
|
| NInitializerElementLabel
|
||
|
| NLcurlyInitializer
|
||
|
| NAsmAttribute
|
||
|
| NGnuAsmExpr
|
||
|
| NTypeMissing
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
{
|
||
|
// import CToken;
|
||
|
import java.io.*;
|
||
|
// import LineObject;
|
||
|
import antlr.*;
|
||
|
}
|
||
|
|
||
|
class StdCLexer extends Lexer;
|
||
|
|
||
|
options
|
||
|
{
|
||
|
k = 3;
|
||
|
exportVocab = STDC;
|
||
|
testLiterals = false;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
LineObject lineObject = new LineObject();
|
||
|
String originalSource = "";
|
||
|
PreprocessorInfoChannel preprocessorInfoChannel = new PreprocessorInfoChannel();
|
||
|
int tokenNumber = 0;
|
||
|
boolean countingTokens = true;
|
||
|
int deferredLineCount = 0;
|
||
|
|
||
|
public void setCountingTokens(boolean ct)
|
||
|
{
|
||
|
countingTokens = ct;
|
||
|
if ( countingTokens ) {
|
||
|
tokenNumber = 0;
|
||
|
}
|
||
|
else {
|
||
|
tokenNumber = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void setOriginalSource(String src)
|
||
|
{
|
||
|
originalSource = src;
|
||
|
lineObject.setSource(src);
|
||
|
}
|
||
|
public void setSource(String src)
|
||
|
{
|
||
|
lineObject.setSource(src);
|
||
|
}
|
||
|
|
||
|
public PreprocessorInfoChannel getPreprocessorInfoChannel()
|
||
|
{
|
||
|
return preprocessorInfoChannel;
|
||
|
}
|
||
|
|
||
|
public void setPreprocessingDirective(String pre)
|
||
|
{
|
||
|
preprocessorInfoChannel.addLineForTokenNumber( pre, new Integer(tokenNumber) );
|
||
|
}
|
||
|
|
||
|
protected Token makeToken(int t)
|
||
|
{
|
||
|
if ( t != Token.SKIP && countingTokens) {
|
||
|
tokenNumber++;
|
||
|
}
|
||
|
CToken tok = (CToken) super.makeToken(t);
|
||
|
tok.setLine(lineObject.line);
|
||
|
tok.setSource(lineObject.source);
|
||
|
tok.setTokenNumber(tokenNumber);
|
||
|
|
||
|
lineObject.line += deferredLineCount;
|
||
|
deferredLineCount = 0;
|
||
|
return tok;
|
||
|
}
|
||
|
|
||
|
public void deferredNewline() {
|
||
|
deferredLineCount++;
|
||
|
}
|
||
|
|
||
|
public void newline() {
|
||
|
lineObject.newline();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
protected
|
||
|
Vocabulary
|
||
|
: '\3'..'\377'
|
||
|
;
|
||
|
|
||
|
|
||
|
/* Operators: */
|
||
|
|
||
|
ASSIGN : '=' ;
|
||
|
COLON : ':' ;
|
||
|
COMMA : ',' ;
|
||
|
QUESTION : '?' ;
|
||
|
SEMI : ';' ;
|
||
|
PTR : "->" ;
|
||
|
|
||
|
|
||
|
// DOT & VARARGS are commented out since they are generated as part of
|
||
|
// the Number rule below due to some bizarre lexical ambiguity shme.
|
||
|
|
||
|
// DOT : '.' ;
|
||
|
protected
|
||
|
DOT:;
|
||
|
|
||
|
// VARARGS : "..." ;
|
||
|
protected
|
||
|
VARARGS:;
|
||
|
|
||
|
|
||
|
LPAREN : '(' ;
|
||
|
RPAREN : ')' ;
|
||
|
LBRACKET : '[' ;
|
||
|
RBRACKET : ']' ;
|
||
|
LCURLY : '{' ;
|
||
|
RCURLY : '}' ;
|
||
|
|
||
|
EQUAL : "==" ;
|
||
|
NOT_EQUAL : "!=" ;
|
||
|
LTE : "<=" ;
|
||
|
LT : "<" ;
|
||
|
GTE : ">=" ;
|
||
|
GT : ">" ;
|
||
|
|
||
|
DIV : '/' ;
|
||
|
DIV_ASSIGN : "/=" ;
|
||
|
PLUS : '+' ;
|
||
|
PLUS_ASSIGN : "+=" ;
|
||
|
INC : "++" ;
|
||
|
MINUS : '-' ;
|
||
|
MINUS_ASSIGN : "-=" ;
|
||
|
DEC : "--" ;
|
||
|
STAR : '*' ;
|
||
|
STAR_ASSIGN : "*=" ;
|
||
|
MOD : '%' ;
|
||
|
MOD_ASSIGN : "%=" ;
|
||
|
RSHIFT : ">>" ;
|
||
|
RSHIFT_ASSIGN : ">>=" ;
|
||
|
LSHIFT : "<<" ;
|
||
|
LSHIFT_ASSIGN : "<<=" ;
|
||
|
|
||
|
LAND : "&&" ;
|
||
|
LNOT : '!' ;
|
||
|
LOR : "||" ;
|
||
|
|
||
|
BAND : '&' ;
|
||
|
BAND_ASSIGN : "&=" ;
|
||
|
BNOT : '~' ;
|
||
|
BOR : '|' ;
|
||
|
BOR_ASSIGN : "|=" ;
|
||
|
BXOR : '^' ;
|
||
|
BXOR_ASSIGN : "^=" ;
|
||
|
|
||
|
|
||
|
Whitespace
|
||
|
: ( ( '\003'..'\010' | '\t' | '\013' | '\f' | '\016'.. '\037' | '\177'..'\377' | ' ' )
|
||
|
| "\r\n" { newline(); }
|
||
|
| ( '\n' | '\r' ) { newline(); }
|
||
|
) { _ttype = Token.SKIP; }
|
||
|
;
|
||
|
|
||
|
|
||
|
Comment
|
||
|
: "/*"
|
||
|
( { LA(2) != '/' }? '*'
|
||
|
| "\r\n" { deferredNewline(); }
|
||
|
| ( '\r' | '\n' ) { deferredNewline(); }
|
||
|
| ~( '*'| '\r' | '\n' )
|
||
|
)*
|
||
|
"*/" { _ttype = Token.SKIP;
|
||
|
}
|
||
|
;
|
||
|
|
||
|
|
||
|
CPPComment
|
||
|
:
|
||
|
"//" ( ~('\n') )*
|
||
|
{
|
||
|
_ttype = Token.SKIP;
|
||
|
}
|
||
|
;
|
||
|
|
||
|
PREPROC_DIRECTIVE
|
||
|
options {
|
||
|
paraphrase = "a line directive";
|
||
|
}
|
||
|
|
||
|
:
|
||
|
'#'
|
||
|
( ( "line" || (( ' ' | '\t' | '\014')+ '0'..'9')) => LineDirective
|
||
|
| (~'\n')* { setPreprocessingDirective(getText()); }
|
||
|
)
|
||
|
{
|
||
|
_ttype = Token.SKIP;
|
||
|
}
|
||
|
;
|
||
|
|
||
|
protected Space:
|
||
|
( ' ' | '\t' | '\014')
|
||
|
;
|
||
|
|
||
|
protected LineDirective
|
||
|
{
|
||
|
boolean oldCountingTokens = countingTokens;
|
||
|
countingTokens = false;
|
||
|
}
|
||
|
:
|
||
|
{
|
||
|
lineObject = new LineObject();
|
||
|
deferredLineCount = 0;
|
||
|
}
|
||
|
("line")? //this would be for if the directive started "#line", but not there for GNU directives
|
||
|
(Space)+
|
||
|
n:Number { lineObject.setLine(Integer.parseInt(n.getText())); }
|
||
|
(Space)+
|
||
|
( fn:StringLiteral { try {
|
||
|
lineObject.setSource(fn.getText().substring(1,fn.getText().length()-1));
|
||
|
}
|
||
|
catch (StringIndexOutOfBoundsException e) { /*not possible*/ }
|
||
|
}
|
||
|
| fi:ID { lineObject.setSource(fi.getText()); }
|
||
|
)?
|
||
|
(Space)*
|
||
|
("1" { lineObject.setEnteringFile(true); } )?
|
||
|
(Space)*
|
||
|
("2" { lineObject.setReturningToFile(true); } )?
|
||
|
(Space)*
|
||
|
("3" { lineObject.setSystemHeader(true); } )?
|
||
|
(Space)*
|
||
|
("4" { lineObject.setTreatAsC(true); } )?
|
||
|
(~('\r' | '\n'))*
|
||
|
("\r\n" | "\r" | "\n")
|
||
|
{
|
||
|
preprocessorInfoChannel.addLineForTokenNumber(new LineObject(lineObject), new Integer(tokenNumber));
|
||
|
countingTokens = oldCountingTokens;
|
||
|
}
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
/* Literals: */
|
||
|
|
||
|
/*
|
||
|
* Note that we do NOT handle tri-graphs nor multi-byte sequences.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Note that we can't have empty character constants (even though we
|
||
|
* can have empty strings :-).
|
||
|
*/
|
||
|
CharLiteral
|
||
|
: '\'' ( Escape | ~( '\'' ) ) '\''
|
||
|
;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Can't have raw imbedded newlines in string constants. Strict reading of
|
||
|
* the standard gives odd dichotomy between newlines & carriage returns.
|
||
|
* Go figure.
|
||
|
*/
|
||
|
StringLiteral
|
||
|
: '"'
|
||
|
( Escape
|
||
|
| (
|
||
|
'\r' { deferredNewline(); }
|
||
|
| '\n' {
|
||
|
deferredNewline();
|
||
|
_ttype = BadStringLiteral;
|
||
|
}
|
||
|
| '\\' '\n' {
|
||
|
deferredNewline();
|
||
|
}
|
||
|
)
|
||
|
| ~( '"' | '\r' | '\n' | '\\' )
|
||
|
)*
|
||
|
'"'
|
||
|
;
|
||
|
|
||
|
|
||
|
protected BadStringLiteral
|
||
|
: // Imaginary token.
|
||
|
;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Handle the various escape sequences.
|
||
|
*
|
||
|
* Note carefully that these numeric escape *sequences* are *not* of the
|
||
|
* same form as the C language numeric *constants*.
|
||
|
*
|
||
|
* There is no such thing as a binary numeric escape sequence.
|
||
|
*
|
||
|
* Octal escape sequences are either 1, 2, or 3 octal digits exactly.
|
||
|
*
|
||
|
* There is no such thing as a decimal escape sequence.
|
||
|
*
|
||
|
* Hexadecimal escape sequences are begun with a leading \x and continue
|
||
|
* until a non-hexadecimal character is found.
|
||
|
*
|
||
|
* No real handling of tri-graph sequences, yet.
|
||
|
*/
|
||
|
|
||
|
protected
|
||
|
Escape
|
||
|
: '\\'
|
||
|
( options{warnWhenFollowAmbig=false;}:
|
||
|
'a'
|
||
|
| 'b'
|
||
|
| 'f'
|
||
|
| 'n'
|
||
|
| 'r'
|
||
|
| 't'
|
||
|
| 'v'
|
||
|
| '"'
|
||
|
| '\''
|
||
|
| '\\'
|
||
|
| '?'
|
||
|
| ('0'..'3') ( options{warnWhenFollowAmbig=false;}: Digit ( options{warnWhenFollowAmbig=false;}: Digit )? )?
|
||
|
| ('4'..'7') ( options{warnWhenFollowAmbig=false;}: Digit )?
|
||
|
| 'x' ( options{warnWhenFollowAmbig=false;}: Digit | 'a'..'f' | 'A'..'F' )+
|
||
|
)
|
||
|
;
|
||
|
|
||
|
|
||
|
/* Numeric Constants: */
|
||
|
|
||
|
protected
|
||
|
Digit
|
||
|
: '0'..'9'
|
||
|
;
|
||
|
|
||
|
protected
|
||
|
LongSuffix
|
||
|
: 'l'
|
||
|
| 'L'
|
||
|
;
|
||
|
|
||
|
protected
|
||
|
UnsignedSuffix
|
||
|
: 'u'
|
||
|
| 'U'
|
||
|
;
|
||
|
|
||
|
protected
|
||
|
FloatSuffix
|
||
|
: 'f'
|
||
|
| 'F'
|
||
|
;
|
||
|
|
||
|
protected
|
||
|
Exponent
|
||
|
: ( 'e' | 'E' ) ( '+' | '-' )? ( Digit )+
|
||
|
;
|
||
|
|
||
|
|
||
|
protected
|
||
|
DoubleDoubleConst:;
|
||
|
|
||
|
protected
|
||
|
FloatDoubleConst:;
|
||
|
|
||
|
protected
|
||
|
LongDoubleConst:;
|
||
|
|
||
|
protected
|
||
|
IntOctalConst:;
|
||
|
|
||
|
protected
|
||
|
LongOctalConst:;
|
||
|
|
||
|
protected
|
||
|
UnsignedOctalConst:;
|
||
|
|
||
|
protected
|
||
|
IntIntConst:;
|
||
|
|
||
|
protected
|
||
|
LongIntConst:;
|
||
|
|
||
|
protected
|
||
|
UnsignedIntConst:;
|
||
|
|
||
|
protected
|
||
|
IntHexConst:;
|
||
|
|
||
|
protected
|
||
|
LongHexConst:;
|
||
|
|
||
|
protected
|
||
|
UnsignedHexConst:;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Number
|
||
|
: ( ( Digit )+ ( '.' | 'e' | 'E' ) )=> ( Digit )+
|
||
|
( '.' ( Digit )* ( Exponent )?
|
||
|
| Exponent
|
||
|
) { _ttype = DoubleDoubleConst; }
|
||
|
( FloatSuffix { _ttype = FloatDoubleConst; }
|
||
|
| LongSuffix { _ttype = LongDoubleConst; }
|
||
|
)?
|
||
|
|
||
|
| ( "..." )=> "..." { _ttype = VARARGS; }
|
||
|
|
||
|
| '.' { _ttype = DOT; }
|
||
|
( ( Digit )+ ( Exponent )?
|
||
|
{ _ttype = DoubleDoubleConst; }
|
||
|
( FloatSuffix { _ttype = FloatDoubleConst; }
|
||
|
| LongSuffix { _ttype = LongDoubleConst; }
|
||
|
)?
|
||
|
)?
|
||
|
|
||
|
| '0' ( '0'..'7' )* { _ttype = IntOctalConst; }
|
||
|
( LongSuffix { _ttype = LongOctalConst; }
|
||
|
| UnsignedSuffix { _ttype = UnsignedOctalConst; }
|
||
|
)?
|
||
|
|
||
|
| '1'..'9' ( Digit )* { _ttype = IntIntConst; }
|
||
|
( LongSuffix { _ttype = LongIntConst; }
|
||
|
| UnsignedSuffix { _ttype = UnsignedIntConst; }
|
||
|
)?
|
||
|
|
||
|
| '0' ( 'x' | 'X' ) ( 'a'..'f' | 'A'..'F' | Digit )+
|
||
|
{ _ttype = IntHexConst; }
|
||
|
( LongSuffix { _ttype = LongHexConst; }
|
||
|
| UnsignedSuffix { _ttype = UnsignedHexConst; }
|
||
|
)?
|
||
|
;
|
||
|
|
||
|
|
||
|
ID
|
||
|
options
|
||
|
{
|
||
|
testLiterals = true;
|
||
|
}
|
||
|
: ( 'a'..'z' | 'A'..'Z' | '_' )
|
||
|
( 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' )*
|
||
|
;
|
||
|
|
||
|
|