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