source: trunk/j/src/bsh/bsh.jjt @ 2

Last change on this file since 2 was 2, checked in by piso, 18 years ago

Initial checkin.

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