It's now an interface
[phpeclipse.git] / net.sourceforge.phpeclipse / src / test / PHPParser.jj
1 options {
2   LOOKAHEAD = 1;
3   CHOICE_AMBIGUITY_CHECK = 2;
4   OTHER_AMBIGUITY_CHECK = 1;
5   STATIC = true;
6   DEBUG_PARSER = false;
7   DEBUG_LOOKAHEAD = false;
8   DEBUG_TOKEN_MANAGER = false;
9   OPTIMIZE_TOKEN_MANAGER = false;
10   ERROR_REPORTING = true;
11   JAVA_UNICODE_ESCAPE = false;
12   UNICODE_INPUT = false;
13   IGNORE_CASE = true;
14   USER_TOKEN_MANAGER = false;
15   USER_CHAR_STREAM = false;
16   BUILD_PARSER = true;
17   BUILD_TOKEN_MANAGER = true;
18   SANITY_CHECK = true;
19   FORCE_LA_CHECK = false;
20 }
21
22 PARSER_BEGIN(PHPParser)
23 package test;
24
25 import org.eclipse.core.resources.IFile;
26 import org.eclipse.core.resources.IMarker;
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.ui.texteditor.MarkerUtilities;
29 import org.eclipse.jface.preference.IPreferenceStore;
30
31 import java.io.CharArrayReader;
32 import java.util.Hashtable;
33 import java.io.StringReader;
34 import java.text.MessageFormat;
35
36 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
37 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
38 import net.sourceforge.phpdt.internal.compiler.parser.PHPOutlineInfo;
39
40 /**
41  * A new php parser.
42  * This php parser is inspired by the Java 1.2 grammar example 
43  * given with JavaCC. You can get JavaCC at http://www.webgain.com
44  * You can test the parser with the PHPParserTestCase2.java
45  * @author Matthieu Casanova
46  */
47 public class PHPParser extends PHPParserSuperclass {
48
49   private static PHPParser me;
50
51   private static IFile fileToParse;
52
53   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
54   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
55   public static final int ERROR = 2;
56   public static final int WARNING = 1;
57   public static final int INFO = 0;
58   PHPOutlineInfo outlineInfo;
59   private static int errorLevel = ERROR;
60   private static String errorMessage;
61
62   public PHPParser() {
63   }
64
65   public static PHPParser getInstance(IFile fileToParse) {
66     if (me == null) {
67       me = new PHPParser(fileToParse);
68     } else {
69       me.setFileToParse(fileToParse);
70     }
71     return me;
72   }
73
74   public void setFileToParse(IFile fileToParse) {
75     this.fileToParse = fileToParse;
76   }
77
78   public static PHPParser getInstance(java.io.Reader stream) {
79     if (me == null) {
80       me = new PHPParser(stream);
81     } else {
82       me.ReInit(stream);
83     }
84     return me;
85   }
86
87   public PHPParser(IFile fileToParse) {
88     this(new StringReader(""));
89     this.fileToParse = fileToParse;
90   }
91
92   public void phpParserTester(String strEval) throws CoreException, ParseException {
93     PHPParserTokenManager.SwitchTo(PHPParserTokenManager.PHPPARSING);
94     StringReader stream = new StringReader(strEval);
95     if (jj_input_stream == null) {
96       jj_input_stream = new SimpleCharStream(stream, 1, 1);
97     }
98     ReInit(new StringReader(strEval));
99     phpTest();
100   }
101
102   public void htmlParserTester(String strEval) throws CoreException, ParseException {
103     StringReader stream = new StringReader(strEval);
104     if (jj_input_stream == null) {
105       jj_input_stream = new SimpleCharStream(stream, 1, 1);
106     }
107     ReInit(stream);
108     phpTest();
109   }
110
111   public PHPOutlineInfo parseInfo(Object parent, String s) {
112     outlineInfo = new PHPOutlineInfo(parent);
113     StringReader stream = new StringReader(s);
114     if (jj_input_stream == null) {
115       jj_input_stream = new SimpleCharStream(stream, 1, 1);
116     }
117     ReInit(stream);
118     try {
119       parse();
120     } catch (ParseException e) {
121       if (errorMessage == null) {
122         PHPeclipsePlugin.log(e);
123       } else {
124         setMarker(errorMessage, e.currentToken.beginLine, errorLevel);
125         errorMessage = null;
126       }
127     }
128     return outlineInfo;
129   }
130
131
132   /**
133    * Create marker for the parse error
134    */
135   private static void setMarker(String message, int lineNumber, int errorLevel) {
136     try {
137       setMarker(fileToParse, message, lineNumber, errorLevel);
138     } catch (CoreException e) {
139       PHPeclipsePlugin.log(e);
140     }
141   }
142
143   public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
144     if (file != null) {
145       Hashtable attributes = new Hashtable();
146       MarkerUtilities.setMessage(attributes, message);
147       switch (errorLevel) {
148         case ERROR :
149           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
150           break;
151         case WARNING :
152           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
153           break;
154         case INFO :
155           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
156           break;
157       }
158       MarkerUtilities.setLineNumber(attributes, lineNumber);
159       MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
160     }
161   }
162
163   /**
164    * Create markers according to the external parser output
165    */
166   private static void createMarkers(String output, IFile file) throws CoreException {
167     // delete all markers
168     file.deleteMarkers(IMarker.PROBLEM, false, 0);
169
170     int indx = 0;
171     int brIndx = 0;
172     boolean flag = true;
173     while ((brIndx = output.indexOf("<br />", indx)) != -1) {
174       // newer php error output (tested with 4.2.3)
175       scanLine(output, file, indx, brIndx);
176       indx = brIndx + 6;
177       flag = false;
178     }
179     if (flag) {
180       while ((brIndx = output.indexOf("<br>", indx)) != -1) {
181         // older php error output (tested with 4.2.3)
182         scanLine(output, file, indx, brIndx);
183         indx = brIndx + 4;
184       }
185     }
186   }
187
188   private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
189     String current;
190     StringBuffer lineNumberBuffer = new StringBuffer(10);
191     char ch;
192     current = output.substring(indx, brIndx);
193
194     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
195       int onLine = current.indexOf("on line <b>");
196       if (onLine != -1) {
197         lineNumberBuffer.delete(0, lineNumberBuffer.length());
198         for (int i = onLine; i < current.length(); i++) {
199           ch = current.charAt(i);
200           if ('0' <= ch && '9' >= ch) {
201             lineNumberBuffer.append(ch);
202           }
203         }
204
205         int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
206
207         Hashtable attributes = new Hashtable();
208
209         current = current.replaceAll("\n", "");
210         current = current.replaceAll("<b>", "");
211         current = current.replaceAll("</b>", "");
212         MarkerUtilities.setMessage(attributes, current);
213
214         if (current.indexOf(PARSE_ERROR_STRING) != -1)
215           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
216         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
217           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
218         else
219           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
220         MarkerUtilities.setLineNumber(attributes, lineNumber);
221         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
222       }
223     }
224   }
225
226   public void parse(String s) throws CoreException {
227     ReInit(new StringReader(s));
228     try {
229       parse();
230     } catch (ParseException e) {
231       PHPeclipsePlugin.log(e);
232     }
233   }
234
235   /**
236    * Call the php parse command ( php -l -f &lt;filename&gt; )
237    * and create markers according to the external parser output
238    */
239   public static void phpExternalParse(IFile file) {
240     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
241     String filename = file.getLocation().toString();
242
243     String[] arguments = { filename };
244     MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
245     String command = form.format(arguments);
246
247     String parserResult = PHPStartApacheAction.getParserOutput(command, "External parser: ");
248
249     try {
250       // parse the buffer to find the errors and warnings
251       createMarkers(parserResult, file);
252     } catch (CoreException e) {
253       PHPeclipsePlugin.log(e);
254     }
255   }
256
257   public void parse() throws ParseException {
258           phpFile();
259   }
260 }
261
262 PARSER_END(PHPParser)
263
264 <DEFAULT> TOKEN :
265 {
266   "<?php" : PHPPARSING
267 | "<?"    : PHPPARSING
268 }
269
270 <DEFAULT> SKIP :
271 {
272  < ~[] >
273 }
274
275 <PHPPARSING> TOKEN :
276 {
277   "?>" : DEFAULT
278 }
279
280 /* WHITE SPACE */
281
282 <PHPPARSING> SKIP :
283 {
284   " "
285 | "\t"
286 | "\n"
287 | "\r"
288 | "\f"
289 }
290
291 /* COMMENTS */
292
293 <PHPPARSING> MORE :
294 {
295   "//" : IN_SINGLE_LINE_COMMENT
296 |
297   <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
298 |
299   "/*" : IN_MULTI_LINE_COMMENT
300 }
301
302 <IN_SINGLE_LINE_COMMENT>
303 SPECIAL_TOKEN :
304 {
305   <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" | "?>" > : PHPPARSING
306 }
307
308 <IN_FORMAL_COMMENT>
309 SPECIAL_TOKEN :
310 {
311   <FORMAL_COMMENT: "*/" > : PHPPARSING
312 }
313
314 <IN_MULTI_LINE_COMMENT>
315 SPECIAL_TOKEN :
316 {
317   <MULTI_LINE_COMMENT: "*/" > : PHPPARSING
318 }
319
320 <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
321 MORE :
322 {
323   < ~[] >
324 }
325
326 /* KEYWORDS */
327 <PHPPARSING> TOKEN :
328 {
329   <CLASS    : "class">
330 | <FUNCTION : "function">
331 | <VAR      : "var">
332 | <IF       : "if">
333 | <ELSEIF   : "elseif">
334 | <ELSE     : "else">
335 | <ARRAY    : "array">
336 }
337
338 /* LANGUAGE CONSTRUCT */
339 <PHPPARSING> TOKEN :
340 {
341   <PRINT : "print">
342 | <ECHO : "echo">
343 | <INCLUDE : "include">
344 | <REQUIRE : "require">
345 | <INCLUDE_ONCE : "include_once">
346 | <REQUIRE_ONCE : "require_once">
347 | <GLOBAL : "global">
348 | <STATIC : "static">
349 | <CLASSACCESS: "->">
350 | <STATICCLASSACCESS: "::">
351 | <ARRAYASSIGN: "=>">
352 }
353
354 /* RESERVED WORDS AND LITERALS */
355
356 <PHPPARSING> TOKEN :
357 {
358   < BREAK: "break" >
359 | < CASE: "case" >
360 | < CONST: "const" >
361 | < CONTINUE: "continue" >
362 | < _DEFAULT: "default" >
363 | < DO: "do" >
364 | < EXTENDS: "extends" >
365 | < FALSE: "false" >
366 | < FOR: "for" >
367 | < GOTO: "goto" >
368 | < NEW: "new" >
369 | < NULL: "null" >
370 | < RETURN: "return" >
371 | < SUPER: "super" >
372 | < SWITCH: "switch" >
373 | < THIS: "this" >
374 | < TRUE: "true" >
375 | < WHILE: "while" >
376 | < ENDWHILE : "endwhile" >
377 }
378
379 /* TYPES */
380
381 <PHPPARSING> TOKEN :
382 {
383   <STRING : "string">
384 | <OBJECT : "object">
385 | <BOOL : "bool">
386 | <BOOLEAN : "boolean">
387 | <REAL : "real">
388 | <DOUBLE : "double">
389 | <FLOAT : "float">
390 | <INT : "int">
391 | <INTEGER : "integer">
392 }
393
394 <PHPPARSING> TOKEN :
395 {
396   < _ORL : "OR" >
397 | < _ANDL: "AND">
398 }
399
400 /* LITERALS */
401
402 <PHPPARSING> TOKEN :
403 {
404   < INTEGER_LITERAL:
405         <DECIMAL_LITERAL> (["l","L"])?
406       | <HEX_LITERAL> (["l","L"])?
407       | <OCTAL_LITERAL> (["l","L"])?
408   >
409 |
410   < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
411 |
412   < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
413 |
414   < #OCTAL_LITERAL: "0" (["0"-"7"])* >
415 |
416   < FLOATING_POINT_LITERAL:
417         (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
418       | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
419       | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
420       | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
421   >
422 |
423   < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
424 |
425   < STRING_LITERAL: (<STRING_1> | <STRING_2> | <STRING_3>)>
426 |    < STRING_1:
427       "\""
428       (   (~["\""])
429         | "\\\""
430       )*
431       "\""
432     >
433 |    < STRING_2:
434       "'"
435       (   (~["'"]))*
436
437       "'"
438     >
439 |   < STRING_3:
440       "`"
441       (   (~["`"]))*
442       "`"
443     >
444 }
445
446 /* IDENTIFIERS */
447
448 <PHPPARSING> TOKEN :
449 {
450   < IDENTIFIER: (<LETTER>|<SPECIAL>) (<LETTER>|<DIGIT>|<SPECIAL>)* >
451 |
452   < #LETTER:
453       ["a"-"z"] | ["A"-"Z"]
454   >
455 |
456   < #DIGIT:
457       ["0"-"9"]
458   >
459 |
460   < #SPECIAL:
461     "_"
462   >
463 }
464
465 /* SEPARATORS */
466
467 <PHPPARSING> TOKEN :
468 {
469   < LPAREN: "(" >
470 | < RPAREN: ")" >
471 | < LBRACE: "{" >
472 | < RBRACE: "}" >
473 | < LBRACKET: "[" >
474 | < RBRACKET: "]" >
475 | < SEMICOLON: ";" >
476 | < COMMA: "," >
477 | < DOT: "." >
478 }
479
480 /* OPERATORS */
481
482 <PHPPARSING> TOKEN :
483 {
484   <AT     : "@">
485 | <DOLLAR : "$">
486 | < ASSIGN: "=" >
487 | < GT: ">" >
488 | < LT: "<" >
489 | < BANG: "!" >
490 | < HOOK: "?" >
491 | < COLON: ":" >
492 | < EQ: "==" >
493 | < LE: "<=" >
494 | < GE: ">=" >
495 | < NE: "!=" >
496 | < SC_OR: "||" >
497 | < SC_AND: "&&" >
498 | < INCR: "++" >
499 | < DECR: "--" >
500 | < PLUS: "+" >
501 | < MINUS: "-" >
502 | < STAR: "*" >
503 | < SLASH: "/" >
504 | < BIT_AND: "&" >
505 | < BIT_OR: "|" >
506 | < XOR: "^" >
507 | < REM: "%" >
508 | < LSHIFT: "<<" >
509 | < RSIGNEDSHIFT: ">>" >
510 | < RUNSIGNEDSHIFT: ">>>" >
511 | < PLUSASSIGN: "+=" >
512 | < MINUSASSIGN: "-=" >
513 | < STARASSIGN: "*=" >
514 | < SLASHASSIGN: "/=" >
515 | < ANDASSIGN: "&=" >
516 | < ORASSIGN: "|=" >
517 | < XORASSIGN: "^=" >
518 | < DOTASSIGN: ".=" >
519 | < REMASSIGN: "%=" >
520 | < LSHIFTASSIGN: "<<=" >
521 | < RSIGNEDSHIFTASSIGN: ">>=" >
522 | < RUNSIGNEDSHIFTASSIGN: ">>>=" >
523 }
524
525 <PHPPARSING> TOKEN :
526 {
527   < DOLLAR_ID: <DOLLAR> <IDENTIFIER>  >
528 }
529
530 /*****************************************
531  * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
532  *****************************************/
533
534 /*
535  * Program structuring syntax follows.
536  */
537
538 void phpTest() :
539 {}
540 {
541   Php()
542   <EOF>
543 }
544
545 void phpFile() :
546 {}
547 {
548  ("<?php" Php() "?>")*
549   <EOF>
550 }
551
552 void Php() :
553 {}
554 {
555   (BlockStatement())*
556 }
557
558 void ClassDeclaration() :
559 {}
560 {
561   <CLASS> <IDENTIFIER> [ <EXTENDS> <IDENTIFIER> ]
562   ClassBody()
563 }
564
565 void ClassBody() :
566 {}
567 {
568   <LBRACE> ( ClassBodyDeclaration() )* <RBRACE>
569 }
570
571 void ClassBodyDeclaration() :
572 {}
573 {
574   MethodDeclaration()
575 |
576   FieldDeclaration()
577 }
578
579 void FieldDeclaration() :
580 {}
581 {
582   <VAR> VariableDeclarator() ( <COMMA> VariableDeclarator() )* <SEMICOLON>
583 }
584
585 void VariableDeclarator() :
586 {}
587 {
588   VariableDeclaratorId() [ <ASSIGN> VariableInitializer() ]
589 }
590
591 void VariableDeclaratorId() :
592 {}
593 {
594   Variable() ( LOOKAHEAD(2) VariableSuffix() )*
595 }
596
597 void Variable():
598 {}
599 {
600   <DOLLAR_ID> (<LBRACE> Expression() <RBRACE>) *
601 |
602   <DOLLAR> VariableName()
603 }
604
605 void VariableName():
606 {}
607 {
608   <LBRACE> Expression() <RBRACE>
609 |
610   <IDENTIFIER> (<LBRACE> Expression() <RBRACE>) *
611 |
612   <DOLLAR> VariableName()
613 }
614
615 void VariableInitializer() :
616 {}
617 {
618   Expression()
619 }
620
621 void ArrayVariable() :
622 {}
623 {
624   Expression() (<ARRAYASSIGN> Expression())*
625 }
626
627 void ArrayInitializer() :
628 {}
629 {
630   <LPAREN> [ ArrayVariable() ( LOOKAHEAD(2) <COMMA> ArrayVariable() )* ]<RPAREN>
631 }
632
633 void MethodDeclaration() :
634 {}
635 {
636   <FUNCTION> MethodDeclarator()
637   ( Block() | <SEMICOLON> )
638 }
639
640 void MethodDeclarator() :
641 {}
642 {
643   [<BIT_AND>] <IDENTIFIER> FormalParameters()
644 }
645
646 void FormalParameters() :
647 {}
648 {
649   <LPAREN> [ FormalParameter() ( <COMMA> FormalParameter() )* ] <RPAREN>
650 }
651
652 void FormalParameter() :
653 {}
654 {
655   [<BIT_AND>] VariableDeclarator()
656 }
657
658 void Type() :
659 {}
660 {
661   <STRING>
662 |
663   <BOOL>
664 |
665   <BOOLEAN>
666 |
667   <REAL>
668 |
669   <DOUBLE>
670 |
671   <FLOAT>
672 |
673   <INT>
674 |
675   <INTEGER>
676 }
677
678 /*
679  * Expression syntax follows.
680  */
681
682 void Expression() :
683 /*
684  * This expansion has been written this way instead of:
685  *   Assignment() | ConditionalExpression()
686  * for performance reasons.
687  * However, it is a weakening of the grammar for it allows the LHS of
688  * assignments to be any conditional expression whereas it can only be
689  * a primary expression.  Consider adding a semantic predicate to work
690  * around this.
691  */
692 {}
693 {
694   PrintExpression()
695 |
696   ConditionalExpression()
697   [
698     AssignmentOperator() Expression()
699   ]
700 }
701
702 void AssignmentOperator() :
703 {}
704 {
705   <ASSIGN> | <STARASSIGN> | <SLASHASSIGN> | <REMASSIGN> | <PLUSASSIGN> | <MINUSASSIGN> | <LSHIFTASSIGN> | <RSIGNEDSHIFTASSIGN> | <RUNSIGNEDSHIFTASSIGN> | <ANDASSIGN> | <XORASSIGN> | <ORASSIGN> | <DOTASSIGN>
706 }
707
708 void ConditionalExpression() :
709 {}
710 {
711   ConditionalOrExpression() [ <HOOK> Expression() <COLON> ConditionalExpression() ]
712 }
713
714 void ConditionalOrExpression() :
715 {}
716 {
717   ConditionalAndExpression() ( (<SC_OR> | <_ORL>) ConditionalAndExpression() )*
718 }
719
720 void ConditionalAndExpression() :
721 {}
722 {
723   ConcatExpression() ( (<SC_AND> | <_ANDL>) ConcatExpression() )*
724 }
725
726 void ConcatExpression() :
727 {}
728 {
729   InclusiveOrExpression() ( <DOT> InclusiveOrExpression() )*
730 }
731
732 void InclusiveOrExpression() :
733 {}
734 {
735   ExclusiveOrExpression() ( <BIT_OR> ExclusiveOrExpression() )*
736 }
737
738 void ExclusiveOrExpression() :
739 {}
740 {
741   AndExpression() ( <XOR> AndExpression() )*
742 }
743
744 void AndExpression() :
745 {}
746 {
747   EqualityExpression() ( <BIT_AND> EqualityExpression() )*
748 }
749
750 void EqualityExpression() :
751 {}
752 {
753   RelationalExpression() ( ( <EQ> | <NE> ) RelationalExpression() )*
754 }
755
756 void RelationalExpression() :
757 {}
758 {
759   ShiftExpression() ( ( <LT> | <GT> | <LE> | <GE> ) ShiftExpression() )*
760 }
761
762 void ShiftExpression() :
763 {}
764 {
765   AdditiveExpression() ( ( <LSHIFT> | <RSIGNEDSHIFT> | <RUNSIGNEDSHIFT> ) AdditiveExpression() )*
766 }
767
768 void AdditiveExpression() :
769 {}
770 {
771   MultiplicativeExpression() ( ( <PLUS> | <MINUS> ) MultiplicativeExpression() )*
772 }
773
774 void MultiplicativeExpression() :
775 {}
776 {
777   UnaryExpression() ( ( <STAR> | <SLASH> | <REM> ) UnaryExpression() )*
778 }
779
780 void UnaryExpression() :
781 {}
782 {
783   <AT> UnaryExpression()
784 |
785   ( <PLUS> | <MINUS> ) UnaryExpression()
786 |
787   PreIncrementExpression()
788 |
789   PreDecrementExpression()
790 |
791   UnaryExpressionNotPlusMinus()
792 }
793
794 void PreIncrementExpression() :
795 {}
796 {
797   <INCR> PrimaryExpression()
798 }
799
800 void PreDecrementExpression() :
801 {}
802 {
803   <DECR> PrimaryExpression()
804 }
805
806 void UnaryExpressionNotPlusMinus() :
807 {}
808 {
809   <BANG> UnaryExpression()
810 |
811   LOOKAHEAD( <LPAREN> Type() <RPAREN> )
812   CastExpression()
813 |
814   PostfixExpression()
815 |
816   Literal()
817 |
818   <LPAREN>Expression()<RPAREN>
819 }
820
821 void CastExpression() :
822 {}
823 {
824   <LPAREN> Type() <RPAREN> UnaryExpression()
825 }
826
827 void PostfixExpression() :
828 {}
829 {
830   PrimaryExpression() [ <INCR> | <DECR> ]
831 }
832
833 void PrimaryExpression() :
834 {}
835 {
836   LOOKAHEAD(2)
837   <IDENTIFIER> <STATICCLASSACCESS> ClassIdentifier() (PrimarySuffix())*
838 |
839   PrimaryPrefix() ( PrimarySuffix() )*
840 |
841   <ARRAY> ArrayInitializer()
842 }
843
844 void PrimaryPrefix() :
845 {}
846 {
847   <IDENTIFIER>
848 |
849   <NEW> ClassIdentifier()
850 |  
851   VariableDeclaratorId()
852 }
853
854 void ClassIdentifier():
855 {}
856 {
857   <IDENTIFIER>
858 |
859   VariableDeclaratorId()
860 }
861
862 void PrimarySuffix() :
863 {}
864 {
865   Arguments()
866 |
867   VariableSuffix()
868 }
869
870 void VariableSuffix() :
871 {}
872 {
873   <CLASSACCESS> VariableName()
874
875   <LBRACKET> [ Expression() ] <RBRACKET>
876 }
877
878 void Literal() :
879 {}
880 {
881   <INTEGER_LITERAL>
882 |
883   <FLOATING_POINT_LITERAL>
884 |
885   <STRING_LITERAL>
886 |
887   BooleanLiteral()
888 |
889   NullLiteral()
890 }
891
892 void BooleanLiteral() :
893 {}
894 {
895   <TRUE>
896 |
897   <FALSE>
898 }
899
900 void NullLiteral() :
901 {}
902 {
903   <NULL>
904 }
905
906 void Arguments() :
907 {}
908 {
909   <LPAREN> [ ArgumentList() ] <RPAREN>
910 }
911
912 void ArgumentList() :
913 {}
914 {
915   Expression() ( <COMMA> Expression() )*
916 }
917
918 /*
919  * Statement syntax follows.
920  */
921
922 void Statement() :
923 {}
924 {
925   LOOKAHEAD(2)
926   Expression()  (<SEMICOLON> | "?>")
927 |
928   LOOKAHEAD(2)
929   LabeledStatement()
930 |
931   Block()
932 |
933   EmptyStatement()
934 |
935   StatementExpression()
936   try {
937     <SEMICOLON>
938   } catch (ParseException e) {
939     errorMessage = "';' expected after expression";
940     errorLevel   = ERROR;
941     throw e;
942   }
943 |
944   SwitchStatement()
945 |
946   IfStatement()
947 |
948   WhileStatement()
949 |
950   DoStatement()
951 |
952   ForStatement()
953 |
954   BreakStatement()
955 |
956   ContinueStatement()
957 |
958   ReturnStatement()
959 |
960   EchoStatement()
961 |
962   IncludeStatement()
963 |
964   StaticStatement()
965 |
966   GlobalStatement()
967 }
968
969 void IncludeStatement() :
970 {}
971 {
972   <REQUIRE> Expression() (<SEMICOLON> | "?>")
973 |
974   <REQUIRE_ONCE> Expression() (<SEMICOLON> | "?>")
975 |
976   <INCLUDE> Expression() (<SEMICOLON> | "?>")
977 |
978   <INCLUDE_ONCE> Expression() (<SEMICOLON> | "?>")
979 }
980
981 void PrintExpression() :
982 {}
983 {
984   <PRINT> Expression()
985 }
986
987 void EchoStatement() :
988 {}
989 {
990   <ECHO> Expression() (<COMMA> Expression())*
991   try {
992     (<SEMICOLON> | "?>")
993   } catch (ParseException e) {
994     errorMessage = "';' expected after 'echo' statement";
995     errorLevel   = ERROR;
996     throw e;
997   }
998 }
999
1000 void GlobalStatement() :
1001 {}
1002 {
1003   <GLOBAL> VariableDeclaratorId() (<COMMA> VariableDeclaratorId())* (<SEMICOLON> | "?>")
1004 }
1005
1006 void StaticStatement() :
1007 {}
1008 {
1009   <STATIC> VariableDeclarator() (<COMMA> VariableDeclarator())* (<SEMICOLON> | "?>")
1010 }
1011
1012 void LabeledStatement() :
1013 {}
1014 {
1015   <IDENTIFIER> <COLON> Statement()
1016 }
1017
1018 void Block() :
1019 {}
1020 {
1021   <LBRACE> ( BlockStatement() )* <RBRACE>
1022 }
1023
1024 void BlockStatement() :
1025 {}
1026 {
1027   Statement()
1028 |
1029   ClassDeclaration()
1030 |
1031   MethodDeclaration()
1032 }
1033
1034 void LocalVariableDeclaration() :
1035 {}
1036 {
1037   VariableDeclarator() ( <COMMA> VariableDeclarator() )*
1038 }
1039
1040 void EmptyStatement() :
1041 {}
1042 {
1043   <SEMICOLON>
1044 }
1045
1046 void StatementExpression() :
1047 /*
1048  * The last expansion of this production accepts more than the legal
1049  * Java expansions for StatementExpression.  This expansion does not
1050  * use PostfixExpression for performance reasons.
1051  */
1052 {}
1053 {
1054   PreIncrementExpression()
1055 |
1056   PreDecrementExpression()
1057 |
1058   PrimaryExpression()
1059   [
1060    <INCR>
1061   |
1062     <DECR>
1063   |
1064     AssignmentOperator() Expression()
1065   ]
1066 }
1067
1068 void SwitchStatement() :
1069 {}
1070 {
1071   <SWITCH> <LPAREN> Expression() <RPAREN> <LBRACE>
1072     ( SwitchLabel() ( BlockStatement() )* )*
1073   <RBRACE>
1074 }
1075
1076 void SwitchLabel() :
1077 {}
1078 {
1079   <CASE> Expression() <COLON>
1080 |
1081   <_DEFAULT> <COLON>
1082 }
1083
1084 void IfStatement() :
1085 /*
1086  * The disambiguating algorithm of JavaCC automatically binds dangling
1087  * else's to the innermost if statement.  The LOOKAHEAD specification
1088  * is to tell JavaCC that we know what we are doing.
1089  */
1090 {}
1091 {
1092   <IF> Condition("if") Statement() [ LOOKAHEAD(1) ElseIfStatement() ] [ LOOKAHEAD(1) <ELSE> Statement() ]
1093 }
1094
1095 void Condition(String keyword) :
1096 {}
1097 {
1098   try {
1099     <LPAREN>
1100   } catch (ParseException e) {
1101     errorMessage = "'(' expected after " + keyword + " keyword";
1102     errorLevel   = ERROR;
1103     throw e;
1104   }
1105   Expression()
1106   try {
1107      <RPAREN>
1108   } catch (ParseException e) {
1109     errorMessage = "')' expected after " + keyword + " keyword";
1110     errorLevel   = ERROR;
1111     throw e;
1112   }
1113 }
1114
1115 void ElseIfStatement() :
1116 {}
1117 {
1118   <ELSEIF> Condition("elseif") Statement()
1119 }
1120
1121 void WhileStatement() :
1122 {}
1123 {
1124   <WHILE> Condition("while") WhileStatement0()
1125 }
1126
1127 void WhileStatement0() :
1128 {}
1129 {
1130   <COLON> (Statement())* <ENDWHILE> (<SEMICOLON> | "?>")
1131 |
1132   Statement()
1133 }
1134
1135 void DoStatement() :
1136 {}
1137 {
1138   <DO> Statement() <WHILE> Condition("while") (<SEMICOLON> | "?>")
1139 }
1140
1141 void ForStatement() :
1142 {}
1143 {
1144   <FOR> <LPAREN> [ ForInit() ] <SEMICOLON> [ Expression() ] <SEMICOLON> [ ForUpdate() ] <RPAREN> Statement()
1145 }
1146
1147 void ForInit() :
1148 {}
1149 {
1150   LOOKAHEAD(LocalVariableDeclaration())
1151   LocalVariableDeclaration()
1152 |
1153   StatementExpressionList()
1154 }
1155
1156 void StatementExpressionList() :
1157 {}
1158 {
1159   StatementExpression() ( <COMMA> StatementExpression() )*
1160 }
1161
1162 void ForUpdate() :
1163 {}
1164 {
1165   StatementExpressionList()
1166 }
1167
1168 void BreakStatement() :
1169 {}
1170 {
1171   <BREAK> [ <IDENTIFIER> ] <SEMICOLON>
1172 }
1173
1174 void ContinueStatement() :
1175 {}
1176 {
1177   <CONTINUE> [ <IDENTIFIER> ] <SEMICOLON>
1178 }
1179
1180 void ReturnStatement() :
1181 {}
1182 {
1183   <RETURN> [ Expression() ] <SEMICOLON>
1184 }