c1d2e5272d63c421914bf0641aebb83f2ec797f0
[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   final Variable var;
1076   AbstractVariable expression = null;
1077 }
1078 {
1079   try {
1080     var = Variable()
1081     (
1082       LOOKAHEAD(2)
1083       expression = VariableSuffix(var)
1084     )*
1085     {
1086      if (expression == null) {
1087        return var;
1088      }
1089      return expression;
1090     }
1091   } catch (ParseException e) {
1092     errorMessage = "'$' expected for variable identifier";
1093     errorLevel   = ERROR;
1094     errorStart = e.currentToken.sourceStart;
1095     errorEnd   = e.currentToken.sourceEnd;
1096     throw e;
1097   }
1098 }
1099
1100 Variable Variable() :
1101 {
1102   Variable variable = null;
1103   final Token token;
1104 }
1105 {
1106   token = <DOLLAR> variable = Var()
1107   {
1108     return variable;
1109   }
1110 }
1111
1112 Variable Var() :
1113 {
1114   Variable variable = null;
1115   final Token token,token2;
1116   ConstantIdentifier constant;
1117   Expression expression;
1118 }
1119 {
1120   token = <DOLLAR> variable = Var()
1121   {return new Variable(variable,variable.sourceStart,variable.sourceEnd);}
1122 |
1123   token = <LBRACE> expression = Expression() token2 = <RBRACE>
1124   {
1125    return new Variable(expression,
1126                        token.sourceStart,
1127                        token2.sourceEnd);
1128   }
1129 |
1130   token = <IDENTIFIER>
1131   {
1132    outlineInfo.addVariable('$' + token.image);
1133    return new Variable(token.image,token.sourceStart,token.sourceEnd);
1134   }
1135 }
1136
1137 Expression VariableInitializer() :
1138 {
1139   final Expression expr;
1140   final Token token, token2;
1141 }
1142 {
1143   expr = Literal()
1144   {return expr;}
1145 |
1146   token2 = <MINUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1147   {return new PrefixedUnaryExpression(new NumberLiteral(token),
1148                                       OperatorIds.MINUS,
1149                                       token2.sourceStart);}
1150 |
1151   token2 = <PLUS> (token = <INTEGER_LITERAL> | token = <FLOATING_POINT_LITERAL>)
1152   {return new PrefixedUnaryExpression(new NumberLiteral(token),
1153                                       OperatorIds.PLUS,
1154                                       token2.sourceStart);}
1155 |
1156   expr = ArrayDeclarator()
1157   {return expr;}
1158 |
1159   token = <IDENTIFIER>
1160   {return new ConstantIdentifier(token);}
1161 }
1162
1163 ArrayVariableDeclaration ArrayVariable() :
1164 {
1165 final Expression expr,expr2;
1166 }
1167 {
1168   expr = Expression()
1169   [
1170     <ARRAYASSIGN> expr2 = Expression()
1171     {return new ArrayVariableDeclaration(expr,expr2);}
1172   ]
1173   {return new ArrayVariableDeclaration(expr,jj_input_stream.getPosition());}
1174 }
1175
1176 ArrayVariableDeclaration[] ArrayInitializer() :
1177 {
1178   ArrayVariableDeclaration expr;
1179   final ArrayList list = new ArrayList();
1180 }
1181 {
1182   <LPAREN>
1183     [
1184       expr = ArrayVariable()
1185       {list.add(expr);}
1186       ( LOOKAHEAD(2) <COMMA> expr = ArrayVariable()
1187       {list.add(expr);}
1188       )*
1189     ]
1190     [
1191       <COMMA> {list.add(null);}
1192     ]
1193   <RPAREN>
1194   {
1195   final ArrayVariableDeclaration[] vars = new ArrayVariableDeclaration[list.size()];
1196   list.toArray(vars);
1197   return vars;}
1198 }
1199
1200 /**
1201  * A Method Declaration.
1202  * <b>function</b> MetodDeclarator() Block()
1203  */
1204 MethodDeclaration MethodDeclaration() :
1205 {
1206   final MethodDeclaration functionDeclaration;
1207   final Block block;
1208   final OutlineableWithChildren seg = currentSegment;
1209   final Token token;
1210 }
1211 {
1212   token = <FUNCTION>
1213   try {
1214     functionDeclaration = MethodDeclarator(token.sourceStart)
1215     {outlineInfo.addVariable(functionDeclaration.name);}
1216   } catch (ParseException e) {
1217     if (errorMessage != null)  throw e;
1218     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
1219     errorLevel   = ERROR;
1220     errorStart = e.currentToken.sourceStart;
1221     errorEnd   = e.currentToken.sourceEnd;
1222     throw e;
1223   }
1224   {currentSegment = functionDeclaration;}
1225   block = Block()
1226   {functionDeclaration.statements = block.statements;
1227    currentSegment = seg;
1228    return functionDeclaration;}
1229 }
1230
1231 /**
1232  * A MethodDeclarator.
1233  * [&] IDENTIFIER(parameters ...).
1234  * @return a function description for the outline
1235  */
1236 MethodDeclaration MethodDeclarator(final int start) :
1237 {
1238   Token identifier = null;
1239   Token reference = null;
1240   final ArrayList formalParameters = new ArrayList();
1241   String identifierChar = SYNTAX_ERROR_CHAR;
1242   int end = start;
1243 }
1244 {
1245   [reference = <BIT_AND> {end = reference.sourceEnd;}]
1246   try {
1247     identifier = <IDENTIFIER>
1248     {
1249       identifierChar = identifier.image;
1250       end = identifier.sourceEnd;
1251     }
1252   } catch (ParseException e) {
1253     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected";
1254     errorLevel   = ERROR;
1255     errorStart = e.currentToken.sourceEnd;
1256     errorEnd   = e.currentToken.next.sourceStart;
1257     processParseExceptionDebug(e);
1258   }
1259   end = FormalParameters(formalParameters)
1260   {
1261   int nameStart, nameEnd;
1262   if (identifier == null) {
1263     if (reference == null) {
1264       nameStart = start + 9;
1265       nameEnd = start + 10;
1266     } else {
1267       nameStart = reference.sourceEnd + 1;
1268       nameEnd = reference.sourceEnd + 2;
1269     }
1270   } else {
1271       nameStart = identifier.sourceStart;
1272       nameEnd = identifier.sourceEnd;
1273   }
1274   return new MethodDeclaration(currentSegment,
1275                                identifierChar,
1276                                formalParameters,
1277                                reference != null,
1278                                nameStart,
1279                                nameEnd,
1280                                start,
1281                                end);
1282   }
1283 }
1284
1285 /**
1286  * FormalParameters follows method identifier.
1287  * (FormalParameter())
1288  */
1289 int FormalParameters(final ArrayList parameters) :
1290 {
1291   VariableDeclaration var;
1292   final Token token;
1293   Token tok = this.token;
1294   int end = tok.sourceEnd;
1295 }
1296 {
1297   try {
1298   tok = <LPAREN>
1299   {end = tok.sourceEnd;}
1300   } catch (ParseException e) {
1301     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected after function identifier";
1302     errorLevel   = ERROR;
1303     errorStart = e.currentToken.next.sourceStart;
1304     errorEnd   = e.currentToken.next.sourceEnd;
1305     processParseExceptionDebug(e);
1306   }
1307   [
1308     var = FormalParameter()
1309     {parameters.add(var);end = var.sourceEnd;}
1310     (
1311       <COMMA> var = FormalParameter()
1312       {parameters.add(var);end = var.sourceEnd;}
1313     )*
1314   ]
1315   try {
1316     token = <RPAREN>
1317     {end = token.sourceEnd;}
1318   } catch (ParseException e) {
1319     errorMessage = "')' expected";
1320     errorLevel   = ERROR;
1321     errorStart = e.currentToken.next.sourceStart;
1322     errorEnd   = e.currentToken.next.sourceEnd;
1323     processParseExceptionDebug(e);
1324   }
1325  {return end;}
1326 }
1327
1328 /**
1329  * A formal parameter.
1330  * $varname[=value] (,$varname[=value])
1331  */
1332 VariableDeclaration FormalParameter() :
1333 {
1334   final VariableDeclaration variableDeclaration;
1335   Token token = null;
1336 }
1337 {
1338   [token = <BIT_AND>] variableDeclaration = VariableDeclaratorNoSuffix()
1339   {
1340     outlineInfo.addVariable('$'+variableDeclaration.name());
1341     if (token != null) {
1342       variableDeclaration.setReference(true);
1343     }
1344     return variableDeclaration;}
1345 }
1346
1347 ConstantIdentifier Type() :
1348 {final Token token;}
1349 {
1350   token = <STRING>    {return new ConstantIdentifier(token);}
1351 | token = <BOOL>      {return new ConstantIdentifier(token);}
1352 | token = <BOOLEAN>   {return new ConstantIdentifier(token);}
1353 | token = <REAL>      {return new ConstantIdentifier(token);}
1354 | token = <DOUBLE>    {return new ConstantIdentifier(token);}
1355 | token = <FLOAT>     {return new ConstantIdentifier(token);}
1356 | token = <INT>       {return new ConstantIdentifier(token);}
1357 | token = <INTEGER>   {return new ConstantIdentifier(token);}
1358 | token = <OBJECT>    {return new ConstantIdentifier(token);}
1359 }
1360
1361 Expression Expression() :
1362 {
1363   final Expression expr;
1364   Expression initializer = null;
1365   int assignOperator = -1;
1366 }
1367 {
1368   LOOKAHEAD(1)
1369   expr = ConditionalExpression()
1370   [
1371     assignOperator = AssignmentOperator()
1372     try {
1373       initializer = Expression()
1374     } catch (ParseException e) {
1375       if (errorMessage != null) {
1376         throw e;
1377       }
1378       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
1379       errorLevel   = ERROR;
1380       errorEnd   = jj_input_stream.getPosition();
1381       throw e;
1382     }
1383   ]
1384   {
1385     if (assignOperator != -1) {// todo : change this, very very bad :(
1386         if (expr instanceof AbstractVariable) {
1387           return new VariableDeclaration(currentSegment,
1388                                          (AbstractVariable) expr,
1389                                          initializer,
1390                                          expr.sourceStart,
1391                                          initializer.sourceEnd);
1392         }
1393         String varName = expr.toStringExpression().substring(1);
1394         return new VariableDeclaration(currentSegment,
1395                                        new Variable(varName,
1396                                                     expr.sourceStart,
1397                                                     expr.sourceEnd),
1398                                        expr.sourceStart,
1399                                        initializer.sourceEnd);
1400     }
1401     return expr;
1402   }
1403 | expr = ExpressionWBang()       {return expr;}
1404 }
1405
1406 Expression ExpressionWBang() :
1407 {
1408   final Expression expr;
1409   final Token token;
1410 }
1411 {
1412   token = <BANG> expr = ExpressionWBang()
1413   {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);}
1414 | expr = ExpressionNoBang() {return expr;}
1415 }
1416
1417 Expression ExpressionNoBang() :
1418 {
1419   Expression expr;
1420 }
1421 {
1422   expr = ListExpression()    {return expr;}
1423 |
1424   expr = PrintExpression()   {return expr;}
1425 }
1426
1427 /**
1428  * Any assignement operator.
1429  * @return the assignement operator id
1430  */
1431 int AssignmentOperator() :
1432 {}
1433 {
1434   <ASSIGN>             {return VariableDeclaration.EQUAL;}
1435 | <STARASSIGN>         {return VariableDeclaration.STAR_EQUAL;}
1436 | <SLASHASSIGN>        {return VariableDeclaration.SLASH_EQUAL;}
1437 | <REMASSIGN>          {return VariableDeclaration.REM_EQUAL;}
1438 | <PLUSASSIGN>         {return VariableDeclaration.PLUS_EQUAL;}
1439 | <MINUSASSIGN>        {return VariableDeclaration.MINUS_EQUAL;}
1440 | <LSHIFTASSIGN>       {return VariableDeclaration.LSHIFT_EQUAL;}
1441 | <RSIGNEDSHIFTASSIGN> {return VariableDeclaration.RSIGNEDSHIFT_EQUAL;}
1442 | <ANDASSIGN>          {return VariableDeclaration.AND_EQUAL;}
1443 | <XORASSIGN>          {return VariableDeclaration.XOR_EQUAL;}
1444 | <ORASSIGN>           {return VariableDeclaration.OR_EQUAL;}
1445 | <DOTASSIGN>          {return VariableDeclaration.DOT_EQUAL;}
1446 | <TILDEEQUAL>         {return VariableDeclaration.TILDE_EQUAL;}
1447 }
1448
1449 Expression ConditionalExpression() :
1450 {
1451   final Expression expr;
1452   Expression expr2 = null;
1453   Expression expr3 = null;
1454 }
1455 {
1456   expr = ConditionalOrExpression() [ <HOOK> expr2 = Expression() <COLON> expr3 = ConditionalExpression() ]
1457 {
1458   if (expr3 == null) {
1459     return expr;
1460   }
1461   return new ConditionalExpression(expr,expr2,expr3);
1462 }
1463 }
1464
1465 Expression ConditionalOrExpression() :
1466 {
1467   Expression expr,expr2;
1468   int operator;
1469 }
1470 {
1471   expr = ConditionalAndExpression()
1472   (
1473     (
1474         <OR_OR> {operator = OperatorIds.OR_OR;}
1475       | <_ORL>  {operator = OperatorIds.ORL;}
1476     )
1477     expr2 = ConditionalAndExpression()
1478     {
1479       expr = new BinaryExpression(expr,expr2,operator);
1480     }
1481   )*
1482   {return expr;}
1483 }
1484
1485 Expression ConditionalAndExpression() :
1486 {
1487   Expression expr,expr2;
1488   int operator;
1489 }
1490 {
1491   expr = ConcatExpression()
1492   (
1493   (  <AND_AND> {operator = OperatorIds.AND_AND;}
1494    | <_ANDL>   {operator = OperatorIds.ANDL;})
1495    expr2 = ConcatExpression() {expr = new BinaryExpression(expr,expr2,operator);}
1496   )*
1497   {return expr;}
1498 }
1499
1500 Expression ConcatExpression() :
1501 {
1502   Expression expr,expr2;
1503 }
1504 {
1505   expr = InclusiveOrExpression()
1506   (
1507     <DOT> expr2 = InclusiveOrExpression()
1508     {expr = new BinaryExpression(expr,expr2,OperatorIds.DOT);}
1509   )*
1510   {return expr;}
1511 }
1512
1513 Expression InclusiveOrExpression() :
1514 {
1515   Expression expr,expr2;
1516 }
1517 {
1518   expr = ExclusiveOrExpression()
1519   (<BIT_OR> expr2 = ExclusiveOrExpression()
1520    {expr = new BinaryExpression(expr,expr2,OperatorIds.OR);}
1521   )*
1522   {return expr;}
1523 }
1524
1525 Expression ExclusiveOrExpression() :
1526 {
1527   Expression expr,expr2;
1528 }
1529 {
1530   expr = AndExpression()
1531   (
1532     <XOR> expr2 = AndExpression()
1533     {expr = new BinaryExpression(expr,expr2,OperatorIds.XOR);}
1534   )*
1535   {return expr;}
1536 }
1537
1538 Expression AndExpression() :
1539 {
1540   Expression expr,expr2;
1541 }
1542 {
1543   expr = EqualityExpression()
1544   (
1545     LOOKAHEAD(1)
1546     <BIT_AND> expr2 = EqualityExpression()
1547     {expr = new BinaryExpression(expr,expr2,OperatorIds.AND);}
1548   )*
1549   {return expr;}
1550 }
1551
1552 Expression EqualityExpression() :
1553 {
1554   Expression expr,expr2;
1555   int operator;
1556   Token token;
1557 }
1558 {
1559   expr = RelationalExpression()
1560   (
1561   (   token = <EQUAL_EQUAL>      {operator = OperatorIds.EQUAL_EQUAL;}
1562     | token = <DIF>              {operator = OperatorIds.DIF;}
1563     | token = <NOT_EQUAL>        {operator = OperatorIds.DIF;}
1564     | token = <BANGDOUBLEEQUAL>  {operator = OperatorIds.BANG_EQUAL_EQUAL;}
1565     | token = <TRIPLEEQUAL>      {operator = OperatorIds.EQUAL_EQUAL_EQUAL;}
1566   )
1567   try {
1568     expr2 = RelationalExpression()
1569   } catch (ParseException e) {
1570     if (errorMessage != null) {
1571       throw e;
1572     }
1573     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
1574     errorLevel   = ERROR;
1575     errorStart = token.sourceEnd +1;
1576     errorEnd   = token.sourceEnd +1;
1577     expr2 = new ConstantIdentifier(SYNTAX_ERROR_CHAR,token.sourceEnd +1,token.sourceEnd +1);
1578     processParseExceptionDebug(e);
1579   }
1580   {
1581     expr = new BinaryExpression(expr,expr2,operator);
1582   }
1583   )*
1584   {return expr;}
1585 }
1586
1587 Expression RelationalExpression() :
1588 {
1589   Expression expr,expr2;
1590   int operator;
1591 }
1592 {
1593   expr = ShiftExpression()
1594   (
1595   ( <LT> {operator = OperatorIds.LESS;}
1596   | <GT> {operator = OperatorIds.GREATER;}
1597   | <LE> {operator = OperatorIds.LESS_EQUAL;}
1598   | <GE> {operator = OperatorIds.GREATER_EQUAL;})
1599    expr2 = ShiftExpression()
1600   {expr = new BinaryExpression(expr,expr2,operator);}
1601   )*
1602   {return expr;}
1603 }
1604
1605 Expression ShiftExpression() :
1606 {
1607   Expression expr,expr2;
1608   int operator;
1609 }
1610 {
1611   expr = AdditiveExpression()
1612   (
1613   ( <LSHIFT>         {operator = OperatorIds.LEFT_SHIFT;}
1614   | <RSIGNEDSHIFT>   {operator = OperatorIds.RIGHT_SHIFT;}
1615   | <RUNSIGNEDSHIFT> {operator = OperatorIds.UNSIGNED_RIGHT_SHIFT;})
1616   expr2 = AdditiveExpression()
1617   {expr = new BinaryExpression(expr,expr2,operator);}
1618   )*
1619   {return expr;}
1620 }
1621
1622 Expression AdditiveExpression() :
1623 {
1624   Expression expr,expr2;
1625   int operator;
1626 }
1627 {
1628   expr = MultiplicativeExpression()
1629   (
1630     LOOKAHEAD(1)
1631      ( <PLUS>  {operator = OperatorIds.PLUS;}
1632      | <MINUS> {operator = OperatorIds.MINUS;}
1633   )
1634    expr2 = MultiplicativeExpression()
1635   {expr = new BinaryExpression(expr,expr2,operator);}
1636    )*
1637   {return expr;}
1638 }
1639
1640 Expression MultiplicativeExpression() :
1641 {
1642   Expression expr,expr2;
1643   int operator;
1644 }
1645 {
1646   try {
1647     expr = UnaryExpression()
1648   } catch (ParseException e) {
1649     if (errorMessage != null) throw e;
1650     errorMessage = "unexpected token '"+e.currentToken.next.image+'\'';
1651     errorLevel   = ERROR;
1652     errorStart = this.token.sourceStart;
1653     errorEnd   = this.token.sourceEnd;
1654     throw e;
1655   }
1656   (
1657    (  <STAR>      {operator = OperatorIds.MULTIPLY;}
1658     | <SLASH>     {operator = OperatorIds.DIVIDE;}
1659     | <REMAINDER> {operator = OperatorIds.REMAINDER;})
1660     expr2 = UnaryExpression()
1661     {expr = new BinaryExpression(expr,expr2,operator);}
1662   )*
1663   {return expr;}
1664 }
1665
1666 /**
1667  * An unary expression starting with @, & or nothing
1668  */
1669 Expression UnaryExpression() :
1670 {
1671   final Expression expr;
1672 }
1673 {
1674  /* <BIT_AND> expr = UnaryExpressionNoPrefix()             //why did I had that ?
1675   {return new PrefixedUnaryExpression(expr,OperatorIds.AND,pos);}
1676 |      */
1677   expr = AtNotTildeUnaryExpression() {return expr;}
1678 }
1679
1680 Expression AtNotTildeUnaryExpression() :
1681 {
1682   final Expression expr;
1683   final Token token;
1684 }
1685 {
1686   token = <AT>
1687   expr = AtNotTildeUnaryExpression()
1688   {return new PrefixedUnaryExpression(expr,OperatorIds.AT,token.sourceStart);}
1689 |
1690   token = <TILDE>
1691   expr = AtNotTildeUnaryExpression()
1692   {return new PrefixedUnaryExpression(expr,OperatorIds.TWIDDLE,token.sourceStart);}
1693 |
1694   token = <BANG>
1695   expr = AtNotUnaryExpression()
1696   {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);}
1697 |
1698   expr = UnaryExpressionNoPrefix()
1699   {return expr;}
1700 }
1701
1702 /**
1703  * An expression prefixed (or not) by one or more @ and !.
1704  * @return the expression
1705  */
1706 Expression AtNotUnaryExpression() :
1707 {
1708   final Expression expr;
1709   final Token token;
1710 }
1711 {
1712   token = <AT>
1713   expr = AtNotUnaryExpression()
1714   {return new PrefixedUnaryExpression(expr,OperatorIds.AT,token.sourceStart);}
1715 |
1716   token = <BANG>
1717   expr = AtNotUnaryExpression()
1718   {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);}
1719 |
1720   expr = UnaryExpressionNoPrefix()
1721   {return expr;}
1722 }
1723
1724 Expression UnaryExpressionNoPrefix() :
1725 {
1726   final Expression expr;
1727   final Token token;
1728 }
1729 {
1730   token = <PLUS> expr = AtNotTildeUnaryExpression()   {return new PrefixedUnaryExpression(expr,
1731                                                                                      OperatorIds.PLUS,
1732                                                                                      token.sourceStart);}
1733 |
1734   token = <MINUS> expr = AtNotTildeUnaryExpression()  {return new PrefixedUnaryExpression(expr,
1735                                                                                      OperatorIds.MINUS,
1736                                                                                      token.sourceStart);}
1737 |
1738   expr = PreIncDecExpression()
1739   {return expr;}
1740 |
1741   expr = UnaryExpressionNotPlusMinus()
1742   {return expr;}
1743 }
1744
1745
1746 Expression PreIncDecExpression() :
1747 {
1748 final Expression expr;
1749 final int operator;
1750 final Token token;
1751 }
1752 {
1753   (
1754       token = <PLUS_PLUS>   {operator = OperatorIds.PLUS_PLUS;}
1755     |
1756       token = <MINUS_MINUS> {operator = OperatorIds.MINUS_MINUS;}
1757   )
1758   expr = PrimaryExpression()
1759   {return new PrefixedUnaryExpression(expr,operator,token.sourceStart);}
1760 }
1761
1762 Expression UnaryExpressionNotPlusMinus() :
1763 {
1764   final Expression expr;
1765 }
1766 {
1767   LOOKAHEAD( <LPAREN> (Type() | <ARRAY>) <RPAREN> )
1768   expr = CastExpression()         {return expr;}
1769 | expr = PostfixExpression()      {return expr;}
1770 | expr = Literal()                {return expr;}
1771 | <LPAREN> expr = Expression()
1772   try {
1773     <RPAREN>
1774   } catch (ParseException e) {
1775     errorMessage = "')' expected";
1776     errorLevel   = ERROR;
1777     errorStart   = expr.sourceEnd +1;
1778     errorEnd     = expr.sourceEnd +1;
1779     processParseExceptionDebug(e);
1780   }
1781   {return expr;}
1782 }
1783
1784 CastExpression CastExpression() :
1785 {
1786 final ConstantIdentifier type;
1787 final Expression expr;
1788 final Token token,token1;
1789 }
1790 {
1791   token1 = <LPAREN>
1792   (
1793       type = Type()
1794     |
1795       token = <ARRAY> {type = new ConstantIdentifier(token);}
1796   )
1797   <RPAREN> expr = UnaryExpression()
1798   {return new CastExpression(type,expr,token1.sourceStart,expr.sourceEnd);}
1799 }
1800
1801 Expression PostfixExpression() :
1802 {
1803   final Expression expr;
1804   int operator = -1;
1805   Token token = null;
1806 }
1807 {
1808   expr = PrimaryExpression()
1809   [
1810       token = <PLUS_PLUS>   {operator = OperatorIds.PLUS_PLUS;}
1811     |
1812       token = <MINUS_MINUS> {operator = OperatorIds.MINUS_MINUS;}
1813   ]
1814   {
1815     if (operator == -1) {
1816       return expr;
1817     }
1818     return new PostfixedUnaryExpression(expr,operator,token.sourceEnd);
1819   }
1820 }
1821
1822 Expression PrimaryExpression() :
1823 {
1824   Expression expr;
1825   Token token = null;
1826 }
1827 {
1828   [token = <BIT_AND>] expr = refPrimaryExpression(token)
1829   {return expr;}
1830 |
1831   expr = ArrayDeclarator()
1832   {return expr;}
1833 }
1834
1835 Expression refPrimaryExpression(final Token reference) :
1836 {
1837   Expression expr;
1838   Expression expr2 = null;
1839   final Token identifier;
1840 }
1841 {
1842   identifier = <IDENTIFIER>
1843   {
1844     expr = new ConstantIdentifier(identifier);
1845   }
1846   (
1847     <STATICCLASSACCESS> expr2 = ClassIdentifier()
1848     {expr = new ClassAccess(expr,
1849                             expr2,
1850                             ClassAccess.STATIC);}
1851   )*
1852   [ expr2 = Arguments(expr) ]
1853   {
1854     if (expr2 == null) {
1855       if (reference != null) {
1856         ParseException e = generateParseException();
1857         errorMessage = "you cannot use a constant by reference";
1858         errorLevel   = ERROR;
1859         errorStart   = reference.sourceStart;
1860         errorEnd     = reference.sourceEnd;
1861         processParseExceptionDebug(e);
1862       }
1863       return expr;
1864     }
1865     return expr2;
1866   }
1867 |
1868   expr = VariableDeclaratorId()  //todo use the reference parameter ...
1869   [ expr = Arguments(expr) ]
1870   {return expr;}
1871 |
1872   token = <NEW>
1873   expr = ClassIdentifier()
1874   {
1875     int start;
1876     if (reference == null) {
1877       start = token.sourceStart;
1878     } else {
1879       start = reference.sourceStart;
1880     }
1881     expr = new ClassInstantiation(expr,
1882                                   reference != null,
1883                                   start);
1884   }
1885   [ expr = Arguments(expr) ]
1886   {return expr;}
1887 }
1888
1889 /**
1890  * An array declarator.
1891  * array(vars)
1892  * @return an array
1893  */
1894 ArrayInitializer ArrayDeclarator() :
1895 {
1896   final ArrayVariableDeclaration[] vars;
1897   final Token token;
1898 }
1899 {
1900   token = <ARRAY> vars = ArrayInitializer()
1901   {return new ArrayInitializer(vars,
1902                                token.sourceStart,
1903                                this.token.sourceEnd);}
1904 }
1905
1906 Expression ClassIdentifier():
1907 {
1908   final Expression expr;
1909   final Token token;
1910 }
1911 {
1912   token = <IDENTIFIER>          {return new ConstantIdentifier(token);}
1913 | expr = Type()                 {return expr;}
1914 | expr = VariableDeclaratorId() {return expr;}
1915 }
1916
1917 /**
1918  * Used by Variabledeclaratorid and primarysuffix
1919  */
1920 AbstractVariable VariableSuffix(final AbstractVariable prefix) :
1921 {
1922   Expression expression = null;
1923   final Token classAccessToken,lbrace,rbrace;
1924   Token token;
1925   int pos;
1926 }
1927 {
1928   classAccessToken = <CLASSACCESS>
1929   try {
1930     (
1931       lbrace = <LBRACE> expression = Expression() rbrace = <RBRACE>
1932                 {
1933                  expression = new Variable(expression,
1934                                            lbrace.sourceStart,
1935                                            rbrace.sourceEnd);
1936                 }
1937       |
1938         token = <IDENTIFIER>
1939         {expression = new ConstantIdentifier(token.image,token.sourceStart,token.sourceEnd);}
1940       |
1941         expression = Variable()
1942     )
1943   } catch (ParseException e) {
1944     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function call or field access expected";
1945     errorLevel   = ERROR;
1946     errorStart = classAccessToken.sourceEnd +1;
1947     errorEnd   = classAccessToken.sourceEnd +1;
1948     processParseExceptionDebug(e);
1949   }
1950   {return new ClassAccess(prefix,
1951                           expression,
1952                           ClassAccess.NORMAL);}
1953 |
1954   token = <LBRACKET> {pos = token.sourceEnd+1;}
1955   [  expression = Expression() {pos = expression.sourceEnd+1;}
1956    | expression = Type()       {pos = expression.sourceEnd+1;}]  //Not good
1957   try {
1958     token = <RBRACKET>
1959     {pos = token.sourceEnd;}
1960   } catch (ParseException e) {
1961     errorMessage = "']' expected";
1962     errorLevel   = ERROR;
1963     errorStart = pos;
1964     errorEnd   = pos;
1965     processParseExceptionDebug(e);
1966   }
1967   {return new ArrayDeclarator(prefix,expression,pos);}
1968 |
1969   token = <LBRACE> {pos = token.sourceEnd+1;}
1970   [  expression = Expression() {pos = expression.sourceEnd+1;}
1971    | expression = Type()       {pos = expression.sourceEnd+1;}]  //Not good
1972   try {
1973     token = <RBRACE>
1974     {pos = token.sourceEnd;}
1975   } catch (ParseException e) {
1976     errorMessage = "']' expected";
1977     errorLevel   = ERROR;
1978     errorStart = pos;
1979     errorEnd   = pos;
1980     processParseExceptionDebug(e);
1981   }
1982   {return new ArrayDeclarator(prefix,expression,pos);}//todo : check braces here
1983 }
1984
1985 Literal Literal() :
1986 {
1987   final Token token;
1988   StringLiteral literal;
1989 }
1990 {
1991   token = <INTEGER_LITERAL>        {return new NumberLiteral(token);}
1992 | token = <FLOATING_POINT_LITERAL> {return new NumberLiteral(token);}
1993 | token = <STRING_LITERAL>         {return new StringLiteral(token);}
1994 | token = <TRUE>                   {return new TrueLiteral(token);}
1995 | token = <FALSE>                  {return new FalseLiteral(token);}
1996 | token = <NULL>                   {return new NullLiteral(token);}
1997 | literal = evaluableString()        {return literal;}
1998 }
1999
2000 StringLiteral evaluableString() :
2001 {
2002   ArrayList list = new ArrayList();
2003   Token start,end;
2004   Token token,lbrace,rbrace;
2005   AbstractVariable var;
2006   Expression expr;
2007 }
2008 {
2009   start = <DOUBLEQUOTE>
2010   (
2011    <DOLLARS>
2012        (
2013         token = <IDENTIFIER> {list.add(new Variable(token.image,
2014                                                     token.sourceStart,
2015                                                     token.sourceEnd));}
2016         |
2017          lbrace = <LBRACE1>
2018          token = <ID>
2019          {list.add(new Variable(token.image,
2020                                 token.sourceStart,
2021                                 token.sourceEnd));}
2022          rbrace = <RBRACE1>
2023        )
2024    )*
2025   end = <DOUBLEQUOTE2>
2026   {
2027   AbstractVariable[] vars = new AbstractVariable[list.size()];
2028   list.toArray(vars);
2029   return new StringLiteral(jj_input_stream.getCurrentBuffer().substring(start.sourceEnd,end.sourceStart),
2030                            start.sourceStart,
2031                            end.sourceEnd,
2032                            vars);
2033   }
2034 }
2035
2036 FunctionCall Arguments(final Expression func) :
2037 {
2038 Expression[] args = null;
2039 final Token token,lparen;
2040 }
2041 {
2042   lparen = <LPAREN> [ args = ArgumentList() ]
2043   try {
2044     token = <RPAREN>
2045     {return new FunctionCall(func,args,token.sourceEnd);}
2046   } catch (ParseException e) {
2047     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list";
2048     errorLevel   = ERROR;
2049     if (args == null) {
2050         errorStart = lparen.sourceEnd+1;
2051         errorEnd   = lparen.sourceEnd+2;
2052     } else {
2053         errorStart = args[args.length-1].sourceEnd+1;
2054         errorEnd   = args[args.length-1].sourceEnd+2;
2055     }
2056     processParseExceptionDebug(e);
2057   }
2058   {
2059   int sourceEnd = (args == null && args.length != 0) ? lparen.sourceEnd+1 : args[args.length-1].sourceEnd;
2060   return new FunctionCall(func,args,sourceEnd);}
2061 }
2062
2063 /**
2064  * An argument list is a list of arguments separated by comma :
2065  * argumentDeclaration() (, argumentDeclaration)*
2066  * @return an array of arguments
2067  */
2068 Expression[] ArgumentList() :
2069 {
2070 Expression arg;
2071 final ArrayList list = new ArrayList();
2072 int pos;
2073 Token token;
2074 }
2075 {
2076   arg = Expression()
2077   {list.add(arg);pos = arg.sourceEnd;}
2078   ( token = <COMMA> {pos = token.sourceEnd;}
2079       try {
2080         arg = Expression()
2081         {list.add(arg);
2082          pos = arg.sourceEnd;}
2083       } catch (ParseException e) {
2084         errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. An expression expected after a comma in argument list";
2085         errorLevel   = ERROR;
2086         errorStart   = pos+1;
2087         errorEnd     = pos+1;
2088         processParseException(e);
2089       }
2090    )*
2091    {
2092    final Expression[] arguments = new Expression[list.size()];
2093    list.toArray(arguments);
2094    return arguments;}
2095 }
2096
2097 /**
2098  * A Statement without break.
2099  * @return a statement
2100  */
2101 Statement StatementNoBreak() :
2102 {
2103   final Statement statement;
2104   Token token = null;
2105 }
2106 {
2107   LOOKAHEAD(2)
2108   statement = expressionStatement()     {return statement;}
2109 | LOOKAHEAD(1)
2110   statement = LabeledStatement()        {return statement;}
2111 | statement = Block()                   {return statement;}
2112 | statement = EmptyStatement()          {return statement;}
2113 | statement = SwitchStatement()         {return statement;}
2114 | statement = IfStatement()             {return statement;}
2115 | statement = WhileStatement()          {return statement;}
2116 | statement = DoStatement()             {return statement;}
2117 | statement = ForStatement()            {return statement;}
2118 | statement = ForeachStatement()        {return statement;}
2119 | statement = ContinueStatement()       {return statement;}
2120 | statement = ReturnStatement()         {return statement;}
2121 | statement = EchoStatement()           {return statement;}
2122 | [token=<AT>] statement = IncludeStatement()
2123   {if (token != null) {
2124     ((InclusionStatement)statement).silent = true;
2125     statement.sourceStart = token.sourceStart;
2126   }
2127   return statement;}
2128 | statement = StaticStatement()         {return statement;}
2129 | statement = GlobalStatement()         {return statement;}
2130 | statement = defineStatement()         {currentSegment.add((Outlineable)statement);return statement;}
2131 }
2132
2133 /**
2134  * A statement expression.
2135  * expression ;
2136  * @return an expression
2137  */
2138 Statement expressionStatement() :
2139 {
2140   final Statement statement;
2141   final Token token;
2142 }
2143 {
2144   statement = Expression()
2145   try {
2146     token = <SEMICOLON>
2147     {statement.sourceEnd = token.sourceEnd;}
2148   } catch (ParseException e) {
2149     if (e.currentToken.next.kind != PHPParserConstants.PHPEND) {
2150       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2151       errorLevel   = ERROR;
2152       errorStart = statement.sourceEnd+1;
2153       errorEnd   = statement.sourceEnd+1;
2154       processParseExceptionDebug(e);
2155     }
2156   }
2157   {return statement;}
2158 }
2159
2160 Define defineStatement() :
2161 {
2162   Expression defineName,defineValue;
2163   final Token defineToken;
2164   Token token;
2165   int pos;
2166 }
2167 {
2168   defineToken = <DEFINE> {pos = defineToken.sourceEnd+1;}
2169   try {
2170     token = <LPAREN>
2171     {pos = token.sourceEnd+1;}
2172   } catch (ParseException e) {
2173     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
2174     errorLevel   = ERROR;
2175     errorStart   = pos;
2176     errorEnd     = pos;
2177     processParseExceptionDebug(e);
2178   }
2179   try {
2180     defineName = Expression()
2181     {pos = defineName.sourceEnd+1;}
2182   } catch (ParseException e) {
2183     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
2184     errorLevel   = ERROR;
2185     errorStart   = pos;
2186     errorEnd     = pos;
2187     processParseExceptionDebug(e);
2188     defineName = new StringLiteral(SYNTAX_ERROR_CHAR,pos,pos);
2189   }
2190   try {
2191     token = <COMMA>
2192     {pos = defineName.sourceEnd+1;}
2193   } catch (ParseException e) {
2194     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
2195     errorLevel   = ERROR;
2196     errorStart   = pos;
2197     errorEnd     = pos;
2198     processParseExceptionDebug(e);
2199   }
2200   try {
2201     defineValue = Expression()
2202     {pos = defineValue.sourceEnd+1;}
2203   } catch (ParseException e) {
2204     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected";
2205     errorLevel   = ERROR;
2206     errorStart   = pos;
2207     errorEnd     = pos;
2208     processParseExceptionDebug(e);
2209     defineValue = new StringLiteral(SYNTAX_ERROR_CHAR,pos,pos);
2210   }
2211   try {
2212     token = <RPAREN>
2213     {pos = token.sourceEnd+1;}
2214   } catch (ParseException e) {
2215     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
2216     errorLevel   = ERROR;
2217     errorStart   = pos;
2218     errorEnd     = pos;
2219     processParseExceptionDebug(e);
2220   }
2221   {return new Define(currentSegment,
2222                      defineName,
2223                      defineValue,
2224                      defineToken.sourceStart,
2225                      pos);}
2226 }
2227
2228 /**
2229  * A Normal statement.
2230  */
2231 Statement Statement() :
2232 {
2233   final Statement statement;
2234 }
2235 {
2236   statement = StatementNoBreak() {return statement;}
2237 | statement = BreakStatement()   {return statement;}
2238 }
2239
2240 /**
2241  * An html block inside a php syntax.
2242  */
2243 HTMLBlock htmlBlock() :
2244 {
2245   final int startIndex = nodePtr;
2246   final AstNode[] blockNodes;
2247   final int nbNodes;
2248   final Token phpEnd;
2249 }
2250 {
2251   phpEnd = <PHPEND>
2252   {htmlStart = phpEnd.sourceEnd;}
2253   (phpEchoBlock())*
2254   try {
2255     (<PHPSTARTLONG> | <PHPSTARTSHORT>)
2256     {createNewHTMLCode();}
2257   } catch (ParseException e) {
2258     errorMessage = "unexpected end of file , '<?php' expected";
2259     errorLevel   = ERROR;
2260     errorStart = e.currentToken.sourceStart;
2261     errorEnd   = e.currentToken.sourceEnd;
2262     throw e;
2263   }
2264   {
2265   nbNodes    = nodePtr - startIndex;
2266   if (nbNodes == 0) {
2267     return null;
2268   }
2269   blockNodes = new AstNode[nbNodes];
2270   System.arraycopy(nodes,startIndex+1,blockNodes,0,nbNodes);
2271   nodePtr = startIndex;
2272   return new HTMLBlock(blockNodes);}
2273 }
2274
2275 /**
2276  * An include statement. It's "include" an expression;
2277  */
2278 InclusionStatement IncludeStatement() :
2279 {
2280   Expression expr;
2281   final int keyword;
2282   final InclusionStatement inclusionStatement;
2283   final Token token, token2;
2284   int pos;
2285 }
2286 {
2287       (  token = <REQUIRE>      {keyword = InclusionStatement.REQUIRE;pos=token.sourceEnd;}
2288        | token = <REQUIRE_ONCE> {keyword = InclusionStatement.REQUIRE_ONCE;pos=token.sourceEnd;}
2289        | token = <INCLUDE>      {keyword = InclusionStatement.INCLUDE;pos=token.sourceEnd;}
2290        | token = <INCLUDE_ONCE> {keyword = InclusionStatement.INCLUDE_ONCE;pos=token.sourceEnd;})
2291   try {
2292     expr = Expression()
2293     {pos = expr.sourceEnd;}
2294   } catch (ParseException e) {
2295     if (errorMessage != null) {
2296       throw e;
2297     }
2298     errorMessage = "unexpected token '"+ e.currentToken.next.image+"', expression expected";
2299     errorLevel   = ERROR;
2300     errorStart   = e.currentToken.next.sourceStart;
2301     errorEnd     = e.currentToken.next.sourceEnd;
2302     expr = new ConstantIdentifier(SYNTAX_ERROR_CHAR,pos,pos);
2303     processParseExceptionDebug(e);
2304   }
2305   try {
2306     token2 = <SEMICOLON>
2307     {pos=token2.sourceEnd;}
2308   } catch (ParseException e) {
2309     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
2310     errorLevel   = ERROR;
2311     errorStart   = e.currentToken.next.sourceStart;
2312     errorEnd     = e.currentToken.next.sourceEnd;
2313     processParseExceptionDebug(e);
2314   }
2315   {
2316    inclusionStatement = new InclusionStatement(currentSegment,
2317                                                keyword,
2318                                                expr,
2319                                                token.sourceStart,
2320                                                pos);
2321    currentSegment.add(inclusionStatement);
2322    return inclusionStatement;
2323   }
2324 }
2325
2326 PrintExpression PrintExpression() :
2327 {
2328   final Expression expr;
2329   final Token printToken;
2330 }
2331 {
2332   token = <PRINT> expr = Expression()
2333   {return new PrintExpression(expr,token.sourceStart,expr.sourceEnd);}
2334 }
2335
2336 ListExpression ListExpression() :
2337 {
2338   Expression expr = null;
2339   final Expression expression;
2340   final ArrayList list = new ArrayList();
2341   int pos;
2342   final Token listToken, rParen;
2343   Token token;
2344 }
2345 {
2346   listToken = <LIST> {pos = listToken.sourceEnd;}
2347   try {
2348     token = <LPAREN> {pos = token.sourceEnd;}
2349   } catch (ParseException e) {
2350     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected";
2351     errorLevel   = ERROR;
2352     errorStart   = listToken.sourceEnd+1;
2353     errorEnd     = listToken.sourceEnd+1;
2354     processParseExceptionDebug(e);
2355   }
2356   [
2357     expr = VariableDeclaratorId()
2358     {list.add(expr);pos = expr.sourceEnd;}
2359   ]
2360   {if (expr == null) list.add(null);}
2361   (
2362     try {
2363       token = <COMMA>
2364       {pos = token.sourceEnd;}
2365     } catch (ParseException e) {
2366       errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected";
2367       errorLevel   = ERROR;
2368       errorStart   = pos+1;
2369       errorEnd     = pos+1;
2370       processParseExceptionDebug(e);
2371     }
2372     [expr = VariableDeclaratorId() {list.add(expr);pos = expr.sourceEnd;}]
2373   )*
2374   try {
2375     rParen = <RPAREN>
2376     {pos = rParen.sourceEnd;}
2377   } catch (ParseException e) {
2378     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected";
2379     errorLevel   = ERROR;
2380     errorStart = pos+1;
2381     errorEnd   = pos+1;
2382       processParseExceptionDebug(e);
2383   }
2384   [ <ASSIGN> expression = Expression()
2385     {
2386     final AbstractVariable[] vars = new AbstractVariable[list.size()];
2387     list.toArray(vars);
2388     return new ListExpression(vars,
2389                               expression,
2390                               listToken.sourceStart,
2391                               expression.sourceEnd);}
2392   ]
2393   {
2394     final AbstractVariable[] vars = new AbstractVariable[list.size()];
2395     list.toArray(vars);
2396     return new ListExpression(vars,listToken.sourceStart,pos);}
2397 }
2398
2399 /**
2400  * An echo statement.
2401  * echo anyexpression (, otherexpression)*
2402  */
2403 EchoStatement EchoStatement() :
2404 {
2405   final ArrayList expressions = new ArrayList();
2406   Expression expr;
2407   Token token;
2408   Token token2 = null;
2409 }
2410 {
2411   token = <ECHO> expr = Expression()
2412   {expressions.add(expr);}
2413   (
2414     <COMMA> expr = Expression()
2415     {expressions.add(expr);}
2416   )*
2417   try {
2418     token2 = <SEMICOLON>
2419   } catch (ParseException e) {
2420     if (e.currentToken.next.kind != 4) {
2421       errorMessage = "';' expected after 'echo' statement";
2422       errorLevel   = ERROR;
2423       errorStart   = e.currentToken.sourceEnd;
2424       errorEnd     = e.currentToken.sourceEnd;
2425       processParseExceptionDebug(e);
2426     }
2427   }
2428   {
2429    final Expression[] exprs = new Expression[expressions.size()];
2430    expressions.toArray(exprs);
2431    if (token2 == null) {
2432      return new EchoStatement(exprs,token.sourceStart, exprs[exprs.length-1].sourceEnd);
2433    }
2434    return new EchoStatement(exprs,token.sourceStart, token2.sourceEnd);
2435    }
2436 }
2437
2438 GlobalStatement GlobalStatement() :
2439 {
2440    Variable expr;
2441    final ArrayList vars = new ArrayList();
2442    final GlobalStatement global;
2443    final Token token, token2;
2444    int pos;
2445 }
2446 {
2447   token = <GLOBAL>
2448     expr = Variable()
2449     {vars.add(expr);pos = expr.sourceEnd+1;}
2450   (<COMMA>
2451     expr = Variable()
2452     {vars.add(expr);pos = expr.sourceEnd+1;}
2453   )*
2454   try {
2455     token2 = <SEMICOLON>
2456     {pos = token2.sourceEnd+1;}
2457   } catch (ParseException e) {
2458     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2459     errorLevel   = ERROR;
2460     errorStart = pos;
2461     errorEnd   = pos;
2462     processParseExceptionDebug(e);
2463   }
2464     {
2465     final Variable[] variables = new Variable[vars.size()];
2466     vars.toArray(variables);
2467     global = new GlobalStatement(currentSegment,
2468                                  variables,
2469                                  token.sourceStart,
2470                                  pos);
2471     currentSegment.add(global);
2472     return global;}
2473 }
2474
2475 StaticStatement StaticStatement() :
2476 {
2477   final ArrayList vars = new ArrayList();
2478   VariableDeclaration expr;
2479   final Token token, token2;
2480   int pos;
2481 }
2482 {
2483   token = <STATIC> expr = VariableDeclarator() {vars.add(expr);pos = expr.sourceEnd+1;}
2484   (
2485     <COMMA> expr = VariableDeclarator() {vars.add(expr);pos = expr.sourceEnd+1;}
2486   )*
2487   try {
2488     token2 = <SEMICOLON>
2489     {pos = token2.sourceEnd+1;}
2490   } catch (ParseException e) {
2491     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected";
2492     errorLevel   = ERROR;
2493     errorStart = pos;
2494     errorEnd   = pos;
2495     processParseException(e);
2496   }
2497     {
2498     final VariableDeclaration[] variables = new VariableDeclaration[vars.size()];
2499     vars.toArray(variables);
2500     return new StaticStatement(variables,
2501                                token.sourceStart,
2502                                pos);}
2503 }
2504
2505 LabeledStatement LabeledStatement() :
2506 {
2507   final Token label;
2508   final Statement statement;
2509 }
2510 {
2511   label = <IDENTIFIER> <COLON> statement = Statement()
2512   {return new LabeledStatement(label.image,statement,label.sourceStart,statement.sourceEnd);}
2513 }
2514
2515 /**
2516  * A Block is
2517  * {
2518  * statements
2519  * }.
2520  * @return a block
2521  */
2522 Block Block() :
2523 {
2524   final ArrayList list = new ArrayList();
2525   Statement statement;
2526   final Token token, token2;
2527   int pos,start;
2528 }
2529 {
2530   try {
2531     token = <LBRACE>
2532     {pos = token.sourceEnd+1;start=token.sourceStart;}
2533   } catch (ParseException e) {
2534     errorMessage = "'{' expected";
2535     errorLevel   = ERROR;
2536     pos = this.token.sourceEnd+1;
2537     start=pos;
2538     errorStart = pos;
2539     errorEnd   = pos;
2540     processParseExceptionDebug(e);
2541   }
2542   ( statement = BlockStatement() {list.add(statement);pos = statement.sourceEnd+1;}
2543   | statement = htmlBlock()      {if (statement != null) {
2544                                     list.add(statement);
2545                                     pos = statement.sourceEnd+1;
2546                                   }
2547                                   pos = this.token.sourceEnd+1;
2548                                  }
2549   )*
2550   try {
2551     token2 = <RBRACE>
2552     {pos = token2.sourceEnd+1;}
2553   } catch (ParseException e) {
2554     errorMessage = "unexpected token : '"+ e.currentToken.image +"', '}' expected";
2555     errorLevel   = ERROR;
2556     errorStart = pos;
2557     errorEnd   = pos;
2558     processParseExceptionDebug(e);
2559   }
2560   {
2561   final Statement[] statements = new Statement[list.size()];
2562   list.toArray(statements);
2563   return new Block(statements,start,pos);}
2564 }
2565
2566 Statement BlockStatement() :
2567 {
2568   final Statement statement;
2569 }
2570 {
2571   try {
2572     statement = Statement()         {if (phpDocument == currentSegment) pushOnAstNodes(statement);
2573                                      return statement;}
2574   } catch (ParseException e) {
2575     errorMessage = "unexpected token : '"+ e.currentToken.image +"', a statement was expected";
2576     errorLevel   = ERROR;
2577     errorStart = e.currentToken.sourceStart;
2578     errorEnd   = e.currentToken.sourceEnd;
2579     throw e;
2580   }
2581 | statement = ClassDeclaration()  {return statement;}
2582 | statement = MethodDeclaration() {if (phpDocument == currentSegment) pushOnAstNodes(statement);
2583                                    currentSegment.add((MethodDeclaration) statement);
2584                                    ((MethodDeclaration) statement).analyzeCode();
2585                                    return statement;}
2586 }
2587
2588 /**
2589  * A Block statement that will not contain any 'break'
2590  */
2591 Statement BlockStatementNoBreak() :
2592 {
2593   final Statement statement;
2594 }
2595 {
2596   statement = StatementNoBreak()  {return statement;}
2597 | statement = ClassDeclaration()  {return statement;}
2598 | statement = MethodDeclaration() {currentSegment.add((MethodDeclaration) statement);
2599                                    ((MethodDeclaration) statement).analyzeCode();
2600                                    return statement;}
2601 }
2602
2603 /**
2604  * used only by ForInit()
2605  */
2606 Expression[] LocalVariableDeclaration() :
2607 {
2608   final ArrayList list = new ArrayList();
2609   Expression var;
2610 }
2611 {
2612   var = Expression()
2613   {list.add(var);}
2614   ( <COMMA> var = Expression() {list.add(var);})*
2615   {
2616     final Expression[] vars = new Expression[list.size()];
2617     list.toArray(vars);
2618     return vars;
2619   }
2620 }
2621
2622 /**
2623  * used only by LocalVariableDeclaration().
2624  */
2625 VariableDeclaration LocalVariableDeclarator() :
2626 {
2627   final Variable varName;
2628   Expression initializer = null;
2629 }
2630 {
2631   varName = Variable() [ <ASSIGN> initializer = Expression() ]
2632   {
2633    if (initializer == null) {
2634     return new VariableDeclaration(currentSegment,
2635                                    varName,
2636                                    varName.sourceStart,
2637                                    varName.sourceEnd);
2638    }
2639     return new VariableDeclaration(currentSegment,
2640                                    varName,
2641                                    initializer,
2642                                    VariableDeclaration.EQUAL,
2643                                    varName.sourceStart);
2644   }
2645 }
2646
2647 EmptyStatement EmptyStatement() :
2648 {
2649   final Token token;
2650 }
2651 {
2652   token = <SEMICOLON>
2653   {return new EmptyStatement(token.sourceStart,token.sourceEnd);}
2654 }
2655
2656 /**
2657  * used only by StatementExpressionList() which is used only by ForInit() and ForStatement()
2658  */
2659 Expression StatementExpression() :
2660 {
2661   final Expression expr;
2662   final Token operator;
2663 }
2664 {
2665   expr = PreIncDecExpression() {return expr;}
2666 |
2667   expr = PrimaryExpression()
2668   [ operator = <PLUS_PLUS> {return new PostfixedUnaryExpression(expr,
2669                                                                 OperatorIds.PLUS_PLUS,
2670                                                                 operator.sourceEnd);}
2671   | operator = <MINUS_MINUS> {return new PostfixedUnaryExpression(expr,
2672                                                                   OperatorIds.MINUS_MINUS,
2673                                                                   operator.sourceEnd);}
2674   ]
2675   {return expr;}
2676 }
2677
2678 SwitchStatement SwitchStatement() :
2679 {
2680   Expression variable;
2681   final AbstractCase[] cases;
2682   final Token switchToken,lparenToken,rparenToken;
2683   int pos;
2684 }
2685 {
2686   switchToken = <SWITCH> {pos = switchToken.sourceEnd+1;}
2687   try {
2688     lparenToken = <LPAREN>
2689     {pos = lparenToken.sourceEnd+1;}
2690   } catch (ParseException e) {
2691     errorMessage = "'(' expected after 'switch'";
2692     errorLevel   = ERROR;
2693     errorStart = pos;
2694     errorEnd   = pos;
2695     processParseExceptionDebug(e);
2696   }
2697   try {
2698     variable = Expression() {pos = variable.sourceEnd+1;}
2699   } catch (ParseException e) {
2700     if (errorMessage != null) {
2701       throw e;
2702     }
2703     errorMessage = "expression expected";
2704     errorLevel   = ERROR;
2705     errorStart = pos;
2706     errorEnd   = pos;
2707     processParseExceptionDebug(e);
2708     variable = new ConstantIdentifier(SYNTAX_ERROR_CHAR,pos,pos);
2709   }
2710   try {
2711     rparenToken = <RPAREN> {pos = rparenToken.sourceEnd+1;}
2712   } catch (ParseException e) {
2713     errorMessage = "')' expected";
2714     errorLevel   = ERROR;
2715     errorStart = pos;
2716     errorEnd   = pos;
2717     processParseExceptionDebug(e);
2718   }
2719   (  cases = switchStatementBrace()
2720    | cases = switchStatementColon(switchToken.sourceStart, switchToken.sourceEnd))
2721   {return new SwitchStatement(variable,
2722                               cases,
2723                               switchToken.sourceStart,
2724                               this.token.sourceEnd);}
2725 }
2726
2727 AbstractCase[] switchStatementBrace() :
2728 {
2729   AbstractCase cas;
2730   final ArrayList cases = new ArrayList();
2731   Token token;
2732   int pos;
2733 }
2734 {
2735   token = <LBRACE> {pos = token.sourceEnd;}
2736  ( cas = switchLabel0() {cases.add(cas);pos = cas.sourceEnd;})*
2737   try {
2738     token = <RBRACE>
2739     {pos = token.sourceEnd;}
2740   } catch (ParseException e) {
2741     errorMessage = "'}' expected";
2742     errorLevel   = ERROR;
2743     errorStart = pos+1;
2744     errorEnd   = pos+1;
2745     processParseExceptionDebug(e);
2746   }
2747   {
2748     final AbstractCase[] abcase = new AbstractCase[cases.size()];
2749     cases.toArray(abcase);
2750     return abcase;
2751   }
2752 }
2753
2754 /**
2755  * A Switch statement with : ... endswitch;
2756  * @param start the begin offset of the switch
2757  * @param end the end offset of the switch
2758  */
2759 AbstractCase[] switchStatementColon(final int start, final int end) :
2760 {
2761   AbstractCase cas;
2762   final ArrayList cases = new ArrayList();
2763   Token token;
2764   int pos;
2765 }
2766 {
2767   token = <COLON> {pos = token.sourceEnd;}
2768   {try {
2769   setMarker(fileToParse,
2770             "Ugly syntax detected, you should switch () {...} instead of switch (): ... enswitch;",
2771             start,
2772             end,
2773             INFO,
2774             "Line " + token.beginLine);
2775   } catch (CoreException e) {
2776     PHPeclipsePlugin.log(e);
2777   }}
2778   ( cas = switchLabel0() {cases.add(cas);pos = cas.sourceEnd;})*
2779   try {
2780     token = <ENDSWITCH> {pos = token.sourceEnd;}
2781   } catch (ParseException e) {
2782     errorMessage = "'endswitch' expected";
2783     errorLevel   = ERROR;
2784     errorStart = pos+1;
2785     errorEnd   = pos+1;
2786     processParseExceptionDebug(e);
2787   }
2788   try {
2789     token = <SEMICOLON> {pos = token.sourceEnd;}
2790   } catch (ParseException e) {
2791     errorMessage = "';' expected after 'endswitch' keyword";
2792     errorLevel   = ERROR;
2793     errorStart = pos+1;
2794     errorEnd   = pos+1;
2795     processParseExceptionDebug(e);
2796   }
2797   {
2798     final AbstractCase[] abcase = new AbstractCase[cases.size()];
2799     cases.toArray(abcase);
2800     return abcase;
2801   }
2802 }
2803
2804 AbstractCase switchLabel0() :
2805 {
2806   final Expression expr;
2807   Statement statement;
2808   final ArrayList stmts = new ArrayList();
2809   final Token token = this.token;
2810   final int start = this.token.next.sourceStart;
2811 }
2812 {
2813   expr = SwitchLabel()
2814   ( statement = BlockStatementNoBreak() {stmts.add(statement);}
2815   | statement = htmlBlock()             {if (statement != null) {stmts.add(statement);}}
2816   | statement = BreakStatement()        {stmts.add(statement);})*
2817   //[ statement = BreakStatement()        {stmts.add(statement);}]
2818   {
2819     final int listSize = stmts.size();
2820     final Statement[] stmtsArray = new Statement[listSize];
2821     stmts.toArray(stmtsArray);
2822     if (expr == null) {//it's a default
2823       final int end = this.token.next.sourceStart;
2824       return new DefaultCase(stmtsArray,start,end);
2825     }
2826     if (listSize != 0) {
2827       return new Case(expr,stmtsArray,expr.sourceStart,stmtsArray[listSize-1].sourceEnd);
2828     } else {
2829       return new Case(expr,stmtsArray,expr.sourceStart,expr.sourceEnd);
2830     }
2831   }
2832 }
2833
2834 /**
2835  * A SwitchLabel.
2836  * case Expression() :
2837  * default :
2838  * @return the if it was a case and null if not
2839  */
2840 Expression SwitchLabel() :
2841 {
2842   final Expression expr;
2843 }
2844 {
2845   token = <CASE>
2846   try {
2847     expr = Expression()
2848   } catch (ParseException e) {
2849     if (errorMessage != null) throw e;
2850     errorMessage = "expression expected after 'case' keyword";
2851     errorLevel   = ERROR;
2852     errorStart = token.sourceEnd +1;
2853     errorEnd   = token.sourceEnd +1;
2854     throw e;
2855   }
2856   try {
2857     token = <COLON>
2858   } catch (ParseException e) {
2859     errorMessage = "':' expected after case expression";
2860     errorLevel   = ERROR;
2861     errorStart = expr.sourceEnd+1;
2862     errorEnd   = expr.sourceEnd+1;
2863     processParseExceptionDebug(e);
2864   }
2865   {return expr;}
2866 |
2867   token = <_DEFAULT>
2868   try {
2869     <COLON>
2870   } catch (ParseException e) {
2871     errorMessage = "':' expected after 'default' keyword";
2872     errorLevel   = ERROR;
2873     errorStart = token.sourceEnd+1;
2874     errorEnd   = token.sourceEnd+1;
2875     processParseExceptionDebug(e);
2876   }
2877   {return null;}
2878 }
2879
2880 Break BreakStatement() :
2881 {
2882   Expression expression = null;
2883   final Token token, token2;
2884   int pos;
2885 }
2886 {
2887   token = <BREAK> {pos = token.sourceEnd+1;}
2888   [ expression = Expression() {pos = expression.sourceEnd+1;}]
2889   try {
2890     token2 = <SEMICOLON>
2891     {pos = token2.sourceEnd;}
2892   } catch (ParseException e) {
2893     errorMessage = "';' expected after 'break' keyword";
2894     errorLevel   = ERROR;
2895     errorStart = pos;
2896     errorEnd   = pos;
2897     processParseExceptionDebug(e);
2898   }
2899   {return new Break(expression, token.sourceStart, pos);}
2900 }
2901
2902 IfStatement IfStatement() :
2903 {
2904   final Expression condition;
2905   final IfStatement ifStatement;
2906   Token token;
2907 }
2908 {
2909   token = <IF> condition = Condition("if")
2910   ifStatement = IfStatement0(condition,token.sourceStart,token.sourceEnd)
2911   {return ifStatement;}
2912 }
2913
2914
2915 Expression Condition(final String keyword) :
2916 {
2917   final Expression condition;
2918 }
2919 {
2920   try {
2921     <LPAREN>
2922   } catch (ParseException e) {
2923     errorMessage = "'(' expected after " + keyword + " keyword";
2924     errorLevel   = ERROR;
2925     errorStart = this.token.sourceEnd + 1;
2926     errorEnd   = this.token.sourceEnd + 1;
2927     processParseExceptionDebug(e);
2928   }
2929   condition = Expression()
2930   try {
2931      <RPAREN>
2932   } catch (ParseException e) {
2933     errorMessage = "')' expected after " + keyword + " keyword";
2934     errorLevel   = ERROR;
2935     errorStart = condition.sourceEnd+1;
2936     errorEnd   = condition.sourceEnd+1;
2937     processParseExceptionDebug(e);
2938   }
2939   {return condition;}
2940 }
2941
2942 IfStatement IfStatement0(final Expression condition, final int start,final int end) :
2943 {
2944   Statement statement;
2945   final Statement stmt;
2946   final Statement[] statementsArray;
2947   ElseIf elseifStatement;
2948   Else elseStatement = null;
2949   final ArrayList stmts;
2950   final ArrayList elseIfList = new ArrayList();
2951   final ElseIf[] elseIfs;
2952   int pos = jj_input_stream.getPosition();
2953   final int endStatements;
2954 }
2955 {
2956   <COLON>
2957   {stmts = new ArrayList();}
2958   (  statement = Statement() {stmts.add(statement);}
2959    | statement = htmlBlock() {if (statement != null) {stmts.add(statement);}})*
2960    {endStatements = jj_input_stream.getPosition();}
2961    (elseifStatement = ElseIfStatementColon() {elseIfList.add(elseifStatement);})*
2962    [elseStatement = ElseStatementColon()]
2963
2964   {try {
2965   setMarker(fileToParse,
2966             "Ugly syntax detected, you should if () {...} instead of if (): ... endif;",
2967             start,
2968             end,
2969             INFO,
2970             "Line " + token.beginLine);
2971   } catch (CoreException e) {
2972     PHPeclipsePlugin.log(e);
2973   }}
2974   try {
2975     <ENDIF>
2976   } catch (ParseException e) {
2977     errorMessage = "'endif' expected";
2978     errorLevel   = ERROR;
2979     errorStart = e.currentToken.sourceStart;
2980     errorEnd   = e.currentToken.sourceEnd;
2981     throw e;
2982   }
2983   try {
2984     <SEMICOLON>
2985   } catch (ParseException e) {
2986     errorMessage = "';' expected after 'endif' keyword";
2987     errorLevel   = ERROR;
2988     errorStart = e.currentToken.sourceStart;
2989     errorEnd   = e.currentToken.sourceEnd;
2990     throw e;
2991   }
2992     {
2993     elseIfs = new ElseIf[elseIfList.size()];
2994     elseIfList.toArray(elseIfs);
2995     if (stmts.size() == 1) {
2996       return new IfStatement(condition,
2997                              (Statement) stmts.get(0),
2998                               elseIfs,
2999                               elseStatement,
3000                               pos,
3001                               jj_input_stream.getPosition());
3002     } else {
3003       statementsArray = new Statement[stmts.size()];
3004       stmts.toArray(statementsArray);
3005       return new IfStatement(condition,
3006                              new Block(statementsArray,pos,endStatements),
3007                              elseIfs,
3008                              elseStatement,
3009                              pos,
3010                              jj_input_stream.getPosition());
3011     }
3012     }
3013
3014 |
3015   (stmt = Statement() | stmt = htmlBlock())
3016   ( LOOKAHEAD(1) elseifStatement = ElseIfStatement() {elseIfList.add(elseifStatement);})*
3017   [ LOOKAHEAD(1)
3018     <ELSE>
3019     try {
3020       {pos = jj_input_stream.getPosition();}
3021       statement = Statement()
3022       {elseStatement = new Else(statement,pos,jj_input_stream.getPosition());}
3023     } catch (ParseException e) {
3024       if (errorMessage != null) {
3025         throw e;
3026       }
3027       errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected";
3028       errorLevel   = ERROR;
3029       errorStart = e.currentToken.sourceStart;
3030       errorEnd   = e.currentToken.sourceEnd;
3031       throw e;
3032     }
3033   ]
3034   {
3035     elseIfs = new ElseIf[elseIfList.size()];
3036     elseIfList.toArray(elseIfs);
3037     return new IfStatement(condition,
3038                            stmt,
3039                            elseIfs,
3040                            elseStatement,
3041                            pos,
3042                            jj_input_stream.getPosition());}
3043 }
3044
3045 ElseIf ElseIfStatementColon() :
3046 {
3047   final Expression condition;
3048   Statement statement;
3049   final ArrayList list = new ArrayList();
3050   final Token elseifToken;
3051 }
3052 {
3053   elseifToken = <ELSEIF> condition = Condition("elseif")
3054   <COLON> (  statement = Statement() {list.add(statement);}
3055            | statement = htmlBlock() {if (statement != null) {list.add(statement);}})*
3056   {
3057   final int sizeList = list.size();
3058   final Statement[] stmtsArray = new Statement[sizeList];
3059   list.toArray(stmtsArray);
3060   return new ElseIf(condition,stmtsArray ,
3061                     elseifToken.sourceStart,
3062                     stmtsArray[sizeList-1].sourceEnd);}
3063 }
3064
3065 Else ElseStatementColon() :
3066 {
3067   Statement statement;
3068   final ArrayList list = new ArrayList();
3069   final Token elseToken;
3070 }
3071 {
3072   elseToken = <ELSE> <COLON> (  statement = Statement() {list.add(statement);}
3073                   | statement = htmlBlock() {if (statement != null) {list.add(statement);}})*
3074   {
3075   final int sizeList = list.size();
3076   final Statement[] stmtsArray = new Statement[sizeList];
3077   list.toArray(stmtsArray);
3078   return new Else(stmtsArray,elseToken.sourceStart,stmtsArray[sizeList-1].sourceEnd);}
3079 }
3080
3081 ElseIf ElseIfStatement() :
3082 {
3083   final Expression condition;
3084   //final Statement statement;
3085   final Token elseifToken;
3086   final Statement[] statement = new Statement[1];
3087 }
3088 {
3089   elseifToken = <ELSEIF> condition = Condition("elseif") statement[0] = Statement()
3090   {
3091   return new ElseIf(condition,statement,elseifToken.sourceStart,statement[0].sourceEnd);}
3092 }
3093
3094 WhileStatement WhileStatement() :
3095 {
3096   final Expression condition;
3097   final Statement action;
3098   final Token whileToken;
3099 }
3100 {
3101   whileToken = <WHILE>
3102     condition = Condition("while")
3103     action    = WhileStatement0(whileToken.sourceStart,whileToken.sourceEnd)
3104     {return new WhileStatement(condition,action,whileToken.sourceStart,action.sourceEnd);}
3105 }
3106
3107 Statement WhileStatement0(final int start, final int end) :
3108 {
3109   Statement statement;
3110   final ArrayList stmts = new ArrayList();
3111   final int pos = jj_input_stream.getPosition();
3112 }
3113 {
3114   <COLON> (statement = Statement() {stmts.add(statement);})*
3115   {try {
3116   setMarker(fileToParse,
3117             "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;",
3118             start,
3119             end,
3120             INFO,
3121             "Line " + token.beginLine);
3122   } catch (CoreException e) {
3123     PHPeclipsePlugin.log(e);
3124   }}
3125   try {
3126     <ENDWHILE>
3127   } catch (ParseException e) {
3128     errorMessage = "'endwhile' expected";
3129     errorLevel   = ERROR;
3130     errorStart = e.currentToken.sourceStart;
3131     errorEnd   = e.currentToken.sourceEnd;
3132     throw e;
3133   }
3134   try {
3135     <SEMICOLON>
3136     {
3137     final Statement[] stmtsArray = new Statement[stmts.size()];
3138     stmts.toArray(stmtsArray);
3139     return new Block(stmtsArray,pos,jj_input_stream.getPosition());}
3140   } catch (ParseException e) {
3141     errorMessage = "';' expected after 'endwhile' keyword";
3142     errorLevel   = ERROR;
3143     errorStart = e.currentToken.sourceStart;
3144     errorEnd   = e.currentToken.sourceEnd;
3145     throw e;
3146   }
3147 |
3148   statement = Statement()
3149   {return statement;}
3150 }
3151
3152 DoStatement DoStatement() :
3153 {
3154   final Statement action;
3155   final Expression condition;
3156   final Token token;
3157   Token token2 = null;
3158 }
3159 {
3160   token = <DO> action = Statement() <WHILE> condition = Condition("while")
3161   try {
3162     token2 = <SEMICOLON>
3163   } catch (ParseException e) {
3164     errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected";
3165     errorLevel   = ERROR;
3166     errorStart = condition.sourceEnd+1;
3167     errorEnd   = condition.sourceEnd+1;
3168     processParseExceptionDebug(e);
3169   }
3170   {
3171     if (token2 == null) {
3172       return new DoStatement(condition,action,token.sourceStart,condition.sourceEnd);
3173     }
3174     return new DoStatement(condition,action,token.sourceStart,token2.sourceEnd);
3175   }
3176 }
3177
3178 ForeachStatement ForeachStatement() :
3179 {
3180   Statement statement = null;
3181   Expression expression = null;
3182   ArrayVariableDeclaration variable = null;
3183   Token foreachToken;
3184   Token lparenToken = null;
3185   Token asToken = null;
3186   Token rparenToken = null;
3187   int pos;
3188 }
3189 {
3190   foreachToken = <FOREACH>
3191   try {
3192     lparenToken = <LPAREN>
3193     {pos = lparenToken.sourceEnd+1;}
3194   } catch (ParseException e) {
3195     errorMessage = "'(' expected after 'foreach' keyword";
3196     errorLevel   = ERROR;
3197     errorStart = e.currentToken.sourceStart;
3198     errorEnd   = e.currentToken.sourceEnd;
3199     processParseExceptionDebug(e);
3200     {pos = foreachToken.sourceEnd+1;}
3201   }
3202   try {
3203     expression = Expression()
3204     {pos = expression.sourceEnd+1;}
3205   } catch (ParseException e) {
3206     errorMessage = "variable expected";
3207     errorLevel   = ERROR;
3208     errorStart = e.currentToken.sourceStart;
3209     errorEnd   = e.currentToken.sourceEnd;
3210     processParseExceptionDebug(e);
3211   }
3212   try {
3213     asToken = <AS>
3214     {pos = asToken.sourceEnd+1;}
3215   } catch (ParseException e) {
3216     errorMessage = "'as' expected";
3217     errorLevel   = ERROR;
3218     errorStart = e.currentToken.sourceStart;
3219     errorEnd   = e.currentToken.sourceEnd;
3220     processParseExceptionDebug(e);
3221   }
3222   try {
3223     variable = ArrayVariable()
3224     {pos = variable.sourceEnd+1;}
3225   } catch (ParseException e) {
3226     if (errorMessage != null) throw e;
3227     errorMessage = "variable expected";
3228     errorLevel   = ERROR;
3229     errorStart = e.currentToken.sourceStart;
3230     errorEnd   = e.currentToken.sourceEnd;
3231     processParseExceptionDebug(e);
3232   }
3233   try {
3234     rparenToken = <RPAREN>
3235     {pos = rparenToken.sourceEnd+1;}
3236   } catch (ParseException e) {
3237     errorMessage = "')' expected after 'foreach' keyword";
3238     errorLevel   = ERROR;
3239     errorStart = e.currentToken.sourceStart;
3240     errorEnd   = e.currentToken.sourceEnd;
3241     processParseExceptionDebug(e);
3242   }
3243   try {
3244     statement = Statement()
3245     {pos = statement.sourceEnd+1;}
3246   } catch (ParseException e) {
3247     if (errorMessage != null) throw e;
3248     errorMessage = "statement expected";
3249     errorLevel   = ERROR;
3250     errorStart = e.currentToken.sourceStart;
3251     errorEnd   = e.currentToken.sourceEnd;
3252     processParseExceptionDebug(e);
3253   }
3254   {
3255    return new ForeachStatement(expression,
3256                                variable,
3257                                statement,
3258                                foreachToken.sourceStart,
3259                                pos);}
3260
3261 }
3262
3263 /**
3264  * a for declaration.
3265  * @return a node representing the for statement
3266  */
3267 ForStatement ForStatement() :
3268 {
3269 final Token token,tokenEndFor,token2,tokenColon;
3270 int pos;
3271 Expression[] initializations = null;
3272 Expression condition = null;
3273 Expression[] increments = null;
3274 Statement action;
3275 final ArrayList list = new ArrayList();
3276 }
3277 {
3278   token = <FOR>
3279   try {
3280     <LPAREN>
3281   } catch (ParseException e) {
3282     errorMessage = "'(' expected after 'for' keyword";
3283     errorLevel   = ERROR;
3284     errorStart = token.sourceEnd;
3285     errorEnd   = token.sourceEnd +1;
3286     processParseExceptionDebug(e);
3287   }
3288      [ initializations = ForInit() ] <SEMICOLON>
3289      [ condition = Expression() ] <SEMICOLON>
3290      [ increments = StatementExpressionList() ] <RPAREN>
3291     (
3292       action = Statement()
3293       {return new ForStatement(initializations,
3294                                condition,
3295                                increments,
3296                                action,
3297                                token.sourceStart,
3298                                action.sourceEnd);}
3299     |
3300       tokenColon = <COLON> {pos = tokenColon.sourceEnd+1;}
3301       (action = Statement() {list.add(action);pos = action.sourceEnd+1;})*
3302       {
3303         try {
3304         setMarker(fileToParse,
3305                   "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;",
3306                   token.sourceStart,
3307                   token.sourceEnd,
3308                   INFO,
3309                   "Line " + token.beginLine);
3310         } catch (CoreException e) {
3311           PHPeclipsePlugin.log(e);
3312         }
3313       }
3314       try {
3315         tokenEndFor = <ENDFOR>
3316         {pos = tokenEndFor.sourceEnd+1;}
3317       } catch (ParseException e) {
3318         errorMessage = "'endfor' expected";
3319         errorLevel   = ERROR;
3320         errorStart = pos;
3321         errorEnd   = pos;
3322         processParseExceptionDebug(e);
3323       }
3324       try {
3325         token2 = <SEMICOLON>
3326         {pos = token2.sourceEnd+1;}
3327       } catch (ParseException e) {
3328         errorMessage = "';' expected after 'endfor' keyword";
3329         errorLevel   = ERROR;
3330         errorStart = pos;
3331         errorEnd   = pos;
3332         processParseExceptionDebug(e);
3333       }
3334       {
3335       final Statement[] stmtsArray = new Statement[list.size()];
3336       list.toArray(stmtsArray);
3337       return new ForStatement(initializations,
3338                               condition,
3339                               increments,
3340                               new Block(stmtsArray,
3341                                         stmtsArray[0].sourceStart,
3342                                         stmtsArray[stmtsArray.length-1].sourceEnd),
3343                               token.sourceStart,
3344                               pos);}
3345     )
3346 }
3347
3348 Expression[] ForInit() :
3349 {
3350   final Expression[] exprs;
3351 }
3352 {
3353   LOOKAHEAD(LocalVariableDeclaration())
3354   exprs = LocalVariableDeclaration()
3355   {return exprs;}
3356 |
3357   exprs = StatementExpressionList()
3358   {return exprs;}
3359 }
3360
3361 Expression[] StatementExpressionList() :
3362 {
3363   final ArrayList list = new ArrayList();
3364   final Expression expr;
3365 }
3366 {
3367   expr = Expression()   {list.add(expr);}
3368   (<COMMA> Expression() {list.add(expr);})*
3369   {
3370     final Expression[] exprsArray = new Expression[list.size()];
3371     list.toArray(exprsArray);
3372     return exprsArray;
3373   }
3374 }
3375
3376 Continue ContinueStatement() :
3377 {
3378   Expression expr = null;
3379   final Token token;
3380   Token token2 = null;
3381 }
3382 {
3383   token = <CONTINUE> [ expr = Expression() ]
3384   try {
3385     token2 = <SEMICOLON>
3386   } catch (ParseException e) {
3387     errorMessage = "';' expected after 'continue' statement";
3388     errorLevel   = ERROR;
3389     if (expr == null) {
3390       errorStart = token.sourceEnd+1;
3391       errorEnd   = token.sourceEnd+1;
3392     } else {
3393       errorStart = expr.sourceEnd+1;
3394       errorEnd   = expr.sourceEnd+1;
3395     }
3396     processParseExceptionDebug(e);
3397   }
3398   {
3399     if (token2 == null) {
3400       if (expr == null) {
3401         return new Continue(expr,token.sourceStart,token.sourceEnd);
3402       }
3403       return new Continue(expr,token.sourceStart,expr.sourceEnd);
3404     }
3405     return new Continue(expr,token.sourceStart,token2.sourceEnd);
3406   }
3407 }
3408
3409 ReturnStatement ReturnStatement() :
3410 {
3411   Expression expr = null;
3412   final Token token;
3413   Token token2 = null;
3414 }
3415 {
3416   token = <RETURN> [ expr = Expression() ]
3417   try {
3418     token2 = <SEMICOLON>
3419   } catch (ParseException e) {
3420     errorMessage = "';' expected after 'return' statement";
3421     errorLevel   = ERROR;
3422     if (expr == null) {
3423       errorStart = token.sourceEnd+1;
3424       errorEnd   = token.sourceEnd+1;
3425     } else {
3426       errorStart = expr.sourceEnd+1;
3427       errorEnd   = expr.sourceEnd+1;
3428     }
3429     processParseExceptionDebug(e);
3430   }
3431   {
3432     if (token2 == null) {
3433       if (expr == null) {
3434         return new ReturnStatement(expr,token.sourceStart,token.sourceEnd);
3435       }
3436       return new ReturnStatement(expr,token.sourceStart,expr.sourceEnd);
3437     }
3438     return new ReturnStatement(expr,token.sourceStart,token2.sourceEnd);
3439   }
3440 }
3441