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