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