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