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