d3b3e594d2a9d9e7e11bbfddbb13d09095ee8462
[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   variableDeclarationPtr = 0;
874   variableDeclarationStack = new VariableDeclaration[AstStackIncrement];
875   VariableDeclaration[] list;
876   final int pos = SimpleCharStream.getPosition();
877 }
878 {
879   <VAR> variableDeclaration = VariableDeclarator()
880   {
881     pushOnVariableDeclarationStack(variableDeclaration);
882     outlineInfo.addVariable(new String(variableDeclaration.name));
883     currentSegment.add(variableDeclaration);
884   }
885   ( <COMMA>
886       variableDeclaration = VariableDeclarator()
887       {pushOnVariableDeclarationStack(variableDeclaration);
888        outlineInfo.addVariable(new String(variableDeclaration.name));
889        currentSegment.add(variableDeclaration);}
890   )*
891   try {
892     <SEMICOLON>
893   } catch (ParseException e) {
894     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected after variable declaration";
895     errorLevel   = ERROR;
896     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
897     errorEnd   = jj_input_stream.getPosition() + 1;
898     throw e;
899   }
900
901   {list = new VariableDeclaration[variableDeclarationPtr];
902    System.arraycopy(variableDeclarationStack,0,list,0,variableDeclarationPtr);
903    return new FieldDeclaration(list,
904                                pos,
905                                SimpleCharStream.getPosition());}
906 }
907
908 VariableDeclaration VariableDeclarator() :
909 {
910   final String varName, varValue;
911   Expression initializer = null;
912   final int pos = jj_input_stream.getPosition();
913 }
914 {
915   varName = VariableDeclaratorId()
916   [
917     <ASSIGN>
918     try {
919       initializer = VariableInitializer()
920     } catch (ParseException e) {
921       errorMessage = "Literal expression expected in variable initializer";
922       errorLevel   = ERROR;
923       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
924       errorEnd   = jj_input_stream.getPosition() + 1;
925       throw e;
926     }
927   ]
928   {
929   if (initializer == null) {
930     return new VariableDeclaration(currentSegment,
931                                   varName.toCharArray(),
932                                   pos,
933                                   jj_input_stream.getPosition());
934   }
935     return new VariableDeclaration(currentSegment,
936                                     varName.toCharArray(),
937                                     initializer,
938                                     pos);
939   }
940 }
941
942 /**
943  * A Variable name.
944  * @return the variable name (with suffix)
945  */
946 String VariableDeclaratorId() :
947 {
948   String expr;
949   Expression expression;
950   final StringBuffer buff = new StringBuffer();
951   final int pos = SimpleCharStream.getPosition();
952   ConstantIdentifier ex;
953 }
954 {
955   try {
956     expr = Variable()   {buff.append(expr);}
957     ( LOOKAHEAD(2)
958       {ex = new ConstantIdentifier(expr.toCharArray(),
959                                    pos,
960                                    SimpleCharStream.getPosition());}
961       expression = VariableSuffix(ex)
962       {buff.append(expression.toStringExpression());}
963     )*
964     {return buff.toString();}
965   } catch (ParseException e) {
966     errorMessage = "'$' expected for variable identifier";
967     errorLevel   = ERROR;
968     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
969     errorEnd   = jj_input_stream.getPosition() + 1;
970     throw e;
971   }
972 }
973
974 String Variable():
975 {
976   final StringBuffer buff;
977   Expression expression = null;
978   final Token token;
979   final String expr;
980 }
981 {
982   token = <DOLLAR_ID> [<LBRACE> expression = Expression() <RBRACE>]
983   {
984     if (expression == null && !assigning) {
985       return token.image.substring(1);
986     }
987     buff = new StringBuffer(token.image);
988     buff.append('{');
989     buff.append(expression.toStringExpression());
990     buff.append('}');
991     return buff.toString();
992   }
993 |
994   <DOLLAR> expr = VariableName()
995   {return expr;}
996 }
997
998 String VariableName():
999 {
1000   final StringBuffer buff;
1001   String expr = null;
1002   Expression expression = null;
1003   final Token token;
1004 }
1005 {
1006   <LBRACE> expression = Expression() <RBRACE>
1007   {buff = new StringBuffer('{');
1008    buff.append(expression.toStringExpression());
1009    buff.append('}');
1010    return buff.toString();}
1011 |
1012   token = <IDENTIFIER> [<LBRACE> expression = Expression() <RBRACE>]
1013   {
1014     if (expression == null) {
1015       return token.image;
1016     }
1017     buff = new StringBuffer(token.image);
1018     buff.append('{');
1019     buff.append(expression.toStringExpression());
1020     buff.append('}');
1021     return buff.toString();
1022   }
1023 |
1024   <DOLLAR> expr = VariableName()
1025   {
1026     buff = new StringBuffer('$');
1027     buff.append(expr);
1028     return buff.toString();
1029   }
1030 |
1031   token = <DOLLAR_ID> {return token.image;}
1032 }
1033
1034 Expression VariableInitializer() :
1035 {
1036   final Expression expr;
1037   final Token token;
1038   final int pos = SimpleCharStream.getPosition();
1039 }
1040 {
1041   expr = Literal()
1042   {return expr;}
1043 |
1044   <MINUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1045   {return new PrefixedUnaryExpression(new NumberLiteral(token.image.toCharArray(),
1046                                                         pos,
1047                                                         SimpleCharStream.getPosition()),
1048                                       OperatorIds.MINUS,
1049                                       pos);}
1050 |
1051   <PLUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1052   {return new PrefixedUnaryExpression(new NumberLiteral(token.image.toCharArray(),
1053                                                         pos,
1054                                                         SimpleCharStream.getPosition()),
1055                                       OperatorIds.PLUS,
1056                                       pos);}
1057 |
1058   expr = ArrayDeclarator()
1059   {return expr;}
1060 |
1061   token = <IDENTIFIER>
1062   {return new ConstantIdentifier(token.image.toCharArray(),pos,SimpleCharStream.getPosition());}
1063 }
1064
1065 ArrayVariableDeclaration ArrayVariable() :
1066 {
1067 Expression expr;
1068 Expression expr2 = null;
1069 }
1070 {
1071   expr = Expression() [<ARRAYASSIGN> expr2 = Expression()]
1072   {return new ArrayVariableDeclaration(expr,expr2);}
1073 }
1074
1075 ArrayVariableDeclaration[] ArrayInitializer() :
1076 {
1077   ArrayVariableDeclaration expr;
1078   final ArrayList list = new ArrayList();
1079 }
1080 {
1081   <LPAREN> [ expr = ArrayVariable()
1082             {list.add(expr);}
1083             ( LOOKAHEAD(2) <COMMA> expr = ArrayVariable()
1084             {list.add(expr);}
1085             )*
1086            ]
1087            [<COMMA> {list.add(null);}]
1088   <RPAREN>
1089   {
1090   ArrayVariableDeclaration[] vars = new ArrayVariableDeclaration[list.size()];
1091   list.toArray(vars);
1092   return vars;}
1093 }
1094
1095 /**
1096  * A Method Declaration.
1097  * <b>function</b> MetodDeclarator() Block()
1098  */
1099 MethodDeclaration MethodDeclaration() :
1100 {
1101   final MethodDeclaration functionDeclaration;
1102   Token functionToken;
1103   final Block block;
1104 }
1105 {
1106   functionToken = <FUNCTION>
1107   try {
1108     functionDeclaration = MethodDeclarator()
1109     {outlineInfo.addVariable(new String(functionDeclaration.name));}
1110   } catch (ParseException e) {
1111     if (errorMessage != null) {
1112       throw e;
1113     }
1114     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
1115     errorLevel   = ERROR;
1116     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1117     errorEnd   = jj_input_stream.getPosition() + 1;
1118     throw e;
1119   }
1120   {
1121     if (currentSegment != null) {
1122       currentSegment.add(functionDeclaration);
1123       currentSegment = functionDeclaration;
1124     }
1125     currentFunction = functionDeclaration;
1126   }
1127   block = Block()
1128   {
1129     functionDeclaration.statements = block.statements;
1130     currentFunction = null;
1131     if (currentSegment != null) {
1132       currentSegment = (OutlineableWithChildren) currentSegment.getParent();
1133     }
1134     return functionDeclaration;
1135   }
1136 }
1137
1138 /**
1139  * A MethodDeclarator.
1140  * [&] IDENTIFIER(parameters ...).
1141  * @return a function description for the outline
1142  */
1143 MethodDeclaration MethodDeclarator() :
1144 {
1145   final Token identifier;
1146   Token reference = null;
1147   final Hashtable formalParameters;
1148   final int pos = SimpleCharStream.getPosition();
1149 }
1150 {
1151   [ reference = <BIT_AND> ]
1152   identifier = <IDENTIFIER>
1153   formalParameters = FormalParameters()
1154   {return new MethodDeclaration(currentSegment,
1155                                  identifier.image.toCharArray(),
1156                                  formalParameters,
1157                                  reference != null,
1158                                  pos,
1159                                  SimpleCharStream.getPosition());}
1160 }
1161
1162 /**
1163  * FormalParameters follows method identifier.
1164  * (FormalParameter())
1165  */
1166 Hashtable FormalParameters() :
1167 {
1168   String expr;
1169   final StringBuffer buff = new StringBuffer("(");
1170   VariableDeclaration var;
1171   final Hashtable parameters = new Hashtable();
1172 }
1173 {
1174   try {
1175   <LPAREN>
1176   } catch (ParseException e) {
1177     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected after function identifier";
1178     errorLevel   = ERROR;
1179     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1180     errorEnd   = jj_input_stream.getPosition() + 1;
1181     throw e;
1182   }
1183             [ var = FormalParameter()
1184               {parameters.put(new String(var.name),var);}
1185               (
1186                 <COMMA> var = FormalParameter()
1187                 {parameters.put(new String(var.name),var);}
1188               )*
1189             ]
1190   try {
1191     <RPAREN>
1192   } catch (ParseException e) {
1193     errorMessage = "')' expected";
1194     errorLevel   = ERROR;
1195     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1196     errorEnd   = jj_input_stream.getPosition() + 1;
1197     throw e;
1198   }
1199  {return parameters;}
1200 }
1201
1202 /**
1203  * A formal parameter.
1204  * $varname[=value] (,$varname[=value])
1205  */
1206 VariableDeclaration FormalParameter() :
1207 {
1208   final VariableDeclaration variableDeclaration;
1209   Token token = null;
1210 }
1211 {
1212   [token = <BIT_AND>] variableDeclaration = VariableDeclarator()
1213   {
1214     if (token != null) {
1215       variableDeclaration.setReference(true);
1216     }
1217     return variableDeclaration;}
1218 }
1219
1220 ConstantIdentifier Type() :
1221 {final int pos;}
1222 {
1223   <STRING>             {pos = SimpleCharStream.getPosition();
1224                         return new ConstantIdentifier(Types.STRING,
1225                                         pos,pos-6);}
1226 | <BOOL>               {pos = SimpleCharStream.getPosition();
1227                         return new ConstantIdentifier(Types.BOOL,
1228                                         pos,pos-4);}
1229 | <BOOLEAN>            {pos = SimpleCharStream.getPosition();
1230                         return new ConstantIdentifier(Types.BOOLEAN,
1231                                         pos,pos-7);}
1232 | <REAL>               {pos = SimpleCharStream.getPosition();
1233                         return new ConstantIdentifier(Types.REAL,
1234                                         pos,pos-4);}
1235 | <DOUBLE>             {pos = SimpleCharStream.getPosition();
1236                         return new ConstantIdentifier(Types.DOUBLE,
1237                                         pos,pos-5);}
1238 | <FLOAT>              {pos = SimpleCharStream.getPosition();
1239                         return new ConstantIdentifier(Types.FLOAT,
1240                                         pos,pos-5);}
1241 | <INT>                {pos = SimpleCharStream.getPosition();
1242                         return new ConstantIdentifier(Types.INT,
1243                                         pos,pos-3);}
1244 | <INTEGER>            {pos = SimpleCharStream.getPosition();
1245                         return new ConstantIdentifier(Types.INTEGER,
1246                                         pos,pos-7);}
1247 | <OBJECT>             {pos = SimpleCharStream.getPosition();
1248                         return new ConstantIdentifier(Types.OBJECT,
1249                                         pos,pos-6);}
1250 }
1251
1252 Expression Expression() :
1253 {
1254   final Expression expr;
1255 }
1256 {
1257   expr = PrintExpression()       {return expr;}
1258 | expr = ListExpression()        {return expr;}
1259 | LOOKAHEAD(varAssignation())
1260   expr = varAssignation()        {return expr;}
1261 | expr = ConditionalExpression() {return expr;}
1262 }
1263
1264 /**
1265  * A Variable assignation.
1266  * varName (an assign operator) any expression
1267  */
1268 VarAssignation varAssignation() :
1269 {
1270   String varName;
1271   final Expression expression;
1272   final int assignOperator;
1273   final int pos = SimpleCharStream.getPosition();
1274 }
1275 {
1276   varName = VariableDeclaratorId()
1277   assignOperator = AssignmentOperator()
1278     try {
1279       expression = Expression()
1280     } catch (ParseException e) {
1281       if (errorMessage != null) {
1282         throw e;
1283       }
1284       errorMessage = "expression expected";
1285       errorLevel   = ERROR;
1286       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1287       errorEnd   = jj_input_stream.getPosition() + 1;
1288       throw e;
1289     }
1290     {return new VarAssignation(varName.toCharArray(),
1291                                expression,
1292                                assignOperator,
1293                                pos,
1294                                SimpleCharStream.getPosition());}
1295 }
1296
1297 int AssignmentOperator() :
1298 {}
1299 {
1300   <ASSIGN>             {return VarAssignation.EQUAL;}
1301 | <STARASSIGN>         {return VarAssignation.STAR_EQUAL;}
1302 | <SLASHASSIGN>        {return VarAssignation.SLASH_EQUAL;}
1303 | <REMASSIGN>          {return VarAssignation.REM_EQUAL;}
1304 | <PLUSASSIGN>         {return VarAssignation.PLUS_EQUAL;}
1305 | <MINUSASSIGN>        {return VarAssignation.MINUS_EQUAL;}
1306 | <LSHIFTASSIGN>       {return VarAssignation.LSHIFT_EQUAL;}
1307 | <RSIGNEDSHIFTASSIGN> {return VarAssignation.RSIGNEDSHIFT_EQUAL;}
1308 | <ANDASSIGN>          {return VarAssignation.AND_EQUAL;}
1309 | <XORASSIGN>          {return VarAssignation.XOR_EQUAL;}
1310 | <ORASSIGN>           {return VarAssignation.OR_EQUAL;}
1311 | <DOTASSIGN>          {return VarAssignation.DOT_EQUAL;}
1312 | <TILDEEQUAL>         {return VarAssignation.TILDE_EQUAL;}
1313 }
1314
1315 Expression ConditionalExpression() :
1316 {
1317   final Expression expr;
1318   Expression expr2 = null;
1319   Expression expr3 = null;
1320 }
1321 {
1322   expr = ConditionalOrExpression() [ <HOOK> expr2 = Expression() <COLON> expr3 = ConditionalExpression() ]
1323 {
1324   if (expr3 == null) {
1325     return expr;
1326   }
1327   return new ConditionalExpression(expr,expr2,expr3);
1328 }
1329 }
1330
1331 Expression ConditionalOrExpression() :
1332 {
1333   Expression expr,expr2;
1334   int operator;
1335 }
1336 {
1337   expr = ConditionalAndExpression()
1338   (
1339     (
1340         <OR_OR> {operator = OperatorIds.OR_OR;}
1341       | <_ORL>  {operator = OperatorIds.ORL;}
1342     ) expr2 = ConditionalAndExpression()
1343     {
1344       expr = new BinaryExpression(expr,expr2,operator);
1345     }
1346   )*
1347   {return expr;}
1348 }
1349
1350 Expression ConditionalAndExpression() :
1351 {
1352   Expression expr,expr2;
1353   int operator;
1354 }
1355 {
1356   expr = ConcatExpression()
1357   (
1358   (  <AND_AND> {operator = OperatorIds.AND_AND;}
1359    | <_ANDL>   {operator = OperatorIds.ANDL;})
1360    expr2 = ConcatExpression() {expr = new BinaryExpression(expr,expr2,operator);}
1361   )*
1362   {return expr;}
1363 }
1364
1365 Expression ConcatExpression() :
1366 {
1367   Expression expr,expr2;
1368 }
1369 {
1370   expr = InclusiveOrExpression()
1371   (
1372     <DOT> expr2 = InclusiveOrExpression()
1373     {expr = new BinaryExpression(expr,expr2,OperatorIds.DOT);}
1374   )*
1375   {return expr;}
1376 }
1377
1378 Expression InclusiveOrExpression() :
1379 {
1380   Expression expr,expr2;
1381 }
1382 {
1383   expr = ExclusiveOrExpression()
1384   (<BIT_OR> expr2 = ExclusiveOrExpression()
1385    {expr = new BinaryExpression(expr,expr2,OperatorIds.OR);}
1386   )*
1387   {return expr;}
1388 }
1389
1390 Expression ExclusiveOrExpression() :
1391 {
1392   Expression expr,expr2;
1393 }
1394 {
1395   expr = AndExpression()
1396   (
1397     <XOR> expr2 = AndExpression()
1398     {expr = new BinaryExpression(expr,expr2,OperatorIds.XOR);}
1399   )*
1400   {return expr;}
1401 }
1402
1403 Expression AndExpression() :
1404 {
1405   Expression expr,expr2;
1406 }
1407 {
1408   expr = EqualityExpression()
1409   (
1410     <BIT_AND> expr2 = EqualityExpression()
1411     {expr = new BinaryExpression(expr,expr2,OperatorIds.AND);}
1412   )*
1413   {return expr;}
1414 }
1415
1416 Expression EqualityExpression() :
1417 {
1418   Expression expr,expr2;
1419   int operator;
1420 }
1421 {
1422   expr = RelationalExpression()
1423   (
1424   (   <EQUAL_EQUAL>      {operator = OperatorIds.EQUAL_EQUAL;}
1425     | <DIF>              {operator = OperatorIds.DIF;}
1426     | <NOT_EQUAL>        {operator = OperatorIds.DIF;}
1427     | <BANGDOUBLEEQUAL>  {operator = OperatorIds.BANG_EQUAL_EQUAL;}
1428     | <TRIPLEEQUAL>      {operator = OperatorIds.EQUAL_EQUAL_EQUAL;}
1429   )
1430   try {
1431     expr2 = RelationalExpression()
1432   } catch (ParseException e) {
1433     if (errorMessage != null) {
1434       throw e;
1435     }
1436     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
1437     errorLevel   = ERROR;
1438     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1439     errorEnd   = jj_input_stream.getPosition() + 1;
1440     throw e;
1441   }
1442   {
1443     expr = new BinaryExpression(expr,expr2,operator);
1444   }
1445   )*
1446   {return expr;}
1447 }
1448
1449 Expression RelationalExpression() :
1450 {
1451   Expression expr,expr2;
1452   int operator;
1453 }
1454 {
1455   expr = ShiftExpression()
1456   (
1457   ( <LT> {operator = OperatorIds.LESS;}
1458   | <GT> {operator = OperatorIds.GREATER;}
1459   | <LE> {operator = OperatorIds.LESS_EQUAL;}
1460   | <GE> {operator = OperatorIds.GREATER_EQUAL;})
1461    expr2 = ShiftExpression()
1462   {expr = new BinaryExpression(expr,expr2,operator);}
1463   )*
1464   {return expr;}
1465 }
1466
1467 Expression ShiftExpression() :
1468 {
1469   Expression expr,expr2;
1470   int operator;
1471 }
1472 {
1473   expr = AdditiveExpression()
1474   (
1475   ( <LSHIFT>         {operator = OperatorIds.LEFT_SHIFT;}
1476   | <RSIGNEDSHIFT>   {operator = OperatorIds.RIGHT_SHIFT;}
1477   | <RUNSIGNEDSHIFT> {operator = OperatorIds.UNSIGNED_RIGHT_SHIFT;})
1478   expr2 = AdditiveExpression()
1479   {expr = new BinaryExpression(expr,expr2,operator);}
1480   )*
1481   {return expr;}
1482 }
1483
1484 Expression AdditiveExpression() :
1485 {
1486   Expression expr,expr2;
1487   int operator;
1488 }
1489 {
1490   expr = MultiplicativeExpression()
1491   (
1492    ( <PLUS>  {operator = OperatorIds.PLUS;}
1493    | <MINUS> {operator = OperatorIds.MINUS;} )
1494    expr2 = MultiplicativeExpression()
1495   {expr = new BinaryExpression(expr,expr2,operator);}
1496    )*
1497   {return expr;}
1498 }
1499
1500 Expression MultiplicativeExpression() :
1501 {
1502   Expression expr,expr2;
1503   int operator;
1504 }
1505 {
1506   try {
1507     expr = UnaryExpression()
1508   } catch (ParseException e) {
1509     if (errorMessage != null) {
1510       throw e;
1511     }
1512     errorMessage = "unexpected token '"+e.currentToken.next.image+"'";
1513     errorLevel   = ERROR;
1514     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1515     errorEnd   = jj_input_stream.getPosition() + 1;
1516     throw e;
1517   }
1518   (
1519    (  <STAR>      {operator = OperatorIds.MULTIPLY;}
1520     | <SLASH>     {operator = OperatorIds.DIVIDE;}
1521     | <REMAINDER> {operator = OperatorIds.REMAINDER;})
1522     expr2 = UnaryExpression()
1523     {expr = new BinaryExpression(expr,expr2,operator);}
1524   )*
1525   {return expr;}
1526 }
1527
1528 /**
1529  * An unary expression starting with @, & or nothing
1530  */
1531 Expression UnaryExpression() :
1532 {
1533   Expression expr;
1534   final int pos = SimpleCharStream.getPosition();
1535 }
1536 {
1537   <BIT_AND> expr = UnaryExpressionNoPrefix()
1538   {return new PrefixedUnaryExpression(expr,OperatorIds.AND,pos);}
1539 |
1540   expr = AtUnaryExpression()
1541   {return expr;}
1542 }
1543
1544 Expression AtUnaryExpression() :
1545 {
1546   Expression expr;
1547   final int pos = SimpleCharStream.getPosition();
1548 }
1549 {
1550   <AT>
1551   expr = AtUnaryExpression()
1552   {return new PrefixedUnaryExpression(expr,OperatorIds.AT,pos);}
1553 |
1554   expr = UnaryExpressionNoPrefix()
1555   {return expr;}
1556 }
1557
1558
1559 Expression UnaryExpressionNoPrefix() :
1560 {
1561   Expression expr;
1562   int operator;
1563   final int pos = SimpleCharStream.getPosition();
1564 }
1565 {
1566   (  <PLUS>  {operator = OperatorIds.PLUS;}
1567    | <MINUS> {operator = OperatorIds.MINUS;})
1568    expr = UnaryExpression()
1569   {return new PrefixedUnaryExpression(expr,operator,pos);}
1570 |
1571   expr = PreIncDecExpression()
1572   {return expr;}
1573 |
1574   expr = UnaryExpressionNotPlusMinus()
1575   {return expr;}
1576 }
1577
1578
1579 Expression PreIncDecExpression() :
1580 {
1581 final Expression expr;
1582 final int operator;
1583   final int pos = SimpleCharStream.getPosition();
1584 }
1585 {
1586   (  <INCR> {operator = OperatorIds.PLUS_PLUS;}
1587    | <DECR> {operator = OperatorIds.MINUS_MINUS;})
1588    expr = PrimaryExpression()
1589   {return new PrefixedUnaryExpression(expr,operator,pos);}
1590 }
1591
1592 Expression UnaryExpressionNotPlusMinus() :
1593 {
1594   Expression expr;
1595   final int pos = SimpleCharStream.getPosition();
1596 }
1597 {
1598   <BANG> expr = UnaryExpression() {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,pos);}
1599 | LOOKAHEAD( <LPAREN> (Type() | <ARRAY>) <RPAREN> )
1600   expr = CastExpression()         {return expr;}
1601 | expr = PostfixExpression()      {return expr;}
1602 | expr = Literal()                {return expr;}
1603 | <LPAREN> expr = Expression()
1604   try {
1605     <RPAREN>
1606   } catch (ParseException e) {
1607     errorMessage = "')' expected";
1608     errorLevel   = ERROR;
1609     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1610     errorEnd     = jj_input_stream.getPosition() + 1;
1611     throw e;
1612   }
1613   {return expr;}
1614 }
1615
1616 CastExpression CastExpression() :
1617 {
1618 final ConstantIdentifier type;
1619 final Expression expr;
1620 final int pos = SimpleCharStream.getPosition();
1621 }
1622 {
1623   <LPAREN>
1624   (type = Type()
1625   | <ARRAY> {type = new ConstantIdentifier(Types.ARRAY,pos,SimpleCharStream.getPosition());})
1626   <RPAREN> expr = UnaryExpression()
1627   {return new CastExpression(type,expr,pos,SimpleCharStream.getPosition());}
1628 }
1629
1630 Expression PostfixExpression() :
1631 {
1632   Expression expr;
1633   int operator = -1;
1634   final int pos = SimpleCharStream.getPosition();
1635 }
1636 {
1637   expr = PrimaryExpression()
1638   [ <INCR> {operator = OperatorIds.PLUS_PLUS;}
1639   | <DECR> {operator = OperatorIds.MINUS_MINUS;}]
1640   {
1641     if (operator == -1) {
1642       return expr;
1643     }
1644     return new PostfixedUnaryExpression(expr,operator,pos);
1645   }
1646 }
1647
1648 Expression PrimaryExpression() :
1649 {
1650   final Token identifier;
1651   Expression expr;
1652   final StringBuffer buff = new StringBuffer();
1653   final int pos = SimpleCharStream.getPosition();
1654 }
1655 {
1656   LOOKAHEAD(2)
1657   identifier = <IDENTIFIER> <STATICCLASSACCESS> expr = ClassIdentifier()
1658   {expr = new ClassAccess(new ConstantIdentifier(identifier.image.toCharArray(),
1659                                                  pos,
1660                                                  SimpleCharStream.getPosition()),
1661                           expr,
1662                           ClassAccess.STATIC);}
1663   (expr = PrimarySuffix(expr))*
1664   {return expr;}
1665 |
1666   expr = PrimaryPrefix()
1667   (expr = PrimarySuffix(expr))*
1668   {return expr;}
1669 |
1670   expr = ArrayDeclarator()
1671   {return expr;}
1672 }
1673
1674 ArrayInitializer ArrayDeclarator() :
1675 {
1676   final ArrayVariableDeclaration[] vars;
1677   final int pos = SimpleCharStream.getPosition();
1678 }
1679 {
1680   <ARRAY> vars = ArrayInitializer()
1681   {return new ArrayInitializer(vars,pos,SimpleCharStream.getPosition());}
1682 }
1683
1684 Expression PrimaryPrefix() :
1685 {
1686   final Expression expr;
1687   final Token token;
1688   final String var;
1689   final int pos = SimpleCharStream.getPosition();
1690 }
1691 {
1692   token = <IDENTIFIER>           {return new ConstantIdentifier(token.image.toCharArray(),
1693                                                                 pos,
1694                                                                 SimpleCharStream.getPosition());}
1695 | <NEW> expr = ClassIdentifier() {return new PrefixedUnaryExpression(expr,
1696                                                                      OperatorIds.NEW,
1697                                                                      pos);}
1698 | var = VariableDeclaratorId()  {return new ConstantIdentifier(var.toCharArray(),
1699                                                                pos,
1700                                                                SimpleCharStream.getPosition());}
1701 }
1702
1703 PrefixedUnaryExpression classInstantiation() :
1704 {
1705   Expression expr;
1706   final StringBuffer buff;
1707   final int pos = SimpleCharStream.getPosition();
1708 }
1709 {
1710   <NEW> expr = ClassIdentifier()
1711   [
1712     {buff = new StringBuffer(expr.toStringExpression());}
1713     expr = PrimaryExpression()
1714     {buff.append(expr.toStringExpression());
1715     expr = new ConstantIdentifier(buff.toString().toCharArray(),
1716                                   pos,
1717                                   SimpleCharStream.getPosition());}
1718   ]
1719   {return new PrefixedUnaryExpression(expr,
1720                                       OperatorIds.NEW,
1721                                       pos);}
1722 }
1723
1724 ConstantIdentifier ClassIdentifier():
1725 {
1726   final String expr;
1727   final Token token;
1728   final int pos = SimpleCharStream.getPosition();
1729 }
1730 {
1731   token = <IDENTIFIER>          {return new ConstantIdentifier(token.image.toCharArray(),
1732                                                                pos,
1733                                                                SimpleCharStream.getPosition());}
1734 | expr = VariableDeclaratorId() {return new ConstantIdentifier(expr.toCharArray(),
1735                                                                pos,
1736                                                                SimpleCharStream.getPosition());}
1737 }
1738
1739 AbstractSuffixExpression PrimarySuffix(Expression prefix) :
1740 {
1741   final AbstractSuffixExpression expr;
1742 }
1743 {
1744   expr = Arguments(prefix)      {return expr;}
1745 | expr = VariableSuffix(prefix) {return expr;}
1746 }
1747
1748 AbstractSuffixExpression VariableSuffix(Expression prefix) :
1749 {
1750   String expr = null;
1751   final int pos = SimpleCharStream.getPosition();
1752   Expression expression = null;
1753 }
1754 {
1755   <CLASSACCESS>
1756   try {
1757     expr = VariableName()
1758   } catch (ParseException e) {
1759     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function call or field access expected";
1760     errorLevel   = ERROR;
1761     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1762     errorEnd   = jj_input_stream.getPosition() + 1;
1763     throw e;
1764   }
1765   {return new ClassAccess(prefix,
1766                           new ConstantIdentifier(expr.toCharArray(),pos,SimpleCharStream.getPosition()),
1767                           ClassAccess.NORMAL);}
1768 |
1769   <LBRACKET> [ expression = Expression() | expression = Type() ]  //Not good
1770   try {
1771     <RBRACKET>
1772   } catch (ParseException e) {
1773     errorMessage = "']' expected";
1774     errorLevel   = ERROR;
1775     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1776     errorEnd   = jj_input_stream.getPosition() + 1;
1777     throw e;
1778   }
1779   {return new ArrayDeclarator(prefix,expression,SimpleCharStream.getPosition());}
1780 }
1781
1782 Literal Literal() :
1783 {
1784   final Token token;
1785   final int pos;
1786 }
1787 {
1788   token = <INTEGER_LITERAL>        {pos = SimpleCharStream.getPosition();
1789                                     return new NumberLiteral(token.image.toCharArray(),pos-token.image.length(),pos);}
1790 | token = <FLOATING_POINT_LITERAL> {pos = SimpleCharStream.getPosition();
1791                                     return new NumberLiteral(token.image.toCharArray(),pos-token.image.length(),pos);}
1792 | token = <STRING_LITERAL>         {pos = SimpleCharStream.getPosition();
1793                                     return new StringLiteral(token.image.toCharArray(),pos-token.image.length(),pos);}
1794 | <TRUE>                           {pos = SimpleCharStream.getPosition();
1795                                     return new TrueLiteral(pos-4,pos);}
1796 | <FALSE>                          {pos = SimpleCharStream.getPosition();
1797                                     return new FalseLiteral(pos-4,pos);}
1798 | <NULL>                           {pos = SimpleCharStream.getPosition();
1799                                     return new NullLiteral(pos-4,pos);}
1800 }
1801
1802 FunctionCall Arguments(Expression func) :
1803 {
1804 ArgumentDeclaration[] args = null;
1805 }
1806 {
1807   <LPAREN> [ args = ArgumentList() ]
1808   try {
1809     <RPAREN>
1810   } catch (ParseException e) {
1811     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list";
1812     errorLevel   = ERROR;
1813     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1814     errorEnd   = jj_input_stream.getPosition() + 1;
1815     throw e;
1816   }
1817   {return new FunctionCall(func,args,SimpleCharStream.getPosition());}
1818 }
1819
1820 ArgumentDeclaration[] ArgumentList() :
1821 {
1822 ArgumentDeclaration arg;
1823 final ArrayList list = new ArrayList();
1824 ArgumentDeclaration argument;
1825 }
1826 {
1827   arg = argumentDeclaration()
1828   {list.add(arg);}
1829   ( <COMMA>
1830       try {
1831         arg = argumentDeclaration()
1832         {list.add(arg);}
1833       } catch (ParseException e) {
1834         errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. An expression expected after a comma in argument list";
1835         errorLevel   = ERROR;
1836         errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1837         errorEnd     = jj_input_stream.getPosition() + 1;
1838         throw e;
1839       }
1840    )*
1841    {
1842    ArgumentDeclaration[] args = new ArgumentDeclaration[list.size()];
1843    list.toArray(args);
1844    return args;}
1845 }
1846
1847 ArgumentDeclaration argumentDeclaration() :
1848 {
1849   boolean reference = false;
1850   String varName;
1851   Expression initializer = null;
1852   final int pos = SimpleCharStream.getPosition();
1853 }
1854 {
1855   [<BIT_AND> {reference = true;}]
1856   varName = VariableDeclaratorId()
1857  [
1858     <ASSIGN>
1859     try {
1860       initializer = VariableInitializer()
1861     } catch (ParseException e) {
1862       errorMessage = "Literal expression expected in variable initializer";
1863       errorLevel   = ERROR;
1864       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1865       errorEnd   = jj_input_stream.getPosition() + 1;
1866       throw e;
1867     }
1868   ]
1869   {
1870   if (initializer == null) {
1871     return new ArgumentDeclaration(varName.toCharArray(),
1872                                    reference,
1873                                    pos);
1874   }
1875   return new ArgumentDeclaration(varName.toCharArray(),
1876                                  reference,
1877                                  initializer,
1878                                  pos);
1879   }
1880 }
1881 /**
1882  * A Statement without break.
1883  */
1884 Statement StatementNoBreak() :
1885 {
1886   final Statement statement;
1887   Token token = null;
1888 }
1889 {
1890   LOOKAHEAD(2)
1891   statement = Expression()
1892   try {
1893     <SEMICOLON>
1894   } catch (ParseException e) {
1895     if (e.currentToken.next.kind != 4) {
1896       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1897       errorLevel   = ERROR;
1898       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1899       errorEnd   = jj_input_stream.getPosition() + 1;
1900       throw e;
1901     }
1902   }
1903   {return statement;}
1904 | LOOKAHEAD(2)
1905   statement = LabeledStatement() {return statement;}
1906 | statement = Block()            {return statement;}
1907 | statement = EmptyStatement()   {return statement;}
1908 | statement = StatementExpression()
1909   try {
1910     <SEMICOLON>
1911   } catch (ParseException e) {
1912     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1913     errorLevel   = ERROR;
1914     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1915     errorEnd     = jj_input_stream.getPosition() + 1;
1916     throw e;
1917   }
1918   {return statement;}
1919 | statement = SwitchStatement()         {return statement;}
1920 | statement = IfStatement()             {return statement;}
1921 | statement = WhileStatement()          {return statement;}
1922 | statement = DoStatement()             {return statement;}
1923 | statement = ForStatement()            {return statement;}
1924 | statement = ForeachStatement()        {return statement;}
1925 | statement = ContinueStatement()       {return statement;}
1926 | statement = ReturnStatement()         {return statement;}
1927 | statement = EchoStatement()           {return statement;}
1928 | [token=<AT>] statement = IncludeStatement()
1929   {if (token != null) {
1930     ((InclusionStatement)statement).silent = true;
1931   }
1932   return statement;}
1933 | statement = StaticStatement()         {return statement;}
1934 | statement = GlobalStatement()         {return statement;}
1935 }
1936
1937 /**
1938  * A Normal statement.
1939  */
1940 Statement Statement() :
1941 {
1942   final Statement statement;
1943 }
1944 {
1945   statement = StatementNoBreak() {return statement;}
1946 | statement = BreakStatement()   {return statement;}
1947 }
1948
1949 /**
1950  * An html block inside a php syntax.
1951  */
1952 HTMLBlock htmlBlock() :
1953 {
1954   final int startIndex = nodePtr;
1955   AstNode[] blockNodes;
1956   int nbNodes;
1957 }
1958 {
1959   <PHPEND> (phpEchoBlock())*
1960   try {
1961     (<PHPSTARTLONG> | <PHPSTARTSHORT>)
1962   } catch (ParseException e) {
1963     errorMessage = "End of file unexpected, '<?php' expected";
1964     errorLevel   = ERROR;
1965     errorStart   = jj_input_stream.getPosition();
1966     errorEnd     = jj_input_stream.getPosition();
1967     throw e;
1968   }
1969   {
1970   nbNodes = nodePtr-startIndex;
1971   blockNodes = new AstNode[nbNodes];
1972   System.arraycopy(nodes,startIndex,blockNodes,0,nbNodes);
1973   return new HTMLBlock(nodes);}
1974 }
1975
1976 /**
1977  * An include statement. It's "include" an expression;
1978  */
1979 InclusionStatement IncludeStatement() :
1980 {
1981   final Expression expr;
1982   final Token token;
1983   final int keyword;
1984   final int pos = jj_input_stream.getPosition();
1985   final InclusionStatement inclusionStatement;
1986 }
1987 {
1988       (  <REQUIRE>      {keyword = InclusionStatement.REQUIRE;}
1989        | <REQUIRE_ONCE> {keyword = InclusionStatement.REQUIRE_ONCE;}
1990        | <INCLUDE>      {keyword = InclusionStatement.INCLUDE;}
1991        | <INCLUDE_ONCE> {keyword = InclusionStatement.INCLUDE_ONCE;})
1992   try {
1993     expr = Expression()
1994   } catch (ParseException e) {
1995     if (errorMessage != null) {
1996       throw e;
1997     }
1998     errorMessage = "unexpected token '"+ e.currentToken.next.image+"', expression expected";
1999     errorLevel   = ERROR;
2000     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2001     errorEnd     = jj_input_stream.getPosition() + 1;
2002     throw e;
2003   }
2004   {inclusionStatement = new InclusionStatement(currentSegment,
2005                                                keyword,
2006                                                expr,
2007                                                pos);
2008    currentSegment.add(inclusionStatement);
2009   }
2010   try {
2011     <SEMICOLON>
2012   } catch (ParseException e) {
2013     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2014     errorLevel   = ERROR;
2015     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2016     errorEnd     = jj_input_stream.getPosition() + 1;
2017     throw e;
2018   }
2019   {return inclusionStatement;}
2020 }
2021
2022 PrintExpression PrintExpression() :
2023 {
2024   final Expression expr;
2025   final int pos = SimpleCharStream.getPosition();
2026 }
2027 {
2028   <PRINT> expr = Expression() {return new PrintExpression(expr,pos,SimpleCharStream.getPosition());}
2029 }
2030
2031 ListExpression ListExpression() :
2032 {
2033   String expr = null;
2034   Expression expression = null;
2035   ArrayList list = new ArrayList();
2036   final int pos = SimpleCharStream.getPosition();
2037 }
2038 {
2039   <LIST>
2040   try {
2041     <LPAREN>
2042   } catch (ParseException e) {
2043     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
2044     errorLevel   = ERROR;
2045     errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2046     errorEnd     = jj_input_stream.getPosition() + 1;
2047     throw e;
2048   }
2049   [
2050     expr = VariableDeclaratorId()
2051     {list.add(expr);}
2052   ]
2053   {if (expr == null) list.add(null);}
2054   (
2055     try {
2056       <COMMA>
2057     } catch (ParseException e) {
2058       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
2059       errorLevel   = ERROR;
2060       errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2061       errorEnd     = jj_input_stream.getPosition() + 1;
2062       throw e;
2063     }
2064     expr = VariableDeclaratorId()
2065     {list.add(expr);}
2066   )*
2067   try {
2068     <RPAREN>
2069   } catch (ParseException e) {
2070     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
2071     errorLevel   = ERROR;
2072     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2073     errorEnd   = jj_input_stream.getPosition() + 1;
2074     throw e;
2075   }
2076   [ <ASSIGN> expression = Expression()
2077     {
2078     String[] strings = new String[list.size()];
2079     list.toArray(strings);
2080     return new ListExpression(strings,
2081                               expression,
2082                               pos,
2083                               SimpleCharStream.getPosition());}
2084   ]
2085   {
2086     String[] strings = new String[list.size()];
2087     list.toArray(strings);
2088     return new ListExpression(strings,pos,SimpleCharStream.getPosition());}
2089 }
2090
2091 /**
2092  * An echo statement.
2093  * echo anyexpression (, otherexpression)*
2094  */
2095 EchoStatement EchoStatement() :
2096 {
2097   final ArrayList expressions = new ArrayList();
2098   Expression expr;
2099   final int pos = SimpleCharStream.getPosition();
2100 }
2101 {
2102   <ECHO> expr = Expression()
2103   {expressions.add(expr);}
2104   (
2105     <COMMA> expr = Expression()
2106     {expressions.add(expr);}
2107   )*
2108   try {
2109     <SEMICOLON>
2110     {
2111     Expression[] exprs = new Expression[expressions.size()];
2112     expressions.toArray(exprs);
2113     return new EchoStatement(exprs,pos);}
2114   } catch (ParseException e) {
2115     if (e.currentToken.next.kind != 4) {
2116       errorMessage = "';' expected after 'echo' statement";
2117       errorLevel   = ERROR;
2118       errorStart   = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2119       errorEnd     = jj_input_stream.getPosition() + 1;
2120       throw e;
2121     }
2122   }
2123 }
2124
2125 GlobalStatement GlobalStatement() :
2126 {
2127    final int pos = jj_input_stream.getPosition();
2128    String expr;
2129    ArrayList vars = new ArrayList();
2130    GlobalStatement global;
2131 }
2132 {
2133   <GLOBAL>
2134     expr = VariableDeclaratorId()
2135     {vars.add(expr);}
2136   (<COMMA>
2137     expr = VariableDeclaratorId()
2138     {vars.add(expr);}
2139   )*
2140   try {
2141     <SEMICOLON>
2142     {
2143     String[] strings = new String[vars.size()];
2144     vars.toArray(strings);
2145     global = new GlobalStatement(currentSegment,
2146                                  strings,
2147                                  pos,
2148                                  SimpleCharStream.getPosition());
2149     currentSegment.add(global);
2150     return global;}
2151   } catch (ParseException e) {
2152     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2153     errorLevel   = ERROR;
2154     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2155     errorEnd   = jj_input_stream.getPosition() + 1;
2156     throw e;
2157   }
2158 }
2159
2160 StaticStatement StaticStatement() :
2161 {
2162   final int pos = SimpleCharStream.getPosition();
2163   final ArrayList vars = new ArrayList();
2164   VariableDeclaration expr;
2165 }
2166 {
2167   <STATIC> expr = VariableDeclarator() {vars.add(new String(expr.name));}
2168   (<COMMA> expr = VariableDeclarator() {vars.add(new String(expr.name));})*
2169   try {
2170     <SEMICOLON>
2171     {
2172     String[] strings = new String[vars.size()];
2173     vars.toArray(strings);
2174     return new StaticStatement(strings,
2175                                 pos,
2176                                 SimpleCharStream.getPosition());}
2177   } catch (ParseException e) {
2178     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2179     errorLevel   = ERROR;
2180     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2181     errorEnd   = jj_input_stream.getPosition() + 1;
2182     throw e;
2183   }
2184 }
2185
2186 LabeledStatement LabeledStatement() :
2187 {
2188   final int pos = SimpleCharStream.getPosition();
2189   final Token label;
2190   final Statement statement;
2191 }
2192 {
2193   label = <IDENTIFIER> <COLON> statement = Statement()
2194   {return new LabeledStatement(label.image.toCharArray(),statement,pos,SimpleCharStream.getPosition());}
2195 }
2196
2197 /**
2198  * A Block is
2199  * {
2200  * statements
2201  * }.
2202  * @return a block
2203  */
2204 Block Block() :
2205 {
2206   final int pos = SimpleCharStream.getPosition();
2207   Statement[] statements;
2208   Statement statement;
2209   final int startingPtr = statementPtr;
2210   final int length;
2211 }
2212 {
2213   try {
2214     <LBRACE>
2215   } catch (ParseException e) {
2216     errorMessage = "'{' expected";
2217     errorLevel   = ERROR;
2218     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2219     errorEnd   = jj_input_stream.getPosition() + 1;
2220     throw e;
2221   }
2222   ( statement = BlockStatement() {pushOnStatementStack(statement);}
2223   | statement = htmlBlock()      {pushOnStatementStack(statement);})*
2224   try {
2225     <RBRACE>
2226   } catch (ParseException e) {
2227     errorMessage = "unexpected token : '"+ e.currentToken.image +"', '}' expected";
2228     errorLevel   = ERROR;
2229     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2230     errorEnd   = jj_input_stream.getPosition() + 1;
2231     throw e;
2232   }
2233   {
2234   length = statementPtr-startingPtr+1;
2235   statements = new Statement[length];
2236   System.arraycopy(variableDeclarationStack,startingPtr+1,statements,0,length);
2237   statementPtr = startingPtr;
2238   return new Block(statements,pos,SimpleCharStream.getPosition());}
2239 }
2240
2241 Statement BlockStatement() :
2242 {
2243   final Statement statement;
2244 }
2245 {
2246   statement = Statement()         {return statement;}
2247 | statement = ClassDeclaration()  {return statement;}
2248 | statement = MethodDeclaration() {return statement;}
2249 }
2250
2251 /**
2252  * A Block statement that will not contain any 'break'
2253  */
2254 Statement BlockStatementNoBreak() :
2255 {
2256   final Statement statement;
2257 }
2258 {
2259   statement = StatementNoBreak()  {return statement;}
2260 | statement = ClassDeclaration()  {return statement;}
2261 | statement = MethodDeclaration() {return statement;}
2262 }
2263
2264 VariableDeclaration[] LocalVariableDeclaration() :
2265 {
2266   final ArrayList list = new ArrayList();
2267   VariableDeclaration var;
2268 }
2269 {
2270   var = LocalVariableDeclarator()
2271   {list.add(var);}
2272   ( <COMMA> var = LocalVariableDeclarator() {list.add(var);})*
2273   {
2274     VariableDeclaration[] vars = new VariableDeclaration[list.size()];
2275     list.toArray(vars);
2276   return vars;}
2277 }
2278
2279 VariableDeclaration LocalVariableDeclarator() :
2280 {
2281   final String varName;
2282   Expression initializer = null;
2283   final int pos = SimpleCharStream.getPosition();
2284 }
2285 {
2286   varName = VariableDeclaratorId() [ <ASSIGN> initializer = Expression() ]
2287   {
2288    if (initializer == null) {
2289     return new VariableDeclaration(currentSegment,
2290                                   varName.toCharArray(),
2291                                   pos,
2292                                   jj_input_stream.getPosition());
2293    }
2294     return new VariableDeclaration(currentSegment,
2295                                     varName.toCharArray(),
2296                                     initializer,
2297                                     pos);
2298   }
2299 }
2300
2301 EmptyStatement EmptyStatement() :
2302 {
2303   final int pos;
2304 }
2305 {
2306   <SEMICOLON>
2307   {pos = SimpleCharStream.getPosition();
2308    return new EmptyStatement(pos-1,pos);}
2309 }
2310
2311 Statement StatementExpression() :
2312 {
2313   Expression expr;
2314 }
2315 {
2316   expr = PreIncDecExpression() {return expr;}
2317 |
2318   expr = PrimaryExpression()
2319   [ <INCR> {expr = new PostfixedUnaryExpression(expr,
2320                                                 OperatorIds.PLUS_PLUS,
2321                                                 SimpleCharStream.getPosition());}
2322   | <DECR> {expr = new PostfixedUnaryExpression(expr,
2323                                                 OperatorIds.MINUS_MINUS,
2324                                                 SimpleCharStream.getPosition());}
2325   | AssignmentOperator() Expression() ]
2326 }
2327
2328 SwitchStatement SwitchStatement() :
2329 {
2330   final Expression variable;
2331   final AbstractCase[] cases;
2332   final int pos = SimpleCharStream.getPosition();
2333 }
2334 {
2335   <SWITCH>
2336   try {
2337     <LPAREN>
2338   } catch (ParseException e) {
2339     errorMessage = "'(' expected after 'switch'";
2340     errorLevel   = ERROR;
2341     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2342     errorEnd   = jj_input_stream.getPosition() + 1;
2343     throw e;
2344   }
2345   try {
2346     variable = Expression()
2347   } catch (ParseException e) {
2348     if (errorMessage != null) {
2349       throw e;
2350     }
2351     errorMessage = "expression expected";
2352     errorLevel   = ERROR;
2353     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2354     errorEnd   = jj_input_stream.getPosition() + 1;
2355     throw e;
2356   }
2357   try {
2358     <RPAREN>
2359   } catch (ParseException e) {
2360     errorMessage = "')' expected";
2361     errorLevel   = ERROR;
2362     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2363     errorEnd   = jj_input_stream.getPosition() + 1;
2364     throw e;
2365   }
2366   (cases = switchStatementBrace() | cases = switchStatementColon(pos, pos + 6))
2367   {return new SwitchStatement(variable,cases,pos,SimpleCharStream.getPosition());}
2368 }
2369
2370 AbstractCase[] switchStatementBrace() :
2371 {
2372   AbstractCase cas;
2373   final ArrayList cases = new ArrayList();
2374 }
2375 {
2376   <LBRACE>
2377  ( cas = switchLabel0() {cases.add(cas);})*
2378   try {
2379     <RBRACE>
2380     {
2381     AbstractCase[] abcase = new AbstractCase[cases.size()];
2382     cases.toArray(abcase);
2383     return abcase;}
2384   } catch (ParseException e) {
2385     errorMessage = "'}' expected";
2386     errorLevel   = ERROR;
2387     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2388     errorEnd   = jj_input_stream.getPosition() + 1;
2389     throw e;
2390   }
2391 }
2392 /**
2393  * A Switch statement with : ... endswitch;
2394  * @param start the begin offset of the switch
2395  * @param end the end offset of the switch
2396  */
2397 AbstractCase[] switchStatementColon(final int start, final int end) :
2398 {
2399   AbstractCase cas;
2400   final ArrayList cases = new ArrayList();
2401 }
2402 {
2403   <COLON>
2404   {try {
2405   setMarker(fileToParse,
2406             "Ugly syntax detected, you should switch () {...} instead of switch (): ... enswitch;",
2407             start,
2408             end,
2409             INFO,
2410             "Line " + token.beginLine);
2411   } catch (CoreException e) {
2412     PHPeclipsePlugin.log(e);
2413   }}
2414   ( cas = switchLabel0() {cases.add(cas);})*
2415   try {
2416     <ENDSWITCH>
2417   } catch (ParseException e) {
2418     errorMessage = "'endswitch' expected";
2419     errorLevel   = ERROR;
2420     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2421     errorEnd   = jj_input_stream.getPosition() + 1;
2422     throw e;
2423   }
2424   try {
2425     <SEMICOLON>
2426     {
2427     AbstractCase[] abcase = new AbstractCase[cases.size()];
2428     cases.toArray(abcase);
2429     return abcase;}
2430   } catch (ParseException e) {
2431     errorMessage = "';' expected after 'endswitch' keyword";
2432     errorLevel   = ERROR;
2433     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2434     errorEnd   = jj_input_stream.getPosition() + 1;
2435     throw e;
2436   }
2437 }
2438
2439 AbstractCase switchLabel0() :
2440 {
2441   final Expression expr;
2442   Statement statement;
2443   final ArrayList stmts = new ArrayList();
2444   final int pos = SimpleCharStream.getPosition();
2445 }
2446 {
2447   expr = SwitchLabel()
2448   ( statement = BlockStatementNoBreak() {stmts.add(statement);}
2449   | statement = htmlBlock()             {stmts.add(statement);})*
2450   [ statement = BreakStatement()        {stmts.add(statement);}]
2451   {
2452   Statement[] stmtsArray = new Statement[stmts.size()];
2453   stmts.toArray(stmtsArray);
2454   if (expr == null) {//it's a default
2455     return new DefaultCase(stmtsArray,pos,SimpleCharStream.getPosition());
2456   }
2457   return new Case(expr,stmtsArray,pos,SimpleCharStream.getPosition());}
2458 }
2459
2460 /**
2461  * A SwitchLabel.
2462  * case Expression() :
2463  * default :
2464  * @return the if it was a case and null if not
2465  */
2466 Expression SwitchLabel() :
2467 {
2468   final Token token;
2469   final Expression expr;
2470 }
2471 {
2472   token = <CASE>
2473   try {
2474     expr = Expression()
2475   } catch (ParseException e) {
2476     if (errorMessage != null) throw e;
2477     errorMessage = "expression expected after 'case' keyword";
2478     errorLevel   = ERROR;
2479     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2480     errorEnd   = jj_input_stream.getPosition() + 1;
2481     throw e;
2482   }
2483   try {
2484     <COLON>
2485     {return expr;}
2486   } catch (ParseException e) {
2487     errorMessage = "':' expected after case expression";
2488     errorLevel   = ERROR;
2489     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2490     errorEnd   = jj_input_stream.getPosition() + 1;
2491     throw e;
2492   }
2493 |
2494   token = <_DEFAULT>
2495   try {
2496     <COLON>
2497     {return null;}
2498   } catch (ParseException e) {
2499     errorMessage = "':' expected after 'default' keyword";
2500     errorLevel   = ERROR;
2501     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2502     errorEnd   = jj_input_stream.getPosition() + 1;
2503     throw e;
2504   }
2505 }
2506
2507 Break BreakStatement() :
2508 {
2509   Expression expression = null;
2510   final int start = SimpleCharStream.getPosition();
2511 }
2512 {
2513   <BREAK> [ expression = Expression() ]
2514   try {
2515     <SEMICOLON>
2516   } catch (ParseException e) {
2517     errorMessage = "';' expected after 'break' keyword";
2518     errorLevel   = ERROR;
2519     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2520     errorEnd   = jj_input_stream.getPosition() + 1;
2521     throw e;
2522   }
2523   {return new Break(expression, start, SimpleCharStream.getPosition());}
2524 }
2525
2526 IfStatement IfStatement() :
2527 {
2528   final int pos = jj_input_stream.getPosition();
2529   Expression condition;
2530   IfStatement ifStatement;
2531 }
2532 {
2533   <IF> condition = Condition("if") ifStatement = IfStatement0(condition, pos,pos+2)
2534   {return ifStatement;}
2535 }
2536
2537
2538 Expression Condition(final String keyword) :
2539 {
2540   final Expression condition;
2541 }
2542 {
2543   try {
2544     <LPAREN>
2545   } catch (ParseException e) {
2546     errorMessage = "'(' expected after " + keyword + " keyword";
2547     errorLevel   = ERROR;
2548     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length();
2549     errorEnd   = errorStart +1;
2550     processParseException(e);
2551   }
2552   condition = Expression()
2553   try {
2554      <RPAREN>
2555      {return condition;}
2556   } catch (ParseException e) {
2557     errorMessage = "')' expected after " + keyword + " keyword";
2558     errorLevel   = ERROR;
2559     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2560     errorEnd   = jj_input_stream.getPosition() + 1;
2561     throw e;
2562   }
2563 }
2564
2565 IfStatement IfStatement0(Expression condition, final int start,final int end) :
2566 {
2567   Statement statement;
2568   Statement stmt;
2569   final Statement[] statementsArray;
2570   ElseIf elseifStatement;
2571   Else elseStatement = null;
2572   ArrayList stmts;
2573   final ArrayList elseIfList = new ArrayList();
2574   ElseIf[] elseIfs;
2575   int pos = SimpleCharStream.getPosition();
2576   int endStatements;
2577 }
2578 {
2579   <COLON>
2580   {stmts = new ArrayList();}
2581   (  statement = Statement() {stmts.add(statement);}
2582    | statement = htmlBlock() {stmts.add(statement);})*
2583    {endStatements = SimpleCharStream.getPosition();}
2584    (elseifStatement = ElseIfStatementColon() {elseIfList.add(elseifStatement);})*
2585    [elseStatement = ElseStatementColon()]
2586
2587   {try {
2588   setMarker(fileToParse,
2589             "Ugly syntax detected, you should if () {...} instead of if (): ... endif;",
2590             start,
2591             end,
2592             INFO,
2593             "Line " + token.beginLine);
2594   } catch (CoreException e) {
2595     PHPeclipsePlugin.log(e);
2596   }}
2597   try {
2598     <ENDIF>
2599   } catch (ParseException e) {
2600     errorMessage = "'endif' expected";
2601     errorLevel   = ERROR;
2602     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2603     errorEnd   = jj_input_stream.getPosition() + 1;
2604     throw e;
2605   }
2606   try {
2607     <SEMICOLON>
2608   } catch (ParseException e) {
2609     errorMessage = "';' expected after 'endif' keyword";
2610     errorLevel   = ERROR;
2611     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2612     errorEnd   = jj_input_stream.getPosition() + 1;
2613     throw e;
2614   }
2615     {
2616     elseIfs = new ElseIf[elseIfList.size()];
2617     elseIfList.toArray(elseIfs);
2618     if (stmts.size() == 1) {
2619       return new IfStatement(condition,
2620                              (Statement) stmts.get(0),
2621                               elseIfs,
2622                               elseStatement,
2623                               pos,
2624                               SimpleCharStream.getPosition());
2625     } else {
2626       statementsArray = new Statement[stmts.size()];
2627       stmts.toArray(statementsArray);
2628       return new IfStatement(condition,
2629                              new Block(statementsArray,pos,endStatements),
2630                               elseIfs,
2631                               elseStatement,
2632                               pos,
2633                               SimpleCharStream.getPosition());
2634     }
2635     }
2636
2637 |
2638   (stmt = Statement() | stmt = htmlBlock())
2639   ( LOOKAHEAD(1) elseifStatement = ElseIfStatement() {elseIfList.add(elseifStatement);})*
2640   [ LOOKAHEAD(1)
2641     <ELSE>
2642     try {
2643       {pos = SimpleCharStream.getPosition();}
2644       statement = Statement()
2645       {elseStatement = new Else(statement,pos,SimpleCharStream.getPosition());}
2646     } catch (ParseException e) {
2647       if (errorMessage != null) {
2648         throw e;
2649       }
2650       errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected";
2651       errorLevel   = ERROR;
2652       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2653       errorEnd   = jj_input_stream.getPosition() + 1;
2654       throw e;
2655     }
2656   ]
2657   {
2658     elseIfs = new ElseIf[elseIfList.size()];
2659     elseIfList.toArray(elseIfs);
2660     return new IfStatement(condition,
2661                            stmt,
2662                            elseIfs,
2663                            elseStatement,
2664                            pos,
2665                            SimpleCharStream.getPosition());}
2666 }
2667
2668 ElseIf ElseIfStatementColon() :
2669 {
2670   Expression condition;
2671   Statement statement;
2672   final ArrayList list = new ArrayList();
2673   final int pos = SimpleCharStream.getPosition();
2674 }
2675 {
2676   <ELSEIF> condition = Condition("elseif")
2677   <COLON> (  statement = Statement() {list.add(statement);}
2678            | statement = htmlBlock() {list.add(statement);})*
2679   {
2680   Statement[] stmtsArray = new Statement[list.size()];
2681   list.toArray(stmtsArray);
2682   return new ElseIf(condition,stmtsArray ,pos,SimpleCharStream.getPosition());}
2683 }
2684
2685 Else ElseStatementColon() :
2686 {
2687   Statement statement;
2688   final ArrayList list = new ArrayList();
2689   final int pos = SimpleCharStream.getPosition();
2690 }
2691 {
2692   <ELSE> <COLON> (  statement = Statement() {list.add(statement);}
2693                   | statement = htmlBlock() {list.add(statement);})*
2694   {
2695   Statement[] stmtsArray = new Statement[list.size()];
2696   list.toArray(stmtsArray);
2697   return new Else(stmtsArray,pos,SimpleCharStream.getPosition());}
2698 }
2699
2700 ElseIf ElseIfStatement() :
2701 {
2702   Expression condition;
2703   Statement statement;
2704   final ArrayList list = new ArrayList();
2705   final int pos = SimpleCharStream.getPosition();
2706 }
2707 {
2708   <ELSEIF> condition = Condition("elseif") statement = Statement() {list.add(statement);/*todo:do better*/}
2709   {
2710   Statement[] stmtsArray = new Statement[list.size()];
2711   list.toArray(stmtsArray);
2712   return new ElseIf(condition,stmtsArray,pos,SimpleCharStream.getPosition());}
2713 }
2714
2715 WhileStatement WhileStatement() :
2716 {
2717   final Expression condition;
2718   final Statement action;
2719   final int pos = SimpleCharStream.getPosition();
2720 }
2721 {
2722   <WHILE>
2723     condition = Condition("while")
2724     action    = WhileStatement0(pos,pos + 5)
2725     {return new WhileStatement(condition,action,pos,SimpleCharStream.getPosition());}
2726 }
2727
2728 Statement WhileStatement0(final int start, final int end) :
2729 {
2730   Statement statement;
2731   final ArrayList stmts = new ArrayList();
2732   final int pos = SimpleCharStream.getPosition();
2733 }
2734 {
2735   <COLON> (statement = Statement() {stmts.add(statement);})*
2736   {try {
2737   setMarker(fileToParse,
2738             "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;",
2739             start,
2740             end,
2741             INFO,
2742             "Line " + token.beginLine);
2743   } catch (CoreException e) {
2744     PHPeclipsePlugin.log(e);
2745   }}
2746   try {
2747     <ENDWHILE>
2748   } catch (ParseException e) {
2749     errorMessage = "'endwhile' expected";
2750     errorLevel   = ERROR;
2751     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2752     errorEnd   = jj_input_stream.getPosition() + 1;
2753     throw e;
2754   }
2755   try {
2756     <SEMICOLON>
2757     {
2758     Statement[] stmtsArray = new Statement[stmts.size()];
2759     stmts.toArray(stmtsArray);
2760     return new Block(stmtsArray,pos,SimpleCharStream.getPosition());}
2761   } catch (ParseException e) {
2762     errorMessage = "';' expected after 'endwhile' keyword";
2763     errorLevel   = ERROR;
2764     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2765     errorEnd   = jj_input_stream.getPosition() + 1;
2766     throw e;
2767   }
2768 |
2769   statement = Statement()
2770   {return statement;}
2771 }
2772
2773 DoStatement DoStatement() :
2774 {
2775   final Statement action;
2776   final Expression condition;
2777   final int pos = SimpleCharStream.getPosition();
2778 }
2779 {
2780   <DO> action = Statement() <WHILE> condition = Condition("while")
2781   try {
2782     <SEMICOLON>
2783     {return new DoStatement(condition,action,pos,SimpleCharStream.getPosition());}
2784   } catch (ParseException e) {
2785     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2786     errorLevel   = ERROR;
2787     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2788     errorEnd   = jj_input_stream.getPosition() + 1;
2789     throw e;
2790   }
2791 }
2792
2793 ForeachStatement ForeachStatement() :
2794 {
2795   Statement statement;
2796   Expression expression;
2797   final StringBuffer buff = new StringBuffer();
2798   final int pos = SimpleCharStream.getPosition();
2799   ArrayVariableDeclaration variable;
2800 }
2801 {
2802   <FOREACH>
2803     try {
2804     <LPAREN>
2805   } catch (ParseException e) {
2806     errorMessage = "'(' expected after 'foreach' keyword";
2807     errorLevel   = ERROR;
2808     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2809     errorEnd   = jj_input_stream.getPosition() + 1;
2810     throw e;
2811   }
2812   try {
2813     expression = Expression()
2814   } catch (ParseException e) {
2815     errorMessage = "variable expected";
2816     errorLevel   = ERROR;
2817     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2818     errorEnd   = jj_input_stream.getPosition() + 1;
2819     throw e;
2820   }
2821   try {
2822     <AS>
2823   } catch (ParseException e) {
2824     errorMessage = "'as' expected";
2825     errorLevel   = ERROR;
2826     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2827     errorEnd   = jj_input_stream.getPosition() + 1;
2828     throw e;
2829   }
2830   try {
2831     variable = ArrayVariable()
2832   } catch (ParseException e) {
2833     errorMessage = "variable expected";
2834     errorLevel   = ERROR;
2835     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2836     errorEnd   = jj_input_stream.getPosition() + 1;
2837     throw e;
2838   }
2839   try {
2840     <RPAREN>
2841   } catch (ParseException e) {
2842     errorMessage = "')' expected after 'foreach' keyword";
2843     errorLevel   = ERROR;
2844     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2845     errorEnd   = jj_input_stream.getPosition() + 1;
2846     throw e;
2847   }
2848   try {
2849     statement = Statement()
2850   } catch (ParseException e) {
2851     if (errorMessage != null) throw e;
2852     errorMessage = "statement expected";
2853     errorLevel   = ERROR;
2854     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2855     errorEnd   = jj_input_stream.getPosition() + 1;
2856     throw e;
2857   }
2858   {return new ForeachStatement(expression,
2859                                variable,
2860                                statement,
2861                                pos,
2862                                SimpleCharStream.getPosition());}
2863
2864 }
2865
2866 ForStatement ForStatement() :
2867 {
2868 final Token token;
2869 final int pos = SimpleCharStream.getPosition();
2870 Statement[] initializations = null;
2871 Expression condition = null;
2872 Statement[] increments = null;
2873 Statement action;
2874 final ArrayList list = new ArrayList();
2875 final int startBlock, endBlock;
2876 }
2877 {
2878   token = <FOR>
2879   try {
2880     <LPAREN>
2881   } catch (ParseException e) {
2882     errorMessage = "'(' expected after 'for' keyword";
2883     errorLevel   = ERROR;
2884     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2885     errorEnd   = jj_input_stream.getPosition() + 1;
2886     throw e;
2887   }
2888      [ initializations = ForInit() ] <SEMICOLON>
2889      [ condition = Expression() ] <SEMICOLON>
2890      [ increments = StatementExpressionList() ] <RPAREN>
2891     (
2892       action = Statement()
2893       {return new ForStatement(initializations,condition,increments,action,pos,SimpleCharStream.getPosition());}
2894     |
2895       <COLON>
2896       {startBlock = SimpleCharStream.getPosition();}
2897       (action = Statement() {list.add(action);})*
2898       {
2899         try {
2900         setMarker(fileToParse,
2901                   "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;",
2902                   pos,
2903                   pos+token.image.length(),
2904                   INFO,
2905                   "Line " + token.beginLine);
2906         } catch (CoreException e) {
2907           PHPeclipsePlugin.log(e);
2908         }
2909       }
2910       {endBlock = SimpleCharStream.getPosition();}
2911       try {
2912         <ENDFOR>
2913       } catch (ParseException e) {
2914         errorMessage = "'endfor' expected";
2915         errorLevel   = ERROR;
2916         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2917         errorEnd   = jj_input_stream.getPosition() + 1;
2918         throw e;
2919       }
2920       try {
2921         <SEMICOLON>
2922         {
2923         Statement[] stmtsArray = new Statement[list.size()];
2924         list.toArray(stmtsArray);
2925         return new ForStatement(initializations,condition,increments,new Block(stmtsArray,startBlock,endBlock),pos,SimpleCharStream.getPosition());}
2926       } catch (ParseException e) {
2927         errorMessage = "';' expected after 'endfor' keyword";
2928         errorLevel   = ERROR;
2929         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2930         errorEnd   = jj_input_stream.getPosition() + 1;
2931         throw e;
2932       }
2933     )
2934 }
2935
2936 Statement[] ForInit() :
2937 {
2938   Statement[] statements;
2939 }
2940 {
2941   LOOKAHEAD(LocalVariableDeclaration())
2942   statements = LocalVariableDeclaration()
2943   {return statements;}
2944 |
2945   statements = StatementExpressionList()
2946   {return statements;}
2947 }
2948
2949 Statement[] StatementExpressionList() :
2950 {
2951   final ArrayList list = new ArrayList();
2952   Statement expr;
2953 }
2954 {
2955   expr = StatementExpression()   {list.add(expr);}
2956   (<COMMA> StatementExpression() {list.add(expr);})*
2957   {
2958   Statement[] stmtsArray = new Statement[list.size()];
2959   list.toArray(stmtsArray);
2960   return stmtsArray;}
2961 }
2962
2963 Continue ContinueStatement() :
2964 {
2965   Expression expr = null;
2966   final int pos = SimpleCharStream.getPosition();
2967 }
2968 {
2969   <CONTINUE> [ expr = Expression() ]
2970   try {
2971     <SEMICOLON>
2972     {return new Continue(expr,pos,SimpleCharStream.getPosition());}
2973   } catch (ParseException e) {
2974     errorMessage = "';' expected after 'continue' statement";
2975     errorLevel   = ERROR;
2976     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2977     errorEnd   = jj_input_stream.getPosition() + 1;
2978     throw e;
2979   }
2980 }
2981
2982 ReturnStatement ReturnStatement() :
2983 {
2984   Expression expr = null;
2985   final int pos = SimpleCharStream.getPosition();
2986 }
2987 {
2988   <RETURN> [ expr = Expression() ]
2989   try {
2990     <SEMICOLON>
2991     {return new ReturnStatement(expr,pos,SimpleCharStream.getPosition());}
2992   } catch (ParseException e) {
2993     errorMessage = "';' expected after 'return' statement";
2994     errorLevel   = ERROR;
2995     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2996     errorEnd   = jj_input_stream.getPosition() + 1;
2997     throw e;
2998   }
2999 }