Files
processing4/editor/processing.plugin.appBundle/processing/app/antlr/expandedpde.g

1584 lines
42 KiB
Plaintext

header {
package processing.app.antlr;
import processing.app.preproc.PdePreprocessor;
}
class PdeRecognizer extends Parser;
options {
importVocab= Java;
exportVocab= PdePartial;
codeGenMakeSwitchThreshold=10;
codeGenBitsetTestThreshold=10;
defaultErrorHandler= false;
k= 2;
buildAST= true;
}
tokens {
CONSTRUCTOR_CAST; EMPTY_FIELD;
}
{
// this clause copied from java15.g! ANTLR does not copy this
// section from the super grammar.
/**
* Counts the number of LT seen in the typeArguments production.
* It is used in semantic predicates to ensure we have seen
* enough closing '>' characters; which actually may have been
* either GT, SR or BSR tokens.
*/
private int ltCounter = 0;
private PdePreprocessor pp;
public PdeRecognizer(final PdePreprocessor pp, final TokenStream ts) {
this(ts);
this.pp = pp;
}
private void mixed() throws RecognitionException, TokenStreamException {
throw new RecognitionException("It looks like you're mixing \"active\" and \"static\" modes.",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}
}
pdeProgram :// Some programs can be equally well interpreted as STATIC or ACTIVE;
// this forces the parser to prefer the STATIC interpretation.
(staticProgram) => staticProgram
{ pp.setMode(PdePreprocessor.Mode.STATIC); }
| (activeProgram) => activeProgram
{ pp.setMode(PdePreprocessor.Mode.ACTIVE); }
| staticProgram
{ pp.setMode(PdePreprocessor.Mode.STATIC); }
;
javaProgram :compilationUnit
;
activeProgram :(
(IDENT LPAREN) => IDENT LPAREN { mixed(); }
| possiblyEmptyField
)+ EOF!
;
staticProgram :(
(builtInType IDENT LPAREN) => builtInType IDENT LPAREN { mixed(); }
| (modifiers) => modifiers builtInType IDENT LPAREN { mixed(); }
| statement
)* EOF!
;
constant :NUM_INT
| CHAR_LITERAL
| STRING_LITERAL
| NUM_FLOAT
| NUM_LONG
| NUM_DOUBLE
| webcolor_literal
;
typeArguments {int currentLtLevel = 0;}
:{currentLtLevel = ltCounter;}
LT! {ltCounter++;}
typeArgument
(options{greedy=true;}: // match as many as possible
{if (! (inputState.guessing !=0 || ltCounter == currentLtLevel + 1)) {
throw new RecognitionException("Maybe too many > characters?",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}}
COMMA! typeArgument
)*
( // turn warning off since Antlr generates the right code,
// plus we have our semantic predicate below
options{generateAmbigWarnings=false;}:
typeArgumentsOrParametersEnd
)?
// make sure we have gobbled up enough '>' characters
// if we are at the "top level" of nested typeArgument productions
{if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) {
throw new RecognitionException("Maybe too many > characters?",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}}
{#typeArguments = #(#[TYPE_ARGUMENTS, "TYPE_ARGUMENTS"], #typeArguments);}
;
typeParameters {int currentLtLevel = 0;}
:{currentLtLevel = ltCounter;}
LT! {ltCounter++;}
typeParameter (COMMA! typeParameter)*
(typeArgumentsOrParametersEnd)?
// make sure we have gobbled up enough '>' characters
// if we are at the "top level" of nested typeArgument productions
{if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) {
throw new RecognitionException("Maybe too many > characters?",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}}
{#typeParameters = #(#[TYPE_PARAMETERS, "TYPE_PARAMETERS"], #typeParameters);}
;
protected typeArgumentsOrParametersEnd :GT! {ltCounter-=1;}
| SR! {ltCounter-=2;}
| BSR! {ltCounter-=3;}
;
webcolor_literal :w:WEBCOLOR_LITERAL
{ if (! (processing.app.Preferences.getBoolean("preproc.web_colors")
&&
w.getText().length() == 6)) {
throw new RecognitionException("Web colors must be exactly 6 hex digits. This looks like " + w.getText().length() + ".",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}} // must be exactly 6 hex digits
;
builtInConsCastType :"void"
| "boolean"
| "byte"
| "char"
| "short"
| "int"
| "float"
| "long"
| "double"
;
builtInType :builtInConsCastType
| "color" // aliased to an int in PDE
{ processing.app.Preferences.getBoolean("preproc.color_datatype") }?
;
constructorCast! :t:consCastTypeSpec[true]
LPAREN!
e:expression
RPAREN!
// if this is a string literal, make sure the type we're trying to cast
// to is one of the supported ones
//
{ #e.getType() != STRING_LITERAL ||
( #t.getType() == LITERAL_byte ||
#t.getType() == LITERAL_double ||
#t.getType() == LITERAL_float ||
#t.getType() == LITERAL_int ||
#t.getType() == LITERAL_long ||
#t.getType() == LITERAL_short ) }?
// create the node
//
{#constructorCast = #(#[CONSTRUCTOR_CAST,"CONSTRUCTOR_CAST"], t, e);}
;
consCastTypeSpec[boolean addImagNode] :builtInConsCastTypeSpec[addImagNode]
// trying to remove String() cast [fry]
;
builtInConsCastTypeSpec[boolean addImagNode] :builtInConsCastType
{
if ( addImagNode ) {
#builtInConsCastTypeSpec = #(#[TYPE,"TYPE"],
#builtInConsCastTypeSpec);
}
}
;
colorMethodCall :c:"color" {#c.setType(IDENT);} // this would default to LITERAL_color
lp:LPAREN^ {#lp.setType(METHOD_CALL);}
argList
RPAREN!
;
primaryExpression :(consCastTypeSpec[false] LPAREN) => constructorCast
{ processing.app.Preferences.getBoolean("preproc.enhanced_casting") }?
| identPrimary ( options {greedy=true;} : DOT^ "class" )?
| constant
| "true"
| "false"
| "null"
| newExpression
| "this"
| "super"
| LPAREN! assignmentExpression RPAREN!
| colorMethodCall
// look for int.class and int[].class
| builtInType
( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
DOT^ "class"
;
variableDefinitions![AST mods, AST t] :vd:variableDeclarator[getASTFactory().dupTree(mods),
getASTFactory().dupTree(t)]
{#variableDefinitions = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods,
t, vd);}
;
variableDeclarator[AST mods, AST t] :( id:IDENT (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
v:varInitializer (COMMA!)? )+
;
explicitConstructorInvocation! :(typeArguments)?
t:"this" LPAREN a1:argList RPAREN SEMI
{#explicitConstructorInvocation = #(#[CTOR_CALL, "CTOR_CALL"],
#t, #a1);}
| s:"super" LPAREN a2:argList RPAREN SEMI
{#explicitConstructorInvocation = #(#[SUPER_CTOR_CALL,
"SUPER_CTOR_CALL"],
#s, #a2);}
;
classDefinition![AST modifiers] :"class" i:IDENT
// it _might_ have type paramaters
(tp:typeParameters)?
// it _might_ have a superclass...
sc:superClassClause
// it might implement some interfaces...
ic:implementsClause
// now parse the body of the class
cb:classBlock
{#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
modifiers,i,tp,sc,ic,cb);
pp.setAdvClassName(i.getText());}
;
possiblyEmptyField :classField
| s:SEMI {#s.setType(EMPTY_FIELD);}
;
// inherited from grammar JavaRecognizer
compilationUnit :// A compilation unit starts with an optional package definition
( (annotations "package")=> packageDefinition
| /* nothing */
)
// Next we have a series of zero or more import statements
( importDefinition )*
// Wrapping things up with any number of class or interface
// definitions
( typeDefinition )*
EOF!
;
// inherited from grammar JavaRecognizer
packageDefinition
options {
defaultErrorHandler= true;
}
:annotations p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
;
// inherited from grammar JavaRecognizer
importDefinition
options {
defaultErrorHandler= true;
}
{ boolean isStatic = false; }
:i:"import"^ {#i.setType(IMPORT);} ( "static"! {#i.setType(STATIC_IMPORT);} )? identifierStar SEMI!
;
// inherited from grammar JavaRecognizer
typeDefinition
options {
defaultErrorHandler= true;
}
:m:modifiers!
typeDefinitionInternal[#m]
| SEMI!
;
// inherited from grammar JavaRecognizer
protected typeDefinitionInternal[AST mods] :classDefinition[#mods] // inner class
| interfaceDefinition[#mods] // inner interface
| enumDefinition[#mods] // inner enum
| annotationDefinition[#mods] // inner annotation
;
// inherited from grammar JavaRecognizer
declaration! :m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
{#declaration = #v;}
;
// inherited from grammar JavaRecognizer
typeSpec[boolean addImagNode] :classTypeSpec[addImagNode]
| builtInTypeSpec[addImagNode]
;
// inherited from grammar JavaRecognizer
classTypeSpec[boolean addImagNode] :classOrInterfaceType[false]
(options{greedy=true;}: // match as many as possible
lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
)*
{
if ( addImagNode ) {
#classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
}
}
;
// inherited from grammar JavaRecognizer
classOrInterfaceType[boolean addImagNode] :IDENT (typeArguments)?
(options{greedy=true;}: // match as many as possible
DOT^
IDENT (typeArguments)?
)*
{
if ( addImagNode ) {
#classOrInterfaceType = #(#[TYPE,"TYPE"], #classOrInterfaceType);
}
}
;
// inherited from grammar JavaRecognizer
typeArgumentSpec :classTypeSpec[true]
| builtInTypeArraySpec[true]
;
// inherited from grammar JavaRecognizer
typeArgument :( typeArgumentSpec
| wildcardType
)
{#typeArgument = #(#[TYPE_ARGUMENT,"TYPE_ARGUMENT"], #typeArgument);}
;
// inherited from grammar JavaRecognizer
wildcardType :q:QUESTION^ {#q.setType(WILDCARD_TYPE);}
(("extends" | "super")=> typeArgumentBounds)?
;
// inherited from grammar JavaRecognizer
typeArgumentBounds {boolean isUpperBounds = false;}
:( "extends"! {isUpperBounds=true;} | "super"! ) classOrInterfaceType[false]
{
if (isUpperBounds)
{
#typeArgumentBounds = #(#[TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS"], #typeArgumentBounds);
}
else
{
#typeArgumentBounds = #(#[TYPE_LOWER_BOUNDS,"TYPE_LOWER_BOUNDS"], #typeArgumentBounds);
}
}
;
// inherited from grammar JavaRecognizer
builtInTypeArraySpec[boolean addImagNode] :builtInType
(options{greedy=true;}: // match as many as possible
lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
)+
{
if ( addImagNode ) {
#builtInTypeArraySpec = #(#[TYPE,"TYPE"], #builtInTypeArraySpec);
}
}
;
// inherited from grammar JavaRecognizer
builtInTypeSpec[boolean addImagNode] :builtInType
(options{greedy=true;}: // match as many as possible
lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
)*
{
if ( addImagNode ) {
#builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
}
}
;
// inherited from grammar JavaRecognizer
type :classOrInterfaceType[false]
| builtInType
;
// inherited from grammar JavaRecognizer
identifier :IDENT ( DOT^ IDENT )*
;
// inherited from grammar JavaRecognizer
identifierStar :IDENT
( DOT^ IDENT )*
( DOT^ STAR )?
;
// inherited from grammar JavaRecognizer
modifiers :(
//hush warnings since the semantic check for "@interface" solves the non-determinism
options{generateAmbigWarnings=false;}:
modifier
|
//Semantic check that we aren't matching @interface as this is not an annotation
//A nicer way to do this would be nice
{LA(1)==AT && !LT(2).getText().equals("interface")}? annotation
)*
{#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
;
// inherited from grammar JavaRecognizer
modifier :"private"
| "public"
| "protected"
| "static"
| "transient"
| "final"
| "abstract"
| "native"
| "threadsafe"
| "synchronized"
| "volatile"
| "strictfp"
;
// inherited from grammar JavaRecognizer
annotation! :AT! i:identifier ( LPAREN! ( args:annotationArguments )? RPAREN! )?
{#annotation = #(#[ANNOTATION,"ANNOTATION"], i, args);}
;
// inherited from grammar JavaRecognizer
annotations :(annotation)*
{#annotations = #([ANNOTATIONS, "ANNOTATIONS"], #annotations);}
;
// inherited from grammar JavaRecognizer
annotationArguments :annotationMemberValueInitializer | anntotationMemberValuePairs
;
// inherited from grammar JavaRecognizer
anntotationMemberValuePairs :annotationMemberValuePair ( COMMA! annotationMemberValuePair )*
;
// inherited from grammar JavaRecognizer
annotationMemberValuePair! :i:IDENT ASSIGN! v:annotationMemberValueInitializer
{#annotationMemberValuePair = #(#[ANNOTATION_MEMBER_VALUE_PAIR,"ANNOTATION_MEMBER_VALUE_PAIR"], i, v);}
;
// inherited from grammar JavaRecognizer
annotationMemberValueInitializer :conditionalExpression | annotation | annotationMemberArrayInitializer
;
// inherited from grammar JavaRecognizer
annotationMemberArrayInitializer :lc:LCURLY^ {#lc.setType(ANNOTATION_ARRAY_INIT);}
( annotationMemberArrayValueInitializer
(
// CONFLICT: does a COMMA after an initializer start a new
// initializer or start the option ',' at end?
// ANTLR generates proper code by matching
// the comma as soon as possible.
options {
warnWhenFollowAmbig = false;
}
:
COMMA! annotationMemberArrayValueInitializer
)*
(COMMA!)?
)?
RCURLY!
;
// inherited from grammar JavaRecognizer
annotationMemberArrayValueInitializer :conditionalExpression
| annotation
;
// inherited from grammar JavaRecognizer
superClassClause! :( "extends" c:classOrInterfaceType[false] )?
{#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],c);}
;
// inherited from grammar JavaRecognizer
interfaceDefinition![AST modifiers] :"interface" IDENT
// it _might_ have type paramaters
(tp:typeParameters)?
// it might extend some other interfaces
ie:interfaceExtends
// now parse the body of the interface (looks like a class...)
ib:interfaceBlock
{#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
modifiers,IDENT,tp,ie,ib);}
;
// inherited from grammar JavaRecognizer
enumDefinition![AST modifiers] :"enum" IDENT
// it might implement some interfaces...
ic:implementsClause
// now parse the body of the enum
eb:enumBlock
{#enumDefinition = #(#[ENUM_DEF,"ENUM_DEF"],
modifiers,IDENT,ic,eb);}
;
// inherited from grammar JavaRecognizer
annotationDefinition![AST modifiers] :AT "interface" IDENT
// now parse the body of the annotation
ab:annotationBlock
{#annotationDefinition = #(#[ANNOTATION_DEF,"ANNOTATION_DEF"],
modifiers,IDENT,ab);}
;
// inherited from grammar JavaRecognizer
typeParameter :// I'm pretty sure Antlr generates the right thing here:
(id:IDENT) ( options{generateAmbigWarnings=false;}: typeParameterBounds )?
{#typeParameter = #(#[TYPE_PARAMETER,"TYPE_PARAMETER"], #typeParameter);}
;
// inherited from grammar JavaRecognizer
typeParameterBounds :"extends"! classOrInterfaceType[false]
(BAND! classOrInterfaceType[false])*
{#typeParameterBounds = #(#[TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS"], #typeParameterBounds);}
;
// inherited from grammar JavaRecognizer
classBlock :LCURLY!
( classField | SEMI! )*
RCURLY!
{#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
;
// inherited from grammar JavaRecognizer
interfaceBlock :LCURLY!
( interfaceField | SEMI! )*
RCURLY!
{#interfaceBlock = #([OBJBLOCK, "OBJBLOCK"], #interfaceBlock);}
;
// inherited from grammar JavaRecognizer
annotationBlock :LCURLY!
( annotationField | SEMI! )*
RCURLY!
{#annotationBlock = #([OBJBLOCK, "OBJBLOCK"], #annotationBlock);}
;
// inherited from grammar JavaRecognizer
enumBlock :LCURLY!
( enumConstant ( options{greedy=true;}: COMMA! enumConstant )* ( COMMA! )? )?
( SEMI! ( classField | SEMI! )* )?
RCURLY!
{#enumBlock = #([OBJBLOCK, "OBJBLOCK"], #enumBlock);}
;
// inherited from grammar JavaRecognizer
annotationField! :mods:modifiers
( td:typeDefinitionInternal[#mods]
{#annotationField = #td;}
| t:typeSpec[false] // annotation field
( i:IDENT // the name of the field
LPAREN! RPAREN!
rt:declaratorBrackets[#t]
( "default" amvi:annotationMemberValueInitializer )?
SEMI
{#annotationField =
#(#[ANNOTATION_FIELD_DEF,"ANNOTATION_FIELD_DEF"],
mods,
#(#[TYPE,"TYPE"],rt),
i,amvi
);}
| v:variableDefinitions[#mods,#t] SEMI // variable
{#annotationField = #v;}
)
)
;
// inherited from grammar JavaRecognizer
enumConstant! :an:annotations
i:IDENT
( LPAREN!
a:argList
RPAREN!
)?
( b:enumConstantBlock )?
{#enumConstant = #([ENUM_CONSTANT_DEF, "ENUM_CONSTANT_DEF"], an, i, a, b);}
;
// inherited from grammar JavaRecognizer
enumConstantBlock :LCURLY!
( enumConstantField | SEMI! )*
RCURLY!
{#enumConstantBlock = #([OBJBLOCK, "OBJBLOCK"], #enumConstantBlock);}
;
// inherited from grammar JavaRecognizer
enumConstantField! :mods:modifiers
( td:typeDefinitionInternal[#mods]
{#enumConstantField = #td;}
| // A generic method has the typeParameters before the return type.
// This is not allowed for variable definitions, but this production
// allows it, a semantic check could be used if you wanted.
(tp:typeParameters)? t:typeSpec[false] // method or variable declaration(s)
( IDENT // the name of the method
// parse the formal parameter declarations.
LPAREN! param:parameterDeclarationList RPAREN!
rt:declaratorBrackets[#t]
// get the list of exceptions that this method is
// declared to throw
(tc:throwsClause)?
( s2:compoundStatement | SEMI )
{#enumConstantField = #(#[METHOD_DEF,"METHOD_DEF"],
mods,
tp,
#(#[TYPE,"TYPE"],rt),
IDENT,
param,
tc,
s2);}
| v:variableDefinitions[#mods,#t] SEMI
{#enumConstantField = #v;}
)
)
// "{ ... }" instance initializer
| s4:compoundStatement
{#enumConstantField = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
;
// inherited from grammar JavaRecognizer
interfaceExtends :(
e:"extends"!
classOrInterfaceType[false] ( COMMA! classOrInterfaceType[false] )*
)?
{#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
#interfaceExtends);}
;
// inherited from grammar JavaRecognizer
implementsClause :(
i:"implements"! classOrInterfaceType[false] ( COMMA! classOrInterfaceType[false] )*
)?
{#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
#implementsClause);}
;
// inherited from grammar JavaRecognizer
classField! :// method, constructor, or variable declaration
mods:modifiers
( td:typeDefinitionInternal[#mods]
{#classField = #td;}
| (tp:typeParameters)?
(
h:ctorHead s:constructorBody // constructor
{#classField = #(#[CTOR_DEF,"CTOR_DEF"], mods, tp, h, s);}
| // A generic method/ctor has the typeParameters before the return type.
// This is not allowed for variable definitions, but this production
// allows it, a semantic check could be used if you wanted.
t:typeSpec[false] // method or variable declaration(s)
( IDENT // the name of the method
// parse the formal parameter declarations.
LPAREN! param:parameterDeclarationList RPAREN!
rt:declaratorBrackets[#t]
// get the list of exceptions that this method is
// declared to throw
(tc:throwsClause)?
( s2:compoundStatement | SEMI )
{#classField = #(#[METHOD_DEF,"METHOD_DEF"],
mods,
tp,
#(#[TYPE,"TYPE"],rt),
IDENT,
param,
tc,
s2);}
| v:variableDefinitions[#mods,#t] SEMI
{#classField = #v;}
)
)
)
// "static { ... }" class initializer
| "static" s3:compoundStatement
{#classField = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
// "{ ... }" instance initializer
| s4:compoundStatement
{#classField = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
;
// inherited from grammar JavaRecognizer
interfaceField! :// method, constructor, or variable declaration
mods:modifiers
( td:typeDefinitionInternal[#mods]
{#interfaceField = #td;}
| (tp:typeParameters)?
// A generic method has the typeParameters before the return type.
// This is not allowed for variable definitions, but this production
// allows it, a semantic check could be used if you want a more strict
// grammar.
t:typeSpec[false] // method or variable declaration(s)
( IDENT // the name of the method
// parse the formal parameter declarations.
LPAREN! param:parameterDeclarationList RPAREN!
rt:declaratorBrackets[#t]
// get the list of exceptions that this method is
// declared to throw
(tc:throwsClause)?
SEMI
{#interfaceField = #(#[METHOD_DEF,"METHOD_DEF"],
mods,
tp,
#(#[TYPE,"TYPE"],rt),
IDENT,
param,
tc);}
| v:variableDefinitions[#mods,#t] SEMI
{#interfaceField = #v;}
)
)
;
// inherited from grammar JavaRecognizer
constructorBody :lc:LCURLY^ {#lc.setType(SLIST);}
( options { greedy=true; } : explicitConstructorInvocation)?
(statement)*
RCURLY!
;
// inherited from grammar JavaRecognizer
declaratorBrackets[AST typ] :{#declaratorBrackets=typ;}
(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
;
// inherited from grammar JavaRecognizer
varInitializer :( ASSIGN^ initializer )?
;
// inherited from grammar JavaRecognizer
arrayInitializer :lc:LCURLY^ {#lc.setType(ARRAY_INIT);}
( initializer
(
// CONFLICT: does a COMMA after an initializer start a new
// initializer or start the option ',' at end?
// ANTLR generates proper code by matching
// the comma as soon as possible.
options {
warnWhenFollowAmbig = false;
}
:
COMMA! initializer
)*
(COMMA!)?
)?
RCURLY!
;
// inherited from grammar JavaRecognizer
initializer :expression
| arrayInitializer
;
// inherited from grammar JavaRecognizer
ctorHead :IDENT // the name of the method
// parse the formal parameter declarations.
LPAREN! parameterDeclarationList RPAREN!
// get the list of exceptions that this method is declared to throw
(throwsClause)?
;
// inherited from grammar JavaRecognizer
throwsClause :"throws"^ identifier ( COMMA! identifier )*
;
// inherited from grammar JavaRecognizer
parameterDeclarationList :( ( parameterDeclaration )=> parameterDeclaration
( options {warnWhenFollowAmbig=false;} : ( COMMA! parameterDeclaration ) => COMMA! parameterDeclaration )*
( COMMA! variableLengthParameterDeclaration )?
|
variableLengthParameterDeclaration
)?
{#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
#parameterDeclarationList);}
;
// inherited from grammar JavaRecognizer
parameterDeclaration! :pm:parameterModifier t:typeSpec[false] id:IDENT
pd:declaratorBrackets[#t]
{#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
pm, #([TYPE,"TYPE"],pd), id);}
;
// inherited from grammar JavaRecognizer
variableLengthParameterDeclaration! :pm:parameterModifier t:typeSpec[false] TRIPLE_DOT! id:IDENT
pd:declaratorBrackets[#t]
{#variableLengthParameterDeclaration = #(#[VARIABLE_PARAMETER_DEF,"VARIABLE_PARAMETER_DEF"],
pm, #([TYPE,"TYPE"],pd), id);}
;
// inherited from grammar JavaRecognizer
parameterModifier :(options{greedy=true;} : annotation)* (f:"final")? (annotation)*
{#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], #parameterModifier);}
;
// inherited from grammar JavaRecognizer
compoundStatement :lc:LCURLY^ {#lc.setType(SLIST);}
// include the (possibly-empty) list of statements
(statement)*
RCURLY!
;
// inherited from grammar JavaRecognizer
statement :compoundStatement
// declarations are ambiguous with "ID DOT" relative to expression
// statements. Must backtrack to be sure. Could use a semantic
// predicate to test symbol table to see what the type was coming
// up, but that's pretty hard without a symbol table ;)
| (declaration)=> declaration SEMI!
// An expression statement. This could be a method call,
// assignment statement, or any other expression evaluated for
// side-effects.
| expression SEMI!
//TODO: what abour interfaces, enums and annotations
// class definition
| m:modifiers! classDefinition[#m]
// Attach a label to the front of a statement
| IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
// If-else statement
| "if"^ LPAREN! expression RPAREN! statement
(
// CONFLICT: the old "dangling-else" problem...
// ANTLR generates proper code matching
// as soon as possible. Hush warning.
options {
warnWhenFollowAmbig = false;
}
:
"else"! statement
)?
// For statement
| forStatement
// While statement
| "while"^ LPAREN! expression RPAREN! statement
// do-while statement
| "do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
// get out of a loop (or switch)
| "break"^ (IDENT)? SEMI!
// do next iteration of a loop
| "continue"^ (IDENT)? SEMI!
// Return an expression
| "return"^ (expression)? SEMI!
// switch/case statement
| "switch"^ LPAREN! expression RPAREN! LCURLY!
( casesGroup )*
RCURLY!
// exception try-catch block
| tryBlock
// throw an exception
| "throw"^ expression SEMI!
// synchronize a statement
| "synchronized"^ LPAREN! expression RPAREN! compoundStatement
// asserts (uncomment if you want 1.4 compatibility)
| "assert"^ expression ( COLON! expression )? SEMI!
// empty statement
| s:SEMI {#s.setType(EMPTY_STAT);}
;
// inherited from grammar JavaRecognizer
forStatement :f:"for"^
LPAREN!
( (forInit SEMI)=>traditionalForClause
| forEachClause
)
RPAREN!
statement // statement to loop over
;
// inherited from grammar JavaRecognizer
traditionalForClause :forInit SEMI! // initializer
forCond SEMI! // condition test
forIter // updater
;
// inherited from grammar JavaRecognizer
forEachClause :p:parameterDeclaration COLON! expression
{#forEachClause = #(#[FOR_EACH_CLAUSE,"FOR_EACH_CLAUSE"], #forEachClause);}
;
// inherited from grammar JavaRecognizer
casesGroup :( // CONFLICT: to which case group do the statements bind?
// ANTLR generates proper code: it groups the
// many "case"/"default" labels together then
// follows them with the statements
options {
greedy = true;
}
:
aCase
)+
caseSList
{#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
;
// inherited from grammar JavaRecognizer
aCase :("case"^ expression | "default") COLON!
;
// inherited from grammar JavaRecognizer
caseSList :(statement)*
{#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
;
// inherited from grammar JavaRecognizer
forInit :((declaration)=> declaration
// otherwise it could be an expression list...
| expressionList
)?
{#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
;
// inherited from grammar JavaRecognizer
forCond :(expression)?
{#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
;
// inherited from grammar JavaRecognizer
forIter :(expressionList)?
{#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
;
// inherited from grammar JavaRecognizer
tryBlock :"try"^ compoundStatement
(handler)*
( finallyClause )?
;
// inherited from grammar JavaRecognizer
finallyClause :"finally"^ compoundStatement
;
// inherited from grammar JavaRecognizer
handler :"catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
;
// inherited from grammar JavaRecognizer
expression :assignmentExpression
{#expression = #(#[EXPR,"EXPR"],#expression);}
;
// inherited from grammar JavaRecognizer
expressionList :expression (COMMA! expression)*
{#expressionList = #(#[ELIST,"ELIST"], expressionList);}
;
// inherited from grammar JavaRecognizer
assignmentExpression :conditionalExpression
( ( ASSIGN^
| PLUS_ASSIGN^
| MINUS_ASSIGN^
| STAR_ASSIGN^
| DIV_ASSIGN^
| MOD_ASSIGN^
| SR_ASSIGN^
| BSR_ASSIGN^
| SL_ASSIGN^
| BAND_ASSIGN^
| BXOR_ASSIGN^
| BOR_ASSIGN^
)
assignmentExpression
)?
;
// inherited from grammar JavaRecognizer
conditionalExpression :logicalOrExpression
( QUESTION^ assignmentExpression COLON! conditionalExpression )?
;
// inherited from grammar JavaRecognizer
logicalOrExpression :logicalAndExpression (LOR^ logicalAndExpression)*
;
// inherited from grammar JavaRecognizer
logicalAndExpression :inclusiveOrExpression (LAND^ inclusiveOrExpression)*
;
// inherited from grammar JavaRecognizer
inclusiveOrExpression :exclusiveOrExpression (BOR^ exclusiveOrExpression)*
;
// inherited from grammar JavaRecognizer
exclusiveOrExpression :andExpression (BXOR^ andExpression)*
;
// inherited from grammar JavaRecognizer
andExpression :equalityExpression (BAND^ equalityExpression)*
;
// inherited from grammar JavaRecognizer
equalityExpression :relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
;
// inherited from grammar JavaRecognizer
relationalExpression :shiftExpression
( ( ( LT^
| GT^
| LE^
| GE^
)
shiftExpression
)*
| "instanceof"^ typeSpec[true]
)
;
// inherited from grammar JavaRecognizer
shiftExpression :additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
;
// inherited from grammar JavaRecognizer
additiveExpression :multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
;
// inherited from grammar JavaRecognizer
multiplicativeExpression :unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
;
// inherited from grammar JavaRecognizer
unaryExpression :INC^ unaryExpression
| DEC^ unaryExpression
| MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
| PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
| unaryExpressionNotPlusMinus
;
// inherited from grammar JavaRecognizer
unaryExpressionNotPlusMinus :BNOT^ unaryExpression
| LNOT^ unaryExpression
| ( // subrule allows option to shut off warnings
options {
// "(int" ambig with postfixExpr due to lack of sequence
// info in linear approximate LL(k). It's ok. Shut up.
generateAmbigWarnings=false;
}
: // If typecast is built in type, must be numeric operand
// Have to backtrack to see if operator follows
(LPAREN builtInTypeSpec[true] RPAREN unaryExpression)=>
lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
unaryExpression
// Have to backtrack to see if operator follows. If no operator
// follows, it's a typecast. No semantic checking needed to parse.
// if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
| (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
unaryExpressionNotPlusMinus
| postfixExpression
)
;
// inherited from grammar JavaRecognizer
postfixExpression :primaryExpression
(
/*
options {
// the use of postfixExpression in SUPER_CTOR_CALL adds DOT
// to the lookahead set, and gives loads of false non-det
// warnings.
// shut them off.
generateAmbigWarnings=false;
}
: */
//type arguments are only appropriate for a parameterized method/ctor invocations
//semantic check may be needed here to ensure that this is the case
DOT^ (typeArguments)?
( IDENT
( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
argList
RPAREN!
)?
| "super"
( // (new Outer()).super() (create enclosing instance)
lp3:LPAREN^ argList RPAREN!
{#lp3.setType(SUPER_CTOR_CALL);}
| DOT^ (typeArguments)? IDENT
( lps:LPAREN^ {#lps.setType(METHOD_CALL);}
argList
RPAREN!
)?
)
)
| DOT^ "this"
| DOT^ newExpression
| lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
)*
( // possibly add on a post-increment or post-decrement.
// allows INC/DEC on too much, but semantics can check
in:INC^ {#in.setType(POST_INC);}
| de:DEC^ {#de.setType(POST_DEC);}
)?
;
// inherited from grammar JavaRecognizer
identPrimary :(ta1:typeArguments!)?
IDENT
// Syntax for method invocation with type arguments is
// <String>foo("blah")
(
options {
// .ident could match here or in postfixExpression.
// We do want to match here. Turn off warning.
greedy=true;
// This turns the ambiguity warning of the second alternative
// off. See below. (The "false" predicate makes it non-issue)
warnWhenFollowAmbig=false;
}
// we have a new nondeterminism because of
// typeArguments... only a syntactic predicate will help...
// The problem is that this loop here conflicts with
// DOT typeArguments "super" in postfixExpression (k=2)
// A proper solution would require a lot of refactoring...
: (DOT (typeArguments)? IDENT) =>
DOT^ (ta2:typeArguments!)? IDENT
| {false}? // FIXME: this is very ugly but it seems to work...
// this will also produce an ANTLR warning!
// Unfortunately a syntactic predicate can only select one of
// multiple alternatives on the same level, not break out of
// an enclosing loop, which is why this ugly hack (a fake
// empty alternative with always-false semantic predicate)
// is necessary.
)*
(
options {
// ARRAY_DECLARATOR here conflicts with INDEX_OP in
// postfixExpression on LBRACK RBRACK.
// We want to match [] here, so greedy. This overcomes
// limitation of linear approximate lookahead.
greedy=true;
}
: ( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
// if the input is valid, only the last IDENT may
// have preceding typeArguments... rather hacky, this is...
{if (#ta2 != null) astFactory.addASTChild(currentAST, #ta2);}
{if (#ta2 == null) astFactory.addASTChild(currentAST, #ta1);}
argList RPAREN!
)
| ( options {greedy=true;} :
lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
)+
)?
;
// inherited from grammar JavaRecognizer
newExpression :"new"^ (typeArguments)? type
( LPAREN! argList RPAREN! (classBlock)?
//java 1.1
// Note: This will allow bad constructs like
// new int[4][][3] {exp,exp}.
// There needs to be a semantic check here...
// to make sure:
// a) [ expr ] and [ ] are not mixed
// b) [ expr ] and an init are not used together
| newArrayDeclarator (arrayInitializer)?
)
;
// inherited from grammar JavaRecognizer
argList :( expressionList
| /*nothing*/
{#argList = #[ELIST,"ELIST"];}
)
;
// inherited from grammar JavaRecognizer
newArrayDeclarator :(
// CONFLICT:
// newExpression is a primaryExpression which can be
// followed by an array index reference. This is ok,
// as the generated code will stay in this loop as
// long as it sees an LBRACK (proper behavior)
options {
warnWhenFollowAmbig = false;
}
:
lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
(expression)?
RBRACK!
)+
;
class PdeLexer extends Lexer;
options {
importVocab=PdePartial;
exportVocab=Pde;
testLiterals=false;
k=4;
charVocabulary='\u0003'..'\uFFFF';
codeGenBitsetTestThreshold=20;
}
{
/** flag for enabling the "assert" keyword */
private boolean assertEnabled = true;
/** flag for enabling the "enum" keyword */
private boolean enumEnabled = true;
/** Enable the "assert" keyword */
public void enableAssert(boolean shouldEnable) { assertEnabled = shouldEnable; }
/** Query the "assert" keyword state */
public boolean isAssertEnabled() { return assertEnabled; }
/** Enable the "enum" keyword */
public void enableEnum(boolean shouldEnable) { enumEnabled = shouldEnable; }
/** Query the "enum" keyword state */
public boolean isEnumEnabled() { return enumEnabled; }
}
WS :( ' '
| '\t'
| '\f'
// handle newlines
| ( options {generateAmbigWarnings=false;}
: "\r\n" // Evil DOS
| '\r' // Macintosh
| '\n' // Unix (the right way)
)
{ newline(); }
)+
;
SL_COMMENT :"//"
(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
{newline();}
;
ML_COMMENT :"/*"
( /* '\r' '\n' can be matched in one alternative or by matching
'\r' in one iteration and '\n' in another. I am trying to
handle any flavor of newline that comes in, but the language
that allows both "\r\n" and "\r" and "\n" to all be valid
newline is ambiguous. Consequently, the resulting grammar
must be ambiguous. I'm shutting this warning off.
*/
options {
generateAmbigWarnings=false;
}
:
{ LA(2)!='/' }? '*'
| '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
| ~('*'|'\n'|'\r')
)*
"*/"
;
WEBCOLOR_LITERAL :'#'! (HEX_DIGIT)+
;
// inherited from grammar JavaLexer
QUESTION :'?' ;
// inherited from grammar JavaLexer
LPAREN :'(' ;
// inherited from grammar JavaLexer
RPAREN :')' ;
// inherited from grammar JavaLexer
LBRACK :'[' ;
// inherited from grammar JavaLexer
RBRACK :']' ;
// inherited from grammar JavaLexer
LCURLY :'{' ;
// inherited from grammar JavaLexer
RCURLY :'}' ;
// inherited from grammar JavaLexer
COLON :':' ;
// inherited from grammar JavaLexer
COMMA :',' ;
// inherited from grammar JavaLexer
ASSIGN :'=' ;
// inherited from grammar JavaLexer
EQUAL :"==" ;
// inherited from grammar JavaLexer
LNOT :'!' ;
// inherited from grammar JavaLexer
BNOT :'~' ;
// inherited from grammar JavaLexer
NOT_EQUAL :"!=" ;
// inherited from grammar JavaLexer
DIV :'/' ;
// inherited from grammar JavaLexer
DIV_ASSIGN :"/=" ;
// inherited from grammar JavaLexer
PLUS :'+' ;
// inherited from grammar JavaLexer
PLUS_ASSIGN :"+=" ;
// inherited from grammar JavaLexer
INC :"++" ;
// inherited from grammar JavaLexer
MINUS :'-' ;
// inherited from grammar JavaLexer
MINUS_ASSIGN :"-=" ;
// inherited from grammar JavaLexer
DEC :"--" ;
// inherited from grammar JavaLexer
STAR :'*' ;
// inherited from grammar JavaLexer
STAR_ASSIGN :"*=" ;
// inherited from grammar JavaLexer
MOD :'%' ;
// inherited from grammar JavaLexer
MOD_ASSIGN :"%=" ;
// inherited from grammar JavaLexer
SR :">>" ;
// inherited from grammar JavaLexer
SR_ASSIGN :">>=" ;
// inherited from grammar JavaLexer
BSR :">>>" ;
// inherited from grammar JavaLexer
BSR_ASSIGN :">>>=" ;
// inherited from grammar JavaLexer
GE :">=" ;
// inherited from grammar JavaLexer
GT :">" ;
// inherited from grammar JavaLexer
SL :"<<" ;
// inherited from grammar JavaLexer
SL_ASSIGN :"<<=" ;
// inherited from grammar JavaLexer
LE :"<=" ;
// inherited from grammar JavaLexer
LT :'<' ;
// inherited from grammar JavaLexer
BXOR :'^' ;
// inherited from grammar JavaLexer
BXOR_ASSIGN :"^=" ;
// inherited from grammar JavaLexer
BOR :'|' ;
// inherited from grammar JavaLexer
BOR_ASSIGN :"|=" ;
// inherited from grammar JavaLexer
LOR :"||" ;
// inherited from grammar JavaLexer
BAND :'&' ;
// inherited from grammar JavaLexer
BAND_ASSIGN :"&=" ;
// inherited from grammar JavaLexer
LAND :"&&" ;
// inherited from grammar JavaLexer
SEMI :';' ;
// inherited from grammar JavaLexer
CHAR_LITERAL :'\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
;
// inherited from grammar JavaLexer
STRING_LITERAL :'"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
;
// inherited from grammar JavaLexer
protected ESC :'\\'
( 'n'
| 'r'
| 't'
| 'b'
| 'f'
| '"'
| '\''
| '\\'
| ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
| '0'..'3'
(
options {
warnWhenFollowAmbig = false;
}
: '0'..'7'
(
options {
warnWhenFollowAmbig = false;
}
: '0'..'7'
)?
)?
| '4'..'7'
(
options {
warnWhenFollowAmbig = false;
}
: '0'..'7'
)?
)
;
// inherited from grammar JavaLexer
protected HEX_DIGIT :('0'..'9'|'A'..'F'|'a'..'f')
;
// inherited from grammar JavaLexer
protected VOCAB :'\3'..'\377'
;
// inherited from grammar JavaLexer
IDENT
options {
testLiterals=true;
}
:('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
{
// check if "assert" keyword is enabled
if (assertEnabled && "assert".equals($getText)) {
$setType(LITERAL_assert); // set token type for the rule in the parser
}
// check if "enum" keyword is enabled
if (enumEnabled && "enum".equals($getText)) {
$setType(LITERAL_enum); // set token type for the rule in the parser
}
}
;
// inherited from grammar JavaLexer
NUM_INT {boolean isDecimal=false; Token t=null;}
:'.' {_ttype = DOT;}
(
(('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
{
if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
_ttype = NUM_FLOAT;
}
else {
_ttype = NUM_DOUBLE; // assume double
}
})
|
// JDK 1.5 token for variable length arguments
(".." {_ttype = TRIPLE_DOT;})
)?
| ( '0' {isDecimal = true;} // special case for just '0'
( ('x'|'X')
( // hex
// the 'e'|'E' and float suffix stuff look
// like hex digits, hence the (...)+ doesn't
// know when to stop: ambig. ANTLR resolves
// it correctly by matching immediately. It
// is therefor ok to hush warning.
options {
warnWhenFollowAmbig=false;
}
: HEX_DIGIT
)+
| //float or double with leading zero
(('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
| ('0'..'7')+ // octal
)?
| ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
)
( ('l'|'L') { _ttype = NUM_LONG; }
// only check to see if it's a float if looks like decimal so far
| {isDecimal}?
( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
| EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
| f4:FLOAT_SUFFIX {t=f4;}
)
{
if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
_ttype = NUM_FLOAT;
}
else {
_ttype = NUM_DOUBLE; // assume double
}
}
)?
;
// inherited from grammar JavaLexer
AT :'@'
;
// inherited from grammar JavaLexer
protected EXPONENT :('e'|'E') ('+'|'-')? ('0'..'9')+
;
// inherited from grammar JavaLexer
protected FLOAT_SUFFIX :'f'|'F'|'d'|'D'
;