PageRenderTime 85ms CodeModel.GetById 21ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/bsh/bsh.jjt

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