e6589898db8ae5fbc1380ed024915d7beffb20f0
[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 import net.sourceforge.phpdt.internal.compiler.parser.PHPSegmentWithChildren;
39 import net.sourceforge.phpdt.internal.compiler.parser.PHPFunctionDeclaration;
40 import net.sourceforge.phpdt.internal.compiler.parser.PHPClassDeclaration;
41 import net.sourceforge.phpdt.internal.compiler.parser.PHPVarDeclaration;
42 import net.sourceforge.phpdt.internal.compiler.parser.PHPReqIncDeclaration;
43
44 /**
45  * A new php parser.
46  * This php parser is inspired by the Java 1.2 grammar example 
47  * given with JavaCC. You can get JavaCC at http://www.webgain.com
48  * You can test the parser with the PHPParserTestCase2.java
49  * @author Matthieu Casanova
50  */
51 public final class PHPParser extends PHPParserSuperclass {
52
53   private static IFile fileToParse;
54
55   /** The current segment */
56   private static PHPSegmentWithChildren currentSegment;
57
58   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
59   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
60   PHPOutlineInfo outlineInfo;
61   private static int errorLevel = ERROR;
62   private static String errorMessage;
63
64   public PHPParser() {
65   }
66
67   public final void setFileToParse(final IFile fileToParse) {
68     this.fileToParse = fileToParse;
69   }
70
71   public PHPParser(final IFile fileToParse) {
72     this(new StringReader(""));
73     this.fileToParse = fileToParse;
74   }
75
76   public static final void phpParserTester(final String strEval) throws CoreException, ParseException {
77     PHPParserTokenManager.SwitchTo(PHPParserTokenManager.PHPPARSING);
78     final StringReader stream = new StringReader(strEval);
79     if (jj_input_stream == null) {
80       jj_input_stream = new SimpleCharStream(stream, 1, 1);
81     }
82     ReInit(new StringReader(strEval));
83     phpTest();
84   }
85
86   public static final void htmlParserTester(final String strEval) throws CoreException, ParseException {
87     final StringReader stream = new StringReader(strEval);
88     if (jj_input_stream == null) {
89       jj_input_stream = new SimpleCharStream(stream, 1, 1);
90     }
91     ReInit(stream);
92     phpFile();
93   }
94
95   public final PHPOutlineInfo parseInfo(final Object parent, final String s) {
96     outlineInfo = new PHPOutlineInfo(parent);
97     currentSegment = outlineInfo.getDeclarations();
98     final StringReader stream = new StringReader(s);
99     if (jj_input_stream == null) {
100       jj_input_stream = new SimpleCharStream(stream, 1, 1);
101     }
102     ReInit(stream);
103     try {
104       parse();
105     } catch (ParseException e) {
106       processParseException(e);
107     }
108     return outlineInfo;
109   }
110
111   /**
112    * This method will process the parse exception.
113    * If the error message is null, the parse exception wasn't catched and a trace is written in the log
114    * @param e the ParseException
115    */
116   private static void processParseException(final ParseException e) {
117     if (errorMessage == null) {
118       PHPeclipsePlugin.log(e);
119       errorMessage = "this exception wasn't handled by the parser please tell us how to reproduce it";
120     }
121     setMarker(e);
122     errorMessage = null;
123   }
124
125   /**
126    * Create marker for the parse error
127    * @param e the ParseException
128    */
129   private static void setMarker(final ParseException e) {
130     try {
131       setMarker(fileToParse,
132                 errorMessage,
133                 jj_input_stream.tokenBegin,
134                 jj_input_stream.tokenBegin + e.currentToken.image.length(),
135                 errorLevel,
136                 "Line " + e.currentToken.beginLine);
137     } catch (CoreException e2) {
138       PHPeclipsePlugin.log(e2);
139     }
140   }
141
142   /**
143    * Create markers according to the external parser output
144    */
145   private static void createMarkers(final String output, final IFile file) throws CoreException {
146     // delete all markers
147     file.deleteMarkers(IMarker.PROBLEM, false, 0);
148
149     int indx = 0;
150     int brIndx;
151     boolean flag = true;
152     while ((brIndx = output.indexOf("<br />", indx)) != -1) {
153       // newer php error output (tested with 4.2.3)
154       scanLine(output, file, indx, brIndx);
155       indx = brIndx + 6;
156       flag = false;
157     }
158     if (flag) {
159       while ((brIndx = output.indexOf("<br>", indx)) != -1) {
160         // older php error output (tested with 4.2.3)
161         scanLine(output, file, indx, brIndx);
162         indx = brIndx + 4;
163       }
164     }
165   }
166
167   private static void scanLine(final String output,
168                                final IFile file,
169                                final int indx,
170                                final int brIndx) throws CoreException {
171     String current;
172     StringBuffer lineNumberBuffer = new StringBuffer(10);
173     char ch;
174     current = output.substring(indx, brIndx);
175
176     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
177       int onLine = current.indexOf("on line <b>");
178       if (onLine != -1) {
179         lineNumberBuffer.delete(0, lineNumberBuffer.length());
180         for (int i = onLine; i < current.length(); i++) {
181           ch = current.charAt(i);
182           if ('0' <= ch && '9' >= ch) {
183             lineNumberBuffer.append(ch);
184           }
185         }
186
187         int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
188
189         Hashtable attributes = new Hashtable();
190
191         current = current.replaceAll("\n", "");
192         current = current.replaceAll("<b>", "");
193         current = current.replaceAll("</b>", "");
194         MarkerUtilities.setMessage(attributes, current);
195
196         if (current.indexOf(PARSE_ERROR_STRING) != -1)
197           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
198         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
199           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
200         else
201           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
202         MarkerUtilities.setLineNumber(attributes, lineNumber);
203         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
204       }
205     }
206   }
207
208   public final void parse(final String s) throws CoreException {
209     final StringReader stream = new StringReader(s);
210     if (jj_input_stream == null) {
211       jj_input_stream = new SimpleCharStream(stream, 1, 1);
212     }
213     ReInit(stream);
214     try {
215       parse();
216     } catch (ParseException e) {
217       processParseException(e);
218     }
219   }
220
221   /**
222    * Call the php parse command ( php -l -f &lt;filename&gt; )
223    * and create markers according to the external parser output
224    */
225   public static void phpExternalParse(final IFile file) {
226     final IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
227     final String filename = file.getLocation().toString();
228
229     final String[] arguments = { filename };
230     final MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
231     final String command = form.format(arguments);
232
233     final String parserResult = PHPStartApacheAction.getParserOutput(command, "External parser: ");
234
235     try {
236       // parse the buffer to find the errors and warnings
237       createMarkers(parserResult, file);
238     } catch (CoreException e) {
239       PHPeclipsePlugin.log(e);
240     }
241   }
242
243   public static final void parse() throws ParseException {
244           phpFile();
245   }
246 }
247
248 PARSER_END(PHPParser)
249
250 <DEFAULT> TOKEN :
251 {
252   <PHPSTARTSHORT : "<?"> : PHPPARSING
253 | <PHPSTARTLONG : "<?php"> : PHPPARSING
254 | <PHPECHOSTART : "<?=">      : PHPPARSING
255 }
256
257 <PHPPARSING> TOKEN :
258 {
259   <PHPEND :"?>"> : DEFAULT
260 }
261
262 <DEFAULT> SKIP :
263 {
264  < ~[] >
265 }
266
267
268 /* WHITE SPACE */
269
270 <PHPPARSING> SKIP :
271 {
272   " "
273 | "\t"
274 | "\n"
275 | "\r"
276 | "\f"
277 }
278
279 /* COMMENTS */
280
281 <PHPPARSING> SPECIAL_TOKEN :
282 {
283   "//" : IN_SINGLE_LINE_COMMENT
284 |
285   <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
286 |
287   "/*" : IN_MULTI_LINE_COMMENT
288 }
289
290 <IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
291 {
292   <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : PHPPARSING
293 }
294
295 <IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
296 {
297   <SINGLE_LINE_COMMENT_PHPEND : "?>" > : DEFAULT
298 }
299
300 <IN_FORMAL_COMMENT>
301 SPECIAL_TOKEN :
302 {
303   <FORMAL_COMMENT: "*/" > : PHPPARSING
304 }
305
306 <IN_MULTI_LINE_COMMENT>
307 SPECIAL_TOKEN :
308 {
309   <MULTI_LINE_COMMENT: "*/" > : PHPPARSING
310 }
311
312 <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
313 MORE :
314 {
315   < ~[] >
316 }
317
318 /* KEYWORDS */
319 <PHPPARSING> TOKEN :
320 {
321   <CLASS    : "class">
322 | <FUNCTION : "function">
323 | <VAR      : "var">
324 | <IF       : "if">
325 | <ELSEIF   : "elseif">
326 | <ELSE     : "else">
327 | <ARRAY    : "array">
328 | <BREAK    : "break">
329 }
330
331 /* LANGUAGE CONSTRUCT */
332 <PHPPARSING> TOKEN :
333 {
334   <PRINT              : "print">
335 | <ECHO               : "echo">
336 | <INCLUDE            : "include">
337 | <REQUIRE            : "require">
338 | <INCLUDE_ONCE       : "include_once">
339 | <REQUIRE_ONCE       : "require_once">
340 | <GLOBAL             : "global">
341 | <STATIC             : "static">
342 | <CLASSACCESS        : "->">
343 | <STATICCLASSACCESS  : "::">
344 | <ARRAYASSIGN        : "=>">
345 }
346
347 <PHPPARSING> TOKEN :
348 {
349   <LIST   : "list">
350 }
351 /* RESERVED WORDS AND LITERALS */
352
353 <PHPPARSING> TOKEN :
354 {
355   <CASE     : "case">
356 | <CONST    : "const">
357 | <CONTINUE : "continue">
358 | <_DEFAULT : "default">
359 | <DO       : "do">
360 | <EXTENDS  : "extends">
361 | <FOR      : "for">
362 | <GOTO     : "goto">
363 | <NEW      : "new">
364 | <NULL     : "null">
365 | <RETURN   : "return">
366 | <SUPER    : "super">
367 | <SWITCH   : "switch">
368 | <THIS     : "this">
369 | <TRUE     : "true">
370 | <FALSE    : "false">
371 | <WHILE    : "while">
372 | <ENDWHILE : "endwhile">
373 | <ENDIF    : "endif">
374 | <ENDFOR   : "endfor">
375 | <FOREACH  : "foreach">
376 | <AS       : "as" >
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       "\""
434     >
435 |    < STRING_2:
436       "'"
437       (
438       ~["'"]
439        |
440        "\\'"
441       )*
442
443       "'"
444     >
445 |   < STRING_3:
446       "`"
447       (
448         ~["`"]
449       |
450         "\\`"
451       )*
452       "`"
453     >
454 }
455
456 /* IDENTIFIERS */
457
458 <PHPPARSING> TOKEN :
459 {
460   < IDENTIFIER: (<LETTER>|<SPECIAL>) (<LETTER>|<DIGIT>|<SPECIAL>)* >
461 |
462   < #LETTER:
463       ["a"-"z"] | ["A"-"Z"]
464   >
465 |
466   < #DIGIT:
467       ["0"-"9"]
468   >
469 |
470   < #SPECIAL:
471     "_" | ["\u007f"-"\u00ff"]
472   >
473 }
474
475 /* SEPARATORS */
476
477 <PHPPARSING> TOKEN :
478 {
479   <LPAREN    : "(">
480 | <RPAREN    : ")">
481 | <LBRACE    : "{">
482 | <RBRACE    : "}">
483 | <LBRACKET  : "[">
484 | <RBRACKET  : "]">
485 | <SEMICOLON : ";">
486 | <COMMA     : ",">
487 | <DOT       : ".">
488 }
489
490
491 /* COMPARATOR */
492 <PHPPARSING> TOKEN :
493 {
494   <GT                 : ">">
495 | <LT                 : "<">
496 | <EQ                 : "==">
497 | <LE                 : "<=">
498 | <GE                 : ">=">
499 | <NE                 : "!=">
500 | <DIF                : "<>">
501 | <BANGDOUBLEEQUAL    : "!==">
502 | <TRIPLEEQUAL        : "===">
503 }
504
505 /* ASSIGNATION */
506 <PHPPARSING> TOKEN :
507 {
508   <ASSIGN             : "=">
509 | <PLUSASSIGN         : "+=">
510 | <MINUSASSIGN        : "-=">
511 | <STARASSIGN         : "*=">
512 | <SLASHASSIGN        : "/=">
513 | <ANDASSIGN          : "&=">
514 | <ORASSIGN           : "|=">
515 | <XORASSIGN          : "^=">
516 | <DOTASSIGN          : ".=">
517 | <REMASSIGN          : "%=">
518 | <TILDEEQUAL         : "~=">
519 }
520
521 /* OPERATORS */
522 <PHPPARSING> TOKEN :
523 {
524   <AT                 : "@">
525 | <DOLLAR             : "$">
526 | <BANG               : "!">
527 | <HOOK               : "?">
528 | <COLON              : ":">
529 | <SC_OR              : "||">
530 | <SC_AND             : "&&">
531 | <INCR               : "++">
532 | <DECR               : "--">
533 | <PLUS               : "+">
534 | <MINUS              : "-">
535 | <STAR               : "*">
536 | <SLASH              : "/">
537 | <BIT_AND            : "&">
538 | <BIT_OR             : "|">
539 | <XOR                : "^">
540 | <REM                : "%">
541 | <LSHIFT             : "<<">
542 | <RSIGNEDSHIFT       : ">>">
543 | <RUNSIGNEDSHIFT     : ">>>">
544 | <LSHIFTASSIGN       : "<<=">
545 | <RSIGNEDSHIFTASSIGN : ">>=">
546 }
547
548 <PHPPARSING> TOKEN :
549 {
550   < DOLLAR_ID: <DOLLAR> <IDENTIFIER>  >
551 }
552
553 void phpTest() :
554 {}
555 {
556   Php()
557   <EOF>
558 }
559
560 void phpFile() :
561 {}
562 {
563   try {
564     (PhpBlock())*
565     <EOF>
566   } catch (TokenMgrError e) {
567     errorMessage = e.getMessage();
568     errorLevel   = ERROR;
569     throw generateParseException();
570   }
571 }
572
573 void PhpBlock() :
574 {
575   final int start = jj_input_stream.bufpos;
576 }
577 {
578   <PHPECHOSTART> Expression() [ <SEMICOLON> ] <PHPEND>
579 |
580   [ <PHPSTARTLONG>
581   | <PHPSTARTSHORT>
582   {try {
583     setMarker(fileToParse,
584               "You should use '<?php' instead of '<?' it will avoid some problems with XML",
585               start,
586               jj_input_stream.bufpos,
587               INFO,
588               "Line " + token.beginLine);
589   } catch (CoreException e) {
590     PHPeclipsePlugin.log(e);
591   }}
592   ]Php()
593   try {
594     <PHPEND>
595   } catch (ParseException e) {
596     errorMessage = "'?>' expected";
597     errorLevel   = ERROR;
598     throw e;
599   }
600 }
601
602 void Php() :
603 {}
604 {
605   (BlockStatement())*
606 }
607
608 void ClassDeclaration() :
609 {
610   final PHPClassDeclaration classDeclaration;
611   final Token className;
612   final int pos = jj_input_stream.bufpos;
613 }
614 {
615   <CLASS> className = <IDENTIFIER> [ <EXTENDS> <IDENTIFIER> ]
616   {
617     if (currentSegment != null) {
618       classDeclaration = new PHPClassDeclaration(currentSegment,className.image,pos);
619       currentSegment.add(classDeclaration);
620       currentSegment = classDeclaration;
621     }
622   }
623   ClassBody()
624   {
625     if (currentSegment != null) {
626       currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
627     }
628   }
629 }
630
631 void ClassBody() :
632 {}
633 {
634   try {
635     <LBRACE>
636   } catch (ParseException e) {
637     errorMessage = "'{' expected";
638     errorLevel   = ERROR;
639     throw e;
640   }
641   ( ClassBodyDeclaration() )*
642   try {
643     <RBRACE>
644   } catch (ParseException e) {
645     errorMessage = "'var', 'function' or '}' expected";
646     errorLevel   = ERROR;
647     throw e;
648   }
649 }
650
651 void ClassBodyDeclaration() :
652 {}
653 {
654   MethodDeclaration()
655 |
656   FieldDeclaration()
657 }
658
659 void FieldDeclaration() :
660 {
661   PHPVarDeclaration variableDeclaration;
662 }
663 {
664   <VAR> variableDeclaration = VariableDeclarator()
665   {
666     if (currentSegment != null) {
667       currentSegment.add(variableDeclaration);
668     }
669   }
670   ( <COMMA>
671       variableDeclaration = VariableDeclarator()
672       {
673       if (currentSegment != null) {
674         currentSegment.add(variableDeclaration);
675       }
676       }
677   )*
678   try {
679     <SEMICOLON>
680   } catch (ParseException e) {
681     errorMessage = "';' expected after variable declaration";
682     errorLevel   = ERROR;
683     throw e;
684   }
685 }
686
687 PHPVarDeclaration VariableDeclarator() :
688 {
689   final String varName;
690   String varValue = null;
691   final int pos = jj_input_stream.bufpos;
692 }
693 {
694   varName = VariableDeclaratorId()
695   [
696     <ASSIGN>
697     try {
698       varValue = VariableInitializer()
699       {return new PHPVarDeclaration(currentSegment,varName,pos,varValue);}
700     } catch (ParseException e) {
701       errorMessage = "Literal expression expected in variable initializer";
702       errorLevel   = ERROR;
703       throw e;
704     }
705   ]
706   {return new PHPVarDeclaration(currentSegment,varName,pos);}
707 }
708
709 String VariableDeclaratorId() :
710 {
711   String expr;
712   final StringBuffer buff = new StringBuffer();
713 }
714 {
715   try {
716     expr = Variable()
717     {buff.append(expr);}
718     ( LOOKAHEAD(2) expr = VariableSuffix()
719     {buff.append(expr);}
720     )*
721     {return buff.toString();}
722   } catch (ParseException e) {
723     errorMessage = "'$' expected for variable identifier";
724     errorLevel   = ERROR;
725     throw e;
726   }
727 }
728
729 String Variable():
730 {
731   String expr = null;
732   final Token token;
733 }
734 {
735   token = <DOLLAR_ID> [<LBRACE> expr = Expression() <RBRACE>]
736   {
737     if (expr == null) {
738       return token.image;
739     }
740     return token + "{" + expr + "}";
741   }
742 |
743   <DOLLAR> expr = VariableName()
744   {return "$" + expr;}
745 }
746
747 String VariableName():
748 {
749 String expr = null;
750 final Token token;
751 }
752 {
753   <LBRACE> expr = Expression() <RBRACE>
754   {return "{"+expr+"}";}
755 |
756   token = <IDENTIFIER> [<LBRACE> expr = Expression() <RBRACE>]
757   {
758     if (expr == null) {
759       return token.image;
760     }
761     return token + "{" + expr + "}";
762   }
763 |
764   <DOLLAR> expr = VariableName()
765   {return "$" + expr;}
766 |
767   token = <DOLLAR_ID> [expr = VariableName()]
768   {
769   if (expr == null) {
770     return token.image;
771   }
772   return token.image + expr;
773   }
774 }
775
776 String VariableInitializer() :
777 {
778   final String expr;
779   final Token token;
780 }
781 {
782   expr = Literal()
783   {return expr;}
784 |
785   <MINUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
786   {return "-" + token.image;}
787 |
788   <PLUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
789   {return "+" + token.image;}
790 |
791   expr = ArrayDeclarator()
792   {return expr;}
793 |
794   token = <IDENTIFIER>
795   {return token.image;}
796 }
797
798 String ArrayVariable() :
799 {
800 String expr;
801 final StringBuffer buff = new StringBuffer();
802 }
803 {
804   expr = Expression()
805   {buff.append(expr);}
806    [<ARRAYASSIGN> expr = Expression()
807    {buff.append("=>").append(expr);}]
808   {return buff.toString();}
809 }
810
811 String ArrayInitializer() :
812 {
813 String expr;
814 final StringBuffer buff = new StringBuffer("(");
815 }
816 {
817   <LPAREN> [ expr = ArrayVariable()
818             {buff.append(expr);}
819             ( LOOKAHEAD(2) <COMMA> expr = ArrayVariable()
820             {buff.append(",").append(expr);}
821             )* ]
822   <RPAREN>
823   {
824     buff.append(")");
825     return buff.toString();
826   }
827 }
828
829 void MethodDeclaration() :
830 {
831   final PHPFunctionDeclaration functionDeclaration;
832 }
833 {
834   <FUNCTION> functionDeclaration = MethodDeclarator()
835   {
836     if (currentSegment != null) {
837       currentSegment.add(functionDeclaration);
838       currentSegment = functionDeclaration;
839     }
840   }
841   Block()
842   {
843     if (currentSegment != null) {
844       currentSegment = (PHPSegmentWithChildren) currentSegment.getParent();
845     }
846   }
847 }
848
849 PHPFunctionDeclaration MethodDeclarator() :
850 {
851   final Token identifier;
852   final StringBuffer methodDeclaration = new StringBuffer();
853   final String formalParameters;
854   final int pos = jj_input_stream.bufpos;
855 }
856 {
857   [ <BIT_AND> {methodDeclaration.append("&");} ]
858   identifier = <IDENTIFIER>
859   {methodDeclaration.append(identifier);}
860     formalParameters = FormalParameters()
861   {
862     methodDeclaration.append(formalParameters);
863     return new PHPFunctionDeclaration(currentSegment,methodDeclaration.toString(),pos);
864   }
865 }
866
867 String FormalParameters() :
868 {
869   String expr;
870   final StringBuffer buff = new StringBuffer("(");
871 }
872 {
873   try {
874   <LPAREN>
875   } catch (ParseException e) {
876     errorMessage = "Formal parameter expected after function identifier";
877     errorLevel   = ERROR;
878     jj_consume_token(token.kind);
879   }
880             [ expr = FormalParameter()
881               {buff.append(expr);}
882             (
883                 <COMMA> expr = FormalParameter()
884                 {buff.append(",").append(expr);}
885             )*
886             ]
887   try {
888     <RPAREN>
889   } catch (ParseException e) {
890     errorMessage = "')' expected";
891     errorLevel   = ERROR;
892     throw e;
893   }
894  {
895   buff.append(")");
896   return buff.toString();
897  }
898 }
899
900 String FormalParameter() :
901 {
902   final PHPVarDeclaration variableDeclaration;
903   final StringBuffer buff = new StringBuffer();
904 }
905 {
906   [<BIT_AND> {buff.append("&");}] variableDeclaration = VariableDeclarator()
907   {
908     buff.append(variableDeclaration.toString());
909     return buff.toString();
910   }
911 }
912
913 String Type() :
914 {}
915 {
916   <STRING>
917   {return "string";}
918 |
919   <BOOL>
920   {return "bool";}
921 |
922   <BOOLEAN>
923   {return "boolean";}
924 |
925   <REAL>
926   {return "real";}
927 |
928   <DOUBLE>
929   {return "double";}
930 |
931   <FLOAT>
932   {return "float";}
933 |
934   <INT>
935   {return "int";}
936 |
937   <INTEGER>
938   {return "integer";}
939 |
940   <OBJECT>
941   {return "object";}
942 }
943
944 String Expression() :
945 {
946   final String expr;
947   final String assignOperator;
948   final String expr2;
949 }
950 {
951   expr = PrintExpression()
952   {return expr;}
953 |
954   expr = ListExpression()
955   {return expr;}
956 |
957   expr = ConditionalExpression()
958   [
959     assignOperator = AssignmentOperator()
960     try {
961       expr2 = Expression()
962       {return expr + assignOperator + expr2;}
963     } catch (ParseException e) {
964       errorMessage = "expression expected";
965       errorLevel   = ERROR;
966       throw e;
967     }
968   ]
969   {return expr;}
970 }
971
972 String AssignmentOperator() :
973 {}
974 {
975   <ASSIGN>
976 {return "=";}
977 | <STARASSIGN>
978 {return "*=";}
979 | <SLASHASSIGN>
980 {return "/=";}
981 | <REMASSIGN>
982 {return "%=";}
983 | <PLUSASSIGN>
984 {return "+=";}
985 | <MINUSASSIGN>
986 {return "-=";}
987 | <LSHIFTASSIGN>
988 {return "<<=";}
989 | <RSIGNEDSHIFTASSIGN>
990 {return ">>=";}
991 | <ANDASSIGN>
992 {return "&=";}
993 | <XORASSIGN>
994 {return "|=";}
995 | <ORASSIGN>
996 {return "|=";}
997 | <DOTASSIGN>
998 {return ".=";}
999 | <TILDEEQUAL>
1000 {return "~=";}
1001 }
1002
1003 String ConditionalExpression() :
1004 {
1005   final String expr;
1006   String expr2 = null;
1007   String expr3 = null;
1008 }
1009 {
1010   expr = ConditionalOrExpression() [ <HOOK> expr2 = Expression() <COLON> expr3 = ConditionalExpression() ]
1011 {
1012   if (expr3 == null) {
1013     return expr;
1014   } else {
1015     return expr + "?" + expr2 + ":" + expr3;
1016   }
1017 }
1018 }
1019
1020 String ConditionalOrExpression() :
1021 {
1022   String expr;
1023   Token operator;
1024   final StringBuffer buff = new StringBuffer();
1025 }
1026 {
1027   expr = ConditionalAndExpression()
1028   {buff.append(expr);}
1029   (
1030     (operator = <SC_OR> | operator = <_ORL>) expr = ConditionalAndExpression()
1031     {
1032       buff.append(operator.image);
1033       buff.append(expr);
1034     }
1035   )*
1036   {
1037     return buff.toString();
1038   }
1039 }
1040
1041 String ConditionalAndExpression() :
1042 {
1043   String expr;
1044   Token operator;
1045   final StringBuffer buff = new StringBuffer();
1046 }
1047 {
1048   expr = ConcatExpression()
1049   {buff.append(expr);}
1050   (
1051   (operator = <SC_AND> | operator = <_ANDL>) expr = ConcatExpression()
1052     {
1053       buff.append(operator.image);
1054       buff.append(expr);
1055     }
1056   )*
1057   {return buff.toString();}
1058 }
1059
1060 String ConcatExpression() :
1061 {
1062   String expr;
1063   final StringBuffer buff = new StringBuffer();
1064 }
1065 {
1066   expr = InclusiveOrExpression()
1067   {buff.append(expr);}
1068   (
1069   <DOT> expr = InclusiveOrExpression()
1070   {buff.append(".").append(expr);}
1071   )*
1072   {return buff.toString();}
1073 }
1074
1075 String InclusiveOrExpression() :
1076 {
1077   String expr;
1078   final StringBuffer buff = new StringBuffer();
1079 }
1080 {
1081   expr = ExclusiveOrExpression()
1082   {buff.append(expr);}
1083   (
1084   <BIT_OR> expr = ExclusiveOrExpression()
1085   {buff.append("|").append(expr);}
1086   )*
1087   {return buff.toString();}
1088 }
1089
1090 String ExclusiveOrExpression() :
1091 {
1092   String expr;
1093   final StringBuffer buff = new StringBuffer();
1094 }
1095 {
1096   expr = AndExpression()
1097   {
1098     buff.append(expr);
1099   }
1100   (
1101     <XOR> expr = AndExpression()
1102   {
1103     buff.append("^");
1104     buff.append(expr);
1105   }
1106   )*
1107   {
1108     return buff.toString();
1109   }
1110 }
1111
1112 String AndExpression() :
1113 {
1114   String expr;
1115   final StringBuffer buff = new StringBuffer();
1116 }
1117 {
1118   expr = EqualityExpression()
1119   {
1120     buff.append(expr);
1121   }
1122   (
1123     <BIT_AND> expr = EqualityExpression()
1124   {
1125     buff.append("&").append(expr);
1126   }
1127   )*
1128   {return buff.toString();}
1129 }
1130
1131 String EqualityExpression() :
1132 {
1133   String expr;
1134   Token operator;
1135   final StringBuffer buff = new StringBuffer();
1136 }
1137 {
1138   expr = RelationalExpression()
1139   {buff.append(expr);}
1140   (
1141   (   operator = <EQ>
1142     | operator = <DIF>
1143     | operator = <NE>
1144     | operator = <BANGDOUBLEEQUAL>
1145     | operator = <TRIPLEEQUAL>
1146   )
1147   expr = RelationalExpression()
1148   {
1149     buff.append(operator.image);
1150     buff.append(expr);
1151   }
1152   )*
1153   {return buff.toString();}
1154 }
1155
1156 String RelationalExpression() :
1157 {
1158   String expr;
1159   Token operator;
1160   final StringBuffer buff = new StringBuffer();
1161 }
1162 {
1163   expr = ShiftExpression()
1164   {buff.append(expr);}
1165   (
1166   ( operator = <LT> | operator = <GT> | operator = <LE> | operator = <GE> ) expr = ShiftExpression()
1167   {buff.append(operator.image).append(expr);}
1168   )*
1169   {return buff.toString();}
1170 }
1171
1172 String ShiftExpression() :
1173 {
1174   String expr;
1175   Token operator;
1176   final StringBuffer buff = new StringBuffer();
1177 }
1178 {
1179   expr = AdditiveExpression()
1180   {buff.append(expr);}
1181   (
1182   (operator = <LSHIFT> | operator = <RSIGNEDSHIFT> | operator = <RUNSIGNEDSHIFT> ) expr = AdditiveExpression()
1183   {
1184     buff.append(operator.image);
1185     buff.append(expr);
1186   }
1187   )*
1188   {return buff.toString();}
1189 }
1190
1191 String AdditiveExpression() :
1192 {
1193   String expr;
1194   Token operator;
1195   final StringBuffer buff = new StringBuffer();
1196 }
1197 {
1198   expr = MultiplicativeExpression()
1199   {buff.append(expr);}
1200   (
1201    ( operator = <PLUS> | operator = <MINUS> ) expr = MultiplicativeExpression()
1202   {
1203     buff.append(operator.image);
1204     buff.append(expr);
1205   }
1206    )*
1207   {return buff.toString();}
1208 }
1209
1210 String MultiplicativeExpression() :
1211 {
1212   String expr;
1213   Token operator;
1214   final StringBuffer buff = new StringBuffer();}
1215 {
1216   expr = UnaryExpression()
1217   {buff.append(expr);}
1218   (
1219   ( operator = <STAR> | operator = <SLASH> | operator = <REM> ) expr = UnaryExpression()
1220   {
1221     buff.append(operator.image);
1222     buff.append(expr);
1223   }
1224   )*
1225   {return buff.toString();}
1226 }
1227
1228 /**
1229  * An unary expression starting with @, & or nothing
1230  */
1231 String UnaryExpression() :
1232 {
1233   final String expr;
1234   final Token token;
1235   final StringBuffer buff = new StringBuffer();
1236 }
1237 {
1238   token = <BIT_AND> expr = UnaryExpressionNoPrefix()
1239   {
1240     if (token == null) {
1241       return expr;
1242     }
1243     return token.image + expr;
1244   }
1245 |
1246   (<AT> {buff.append("@");})* expr = UnaryExpressionNoPrefix()
1247   {return buff.append(expr).toString();}
1248 }
1249
1250 String UnaryExpressionNoPrefix() :
1251 {
1252   final String expr;
1253   final Token token;
1254 }
1255 {
1256   ( token = <PLUS> | token = <MINUS> ) expr = UnaryExpression()
1257   {
1258     return token.image + expr;
1259   }
1260 |
1261   expr = PreIncrementExpression()
1262   {return expr;}
1263 |
1264   expr = PreDecrementExpression()
1265   {return expr;}
1266 |
1267   expr = UnaryExpressionNotPlusMinus()
1268   {return expr;}
1269 }
1270
1271
1272 String PreIncrementExpression() :
1273 {
1274 final String expr;
1275 }
1276 {
1277   <INCR> expr = PrimaryExpression()
1278   {return "++"+expr;}
1279 }
1280
1281 String PreDecrementExpression() :
1282 {
1283 final String expr;
1284 }
1285 {
1286   <DECR> expr = PrimaryExpression()
1287   {return "--"+expr;}
1288 }
1289
1290 String UnaryExpressionNotPlusMinus() :
1291 {
1292   final String expr;
1293 }
1294 {
1295   <BANG> expr = UnaryExpression()
1296   {return "!" + expr;}
1297 |
1298   LOOKAHEAD( <LPAREN> Type() <RPAREN> )
1299   expr = CastExpression()
1300   {return expr;}
1301 |
1302   expr = PostfixExpression()
1303   {return expr;}
1304 |
1305   expr = Literal()
1306   {return expr;}
1307 |
1308   <LPAREN> expr = Expression()<RPAREN>
1309   {return "("+expr+")";}
1310 }
1311
1312 String CastExpression() :
1313 {
1314 final String type, expr;
1315 }
1316 {
1317   <LPAREN> type = Type() <RPAREN> expr = UnaryExpression()
1318   {return "(" + type + ")" + expr;}
1319 }
1320
1321 String PostfixExpression() :
1322 {
1323   final String expr;
1324   Token operator = null;
1325 }
1326 {
1327   expr = PrimaryExpression() [ operator = <INCR> | operator = <DECR> ]
1328   {
1329     if (operator == null) {
1330       return expr;
1331     }
1332     return expr + operator.image;
1333   }
1334 }
1335
1336 String PrimaryExpression() :
1337 {
1338   final Token identifier;
1339   String expr;
1340   final StringBuffer buff = new StringBuffer();
1341 }
1342 {
1343   LOOKAHEAD(2)
1344   identifier = <IDENTIFIER> <STATICCLASSACCESS> expr = ClassIdentifier()
1345   {buff.append(identifier.image).append("::").append(expr);}
1346   (
1347   expr = PrimarySuffix()
1348   {buff.append(expr);}
1349   )*
1350   {return buff.toString();}
1351 |
1352   expr = PrimaryPrefix()  {buff.append(expr);}
1353   ( expr = PrimarySuffix()  {buff.append(expr);} )*
1354   {return buff.toString();}
1355 |
1356   expr = ArrayDeclarator()
1357   {return "array" + expr;}
1358 }
1359
1360 String ArrayDeclarator() :
1361 {
1362   final String expr;
1363 }
1364 {
1365   <ARRAY> expr = ArrayInitializer()
1366   {return "array" + expr;}
1367 }
1368
1369 String PrimaryPrefix() :
1370 {
1371   final String expr;
1372   final Token token;
1373 }
1374 {
1375   token = <IDENTIFIER>
1376   {return token.image;}
1377 |
1378   <NEW> expr = ClassIdentifier()
1379   {
1380     return "new " + expr;
1381   }
1382 |  
1383   expr = VariableDeclaratorId()
1384   {return expr;}
1385 }
1386
1387 String ClassIdentifier():
1388 {
1389   final String expr;
1390   final Token token;
1391 }
1392 {
1393   token = <IDENTIFIER>
1394   {return token.image;}
1395 |
1396   expr = VariableDeclaratorId()
1397   {return expr;}
1398 }
1399
1400 String PrimarySuffix() :
1401 {
1402   final String expr;
1403 }
1404 {
1405   expr = Arguments()
1406   {return expr;}
1407 |
1408   expr = VariableSuffix()
1409   {return expr;}
1410 }
1411
1412 String VariableSuffix() :
1413 {
1414   String expr = null;
1415 }
1416 {
1417   <CLASSACCESS> expr = VariableName()
1418   {return "->" + expr;}
1419
1420   <LBRACKET> [ expr = Expression() ]
1421   try {
1422     <RBRACKET>
1423   } catch (ParseException e) {
1424     errorMessage = "']' expected";
1425     errorLevel   = ERROR;
1426     throw e;
1427   }
1428   {
1429     if(expr == null) {
1430       return "[]";
1431     }
1432     return "[" + expr + "]";
1433   }
1434 }
1435
1436 String Literal() :
1437 {
1438   final String expr;
1439   final Token token;
1440 }
1441 {
1442   token = <INTEGER_LITERAL>
1443   {return token.image;}
1444 |
1445   token = <FLOATING_POINT_LITERAL>
1446   {return token.image;}
1447 |
1448   token = <STRING_LITERAL>
1449   {return token.image;}
1450 |
1451   expr = BooleanLiteral()
1452   {return expr;}
1453 |
1454   expr = NullLiteral()
1455   {return expr;}
1456 }
1457
1458 String BooleanLiteral() :
1459 {}
1460 {
1461   <TRUE>
1462   {return "true";}
1463 |
1464   <FALSE>
1465   {return "false";}
1466 }
1467
1468 String NullLiteral() :
1469 {}
1470 {
1471   <NULL>
1472   {return "null";}
1473 }
1474
1475 String Arguments() :
1476 {
1477 String expr = null;
1478 }
1479 {
1480   <LPAREN> [ expr = ArgumentList() ]
1481   try {
1482     <RPAREN>
1483   } catch (ParseException e) {
1484     errorMessage = "')' expected to close the argument list";
1485     errorLevel   = ERROR;
1486     throw e;
1487   }
1488   {
1489   if (expr == null) {
1490     return "()";
1491   }
1492   return "(" + expr + ")";
1493   }
1494 }
1495
1496 String ArgumentList() :
1497 {
1498 String expr;
1499 final StringBuffer buff = new StringBuffer();
1500 }
1501 {
1502   expr = Expression()
1503   {buff.append(expr);}
1504   ( <COMMA>
1505       try {
1506         expr = Expression()
1507       } catch (ParseException e) {
1508         errorMessage = "expression expected after a comma in argument list";
1509         errorLevel   = ERROR;
1510         throw e;
1511       }
1512     {
1513       buff.append(",").append(expr);
1514     }
1515    )*
1516    {return buff.toString();}
1517 }
1518
1519 /*
1520  * Statement syntax follows.
1521  */
1522
1523 void Statement() :
1524 {}
1525 {
1526   LOOKAHEAD(2)
1527   Expression()
1528   try {
1529     (<SEMICOLON> | <PHPEND>)
1530   } catch (ParseException e) {
1531     errorMessage = "';' expected";
1532     errorLevel   = ERROR;
1533     throw e;
1534   }
1535 |
1536   LOOKAHEAD(2)
1537   LabeledStatement()
1538 |
1539   Block()
1540 |
1541   EmptyStatement()
1542 |
1543   StatementExpression()
1544   try {
1545     <SEMICOLON>
1546   } catch (ParseException e) {
1547     errorMessage = "';' expected after expression";
1548     errorLevel   = ERROR;
1549     throw e;
1550   }
1551 |
1552   SwitchStatement()
1553 |
1554   IfStatement()
1555 |
1556   WhileStatement()
1557 |
1558   DoStatement()
1559 |
1560   ForStatement()
1561 |
1562   ForeachStatement()
1563 |
1564   BreakStatement()
1565 |
1566   ContinueStatement()
1567 |
1568   ReturnStatement()
1569 |
1570   EchoStatement()
1571 |
1572   [<AT>] IncludeStatement()
1573 |
1574   StaticStatement()
1575 |
1576   GlobalStatement()
1577 }
1578
1579 void IncludeStatement() :
1580 {
1581   final String expr;
1582   final int pos = jj_input_stream.bufpos;
1583 }
1584 {
1585   <REQUIRE>
1586   expr = Expression()
1587   {
1588     if (currentSegment != null) {
1589       currentSegment.add(new PHPReqIncDeclaration(currentSegment, "require",pos,expr));
1590     }
1591   }
1592   try {
1593     (<SEMICOLON> | "?>")
1594   } catch (ParseException e) {
1595     errorMessage = "';' expected";
1596     errorLevel   = ERROR;
1597     throw e;
1598   }
1599 |
1600   <REQUIRE_ONCE>
1601   expr = Expression()
1602   {
1603     if (currentSegment != null) {
1604       currentSegment.add(new PHPReqIncDeclaration(currentSegment, "require_once",pos,expr));
1605     }
1606   }
1607   try {
1608     (<SEMICOLON> | "?>")
1609   } catch (ParseException e) {
1610     errorMessage = "';' expected";
1611     errorLevel   = ERROR;
1612     throw e;
1613   }
1614 |
1615   <INCLUDE>
1616   expr = Expression()
1617   {
1618     if (currentSegment != null) {
1619       currentSegment.add(new PHPReqIncDeclaration(currentSegment, "include",pos,expr));
1620     }
1621   }
1622   try {
1623     (<SEMICOLON> | "?>")
1624   } catch (ParseException e) {
1625     errorMessage = "';' expected";
1626     errorLevel   = ERROR;
1627     throw e;
1628   }
1629 |
1630   <INCLUDE_ONCE>
1631   expr = Expression()
1632   {
1633     if (currentSegment != null) {
1634       currentSegment.add(new PHPReqIncDeclaration(currentSegment, "include_once",pos,expr));
1635     }
1636   }
1637   try {
1638     (<SEMICOLON> | "?>")
1639   } catch (ParseException e) {
1640     errorMessage = "';' expected";
1641     errorLevel   = ERROR;
1642     throw e;
1643   }
1644 }
1645
1646 String PrintExpression() :
1647 {
1648   final StringBuffer buff = new StringBuffer("print ");
1649   final String expr;
1650 }
1651 {
1652   <PRINT> expr = Expression()
1653   {
1654     buff.append(expr);
1655     return buff.toString();
1656   }
1657 }
1658
1659 String ListExpression() :
1660 {
1661   final StringBuffer buff = new StringBuffer("list(");
1662   String expr;
1663 }
1664 {
1665   <LIST> <LPAREN>
1666   [
1667     expr = VariableDeclaratorId()
1668     {buff.append(expr);}
1669   ]
1670   <COMMA>
1671   {buff.append(",");}
1672   [
1673     expr = VariableDeclaratorId()
1674     {buff.append(expr);}
1675   ]
1676   <RPAREN>
1677   {
1678     buff.append(")");
1679     return buff.toString();
1680   }
1681 }
1682
1683 void EchoStatement() :
1684 {}
1685 {
1686   <ECHO> Expression() (<COMMA> Expression())*
1687   try {
1688     (<SEMICOLON> | "?>")
1689   } catch (ParseException e) {
1690     errorMessage = "';' expected after 'echo' statement";
1691     errorLevel   = ERROR;
1692     throw e;
1693   }
1694 }
1695
1696 void GlobalStatement() :
1697 {}
1698 {
1699   <GLOBAL> VariableDeclaratorId() (<COMMA> VariableDeclaratorId())*
1700   try {
1701     (<SEMICOLON> | "?>")
1702   } catch (ParseException e) {
1703     errorMessage = "';' expected";
1704     errorLevel   = ERROR;
1705     throw e;
1706   }
1707 }
1708
1709 void StaticStatement() :
1710 {}
1711 {
1712   <STATIC> VariableDeclarator() (<COMMA> VariableDeclarator())*
1713   try {
1714     (<SEMICOLON> | "?>")
1715   } catch (ParseException e) {
1716     errorMessage = "';' expected";
1717     errorLevel   = ERROR;
1718     throw e;
1719   }
1720 }
1721
1722 void LabeledStatement() :
1723 {}
1724 {
1725   <IDENTIFIER> <COLON> Statement()
1726 }
1727
1728 void Block() :
1729 {}
1730 {
1731   try {
1732     <LBRACE>
1733   } catch (ParseException e) {
1734     errorMessage = "'{' expected";
1735     errorLevel   = ERROR;
1736     throw e;
1737   }
1738   ( BlockStatement() )*
1739   <RBRACE>
1740 }
1741
1742 void BlockStatement() :
1743 {}
1744 {
1745   Statement()
1746 |
1747   ClassDeclaration()
1748 |
1749   MethodDeclaration()
1750 }
1751
1752 void LocalVariableDeclaration() :
1753 {}
1754 {
1755   LocalVariableDeclarator() ( <COMMA> LocalVariableDeclarator() )*
1756 }
1757
1758 void LocalVariableDeclarator() :
1759 {}
1760 {
1761   VariableDeclaratorId() [ <ASSIGN> Expression() ]
1762 }
1763
1764 void EmptyStatement() :
1765 {}
1766 {
1767   <SEMICOLON>
1768 }
1769
1770 void StatementExpression() :
1771 {}
1772 {
1773   PreIncrementExpression()
1774 |
1775   PreDecrementExpression()
1776 |
1777   PrimaryExpression()
1778   [
1779    <INCR>
1780   |
1781     <DECR>
1782   |
1783     AssignmentOperator() Expression()
1784   ]
1785 }
1786
1787 void SwitchStatement() :
1788 {
1789   Token breakToken = null;
1790   int line;
1791 }
1792 {
1793   <SWITCH>
1794   try {
1795     <LPAREN>
1796   } catch (ParseException e) {
1797     errorMessage = "'(' expected after 'switch'";
1798     errorLevel   = ERROR;
1799     throw e;
1800   }
1801   Expression()
1802   try {
1803     <RPAREN>
1804   } catch (ParseException e) {
1805     errorMessage = "')' expected";
1806     errorLevel   = ERROR;
1807     throw e;
1808   }
1809   try {
1810   <LBRACE>
1811   } catch (ParseException e) {
1812     errorMessage = "'{' expected";
1813     errorLevel   = ERROR;
1814     throw e;
1815   }
1816     (
1817       line = SwitchLabel()
1818       ( BlockStatement() )*
1819       [ breakToken = <BREAK> ]
1820       {
1821         try {
1822           if (breakToken == null) {
1823             setMarker(fileToParse,
1824                       "You should use put a 'break' at the end of your statement",
1825                       line,
1826                       INFO,
1827                       "Line " + line);
1828           }
1829         } catch (CoreException e) {
1830           PHPeclipsePlugin.log(e);
1831         }
1832       }
1833     )*
1834   try {
1835     <RBRACE>
1836   } catch (ParseException e) {
1837     errorMessage = "'}' expected";
1838     errorLevel   = ERROR;
1839     throw e;
1840   }
1841 }
1842
1843 int SwitchLabel() :
1844 {
1845   final Token token;
1846 }
1847 {
1848   token = <CASE>
1849   try {
1850     Expression()
1851   } catch (ParseException e) {
1852     if (errorMessage != null) throw e;
1853     errorMessage = "expression expected after 'case' keyword";
1854     errorLevel   = ERROR;
1855     throw e;
1856   }
1857   try {
1858     <COLON>
1859   } catch (ParseException e) {
1860     errorMessage = "':' expected after case expression";
1861     errorLevel   = ERROR;
1862     throw e;
1863   }
1864   {return token.beginLine;}
1865 |
1866   token = <_DEFAULT>
1867   try {
1868     <COLON>
1869   } catch (ParseException e) {
1870     errorMessage = "':' expected after 'default' keyword";
1871     errorLevel   = ERROR;
1872     throw e;
1873   }
1874   {return token.beginLine;}
1875 }
1876
1877 void IfStatement() :
1878 {
1879   final Token token;
1880   final int pos = jj_input_stream.bufpos;
1881 }
1882 {
1883   token = <IF> Condition("if") IfStatement0(pos,pos+token.image.length())
1884 }
1885
1886 void Condition(final String keyword) :
1887 {}
1888 {
1889   try {
1890     <LPAREN>
1891   } catch (ParseException e) {
1892     errorMessage = "'(' expected after " + keyword + " keyword";
1893     errorLevel   = ERROR;
1894     throw e;
1895   }
1896   Expression()
1897   try {
1898      <RPAREN>
1899   } catch (ParseException e) {
1900     errorMessage = "')' expected after " + keyword + " keyword";
1901     errorLevel   = ERROR;
1902     throw e;
1903   }
1904 }
1905
1906 void IfStatement0(final int start,final int end) :
1907 {
1908 }
1909 {
1910   <COLON> (Statement())* (ElseIfStatementColon())* [ElseStatementColon()]
1911
1912   {try {
1913   setMarker(fileToParse,
1914             "Ugly syntax detected, you should if () {...} instead of if (): ... endif;",
1915             start,
1916             end,
1917             INFO,
1918             "Line " + token.beginLine);
1919   } catch (CoreException e) {
1920     PHPeclipsePlugin.log(e);
1921   }}
1922   try {
1923     <ENDIF>
1924   } catch (ParseException e) {
1925     errorMessage = "'endif' expected";
1926     errorLevel   = ERROR;
1927     throw e;
1928   }
1929   try {
1930     <SEMICOLON>
1931   } catch (ParseException e) {
1932     errorMessage = "';' expected 'endif' keyword";
1933     errorLevel   = ERROR;
1934     throw e;
1935   }
1936 |
1937   Statement() ( LOOKAHEAD(1) ElseIfStatement() )* [ LOOKAHEAD(1) <ELSE> Statement() ]
1938 }
1939
1940 void ElseIfStatementColon() :
1941 {}
1942 {
1943   <ELSEIF> Condition("elseif") <COLON> (Statement())*
1944 }
1945
1946 void ElseStatementColon() :
1947 {}
1948 {
1949   <ELSE> <COLON> (Statement())*
1950 }
1951
1952 void ElseIfStatement() :
1953 {}
1954 {
1955   <ELSEIF> Condition("elseif") Statement()
1956 }
1957
1958 void WhileStatement() :
1959 {
1960   final Token token;
1961   final int pos = jj_input_stream.bufpos;
1962 }
1963 {
1964   token = <WHILE> Condition("while") WhileStatement0(pos,pos + token.image.length())
1965 }
1966
1967 void WhileStatement0(final int start, final int end) :
1968 {}
1969 {
1970   <COLON> (Statement())*
1971   {try {
1972   setMarker(fileToParse,
1973             "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;",
1974             start,
1975             end,
1976             INFO,
1977             "Line " + token.beginLine);
1978   } catch (CoreException e) {
1979     PHPeclipsePlugin.log(e);
1980   }}
1981   try {
1982     <ENDWHILE>
1983   } catch (ParseException e) {
1984     errorMessage = "'endwhile' expected";
1985     errorLevel   = ERROR;
1986     throw e;
1987   }
1988   try {
1989     (<SEMICOLON> | "?>")
1990   } catch (ParseException e) {
1991     errorMessage = "';' expected after 'endwhile' keyword";
1992     errorLevel   = ERROR;
1993     throw e;
1994   }
1995 |
1996   Statement()
1997 }
1998
1999 void DoStatement() :
2000 {}
2001 {
2002   <DO> Statement() <WHILE> Condition("while")
2003   try {
2004     (<SEMICOLON> | "?>")
2005   } catch (ParseException e) {
2006     errorMessage = "';' expected";
2007     errorLevel   = ERROR;
2008     throw e;
2009   }
2010 }
2011
2012 void ForeachStatement() :
2013 {}
2014 {
2015   <FOREACH>
2016     try {
2017     <LPAREN>
2018   } catch (ParseException e) {
2019     errorMessage = "'(' expected after 'foreach' keyword";
2020     errorLevel   = ERROR;
2021     throw e;
2022   }
2023   try {
2024     Variable()
2025   } catch (ParseException e) {
2026     errorMessage = "variable expected";
2027     errorLevel   = ERROR;
2028     throw e;
2029   }
2030   [ VariableSuffix() ]
2031   try {
2032     <AS>
2033   } catch (ParseException e) {
2034     errorMessage = "'as' expected";
2035     errorLevel   = ERROR;
2036     throw e;
2037   }
2038   try {
2039     Variable()
2040   } catch (ParseException e) {
2041     errorMessage = "variable expected";
2042     errorLevel   = ERROR;
2043     throw e;
2044   }
2045   [ <ARRAYASSIGN> Expression() ]
2046   try {
2047     <RPAREN>
2048   } catch (ParseException e) {
2049     errorMessage = "')' expected after 'foreach' keyword";
2050     errorLevel   = ERROR;
2051     throw e;
2052   }
2053   try {
2054     Statement()
2055   } catch (ParseException e) {
2056     if (errorMessage != null) throw e;
2057     errorMessage = "statement expected";
2058     errorLevel   = ERROR;
2059     throw e;
2060   }
2061 }
2062
2063 void ForStatement() :
2064 {
2065 final Token token;
2066 final int pos = jj_input_stream.bufpos;
2067 }
2068 {
2069   token = <FOR>
2070   try {
2071     <LPAREN>
2072   } catch (ParseException e) {
2073     errorMessage = "'(' expected after 'for' keyword";
2074     errorLevel   = ERROR;
2075     throw e;
2076   }
2077      [ ForInit() ] <SEMICOLON> [ Expression() ] <SEMICOLON> [ ForUpdate() ] <RPAREN>
2078     (
2079       Statement()
2080     |
2081       <COLON> (Statement())*
2082       {
2083         try {
2084         setMarker(fileToParse,
2085                   "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;",
2086                   pos,
2087                   pos+token.image.length(),
2088                   INFO,
2089                   "Line " + token.beginLine);
2090         } catch (CoreException e) {
2091           PHPeclipsePlugin.log(e);
2092         }
2093       }
2094       try {
2095         <ENDFOR>
2096       } catch (ParseException e) {
2097         errorMessage = "'endfor' expected";
2098         errorLevel   = ERROR;
2099         throw e;
2100       }
2101       try {
2102         <SEMICOLON>
2103       } catch (ParseException e) {
2104         errorMessage = "';' expected 'endfor' keyword";
2105         errorLevel   = ERROR;
2106         throw e;
2107       }
2108     )
2109 }
2110
2111 void ForInit() :
2112 {}
2113 {
2114   LOOKAHEAD(LocalVariableDeclaration())
2115   LocalVariableDeclaration()
2116 |
2117   StatementExpressionList()
2118 }
2119
2120 void StatementExpressionList() :
2121 {}
2122 {
2123   StatementExpression() ( <COMMA> StatementExpression() )*
2124 }
2125
2126 void ForUpdate() :
2127 {}
2128 {
2129   StatementExpressionList()
2130 }
2131
2132 void BreakStatement() :
2133 {}
2134 {
2135   <BREAK> [ <IDENTIFIER> ] <SEMICOLON>
2136 }
2137
2138 void ContinueStatement() :
2139 {}
2140 {
2141   <CONTINUE> [ <IDENTIFIER> ] <SEMICOLON>
2142 }
2143
2144 void ReturnStatement() :
2145 {}
2146 {
2147   <RETURN> [ Expression() ] <SEMICOLON>
2148 }