JavaCC Grammar -- JavaCCtoHTML

Produced by JavaCCtoHTML program

options {
  JAVA_UNICODE_ESCAPE = true;
  STATIC = false;
}

PARSER_BEGIN(JavaCCtoHTML)

import java.io.*;

public class JavaCCtoHTML {


    private final int JAVA_FILE = 0;
    private final int JAVACC_FILE = 1;
    private final int OTHER_FILE = 2;
    private int fileType;

    private String fileName;

    public static void process(String file)
    {


        Token tokenList = null;
        JavaCCtoHTML parser = null;
        InputStream in = null;

        try
        {
            in = (file == null ? System.in : new FileInputStream(file));

            parser = new JavaCCtoHTML(in);

            if (file == null)
            {
                parser.fileType = parser.OTHER_FILE;
                parser.fileName = "stdin";
            }
            else
            {
                parser.fileName = file;
                String fileLcase = file.toLowerCase();

                if (fileLcase.endsWith(".java"))
                    parser.fileType = parser.JAVA_FILE;
                else if (fileLcase.endsWith(".jj") || fileLcase.endsWith(".jjt"))
                    parser.fileType = parser.JAVACC_FILE;
                else
                    parser.fileType = parser.OTHER_FILE;
            }

            switch (parser.fileType)
            {
                case parser.JAVA_FILE:
                    tokenList = parser.JavaCompilationUnit();
                    break;

                case parser.JAVACC_FILE:
                     tokenList = parser.javacc_input();
                    break;

                case parser.OTHER_FILE:
                    tokenList = parser.readTokens();
                    break;

            }
        }
        catch(ParseException e)
        {
            // TODO
            System.err.println(e);
            return;
        }
        catch(IOException e)
        {
            // TODO
            System.err.println(e);
            return;
        }

        // Parsed OK. Now create the output file.

        PrintStream out = null;

        if (file == null)
        {
            in = System.in;
        }
        else
        {
            try
            {
                out = new PrintStream(new FileOutputStream(file + ".html"));
            }
            catch (Exception e)
            {
                // TODO
                System.err.println(e);
                return;
            }
        }

        parser.writeOut(tokenList, out);
    }

  public static void main(String args[]) {

    //JavaCCtoHTML p = new JavaCCtoHTML((java.io.InputStream)null);

    if (args.length == 0) {
      System.out.println("JavaCC Parser:  Reading from standard input . . .");
      process(null);
    } else {
      for (int i = 0; i < args.length; i++)
      {
          System.out.println("JavaCC Parser:  Reading from file " + args[i] + " . . .");
          process(args[i]);
      }
    }
  }

  /*
   * Returns true if the next token is not in the FOLLOW list of "expansion".
   * It is used to decide when the end of an "expansion" has been reached.
   */
  private boolean notTailOfExpansionUnit() {
    Token t;
    t = getToken(1);
    if (t.kind == BIT_OR || t.kind == COMMA || t.kind == RPAREN || t.kind == RBRACE || t.kind == RBRACKET) return false;
    return true;
  }

    private String parserName = null;


    private void writeHeader(PrintStream out)
    {
        out.println("<!DOCTYPE HTML PUBLIC >");
        out.println("");
        out.println("<HTML>");
        out.println("<HEAD>");
        out.println("<STYLE TYPE=\"text/css\">");
        out.println(".keyword  { font-weight: bold; }");
        out.println(".comment  { color: darkgreen}");
        out.println(".production  { font-weight: bold; color: blue; }");
        out.println(".regexp  { font-weight: bold; color: blue; }");
        out.println(".brace  { font-weight: bold; color: darkred; }");
        out.println("</STYLE>");
        out.println("");
        out.println("<TITLE>" + fileName + "</TITLE>");
        out.println("</HEAD>");
        out.println("<BODY >");
        //out.println("<H1> JavaCC Grammar -- " + title + "</H1>");
        switch (fileType)
        {
            case JAVA_FILE:
                out.println("<H1> Java file -- " + fileName + "</H1>");
                break;

            case JAVACC_FILE:
                 out.println("<H1> JavaCC Grammar -- " + parserName + "</H1>");
                break;

            case OTHER_FILE:
                out.println("<H1> File -- " + fileName + "</H1>");
                break;
        }
        out.println("<I>Produced by <A HREF=/geocities.yahoo.com/vbparser/javacctohtml/>JavaCCtoHTML</A> program</I>");
        out.println("<BR><BR>");
        out.println("<PRE>");
    }

    private void writeTrailer(PrintStream out)
    {
        out.println("</PRE>");
        out.println("</HTML>");
    }


    private void setClass(String className)
    {
        getToken(0).textClass = className;
    }

    private void setAnchorDef(String anchorName)
    {
        getToken(0).anchorDef = anchorName;
    }


    private void setExternalAnchorRef(String anchorName)
    {
        getToken(0).anchorRef = anchorName;
    }

    private void setAnchorRef(String anchorName)
    {
        getToken(0).anchorRef = "#" + anchorName;
    }


    private int linePos = 0;
    private int tabLength = 4;

    private void writeOut(Token tokenList, PrintStream out)
    {
        writeHeader(out);

        Token t = tokenList;

        while (t != null)
        {
            writeToken(out, t);
            t = t.next;
        }

        writeTrailer(out);
    }

    private void writeToken(PrintStream out, Token t)
    {
        Token tt = t.specialToken;

        // Find the start of the special token chain.

        if (tt != null)
        {
            while (tt.specialToken != null)
                tt = tt.specialToken;

            // Now follow the chain forwards, writing text
            while (tt != null)
            {
                writeSingleToken(out, tt);
                tt = tt.next;
            }
        }

        // Now write this token
        writeSingleToken(out, t);
    }


    private void writeSingleToken(PrintStream out, Token t)
    {
        if (t.textClass != null)
        {
            out.print("<SPAN CLASS=" + t.textClass + ">");
        }

        if (t.anchorDef != null)
        {
            out.print("<A NAME=" + t.anchorDef + ">");
        }

        if (t.anchorRef != null)
        {
            out.print("<A HREF=" + t.anchorRef + ">");
        }

        for( int i = 0 ; i < t.image.length() ; ++i )
        {
            char ch = t.image.charAt( i ) ;
            switch( ch )
            {

                case '<' :
                    out.print( "<" );
                    linePos++;
                    break ;

                case '>' :
                    out.print( ">" );
                    linePos++;
                    break ;


                case '\t':
                    do
                    {
                        out.print(" ");
                        linePos++;
                    }
                    while (linePos % tabLength != 0);

                    break;

                case '\r' :
                    break ;

                case '\n' :
                    out.print( ch ) ;
                    linePos = 0;
                    break ;

                default :
                    out.print( ch ) ;
            }
        }

        if (t.anchorDef != null || t.anchorRef != null)
        {
            out.print("</A>");
        }


        if (t.textClass != null)
        {
            out.print("</SPAN>");
        }
    }
}

PARSER_END(JavaCCtoHTML)


/**********************************************
 * THE JAVACC TOKEN SPECIFICATION STARTS HERE *
 **********************************************/

/* JAVACC RESERVED WORDS: These are the only tokens in JavaCC but not in Java */

TOKEN :
{
  < _OPTIONS: "options" >
| < _LOOKAHEAD: "LOOKAHEAD" >
| < _IGNORE_CASE: "IGNORE_CASE" >
| < _PARSER_BEGIN: "PARSER_BEGIN" >              { matchedToken.setClass("keyword"); }
| < _PARSER_END: "PARSER_END" >              { matchedToken.setClass("keyword"); }
| < _JAVACODE: "JAVACODE" >              { matchedToken.setClass("keyword"); }
| < _TOKEN: "TOKEN" >              { matchedToken.setClass("keyword"); }
| < _SPECIAL_TOKEN: "SPECIAL_TOKEN" >              { matchedToken.setClass("keyword"); }
| < _MORE: "MORE" >              { matchedToken.setClass("keyword"); }
| < _SKIP: "SKIP" >              { matchedToken.setClass("keyword"); }
| < _TOKEN_MGR_DECLS: "TOKEN_MGR_DECLS" >              { matchedToken.setClass("keyword"); }
| < _EOF: "EOF" >              { matchedToken.setClass("keyword"); }
}

/*
 * The remainder of the tokens are exactly (except for the removal of tokens
 * containing ">>" and "<<") as in the Java grammar and must be diff equivalent
 * (again with the exceptions above) to it.
 */

/* WHITE SPACE */

SPECIAL_TOKEN :
{
  " "
| "\t"
| "\r"
| "\f"
}


SPECIAL_TOKEN :
{
  < EOL: "\n" >
}


/* COMMENTS */

MORE :
{
  "//" : IN_SINGLE_LINE_COMMENT
|
  <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
|
  "/*" : IN_MULTI_LINE_COMMENT
}

<IN_SINGLE_LINE_COMMENT>
SPECIAL_TOKEN :
{
  <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" >
      { matchedToken.textClass = "comment"; }
  : DEFAULT
}

<IN_FORMAL_COMMENT>
SPECIAL_TOKEN :
{
  <FORMAL_COMMENT: "*/" >
      { matchedToken.textClass = "comment"; }
  : DEFAULT
}

<IN_MULTI_LINE_COMMENT>
SPECIAL_TOKEN :
{
  <MULTI_LINE_COMMENT: "*/" >
  { matchedToken.textClass = "comment"; }
  : DEFAULT
}

<IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
MORE :
{
  < ~[] >
}

/* JAVA RESERVED WORDS AND LITERALS */

TOKEN :
{
  < ABSTRACT: "abstract" >              { matchedToken.setClass("keyword"); }
| < BOOLEAN: "boolean" >              { matchedToken.setClass("keyword"); }
| < BREAK: "break" >              { matchedToken.setClass("keyword"); }
| < BYTE: "byte" >              { matchedToken.setClass("keyword"); }
| < CASE: "case" >              { matchedToken.setClass("keyword"); }
| < CATCH: "catch" >              { matchedToken.setClass("keyword"); }
| < CHAR: "char" >              { matchedToken.setClass("keyword"); }
| < CLASS: "class" >              { matchedToken.setClass("keyword"); }
| < CONST: "const" >              { matchedToken.setClass("keyword"); }
| < CONTINUE: "continue" >              { matchedToken.setClass("keyword"); }
| < _DEFAULT: "default" >              { matchedToken.setClass("keyword"); }
| < DO: "do" >              { matchedToken.setClass("keyword"); }
| < DOUBLE: "double" >              { matchedToken.setClass("keyword"); }
| < ELSE: "else" >              { matchedToken.setClass("keyword"); }
| < EXTENDS: "extends" >              { matchedToken.setClass("keyword"); }
| < FALSE: "false" >              { matchedToken.setClass("keyword"); }
| < FINAL: "final" >              { matchedToken.setClass("keyword"); }
| < FINALLY: "finally" >              { matchedToken.setClass("keyword"); }
| < FLOAT: "float" >              { matchedToken.setClass("keyword"); }
| < FOR: "for" >              { matchedToken.setClass("keyword"); }
| < GOTO: "goto" >              { matchedToken.setClass("keyword"); }
| < IF: "if" >              { matchedToken.setClass("keyword"); }
| < IMPLEMENTS: "implements" >              { matchedToken.setClass("keyword"); }
| < IMPORT: "import" >              { matchedToken.setClass("keyword"); }
| < INSTANCEOF: "instanceof" >              { matchedToken.setClass("keyword"); }
| < INT: "int" >              { matchedToken.setClass("keyword"); }
| < INTERFACE: "interface" >              { matchedToken.setClass("keyword"); }
| < LONG: "long" >              { matchedToken.setClass("keyword"); }
| < NATIVE: "native" >              { matchedToken.setClass("keyword"); }
| < NEW: "new" >              { matchedToken.setClass("keyword"); }
| < NULL: "null" >              { matchedToken.setClass("keyword"); }
| < PACKAGE: "package">              { matchedToken.setClass("keyword"); }
| < PRIVATE: "private" >              { matchedToken.setClass("keyword"); }
| < PROTECTED: "protected" >              { matchedToken.setClass("keyword"); }
| < PUBLIC: "public" >              { matchedToken.setClass("keyword"); }
| < RETURN: "return" >              { matchedToken.setClass("keyword"); }
| < SHORT: "short" >              { matchedToken.setClass("keyword"); }
| < STATIC: "static" >              { matchedToken.setClass("keyword"); }
| < SUPER: "super" >              { matchedToken.setClass("keyword"); }
| < SWITCH: "switch" >              { matchedToken.setClass("keyword"); }
| < SYNCHRONIZED: "synchronized" >              { matchedToken.setClass("keyword"); }
| < THIS: "this" >              { matchedToken.setClass("keyword"); }
| < THROW: "throw" >              { matchedToken.setClass("keyword"); }
| < THROWS: "throws" >              { matchedToken.setClass("keyword"); }
| < TRANSIENT: "transient" >              { matchedToken.setClass("keyword"); }
| < TRUE: "true" >              { matchedToken.setClass("keyword"); }
| < TRY: "try" >              { matchedToken.setClass("keyword"); }
| < VOID: "void" >              { matchedToken.setClass("keyword"); }
| < VOLATILE: "volatile" >              { matchedToken.setClass("keyword"); }
| < WHILE: "while" >              { matchedToken.setClass("keyword"); }
}

/* JAVA LITERALS */

TOKEN :
{
  < INTEGER_LITERAL:
        <DECIMAL_LITERAL> (["l","L"])?
      | <HEX_LITERAL> (["l","L"])?
      | <OCTAL_LITERAL> (["l","L"])?
  >
|
  < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
|
  < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
|
  < #OCTAL_LITERAL: "0" (["0"-"7"])* >
|
  < FLOATING_POINT_LITERAL:
        (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
      | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
      | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
      | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
  >
|
  < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
|
  < CHARACTER_LITERAL:
      "'"
      (   (~["'","\\","\n","\r"])
        | ("\\"
            ( ["n","t","b","r","f","\\","'","\""]
            | ["0"-"7"] ( ["0"-"7"] )?
            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
            )
          )
      )
      "'"
  >
|
  < STRING_LITERAL:
      "\""
      (   (~["\"","\\","\n","\r"])
        | ("\\"
            ( ["n","t","b","r","f","\\","'","\""]
            | ["0"-"7"] ( ["0"-"7"] )?
            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
            )
          )
      )*
      "\""
  >
}

/* IDENTIFIERS */

TOKEN :
{
  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
|
  < #LETTER:
      [
       "$",
       "A"-"Z",
       "_",
       "a"-"z",
       "À"-"Ö",
       "Ø"-"ö",
       "ø"-"ÿ",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?"
      ]
  >
|
  < #DIGIT:
      [
       "0"-"9",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?",
       "?"-"?"
      ]
  >
}

/* SEPARATORS */

TOKEN :
{
  < LPAREN: "(" >
| < RPAREN: ")" >
| < LBRACE: "{" >          { matchedToken.setClass("brace"); }
| < RBRACE: "}" >          { matchedToken.setClass("brace"); }
| < LBRACKET: "[" >
| < RBRACKET: "]" >
| < SEMICOLON: ";" >
| < COMMA: "," >
| < DOT: "." >
}

/* OPERATORS */

TOKEN :
{
  < HASH: "#" >
| < ASSIGN: "=" >
| < GT: ">" >
| < LT: "<" >
| < BANG: "!" >
| < TILDE: "~" >
| < HOOK: "?" >
| < COLON: ":" >
| < EQ: "==" >
| < LE: "<=" >
| < GE: ">=" >
| < NE: "!=" >
| < SC_OR: "||" >
| < SC_AND: "&&" >
| < INCR: "++" >
| < DECR: "--" >
| < PLUS: "+" >
| < MINUS: "-" >
| < STAR: "*" >
| < SLASH: "/" >
| < BIT_AND: "&" >
| < BIT_OR: "|" >
| < XOR: "^" >
| < REM: "%" >
//    | < LSHIFT: "<<" >
//    | < RSIGNEDSHIFT: ">>" >
//    | < RUNSIGNEDSHIFT: ">>>" >
| < PLUSASSIGN: "+=" >
| < MINUSASSIGN: "-=" >
| < STARASSIGN: "*=" >
| < SLASHASSIGN: "/=" >
| < ANDASSIGN: "&=" >
| < ORASSIGN: "|=" >
| < XORASSIGN: "^=" >
| < REMASSIGN: "%=" >
//    | < LSHIFTASSIGN: "<<=" >
//    | < RSIGNEDSHIFTASSIGN: ">>=" >
//    | < RUNSIGNEDSHIFTASSIGN: ">>>=" >
}

TOKEN :
{
    < ANYTHING_ELSE: ( ~[] ) >
}

/************************************************
 * THE JAVACC GRAMMAR SPECIFICATION STARTS HERE *
 ************************************************/

Token javacc_input() :
{
    Token t = getToken(1);
}
{
  javacc_options()
  "PARSER_BEGIN" "(" identifier() { parserName = getToken(0).image; }  ")"
  CompilationUnit()
  "PARSER_END" "(" identifier() { setClass("keyword"); }")"
  ( production() )+
  <EOF>

      { return t;}
}

void javacc_options() :
{}
{
  [ "options" "{" ( option_binding() )+ "}" ]
}

void option_binding() :
{}
{
  ( <IDENTIFIER> | "LOOKAHEAD" | "IGNORE_CASE" | "static" )
  "="
  ( IntegerLiteral() | BooleanLiteral() | StringLiteral() )
  ";"
}

void production() :
{}
{
  LOOKAHEAD(1)
  /*
   * Since JAVACODE is both a JavaCC reserved word and a Java identifier,
   * we need to give preference to "javacode_production" over
   * "bnf_production".
   */
  javacode_production()
|
  LOOKAHEAD(1)
  /*
   * Since SKIP, TOKEN, etc. are both JavaCC reserved words and Java
   * identifiers, we need to give preference to "regular_expression_production"
   * over "bnf_production".
   */
  regular_expr_production()
|
  LOOKAHEAD(1)
  /*
   * Since TOKEN_MGR_DECLS is both a JavaCC reserved word and a Java identifier,
   * we need to give preference to "token_manager_decls" over
   * "bnf_production".
   */
  token_manager_decls()
|
  bnf_production()
}

void javacode_production() :
{}
{
  "JAVACODE" { setClass("keyword"); }
  ResultType() identifier() { setClass("production"); setAnchorDef(getToken(0).image); } FormalParameters()
  [ "throws" Name() ( "," Name() )* ]
  [ node_descriptor() ]
  Block()
}

void bnf_production() :
{}
{
  ResultType() identifier() { setClass("production");  setAnchorDef(getToken(0).image);} FormalParameters()
  [ "throws" Name() ( "," Name() )* ]
  [ node_descriptor() ]
  ":"
  Block()
  "{" expansion_choices() "}"
}

void regular_expr_production() :
{}
{
  [
    LOOKAHEAD(2) "<" "*" ">"
  |
    "<" <IDENTIFIER> ( "," <IDENTIFIER> )* ">"
  ]
  regexpr_kind() [ "[" "IGNORE_CASE" "]" ] ":"
  "{" regexpr_spec() ( "|" regexpr_spec() )* "}"
}

void token_manager_decls() :
{}
{
  "TOKEN_MGR_DECLS" ":" ClassBody()
}

void regexpr_kind() :
{}
{
  "TOKEN"
|
  "SPECIAL_TOKEN"
|
  "SKIP"
|
  "MORE"
}

void regexpr_spec() :
{}
{
  regular_expression(true) [ Block() ] [ ":" <IDENTIFIER> ]
}

void expansion_choices() :
{}
{
  expansion() ( "|" expansion() )*
}

void expansion() :
{}
{
  ( LOOKAHEAD(1)
    "LOOKAHEAD" "(" local_lookahead() ")"
  )?
  ( LOOKAHEAD(0, { notTailOfExpansionUnit() } )
    expansion_unit()
    [ node_descriptor() ]
  )+
}

void local_lookahead() :
    {
      boolean commaAtEnd = false, emptyLA = true;
    }
{
  [
    /*
     * The lookahead of 1 is to turn off the warning message that lets
     * us know that an expansion choice can also start with an integer
     * literal because a primary expression can do the same.  But we
     * know that this is what we want.
     */
    LOOKAHEAD(1)
    IntegerLiteral()
    {
      emptyLA = false;
    }
  ]
  [ LOOKAHEAD(0, { !emptyLA && (getToken(1).kind != RPAREN) } )
    ","
    {
      commaAtEnd = true;
    }
  ]
  [ LOOKAHEAD(0, { getToken(1).kind != RPAREN && getToken(1).kind != LBRACE } )
    expansion_choices()
    {
      emptyLA = false; commaAtEnd = false;
    }
  ]
  [ LOOKAHEAD(0, { !emptyLA && !commaAtEnd && (getToken(1).kind != RPAREN) } )
    ","
    {
      commaAtEnd = true;
    }
  ]
  [ LOOKAHEAD(0, { emptyLA || commaAtEnd } )
    "{" Expression() "}"
  ]
}

void expansion_unit() :
{}
{
  LOOKAHEAD(1)
  /*
   * We give this priority over primary expressions which use LOOKAHEAD as the
   * name of its identifier.
   */
  "LOOKAHEAD" "(" local_lookahead() ")"
|
  Block()
|
  "[" expansion_choices() "]"
|
  "try" "{" expansion_choices() "}"
  ( "catch" "(" Name() <IDENTIFIER> ")" Block() )*
  [ "finally" Block() ]
|
  LOOKAHEAD( identifier() | StringLiteral() | "<" | PrimaryExpression() "=" )
  [
    LOOKAHEAD(PrimaryExpression() "=")
    PrimaryExpression() "="
  ]
  ( regular_expression(false) | identifier() { setAnchorRef(getToken(0).image); } Arguments() )
|
  "(" expansion_choices() ")" ( "+" | "*" | "?" )?
}

void regular_expression(boolean defining) :
{}
{
  StringLiteral()
|
  LOOKAHEAD(3)
  "<" [ [ "#" ] identifier() { setAnchorDef(getToken(0).image); setClass("regexp"); } ":" ] complex_regular_expression_choices() ">"
|
  LOOKAHEAD(2)
  "<" identifier()
      {
      if (defining)
      {
          setAnchorDef(getToken(0).image);
          setClass("regexp");
      }
      else
      {
          setAnchorRef(getToken(0).image);
        }
    } ">"

|
  "<" "EOF" ">"
}

void complex_regular_expression_choices() :
{}
{
  complex_regular_expression() ( "|" complex_regular_expression() )*
}

void complex_regular_expression() :
{}
{
  ( complex_regular_expression_unit() )+
}

void complex_regular_expression_unit() :
{}
{
  StringLiteral()
|
  "<" identifier() ">"
|
  character_list()
|
  "(" complex_regular_expression_choices() ")" ( "+" | "*" | "?" )?
}

void character_list() :
{}
{
  [ "~" ] "[" [ character_descriptor() ( "," character_descriptor() )* ] "]"
}

void character_descriptor() :
{}
{
  StringLiteral() [ "-" StringLiteral() ]
}

void identifier() :
{}
{
  <IDENTIFIER>
}


/**********************************************
 * THE JJTREE PRODUCTIONS START HERE          *
 **********************************************/

void node_descriptor() :
{}
{
  "#" (
          <IDENTIFIER>
              { setExternalAnchorRef("AST" + getToken(0).image + ".java"); }
        | <VOID> )
  [
   LOOKAHEAD(1)
   "(" [ ">" ] node_descriptor_expression() ")"
  ]
}


JAVACODE
void node_descriptor_expression()
{
  Token tok;
  int nesting = 1;
  while (true) {
    tok = getToken(1);
    if (tok.kind == 0) {
      throw new ParseException();
    }
    if (tok.kind == LPAREN) nesting++;
    if (tok.kind == RPAREN) {
      nesting--;
      if (nesting == 0) break;
    }
    tok = getNextToken();
  }
}


JAVACODE
Token readTokens()
{
    Token t = getToken(1);

    while (getToken(1).kind != EOF)
        getNextToken();

    return t;
}

/**********************************************
 * THE JAVA GRAMMAR SPECIFICATION STARTS HERE *
 **********************************************/

/*
 * The Java grammar is modified to use sequences of tokens
 * for the missing tokens - those that include "<<" and ">>".
 */

/*
 * The following production defines Java identifiers - it
 * includes the reserved words of JavaCC also.
 */

void JavaIdentifier() :
{}
{
  <IDENTIFIER>
| "options"
| "LOOKAHEAD"
| "IGNORE_CASE"
| "PARSER_BEGIN"
| "PARSER_END"
| "JAVACODE"
| "TOKEN"
| "SPECIAL_TOKEN"
| "MORE"
| "SKIP"
| "TOKEN_MGR_DECLS"
| "EOF"
}

/*
 * The productions for the missing code follows.  Obviously
 * these productions accept more than what is legal in Java,
 * but that is OK for our purposes.
 */

void ShiftOps() :
{}
{
  "<" "<"
|
  ">" ">" [ ">" ]
}

void OtherAssignmentOps() :
{}
{
  "<" "<="
|
  ">" [ ">" ] ">="
}

/*
 * Program structuring syntax follows.
 */

void CompilationUnit() :
/*
 * The <EOF> is deleted since the compilation unit is embedded
 * within grammar code.  To parse to CompilationUnit, we use
 * a special production JavaCompilationUnit below.
 */
{}
{
  [ PackageDeclaration() ]
  ( ImportDeclaration() )*
  ( TypeDeclaration() )*
}

Token JavaCompilationUnit() :
/*
 * Use this to parse a Java compilation unit.
 */
{
    Token t = getToken(1);
}
{
  CompilationUnit()
  <EOF>

      { return t;}
}

void PackageDeclaration() :
{}
{
  "package" Name() ";"
}

void ImportDeclaration() :
{}
{
  "import" Name() [ "." "*" ] ";"
}

void TypeDeclaration() :
{}
{
  LOOKAHEAD( ( "abstract" | "final" | "public" )* "class" )
  ClassDeclaration()
|
  InterfaceDeclaration()
|
  ";"
}


/*
 * Declaration syntax follows.
 */

void ClassDeclaration() :
{}
{
  ( "abstract" | "final" | "public" )*
  UnmodifiedClassDeclaration()
}

void UnmodifiedClassDeclaration() :
{}
{
  "class" JavaIdentifier() [ "extends" Name() ] [ "implements" NameList() ]
  ClassBody()
}

void ClassBody() :
{}
{
  "{" ( ClassBodyDeclaration() )* "}"
}

void NestedClassDeclaration() :
{}
{
  ( "static" | "abstract" | "final" | "public" | "protected" | "private" )*
  UnmodifiedClassDeclaration()
}

void ClassBodyDeclaration() :
{}
{
  LOOKAHEAD(2)
  Initializer()
|
  LOOKAHEAD( ( "static" | "abstract" | "final" | "public" | "protected" | "private" )* "class" )
  NestedClassDeclaration()
|
  LOOKAHEAD( ( "static" | "abstract" | "final" | "public" | "protected" | "private" )* "interface" )
  NestedInterfaceDeclaration()
|
  LOOKAHEAD( [ "public" | "protected" | "private" ] Name() "(" )
  ConstructorDeclaration()
|
  LOOKAHEAD( MethodDeclarationLookahead() )
  MethodDeclaration()
|
  FieldDeclaration()
}

// This production is to determine lookahead only.
void MethodDeclarationLookahead() :
{}
{
  ( "public" | "protected" | "private" | "static" | "abstract" | "final" | "native" | "synchronized" )*
  ResultType() JavaIdentifier() "("
}

void InterfaceDeclaration() :
{}
{
  ( "abstract" | "public" )*
  UnmodifiedInterfaceDeclaration()
}

void NestedInterfaceDeclaration() :
{}
{
  ( "static" | "abstract" | "final" | "public" | "protected" | "private" )*
  UnmodifiedInterfaceDeclaration()
}

void UnmodifiedInterfaceDeclaration() :
{}
{
  "interface" JavaIdentifier() [ "extends" NameList() ]
  "{" ( InterfaceMemberDeclaration() )* "}"
}

void InterfaceMemberDeclaration() :
{}
{
  LOOKAHEAD( ( "static" | "abstract" | "final" | "public" | "protected" | "private" )* "class" )
  NestedClassDeclaration()
|
  LOOKAHEAD( ( "static" | "abstract" | "final" | "public" | "protected" | "private" )* "interface" )
  NestedInterfaceDeclaration()
|
  LOOKAHEAD( MethodDeclarationLookahead() )
  MethodDeclaration()
|
  FieldDeclaration()
}

void FieldDeclaration() :
{}
{
  ( "public" | "protected" | "private" | "static" | "final" | "transient" | "volatile" )*
  Type() VariableDeclarator() ( "," VariableDeclarator() )* ";"
}

void VariableDeclarator() :
{}
{
  VariableDeclaratorId() [ "=" VariableInitializer() ]
}

void VariableDeclaratorId() :
{}
{
  JavaIdentifier() ( "[" "]" )*
}

void VariableInitializer() :
{}
{
  ArrayInitializer()
|
  Expression()
}

void ArrayInitializer() :
{}
{
  "{" [ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}"
}

void MethodDeclaration() :
{}
{
  ( "public" | "protected" | "private" | "static" | "abstract" | "final" | "native" | "synchronized" )*
  ResultType() MethodDeclarator() [ "throws" NameList() ]
  ( Block() | ";" )
}

void MethodDeclarator() :
{}
{
  JavaIdentifier() FormalParameters() ( "[" "]" )*
}

void FormalParameters() :
{}
{
  "(" [ FormalParameter() ( "," FormalParameter() )* ] ")"
}

void FormalParameter() :
{}
{
  [ "final" ] Type() VariableDeclaratorId()
}

void ConstructorDeclaration() :
{}
{
  [ "public" | "protected" | "private" ]
  JavaIdentifier() FormalParameters() [ "throws" NameList() ]
  "{"
    [ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ]
    ( BlockStatement() )*
  "}"
}

void ExplicitConstructorInvocation() :
{}
{
  LOOKAHEAD("this" Arguments() ";")
  "this" Arguments() ";"
|
  [ LOOKAHEAD(2) PrimaryExpression() "." ] "super" Arguments() ";"
}

void Initializer() :
{}
{
  [ "static" ] Block()
}


/*
 * Type, name and expression syntax follows.
 */

void Type() :
{}
{
  ( PrimitiveType() | Name() ) ( "[" "]" )*
}

void PrimitiveType() :
{}
{
  "boolean"
|
  "char"
|
  "byte"
|
  "short"
|
  "int"
|
  "long"
|
  "float"
|
  "double"
}

void ResultType() :
{}
{
  "void"
|
  Type()
}

void Name() :
/*
 * A lookahead of 2 is required below since "Name" can be followed
 * by a ".*" when used in the context of an "ImportDeclaration".
 */
{}
{
  JavaIdentifier()
  ( LOOKAHEAD(2) "." JavaIdentifier() )*
}

void NameList() :
{}
{
  Name() ( "," Name() )*
}


/*
 * Expression syntax follows.
 */

void Expression() :
/*
 * This expansion has been written this way instead of:
 *   Assignment() | ConditionalExpression()
 * for performance reasons.
 * However, it is a weakening of the grammar for it allows the LHS of
 * assignments to be any conditional expression whereas it can only be
 * a primary expression.  Consider adding a semantic predicate to work
 * around this.
 */
{}
{
  ConditionalExpression() [ AssignmentOperator() Expression() ]
}

void AssignmentOperator() :
{}
{
  "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "&=" | "^=" | "|="
|
  OtherAssignmentOps()
}

void ConditionalExpression() :
{}
{
  ConditionalOrExpression() [ "?" Expression() ":" ConditionalExpression() ]
}

void ConditionalOrExpression() :
{}
{
  ConditionalAndExpression() ( "||" ConditionalAndExpression() )*
}

void ConditionalAndExpression() :
{}
{
  InclusiveOrExpression() ( "&&" InclusiveOrExpression() )*
}

void InclusiveOrExpression() :
{}
{
  ExclusiveOrExpression() ( "|" ExclusiveOrExpression() )*
}

void ExclusiveOrExpression() :
{}
{
  AndExpression() ( "^" AndExpression() )*
}

void AndExpression() :
{}
{
  EqualityExpression() ( "&" EqualityExpression() )*
}

void EqualityExpression() :
{}
{
  InstanceOfExpression() ( ( "==" | "!=" ) InstanceOfExpression() )*
}

void InstanceOfExpression() :
{}
{
  RelationalExpression() [ "instanceof" Type() ]
}

void RelationalExpression() :
{}
{
  /*
   * The lookahead of 2 below is due to the fact that we have split
   * the shift and shift assignment operator into multiple tokens that
   * now clash with these tokens.
   */
  ShiftExpression() ( LOOKAHEAD(2) ( "<" | ">" | "<=" | ">=" ) ShiftExpression() )*
}

void ShiftExpression() :
{}
{
  /*
   * The lookahead of 3 below is due to the fact that we have split
   * the shift and shift assignment operator into multiple tokens that
   * now clash with these tokens and the relational operators.
   */
  AdditiveExpression() ( LOOKAHEAD(3) ( ShiftOps() ) AdditiveExpression() )*
}

void AdditiveExpression() :
{}
{
  MultiplicativeExpression() ( ( "+" | "-" ) MultiplicativeExpression() )*
}

void MultiplicativeExpression() :
{}
{
  UnaryExpression() ( ( "*" | "/" | "%" ) UnaryExpression() )*
}

void UnaryExpression() :
{}
{
  ( "+" | "-" ) UnaryExpression()
|
  PreIncrementExpression()
|
  PreDecrementExpression()
|
  UnaryExpressionNotPlusMinus()
}

void PreIncrementExpression() :
{}
{
  "++" PrimaryExpression()
}

void PreDecrementExpression() :
{}
{
  "--" PrimaryExpression()
}

void UnaryExpressionNotPlusMinus() :
{}
{
  ( "~" | "!" ) UnaryExpression()
|
  LOOKAHEAD( CastLookahead() )
  CastExpression()
|
  PostfixExpression()
}

// This production is to determine lookahead only.  The LOOKAHEAD specifications
// below are not used, but they are there just to indicate that we know about
// this.
void CastLookahead() :
{}
{
  LOOKAHEAD(2)
  "(" PrimitiveType()
|
  LOOKAHEAD("(" Name() "[")
  "(" Name() "[" "]"
|
  "(" Name() ")" ( "~" | "!" | "(" | JavaIdentifier() | "this" | "super" | "new" | Literal() )
}

void PostfixExpression() :
{}
{
  PrimaryExpression() [ "++" | "--" ]
}

void CastExpression() :
{}
{
  LOOKAHEAD("(" PrimitiveType())
  "(" Type() ")" UnaryExpression()
|
  LOOKAHEAD("(" Name())
  "(" Type() ")" UnaryExpressionNotPlusMinus()
}

void PrimaryExpression() :
{}
{
  PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )*
}

void PrimaryPrefix() :
{}
{
  Literal()
|
  "this"
|
  "super" "." JavaIdentifier()
|
  "(" Expression() ")"
|
  AllocationExpression()
|
  LOOKAHEAD( ResultType() "." "class" )
  ResultType() "." "class"
|
  Name()
}

void PrimarySuffix() :
{}
{
  LOOKAHEAD(2)
  "." "this"
|
  LOOKAHEAD(2)
  "." AllocationExpression()
|
  "[" Expression() "]"
|
  "." JavaIdentifier()
|
  Arguments()
}

void Literal() :
{}
{
  <INTEGER_LITERAL>
|
  <FLOATING_POINT_LITERAL>
|
  <CHARACTER_LITERAL>
|
  <STRING_LITERAL>
|
  BooleanLiteral()
|
  NullLiteral()
}

void IntegerLiteral() :
{}
{
  <INTEGER_LITERAL>
}

void BooleanLiteral() :
{}
{
  "true"
|
  "false"
}

void StringLiteral() :
{}
{
  <STRING_LITERAL>
}

void NullLiteral() :
{}
{
  "null"
}

void Arguments() :
{}
{
  "(" [ ArgumentList() ] ")"
}

void ArgumentList() :
{}
{
  Expression() ( "," Expression() )*
}

void AllocationExpression() :
{}
{
  LOOKAHEAD(2)
  "new" PrimitiveType() ArrayDimsAndInits()
|
  "new" Name()
    (
      ArrayDimsAndInits()
    |
      Arguments() [ ClassBody() ]
    )
}

/*
 * The second LOOKAHEAD specification below is to parse to PrimarySuffix
 * if there is an expression between the "[...]".
 */
void ArrayDimsAndInits() :
{}
{
  LOOKAHEAD(2)
  ( LOOKAHEAD(2) "[" Expression() "]" )+ ( LOOKAHEAD(2) "[" "]" )*
|
  ( "[" "]" )+ ArrayInitializer()
}


/*
 * Statement syntax follows.
 */

void Statement() :
{}
{
  LOOKAHEAD(2)
  LabeledStatement()
|
  Block()
|
  EmptyStatement()
|
  StatementExpression() ";"
|
  SwitchStatement()
|
  IfStatement()
|
  WhileStatement()
|
  DoStatement()
|
  ForStatement()
|
  BreakStatement()
|
  ContinueStatement()
|
  ReturnStatement()
|
  ThrowStatement()
|
  SynchronizedStatement()
|
  TryStatement()
}

void LabeledStatement() :
{}
{
  JavaIdentifier() ":" Statement()
}

void Block() :
{}
{
  "{" ( BlockStatement() )* "}"
}

void BlockStatement() :
{}
{
  LOOKAHEAD([ "final" ] Type() JavaIdentifier())
  LocalVariableDeclaration() ";"
|
  Statement()
|
  UnmodifiedClassDeclaration()
|
  UnmodifiedInterfaceDeclaration()
}

void LocalVariableDeclaration() :
{}
{
  [ "final" ] Type() VariableDeclarator() ( "," VariableDeclarator() )*
}

void EmptyStatement() :
{}
{
  ";"
}

void StatementExpression() :
/*
 * The last expansion of this production accepts more than the legal
 * Java expansions for StatementExpression.  This expansion does not
 * use PostfixExpression for performance reasons.
 */
{}
{
  PreIncrementExpression()
|
  PreDecrementExpression()
|
  PrimaryExpression()
  [
    "++"
  |
    "--"
  |
    AssignmentOperator() Expression()
  ]
}

void SwitchStatement() :
{}
{
  "switch" "(" Expression() ")" "{"
    ( SwitchLabel() ( BlockStatement() )* )*
  "}"
}

void SwitchLabel() :
{}
{
  "case" Expression() ":"
|
  "default" ":"
}

void IfStatement() :
/*
 * The disambiguating algorithm of JavaCC automatically binds dangling
 * else's to the innermost if statement.  The LOOKAHEAD specification
 * is to tell JavaCC that we know what we are doing.
 */
{}
{
  "if" "(" Expression() ")" Statement() [ LOOKAHEAD(1) "else" Statement() ]
}

void WhileStatement() :
{}
{
  "while" "(" Expression() ")" Statement()
}

void DoStatement() :
{}
{
  "do" Statement() "while" "(" Expression() ")" ";"
}

void ForStatement() :
{}
{
  "for" "(" [ ForInit() ] ";" [ Expression() ] ";" [ ForUpdate() ] ")" Statement()
}

void ForInit() :
{}
{
  LOOKAHEAD( [ "final" ] Type() JavaIdentifier() )
  LocalVariableDeclaration()
|
  StatementExpressionList()
}

void StatementExpressionList() :
{}
{
  StatementExpression() ( "," StatementExpression() )*
}

void ForUpdate() :
{}
{
  StatementExpressionList()
}

void BreakStatement() :
{}
{
  "break" [ JavaIdentifier() ] ";"
}

void ContinueStatement() :
{}
{
  "continue" [ JavaIdentifier() ] ";"
}

void ReturnStatement() :
{}
{
  "return" [ Expression() ] ";"
}

void ThrowStatement() :
{}
{
  "throw" Expression() ";"
}

void SynchronizedStatement() :
{}
{
  "synchronized" "(" Expression() ")" Block()
}

void TryStatement() :
/*
 * Semantic check required here to make sure that at least one
 * finally/catch is present.
 */
{}
{
  "try" Block()
  ( "catch" "(" FormalParameter() ")" Block() )*
  [ "finally" Block() ]
}