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