1/*****************************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one                *
3 * or more contributor license agreements.  See the NOTICE file              *
4 * distributed with this work for additional information                     *
5 * regarding copyright ownership.  The ASF licenses this file                *
6 * to you under the Apache License, Version 2.0 (the                         *
7 * "License"); you may not use this file except in compliance                *
8 * with the License.  You may obtain a copy of the License at                *
9 *                                                                           *
10 *     http://www.apache.org/licenses/LICENSE-2.0                            *
11 *                                                                           *
12 * Unless required by applicable law or agreed to in writing,                *
13 * software distributed under the License is distributed on an               *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY                    *
15 * KIND, either express or implied.  See the License for the                 *
16 * specific language governing permissions and limitations                   *
17 * under the License.                                                        *
18 *                                                                           *
19 * This file is part of the BeanShell Java Scripting distribution.           *
20 * Documentation and updates may be found at http://www.beanshell.org/       *
21 * Patrick Niemeyer (pat@pat.net)                                            *
22 * Author of Learning Java, O'Reilly & Associates                            *
23 *                                                                           *
24 *****************************************************************************/
25
26/*
27	Notes:
28	There is probably a lot of room for improvement in here.
29	All of the syntactic lookaheads have been commented with:
30		SYNTACTIC_LOOKAHEAD
31	These are probably expensive and we may want to start weeding them out
32	where possible.
33*/
34
35options {
36    JAVA_UNICODE_ESCAPE=true;
37    STATIC=false;
38    MULTI=true;
39    NODE_DEFAULT_VOID=true;
40	NODE_SCOPE_HOOK=true;
41	NODE_PREFIX="BSH";
42	/* Print grammar debugging info as we parse
43	DEBUG_PARSER=true;
44	*/
45	/* Print detailed lookahead debugging info
46	DEBUG_LOOKAHEAD=true;
47	*/
48
49	/*
50		There are weird issues related to this flag.
51		The default value, true, creates line level error detail in the parse
52		exceptions.  However it gives us strange LookaheadSuccess Errors thrown
53		on some syntax errors.
54		http://groups-beta.google.com/group/comp.compilers.tools.javacc/browse_thread/thread/14d3471883f8794f/ecf7b1d81151839c?q=Parser$LookaheadSuccess&rnum=1&hl=en#ecf7b1d81151839c
55		I have manually hacked the Parser.java to catch LookaheadSuccess in
56		the jj_rescan_token() method...  The bug report indicates that this
57		is fixed, apparently in some post javacc 3.2 version.
58	*/
59	//ERROR_REPORTING=false;
60
61	// This breaks something for interactive use on the command line,
62	// but may be useful in non-interactive use.
63	//CACHE_TOKENS=true;
64}
65
66PARSER_BEGIN(Parser)
67package bsh;
68
69import java.io.*;
70import java.util.Vector;
71
72/**
73	This is the BeanShell parser.  It is used internally by the Interpreter
74	class (which is probably what you are looking for).  The parser knows
75	only how to parse the structure of the language, it does not understand
76	names, commands, etc.
77	<p>
78	You can use the Parser from the command line to do basic structural
79	validation of BeanShell files without actually executing them. e.g.
80	<code><pre>
81		java bsh.Parser [ -p ] file [ file ] [ ... ]
82	</pre></code>
83	<p>
84	The -p option causes the abstract syntax to be printed.
85	<p>
86
87	From code you'd use the Parser like this:
88	<p
89	<code><pre>
90		Parser parser = new Parser(in);
91		while( !(eof=parser.Line()) ) {
92			SimpleNode node = parser.popNode();
93			// use the node, etc. (See bsh.BSH* classes)
94		}
95	</pre></code>
96*/
97public class Parser
98{
99	boolean retainComments = false;
100
101	public void setRetainComments( boolean b ) {
102		retainComments = b;
103	}
104
105	void jjtreeOpenNodeScope(Node n) {
106		((SimpleNode)n).firstToken = getToken(1);
107	}
108
109	void jjtreeCloseNodeScope(Node n) {
110		((SimpleNode)n).lastToken = getToken(0);
111	}
112
113	/**
114		Re-initialize the input stream and token source.
115	*/
116	void reInitInput( Reader in ) {
117		ReInit(in);
118	}
119
120	public SimpleNode popNode()
121	{
122		if ( jjtree.nodeArity() > 0)  // number of child nodes
123			return (SimpleNode)jjtree.popNode();
124		else
125			return null;
126	}
127
128	/**
129		Explicitly re-initialize just the token reader.
130		This seems to be necessary to avoid certain looping errors when
131		reading bogus input.  See Interpreter.
132	*/
133	void reInitTokenInput( Reader in ) {
134		jj_input_stream.ReInit( in,
135			jj_input_stream.getEndLine(),
136			jj_input_stream.getEndColumn() );
137	}
138
139	public static void main( String [] args )
140		throws IOException, ParseException
141	{
142		boolean print = false;
143		int i=0;
144		if ( args[0].equals("-p") ) {
145			i++;
146			print=true;
147		}
148		for(; i< args.length; i++) {
149			Reader in = new FileReader(args[i]);
150			Parser parser = new Parser(in);
151			parser.setRetainComments(true);
152			while( !parser.Line()/*eof*/ )
153				if ( print )
154					System.out.println( parser.popNode() );
155		}
156	}
157
158	/**
159		Lookahead for the enhanced for statement.
160		Expect "for" "(" and then see whether we hit ":" or a ";" first.
161	*/
162	boolean isRegularForStatement()
163	{
164		int curTok = 1;
165		Token tok;
166		tok = getToken(curTok++);
167		if ( tok.kind != FOR ) return false;
168		tok = getToken(curTok++);
169		if ( tok.kind != LPAREN ) return false;
170		while (true)
171		{
172			tok = getToken(curTok++);
173			switch (tok.kind) {
174				case COLON:
175					return false;
176				case SEMICOLON:
177					return true;
178				case EOF:
179					return false;
180			}
181		}
182	}
183
184	/**
185		Generate a ParseException with the specified message, pointing to the
186		current token.
187		The auto-generated Parser.generateParseException() method does not
188		provide line number info, therefore we do this.
189	*/
190	ParseException createParseException( String message, Exception e )
191	{
192		Token errortok = token;
193		int line = errortok.beginLine, column = errortok.beginColumn;
194		String mess = (errortok.kind == 0) ? tokenImage[0] : errortok.image;
195		return new ParseException( "Parse error at line " + line
196			+ ", column " + column + " : " + message, e );
197	}
198
199	int parseInt(String s) throws NumberFormatException {
200		int radix;
201		int i;
202		if( s.startsWith("0x") || s.startsWith("0X") ) {
203			radix = 16;
204			i = 2;
205		} else if( s.startsWith("0") && s.length() > 1 ) {
206			radix = 8;
207			i = 1;
208		} else {
209			radix = 10;
210			i = 0;
211		}
212		int result = 0;
213		int len = s.length();
214		for( ; i<len; i++ ) {
215			if( result < 0 )
216				throw new NumberFormatException("Number too big for integer type: "+s);
217			result *= radix;
218			int digit = Character.digit(s.charAt(i),radix);
219			if( digit < 0 )
220				throw new NumberFormatException("Invalid integer type: "+s);
221			result += digit;
222		}
223		return result;
224	}
225
226	long parseLong(String s) throws NumberFormatException {
227		int radix;
228		int i;
229		if( s.startsWith("0x") || s.startsWith("0X") ) {
230			radix = 16;
231			i = 2;
232		} else if( s.startsWith("0") && s.length() > 1 ) {
233			radix = 8;
234			i = 1;
235		} else {
236			radix = 10;
237			i = 0;
238		}
239		long result = 0;
240		int len = s.length();
241		for( ; i<len; i++ ) {
242			if( result < 0L )
243				throw new NumberFormatException("Number too big for long type: "+s);
244			result *= radix;
245			int digit = Character.digit(s.charAt(i),radix);
246			if( digit < 0 )
247				throw new NumberFormatException("Invalid long type: "+s);
248			result += digit;
249		}
250		return result;
251	}
252}
253
254PARSER_END(Parser)
255
256SKIP : /* WHITE SPACE */
257{
258	" " | "\t" | "\r" | "\f"
259	| "\n"
260	| < NONPRINTABLE: (["\u0000"-"\u0020", "\u0080"-"\u00ff"])+ >
261}
262
263SPECIAL_TOKEN : /* COMMENTS */
264{
265/*
266	SINGLE_LINE_COMMENT includes a hack to accept SLC at the end of a file
267	with no terminanting linefeed.  This is actually illegal according to
268	spec, but comes up often enough to warrant it... (especially in eval()).
269*/
270  <SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")? >
271
272| <HASH_BANG_COMMENT: "#!" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
273
274 /* Moved FORMAL_COMMENT to a real token.  Modified MULTI_LINE_COMMENT to not
275    catch formal comments (require no star after star) */
276| <MULTI_LINE_COMMENT:
277	"/*" (~["*"])+ "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
278}
279
280TOKEN : /* RESERVED WORDS AND LITERALS */
281{
282< ABSTRACT : "abstract" >
283| < BOOLEAN: "boolean" >
284| < BREAK: "break" >
285| < CLASS: "class" >
286| < BYTE: "byte" >
287| < CASE: "case" >
288| < CATCH: "catch" >
289| < CHAR: "char" >
290| < CONST: "const" >
291| < CONTINUE: "continue" >
292| < _DEFAULT: "default" >
293| < DO: "do" >
294| < DOUBLE: "double" >
295| < ELSE: "else" >
296| < ENUM: "enum" >
297| < EXTENDS: "extends" >
298| < FALSE: "false" >
299| < FINAL: "final" >
300| < FINALLY: "finally" >
301| < FLOAT: "float" >
302| < FOR: "for" >
303| < GOTO: "goto" >
304| < IF: "if" >
305| < IMPLEMENTS: "implements" >
306| < IMPORT: "import" >
307| < INSTANCEOF: "instanceof" >
308| < INT: "int" >
309| < INTERFACE: "interface" >
310| < LONG: "long" >
311| < NATIVE: "native" >
312| < NEW: "new" >
313| < NULL: "null" >
314| < PACKAGE: "package" >
315| < PRIVATE: "private" >
316| < PROTECTED: "protected" >
317| < PUBLIC: "public" >
318| < RETURN: "return" >
319| < SHORT: "short" >
320| < STATIC: "static" >
321| < STRICTFP : "strictfp" >
322| < SWITCH: "switch" >
323| < SYNCHRONIZED: "synchronized" >
324| < TRANSIENT: "transient" >
325| < THROW: "throw" >
326| < THROWS: "throws" >
327| < TRUE: "true" >
328| < TRY: "try" >
329| < VOID: "void" >
330| < VOLATILE: "volatile" >
331| < WHILE: "while" >
332}
333
334TOKEN : /* LITERALS */
335{
336  < INTEGER_LITERAL:
337        <DECIMAL_LITERAL> (["l","L"])?
338      | <HEX_LITERAL> (["l","L"])?
339      | <OCTAL_LITERAL> (["l","L"])?
340  >
341|
342  < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
343|
344  < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
345|
346  < #OCTAL_LITERAL: "0" (["0"-"7"])* >
347|
348  < FLOATING_POINT_LITERAL:
349        (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
350      | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
351      | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
352      | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
353  >
354|
355  < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
356|
357  < CHARACTER_LITERAL:
358      "'"
359      (   (~["'","\\","\n","\r"])
360        | ("\\"
361            ( ["n","t","b","r","f","\\","'","\""]
362            | ["0"-"7"] ( ["0"-"7"] )?
363            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
364            )
365          )
366      )
367      "'"
368  >
369|
370  < STRING_LITERAL:
371      "\""
372      (   (~["\"","\\","\n","\r"])
373        | ("\\"
374            ( ["n","t","b","r","f","\\","'","\""]
375            | ["0"-"7"] ( ["0"-"7"] )?
376            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
377            )
378          )
379      )*
380      "\""
381  >
382|
383  < LONG_STRING_LITERAL:
384      "\"\"\""
385      ( ~["\""] ("\"")? ("\"")? )*
386      "\"\"\""
387  >
388|
389   < FORMAL_COMMENT:
390		"/**" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/"
391	>
392}
393
394TOKEN : /* IDENTIFIERS */
395{
396  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
397|
398  < #LETTER:
399      [
400       "\u0024",
401       "\u0041"-"\u005a",
402       "\u005f",
403       "\u0061"-"\u007a",
404       "\u00c0"-"\u00d6",
405       "\u00d8"-"\u00f6",
406       "\u00f8"-"\u00ff",
407       "\u0100"-"\u1fff",
408       "\u3040"-"\u318f",
409       "\u3300"-"\u337f",
410       "\u3400"-"\u3d2d",
411       "\u4e00"-"\u9fff",
412       "\uf900"-"\ufaff"
413      ]
414  >
415|
416  < #DIGIT:
417      [
418       "\u0030"-"\u0039",
419       "\u0660"-"\u0669",
420       "\u06f0"-"\u06f9",
421       "\u0966"-"\u096f",
422       "\u09e6"-"\u09ef",
423       "\u0a66"-"\u0a6f",
424       "\u0ae6"-"\u0aef",
425       "\u0b66"-"\u0b6f",
426       "\u0be7"-"\u0bef",
427       "\u0c66"-"\u0c6f",
428       "\u0ce6"-"\u0cef",
429       "\u0d66"-"\u0d6f",
430       "\u0e50"-"\u0e59",
431       "\u0ed0"-"\u0ed9",
432       "\u1040"-"\u1049"
433      ]
434  >
435}
436
437TOKEN : /* SEPARATORS */
438{
439  < LPAREN: "(" >
440| < RPAREN: ")" >
441| < LBRACE: "{" >
442| < RBRACE: "}" >
443| < LBRACKET: "[" >
444| < RBRACKET: "]" >
445| < SEMICOLON: ";" >
446| < COMMA: "," >
447| < DOT: "." >
448}
449
450TOKEN : /* OPERATORS */
451{
452  < ASSIGN: "=" >
453| < GT: ">" >
454| < GTX: "@gt" >
455| < LT: "<" >
456| < LTX: "@lt" >
457| < BANG: "!" >
458| < TILDE: "~" >
459| < HOOK: "?" >
460| < COLON: ":" >
461| < EQ: "==" >
462| < LE: "<=" >
463| < LEX: "@lteq" >
464| < GE: ">=" >
465| < GEX: "@gteq" >
466| < NE: "!=" >
467| < BOOL_OR: "||" >
468| < BOOL_ORX: "@or" >
469| < BOOL_AND: "&&" >
470| < BOOL_ANDX: "@and" >
471| < INCR: "++" >
472| < DECR: "--" >
473| < PLUS: "+" >
474| < MINUS: "-" >
475| < STAR: "*" >
476| < SLASH: "/" >
477| < BIT_AND: "&" >
478| < BIT_ANDX: "@bitwise_and" >
479| < BIT_OR: "|" >
480| < BIT_ORX: "@bitwise_or" >
481| < XOR: "^" >
482| < MOD: "%" >
483| < LSHIFT: "<<" >
484| < LSHIFTX: "@left_shift" >
485| < RSIGNEDSHIFT: ">>" >
486| < RSIGNEDSHIFTX: "@right_shift" >
487| < RUNSIGNEDSHIFT: ">>>" >
488| < RUNSIGNEDSHIFTX: "@right_unsigned_shift" >
489| < PLUSASSIGN: "+=" >
490| < MINUSASSIGN: "-=" >
491| < STARASSIGN: "*=" >
492| < SLASHASSIGN: "/=" >
493| < ANDASSIGN: "&=" >
494| < ANDASSIGNX: "@and_assign" >
495| < ORASSIGN: "|=" >
496| < ORASSIGNX: "@or_assign" >
497| < XORASSIGN: "^=" >
498| < MODASSIGN: "%=" >
499| < LSHIFTASSIGN: "<<=" >
500| < LSHIFTASSIGNX: "@left_shift_assign" >
501| < RSIGNEDSHIFTASSIGN: ">>=" >
502| < RSIGNEDSHIFTASSIGNX: "@right_shift_assign" >
503| < RUNSIGNEDSHIFTASSIGN: ">>>=" >
504| < RUNSIGNEDSHIFTASSIGNX: "@right_unsigned_shift_assign" >
505}
506
507
508/*
509	Thanks to Sreenivasa Viswanadha for suggesting how to get rid of expensive
510	lookahead here.
511*/
512boolean Line() :
513{}
514{
515  <EOF> {
516	Interpreter.debug("End of File!");
517	return true;
518  }
519|
520  BlockStatement() {
521	return false;
522  }
523}
524
525/*****************************************
526 * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
527 *****************************************/
528
529/*
530	Gather modifiers for a class, method, or field.
531	I lookahead is true then we are being called as part of a lookahead and we
532	should not enforce any rules.  Otherwise we validate based on context
533	(field, method, class)
534*/
535Modifiers Modifiers( int context, boolean lookahead ) :
536{
537	Modifiers mods = null;
538}
539{
540  (
541	(
542		"private" |	"protected" | "public" | "synchronized" | "final"
543		| "native" | "transient" | "volatile" |	"abstract" | "static"
544		| "strictfp"
545	) {
546		if ( !lookahead )
547			try {
548				if ( mods == null ) mods = new Modifiers();
549				mods.addModifier( context, getToken(0).image );
550			} catch ( IllegalStateException e ) {
551				throw createParseException( e.getMessage(), e );
552			}
553	}
554  )* {
555  	return mods;
556  }
557}
558
559
560/**
561*/
562void ClassDeclaration() #ClassDeclaration :
563{
564	Modifiers mods;
565	Token name;
566	int numInterfaces;
567}
568{
569	mods = Modifiers( Modifiers.CLASS, false )
570	( "class" | "interface" { jjtThis.isInterface=true; } )
571	name=<IDENTIFIER>
572	[ "extends" AmbiguousName() { jjtThis.extend = true; } ]
573	[ "implements" numInterfaces=NameList()
574		{ jjtThis.numInterfaces=numInterfaces; } ]
575	Block()
576	{
577		jjtThis.modifiers = mods;
578		jjtThis.name = name.image;
579	}
580}
581
582void MethodDeclaration() #MethodDeclaration :
583{
584	Token t = null;
585	Modifiers mods;
586	int count;
587}
588{
589	mods = Modifiers( Modifiers.METHOD, false ) { jjtThis.modifiers = mods; }
590(
591	LOOKAHEAD( <IDENTIFIER> "(" )
592	t = <IDENTIFIER> { jjtThis.name = t.image; }
593|
594    ReturnType()
595	t = <IDENTIFIER> { jjtThis.name = t.image; }
596)
597    FormalParameters()
598	[ "throws" count=NameList() { jjtThis.numThrows=count; } ]
599	( Block() | ";" )
600}
601
602void PackageDeclaration () #PackageDeclaration:
603{ }
604{
605	"package" AmbiguousName()
606}
607
608void ImportDeclaration() #ImportDeclaration :
609{
610    Token s = null;
611	Token t = null;
612}
613{
614  LOOKAHEAD( 3 )
615  [ s = "static" ] "import" AmbiguousName() [ t = "." "*" ] ";"
616  {
617		if ( s != null ) jjtThis.staticImport = true;
618		if ( t != null ) jjtThis.importPackage = true;
619  }
620  |
621	// bsh super import statement
622  "import" "*" ";" {
623		jjtThis.superImport = true;
624	}
625}
626
627void VariableDeclarator() #VariableDeclarator :
628{
629	Token t;
630}
631{
632	t=<IDENTIFIER> [ "=" VariableInitializer() ]
633	{
634  		jjtThis.name = t.image;
635	}
636}
637
638/*
639this originally handled postfix array dimensions...
640
641void VariableDeclaratorId() #VariableDeclaratorId :
642{ Token t; }
643{
644  t=<IDENTIFIER> { jjtThis.name = t.image; }
645  ( "[" "]" { jjtThis.addUndefinedDimension(); } )*
646}
647*/
648
649void VariableInitializer() :
650{}
651{
652  ArrayInitializer()
653|
654  Expression()
655}
656
657void ArrayInitializer() #ArrayInitializer :
658{}
659{
660  "{" [ VariableInitializer()
661		( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}"
662}
663
664void FormalParameters() #FormalParameters :
665{}
666{
667  "(" [ FormalParameter() ( "," FormalParameter() )* ] ")"
668}
669
670void FormalParameter() #FormalParameter :
671{ Token t; }
672{
673  // added [] to Type for bsh.  Removed [ final ] - is that legal?
674  LOOKAHEAD(2) ["final"] Type() [ TypeArguments() ] t=<IDENTIFIER> { jjtThis.name = t.image; }
675|
676  t=<IDENTIFIER> { jjtThis.name = t.image; }
677}
678
679
680/*
681	Type, name and expression syntax follows.
682*/
683void Type() #Type :
684{ }
685{
686	/*
687		The embedded lookahead is (was?) necessary to disambiguate for
688		PrimaryPrefix.  ( )* is a choice point.  It took me a while to
689		figure out where to put that.  This stuff is annoying.
690	*/
691  ( PrimitiveType() | AmbiguousName() )
692	( LOOKAHEAD(2) "[" "]" { jjtThis.addArrayDimension(); } )*
693}
694
695/*
696	Originally called ResultType in the grammar
697*/
698void ReturnType() #ReturnType :
699{ }
700{
701  "void" { jjtThis.isVoid = true; }
702|
703  Type() [ TypeArguments() ]
704}
705
706void PrimitiveType() #PrimitiveType :
707{ } {
708  "boolean" { jjtThis.type = Boolean.TYPE; }
709| "char" { jjtThis.type =  Character.TYPE; }
710| "byte" { jjtThis.type =  Byte.TYPE; }
711| "short" { jjtThis.type =  Short.TYPE; }
712| "int" { jjtThis.type =  Integer.TYPE; }
713| "long" { jjtThis.type =  Long.TYPE; }
714| "float" { jjtThis.type =  Float.TYPE; }
715| "double" { jjtThis.type =  Double.TYPE; }
716}
717
718void AmbiguousName() #AmbiguousName :
719/*
720	A lookahead of 2 is required below since "Name" can be followed by a ".*"
721	when used in the context of an "ImportDeclaration".
722*/
723{
724    Token t;
725    StringBuilder s;
726}
727{
728  t = <IDENTIFIER> {
729  	s = new StringBuilder(t.image);
730  }
731  ( LOOKAHEAD(2) "." t = <IDENTIFIER> { s.append("."+t.image); } )* {
732  	jjtThis.text = s.toString();
733  }
734}
735
736int NameList() :
737{ int count = 0; }
738{
739  AmbiguousName() { ++count; } ( "," AmbiguousName() { ++count; } )*
740  { return count; }
741}
742
743/*
744 * Expression syntax follows.
745 */
746void Expression() :
747{ }
748{
749	/**
750		SYNTACTIC_LOOKAHEAD
751		Note: the original grammar was cheating here and we've fixed that,
752		but at the expense of another syntactic lookahead.
753	*/
754  LOOKAHEAD( PrimaryExpression() AssignmentOperator() )
755  Assignment()
756|
757  ConditionalExpression()
758}
759
760void Assignment() #Assignment :
761{ int op ; }
762{
763  PrimaryExpression()
764  	op = AssignmentOperator() { jjtThis.operator = op; }
765	// Add this for blocks, e.g. foo = { };
766	//( Expression() | Block() )
767	Expression()
768}
769
770int AssignmentOperator() :
771{ Token t; }
772{
773    ( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "&=" | "^=" | "|=" |
774      "<<=" | "@left_shift_assign" | ">>=" | "@right_shift_assign" |
775      ">>>=" | "@right_unsigned_shift_assign" )
776    {
777        t = getToken(0);
778        return t.kind;
779    }
780}
781
782void ConditionalExpression() :
783{ }
784{
785  ConditionalOrExpression() [ "?" Expression() ":" ConditionalExpression()
786	#TernaryExpression(3) ]
787}
788
789void ConditionalOrExpression() :
790{ Token t=null; }
791{
792  ConditionalAndExpression()
793  ( ( t = "||" | t = "@or" )
794    ConditionalAndExpression()
795    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
796}
797
798void ConditionalAndExpression() :
799{ Token t=null; }
800{
801  InclusiveOrExpression()
802  ( ( t = "&&" | t = "@and" )
803    InclusiveOrExpression()
804    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
805}
806
807void InclusiveOrExpression() :
808{ Token t=null; }
809{
810  ExclusiveOrExpression()
811  ( ( t = "|" | t = "@bitwise_or" )
812    ExclusiveOrExpression()
813    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
814}
815
816void ExclusiveOrExpression() :
817{ Token t=null; }
818{
819  AndExpression() ( t="^" AndExpression()
820    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
821}
822
823void AndExpression() :
824{ Token t=null; }
825{
826  EqualityExpression()
827  ( ( t = "&" | t = "@bitwise_and" )
828    EqualityExpression()
829    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
830}
831
832void EqualityExpression() :
833{ Token t = null; }
834{
835  InstanceOfExpression() ( ( t= "==" | t= "!=" ) InstanceOfExpression()
836    { jjtThis.kind = t.kind; } #BinaryExpression(2)
837  )*
838}
839
840void InstanceOfExpression() :
841{ Token t = null; }
842{
843  RelationalExpression()
844  [ t = "instanceof" Type() { jjtThis.kind = t.kind; } #BinaryExpression(2) ]
845}
846
847void RelationalExpression() :
848{ Token t = null; }
849{
850  ShiftExpression()
851  ( ( t = "<" | t = "@lt" | t = ">" | t = "@gt" |
852      t = "<=" | t = "@lteq" | t = ">=" | t = "@gteq" )
853  ShiftExpression()
854  { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
855}
856
857void ShiftExpression() :
858{ Token t = null; }
859{
860  AdditiveExpression()
861  ( ( t = "<<" | t = "@left_shift" | t = ">>" | t = "@right_shift" |
862      t = ">>>" | t = "@right_unsigned_shift" )
863  AdditiveExpression()
864  { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
865}
866
867void AdditiveExpression() :
868{ Token t = null; }
869{
870  MultiplicativeExpression()
871  ( ( t= "+" | t= "-" ) MultiplicativeExpression() { jjtThis.kind = t.kind; }
872    #BinaryExpression(2)
873  )*
874}
875
876void MultiplicativeExpression() :
877{ Token t = null; }
878{
879  UnaryExpression() ( ( t= "*" | t= "/" | t= "%" )
880  UnaryExpression() { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
881}
882
883void UnaryExpression() :
884{ Token t = null; }
885{
886  ( t="+" | t="-" ) UnaryExpression()
887    { jjtThis.kind = t.kind; } #UnaryExpression(1)
888|
889  PreIncrementExpression()
890|
891  PreDecrementExpression()
892|
893  UnaryExpressionNotPlusMinus()
894}
895
896void PreIncrementExpression() :
897{ Token t = null; }
898{
899  t="++" PrimaryExpression()
900    { jjtThis.kind = t.kind; } #UnaryExpression(1)
901}
902
903void PreDecrementExpression() :
904{ Token t = null; }
905{
906  t="--" PrimaryExpression()
907    { jjtThis.kind = t.kind; } #UnaryExpression(1)
908}
909
910void UnaryExpressionNotPlusMinus() :
911{ Token t = null; }
912{
913  ( t="~" | t="!" ) UnaryExpression()
914    { jjtThis.kind = t.kind; } #UnaryExpression(1)
915|
916	// SYNTACTIC_LOOKAHEAD
917  LOOKAHEAD( CastLookahead() ) CastExpression()
918|
919  PostfixExpression()
920}
921
922// This production is to determine lookahead only.
923void CastLookahead() : { }
924{
925  LOOKAHEAD(2) "(" PrimitiveType()
926|
927// SYNTACTIC_LOOKAHEAD
928  LOOKAHEAD( "(" AmbiguousName() "[" ) "(" AmbiguousName() "[" "]"
929|
930  "(" AmbiguousName() ")" ( "~" | "!" | "(" | <IDENTIFIER> | /* "this" | "super" | */ "new" | Literal() )
931}
932
933void PostfixExpression() :
934{ Token t = null; }
935{
936// SYNTACTIC_LOOKAHEAD
937  LOOKAHEAD( PrimaryExpression() ("++"|"--") )
938  PrimaryExpression()
939	  ( t="++" | t="--" ) {
940		jjtThis.kind = t.kind; jjtThis.postfix = true; } #UnaryExpression(1)
941|
942  PrimaryExpression()
943}
944
945void CastExpression() #CastExpression :
946{ }
947{
948// SYNTACTIC_LOOKAHEAD
949  LOOKAHEAD( "(" PrimitiveType() ) "(" Type() ")" UnaryExpression()
950|
951  "(" Type() ")" UnaryExpressionNotPlusMinus()
952}
953
954void PrimaryExpression() #PrimaryExpression : { }
955{
956  PrimaryPrefix() ( PrimarySuffix() )*
957}
958
959void MethodInvocation() #MethodInvocation : { }
960{
961   AmbiguousName() Arguments()
962}
963
964void PrimaryPrefix() : { }
965{
966  Literal()
967|
968  "(" Expression() ")"
969|
970  AllocationExpression()
971|
972  // SYNTACTIC_LOOKAHEAD
973  LOOKAHEAD( MethodInvocation() )
974	MethodInvocation()
975|
976  LOOKAHEAD( Type() "." "class" )
977	Type()
978|
979  AmbiguousName()
980
981/*
982|
983  LOOKAHEAD( "void" "." "class" )
984*/
985}
986
987void PrimarySuffix() #PrimarySuffix :
988{
989    Token t = null;
990}
991{
992  LOOKAHEAD(2)
993  "." "class" {
994        jjtThis.operation = BSHPrimarySuffix.CLASS;
995    }
996|
997  "[" Expression() "]" {
998        jjtThis.operation = BSHPrimarySuffix.INDEX;
999    }
1000|
1001    // Field access or method invocation
1002  "." t = <IDENTIFIER> [ Arguments() ] {
1003        jjtThis.operation = BSHPrimarySuffix.NAME;
1004        jjtThis.field = t.image;
1005    }
1006|
1007  "{" Expression() "}" {
1008        jjtThis.operation = BSHPrimarySuffix.PROPERTY;
1009    }
1010/*
1011    For inner classes
1012|
1013  LOOKAHEAD(2)
1014  "." AllocationExpression()
1015*/
1016}
1017
1018void Literal() #Literal :
1019{
1020    Token x;
1021    boolean b;
1022    String literal;
1023    char ch;
1024}
1025{
1026  x = <INTEGER_LITERAL>
1027  {
1028    literal = x.image;
1029    ch = literal.charAt(literal.length()-1);
1030    if(ch == 'l' || ch == 'L')
1031    {
1032        literal = literal.substring(0,literal.length()-1);
1033		try {
1034        	jjtThis.value = new Primitive( parseLong(literal) );
1035		} catch ( NumberFormatException e ) {
1036			throw createParseException( e.getMessage(), e );
1037		}
1038    }
1039    else
1040		try {
1041        	jjtThis.value = new Primitive( parseInt(literal) );
1042		} catch ( NumberFormatException e ) {
1043			throw createParseException( e.getMessage(), e );
1044		}
1045  }
1046|
1047  x = <FLOATING_POINT_LITERAL>
1048  {
1049    literal = x.image;
1050    ch = literal.charAt(literal.length()-1);
1051    if(ch == 'f' || ch == 'F')
1052    {
1053        literal = literal.substring(0,literal.length()-1);
1054        jjtThis.value = new Primitive( new Float( literal ).floatValue() );
1055    }
1056    else
1057    {
1058        if(ch == 'd' || ch == 'D')
1059            literal = literal.substring(0,literal.length()-1);
1060
1061        jjtThis.value = new Primitive( new Double( literal ).doubleValue() );
1062    }
1063  }
1064|
1065  x = <CHARACTER_LITERAL> {
1066		try {
1067    		jjtThis.charSetup( x.image.substring(1, x.image.length() - 1) );
1068		} catch ( Exception e ) {
1069			throw createParseException("Error parsing character: "+x.image, e);
1070		}
1071    }
1072|
1073  x = <STRING_LITERAL> {
1074		try {
1075			jjtThis.stringSetup( x.image.substring(1, x.image.length() - 1) );
1076		} catch ( Exception e ) {
1077			throw createParseException("Error parsing string: "+x.image, e);
1078		}
1079    }
1080|
1081  x = <LONG_STRING_LITERAL> {
1082		try {
1083			jjtThis.value = x.image.substring(3, x.image.length() - 3);
1084		} catch ( Exception e ) {
1085			throw createParseException("Error parsing long string: "+x.image, e);
1086		}
1087    }
1088|
1089  b = BooleanLiteral()  {
1090    jjtThis.value = b ? Primitive.TRUE : Primitive.FALSE; }
1091|
1092  NullLiteral() {
1093    jjtThis.value = Primitive.NULL;
1094}
1095|
1096 VoidLiteral() {
1097    jjtThis.value = Primitive.VOID; }
1098}
1099
1100boolean BooleanLiteral() :
1101{}
1102{
1103  "true" { return true; }
1104|
1105  "false" { return false; }
1106}
1107
1108void NullLiteral() :
1109{}
1110{
1111  "null"
1112}
1113
1114void VoidLiteral() :
1115{}
1116{
1117  "void"
1118}
1119
1120void Arguments() #Arguments :
1121{ }
1122{
1123  "(" [ ArgumentList()  ]  ")"
1124}
1125
1126// leave these on the stack for Arguments() to handle
1127void ArgumentList() :
1128{ }
1129{
1130  Expression()
1131  ( "," Expression() )*
1132}
1133
1134void TypeArguments() :
1135{ }
1136{
1137	"<" <IDENTIFIER> ">"
1138}
1139
1140void AllocationExpression() #AllocationExpression :
1141{ }
1142{
1143  LOOKAHEAD(2)
1144  "new" PrimitiveType() ArrayDimensions()
1145|
1146  "new" AmbiguousName() [ TypeArguments() ]
1147	(
1148		ArrayDimensions()
1149	|
1150		// SYNTACTIC_LOOKAHEAD
1151		Arguments() [ LOOKAHEAD(2) Block() ]
1152	)
1153}
1154
1155void ArrayDimensions() #ArrayDimensions :
1156{}
1157{
1158	// e.g. int [4][3][][];
1159  LOOKAHEAD(2)
1160  ( LOOKAHEAD(2) "[" Expression() "]" { jjtThis.addDefinedDimension(); } )+
1161  ( LOOKAHEAD(2) "[" "]" { jjtThis.addUndefinedDimension(); } )*
1162|
1163	// e.g. int [][] { {1,2}, {3,4} };
1164  ( "[" "]" { jjtThis.addUndefinedDimension(); } )+ ArrayInitializer()
1165}
1166
1167
1168/*
1169 * Statement syntax follows.
1170 */
1171
1172void Statement() : { }
1173{
1174  LOOKAHEAD(2)
1175  LabeledStatement()
1176|
1177  Block()
1178|
1179  EmptyStatement()
1180|
1181  StatementExpression() ";"
1182|
1183  SwitchStatement()
1184|
1185  IfStatement()
1186|
1187  WhileStatement()
1188|
1189  DoStatement()
1190|
1191  LOOKAHEAD ( { isRegularForStatement() } )
1192  ForStatement()
1193|
1194  EnhancedForStatement()
1195|
1196  BreakStatement()
1197|
1198  ContinueStatement()
1199|
1200  ReturnStatement()
1201|
1202  SynchronizedStatement()
1203|
1204  ThrowStatement()
1205|
1206  TryStatement()
1207}
1208
1209void LabeledStatement() :
1210{}
1211{
1212  <IDENTIFIER> ":" Statement()
1213}
1214
1215void Block() #Block :
1216{}
1217{
1218  "{" ( BlockStatement() )* "}"
1219}
1220
1221void BlockStatement() :
1222{
1223}
1224{
1225  LOOKAHEAD( Modifiers( Modifiers.FIELD, true ) ( "class" | "interface" ) )
1226  ClassDeclaration()
1227|
1228  LOOKAHEAD ( Modifiers( Modifiers.METHOD, true )
1229		ReturnType() <IDENTIFIER> "("
1230  )
1231  	MethodDeclaration()
1232|
1233  LOOKAHEAD ( Modifiers( Modifiers.METHOD, true )
1234		<IDENTIFIER> FormalParameters() [ "throws" NameList() ] "{"
1235  )
1236  	MethodDeclaration()
1237|
1238  // SYNTACTIC_LOOKAHEAD
1239  LOOKAHEAD( Modifiers( Modifiers.FIELD, true ) Type() [ TypeArguments() ] <IDENTIFIER> )
1240  TypedVariableDeclaration() ";"
1241|
1242  Statement()
1243
1244|
1245  // Allow BeanShell imports in any block
1246  ImportDeclaration()
1247|
1248  // Allow BeanShell package declarations in any block
1249  PackageDeclaration()
1250|
1251  FormalComment()
1252}
1253
1254void FormalComment() #FormalComment( retainComments ) :
1255{
1256	Token t;
1257}
1258{
1259	t=<FORMAL_COMMENT>  {
1260		jjtThis.text=t.image;
1261	}
1262}
1263
1264void EmptyStatement() :
1265{}
1266{
1267  ";"
1268}
1269
1270void StatementExpression() :
1271{ }
1272{
1273  /*
1274	This is looser than normal Java to simplify the grammar.  This allows
1275	us to type arbitrary expressions on the command line, e.g. "1+1;"
1276	We should turn this off in the implementation in strict java mode.
1277  */
1278  Expression()
1279/*
1280	// This was the original Java grammar.
1281
1282	//  Original comment:
1283	//  The last expansion of this production accepts more than the legal
1284	//  Java expansions for StatementExpression.
1285	  PreIncrementExpression()
1286	|
1287	  PreDecrementExpression()
1288	|
1289	  // SYNTACTIC_LOOKAHEAD
1290	  LOOKAHEAD( PrimaryExpression() AssignmentOperator() )
1291	  Assignment() { }
1292	|
1293	  PostfixExpression()
1294*/
1295
1296}
1297
1298void SwitchStatement() #SwitchStatement :
1299{}
1300{
1301  "switch" "(" Expression() ")" "{"
1302    ( SwitchLabel() ( BlockStatement() )* )*
1303  "}"
1304}
1305
1306void SwitchLabel() #SwitchLabel :
1307{}
1308{
1309  "case" Expression() ":"
1310|
1311  "default" ":" { jjtThis.isDefault = true; }
1312}
1313
1314void IfStatement() #IfStatement :
1315/*
1316 * The disambiguating algorithm of JavaCC automatically binds dangling
1317 * else's to the innermost if statement.  The LOOKAHEAD specification
1318 * is to tell JavaCC that we know what we are doing.
1319 */
1320{}
1321{
1322  "if" "(" Expression() ")" Statement() [ LOOKAHEAD(1) "else" Statement() ]
1323}
1324
1325void WhileStatement() #WhileStatement :
1326{}
1327{
1328  "while" "(" Expression() ")" Statement()
1329}
1330
1331/*
1332	Do statement is just a While statement with a special hook to execute
1333	at least once.
1334*/
1335void DoStatement() #WhileStatement :
1336{}
1337{
1338  "do" Statement() "while" "(" Expression() ")" ";"
1339	{ jjtThis.isDoStatement=true;  }
1340}
1341
1342void ForStatement() #ForStatement :
1343{ Token t = null; }
1344{
1345  "for" "(" [ ForInit() { jjtThis.hasForInit=true; } ]
1346    ";" [ Expression() { jjtThis.hasExpression=true; } ]
1347    ";" [ ForUpdate() { jjtThis.hasForUpdate=true; } ] ")"
1348    Statement()
1349}
1350
1351/*
1352	The new JDK1.5 enhanced for statement.
1353	e.g. for( int a : arrayOfInts ) { }
1354	We also support loose typing of the iterator var for BeanShell
1355	e.g. for( a : arrayOfInts ) { }
1356*/
1357void EnhancedForStatement() #EnhancedForStatement :
1358{ Token t = null; }
1359{
1360  LOOKAHEAD( 4 ) // look ahead for the ":" before deciding
1361  "for" "(" t=<IDENTIFIER> ":" Expression() ")"
1362    Statement() { jjtThis.varName = t.image; }
1363  |
1364  "for" "(" Type() t=<IDENTIFIER> ":" Expression() ")"
1365    Statement() { jjtThis.varName = t.image; }
1366}
1367
1368void ForInit() :
1369{ Token t = null; }
1370{
1371// SYNTACTIC_LOOKAHEAD
1372  LOOKAHEAD( Modifiers( Modifiers.FIELD, true ) Type() <IDENTIFIER> )
1373  TypedVariableDeclaration()
1374|
1375  StatementExpressionList()
1376}
1377
1378/**
1379	Declared a typed variable.
1380	Untyped variables are not declared per-se but are handled by the part
1381	of the grammar that deals with assignments.
1382*/
1383void TypedVariableDeclaration() #TypedVariableDeclaration :
1384{
1385	Token t = null;
1386	Modifiers mods;
1387}
1388{
1389	mods = Modifiers( Modifiers.FIELD, false )
1390  	Type() [ TypeArguments() ] VariableDeclarator() ( "," VariableDeclarator() )*
1391	{
1392        jjtThis.modifiers = mods;
1393    }
1394}
1395
1396void StatementExpressionList() #StatementExpressionList :
1397{}
1398{
1399  StatementExpression() ( "," StatementExpression() )*
1400}
1401
1402void ForUpdate() :
1403{}
1404{
1405  StatementExpressionList()
1406}
1407
1408void BreakStatement() #ReturnStatement :
1409{}
1410{
1411  "break" [ <IDENTIFIER> ] ";" { jjtThis.kind = BREAK; }
1412}
1413
1414void ContinueStatement() #ReturnStatement :
1415{}
1416{
1417  "continue" [ <IDENTIFIER> ] ";" { jjtThis.kind = CONTINUE; }
1418}
1419
1420void ReturnStatement() #ReturnStatement :
1421{}
1422{
1423  "return" [ Expression() ] ";" { jjtThis.kind = RETURN; }
1424}
1425
1426void SynchronizedStatement() #Block :
1427{
1428}
1429{
1430  "synchronized" "(" Expression() ")" Block() {
1431  		jjtThis.isSynchronized=true;
1432  }
1433}
1434
1435void ThrowStatement() #ThrowStatement :
1436{}
1437{
1438  "throw" Expression() ";"
1439}
1440
1441void TryStatement() #TryStatement:
1442/*
1443	Semantic check required here to make sure that at least one
1444	finally/catch is present.  (You can have a try with finally and no catch).
1445 */
1446{ boolean closed = false; }
1447{
1448	"try" Block()
1449	( "catch" "(" FormalParameter() ")" Block() { closed = true; } )*
1450	[ "finally" Block() { closed = true; } ]
1451	{
1452		if ( !closed ) throw generateParseException();
1453	}
1454}
1455