initial nl support for phphelp plugin
[phpeclipse.git] / net.sourceforge.phpeclipse / src / test / PHPParser.jj
1
2 options {
3   LOOKAHEAD = 1;
4   CHOICE_AMBIGUITY_CHECK = 2;
5   OTHER_AMBIGUITY_CHECK = 1;
6   STATIC = true;
7   DEBUG_PARSER = false;
8   DEBUG_LOOKAHEAD = false;
9   DEBUG_TOKEN_MANAGER = false;
10   OPTIMIZE_TOKEN_MANAGER = false;
11   ERROR_REPORTING = true;
12   JAVA_UNICODE_ESCAPE = false;
13   UNICODE_INPUT = false;
14   IGNORE_CASE = true;
15   USER_TOKEN_MANAGER = false;
16   USER_CHAR_STREAM = false;
17   BUILD_PARSER = true;
18   BUILD_TOKEN_MANAGER = true;
19   SANITY_CHECK = true;
20   FORCE_LA_CHECK = false;
21   COMMON_TOKEN_ACTION = true;
22 }
23
24 PARSER_BEGIN(PHPParser)
25 package test;
26
27 import org.eclipse.core.resources.IFile;
28 import org.eclipse.core.resources.IMarker;
29 import org.eclipse.core.runtime.CoreException;
30 import org.eclipse.ui.texteditor.MarkerUtilities;
31 import org.eclipse.jface.preference.IPreferenceStore;
32
33 import java.util.Hashtable;
34 import java.util.ArrayList;
35 import java.io.StringReader;
36 import java.io.*;
37 import java.text.MessageFormat;
38
39 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
40 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
41 import net.sourceforge.phpdt.internal.compiler.ast.*;
42 import net.sourceforge.phpdt.internal.compiler.parser.OutlineableWithChildren;
43 import net.sourceforge.phpdt.internal.compiler.parser.Outlineable;
44 import net.sourceforge.phpdt.internal.compiler.parser.PHPOutlineInfo;
45 import net.sourceforge.phpdt.internal.corext.Assert;
46
47 /**
48  * A new php parser.
49  * This php parser is inspired by the Java 1.2 grammar example
50  * given with JavaCC. You can get JavaCC at http://www.webgain.com
51  * You can test the parser with the PHPParserTestCase2.java
52  * @author Matthieu Casanova
53  */
54 public final class PHPParser extends PHPParserSuperclass {
55
56 //todo : fix the variables names bug
57 //todo : handle tilde operator
58
59
60   /** The current segment. */
61   private static OutlineableWithChildren currentSegment;
62
63   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
64   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
65   static PHPOutlineInfo outlineInfo;
66
67   /** The error level of the current ParseException. */
68   private static int errorLevel = ERROR;
69   /** The message of the current ParseException. If it's null it's because the parse exception wasn't handled */
70   private static String errorMessage;
71
72   private static int errorStart = -1;
73   private static int errorEnd = -1;
74   private static PHPDocument phpDocument;
75
76   private static final String SYNTAX_ERROR_CHAR = "syntax error";
77   /**
78    * The point where html starts.
79    * It will be used by the token manager to create HTMLCode objects
80    */
81   public static int htmlStart;
82
83   //ast stack
84   private final static int AstStackIncrement = 100;
85   /** The stack of node. */
86   private static AstNode[] nodes;
87   /** The cursor in expression stack. */
88   private static int nodePtr;
89
90   public static final boolean PARSER_DEBUG = false;
91
92   public final void setFileToParse(final IFile fileToParse) {
93     PHPParser.fileToParse = fileToParse;
94   }
95
96   public PHPParser() {
97   }
98
99   public PHPParser(final IFile fileToParse) {
100     this(new StringReader(""));
101     PHPParser.fileToParse = fileToParse;
102   }
103
104   public static final void phpParserTester(final String strEval) throws ParseException {
105     final StringReader stream = new StringReader(strEval);
106     if (jj_input_stream == null) {
107       jj_input_stream = new SimpleCharStream(stream, 1, 1);
108     }
109     ReInit(new StringReader(strEval));
110     init();
111     phpDocument = new PHPDocument(null,"_root".toCharArray());
112     currentSegment = phpDocument;
113     outlineInfo = new PHPOutlineInfo(null, currentSegment);
114     PHPParserTokenManager.SwitchTo(PHPParserTokenManager.PHPPARSING);
115     phpTest();
116   }
117
118   public static final void htmlParserTester(final File fileName) throws FileNotFoundException, ParseException {
119     final Reader stream = new FileReader(fileName);
120     if (jj_input_stream == null) {
121       jj_input_stream = new SimpleCharStream(stream, 1, 1);
122     }
123     ReInit(stream);
124     init();
125     phpDocument = new PHPDocument(null,"_root".toCharArray());
126     currentSegment = phpDocument;
127     outlineInfo = new PHPOutlineInfo(null, currentSegment);
128     phpFile();
129   }
130
131   public static final void htmlParserTester(final String strEval) throws ParseException {
132     final StringReader stream = new StringReader(strEval);
133     if (jj_input_stream == null) {
134       jj_input_stream = new SimpleCharStream(stream, 1, 1);
135     }
136     ReInit(stream);
137     init();
138     phpDocument = new PHPDocument(null,"_root".toCharArray());
139     currentSegment = phpDocument;
140     outlineInfo = new PHPOutlineInfo(null, currentSegment);
141     phpFile();
142   }
143
144   /**
145    * Reinitialize the parser.
146    */
147   private static final void init() {
148     nodes = new AstNode[AstStackIncrement];
149     nodePtr = -1;
150     htmlStart = 0;
151   }
152
153   /**
154    * Add an php node on the stack.
155    * @param node the node that will be added to the stack
156    */
157   private static final void pushOnAstNodes(final AstNode node) {
158     try {
159       nodes[++nodePtr] = node;
160     } catch (IndexOutOfBoundsException e) {
161       final int oldStackLength = nodes.length;
162       final AstNode[] oldStack = nodes;
163       nodes = new AstNode[oldStackLength + AstStackIncrement];
164       System.arraycopy(oldStack, 0, nodes, 0, oldStackLength);
165       nodePtr = oldStackLength;
166       nodes[nodePtr] = node;
167     }
168   }
169
170   public final PHPOutlineInfo parseInfo(final Object parent, final String s) {
171     phpDocument = new PHPDocument(parent,"_root".toCharArray());
172     currentSegment = phpDocument;
173     outlineInfo = new PHPOutlineInfo(parent, currentSegment);
174     final StringReader stream = new StringReader(s);
175     if (jj_input_stream == null) {
176       jj_input_stream = new SimpleCharStream(stream, 1, 1);
177     }
178     ReInit(stream);
179     init();
180     try {
181       parse();
182       phpDocument.nodes = new AstNode[nodes.length];
183       System.arraycopy(nodes,0,phpDocument.nodes,0,nodes.length);
184       if (PHPeclipsePlugin.DEBUG) {
185         PHPeclipsePlugin.log(1,phpDocument.toString());
186       }
187     } catch (ParseException e) {
188       processParseException(e);
189     }
190     return outlineInfo;
191   }
192
193   /**
194    * This function will throw the exception if we are in debug mode
195    * and process it if we are in production mode.
196    * this should be fast since the PARSER_DEBUG is static final so the difference will be at compile time
197    * @param e the exception
198    * @throws ParseException the thrown exception
199    */
200   private static void processParseExceptionDebug(final ParseException e) throws ParseException {
201     if (PARSER_DEBUG) {
202       throw e;
203     }
204     processParseException(e);
205   }
206   /**
207    * This method will process the parse exception.
208    * If the error message is null, the parse exception wasn't catched and a trace is written in the log
209    * @param e the ParseException
210    */
211   private static void processParseException(final ParseException e) {
212     if (errorMessage == null) {
213       PHPeclipsePlugin.log(e);
214       errorMessage = "this exception wasn't handled by the parser please tell us how to reproduce it";
215       errorStart = e.currentToken.sourceStart;
216       errorEnd   = e.currentToken.sourceEnd;
217     }
218     setMarker(e);
219     errorMessage = null;
220   //  if (PHPeclipsePlugin.DEBUG) PHPeclipsePlugin.log(e);
221   }
222
223   /**
224    * Create marker for the parse error.
225    * @param e the ParseException
226    */
227   private static void setMarker(final ParseException e) {
228     try {
229       if (errorStart == -1) {
230         setMarker(fileToParse,
231                   errorMessage,
232                   e.currentToken.sourceStart,
233                   e.currentToken.sourceEnd,
234                   errorLevel,
235                   "Line " + e.currentToken.beginLine+", "+e.currentToken.sourceStart+':'+e.currentToken.sourceEnd);
236       } else {
237         setMarker(fileToParse,
238                   errorMessage,
239                   errorStart,
240                   errorEnd,
241                   errorLevel,
242                   "Line " + e.currentToken.beginLine+", "+errorStart+':'+errorEnd);
243         errorStart = -1;
244         errorEnd = -1;
245       }
246     } catch (CoreException e2) {
247       PHPeclipsePlugin.log(e2);
248     }
249   }
250
251   private static void scanLine(final String output,
252                                final IFile file,
253                                final int indx,
254                                final int brIndx) throws CoreException {
255     String current;
256     final StringBuffer lineNumberBuffer = new StringBuffer(10);
257     char ch;
258     current = output.substring(indx, brIndx);
259
260     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
261       final int onLine = current.indexOf("on line <b>");
262       if (onLine != -1) {
263         lineNumberBuffer.delete(0, lineNumberBuffer.length());
264         for (int i = onLine; i < current.length(); i++) {
265           ch = current.charAt(i);
266           if ('0' <= ch && '9' >= ch) {
267             lineNumberBuffer.append(ch);
268           }
269         }
270
271         final int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
272
273         final Hashtable attributes = new Hashtable();
274
275         current = current.replaceAll("\n", "");
276         current = current.replaceAll("<b>", "");
277         current = current.replaceAll("</b>", "");
278         MarkerUtilities.setMessage(attributes, current);
279
280         if (current.indexOf(PARSE_ERROR_STRING) != -1)
281           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
282         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
283           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
284         else
285           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
286         MarkerUtilities.setLineNumber(attributes, lineNumber);
287         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
288       }
289     }
290   }
291
292   public final void parse(final String s) {
293     final StringReader stream = new StringReader(s);
294     if (jj_input_stream == null) {
295       jj_input_stream = new SimpleCharStream(stream, 1, 1);
296     }
297     ReInit(stream);
298     init();
299     try {
300       parse();
301     } catch (ParseException e) {
302       processParseException(e);
303     }
304   }
305
306   /**
307    * Call the php parse command ( php -l -f &lt;filename&gt; )
308    * and create markers according to the external parser output
309    */
310   public static void phpExternalParse(final IFile file) {
311     final IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
312     final String filename = file.getLocation().toString();
313
314     final String[] arguments = { filename };
315     final MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
316     final String command = form.format(arguments);
317
318     final String parserResult = PHPStartApacheAction.getParserOutput(command, "External parser: ");
319
320     try {
321       // parse the buffer to find the errors and warnings
322       createMarkers(parserResult, file);
323     } catch (CoreException e) {
324       PHPeclipsePlugin.log(e);
325     }
326   }
327
328   /**
329    * Put a new html block in the stack.
330    */
331   public static final void createNewHTMLCode() {
332     final int currentPosition = token.sourceStart;
333     if (currentPosition == htmlStart ||
334           currentPosition < htmlStart ||
335           currentPosition > SimpleCharStream.currentBuffer.length()) {
336       return;
337     }
338     final String html = SimpleCharStream.currentBuffer.substring(htmlStart, currentPosition);
339     pushOnAstNodes(new HTMLCode(html, htmlStart,currentPosition));
340   }
341
342   /** Create a new task. */
343   public static final void createNewTask(final int todoStart) {
344     final String  todo = SimpleCharStream.currentBuffer.substring(todoStart,
345                                                                   SimpleCharStream.currentBuffer.indexOf("\n",
346                                                                                                          todoStart)-1);
347     if (!PARSER_DEBUG) {
348       try {
349         setMarker(fileToParse,
350                   todo,
351                   SimpleCharStream.getBeginLine(),
352                   TASK,
353                   "Line "+SimpleCharStream.getBeginLine());
354       } catch (CoreException e) {
355         PHPeclipsePlugin.log(e);
356       }
357     }
358   }
359
360   private static final void parse() throws ParseException {
361           phpFile();
362   }
363 }
364
365 PARSER_END(PHPParser)
366
367 TOKEN_MGR_DECLS:
368 {
369   // CommonTokenAction: use the begins/ends fields added to the Jack
370   // CharStream class to set corresponding fields in each Token (which was
371   // also extended with new fields). By default Jack doesn't supply absolute
372   // offsets, just line/column offsets
373   static void CommonTokenAction(Token t) {
374     t.sourceStart = input_stream.beginOffset;
375     t.sourceEnd = input_stream.endOffset;
376   } // CommonTokenAction
377 } // TOKEN_MGR_DECLS
378
379 <DEFAULT> TOKEN :
380 {
381   <PHPSTARTSHORT : "<?">    : PHPPARSING
382 | <PHPSTARTLONG  : "<?php"> : PHPPARSING
383 | <PHPECHOSTART  : "<?=">   : PHPPARSING
384 }
385
386 <PHPPARSING, IN_SINGLE_LINE_COMMENT,IN_VARIABLE> TOKEN :
387 {
388   <PHPEND :"?>"> : DEFAULT
389 }
390
391 /* Skip any character if we are not in php mode */
392 <DEFAULT> SKIP :
393 {
394  < ~[] >
395 }
396
397
398 /* WHITE SPACE */
399 <PHPPARSING> SKIP :
400 {
401   " "
402 | "\t"
403 | "\n"
404 | "\r"
405 | "\f"
406 }
407
408 <IN_VARIABLE> SPECIAL_TOKEN :
409 {
410   " " : PHPPARSING
411 | "\t" : PHPPARSING
412 | "\n" : PHPPARSING
413 | "\r" : PHPPARSING
414 | "\f" : PHPPARSING
415 }
416 /* COMMENTS */
417 <PHPPARSING> SPECIAL_TOKEN :
418 {
419   "//" : IN_SINGLE_LINE_COMMENT
420 | "#"  : IN_SINGLE_LINE_COMMENT
421 | <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
422 | "/*" : IN_MULTI_LINE_COMMENT
423 }
424
425 <IN_SINGLE_LINE_COMMENT> SPECIAL_TOKEN :
426 {
427   <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : PHPPARSING
428 | < ~[] >
429 }
430
431 <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT> SPECIAL_TOKEN :
432 {
433  "todo"
434 }
435
436 void todo() :
437 {Token todoToken;}
438 {
439   todoToken = "TODO" {createNewTask(todoToken.sourceStart);}
440 }
441 <IN_FORMAL_COMMENT> SPECIAL_TOKEN :
442 {
443   "*/" : PHPPARSING
444 }
445
446 <IN_MULTI_LINE_COMMENT> SPECIAL_TOKEN :
447 {
448   "*/" : PHPPARSING
449 }
450
451 <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
452 MORE :
453 {
454   < ~[] >
455 }
456
457 /* KEYWORDS */
458 <PHPPARSING> TOKEN :
459 {
460   <CLASS    : "class">
461 | <FUNCTION : "function">
462 | <VAR      : "var">
463 | <IF       : "if">
464 | <ELSEIF   : "elseif">
465 | <ELSE     : "else">
466 | <ARRAY    : "array">
467 | <BREAK    : "break">
468 | <LIST     : "list">
469 }
470
471 /* LANGUAGE CONSTRUCT */
472 <PHPPARSING> TOKEN :
473 {
474   <PRINT              : "print">
475 | <ECHO               : "echo">
476 | <INCLUDE            : "include">
477 | <REQUIRE            : "require">
478 | <INCLUDE_ONCE       : "include_once">
479 | <REQUIRE_ONCE       : "require_once">
480 | <GLOBAL             : "global">
481 | <DEFINE             : "define">
482 | <STATIC             : "static">
483 }
484
485 <PHPPARSING,IN_VARIABLE> TOKEN :
486 {
487   <CLASSACCESS        : "->"> : PHPPARSING
488 | <STATICCLASSACCESS  : "::"> : PHPPARSING
489 | <ARRAYASSIGN        : "=>"> : PHPPARSING
490 }
491
492 /* RESERVED WORDS AND LITERALS */
493
494 <PHPPARSING> TOKEN :
495 {
496   <CASE     : "case">
497 | <CONST    : "const">
498 | <CONTINUE : "continue">
499 | <_DEFAULT : "default">
500 | <DO       : "do">
501 | <EXTENDS  : "extends">
502 | <FOR      : "for">
503 | <GOTO     : "goto">
504 | <NEW      : "new">
505 | <NULL     : "null">
506 | <RETURN   : "return">
507 | <SUPER    : "super">
508 | <SWITCH   : "switch">
509 | <THIS     : "this">
510 | <TRUE     : "true">
511 | <FALSE    : "false">
512 | <WHILE    : "while">
513 | <ENDWHILE : "endwhile">
514 | <ENDSWITCH: "endswitch">
515 | <ENDIF    : "endif">
516 | <ENDFOR   : "endfor">
517 | <FOREACH  : "foreach">
518 | <AS       : "as" >
519 }
520
521 /* TYPES */
522 <PHPPARSING> TOKEN :
523 {
524   <STRING  : "string">
525 | <OBJECT  : "object">
526 | <BOOL    : "bool">
527 | <BOOLEAN : "boolean">
528 | <REAL    : "real">
529 | <DOUBLE  : "double">
530 | <FLOAT   : "float">
531 | <INT     : "int">
532 | <INTEGER : "integer">
533 }
534
535 //Misc token
536 <PHPPARSING,IN_VARIABLE> TOKEN :
537 {
538   <AT                 : "@"> : PHPPARSING
539 | <BANG               : "!"> : PHPPARSING
540 | <TILDE              : "~"> : PHPPARSING
541 | <HOOK               : "?"> : PHPPARSING
542 | <COLON              : ":"> : PHPPARSING
543 }
544
545 /* OPERATORS */
546 <PHPPARSING,IN_VARIABLE> TOKEN :
547 {
548   <OR_OR              : "||"> : PHPPARSING
549 | <AND_AND            : "&&"> : PHPPARSING
550 | <PLUS_PLUS          : "++"> : PHPPARSING
551 | <MINUS_MINUS        : "--"> : PHPPARSING
552 | <PLUS               : "+"> : PHPPARSING
553 | <MINUS              : "-"> : PHPPARSING
554 | <STAR               : "*"> : PHPPARSING
555 | <SLASH              : "/"> : PHPPARSING
556 | <BIT_AND            : "&"> : PHPPARSING
557 | <BIT_OR             : "|"> : PHPPARSING
558 | <XOR                : "^"> : PHPPARSING
559 | <REMAINDER          : "%">  : PHPPARSING
560 | <LSHIFT             : "<<"> : PHPPARSING
561 | <RSIGNEDSHIFT       : ">>"> : PHPPARSING
562 | <RUNSIGNEDSHIFT     : ">>>"> : PHPPARSING
563 | <_ORL               : "OR"> : PHPPARSING
564 | <_ANDL              : "AND"> : PHPPARSING
565 }
566
567 /* LITERALS */
568 <PHPPARSING> TOKEN :
569 {
570   <INTEGER_LITERAL:
571         <DECIMAL_LITERAL> (["l","L"])?
572       | <HEX_LITERAL> (["l","L"])?
573       | <OCTAL_LITERAL> (["l","L"])?
574   >
575 |
576   <#DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
577 |
578   <#HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
579 |
580   <#OCTAL_LITERAL: "0" (["0"-"7"])* >
581 |
582   <FLOATING_POINT_LITERAL:
583         (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
584       | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
585       | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
586       | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
587   >
588 |
589   <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
590 |
591   <STRING_LITERAL: (<STRING_2> | <STRING_3>)>
592 //|   <STRING_1: "\"" ( ~["\"","\\"] | "\\" ~[] )* "\"">
593 |   <STRING_2: "'"  ( ~["'","\\"]  | "\\" ~[] )* "'">
594 |   <STRING_3: "`"  ( ~["`","\\"]  | "\\" ~[] )* "`">
595 }
596
597 <IN_STRING,DOLLAR_IN_STRING> SKIP :
598 {
599   <ESCAPED : ("\\" ~[])> : IN_STRING
600 }
601
602 <PHPPARSING> TOKEN :
603 {
604   <DOUBLEQUOTE : "\""> : IN_STRING
605 }
606
607
608 <IN_STRING> TOKEN :
609 {
610   <DOLLARS : "$"> : DOLLAR_IN_STRING
611 }
612
613 <IN_STRING,DOLLAR_IN_STRING> TOKEN :
614 {
615   <DOUBLEQUOTE2 : "\""> : PHPPARSING
616 }
617
618 <DOLLAR_IN_STRING> TOKEN :
619 {
620   <LBRACE1 : "{"> : DOLLAR_IN_STRING_EXPR
621 }
622
623 <IN_STRING> SPECIAL_TOKEN :
624 {
625     <"{"> : SKIPSTRING
626 }
627
628 <SKIPSTRING> SPECIAL_TOKEN :
629 {
630     <"}"> : IN_STRING
631 }
632
633 <SKIPSTRING> SKIP :
634 {
635     <~[]>
636 }
637
638 <DOLLAR_IN_STRING_EXPR> TOKEN :
639 {
640   <RBRACE1 : "}"> : DOLLAR_IN_STRING
641 }
642
643 <DOLLAR_IN_STRING_EXPR> TOKEN :
644 {
645   <ID : (~["}"])*>
646 }
647
648 <IN_STRING> SKIP :
649 {
650   <~[]>
651 }
652
653 <DOLLAR_IN_STRING_EXPR,IN_STRING> SKIP :
654 {
655   <~[]>
656 }
657 /* IDENTIFIERS */
658
659
660 <PHPPARSING,IN_VARIABLE> TOKEN : {<DOLLAR : "$"> : IN_VARIABLE}
661
662
663 <PHPPARSING, IN_VARIABLE, DOLLAR_IN_STRING> TOKEN :
664 {
665   <IDENTIFIER: (<LETTER>|<SPECIAL>) (<LETTER>|<DIGIT>|<SPECIAL>)* >
666 |
667   < #LETTER:
668       ["a"-"z"] | ["A"-"Z"]
669   >
670 |
671   < #DIGIT:
672       ["0"-"9"]
673   >
674 |
675   < #SPECIAL:
676     "_" | ["\u007f"-"\u00ff"]
677   >
678 }
679
680 <DOLLAR_IN_STRING> SPECIAL_TOKEN :
681 {
682  < ~[] > : IN_STRING
683 }
684 /* SEPARATORS */
685
686 <PHPPARSING,IN_VARIABLE> TOKEN :
687 {
688   <LPAREN    : "("> : PHPPARSING
689 | <RPAREN    : ")"> : PHPPARSING
690 | <LBRACE    : "{"> : PHPPARSING
691 | <RBRACE    : "}"> : PHPPARSING
692 | <LBRACKET  : "["> : PHPPARSING
693 | <RBRACKET  : "]"> : PHPPARSING
694 | <SEMICOLON : ";"> : PHPPARSING
695 | <COMMA     : ","> : PHPPARSING
696 | <DOT       : "."> : PHPPARSING
697 }
698
699
700 /* COMPARATOR */
701 <PHPPARSING,IN_VARIABLE> TOKEN :
702 {
703   <GT                 : ">"> : PHPPARSING
704 | <LT                 : "<"> : PHPPARSING
705 | <EQUAL_EQUAL        : "=="> : PHPPARSING
706 | <LE                 : "<="> : PHPPARSING
707 | <GE                 : ">="> : PHPPARSING
708 | <NOT_EQUAL          : "!="> : PHPPARSING
709 | <DIF                : "<>"> : PHPPARSING
710 | <BANGDOUBLEEQUAL    : "!=="> : PHPPARSING
711 | <TRIPLEEQUAL        : "==="> : PHPPARSING
712 }
713
714 /* ASSIGNATION */
715 <PHPPARSING,IN_VARIABLE> TOKEN :
716 {
717   <ASSIGN             : "="> : PHPPARSING
718 | <PLUSASSIGN         : "+="> : PHPPARSING
719 | <MINUSASSIGN        : "-="> : PHPPARSING
720 | <STARASSIGN         : "*="> : PHPPARSING
721 | <SLASHASSIGN        : "/="> : PHPPARSING
722 | <ANDASSIGN          : "&="> : PHPPARSING
723 | <ORASSIGN           : "|="> : PHPPARSING
724 | <XORASSIGN          : "^="> : PHPPARSING
725 | <DOTASSIGN          : ".="> : PHPPARSING
726 | <REMASSIGN          : "%="> : PHPPARSING
727 | <TILDEEQUAL         : "~="> : PHPPARSING
728 | <LSHIFTASSIGN       : "<<="> : PHPPARSING
729 | <RSIGNEDSHIFTASSIGN : ">>="> : PHPPARSING
730 }
731
732 void phpTest() :
733 {}
734 {
735   Php()
736   <EOF>
737 }
738
739 void phpFile() :
740 {}
741 {
742   try {
743     (PhpBlock())*
744     {PHPParser.createNewHTMLCode();}
745   } catch (TokenMgrError e) {
746     PHPeclipsePlugin.log(e);
747     errorStart   = SimpleCharStream.beginOffset;
748     errorEnd     = SimpleCharStream.endOffset;
749     errorMessage = e.getMessage();
750     errorLevel   = ERROR;
751     throw generateParseException();
752   }
753 }
754
755 /**
756  * A php block is a <?= expression [;]?>
757  * or <?php somephpcode ?>
758  * or <? somephpcode ?>
759  */
760 void PhpBlock() :
761 {
762   final PHPEchoBlock phpEchoBlock;
763   final Token token,phpEnd;
764 }
765 {
766   phpEchoBlock = phpEchoBlock()
767   {pushOnAstNodes(phpEchoBlock);}
768 |
769   [   <PHPSTARTLONG>
770     | token = <PHPSTARTSHORT>
771     {try {
772       setMarker(fileToParse,
773                 "You should use '<?php' instead of '<?' it will avoid some problems with XML",
774                 token.sourceStart,
775                 token.sourceEnd,
776                 INFO,
777                 "Line " + token.beginLine);
778     } catch (CoreException e) {
779       PHPeclipsePlugin.log(e);
780     }}
781   ]
782   {PHPParser.createNewHTMLCode();}
783   Php()
784   try {
785     phpEnd = <PHPEND>
786    {htmlStart = phpEnd.sourceEnd;}
787   } catch (ParseException e) {
788     errorMessage = "'?>' expected";
789     errorLevel   = ERROR;
790     errorStart = e.currentToken.sourceStart;
791     errorEnd   = e.currentToken.sourceEnd;
792     processParseExceptionDebug(e);
793   }
794 }
795
796 PHPEchoBlock phpEchoBlock() :
797 {
798   final Expression expr;
799   final PHPEchoBlock echoBlock;
800   final Token token, token2;
801 }
802 {
803   token = <PHPECHOSTART> {PHPParser.createNewHTMLCode();}
804   expr = Expression() [ <SEMICOLON> ] token2 = <PHPEND>
805   {
806   htmlStart = token2.sourceEnd;
807
808   echoBlock = new PHPEchoBlock(expr,token.sourceStart,token2.sourceEnd);
809   pushOnAstNodes(echoBlock);
810   return echoBlock;}
811 }
812
813 void Php() :
814 {}
815 {
816   (BlockStatement())*
817 }
818
819 ClassDeclaration ClassDeclaration() :
820 {
821   final ClassDeclaration classDeclaration;
822   Token className = null;
823   final Token superclassName, token, extendsToken;
824   String classNameImage = SYNTAX_ERROR_CHAR;
825   String superclassNameImage = null;
826   final int classEnd;
827 }
828 {
829   token = <CLASS>
830   try {
831     className = <IDENTIFIER>
832     {classNameImage = className.image;}
833   } catch (ParseException e) {
834     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected";
835     errorLevel   = ERROR;
836     errorStart   = token.sourceEnd+1;
837     errorEnd     = token.sourceEnd+1;
838     processParseExceptionDebug(e);
839   }
840   [
841     extendsToken = <EXTENDS>
842     try {
843       superclassName = <IDENTIFIER>
844       {superclassNameImage = superclassName.image;}
845     } catch (ParseException e) {
846       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected";
847       errorLevel   = ERROR;
848       errorStart = extendsToken.sourceEnd+1;
849       errorEnd   = extendsToken.sourceEnd+1;
850       processParseExceptionDebug(e);
851       superclassNameImage = SYNTAX_ERROR_CHAR;
852     }
853   ]
854   {
855     int start, end;
856     if (className == null) {
857       start = token.sourceStart;
858       end = token.sourceEnd;
859     } else {
860       start = className.sourceStart;
861       end = className.sourceEnd;
862     }
863     if (superclassNameImage == null) {
864
865       classDeclaration = new ClassDeclaration(currentSegment,
866                                               classNameImage,
867                                               start,
868                                               end);
869     } else {
870       classDeclaration = new ClassDeclaration(currentSegment,
871                                               classNameImage,
872                                               superclassNameImage,
873                                               start,
874                                               end);
875     }
876       currentSegment.add(classDeclaration);
877       currentSegment = classDeclaration;
878   }
879   classEnd = ClassBody(classDeclaration)
880   {currentSegment = (OutlineableWithChildren) currentSegment.getParent();
881    classDeclaration.sourceEnd = classEnd;
882    pushOnAstNodes(classDeclaration);
883    return classDeclaration;}
884 }
885
886 int ClassBody(final ClassDeclaration classDeclaration) :
887 {
888 Token token;
889 }
890 {
891   try {
892     <LBRACE>
893   } catch (ParseException e) {
894     errorMessage = "unexpected token : '"+ e.currentToken.next.image + "'. '{' expected";
895     errorLevel   = ERROR;
896     errorStart = e.currentToken.sourceStart;
897     errorEnd   = e.currentToken.sourceEnd;
898     processParseExceptionDebug(e);
899   }
900   ( ClassBodyDeclaration(classDeclaration) )*
901   try {
902     token = <RBRACE>
903     {return token.sourceEnd;}
904   } catch (ParseException e) {
905     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. 'var', 'function' or '}' expected";
906     errorLevel   = ERROR;
907     errorStart = e.currentToken.sourceStart;
908     errorEnd   = e.currentToken.sourceEnd;
909     processParseExceptionDebug(e);
910     return PHPParser.token.sourceEnd;
911   }
912 }
913
914 /**
915  * A class can contain only methods and fields.
916  */
917 void ClassBodyDeclaration(final ClassDeclaration classDeclaration) :
918 {
919   final MethodDeclaration method;
920   final FieldDeclaration field;
921 }
922 {
923   method = MethodDeclaration() {method.analyzeCode();
924                                 classDeclaration.addMethod(method);}
925 | field = FieldDeclaration()   {classDeclaration.addField(field);}
926 }
927
928 /**
929  * A class field declaration : it's var VariableDeclarator() (, VariableDeclarator())*;.
930  * it is only used by ClassBodyDeclaration()
931  */
932 FieldDeclaration FieldDeclaration() :
933 {
934   VariableDeclaration variableDeclaration;
935   final VariableDeclaration[] list;
936   final ArrayList arrayList = new ArrayList();
937   final Token token;
938   Token token2 = null;
939   int pos;
940 }
941 {
942   token = <VAR> variableDeclaration = VariableDeclaratorNoSuffix()
943   {
944     arrayList.add(variableDeclaration);
945     pos = variableDeclaration.sourceEnd;
946   }
947   (
948     <COMMA> variableDeclaration = VariableDeclaratorNoSuffix()
949       {
950         arrayList.add(variableDeclaration);
951         outlineInfo.addVariable(variableDeclaration.name());
952         pos = variableDeclaration.sourceEnd;
953       }
954   )*
955   try {
956     token2 = <SEMICOLON>
957   } catch (ParseException e) {
958     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected after variable declaration";
959     errorLevel   = ERROR;
960     errorStart   = pos+1;
961     errorEnd     = pos+1;
962     processParseExceptionDebug(e);
963   }
964
965   {list = new VariableDeclaration[arrayList.size()];
966    arrayList.toArray(list);
967    int end;
968    if (token2 == null) {
969      end = list[list.length-1].sourceEnd;
970    } else {
971      end = token2.sourceEnd;
972    }
973    return new FieldDeclaration(list,
974                                token.sourceStart,
975                                end,
976                                currentSegment);}
977 }
978
979 /**
980  * a strict variable declarator : there cannot be a suffix here.
981  * It will be used by fields and formal parameters
982  */
983 VariableDeclaration VariableDeclaratorNoSuffix() :
984 {
985   final Token token, lbrace,rbrace;
986   Expression expr, initializer = null;
987   Token assignToken;
988   Variable variable;
989 }
990 {
991   <DOLLAR>
992   (
993      token = <IDENTIFIER>
994      {variable = new Variable(token.image,token.sourceStart,token.sourceEnd);}
995    |
996      lbrace = <LBRACE> expr = Expression() rbrace = <RBRACE>
997      {variable = new Variable(expr,lbrace.sourceStart,rbrace.sourceEnd);}
998   )
999   [
1000     assignToken = <ASSIGN>
1001     try {
1002       initializer = VariableInitializer()
1003     } catch (ParseException e) {
1004       errorMessage = "Literal expression expected in variable initializer";
1005       errorLevel   = ERROR;
1006       errorStart = assignToken.sourceEnd +1;
1007       errorEnd   = assignToken.sourceEnd +1;
1008       processParseExceptionDebug(e);
1009     }
1010   ]
1011   {
1012   if (initializer == null) {
1013     return new VariableDeclaration(currentSegment,
1014                                    variable,
1015                                    variable.sourceStart,
1016                                    variable.sourceEnd);
1017   }
1018   return new VariableDeclaration(currentSegment,
1019                                  variable,
1020                                  initializer,
1021                                  VariableDeclaration.EQUAL,
1022                                  variable.sourceStart);
1023   }
1024 }
1025
1026 /**
1027  * this will be used by static statement
1028  */
1029 VariableDeclaration VariableDeclarator() :
1030 {
1031   final AbstractVariable variable;
1032   Expression initializer = null;
1033   final Token token;
1034 }
1035 {
1036   variable = VariableDeclaratorId()
1037   [
1038     token = <ASSIGN>
1039     try {
1040       initializer = VariableInitializer()
1041     } catch (ParseException e) {
1042       errorMessage = "Literal expression expected in variable initializer";
1043       errorLevel   = ERROR;
1044       errorStart = token.sourceEnd+1;
1045       errorEnd   = token.sourceEnd+1;
1046       processParseExceptionDebug(e);
1047     }
1048   ]
1049   {
1050   if (initializer == null) {
1051     return new VariableDeclaration(currentSegment,
1052                                    variable,
1053                                    variable.sourceStart,
1054                                    variable.sourceEnd);
1055   }
1056     return new VariableDeclaration(currentSegment,
1057                                    variable,
1058                                    initializer,
1059                                    VariableDeclaration.EQUAL,
1060                                    variable.sourceStart);
1061   }
1062 }
1063
1064 /**
1065  * A Variable name.
1066  * @return the variable name (with suffix)
1067  */
1068 AbstractVariable VariableDeclaratorId() :
1069 {
1070   final Variable var;
1071   AbstractVariable expression = null;
1072 }
1073 {
1074   try {
1075     var = Variable()
1076     (
1077       LOOKAHEAD(2)
1078       expression = VariableSuffix(var)
1079     )*
1080     {
1081      if (expression == null) {
1082        return var;
1083      }
1084      return expression;
1085     }
1086   } catch (ParseException e) {
1087     errorMessage = "'$' expected for variable identifier";
1088     errorLevel   = ERROR;
1089     errorStart = e.currentToken.sourceStart;
1090     errorEnd   = e.currentToken.sourceEnd;
1091     throw e;
1092   }
1093 }
1094
1095 Variable Variable() :
1096 {
1097   Variable variable = null;
1098   final Token token;
1099 }
1100 {
1101   token = <DOLLAR> variable = Var()
1102   {
1103     return variable;
1104   }
1105 }
1106
1107 Variable Var() :
1108 {
1109   Variable variable = null;
1110   final Token token,token2;
1111   ConstantIdentifier constant;
1112   Expression expression;
1113 }
1114 {
1115   token = <DOLLAR> variable = Var()
1116   {return new Variable(variable,variable.sourceStart,variable.sourceEnd);}
1117 |
1118   token = <LBRACE> expression = Expression() token2 = <RBRACE>
1119   {
1120    return new Variable(expression,
1121                        token.sourceStart,
1122                        token2.sourceEnd);
1123   }
1124 |
1125   token = <IDENTIFIER>
1126   {
1127    outlineInfo.addVariable('$' + token.image);
1128    return new Variable(token.image,token.sourceStart,token.sourceEnd);
1129   }
1130 }
1131
1132 Expression VariableInitializer() :
1133 {
1134   final Expression expr;
1135   final Token token, token2;
1136 }
1137 {
1138   expr = Literal()
1139   {return expr;}
1140 |
1141   token2 = <MINUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1142   {return new PrefixedUnaryExpression(new NumberLiteral(token),
1143                                       OperatorIds.MINUS,
1144                                       token2.sourceStart);}
1145 |
1146   token2 = <PLUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1147   {return new PrefixedUnaryExpression(new NumberLiteral(token),
1148                                       OperatorIds.PLUS,
1149                                       token2.sourceStart);}
1150 |
1151   expr = ArrayDeclarator()
1152   {return expr;}
1153 |
1154   token = <IDENTIFIER>
1155   {return new ConstantIdentifier(token);}
1156 }
1157
1158 ArrayVariableDeclaration ArrayVariable() :
1159 {
1160 final Expression expr,expr2;
1161 }
1162 {
1163   expr = Expression()
1164   [
1165     <ARRAYASSIGN> expr2 = Expression()
1166     {return new ArrayVariableDeclaration(expr,expr2);}
1167   ]
1168   {return new ArrayVariableDeclaration(expr,SimpleCharStream.getPosition());}
1169 }
1170
1171 ArrayVariableDeclaration[] ArrayInitializer() :
1172 {
1173   ArrayVariableDeclaration expr;
1174   final ArrayList list = new ArrayList();
1175 }
1176 {
1177   <LPAREN>
1178     [
1179       expr = ArrayVariable()
1180       {list.add(expr);}
1181       ( LOOKAHEAD(2) <COMMA> expr = ArrayVariable()
1182       {list.add(expr);}
1183       )*
1184     ]
1185     [
1186       <COMMA> {list.add(null);}
1187     ]
1188   <RPAREN>
1189   {
1190   final ArrayVariableDeclaration[] vars = new ArrayVariableDeclaration[list.size()];
1191   list.toArray(vars);
1192   return vars;}
1193 }
1194
1195 /**
1196  * A Method Declaration.
1197  * <b>function</b> MetodDeclarator() Block()
1198  */
1199 MethodDeclaration MethodDeclaration() :
1200 {
1201   final MethodDeclaration functionDeclaration;
1202   final Block block;
1203   final OutlineableWithChildren seg = currentSegment;
1204   final Token token;
1205 }
1206 {
1207   token = <FUNCTION>
1208   try {
1209     functionDeclaration = MethodDeclarator(token.sourceStart)
1210     {outlineInfo.addVariable(functionDeclaration.name);}
1211   } catch (ParseException e) {
1212     if (errorMessage != null)  throw e;
1213     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
1214     errorLevel   = ERROR;
1215     errorStart = e.currentToken.sourceStart;
1216     errorEnd   = e.currentToken.sourceEnd;
1217     throw e;
1218   }
1219   {currentSegment = functionDeclaration;}
1220   block = Block()
1221   {functionDeclaration.statements = block.statements;
1222    currentSegment = seg;
1223    return functionDeclaration;}
1224 }
1225
1226 /**
1227  * A MethodDeclarator.
1228  * [&] IDENTIFIER(parameters ...).
1229  * @return a function description for the outline
1230  */
1231 MethodDeclaration MethodDeclarator(final int start) :
1232 {
1233   Token identifier = null;
1234   Token reference = null;
1235   final ArrayList formalParameters = new ArrayList();
1236   String identifierChar = SYNTAX_ERROR_CHAR;
1237   int end = start;
1238 }
1239 {
1240   [reference = <BIT_AND> {end = reference.sourceEnd;}]
1241   try {
1242     identifier = <IDENTIFIER>
1243     {
1244       identifierChar = identifier.image;
1245       end = identifier.sourceEnd;
1246     }
1247   } catch (ParseException e) {
1248     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
1249     errorLevel   = ERROR;
1250     errorStart = e.currentToken.sourceEnd;
1251     errorEnd   = e.currentToken.next.sourceStart;
1252     processParseExceptionDebug(e);
1253   }
1254   end = FormalParameters(formalParameters)
1255   {
1256   int nameStart, nameEnd;
1257   if (identifier == null) {
1258     if (reference == null) {
1259       nameStart = start + 9;
1260       nameEnd = start + 10;
1261     } else {
1262       nameStart = reference.sourceEnd + 1;
1263       nameEnd = reference.sourceEnd + 2;
1264     }
1265   } else {
1266       nameStart = identifier.sourceStart;
1267       nameEnd = identifier.sourceEnd;
1268   }
1269   return new MethodDeclaration(currentSegment,
1270                                identifierChar,
1271                                formalParameters,
1272                                reference != null,
1273                                nameStart,
1274                                nameEnd,
1275                                start,
1276                                end);
1277   }
1278 }
1279
1280 /**
1281  * FormalParameters follows method identifier.
1282  * (FormalParameter())
1283  */
1284 int FormalParameters(final ArrayList parameters) :
1285 {
1286   VariableDeclaration var;
1287   final Token token;
1288   Token tok = PHPParser.token;
1289   int end = tok.sourceEnd;
1290 }
1291 {
1292   try {
1293   tok = <LPAREN>
1294   {end = tok.sourceEnd;}
1295   } catch (ParseException e) {
1296     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected after function identifier";
1297     errorLevel   = ERROR;
1298     errorStart = e.currentToken.next.sourceStart;
1299     errorEnd   = e.currentToken.next.sourceEnd;
1300     processParseExceptionDebug(e);
1301   }
1302   [
1303     var = FormalParameter()
1304     {parameters.add(var);end = var.sourceEnd;}
1305     (
1306       <COMMA> var = FormalParameter()
1307       {parameters.add(var);end = var.sourceEnd;}
1308     )*
1309   ]
1310   try {
1311     token = <RPAREN>
1312     {end = token.sourceEnd;}
1313   } catch (ParseException e) {
1314     errorMessage = "')' expected";
1315     errorLevel   = ERROR;
1316     errorStart = e.currentToken.next.sourceStart;
1317     errorEnd   = e.currentToken.next.sourceEnd;
1318     processParseExceptionDebug(e);
1319   }
1320  {return end;}
1321 }
1322
1323 /**
1324  * A formal parameter.
1325  * $varname[=value] (,$varname[=value])
1326  */
1327 VariableDeclaration FormalParameter() :
1328 {
1329   final VariableDeclaration variableDeclaration;
1330   Token token = null;
1331 }
1332 {
1333   [token = <BIT_AND>] variableDeclaration = VariableDeclaratorNoSuffix()
1334   {
1335     outlineInfo.addVariable('$'+variableDeclaration.name());
1336     if (token != null) {
1337       variableDeclaration.setReference(true);
1338     }
1339     return variableDeclaration;}
1340 }
1341
1342 ConstantIdentifier Type() :
1343 {final Token token;}
1344 {
1345   token = <STRING>    {return new ConstantIdentifier(token);}
1346 | token = <BOOL>      {return new ConstantIdentifier(token);}
1347 | token = <BOOLEAN>   {return new ConstantIdentifier(token);}
1348 | token = <REAL>      {return new ConstantIdentifier(token);}
1349 | token = <DOUBLE>    {return new ConstantIdentifier(token);}
1350 | token = <FLOAT>     {return new ConstantIdentifier(token);}
1351 | token = <INT>       {return new ConstantIdentifier(token);}
1352 | token = <INTEGER>   {return new ConstantIdentifier(token);}
1353 | token = <OBJECT>    {return new ConstantIdentifier(token);}
1354 }
1355
1356 Expression Expression() :
1357 {
1358   final Expression expr;
1359   Expression initializer = null;
1360   int assignOperator = -1;
1361 }
1362 {
1363   LOOKAHEAD(1)
1364   expr = ConditionalExpression()
1365   [
1366     assignOperator = AssignmentOperator()
1367     try {
1368       initializer = Expression()
1369     } catch (ParseException e) {
1370       if (errorMessage != null) {
1371         throw e;
1372       }
1373       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
1374       errorLevel   = ERROR;
1375       errorEnd   = SimpleCharStream.getPosition();
1376       throw e;
1377     }
1378   ]
1379   {
1380     if (assignOperator != -1) {// todo : change this, very very bad :(
1381         if (expr instanceof AbstractVariable) {
1382           return new VariableDeclaration(currentSegment,
1383                                          (AbstractVariable) expr,
1384                                          initializer,
1385                                          expr.sourceStart,
1386                                          initializer.sourceEnd);
1387         }
1388         String varName = expr.toStringExpression().substring(1);
1389         return new VariableDeclaration(currentSegment,
1390                                        new Variable(varName,
1391                                                     expr.sourceStart,
1392                                                     expr.sourceEnd),
1393                                        expr.sourceStart,
1394                                        initializer.sourceEnd);
1395     }
1396     return expr;
1397   }
1398 | expr = ExpressionWBang()       {return expr;}
1399 }
1400
1401 Expression ExpressionWBang() :
1402 {
1403   final Expression expr;
1404   final Token token;
1405 }
1406 {
1407   token = <BANG> expr = ExpressionWBang()
1408   {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);}
1409 | expr = ExpressionNoBang() {return expr;}
1410 }
1411
1412 Expression ExpressionNoBang() :
1413 {
1414   Expression expr;
1415 }
1416 {
1417   expr = ListExpression()    {return expr;}
1418 |
1419   expr = PrintExpression()   {return expr;}
1420 }
1421
1422 /**
1423  * Any assignement operator.
1424  * @return the assignement operator id
1425  */
1426 int AssignmentOperator() :
1427 {}
1428 {
1429   <ASSIGN>             {return VariableDeclaration.EQUAL;}
1430 | <STARASSIGN>         {return VariableDeclaration.STAR_EQUAL;}
1431 | <SLASHASSIGN>        {return VariableDeclaration.SLASH_EQUAL;}
1432 | <REMASSIGN>          {return VariableDeclaration.REM_EQUAL;}
1433 | <PLUSASSIGN>         {return VariableDeclaration.PLUS_EQUAL;}
1434 | <MINUSASSIGN>        {return VariableDeclaration.MINUS_EQUAL;}
1435 | <LSHIFTASSIGN>       {return VariableDeclaration.LSHIFT_EQUAL;}
1436 | <RSIGNEDSHIFTASSIGN> {return VariableDeclaration.RSIGNEDSHIFT_EQUAL;}
1437 | <ANDASSIGN>          {return VariableDeclaration.AND_EQUAL;}
1438 | <XORASSIGN>          {return VariableDeclaration.XOR_EQUAL;}
1439 | <ORASSIGN>           {return VariableDeclaration.OR_EQUAL;}
1440 | <DOTASSIGN>          {return VariableDeclaration.DOT_EQUAL;}
1441 | <TILDEEQUAL>         {return VariableDeclaration.TILDE_EQUAL;}
1442 }
1443
1444 Expression ConditionalExpression() :
1445 {
1446   final Expression expr;
1447   Expression expr2 = null;
1448   Expression expr3 = null;
1449 }
1450 {
1451   expr = ConditionalOrExpression() [ <HOOK> expr2 = Expression() <COLON> expr3 = ConditionalExpression() ]
1452 {
1453   if (expr3 == null) {
1454     return expr;
1455   }
1456   return new ConditionalExpression(expr,expr2,expr3);
1457 }
1458 }
1459
1460 Expression ConditionalOrExpression() :
1461 {
1462   Expression expr,expr2;
1463   int operator;
1464 }
1465 {
1466   expr = ConditionalAndExpression()
1467   (
1468     (
1469         <OR_OR> {operator = OperatorIds.OR_OR;}
1470       | <_ORL>  {operator = OperatorIds.ORL;}
1471     )
1472     expr2 = ConditionalAndExpression()
1473     {
1474       expr = new BinaryExpression(expr,expr2,operator);
1475     }
1476   )*
1477   {return expr;}
1478 }
1479
1480 Expression ConditionalAndExpression() :
1481 {
1482   Expression expr,expr2;
1483   int operator;
1484 }
1485 {
1486   expr = ConcatExpression()
1487   (
1488   (  <AND_AND> {operator = OperatorIds.AND_AND;}
1489    | <_ANDL>   {operator = OperatorIds.ANDL;})
1490    expr2 = ConcatExpression() {expr = new BinaryExpression(expr,expr2,operator);}
1491   )*
1492   {return expr;}
1493 }
1494
1495 Expression ConcatExpression() :
1496 {
1497   Expression expr,expr2;
1498 }
1499 {
1500   expr = InclusiveOrExpression()
1501   (
1502     <DOT> expr2 = InclusiveOrExpression()
1503     {expr = new BinaryExpression(expr,expr2,OperatorIds.DOT);}
1504   )*
1505   {return expr;}
1506 }
1507
1508 Expression InclusiveOrExpression() :
1509 {
1510   Expression expr,expr2;
1511 }
1512 {
1513   expr = ExclusiveOrExpression()
1514   (<BIT_OR> expr2 = ExclusiveOrExpression()
1515    {expr = new BinaryExpression(expr,expr2,OperatorIds.OR);}
1516   )*
1517   {return expr;}
1518 }
1519
1520 Expression ExclusiveOrExpression() :
1521 {
1522   Expression expr,expr2;
1523 }
1524 {
1525   expr = AndExpression()
1526   (
1527     <XOR> expr2 = AndExpression()
1528     {expr = new BinaryExpression(expr,expr2,OperatorIds.XOR);}
1529   )*
1530   {return expr;}
1531 }
1532
1533 Expression AndExpression() :
1534 {
1535   Expression expr,expr2;
1536 }
1537 {
1538   expr = EqualityExpression()
1539   (
1540     LOOKAHEAD(1)
1541     <BIT_AND> expr2 = EqualityExpression()
1542     {expr = new BinaryExpression(expr,expr2,OperatorIds.AND);}
1543   )*
1544   {return expr;}
1545 }
1546
1547 Expression EqualityExpression() :
1548 {
1549   Expression expr,expr2;
1550   int operator;
1551   Token token;
1552 }
1553 {
1554   expr = RelationalExpression()
1555   (
1556   (   token = <EQUAL_EQUAL>      {operator = OperatorIds.EQUAL_EQUAL;}
1557     | token = <DIF>              {operator = OperatorIds.DIF;}
1558     | token = <NOT_EQUAL>        {operator = OperatorIds.DIF;}
1559     | token = <BANGDOUBLEEQUAL>  {operator = OperatorIds.BANG_EQUAL_EQUAL;}
1560     | token = <TRIPLEEQUAL>      {operator = OperatorIds.EQUAL_EQUAL_EQUAL;}
1561   )
1562   try {
1563     expr2 = RelationalExpression()
1564   } catch (ParseException e) {
1565     if (errorMessage != null) {
1566       throw e;
1567     }
1568     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
1569     errorLevel   = ERROR;
1570     errorStart = token.sourceEnd +1;
1571     errorEnd   = token.sourceEnd +1;
1572     expr2 = new ConstantIdentifier(SYNTAX_ERROR_CHAR,token.sourceEnd +1,token.sourceEnd +1);
1573     processParseExceptionDebug(e);
1574   }
1575   {
1576     expr = new BinaryExpression(expr,expr2,operator);
1577   }
1578   )*
1579   {return expr;}
1580 }
1581
1582 Expression RelationalExpression() :
1583 {
1584   Expression expr,expr2;
1585   int operator;
1586 }
1587 {
1588   expr = ShiftExpression()
1589   (
1590   ( <LT> {operator = OperatorIds.LESS;}
1591   | <GT> {operator = OperatorIds.GREATER;}
1592   | <LE> {operator = OperatorIds.LESS_EQUAL;}
1593   | <GE> {operator = OperatorIds.GREATER_EQUAL;})
1594    expr2 = ShiftExpression()
1595   {expr = new BinaryExpression(expr,expr2,operator);}
1596   )*
1597   {return expr;}
1598 }
1599
1600 Expression ShiftExpression() :
1601 {
1602   Expression expr,expr2;
1603   int operator;
1604 }
1605 {
1606   expr = AdditiveExpression()
1607   (
1608   ( <LSHIFT>         {operator = OperatorIds.LEFT_SHIFT;}
1609   | <RSIGNEDSHIFT>   {operator = OperatorIds.RIGHT_SHIFT;}
1610   | <RUNSIGNEDSHIFT> {operator = OperatorIds.UNSIGNED_RIGHT_SHIFT;})
1611   expr2 = AdditiveExpression()
1612   {expr = new BinaryExpression(expr,expr2,operator);}
1613   )*
1614   {return expr;}
1615 }
1616
1617 Expression AdditiveExpression() :
1618 {
1619   Expression expr,expr2;
1620   int operator;
1621 }
1622 {
1623   expr = MultiplicativeExpression()
1624   (
1625     LOOKAHEAD(1)
1626      ( <PLUS>  {operator = OperatorIds.PLUS;}
1627      | <MINUS> {operator = OperatorIds.MINUS;}
1628   )
1629    expr2 = MultiplicativeExpression()
1630   {expr = new BinaryExpression(expr,expr2,operator);}
1631    )*
1632   {return expr;}
1633 }
1634
1635 Expression MultiplicativeExpression() :
1636 {
1637   Expression expr,expr2;
1638   int operator;
1639 }
1640 {
1641   try {
1642     expr = UnaryExpression()
1643   } catch (ParseException e) {
1644     if (errorMessage != null) throw e;
1645     errorMessage = "unexpected token '"+e.currentToken.next.image+'\'';
1646     errorLevel   = ERROR;
1647     errorStart = PHPParser.token.sourceStart;
1648     errorEnd   = PHPParser.token.sourceEnd;
1649     throw e;
1650   }
1651   (
1652    (  <STAR>      {operator = OperatorIds.MULTIPLY;}
1653     | <SLASH>     {operator = OperatorIds.DIVIDE;}
1654     | <REMAINDER> {operator = OperatorIds.REMAINDER;})
1655     expr2 = UnaryExpression()
1656     {expr = new BinaryExpression(expr,expr2,operator);}
1657   )*
1658   {return expr;}
1659 }
1660
1661 /**
1662  * An unary expression starting with @, & or nothing
1663  */
1664 Expression UnaryExpression() :
1665 {
1666   final Expression expr;
1667 }
1668 {
1669  /* <BIT_AND> expr = UnaryExpressionNoPrefix()             //why did I had that ?
1670   {return new PrefixedUnaryExpression(expr,OperatorIds.AND,pos);}
1671 |      */
1672   expr = AtNotTildeUnaryExpression() {return expr;}
1673 }
1674
1675 Expression AtNotTildeUnaryExpression() :
1676 {
1677   final Expression expr;
1678   final Token token;
1679 }
1680 {
1681   token = <AT>
1682   expr = AtNotTildeUnaryExpression()
1683   {return new PrefixedUnaryExpression(expr,OperatorIds.AT,token.sourceStart);}
1684 |
1685   token = <TILDE>
1686   expr = AtNotTildeUnaryExpression()
1687   {return new PrefixedUnaryExpression(expr,OperatorIds.TWIDDLE,token.sourceStart);}
1688 |
1689   token = <BANG>
1690   expr = AtNotUnaryExpression()
1691   {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);}
1692 |
1693   expr = UnaryExpressionNoPrefix()
1694   {return expr;}
1695 }
1696
1697 /**
1698  * An expression prefixed (or not) by one or more @ and !.
1699  * @return the expression
1700  */
1701 Expression AtNotUnaryExpression() :
1702 {
1703   final Expression expr;
1704   final Token token;
1705 }
1706 {
1707   token = <AT>
1708   expr = AtNotUnaryExpression()
1709   {return new PrefixedUnaryExpression(expr,OperatorIds.AT,token.sourceStart);}
1710 |
1711   token = <BANG>
1712   expr = AtNotUnaryExpression()
1713   {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);}
1714 |
1715   expr = UnaryExpressionNoPrefix()
1716   {return expr;}
1717 }
1718
1719 Expression UnaryExpressionNoPrefix() :
1720 {
1721   final Expression expr;
1722   final Token token;
1723 }
1724 {
1725   token = <PLUS> expr = AtNotTildeUnaryExpression()   {return new PrefixedUnaryExpression(expr,
1726                                                                                      OperatorIds.PLUS,
1727                                                                                      token.sourceStart);}
1728 |
1729   token = <MINUS> expr = AtNotTildeUnaryExpression()  {return new PrefixedUnaryExpression(expr,
1730                                                                                      OperatorIds.MINUS,
1731                                                                                      token.sourceStart);}
1732 |
1733   expr = PreIncDecExpression()
1734   {return expr;}
1735 |
1736   expr = UnaryExpressionNotPlusMinus()
1737   {return expr;}
1738 }
1739
1740
1741 Expression PreIncDecExpression() :
1742 {
1743 final Expression expr;
1744 final int operator;
1745 final Token token;
1746 }
1747 {
1748   (
1749       token = <PLUS_PLUS>   {operator = OperatorIds.PLUS_PLUS;}
1750     |
1751       token = <MINUS_MINUS> {operator = OperatorIds.MINUS_MINUS;}
1752   )
1753   expr = PrimaryExpression()
1754   {return new PrefixedUnaryExpression(expr,operator,token.sourceStart);}
1755 }
1756
1757 Expression UnaryExpressionNotPlusMinus() :
1758 {
1759   final Expression expr;
1760 }
1761 {
1762   LOOKAHEAD( <LPAREN> (Type() | <ARRAY>) <RPAREN> )
1763   expr = CastExpression()         {return expr;}
1764 | expr = PostfixExpression()      {return expr;}
1765 | expr = Literal()                {return expr;}
1766 | <LPAREN> expr = Expression()
1767   try {
1768     <RPAREN>
1769   } catch (ParseException e) {
1770     errorMessage = "')' expected";
1771     errorLevel   = ERROR;
1772     errorStart   = expr.sourceEnd +1;
1773     errorEnd     = expr.sourceEnd +1;
1774     processParseExceptionDebug(e);
1775   }
1776   {return expr;}
1777 }
1778
1779 CastExpression CastExpression() :
1780 {
1781 final ConstantIdentifier type;
1782 final Expression expr;
1783 final Token token,token1;
1784 }
1785 {
1786   token1 = <LPAREN>
1787   (
1788       type = Type()
1789     |
1790       token = <ARRAY> {type = new ConstantIdentifier(token);}
1791   )
1792   <RPAREN> expr = UnaryExpression()
1793   {return new CastExpression(type,expr,token1.sourceStart,expr.sourceEnd);}
1794 }
1795
1796 Expression PostfixExpression() :
1797 {
1798   final Expression expr;
1799   int operator = -1;
1800   Token token = null;
1801 }
1802 {
1803   expr = PrimaryExpression()
1804   [
1805       token = <PLUS_PLUS>   {operator = OperatorIds.PLUS_PLUS;}
1806     |
1807       token = <MINUS_MINUS> {operator = OperatorIds.MINUS_MINUS;}
1808   ]
1809   {
1810     if (operator == -1) {
1811       return expr;
1812     }
1813     return new PostfixedUnaryExpression(expr,operator,token.sourceEnd);
1814   }
1815 }
1816
1817 Expression PrimaryExpression() :
1818 {
1819   Expression expr;
1820   Token token = null;
1821 }
1822 {
1823   [token = <BIT_AND>] expr = refPrimaryExpression(token)
1824   {return expr;}
1825 |
1826   expr = ArrayDeclarator()
1827   {return expr;}
1828 }
1829
1830 Expression refPrimaryExpression(final Token reference) :
1831 {
1832   Expression expr;
1833   Expression expr2 = null;
1834   final Token identifier;
1835 }
1836 {
1837   identifier = <IDENTIFIER>
1838   {
1839     expr = new ConstantIdentifier(identifier);
1840   }
1841   (
1842     <STATICCLASSACCESS> expr2 = ClassIdentifier()
1843     {expr = new ClassAccess(expr,
1844                             expr2,
1845                             ClassAccess.STATIC);}
1846   )*
1847   [ expr2 = Arguments(expr) ]
1848   {
1849     if (expr2 == null) {
1850       if (reference != null) {
1851         ParseException e = generateParseException();
1852         errorMessage = "you cannot use a constant by reference";
1853         errorLevel   = ERROR;
1854         errorStart   = reference.sourceStart;
1855         errorEnd     = reference.sourceEnd;
1856         processParseExceptionDebug(e);
1857       }
1858       return expr;
1859     }
1860     return expr2;
1861   }
1862 |
1863   expr = VariableDeclaratorId()  //todo use the reference parameter ...
1864   [ expr = Arguments(expr) ]
1865   {return expr;}
1866 |
1867   token = <NEW>
1868   expr = ClassIdentifier()
1869   {
1870     int start;
1871     if (reference == null) {
1872       start = token.sourceStart;
1873     } else {
1874       start = reference.sourceStart;
1875     }
1876     expr = new ClassInstantiation(expr,
1877                                   reference != null,
1878                                   start);
1879   }
1880   [ expr = Arguments(expr) ]
1881   {return expr;}
1882 }
1883
1884 /**
1885  * An array declarator.
1886  * array(vars)
1887  * @return an array
1888  */
1889 ArrayInitializer ArrayDeclarator() :
1890 {
1891   final ArrayVariableDeclaration[] vars;
1892   final Token token;
1893 }
1894 {
1895   token = <ARRAY> vars = ArrayInitializer()
1896   {return new ArrayInitializer(vars,
1897                                token.sourceStart,
1898                                PHPParser.token.sourceEnd);}
1899 }
1900
1901 Expression ClassIdentifier():
1902 {
1903   final Expression expr;
1904   final Token token;
1905 }
1906 {
1907   token = <IDENTIFIER>          {return new ConstantIdentifier(token);}
1908 | expr = Type()                 {return expr;}
1909 | expr = VariableDeclaratorId() {return expr;}
1910 }
1911
1912 /**
1913  * Used by Variabledeclaratorid and primarysuffix
1914  */
1915 AbstractVariable VariableSuffix(final AbstractVariable prefix) :
1916 {
1917   Expression expression = null;
1918   final Token classAccessToken,lbrace,rbrace;
1919   Token token;
1920   int pos;
1921 }
1922 {
1923   classAccessToken = <CLASSACCESS>
1924   try {
1925     (
1926       lbrace = <LBRACE> expression = Expression() rbrace = <RBRACE>
1927                 {
1928                  expression = new Variable(expression,
1929                                            lbrace.sourceStart,
1930                                            rbrace.sourceEnd);
1931                 }
1932       |
1933         token = <IDENTIFIER>
1934         {expression = new ConstantIdentifier(token.image,token.sourceStart,token.sourceEnd);}
1935       |
1936         expression = Variable()
1937     )
1938   } catch (ParseException e) {
1939     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function call or field access expected";
1940     errorLevel   = ERROR;
1941     errorStart = classAccessToken.sourceEnd +1;
1942     errorEnd   = classAccessToken.sourceEnd +1;
1943     processParseExceptionDebug(e);
1944   }
1945   {return new ClassAccess(prefix,
1946                           expression,
1947                           ClassAccess.NORMAL);}
1948 |
1949   token = <LBRACKET> {pos = token.sourceEnd+1;}
1950   [  expression = Expression() {pos = expression.sourceEnd+1;}
1951    | expression = Type()       {pos = expression.sourceEnd+1;}]  //Not good
1952   try {
1953     token = <RBRACKET>
1954     {pos = token.sourceEnd;}
1955   } catch (ParseException e) {
1956     errorMessage = "']' expected";
1957     errorLevel   = ERROR;
1958     errorStart = pos;
1959     errorEnd   = pos;
1960     processParseExceptionDebug(e);
1961   }
1962   {return new ArrayDeclarator(prefix,expression,pos);}
1963 |
1964   token = <LBRACE> {pos = token.sourceEnd+1;}
1965   [  expression = Expression() {pos = expression.sourceEnd+1;}
1966    | expression = Type()       {pos = expression.sourceEnd+1;}]  //Not good
1967   try {
1968     token = <RBRACE>
1969     {pos = token.sourceEnd;}
1970   } catch (ParseException e) {
1971     errorMessage = "']' expected";
1972     errorLevel   = ERROR;
1973     errorStart = pos;
1974     errorEnd   = pos;
1975     processParseExceptionDebug(e);
1976   }
1977   {return new ArrayDeclarator(prefix,expression,pos);}//todo : check braces here
1978 }
1979
1980 Literal Literal() :
1981 {
1982   final Token token;
1983   StringLiteral literal;
1984 }
1985 {
1986   token = <INTEGER_LITERAL>        {return new NumberLiteral(token);}
1987 | token = <FLOATING_POINT_LITERAL> {return new NumberLiteral(token);}
1988 | token = <STRING_LITERAL>         {return new StringLiteral(token);}
1989 | token = <TRUE>                   {return new TrueLiteral(token);}
1990 | token = <FALSE>                  {return new FalseLiteral(token);}
1991 | token = <NULL>                   {return new NullLiteral(token);}
1992 | literal = evaluableString()        {return literal;}
1993 }
1994
1995 StringLiteral evaluableString() :
1996 {
1997   ArrayList list = new ArrayList();
1998   Token start,end;
1999   Token token,lbrace,rbrace;
2000   AbstractVariable var;
2001   Expression expr;
2002 }
2003 {
2004   start = <DOUBLEQUOTE>
2005   (
2006    <DOLLARS>
2007        (
2008         token = <IDENTIFIER> {list.add(new Variable(token.image,
2009                                                     token.sourceStart,
2010                                                     token.sourceEnd));}
2011         |
2012          lbrace = <LBRACE1>
2013          token = <ID>
2014          {list.add(new Variable(token.image,
2015                                 token.sourceStart,
2016                                 token.sourceEnd));}
2017          rbrace = <RBRACE1>
2018        )
2019    )*
2020   end = <DOUBLEQUOTE2>
2021   {
2022   AbstractVariable[] vars = new AbstractVariable[list.size()];
2023   list.toArray(vars);
2024   return new StringLiteral(SimpleCharStream.currentBuffer.substring(start.sourceEnd,end.sourceStart),
2025                            start.sourceStart,
2026                            end.sourceEnd,
2027                            vars);
2028   }
2029 }
2030
2031 FunctionCall Arguments(final Expression func) :
2032 {
2033 Expression[] args = null;
2034 final Token token,lparen;
2035 }
2036 {
2037   lparen = <LPAREN> [ args = ArgumentList() ]
2038   try {
2039     token = <RPAREN>
2040     {return new FunctionCall(func,args,token.sourceEnd);}
2041   } catch (ParseException e) {
2042     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list";
2043     errorLevel   = ERROR;
2044     if (args == null) {
2045         errorStart = lparen.sourceEnd+1;
2046         errorEnd   = lparen.sourceEnd+2;
2047     } else {
2048         errorStart = args[args.length-1].sourceEnd+1;
2049         errorEnd   = args[args.length-1].sourceEnd+2;
2050     }
2051     processParseExceptionDebug(e);
2052   }
2053   {
2054   int sourceEnd = (args == null && args.length != 0) ? lparen.sourceEnd+1 : args[args.length-1].sourceEnd;
2055   return new FunctionCall(func,args,sourceEnd);}
2056 }
2057
2058 /**
2059  * An argument list is a list of arguments separated by comma :
2060  * argumentDeclaration() (, argumentDeclaration)*
2061  * @return an array of arguments
2062  */
2063 Expression[] ArgumentList() :
2064 {
2065 Expression arg;
2066 final ArrayList list = new ArrayList();
2067 int pos;
2068 Token token;
2069 }
2070 {
2071   arg = Expression()
2072   {list.add(arg);pos = arg.sourceEnd;}
2073   ( token = <COMMA> {pos = token.sourceEnd;}
2074       try {
2075         arg = Expression()
2076         {list.add(arg);
2077          pos = arg.sourceEnd;}
2078       } catch (ParseException e) {
2079         errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. An expression expected after a comma in argument list";
2080         errorLevel   = ERROR;
2081         errorStart   = pos+1;
2082         errorEnd     = pos+1;
2083         processParseException(e);
2084       }
2085    )*
2086    {
2087    final Expression[] arguments = new Expression[list.size()];
2088    list.toArray(arguments);
2089    return arguments;}
2090 }
2091
2092 /**
2093  * A Statement without break.
2094  * @return a statement
2095  */
2096 Statement StatementNoBreak() :
2097 {
2098   final Statement statement;
2099   Token token = null;
2100 }
2101 {
2102   LOOKAHEAD(2)
2103   statement = expressionStatement()     {return statement;}
2104 | LOOKAHEAD(1)
2105   statement = LabeledStatement()        {return statement;}
2106 | statement = Block()                   {return statement;}
2107 | statement = EmptyStatement()          {return statement;}
2108 | statement = SwitchStatement()         {return statement;}
2109 | statement = IfStatement()             {return statement;}
2110 | statement = WhileStatement()          {return statement;}
2111 | statement = DoStatement()             {return statement;}
2112 | statement = ForStatement()            {return statement;}
2113 | statement = ForeachStatement()        {return statement;}
2114 | statement = ContinueStatement()       {return statement;}
2115 | statement = ReturnStatement()         {return statement;}
2116 | statement = EchoStatement()           {return statement;}
2117 | [token=<AT>] statement = IncludeStatement()
2118   {if (token != null) {
2119     ((InclusionStatement)statement).silent = true;
2120     statement.sourceStart = token.sourceStart;
2121   }
2122   return statement;}
2123 | statement = StaticStatement()         {return statement;}
2124 | statement = GlobalStatement()         {return statement;}
2125 | statement = defineStatement()         {currentSegment.add((Outlineable)statement);return statement;}
2126 }
2127
2128 /**
2129  * A statement expression.
2130  * expression ;
2131  * @return an expression
2132  */
2133 Statement expressionStatement() :
2134 {
2135   final Statement statement;
2136   final Token token;
2137 }
2138 {
2139   statement = Expression()
2140   try {
2141     token = <SEMICOLON>
2142     {statement.sourceEnd = token.sourceEnd;}
2143   } catch (ParseException e) {
2144     if (e.currentToken.next.kind != PHPParserConstants.PHPEND) {
2145       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2146       errorLevel   = ERROR;
2147       errorStart = statement.sourceEnd+1;
2148       errorEnd   = statement.sourceEnd+1;
2149       processParseExceptionDebug(e);
2150     }
2151   }
2152   {return statement;}
2153 }
2154
2155 Define defineStatement() :
2156 {
2157   Expression defineName,defineValue;
2158   final Token defineToken;
2159   Token token;
2160   int pos;
2161 }
2162 {
2163   defineToken = <DEFINE> {pos = defineToken.sourceEnd+1;}
2164   try {
2165     token = <LPAREN>
2166     {pos = token.sourceEnd+1;}
2167   } catch (ParseException e) {
2168     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
2169     errorLevel   = ERROR;
2170     errorStart   = pos;
2171     errorEnd     = pos;
2172     processParseExceptionDebug(e);
2173   }
2174   try {
2175     defineName = Expression()
2176     {pos = defineName.sourceEnd+1;}
2177   } catch (ParseException e) {
2178     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
2179     errorLevel   = ERROR;
2180     errorStart   = pos;
2181     errorEnd     = pos;
2182     processParseExceptionDebug(e);
2183     defineName = new StringLiteral(SYNTAX_ERROR_CHAR,pos,pos);
2184   }
2185   try {
2186     token = <COMMA>
2187     {pos = defineName.sourceEnd+1;}
2188   } catch (ParseException e) {
2189     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
2190     errorLevel   = ERROR;
2191     errorStart   = pos;
2192     errorEnd     = pos;
2193     processParseExceptionDebug(e);
2194   }
2195   try {
2196     defineValue = Expression()
2197     {pos = defineValue.sourceEnd+1;}
2198   } catch (ParseException e) {
2199     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
2200     errorLevel   = ERROR;
2201     errorStart   = pos;
2202     errorEnd     = pos;
2203     processParseExceptionDebug(e);
2204     defineValue = new StringLiteral(SYNTAX_ERROR_CHAR,pos,pos);
2205   }
2206   try {
2207     token = <RPAREN>
2208     {pos = token.sourceEnd+1;}
2209   } catch (ParseException e) {
2210     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
2211     errorLevel   = ERROR;
2212     errorStart   = pos;
2213     errorEnd     = pos;
2214     processParseExceptionDebug(e);
2215   }
2216   {return new Define(currentSegment,
2217                      defineName,
2218                      defineValue,
2219                      defineToken.sourceStart,
2220                      pos);}
2221 }
2222
2223 /**
2224  * A Normal statement.
2225  */
2226 Statement Statement() :
2227 {
2228   final Statement statement;
2229 }
2230 {
2231   statement = StatementNoBreak() {return statement;}
2232 | statement = BreakStatement()   {return statement;}
2233 }
2234
2235 /**
2236  * An html block inside a php syntax.
2237  */
2238 HTMLBlock htmlBlock() :
2239 {
2240   final int startIndex = nodePtr;
2241   final AstNode[] blockNodes;
2242   final int nbNodes;
2243   final Token phpEnd;
2244 }
2245 {
2246   phpEnd = <PHPEND>
2247   {htmlStart = phpEnd.sourceEnd;}
2248   (phpEchoBlock())*
2249   try {
2250     (<PHPSTARTLONG> | <PHPSTARTSHORT>)
2251     {PHPParser.createNewHTMLCode();}
2252   } catch (ParseException e) {
2253     errorMessage = "unexpected end of file , '<?php' expected";
2254     errorLevel   = ERROR;
2255     errorStart = e.currentToken.sourceStart;
2256     errorEnd   = e.currentToken.sourceEnd;
2257     throw e;
2258   }
2259   {
2260   nbNodes    = nodePtr - startIndex;
2261   if (nbNodes == 0) {
2262     return null;
2263   }
2264   blockNodes = new AstNode[nbNodes];
2265   System.arraycopy(nodes,startIndex+1,blockNodes,0,nbNodes);
2266   nodePtr = startIndex;
2267   return new HTMLBlock(blockNodes);}
2268 }
2269
2270 /**
2271  * An include statement. It's "include" an expression;
2272  */
2273 InclusionStatement IncludeStatement() :
2274 {
2275   Expression expr;
2276   final int keyword;
2277   final InclusionStatement inclusionStatement;
2278   final Token token, token2;
2279   int pos;
2280 }
2281 {
2282       (  token = <REQUIRE>      {keyword = InclusionStatement.REQUIRE;pos=token.sourceEnd;}
2283        | token = <REQUIRE_ONCE> {keyword = InclusionStatement.REQUIRE_ONCE;pos=token.sourceEnd;}
2284        | token = <INCLUDE>      {keyword = InclusionStatement.INCLUDE;pos=token.sourceEnd;}
2285        | token = <INCLUDE_ONCE> {keyword = InclusionStatement.INCLUDE_ONCE;pos=token.sourceEnd;})
2286   try {
2287     expr = Expression()
2288     {pos = expr.sourceEnd;}
2289   } catch (ParseException e) {
2290     if (errorMessage != null) {
2291       throw e;
2292     }
2293     errorMessage = "unexpected token '"+ e.currentToken.next.image+"', expression expected";
2294     errorLevel   = ERROR;
2295     errorStart   = e.currentToken.next.sourceStart;
2296     errorEnd     = e.currentToken.next.sourceEnd;
2297     expr = new ConstantIdentifier(SYNTAX_ERROR_CHAR,pos,pos);
2298     processParseExceptionDebug(e);
2299   }
2300   try {
2301     token2 = <SEMICOLON>
2302     {pos=token2.sourceEnd;}
2303   } catch (ParseException e) {
2304     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2305     errorLevel   = ERROR;
2306     errorStart   = e.currentToken.next.sourceStart;
2307     errorEnd     = e.currentToken.next.sourceEnd;
2308     processParseExceptionDebug(e);
2309   }
2310   {
2311    inclusionStatement = new InclusionStatement(currentSegment,
2312                                                keyword,
2313                                                expr,
2314                                                token.sourceStart,
2315                                                pos);
2316    currentSegment.add(inclusionStatement);
2317    return inclusionStatement;
2318   }
2319 }
2320
2321 PrintExpression PrintExpression() :
2322 {
2323   final Expression expr;
2324   final Token printToken;
2325 }
2326 {
2327   token = <PRINT> expr = Expression()
2328   {return new PrintExpression(expr,token.sourceStart,expr.sourceEnd);}
2329 }
2330
2331 ListExpression ListExpression() :
2332 {
2333   Expression expr = null;
2334   final Expression expression;
2335   final ArrayList list = new ArrayList();
2336   int pos;
2337   final Token listToken, rParen;
2338   Token token;
2339 }
2340 {
2341   listToken = <LIST> {pos = listToken.sourceEnd;}
2342   try {
2343     token = <LPAREN> {pos = token.sourceEnd;}
2344   } catch (ParseException e) {
2345     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
2346     errorLevel   = ERROR;
2347     errorStart   = listToken.sourceEnd+1;
2348     errorEnd     = listToken.sourceEnd+1;
2349     processParseExceptionDebug(e);
2350   }
2351   [
2352     expr = VariableDeclaratorId()
2353     {list.add(expr);pos = expr.sourceEnd;}
2354   ]
2355   {if (expr == null) list.add(null);}
2356   (
2357     try {
2358       token = <COMMA>
2359       {pos = token.sourceEnd;}
2360     } catch (ParseException e) {
2361       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
2362       errorLevel   = ERROR;
2363       errorStart   = pos+1;
2364       errorEnd     = pos+1;
2365       processParseExceptionDebug(e);
2366     }
2367     [expr = VariableDeclaratorId() {list.add(expr);pos = expr.sourceEnd;}]
2368   )*
2369   try {
2370     rParen = <RPAREN>
2371     {pos = rParen.sourceEnd;}
2372   } catch (ParseException e) {
2373     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
2374     errorLevel   = ERROR;
2375     errorStart = pos+1;
2376     errorEnd   = pos+1;
2377       processParseExceptionDebug(e);
2378   }
2379   [ <ASSIGN> expression = Expression()
2380     {
2381     final AbstractVariable[] vars = new AbstractVariable[list.size()];
2382     list.toArray(vars);
2383     return new ListExpression(vars,
2384                               expression,
2385                               listToken.sourceStart,
2386                               expression.sourceEnd);}
2387   ]
2388   {
2389     final AbstractVariable[] vars = new AbstractVariable[list.size()];
2390     list.toArray(vars);
2391     return new ListExpression(vars,listToken.sourceStart,pos);}
2392 }
2393
2394 /**
2395  * An echo statement.
2396  * echo anyexpression (, otherexpression)*
2397  */
2398 EchoStatement EchoStatement() :
2399 {
2400   final ArrayList expressions = new ArrayList();
2401   Expression expr;
2402   Token token;
2403   Token token2 = null;
2404 }
2405 {
2406   token = <ECHO> expr = Expression()
2407   {expressions.add(expr);}
2408   (
2409     <COMMA> expr = Expression()
2410     {expressions.add(expr);}
2411   )*
2412   try {
2413     token2 = <SEMICOLON>
2414   } catch (ParseException e) {
2415     if (e.currentToken.next.kind != 4) {
2416       errorMessage = "';' expected after 'echo' statement";
2417       errorLevel   = ERROR;
2418       errorStart   = e.currentToken.sourceEnd;
2419       errorEnd     = e.currentToken.sourceEnd;
2420       processParseExceptionDebug(e);
2421     }
2422   }
2423   {
2424    final Expression[] exprs = new Expression[expressions.size()];
2425    expressions.toArray(exprs);
2426    if (token2 == null) {
2427      return new EchoStatement(exprs,token.sourceStart, exprs[exprs.length-1].sourceEnd);
2428    }
2429    return new EchoStatement(exprs,token.sourceStart, token2.sourceEnd);
2430    }
2431 }
2432
2433 GlobalStatement GlobalStatement() :
2434 {
2435    Variable expr;
2436    final ArrayList vars = new ArrayList();
2437    final GlobalStatement global;
2438    final Token token, token2;
2439    int pos;
2440 }
2441 {
2442   token = <GLOBAL>
2443     expr = Variable()
2444     {vars.add(expr);pos = expr.sourceEnd+1;}
2445   (<COMMA>
2446     expr = Variable()
2447     {vars.add(expr);pos = expr.sourceEnd+1;}
2448   )*
2449   try {
2450     token2 = <SEMICOLON>
2451     {pos = token2.sourceEnd+1;}
2452   } catch (ParseException e) {
2453     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2454     errorLevel   = ERROR;
2455     errorStart = pos;
2456     errorEnd   = pos;
2457     processParseExceptionDebug(e);
2458   }
2459     {
2460     final Variable[] variables = new Variable[vars.size()];
2461     vars.toArray(variables);
2462     global = new GlobalStatement(currentSegment,
2463                                  variables,
2464                                  token.sourceStart,
2465                                  pos);
2466     currentSegment.add(global);
2467     return global;}
2468 }
2469
2470 StaticStatement StaticStatement() :
2471 {
2472   final ArrayList vars = new ArrayList();
2473   VariableDeclaration expr;
2474   final Token token, token2;
2475   int pos;
2476 }
2477 {
2478   token = <STATIC> expr = VariableDeclarator() {vars.add(expr);pos = expr.sourceEnd+1;}
2479   (
2480     <COMMA> expr = VariableDeclarator() {vars.add(expr);pos = expr.sourceEnd+1;}
2481   )*
2482   try {
2483     token2 = <SEMICOLON>
2484     {pos = token2.sourceEnd+1;}
2485   } catch (ParseException e) {
2486     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2487     errorLevel   = ERROR;
2488     errorStart = pos;
2489     errorEnd   = pos;
2490     processParseException(e);
2491   }
2492     {
2493     final VariableDeclaration[] variables = new VariableDeclaration[vars.size()];
2494     vars.toArray(variables);
2495     return new StaticStatement(variables,
2496                                token.sourceStart,
2497                                pos);}
2498 }
2499
2500 LabeledStatement LabeledStatement() :
2501 {
2502   final Token label;
2503   final Statement statement;
2504 }
2505 {
2506   label = <IDENTIFIER> <COLON> statement = Statement()
2507   {return new LabeledStatement(label.image,statement,label.sourceStart,statement.sourceEnd);}
2508 }
2509
2510 /**
2511  * A Block is
2512  * {
2513  * statements
2514  * }.
2515  * @return a block
2516  */
2517 Block Block() :
2518 {
2519   final ArrayList list = new ArrayList();
2520   Statement statement;
2521   final Token token, token2;
2522   int pos,start;
2523 }
2524 {
2525   try {
2526     token = <LBRACE>
2527     {pos = token.sourceEnd+1;start=token.sourceStart;}
2528   } catch (ParseException e) {
2529     errorMessage = "'{' expected";
2530     errorLevel   = ERROR;
2531     pos = PHPParser.token.sourceEnd+1;
2532     start=pos;
2533     errorStart = pos;
2534     errorEnd   = pos;
2535     processParseExceptionDebug(e);
2536   }
2537   ( statement = BlockStatement() {list.add(statement);pos = statement.sourceEnd+1;}
2538   | statement = htmlBlock()      {if (statement != null) {
2539                                     list.add(statement);
2540                                     pos = statement.sourceEnd+1;
2541                                   }
2542                                   pos = PHPParser.token.sourceEnd+1;
2543                                  }
2544   )*
2545   try {
2546     token2 = <RBRACE>
2547     {pos = token2.sourceEnd+1;}
2548   } catch (ParseException e) {
2549     errorMessage = "unexpected token : '"+ e.currentToken.image +"', '}' expected";
2550     errorLevel   = ERROR;
2551     errorStart = pos;
2552     errorEnd   = pos;
2553     processParseExceptionDebug(e);
2554   }
2555   {
2556   final Statement[] statements = new Statement[list.size()];
2557   list.toArray(statements);
2558   return new Block(statements,start,pos);}
2559 }
2560
2561 Statement BlockStatement() :
2562 {
2563   final Statement statement;
2564 }
2565 {
2566   try {
2567     statement = Statement()         {if (phpDocument == currentSegment) pushOnAstNodes(statement);
2568                                      return statement;}
2569   } catch (ParseException e) {
2570     errorMessage = "unexpected token : '"+ e.currentToken.image +"', a statement was expected";
2571     errorLevel   = ERROR;
2572     errorStart = e.currentToken.sourceStart;
2573     errorEnd   = e.currentToken.sourceEnd;
2574     throw e;
2575   }
2576 | statement = ClassDeclaration()  {return statement;}
2577 | statement = MethodDeclaration() {if (phpDocument == currentSegment) pushOnAstNodes(statement);
2578                                    currentSegment.add((MethodDeclaration) statement);
2579                                    ((MethodDeclaration) statement).analyzeCode();
2580                                    return statement;}
2581 }
2582
2583 /**
2584  * A Block statement that will not contain any 'break'
2585  */
2586 Statement BlockStatementNoBreak() :
2587 {
2588   final Statement statement;
2589 }
2590 {
2591   statement = StatementNoBreak()  {return statement;}
2592 | statement = ClassDeclaration()  {return statement;}
2593 | statement = MethodDeclaration() {currentSegment.add((MethodDeclaration) statement);
2594                                    ((MethodDeclaration) statement).analyzeCode();
2595                                    return statement;}
2596 }
2597
2598 /**
2599  * used only by ForInit()
2600  */
2601 Expression[] LocalVariableDeclaration() :
2602 {
2603   final ArrayList list = new ArrayList();
2604   Expression var;
2605 }
2606 {
2607   var = Expression()
2608   {list.add(var);}
2609   ( <COMMA> var = Expression() {list.add(var);})*
2610   {
2611     final Expression[] vars = new Expression[list.size()];
2612     list.toArray(vars);
2613     return vars;
2614   }
2615 }
2616
2617 /**
2618  * used only by LocalVariableDeclaration().
2619  */
2620 VariableDeclaration LocalVariableDeclarator() :
2621 {
2622   final Variable varName;
2623   Expression initializer = null;
2624 }
2625 {
2626   varName = Variable() [ <ASSIGN> initializer = Expression() ]
2627   {
2628    if (initializer == null) {
2629     return new VariableDeclaration(currentSegment,
2630                                    varName,
2631                                    varName.sourceStart,
2632                                    varName.sourceEnd);
2633    }
2634     return new VariableDeclaration(currentSegment,
2635                                    varName,
2636                                    initializer,
2637                                    VariableDeclaration.EQUAL,
2638                                    varName.sourceStart);
2639   }
2640 }
2641
2642 EmptyStatement EmptyStatement() :
2643 {
2644   final Token token;
2645 }
2646 {
2647   token = <SEMICOLON>
2648   {return new EmptyStatement(token.sourceStart,token.sourceEnd);}
2649 }
2650
2651 /**
2652  * used only by StatementExpressionList() which is used only by ForInit() and ForStatement()
2653  */
2654 Expression StatementExpression() :
2655 {
2656   final Expression expr;
2657   final Token operator;
2658 }
2659 {
2660   expr = PreIncDecExpression() {return expr;}
2661 |
2662   expr = PrimaryExpression()
2663   [ operator = <PLUS_PLUS> {return new PostfixedUnaryExpression(expr,
2664                                                                 OperatorIds.PLUS_PLUS,
2665                                                                 operator.sourceEnd);}
2666   | operator = <MINUS_MINUS> {return new PostfixedUnaryExpression(expr,
2667                                                                   OperatorIds.MINUS_MINUS,
2668                                                                   operator.sourceEnd);}
2669   ]
2670   {return expr;}
2671 }
2672
2673 SwitchStatement SwitchStatement() :
2674 {
2675   Expression variable;
2676   final AbstractCase[] cases;
2677   final Token switchToken,lparenToken,rparenToken;
2678   int pos;
2679 }
2680 {
2681   switchToken = <SWITCH> {pos = switchToken.sourceEnd+1;}
2682   try {
2683     lparenToken = <LPAREN>
2684     {pos = lparenToken.sourceEnd+1;}
2685   } catch (ParseException e) {
2686     errorMessage = "'(' expected after 'switch'";
2687     errorLevel   = ERROR;
2688     errorStart = pos;
2689     errorEnd   = pos;
2690     processParseExceptionDebug(e);
2691   }
2692   try {
2693     variable = Expression() {pos = variable.sourceEnd+1;}
2694   } catch (ParseException e) {
2695     if (errorMessage != null) {
2696       throw e;
2697     }
2698     errorMessage = "expression expected";
2699     errorLevel   = ERROR;
2700     errorStart = pos;
2701     errorEnd   = pos;
2702     processParseExceptionDebug(e);
2703     variable = new ConstantIdentifier(SYNTAX_ERROR_CHAR,pos,pos);
2704   }
2705   try {
2706     rparenToken = <RPAREN> {pos = rparenToken.sourceEnd+1;}
2707   } catch (ParseException e) {
2708     errorMessage = "')' expected";
2709     errorLevel   = ERROR;
2710     errorStart = pos;
2711     errorEnd   = pos;
2712     processParseExceptionDebug(e);
2713   }
2714   (  cases = switchStatementBrace()
2715    | cases = switchStatementColon(switchToken.sourceStart, switchToken.sourceEnd))
2716   {return new SwitchStatement(variable,
2717                               cases,
2718                               switchToken.sourceStart,
2719                               PHPParser.token.sourceEnd);}
2720 }
2721
2722 AbstractCase[] switchStatementBrace() :
2723 {
2724   AbstractCase cas;
2725   final ArrayList cases = new ArrayList();
2726   Token token;
2727   int pos;
2728 }
2729 {
2730   token = <LBRACE> {pos = token.sourceEnd;}
2731  ( cas = switchLabel0() {cases.add(cas);pos = cas.sourceEnd;})*
2732   try {
2733     token = <RBRACE>
2734     {pos = token.sourceEnd;}
2735   } catch (ParseException e) {
2736     errorMessage = "'}' expected";
2737     errorLevel   = ERROR;
2738     errorStart = pos+1;
2739     errorEnd   = pos+1;
2740     processParseExceptionDebug(e);
2741   }
2742   {
2743     final AbstractCase[] abcase = new AbstractCase[cases.size()];
2744     cases.toArray(abcase);
2745     return abcase;
2746   }
2747 }
2748
2749 /**
2750  * A Switch statement with : ... endswitch;
2751  * @param start the begin offset of the switch
2752  * @param end the end offset of the switch
2753  */
2754 AbstractCase[] switchStatementColon(final int start, final int end) :
2755 {
2756   AbstractCase cas;
2757   final ArrayList cases = new ArrayList();
2758   Token token;
2759   int pos;
2760 }
2761 {
2762   token = <COLON> {pos = token.sourceEnd;}
2763   {try {
2764   setMarker(fileToParse,
2765             "Ugly syntax detected, you should switch () {...} instead of switch (): ... enswitch;",
2766             start,
2767             end,
2768             INFO,
2769             "Line " + token.beginLine);
2770   } catch (CoreException e) {
2771     PHPeclipsePlugin.log(e);
2772   }}
2773   ( cas = switchLabel0() {cases.add(cas);pos = cas.sourceEnd;})*
2774   try {
2775     token = <ENDSWITCH> {pos = token.sourceEnd;}
2776   } catch (ParseException e) {
2777     errorMessage = "'endswitch' expected";
2778     errorLevel   = ERROR;
2779     errorStart = pos+1;
2780     errorEnd   = pos+1;
2781     processParseExceptionDebug(e);
2782   }
2783   try {
2784     token = <SEMICOLON> {pos = token.sourceEnd;}
2785   } catch (ParseException e) {
2786     errorMessage = "';' expected after 'endswitch' keyword";
2787     errorLevel   = ERROR;
2788     errorStart = pos+1;
2789     errorEnd   = pos+1;
2790     processParseExceptionDebug(e);
2791   }
2792   {
2793     final AbstractCase[] abcase = new AbstractCase[cases.size()];
2794     cases.toArray(abcase);
2795     return abcase;
2796   }
2797 }
2798
2799 AbstractCase switchLabel0() :
2800 {
2801   final Expression expr;
2802   Statement statement;
2803   final ArrayList stmts = new ArrayList();
2804   final Token token = PHPParser.token;
2805   final int start = PHPParser.token.next.sourceStart;
2806 }
2807 {
2808   expr = SwitchLabel()
2809   ( statement = BlockStatementNoBreak() {stmts.add(statement);}
2810   | statement = htmlBlock()             {if (statement != null) {stmts.add(statement);}}
2811   | statement = BreakStatement()        {stmts.add(statement);})*
2812   //[ statement = BreakStatement()        {stmts.add(statement);}]
2813   {
2814     final int listSize = stmts.size();
2815     final Statement[] stmtsArray = new Statement[listSize];
2816     stmts.toArray(stmtsArray);
2817     if (expr == null) {//it's a default
2818       final int end = PHPParser.token.next.sourceStart;
2819       return new DefaultCase(stmtsArray,start,end);
2820     }
2821     if (listSize != 0) {
2822       return new Case(expr,stmtsArray,expr.sourceStart,stmtsArray[listSize-1].sourceEnd);
2823     } else {
2824       return new Case(expr,stmtsArray,expr.sourceStart,expr.sourceEnd);
2825     }
2826   }
2827 }
2828
2829 /**
2830  * A SwitchLabel.
2831  * case Expression() :
2832  * default :
2833  * @return the if it was a case and null if not
2834  */
2835 Expression SwitchLabel() :
2836 {
2837   final Expression expr;
2838 }
2839 {
2840   token = <CASE>
2841   try {
2842     expr = Expression()
2843   } catch (ParseException e) {
2844     if (errorMessage != null) throw e;
2845     errorMessage = "expression expected after 'case' keyword";
2846     errorLevel   = ERROR;
2847     errorStart = token.sourceEnd +1;
2848     errorEnd   = token.sourceEnd +1;
2849     throw e;
2850   }
2851   try {
2852     token = <COLON>
2853   } catch (ParseException e) {
2854     errorMessage = "':' expected after case expression";
2855     errorLevel   = ERROR;
2856     errorStart = expr.sourceEnd+1;
2857     errorEnd   = expr.sourceEnd+1;
2858     processParseExceptionDebug(e);
2859   }
2860   {return expr;}
2861 |
2862   token = <_DEFAULT>
2863   try {
2864     <COLON>
2865   } catch (ParseException e) {
2866     errorMessage = "':' expected after 'default' keyword";
2867     errorLevel   = ERROR;
2868     errorStart = token.sourceEnd+1;
2869     errorEnd   = token.sourceEnd+1;
2870     processParseExceptionDebug(e);
2871   }
2872   {return null;}
2873 }
2874
2875 Break BreakStatement() :
2876 {
2877   Expression expression = null;
2878   final Token token, token2;
2879   int pos;
2880 }
2881 {
2882   token = <BREAK> {pos = token.sourceEnd+1;}
2883   [ expression = Expression() {pos = expression.sourceEnd+1;}]
2884   try {
2885     token2 = <SEMICOLON>
2886     {pos = token2.sourceEnd;}
2887   } catch (ParseException e) {
2888     errorMessage = "';' expected after 'break' keyword";
2889     errorLevel   = ERROR;
2890     errorStart = pos;
2891     errorEnd   = pos;
2892     processParseExceptionDebug(e);
2893   }
2894   {return new Break(expression, token.sourceStart, pos);}
2895 }
2896
2897 IfStatement IfStatement() :
2898 {
2899   final Expression condition;
2900   final IfStatement ifStatement;
2901   Token token;
2902 }
2903 {
2904   token = <IF> condition = Condition("if")
2905   ifStatement = IfStatement0(condition,token.sourceStart,token.sourceEnd)
2906   {return ifStatement;}
2907 }
2908
2909
2910 Expression Condition(final String keyword) :
2911 {
2912   final Expression condition;
2913 }
2914 {
2915   try {
2916     <LPAREN>
2917   } catch (ParseException e) {
2918     errorMessage = "'(' expected after " + keyword + " keyword";
2919     errorLevel   = ERROR;
2920     errorStart = PHPParser.token.sourceEnd + 1;
2921     errorEnd   = PHPParser.token.sourceEnd + 1;
2922     processParseExceptionDebug(e);
2923   }
2924   condition = Expression()
2925   try {
2926      <RPAREN>
2927   } catch (ParseException e) {
2928     errorMessage = "')' expected after " + keyword + " keyword";
2929     errorLevel   = ERROR;
2930     errorStart = condition.sourceEnd+1;
2931     errorEnd   = condition.sourceEnd+1;
2932     processParseExceptionDebug(e);
2933   }
2934   {return condition;}
2935 }
2936
2937 IfStatement IfStatement0(final Expression condition, final int start,final int end) :
2938 {
2939   Statement statement;
2940   final Statement stmt;
2941   final Statement[] statementsArray;
2942   ElseIf elseifStatement;
2943   Else elseStatement = null;
2944   final ArrayList stmts;
2945   final ArrayList elseIfList = new ArrayList();
2946   final ElseIf[] elseIfs;
2947   int pos = SimpleCharStream.getPosition();
2948   final int endStatements;
2949 }
2950 {
2951   <COLON>
2952   {stmts = new ArrayList();}
2953   (  statement = Statement() {stmts.add(statement);}
2954    | statement = htmlBlock() {if (statement != null) {stmts.add(statement);}})*
2955    {endStatements = SimpleCharStream.getPosition();}
2956    (elseifStatement = ElseIfStatementColon() {elseIfList.add(elseifStatement);})*
2957    [elseStatement = ElseStatementColon()]
2958
2959   {try {
2960   setMarker(fileToParse,
2961             "Ugly syntax detected, you should if () {...} instead of if (): ... endif;",
2962             start,
2963             end,
2964             INFO,
2965             "Line " + token.beginLine);
2966   } catch (CoreException e) {
2967     PHPeclipsePlugin.log(e);
2968   }}
2969   try {
2970     <ENDIF>
2971   } catch (ParseException e) {
2972     errorMessage = "'endif' expected";
2973     errorLevel   = ERROR;
2974     errorStart = e.currentToken.sourceStart;
2975     errorEnd   = e.currentToken.sourceEnd;
2976     throw e;
2977   }
2978   try {
2979     <SEMICOLON>
2980   } catch (ParseException e) {
2981     errorMessage = "';' expected after 'endif' keyword";
2982     errorLevel   = ERROR;
2983     errorStart = e.currentToken.sourceStart;
2984     errorEnd   = e.currentToken.sourceEnd;
2985     throw e;
2986   }
2987     {
2988     elseIfs = new ElseIf[elseIfList.size()];
2989     elseIfList.toArray(elseIfs);
2990     if (stmts.size() == 1) {
2991       return new IfStatement(condition,
2992                              (Statement) stmts.get(0),
2993                               elseIfs,
2994                               elseStatement,
2995                               pos,
2996                               SimpleCharStream.getPosition());
2997     } else {
2998       statementsArray = new Statement[stmts.size()];
2999       stmts.toArray(statementsArray);
3000       return new IfStatement(condition,
3001                              new Block(statementsArray,pos,endStatements),
3002                              elseIfs,
3003                              elseStatement,
3004                              pos,
3005                              SimpleCharStream.getPosition());
3006     }
3007     }
3008
3009 |
3010   (stmt = Statement() | stmt = htmlBlock())
3011   ( LOOKAHEAD(1) elseifStatement = ElseIfStatement() {elseIfList.add(elseifStatement);})*
3012   [ LOOKAHEAD(1)
3013     <ELSE>
3014     try {
3015       {pos = SimpleCharStream.getPosition();}
3016       statement = Statement()
3017       {elseStatement = new Else(statement,pos,SimpleCharStream.getPosition());}
3018     } catch (ParseException e) {
3019       if (errorMessage != null) {
3020         throw e;
3021       }
3022       errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected";
3023       errorLevel   = ERROR;
3024       errorStart = e.currentToken.sourceStart;
3025       errorEnd   = e.currentToken.sourceEnd;
3026       throw e;
3027     }
3028   ]
3029   {
3030     elseIfs = new ElseIf[elseIfList.size()];
3031     elseIfList.toArray(elseIfs);
3032     return new IfStatement(condition,
3033                            stmt,
3034                            elseIfs,
3035                            elseStatement,
3036                            pos,
3037                            SimpleCharStream.getPosition());}
3038 }
3039
3040 ElseIf ElseIfStatementColon() :
3041 {
3042   final Expression condition;
3043   Statement statement;
3044   final ArrayList list = new ArrayList();
3045   final Token elseifToken;
3046 }
3047 {
3048   elseifToken = <ELSEIF> condition = Condition("elseif")
3049   <COLON> (  statement = Statement() {list.add(statement);}
3050            | statement = htmlBlock() {if (statement != null) {list.add(statement);}})*
3051   {
3052   final int sizeList = list.size();
3053   final Statement[] stmtsArray = new Statement[sizeList];
3054   list.toArray(stmtsArray);
3055   return new ElseIf(condition,stmtsArray ,
3056                     elseifToken.sourceStart,
3057                     stmtsArray[sizeList-1].sourceEnd);}
3058 }
3059
3060 Else ElseStatementColon() :
3061 {
3062   Statement statement;
3063   final ArrayList list = new ArrayList();
3064   final Token elseToken;
3065 }
3066 {
3067   elseToken = <ELSE> <COLON> (  statement = Statement() {list.add(statement);}
3068                   | statement = htmlBlock() {if (statement != null) {list.add(statement);}})*
3069   {
3070   final int sizeList = list.size();
3071   final Statement[] stmtsArray = new Statement[sizeList];
3072   list.toArray(stmtsArray);
3073   return new Else(stmtsArray,elseToken.sourceStart,stmtsArray[sizeList-1].sourceEnd);}
3074 }
3075
3076 ElseIf ElseIfStatement() :
3077 {
3078   final Expression condition;
3079   //final Statement statement;
3080   final Token elseifToken;
3081   final Statement[] statement = new Statement[1];
3082 }
3083 {
3084   elseifToken = <ELSEIF> condition = Condition("elseif") statement[0] = Statement()
3085   {
3086   return new ElseIf(condition,statement,elseifToken.sourceStart,statement[0].sourceEnd);}
3087 }
3088
3089 WhileStatement WhileStatement() :
3090 {
3091   final Expression condition;
3092   final Statement action;
3093   final Token whileToken;
3094 }
3095 {
3096   whileToken = <WHILE>
3097     condition = Condition("while")
3098     action    = WhileStatement0(whileToken.sourceStart,whileToken.sourceEnd)
3099     {return new WhileStatement(condition,action,whileToken.sourceStart,action.sourceEnd);}
3100 }
3101
3102 Statement WhileStatement0(final int start, final int end) :
3103 {
3104   Statement statement;
3105   final ArrayList stmts = new ArrayList();
3106   final int pos = SimpleCharStream.getPosition();
3107 }
3108 {
3109   <COLON> (statement = Statement() {stmts.add(statement);})*
3110   {try {
3111   setMarker(fileToParse,
3112             "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;",
3113             start,
3114             end,
3115             INFO,
3116             "Line " + token.beginLine);
3117   } catch (CoreException e) {
3118     PHPeclipsePlugin.log(e);
3119   }}
3120   try {
3121     <ENDWHILE>
3122   } catch (ParseException e) {
3123     errorMessage = "'endwhile' expected";
3124     errorLevel   = ERROR;
3125     errorStart = e.currentToken.sourceStart;
3126     errorEnd   = e.currentToken.sourceEnd;
3127     throw e;
3128   }
3129   try {
3130     <SEMICOLON>
3131     {
3132     final Statement[] stmtsArray = new Statement[stmts.size()];
3133     stmts.toArray(stmtsArray);
3134     return new Block(stmtsArray,pos,SimpleCharStream.getPosition());}
3135   } catch (ParseException e) {
3136     errorMessage = "';' expected after 'endwhile' keyword";
3137     errorLevel   = ERROR;
3138     errorStart = e.currentToken.sourceStart;
3139     errorEnd   = e.currentToken.sourceEnd;
3140     throw e;
3141   }
3142 |
3143   statement = Statement()
3144   {return statement;}
3145 }
3146
3147 DoStatement DoStatement() :
3148 {
3149   final Statement action;
3150   final Expression condition;
3151   final Token token;
3152   Token token2 = null;
3153 }
3154 {
3155   token = <DO> action = Statement() <WHILE> condition = Condition("while")
3156   try {
3157     token2 = <SEMICOLON>
3158   } catch (ParseException e) {
3159     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
3160     errorLevel   = ERROR;
3161     errorStart = condition.sourceEnd+1;
3162     errorEnd   = condition.sourceEnd+1;
3163     processParseExceptionDebug(e);
3164   }
3165   {
3166     if (token2 == null) {
3167       return new DoStatement(condition,action,token.sourceStart,condition.sourceEnd);
3168     }
3169     return new DoStatement(condition,action,token.sourceStart,token2.sourceEnd);
3170   }
3171 }
3172
3173 ForeachStatement ForeachStatement() :
3174 {
3175   Statement statement = null;
3176   Expression expression = null;
3177   ArrayVariableDeclaration variable = null;
3178   Token foreachToken;
3179   Token lparenToken = null;
3180   Token asToken = null;
3181   Token rparenToken = null;
3182   int pos;
3183 }
3184 {
3185   foreachToken = <FOREACH>
3186   try {
3187     lparenToken = <LPAREN>
3188     {pos = lparenToken.sourceEnd+1;}
3189   } catch (ParseException e) {
3190     errorMessage = "'(' expected after 'foreach' keyword";
3191     errorLevel   = ERROR;
3192     errorStart = e.currentToken.sourceStart;
3193     errorEnd   = e.currentToken.sourceEnd;
3194     processParseExceptionDebug(e);
3195     {pos = foreachToken.sourceEnd+1;}
3196   }
3197   try {
3198     expression = Expression()
3199     {pos = expression.sourceEnd+1;}
3200   } catch (ParseException e) {
3201     errorMessage = "variable expected";
3202     errorLevel   = ERROR;
3203     errorStart = e.currentToken.sourceStart;
3204     errorEnd   = e.currentToken.sourceEnd;
3205     processParseExceptionDebug(e);
3206   }
3207   try {
3208     asToken = <AS>
3209     {pos = asToken.sourceEnd+1;}
3210   } catch (ParseException e) {
3211     errorMessage = "'as' expected";
3212     errorLevel   = ERROR;
3213     errorStart = e.currentToken.sourceStart;
3214     errorEnd   = e.currentToken.sourceEnd;
3215     processParseExceptionDebug(e);
3216   }
3217   try {
3218     variable = ArrayVariable()
3219     {pos = variable.sourceEnd+1;}
3220   } catch (ParseException e) {
3221     if (errorMessage != null) throw e;
3222     errorMessage = "variable expected";
3223     errorLevel   = ERROR;
3224     errorStart = e.currentToken.sourceStart;
3225     errorEnd   = e.currentToken.sourceEnd;
3226     processParseExceptionDebug(e);
3227   }
3228   try {
3229     rparenToken = <RPAREN>
3230     {pos = rparenToken.sourceEnd+1;}
3231   } catch (ParseException e) {
3232     errorMessage = "')' expected after 'foreach' keyword";
3233     errorLevel   = ERROR;
3234     errorStart = e.currentToken.sourceStart;
3235     errorEnd   = e.currentToken.sourceEnd;
3236     processParseExceptionDebug(e);
3237   }
3238   try {
3239     statement = Statement()
3240     {pos = statement.sourceEnd+1;}
3241   } catch (ParseException e) {
3242     if (errorMessage != null) throw e;
3243     errorMessage = "statement expected";
3244     errorLevel   = ERROR;
3245     errorStart = e.currentToken.sourceStart;
3246     errorEnd   = e.currentToken.sourceEnd;
3247     processParseExceptionDebug(e);
3248   }
3249   {
3250    return new ForeachStatement(expression,
3251                                variable,
3252                                statement,
3253                                foreachToken.sourceStart,
3254                                pos);}
3255
3256 }
3257
3258 /**
3259  * a for declaration.
3260  * @return a node representing the for statement
3261  */
3262 ForStatement ForStatement() :
3263 {
3264 final Token token,tokenEndFor,token2,tokenColon;
3265 int pos;
3266 Expression[] initializations = null;
3267 Expression condition = null;
3268 Expression[] increments = null;
3269 Statement action;
3270 final ArrayList list = new ArrayList();
3271 }
3272 {
3273   token = <FOR>
3274   try {
3275     <LPAREN>
3276   } catch (ParseException e) {
3277     errorMessage = "'(' expected after 'for' keyword";
3278     errorLevel   = ERROR;
3279     errorStart = token.sourceEnd;
3280     errorEnd   = token.sourceEnd +1;
3281     processParseExceptionDebug(e);
3282   }
3283      [ initializations = ForInit() ] <SEMICOLON>
3284      [ condition = Expression() ] <SEMICOLON>
3285      [ increments = StatementExpressionList() ] <RPAREN>
3286     (
3287       action = Statement()
3288       {return new ForStatement(initializations,
3289                                condition,
3290                                increments,
3291                                action,
3292                                token.sourceStart,
3293                                action.sourceEnd);}
3294     |
3295       tokenColon = <COLON> {pos = tokenColon.sourceEnd+1;}
3296       (action = Statement() {list.add(action);pos = action.sourceEnd+1;})*
3297       {
3298         try {
3299         setMarker(fileToParse,
3300                   "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;",
3301                   token.sourceStart,
3302                   token.sourceEnd,
3303                   INFO,
3304                   "Line " + token.beginLine);
3305         } catch (CoreException e) {
3306           PHPeclipsePlugin.log(e);
3307         }
3308       }
3309       try {
3310         tokenEndFor = <ENDFOR>
3311         {pos = tokenEndFor.sourceEnd+1;}
3312       } catch (ParseException e) {
3313         errorMessage = "'endfor' expected";
3314         errorLevel   = ERROR;
3315         errorStart = pos;
3316         errorEnd   = pos;
3317         processParseExceptionDebug(e);
3318       }
3319       try {
3320         token2 = <SEMICOLON>
3321         {pos = token2.sourceEnd+1;}
3322       } catch (ParseException e) {
3323         errorMessage = "';' expected after 'endfor' keyword";
3324         errorLevel   = ERROR;
3325         errorStart = pos;
3326         errorEnd   = pos;
3327         processParseExceptionDebug(e);
3328       }
3329       {
3330       final Statement[] stmtsArray = new Statement[list.size()];
3331       list.toArray(stmtsArray);
3332       return new ForStatement(initializations,
3333                               condition,
3334                               increments,
3335                               new Block(stmtsArray,
3336                                         stmtsArray[0].sourceStart,
3337                                         stmtsArray[stmtsArray.length-1].sourceEnd),
3338                               token.sourceStart,
3339                               pos);}
3340     )
3341 }
3342
3343 Expression[] ForInit() :
3344 {
3345   final Expression[] exprs;
3346 }
3347 {
3348   LOOKAHEAD(LocalVariableDeclaration())
3349   exprs = LocalVariableDeclaration()
3350   {return exprs;}
3351 |
3352   exprs = StatementExpressionList()
3353   {return exprs;}
3354 }
3355
3356 Expression[] StatementExpressionList() :
3357 {
3358   final ArrayList list = new ArrayList();
3359   final Expression expr;
3360 }
3361 {
3362   expr = Expression()   {list.add(expr);}
3363   (<COMMA> Expression() {list.add(expr);})*
3364   {
3365     final Expression[] exprsArray = new Expression[list.size()];
3366     list.toArray(exprsArray);
3367     return exprsArray;
3368   }
3369 }
3370
3371 Continue ContinueStatement() :
3372 {
3373   Expression expr = null;
3374   final Token token;
3375   Token token2 = null;
3376 }
3377 {
3378   token = <CONTINUE> [ expr = Expression() ]
3379   try {
3380     token2 = <SEMICOLON>
3381   } catch (ParseException e) {
3382     errorMessage = "';' expected after 'continue' statement";
3383     errorLevel   = ERROR;
3384     if (expr == null) {
3385       errorStart = token.sourceEnd+1;
3386       errorEnd   = token.sourceEnd+1;
3387     } else {
3388       errorStart = expr.sourceEnd+1;
3389       errorEnd   = expr.sourceEnd+1;
3390     }
3391     processParseExceptionDebug(e);
3392   }
3393   {
3394     if (token2 == null) {
3395       if (expr == null) {
3396         return new Continue(expr,token.sourceStart,token.sourceEnd);
3397       }
3398       return new Continue(expr,token.sourceStart,expr.sourceEnd);
3399     }
3400     return new Continue(expr,token.sourceStart,token2.sourceEnd);
3401   }
3402 }
3403
3404 ReturnStatement ReturnStatement() :
3405 {
3406   Expression expr = null;
3407   final Token token;
3408   Token token2 = null;
3409 }
3410 {
3411   token = <RETURN> [ expr = Expression() ]
3412   try {
3413     token2 = <SEMICOLON>
3414   } catch (ParseException e) {
3415     errorMessage = "';' expected after 'return' statement";
3416     errorLevel   = ERROR;
3417     if (expr == null) {
3418       errorStart = token.sourceEnd+1;
3419       errorEnd   = token.sourceEnd+1;
3420     } else {
3421       errorStart = expr.sourceEnd+1;
3422       errorEnd   = expr.sourceEnd+1;
3423     }
3424     processParseExceptionDebug(e);
3425   }
3426   {
3427     if (token2 == null) {
3428       if (expr == null) {
3429         return new ReturnStatement(expr,token.sourceStart,token.sourceEnd);
3430       }
3431       return new ReturnStatement(expr,token.sourceStart,expr.sourceEnd);
3432     }
3433     return new ReturnStatement(expr,token.sourceStart,token2.sourceEnd);
3434   }
3435 }
3436