improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
1 /***********************************************************************************************************************************
2  * Copyright (c) 2002 www.phpeclipse.de All rights reserved. This program and the accompanying material are made available under the
3  * terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html
5  * 
6  * Contributors: www.phpeclipse.de
7  **********************************************************************************************************************************/
8 package net.sourceforge.phpdt.internal.compiler.parser;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
15 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
16 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
17 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
18 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
20 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
21 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
22 import net.sourceforge.phpdt.internal.compiler.util.Util;
23 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
24 import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
25 import net.sourceforge.phpeclipse.internal.compiler.ast.AND_AND_Expression;
26 import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
27 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
28 import net.sourceforge.phpeclipse.internal.compiler.ast.BinaryExpression;
29 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
30 import net.sourceforge.phpeclipse.internal.compiler.ast.ConditionalExpression;
31 import net.sourceforge.phpeclipse.internal.compiler.ast.EmptyStatement;
32 import net.sourceforge.phpeclipse.internal.compiler.ast.EqualExpression;
33 import net.sourceforge.phpeclipse.internal.compiler.ast.Expression;
34 import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
35 import net.sourceforge.phpeclipse.internal.compiler.ast.FieldReference;
36 import net.sourceforge.phpeclipse.internal.compiler.ast.IfStatement;
37 import net.sourceforge.phpeclipse.internal.compiler.ast.ImportReference;
38 import net.sourceforge.phpeclipse.internal.compiler.ast.InstanceOfExpression;
39 import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration;
40 import net.sourceforge.phpeclipse.internal.compiler.ast.OR_OR_Expression;
41 import net.sourceforge.phpeclipse.internal.compiler.ast.OperatorIds;
42 import net.sourceforge.phpeclipse.internal.compiler.ast.SingleTypeReference;
43 import net.sourceforge.phpeclipse.internal.compiler.ast.Statement;
44 import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteral;
45 import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteralDQ;
46 import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteralSQ;
47 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
48 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeReference;
49 import net.sourceforge.phpeclipse.ui.overlaypages.ProjectPrefUtil;
50
51 import org.eclipse.core.resources.IFile;
52 import org.eclipse.core.resources.IProject;
53 import org.eclipse.core.resources.IResource;
54 import org.eclipse.core.runtime.IPath;
55
56 public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicInformation {
57   protected final static int StackIncrement = 255;
58
59   protected int stateStackTop;
60
61   //  protected int[] stack = new int[StackIncrement];
62
63   public int firstToken; // handle for multiple parsing goals
64
65   public int lastAct; //handle for multiple parsing goals
66
67   //  protected RecoveredElement currentElement;
68
69   public static boolean VERBOSE_RECOVERY = false;
70
71   protected boolean diet = false; //tells the scanner to jump over some
72
73   // parts of the code/expressions like
74   // method bodies
75   //scanner token
76   public Scanner scanner;
77
78   //  private ArrayList phpList;
79
80   //  private int currentPHPString;
81
82   //  private boolean phpEnd;
83
84   // private static HashMap keywordMap = null;
85   private String str;
86
87   // current character
88   //  char ch;
89   // current token
90   int token;
91
92   // row counter for syntax errors:
93   //int rowCount;
94   // column counter for syntax errors:
95   //int columnCount;
96   //int chIndx;
97   //
98   //    // current identifier
99   //    String identifier;
100   //  Long longNumber;
101
102   //  Double doubleNumber;
103
104   //  private String stringValue;
105
106   /** Contains the current expression. */
107   // private StringBuffer expression;
108   //private boolean phpMode;
109   protected int modifiers;
110
111   protected int modifiersSourceStart;
112
113   protected Parser(ProblemReporter problemReporter) {
114     this.problemReporter = problemReporter;
115     this.options = problemReporter.options;
116     //    this.currentPHPString = 0;
117     //          PHPParserSuperclass.fileToParse = fileToParse;
118     //    this.phpList = null;
119     //    this.indexManager = null;
120     this.str = "";
121     this.token = TokenNameEOF;
122     //    this.chIndx = 0;
123     //    this.rowCount = 1;
124     //    this.columnCount = 0;
125     //    this.phpEnd = false;
126     //   getNextToken();
127     this.initializeScanner();
128   }
129
130   public void setFileToParse(IFile fileToParse) {
131     //    this.currentPHPString = 0;
132     //    PHPParserSuperclass.fileToParse = fileToParse;
133     //    this.phpList = null;
134     //    this.indexManager = null;
135     this.str = "";
136     this.token = TokenNameEOF;
137     //    this.phpEnd = false;
138     this.initializeScanner();
139   }
140
141   /**
142    * ClassDeclaration Constructor.
143    * 
144    * @param s
145    * @param sess
146    *          Description of Parameter
147    * @see
148    */
149   public Parser(IFile fileToParse) {
150     //    if (keywordMap == null) {
151     //      keywordMap = new HashMap();
152     //      for (int i = 0; i < PHP_KEYWORS.length; i++) {
153     //        keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
154     //      }
155     //    }
156     //    this.currentPHPString = 0;
157     //    PHPParserSuperclass.fileToParse = fileToParse;
158     //    this.phpList = null;
159     this.includesList = null;
160     this.str = "";
161     this.token = TokenNameEOF;
162     //    this.chIndx = 0;
163     //    this.rowCount = 1;
164     //    this.columnCount = 0;
165     //    this.phpEnd = false;
166     //   getNextToken();
167     this.initializeScanner();
168   }
169
170   public void initializeScanner() {
171     this.scanner = new Scanner(false /* comment */, false /* whitespace */, this.options
172         .getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /* nls */, false, false,
173         this.options.taskTags/* taskTags */, this.options.taskPriorites/* taskPriorities */, true/* isTaskCaseSensitive */);
174   }
175
176   /**
177    * Create marker for the parse error
178    */
179   //  private void setMarker(String message, int charStart, int charEnd, int
180   // errorLevel) {
181   //    setMarker(fileToParse, message, charStart, charEnd, errorLevel);
182   //  }
183   /**
184    * This method will throw the SyntaxError. It will add the good lines and columns to the Error
185    * 
186    * @param error
187    *          the error message
188    * @throws SyntaxError
189    *           the error raised
190    */
191   private void throwSyntaxError(String error) {
192     int problemStartPosition = scanner.getCurrentTokenStartPosition();
193     int problemEndPosition = scanner.getCurrentTokenEndPosition();
194     throwSyntaxError(error, problemStartPosition, problemEndPosition + 1);
195   }
196
197   /**
198    * This method will throw the SyntaxError. It will add the good lines and columns to the Error
199    * 
200    * @param error
201    *          the error message
202    * @throws SyntaxError
203    *           the error raised
204    */
205   //  private void throwSyntaxError(String error, int startRow) {
206   //    throw new SyntaxError(startRow, 0, " ", error);
207   //  }
208   private void throwSyntaxError(String error, int problemStartPosition, int problemEndPosition) {
209     if (referenceContext != null) {
210       problemReporter.phpParsingError(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext,
211           compilationUnit.compilationResult);
212     }
213     throw new SyntaxError(1, 0, " ", error);
214   }
215
216   private void reportSyntaxError(String error) {
217     int problemStartPosition = scanner.getCurrentTokenStartPosition();
218     int problemEndPosition = scanner.getCurrentTokenEndPosition();
219     reportSyntaxError(error, problemStartPosition, problemEndPosition + 1);
220   }
221
222   private void reportSyntaxError(String error, int problemStartPosition, int problemEndPosition) {
223     if (referenceContext != null) {
224       problemReporter.phpParsingError(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext,
225           compilationUnit.compilationResult);
226     }
227   }
228
229   private void reportSyntaxWarning(String error, int problemStartPosition, int problemEndPosition) {
230     if (referenceContext != null) {
231       problemReporter.phpParsingWarning(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext,
232           compilationUnit.compilationResult);
233     }
234   }
235
236   /**
237    * gets the next token from input
238    */
239   private void getNextToken() {
240     try {
241       token = scanner.getNextToken();
242       if (Scanner.DEBUG) {
243         int currentEndPosition = scanner.getCurrentTokenEndPosition();
244         int currentStartPosition = scanner.getCurrentTokenStartPosition();
245         System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
246         System.out.println(scanner.toStringAction(token));
247       }
248     } catch (InvalidInputException e) {
249       token = TokenNameERROR;
250       String detailedMessage = e.getMessage();
251
252       if (detailedMessage == Scanner.UNTERMINATED_STRING) {
253         throwSyntaxError("Unterminated string.");
254       } else if (detailedMessage == Scanner.UNTERMINATED_COMMENT) {
255         throwSyntaxError("Unterminated commment.");
256       }
257     }
258     return;
259   }
260
261   public void init(String s) {
262     this.str = s;
263     this.token = TokenNameEOF;
264     this.includesList = new ArrayList();
265     //    this.chIndx = 0;
266     //    this.rowCount = 1;
267     //    this.columnCount = 0;
268     //    this.phpEnd = false;
269     //    this.phpMode = false;
270     /* scanner initialization */
271     scanner.setSource(s.toCharArray());
272     scanner.setPHPMode(false);
273     astPtr = 0;
274   }
275
276   protected void initialize(boolean phpMode) {
277     initialize(phpMode, null);
278   }
279
280   protected void initialize(boolean phpMode, IdentifierIndexManager indexManager) {
281     compilationUnit = null;
282     referenceContext = null;
283     this.includesList = new ArrayList();
284     //    this.indexManager = indexManager;
285     this.str = "";
286     this.token = TokenNameEOF;
287     //    this.chIndx = 0;
288     //    this.rowCount = 1;
289     //    this.columnCount = 0;
290     //    this.phpEnd = false;
291     //    this.phpMode = phpMode;
292     scanner.setPHPMode(phpMode);
293     astPtr = 0;
294   }
295
296   /**
297    * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
298    */
299   public void parse(String s) {
300     parse(s, null);
301   }
302
303   /**
304    * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
305    */
306   public void parse(String s, HashMap variables) {
307     fMethodVariables = variables;
308     init(s);
309     parse();
310   }
311
312   /**
313    * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
314    */
315   protected void parse() {
316     if (scanner.compilationUnit != null) {
317       IResource resource = scanner.compilationUnit.getResource();
318       if (resource != null && resource instanceof IFile) {
319         // set the package name
320         consumePackageDeclarationName((IFile) resource);
321       }
322     }
323     getNextToken();
324     do {
325       try {
326         if (token != TokenNameEOF && token != TokenNameERROR) {
327           statementList();
328         }
329         if (token != TokenNameEOF) {
330           if (token == TokenNameERROR) {
331             throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
332           }
333           if (token == TokenNameRPAREN) {
334             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
335           }
336           if (token == TokenNameRBRACE) {
337             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
338           }
339           if (token == TokenNameRBRACKET) {
340             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
341           }
342           if (token == TokenNameLPAREN) {
343             throwSyntaxError("Read character '('; end-of-file not reached.");
344           }
345           if (token == TokenNameLBRACE) {
346             throwSyntaxError("Read character '{';  end-of-file not reached.");
347           }
348           if (token == TokenNameLBRACKET) {
349             throwSyntaxError("Read character '[';  end-of-file not reached.");
350           }
351           throwSyntaxError("End-of-file not reached.");
352         }
353         break;
354       } catch (SyntaxError sytaxErr1) {
355         break;
356         //        // if an error occured,
357         //        // try to find keywords 'abstract' 'final' 'class' or 'function'
358         //        // to parse the rest of the string
359         //        boolean tokenize = scanner.tokenizeStrings;
360         //        if (!tokenize) {
361         //          scanner.tokenizeStrings = true;
362         //        }
363         //        try {
364         //          while (token != TokenNameEOF) {
365         //            if (token == TokenNameabstract || token == TokenNamefinal || token == TokenNameclass || token == TokenNamefunction) {
366         //              break;
367         //            }
368         //            getNextToken();
369         //          }
370         //          if (token == TokenNameEOF) {
371         //            break;
372         //          }
373         //        } catch (SyntaxError sytaxErr2) {
374         //          break;
375         //        } finally {
376         //          scanner.tokenizeStrings = tokenize;
377         //        }
378       }
379     } while (true);
380
381     endParse(0);
382   }
383
384   /**
385    * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
386    */
387   public void parseFunction(String s, HashMap variables) {
388     init(s);
389     scanner.phpMode = true;
390     parseFunction(variables);
391   }
392
393   /**
394    * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
395    */
396   protected void parseFunction(HashMap variables) {
397     getNextToken();
398     boolean hasModifiers = member_modifiers();
399     if (token == TokenNamefunction) {
400       if (!hasModifiers) {
401         checkAndSetModifiers(AccPublic);
402       }
403       this.fMethodVariables = variables;
404
405       MethodDeclaration methodDecl = new MethodDeclaration(null);
406       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
407       methodDecl.modifiers = this.modifiers;
408       methodDecl.type = MethodDeclaration.METHOD_DEFINITION;
409       try {
410         getNextToken();
411         functionDefinition(methodDecl);
412       } catch (SyntaxError sytaxErr1) {
413         return;
414       } finally {
415         int sourceEnd = scanner.getCurrentTokenStartPosition();
416         if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) {
417           sourceEnd = methodDecl.declarationSourceStart + 1;
418         }
419         methodDecl.declarationSourceEnd = sourceEnd;
420       }
421     }
422   }
423
424   protected CompilationUnitDeclaration endParse(int act) {
425
426     this.lastAct = act;
427
428     //    if (currentElement != null) {
429     //      currentElement.topElement().updateParseTree();
430     //      if (VERBOSE_RECOVERY) {
431     //        System.out.print(Util.bind("parser.syntaxRecovery")); //$NON-NLS-1$
432     //        System.out.println("--------------------------"); //$NON-NLS-1$
433     //        System.out.println(compilationUnit);
434     //        System.out.println("----------------------------------"); //$NON-NLS-1$
435     //      }
436     //    } else {
437     if (diet & VERBOSE_RECOVERY) {
438       System.out.print(Util.bind("parser.regularParse")); //$NON-NLS-1$
439       System.out.println("--------------------------"); //$NON-NLS-1$
440       System.out.println(compilationUnit);
441       System.out.println("----------------------------------"); //$NON-NLS-1$
442     }
443     //    }
444     if (scanner.recordLineSeparator) {
445       compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
446     }
447     if (scanner.taskTags != null) {
448       for (int i = 0; i < scanner.foundTaskCount; i++) {
449         problemReporter().task(new String(scanner.foundTaskTags[i]), new String(scanner.foundTaskMessages[i]),
450             scanner.foundTaskPriorities[i] == null ? null : new String(scanner.foundTaskPriorities[i]),
451             scanner.foundTaskPositions[i][0], scanner.foundTaskPositions[i][1]);
452       }
453     }
454     compilationUnit.imports = new ImportReference[includesList.size()];
455     for (int i = 0; i < includesList.size(); i++) {
456       compilationUnit.imports[i] = (ImportReference) includesList.get(i);
457     }
458     return compilationUnit;
459   }
460
461   private boolean isVariable() {
462     return token == TokenNameVariable; //  || token == TokenNamethis;
463   }
464
465   private void statementList() {
466     do {
467       try {
468         statement(TokenNameEOF);
469         if ((token == TokenNameRBRACE) || (token == TokenNamecase) || (token == TokenNamedefault) || (token == TokenNameelse)
470             || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor)
471             || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch)
472             || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) {
473           return;
474         }
475       } catch (SyntaxError sytaxErr1) {
476         // if an error occured,
477         // try to find keywords
478         // to parse the rest of the string
479         boolean tokenize = scanner.tokenizeStrings;
480         if (!tokenize) {
481           scanner.tokenizeStrings = true;
482         }
483         try {
484           while (token != TokenNameEOF) {
485             if ((token == TokenNameRBRACE) || (token == TokenNamecase) || (token == TokenNamedefault) || (token == TokenNameelse)
486                 || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor)
487                 || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch)
488                 || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) {
489               return;
490             }
491             if (token == TokenNameif || token == TokenNameswitch || token == TokenNamefor || token == TokenNamewhile
492                 || token == TokenNamedo || token == TokenNameforeach || token == TokenNamecontinue || token == TokenNamebreak
493                 || token == TokenNamereturn || token == TokenNameexit || token == TokenNameecho || token == TokenNameglobal
494                 || token == TokenNamestatic || token == TokenNameunset || token == TokenNamefunction || token == TokenNamedeclare
495                 || token == TokenNametry || token == TokenNamecatch || token == TokenNamethrow || token == TokenNamefinal
496                 || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
497               break;
498             }
499             //            System.out.println(scanner.toStringAction(token));
500             getNextToken();
501             //            System.out.println(scanner.toStringAction(token));
502           }
503           if (token == TokenNameEOF) {
504             throw sytaxErr1;
505           }
506         } finally {
507           scanner.tokenizeStrings = tokenize;
508         }
509       }
510     } while (true);
511   }
512
513   private void functionBody(MethodDeclaration methodDecl) {
514     // '{' [statement-list] '}'
515     if (token == TokenNameLBRACE) {
516       getNextToken();
517     } else {
518       throwSyntaxError("'{' expected in compound-statement.");
519     }
520     if (token != TokenNameRBRACE) {
521       statementList();
522     }
523     if (token == TokenNameRBRACE) {
524       //      methodDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
525       getNextToken();
526     } else {
527       throwSyntaxError("'}' expected in compound-statement.");
528     }
529   }
530
531   private Statement statement(int previousToken) {
532     Statement statement = null;
533     Expression expression;
534     int sourceStart = scanner.getCurrentTokenStartPosition();
535     if (token == TokenNameif) {
536       getNextToken();
537       if (token == TokenNameLPAREN) {
538         getNextToken();
539       } else {
540         throwSyntaxError("'(' expected after 'if' keyword.");
541       }
542       expression = expr();
543       if (token == TokenNameRPAREN) {
544         getNextToken();
545       } else {
546         throwSyntaxError("')' expected after 'if' condition.");
547       }
548       ifStatement();
549       return new IfStatement(expression, statement, sourceStart, scanner.getCurrentTokenEndPosition());
550     } else if (token == TokenNameswitch) {
551       getNextToken();
552       if (token == TokenNameLPAREN) {
553         getNextToken();
554       } else {
555         throwSyntaxError("'(' expected after 'switch' keyword.");
556       }
557       expr();
558       if (token == TokenNameRPAREN) {
559         getNextToken();
560       } else {
561         throwSyntaxError("')' expected after 'switch' condition.");
562       }
563       switchStatement();
564       return statement;
565     } else if (token == TokenNamefor) {
566       getNextToken();
567       if (token == TokenNameLPAREN) {
568         getNextToken();
569       } else {
570         throwSyntaxError("'(' expected after 'for' keyword.");
571       }
572       if (token == TokenNameSEMICOLON) {
573         getNextToken();
574       } else {
575         expressionList();
576         if (token == TokenNameSEMICOLON) {
577           getNextToken();
578         } else {
579           throwSyntaxError("';' expected after 'for'.");
580         }
581       }
582       if (token == TokenNameSEMICOLON) {
583         getNextToken();
584       } else {
585         expressionList();
586         if (token == TokenNameSEMICOLON) {
587           getNextToken();
588         } else {
589           throwSyntaxError("';' expected after 'for'.");
590         }
591       }
592       if (token == TokenNameRPAREN) {
593         getNextToken();
594       } else {
595         expressionList();
596         if (token == TokenNameRPAREN) {
597           getNextToken();
598         } else {
599           throwSyntaxError("')' expected after 'for'.");
600         }
601       }
602       forStatement();
603       return statement;
604     } else if (token == TokenNamewhile) {
605       getNextToken();
606       if (token == TokenNameLPAREN) {
607         getNextToken();
608       } else {
609         throwSyntaxError("'(' expected after 'while' keyword.");
610       }
611       expr();
612       if (token == TokenNameRPAREN) {
613         getNextToken();
614       } else {
615         throwSyntaxError("')' expected after 'while' condition.");
616       }
617       whileStatement();
618       return statement;
619     } else if (token == TokenNamedo) {
620       getNextToken();
621       if (token == TokenNameLBRACE) {
622         getNextToken();
623         if (token != TokenNameRBRACE) {
624           statementList();
625         }
626         if (token == TokenNameRBRACE) {
627           getNextToken();
628         } else {
629           throwSyntaxError("'}' expected after 'do' keyword.");
630         }
631       } else {
632         statement(TokenNameEOF);
633       }
634       if (token == TokenNamewhile) {
635         getNextToken();
636         if (token == TokenNameLPAREN) {
637           getNextToken();
638         } else {
639           throwSyntaxError("'(' expected after 'while' keyword.");
640         }
641         expr();
642         if (token == TokenNameRPAREN) {
643           getNextToken();
644         } else {
645           throwSyntaxError("')' expected after 'while' condition.");
646         }
647       } else {
648         throwSyntaxError("'while' expected after 'do' keyword.");
649       }
650       if (token == TokenNameSEMICOLON) {
651         getNextToken();
652       } else {
653         if (token != TokenNameINLINE_HTML) {
654           throwSyntaxError("';' expected after do-while statement.");
655         }
656         getNextToken();
657       }
658       return statement;
659     } else if (token == TokenNameforeach) {
660       getNextToken();
661       if (token == TokenNameLPAREN) {
662         getNextToken();
663       } else {
664         throwSyntaxError("'(' expected after 'foreach' keyword.");
665       }
666       expr();
667       if (token == TokenNameas) {
668         getNextToken();
669       } else {
670         throwSyntaxError("'as' expected after 'foreach' exxpression.");
671       }
672       //      variable();
673       foreach_variable();
674       foreach_optional_arg();
675       if (token == TokenNameEQUAL_GREATER) {
676         getNextToken();
677         variable();
678       }
679       if (token == TokenNameRPAREN) {
680         getNextToken();
681       } else {
682         throwSyntaxError("')' expected after 'foreach' expression.");
683       }
684       foreachStatement();
685       return statement;
686     } else if (token == TokenNamecontinue || token == TokenNamebreak || token == TokenNamereturn) {
687       getNextToken();
688       if (token != TokenNameSEMICOLON) {
689         expr();
690       }
691       if (token == TokenNameSEMICOLON) {
692         getNextToken();
693       } else {
694         if (token != TokenNameINLINE_HTML) {
695           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
696         }
697         getNextToken();
698       }
699       return statement;
700     } else if (token == TokenNameecho) {
701       getNextToken();
702       expressionList();
703       if (token == TokenNameSEMICOLON) {
704         getNextToken();
705       } else {
706         if (token != TokenNameINLINE_HTML) {
707           throwSyntaxError("';' expected after 'echo' statement.");
708         }
709         getNextToken();
710       }
711       return statement;
712     } else if (token == TokenNameINLINE_HTML) {
713       getNextToken();
714       return statement;
715       //    } else if (token == TokenNameprint) {
716       //      getNextToken();
717       //      expression();
718       //      if (token == TokenNameSEMICOLON) {
719       //        getNextToken();
720       //      } else {
721       //        if (token != TokenNameStopPHP) {
722       //          throwSyntaxError("';' expected after 'print' statement.");
723       //        }
724       //        getNextToken();
725       //      }
726       //      return;
727     } else if (token == TokenNameglobal) {
728       getNextToken();
729       global_var_list();
730       if (token == TokenNameSEMICOLON) {
731         getNextToken();
732       } else {
733         if (token != TokenNameINLINE_HTML) {
734           throwSyntaxError("';' expected after 'global' statement.");
735         }
736         getNextToken();
737       }
738       return statement;
739     } else if (token == TokenNamestatic) {
740       getNextToken();
741       static_var_list();
742       if (token == TokenNameSEMICOLON) {
743         getNextToken();
744       } else {
745         if (token != TokenNameINLINE_HTML) {
746           throwSyntaxError("';' expected after 'static' statement.");
747         }
748         getNextToken();
749       }
750       return statement;
751     } else if (token == TokenNameunset) {
752       getNextToken();
753       if (token == TokenNameLPAREN) {
754         getNextToken();
755       } else {
756         throwSyntaxError("'(' expected after 'unset' statement.");
757       }
758       unset_variables();
759       if (token == TokenNameRPAREN) {
760         getNextToken();
761       } else {
762         throwSyntaxError("')' expected after 'unset' statement.");
763       }
764       if (token == TokenNameSEMICOLON) {
765         getNextToken();
766       } else {
767         if (token != TokenNameINLINE_HTML) {
768           throwSyntaxError("';' expected after 'unset' statement.");
769         }
770         getNextToken();
771       }
772       return statement;
773     } else if (token == TokenNamefunction) {
774       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
775       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
776       methodDecl.modifiers = AccDefault;
777       methodDecl.type = MethodDeclaration.FUNCTION_DEFINITION;
778       try {
779         getNextToken();
780         functionDefinition(methodDecl);
781       } finally {
782         int sourceEnd = scanner.getCurrentTokenStartPosition();
783         if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) {
784           sourceEnd = methodDecl.declarationSourceStart + 1;
785         }
786         methodDecl.declarationSourceEnd = sourceEnd;
787       }
788       return statement;
789     } else if (token == TokenNamedeclare) {
790       //T_DECLARE '(' declare_list ')' declare_statement
791       getNextToken();
792       if (token != TokenNameLPAREN) {
793         throwSyntaxError("'(' expected in 'declare' statement.");
794       }
795       getNextToken();
796       declare_list();
797       if (token != TokenNameRPAREN) {
798         throwSyntaxError("')' expected in 'declare' statement.");
799       }
800       getNextToken();
801       declare_statement();
802       return statement;
803     } else if (token == TokenNametry) {
804       getNextToken();
805       if (token != TokenNameLBRACE) {
806         throwSyntaxError("'{' expected in 'try' statement.");
807       }
808       getNextToken();
809       statementList();
810       if (token != TokenNameRBRACE) {
811         throwSyntaxError("'}' expected in 'try' statement.");
812       }
813       getNextToken();
814       return statement;
815     } else if (token == TokenNamecatch) {
816       getNextToken();
817       if (token != TokenNameLPAREN) {
818         throwSyntaxError("'(' expected in 'catch' statement.");
819       }
820       getNextToken();
821       fully_qualified_class_name();
822       if (token != TokenNameVariable) {
823         throwSyntaxError("Variable expected in 'catch' statement.");
824       }
825       getNextToken();
826       if (token != TokenNameRPAREN) {
827         throwSyntaxError("')' expected in 'catch' statement.");
828       }
829       getNextToken();
830       if (token != TokenNameLBRACE) {
831         throwSyntaxError("'{' expected in 'catch' statement.");
832       }
833       getNextToken();
834       if (token != TokenNameRBRACE) {
835         statementList();
836         if (token != TokenNameRBRACE) {
837           throwSyntaxError("'}' expected in 'catch' statement.");
838         }
839       }
840       getNextToken();
841       additional_catches();
842       return statement;
843     } else if (token == TokenNamethrow) {
844       getNextToken();
845       expr();
846       if (token == TokenNameSEMICOLON) {
847         getNextToken();
848       } else {
849         throwSyntaxError("';' expected after 'throw' exxpression.");
850       }
851       return statement;
852     } else if (token == TokenNamefinal || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
853       try {
854         TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
855         typeDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
856         typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
857         typeDecl.name = new char[] { ' ' };
858         // default super class
859         typeDecl.superclass = new SingleTypeReference(TypeConstants.OBJECT, 0);
860         compilationUnit.types.add(typeDecl);
861         pushOnAstStack(typeDecl);
862         unticked_class_declaration_statement(typeDecl);
863       } finally {
864         // reduce stack:
865         astPtr--;
866         astLengthPtr--;
867       }
868       return statement;
869       //      } else {
870       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
871     } else if (token == TokenNameLBRACE) {
872       getNextToken();
873       if (token != TokenNameRBRACE) {
874         statementList();
875       }
876       if (token == TokenNameRBRACE) {
877         getNextToken();
878         return statement;
879       } else {
880         throwSyntaxError("'}' expected.");
881       }
882     } else {
883       if (token != TokenNameSEMICOLON) {
884         expr();
885       }
886       if (token == TokenNameSEMICOLON) {
887         getNextToken();
888         return statement;
889       } else {
890         if (token == TokenNameRBRACE) {
891           reportSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
892         } else {
893           if (token != TokenNameINLINE_HTML && token != TokenNameEOF) {
894             throwSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
895           }
896           getNextToken();
897         }
898       }
899     }
900     // may be null
901     return statement;
902   }
903
904   private void declare_statement() {
905     //  statement
906     //| ':' inner_statement_list T_ENDDECLARE ';'
907     //;
908     if (token == TokenNameCOLON) {
909       getNextToken();
910       // TODO: implement inner_statement_list();
911       statementList();
912       if (token != TokenNameenddeclare) {
913         throwSyntaxError("'enddeclare' expected in 'declare' statement.");
914       }
915       getNextToken();
916       if (token != TokenNameSEMICOLON) {
917         throwSyntaxError("';' expected after 'enddeclare' keyword.");
918       }
919       getNextToken();
920     } else {
921       statement(TokenNameRPAREN);
922     }
923   }
924
925   private void declare_list() {
926     //  T_STRING '=' static_scalar
927     //| declare_list ',' T_STRING '=' static_scalar
928     while (true) {
929       if (token != TokenNameIdentifier) {
930         throwSyntaxError("Identifier expected in 'declare' list.");
931       }
932       getNextToken();
933       if (token != TokenNameEQUAL) {
934         throwSyntaxError("'=' expected in 'declare' list.");
935       }
936       getNextToken();
937       static_scalar();
938       if (token != TokenNameCOMMA) {
939         break;
940       }
941       getNextToken();
942     }
943   }
944
945   private void additional_catches() {
946     while (token == TokenNamecatch) {
947       getNextToken();
948       if (token != TokenNameLPAREN) {
949         throwSyntaxError("'(' expected in 'catch' statement.");
950       }
951       getNextToken();
952       fully_qualified_class_name();
953       if (token != TokenNameVariable) {
954         throwSyntaxError("Variable expected in 'catch' statement.");
955       }
956       getNextToken();
957       if (token != TokenNameRPAREN) {
958         throwSyntaxError("')' expected in 'catch' statement.");
959       }
960       getNextToken();
961       if (token != TokenNameLBRACE) {
962         throwSyntaxError("'{' expected in 'catch' statement.");
963       }
964       getNextToken();
965       if (token != TokenNameRBRACE) {
966         statementList();
967       }
968       if (token != TokenNameRBRACE) {
969         throwSyntaxError("'}' expected in 'catch' statement.");
970       }
971       getNextToken();
972     }
973   }
974
975   private void foreach_variable() {
976     //  w_variable
977     //| '&' w_variable
978     if (token == TokenNameAND) {
979       getNextToken();
980     }
981     w_variable();
982   }
983
984   private void foreach_optional_arg() {
985     //  /* empty */
986     //| T_DOUBLE_ARROW foreach_variable
987     if (token == TokenNameEQUAL_GREATER) {
988       getNextToken();
989       foreach_variable();
990     }
991   }
992
993   private void global_var_list() {
994     //  global_var_list:
995     //  global_var_list ',' global_var
996     //| global_var
997     while (true) {
998       global_var();
999       if (token != TokenNameCOMMA) {
1000         break;
1001       }
1002       getNextToken();
1003     }
1004   }
1005
1006   private void global_var() {
1007     //global_var:
1008     //  T_VARIABLE
1009     //| '$' r_variable
1010     //| '$' '{' expr '}'
1011     if (token == TokenNameVariable) {
1012       VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_GLOBAL_VAR);
1013       if (fMethodVariables != null) {
1014         fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1015       }
1016       getNextToken();
1017     } else if (token == TokenNameDOLLAR) {
1018       getNextToken();
1019       if (token == TokenNameLBRACE) {
1020         getNextToken();
1021         expr();
1022         if (token != TokenNameRBRACE) {
1023           throwSyntaxError("'}' expected in global variable.");
1024         }
1025         getNextToken();
1026       } else {
1027         r_variable();
1028       }
1029     }
1030   }
1031
1032   private void static_var_list() {
1033     //static_var_list:
1034     //  static_var_list ',' T_VARIABLE
1035     //| static_var_list ',' T_VARIABLE '=' static_scalar
1036     //| T_VARIABLE
1037     //| T_VARIABLE '=' static_scalar
1038     while (true) {
1039       if (token == TokenNameVariable) {
1040         VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_STATIC_VAR);
1041         if (fMethodVariables != null) {
1042           fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1043         }
1044         getNextToken();
1045         if (token == TokenNameEQUAL) {
1046           getNextToken();
1047           static_scalar();
1048         }
1049         if (token != TokenNameCOMMA) {
1050           break;
1051         }
1052         getNextToken();
1053       } else {
1054         break;
1055       }
1056     }
1057   }
1058
1059   private void unset_variables() {
1060     //    unset_variables:
1061     //                  unset_variable
1062     //          | unset_variables ',' unset_variable
1063     //    unset_variable:
1064     //                  variable
1065     while (true) {
1066       variable();
1067       if (token != TokenNameCOMMA) {
1068         break;
1069       }
1070       getNextToken();
1071     }
1072   }
1073
1074   private final void initializeModifiers() {
1075     this.modifiers = 0;
1076     this.modifiersSourceStart = -1;
1077   }
1078
1079   private final void checkAndSetModifiers(int flag) {
1080     this.modifiers |= flag;
1081     if (this.modifiersSourceStart < 0)
1082       this.modifiersSourceStart = this.scanner.startPosition;
1083   }
1084
1085   private void unticked_class_declaration_statement(TypeDeclaration typeDecl) {
1086     initializeModifiers();
1087     if (token == TokenNameinterface) {
1088       //      interface_entry T_STRING
1089       //                interface_extends_list
1090       //                '{' class_statement_list '}'
1091       checkAndSetModifiers(AccInterface);
1092       getNextToken();
1093       typeDecl.modifiers = this.modifiers;
1094       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1095       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1096       if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
1097         typeDecl.name = scanner.getCurrentIdentifierSource();
1098         if (token > TokenNameKEYWORD) {
1099           problemReporter.phpKeywordWarning(new String[] { scanner.toStringAction(token) }, scanner.getCurrentTokenStartPosition(),
1100               scanner.getCurrentTokenEndPosition(), referenceContext, compilationUnit.compilationResult);
1101           //          throwSyntaxError("Don't use a keyword for interface declaration [" + scanner.toStringAction(token) + "].",
1102           //              typeDecl.sourceStart, typeDecl.sourceEnd);
1103         }
1104         getNextToken();
1105         interface_extends_list(typeDecl);
1106       } else {
1107         typeDecl.name = new char[] { ' ' };
1108         throwSyntaxError("Interface name expected after keyword 'interface'.", typeDecl.sourceStart, typeDecl.sourceEnd);
1109         return;
1110       }
1111     } else {
1112       //      class_entry_type T_STRING extends_from
1113       //                implements_list
1114       //                '{' class_statement_list'}'
1115       class_entry_type();
1116       typeDecl.modifiers = this.modifiers;
1117       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1118       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1119       //identifier
1120       //identifier 'extends' identifier
1121       if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
1122         typeDecl.name = scanner.getCurrentIdentifierSource();
1123         if (token > TokenNameKEYWORD) {
1124           problemReporter.phpKeywordWarning(new String[] { scanner.toStringAction(token) }, scanner.getCurrentTokenStartPosition(),
1125               scanner.getCurrentTokenEndPosition(), referenceContext, compilationUnit.compilationResult);
1126           //          throwSyntaxError("Don't use a keyword for class declaration [" + scanner.toStringAction(token) + "].",
1127           //              typeDecl.sourceStart, typeDecl.sourceEnd);
1128         }
1129         getNextToken();
1130         //    extends_from:
1131         //              /* empty */
1132         //      | T_EXTENDS fully_qualified_class_name
1133         if (token == TokenNameextends) {
1134           interface_extends_list(typeDecl);
1135           //          getNextToken();
1136           //          if (token != TokenNameIdentifier) {
1137           //            throwSyntaxError("Class name expected after keyword
1138           // 'extends'.",
1139           //                scanner.getCurrentTokenStartPosition(), scanner
1140           //                    .getCurrentTokenEndPosition());
1141           //          }
1142         }
1143         implements_list(typeDecl);
1144       } else {
1145         typeDecl.name = new char[] { ' ' };
1146         throwSyntaxError("Class name expected after keyword 'class'.", typeDecl.sourceStart, typeDecl.sourceEnd);
1147         return;
1148       }
1149     }
1150     //  '{' class_statement_list '}'
1151     if (token == TokenNameLBRACE) {
1152       getNextToken();
1153       if (token != TokenNameRBRACE) {
1154         ArrayList list = new ArrayList();
1155         class_statement_list(list);
1156         typeDecl.fields = new FieldDeclaration[list.size()];
1157         for (int i = 0; i < list.size(); i++) {
1158           typeDecl.fields[i] = (FieldDeclaration) list.get(i);
1159         }
1160       }
1161       if (token == TokenNameRBRACE) {
1162         typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1163         getNextToken();
1164       } else {
1165         throwSyntaxError("'}' expected at end of class body.");
1166       }
1167     } else {
1168       throwSyntaxError("'{' expected at start of class body.");
1169     }
1170   }
1171
1172   private void class_entry_type() {
1173     //  T_CLASS
1174     //  | T_ABSTRACT T_CLASS
1175     //  | T_FINAL T_CLASS
1176     if (token == TokenNameclass) {
1177       getNextToken();
1178     } else if (token == TokenNameabstract) {
1179       checkAndSetModifiers(AccAbstract);
1180       getNextToken();
1181       if (token != TokenNameclass) {
1182         throwSyntaxError("Keyword 'class' expected after keyword 'abstract'.");
1183       }
1184       getNextToken();
1185     } else if (token == TokenNamefinal) {
1186       checkAndSetModifiers(AccFinal);
1187       getNextToken();
1188       if (token != TokenNameclass) {
1189         throwSyntaxError("Keyword 'class' expected after keyword 'final'.");
1190       }
1191       getNextToken();
1192     } else {
1193       throwSyntaxError("Keyword 'class' 'final' or 'abstract' expected");
1194     }
1195   }
1196
1197   private void class_extends(TypeDeclaration typeDecl) {
1198     //  /* empty */
1199     //  | T_EXTENDS interface_list
1200     if (token == TokenNameextends) {
1201       getNextToken();
1202
1203       if (token == TokenNameIdentifier) {
1204         getNextToken();
1205       } else {
1206         throwSyntaxError("Class name expected after keyword 'extends'.");
1207       }
1208     }
1209   }
1210
1211   private void interface_extends_list(TypeDeclaration typeDecl) {
1212     //  /* empty */
1213     //  | T_EXTENDS interface_list
1214     if (token == TokenNameextends) {
1215       getNextToken();
1216       interface_list();
1217     }
1218   }
1219
1220   private void implements_list(TypeDeclaration typeDecl) {
1221     //  /* empty */
1222     //  | T_IMPLEMENTS interface_list
1223     if (token == TokenNameimplements) {
1224       getNextToken();
1225       interface_list();
1226     }
1227   }
1228
1229   private void interface_list() {
1230     //  interface_list:
1231     //  fully_qualified_class_name
1232     //| interface_list ',' fully_qualified_class_name
1233     do {
1234       if (token == TokenNameIdentifier) {
1235         getNextToken();
1236       } else {
1237         throwSyntaxError("Interface name expected after keyword 'implements'.");
1238       }
1239       if (token != TokenNameCOMMA) {
1240         return;
1241       }
1242       getNextToken();
1243     } while (true);
1244   }
1245
1246   //  private void classBody(TypeDeclaration typeDecl) {
1247   //    //'{' [class-element-list] '}'
1248   //    if (token == TokenNameLBRACE) {
1249   //      getNextToken();
1250   //      if (token != TokenNameRBRACE) {
1251   //        class_statement_list();
1252   //      }
1253   //      if (token == TokenNameRBRACE) {
1254   //        typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1255   //        getNextToken();
1256   //      } else {
1257   //        throwSyntaxError("'}' expected at end of class body.");
1258   //      }
1259   //    } else {
1260   //      throwSyntaxError("'{' expected at start of class body.");
1261   //    }
1262   //  }
1263   private void class_statement_list(ArrayList list) {
1264     do {
1265       try {
1266         class_statement(list);
1267         if (token == TokenNamepublic || token == TokenNameprotected || token == TokenNameprivate || token == TokenNamestatic
1268             || token == TokenNameabstract || token == TokenNamefinal || token == TokenNamefunction || token == TokenNamevar
1269             || token == TokenNameconst) {
1270           continue;
1271         }
1272         if (token == TokenNameRBRACE) {
1273           break;
1274         }
1275         throwSyntaxError("'}' at end of class statement.");
1276       } catch (SyntaxError sytaxErr1) {
1277         boolean tokenize = scanner.tokenizeStrings;
1278         if (!tokenize) {
1279           scanner.tokenizeStrings = true;
1280         }
1281         try {
1282           // if an error occured,
1283           // try to find keywords
1284           // to parse the rest of the string
1285           while (token != TokenNameEOF) {
1286             if (token == TokenNamepublic || token == TokenNameprotected || token == TokenNameprivate || token == TokenNamestatic
1287                 || token == TokenNameabstract || token == TokenNamefinal || token == TokenNamefunction || token == TokenNamevar
1288                 || token == TokenNameconst) {
1289               break;
1290             }
1291             //            System.out.println(scanner.toStringAction(token));
1292             getNextToken();
1293           }
1294           if (token == TokenNameEOF) {
1295             throw sytaxErr1;
1296           }
1297         } finally {
1298           scanner.tokenizeStrings = tokenize;
1299         }
1300       }
1301     } while (true);
1302   }
1303
1304   private void class_statement(ArrayList list) {
1305     //    class_statement:
1306     //          variable_modifiers class_variable_declaration ';'
1307     //  | class_constant_declaration ';'
1308     //  | method_modifiers T_FUNCTION is_reference T_STRING
1309     //    '(' parameter_list ')' method_body
1310     initializeModifiers();
1311     int declarationSourceStart = scanner.getCurrentTokenStartPosition();
1312
1313     if (token == TokenNamevar) {
1314       checkAndSetModifiers(AccPublic);
1315       problemReporter.phpVarDeprecatedWarning(scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(),
1316           referenceContext, compilationUnit.compilationResult);
1317       getNextToken();
1318       class_variable_declaration(declarationSourceStart, list);
1319     } else if (token == TokenNameconst) {
1320       checkAndSetModifiers(AccFinal | AccPublic);
1321       class_constant_declaration(declarationSourceStart, list);
1322       if (token != TokenNameSEMICOLON) {
1323         throwSyntaxError("';' expected after class const declaration.");
1324       }
1325       getNextToken();
1326     } else {
1327       boolean hasModifiers = member_modifiers();
1328       if (token == TokenNamefunction) {
1329         if (!hasModifiers) {
1330           checkAndSetModifiers(AccPublic);
1331         }
1332         MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1333         methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1334         methodDecl.modifiers = this.modifiers;
1335         methodDecl.type = MethodDeclaration.METHOD_DEFINITION;
1336         try {
1337           getNextToken();
1338           functionDefinition(methodDecl);
1339         } finally {
1340           int sourceEnd = scanner.getCurrentTokenStartPosition();
1341           if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) {
1342             sourceEnd = methodDecl.declarationSourceStart + 1;
1343           }
1344           methodDecl.declarationSourceEnd = sourceEnd;
1345         }
1346       } else {
1347         if (!hasModifiers) {
1348           throwSyntaxError("'public' 'private' or 'protected' modifier expected for field declarations.");
1349         }
1350         class_variable_declaration(declarationSourceStart, list);
1351       }
1352     }
1353   }
1354
1355   private void class_constant_declaration(int declarationSourceStart, ArrayList list) {
1356     //  class_constant_declaration ',' T_STRING '=' static_scalar
1357     //  | T_CONST T_STRING '=' static_scalar
1358     if (token != TokenNameconst) {
1359       throwSyntaxError("'const' keyword expected in class declaration.");
1360     } else {
1361       getNextToken();
1362     }
1363     while (true) {
1364       if (token != TokenNameIdentifier) {
1365         throwSyntaxError("Identifier expected in class const declaration.");
1366       }
1367       FieldDeclaration fieldDeclaration = new FieldDeclaration(scanner.getCurrentIdentifierSource(), scanner
1368           .getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
1369       fieldDeclaration.modifiers = this.modifiers;
1370       fieldDeclaration.declarationSourceStart = declarationSourceStart;
1371       fieldDeclaration.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1372       fieldDeclaration.modifiersSourceStart = declarationSourceStart;
1373       //        fieldDeclaration.type
1374       list.add(fieldDeclaration);
1375       getNextToken();
1376       if (token != TokenNameEQUAL) {
1377         throwSyntaxError("'=' expected in class const declaration.");
1378       }
1379       getNextToken();
1380       static_scalar();
1381       if (token != TokenNameCOMMA) {
1382         break; // while(true)-loop
1383       }
1384       getNextToken();
1385     }
1386   }
1387
1388   //  private void variable_modifiers() {
1389   //    // variable_modifiers:
1390   //    // non_empty_member_modifiers
1391   //    //| T_VAR
1392   //    initializeModifiers();
1393   //    if (token == TokenNamevar) {
1394   //      checkAndSetModifiers(AccPublic);
1395   //      reportSyntaxError(
1396   //          "Keyword 'var' is deprecated. Please use 'public' 'private' or
1397   // 'protected'
1398   // modifier for field declarations.",
1399   //          scanner.getCurrentTokenStartPosition(), scanner
1400   //              .getCurrentTokenEndPosition());
1401   //      getNextToken();
1402   //    } else {
1403   //      if (!member_modifiers()) {
1404   //        throwSyntaxError("'public' 'private' or 'protected' modifier expected for
1405   // field declarations.");
1406   //      }
1407   //    }
1408   //  }
1409   //  private void method_modifiers() {
1410   //    //method_modifiers:
1411   //    // /* empty */
1412   //    //| non_empty_member_modifiers
1413   //    initializeModifiers();
1414   //    if (!member_modifiers()) {
1415   //      checkAndSetModifiers(AccPublic);
1416   //    }
1417   //  }
1418   private boolean member_modifiers() {
1419     //  T_PUBLIC
1420     //| T_PROTECTED
1421     //| T_PRIVATE
1422     //| T_STATIC
1423     //| T_ABSTRACT
1424     //| T_FINAL
1425     boolean foundToken = false;
1426     while (true) {
1427       if (token == TokenNamepublic) {
1428         checkAndSetModifiers(AccPublic);
1429         getNextToken();
1430         foundToken = true;
1431       } else if (token == TokenNameprotected) {
1432         checkAndSetModifiers(AccProtected);
1433         getNextToken();
1434         foundToken = true;
1435       } else if (token == TokenNameprivate) {
1436         checkAndSetModifiers(AccPrivate);
1437         getNextToken();
1438         foundToken = true;
1439       } else if (token == TokenNamestatic) {
1440         checkAndSetModifiers(AccStatic);
1441         getNextToken();
1442         foundToken = true;
1443       } else if (token == TokenNameabstract) {
1444         checkAndSetModifiers(AccAbstract);
1445         getNextToken();
1446         foundToken = true;
1447       } else if (token == TokenNamefinal) {
1448         checkAndSetModifiers(AccFinal);
1449         getNextToken();
1450         foundToken = true;
1451       } else {
1452         break;
1453       }
1454     }
1455     return foundToken;
1456   }
1457
1458   private void class_variable_declaration(int declarationSourceStart, ArrayList list) {
1459     //    class_variable_declaration:
1460     //          class_variable_declaration ',' T_VARIABLE
1461     //  | class_variable_declaration ',' T_VARIABLE '=' static_scalar
1462     //  | T_VARIABLE
1463     //  | T_VARIABLE '=' static_scalar
1464     char[] classVariable;
1465     do {
1466       if (token == TokenNameVariable) {
1467         classVariable = scanner.getCurrentIdentifierSource();
1468         //  indexManager.addIdentifierInformation('v', classVariable, buf, -1, -1);
1469         FieldDeclaration fieldDeclaration = new FieldDeclaration(classVariable, scanner.getCurrentTokenStartPosition(), scanner
1470             .getCurrentTokenEndPosition());
1471         fieldDeclaration.modifiers = this.modifiers;
1472         fieldDeclaration.declarationSourceStart = declarationSourceStart;
1473         fieldDeclaration.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1474         fieldDeclaration.modifiersSourceStart = declarationSourceStart;
1475         list.add(fieldDeclaration);
1476         if (fTypeVariables != null) {
1477           VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_CLASS_UNIT);
1478           fTypeVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1479         }
1480         getNextToken();
1481         if (token == TokenNameEQUAL) {
1482           getNextToken();
1483           static_scalar();
1484         }
1485       } else {
1486         //        if (token == TokenNamethis) {
1487         //          throwSyntaxError("'$this' not allowed after keyword 'public'
1488         // 'protected' 'private' 'var'.");
1489         //        }
1490         throwSyntaxError("Variable expected after keyword 'public' 'protected' 'private' 'var'.");
1491       }
1492       if (token != TokenNameCOMMA) {
1493         break;
1494       }
1495       getNextToken();
1496     } while (true);
1497     if (token != TokenNameSEMICOLON) {
1498       throwSyntaxError("';' expected after field declaration.");
1499     }
1500     getNextToken();
1501   }
1502
1503   private void functionDefinition(MethodDeclaration methodDecl) {
1504     boolean isAbstract = false;
1505     if (astPtr == 0) {
1506       if (compilationUnit != null) {
1507         compilationUnit.types.add(methodDecl);
1508       }
1509     } else {
1510       ASTNode node = astStack[astPtr];
1511       if (node instanceof TypeDeclaration) {
1512         TypeDeclaration typeDecl = ((TypeDeclaration) node);
1513         if (typeDecl.methods == null) {
1514           typeDecl.methods = new AbstractMethodDeclaration[] { methodDecl };
1515         } else {
1516           AbstractMethodDeclaration[] newMethods;
1517           System.arraycopy(typeDecl.methods, 0, newMethods = new AbstractMethodDeclaration[typeDecl.methods.length + 1], 0,
1518               typeDecl.methods.length);
1519           newMethods[typeDecl.methods.length] = methodDecl;
1520           typeDecl.methods = newMethods;
1521         }
1522         if ((typeDecl.modifiers & AccAbstract) == AccAbstract) {
1523           isAbstract = true;
1524         } else if ((typeDecl.modifiers & AccInterface) == AccInterface) {
1525           isAbstract = true;
1526         }
1527       }
1528     }
1529     functionDeclarator(methodDecl);
1530     if (token == TokenNameSEMICOLON) {
1531       if (!isAbstract) {
1532         throwSyntaxError("Body declaration expected for method: " + new String(methodDecl.selector));
1533       }
1534       getNextToken();
1535       return;
1536     }
1537     functionBody(methodDecl);
1538   }
1539
1540   private void functionDeclarator(MethodDeclaration methodDecl) {
1541     //identifier '(' [parameter-list] ')'
1542     if (token == TokenNameAND) {
1543       getNextToken();
1544     }
1545     methodDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1546     methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1547     if (Scanner.isIdentifierOrKeyword(token)) {
1548       methodDecl.selector = scanner.getCurrentIdentifierSource();
1549       if (token > TokenNameKEYWORD) {
1550         problemReporter.phpKeywordWarning(new String[] { scanner.toStringAction(token) }, scanner.getCurrentTokenStartPosition(),
1551             scanner.getCurrentTokenEndPosition(), referenceContext, compilationUnit.compilationResult);
1552       }
1553       getNextToken();
1554       if (token == TokenNameLPAREN) {
1555         getNextToken();
1556       } else {
1557         throwSyntaxError("'(' expected in function declaration.");
1558       }
1559       if (token != TokenNameRPAREN) {
1560         parameter_list(methodDecl);
1561       }
1562       if (token != TokenNameRPAREN) {
1563         throwSyntaxError("')' expected in function declaration.");
1564       } else {
1565         methodDecl.bodyStart = scanner.getCurrentTokenEndPosition() + 1;
1566         getNextToken();
1567       }
1568     } else {
1569       methodDecl.selector = "<undefined>".toCharArray();
1570       throwSyntaxError("Function name expected after keyword 'function'.");
1571     }
1572   }
1573
1574   //
1575   private void parameter_list(MethodDeclaration methodDecl) {
1576     //  non_empty_parameter_list
1577     //  | /* empty */
1578     non_empty_parameter_list(methodDecl, true);
1579   }
1580
1581   private void non_empty_parameter_list(MethodDeclaration methodDecl, boolean empty_allowed) {
1582     //  optional_class_type T_VARIABLE
1583     //  | optional_class_type '&' T_VARIABLE
1584     //  | optional_class_type '&' T_VARIABLE '=' static_scalar
1585     //  | optional_class_type T_VARIABLE '=' static_scalar
1586     //  | non_empty_parameter_list ',' optional_class_type T_VARIABLE
1587     //  | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE
1588     //  | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '='
1589     // static_scalar
1590     //  | non_empty_parameter_list ',' optional_class_type T_VARIABLE '='
1591     // static_scalar
1592     char[] typeIdentifier = null;
1593     if (token == TokenNameIdentifier || token == TokenNameVariable || token == TokenNameAND) {
1594       while (true) {
1595         if (token == TokenNameIdentifier) {
1596           typeIdentifier = scanner.getCurrentIdentifierSource();
1597           getNextToken();
1598         }
1599         if (token == TokenNameAND) {
1600           getNextToken();
1601         }
1602         if (token == TokenNameVariable) {
1603           if (fMethodVariables != null) {
1604             VariableInfo info;
1605             if (methodDecl.type == MethodDeclaration.FUNCTION_DEFINITION) {
1606               info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_FUNCTION_DEFINITION);
1607             } else {
1608               info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_METHOD_DEFINITION);
1609             }
1610             info.typeIdentifier = typeIdentifier;
1611             fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1612           }
1613           getNextToken();
1614           if (token == TokenNameEQUAL) {
1615             getNextToken();
1616             static_scalar();
1617           }
1618         } else {
1619           throwSyntaxError("Variable expected in parameter list.");
1620         }
1621         if (token != TokenNameCOMMA) {
1622           break;
1623         }
1624         getNextToken();
1625       }
1626       return;
1627     }
1628     if (!empty_allowed) {
1629       throwSyntaxError("Identifier expected in parameter list.");
1630     }
1631   }
1632
1633   private void optional_class_type() {
1634     //  /* empty */
1635     //| T_STRING
1636   }
1637
1638   //  private void parameterDeclaration() {
1639   //    //variable
1640   //    //variable-reference
1641   //    if (token == TokenNameAND) {
1642   //      getNextToken();
1643   //      if (isVariable()) {
1644   //        getNextToken();
1645   //      } else {
1646   //        throwSyntaxError("Variable expected after reference operator '&'.");
1647   //      }
1648   //    }
1649   //    //variable '=' constant
1650   //    if (token == TokenNameVariable) {
1651   //      getNextToken();
1652   //      if (token == TokenNameEQUAL) {
1653   //        getNextToken();
1654   //        static_scalar();
1655   //      }
1656   //      return;
1657   //    }
1658   //    // if (token == TokenNamethis) {
1659   //    // throwSyntaxError("Reserved word '$this' not allowed in parameter
1660   //    // declaration.");
1661   //    // }
1662   //  }
1663
1664   private void labeledStatementList() {
1665     if (token != TokenNamecase && token != TokenNamedefault) {
1666       throwSyntaxError("'case' or 'default' expected.");
1667     }
1668     do {
1669       if (token == TokenNamecase) {
1670         getNextToken();
1671         expr(); //constant();
1672         if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
1673           getNextToken();
1674           if (token == TokenNamecase || token == TokenNamedefault) {
1675             // empty case statement ?
1676             continue;
1677           }
1678           statementList();
1679         }
1680         //        else if (token == TokenNameSEMICOLON) {
1681         //          setMarker(
1682         //            "':' expected after 'case' keyword (Found token: " +
1683         // scanner.toStringAction(token) + ")",
1684         //            scanner.getCurrentTokenStartPosition(),
1685         //            scanner.getCurrentTokenEndPosition(),
1686         //            INFO);
1687         //          getNextToken();
1688         //          if (token == TokenNamecase) { // empty case statement ?
1689         //            continue;
1690         //          }
1691         //          statementList();
1692         //        }
1693         else {
1694           throwSyntaxError("':' character expected after 'case' constant (Found token: " + scanner.toStringAction(token) + ")");
1695         }
1696       } else { // TokenNamedefault
1697         getNextToken();
1698         if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
1699           getNextToken();
1700           if (token == TokenNameRBRACE) {
1701             // empty default case
1702             break;
1703           }
1704           if (token != TokenNamecase) {
1705             statementList();
1706           }
1707         } else {
1708           throwSyntaxError("':' character expected after 'default'.");
1709         }
1710       }
1711     } while (token == TokenNamecase || token == TokenNamedefault);
1712   }
1713
1714   //  public void labeledStatement() {
1715   //    if (token == TokenNamecase) {
1716   //      getNextToken();
1717   //      constant();
1718   //      if (token == TokenNameDDOT) {
1719   //        getNextToken();
1720   //        statement();
1721   //      } else {
1722   //        throwSyntaxError("':' character after 'case' constant expected.");
1723   //      }
1724   //      return;
1725   //    } else if (token == TokenNamedefault) {
1726   //      getNextToken();
1727   //      if (token == TokenNameDDOT) {
1728   //        getNextToken();
1729   //        statement();
1730   //      } else {
1731   //        throwSyntaxError("':' character after 'default' expected.");
1732   //      }
1733   //      return;
1734   //    }
1735   //  }
1736   //  public void expressionStatement() {
1737   //  }
1738   //  private void inclusionStatement() {
1739   //  }
1740   //  public void compoundStatement() {
1741   //  }
1742   //  public void selectionStatement() {
1743   //  }
1744   //
1745   //  public void iterationStatement() {
1746   //  }
1747   //
1748   //  public void jumpStatement() {
1749   //  }
1750   //
1751   //  public void outputStatement() {
1752   //  }
1753   //
1754   //  public void scopeStatement() {
1755   //  }
1756   //
1757   //  public void flowStatement() {
1758   //  }
1759   //
1760   //  public void definitionStatement() {
1761   //  }
1762   private void ifStatement() {
1763     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
1764     if (token == TokenNameCOLON) {
1765       getNextToken();
1766       if (token != TokenNameendif) {
1767         statementList();
1768         switch (token) {
1769         case TokenNameelse:
1770           getNextToken();
1771           if (token == TokenNameCOLON) {
1772             getNextToken();
1773             if (token != TokenNameendif) {
1774               statementList();
1775             }
1776           } else {
1777             if (token == TokenNameif) { //'else if'
1778               getNextToken();
1779               elseifStatementList();
1780             } else {
1781               throwSyntaxError("':' expected after 'else'.");
1782             }
1783           }
1784           break;
1785         case TokenNameelseif:
1786           getNextToken();
1787           elseifStatementList();
1788           break;
1789         }
1790       }
1791       if (token != TokenNameendif) {
1792         throwSyntaxError("'endif' expected.");
1793       }
1794       getNextToken();
1795       if (token != TokenNameSEMICOLON) {
1796         throwSyntaxError("';' expected after if-statement.");
1797       }
1798       getNextToken();
1799     } else {
1800       // statement [else-statement]
1801       statement(TokenNameEOF);
1802       if (token == TokenNameelseif) {
1803         getNextToken();
1804         if (token == TokenNameLPAREN) {
1805           getNextToken();
1806         } else {
1807           throwSyntaxError("'(' expected after 'elseif' keyword.");
1808         }
1809         expr();
1810         if (token == TokenNameRPAREN) {
1811           getNextToken();
1812         } else {
1813           throwSyntaxError("')' expected after 'elseif' condition.");
1814         }
1815         ifStatement();
1816       } else if (token == TokenNameelse) {
1817         getNextToken();
1818         statement(TokenNameEOF);
1819       }
1820     }
1821   }
1822
1823   private void elseifStatementList() {
1824     do {
1825       elseifStatement();
1826       switch (token) {
1827       case TokenNameelse:
1828         getNextToken();
1829         if (token == TokenNameCOLON) {
1830           getNextToken();
1831           if (token != TokenNameendif) {
1832             statementList();
1833           }
1834           return;
1835         } else {
1836           if (token == TokenNameif) { //'else if'
1837             getNextToken();
1838           } else {
1839             throwSyntaxError("':' expected after 'else'.");
1840           }
1841         }
1842         break;
1843       case TokenNameelseif:
1844         getNextToken();
1845         break;
1846       default:
1847         return;
1848       }
1849     } while (true);
1850   }
1851
1852   private void elseifStatement() {
1853     if (token == TokenNameLPAREN) {
1854       getNextToken();
1855       expr();
1856       if (token != TokenNameRPAREN) {
1857         throwSyntaxError("')' expected in else-if-statement.");
1858       }
1859       getNextToken();
1860       if (token != TokenNameCOLON) {
1861         throwSyntaxError("':' expected in else-if-statement.");
1862       }
1863       getNextToken();
1864       if (token != TokenNameendif) {
1865         statementList();
1866       }
1867     }
1868   }
1869
1870   private void switchStatement() {
1871     if (token == TokenNameCOLON) {
1872       // ':' [labeled-statement-list] 'endswitch' ';'
1873       getNextToken();
1874       labeledStatementList();
1875       if (token != TokenNameendswitch) {
1876         throwSyntaxError("'endswitch' expected.");
1877       }
1878       getNextToken();
1879       if (token != TokenNameSEMICOLON) {
1880         throwSyntaxError("';' expected after switch-statement.");
1881       }
1882       getNextToken();
1883     } else {
1884       // '{' [labeled-statement-list] '}'
1885       if (token != TokenNameLBRACE) {
1886         throwSyntaxError("'{' expected in switch statement.");
1887       }
1888       getNextToken();
1889       if (token != TokenNameRBRACE) {
1890         labeledStatementList();
1891       }
1892       if (token != TokenNameRBRACE) {
1893         throwSyntaxError("'}' expected in switch statement.");
1894       }
1895       getNextToken();
1896     }
1897   }
1898
1899   private void forStatement() {
1900     if (token == TokenNameCOLON) {
1901       getNextToken();
1902       statementList();
1903       if (token != TokenNameendfor) {
1904         throwSyntaxError("'endfor' expected.");
1905       }
1906       getNextToken();
1907       if (token != TokenNameSEMICOLON) {
1908         throwSyntaxError("';' expected after for-statement.");
1909       }
1910       getNextToken();
1911     } else {
1912       statement(TokenNameEOF);
1913     }
1914   }
1915
1916   private void whileStatement() {
1917     // ':' statement-list 'endwhile' ';'
1918     if (token == TokenNameCOLON) {
1919       getNextToken();
1920       statementList();
1921       if (token != TokenNameendwhile) {
1922         throwSyntaxError("'endwhile' expected.");
1923       }
1924       getNextToken();
1925       if (token != TokenNameSEMICOLON) {
1926         throwSyntaxError("';' expected after while-statement.");
1927       }
1928       getNextToken();
1929     } else {
1930       statement(TokenNameEOF);
1931     }
1932   }
1933
1934   private void foreachStatement() {
1935     if (token == TokenNameCOLON) {
1936       getNextToken();
1937       statementList();
1938       if (token != TokenNameendforeach) {
1939         throwSyntaxError("'endforeach' expected.");
1940       }
1941       getNextToken();
1942       if (token != TokenNameSEMICOLON) {
1943         throwSyntaxError("';' expected after foreach-statement.");
1944       }
1945       getNextToken();
1946     } else {
1947       statement(TokenNameEOF);
1948     }
1949   }
1950
1951   //  private void exitStatus() {
1952   //    if (token == TokenNameLPAREN) {
1953   //      getNextToken();
1954   //    } else {
1955   //      throwSyntaxError("'(' expected in 'exit-status'.");
1956   //    }
1957   //    if (token != TokenNameRPAREN) {
1958   //      expression();
1959   //    }
1960   //    if (token == TokenNameRPAREN) {
1961   //      getNextToken();
1962   //    } else {
1963   //      throwSyntaxError("')' expected after 'exit-status'.");
1964   //    }
1965   //  }
1966   private void expressionList() {
1967     do {
1968       expr();
1969       if (token == TokenNameCOMMA) {
1970         getNextToken();
1971       } else {
1972         break;
1973       }
1974     } while (true);
1975   }
1976
1977   private Expression expr() {
1978     //  r_variable
1979     //  | expr_without_variable
1980     //    if (token!=TokenNameEOF) {
1981     if (Scanner.TRACE) {
1982       System.out.println("TRACE: expr()");
1983     }
1984     return expr_without_variable(true);
1985     //    }
1986   }
1987
1988   private Expression expr_without_variable(boolean only_variable) {
1989     int exprSourceStart = scanner.getCurrentTokenStartPosition();
1990     int exprSourceEnd = scanner.getCurrentTokenEndPosition();
1991     Expression expression = new Expression();
1992     expression.sourceStart = exprSourceStart;
1993     // default, may be overwritten
1994     expression.sourceEnd = exprSourceEnd;
1995     try {
1996       //                internal_functions_in_yacc
1997       //        | T_CLONE expr
1998       //        | T_PRINT expr
1999       //        | '(' expr ')'
2000       //        | '@' expr
2001       //        | '+' expr
2002       //        | '-' expr
2003       //        | '!' expr
2004       //        | '~' expr
2005       //        | T_INC rw_variable
2006       //        | T_DEC rw_variable
2007       //        | T_INT_CAST expr
2008       //        | T_DOUBLE_CAST expr
2009       //        | T_STRING_CAST expr
2010       //        | T_ARRAY_CAST expr
2011       //        | T_OBJECT_CAST expr
2012       //        | T_BOOL_CAST expr
2013       //        | T_UNSET_CAST expr
2014       //        | T_EXIT exit_expr
2015       //        | scalar
2016       //        | T_ARRAY '(' array_pair_list ')'
2017       //        | '`' encaps_list '`'
2018       //        | T_LIST '(' assignment_list ')' '=' expr
2019       //        | T_NEW class_name_reference ctor_arguments
2020       //        | variable '=' expr
2021       //        | variable '=' '&' variable
2022       //        | variable '=' '&' T_NEW class_name_reference ctor_arguments
2023       //        | variable T_PLUS_EQUAL expr
2024       //        | variable T_MINUS_EQUAL expr
2025       //        | variable T_MUL_EQUAL expr
2026       //        | variable T_DIV_EQUAL expr
2027       //        | variable T_CONCAT_EQUAL expr
2028       //        | variable T_MOD_EQUAL expr
2029       //        | variable T_AND_EQUAL expr
2030       //        | variable T_OR_EQUAL expr
2031       //        | variable T_XOR_EQUAL expr
2032       //        | variable T_SL_EQUAL expr
2033       //        | variable T_SR_EQUAL expr
2034       //        | rw_variable T_INC
2035       //        | rw_variable T_DEC
2036       //        | expr T_BOOLEAN_OR expr
2037       //        | expr T_BOOLEAN_AND expr
2038       //        | expr T_LOGICAL_OR expr
2039       //        | expr T_LOGICAL_AND expr
2040       //        | expr T_LOGICAL_XOR expr
2041       //        | expr '|' expr
2042       //        | expr '&' expr
2043       //        | expr '^' expr
2044       //        | expr '.' expr
2045       //        | expr '+' expr
2046       //        | expr '-' expr
2047       //        | expr '*' expr
2048       //        | expr '/' expr
2049       //        | expr '%' expr
2050       //        | expr T_SL expr
2051       //        | expr T_SR expr
2052       //        | expr T_IS_IDENTICAL expr
2053       //        | expr T_IS_NOT_IDENTICAL expr
2054       //        | expr T_IS_EQUAL expr
2055       //        | expr T_IS_NOT_EQUAL expr
2056       //        | expr '<' expr
2057       //        | expr T_IS_SMALLER_OR_EQUAL expr
2058       //        | expr '>' expr
2059       //        | expr T_IS_GREATER_OR_EQUAL expr
2060       //        | expr T_INSTANCEOF class_name_reference
2061       //        | expr '?' expr ':' expr
2062       if (Scanner.TRACE) {
2063         System.out.println("TRACE: expr_without_variable() PART 1");
2064       }
2065       switch (token) {
2066       case TokenNameisset:
2067       case TokenNameempty:
2068       case TokenNameeval:
2069       case TokenNameinclude:
2070       case TokenNameinclude_once:
2071       case TokenNamerequire:
2072       case TokenNamerequire_once:
2073         internal_functions_in_yacc();
2074         break;
2075       //        | '(' expr ')'
2076       case TokenNameLPAREN:
2077         getNextToken();
2078         expr();
2079         if (token == TokenNameRPAREN) {
2080           getNextToken();
2081         } else {
2082           throwSyntaxError("')' expected in expression.");
2083         }
2084         break;
2085       //    | T_CLONE expr
2086       //    | T_PRINT expr
2087       //    | '@' expr
2088       //    | '+' expr
2089       //    | '-' expr
2090       //    | '!' expr
2091       //    | '~' expr
2092       //    | T_INT_CAST expr
2093       //        | T_DOUBLE_CAST expr
2094       //        | T_STRING_CAST expr
2095       //        | T_ARRAY_CAST expr
2096       //        | T_OBJECT_CAST expr
2097       //        | T_BOOL_CAST expr
2098       //        | T_UNSET_CAST expr
2099       case TokenNameclone:
2100       case TokenNameprint:
2101       case TokenNameAT:
2102       case TokenNamePLUS:
2103       case TokenNameMINUS:
2104       case TokenNameNOT:
2105       case TokenNameTWIDDLE:
2106       case TokenNameintCAST:
2107       case TokenNamedoubleCAST:
2108       case TokenNamestringCAST:
2109       case TokenNamearrayCAST:
2110       case TokenNameobjectCAST:
2111       case TokenNameboolCAST:
2112       case TokenNameunsetCAST:
2113         getNextToken();
2114         expr();
2115         break;
2116       case TokenNameexit:
2117         getNextToken();
2118         exit_expr();
2119         break;
2120       //  scalar:
2121       //        T_STRING
2122       //| T_STRING_VARNAME
2123       //| class_constant
2124       //| T_START_HEREDOC encaps_list T_END_HEREDOC
2125       //        | '`' encaps_list '`'
2126       //  | common_scalar
2127       //        | '`' encaps_list '`'
2128       case TokenNameEncapsedString0:
2129         scanner.encapsedStringStack.push(new Character('`'));
2130         getNextToken();
2131         try {
2132           if (token == TokenNameEncapsedString0) {
2133           } else {
2134             encaps_list();
2135             if (token != TokenNameEncapsedString0) {
2136               throwSyntaxError("\'`\' expected at end of string" + "(Found token: " + scanner.toStringAction(token) + " )");
2137             }
2138           }
2139         } finally {
2140           scanner.encapsedStringStack.pop();
2141           getNextToken();
2142         }
2143         break;
2144       //      | '\'' encaps_list '\''
2145       case TokenNameEncapsedString1:
2146         scanner.encapsedStringStack.push(new Character('\''));
2147         getNextToken();
2148         try {
2149           exprSourceStart = scanner.getCurrentTokenStartPosition();
2150           if (token == TokenNameEncapsedString1) {
2151             expression = new StringLiteralSQ(scanner.getCurrentStringLiteralSource(exprSourceStart), exprSourceStart, scanner
2152                 .getCurrentTokenEndPosition());
2153           } else {
2154             encaps_list();
2155             if (token != TokenNameEncapsedString1) {
2156               throwSyntaxError("\'\'\' expected at end of string" + "(Found token: " + scanner.toStringAction(token) + " )");
2157             } else {
2158               expression = new StringLiteralSQ(scanner.getCurrentStringLiteralSource(exprSourceStart), exprSourceStart, scanner
2159                   .getCurrentTokenEndPosition());
2160             }
2161           }
2162         } finally {
2163           scanner.encapsedStringStack.pop();
2164           getNextToken();
2165         }
2166         break;
2167       //| '"' encaps_list '"'
2168       case TokenNameEncapsedString2:
2169         scanner.encapsedStringStack.push(new Character('"'));
2170         getNextToken();
2171         try {
2172           exprSourceStart = scanner.getCurrentTokenStartPosition();
2173           if (token == TokenNameEncapsedString2) {
2174             expression = new StringLiteralDQ(scanner.getCurrentStringLiteralSource(exprSourceStart), exprSourceStart, scanner
2175                 .getCurrentTokenEndPosition());
2176           } else {
2177             encaps_list();
2178             if (token != TokenNameEncapsedString2) {
2179               throwSyntaxError("'\"' expected at end of string" + "(Found token: " + scanner.toStringAction(token) + " )");
2180             } else {
2181               expression = new StringLiteralDQ(scanner.getCurrentStringLiteralSource(exprSourceStart), exprSourceStart, scanner
2182                   .getCurrentTokenEndPosition());
2183             }
2184           }
2185         } finally {
2186           scanner.encapsedStringStack.pop();
2187           getNextToken();
2188         }
2189         break;
2190       case TokenNameStringDoubleQuote:
2191         expression = new StringLiteralDQ(scanner.getCurrentStringLiteralSource(), scanner.getCurrentTokenStartPosition(), scanner
2192             .getCurrentTokenEndPosition());
2193         common_scalar();
2194         break;
2195       case TokenNameStringSingleQuote:
2196         expression = new StringLiteralSQ(scanner.getCurrentStringLiteralSource(), scanner.getCurrentTokenStartPosition(), scanner
2197             .getCurrentTokenEndPosition());
2198         common_scalar();
2199         break;
2200       case TokenNameIntegerLiteral:
2201       case TokenNameDoubleLiteral:
2202       case TokenNameStringInterpolated:
2203       case TokenNameFILE:
2204       case TokenNameLINE:
2205       case TokenNameCLASS_C:
2206       case TokenNameMETHOD_C:
2207       case TokenNameFUNC_C:
2208         common_scalar();
2209         break;
2210       case TokenNameHEREDOC:
2211         getNextToken();
2212         break;
2213       case TokenNamearray:
2214         //    T_ARRAY '(' array_pair_list ')'
2215         getNextToken();
2216         if (token == TokenNameLPAREN) {
2217           getNextToken();
2218           if (token == TokenNameRPAREN) {
2219             getNextToken();
2220             break;
2221           }
2222           array_pair_list();
2223           if (token != TokenNameRPAREN) {
2224             throwSyntaxError("')' or ',' expected after keyword 'array'" + "(Found token: " + scanner.toStringAction(token) + ")");
2225           }
2226           getNextToken();
2227         } else {
2228           throwSyntaxError("'(' expected after keyword 'array'" + "(Found token: " + scanner.toStringAction(token) + ")");
2229         }
2230         break;
2231       case TokenNamelist:
2232         //    | T_LIST '(' assignment_list ')' '=' expr
2233         getNextToken();
2234         if (token == TokenNameLPAREN) {
2235           getNextToken();
2236           assignment_list();
2237           if (token != TokenNameRPAREN) {
2238             throwSyntaxError("')' expected after 'list' keyword.");
2239           }
2240           getNextToken();
2241           if (token != TokenNameEQUAL) {
2242             throwSyntaxError("'=' expected after 'list' keyword.");
2243           }
2244           getNextToken();
2245           expr();
2246         } else {
2247           throwSyntaxError("'(' expected after 'list' keyword.");
2248         }
2249         break;
2250       case TokenNamenew:
2251         //      | T_NEW class_name_reference ctor_arguments
2252         getNextToken();
2253         Expression typeRef = class_name_reference();
2254         ctor_arguments();
2255         if (typeRef != null) {
2256           expression = typeRef;
2257         }
2258         break;
2259       //        | T_INC rw_variable
2260       //        | T_DEC rw_variable
2261       case TokenNamePLUS_PLUS:
2262       case TokenNameMINUS_MINUS:
2263         getNextToken();
2264         rw_variable();
2265         break;
2266       //        | variable '=' expr
2267       //        | variable '=' '&' variable
2268       //        | variable '=' '&' T_NEW class_name_reference ctor_arguments
2269       //        | variable T_PLUS_EQUAL expr
2270       //        | variable T_MINUS_EQUAL expr
2271       //        | variable T_MUL_EQUAL expr
2272       //        | variable T_DIV_EQUAL expr
2273       //        | variable T_CONCAT_EQUAL expr
2274       //        | variable T_MOD_EQUAL expr
2275       //        | variable T_AND_EQUAL expr
2276       //        | variable T_OR_EQUAL expr
2277       //        | variable T_XOR_EQUAL expr
2278       //        | variable T_SL_EQUAL expr
2279       //        | variable T_SR_EQUAL expr
2280       //        | rw_variable T_INC
2281       //        | rw_variable T_DEC
2282       case TokenNameIdentifier:
2283       case TokenNameVariable:
2284       case TokenNameDOLLAR:
2285         boolean rememberedVar = false;
2286         Expression lhs = variable();
2287         switch (token) {
2288         case TokenNameEQUAL:
2289           getNextToken();
2290           if (token == TokenNameAND) {
2291             getNextToken();
2292             if (token == TokenNamenew) {
2293               // | variable '=' '&' T_NEW class_name_reference
2294               // ctor_arguments
2295               getNextToken();
2296               SingleTypeReference classRef = class_name_reference();
2297               ctor_arguments();
2298               if (classRef != null) {
2299                 if (lhs != null && lhs instanceof FieldReference) {
2300                   // example:
2301                   // $var = & new Object();
2302                   if (fMethodVariables != null) {
2303                     VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
2304                     lhsInfo.reference = classRef;
2305                     lhsInfo.typeIdentifier = classRef.token;
2306                     fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2307                     rememberedVar = true;
2308                   }
2309                 }
2310               }
2311             } else {
2312               Expression rhs = variable();
2313               if (rhs != null && rhs instanceof FieldReference && lhs != null && lhs instanceof FieldReference) {
2314                 // example:
2315                 // $var = &$ref;
2316                 if (fMethodVariables != null) {
2317                   VariableInfo rhsInfo = (VariableInfo) fMethodVariables.get(((FieldReference) rhs).token);
2318                   if (rhsInfo != null && rhsInfo.reference != null) {
2319                     VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
2320                     lhsInfo.reference = rhsInfo.reference;
2321                     lhsInfo.typeIdentifier = rhsInfo.typeIdentifier;
2322                     fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2323                     rememberedVar = true;
2324                   }
2325                 }
2326               }
2327             }
2328           } else {
2329             Expression rhs = expr();
2330             if (lhs != null && lhs instanceof FieldReference) {
2331               if (rhs != null && rhs instanceof FieldReference) {
2332                 // example:
2333                 // $var = $ref;
2334                 if (fMethodVariables != null) {
2335                   VariableInfo rhsInfo = (VariableInfo) fMethodVariables.get(((FieldReference) rhs).token);
2336                   if (rhsInfo != null && rhsInfo.reference != null) {
2337                     VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
2338                     lhsInfo.reference = rhsInfo.reference;
2339                     lhsInfo.typeIdentifier = rhsInfo.typeIdentifier;
2340                     fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2341                     rememberedVar = true;
2342                   }
2343                 }
2344               } else if (rhs != null && rhs instanceof SingleTypeReference) {
2345                 // example:
2346                 // $var = new Object();
2347                 if (fMethodVariables != null) {
2348                   VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
2349                   lhsInfo.reference = (SingleTypeReference) rhs;
2350                   lhsInfo.typeIdentifier = ((SingleTypeReference) rhs).token;
2351                   fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2352                   rememberedVar = true;
2353                 }
2354               }
2355             }
2356           }
2357           if (rememberedVar == false && lhs != null && lhs instanceof FieldReference) {
2358             if (fMethodVariables != null) {
2359               VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
2360               fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2361             }
2362           }
2363           break;
2364         case TokenNamePLUS_EQUAL:
2365         case TokenNameMINUS_EQUAL:
2366         case TokenNameMULTIPLY_EQUAL:
2367         case TokenNameDIVIDE_EQUAL:
2368         case TokenNameDOT_EQUAL:
2369         case TokenNameREMAINDER_EQUAL:
2370         case TokenNameAND_EQUAL:
2371         case TokenNameOR_EQUAL:
2372         case TokenNameXOR_EQUAL:
2373         case TokenNameRIGHT_SHIFT_EQUAL:
2374         case TokenNameLEFT_SHIFT_EQUAL:
2375           getNextToken();
2376           expr();
2377           break;
2378         case TokenNamePLUS_PLUS:
2379         case TokenNameMINUS_MINUS:
2380           getNextToken();
2381           break;
2382         default:
2383           if (!only_variable) {
2384             throwSyntaxError("Variable expression not allowed (found token '" + scanner.toStringAction(token) + "').");
2385           }
2386           if (lhs != null) {
2387             expression = lhs;
2388           }
2389         }
2390         break;
2391       default:
2392         if (token != TokenNameINLINE_HTML) {
2393           if (token > TokenNameKEYWORD) {
2394             getNextToken();
2395             break;
2396           } else {
2397             throwSyntaxError("Error in expression (found token '" + scanner.toStringAction(token) + "').");
2398           }
2399         }
2400         return expression;
2401       }
2402       if (Scanner.TRACE) {
2403         System.out.println("TRACE: expr_without_variable() PART 2");
2404       }
2405       //        | expr T_BOOLEAN_OR expr
2406       //        | expr T_BOOLEAN_AND expr
2407       //        | expr T_LOGICAL_OR expr
2408       //        | expr T_LOGICAL_AND expr
2409       //        | expr T_LOGICAL_XOR expr
2410       //        | expr '|' expr
2411       //        | expr '&' expr
2412       //        | expr '^' expr
2413       //        | expr '.' expr
2414       //        | expr '+' expr
2415       //        | expr '-' expr
2416       //        | expr '*' expr
2417       //        | expr '/' expr
2418       //        | expr '%' expr
2419       //        | expr T_SL expr
2420       //        | expr T_SR expr
2421       //        | expr T_IS_IDENTICAL expr
2422       //        | expr T_IS_NOT_IDENTICAL expr
2423       //        | expr T_IS_EQUAL expr
2424       //        | expr T_IS_NOT_EQUAL expr
2425       //        | expr '<' expr
2426       //        | expr T_IS_SMALLER_OR_EQUAL expr
2427       //        | expr '>' expr
2428       //        | expr T_IS_GREATER_OR_EQUAL expr
2429       while (true) {
2430         switch (token) {
2431         case TokenNameOR_OR:
2432           getNextToken();
2433           expression = new OR_OR_Expression(expression, expr(), token);
2434           break;
2435         case TokenNameAND_AND:
2436           getNextToken();
2437           expression = new AND_AND_Expression(expression, expr(), token);
2438           break;
2439         case TokenNameEQUAL_EQUAL:
2440           getNextToken();
2441           expression = new EqualExpression(expression, expr(), token);
2442           break;
2443         case TokenNameand:
2444         case TokenNameor:
2445         case TokenNamexor:
2446         case TokenNameAND:
2447         case TokenNameOR:
2448         case TokenNameXOR:
2449         case TokenNameDOT:
2450         case TokenNamePLUS:
2451         case TokenNameMINUS:
2452         case TokenNameMULTIPLY:
2453         case TokenNameDIVIDE:
2454         case TokenNameREMAINDER:
2455         case TokenNameLEFT_SHIFT:
2456         case TokenNameRIGHT_SHIFT:
2457         case TokenNameEQUAL_EQUAL_EQUAL:
2458         case TokenNameNOT_EQUAL_EQUAL:
2459         case TokenNameNOT_EQUAL:
2460         case TokenNameLESS:
2461         case TokenNameLESS_EQUAL:
2462         case TokenNameGREATER:
2463         case TokenNameGREATER_EQUAL:
2464           getNextToken();
2465           expression = new BinaryExpression(expression, expr(), token);
2466           break;
2467         //  | expr T_INSTANCEOF class_name_reference
2468         //      | expr '?' expr ':' expr
2469         case TokenNameinstanceof:
2470           getNextToken();
2471           TypeReference classRef = class_name_reference();
2472           expression = new InstanceOfExpression(expression, classRef, OperatorIds.INSTANCEOF);
2473           expression.sourceStart = exprSourceStart;
2474           expression.sourceEnd = scanner.getCurrentTokenEndPosition();
2475           break;
2476         case TokenNameQUESTION:
2477           getNextToken();
2478           Expression valueIfTrue = expr();
2479           if (token != TokenNameCOLON) {
2480             throwSyntaxError("':' expected in conditional expression.");
2481           }
2482           getNextToken();
2483           Expression valueIfFalse = expr();
2484
2485           expression = new ConditionalExpression(expression, valueIfTrue, valueIfFalse);
2486           break;
2487         default:
2488           return expression;
2489         }
2490       }
2491     } catch (SyntaxError e) {
2492       // try to find next token after expression with errors:
2493       if (token == TokenNameSEMICOLON) {
2494         getNextToken();
2495         return expression;
2496       }
2497       if (token == TokenNameRBRACE || token == TokenNameRPAREN || token == TokenNameRBRACKET) {
2498         getNextToken();
2499         return expression;
2500       }
2501       throw e;
2502     }
2503   }
2504
2505   private SingleTypeReference class_name_reference() {
2506     //  class_name_reference:
2507     //  T_STRING
2508     //| dynamic_class_name_reference
2509     SingleTypeReference ref = null;
2510     if (Scanner.TRACE) {
2511       System.out.println("TRACE: class_name_reference()");
2512     }
2513     if (token == TokenNameIdentifier) {
2514       ref = new SingleTypeReference(scanner.getCurrentIdentifierSource(), scanner.getCurrentTokenStartPosition());
2515       getNextToken();
2516     } else {
2517       ref = null;
2518       dynamic_class_name_reference();
2519     }
2520     return ref;
2521   }
2522
2523   private void dynamic_class_name_reference() {
2524     //dynamic_class_name_reference:
2525     //  base_variable T_OBJECT_OPERATOR object_property
2526     // dynamic_class_name_variable_properties
2527     //| base_variable
2528     if (Scanner.TRACE) {
2529       System.out.println("TRACE: dynamic_class_name_reference()");
2530     }
2531     base_variable();
2532     if (token == TokenNameMINUS_GREATER) {
2533       getNextToken();
2534       object_property();
2535       dynamic_class_name_variable_properties();
2536     }
2537   }
2538
2539   private void dynamic_class_name_variable_properties() {
2540     //  dynamic_class_name_variable_properties:
2541     //                  dynamic_class_name_variable_properties
2542     // dynamic_class_name_variable_property
2543     //          | /* empty */
2544     if (Scanner.TRACE) {
2545       System.out.println("TRACE: dynamic_class_name_variable_properties()");
2546     }
2547     while (token == TokenNameMINUS_GREATER) {
2548       dynamic_class_name_variable_property();
2549     }
2550   }
2551
2552   private void dynamic_class_name_variable_property() {
2553     //  dynamic_class_name_variable_property:
2554     //  T_OBJECT_OPERATOR object_property
2555     if (Scanner.TRACE) {
2556       System.out.println("TRACE: dynamic_class_name_variable_property()");
2557     }
2558     if (token == TokenNameMINUS_GREATER) {
2559       getNextToken();
2560       object_property();
2561     }
2562   }
2563
2564   private void ctor_arguments() {
2565     //  ctor_arguments:
2566     //  /* empty */
2567     //| '(' function_call_parameter_list ')'
2568     if (token == TokenNameLPAREN) {
2569       getNextToken();
2570       if (token == TokenNameRPAREN) {
2571         getNextToken();
2572         return;
2573       }
2574       non_empty_function_call_parameter_list();
2575       if (token != TokenNameRPAREN) {
2576         throwSyntaxError("')' expected in ctor_arguments.");
2577       }
2578       getNextToken();
2579     }
2580   }
2581
2582   private void assignment_list() {
2583     //  assignment_list:
2584     //  assignment_list ',' assignment_list_element
2585     //| assignment_list_element
2586     while (true) {
2587       assignment_list_element();
2588       if (token != TokenNameCOMMA) {
2589         break;
2590       }
2591       getNextToken();
2592     }
2593   }
2594
2595   private void assignment_list_element() {
2596     //assignment_list_element:
2597     //  variable
2598     //| T_LIST '(' assignment_list ')'
2599     //| /* empty */
2600     if (token == TokenNameVariable || token == TokenNameDOLLAR) {
2601       variable();
2602     } else {
2603       if (token == TokenNamelist) {
2604         getNextToken();
2605         if (token == TokenNameLPAREN) {
2606           getNextToken();
2607           assignment_list();
2608           if (token != TokenNameRPAREN) {
2609             throwSyntaxError("')' expected after 'list' keyword.");
2610           }
2611           getNextToken();
2612         } else {
2613           throwSyntaxError("'(' expected after 'list' keyword.");
2614         }
2615       }
2616     }
2617   }
2618
2619   private void array_pair_list() {
2620     //  array_pair_list:
2621     //  /* empty */
2622     //| non_empty_array_pair_list possible_comma
2623     non_empty_array_pair_list();
2624     if (token == TokenNameCOMMA) {
2625       getNextToken();
2626     }
2627   }
2628
2629   private void non_empty_array_pair_list() {
2630     //non_empty_array_pair_list:
2631     //  non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr
2632     //| non_empty_array_pair_list ',' expr
2633     //| expr T_DOUBLE_ARROW expr
2634     //| expr
2635     //| non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable
2636     //| non_empty_array_pair_list ',' '&' w_variable
2637     //| expr T_DOUBLE_ARROW '&' w_variable
2638     //| '&' w_variable
2639     while (true) {
2640       if (token == TokenNameAND) {
2641         getNextToken();
2642         variable();
2643       } else {
2644         expr();
2645         if (token == TokenNameAND) {
2646           getNextToken();
2647           variable();
2648         } else if (token == TokenNameEQUAL_GREATER) {
2649           getNextToken();
2650           if (token == TokenNameAND) {
2651             getNextToken();
2652             variable();
2653           } else {
2654             expr();
2655           }
2656         }
2657       }
2658       if (token != TokenNameCOMMA) {
2659         return;
2660       }
2661       getNextToken();
2662       if (token == TokenNameRPAREN) {
2663         return;
2664       }
2665     }
2666   }
2667
2668   //  private void variableList() {
2669   //    do {
2670   //      variable();
2671   //      if (token == TokenNameCOMMA) {
2672   //        getNextToken();
2673   //      } else {
2674   //        break;
2675   //      }
2676   //    } while (true);
2677   //  }
2678   private Expression variable_without_objects() {
2679     //  variable_without_objects:
2680     //                  reference_variable
2681     //          | simple_indirect_reference reference_variable
2682     if (Scanner.TRACE) {
2683       System.out.println("TRACE: variable_without_objects()");
2684     }
2685     while (token == TokenNameDOLLAR) {
2686       getNextToken();
2687     }
2688     return reference_variable();
2689   }
2690
2691   private Expression function_call() {
2692     //  function_call:
2693     //  T_STRING '(' function_call_parameter_list ')'
2694     //| class_constant '(' function_call_parameter_list ')'
2695     //| static_member '(' function_call_parameter_list ')'
2696     //| variable_without_objects '(' function_call_parameter_list ')'
2697     char[] defineName = null;
2698     char[] ident = null;
2699     int startPos = 0;
2700     int endPos = 0;
2701     Expression ref = null;
2702     if (Scanner.TRACE) {
2703       System.out.println("TRACE: function_call()");
2704     }
2705     if (token == TokenNameIdentifier) {
2706       ident = scanner.getCurrentIdentifierSource();
2707       defineName = ident;
2708       startPos = scanner.getCurrentTokenStartPosition();
2709       endPos = scanner.getCurrentTokenEndPosition();
2710       getNextToken();
2711       switch (token) {
2712       case TokenNamePAAMAYIM_NEKUDOTAYIM:
2713         // static member:
2714         defineName = null;
2715         getNextToken();
2716         if (token == TokenNameIdentifier) {
2717           // class _constant
2718           getNextToken();
2719         } else {
2720           //        static member:
2721           variable_without_objects();
2722         }
2723         break;
2724       }
2725     } else {
2726       ref = variable_without_objects();
2727     }
2728     if (token != TokenNameLPAREN) {
2729       if (defineName != null) {
2730         // does this identifier contain only uppercase characters?
2731         if (defineName.length == 3) {
2732           if (defineName[0] == 'd' && defineName[1] == 'i' && defineName[2] == 'e') {
2733             defineName = null;
2734           }
2735         } else if (defineName.length == 4) {
2736           if (defineName[0] == 't' && defineName[1] == 'r' && defineName[2] == 'u' && defineName[3] == 'e') {
2737             defineName = null;
2738           } else if (defineName[0] == 'n' && defineName[1] == 'u' && defineName[2] == 'l' && defineName[3] == 'l') {
2739             defineName = null;
2740           }
2741         } else if (defineName.length == 5) {
2742           if (defineName[0] == 'f' && defineName[1] == 'a' && defineName[2] == 'l' && defineName[3] == 's' && defineName[4] == 'e') {
2743             defineName = null;
2744           }
2745         }
2746         if (defineName != null) {
2747           for (int i = 0; i < defineName.length; i++) {
2748             if (Character.isLowerCase(defineName[i])) {
2749               problemReporter.phpUppercaseIdentifierWarning(startPos, endPos, referenceContext, compilationUnit.compilationResult);
2750               break;
2751             }
2752           }
2753         }
2754       }
2755       // TODO is this ok ?
2756       return ref;
2757       //      throwSyntaxError("'(' expected in function call.");
2758     }
2759     getNextToken();
2760     if (token == TokenNameRPAREN) {
2761       getNextToken();
2762       return ref;
2763     }
2764     non_empty_function_call_parameter_list();
2765     if (token != TokenNameRPAREN) {
2766       String functionName;
2767       if (ident == null) {
2768         functionName = new String(" ");
2769       } else {
2770         functionName = new String(ident);
2771       }
2772       throwSyntaxError("')' expected in function call (" + functionName + ").");
2773     }
2774     getNextToken();
2775     return ref;
2776   }
2777
2778   //  private void function_call_parameter_list() {
2779   //    function_call_parameter_list:
2780   //            non_empty_function_call_parameter_list { $$ = $1; }
2781   //    | /* empty */
2782   //  }
2783   private void non_empty_function_call_parameter_list() {
2784     //non_empty_function_call_parameter_list:
2785     //          expr_without_variable
2786     //  | variable
2787     //  | '&' w_variable
2788     //  | non_empty_function_call_parameter_list ',' expr_without_variable
2789     //  | non_empty_function_call_parameter_list ',' variable
2790     //  | non_empty_function_call_parameter_list ',' '&' w_variable
2791     if (Scanner.TRACE) {
2792       System.out.println("TRACE: non_empty_function_call_parameter_list()");
2793     }
2794     while (true) {
2795       if (token == TokenNameAND) {
2796         getNextToken();
2797         w_variable();
2798       } else {
2799         //        if (token == TokenNameIdentifier || token ==
2800         // TokenNameVariable
2801         //            || token == TokenNameDOLLAR) {
2802         //          variable();
2803         //        } else {
2804         expr_without_variable(true);
2805         //        }
2806       }
2807       if (token != TokenNameCOMMA) {
2808         break;
2809       }
2810       getNextToken();
2811     }
2812   }
2813
2814   private void fully_qualified_class_name() {
2815     if (token == TokenNameIdentifier) {
2816       getNextToken();
2817     } else {
2818       throwSyntaxError("Class name expected.");
2819     }
2820   }
2821
2822   private void static_member() {
2823     //  static_member:
2824     //  fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM
2825     // variable_without_objects
2826     if (Scanner.TRACE) {
2827       System.out.println("TRACE: static_member()");
2828     }
2829     fully_qualified_class_name();
2830     if (token != TokenNamePAAMAYIM_NEKUDOTAYIM) {
2831       throwSyntaxError("'::' expected after class name (static_member).");
2832     }
2833     getNextToken();
2834     variable_without_objects();
2835   }
2836
2837   private Expression base_variable_with_function_calls() {
2838     //  base_variable_with_function_calls:
2839     //  base_variable
2840     //| function_call
2841     boolean functionCall = false;
2842     if (Scanner.TRACE) {
2843       System.out.println("TRACE: base_variable_with_function_calls()");
2844     }
2845     //    if (token == TokenNameIdentifier) {
2846     //      functionCall = true;
2847     //    } else if (token == TokenNameVariable) {
2848     //      int tempToken = token;
2849     //      int tempPosition = scanner.currentPosition;
2850     //      getNextToken();
2851     //      if (token == TokenNameLPAREN) {
2852     //        functionCall = true;
2853     //      }
2854     //      token = tempToken;
2855     //      scanner.currentPosition = tempPosition;
2856     //      scanner.phpMode = true;
2857     //    }
2858     //    if (functionCall) {
2859     return function_call();
2860     //    } else {
2861     //      base_variable();
2862     //    }
2863   }
2864
2865   private Expression base_variable() {
2866     //  base_variable:
2867     //                  reference_variable
2868     //          | simple_indirect_reference reference_variable
2869     //          | static_member
2870     Expression ref = null;
2871     if (Scanner.TRACE) {
2872       System.out.println("TRACE: base_variable()");
2873     }
2874     if (token == TokenNameIdentifier) {
2875       static_member();
2876     } else {
2877       while (token == TokenNameDOLLAR) {
2878         getNextToken();
2879       }
2880       reference_variable();
2881     }
2882     return ref;
2883   }
2884
2885   //  private void simple_indirect_reference() {
2886   //    // simple_indirect_reference:
2887   //    // '$'
2888   //    //| simple_indirect_reference '$'
2889   //  }
2890   private Expression reference_variable() {
2891     //  reference_variable:
2892     //                  reference_variable '[' dim_offset ']'
2893     //          | reference_variable '{' expr '}'
2894     //          | compound_variable
2895     Expression ref = null;
2896     if (Scanner.TRACE) {
2897       System.out.println("TRACE: reference_variable()");
2898     }
2899     ref = compound_variable();
2900     while (true) {
2901       if (token == TokenNameLBRACE) {
2902         ref = null;
2903         getNextToken();
2904         expr();
2905         if (token != TokenNameRBRACE) {
2906           throwSyntaxError("'}' expected in reference variable.");
2907         }
2908         getNextToken();
2909       } else if (token == TokenNameLBRACKET) {
2910         ref = null;
2911         getNextToken();
2912         if (token != TokenNameRBRACKET) {
2913           expr();
2914           //        dim_offset();
2915           if (token != TokenNameRBRACKET) {
2916             throwSyntaxError("']' expected in reference variable.");
2917           }
2918         }
2919         getNextToken();
2920       } else {
2921         break;
2922       }
2923     }
2924     return ref;
2925   }
2926
2927   private Expression compound_variable() {
2928     //  compound_variable:
2929     //                  T_VARIABLE
2930     //          | '$' '{' expr '}'
2931     if (Scanner.TRACE) {
2932       System.out.println("TRACE: compound_variable()");
2933     }
2934     if (token == TokenNameVariable) {
2935       FieldReference ref = new FieldReference(scanner.getCurrentIdentifierSource(), scanner.getCurrentTokenStartPosition());
2936       getNextToken();
2937       return ref;
2938     } else {
2939       // because of simple_indirect_reference
2940       while (token == TokenNameDOLLAR) {
2941         getNextToken();
2942       }
2943       if (token != TokenNameLBRACE) {
2944         reportSyntaxError("'{' expected after compound variable token '$'.");
2945         return null;
2946       }
2947       getNextToken();
2948       expr();
2949       if (token != TokenNameRBRACE) {
2950         throwSyntaxError("'}' expected after compound variable token '$'.");
2951       }
2952       getNextToken();
2953     }
2954     return null;
2955   }
2956
2957   //  private void dim_offset() {
2958   //    // dim_offset:
2959   //    // /* empty */
2960   //    // | expr
2961   //    expr();
2962   //  }
2963   private void object_property() {
2964     //  object_property:
2965     //  object_dim_list
2966     //| variable_without_objects
2967     if (Scanner.TRACE) {
2968       System.out.println("TRACE: object_property()");
2969     }
2970     if (token == TokenNameVariable || token == TokenNameDOLLAR) {
2971       variable_without_objects();
2972     } else {
2973       object_dim_list();
2974     }
2975   }
2976
2977   private void object_dim_list() {
2978     //object_dim_list:
2979     //  object_dim_list '[' dim_offset ']'
2980     //| object_dim_list '{' expr '}'
2981     //| variable_name
2982     if (Scanner.TRACE) {
2983       System.out.println("TRACE: object_dim_list()");
2984     }
2985     variable_name();
2986     while (true) {
2987       if (token == TokenNameLBRACE) {
2988         getNextToken();
2989         expr();
2990         if (token != TokenNameRBRACE) {
2991           throwSyntaxError("'}' expected in object_dim_list.");
2992         }
2993         getNextToken();
2994       } else if (token == TokenNameLBRACKET) {
2995         getNextToken();
2996         if (token == TokenNameRBRACKET) {
2997           getNextToken();
2998           continue;
2999         }
3000         expr();
3001         if (token != TokenNameRBRACKET) {
3002           throwSyntaxError("']' expected in object_dim_list.");
3003         }
3004         getNextToken();
3005       } else {
3006         break;
3007       }
3008     }
3009   }
3010
3011   private void variable_name() {
3012     //variable_name:
3013     //  T_STRING
3014     //| '{' expr '}'
3015     if (Scanner.TRACE) {
3016       System.out.println("TRACE: variable_name()");
3017     }
3018     if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
3019       if (token > TokenNameKEYWORD) {
3020         // TODO show a warning "Keyword used as variable" ?
3021       }
3022       getNextToken();
3023     } else {
3024       if (token != TokenNameLBRACE) {
3025         throwSyntaxError("'{' expected in variable name.");
3026       }
3027       getNextToken();
3028       expr();
3029       if (token != TokenNameRBRACE) {
3030         throwSyntaxError("'}' expected in variable name.");
3031       }
3032       getNextToken();
3033     }
3034   }
3035
3036   private void r_variable() {
3037     variable();
3038   }
3039
3040   private void w_variable() {
3041     variable();
3042   }
3043
3044   private void rw_variable() {
3045     variable();
3046   }
3047
3048   private Expression variable() {
3049     //    variable:
3050     //          base_variable_with_function_calls T_OBJECT_OPERATOR
3051     //                  object_property method_or_not variable_properties
3052     //  | base_variable_with_function_calls
3053     Expression ref = base_variable_with_function_calls();
3054     if (token == TokenNameMINUS_GREATER) {
3055       ref = null;
3056       getNextToken();
3057       object_property();
3058       method_or_not();
3059       variable_properties();
3060     }
3061     return ref;
3062   }
3063
3064   private void variable_properties() {
3065     //  variable_properties:
3066     //                  variable_properties variable_property
3067     //          | /* empty */
3068     while (token == TokenNameMINUS_GREATER) {
3069       variable_property();
3070     }
3071   }
3072
3073   private void variable_property() {
3074     //  variable_property:
3075     //                  T_OBJECT_OPERATOR object_property method_or_not
3076     if (Scanner.TRACE) {
3077       System.out.println("TRACE: variable_property()");
3078     }
3079     if (token == TokenNameMINUS_GREATER) {
3080       getNextToken();
3081       object_property();
3082       method_or_not();
3083     } else {
3084       throwSyntaxError("'->' expected in variable_property.");
3085     }
3086   }
3087
3088   private void method_or_not() {
3089     //  method_or_not:
3090     //                  '(' function_call_parameter_list ')'
3091     //          | /* empty */
3092     if (Scanner.TRACE) {
3093       System.out.println("TRACE: method_or_not()");
3094     }
3095     if (token == TokenNameLPAREN) {
3096       getNextToken();
3097       if (token == TokenNameRPAREN) {
3098         getNextToken();
3099         return;
3100       }
3101       non_empty_function_call_parameter_list();
3102       if (token != TokenNameRPAREN) {
3103         throwSyntaxError("')' expected in method_or_not.");
3104       }
3105       getNextToken();
3106     }
3107   }
3108
3109   private void exit_expr() {
3110     //  /* empty */
3111     //  | '(' ')'
3112     //  | '(' expr ')'
3113     if (token != TokenNameLPAREN) {
3114       return;
3115     }
3116     getNextToken();
3117     if (token == TokenNameRPAREN) {
3118       getNextToken();
3119       return;
3120     }
3121     expr();
3122     if (token != TokenNameRPAREN) {
3123       throwSyntaxError("')' expected after keyword 'exit'");
3124     }
3125     getNextToken();
3126   }
3127
3128   private void encaps_list() {
3129     //                  encaps_list encaps_var
3130     //          | encaps_list T_STRING
3131     //          | encaps_list T_NUM_STRING
3132     //          | encaps_list T_ENCAPSED_AND_WHITESPACE
3133     //          | encaps_list T_CHARACTER
3134     //          | encaps_list T_BAD_CHARACTER
3135     //          | encaps_list '['
3136     //          | encaps_list ']'
3137     //          | encaps_list '{'
3138     //          | encaps_list '}'
3139     //          | encaps_list T_OBJECT_OPERATOR
3140     //          | /* empty */
3141     while (true) {
3142       switch (token) {
3143       case TokenNameSTRING:
3144         getNextToken();
3145         break;
3146       case TokenNameLBRACE:
3147         //          scanner.encapsedStringStack.pop();
3148         getNextToken();
3149         break;
3150       case TokenNameRBRACE:
3151         //          scanner.encapsedStringStack.pop();
3152         getNextToken();
3153         break;
3154       case TokenNameLBRACKET:
3155         //          scanner.encapsedStringStack.pop();
3156         getNextToken();
3157         break;
3158       case TokenNameRBRACKET:
3159         //          scanner.encapsedStringStack.pop();
3160         getNextToken();
3161         break;
3162       case TokenNameMINUS_GREATER:
3163         //          scanner.encapsedStringStack.pop();
3164         getNextToken();
3165         break;
3166       case TokenNameVariable:
3167       case TokenNameDOLLAR_LBRACE:
3168       case TokenNameLBRACE_DOLLAR:
3169         encaps_var();
3170         break;
3171       default:
3172         char encapsedChar = ((Character) scanner.encapsedStringStack.peek()).charValue();
3173         if (encapsedChar == '$') {
3174           scanner.encapsedStringStack.pop();
3175           encapsedChar = ((Character) scanner.encapsedStringStack.peek()).charValue();
3176           switch (encapsedChar) {
3177           case '`':
3178             if (token == TokenNameEncapsedString0) {
3179               return;
3180             }
3181             token = TokenNameSTRING;
3182             continue;
3183           case '\'':
3184             if (token == TokenNameEncapsedString1) {
3185               return;
3186             }
3187             token = TokenNameSTRING;
3188             continue;
3189           case '"':
3190             if (token == TokenNameEncapsedString2) {
3191               return;
3192             }
3193             token = TokenNameSTRING;
3194             continue;
3195           }
3196         }
3197         return;
3198       }
3199     }
3200   }
3201
3202   private void encaps_var() {
3203     //                  T_VARIABLE
3204     //          | T_VARIABLE '[' encaps_var_offset ']'
3205     //          | T_VARIABLE T_OBJECT_OPERATOR T_STRING
3206     //          | T_DOLLAR_OPEN_CURLY_BRACES expr '}'
3207     //          | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
3208     //          | T_CURLY_OPEN variable '}'
3209     switch (token) {
3210     case TokenNameVariable:
3211       getNextToken();
3212       if (token == TokenNameLBRACKET) {
3213         getNextToken();
3214         expr(); //encaps_var_offset();
3215         if (token != TokenNameRBRACKET) {
3216           throwSyntaxError("']' expected after variable.");
3217         }
3218         //          scanner.encapsedStringStack.pop();
3219         getNextToken();
3220         //          }
3221       } else if (token == TokenNameMINUS_GREATER) {
3222         getNextToken();
3223         if (token != TokenNameIdentifier) {
3224           throwSyntaxError("Identifier expected after '->'.");
3225         }
3226         //          scanner.encapsedStringStack.pop();
3227         getNextToken();
3228       }
3229       //        else {
3230       //          // scanner.encapsedStringStack.pop();
3231       //          int tempToken = TokenNameSTRING;
3232       //          if (!scanner.encapsedStringStack.isEmpty()
3233       //              && (token == TokenNameEncapsedString0
3234       //                  || token == TokenNameEncapsedString1
3235       //                  || token == TokenNameEncapsedString2 || token ==
3236       // TokenNameERROR)) {
3237       //            char encapsedChar = ((Character)
3238       // scanner.encapsedStringStack.peek())
3239       //                .charValue();
3240       //            switch (token) {
3241       //              case TokenNameEncapsedString0 :
3242       //                if (encapsedChar == '`') {
3243       //                  tempToken = TokenNameEncapsedString0;
3244       //                }
3245       //                break;
3246       //              case TokenNameEncapsedString1 :
3247       //                if (encapsedChar == '\'') {
3248       //                  tempToken = TokenNameEncapsedString1;
3249       //                }
3250       //                break;
3251       //              case TokenNameEncapsedString2 :
3252       //                if (encapsedChar == '"') {
3253       //                  tempToken = TokenNameEncapsedString2;
3254       //                }
3255       //                break;
3256       //              case TokenNameERROR :
3257       //                if (scanner.source[scanner.currentPosition - 1] == '\\') {
3258       //                  scanner.currentPosition--;
3259       //                  getNextToken();
3260       //                }
3261       //                break;
3262       //            }
3263       //          }
3264       //          token = tempToken;
3265       //        }
3266       break;
3267     case TokenNameDOLLAR_LBRACE:
3268       getNextToken();
3269       if (token == TokenNameDOLLAR_LBRACE) {
3270         encaps_var();
3271       } else if (token == TokenNameIdentifier) {
3272         getNextToken();
3273         if (token == TokenNameLBRACKET) {
3274           getNextToken();
3275           //            if (token == TokenNameRBRACKET) {
3276           //              getNextToken();
3277           //            } else {
3278           expr();
3279           if (token != TokenNameRBRACKET) {
3280             throwSyntaxError("']' expected after '${'.");
3281           }
3282           getNextToken();
3283           //            }
3284         }
3285       } else {
3286         expr();
3287       }
3288       if (token != TokenNameRBRACE) {
3289         throwSyntaxError("'}' expected.");
3290       }
3291       getNextToken();
3292       break;
3293     case TokenNameLBRACE_DOLLAR:
3294       getNextToken();
3295       if (token == TokenNameLBRACE_DOLLAR) {
3296         encaps_var();
3297       } else if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
3298         getNextToken();
3299         if (token == TokenNameLBRACKET) {
3300           getNextToken();
3301           //            if (token == TokenNameRBRACKET) {
3302           //              getNextToken();
3303           //            } else {
3304           expr();
3305           if (token != TokenNameRBRACKET) {
3306             throwSyntaxError("']' expected.");
3307           }
3308           getNextToken();
3309           //            }
3310         } else if (token == TokenNameMINUS_GREATER) {
3311           getNextToken();
3312           if (token != TokenNameIdentifier && token != TokenNameVariable) {
3313             throwSyntaxError("String or Variable token expected.");
3314           }
3315           getNextToken();
3316           if (token == TokenNameLBRACKET) {
3317             getNextToken();
3318             //            if (token == TokenNameRBRACKET) {
3319             //              getNextToken();
3320             //            } else {
3321             expr();
3322             if (token != TokenNameRBRACKET) {
3323               throwSyntaxError("']' expected after '${'.");
3324             }
3325             getNextToken();
3326             //            }
3327           }
3328         }
3329         //          if (token != TokenNameRBRACE) {
3330         //            throwSyntaxError("'}' expected after '{$'.");
3331         //          }
3332         //          // scanner.encapsedStringStack.pop();
3333         //          getNextToken();
3334       } else {
3335         expr();
3336         if (token != TokenNameRBRACE) {
3337           throwSyntaxError("'}' expected.");
3338         }
3339         //          scanner.encapsedStringStack.pop();
3340         getNextToken();
3341       }
3342       break;
3343     }
3344   }
3345
3346   private void encaps_var_offset() {
3347     //                  T_STRING
3348     //          | T_NUM_STRING
3349     //          | T_VARIABLE
3350     switch (token) {
3351     case TokenNameSTRING:
3352       getNextToken();
3353       break;
3354     case TokenNameIntegerLiteral:
3355       getNextToken();
3356       break;
3357     case TokenNameVariable:
3358       getNextToken();
3359       break;
3360     case TokenNameIdentifier:
3361       getNextToken();
3362       break;
3363     default:
3364       throwSyntaxError("Variable or String token expected.");
3365       break;
3366     }
3367   }
3368
3369   private void internal_functions_in_yacc() {
3370     //    int start = 0;
3371     switch (token) {
3372     case TokenNameisset:
3373       //        T_ISSET '(' isset_variables ')'
3374       getNextToken();
3375       if (token != TokenNameLPAREN) {
3376         throwSyntaxError("'(' expected after keyword 'isset'");
3377       }
3378       getNextToken();
3379       isset_variables();
3380       if (token != TokenNameRPAREN) {
3381         throwSyntaxError("')' expected after keyword 'isset'");
3382       }
3383       getNextToken();
3384       break;
3385     case TokenNameempty:
3386       //        T_EMPTY '(' variable ')'
3387       getNextToken();
3388       if (token != TokenNameLPAREN) {
3389         throwSyntaxError("'(' expected after keyword 'empty'");
3390       }
3391       getNextToken();
3392       variable();
3393       if (token != TokenNameRPAREN) {
3394         throwSyntaxError("')' expected after keyword 'empty'");
3395       }
3396       getNextToken();
3397       break;
3398     case TokenNameinclude:
3399       //T_INCLUDE expr
3400       checkFileName(token);
3401       break;
3402     case TokenNameinclude_once:
3403       //        T_INCLUDE_ONCE expr
3404       checkFileName(token);
3405       break;
3406     case TokenNameeval:
3407       //        T_EVAL '(' expr ')'
3408       getNextToken();
3409       if (token != TokenNameLPAREN) {
3410         throwSyntaxError("'(' expected after keyword 'eval'");
3411       }
3412       getNextToken();
3413       expr();
3414       if (token != TokenNameRPAREN) {
3415         throwSyntaxError("')' expected after keyword 'eval'");
3416       }
3417       getNextToken();
3418       break;
3419     case TokenNamerequire:
3420       //T_REQUIRE expr
3421       checkFileName(token);
3422       break;
3423     case TokenNamerequire_once:
3424       //        T_REQUIRE_ONCE expr
3425       checkFileName(token);
3426       break;
3427     }
3428   }
3429
3430   private void checkFileName(int includeToken) {
3431     //<include-token> expr
3432     int start = scanner.getCurrentTokenStartPosition();
3433     boolean hasLPAREN = false;
3434     getNextToken();
3435     if (token == TokenNameLPAREN) {
3436       hasLPAREN = true;
3437       getNextToken();
3438     }
3439     Expression expression = expr();
3440     if (hasLPAREN) {
3441       if (token == TokenNameRPAREN) {
3442         getNextToken();
3443       } else {
3444         throwSyntaxError("')' expected for keyword '" + scanner.toStringAction(includeToken) + "'");
3445       }
3446     }
3447     char[] currTokenSource = scanner.getCurrentTokenSource(start);
3448     IFile file = null;
3449     if (scanner.compilationUnit != null) {
3450       IResource resource = scanner.compilationUnit.getResource();
3451       if (resource != null && resource instanceof IFile) {
3452         file = (IFile) resource;
3453       }
3454     }
3455     char[][] tokens;
3456     tokens = new char[1][];
3457     tokens[0] = currTokenSource;
3458
3459     ImportReference impt = new ImportReference(tokens, currTokenSource, start, scanner.getCurrentTokenEndPosition(), false);
3460     impt.declarationSourceEnd = impt.sourceEnd;
3461     impt.declarationEnd = impt.declarationSourceEnd;
3462     //endPosition is just before the ;
3463     impt.declarationSourceStart = start;
3464     includesList.add(impt);
3465
3466     if (expression instanceof StringLiteral) {
3467       StringLiteral literal = (StringLiteral) expression;
3468       char[] includeName = literal.source();
3469       if (includeName.length == 0) {
3470         reportSyntaxError("Empty filename after keyword '" + scanner.toStringAction(includeToken) + "'", literal.sourceStart,
3471             literal.sourceStart + 1);
3472       }
3473       String includeNameString = new String(includeName);
3474       if (literal instanceof StringLiteralDQ) {
3475         if (includeNameString.indexOf('$') >= 0) {
3476           // assuming that the filename contains a variable => no filename check
3477           return;
3478         }
3479       }
3480       if (includeNameString.startsWith("http://")) {
3481         // assuming external include location
3482         return;
3483       }
3484       if (file != null) {
3485         // check the filename:
3486         //      System.out.println(new String(compilationUnit.getFileName())+" - "+ expression.toStringExpression());
3487         IProject project = file.getProject();
3488         if (project != null) {
3489           IPath path = PHPFileUtil.determineFilePath(includeNameString, file, project);
3490
3491           if (path == null) {
3492             //              reportSyntaxError("File: " + expression.toStringExpression() + " doesn't exist in project: "
3493             //                  + project.getLocation().toString(), literal.sourceStart, literal.sourceEnd);
3494             String[] args = { expression.toStringExpression(), project.getLocation().toString() };
3495             problemReporter.phpIncludeNotExistWarning(args, literal.sourceStart, literal.sourceEnd, referenceContext,
3496                 compilationUnit.compilationResult);
3497           } else {
3498             try {
3499               //              String projectPath = ProjectPrefUtil.getDocumentRoot(file.getProject()).toString();
3500               //              String filePath = file.getRawLocation().toString();
3501               String filePath = path.toString();
3502               String ext = file.getRawLocation().getFileExtension();
3503               int fileExtensionLength = ext == null ? 0 : ext.length() + 1;
3504               int length;
3505
3506               impt.tokens = CharOperation.splitOn('/', filePath.toCharArray(), 0, filePath.length() - fileExtensionLength);
3507               impt.setFile(PHPFileUtil.createFile(path, project));
3508             } catch (Exception e) {
3509               // the file is outside of the workspace
3510             }
3511           }
3512         }
3513       }
3514     }
3515   }
3516
3517   private void isset_variables() {
3518     //  variable
3519     //  | isset_variables ','
3520     if (token == TokenNameRPAREN) {
3521       throwSyntaxError("Variable expected after keyword 'isset'");
3522     }
3523     while (true) {
3524       variable();
3525       if (token == TokenNameCOMMA) {
3526         getNextToken();
3527       } else {
3528         break;
3529       }
3530     }
3531   }
3532
3533   private boolean common_scalar() {
3534     //  common_scalar:
3535     //  T_LNUMBER
3536     //  | T_DNUMBER
3537     //  | T_CONSTANT_ENCAPSED_STRING
3538     //  | T_LINE
3539     //  | T_FILE
3540     //  | T_CLASS_C
3541     //  | T_METHOD_C
3542     //  | T_FUNC_C
3543     switch (token) {
3544     case TokenNameIntegerLiteral:
3545       getNextToken();
3546       return true;
3547     case TokenNameDoubleLiteral:
3548       getNextToken();
3549       return true;
3550     case TokenNameStringDoubleQuote:
3551       getNextToken();
3552       return true;
3553     case TokenNameStringSingleQuote:
3554       getNextToken();
3555       return true;
3556     case TokenNameStringInterpolated:
3557       getNextToken();
3558       return true;
3559     case TokenNameFILE:
3560       getNextToken();
3561       return true;
3562     case TokenNameLINE:
3563       getNextToken();
3564       return true;
3565     case TokenNameCLASS_C:
3566       getNextToken();
3567       return true;
3568     case TokenNameMETHOD_C:
3569       getNextToken();
3570       return true;
3571     case TokenNameFUNC_C:
3572       getNextToken();
3573       return true;
3574     }
3575     return false;
3576   }
3577
3578   private void scalar() {
3579     //  scalar:
3580     //  T_STRING
3581     //| T_STRING_VARNAME
3582     //| class_constant
3583     //| common_scalar
3584     //| '"' encaps_list '"'
3585     //| '\'' encaps_list '\''
3586     //| T_START_HEREDOC encaps_list T_END_HEREDOC
3587     throwSyntaxError("Not yet implemented (scalar).");
3588   }
3589
3590   private void static_scalar() {
3591     //    static_scalar: /* compile-time evaluated scalars */
3592     //          common_scalar
3593     //  | T_STRING
3594     //  | '+' static_scalar
3595     //  | '-' static_scalar
3596     //  | T_ARRAY '(' static_array_pair_list ')'
3597     //  | static_class_constant
3598     if (common_scalar()) {
3599       return;
3600     }
3601     switch (token) {
3602     case TokenNameIdentifier:
3603       getNextToken();
3604       //        static_class_constant:
3605       //                T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING
3606       if (token == TokenNamePAAMAYIM_NEKUDOTAYIM) {
3607         getNextToken();
3608         if (token == TokenNameIdentifier) {
3609           getNextToken();
3610         } else {
3611           throwSyntaxError("Identifier expected after '::' operator.");
3612         }
3613       }
3614       break;
3615     case TokenNameEncapsedString0:
3616       try {
3617         scanner.currentCharacter = scanner.source[scanner.currentPosition++];
3618         while (scanner.currentCharacter != '`') {
3619           if (scanner.currentCharacter == '\\') {
3620             scanner.currentPosition++;
3621           }
3622           scanner.currentCharacter = scanner.source[scanner.currentPosition++];
3623         }
3624         getNextToken();
3625       } catch (IndexOutOfBoundsException e) {
3626         throwSyntaxError("'`' expected at end of static string.");
3627       }
3628       break;
3629     case TokenNameEncapsedString1:
3630       try {
3631         scanner.currentCharacter = scanner.source[scanner.currentPosition++];
3632         while (scanner.currentCharacter != '\'') {
3633           if (scanner.currentCharacter == '\\') {
3634             scanner.currentPosition++;
3635           }
3636           scanner.currentCharacter = scanner.source[scanner.currentPosition++];
3637         }
3638         getNextToken();
3639       } catch (IndexOutOfBoundsException e) {
3640         throwSyntaxError("'\'' expected at end of static string.");
3641       }
3642       break;
3643     case TokenNameEncapsedString2:
3644       try {
3645         scanner.currentCharacter = scanner.source[scanner.currentPosition++];
3646         while (scanner.currentCharacter != '"') {
3647           if (scanner.currentCharacter == '\\') {
3648             scanner.currentPosition++;
3649           }
3650           scanner.currentCharacter = scanner.source[scanner.currentPosition++];
3651         }
3652         getNextToken();
3653       } catch (IndexOutOfBoundsException e) {
3654         throwSyntaxError("'\"' expected at end of static string.");
3655       }
3656       break;
3657     case TokenNamePLUS:
3658       getNextToken();
3659       static_scalar();
3660       break;
3661     case TokenNameMINUS:
3662       getNextToken();
3663       static_scalar();
3664       break;
3665     case TokenNamearray:
3666       getNextToken();
3667       if (token != TokenNameLPAREN) {
3668         throwSyntaxError("'(' expected after keyword 'array'");
3669       }
3670       getNextToken();
3671       if (token == TokenNameRPAREN) {
3672         getNextToken();
3673         break;
3674       }
3675       non_empty_static_array_pair_list();
3676       if (token != TokenNameRPAREN) {
3677         throwSyntaxError("')' or ',' expected after keyword 'array'");
3678       }
3679       getNextToken();
3680       break;
3681     //      case TokenNamenull :
3682     //        getNextToken();
3683     //        break;
3684     //      case TokenNamefalse :
3685     //        getNextToken();
3686     //        break;
3687     //      case TokenNametrue :
3688     //        getNextToken();
3689     //        break;
3690     default:
3691       throwSyntaxError("Static scalar/constant expected.");
3692     }
3693   }
3694
3695   private void non_empty_static_array_pair_list() {
3696     //  non_empty_static_array_pair_list:
3697     //  non_empty_static_array_pair_list ',' static_scalar T_DOUBLE_ARROW
3698     // static_scalar
3699     //| non_empty_static_array_pair_list ',' static_scalar
3700     //| static_scalar T_DOUBLE_ARROW static_scalar
3701     //| static_scalar
3702     while (true) {
3703       static_scalar();
3704       if (token == TokenNameEQUAL_GREATER) {
3705         getNextToken();
3706         static_scalar();
3707       }
3708       if (token != TokenNameCOMMA) {
3709         break;
3710       }
3711       getNextToken();
3712       if (token == TokenNameRPAREN) {
3713         break;
3714       }
3715     }
3716   }
3717
3718   public void reportSyntaxError() { //int act, int currentKind, int
3719     // stateStackTop) {
3720     /* remember current scanner position */
3721     int startPos = scanner.startPosition;
3722     int currentPos = scanner.currentPosition;
3723     //          String[] expectings;
3724     //          String tokenName = name[symbol_index[currentKind]];
3725     //fetch all "accurate" possible terminals that could recover the error
3726     //          int start, end = start = asi(stack[stateStackTop]);
3727     //          while (asr[end] != 0)
3728     //                  end++;
3729     //          int length = end - start;
3730     //          expectings = new String[length];
3731     //          if (length != 0) {
3732     //                  char[] indexes = new char[length];
3733     //                  System.arraycopy(asr, start, indexes, 0, length);
3734     //                  for (int i = 0; i < length; i++) {
3735     //                          expectings[i] = name[symbol_index[indexes[i]]];
3736     //                  }
3737     //          }
3738     //if the pb is an EOF, try to tell the user that they are some
3739     //          if (tokenName.equals(UNEXPECTED_EOF)) {
3740     //                  if (!this.checkAndReportBracketAnomalies(problemReporter())) {
3741     //                          char[] tokenSource;
3742     //                          try {
3743     //                                  tokenSource = this.scanner.getCurrentTokenSource();
3744     //                          } catch (Exception e) {
3745     //                                  tokenSource = new char[] {};
3746     //                          }
3747     //                          problemReporter().parseError(
3748     //                                  this.scanner.startPosition,
3749     //                                  this.scanner.currentPosition - 1,
3750     //                                  tokenSource,
3751     //                                  tokenName,
3752     //                                  expectings);
3753     //                  }
3754     //          } else { //the next test is HEAVILY grammar DEPENDENT.
3755     //                  if ((length == 14)
3756     //                          && (expectings[0] == "=") //$NON-NLS-1$
3757     //                          && (expectings[1] == "*=") //$NON-NLS-1$
3758     //                          && (expressionPtr > -1)) {
3759     //                                  switch(currentKind) {
3760     //                                          case TokenNameSEMICOLON:
3761     //                                          case TokenNamePLUS:
3762     //                                          case TokenNameMINUS:
3763     //                                          case TokenNameDIVIDE:
3764     //                                          case TokenNameREMAINDER:
3765     //                                          case TokenNameMULTIPLY:
3766     //                                          case TokenNameLEFT_SHIFT:
3767     //                                          case TokenNameRIGHT_SHIFT:
3768     //// case TokenNameUNSIGNED_RIGHT_SHIFT:
3769     //                                          case TokenNameLESS:
3770     //                                          case TokenNameGREATER:
3771     //                                          case TokenNameLESS_EQUAL:
3772     //                                          case TokenNameGREATER_EQUAL:
3773     //                                          case TokenNameEQUAL_EQUAL:
3774     //                                          case TokenNameNOT_EQUAL:
3775     //                                          case TokenNameXOR:
3776     //                                          case TokenNameAND:
3777     //                                          case TokenNameOR:
3778     //                                          case TokenNameOR_OR:
3779     //                                          case TokenNameAND_AND:
3780     //                                                  // the ; is not the expected token ==> it ends a statement when an
3781     // expression is not ended
3782     //                                                  problemReporter().invalidExpressionAsStatement(expressionStack[expressionPtr]);
3783     //                                                  break;
3784     //                                          case TokenNameRBRACE :
3785     //                                                  problemReporter().missingSemiColon(expressionStack[expressionPtr]);
3786     //                                                  break;
3787     //                                          default:
3788     //                                                  char[] tokenSource;
3789     //                                                  try {
3790     //                                                          tokenSource = this.scanner.getCurrentTokenSource();
3791     //                                                  } catch (Exception e) {
3792     //                                                          tokenSource = new char[] {};
3793     //                                                  }
3794     //                                                  problemReporter().parseError(
3795     //                                                          this.scanner.startPosition,
3796     //                                                          this.scanner.currentPosition - 1,
3797     //                                                          tokenSource,
3798     //                                                          tokenName,
3799     //                                                          expectings);
3800     //                                                  this.checkAndReportBracketAnomalies(problemReporter());
3801     //                                  }
3802     //                  } else {
3803     char[] tokenSource;
3804     try {
3805       tokenSource = this.scanner.getCurrentTokenSource();
3806     } catch (Exception e) {
3807       tokenSource = new char[] {};
3808     }
3809     //                          problemReporter().parseError(
3810     //                                  this.scanner.startPosition,
3811     //                                  this.scanner.currentPosition - 1,
3812     //                                  tokenSource,
3813     //                                  tokenName,
3814     //                                  expectings);
3815     this.checkAndReportBracketAnomalies(problemReporter());
3816     //                  }
3817     //          }
3818     /* reset scanner where it was */
3819     scanner.startPosition = startPos;
3820     scanner.currentPosition = currentPos;
3821   }
3822
3823   public static final int RoundBracket = 0;
3824
3825   public static final int SquareBracket = 1;
3826
3827   public static final int CurlyBracket = 2;
3828
3829   public static final int BracketKinds = 3;
3830
3831   protected int[] nestedMethod; //the ptr is nestedType
3832
3833   protected int nestedType, dimensions;
3834
3835   //variable set stack
3836   final static int VariableStackIncrement = 10;
3837
3838   HashMap fTypeVariables = null;
3839
3840   HashMap fMethodVariables = null;
3841
3842   //ast stack
3843   final static int AstStackIncrement = 100;
3844
3845   protected int astPtr;
3846
3847   protected ASTNode[] astStack = new ASTNode[AstStackIncrement];
3848
3849   protected int astLengthPtr;
3850
3851   protected int[] astLengthStack;
3852
3853   ASTNode[] noAstNodes = new ASTNode[AstStackIncrement];
3854
3855   public CompilationUnitDeclaration compilationUnit; /*
3856                                                       * the result from parse()
3857                                                       */
3858
3859   protected ReferenceContext referenceContext;
3860
3861   protected ProblemReporter problemReporter;
3862
3863   protected CompilerOptions options;
3864
3865   private ArrayList includesList;
3866
3867   //  protected CompilationResult compilationResult;
3868   /**
3869    * Returns this parser's problem reporter initialized with its reference context. Also it is assumed that a problem is going to be
3870    * reported, so initializes the compilation result's line positions.
3871    */
3872   public ProblemReporter problemReporter() {
3873     if (scanner.recordLineSeparator) {
3874       compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
3875     }
3876     problemReporter.referenceContext = referenceContext;
3877     return problemReporter;
3878   }
3879
3880   /*
3881    * Reconsider the entire source looking for inconsistencies in {} () []
3882    */
3883   public boolean checkAndReportBracketAnomalies(ProblemReporter problemReporter) {
3884     scanner.wasAcr = false;
3885     boolean anomaliesDetected = false;
3886     try {
3887       char[] source = scanner.source;
3888       int[] leftCount = { 0, 0, 0 };
3889       int[] rightCount = { 0, 0, 0 };
3890       int[] depths = { 0, 0, 0 };
3891       int[][] leftPositions = new int[][] { new int[10], new int[10], new int[10] };
3892       int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] };
3893       int[][] rightPositions = new int[][] { new int[10], new int[10], new int[10] };
3894       int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10] };
3895       scanner.currentPosition = scanner.initialPosition; //starting
3896       // point
3897       // (first-zero-based
3898       // char)
3899       while (scanner.currentPosition < scanner.eofPosition) { //loop for
3900         // jumping
3901         // over
3902         // comments
3903         try {
3904           // ---------Consume white space and handles
3905           // startPosition---------
3906           boolean isWhiteSpace;
3907           do {
3908             scanner.startPosition = scanner.currentPosition;
3909             //                                          if (((scanner.currentCharacter =
3910             // source[scanner.currentPosition++]) == '\\') &&
3911             // (source[scanner.currentPosition] == 'u')) {
3912             //                                                  isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace();
3913             //                                          } else {
3914             if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
3915               if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
3916                 // only record line positions we have not
3917                 // recorded yet
3918                 scanner.pushLineSeparator();
3919               }
3920             }
3921             isWhiteSpace = CharOperation.isWhitespace(scanner.currentCharacter);
3922             //                                          }
3923           } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition));
3924           // -------consume token until } is found---------
3925           switch (scanner.currentCharacter) {
3926           case '{': {
3927             int index = leftCount[CurlyBracket]++;
3928             if (index == leftPositions[CurlyBracket].length) {
3929               System.arraycopy(leftPositions[CurlyBracket], 0, (leftPositions[CurlyBracket] = new int[index * 2]), 0, index);
3930               System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] = new int[index * 2]), 0, index);
3931             }
3932             leftPositions[CurlyBracket][index] = scanner.startPosition;
3933             leftDepths[CurlyBracket][index] = depths[CurlyBracket]++;
3934           }
3935             break;
3936           case '}': {
3937             int index = rightCount[CurlyBracket]++;
3938             if (index == rightPositions[CurlyBracket].length) {
3939               System.arraycopy(rightPositions[CurlyBracket], 0, (rightPositions[CurlyBracket] = new int[index * 2]), 0, index);
3940               System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] = new int[index * 2]), 0, index);
3941             }
3942             rightPositions[CurlyBracket][index] = scanner.startPosition;
3943             rightDepths[CurlyBracket][index] = --depths[CurlyBracket];
3944           }
3945             break;
3946           case '(': {
3947             int index = leftCount[RoundBracket]++;
3948             if (index == leftPositions[RoundBracket].length) {
3949               System.arraycopy(leftPositions[RoundBracket], 0, (leftPositions[RoundBracket] = new int[index * 2]), 0, index);
3950               System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] = new int[index * 2]), 0, index);
3951             }
3952             leftPositions[RoundBracket][index] = scanner.startPosition;
3953             leftDepths[RoundBracket][index] = depths[RoundBracket]++;
3954           }
3955             break;
3956           case ')': {
3957             int index = rightCount[RoundBracket]++;
3958             if (index == rightPositions[RoundBracket].length) {
3959               System.arraycopy(rightPositions[RoundBracket], 0, (rightPositions[RoundBracket] = new int[index * 2]), 0, index);
3960               System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] = new int[index * 2]), 0, index);
3961             }
3962             rightPositions[RoundBracket][index] = scanner.startPosition;
3963             rightDepths[RoundBracket][index] = --depths[RoundBracket];
3964           }
3965             break;
3966           case '[': {
3967             int index = leftCount[SquareBracket]++;
3968             if (index == leftPositions[SquareBracket].length) {
3969               System.arraycopy(leftPositions[SquareBracket], 0, (leftPositions[SquareBracket] = new int[index * 2]), 0, index);
3970               System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] = new int[index * 2]), 0, index);
3971             }
3972             leftPositions[SquareBracket][index] = scanner.startPosition;
3973             leftDepths[SquareBracket][index] = depths[SquareBracket]++;
3974           }
3975             break;
3976           case ']': {
3977             int index = rightCount[SquareBracket]++;
3978             if (index == rightPositions[SquareBracket].length) {
3979               System.arraycopy(rightPositions[SquareBracket], 0, (rightPositions[SquareBracket] = new int[index * 2]), 0, index);
3980               System.arraycopy(rightDepths[SquareBracket], 0, (rightDepths[SquareBracket] = new int[index * 2]), 0, index);
3981             }
3982             rightPositions[SquareBracket][index] = scanner.startPosition;
3983             rightDepths[SquareBracket][index] = --depths[SquareBracket];
3984           }
3985             break;
3986           case '\'': {
3987             if (scanner.getNextChar('\\')) {
3988               scanner.scanEscapeCharacter();
3989             } else { // consume next character
3990               scanner.unicodeAsBackSlash = false;
3991               //                                                                        if (((scanner.currentCharacter =
3992               // source[scanner.currentPosition++]) ==
3993               // '\\') &&
3994               // (source[scanner.currentPosition] ==
3995               // 'u')) {
3996               //                                                                                scanner.getNextUnicodeChar();
3997               //                                                                        } else {
3998               if (scanner.withoutUnicodePtr != 0) {
3999                 scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
4000               }
4001               //                                                                        }
4002             }
4003             scanner.getNextChar('\'');
4004             break;
4005           }
4006           case '"':
4007             // consume next character
4008             scanner.unicodeAsBackSlash = false;
4009             //                                                  if (((scanner.currentCharacter =
4010             // source[scanner.currentPosition++]) == '\\') &&
4011             // (source[scanner.currentPosition] == 'u')) {
4012             //                                                          scanner.getNextUnicodeChar();
4013             //                                                  } else {
4014             if (scanner.withoutUnicodePtr != 0) {
4015               scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
4016             }
4017             //                                                  }
4018             while (scanner.currentCharacter != '"') {
4019               if (scanner.currentCharacter == '\r') {
4020                 if (source[scanner.currentPosition] == '\n')
4021                   scanner.currentPosition++;
4022                 break; // the string cannot go further that
4023                 // the line
4024               }
4025               if (scanner.currentCharacter == '\n') {
4026                 break; // the string cannot go further that
4027                 // the line
4028               }
4029               if (scanner.currentCharacter == '\\') {
4030                 scanner.scanEscapeCharacter();
4031               }
4032               // consume next character
4033               scanner.unicodeAsBackSlash = false;
4034               //                                                                if (((scanner.currentCharacter =
4035               // source[scanner.currentPosition++]) == '\\')
4036               // && (source[scanner.currentPosition] == 'u'))
4037               // {
4038               //                                                                        scanner.getNextUnicodeChar();
4039               //                                                                } else {
4040               if (scanner.withoutUnicodePtr != 0) {
4041                 scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
4042               }
4043               //                                                                }
4044             }
4045             break;
4046           case '/': {
4047             int test;
4048             if ((test = scanner.getNextChar('/', '*')) == 0) { //line
4049               // comment
4050               //get the next char
4051               if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
4052                   && (source[scanner.currentPosition] == 'u')) {
4053                 //-------------unicode traitement
4054                 // ------------
4055                 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4056                 scanner.currentPosition++;
4057                 while (source[scanner.currentPosition] == 'u') {
4058                   scanner.currentPosition++;
4059                 }
4060                 if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0
4061                     || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0
4062                     || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0
4063                     || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error
4064                   // don't
4065                   // care of the
4066                   // value
4067                   scanner.currentCharacter = 'A';
4068                 } //something different from \n and \r
4069                 else {
4070                   scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4071                 }
4072               }
4073               while (scanner.currentCharacter != '\r' && scanner.currentCharacter != '\n') {
4074                 //get the next char
4075                 scanner.startPosition = scanner.currentPosition;
4076                 if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
4077                     && (source[scanner.currentPosition] == 'u')) {
4078                   //-------------unicode traitement
4079                   // ------------
4080                   int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4081                   scanner.currentPosition++;
4082                   while (source[scanner.currentPosition] == 'u') {
4083                     scanner.currentPosition++;
4084                   }
4085                   if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0
4086                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0
4087                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0
4088                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error
4089                     // don't
4090                     // care of the
4091                     // value
4092                     scanner.currentCharacter = 'A';
4093                   } //something different from \n
4094                   // and \r
4095                   else {
4096                     scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4097                   }
4098                 }
4099               }
4100               if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
4101                 if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
4102                   // only record line positions we
4103                   // have not recorded yet
4104                   scanner.pushLineSeparator();
4105                   if (this.scanner.taskTags != null) {
4106                     this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner
4107                         .getCurrentTokenEndPosition());
4108                   }
4109                 }
4110               }
4111               break;
4112             }
4113             if (test > 0) { //traditional and annotation
4114               // comment
4115               boolean star = false;
4116               // consume next character
4117               scanner.unicodeAsBackSlash = false;
4118               //                                                                        if (((scanner.currentCharacter =
4119               // source[scanner.currentPosition++]) ==
4120               // '\\') &&
4121               // (source[scanner.currentPosition] ==
4122               // 'u')) {
4123               //                                                                                scanner.getNextUnicodeChar();
4124               //                                                                        } else {
4125               if (scanner.withoutUnicodePtr != 0) {
4126                 scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
4127               }
4128               //                                                                        }
4129               if (scanner.currentCharacter == '*') {
4130                 star = true;
4131               }
4132               //get the next char
4133               if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
4134                   && (source[scanner.currentPosition] == 'u')) {
4135                 //-------------unicode traitement
4136                 // ------------
4137                 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4138                 scanner.currentPosition++;
4139                 while (source[scanner.currentPosition] == 'u') {
4140                   scanner.currentPosition++;
4141                 }
4142                 if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0
4143                     || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0
4144                     || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0
4145                     || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error
4146                   // don't
4147                   // care of the
4148                   // value
4149                   scanner.currentCharacter = 'A';
4150                 } //something different from * and /
4151                 else {
4152                   scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4153                 }
4154               }
4155               //loop until end of comment */
4156               while ((scanner.currentCharacter != '/') || (!star)) {
4157                 star = scanner.currentCharacter == '*';
4158                 //get next char
4159                 if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
4160                     && (source[scanner.currentPosition] == 'u')) {
4161                   //-------------unicode traitement
4162                   // ------------
4163                   int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4164                   scanner.currentPosition++;
4165                   while (source[scanner.currentPosition] == 'u') {
4166                     scanner.currentPosition++;
4167                   }
4168                   if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0
4169                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0
4170                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0
4171                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error
4172                     // don't
4173                     // care of the
4174                     // value
4175                     scanner.currentCharacter = 'A';
4176                   } //something different from * and
4177                   // /
4178                   else {
4179                     scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4180                   }
4181                 }
4182               }
4183               if (this.scanner.taskTags != null) {
4184                 this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
4185               }
4186               break;
4187             }
4188             break;
4189           }
4190           default:
4191             if (Scanner.isPHPIdentifierStart(scanner.currentCharacter)) {
4192               scanner.scanIdentifierOrKeyword(false);
4193               break;
4194             }
4195             if (Character.isDigit(scanner.currentCharacter)) {
4196               scanner.scanNumber(false);
4197               break;
4198             }
4199           }
4200           //-----------------end switch while
4201           // try--------------------
4202         } catch (IndexOutOfBoundsException e) {
4203           break; // read until EOF
4204         } catch (InvalidInputException e) {
4205           return false; // no clue
4206         }
4207       }
4208       if (scanner.recordLineSeparator) {
4209         //                              compilationUnit.compilationResult.lineSeparatorPositions =
4210         // scanner.getLineEnds();
4211       }
4212       // check placement anomalies against other kinds of brackets
4213       for (int kind = 0; kind < BracketKinds; kind++) {
4214         for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) {
4215           int start = leftPositions[kind][leftIndex]; // deepest
4216           // first
4217           // find matching closing bracket
4218           int depth = leftDepths[kind][leftIndex];
4219           int end = -1;
4220           for (int i = 0; i < rightCount[kind]; i++) {
4221             int pos = rightPositions[kind][i];
4222             // want matching bracket further in source with same
4223             // depth
4224             if ((pos > start) && (depth == rightDepths[kind][i])) {
4225               end = pos;
4226               break;
4227             }
4228           }
4229           if (end < 0) { // did not find a good closing match
4230             problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult);
4231             return true;
4232           }
4233           // check if even number of opening/closing other brackets
4234           // in between this pair of brackets
4235           int balance = 0;
4236           for (int otherKind = 0; (balance == 0) && (otherKind < BracketKinds); otherKind++) {
4237             for (int i = 0; i < leftCount[otherKind]; i++) {
4238               int pos = leftPositions[otherKind][i];
4239               if ((pos > start) && (pos < end))
4240                 balance++;
4241             }
4242             for (int i = 0; i < rightCount[otherKind]; i++) {
4243               int pos = rightPositions[otherKind][i];
4244               if ((pos > start) && (pos < end))
4245                 balance--;
4246             }
4247             if (balance != 0) {
4248               problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult); //bracket
4249               // anomaly
4250               return true;
4251             }
4252           }
4253         }
4254         // too many opening brackets ?
4255         for (int i = rightCount[kind]; i < leftCount[kind]; i++) {
4256           anomaliesDetected = true;
4257           problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i - 1], referenceContext,
4258               compilationUnit.compilationResult);
4259         }
4260         // too many closing brackets ?
4261         for (int i = leftCount[kind]; i < rightCount[kind]; i++) {
4262           anomaliesDetected = true;
4263           problemReporter.unmatchedBracket(rightPositions[kind][i], referenceContext, compilationUnit.compilationResult);
4264         }
4265         if (anomaliesDetected)
4266           return true;
4267       }
4268       return anomaliesDetected;
4269     } catch (ArrayStoreException e) { // jdk1.2.2 jit bug
4270       return anomaliesDetected;
4271     } catch (NullPointerException e) { // jdk1.2.2 jit bug
4272       return anomaliesDetected;
4273     }
4274   }
4275
4276   protected void pushOnAstLengthStack(int pos) {
4277     try {
4278       astLengthStack[++astLengthPtr] = pos;
4279     } catch (IndexOutOfBoundsException e) {
4280       int oldStackLength = astLengthStack.length;
4281       int[] oldPos = astLengthStack;
4282       astLengthStack = new int[oldStackLength + StackIncrement];
4283       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
4284       astLengthStack[astLengthPtr] = pos;
4285     }
4286   }
4287
4288   protected void pushOnAstStack(ASTNode node) {
4289     /*
4290      * add a new obj on top of the ast stack
4291      */
4292     try {
4293       astStack[++astPtr] = node;
4294     } catch (IndexOutOfBoundsException e) {
4295       int oldStackLength = astStack.length;
4296       ASTNode[] oldStack = astStack;
4297       astStack = new ASTNode[oldStackLength + AstStackIncrement];
4298       System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
4299       astPtr = oldStackLength;
4300       astStack[astPtr] = node;
4301     }
4302     try {
4303       astLengthStack[++astLengthPtr] = 1;
4304     } catch (IndexOutOfBoundsException e) {
4305       int oldStackLength = astLengthStack.length;
4306       int[] oldPos = astLengthStack;
4307       astLengthStack = new int[oldStackLength + AstStackIncrement];
4308       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
4309       astLengthStack[astLengthPtr] = 1;
4310     }
4311   }
4312
4313   protected void resetModifiers() {
4314     this.modifiers = AccDefault;
4315     this.modifiersSourceStart = -1; // <-- see comment into
4316     // modifiersFlag(int)
4317     this.scanner.commentPtr = -1;
4318   }
4319
4320   protected void consumePackageDeclarationName(IFile file) {
4321     // create a package name similar to java package names
4322     String projectPath = ProjectPrefUtil.getDocumentRoot(file.getProject()).toString();
4323     String filePath = file.getRawLocation().toString();
4324     String ext = file.getRawLocation().getFileExtension();
4325     int fileExtensionLength = ext == null ? 0 : ext.length() + 1;
4326     ImportReference impt;
4327     int length;
4328     char[][] tokens;
4329     if (filePath.startsWith(projectPath)) {
4330       tokens = CharOperation
4331           .splitOn('/', filePath.toCharArray(), projectPath.length() + 1, filePath.length() - fileExtensionLength);
4332     } else {
4333       String name = file.getName();
4334       tokens = new char[1][];
4335       tokens[0] = name.substring(0, ext.length() - fileExtensionLength).toCharArray();
4336     }
4337
4338     this.compilationUnit.currentPackage = impt = new ImportReference(tokens, new char[0], 0, 0, true);
4339
4340     impt.declarationSourceStart = 0;
4341     impt.declarationSourceEnd = 0;
4342     impt.declarationEnd = 0;
4343     //endPosition is just before the ;
4344
4345   }
4346 }