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