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