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