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