This is an ANTLR “Tree Grammar” – a specification which will
Be used to generate code that will walk an AST and print it out
As well-formated Java code.
Key:
ANTLR syntax in blue.
Java syntax that requires knowledge of ANTLR in purple.
Vanilla Java code in red.
header {package templates;
import com.jguru.util.st.*;
}
/** Java 1.3 AST Recognizer Grammar
*
* Author: (see java.g preamble)
*
* This grammar is in the PUBLIC DOMAIN
*
* DIFFS FROM STANDARD ANTLR-JAVA GRAMMAR:
oooo in primaryExpression I fixed array_declarator:
| #(ARRAY_DECLARATOR typeSpecArray) "class" {out("class");} | builtInType "class" {out("class");}
removed optionals on class for those, had to add class to first one.
oooo Changed newArrayDeclarator(s); fixed comment on newExpression
newExpression
: #( "new" {out("new ");} type ( {out("(");} elist {out(")");} (objBlock)? | (newArrayDeclarator)+ (arrayInitializer)?
)
)
;
newArrayDeclarator
: #( ARRAY_DECLARATOR (expression)? )
;
oooo moved ctorCall to stat; didn't belong in expr.
oooo rm comments in java.g postfixExpression
*/
class JavaOutputTreeParser extends TreeParser;
options { importVocab = Java;
}
{ /** A big buffer to store output. A single
* output buffer works because the order of
* rule calls mirrors the order in which we want
* to generate output for Java->Java.
*/
protected StringBuffer output = null;
/** Tab indent level 0..n */
protected int tabs = 0;
/** Track when do a newline; implies indent should happen next. */
protected boolean lastOutputWasNewline = true;
protected static final int MAX_TOKEN_TYPE=300; // imprecise but big enough
/** Encodes precedence of various operators; indexed by token type.
* If precedence[op1] > precedence[op2] then op1 should happen
* before op2;
*/
public static int precedence[] = new int[MAX_TOKEN_TYPE];
static { for (int i=0; iprecedence[op2];
}
protected void out(String text) { if ( lastOutputWasNewline ) { tab();
}
lastOutputWasNewline = false;
output.append(text);
}
/** Indent to correct tab position */
protected void tab() { for (int i=1; i<=tabs; i++) { output.append('\t'); }
}
/** Indent one level */
protected void indent() { tabs++;
}
/** Indent out one level */
protected void undent() { tabs--;
}
protected void nl() { output.append('\n'); lastOutputWasNewline = true;
}
public JavaOutputTreeParser(StringBuffer output) { this();
this.output = output;
}
}
compilationUnit
: (packageDefinition)?
(importDefinition)*
(typeDefinition)*
;
packageDefinition
: #( PACKAGE_DEF {out("package ");} identifier ) {out(";"); nl();} ;
importDefinition
: #( IMPORT {out("import ");} identifierStar ) {out(";"); nl();} ;
typeDefinition
: #(CLASS_DEF modifiers {out("class ");} cid:IDENT {out(cid.getText()+" ");} extendsClause implementsClause
{out(" {"); nl(); indent();} objBlock
{undent(); out("}"); nl();} )
| #(INTERFACE_DEF modifiers {out("interface ");} iid:IDENT {out(iid.getText()+" ");} extendsClause
{out(" {"); nl(); indent();} interfaceBlock
{undent(); out("}"); nl();} )
;
typeSpec
: #(TYPE typeSpecArray)
;
typeSpecArray
: #( ARRAY_DECLARATOR typeSpecArray {out("[]");} ) | type
;
type: identifier {out(" ");} | builtInType
;
builtInType
{out(#builtInType.getText()+" ");} : "void"
| "boolean"
| "byte"
| "char"
| "short"
| "int"
| "float"
| "long"
| "double"
;
modifiers
: #( MODIFIERS (modifier)* )
;
modifier
{out(#modifier.getText()+" ");} : "private"
| "public"
| "protected"
| "static"
| "transient"
| "final"
| "abstract"
| "native"
| "threadsafe"
| "synchronized"
| "const"
| "volatile"
| "strictfp"
;
extendsClause
: #( EXTENDS_CLAUSE
{if (#extendsClause.getFirstChild()!=null) out("extends ");} ( id:identifier {if (id.getNextSibling()!=null) out(", ");} )* )
;
implementsClause
: #( IMPLEMENTS_CLAUSE
{if (#implementsClause.getFirstChild()!=null) out(" implements ");} (id:identifier {if (id.getNextSibling()!=null) out(", ");} )* )
;
interfaceBlock
: #( OBJBLOCK
( methodDecl
| variableDef
)*
)
;
objBlock
: #( OBJBLOCK
( ctorDef
| methodDef
| variableDef
| typeDefinition
| #(STATIC_INIT {out("static ");} slist) | #(INSTANCE_INIT slist)
)*
)
;
ctorDef
: #(CTOR_DEF modifiers methodHead (slist)?)
;
methodDecl
: #(METHOD_DEF modifiers typeSpec methodHead)
;
methodDef
: #(METHOD_DEF modifiers typeSpec methodHead (slist)?)
;
variableDef
: #(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
{out(";"); nl();} ;
parameterDef
: #(PARAMETER_DEF modifiers typeSpec id:IDENT {out(" "+#id.getText());} ) ;
objectinitializer
: #(INSTANCE_INIT slist)
;
variableDeclarator
: id:IDENT {out(" "+id.getText());} | LBRACK variableDeclarator {out("[]");} ;
varInitializer
: #(ASSIGN {out(" = ");} initializer) |
;
initializer
: expression
| arrayInitializer
;
arrayInitializer
: #( ARRAY_INIT
{out("{"); nl(); indent();} ( init:initializer
{if (init.getNextSibling()!=null) out(", ");} )*
{undent(); nl(); out("}");} )
;
methodHead
: id:IDENT {out(" "+id.getText()+"(");} #( PARAMETERS
( p:parameterDef
{if (#p.getNextSibling()!=null) out(",");} )*
)
{out(") ");} (throwsClause)?
;
throwsClause
: #( "throws" {out("throws ");} ( id:identifier
{if (id.getNextSibling()!=null) out(", ");} )*
)
;
identifier
: id:IDENT {out(id.getText());} | #( DOT identifier id2:IDENT ) {out("."+id2.getText());} ;
identifierStar
: id:IDENT {out(id.getText());} | #( DOT identifier
( id2:IDENT {out("."+id2.getText());} | STAR {out(".*");} )
)
;
slist
: #( SLIST
{out("{"); nl(); indent();} (stat)*
{undent(); out("}"); nl();} )
;
stat: typeDefinition
| variableDef
| expression {out(";"); nl();} | #(LABELED_STAT id:IDENT {out(id.getText()+":"); nl();} stat) | #("if" {out("if (");} expression {out(") ");} stat ( {out("else ");} stat)? ) | #( "for" {out("for (");} #(FOR_INIT (variableDef | elist | {out(";");})) #(FOR_CONDITION (expression)?)
{out(";");} #(FOR_ITERATOR (elist)?)
{out(") ");} stat
)
| #("while" {out("while (");} expression {out(") ");} stat) | #("do" {out("do ");} stat {out(" while (");} expression {out(");"); nl();} ) | #("break" {out("break ");} (bid:IDENT {out(#bid.getText());} )? )
{out(";"); nl();} | #("continue" {out("continue ");} (cid:IDENT {out(#cid.getText());} )? )
{out(";"); nl();} | #("return" {out("return ");} (expression)? ) {out(";"); nl();} | #("switch" {out("switch (");} expression {out(") {"); nl(); indent();} (caseGroup)*
{undent(); out("}"); nl();} )
| #("throw" {out("throw ");} expression) {out(";"); nl();} | #("synchronized" {out("synchronized (");} expression {out(") ");} stat) | tryBlock
| slist // nested SLIST
// uncomment to make assert JDK 1.4 stuff work
// | #("assert" expression (expression)?)
| ctorCall {out(";"); nl();}
| EMPTY_STAT {out(";");} ;
caseGroup
: #( CASE_GROUP
( #("case" {out("case ");} expression {out(" :"); nl();}) | "default" {out("default :"); nl();} )+
slist
)
;
tryBlock
: #( "try" {out("try ");} slist (handler)*
( #("finally" {out("finally ");} slist) )? )
;
handler
: #( "catch" {out("catch (");} parameterDef {out(") ");} slist ) ;
elist
: #( ELIST (e:expression {if (#e.getNextSibling()!=null) out(",");} )* ) ;
expression
: #(EXPR expr)
;
expr: #(QUESTION expr {out("?");} expr {out(":");} expr) // trinary operator // binary operators...
| (ASSIGN|PLUS_ASSIGN|MINUS_ASSIGN|STAR_ASSIGN|DIV_ASSIGN
|MOD_ASSIGN|SR_ASSIGN|BSR_ASSIGN|SL_ASSIGN|BAND_ASSIGN
|BXOR_ASSIGN|BOR_ASSIGN|LOR|LAND|BOR|BXOR|BAND|NOT_EQUAL
|EQUAL|LT|GT|LE|GE|SL|SR|BSR|PLUS|MINUS|DIV|MOD|STAR|INSTANCEOF
)
{ AST op = #expr;
AST left = op.getFirstChild();
AST right = left.getNextSibling();
boolean lp = false;
boolean rp = false;
if ( hasHigherPrecedence(op.getType(),left.getType()) ) { lp = true;
}
if ( hasHigherPrecedence(op.getType(),right.getType()) ) { rp = true;
}
if ( lp ) out("("); expr(left);
if ( lp ) out(")"); if ( op.getType()==INSTANCEOF ) { out(" "+#op.getText()+" "); }
else { out(#op.getText());
}
if ( rp ) out("("); expr(right); // manually invoke
if ( rp ) out(")"); }
| (INC|DEC|BNOT|LNOT|UNARY_MINUS|UNARY_PLUS)
{ AST op = #expr;
AST opnd = op.getFirstChild();
boolean p = false;
if ( hasHigherPrecedence(op.getType(),opnd.getType()) ) { p = true;
}
out(op.getText());
if ( p ) out("("); expr(opnd);
if ( p ) out(")"); }
| #( POST_INC expr {out("++");} ) | #( POST_DEC expr {out("--");} ) | primaryExpression
;
primaryExpression
: id:IDENT {out(id.getText());} | #( DOT
( expr {out(".");} ( id2:IDENT {out(id2.getText());} | arrayIndex
| "this" {out("this");} | "class" {out("class");} | #( "new" id3:IDENT {out("new "+id3.getText());} elist ) | "super" {out("super");} )
| #(ARRAY_DECLARATOR typeSpecArray) "class" {out("class");} | builtInType "class" {out("class");} )
)
| arrayIndex
| #(METHOD_CALL primaryExpression {out("(");} elist {out(")");} ) | #(TYPECAST {out("((");} typeSpec {out(")");} expr {out(")");} ) | newExpression
| constant
| ("super"|"true"|"false"|"this"|"null") {out(#primaryExpression.getText());} | typeSpec // type name used with instanceof
;
ctorCall
: #( CTOR_CALL {out("this(");} elist {out(")");} ) | #( SUPER_CTOR_CALL {out("super(");} ( elist
| primaryExpression {out(".");} elist )
{out(")");} )
;
arrayIndex
: #(INDEX_OP expr {out("[");} expression {out("]");} ) ;
constant
{out(#constant.getText());} : NUM_INT
| CHAR_LITERAL
| STRING_LITERAL
| NUM_FLOAT
| NUM_DOUBLE
| NUM_LONG
;
newExpression
: #( "new" {out("new ");} type ( {out("(");} elist {out(")");} (
{out(" {"); nl(); indent();} objBlock
{undent(); out("}"); nl();} )?
| (newArrayDeclarator)+ (arrayInitializer)?
)
)
;
newArrayDeclarator
: #( ARRAY_DECLARATOR {out("[");} (expression)? {out("]");} ) ;