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