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