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