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