Prepared for multiple Partitioners
[phpeclipse.git] / net.sourceforge.phpeclipse / src / test / PHPParser.jj
1 options {
2   LOOKAHEAD = 1;
3   CHOICE_AMBIGUITY_CHECK = 2;
4   OTHER_AMBIGUITY_CHECK = 1;
5   STATIC = true;
6   DEBUG_PARSER = false;
7   DEBUG_LOOKAHEAD = false;
8   DEBUG_TOKEN_MANAGER = false;
9   OPTIMIZE_TOKEN_MANAGER = false;
10   ERROR_REPORTING = true;
11   JAVA_UNICODE_ESCAPE = false;
12   UNICODE_INPUT = false;
13   IGNORE_CASE = true;
14   USER_TOKEN_MANAGER = false;
15   USER_CHAR_STREAM = false;
16   BUILD_PARSER = true;
17   BUILD_TOKEN_MANAGER = true;
18   SANITY_CHECK = true;
19   FORCE_LA_CHECK = false;
20 }
21
22 PARSER_BEGIN(PHPParser)
23 package test;
24
25 import org.eclipse.core.resources.IFile;
26 import org.eclipse.core.resources.IMarker;
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.ui.texteditor.MarkerUtilities;
29 import org.eclipse.jface.preference.IPreferenceStore;
30
31 import java.util.Hashtable;
32 import java.util.Enumeration;
33 import java.io.StringReader;
34 import java.io.*;
35 import java.text.MessageFormat;
36
37 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
38 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
39 import net.sourceforge.phpdt.internal.compiler.parser.*;
40
41 /**
42  * A new php parser.
43  * This php parser is inspired by the Java 1.2 grammar example
44  * given with JavaCC. You can get JavaCC at http://www.webgain.com
45  * You can test the parser with the PHPParserTestCase2.java
46  * @author Matthieu Casanova
47  */
48 public final class PHPParser extends PHPParserSuperclass {
49
50   /** The file that is parsed. */
51   private static IFile fileToParse;
52
53   /** The current segment. */
54   private static PHPSegmentWithChildren currentSegment;
55
56   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
57   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
58   PHPOutlineInfo outlineInfo;
59
60   private static PHPFunctionDeclaration currentFunction;
61   private static boolean assigning;
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 final void setFileToParse(final IFile fileToParse) {
72     this.fileToParse = fileToParse;
73   }
74
75   public PHPParser() {
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,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 && !assigning) {
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.substring(1);
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().setReference(true);
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   LOOKAHEAD(varAssignation())
1129   expr = varAssignation()
1130   {return expr;}
1131 |
1132   expr = ConditionalExpression()
1133   {return expr;}
1134 }
1135
1136 /**
1137  * A Variable assignation.
1138  * varName (an assign operator) any expression
1139  */
1140 String varAssignation() :
1141 {
1142   String varName,assignOperator,expr2;
1143   PHPVarDeclaration variable;
1144   final int pos = SimpleCharStream.getPosition();
1145 }
1146 {
1147   varName = VariableDeclaratorId()
1148   assignOperator = AssignmentOperator()
1149     try {
1150       expr2 = Expression()
1151     } catch (ParseException e) {
1152       if (errorMessage != null) {
1153         throw e;
1154       }
1155       errorMessage = "expression expected";
1156       errorLevel   = ERROR;
1157       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1158       errorEnd   = jj_input_stream.getPosition() + 1;
1159       throw e;
1160     }
1161     {return varName + assignOperator + expr2;}
1162 }
1163
1164 String AssignmentOperator() :
1165 {}
1166 {
1167   <ASSIGN>
1168 {return "=";}
1169 | <STARASSIGN>
1170 {return "*=";}
1171 | <SLASHASSIGN>
1172 {return "/=";}
1173 | <REMASSIGN>
1174 {return "%=";}
1175 | <PLUSASSIGN>
1176 {return "+=";}
1177 | <MINUSASSIGN>
1178 {return "-=";}
1179 | <LSHIFTASSIGN>
1180 {return "<<=";}
1181 | <RSIGNEDSHIFTASSIGN>
1182 {return ">>=";}
1183 | <ANDASSIGN>
1184 {return "&=";}
1185 | <XORASSIGN>
1186 {return "|=";}
1187 | <ORASSIGN>
1188 {return "|=";}
1189 | <DOTASSIGN>
1190 {return ".=";}
1191 | <TILDEEQUAL>
1192 {return "~=";}
1193 }
1194
1195 String ConditionalExpression() :
1196 {
1197   final String expr;
1198   String expr2 = null;
1199   String expr3 = null;
1200 }
1201 {
1202   expr = ConditionalOrExpression() [ <HOOK> expr2 = Expression() <COLON> expr3 = ConditionalExpression() ]
1203 {
1204   if (expr3 == null) {
1205     return expr;
1206   } else {
1207     return expr + "?" + expr2 + ":" + expr3;
1208   }
1209 }
1210 }
1211
1212 String ConditionalOrExpression() :
1213 {
1214   String expr;
1215   Token operator;
1216   final StringBuffer buff = new StringBuffer();
1217 }
1218 {
1219   expr = ConditionalAndExpression()
1220   {buff.append(expr);}
1221   (
1222     (operator = <SC_OR> | operator = <_ORL>) expr = ConditionalAndExpression()
1223     {
1224       buff.append(operator.image);
1225       buff.append(expr);
1226     }
1227   )*
1228   {
1229     return buff.toString();
1230   }
1231 }
1232
1233 String ConditionalAndExpression() :
1234 {
1235   String expr;
1236   Token operator;
1237   final StringBuffer buff = new StringBuffer();
1238 }
1239 {
1240   expr = ConcatExpression()
1241   {buff.append(expr);}
1242   (
1243   (operator = <SC_AND> | operator = <_ANDL>) expr = ConcatExpression()
1244     {
1245       buff.append(operator.image);
1246       buff.append(expr);
1247     }
1248   )*
1249   {return buff.toString();}
1250 }
1251
1252 String ConcatExpression() :
1253 {
1254   String expr;
1255   final StringBuffer buff = new StringBuffer();
1256 }
1257 {
1258   expr = InclusiveOrExpression()
1259   {buff.append(expr);}
1260   (
1261   <DOT> expr = InclusiveOrExpression()
1262   {buff.append(".").append(expr);}
1263   )*
1264   {return buff.toString();}
1265 }
1266
1267 String InclusiveOrExpression() :
1268 {
1269   String expr;
1270   final StringBuffer buff = new StringBuffer();
1271 }
1272 {
1273   expr = ExclusiveOrExpression()
1274   {buff.append(expr);}
1275   (
1276   <BIT_OR> expr = ExclusiveOrExpression()
1277   {buff.append("|").append(expr);}
1278   )*
1279   {return buff.toString();}
1280 }
1281
1282 String ExclusiveOrExpression() :
1283 {
1284   String expr;
1285   final StringBuffer buff = new StringBuffer();
1286 }
1287 {
1288   expr = AndExpression()
1289   {
1290     buff.append(expr);
1291   }
1292   (
1293     <XOR> expr = AndExpression()
1294   {
1295     buff.append("^");
1296     buff.append(expr);
1297   }
1298   )*
1299   {
1300     return buff.toString();
1301   }
1302 }
1303
1304 String AndExpression() :
1305 {
1306   String expr;
1307   final StringBuffer buff = new StringBuffer();
1308 }
1309 {
1310   expr = EqualityExpression()
1311   {
1312     buff.append(expr);
1313   }
1314   (
1315     <BIT_AND> expr = EqualityExpression()
1316   {
1317     buff.append("&").append(expr);
1318   }
1319   )*
1320   {return buff.toString();}
1321 }
1322
1323 String EqualityExpression() :
1324 {
1325   String expr;
1326   Token operator;
1327   final StringBuffer buff = new StringBuffer();
1328 }
1329 {
1330   expr = RelationalExpression()
1331   {buff.append(expr);}
1332   (
1333   (   operator = <EQ>
1334     | operator = <DIF>
1335     | operator = <NE>
1336     | operator = <BANGDOUBLEEQUAL>
1337     | operator = <TRIPLEEQUAL>
1338   )
1339   try {
1340     expr = RelationalExpression()
1341   } catch (ParseException e) {
1342     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected after '"+operator.image+"'";
1343     errorLevel   = ERROR;
1344     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1345     errorEnd   = jj_input_stream.getPosition() + 1;
1346     throw e;
1347   }
1348   {
1349     buff.append(operator.image);
1350     buff.append(expr);
1351   }
1352   )*
1353   {return buff.toString();}
1354 }
1355
1356 String RelationalExpression() :
1357 {
1358   String expr;
1359   Token operator;
1360   final StringBuffer buff = new StringBuffer();
1361 }
1362 {
1363   expr = ShiftExpression()
1364   {buff.append(expr);}
1365   (
1366   ( operator = <LT> | operator = <GT> | operator = <LE> | operator = <GE> ) expr = ShiftExpression()
1367   {buff.append(operator.image).append(expr);}
1368   )*
1369   {return buff.toString();}
1370 }
1371
1372 String ShiftExpression() :
1373 {
1374   String expr;
1375   Token operator;
1376   final StringBuffer buff = new StringBuffer();
1377 }
1378 {
1379   expr = AdditiveExpression()
1380   {buff.append(expr);}
1381   (
1382   (operator = <LSHIFT> | operator = <RSIGNEDSHIFT> | operator = <RUNSIGNEDSHIFT> ) expr = AdditiveExpression()
1383   {
1384     buff.append(operator.image);
1385     buff.append(expr);
1386   }
1387   )*
1388   {return buff.toString();}
1389 }
1390
1391 String AdditiveExpression() :
1392 {
1393   String expr;
1394   Token operator;
1395   final StringBuffer buff = new StringBuffer();
1396 }
1397 {
1398   expr = MultiplicativeExpression()
1399   {buff.append(expr);}
1400   (
1401    ( operator = <PLUS> | operator = <MINUS> ) expr = MultiplicativeExpression()
1402   {
1403     buff.append(operator.image);
1404     buff.append(expr);
1405   }
1406    )*
1407   {return buff.toString();}
1408 }
1409
1410 String MultiplicativeExpression() :
1411 {
1412   String expr;
1413   Token operator;
1414   final StringBuffer buff = new StringBuffer();}
1415 {
1416   try {
1417     expr = UnaryExpression()
1418   } catch (ParseException e) {
1419     errorMessage = "unexpected token '"+e.currentToken.next.image+"'";
1420     errorLevel   = ERROR;
1421     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1422     errorEnd   = jj_input_stream.getPosition() + 1;
1423     throw e;
1424   }
1425   {buff.append(expr);}
1426   (
1427     ( operator = <STAR> | operator = <SLASH> | operator = <REM> ) expr = UnaryExpression()
1428     {
1429       buff.append(operator.image);
1430       buff.append(expr);
1431     }
1432   )*
1433   {return buff.toString();}
1434 }
1435
1436 /**
1437  * An unary expression starting with @, & or nothing
1438  */
1439 String UnaryExpression() :
1440 {
1441   final String expr;
1442   final Token token;
1443   final StringBuffer buff = new StringBuffer();
1444 }
1445 {
1446   token = <BIT_AND> expr = UnaryExpressionNoPrefix()
1447   {
1448     if (token == null) {
1449       return expr;
1450     }
1451     return token.image + expr;
1452   }
1453 |
1454   (<AT> {buff.append("@");})* expr = UnaryExpressionNoPrefix()
1455   {return buff.append(expr).toString();}
1456 }
1457
1458 String UnaryExpressionNoPrefix() :
1459 {
1460   final String expr;
1461   final Token token;
1462 }
1463 {
1464   ( token = <PLUS> | token = <MINUS> ) expr = UnaryExpression()
1465   {
1466     return token.image + expr;
1467   }
1468 |
1469   expr = PreIncDecExpression()
1470   {return expr;}
1471 |
1472   expr = UnaryExpressionNotPlusMinus()
1473   {return expr;}
1474 }
1475
1476
1477 String PreIncDecExpression() :
1478 {
1479 final String expr;
1480 final Token token;
1481 }
1482 {
1483   (token = <INCR> | token = <DECR>) expr = PrimaryExpression()
1484   {return token.image + expr;}
1485 }
1486
1487 String UnaryExpressionNotPlusMinus() :
1488 {
1489   final String expr;
1490 }
1491 {
1492   <BANG> expr = UnaryExpression()
1493   {return "!" + expr;}
1494 |
1495   LOOKAHEAD( <LPAREN> (Type() | <ARRAY>) <RPAREN> )
1496   expr = CastExpression()
1497   {return expr;}
1498 |
1499   expr = PostfixExpression()
1500   {return expr;}
1501 |
1502   expr = Literal()
1503   {return expr;}
1504 |
1505   <LPAREN> expr = Expression()
1506   try {
1507     <RPAREN>
1508   } catch (ParseException e) {
1509     errorMessage = "')' expected";
1510     errorLevel   = ERROR;
1511     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1512     errorEnd   = jj_input_stream.getPosition() + 1;
1513     throw e;
1514   }
1515   {return "("+expr+")";}
1516 }
1517
1518 String CastExpression() :
1519 {
1520 final String type, expr;
1521 }
1522 {
1523   <LPAREN> (type = Type() | <ARRAY> {type = "array";}) <RPAREN> expr = UnaryExpression()
1524   {return "(" + type + ")" + expr;}
1525 }
1526
1527 String PostfixExpression() :
1528 {
1529   final String expr;
1530   Token operator = null;
1531 }
1532 {
1533   expr = PrimaryExpression() [ operator = <INCR> | operator = <DECR> ]
1534   {
1535     if (operator == null) {
1536       return expr;
1537     }
1538     return expr + operator.image;
1539   }
1540 }
1541
1542 String PrimaryExpression() :
1543 {
1544   final Token identifier;
1545   String expr;
1546   final StringBuffer buff = new StringBuffer();
1547 }
1548 {
1549   LOOKAHEAD(2)
1550   identifier = <IDENTIFIER> <STATICCLASSACCESS> expr = ClassIdentifier()
1551   {buff.append(identifier.image).append("::").append(expr);}
1552   (
1553   expr = PrimarySuffix()
1554   {buff.append(expr);}
1555   )*
1556   {return buff.toString();}
1557 |
1558   expr = PrimaryPrefix()  {buff.append(expr);}
1559   ( expr = PrimarySuffix()  {buff.append(expr);} )*
1560   {return buff.toString();}
1561 |
1562   expr = ArrayDeclarator()
1563   {return "array" + expr;}
1564 }
1565
1566 String ArrayDeclarator() :
1567 {
1568   final String expr;
1569 }
1570 {
1571   <ARRAY> expr = ArrayInitializer()
1572   {return "array" + expr;}
1573 }
1574
1575 String PrimaryPrefix() :
1576 {
1577   final String expr;
1578   final Token token;
1579 }
1580 {
1581   token = <IDENTIFIER>
1582   {return token.image;}
1583 |
1584   <NEW> expr = ClassIdentifier()
1585   {
1586     return "new " + expr;
1587   }
1588 |
1589   expr = VariableDeclaratorId()
1590   {return expr;}
1591 }
1592
1593 String classInstantiation() :
1594 {
1595   String expr;
1596   final StringBuffer buff = new StringBuffer("new ");
1597 }
1598 {
1599   <NEW> expr = ClassIdentifier()
1600   {buff.append(expr);}
1601   [
1602     expr = PrimaryExpression()
1603     {buff.append(expr);}
1604   ]
1605   {return buff.toString();}
1606 }
1607
1608 String ClassIdentifier():
1609 {
1610   final String expr;
1611   final Token token;
1612 }
1613 {
1614   token = <IDENTIFIER>
1615   {return token.image;}
1616 |
1617   expr = VariableDeclaratorId()
1618   {return expr;}
1619 }
1620
1621 String PrimarySuffix() :
1622 {
1623   final String expr;
1624 }
1625 {
1626   expr = Arguments()
1627   {return expr;}
1628 |
1629   expr = VariableSuffix()
1630   {return expr;}
1631 }
1632
1633 String VariableSuffix() :
1634 {
1635   String expr = null;
1636 }
1637 {
1638   <CLASSACCESS>
1639   try {
1640     expr = VariableName()
1641   } catch (ParseException e) {
1642     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function call or field access expected";
1643     errorLevel   = ERROR;
1644     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1645     errorEnd   = jj_input_stream.getPosition() + 1;
1646     throw e;
1647   }
1648   {return "->" + expr;}
1649 |
1650   <LBRACKET> [ expr = Expression() | expr = Type() ]  //Not good
1651   try {
1652     <RBRACKET>
1653   } catch (ParseException e) {
1654     errorMessage = "']' expected";
1655     errorLevel   = ERROR;
1656     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1657     errorEnd   = jj_input_stream.getPosition() + 1;
1658     throw e;
1659   }
1660   {
1661     if(expr == null) {
1662       return "[]";
1663     }
1664     return "[" + expr + "]";
1665   }
1666 }
1667
1668 String Literal() :
1669 {
1670   final String expr;
1671   final Token token;
1672 }
1673 {
1674   token = <INTEGER_LITERAL>
1675   {return token.image;}
1676 |
1677   token = <FLOATING_POINT_LITERAL>
1678   {return token.image;}
1679 |
1680   token = <STRING_LITERAL>
1681   {return token.image;}
1682 |
1683   expr = BooleanLiteral()
1684   {return expr;}
1685 |
1686   <NULL>
1687   {return "null";}
1688 }
1689
1690 String BooleanLiteral() :
1691 {}
1692 {
1693   <TRUE>
1694   {return "true";}
1695 |
1696   <FALSE>
1697   {return "false";}
1698 }
1699
1700 String Arguments() :
1701 {
1702 String expr = null;
1703 }
1704 {
1705   <LPAREN> [ expr = ArgumentList() ]
1706   try {
1707     <RPAREN>
1708   } catch (ParseException e) {
1709     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list";
1710     errorLevel   = ERROR;
1711     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1712     errorEnd   = jj_input_stream.getPosition() + 1;
1713     throw e;
1714   }
1715   {
1716   if (expr == null) {
1717     return "()";
1718   }
1719   return "(" + expr + ")";
1720   }
1721 }
1722
1723 String ArgumentList() :
1724 {
1725 String expr;
1726 final StringBuffer buff = new StringBuffer();
1727 }
1728 {
1729   expr = Expression()
1730   {buff.append(expr);}
1731   ( <COMMA>
1732       try {
1733         expr = Expression()
1734       } catch (ParseException e) {
1735         errorMessage = "expression expected after a comma in argument list";
1736         errorLevel   = ERROR;
1737         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1738         errorEnd   = jj_input_stream.getPosition() + 1;
1739         throw e;
1740       }
1741     {
1742       buff.append(",").append(expr);
1743     }
1744    )*
1745    {return buff.toString();}
1746 }
1747
1748 /**
1749  * A Statement without break
1750  */
1751 void StatementNoBreak() :
1752 {}
1753 {
1754   LOOKAHEAD(2)
1755   Expression()
1756   try {
1757     <SEMICOLON>
1758   } catch (ParseException e) {
1759     if (e.currentToken.next.kind != 4) {
1760       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was 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 |
1768   LOOKAHEAD(2)
1769   LabeledStatement()
1770 |
1771   Block()
1772 |
1773   EmptyStatement()
1774 |
1775   StatementExpression()
1776   try {
1777     <SEMICOLON>
1778   } catch (ParseException e) {
1779     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1780     errorLevel   = ERROR;
1781     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1782     errorEnd   = jj_input_stream.getPosition() + 1;
1783     throw e;
1784   }
1785 |
1786   SwitchStatement()
1787 |
1788   IfStatement()
1789 |
1790   WhileStatement()
1791 |
1792   DoStatement()
1793 |
1794   ForStatement()
1795 |
1796   ForeachStatement()
1797 |
1798   ContinueStatement()
1799 |
1800   ReturnStatement()
1801 |
1802   EchoStatement()
1803 |
1804   [<AT>] IncludeStatement()
1805 |
1806   StaticStatement()
1807 |
1808   GlobalStatement()
1809 }
1810
1811 /**
1812  * A Normal statement
1813  */
1814 void Statement() :
1815 {}
1816 {
1817   StatementNoBreak()
1818 |
1819   BreakStatement()
1820 }
1821
1822 void htmlBlock() :
1823 {}
1824 {
1825   <PHPEND> (phpEchoBlock())* (<PHPSTARTLONG> | <PHPSTARTSHORT>)
1826 }
1827
1828 /**
1829  * An include statement. It's "include" an expression;
1830  */
1831 void IncludeStatement() :
1832 {
1833   final String expr;
1834   final Token token;
1835   final int pos = jj_input_stream.getPosition();
1836 }
1837 {
1838   (  token = <REQUIRE>
1839    | token = <REQUIRE_ONCE>
1840    | token = <INCLUDE>
1841    | token = <INCLUDE_ONCE> )
1842   expr = Expression()
1843   {
1844     if (currentSegment != null) {
1845       currentSegment.add(new PHPReqIncDeclaration(currentSegment, token.image,pos,expr));
1846     }
1847   }
1848   try {
1849     <SEMICOLON>
1850   } catch (ParseException e) {
1851     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1852     errorLevel   = ERROR;
1853     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1854     errorEnd   = jj_input_stream.getPosition() + 1;
1855     throw e;
1856   }
1857 }
1858
1859 String PrintExpression() :
1860 {
1861   final StringBuffer buff = new StringBuffer("print ");
1862   final String expr;
1863 }
1864 {
1865   <PRINT> expr = Expression()
1866   {
1867     buff.append(expr);
1868     return buff.toString();
1869   }
1870 }
1871
1872 String ListExpression() :
1873 {
1874   final StringBuffer buff = new StringBuffer("list(");
1875   String expr;
1876 }
1877 {
1878   <LIST>
1879   try {
1880     <LPAREN>
1881   } catch (ParseException e) {
1882     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
1883     errorLevel   = ERROR;
1884     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1885     errorEnd   = jj_input_stream.getPosition() + 1;
1886     throw e;
1887   }
1888   [
1889     expr = VariableDeclaratorId()
1890     {buff.append(expr);}
1891   ]
1892   (
1893     try {
1894       <COMMA>
1895     } catch (ParseException e) {
1896       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
1897       errorLevel   = ERROR;
1898       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1899       errorEnd   = jj_input_stream.getPosition() + 1;
1900       throw e;
1901     }
1902     expr = VariableDeclaratorId()
1903     {buff.append(",").append(expr);}
1904   )*
1905   {buff.append(")");}
1906   try {
1907     <RPAREN>
1908   } catch (ParseException e) {
1909     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
1910     errorLevel   = ERROR;
1911     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1912     errorEnd   = jj_input_stream.getPosition() + 1;
1913     throw e;
1914   }
1915   [ <ASSIGN> expr = Expression() {buff.append("(").append(expr);}]
1916   {return buff.toString();}
1917 }
1918
1919 /**
1920  * An echo statement is like this : echo anyexpression (, otherexpression)*
1921  */
1922 void EchoStatement() :
1923 {}
1924 {
1925   <ECHO> Expression() (<COMMA> Expression())*
1926   try {
1927     <SEMICOLON>
1928   } catch (ParseException e) {
1929     if (e.currentToken.next.kind != 4) {
1930       errorMessage = "';' expected after 'echo' statement";
1931       errorLevel   = ERROR;
1932       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1933       errorEnd   = jj_input_stream.getPosition() + 1;
1934       throw e;
1935     }
1936   }
1937 }
1938
1939 void GlobalStatement() :
1940 {
1941    final int pos = jj_input_stream.getPosition();
1942    String expr;
1943 }
1944 {
1945   <GLOBAL>
1946     expr = VariableDeclaratorId()
1947     {if (currentSegment != null) {
1948       currentSegment.add(new PHPGlobalDeclaration(currentSegment, "global",pos,expr));
1949     }}
1950   (<COMMA>
1951     expr = VariableDeclaratorId()
1952     {if (currentSegment != null) {
1953       currentSegment.add(new PHPGlobalDeclaration(currentSegment, "global",pos,expr));
1954     }}
1955   )*
1956   try {
1957     <SEMICOLON>
1958   } catch (ParseException e) {
1959     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1960     errorLevel   = ERROR;
1961     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1962     errorEnd   = jj_input_stream.getPosition() + 1;
1963     throw e;
1964   }
1965 }
1966
1967 void StaticStatement() :
1968 {}
1969 {
1970   <STATIC> VariableDeclarator() (<COMMA> VariableDeclarator())*
1971   try {
1972     <SEMICOLON>
1973   } catch (ParseException e) {
1974     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
1975     errorLevel   = ERROR;
1976     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1977     errorEnd   = jj_input_stream.getPosition() + 1;
1978     throw e;
1979   }
1980 }
1981
1982 void LabeledStatement() :
1983 {}
1984 {
1985   <IDENTIFIER> <COLON> Statement()
1986 }
1987
1988 void Block() :
1989 {}
1990 {
1991   try {
1992     <LBRACE>
1993   } catch (ParseException e) {
1994     errorMessage = "'{' expected";
1995     errorLevel   = ERROR;
1996     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
1997     errorEnd   = jj_input_stream.getPosition() + 1;
1998     throw e;
1999   }
2000   ( BlockStatement() | htmlBlock())*
2001   try {
2002     <RBRACE>
2003   } catch (ParseException e) {
2004     errorMessage = "unexpected token : '"+ e.currentToken.image +"', '}' expected";
2005     errorLevel   = ERROR;
2006     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2007     errorEnd   = jj_input_stream.getPosition() + 1;
2008     throw e;
2009   }
2010 }
2011
2012 void BlockStatement() :
2013 {}
2014 {
2015   Statement()
2016 |
2017   ClassDeclaration()
2018 |
2019   MethodDeclaration()
2020 }
2021
2022 /**
2023  * A Block statement that will not contain any 'break'
2024  */
2025 void BlockStatementNoBreak() :
2026 {}
2027 {
2028   StatementNoBreak()
2029 |
2030   ClassDeclaration()
2031 |
2032   MethodDeclaration()
2033 }
2034
2035 void LocalVariableDeclaration() :
2036 {}
2037 {
2038   LocalVariableDeclarator() ( <COMMA> LocalVariableDeclarator() )*
2039 }
2040
2041 void LocalVariableDeclarator() :
2042 {}
2043 {
2044   VariableDeclaratorId() [ <ASSIGN> Expression() ]
2045 }
2046
2047 void EmptyStatement() :
2048 {}
2049 {
2050   <SEMICOLON>
2051 }
2052
2053 void StatementExpression() :
2054 {}
2055 {
2056   PreIncDecExpression()
2057 |
2058   PrimaryExpression()
2059   [
2060    <INCR>
2061   |
2062     <DECR>
2063   |
2064     AssignmentOperator() Expression()
2065   ]
2066 }
2067
2068 void SwitchStatement() :
2069 {
2070   final int pos = jj_input_stream.getPosition();
2071 }
2072 {
2073   <SWITCH>
2074   try {
2075     <LPAREN>
2076   } catch (ParseException e) {
2077     errorMessage = "'(' expected after 'switch'";
2078     errorLevel   = ERROR;
2079     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2080     errorEnd   = jj_input_stream.getPosition() + 1;
2081     throw e;
2082   }
2083   Expression()
2084   try {
2085     <RPAREN>
2086   } catch (ParseException e) {
2087     errorMessage = "')' expected";
2088     errorLevel   = ERROR;
2089     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2090     errorEnd   = jj_input_stream.getPosition() + 1;
2091     throw e;
2092   }
2093   (switchStatementBrace() | switchStatementColon(pos, pos + 6))
2094 }
2095
2096 void switchStatementBrace() :
2097 {}
2098 {
2099   <LBRACE>
2100  ( switchLabel0() )*
2101   try {
2102     <RBRACE>
2103   } catch (ParseException e) {
2104     errorMessage = "'}' expected";
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 }
2111 /**
2112  * A Switch statement with : ... endswitch;
2113  * @param start the begin offset of the switch
2114  * @param end the end offset of the switch
2115  */
2116 void switchStatementColon(final int start, final int end) :
2117 {}
2118 {
2119   <COLON>
2120   {try {
2121   setMarker(fileToParse,
2122             "Ugly syntax detected, you should switch () {...} instead of switch (): ... enswitch;",
2123             start,
2124             end,
2125             INFO,
2126             "Line " + token.beginLine);
2127   } catch (CoreException e) {
2128     PHPeclipsePlugin.log(e);
2129   }}
2130   (switchLabel0())*
2131   try {
2132     <ENDSWITCH>
2133   } catch (ParseException e) {
2134     errorMessage = "'endswitch' expected";
2135     errorLevel   = ERROR;
2136     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2137     errorEnd   = jj_input_stream.getPosition() + 1;
2138     throw e;
2139   }
2140   try {
2141     <SEMICOLON>
2142   } catch (ParseException e) {
2143     errorMessage = "';' expected after 'endswitch' keyword";
2144     errorLevel   = ERROR;
2145     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2146     errorEnd   = jj_input_stream.getPosition() + 1;
2147     throw e;
2148   }
2149 }
2150
2151 void switchLabel0() :
2152 {
2153   Token breakToken = null;
2154   final int line;
2155 }
2156 {
2157   line = SwitchLabel()
2158   ( BlockStatementNoBreak() | htmlBlock() )*
2159   [ breakToken = BreakStatement() ]
2160   {
2161     try {
2162       if (breakToken == null) {
2163         setMarker(fileToParse,
2164                   "You should use put a 'break' at the end of your statement",
2165                   line,
2166                   INFO,
2167                   "Line " + line);
2168       }
2169     } catch (CoreException e) {
2170       PHPeclipsePlugin.log(e);
2171     }
2172   }
2173 }
2174
2175 Token BreakStatement() :
2176 {
2177   final Token token;
2178 }
2179 {
2180   token = <BREAK> [ Expression() ]
2181   try {
2182     <SEMICOLON>
2183   } catch (ParseException e) {
2184     errorMessage = "';' expected after 'break' keyword";
2185     errorLevel   = ERROR;
2186     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2187     errorEnd   = jj_input_stream.getPosition() + 1;
2188     throw e;
2189   }
2190   {return token;}
2191 }
2192
2193 int SwitchLabel() :
2194 {
2195   final Token token;
2196 }
2197 {
2198   token = <CASE>
2199   try {
2200     Expression()
2201   } catch (ParseException e) {
2202     if (errorMessage != null) throw e;
2203     errorMessage = "expression expected after 'case' keyword";
2204     errorLevel   = ERROR;
2205     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2206     errorEnd   = jj_input_stream.getPosition() + 1;
2207     throw e;
2208   }
2209   try {
2210     <COLON>
2211   } catch (ParseException e) {
2212     errorMessage = "':' expected after case expression";
2213     errorLevel   = ERROR;
2214     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2215     errorEnd   = jj_input_stream.getPosition() + 1;
2216     throw e;
2217   }
2218   {return token.beginLine;}
2219 |
2220   token = <_DEFAULT>
2221   try {
2222     <COLON>
2223   } catch (ParseException e) {
2224     errorMessage = "':' expected after 'default' keyword";
2225     errorLevel   = ERROR;
2226     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2227     errorEnd   = jj_input_stream.getPosition() + 1;
2228     throw e;
2229   }
2230   {return token.beginLine;}
2231 }
2232
2233 void IfStatement() :
2234 {
2235   final Token token;
2236   final int pos = jj_input_stream.getPosition();
2237 }
2238 {
2239   token = <IF> Condition("if") IfStatement0(pos,pos+token.image.length())
2240 }
2241
2242 void Condition(final String keyword) :
2243 {}
2244 {
2245   try {
2246     <LPAREN>
2247   } catch (ParseException e) {
2248     errorMessage = "'(' expected after " + keyword + " keyword";
2249     errorLevel   = ERROR;
2250     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length();
2251     errorEnd   = errorStart +1;
2252     processParseException(e);
2253   }
2254   Expression()
2255   try {
2256      <RPAREN>
2257   } catch (ParseException e) {
2258     errorMessage = "')' expected after " + keyword + " keyword";
2259     errorLevel   = ERROR;
2260     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2261     errorEnd   = jj_input_stream.getPosition() + 1;
2262     throw e;
2263   }
2264 }
2265
2266 void IfStatement0(final int start,final int end) :
2267 {}
2268 {
2269   <COLON> (Statement() | htmlBlock())* (ElseIfStatementColon())* [ElseStatementColon()]
2270
2271   {try {
2272   setMarker(fileToParse,
2273             "Ugly syntax detected, you should if () {...} instead of if (): ... endif;",
2274             start,
2275             end,
2276             INFO,
2277             "Line " + token.beginLine);
2278   } catch (CoreException e) {
2279     PHPeclipsePlugin.log(e);
2280   }}
2281   try {
2282     <ENDIF>
2283   } catch (ParseException e) {
2284     errorMessage = "'endif' expected";
2285     errorLevel   = ERROR;
2286     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2287     errorEnd   = jj_input_stream.getPosition() + 1;
2288     throw e;
2289   }
2290   try {
2291     <SEMICOLON>
2292   } catch (ParseException e) {
2293     errorMessage = "';' expected after 'endif' keyword";
2294     errorLevel   = ERROR;
2295     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2296     errorEnd   = jj_input_stream.getPosition() + 1;
2297     throw e;
2298   }
2299 |
2300   (Statement() |  htmlBlock())
2301   ( LOOKAHEAD(1) ElseIfStatement() )*
2302   [ LOOKAHEAD(1)
2303     <ELSE>
2304     try {
2305       Statement()
2306     } catch (ParseException e) {
2307       if (errorMessage != null) {
2308         throw e;
2309       }
2310       errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected";
2311       errorLevel   = ERROR;
2312       errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2313       errorEnd   = jj_input_stream.getPosition() + 1;
2314       throw e;
2315     }
2316   ]
2317 }
2318
2319 void ElseIfStatementColon() :
2320 {}
2321 {
2322   <ELSEIF> Condition("elseif") <COLON> (Statement() | htmlBlock())*
2323 }
2324
2325 void ElseStatementColon() :
2326 {}
2327 {
2328   <ELSE> <COLON> (Statement() | htmlBlock())*
2329 }
2330
2331 void ElseIfStatement() :
2332 {}
2333 {
2334   <ELSEIF> Condition("elseif") Statement()
2335 }
2336
2337 void WhileStatement() :
2338 {
2339   final Token token;
2340   final int pos = jj_input_stream.getPosition();
2341 }
2342 {
2343   token = <WHILE> Condition("while") WhileStatement0(pos,pos + token.image.length())
2344 }
2345
2346 void WhileStatement0(final int start, final int end) :
2347 {}
2348 {
2349   <COLON> (Statement())*
2350   {try {
2351   setMarker(fileToParse,
2352             "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;",
2353             start,
2354             end,
2355             INFO,
2356             "Line " + token.beginLine);
2357   } catch (CoreException e) {
2358     PHPeclipsePlugin.log(e);
2359   }}
2360   try {
2361     <ENDWHILE>
2362   } catch (ParseException e) {
2363     errorMessage = "'endwhile' expected";
2364     errorLevel   = ERROR;
2365     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2366     errorEnd   = jj_input_stream.getPosition() + 1;
2367     throw e;
2368   }
2369   try {
2370     <SEMICOLON>
2371   } catch (ParseException e) {
2372     errorMessage = "';' expected after 'endwhile' keyword";
2373     errorLevel   = ERROR;
2374     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2375     errorEnd   = jj_input_stream.getPosition() + 1;
2376     throw e;
2377   }
2378 |
2379   Statement()
2380 }
2381
2382 void DoStatement() :
2383 {}
2384 {
2385   <DO> Statement() <WHILE> Condition("while")
2386   try {
2387     <SEMICOLON>
2388   } catch (ParseException e) {
2389     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2390     errorLevel   = ERROR;
2391     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2392     errorEnd   = jj_input_stream.getPosition() + 1;
2393     throw e;
2394   }
2395 }
2396
2397 void ForeachStatement() :
2398 {}
2399 {
2400   <FOREACH>
2401     try {
2402     <LPAREN>
2403   } catch (ParseException e) {
2404     errorMessage = "'(' expected after 'foreach' keyword";
2405     errorLevel   = ERROR;
2406     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2407     errorEnd   = jj_input_stream.getPosition() + 1;
2408     throw e;
2409   }
2410   try {
2411     Variable()
2412   } catch (ParseException e) {
2413     errorMessage = "variable expected";
2414     errorLevel   = ERROR;
2415     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2416     errorEnd   = jj_input_stream.getPosition() + 1;
2417     throw e;
2418   }
2419   ( VariableSuffix() )*
2420   try {
2421     <AS>
2422   } catch (ParseException e) {
2423     errorMessage = "'as' expected";
2424     errorLevel   = ERROR;
2425     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2426     errorEnd   = jj_input_stream.getPosition() + 1;
2427     throw e;
2428   }
2429   try {
2430     Variable()
2431   } catch (ParseException e) {
2432     errorMessage = "variable expected";
2433     errorLevel   = ERROR;
2434     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2435     errorEnd   = jj_input_stream.getPosition() + 1;
2436     throw e;
2437   }
2438   [ <ARRAYASSIGN> Expression() ]
2439   try {
2440     <RPAREN>
2441   } catch (ParseException e) {
2442     errorMessage = "')' expected after 'foreach' keyword";
2443     errorLevel   = ERROR;
2444     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2445     errorEnd   = jj_input_stream.getPosition() + 1;
2446     throw e;
2447   }
2448   try {
2449     Statement()
2450   } catch (ParseException e) {
2451     if (errorMessage != null) throw e;
2452     errorMessage = "statement expected";
2453     errorLevel   = ERROR;
2454     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2455     errorEnd   = jj_input_stream.getPosition() + 1;
2456     throw e;
2457   }
2458 }
2459
2460 void ForStatement() :
2461 {
2462 final Token token;
2463 final int pos = jj_input_stream.getPosition();
2464 }
2465 {
2466   token = <FOR>
2467   try {
2468     <LPAREN>
2469   } catch (ParseException e) {
2470     errorMessage = "'(' expected after 'for' keyword";
2471     errorLevel   = ERROR;
2472     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2473     errorEnd   = jj_input_stream.getPosition() + 1;
2474     throw e;
2475   }
2476      [ ForInit() ] <SEMICOLON> [ Expression() ] <SEMICOLON> [ StatementExpressionList() ] <RPAREN>
2477     (
2478       Statement()
2479     |
2480       <COLON> (Statement())*
2481       {
2482         try {
2483         setMarker(fileToParse,
2484                   "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;",
2485                   pos,
2486                   pos+token.image.length(),
2487                   INFO,
2488                   "Line " + token.beginLine);
2489         } catch (CoreException e) {
2490           PHPeclipsePlugin.log(e);
2491         }
2492       }
2493       try {
2494         <ENDFOR>
2495       } catch (ParseException e) {
2496         errorMessage = "'endfor' expected";
2497         errorLevel   = ERROR;
2498         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2499         errorEnd   = jj_input_stream.getPosition() + 1;
2500         throw e;
2501       }
2502       try {
2503         <SEMICOLON>
2504       } catch (ParseException e) {
2505         errorMessage = "';' expected after 'endfor' keyword";
2506         errorLevel   = ERROR;
2507         errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2508         errorEnd   = jj_input_stream.getPosition() + 1;
2509         throw e;
2510       }
2511     )
2512 }
2513
2514 void ForInit() :
2515 {}
2516 {
2517   LOOKAHEAD(LocalVariableDeclaration())
2518   LocalVariableDeclaration()
2519 |
2520   StatementExpressionList()
2521 }
2522
2523 void StatementExpressionList() :
2524 {}
2525 {
2526   StatementExpression() ( <COMMA> StatementExpression() )*
2527 }
2528
2529 void ContinueStatement() :
2530 {}
2531 {
2532   <CONTINUE> [ Expression() ]
2533   try {
2534     <SEMICOLON>
2535   } catch (ParseException e) {
2536     errorMessage = "';' expected after 'continue' statement";
2537     errorLevel   = ERROR;
2538     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2539     errorEnd   = jj_input_stream.getPosition() + 1;
2540     throw e;
2541   }
2542 }
2543
2544 void ReturnStatement() :
2545 {}
2546 {
2547   <RETURN> [ Expression() ]
2548   try {
2549     <SEMICOLON>
2550   } catch (ParseException e) {
2551     errorMessage = "';' expected after 'return' statement";
2552     errorLevel   = ERROR;
2553     errorStart = jj_input_stream.getPosition() - e.currentToken.next.image.length() + 1;
2554     errorEnd   = jj_input_stream.getPosition() + 1;
2555     throw e;
2556   }
2557 }