628b52aba75ce990403a04c61e9c24b41635d47b
[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.util.Enumeration;
33 import java.util.ArrayList;
34 import java.io.StringReader;
35 import java.io.*;
36 import java.text.MessageFormat;
37
38 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
39 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
40 import net.sourceforge.phpdt.internal.compiler.ast.*;
41 import net.sourceforge.phpdt.internal.compiler.parser.OutlineableWithChildren;
42 import net.sourceforge.phpdt.internal.compiler.parser.PHPOutlineInfo;
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   /** The file that is parsed. */
54   private static IFile fileToParse;
55
56   /** The current segment. */
57   private static OutlineableWithChildren currentSegment;
58
59   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
60   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
61   static PHPOutlineInfo outlineInfo;
62
63   public static MethodDeclaration currentFunction;
64   private static boolean assigning;
65
66   /** The error level of the current ParseException. */
67   private static int errorLevel = ERROR;
68   /** The message of the current ParseException. If it's null it's because the parse exception wasn't handled */
69   private static String errorMessage;
70
71   private static int errorStart = -1;
72   private static int errorEnd = -1;
73   private static PHPDocument phpDocument;
74   /**
75    * The point where html starts.
76    * It will be used by the token manager to create HTMLCode objects
77    */
78   public static int htmlStart;
79
80   //ast stack
81   private final static int AstStackIncrement = 100;
82   /** The stack of node. */
83   private static AstNode[] nodes;
84   /** The cursor in expression stack. */
85   private static int nodePtr;
86   private static VariableDeclaration[] variableDeclarationStack;
87   private static int variableDeclarationPtr;
88   private static Statement[] statementStack;
89   private static int statementPtr;
90   private static ElseIf[] elseIfStack;
91   private static int elseIfPtr;
92
93   public final void setFileToParse(final IFile fileToParse) {
94     this.fileToParse = fileToParse;
95   }
96
97   public PHPParser() {
98   }
99
100   public PHPParser(final IFile fileToParse) {
101     this(new StringReader(""));
102     this.fileToParse = fileToParse;
103   }
104
105   /**
106    * Reinitialize the parser.
107    */
108   private static final void init() {
109     nodes = new AstNode[AstStackIncrement];
110     statementStack = new Statement[AstStackIncrement];
111     elseIfStack = new ElseIf[AstStackIncrement];
112     nodePtr = -1;
113     statementPtr = -1;
114     elseIfPtr = -1;
115     htmlStart = 0;
116   }
117
118   /**
119    * Add an php node on the stack.
120    * @param node the node that will be added to the stack
121    */
122   private static final void pushOnAstNodes(AstNode node) {
123     try {
124       nodes[++nodePtr] = node;
125     } catch (IndexOutOfBoundsException e) {
126       int oldStackLength = nodes.length;
127       AstNode[] oldStack = nodes;
128       nodes = new AstNode[oldStackLength + AstStackIncrement];
129       System.arraycopy(oldStack, 0, nodes, 0, oldStackLength);
130       nodePtr = oldStackLength;
131       nodes[nodePtr] = node;
132     }
133   }
134
135   private static final void pushOnVariableDeclarationStack(VariableDeclaration var) {
136     try {
137       variableDeclarationStack[++variableDeclarationPtr] = var;
138     } catch (IndexOutOfBoundsException e) {
139       int oldStackLength = variableDeclarationStack.length;
140       VariableDeclaration[] oldStack = variableDeclarationStack;
141       variableDeclarationStack = new VariableDeclaration[oldStackLength + AstStackIncrement];
142       System.arraycopy(oldStack, 0, variableDeclarationStack, 0, oldStackLength);
143       variableDeclarationPtr = oldStackLength;
144       variableDeclarationStack[variableDeclarationPtr] = var;
145     }
146   }
147
148   private static final void pushOnStatementStack(Statement statement) {
149     try {
150       statementStack[++statementPtr] = statement;
151     } catch (IndexOutOfBoundsException e) {
152       int oldStackLength = statementStack.length;
153       Statement[] oldStack = statementStack;
154       statementStack = new Statement[oldStackLength + AstStackIncrement];
155       System.arraycopy(oldStack, 0, statementStack, 0, oldStackLength);
156       statementPtr = oldStackLength;
157       statementStack[statementPtr] = statement;
158     }
159   }
160
161   private static final void pushOnElseIfStack(ElseIf elseIf) {
162     try {
163       elseIfStack[++elseIfPtr] = elseIf;
164     } catch (IndexOutOfBoundsException e) {
165       int oldStackLength = elseIfStack.length;
166       ElseIf[] oldStack = elseIfStack;
167       elseIfStack = new ElseIf[oldStackLength + AstStackIncrement];
168       System.arraycopy(oldStack, 0, elseIfStack, 0, oldStackLength);
169       elseIfPtr = oldStackLength;
170       elseIfStack[elseIfPtr] = elseIf;
171     }
172   }
173
174   public static final void phpParserTester(final String strEval) throws CoreException, ParseException {
175     PHPParserTokenManager.SwitchTo(PHPParserTokenManager.PHPPARSING);
176     final StringReader stream = new StringReader(strEval);
177     if (jj_input_stream == null) {
178       jj_input_stream = new SimpleCharStream(stream, 1, 1);
179     }
180     ReInit(new StringReader(strEval));
181     init();
182     phpTest();
183   }
184
185   public static final void htmlParserTester(final File fileName) throws CoreException, ParseException {
186     try {
187       final Reader stream = new FileReader(fileName);
188       if (jj_input_stream == null) {
189         jj_input_stream = new SimpleCharStream(stream, 1, 1);
190       }
191       ReInit(stream);
192       init();
193       phpFile();
194     } catch (FileNotFoundException e) {
195       e.printStackTrace();  //To change body of catch statement use Options | File Templates.
196     }
197   }
198
199   public static final void htmlParserTester(final String strEval) throws CoreException, ParseException {
200     final StringReader stream = new StringReader(strEval);
201     if (jj_input_stream == null) {
202       jj_input_stream = new SimpleCharStream(stream, 1, 1);
203     }
204     ReInit(stream);
205     init();
206     phpFile();
207   }
208
209   public final PHPOutlineInfo parseInfo(final Object parent, final String s) {
210     currentSegment = new PHPDocument(parent);
211     outlineInfo = new PHPOutlineInfo(parent);
212     final StringReader stream = new StringReader(s);
213     if (jj_input_stream == null) {
214       jj_input_stream = new SimpleCharStream(stream, 1, 1);
215     }
216     ReInit(stream);
217     init();
218     try {
219       parse();
220       phpDocument = new PHPDocument(null);
221       phpDocument.nodes = nodes;
222       PHPeclipsePlugin.log(1,phpDocument.toString());
223     } catch (ParseException e) {
224       processParseException(e);
225     }
226     return outlineInfo;
227   }
228
229   /**
230    * This method will process the parse exception.
231    * If the error message is null, the parse exception wasn't catched and a trace is written in the log
232    * @param e the ParseException
233    */
234   private static void processParseException(final ParseException e) {
235     if (errorMessage == null) {
236       PHPeclipsePlugin.log(e);
237       errorMessage = "this exception wasn't handled by the parser please tell us how to reproduce it";
238       errorStart = jj_input_stream.getPosition();
239       errorEnd   = errorStart + 1;
240     }
241     setMarker(e);
242     errorMessage = null;
243   }
244
245   /**
246    * Create marker for the parse error
247    * @param e the ParseException
248    */
249   private static void setMarker(final ParseException e) {
250     try {
251       if (errorStart == -1) {
252         setMarker(fileToParse,
253                   errorMessage,
254                   jj_input_stream.tokenBegin,
255                   jj_input_stream.tokenBegin + e.currentToken.image.length(),
256                   errorLevel,
257                   "Line " + e.currentToken.beginLine);
258       } else {
259         setMarker(fileToParse,
260                   errorMessage,
261                   errorStart,
262                   errorEnd,
263                   errorLevel,
264                   "Line " + e.currentToken.beginLine);
265         errorStart = -1;
266         errorEnd = -1;
267       }
268     } catch (CoreException e2) {
269       PHPeclipsePlugin.log(e2);
270     }
271   }
272
273   /**
274    * Create markers according to the external parser output
275    */
276   private static void createMarkers(final String output, final IFile file) throws CoreException {
277     // delete all markers
278     file.deleteMarkers(IMarker.PROBLEM, false, 0);
279
280     int indx = 0;
281     int brIndx;
282     boolean flag = true;
283     while ((brIndx = output.indexOf("<br />", indx)) != -1) {
284       // newer php error output (tested with 4.2.3)
285       scanLine(output, file, indx, brIndx);
286       indx = brIndx + 6;
287       flag = false;
288     }
289     if (flag) {
290       while ((brIndx = output.indexOf("<br>", indx)) != -1) {
291         // older php error output (tested with 4.2.3)
292         scanLine(output, file, indx, brIndx);
293         indx = brIndx + 4;
294       }
295     }
296   }
297
298   private static void scanLine(final String output,
299                                final IFile file,
300                                final int indx,
301                                final int brIndx) throws CoreException {
302     String current;
303     StringBuffer lineNumberBuffer = new StringBuffer(10);
304     char ch;
305     current = output.substring(indx, brIndx);
306
307     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
308       int onLine = current.indexOf("on line <b>");
309       if (onLine != -1) {
310         lineNumberBuffer.delete(0, lineNumberBuffer.length());
311         for (int i = onLine; i < current.length(); i++) {
312           ch = current.charAt(i);
313           if ('0' <= ch && '9' >= ch) {
314             lineNumberBuffer.append(ch);
315           }
316         }
317
318         int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
319
320         Hashtable attributes = new Hashtable();
321
322         current = current.replaceAll("\n", "");
323         current = current.replaceAll("<b>", "");
324         current = current.replaceAll("</b>", "");
325         MarkerUtilities.setMessage(attributes, current);
326
327         if (current.indexOf(PARSE_ERROR_STRING) != -1)
328           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
329         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
330           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
331         else
332           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
333         MarkerUtilities.setLineNumber(attributes, lineNumber);
334         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
335       }
336     }
337   }
338
339   public final void parse(final String s) throws CoreException {
340     final StringReader stream = new StringReader(s);
341     if (jj_input_stream == null) {
342       jj_input_stream = new SimpleCharStream(stream, 1, 1);
343     }
344     ReInit(stream);
345     init();
346     try {
347       parse();
348     } catch (ParseException e) {
349       processParseException(e);
350     }
351   }
352
353   /**
354    * Call the php parse command ( php -l -f &lt;filename&gt; )
355    * and create markers according to the external parser output
356    */
357   public static void phpExternalParse(final IFile file) {
358     final IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
359     final String filename = file.getLocation().toString();
360
361     final String[] arguments = { filename };
362     final MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
363     final String command = form.format(arguments);
364
365     final String parserResult = PHPStartApacheAction.getParserOutput(command, "External parser: ");
366
367     try {
368       // parse the buffer to find the errors and warnings
369       createMarkers(parserResult, file);
370     } catch (CoreException e) {
371       PHPeclipsePlugin.log(e);
372     }
373   }
374
375   /**
376    * Put a new html block in the stack.
377    */
378   public static final void createNewHTMLCode() {
379     final int currentPosition = SimpleCharStream.getPosition();
380     if (currentPosition == htmlStart) {
381       return;
382     }
383     final char[] chars = SimpleCharStream.currentBuffer.substring(htmlStart,currentPosition).toCharArray();
384     pushOnAstNodes(new HTMLCode(chars, htmlStart,currentPosition));
385   }
386
387   private static final void parse() throws ParseException {
388           phpFile();
389   }
390 }
391
392 PARSER_END(PHPParser)
393
394 <DEFAULT> TOKEN :
395 {
396   <PHPSTARTSHORT : "<?">    {PHPParser.createNewHTMLCode();} : PHPPARSING
397 | <PHPSTARTLONG  : "<?php"> {PHPParser.createNewHTMLCode();} : PHPPARSING
398 | <PHPECHOSTART  : "<?=">   {PHPParser.createNewHTMLCode();} : PHPPARSING
399 }
400
401 <PHPPARSING> TOKEN :
402 {
403   <PHPEND :"?>"> {PHPParser.htmlStart = SimpleCharStream.getPosition();} : DEFAULT
404 }
405
406 /* Skip any character if we are not in php mode */
407 <DEFAULT> SKIP :
408 {
409  < ~[] >
410 }
411
412
413 /* WHITE SPACE */
414 <PHPPARSING> SKIP :
415 {
416   " "
417 | "\t"
418 | "\n"
419 | "\r"
420 | "\f"
421 }
422
423 /* COMMENTS */
424 <PHPPARSING> SPECIAL_TOKEN :
425 {
426   "//" : IN_SINGLE_LINE_COMMENT
427 |
428   "#"  : IN_SINGLE_LINE_COMMENT
429 |
430   <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
431 |
432   "/*" : IN_MULTI_LINE_COMMENT
433 }
434
435 <IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
436 {
437   <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : PHPPARSING
438 }
439
440 <IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
441 {
442   <SINGLE_LINE_COMMENT_PHPEND : "?>" > : DEFAULT
443 }
444
445 <IN_FORMAL_COMMENT>
446 SPECIAL_TOKEN :
447 {
448   <FORMAL_COMMENT: "*/" > : PHPPARSING
449 }
450
451 <IN_MULTI_LINE_COMMENT>
452 SPECIAL_TOKEN :
453 {
454   <MULTI_LINE_COMMENT: "*/" > : PHPPARSING
455 }
456
457 <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
458 MORE :
459 {
460   < ~[] >
461 }
462
463 /* KEYWORDS */
464 <PHPPARSING> TOKEN :
465 {
466   <CLASS    : "class">
467 | <FUNCTION : "function">
468 | <VAR      : "var">
469 | <IF       : "if">
470 | <ELSEIF   : "elseif">
471 | <ELSE     : "else">
472 | <ARRAY    : "array">
473 | <BREAK    : "break">
474 | <LIST     : "list">
475 }
476
477 /* LANGUAGE CONSTRUCT */
478 <PHPPARSING> TOKEN :
479 {
480   <PRINT              : "print">
481 | <ECHO               : "echo">
482 | <INCLUDE            : "include">
483 | <REQUIRE            : "require">
484 | <INCLUDE_ONCE       : "include_once">
485 | <REQUIRE_ONCE       : "require_once">
486 | <GLOBAL             : "global">
487 | <STATIC             : "static">
488 | <CLASSACCESS        : "->">
489 | <STATICCLASSACCESS  : "::">
490 | <ARRAYASSIGN        : "=>">
491 }
492
493 /* RESERVED WORDS AND LITERALS */
494
495 <PHPPARSING> TOKEN :
496 {
497   <CASE     : "case">
498 | <CONST    : "const">
499 | <CONTINUE : "continue">
500 | <_DEFAULT : "default">
501 | <DO       : "do">
502 | <EXTENDS  : "extends">
503 | <FOR      : "for">
504 | <GOTO     : "goto">
505 | <NEW      : "new">
506 | <NULL     : "null">
507 | <RETURN   : "return">
508 | <SUPER    : "super">
509 | <SWITCH   : "switch">
510 | <THIS     : "this">
511 | <TRUE     : "true">
512 | <FALSE    : "false">
513 | <WHILE    : "while">
514 | <ENDWHILE : "endwhile">
515 | <ENDSWITCH: "endswitch">
516 | <ENDIF    : "endif">
517 | <ENDFOR   : "endfor">
518 | <FOREACH  : "foreach">
519 | <AS       : "as" >
520 }
521
522 /* TYPES */
523 <PHPPARSING> TOKEN :
524 {
525   <STRING  : "string">
526 | <OBJECT  : "object">
527 | <BOOL    : "bool">
528 | <BOOLEAN : "boolean">
529 | <REAL    : "real">
530 | <DOUBLE  : "double">
531 | <FLOAT   : "float">
532 | <INT     : "int">
533 | <INTEGER : "integer">
534 }
535
536 //Misc token
537 <PHPPARSING> TOKEN :
538 {
539   <AT                 : "@">
540 | <DOLLAR             : "$">
541 | <BANG               : "!">
542 | <TILDE              : "~">
543 | <HOOK               : "?">
544 | <COLON              : ":">
545 }
546
547 /* OPERATORS */
548 <PHPPARSING> TOKEN :
549 {
550   <OR_OR              : "||">
551 | <AND_AND            : "&&">
552 | <INCR               : "++">
553 | <DECR               : "--">
554 | <PLUS               : "+">
555 | <MINUS              : "-">
556 | <STAR               : "*">
557 | <SLASH              : "/">
558 | <BIT_AND            : "&">
559 | <BIT_OR             : "|">
560 | <XOR                : "^">
561 | <REMAINDER          : "%">
562 | <LSHIFT             : "<<">
563 | <RSIGNEDSHIFT       : ">>">
564 | <RUNSIGNEDSHIFT     : ">>>">
565 | <_ORL               : "OR">
566 | <_ANDL              : "AND">
567 }
568
569 /* LITERALS */
570 <PHPPARSING> TOKEN :
571 {
572   <INTEGER_LITERAL:
573         <DECIMAL_LITERAL> (["l","L"])?
574       | <HEX_LITERAL> (["l","L"])?
575       | <OCTAL_LITERAL> (["l","L"])?
576   >
577 |
578   <#DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
579 |
580   <#HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
581 |
582   <#OCTAL_LITERAL: "0" (["0"-"7"])* >
583 |
584   <FLOATING_POINT_LITERAL:
585         (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
586       | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
587       | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
588       | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
589   >
590 |
591   <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
592 |
593   <STRING_LITERAL: (<STRING_1> | <STRING_2> | <STRING_3>)>
594 |    <STRING_1:
595       "\""
596       (
597           ~["\"","{","}"]
598         | "\\\""
599         | "\\"
600         | "{" ~["\""] "}"
601       )*
602       "\""
603     >
604 |    <STRING_2:
605       "'"
606       (
607          ~["'"]
608        | "\\'"
609       )*
610
611       "'"
612     >
613 |   <STRING_3:
614       "`"
615       (
616         ~["`"]
617       | "\\`"
618       )*
619       "`"
620     >
621 }
622
623 /* IDENTIFIERS */
624
625 <PHPPARSING> TOKEN :
626 {
627   < IDENTIFIER: (<LETTER>|<SPECIAL>) (<LETTER>|<DIGIT>|<SPECIAL>)* >
628 |
629   < #LETTER:
630       ["a"-"z"] | ["A"-"Z"]
631   >
632 |
633   < #DIGIT:
634       ["0"-"9"]
635   >
636 |
637   < #SPECIAL:
638     "_" | ["\u007f"-"\u00ff"]
639   >
640 }
641
642 /* SEPARATORS */
643
644 <PHPPARSING> TOKEN :
645 {
646   <LPAREN    : "(">
647 | <RPAREN    : ")">
648 | <LBRACE    : "{">
649 | <RBRACE    : "}">
650 | <LBRACKET  : "[">
651 | <RBRACKET  : "]">
652 | <SEMICOLON : ";">
653 | <COMMA     : ",">
654 | <DOT       : ".">
655 }
656
657
658 /* COMPARATOR */
659 <PHPPARSING> TOKEN :
660 {
661   <GT                 : ">">
662 | <LT                 : "<">
663 | <EQUAL_EQUAL        : "==">
664 | <LE                 : "<=">
665 | <GE                 : ">=">
666 | <NOT_EQUAL          : "!=">
667 | <DIF                : "<>">
668 | <BANGDOUBLEEQUAL    : "!==">
669 | <TRIPLEEQUAL        : "===">
670 }
671
672 /* ASSIGNATION */
673 <PHPPARSING> TOKEN :
674 {
675   <ASSIGN             : "=">
676 | <PLUSASSIGN         : "+=">
677 | <MINUSASSIGN        : "-=">
678 | <STARASSIGN         : "*=">
679 | <SLASHASSIGN        : "/=">
680 | <ANDASSIGN          : "&=">
681 | <ORASSIGN           : "|=">
682 | <XORASSIGN          : "^=">
683 | <DOTASSIGN          : ".=">
684 | <REMASSIGN          : "%=">
685 | <TILDEEQUAL         : "~=">
686 | <LSHIFTASSIGN       : "<<=">
687 | <RSIGNEDSHIFTASSIGN : ">>=">
688 }
689
690 <PHPPARSING> TOKEN :
691 {
692   < DOLLAR_ID: <DOLLAR> <IDENTIFIER>  >
693 }
694
695 void phpTest() :
696 {}
697 {
698   Php()
699   <EOF>
700   {PHPParser.createNewHTMLCode();}
701 }
702
703 void phpFile() :
704 {}
705 {
706   try {
707     (PhpBlock())*
708     <EOF>
709   } catch (TokenMgrError e) {
710     PHPeclipsePlugin.log(e);
711     errorStart   = SimpleCharStream.getPosition();
712     errorEnd     = errorStart + 1;
713     errorMessage = e.getMessage();
714     errorLevel   = ERROR;
715     throw generateParseException();
716   }
717 }
718
719 /**
720  * A php block is a <?= expression [;]?>
721  * or <?php somephpcode ?>
722  * or <? somephpcode ?>
723  */
724 void PhpBlock() :
725 {
726   final int start = jj_input_stream.getPosition();
727 }
728 {
729   phpEchoBlock()
730 |
731   [ <PHPSTARTLONG>
732     | <PHPSTARTSHORT>
733     {try {
734       setMarker(fileToParse,
735                 "You should use '<?php' instead of '<?' it will avoid some problems with XML",
736                 start,
737                 jj_input_stream.getPosition(),
738                 INFO,
739                 "Line " + token.beginLine);
740     } catch (CoreException e) {
741       PHPeclipsePlugin.log(e);
742     }}
743   ]
744   Php()
745   try {
746     <PHPEND>
747   } catch (ParseException e) {
748     errorMessage = "'?>' expected";
749     errorLevel   = ERROR;
750     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
751     errorEnd   = jj_input_stream.getPosition() + 1;
752     throw e;
753   }
754 }
755
756 PHPEchoBlock phpEchoBlock() :
757 {
758   final Expression expr;
759   final int pos = SimpleCharStream.getPosition();
760   PHPEchoBlock echoBlock;
761 }
762 {
763   <PHPECHOSTART> expr = Expression() [ <SEMICOLON> ] <PHPEND>
764   {
765   echoBlock = new PHPEchoBlock(expr,pos,SimpleCharStream.getPosition());
766   pushOnAstNodes(echoBlock);
767   return echoBlock;}
768 }
769
770 void Php() :
771 {}
772 {
773   (BlockStatement())*
774 }
775
776 ClassDeclaration ClassDeclaration() :
777 {
778   final ClassDeclaration classDeclaration;
779   final Token className;
780   Token superclassName = null;
781   final int pos;
782 }
783 {
784   <CLASS>
785   try {
786     {pos = jj_input_stream.getPosition();}
787     className = <IDENTIFIER>
788   } catch (ParseException e) {
789     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected";
790     errorLevel   = ERROR;
791     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
792     errorEnd     = jj_input_stream.getPosition() + 1;
793     throw e;
794   }
795   [
796     <EXTENDS>
797     try {
798       superclassName = <IDENTIFIER>
799     } catch (ParseException e) {
800       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected";
801       errorLevel   = ERROR;
802       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
803       errorEnd   = jj_input_stream.getPosition() + 1;
804       throw e;
805     }
806   ]
807   {
808     if (superclassName == null) {
809       classDeclaration = new ClassDeclaration(currentSegment,
810                                               className.image.toCharArray(),
811                                               pos,
812                                               0);
813     } else {
814       classDeclaration = new ClassDeclaration(currentSegment,
815                                               className.image.toCharArray(),
816                                               superclassName.image.toCharArray(),
817                                               pos,
818                                               0);
819     }
820       currentSegment.add(classDeclaration);
821       currentSegment = classDeclaration;
822   }
823   ClassBody(classDeclaration)
824   {currentSegment = (OutlineableWithChildren) currentSegment.getParent();
825    classDeclaration.sourceEnd = SimpleCharStream.getPosition();
826    pushOnAstNodes(classDeclaration);
827    return classDeclaration;}
828 }
829
830 void ClassBody(ClassDeclaration classDeclaration) :
831 {}
832 {
833   try {
834     <LBRACE>
835   } catch (ParseException e) {
836     errorMessage = "unexpected token : '"+ e.currentToken.next.image + "', '{' expected";
837     errorLevel   = ERROR;
838     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
839     errorEnd   = jj_input_stream.getPosition() + 1;
840     throw e;
841   }
842   ( ClassBodyDeclaration(classDeclaration) )*
843   try {
844     <RBRACE>
845   } catch (ParseException e) {
846     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', 'var', 'function' or '}' expected";
847     errorLevel   = ERROR;
848     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
849     errorEnd   = jj_input_stream.getPosition() + 1;
850     throw e;
851   }
852 }
853
854 /**
855  * A class can contain only methods and fields.
856  */
857 void ClassBodyDeclaration(ClassDeclaration classDeclaration) :
858 {
859   MethodDeclaration method;
860   FieldDeclaration field;
861 }
862 {
863   method = MethodDeclaration() {classDeclaration.addMethod(method);}
864 | field = FieldDeclaration()   {classDeclaration.addVariable(field);}
865 }
866
867 /**
868  * A class field declaration : it's var VariableDeclarator() (, VariableDeclarator())*;.
869  */
870 FieldDeclaration FieldDeclaration() :
871 {
872   VariableDeclaration variableDeclaration;
873   VariableDeclaration[] list;
874   final ArrayList arrayList = new ArrayList();
875   final int pos = SimpleCharStream.getPosition();
876 }
877 {
878   <VAR> variableDeclaration = VariableDeclarator()
879   {arrayList.add(variableDeclaration);
880    outlineInfo.addVariable(new String(variableDeclaration.name));
881    currentSegment.add(variableDeclaration);}
882   ( <COMMA> variableDeclaration = VariableDeclarator()
883       {arrayList.add(variableDeclaration);
884        outlineInfo.addVariable(new String(variableDeclaration.name));
885        currentSegment.add(variableDeclaration);}
886   )*
887   try {
888     <SEMICOLON>
889   } catch (ParseException e) {
890     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected after variable declaration";
891     errorLevel   = ERROR;
892     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
893     errorEnd   = jj_input_stream.getPosition() + 1;
894     throw e;
895   }
896
897   {list = new VariableDeclaration[arrayList.size()];
898    arrayList.toArray(list);
899    return new FieldDeclaration(list,
900                                pos,
901                                SimpleCharStream.getPosition());}
902 }
903
904 VariableDeclaration VariableDeclarator() :
905 {
906   final String varName, varValue;
907   Expression initializer = null;
908   final int pos = jj_input_stream.getPosition();
909 }
910 {
911   varName = VariableDeclaratorId()
912   [
913     <ASSIGN>
914     try {
915       initializer = VariableInitializer()
916     } catch (ParseException e) {
917       errorMessage = "Literal expression expected in variable initializer";
918       errorLevel   = ERROR;
919       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
920       errorEnd   = jj_input_stream.getPosition() + 1;
921       throw e;
922     }
923   ]
924   {
925   if (initializer == null) {
926     return new VariableDeclaration(currentSegment,
927                                   varName.toCharArray(),
928                                   pos,
929                                   jj_input_stream.getPosition());
930   }
931     return new VariableDeclaration(currentSegment,
932                                     varName.toCharArray(),
933                                     initializer,
934                                     pos);
935   }
936 }
937
938 /**
939  * A Variable name.
940  * @return the variable name (with suffix)
941  */
942 String VariableDeclaratorId() :
943 {
944   String expr;
945   Expression expression;
946   final StringBuffer buff = new StringBuffer();
947   final int pos = SimpleCharStream.getPosition();
948   ConstantIdentifier ex;
949 }
950 {
951   try {
952     expr = Variable()   {buff.append(expr);}
953     ( LOOKAHEAD(2)
954       {ex = new ConstantIdentifier(expr.toCharArray(),
955                                    pos,
956                                    SimpleCharStream.getPosition());}
957       expression = VariableSuffix(ex)
958       {buff.append(expression.toStringExpression());}
959     )*
960     {return buff.toString();}
961   } catch (ParseException e) {
962     errorMessage = "'$' expected for variable identifier";
963     errorLevel   = ERROR;
964     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
965     errorEnd   = jj_input_stream.getPosition() + 1;
966     throw e;
967   }
968 }
969
970 String Variable():
971 {
972   final StringBuffer buff;
973   Expression expression = null;
974   final Token token;
975   final String expr;
976 }
977 {
978   token = <DOLLAR_ID> [<LBRACE> expression = Expression() <RBRACE>]
979   {
980     if (expression == null && !assigning) {
981       return token.image.substring(1);
982     }
983     buff = new StringBuffer(token.image);
984     buff.append('{');
985     buff.append(expression.toStringExpression());
986     buff.append('}');
987     return buff.toString();
988   }
989 |
990   <DOLLAR> expr = VariableName()
991   {return expr;}
992 }
993
994 String VariableName():
995 {
996   final StringBuffer buff;
997   String expr = null;
998   Expression expression = null;
999   final Token token;
1000 }
1001 {
1002   <LBRACE> expression = Expression() <RBRACE>
1003   {buff = new StringBuffer('{');
1004    buff.append(expression.toStringExpression());
1005    buff.append('}');
1006    return buff.toString();}
1007 |
1008   token = <IDENTIFIER> [<LBRACE> expression = Expression() <RBRACE>]
1009   {
1010     if (expression == null) {
1011       return token.image;
1012     }
1013     buff = new StringBuffer(token.image);
1014     buff.append('{');
1015     buff.append(expression.toStringExpression());
1016     buff.append('}');
1017     return buff.toString();
1018   }
1019 |
1020   <DOLLAR> expr = VariableName()
1021   {
1022     buff = new StringBuffer('$');
1023     buff.append(expr);
1024     return buff.toString();
1025   }
1026 |
1027   token = <DOLLAR_ID> {return token.image;}
1028 }
1029
1030 Expression VariableInitializer() :
1031 {
1032   final Expression expr;
1033   final Token token;
1034   final int pos = SimpleCharStream.getPosition();
1035 }
1036 {
1037   expr = Literal()
1038   {return expr;}
1039 |
1040   <MINUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1041   {return new PrefixedUnaryExpression(new NumberLiteral(token.image.toCharArray(),
1042                                                         pos,
1043                                                         SimpleCharStream.getPosition()),
1044                                       OperatorIds.MINUS,
1045                                       pos);}
1046 |
1047   <PLUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1048   {return new PrefixedUnaryExpression(new NumberLiteral(token.image.toCharArray(),
1049                                                         pos,
1050                                                         SimpleCharStream.getPosition()),
1051                                       OperatorIds.PLUS,
1052                                       pos);}
1053 |
1054   expr = ArrayDeclarator()
1055   {return expr;}
1056 |
1057   token = <IDENTIFIER>
1058   {return new ConstantIdentifier(token.image.toCharArray(),pos,SimpleCharStream.getPosition());}
1059 }
1060
1061 ArrayVariableDeclaration ArrayVariable() :
1062 {
1063 Expression expr,expr2;
1064 }
1065 {
1066   expr = Expression()
1067   [<ARRAYASSIGN> expr2 = Expression()
1068   {return new ArrayVariableDeclaration(expr,expr2);}
1069   ]
1070   {return new ArrayVariableDeclaration(expr,SimpleCharStream.getPosition());}
1071 }
1072
1073 ArrayVariableDeclaration[] ArrayInitializer() :
1074 {
1075   ArrayVariableDeclaration expr;
1076   final ArrayList list = new ArrayList();
1077 }
1078 {
1079   <LPAREN> [ expr = ArrayVariable()
1080             {list.add(expr);}
1081             ( LOOKAHEAD(2) <COMMA> expr = ArrayVariable()
1082             {list.add(expr);}
1083             )*
1084            ]
1085            [<COMMA> {list.add(null);}]
1086   <RPAREN>
1087   {
1088   ArrayVariableDeclaration[] vars = new ArrayVariableDeclaration[list.size()];
1089   list.toArray(vars);
1090   return vars;}
1091 }
1092
1093 /**
1094  * A Method Declaration.
1095  * <b>function</b> MetodDeclarator() Block()
1096  */
1097 MethodDeclaration MethodDeclaration() :
1098 {
1099   final MethodDeclaration functionDeclaration;
1100   Token functionToken;
1101   final Block block;
1102 }
1103 {
1104   functionToken = <FUNCTION>
1105   try {
1106     functionDeclaration = MethodDeclarator()
1107     {outlineInfo.addVariable(new String(functionDeclaration.name));}
1108   } catch (ParseException e) {
1109     if (errorMessage != null)  throw e;
1110     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
1111     errorLevel   = ERROR;
1112     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1113     errorEnd   = jj_input_stream.getPosition() + 1;
1114     throw e;
1115   }
1116   {
1117     if (currentSegment != null) {
1118       currentSegment.add(functionDeclaration);
1119       currentSegment = functionDeclaration;
1120     }
1121     currentFunction = functionDeclaration;
1122   }
1123   block = Block()
1124   {
1125     functionDeclaration.statements = block.statements;
1126     currentFunction = null;
1127     if (currentSegment != null) {
1128       currentSegment = (OutlineableWithChildren) currentSegment.getParent();
1129     }
1130     return functionDeclaration;
1131   }
1132 }
1133
1134 /**
1135  * A MethodDeclarator.
1136  * [&] IDENTIFIER(parameters ...).
1137  * @return a function description for the outline
1138  */
1139 MethodDeclaration MethodDeclarator() :
1140 {
1141   final Token identifier;
1142   Token reference = null;
1143   final Hashtable formalParameters;
1144   final int pos = SimpleCharStream.getPosition();
1145 }
1146 {
1147   [reference = <BIT_AND>] identifier = <IDENTIFIER>
1148   formalParameters = FormalParameters()
1149   {return new MethodDeclaration(currentSegment,
1150                                  identifier.image.toCharArray(),
1151                                  formalParameters,
1152                                  reference != null,
1153                                  pos,
1154                                  SimpleCharStream.getPosition());}
1155 }
1156
1157 /**
1158  * FormalParameters follows method identifier.
1159  * (FormalParameter())
1160  */
1161 Hashtable FormalParameters() :
1162 {
1163   String expr;
1164   final StringBuffer buff = new StringBuffer("(");
1165   VariableDeclaration var;
1166   final Hashtable parameters = new Hashtable();
1167 }
1168 {
1169   try {
1170   <LPAREN>
1171   } catch (ParseException e) {
1172     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected after function identifier";
1173     errorLevel   = ERROR;
1174     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1175     errorEnd   = jj_input_stream.getPosition() + 1;
1176     throw e;
1177   }
1178             [ var = FormalParameter()
1179               {parameters.put(new String(var.name),var);}
1180               (
1181                 <COMMA> var = FormalParameter()
1182                 {parameters.put(new String(var.name),var);}
1183               )*
1184             ]
1185   try {
1186     <RPAREN>
1187   } catch (ParseException e) {
1188     errorMessage = "')' expected";
1189     errorLevel   = ERROR;
1190     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1191     errorEnd   = jj_input_stream.getPosition() + 1;
1192     throw e;
1193   }
1194  {return parameters;}
1195 }
1196
1197 /**
1198  * A formal parameter.
1199  * $varname[=value] (,$varname[=value])
1200  */
1201 VariableDeclaration FormalParameter() :
1202 {
1203   final VariableDeclaration variableDeclaration;
1204   Token token = null;
1205 }
1206 {
1207   [token = <BIT_AND>] variableDeclaration = VariableDeclarator()
1208   {
1209     if (token != null) {
1210       variableDeclaration.setReference(true);
1211     }
1212     return variableDeclaration;}
1213 }
1214
1215 ConstantIdentifier Type() :
1216 {final int pos;}
1217 {
1218   <STRING>             {pos = SimpleCharStream.getPosition();
1219                         return new ConstantIdentifier(Types.STRING,
1220                                         pos,pos-6);}
1221 | <BOOL>               {pos = SimpleCharStream.getPosition();
1222                         return new ConstantIdentifier(Types.BOOL,
1223                                         pos,pos-4);}
1224 | <BOOLEAN>            {pos = SimpleCharStream.getPosition();
1225                         return new ConstantIdentifier(Types.BOOLEAN,
1226                                         pos,pos-7);}
1227 | <REAL>               {pos = SimpleCharStream.getPosition();
1228                         return new ConstantIdentifier(Types.REAL,
1229                                         pos,pos-4);}
1230 | <DOUBLE>             {pos = SimpleCharStream.getPosition();
1231                         return new ConstantIdentifier(Types.DOUBLE,
1232                                         pos,pos-5);}
1233 | <FLOAT>              {pos = SimpleCharStream.getPosition();
1234                         return new ConstantIdentifier(Types.FLOAT,
1235                                         pos,pos-5);}
1236 | <INT>                {pos = SimpleCharStream.getPosition();
1237                         return new ConstantIdentifier(Types.INT,
1238                                         pos,pos-3);}
1239 | <INTEGER>            {pos = SimpleCharStream.getPosition();
1240                         return new ConstantIdentifier(Types.INTEGER,
1241                                         pos,pos-7);}
1242 | <OBJECT>             {pos = SimpleCharStream.getPosition();
1243                         return new ConstantIdentifier(Types.OBJECT,
1244                                         pos,pos-6);}
1245 }
1246
1247 Expression Expression() :
1248 {
1249   final Expression expr;
1250 }
1251 {
1252   expr = PrintExpression()       {return expr;}
1253 | expr = ListExpression()        {return expr;}
1254 | LOOKAHEAD(varAssignation())
1255   expr = varAssignation()        {return expr;}
1256 | expr = ConditionalExpression() {return expr;}
1257 }
1258
1259 /**
1260  * A Variable assignation.
1261  * varName (an assign operator) any expression
1262  */
1263 VarAssignation varAssignation() :
1264 {
1265   String varName;
1266   final Expression expression;
1267   final int assignOperator;
1268   final int pos = SimpleCharStream.getPosition();
1269 }
1270 {
1271   varName = VariableDeclaratorId()
1272   assignOperator = AssignmentOperator()
1273     try {
1274       expression = Expression()
1275     } catch (ParseException e) {
1276       if (errorMessage != null) {
1277         throw e;
1278       }
1279       errorMessage = "expression expected";
1280       errorLevel   = ERROR;
1281       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1282       errorEnd   = jj_input_stream.getPosition() + 1;
1283       throw e;
1284     }
1285     {return new VarAssignation(varName.toCharArray(),
1286                                expression,
1287                                assignOperator,
1288                                pos,
1289                                SimpleCharStream.getPosition());}
1290 }
1291
1292 int AssignmentOperator() :
1293 {}
1294 {
1295   <ASSIGN>             {return VarAssignation.EQUAL;}
1296 | <STARASSIGN>         {return VarAssignation.STAR_EQUAL;}
1297 | <SLASHASSIGN>        {return VarAssignation.SLASH_EQUAL;}
1298 | <REMASSIGN>          {return VarAssignation.REM_EQUAL;}
1299 | <PLUSASSIGN>         {return VarAssignation.PLUS_EQUAL;}
1300 | <MINUSASSIGN>        {return VarAssignation.MINUS_EQUAL;}
1301 | <LSHIFTASSIGN>       {return VarAssignation.LSHIFT_EQUAL;}
1302 | <RSIGNEDSHIFTASSIGN> {return VarAssignation.RSIGNEDSHIFT_EQUAL;}
1303 | <ANDASSIGN>          {return VarAssignation.AND_EQUAL;}
1304 | <XORASSIGN>          {return VarAssignation.XOR_EQUAL;}
1305 | <ORASSIGN>           {return VarAssignation.OR_EQUAL;}
1306 | <DOTASSIGN>          {return VarAssignation.DOT_EQUAL;}
1307 | <TILDEEQUAL>         {return VarAssignation.TILDE_EQUAL;}
1308 }
1309
1310 Expression ConditionalExpression() :
1311 {
1312   final Expression expr;
1313   Expression expr2 = null;
1314   Expression expr3 = null;
1315 }
1316 {
1317   expr = ConditionalOrExpression() [ <HOOK> expr2 = Expression() <COLON> expr3 = ConditionalExpression() ]
1318 {
1319   if (expr3 == null) {
1320     return expr;
1321   }
1322   return new ConditionalExpression(expr,expr2,expr3);
1323 }
1324 }
1325
1326 Expression ConditionalOrExpression() :
1327 {
1328   Expression expr,expr2;
1329   int operator;
1330 }
1331 {
1332   expr = ConditionalAndExpression()
1333   (
1334     (
1335         <OR_OR> {operator = OperatorIds.OR_OR;}
1336       | <_ORL>  {operator = OperatorIds.ORL;}
1337     ) expr2 = ConditionalAndExpression()
1338     {
1339       expr = new BinaryExpression(expr,expr2,operator);
1340     }
1341   )*
1342   {return expr;}
1343 }
1344
1345 Expression ConditionalAndExpression() :
1346 {
1347   Expression expr,expr2;
1348   int operator;
1349 }
1350 {
1351   expr = ConcatExpression()
1352   (
1353   (  <AND_AND> {operator = OperatorIds.AND_AND;}
1354    | <_ANDL>   {operator = OperatorIds.ANDL;})
1355    expr2 = ConcatExpression() {expr = new BinaryExpression(expr,expr2,operator);}
1356   )*
1357   {return expr;}
1358 }
1359
1360 Expression ConcatExpression() :
1361 {
1362   Expression expr,expr2;
1363 }
1364 {
1365   expr = InclusiveOrExpression()
1366   (
1367     <DOT> expr2 = InclusiveOrExpression()
1368     {expr = new BinaryExpression(expr,expr2,OperatorIds.DOT);}
1369   )*
1370   {return expr;}
1371 }
1372
1373 Expression InclusiveOrExpression() :
1374 {
1375   Expression expr,expr2;
1376 }
1377 {
1378   expr = ExclusiveOrExpression()
1379   (<BIT_OR> expr2 = ExclusiveOrExpression()
1380    {expr = new BinaryExpression(expr,expr2,OperatorIds.OR);}
1381   )*
1382   {return expr;}
1383 }
1384
1385 Expression ExclusiveOrExpression() :
1386 {
1387   Expression expr,expr2;
1388 }
1389 {
1390   expr = AndExpression()
1391   (
1392     <XOR> expr2 = AndExpression()
1393     {expr = new BinaryExpression(expr,expr2,OperatorIds.XOR);}
1394   )*
1395   {return expr;}
1396 }
1397
1398 Expression AndExpression() :
1399 {
1400   Expression expr,expr2;
1401 }
1402 {
1403   expr = EqualityExpression()
1404   (
1405     <BIT_AND> expr2 = EqualityExpression()
1406     {expr = new BinaryExpression(expr,expr2,OperatorIds.AND);}
1407   )*
1408   {return expr;}
1409 }
1410
1411 Expression EqualityExpression() :
1412 {
1413   Expression expr,expr2;
1414   int operator;
1415 }
1416 {
1417   expr = RelationalExpression()
1418   (
1419   (   <EQUAL_EQUAL>      {operator = OperatorIds.EQUAL_EQUAL;}
1420     | <DIF>              {operator = OperatorIds.DIF;}
1421     | <NOT_EQUAL>        {operator = OperatorIds.DIF;}
1422     | <BANGDOUBLEEQUAL>  {operator = OperatorIds.BANG_EQUAL_EQUAL;}
1423     | <TRIPLEEQUAL>      {operator = OperatorIds.EQUAL_EQUAL_EQUAL;}
1424   )
1425   try {
1426     expr2 = RelationalExpression()
1427   } catch (ParseException e) {
1428     if (errorMessage != null) {
1429       throw e;
1430     }
1431     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
1432     errorLevel   = ERROR;
1433     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1434     errorEnd   = jj_input_stream.getPosition() + 1;
1435     throw e;
1436   }
1437   {
1438     expr = new BinaryExpression(expr,expr2,operator);
1439   }
1440   )*
1441   {return expr;}
1442 }
1443
1444 Expression RelationalExpression() :
1445 {
1446   Expression expr,expr2;
1447   int operator;
1448 }
1449 {
1450   expr = ShiftExpression()
1451   (
1452   ( <LT> {operator = OperatorIds.LESS;}
1453   | <GT> {operator = OperatorIds.GREATER;}
1454   | <LE> {operator = OperatorIds.LESS_EQUAL;}
1455   | <GE> {operator = OperatorIds.GREATER_EQUAL;})
1456    expr2 = ShiftExpression()
1457   {expr = new BinaryExpression(expr,expr2,operator);}
1458   )*
1459   {return expr;}
1460 }
1461
1462 Expression ShiftExpression() :
1463 {
1464   Expression expr,expr2;
1465   int operator;
1466 }
1467 {
1468   expr = AdditiveExpression()
1469   (
1470   ( <LSHIFT>         {operator = OperatorIds.LEFT_SHIFT;}
1471   | <RSIGNEDSHIFT>   {operator = OperatorIds.RIGHT_SHIFT;}
1472   | <RUNSIGNEDSHIFT> {operator = OperatorIds.UNSIGNED_RIGHT_SHIFT;})
1473   expr2 = AdditiveExpression()
1474   {expr = new BinaryExpression(expr,expr2,operator);}
1475   )*
1476   {return expr;}
1477 }
1478
1479 Expression AdditiveExpression() :
1480 {
1481   Expression expr,expr2;
1482   int operator;
1483 }
1484 {
1485   expr = MultiplicativeExpression()
1486   (
1487    ( <PLUS>  {operator = OperatorIds.PLUS;}
1488    | <MINUS> {operator = OperatorIds.MINUS;} )
1489    expr2 = MultiplicativeExpression()
1490   {expr = new BinaryExpression(expr,expr2,operator);}
1491    )*
1492   {return expr;}
1493 }
1494
1495 Expression MultiplicativeExpression() :
1496 {
1497   Expression expr,expr2;
1498   int operator;
1499 }
1500 {
1501   try {
1502     expr = UnaryExpression()
1503   } catch (ParseException e) {
1504     if (errorMessage != null) throw e;
1505     errorMessage = "unexpected token '"+e.currentToken.next.image+"'";
1506     errorLevel   = ERROR;
1507     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1508     errorEnd   = jj_input_stream.getPosition() + 1;
1509     throw e;
1510   }
1511   (
1512    (  <STAR>      {operator = OperatorIds.MULTIPLY;}
1513     | <SLASH>     {operator = OperatorIds.DIVIDE;}
1514     | <REMAINDER> {operator = OperatorIds.REMAINDER;})
1515     expr2 = UnaryExpression()
1516     {expr = new BinaryExpression(expr,expr2,operator);}
1517   )*
1518   {return expr;}
1519 }
1520
1521 /**
1522  * An unary expression starting with @, & or nothing
1523  */
1524 Expression UnaryExpression() :
1525 {
1526   Expression expr;
1527   final int pos = SimpleCharStream.getPosition();
1528 }
1529 {
1530   <BIT_AND> expr = UnaryExpressionNoPrefix()
1531   {return new PrefixedUnaryExpression(expr,OperatorIds.AND,pos);}
1532 |
1533   expr = AtUnaryExpression() {return expr;}
1534 }
1535
1536 Expression AtUnaryExpression() :
1537 {
1538   Expression expr;
1539   final int pos = SimpleCharStream.getPosition();
1540 }
1541 {
1542   <AT>
1543   expr = AtUnaryExpression()
1544   {return new PrefixedUnaryExpression(expr,OperatorIds.AT,pos);}
1545 |
1546   expr = UnaryExpressionNoPrefix()
1547   {return expr;}
1548 }
1549
1550
1551 Expression UnaryExpressionNoPrefix() :
1552 {
1553   Expression expr;
1554   int operator;
1555   final int pos = SimpleCharStream.getPosition();
1556 }
1557 {
1558   (  <PLUS>  {operator = OperatorIds.PLUS;}
1559    | <MINUS> {operator = OperatorIds.MINUS;})
1560    expr = UnaryExpression()
1561   {return new PrefixedUnaryExpression(expr,operator,pos);}
1562 |
1563   expr = PreIncDecExpression()
1564   {return expr;}
1565 |
1566   expr = UnaryExpressionNotPlusMinus()
1567   {return expr;}
1568 }
1569
1570
1571 Expression PreIncDecExpression() :
1572 {
1573 final Expression expr;
1574 final int operator;
1575   final int pos = SimpleCharStream.getPosition();
1576 }
1577 {
1578   (  <INCR> {operator = OperatorIds.PLUS_PLUS;}
1579    | <DECR> {operator = OperatorIds.MINUS_MINUS;})
1580    expr = PrimaryExpression()
1581   {return new PrefixedUnaryExpression(expr,operator,pos);}
1582 }
1583
1584 Expression UnaryExpressionNotPlusMinus() :
1585 {
1586   Expression expr;
1587   final int pos = SimpleCharStream.getPosition();
1588 }
1589 {
1590   <BANG> expr = UnaryExpression() {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,pos);}
1591 | LOOKAHEAD( <LPAREN> (Type() | <ARRAY>) <RPAREN> )
1592   expr = CastExpression()         {return expr;}
1593 | expr = PostfixExpression()      {return expr;}
1594 | expr = Literal()                {return expr;}
1595 | <LPAREN> expr = Expression()
1596   try {
1597     <RPAREN>
1598   } catch (ParseException e) {
1599     errorMessage = "')' expected";
1600     errorLevel   = ERROR;
1601     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1602     errorEnd     = jj_input_stream.getPosition() + 1;
1603     throw e;
1604   }
1605   {return expr;}
1606 }
1607
1608 CastExpression CastExpression() :
1609 {
1610 final ConstantIdentifier type;
1611 final Expression expr;
1612 final int pos = SimpleCharStream.getPosition();
1613 }
1614 {
1615   <LPAREN>
1616   (type = Type()
1617   | <ARRAY> {type = new ConstantIdentifier(Types.ARRAY,pos,SimpleCharStream.getPosition());})
1618   <RPAREN> expr = UnaryExpression()
1619   {return new CastExpression(type,expr,pos,SimpleCharStream.getPosition());}
1620 }
1621
1622 Expression PostfixExpression() :
1623 {
1624   Expression expr;
1625   int operator = -1;
1626   final int pos = SimpleCharStream.getPosition();
1627 }
1628 {
1629   expr = PrimaryExpression()
1630   [ <INCR> {operator = OperatorIds.PLUS_PLUS;}
1631   | <DECR> {operator = OperatorIds.MINUS_MINUS;}]
1632   {
1633     if (operator == -1) {
1634       return expr;
1635     }
1636     return new PostfixedUnaryExpression(expr,operator,pos);
1637   }
1638 }
1639
1640 Expression PrimaryExpression() :
1641 {
1642   final Token identifier;
1643   Expression expr;
1644   final StringBuffer buff = new StringBuffer();
1645   final int pos = SimpleCharStream.getPosition();
1646 }
1647 {
1648   LOOKAHEAD(2)
1649   identifier = <IDENTIFIER> <STATICCLASSACCESS> expr = ClassIdentifier()
1650   {expr = new ClassAccess(new ConstantIdentifier(identifier.image.toCharArray(),
1651                                                  pos,
1652                                                  SimpleCharStream.getPosition()),
1653                           expr,
1654                           ClassAccess.STATIC);}
1655   (expr = PrimarySuffix(expr))*
1656   {return expr;}
1657 |
1658   expr = PrimaryPrefix()
1659   (expr = PrimarySuffix(expr))*
1660   {return expr;}
1661 |
1662   expr = ArrayDeclarator()
1663   {return expr;}
1664 }
1665
1666 ArrayInitializer ArrayDeclarator() :
1667 {
1668   final ArrayVariableDeclaration[] vars;
1669   final int pos = SimpleCharStream.getPosition();
1670 }
1671 {
1672   <ARRAY> vars = ArrayInitializer()
1673   {return new ArrayInitializer(vars,pos,SimpleCharStream.getPosition());}
1674 }
1675
1676 Expression PrimaryPrefix() :
1677 {
1678   final Expression expr;
1679   final Token token;
1680   final String var;
1681   final int pos = SimpleCharStream.getPosition();
1682 }
1683 {
1684   token = <IDENTIFIER>           {return new ConstantIdentifier(token.image.toCharArray(),
1685                                                                 pos,
1686                                                                 SimpleCharStream.getPosition());}
1687 | <NEW> expr = ClassIdentifier() {return new PrefixedUnaryExpression(expr,
1688                                                                      OperatorIds.NEW,
1689                                                                      pos);}
1690 | var = VariableDeclaratorId()  {return new ConstantIdentifier(var.toCharArray(),
1691                                                                pos,
1692                                                                SimpleCharStream.getPosition());}
1693 }
1694
1695 PrefixedUnaryExpression classInstantiation() :
1696 {
1697   Expression expr;
1698   final StringBuffer buff;
1699   final int pos = SimpleCharStream.getPosition();
1700 }
1701 {
1702   <NEW> expr = ClassIdentifier()
1703   [
1704     {buff = new StringBuffer(expr.toStringExpression());}
1705     expr = PrimaryExpression()
1706     {buff.append(expr.toStringExpression());
1707     expr = new ConstantIdentifier(buff.toString().toCharArray(),
1708                                   pos,
1709                                   SimpleCharStream.getPosition());}
1710   ]
1711   {return new PrefixedUnaryExpression(expr,
1712                                       OperatorIds.NEW,
1713                                       pos);}
1714 }
1715
1716 ConstantIdentifier ClassIdentifier():
1717 {
1718   final String expr;
1719   final Token token;
1720   final int pos = SimpleCharStream.getPosition();
1721 }
1722 {
1723   token = <IDENTIFIER>          {return new ConstantIdentifier(token.image.toCharArray(),
1724                                                                pos,
1725                                                                SimpleCharStream.getPosition());}
1726 | expr = VariableDeclaratorId() {return new ConstantIdentifier(expr.toCharArray(),
1727                                                                pos,
1728                                                                SimpleCharStream.getPosition());}
1729 }
1730
1731 AbstractSuffixExpression PrimarySuffix(Expression prefix) :
1732 {
1733   final AbstractSuffixExpression expr;
1734 }
1735 {
1736   expr = Arguments(prefix)      {return expr;}
1737 | expr = VariableSuffix(prefix) {return expr;}
1738 }
1739
1740 AbstractSuffixExpression VariableSuffix(Expression prefix) :
1741 {
1742   String expr = null;
1743   final int pos = SimpleCharStream.getPosition();
1744   Expression expression = null;
1745 }
1746 {
1747   <CLASSACCESS>
1748   try {
1749     expr = VariableName()
1750   } catch (ParseException e) {
1751     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function call or field access expected";
1752     errorLevel   = ERROR;
1753     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1754     errorEnd   = jj_input_stream.getPosition() + 1;
1755     throw e;
1756   }
1757   {return new ClassAccess(prefix,
1758                           new ConstantIdentifier(expr.toCharArray(),pos,SimpleCharStream.getPosition()),
1759                           ClassAccess.NORMAL);}
1760 |
1761   <LBRACKET> [ expression = Expression() | expression = Type() ]  //Not good
1762   try {
1763     <RBRACKET>
1764   } catch (ParseException e) {
1765     errorMessage = "']' expected";
1766     errorLevel   = ERROR;
1767     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1768     errorEnd   = jj_input_stream.getPosition() + 1;
1769     throw e;
1770   }
1771   {return new ArrayDeclarator(prefix,expression,SimpleCharStream.getPosition());}
1772 }
1773
1774 Literal Literal() :
1775 {
1776   final Token token;
1777   final int pos;
1778 }
1779 {
1780   token = <INTEGER_LITERAL>        {pos = SimpleCharStream.getPosition();
1781                                     return new NumberLiteral(token.image.toCharArray(),pos-token.image.length(),pos);}
1782 | token = <FLOATING_POINT_LITERAL> {pos = SimpleCharStream.getPosition();
1783                                     return new NumberLiteral(token.image.toCharArray(),pos-token.image.length(),pos);}
1784 | token = <STRING_LITERAL>         {pos = SimpleCharStream.getPosition();
1785                                     return new StringLiteral(token.image.toCharArray(),pos-token.image.length(),pos);}
1786 | <TRUE>                           {pos = SimpleCharStream.getPosition();
1787                                     return new TrueLiteral(pos-4,pos);}
1788 | <FALSE>                          {pos = SimpleCharStream.getPosition();
1789                                     return new FalseLiteral(pos-4,pos);}
1790 | <NULL>                           {pos = SimpleCharStream.getPosition();
1791                                     return new NullLiteral(pos-4,pos);}
1792 }
1793
1794 FunctionCall Arguments(Expression func) :
1795 {
1796 ArgumentDeclaration[] args = null;
1797 }
1798 {
1799   <LPAREN> [ args = ArgumentList() ]
1800   try {
1801     <RPAREN>
1802   } catch (ParseException e) {
1803     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list";
1804     errorLevel   = ERROR;
1805     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1806     errorEnd   = jj_input_stream.getPosition() + 1;
1807     throw e;
1808   }
1809   {return new FunctionCall(func,args,SimpleCharStream.getPosition());}
1810 }
1811
1812 /**
1813  * An argument list is a list of arguments separated by comma :
1814  * argumentDeclaration() (, argumentDeclaration)*
1815  * @return an array of arguments
1816  */
1817 ArgumentDeclaration[] ArgumentList() :
1818 {
1819 ArgumentDeclaration arg;
1820 final ArrayList list = new ArrayList();
1821 ArgumentDeclaration argument;
1822 }
1823 {
1824   arg = argumentDeclaration()
1825   {list.add(arg);}
1826   ( <COMMA>
1827       try {
1828         arg = argumentDeclaration()
1829         {list.add(arg);}
1830       } catch (ParseException e) {
1831         errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. An expression expected after a comma in argument list";
1832         errorLevel   = ERROR;
1833         errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1834         errorEnd     = jj_input_stream.getPosition() + 1;
1835         throw e;
1836       }
1837    )*
1838    {
1839    ArgumentDeclaration[] args = new ArgumentDeclaration[list.size()];
1840    list.toArray(args);
1841    return args;}
1842 }
1843
1844 /**
1845  * Here is an argument declaration.
1846  * It's [&]$variablename[=variableInitializer]
1847  */
1848 ArgumentDeclaration argumentDeclaration() :
1849 {
1850   boolean reference = false;
1851   String varName;
1852   Expression initializer = null;
1853   final int pos = SimpleCharStream.getPosition();
1854 }
1855 {
1856   [<BIT_AND> {reference = true;}]
1857   varName = VariableDeclaratorId()
1858  [
1859     <ASSIGN>
1860     try {
1861       initializer = VariableInitializer()
1862     } catch (ParseException e) {
1863       errorMessage = "Literal expression expected in variable initializer";
1864       errorLevel   = ERROR;
1865       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1866       errorEnd   = jj_input_stream.getPosition() + 1;
1867       throw e;
1868     }
1869   ]
1870   {
1871   if (initializer == null) {
1872     return new ArgumentDeclaration(varName.toCharArray(),
1873                                    reference,
1874                                    pos);
1875   }
1876   return new ArgumentDeclaration(varName.toCharArray(),
1877                                  reference,
1878                                  initializer,
1879                                  pos);
1880   }
1881 }
1882 /**
1883  * A Statement without break.
1884  */
1885 Statement StatementNoBreak() :
1886 {
1887   final Statement statement;
1888   Token token = null;
1889 }
1890 {
1891   LOOKAHEAD(2)
1892   statement = Expression()
1893   try {
1894     <SEMICOLON>
1895   } catch (ParseException e) {
1896     if (e.currentToken.next.kind != 4) {
1897       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1898       errorLevel   = ERROR;
1899       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1900       errorEnd   = jj_input_stream.getPosition() + 1;
1901       throw e;
1902     }
1903   }
1904   {return statement;}
1905 | LOOKAHEAD(2)
1906   statement = LabeledStatement() {return statement;}
1907 | statement = Block()            {return statement;}
1908 | statement = EmptyStatement()   {return statement;}
1909 | statement = StatementExpression()
1910   try {
1911     <SEMICOLON>
1912   } catch (ParseException e) {
1913     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1914     errorLevel   = ERROR;
1915     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1916     errorEnd     = jj_input_stream.getPosition() + 1;
1917     throw e;
1918   }
1919   {return statement;}
1920 | statement = SwitchStatement()         {return statement;}
1921 | statement = IfStatement()             {return statement;}
1922 | statement = WhileStatement()          {return statement;}
1923 | statement = DoStatement()             {return statement;}
1924 | statement = ForStatement()            {return statement;}
1925 | statement = ForeachStatement()        {return statement;}
1926 | statement = ContinueStatement()       {return statement;}
1927 | statement = ReturnStatement()         {return statement;}
1928 | statement = EchoStatement()           {return statement;}
1929 | [token=<AT>] statement = IncludeStatement()
1930   {if (token != null) {
1931     ((InclusionStatement)statement).silent = true;
1932   }
1933   return statement;}
1934 | statement = StaticStatement()         {return statement;}
1935 | statement = GlobalStatement()         {return statement;}
1936 }
1937
1938 /**
1939  * A Normal statement.
1940  */
1941 Statement Statement() :
1942 {
1943   final Statement statement;
1944 }
1945 {
1946   statement = StatementNoBreak() {return statement;}
1947 | statement = BreakStatement()   {return statement;}
1948 }
1949
1950 /**
1951  * An html block inside a php syntax.
1952  */
1953 HTMLBlock htmlBlock() :
1954 {
1955   final int startIndex = nodePtr;
1956   AstNode[] blockNodes;
1957   int nbNodes;
1958 }
1959 {
1960   <PHPEND> (phpEchoBlock())*
1961   try {
1962     (<PHPSTARTLONG> | <PHPSTARTSHORT>)
1963   } catch (ParseException e) {
1964     errorMessage = "End of file unexpected, '<?php' expected";
1965     errorLevel   = ERROR;
1966     errorStart   = jj_input_stream.getPosition();
1967     errorEnd     = jj_input_stream.getPosition();
1968     throw e;
1969   }
1970   {
1971   nbNodes = nodePtr-startIndex - 1;
1972   blockNodes = new AstNode[nbNodes];
1973   System.arraycopy(nodes,startIndex,blockNodes,0,nbNodes);
1974   return new HTMLBlock(nodes);}
1975 }
1976
1977 /**
1978  * An include statement. It's "include" an expression;
1979  */
1980 InclusionStatement IncludeStatement() :
1981 {
1982   final Expression expr;
1983   final Token token;
1984   final int keyword;
1985   final int pos = jj_input_stream.getPosition();
1986   final InclusionStatement inclusionStatement;
1987 }
1988 {
1989       (  <REQUIRE>      {keyword = InclusionStatement.REQUIRE;}
1990        | <REQUIRE_ONCE> {keyword = InclusionStatement.REQUIRE_ONCE;}
1991        | <INCLUDE>      {keyword = InclusionStatement.INCLUDE;}
1992        | <INCLUDE_ONCE> {keyword = InclusionStatement.INCLUDE_ONCE;})
1993   try {
1994     expr = Expression()
1995   } catch (ParseException e) {
1996     if (errorMessage != null) {
1997       throw e;
1998     }
1999     errorMessage = "unexpected token '"+ e.currentToken.next.image+"', expression expected";
2000     errorLevel   = ERROR;
2001     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2002     errorEnd     = jj_input_stream.getPosition() + 1;
2003     throw e;
2004   }
2005   {inclusionStatement = new InclusionStatement(currentSegment,
2006                                                keyword,
2007                                                expr,
2008                                                pos);
2009    currentSegment.add(inclusionStatement);
2010   }
2011   try {
2012     <SEMICOLON>
2013   } catch (ParseException e) {
2014     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2015     errorLevel   = ERROR;
2016     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2017     errorEnd     = jj_input_stream.getPosition() + 1;
2018     throw e;
2019   }
2020   {return inclusionStatement;}
2021 }
2022
2023 PrintExpression PrintExpression() :
2024 {
2025   final Expression expr;
2026   final int pos = SimpleCharStream.getPosition();
2027 }
2028 {
2029   <PRINT> expr = Expression() {return new PrintExpression(expr,pos,SimpleCharStream.getPosition());}
2030 }
2031
2032 ListExpression ListExpression() :
2033 {
2034   String expr = null;
2035   Expression expression = null;
2036   ArrayList list = new ArrayList();
2037   final int pos = SimpleCharStream.getPosition();
2038 }
2039 {
2040   <LIST>
2041   try {
2042     <LPAREN>
2043   } catch (ParseException e) {
2044     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
2045     errorLevel   = ERROR;
2046     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2047     errorEnd     = jj_input_stream.getPosition() + 1;
2048     throw e;
2049   }
2050   [
2051     expr = VariableDeclaratorId()
2052     {list.add(expr);}
2053   ]
2054   {if (expr == null) list.add(null);}
2055   (
2056     try {
2057       <COMMA>
2058     } catch (ParseException e) {
2059       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
2060       errorLevel   = ERROR;
2061       errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2062       errorEnd     = jj_input_stream.getPosition() + 1;
2063       throw e;
2064     }
2065     expr = VariableDeclaratorId()
2066     {list.add(expr);}
2067   )*
2068   try {
2069     <RPAREN>
2070   } catch (ParseException e) {
2071     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
2072     errorLevel   = ERROR;
2073     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2074     errorEnd   = jj_input_stream.getPosition() + 1;
2075     throw e;
2076   }
2077   [ <ASSIGN> expression = Expression()
2078     {
2079     String[] strings = new String[list.size()];
2080     list.toArray(strings);
2081     return new ListExpression(strings,
2082                               expression,
2083                               pos,
2084                               SimpleCharStream.getPosition());}
2085   ]
2086   {
2087     String[] strings = new String[list.size()];
2088     list.toArray(strings);
2089     return new ListExpression(strings,pos,SimpleCharStream.getPosition());}
2090 }
2091
2092 /**
2093  * An echo statement.
2094  * echo anyexpression (, otherexpression)*
2095  */
2096 EchoStatement EchoStatement() :
2097 {
2098   final ArrayList expressions = new ArrayList();
2099   Expression expr;
2100   final int pos = SimpleCharStream.getPosition();
2101 }
2102 {
2103   <ECHO> expr = Expression()
2104   {expressions.add(expr);}
2105   (
2106     <COMMA> expr = Expression()
2107     {expressions.add(expr);}
2108   )*
2109   try {
2110     <SEMICOLON>
2111     {
2112     Expression[] exprs = new Expression[expressions.size()];
2113     expressions.toArray(exprs);
2114     return new EchoStatement(exprs,pos);}
2115   } catch (ParseException e) {
2116     if (e.currentToken.next.kind != 4) {
2117       errorMessage = "';' expected after 'echo' statement";
2118       errorLevel   = ERROR;
2119       errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2120       errorEnd     = jj_input_stream.getPosition() + 1;
2121       throw e;
2122     }
2123   }
2124 }
2125
2126 GlobalStatement GlobalStatement() :
2127 {
2128    final int pos = jj_input_stream.getPosition();
2129    String expr;
2130    ArrayList vars = new ArrayList();
2131    GlobalStatement global;
2132 }
2133 {
2134   <GLOBAL>
2135     expr = VariableDeclaratorId()
2136     {vars.add(expr);}
2137   (<COMMA>
2138     expr = VariableDeclaratorId()
2139     {vars.add(expr);}
2140   )*
2141   try {
2142     <SEMICOLON>
2143     {
2144     String[] strings = new String[vars.size()];
2145     vars.toArray(strings);
2146     global = new GlobalStatement(currentSegment,
2147                                  strings,
2148                                  pos,
2149                                  SimpleCharStream.getPosition());
2150     currentSegment.add(global);
2151     return global;}
2152   } catch (ParseException e) {
2153     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2154     errorLevel   = ERROR;
2155     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2156     errorEnd   = jj_input_stream.getPosition() + 1;
2157     throw e;
2158   }
2159 }
2160
2161 StaticStatement StaticStatement() :
2162 {
2163   final int pos = SimpleCharStream.getPosition();
2164   final ArrayList vars = new ArrayList();
2165   VariableDeclaration expr;
2166 }
2167 {
2168   <STATIC> expr = VariableDeclarator() {vars.add(new String(expr.name));}
2169   (<COMMA> expr = VariableDeclarator() {vars.add(new String(expr.name));})*
2170   try {
2171     <SEMICOLON>
2172     {
2173     String[] strings = new String[vars.size()];
2174     vars.toArray(strings);
2175     return new StaticStatement(strings,
2176                                 pos,
2177                                 SimpleCharStream.getPosition());}
2178   } catch (ParseException e) {
2179     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2180     errorLevel   = ERROR;
2181     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2182     errorEnd   = jj_input_stream.getPosition() + 1;
2183     throw e;
2184   }
2185 }
2186
2187 LabeledStatement LabeledStatement() :
2188 {
2189   final int pos = SimpleCharStream.getPosition();
2190   final Token label;
2191   final Statement statement;
2192 }
2193 {
2194   label = <IDENTIFIER> <COLON> statement = Statement()
2195   {return new LabeledStatement(label.image.toCharArray(),statement,pos,SimpleCharStream.getPosition());}
2196 }
2197
2198 /**
2199  * A Block is
2200  * {
2201  * statements
2202  * }.
2203  * @return a block
2204  */
2205 Block Block() :
2206 {
2207   final int pos = SimpleCharStream.getPosition();
2208   final ArrayList list = new ArrayList();
2209   Statement statement;
2210 }
2211 {
2212   try {
2213     <LBRACE>
2214   } catch (ParseException e) {
2215     errorMessage = "'{' expected";
2216     errorLevel   = ERROR;
2217     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2218     errorEnd   = jj_input_stream.getPosition() + 1;
2219     throw e;
2220   }
2221   ( statement = BlockStatement() {list.add(statement);}
2222   | statement = htmlBlock()      {list.add(statement);})*
2223   try {
2224     <RBRACE>
2225   } catch (ParseException e) {
2226     errorMessage = "unexpected token : '"+ e.currentToken.image +"', '}' expected";
2227     errorLevel   = ERROR;
2228     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2229     errorEnd   = jj_input_stream.getPosition() + 1;
2230     throw e;
2231   }
2232   {
2233   Statement[] statements = new Statement[list.size()];
2234   list.toArray(statements);
2235   return new Block(statements,pos,SimpleCharStream.getPosition());}
2236 }
2237
2238 Statement BlockStatement() :
2239 {
2240   final Statement statement;
2241 }
2242 {
2243   statement = Statement()         {return statement;}
2244 | statement = ClassDeclaration()  {return statement;}
2245 | statement = MethodDeclaration() {return statement;}
2246 }
2247
2248 /**
2249  * A Block statement that will not contain any 'break'
2250  */
2251 Statement BlockStatementNoBreak() :
2252 {
2253   final Statement statement;
2254 }
2255 {
2256   statement = StatementNoBreak()  {return statement;}
2257 | statement = ClassDeclaration()  {return statement;}
2258 | statement = MethodDeclaration() {return statement;}
2259 }
2260
2261 VariableDeclaration[] LocalVariableDeclaration() :
2262 {
2263   final ArrayList list = new ArrayList();
2264   VariableDeclaration var;
2265 }
2266 {
2267   var = LocalVariableDeclarator()
2268   {list.add(var);}
2269   ( <COMMA> var = LocalVariableDeclarator() {list.add(var);})*
2270   {
2271     VariableDeclaration[] vars = new VariableDeclaration[list.size()];
2272     list.toArray(vars);
2273   return vars;}
2274 }
2275
2276 VariableDeclaration LocalVariableDeclarator() :
2277 {
2278   final String varName;
2279   Expression initializer = null;
2280   final int pos = SimpleCharStream.getPosition();
2281 }
2282 {
2283   varName = VariableDeclaratorId() [ <ASSIGN> initializer = Expression() ]
2284   {
2285    if (initializer == null) {
2286     return new VariableDeclaration(currentSegment,
2287                                   varName.toCharArray(),
2288                                   pos,
2289                                   jj_input_stream.getPosition());
2290    }
2291     return new VariableDeclaration(currentSegment,
2292                                     varName.toCharArray(),
2293                                     initializer,
2294                                     pos);
2295   }
2296 }
2297
2298 EmptyStatement EmptyStatement() :
2299 {
2300   final int pos;
2301 }
2302 {
2303   <SEMICOLON>
2304   {pos = SimpleCharStream.getPosition();
2305    return new EmptyStatement(pos-1,pos);}
2306 }
2307
2308 Statement StatementExpression() :
2309 {
2310   Expression expr,expr2;
2311   int operator;
2312 }
2313 {
2314   expr = PreIncDecExpression() {return expr;}
2315 |
2316   expr = PrimaryExpression()
2317   [ <INCR> {return new PostfixedUnaryExpression(expr,
2318                                                 OperatorIds.PLUS_PLUS,
2319                                                 SimpleCharStream.getPosition());}
2320   | <DECR> {return new PostfixedUnaryExpression(expr,
2321                                                 OperatorIds.MINUS_MINUS,
2322                                                 SimpleCharStream.getPosition());}
2323   | operator = AssignmentOperator() expr2 = Expression()
2324     {return new BinaryExpression(expr,expr2,operator);}
2325   ]
2326   {return expr;}
2327 }
2328
2329 SwitchStatement SwitchStatement() :
2330 {
2331   final Expression variable;
2332   final AbstractCase[] cases;
2333   final int pos = SimpleCharStream.getPosition();
2334 }
2335 {
2336   <SWITCH>
2337   try {
2338     <LPAREN>
2339   } catch (ParseException e) {
2340     errorMessage = "'(' expected after 'switch'";
2341     errorLevel   = ERROR;
2342     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2343     errorEnd   = jj_input_stream.getPosition() + 1;
2344     throw e;
2345   }
2346   try {
2347     variable = Expression()
2348   } catch (ParseException e) {
2349     if (errorMessage != null) {
2350       throw e;
2351     }
2352     errorMessage = "expression expected";
2353     errorLevel   = ERROR;
2354     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2355     errorEnd   = jj_input_stream.getPosition() + 1;
2356     throw e;
2357   }
2358   try {
2359     <RPAREN>
2360   } catch (ParseException e) {
2361     errorMessage = "')' expected";
2362     errorLevel   = ERROR;
2363     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2364     errorEnd   = jj_input_stream.getPosition() + 1;
2365     throw e;
2366   }
2367   (cases = switchStatementBrace() | cases = switchStatementColon(pos, pos + 6))
2368   {return new SwitchStatement(variable,cases,pos,SimpleCharStream.getPosition());}
2369 }
2370
2371 AbstractCase[] switchStatementBrace() :
2372 {
2373   AbstractCase cas;
2374   final ArrayList cases = new ArrayList();
2375 }
2376 {
2377   <LBRACE>
2378  ( cas = switchLabel0() {cases.add(cas);})*
2379   try {
2380     <RBRACE>
2381     {
2382     AbstractCase[] abcase = new AbstractCase[cases.size()];
2383     cases.toArray(abcase);
2384     return abcase;}
2385   } catch (ParseException e) {
2386     errorMessage = "'}' expected";
2387     errorLevel   = ERROR;
2388     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2389     errorEnd   = jj_input_stream.getPosition() + 1;
2390     throw e;
2391   }
2392 }
2393 /**
2394  * A Switch statement with : ... endswitch;
2395  * @param start the begin offset of the switch
2396  * @param end the end offset of the switch
2397  */
2398 AbstractCase[] switchStatementColon(final int start, final int end) :
2399 {
2400   AbstractCase cas;
2401   final ArrayList cases = new ArrayList();
2402 }
2403 {
2404   <COLON>
2405   {try {
2406   setMarker(fileToParse,
2407             "Ugly syntax detected, you should switch () {...} instead of switch (): ... enswitch;",
2408             start,
2409             end,
2410             INFO,
2411             "Line " + token.beginLine);
2412   } catch (CoreException e) {
2413     PHPeclipsePlugin.log(e);
2414   }}
2415   ( cas = switchLabel0() {cases.add(cas);})*
2416   try {
2417     <ENDSWITCH>
2418   } catch (ParseException e) {
2419     errorMessage = "'endswitch' expected";
2420     errorLevel   = ERROR;
2421     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2422     errorEnd   = jj_input_stream.getPosition() + 1;
2423     throw e;
2424   }
2425   try {
2426     <SEMICOLON>
2427     {
2428     AbstractCase[] abcase = new AbstractCase[cases.size()];
2429     cases.toArray(abcase);
2430     return abcase;}
2431   } catch (ParseException e) {
2432     errorMessage = "';' expected after 'endswitch' keyword";
2433     errorLevel   = ERROR;
2434     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2435     errorEnd   = jj_input_stream.getPosition() + 1;
2436     throw e;
2437   }
2438 }
2439
2440 AbstractCase switchLabel0() :
2441 {
2442   final Expression expr;
2443   Statement statement;
2444   final ArrayList stmts = new ArrayList();
2445   final int pos = SimpleCharStream.getPosition();
2446 }
2447 {
2448   expr = SwitchLabel()
2449   ( statement = BlockStatementNoBreak() {stmts.add(statement);}
2450   | statement = htmlBlock()             {stmts.add(statement);})*
2451   [ statement = BreakStatement()        {stmts.add(statement);}]
2452   {
2453   Statement[] stmtsArray = new Statement[stmts.size()];
2454   stmts.toArray(stmtsArray);
2455   if (expr == null) {//it's a default
2456     return new DefaultCase(stmtsArray,pos,SimpleCharStream.getPosition());
2457   }
2458   return new Case(expr,stmtsArray,pos,SimpleCharStream.getPosition());}
2459 }
2460
2461 /**
2462  * A SwitchLabel.
2463  * case Expression() :
2464  * default :
2465  * @return the if it was a case and null if not
2466  */
2467 Expression SwitchLabel() :
2468 {
2469   final Token token;
2470   final Expression expr;
2471 }
2472 {
2473   token = <CASE>
2474   try {
2475     expr = Expression()
2476   } catch (ParseException e) {
2477     if (errorMessage != null) throw e;
2478     errorMessage = "expression expected after 'case' keyword";
2479     errorLevel   = ERROR;
2480     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2481     errorEnd   = jj_input_stream.getPosition() + 1;
2482     throw e;
2483   }
2484   try {
2485     <COLON>
2486     {return expr;}
2487   } catch (ParseException e) {
2488     errorMessage = "':' expected after case expression";
2489     errorLevel   = ERROR;
2490     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2491     errorEnd   = jj_input_stream.getPosition() + 1;
2492     throw e;
2493   }
2494 |
2495   token = <_DEFAULT>
2496   try {
2497     <COLON>
2498     {return null;}
2499   } catch (ParseException e) {
2500     errorMessage = "':' expected after 'default' keyword";
2501     errorLevel   = ERROR;
2502     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2503     errorEnd   = jj_input_stream.getPosition() + 1;
2504     throw e;
2505   }
2506 }
2507
2508 Break BreakStatement() :
2509 {
2510   Expression expression = null;
2511   final int start = SimpleCharStream.getPosition();
2512 }
2513 {
2514   <BREAK> [ expression = Expression() ]
2515   try {
2516     <SEMICOLON>
2517   } catch (ParseException e) {
2518     errorMessage = "';' expected after 'break' keyword";
2519     errorLevel   = ERROR;
2520     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2521     errorEnd   = jj_input_stream.getPosition() + 1;
2522     throw e;
2523   }
2524   {return new Break(expression, start, SimpleCharStream.getPosition());}
2525 }
2526
2527 IfStatement IfStatement() :
2528 {
2529   final int pos = jj_input_stream.getPosition();
2530   Expression condition;
2531   IfStatement ifStatement;
2532 }
2533 {
2534   <IF> condition = Condition("if") ifStatement = IfStatement0(condition, pos,pos+2)
2535   {return ifStatement;}
2536 }
2537
2538
2539 Expression Condition(final String keyword) :
2540 {
2541   final Expression condition;
2542 }
2543 {
2544   try {
2545     <LPAREN>
2546   } catch (ParseException e) {
2547     errorMessage = "'(' expected after " + keyword + " keyword";
2548     errorLevel   = ERROR;
2549     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length();
2550     errorEnd   = errorStart +1;
2551     processParseException(e);
2552   }
2553   condition = Expression()
2554   try {
2555      <RPAREN>
2556      {return condition;}
2557   } catch (ParseException e) {
2558     errorMessage = "')' expected after " + keyword + " keyword";
2559     errorLevel   = ERROR;
2560     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2561     errorEnd   = jj_input_stream.getPosition() + 1;
2562     throw e;
2563   }
2564 }
2565
2566 IfStatement IfStatement0(Expression condition, final int start,final int end) :
2567 {
2568   Statement statement;
2569   Statement stmt;
2570   final Statement[] statementsArray;
2571   ElseIf elseifStatement;
2572   Else elseStatement = null;
2573   ArrayList stmts;
2574   final ArrayList elseIfList = new ArrayList();
2575   ElseIf[] elseIfs;
2576   int pos = SimpleCharStream.getPosition();
2577   int endStatements;
2578 }
2579 {
2580   <COLON>
2581   {stmts = new ArrayList();}
2582   (  statement = Statement() {stmts.add(statement);}
2583    | statement = htmlBlock() {stmts.add(statement);})*
2584    {endStatements = SimpleCharStream.getPosition();}
2585    (elseifStatement = ElseIfStatementColon() {elseIfList.add(elseifStatement);})*
2586    [elseStatement = ElseStatementColon()]
2587
2588   {try {
2589   setMarker(fileToParse,
2590             "Ugly syntax detected, you should if () {...} instead of if (): ... endif;",
2591             start,
2592             end,
2593             INFO,
2594             "Line " + token.beginLine);
2595   } catch (CoreException e) {
2596     PHPeclipsePlugin.log(e);
2597   }}
2598   try {
2599     <ENDIF>
2600   } catch (ParseException e) {
2601     errorMessage = "'endif' expected";
2602     errorLevel   = ERROR;
2603     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2604     errorEnd   = jj_input_stream.getPosition() + 1;
2605     throw e;
2606   }
2607   try {
2608     <SEMICOLON>
2609   } catch (ParseException e) {
2610     errorMessage = "';' expected after 'endif' keyword";
2611     errorLevel   = ERROR;
2612     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2613     errorEnd   = jj_input_stream.getPosition() + 1;
2614     throw e;
2615   }
2616     {
2617     elseIfs = new ElseIf[elseIfList.size()];
2618     elseIfList.toArray(elseIfs);
2619     if (stmts.size() == 1) {
2620       return new IfStatement(condition,
2621                              (Statement) stmts.get(0),
2622                               elseIfs,
2623                               elseStatement,
2624                               pos,
2625                               SimpleCharStream.getPosition());
2626     } else {
2627       statementsArray = new Statement[stmts.size()];
2628       stmts.toArray(statementsArray);
2629       return new IfStatement(condition,
2630                              new Block(statementsArray,pos,endStatements),
2631                               elseIfs,
2632                               elseStatement,
2633                               pos,
2634                               SimpleCharStream.getPosition());
2635     }
2636     }
2637
2638 |
2639   (stmt = Statement() | stmt = htmlBlock())
2640   ( LOOKAHEAD(1) elseifStatement = ElseIfStatement() {elseIfList.add(elseifStatement);})*
2641   [ LOOKAHEAD(1)
2642     <ELSE>
2643     try {
2644       {pos = SimpleCharStream.getPosition();}
2645       statement = Statement()
2646       {elseStatement = new Else(statement,pos,SimpleCharStream.getPosition());}
2647     } catch (ParseException e) {
2648       if (errorMessage != null) {
2649         throw e;
2650       }
2651       errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected";
2652       errorLevel   = ERROR;
2653       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2654       errorEnd   = jj_input_stream.getPosition() + 1;
2655       throw e;
2656     }
2657   ]
2658   {
2659     elseIfs = new ElseIf[elseIfList.size()];
2660     elseIfList.toArray(elseIfs);
2661     return new IfStatement(condition,
2662                            stmt,
2663                            elseIfs,
2664                            elseStatement,
2665                            pos,
2666                            SimpleCharStream.getPosition());}
2667 }
2668
2669 ElseIf ElseIfStatementColon() :
2670 {
2671   Expression condition;
2672   Statement statement;
2673   final ArrayList list = new ArrayList();
2674   final int pos = SimpleCharStream.getPosition();
2675 }
2676 {
2677   <ELSEIF> condition = Condition("elseif")
2678   <COLON> (  statement = Statement() {list.add(statement);}
2679            | statement = htmlBlock() {list.add(statement);})*
2680   {
2681   Statement[] stmtsArray = new Statement[list.size()];
2682   list.toArray(stmtsArray);
2683   return new ElseIf(condition,stmtsArray ,pos,SimpleCharStream.getPosition());}
2684 }
2685
2686 Else ElseStatementColon() :
2687 {
2688   Statement statement;
2689   final ArrayList list = new ArrayList();
2690   final int pos = SimpleCharStream.getPosition();
2691 }
2692 {
2693   <ELSE> <COLON> (  statement = Statement() {list.add(statement);}
2694                   | statement = htmlBlock() {list.add(statement);})*
2695   {
2696   Statement[] stmtsArray = new Statement[list.size()];
2697   list.toArray(stmtsArray);
2698   return new Else(stmtsArray,pos,SimpleCharStream.getPosition());}
2699 }
2700
2701 ElseIf ElseIfStatement() :
2702 {
2703   Expression condition;
2704   Statement statement;
2705   final ArrayList list = new ArrayList();
2706   final int pos = SimpleCharStream.getPosition();
2707 }
2708 {
2709   <ELSEIF> condition = Condition("elseif") statement = Statement() {list.add(statement);/*todo:do better*/}
2710   {
2711   Statement[] stmtsArray = new Statement[list.size()];
2712   list.toArray(stmtsArray);
2713   return new ElseIf(condition,stmtsArray,pos,SimpleCharStream.getPosition());}
2714 }
2715
2716 WhileStatement WhileStatement() :
2717 {
2718   final Expression condition;
2719   final Statement action;
2720   final int pos = SimpleCharStream.getPosition();
2721 }
2722 {
2723   <WHILE>
2724     condition = Condition("while")
2725     action    = WhileStatement0(pos,pos + 5)
2726     {return new WhileStatement(condition,action,pos,SimpleCharStream.getPosition());}
2727 }
2728
2729 Statement WhileStatement0(final int start, final int end) :
2730 {
2731   Statement statement;
2732   final ArrayList stmts = new ArrayList();
2733   final int pos = SimpleCharStream.getPosition();
2734 }
2735 {
2736   <COLON> (statement = Statement() {stmts.add(statement);})*
2737   {try {
2738   setMarker(fileToParse,
2739             "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;",
2740             start,
2741             end,
2742             INFO,
2743             "Line " + token.beginLine);
2744   } catch (CoreException e) {
2745     PHPeclipsePlugin.log(e);
2746   }}
2747   try {
2748     <ENDWHILE>
2749   } catch (ParseException e) {
2750     errorMessage = "'endwhile' expected";
2751     errorLevel   = ERROR;
2752     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2753     errorEnd   = jj_input_stream.getPosition() + 1;
2754     throw e;
2755   }
2756   try {
2757     <SEMICOLON>
2758     {
2759     Statement[] stmtsArray = new Statement[stmts.size()];
2760     stmts.toArray(stmtsArray);
2761     return new Block(stmtsArray,pos,SimpleCharStream.getPosition());}
2762   } catch (ParseException e) {
2763     errorMessage = "';' expected after 'endwhile' keyword";
2764     errorLevel   = ERROR;
2765     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2766     errorEnd   = jj_input_stream.getPosition() + 1;
2767     throw e;
2768   }
2769 |
2770   statement = Statement()
2771   {return statement;}
2772 }
2773
2774 DoStatement DoStatement() :
2775 {
2776   final Statement action;
2777   final Expression condition;
2778   final int pos = SimpleCharStream.getPosition();
2779 }
2780 {
2781   <DO> action = Statement() <WHILE> condition = Condition("while")
2782   try {
2783     <SEMICOLON>
2784     {return new DoStatement(condition,action,pos,SimpleCharStream.getPosition());}
2785   } catch (ParseException e) {
2786     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2787     errorLevel   = ERROR;
2788     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2789     errorEnd   = jj_input_stream.getPosition() + 1;
2790     throw e;
2791   }
2792 }
2793
2794 ForeachStatement ForeachStatement() :
2795 {
2796   Statement statement;
2797   Expression expression;
2798   final StringBuffer buff = new StringBuffer();
2799   final int pos = SimpleCharStream.getPosition();
2800   ArrayVariableDeclaration variable;
2801 }
2802 {
2803   <FOREACH>
2804     try {
2805     <LPAREN>
2806   } catch (ParseException e) {
2807     errorMessage = "'(' expected after 'foreach' keyword";
2808     errorLevel   = ERROR;
2809     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2810     errorEnd   = jj_input_stream.getPosition() + 1;
2811     throw e;
2812   }
2813   try {
2814     expression = Expression()
2815   } catch (ParseException e) {
2816     errorMessage = "variable expected";
2817     errorLevel   = ERROR;
2818     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2819     errorEnd   = jj_input_stream.getPosition() + 1;
2820     throw e;
2821   }
2822   try {
2823     <AS>
2824   } catch (ParseException e) {
2825     errorMessage = "'as' expected";
2826     errorLevel   = ERROR;
2827     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2828     errorEnd   = jj_input_stream.getPosition() + 1;
2829     throw e;
2830   }
2831   try {
2832     variable = ArrayVariable()
2833   } catch (ParseException e) {
2834     errorMessage = "variable expected";
2835     errorLevel   = ERROR;
2836     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2837     errorEnd   = jj_input_stream.getPosition() + 1;
2838     throw e;
2839   }
2840   try {
2841     <RPAREN>
2842   } catch (ParseException e) {
2843     errorMessage = "')' expected after 'foreach' keyword";
2844     errorLevel   = ERROR;
2845     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2846     errorEnd   = jj_input_stream.getPosition() + 1;
2847     throw e;
2848   }
2849   try {
2850     statement = Statement()
2851   } catch (ParseException e) {
2852     if (errorMessage != null) throw e;
2853     errorMessage = "statement expected";
2854     errorLevel   = ERROR;
2855     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2856     errorEnd   = jj_input_stream.getPosition() + 1;
2857     throw e;
2858   }
2859   {return new ForeachStatement(expression,
2860                                variable,
2861                                statement,
2862                                pos,
2863                                SimpleCharStream.getPosition());}
2864
2865 }
2866
2867 ForStatement ForStatement() :
2868 {
2869 final Token token;
2870 final int pos = SimpleCharStream.getPosition();
2871 Statement[] initializations = null;
2872 Expression condition = null;
2873 Statement[] increments = null;
2874 Statement action;
2875 final ArrayList list = new ArrayList();
2876 final int startBlock, endBlock;
2877 }
2878 {
2879   token = <FOR>
2880   try {
2881     <LPAREN>
2882   } catch (ParseException e) {
2883     errorMessage = "'(' expected after 'for' keyword";
2884     errorLevel   = ERROR;
2885     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2886     errorEnd   = jj_input_stream.getPosition() + 1;
2887     throw e;
2888   }
2889      [ initializations = ForInit() ] <SEMICOLON>
2890      [ condition = Expression() ] <SEMICOLON>
2891      [ increments = StatementExpressionList() ] <RPAREN>
2892     (
2893       action = Statement()
2894       {return new ForStatement(initializations,condition,increments,action,pos,SimpleCharStream.getPosition());}
2895     |
2896       <COLON>
2897       {startBlock = SimpleCharStream.getPosition();}
2898       (action = Statement() {list.add(action);})*
2899       {
2900         try {
2901         setMarker(fileToParse,
2902                   "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;",
2903                   pos,
2904                   pos+token.image.length(),
2905                   INFO,
2906                   "Line " + token.beginLine);
2907         } catch (CoreException e) {
2908           PHPeclipsePlugin.log(e);
2909         }
2910       }
2911       {endBlock = SimpleCharStream.getPosition();}
2912       try {
2913         <ENDFOR>
2914       } catch (ParseException e) {
2915         errorMessage = "'endfor' expected";
2916         errorLevel   = ERROR;
2917         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2918         errorEnd   = jj_input_stream.getPosition() + 1;
2919         throw e;
2920       }
2921       try {
2922         <SEMICOLON>
2923         {
2924         Statement[] stmtsArray = new Statement[list.size()];
2925         list.toArray(stmtsArray);
2926         return new ForStatement(initializations,condition,increments,new Block(stmtsArray,startBlock,endBlock),pos,SimpleCharStream.getPosition());}
2927       } catch (ParseException e) {
2928         errorMessage = "';' expected after 'endfor' keyword";
2929         errorLevel   = ERROR;
2930         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2931         errorEnd   = jj_input_stream.getPosition() + 1;
2932         throw e;
2933       }
2934     )
2935 }
2936
2937 Statement[] ForInit() :
2938 {
2939   Statement[] statements;
2940 }
2941 {
2942   LOOKAHEAD(LocalVariableDeclaration())
2943   statements = LocalVariableDeclaration()
2944   {return statements;}
2945 |
2946   statements = StatementExpressionList()
2947   {return statements;}
2948 }
2949
2950 Statement[] StatementExpressionList() :
2951 {
2952   final ArrayList list = new ArrayList();
2953   Statement expr;
2954 }
2955 {
2956   expr = StatementExpression()   {list.add(expr);}
2957   (<COMMA> StatementExpression() {list.add(expr);})*
2958   {
2959   Statement[] stmtsArray = new Statement[list.size()];
2960   list.toArray(stmtsArray);
2961   return stmtsArray;}
2962 }
2963
2964 Continue ContinueStatement() :
2965 {
2966   Expression expr = null;
2967   final int pos = SimpleCharStream.getPosition();
2968 }
2969 {
2970   <CONTINUE> [ expr = Expression() ]
2971   try {
2972     <SEMICOLON>
2973     {return new Continue(expr,pos,SimpleCharStream.getPosition());}
2974   } catch (ParseException e) {
2975     errorMessage = "';' expected after 'continue' statement";
2976     errorLevel   = ERROR;
2977     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2978     errorEnd   = jj_input_stream.getPosition() + 1;
2979     throw e;
2980   }
2981 }
2982
2983 ReturnStatement ReturnStatement() :
2984 {
2985   Expression expr = null;
2986   final int pos = SimpleCharStream.getPosition();
2987 }
2988 {
2989   <RETURN> [ expr = Expression() ]
2990   try {
2991     <SEMICOLON>
2992     {return new ReturnStatement(expr,pos,SimpleCharStream.getPosition());}
2993   } catch (ParseException e) {
2994     errorMessage = "';' expected after 'return' statement";
2995     errorLevel   = ERROR;
2996     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2997     errorEnd   = jj_input_stream.getPosition() + 1;
2998     throw e;
2999   }
3000 }