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