PageRenderTime 2289ms CodeModel.GetById 410ms app.highlight 98ms RepoModel.GetById 2ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre4/bsh/bsh.jjt

#
Unknown | 1286 lines | 1172 code | 114 blank | 0 comment | 0 complexity | a44a0fde74aa281fdf6f07a77109755d 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
  58PARSER_BEGIN(Parser)
  59package bsh;
  60
  61import java.io.*;
  62
  63/**
  64	This is the BeanShell parser.  It is used internally by the Interpreter
  65	class (which is probably what you are looking for).  The parser knows
  66	only how to parse the structure of the language, it does not understand
  67	names, commands, etc.
  68	<p>
  69	You can use the Parser from the command line to do basic structural 
  70	validation of BeanShell files without actually executing them. e.g.
  71	<code><pre>
  72		java bsh.Parser [ -p ] file [ file ] [ ... ]
  73	</pre></code>
  74	<p>
  75	The -p option causes the abstract syntax to be printed.
  76	<p>
  77
  78	From code you'd use the Parser like this:
  79	<p
  80	<code><pre>
  81		Parser parser = new Parser(in);
  82		while( !(eof=parser.Line()) ) {
  83			SimpleNode node = parser.popNode();
  84			// use the node, etc. (See bsh.BSH* classes)
  85		}
  86	</pre></code>
  87*/
  88public class Parser 
  89{ 
  90	boolean retainComments = false;
  91	
  92	public void setRetainComments( boolean b ) {
  93		retainComments = b;
  94	}
  95
  96	void jjtreeOpenNodeScope(Node n) {
  97		((SimpleNode)n).firstToken = getToken(1);
  98	}
  99
 100	void jjtreeCloseNodeScope(Node n) {
 101		((SimpleNode)n).lastToken = getToken(0);
 102	}
 103
 104	/**
 105		Re-initialize the input stream and token source.
 106	*/
 107	void reInitInput( Reader in ) {
 108		ReInit(in);
 109	}
 110
 111	public SimpleNode popNode() 
 112	{
 113		if ( jjtree.nodeArity() > 0)  // number of child nodes 
 114			return (SimpleNode)jjtree.popNode();
 115		else
 116			return null;
 117	}
 118
 119	/**
 120		Explicitly re-initialize just the token reader.
 121		This seems to be necessary to avoid certain looping errors when
 122		reading bogus input.  See Interpreter.
 123	*/
 124	void reInitTokenInput( Reader in ) {
 125		jj_input_stream.ReInit( in, 
 126			jj_input_stream.getEndLine(), 
 127			jj_input_stream.getEndColumn() );
 128	}
 129
 130	public static void main( String [] args ) 
 131		throws IOException, ParseException
 132	{
 133		boolean print = false;
 134		int i=0;
 135		if ( args[0].equals("-p") ) {
 136			i++;
 137			print=true;
 138		}
 139		for(; i< args.length; i++) {
 140			Reader in = new FileReader(args[i]);
 141			Parser parser = new Parser(in);
 142			parser.setRetainComments(true);
 143			while( !parser.Line()/*eof*/ )
 144				if ( print )
 145					System.out.println( parser.popNode() );
 146		}
 147	}
 148
 149}
 150
 151
 152PARSER_END(Parser)
 153
 154SKIP : /* WHITE SPACE */
 155{ 
 156	" " | "\t" | "\r" | "\f"
 157	| "\n" 
 158	| < NONPRINTABLE: (["\u0000"-"\u0020", "\u0080"-"\u00ff"])+ >
 159}
 160
 161SPECIAL_TOKEN : /* COMMENTS */
 162{
 163/*
 164	SINGLE_LINE_COMMENT includes a hack to accept SLC at the end of a file
 165	with no terminanting linefeed.  This is actually illegal according to 
 166	spec, but comes up often enough to warrant it... (especially in eval()).
 167*/
 168  <SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")? >
 169
 170| <HASH_BANG_COMMENT: "#!" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
 171
 172 /* Moved FORMAL_COMMENT to a real token.  Modified MULTI_LINE_COMMENT to not 
 173    catch formal comments (require no star after star) */
 174| <MULTI_LINE_COMMENT: 
 175	"/*" (~["*"])+ "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
 176}
 177
 178TOKEN : /* RESERVED WORDS AND LITERALS */
 179{
 180< BOOLEAN: "boolean" >
 181| < BREAK: "break" >
 182| < CLASS: "class" >
 183| < BYTE: "byte" >
 184| < CASE: "case" >
 185| < CATCH: "catch" >
 186| < CHAR: "char" >
 187| < CONST: "const" >
 188| < CONTINUE: "continue" >
 189| < _DEFAULT: "default" >
 190| < DO: "do" >
 191| < DOUBLE: "double" >
 192| < ELSE: "else" >
 193| < FALSE: "false" >
 194| < FINAL: "final" >
 195| < FINALLY: "finally" >
 196| < FLOAT: "float" >
 197| < FOR: "for" >
 198| < GOTO: "goto" >
 199| < IF: "if" >
 200| < IMPORT: "import" >
 201| < INSTANCEOF: "instanceof" >
 202| < INT: "int" >
 203| < INTERFACE: "interface" >
 204| < LONG: "long" >
 205| < NEW: "new" >
 206| < NULL: "null" >
 207| < PRIVATE: "private" >
 208| < PROTECTED: "protected" >
 209| < PUBLIC: "public" >
 210| < RETURN: "return" >
 211| < SHORT: "short" >
 212| < STATIC: "static" >
 213| < SWITCH: "switch" >
 214| < THROW: "throw" >
 215| < TRUE: "true" >
 216| < TRY: "try" >
 217| < VOID: "void" >
 218| < WHILE: "while" >
 219}
 220
 221TOKEN : /* LITERALS */
 222{
 223  < INTEGER_LITERAL:
 224        <DECIMAL_LITERAL> (["l","L"])?
 225      | <HEX_LITERAL> (["l","L"])?
 226      | <OCTAL_LITERAL> (["l","L"])?
 227  >
 228|
 229  < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
 230|
 231  < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
 232|
 233  < #OCTAL_LITERAL: "0" (["0"-"7"])* >
 234|
 235  < FLOATING_POINT_LITERAL:
 236        (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
 237      | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
 238      | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
 239      | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
 240  >
 241|
 242  < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
 243|
 244  < CHARACTER_LITERAL:
 245      "'"
 246      (   (~["'","\\","\n","\r"])
 247        | ("\\"
 248            ( ["n","t","b","r","f","\\","'","\""]
 249            | ["0"-"7"] ( ["0"-"7"] )?
 250            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
 251            )
 252          )
 253      )
 254      "'"
 255  >
 256|
 257  < STRING_LITERAL:
 258      "\""
 259      (   (~["\"","\\","\n","\r"])
 260        | ("\\"
 261            ( ["n","t","b","r","f","\\","'","\""]
 262            | ["0"-"7"] ( ["0"-"7"] )?
 263            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
 264            )
 265          )
 266      )*
 267      "\""
 268  >
 269|
 270   < FORMAL_COMMENT: 
 271		"/**" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/"
 272	>
 273}
 274
 275TOKEN : /* IDENTIFIERS */
 276{
 277  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
 278|
 279  < #LETTER:
 280      [
 281       "\u0024",
 282       "\u0041"-"\u005a",
 283       "\u005f",
 284       "\u0061"-"\u007a",
 285       "\u00c0"-"\u00d6",
 286       "\u00d8"-"\u00f6",
 287       "\u00f8"-"\u00ff",
 288       "\u0100"-"\u1fff",
 289       "\u3040"-"\u318f",
 290       "\u3300"-"\u337f",
 291       "\u3400"-"\u3d2d",
 292       "\u4e00"-"\u9fff",
 293       "\uf900"-"\ufaff"
 294      ]
 295  >
 296|
 297  < #DIGIT:
 298      [
 299       "\u0030"-"\u0039",
 300       "\u0660"-"\u0669",
 301       "\u06f0"-"\u06f9",
 302       "\u0966"-"\u096f",
 303       "\u09e6"-"\u09ef",
 304       "\u0a66"-"\u0a6f",
 305       "\u0ae6"-"\u0aef",
 306       "\u0b66"-"\u0b6f",
 307       "\u0be7"-"\u0bef",
 308       "\u0c66"-"\u0c6f",
 309       "\u0ce6"-"\u0cef",
 310       "\u0d66"-"\u0d6f",
 311       "\u0e50"-"\u0e59",
 312       "\u0ed0"-"\u0ed9",
 313       "\u1040"-"\u1049"
 314      ]
 315  >
 316}
 317
 318TOKEN : /* SEPARATORS */
 319{
 320  < LPAREN: "(" >
 321| < RPAREN: ")" >
 322| < LBRACE: "{" >
 323| < RBRACE: "}" >
 324| < LBRACKET: "[" >
 325| < RBRACKET: "]" >
 326| < SEMICOLON: ";" >
 327| < COMMA: "," >
 328| < DOT: "." >
 329}
 330
 331TOKEN : /* OPERATORS */
 332{
 333  < ASSIGN: "=" >
 334| < GT: ">" >
 335| < GTX: "@gt" >
 336| < LT: "<" >
 337| < LTX: "@lt" >
 338| < BANG: "!" >
 339| < TILDE: "~" >
 340| < HOOK: "?" >
 341| < COLON: ":" >
 342| < EQ: "==" >
 343| < LE: "<=" >
 344| < LEX: "@lteq" >
 345| < GE: ">=" >
 346| < GEX: "@gteq" >
 347| < NE: "!=" >
 348| < BOOL_OR: "||" >
 349| < BOOL_ORX: "@or" >
 350| < BOOL_AND: "&&" >
 351| < BOOL_ANDX: "@and" >
 352| < INCR: "++" >
 353| < DECR: "--" >
 354| < PLUS: "+" >
 355| < MINUS: "-" >
 356| < STAR: "*" >
 357| < SLASH: "/" >
 358| < BIT_AND: "&" >
 359| < BIT_ANDX: "@bitwise_and" >
 360| < BIT_OR: "|" >
 361| < BIT_ORX: "@bitwise_or" >
 362| < XOR: "^" >
 363| < MOD: "%" >
 364| < LSHIFT: "<<" >
 365| < LSHIFTX: "@left_shift" >
 366| < RSIGNEDSHIFT: ">>" >
 367| < RSIGNEDSHIFTX: "@right_shift" >
 368| < RUNSIGNEDSHIFT: ">>>" >
 369| < RUNSIGNEDSHIFTX: "@right_unsigned_shift" >
 370| < PLUSASSIGN: "+=" >
 371| < MINUSASSIGN: "-=" >
 372| < STARASSIGN: "*=" >
 373| < SLASHASSIGN: "/=" >
 374| < ANDASSIGN: "&=" >
 375| < ANDASSIGNX: "@and_assign" >
 376| < ORASSIGN: "|=" >
 377| < ORASSIGNX: "@or_assign" >
 378| < XORASSIGN: "^=" >
 379| < MODASSIGN: "%=" >
 380| < LSHIFTASSIGN: "<<=" >
 381| < LSHIFTASSIGNX: "@left_shift_assign" >
 382| < RSIGNEDSHIFTASSIGN: ">>=" >
 383| < RSIGNEDSHIFTASSIGNX: "@right_shift_assign" >
 384| < RUNSIGNEDSHIFTASSIGN: ">>>=" >
 385| < RUNSIGNEDSHIFTASSIGNX: "@right_unsigned_shift_assign" >
 386}
 387
 388
 389boolean Line() :
 390{}
 391{
 392  <EOF> { 
 393	Interpreter.debug("End of File!"); 
 394	return true; 
 395	}
 396|
 397  (
 398	/*
 399		SYNTACTIC_LOOKAHEAD
 400		I'm guessing this is expensive, but I don't know how to work around
 401		it...  Is there another syntactic indication that we are working 
 402		through an expression as opposed to a statement?
 403		What is the difference?  Well, some statements don't require a
 404		semicolon and they don't return vlues...  We could probably broaden
 405		bsh to allow everything to return a value, but the semi-colon thing
 406		is tougher.  You don't want to have to say if ( foo ) { } ;
 407		Maybe we can invert ths and enumerate all of those types of 
 408		statements in a special lookahead that's cheaper??
 409	*/
 410   LOOKAHEAD( Expression() ";" )
 411   Expression() ";" 
 412  |
 413   BlockStatement()
 414  )
 415	{ 
 416		return false; 
 417	}
 418}
 419
 420/*****************************************
 421 * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
 422 *****************************************/
 423
 424void MethodDeclaration() #MethodDeclaration :
 425{ Token t = null; }
 426{
 427	// SYNTACTIC_LOOKAHEAD
 428	// this one seems cheap enough
 429    LOOKAHEAD( MethodDeclarationTypeLookahead() )
 430    ReturnType() t = <IDENTIFIER> { jjtThis.name = t.image; }
 431    FormalParameters() Block()
 432|
 433    t = <IDENTIFIER> { jjtThis.name = t.image; }
 434    FormalParameters() Block()
 435}
 436
 437void MethodDeclarationLookahead() : { }
 438{
 439	// SYNTACTIC_LOOKAHEAD
 440	// this one seems cheap enough
 441    LOOKAHEAD( MethodDeclarationTypeLookahead() )
 442    ReturnType() <IDENTIFIER> FormalParameters() "{"
 443|
 444    <IDENTIFIER> FormalParameters() "{"
 445}
 446
 447void MethodDeclarationTypeLookahead() : { }
 448{
 449    ReturnType() <IDENTIFIER> "("
 450}
 451
 452void ImportDeclaration() #ImportDeclaration :
 453{
 454    Token t = null;
 455}
 456{
 457  LOOKAHEAD( 2 )
 458
 459  "import" AmbiguousName() [ t = "." "*" ] ";" {
 460    if ( t != null )
 461        jjtThis.importPackage = true;
 462    }
 463  |
 464	// bsh super import statement
 465  "import" "*" ";" {
 466		jjtThis.superImport = true;
 467	}
 468}
 469
 470void VariableDeclarator() #VariableDeclarator :
 471{ Token t; }
 472{
 473  t=<IDENTIFIER> [ "=" VariableInitializer() ] { jjtThis.name = t.image; }
 474}
 475
 476/*
 477Can get rid of this if we ignore postfix array dimensions in declarations.
 478I don't like them and I don't want to deal with them right now.
 479
 480void VariableDeclaratorId() #VariableDeclaratorId :
 481{ Token t; }
 482{
 483  t=<IDENTIFIER> { jjtThis.name = t.image; }
 484  ( "[" "]" { jjtThis.addArrayDimension(); } )*
 485}
 486*/
 487
 488void VariableInitializer() :
 489{}
 490{
 491  ArrayInitializer()
 492|
 493  Expression()
 494}
 495
 496void ArrayInitializer() #ArrayInitializer :
 497{}
 498{
 499  "{" [ VariableInitializer() 
 500		( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}"
 501}
 502
 503void FormalParameters() #FormalParameters :
 504{}
 505{
 506  "(" [ FormalParameter() ( "," FormalParameter() )* ] ")"
 507}
 508
 509/*
 510void FormalParameter() #FormalParameter :
 511{ Token t; }
 512{
 513    // added [] to Type for bsh.  Removed [ final ] - is that legal?
 514  [ LOOKAHEAD(2) Type() ] t=<IDENTIFIER> { jjtThis.name = t.image; }
 515}
 516*/
 517void FormalParameter() #FormalParameter :
 518{ Token t; }
 519{
 520  // added [] to Type for bsh.  Removed [ final ] - is that legal?
 521  LOOKAHEAD(2) Type() t=<IDENTIFIER> { jjtThis.name = t.image; }
 522|
 523  t=<IDENTIFIER> { jjtThis.name = t.image; }
 524}
 525
 526
 527/*
 528	Type, name and expression syntax follows.
 529*/
 530void Type() #Type :
 531{ }
 532{
 533	/* 
 534		The embedded lookahead is (was?) necessary to disambiguate for
 535		PrimaryPrefix.  ( )* is a choice point.  It took me a while to
 536		figure out where to put that.  This stuff is annoying.
 537	*/
 538  ( PrimitiveType() | AmbiguousName() ) 
 539	( LOOKAHEAD(2) "[" "]" { jjtThis.addArrayDimension(); } )* 
 540}
 541
 542/*
 543	Originally called ResultType in the grammar
 544*/
 545void ReturnType() #ReturnType :
 546{ }
 547{
 548  "void" { jjtThis.isVoid = true; }
 549|
 550  Type()
 551}
 552
 553void PrimitiveType() #PrimitiveType :
 554{ } {
 555"boolean" { jjtThis.type = Boolean.TYPE; }
 556| "char" { jjtThis.type =  Character.TYPE; }
 557| "byte" { jjtThis.type =  Byte.TYPE; }
 558| "short" { jjtThis.type =  Short.TYPE; }
 559| "int" { jjtThis.type =  Integer.TYPE; }
 560| "long" { jjtThis.type =  Long.TYPE; }
 561| "float" { jjtThis.type =  Float.TYPE; }
 562| "double" { jjtThis.type =  Double.TYPE; }
 563}
 564
 565void AmbiguousName() #AmbiguousName :
 566/*
 567 * A lookahead of 2 is required below since "Name" can be followed
 568 * by a ".*" when used in the context of an "ImportDeclaration".
 569 */
 570{
 571    Token t;
 572    StringBuffer s;
 573}
 574{
 575  t = <IDENTIFIER> {
 576        s = new StringBuffer(t.image);
 577    }
 578  ( LOOKAHEAD(2) "." t = <IDENTIFIER> {
 579        s.append("."+t.image);
 580    }
 581  )* {
 582        jjtThis.text = s.toString();
 583    }
 584}
 585
 586/*
 587 * Expression syntax follows.
 588 */
 589void Expression() :
 590{ }
 591{
 592	/**
 593		SYNTACTIC_LOOKAHEAD
 594		This is probably expensive.  Can we simplify it somehow?
 595	*/
 596  LOOKAHEAD( LHSPrimaryExpression() AssignmentOperator() )
 597  Assignment()
 598|
 599  ConditionalExpression()
 600}
 601
 602void Assignment() #Assignment :
 603{ int op ; }
 604{
 605  LHSPrimaryExpression()
 606  op = AssignmentOperator() {
 607    jjtThis.operator = op;
 608  }
 609  Expression()
 610}
 611
 612int AssignmentOperator() :
 613{ Token t; }
 614{
 615    ( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "&=" | "^=" | "|=" |
 616      "<<=" | "@left_shift_assign" | ">>=" | "@right_shift_assign" |
 617      ">>>=" | "@right_unsigned_shift_assign" )
 618    {
 619        t = getToken(0);
 620        return t.kind;
 621    }
 622}
 623
 624void ConditionalExpression() : 
 625{ }
 626{
 627  ConditionalOrExpression() [ "?" Expression() ":" ConditionalExpression() 
 628	#TernaryExpression(3) ]
 629}
 630
 631void ConditionalOrExpression() :
 632{ Token t=null; }
 633{
 634  ConditionalAndExpression()
 635  ( ( t = "||" | t = "@or" )
 636    ConditionalAndExpression()
 637    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 638}
 639
 640void ConditionalAndExpression() :
 641{ Token t=null; }
 642{
 643  InclusiveOrExpression()
 644  ( ( t = "&&" | t = "@and" )
 645    InclusiveOrExpression()
 646    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 647}
 648
 649void InclusiveOrExpression() :
 650{ Token t=null; }
 651{
 652  ExclusiveOrExpression()
 653  ( ( t = "|" | t = "@bitwise_or" )
 654    ExclusiveOrExpression()
 655    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 656}
 657
 658void ExclusiveOrExpression() :
 659{ Token t=null; }
 660{
 661  AndExpression() ( t="^" AndExpression()
 662    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 663}
 664
 665void AndExpression() :
 666{ Token t=null; }
 667{
 668  EqualityExpression()
 669  ( ( t = "&" | t = "@bitwise_and" )
 670    EqualityExpression()
 671    { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 672}
 673
 674void EqualityExpression() :
 675{ Token t = null; }
 676{
 677  InstanceOfExpression() ( ( t= "==" | t= "!=" ) InstanceOfExpression()
 678    { jjtThis.kind = t.kind; } #BinaryExpression(2)
 679  )*
 680}
 681
 682void InstanceOfExpression() :
 683{ Token t = null; }
 684{
 685  RelationalExpression()
 686  [ t = "instanceof" Type() { jjtThis.kind = t.kind; } #BinaryExpression(2) ]
 687}
 688
 689void RelationalExpression() :
 690{ Token t = null; }
 691{
 692  ShiftExpression()
 693  ( ( t = "<" | t = "@lt" | t = ">" | t = "@gt" |
 694      t = "<=" | t = "@lteq" | t = ">=" | t = "@gteq" )
 695  ShiftExpression()
 696  { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 697}
 698
 699void ShiftExpression() :
 700{ Token t = null; }
 701{
 702  AdditiveExpression()
 703  ( ( t = "<<" | t = "@left_shift" | t = ">>" | t = "@right_shift" |
 704      t = ">>>" | t = "@right_unsigned_shift" )
 705  AdditiveExpression()
 706  { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 707}
 708
 709void AdditiveExpression() :
 710{ Token t = null; }
 711{
 712  MultiplicativeExpression()
 713  ( ( t= "+" | t= "-" ) MultiplicativeExpression() { jjtThis.kind = t.kind; }
 714    #BinaryExpression(2)
 715  )*
 716}
 717
 718void MultiplicativeExpression() :
 719{ Token t = null; }
 720{
 721  UnaryExpression() ( ( t= "*" | t= "/" | t= "%" )
 722  UnaryExpression() { jjtThis.kind = t.kind; } #BinaryExpression(2) )*
 723}
 724
 725void UnaryExpression() :
 726{ Token t = null; }
 727{
 728  ( t="+" | t="-" ) UnaryExpression()
 729    { jjtThis.kind = t.kind; } #UnaryExpression(1)
 730|
 731  PreIncrementExpression()
 732|
 733  PreDecrementExpression()
 734|
 735  UnaryExpressionNotPlusMinus()
 736}
 737
 738void PreIncrementExpression() :
 739{ Token t = null; }
 740{
 741  t="++" LHSPrimaryExpression()
 742    { jjtThis.kind = t.kind; } #UnaryExpression(1)
 743}
 744
 745void PreDecrementExpression() :
 746{ Token t = null; }
 747{
 748  t="--" LHSPrimaryExpression()
 749    { jjtThis.kind = t.kind; } #UnaryExpression(1)
 750}
 751
 752void UnaryExpressionNotPlusMinus() :
 753{ Token t = null; }
 754{
 755  ( t="~" | t="!" ) UnaryExpression()
 756    { jjtThis.kind = t.kind; } #UnaryExpression(1)
 757|
 758	// SYNTACTIC_LOOKAHEAD
 759  LOOKAHEAD( CastLookahead() ) CastExpression()
 760|
 761  PostfixExpression()
 762}
 763
 764// This production is to determine lookahead only.
 765void CastLookahead() : { }
 766{
 767  LOOKAHEAD(2) "(" PrimitiveType()
 768|
 769// SYNTACTIC_LOOKAHEAD
 770  LOOKAHEAD( "(" AmbiguousName() "[" ) "(" AmbiguousName() "[" "]"
 771|
 772  "(" AmbiguousName() ")" ( "~" | "!" | "(" | <IDENTIFIER> | /* "this" | "super" | */ "new" | Literal() )
 773}
 774
 775void PostfixExpression() :
 776{ Token t = null; }
 777{
 778// SYNTACTIC_LOOKAHEAD
 779  LOOKAHEAD( LHSPrimaryExpression() ("++"|"--") )
 780  LHSPrimaryExpression()
 781	  ( t="++" | t="--" ) { 
 782		jjtThis.kind = t.kind; jjtThis.postfix = true; } #UnaryExpression(1)
 783|
 784  PrimaryExpression()
 785}
 786
 787void CastExpression() #CastExpression :
 788{ }
 789{
 790// SYNTACTIC_LOOKAHEAD
 791  LOOKAHEAD( "(" PrimitiveType() ) "(" Type() ")" UnaryExpression()
 792|
 793  "(" Type() ")" UnaryExpressionNotPlusMinus()
 794}
 795
 796void PrimaryExpression() #PrimaryExpression : { }
 797{
 798  PrimaryPrefix() ( PrimarySuffix() )*
 799}
 800
 801void MethodInvocation() #MethodInvocation : { }
 802{
 803   AmbiguousName() Arguments() 
 804}
 805
 806void PrimaryPrefix() : { }
 807{
 808  Literal()
 809|
 810  "(" Expression() ")"
 811|
 812  AllocationExpression()
 813|
 814  // SYNTACTIC_LOOKAHEAD
 815  LOOKAHEAD( MethodInvocation() ) 
 816	MethodInvocation()
 817|
 818  LOOKAHEAD( Type() "." "class" ) 
 819	Type()
 820|
 821  AmbiguousName()
 822
 823/*
 824|
 825  LOOKAHEAD( "void" "." "class" )
 826*/
 827}
 828
 829void PrimarySuffix() #PrimarySuffix :
 830{
 831    Token t = null;
 832}
 833{
 834  LOOKAHEAD(2)
 835  "." "class" {
 836        jjtThis.operation = BSHPrimarySuffix.CLASS;
 837    }
 838|
 839  "[" Expression() "]" {
 840        jjtThis.operation = BSHPrimarySuffix.INDEX;
 841    }
 842|
 843    // Field access or method invocation
 844  "." t = <IDENTIFIER> [ Arguments() ] {
 845        jjtThis.operation = BSHPrimarySuffix.NAME;
 846        jjtThis.field = t.image;
 847    }
 848|
 849  "{" Expression() "}" {
 850        jjtThis.operation = BSHPrimarySuffix.PROPERTY;
 851    }
 852/*
 853    For inner classes
 854|
 855  LOOKAHEAD(2)
 856  "." AllocationExpression()
 857*/
 858}
 859
 860
 861/*
 862	Begin LHS part of the grammar --
 863
 864	The reason this stuff is duplicated (e.g. LHSPrimaryPrefix and 
 865	PrimaryPrefix) is that the whole grammar splits based on whether we 
 866	are preparig to do an assignment or not.  This is an important issue 
 867	to revisit in the future.
 868*/
 869/**
 870	The method invocation is here to force this to an object type in order 
 871	to simplify the suffix processing.  
 872*/
 873void LHSPrimaryPrefix() : { }
 874{
 875/*
 876  // SYNTACTIC_LOOKAHEAD
 877  LOOKAHEAD( MethodInvocation() )
 878  MethodInvocation()
 879|
 880*/
 881  AmbiguousName()
 882}
 883
 884void LHSPrimaryExpression() #LHSPrimaryExpression : { }
 885{
 886  LHSPrimaryPrefix() ( LHSPrimarySuffix( ) )*
 887}
 888
 889void LHSPrimarySuffix() #LHSPrimarySuffix :
 890{
 891    Token t=null, t1, t2 = null;
 892}
 893{
 894    // Indexed to a field
 895  "[" Expression() "]" {
 896        jjtThis.operation = BSHLHSPrimarySuffix.INDEX;
 897    }
 898|
 899/*
 900	Broken - return to this...
 901	Look at PrimarySuffix... why can't we do it right, as there?
 902	See BSHLHSPrimarySuffix.java
 903*/
 904    // Field access or method invocation followed by field access
 905  "." t1 = <IDENTIFIER> [ Arguments() "." t2 = <IDENTIFIER> ] {
 906        jjtThis.operation = BSHLHSPrimarySuffix.NAME;
 907        if ( t2 == null )
 908            jjtThis.field = t1.image;
 909        else {
 910            jjtThis.method = t1.image;
 911            jjtThis.field = t2.image;
 912        }
 913    }
 914|
 915  "{" Expression() "}" {
 916        jjtThis.operation = BSHLHSPrimarySuffix.PROPERTY;
 917    }
 918}
 919
 920/*
 921	-- End LHS part of the grammar
 922*/
 923
 924void Literal() #Literal :
 925{
 926    Token x;
 927    boolean b;
 928    String literal;
 929    char ch;
 930}
 931{
 932  x = <INTEGER_LITERAL>
 933  {
 934    literal = x.image;
 935    ch = literal.charAt(literal.length()-1);
 936    if(ch == 'l' || ch == 'L')
 937    {
 938        literal = literal.substring(0,literal.length()-1);
 939
 940        // This really should be Long.decode, but there isn't one. As a result,
 941        // hex and octal literals ending in 'l' or 'L' don't work.
 942        jjtThis.value = new Primitive( new Long( literal ) );
 943    }
 944    else
 945        jjtThis.value = new Primitive( Integer.decode( literal ) );
 946  }
 947|
 948  x = <FLOATING_POINT_LITERAL>
 949  {
 950    literal = x.image;
 951    ch = literal.charAt(literal.length()-1);
 952    if(ch == 'f' || ch == 'F')
 953    {
 954        literal = literal.substring(0,literal.length()-1);
 955        jjtThis.value = new Primitive( new Float( literal ) );
 956    }
 957    else
 958    {
 959        if(ch == 'd' || ch == 'D')
 960            literal = literal.substring(0,literal.length()-1);
 961
 962        jjtThis.value = new Primitive( new Double( literal ) );
 963    }
 964  }
 965|
 966  x = <CHARACTER_LITERAL> {
 967		try {
 968    		jjtThis.charSetup( x.image.substring(1, x.image.length() - 1) );
 969		} catch ( Exception e ) {
 970			throw new ParseException("Error parsing character: "+x.image);
 971		}
 972    }
 973|
 974  x = <STRING_LITERAL> {
 975		try {
 976			jjtThis.stringSetup( x.image.substring(1, x.image.length() - 1) );
 977		} catch ( Exception e ) {
 978			throw new ParseException("Error parsing string: "+x.image);
 979		}
 980    }
 981|
 982  b = BooleanLiteral()  {
 983    jjtThis.value = new Primitive( new Boolean(b) ); }
 984|
 985  NullLiteral() {
 986    jjtThis.value = Primitive.NULL; 
 987}
 988|
 989 VoidLiteral() {
 990    jjtThis.value = Primitive.VOID; }
 991}
 992
 993boolean BooleanLiteral() :
 994{}
 995{
 996  "true" { return true; }
 997|
 998  "false" { return false; }
 999}
1000
1001void NullLiteral() :
1002{}
1003{
1004  "null"
1005}
1006
1007void VoidLiteral() :
1008{}
1009{
1010  "void"
1011}
1012
1013void Arguments() #Arguments :
1014{ }
1015{
1016  "(" [ ArgumentList()  ]  ")"
1017}
1018
1019// leave these on the stack for Arguments() to handle
1020void ArgumentList() :
1021{ }
1022{
1023  Expression()
1024  ( "," Expression() )*
1025}
1026
1027void AllocationExpression() #AllocationExpression :
1028{ }
1029{
1030  LOOKAHEAD(2)
1031  "new" PrimitiveType() ArrayDimensions()
1032|
1033  "new" AmbiguousName() 
1034	( 
1035		ArrayDimensions() 
1036	| 
1037		// SYNTACTIC_LOOKAHEAD
1038		Arguments() [ LOOKAHEAD(2) Block() ]
1039	)
1040}
1041
1042void ArrayDimensions() #ArrayDimensions :
1043{}
1044{
1045  LOOKAHEAD(2)
1046  ( LOOKAHEAD(2) "[" Expression() "]" { jjtThis.addArrayDimension(); } )+
1047  // Removed trailing "[]" identifiers.  Specify array dims fully.
1048|
1049  ( "[" "]" { jjtThis.addArrayDimension(); } )+ ArrayInitializer()
1050}
1051
1052
1053/*
1054 * Statement syntax follows.
1055 */
1056
1057void Statement() : { }
1058{
1059  LOOKAHEAD(2)
1060  LabeledStatement()
1061|
1062  Block()
1063|
1064  EmptyStatement()
1065|
1066  StatementExpression() ";"
1067|
1068  SwitchStatement()
1069|
1070  IfStatement()
1071|
1072  WhileStatement()
1073|
1074  DoStatement()
1075|
1076  ForStatement()
1077|
1078  BreakStatement()
1079|
1080  ContinueStatement()
1081|
1082  ReturnStatement()
1083|
1084  ThrowStatement()
1085|
1086  TryStatement()
1087}
1088
1089void LabeledStatement() :
1090{}
1091{
1092  <IDENTIFIER> ":" Statement()
1093}
1094
1095void Block() #Block :
1096{}
1097{
1098  "{" ( BlockStatement() )* "}"
1099}
1100
1101void BlockStatement() :
1102{
1103}
1104{
1105// SYNTACTIC_LOOKAHEAD
1106  LOOKAHEAD( MethodDeclarationLookahead() ) MethodDeclaration()
1107|
1108// SYNTACTIC_LOOKAHEAD
1109  LOOKAHEAD([ "final" ] Type() <IDENTIFIER>)
1110  TypedVariableDeclaration() ";"
1111|
1112  Statement()
1113
1114/* end */ // ??
1115
1116|  
1117  // Allow BeanShell imports in any block
1118  ImportDeclaration()
1119|
1120  FormalComment()
1121}
1122
1123void FormalComment() #FormalComment( retainComments ) :
1124{
1125	Token t;
1126}
1127{
1128	t=<FORMAL_COMMENT>  {
1129		jjtThis.text=t.image;
1130	}
1131}
1132
1133void EmptyStatement() :
1134{}
1135{
1136  ";"
1137}
1138
1139void StatementExpression() :
1140/*
1141 * The last expansion of this production accepts more than the legal
1142 * Java expansions for StatementExpression.
1143 */
1144{ }
1145{
1146  PreIncrementExpression()
1147|
1148  PreDecrementExpression()
1149|
1150// SYNTACTIC_LOOKAHEAD
1151  LOOKAHEAD( PrimaryExpression() AssignmentOperator() )
1152  Assignment() { }
1153|
1154  PostfixExpression()
1155}
1156
1157void SwitchStatement() #SwitchStatement :
1158{}
1159{
1160  "switch" "(" Expression() ")" "{"
1161    ( SwitchLabel() ( BlockStatement() )* )*
1162  "}"
1163}
1164
1165void SwitchLabel() #SwitchLabel :
1166{}
1167{
1168  "case" Expression() ":"
1169|
1170  "default" ":" { jjtThis.isDefault = true; }
1171}
1172
1173void IfStatement() #IfStatement :
1174/*
1175 * The disambiguating algorithm of JavaCC automatically binds dangling
1176 * else's to the innermost if statement.  The LOOKAHEAD specification
1177 * is to tell JavaCC that we know what we are doing.
1178 */
1179{}
1180{
1181  "if" "(" Expression() ")" Statement() [ LOOKAHEAD(1) "else" Statement() ]
1182}
1183
1184void WhileStatement() #WhileStatement :
1185{}
1186{
1187  "while" "(" Expression() ")" Statement()
1188}
1189
1190/*
1191	Do statement is just a While statement with a special hook to execute
1192	at least once.
1193*/
1194void DoStatement() #WhileStatement :
1195{}
1196{
1197  "do" Statement() "while" "(" Expression() ")" ";" 
1198	{ jjtThis.isDoStatement=true;  }
1199}
1200
1201void ForStatement() #ForStatement :
1202{}
1203{
1204  "for" "(" [ ForInit() { jjtThis.hasForInit=true; } ]
1205    ";" [ Expression() { jjtThis.hasExpression=true; } ]
1206    ";" [ ForUpdate() { jjtThis.hasForUpdate=true; } ] ")"
1207    Statement()
1208}
1209
1210void ForInit() :
1211{ Token t = null; }
1212{
1213// SYNTACTIC_LOOKAHEAD
1214  LOOKAHEAD( [ t="final" ] Type() <IDENTIFIER> )
1215  TypedVariableDeclaration()
1216|
1217  StatementExpressionList()
1218}
1219
1220/**
1221	Declared a typed variable.
1222	Untyped variables are not declared per-se but are handled by the part
1223	of the grammar that deals with assignments.
1224*/
1225void TypedVariableDeclaration() #TypedVariableDeclaration :
1226{ 
1227	Token t = null; 
1228}
1229{
1230  [ t="final" ] Type() 
1231		VariableDeclarator() ( "," VariableDeclarator() )*  
1232	{
1233        jjtThis.isFinal = (t!=null);
1234    }
1235}
1236
1237void StatementExpressionList() #StatementExpressionList :
1238{}
1239{
1240  StatementExpression() ( "," StatementExpression() )*
1241}
1242
1243void ForUpdate() :
1244{}
1245{
1246  StatementExpressionList()
1247}
1248
1249void BreakStatement() #ReturnStatement :
1250{}
1251{
1252  "break" [ <IDENTIFIER> ] ";" { jjtThis.kind = BREAK; }
1253}
1254
1255void ContinueStatement() #ReturnStatement :
1256{}
1257{
1258  "continue" [ <IDENTIFIER> ] ";" { jjtThis.kind = CONTINUE; }
1259}
1260
1261void ReturnStatement() #ReturnStatement :
1262{}
1263{
1264  "return" [ Expression() ] ";" { jjtThis.kind = RETURN; }
1265}
1266
1267void ThrowStatement() #ThrowStatement :
1268{}
1269{
1270  "throw" Expression() ";"
1271}
1272
1273void TryStatement() #TryStatement:
1274/*
1275	Semantic check required here to make sure that at least one
1276	finally/catch is present.  (You can have a try with finally and no catch).
1277 */
1278{ boolean closed = false; }
1279{
1280	"try" Block()
1281	( "catch" "(" FormalParameter() ")" Block() { closed = true; } )*
1282	[ "finally" Block() { closed = true; } ]
1283	{ 	
1284		if ( !closed ) throw generateParseException();
1285	}
1286}