/**
 *     Caption: Zaval Java Resource Editor
 *     $Revision: 0.37 $
 *     $Date: 2002/03/28 9:24:42 $
 *
 *     @author:     Victor Krapivin
 *     @version:    1.3
 *
 * Zaval JRC Editor is a visual editor which allows you to manipulate 
 * localization strings for all Java based software with appropriate 
 * support embedded.
 * 
 * For more info on this product read Zaval Java Resource Editor User's Guide
 * (It comes within this package).
 * The latest product version is always available from the product's homepage:
 * http://www.zaval.org/products/jrc-editor/
 * and from the SourceForge:
 * http://sourceforge.net/projects/zaval0002/
 *
 * Contacts:
 *   Support : support@zaval.org
 *   Change Requests : change-request@zaval.org
 *   Feedback : feedback@zaval.org
 *   Other : info@zaval.org
 * 
 * Copyright (C) 2001-2002  Zaval Creative Engineering Group (http://www.zaval.org)
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * (version 2) as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */
/*
    This Java 1.2.x grammar parser have contributed from JavaCC 2.0
    examples and have slightly updated. The string literals, package,
    class and function declarations have modified to get appropriate
    identifiers. Also the Name() function have updated to return full
    qualified name of as a string.

    All copyright information and revision history can be obtained
    from MetaMata distributuin; this information is skipped hereand the
    this reference have placed instead.
*/
options {
  JAVA_UNICODE_ESCAPE = true;
  STATIC = false;
  ERROR_REPORTING = true;
  UNICODE_INPUT = false;
}

PARSER_BEGIN(JavaParser)

package org.zaval.tools.i18n.translator;

import java.io.*;
import java.util.*;

public class JavaParser
{
    private Stack cNames = new Stack();
    private Stack fNames = new Stack();
    private String pkgName, className, funName;
    private Hashtable hash = new Hashtable();

    private void makeCName(Token tok)
    {
        String s = tok.image;
        if(className!=null) cNames.push(className);
        className = s;
    }

    private void makeCName()
    {
        String s = (String)cNames.pop();
        className = s;
    }

    private void makeFName(Token tok)
    {
        String s = tok.image;
        if(funName!=null) fNames.push(funName);
        funName = s;
    }

    private void makeFName()
    {
        String s = fNames.empty() ? null : (String)fNames.pop();
        funName = s;
    }

    public Hashtable parse()
    throws ParseException
    {
        CompilationUnit();
        return hash;
    }

    private boolean valid(String s)
    {
        char c;
        int j, k = s.length();
        c = s.charAt(0);
        if(!Character.isLetter(c)) return false;
        for(j=1;j<k;++j){
            c = s.charAt(j);
            if(!Character.isLetter(c) && !Character.isDigit(c) &&
                c!='_' && c!='-' && c!='.')
                    return false;
        }
        return true;
    }

    private String canonify(String s)
    {
        char c;
        StringBuffer sb = new StringBuffer();

        int j, k = s.length();
        for(j=0;j<k;++j){
            c = s.charAt(j);
            if(Character.isLetter(c) || Character.isDigit(c) ||
                c=='-' || c=='.' || c=='_')
                    sb.append(c=='.' || c=='_' ? '-' : c);
        }
        return sb.toString();
    }

    private void add(Token tok)
    {
        String value = tok.image;
        if(value.length() < 3) return;
        value = value.substring(1, value.length() - 1);
        String orgVal = value;
        value = value.trim();
        if(value.length() < 5) return;
        StringTokenizer st = new StringTokenizer(value);
        if(st.countTokens()<1) return;
        String kk = canonify(st.nextToken().toLowerCase());
        String kk1 = kk;
        while(st.hasMoreTokens() && kk1.length() < 4)
            kk1 = canonify(st.nextToken().toLowerCase());
        if(kk1.length() > kk.length()) kk = kk1;

        String key = pkgName + "." + className;
        if(funName!=null) key += "." + funName;
        key += "." + kk;

        if(kk.indexOf('.')>0) key = kk;
        while(kk.endsWith(".") || kk.endsWith("_")) kk = kk.substring(0, kk.length()-1);
        if(kk.length() < 5) return;
        if(!valid(kk)) return;

        if(hash.containsKey(key)){
            String oldVal = (String)hash.get(key);
            if(!oldVal.equals(orgVal)){
                int i = 0;
                for(i = 0; hash.containsKey(key + "-" + i); ++i);
                key += "-" + i;
            }
        }
        hash.put(key, orgVal);
    }

    public static void main(String[] fn)
    throws Exception
    {
        for(int i=0;i<fn.length;++i){
            FileInputStream in = new FileInputStream(fn[i]);
            System.out.println(fn[i] + ":");
            JavaParser t = new JavaParser(in);
            Hashtable s = t.parse();
            System.err.println(fn[i] + ":" + s.size());
        }
    }
}

PARSER_END(JavaParser)


/* WHITE SPACE */

SKIP :
{
  " "
| "\t"
| "\n"
| "\r"
| "\f"
}

/* 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" > : DEFAULT
}

<IN_FORMAL_COMMENT>
SPECIAL_TOKEN :
{
  <FORMAL_COMMENT: "*/" > : DEFAULT
}

<IN_MULTI_LINE_COMMENT>
SPECIAL_TOKEN :
{
  <MULTI_LINE_COMMENT: "*/" > : DEFAULT
}

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

/* RESERVED WORDS AND LITERALS */

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

/* 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:
      [
       "\u0024",
       "\u0041"-"\u005a",
       "\u005f",
       "\u0061"-"\u007a",
       "\u00c0"-"\u00d6",
       "\u00d8"-"\u00f6",
       "\u00f8"-"\u00ff",
       "\u0100"-"\u1fff",
       "\u3040"-"\u318f",
       "\u3300"-"\u337f",
       "\u3400"-"\u3d2d",
       "\u4e00"-"\u9fff",
       "\uf900"-"\ufaff"
      ]
  >
|
  < #DIGIT:
      [
       "\u0030"-"\u0039",
       "\u0660"-"\u0669",
       "\u06f0"-"\u06f9",
       "\u0966"-"\u096f",
       "\u09e6"-"\u09ef",
       "\u0a66"-"\u0a6f",
       "\u0ae6"-"\u0aef",
       "\u0b66"-"\u0b6f",
       "\u0be7"-"\u0bef",
       "\u0c66"-"\u0c6f",
       "\u0ce6"-"\u0cef",
       "\u0d66"-"\u0d6f",
       "\u0e50"-"\u0e59",
       "\u0ed0"-"\u0ed9",
       "\u1040"-"\u1049"
      ]
  >
}

/* SEPARATORS */

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

/* OPERATORS */

TOKEN :
{
  < 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: ">>>=" >
}


/*****************************************
 * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
 *****************************************/

/*
 * Program structuring syntax follows.
 */

void CompilationUnit() :
{}
{
  [ PackageDeclaration() ]
  ( ImportDeclaration() )*
  ( TypeDeclaration() )*
  <EOF>
}

void PackageDeclaration() :
{ String s; }
{
  "package" s = Name(){ pkgName = s; } ";"
}

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

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


/*
 * Declaration syntax follows.
 */

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

void UnmodifiedClassDeclaration() :
{ Token tok; }
{
  "class" tok=<IDENTIFIER>{ makeCName(tok); } [ "extends" Name() ] [ "implements" NameList() ]
  ClassBody()
}

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

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

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

// This production is to determine lookahead only.
void MethodDeclarationLookahead() :
{ Token tok; }
{
  ( "public" | "protected" | "private" | "static" | "abstract" | "final" | "native" | "synchronized" | "strictfp")*
  ResultType() tok=<IDENTIFIER>{ funName = tok.image; } "("
}

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

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

void UnmodifiedInterfaceDeclaration() :
{}
{
  "interface" <IDENTIFIER> [ "extends" NameList() ]
  "{" ( InterfaceMemberDeclaration() )* "}"
}

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

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

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

void VariableDeclaratorId() :
{}
{
  <IDENTIFIER> ( "[" "]" )*
}

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

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

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

void MethodDeclarator() :
{ Token tok; }
{
  tok=<IDENTIFIER>{ makeFName(tok); } FormalParameters() ( "[" "]" )*
}

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

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

void ConstructorDeclaration() :
{}
{
  [ "public" | "protected" | "private" ]
  <IDENTIFIER> 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()
}

String Name() :
/*
 * A lookahead of 2 is required below since "Name" can be followed
 * by a ".*" when used in the context of an "ImportDeclaration".
 */
{ String s; Token tok; }
{
  tok = <IDENTIFIER>{ s = tok.image; }
  ( LOOKAHEAD(2) "." tok = <IDENTIFIER>{ s += "." + tok.image; }
  )*{ return s; }
}

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() :
{}
{
  "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|="
}

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() :
{}
{
  ShiftExpression() ( ( "<" | ">" | "<=" | ">=" ) ShiftExpression() )*
}

void ShiftExpression() :
{}
{
  AdditiveExpression() ( ( "<<" | ">>" | ">>>" ) 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() ")" ( "~" | "!" | "(" | <IDENTIFIER> | "this" | "super" | "new" | Literal() )
}

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

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

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

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

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

void Literal() :
{ Token tok; }
{
  <INTEGER_LITERAL>
|
  <FLOATING_POINT_LITERAL>
|
  tok = <CHARACTER_LITERAL>{ add(tok); }
|
  tok=<STRING_LITERAL>{ add(tok); }
|
  BooleanLiteral()
|
  NullLiteral()
}

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

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() :
{}
{
  <IDENTIFIER> ":" Statement()
}

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

void BlockStatement() :
{}
{
  LOOKAHEAD([ "final" ] Type() <IDENTIFIER>)
  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() <IDENTIFIER> )
  LocalVariableDeclaration()
|
  StatementExpressionList()
}

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

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

void BreakStatement() :
{}
{
  "break" [ <IDENTIFIER> ] ";"
}

void ContinueStatement() :
{}
{
  "continue" [ <IDENTIFIER> ] ";"
}

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