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