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