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