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("]");} )
        ;