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