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