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