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