KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > parser > QuercusParser


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.quercus.parser;
31
32 import com.caucho.quercus.Location;
33 import com.caucho.quercus.Quercus;
34 import com.caucho.quercus.QuercusRuntimeException;
35 import com.caucho.quercus.env.BooleanValue;
36 import com.caucho.quercus.env.CallbackFunction;
37 import com.caucho.quercus.env.DoubleValue;
38 import com.caucho.quercus.env.Env;
39 import com.caucho.quercus.env.LongValue;
40 import com.caucho.quercus.env.Value;
41 import com.caucho.quercus.expr.*;
42 import com.caucho.quercus.program.*;
43 import com.caucho.util.CharBuffer;
44 import com.caucho.util.IntMap;
45 import com.caucho.util.L10N;
46 import com.caucho.vfs.*;
47
48 import java.io.CharConversionException JavaDoc;
49 import java.io.IOException JavaDoc;
50 import java.io.Reader JavaDoc;
51 import java.util.ArrayList JavaDoc;
52
53 /**
54  * Parses a PHP program.
55  */

56 public class QuercusParser {
57   private final static L10N L = new L10N(QuercusParser.class);
58
59   private final static int M_STATIC = 0x1;
60   private final static int M_PUBLIC = 0x2;
61   private final static int M_PROTECTED = 0x4;
62   private final static int M_PRIVATE = 0x8;
63   private final static int M_FINAL = 0x10;
64   private final static int M_ABSTRACT = 0x20;
65   private final static int M_INTERFACE = 0x40;
66   
67   private final static int IDENTIFIER = 256;
68   private final static int STRING = 257;
69   private final static int LONG = 258;
70   private final static int DOUBLE = 259;
71   private final static int LSHIFT = 260;
72   private final static int RSHIFT = 261;
73   private final static int PHP_END = 262;
74   private final static int EQ = 263;
75   private final static int DEREF = 264;
76   private final static int LEQ = 268;
77   private final static int GEQ = 269;
78   private final static int NEQ = 270;
79   private final static int EQUALS = 271;
80   private final static int NEQUALS = 272;
81   private final static int C_AND = 273;
82   private final static int C_OR = 274;
83   
84   private final static int PLUS_ASSIGN = 278;
85   private final static int MINUS_ASSIGN = 279;
86   private final static int APPEND_ASSIGN = 280;
87   private final static int MUL_ASSIGN = 281;
88   private final static int DIV_ASSIGN = 282;
89   private final static int MOD_ASSIGN = 283;
90   private final static int AND_ASSIGN = 284;
91   private final static int OR_ASSIGN = 285;
92   private final static int XOR_ASSIGN = 286;
93   private final static int LSHIFT_ASSIGN = 287;
94   private final static int RSHIFT_ASSIGN = 288;
95   
96   private final static int INCR = 289;
97   private final static int DECR = 290;
98   
99   private final static int SCOPE = 291;
100   private final static int ESCAPED_STRING = 292;
101   private final static int HEREDOC = 293;
102   private final static int ARRAY_RIGHT = 294;
103   private final static int SIMPLE_STRING_ESCAPE = 295;
104   private final static int COMPLEX_STRING_ESCAPE = 296;
105
106   private final static int BINARY = 297;
107   private final static int SIMPLE_BINARY_ESCAPE = 298;
108   private final static int COMPLEX_BINARY_ESCAPE = 299;
109   
110   private final static int FIRST_IDENTIFIER_LEXEME = 512;
111   private final static int ECHO = 512;
112   private final static int NULL = 513;
113   private final static int IF = 514;
114   private final static int WHILE = 515;
115   private final static int FUNCTION = 516;
116   private final static int CLASS = 517;
117   private final static int NEW = 518;
118   private final static int RETURN = 519;
119   private final static int VAR = 520;
120   private final static int PRIVATE = 521;
121   private final static int PROTECTED = 522;
122   private final static int PUBLIC = 523;
123   private final static int FOR = 524;
124   private final static int DO = 525;
125   private final static int BREAK = 526;
126   private final static int CONTINUE = 527;
127   private final static int ELSE = 528;
128   private final static int EXTENDS = 529;
129   private final static int STATIC = 530;
130   private final static int INCLUDE = 531;
131   private final static int REQUIRE = 532;
132   private final static int INCLUDE_ONCE = 533;
133   private final static int REQUIRE_ONCE = 534;
134   private final static int UNSET = 535;
135   private final static int FOREACH = 536;
136   private final static int AS = 537;
137   private final static int TEXT = 538;
138   private final static int ISSET = 539;
139   private final static int SWITCH = 540;
140   private final static int CASE = 541;
141   private final static int DEFAULT = 542;
142   private final static int EXIT = 543;
143   private final static int GLOBAL = 544;
144   private final static int ELSEIF = 545;
145   private final static int PRINT = 546;
146   private final static int SYSTEM_STRING = 547;
147   private final static int SIMPLE_SYSTEM_STRING = 548;
148   private final static int COMPLEX_SYSTEM_STRING = 549;
149   private final static int TEXT_ECHO = 550;
150   private final static int ENDIF = 551;
151   private final static int ENDWHILE = 552;
152   private final static int ENDFOR = 553;
153   private final static int ENDFOREACH = 554;
154   private final static int ENDSWITCH = 555;
155   
156   private final static int XOR_RES = 556;
157   private final static int AND_RES = 557;
158   private final static int OR_RES = 558;
159   private final static int LIST = 559;
160   
161   private final static int THIS = 560;
162   private final static int TRUE = 561;
163   private final static int FALSE = 562;
164   private final static int CLONE = 563;
165   private final static int INSTANCEOF = 564;
166   private final static int CONST = 565;
167   private final static int ABSTRACT = 566;
168   private final static int FINAL = 567;
169   private final static int DIE = 568;
170   private final static int THROW = 569;
171   private final static int TRY = 570;
172   private final static int CATCH = 571;
173   private final static int INTERFACE = 572;
174   private final static int IMPLEMENTS = 573;
175   
176   private final static int LAST_IDENTIFIER_LEXEME = 1024;
177
178   private final static IntMap _insensitiveReserved = new IntMap();
179   private final static IntMap _reserved = new IntMap();
180
181   private Quercus _quercus;
182
183   private Path _sourceFile;
184
185   private ParserLocation _parserLocation = new ParserLocation();
186
187   private ExprFactory _factory;
188
189   private boolean _hasCr;
190
191   private int _peek = -1;
192   private Reader JavaDoc _is;
193
194   private CharBuffer _sb = new CharBuffer();
195
196   private int _peekToken = -1;
197   private String JavaDoc _lexeme = "";
198   private String JavaDoc _heredocEnd = null;
199
200   private GlobalScope _globalScope;
201
202   private boolean _returnsReference = false;
203
204   private Scope _scope;
205   private InterpretedClassDef _quercusClass;
206
207   private FunctionInfo _function;
208   
209   private boolean _isTop;
210
211   QuercusParser(Quercus quercus)
212   {
213     _quercus = quercus;
214     _factory = ExprFactory.create();
215     _globalScope = new GlobalScope(_factory);
216     _scope = _globalScope;
217   }
218
219   public QuercusParser(Quercus quercus, Path sourceFile, Reader JavaDoc is)
220   {
221     this(quercus);
222
223     init(sourceFile, is);
224   }
225
226   private void init(Path sourceFile)
227     throws IOException JavaDoc
228   {
229     init(sourceFile, sourceFile.openRead().getReader());
230   }
231
232   private void init(Path sourceFile, Reader JavaDoc is)
233   {
234     _sourceFile = sourceFile;
235     _is = is;
236
237     if (sourceFile != null)
238       _parserLocation.setFileName(sourceFile.getPath());
239     else
240       _parserLocation.setFileName("eval:");
241
242     _parserLocation.setLineNumber(1);
243
244     _peek = -1;
245     _peekToken = -1;
246   }
247
248   public void setLocation(String JavaDoc fileName, int line)
249   {
250     _parserLocation.setFileName(fileName);
251     _parserLocation.setLineNumber(line);
252   }
253   
254   public static QuercusProgram parse(Quercus quercus,
255                      Path path,
256                      String JavaDoc encoding)
257     throws IOException JavaDoc
258   {
259     ReadStream is = path.openRead();
260
261     try {
262       is.setEncoding(encoding);
263       
264       QuercusParser parser;
265       parser = new QuercusParser(quercus, path, is.getReader());
266
267       return parser.parse();
268     } finally {
269       is.close();
270     }
271   }
272   
273   public static QuercusProgram parse(Quercus quercus,
274                      Path path,
275                      String JavaDoc encoding,
276                      String JavaDoc fileName,
277                      int line)
278     throws IOException JavaDoc
279   {
280     ReadStream is = path.openRead();
281
282     try {
283       is.setEncoding(encoding);
284       
285       QuercusParser parser;
286       parser = new QuercusParser(quercus, path, is.getReader());
287
288       if (fileName != null && line >= 0)
289     parser.setLocation(fileName, line);
290
291       return parser.parse();
292     } finally {
293       is.close();
294     }
295   }
296   
297   public static QuercusProgram parse(Quercus quercus,
298                      ReadStream is)
299     throws IOException JavaDoc
300   {
301     QuercusParser parser;
302     parser = new QuercusParser(quercus, is.getPath(), is.getReader());
303
304     return parser.parse();
305   }
306   
307   public static QuercusProgram parse(Quercus quercus,
308                      Path path, Reader JavaDoc is)
309     throws IOException JavaDoc
310   {
311     return new QuercusParser(quercus, path, is).parse();
312   }
313   
314   public static QuercusProgram parseEval(Quercus quercus, String JavaDoc str)
315     throws IOException JavaDoc
316   {
317     Path path = new StringPath(str);
318
319     QuercusParser parser = new QuercusParser(quercus, path, path.openRead().getReader());
320
321     return parser.parseCode();
322   }
323   
324   public static QuercusProgram parseEvalExpr(Quercus quercus, String JavaDoc str)
325     throws IOException JavaDoc
326   {
327     Path path = new StringPath(str);
328
329     QuercusParser parser = new QuercusParser(quercus, path, path.openRead().getReader());
330
331     return parser.parseCode().createExprReturn();
332   }
333   
334   public static Value parseFunction(Quercus quercus, String JavaDoc args, String JavaDoc code)
335     throws IOException JavaDoc
336   {
337     Path argPath = new StringPath(args);
338     Path codePath = new StringPath(code);
339
340     QuercusParser parser = new QuercusParser(quercus);
341
342     Function fun = parser.parseFunction(argPath, codePath);
343
344     return new CallbackFunction(fun);
345   }
346   
347   public static Expr parse(Quercus quercus, String JavaDoc str)
348     throws IOException JavaDoc
349   {
350       Path path = new StringPath(str);
351     
352     return new QuercusParser(quercus, path, new java.io.StringReader JavaDoc(str)).parseExpr();
353   }
354   
355   public static Expr parseDefault(String JavaDoc str)
356   {
357     try {
358       Path path = new StringPath(str);
359     
360       return new QuercusParser(null, path, new java.io.StringReader JavaDoc(str)).parseExpr();
361     } catch (IOException JavaDoc e) {
362       e.printStackTrace();
363       
364       throw new QuercusRuntimeException(e);
365     }
366   }
367
368   /**
369    * Returns the current filename.
370    */

371   public String JavaDoc getFileName()
372   {
373     if (_sourceFile == null)
374       return null;
375     else
376       return _sourceFile.getPath();
377   }
378
379   /**
380    * Returns the current line
381    */

382   public int getLine()
383   {
384     return _parserLocation.getLineNumber();
385   }
386
387   public ExprFactory getExprFactory()
388   {
389     return _factory;
390   }
391
392   public ExprFactory getFactory()
393   {
394     return _factory;
395   }
396
397   public QuercusProgram parse()
398     throws IOException JavaDoc
399   {
400     _function = new FunctionInfo(_quercus, "main");
401     _function.setPageMain(true);
402
403     // quercus/0b0d
404
_function.setVariableVar(true);
405     _function.setUsesSymbolTable(true);
406     
407     Statement stmt = parseTop();
408
409     QuercusProgram program = new QuercusProgram(_quercus, _sourceFile,
410                         _globalScope.getFunctionMap(),
411                         _globalScope.getClassMap(),
412                         _function,
413                         stmt);
414     return program;
415
416     /*
417     com.caucho.vfs.WriteStream out = com.caucho.vfs.Vfs.lookup("stdout:").openWrite();
418     out.setFlushOnNewline(true);
419     stmt.debug(new JavaWriter(out));
420     */

421   }
422
423   QuercusProgram parseCode()
424     throws IOException JavaDoc
425   {
426     _function = new FunctionInfo(_quercus, "eval");
427     // XXX: need param or better function name for non-global?
428
_function.setGlobal(false);
429
430     Location location = getLocation();
431
432     ArrayList JavaDoc<Statement> stmtList = parseStatementList();
433     
434     return new QuercusProgram(_quercus, _sourceFile,
435                   _globalScope.getFunctionMap(),
436                   _globalScope.getClassMap(),
437                   _function,
438                   _factory.createBlock(location, stmtList));
439   }
440
441   Function parseFunction(Path argPath, Path codePath)
442     throws IOException JavaDoc
443   {
444     _function = new FunctionInfo(_quercus, "anonymous");
445     // XXX: need param or better function name for non-global?
446
_function.setGlobal(false);
447     _function.setPageMain(true);
448
449     init(argPath);
450
451     ArrayList JavaDoc<Arg> args = parseFunctionArgDefinition();
452       
453     init(codePath);
454       
455     ArrayList JavaDoc<Statement> statementList;
456
457     statementList = parseStatementList();
458
459     return _factory.createFunction(Location.UNKNOWN,
460                        "anonymous",
461                        _function,
462                        args,
463                        statementList);
464   }
465
466   /**
467    * Parses the top page.
468    */

469   Statement parseTop()
470     throws IOException JavaDoc
471   {
472     _isTop = true;
473     
474     ArrayList JavaDoc<Statement> statements = new ArrayList JavaDoc<Statement>();
475
476     Location location = getLocation();
477
478     int token = parsePhpText();
479
480     if (_lexeme.length() > 0)
481       statements.add(_factory.createText(location, _lexeme));
482
483     if (token == TEXT_ECHO) {
484       parseEcho(statements);
485     }
486     
487     statements.addAll(parseStatementList());
488
489     return _factory.createBlock(location, statements);
490   }
491
492   /**
493    * Parses a statement list.
494    */

495   private ArrayList JavaDoc<Statement> parseStatementList()
496     throws IOException JavaDoc
497   {
498     ArrayList JavaDoc<Statement> statements = new ArrayList JavaDoc<Statement>();
499
500     while (true) {
501       Location location = getLocation();
502
503       int token = parseToken();
504
505       switch (token) {
506       case -1:
507     return statements;
508
509       case ';':
510     break;
511
512       case ECHO:
513     parseEcho(statements);
514     break;
515
516       case PRINT:
517     statements.add(parsePrint());
518     break;
519
520       case UNSET:
521     parseUnset(statements);
522     break;
523
524       case ABSTRACT:
525       case FINAL:
526     {
527       _peekToken = token;
528
529       int modifiers = 0;
530       do {
531         token = parseToken();
532
533         switch (token) {
534         case ABSTRACT:
535           modifiers |= M_ABSTRACT;
536           break;
537         case FINAL:
538           modifiers |= M_FINAL;
539           break;
540         case CLASS:
541           parseClassDefinition(modifiers);
542           break;
543         default:
544           throw error(L.l("expected 'class' at {0}",
545                   tokenName(token)));
546         }
547       } while (token != CLASS);
548     }
549     break;
550
551       case FUNCTION:
552     {
553           Location functionLocation = getLocation();
554
555           Function fun = parseFunctionDefinition(M_STATIC);
556
557       if (! _isTop) {
558         statements.add(_factory.createFunctionDef(functionLocation, fun));
559       }
560     }
561     break;
562
563       case CLASS:
564     parseClassDefinition(0);
565     // statements.add(new ClassDefStatement(parseClassDefinition()));
566
break;
567
568       case INTERFACE:
569     parseClassDefinition(M_INTERFACE);
570     // statements.add(new ClassDefStatement(parseClassDefinition()));
571
break;
572
573       case IF:
574     statements.add(parseIf());
575     break;
576
577       case SWITCH:
578     statements.add(parseSwitch());
579     break;
580
581       case WHILE:
582     statements.add(parseWhile());
583     break;
584
585       case DO:
586     statements.add(parseDo());
587     break;
588
589       case FOR:
590     statements.add(parseFor());
591     break;
592
593       case FOREACH:
594     statements.add(parseForeach());
595     break;
596
597       case PHP_END:
598     return statements;
599
600       case RETURN:
601     statements.add(parseReturn());
602     break;
603
604       case THROW:
605     statements.add(parseThrow());
606     break;
607
608       case BREAK:
609     statements.add(_factory.createBreak());
610     break;
611
612       case CONTINUE:
613     statements.add(_factory.createContinue());
614     break;
615
616       case GLOBAL:
617     statements.add(parseGlobal());
618     break;
619     
620       case STATIC:
621     statements.add(parseStatic());
622     break;
623     
624       case TRY:
625     statements.add(parseTry());
626     break;
627
628       case '{':
629     {
630       ArrayList JavaDoc<Statement> statementList = parseStatementList();
631
632       expect('}');
633
634       statements.addAll(statementList);
635     }
636     break;
637
638       case '}':
639       case CASE:
640       case DEFAULT:
641       case ELSE:
642       case ELSEIF:
643       case ENDIF:
644       case ENDWHILE:
645       case ENDFOR:
646       case ENDFOREACH:
647       case ENDSWITCH:
648     _peekToken = token;
649     return statements;
650
651       case TEXT:
652     if (_lexeme.length() > 0) {
653       statements.add(_factory.createText(location, _lexeme));
654     }
655     break;
656     
657       case TEXT_ECHO:
658     if (_lexeme.length() > 0)
659       statements.add(_factory.createText(location, _lexeme));
660
661     parseEcho(statements);
662
663     break;
664
665       default:
666     _peekToken = token;
667     
668     statements.add(parseExprStatement());
669     break;
670       }
671     }
672   }
673
674   private Statement parseStatement()
675     throws IOException JavaDoc
676   {
677     Location location = getLocation();
678
679     int token = parseToken();
680
681     switch (token) {
682     case ';':
683       return _factory.createNullStatement();
684
685     case '{':
686       location = getLocation();
687
688       ArrayList JavaDoc<Statement> statementList = parseStatementList();
689
690       expect('}');
691
692       return _factory.createBlock(location, statementList);
693
694     case IF:
695       return parseIf();
696
697     case SWITCH:
698       return parseSwitch();
699
700     case WHILE:
701       return parseWhile();
702
703     case DO:
704       return parseDo();
705
706     case FOR:
707       return parseFor();
708
709     case FOREACH:
710       return parseForeach();
711
712     case TRY:
713       return parseTry();
714
715     case TEXT:
716       if (_lexeme.length() > 0) {
717     return _factory.createText(location, _lexeme);
718       }
719       else
720     return parseStatement();
721       
722     default:
723       Statement stmt = parseStatementImpl(token);
724
725       token = parseToken();
726       if (token != ';')
727     _peekToken = token;
728
729       return stmt;
730     }
731   }
732
733   /**
734    * Parses statements that expect to be terminated by ';'.
735    */

736   private Statement parseStatementImpl(int token)
737     throws IOException JavaDoc
738   {
739     switch (token) {
740     case ECHO:
741       {
742         Location location = getLocation();
743
744         ArrayList JavaDoc<Statement> statementList = new ArrayList JavaDoc<Statement>();
745     parseEcho(statementList);
746
747     return _factory.createBlock(location, statementList);
748       }
749
750     case PRINT:
751       return parsePrint();
752
753     case UNSET:
754       return parseUnset();
755
756     case GLOBAL:
757       return parseGlobal();
758
759     case STATIC:
760       return parseStatic();
761
762     case BREAK:
763       return _factory.createBreak();
764
765     case CONTINUE:
766       return _factory.createContinue();
767
768     case RETURN:
769       return parseReturn();
770
771     case THROW:
772       return parseThrow();
773
774     case TRY:
775       return parseTry();
776
777     default:
778       _peekToken = token;
779       return parseExprStatement();
780
781       /*
782     default:
783       throw error(L.l("unexpected token {0}.", tokenName(token)));
784       */

785     }
786   }
787
788   /**
789    * Parses the echo statement.
790    */

791   private void parseEcho(ArrayList JavaDoc<Statement> statements)
792     throws IOException JavaDoc
793   {
794     Location location = getLocation();
795
796     while (true) {
797       Expr expr = parseTopExpr();
798
799       createEchoStatements(location, statements, expr);
800
801       int token = parseToken();
802
803       if (token != ',') {
804     _peekToken = token;
805     return;
806       }
807     }
808   }
809
810   /**
811    * Creates echo statements from an expression.
812    */

813   private void createEchoStatements(Location location,
814                                     ArrayList JavaDoc<Statement> statements,
815                     Expr expr)
816   {
817     if (expr == null) {
818       // since AppendExpr.getNext() can be null.
819
}
820     else if (expr instanceof AppendExpr) {
821       AppendExpr append = (AppendExpr) expr;
822
823       // XXX: children of append print differently?
824

825       createEchoStatements(location, statements, append.getValue());
826       createEchoStatements(location, statements, append.getNext());
827     }
828     else if (expr instanceof StringLiteralExpr) {
829       StringLiteralExpr string = (StringLiteralExpr) expr;
830       
831       Statement statement
832     = _factory.createText(location, string.evalConstant().toString());
833
834       statements.add(statement);
835     }
836     else {
837       Statement statement = _factory.createEcho(location, expr);
838
839       statements.add(statement);
840     }
841   }
842
843   /**
844    * Parses the print statement.
845    */

846   private Statement parsePrint()
847     throws IOException JavaDoc
848   {
849     return _factory.createExpr(getLocation(), parsePrintExpr());
850   }
851
852   /**
853    * Parses the print statement.
854    */

855   private Expr parsePrintExpr()
856     throws IOException JavaDoc
857   {
858     ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
859     args.add(parseTopExpr());
860
861     return _factory.createFunction(getLocation(), "print", args);
862   }
863
864   /**
865    * Parses the global statement.
866    */

867   private Statement parseGlobal()
868     throws IOException JavaDoc
869   {
870     ArrayList JavaDoc<Statement> statementList = new ArrayList JavaDoc<Statement>();
871
872     Location location = getLocation();
873
874     while (true) {
875       Expr expr = parseTopExpr();
876
877       if (expr instanceof VarExpr) {
878     VarExpr var = (VarExpr) expr;
879
880     // php/3a6g, php/3a58
881
var.getVarInfo().setReference();
882
883     statementList.add(_factory.createGlobal(location, var));
884       }
885       else if (expr instanceof VarVarExpr) {
886     VarVarExpr var = (VarVarExpr) expr;
887
888     statementList.add(new VarGlobalStatement(location, var));
889       }
890       else
891     throw error(L.l("unknown expr {0} to global", expr));
892
893       // statementList.add(new ExprStatement(expr));
894

895       int token = parseToken();
896
897       if (token != ',') {
898     _peekToken = token;
899     return _factory.createBlock(location, statementList);
900       }
901     }
902   }
903
904   /**
905    * Parses the static statement.
906    */

907   private Statement parseStatic()
908     throws IOException JavaDoc
909   {
910     ArrayList JavaDoc<Statement> statementList = new ArrayList JavaDoc<Statement>();
911
912     Location location = getLocation();
913
914     while (true) {
915       expect('$');
916
917       String JavaDoc name = parseIdentifier();
918
919       VarExpr var = _factory.createVar(_function.createVar(name));
920
921       Expr init = null;
922
923       int token = parseToken();
924
925       if (token == '=') {
926     init = parseExpr();
927     token = parseToken();
928       }
929
930       var.getVarInfo().setReference();
931       statementList.add(_factory.createStatic(location, var, init));
932       
933       if (token != ',') {
934     _peekToken = token;
935     return _factory.createBlock(location, statementList);
936       }
937     }
938   }
939
940   /**
941    * Parses the unset statement.
942    */

943   private Statement parseUnset()
944     throws IOException JavaDoc
945   {
946     Location location = getLocation();
947
948     ArrayList JavaDoc<Statement> statementList = new ArrayList JavaDoc<Statement>();
949     parseUnset(statementList);
950
951     return _factory.createBlock(location, statementList);
952   }
953
954   /**
955    * Parses the unset statement.
956    */

957   private void parseUnset(ArrayList JavaDoc<Statement> statementList)
958     throws IOException JavaDoc
959   {
960     Location location = getLocation();
961
962     int token = parseToken();
963
964     if (token != '(') {
965       _peekToken = token;
966
967       statementList.add(parseTopExpr().createUnset(_factory, location));
968
969       return;
970     }
971
972     do {
973       statementList.add(parseTopExpr().createUnset(_factory, getLocation()));
974     } while ((token = parseToken()) == ',');
975
976     _peekToken = token;
977     expect(')');
978   }
979
980   /**
981    * Parses the if statement
982    */

983   private Statement parseIf()
984     throws IOException JavaDoc
985   {
986     boolean oldTop = _isTop;
987     _isTop = false;
988
989     try {
990       Location location = getLocation();
991
992       expect('(');
993
994       Expr test = parseExpr();
995
996       expect(')');
997
998       int token = parseToken();
999
1000      if (token == ':')
1001    return parseAlternateIf(test, location);
1002      else
1003    _peekToken = token;
1004
1005      Statement trueBlock = parseStatement();
1006      Statement falseBlock = null;
1007
1008      token = parseToken();
1009
1010      if (token == ELSEIF) {
1011    falseBlock = parseIf();
1012      }
1013      else if (token == ELSE) {
1014    falseBlock = parseStatement();
1015      }
1016      else
1017    _peekToken = token;
1018
1019      return _factory.createIf(location, test, trueBlock, falseBlock);
1020
1021    } finally {
1022      _isTop = oldTop;
1023    }
1024  }
1025
1026  /**
1027   * Parses the if statement
1028   */

1029  private Statement parseAlternateIf(Expr test, Location location)
1030    throws IOException JavaDoc
1031  {
1032    Statement trueBlock = _factory.createBlock(location,
1033                           parseStatementList());
1034
1035    Statement falseBlock = null;
1036
1037    int token = parseToken();
1038
1039    if (token == ELSEIF) {
1040      Location subLocation = getLocation();
1041
1042      Expr subTest = parseExpr();
1043      expect(':');
1044      
1045      falseBlock = parseAlternateIf(subTest, subLocation);
1046    }
1047    else if (token == ELSE) {
1048      expect(':');
1049      
1050      falseBlock = _factory.createBlock(getLocation(),
1051                        parseStatementList());
1052
1053      expect(ENDIF);
1054    }
1055    else {
1056      _peekToken = token;
1057      expect(ENDIF);
1058    }
1059
1060    return _factory.createIf(location, test, trueBlock, falseBlock);
1061  }
1062
1063  /**
1064   * Parses the switch statement
1065   */

1066  private Statement parseSwitch()
1067    throws IOException JavaDoc
1068  {
1069    Location location = getLocation();
1070
1071    boolean oldTop = _isTop;
1072    _isTop = false;
1073
1074    try {
1075      expect('(');
1076
1077      Expr test = parseExpr();
1078
1079      expect(')');
1080
1081      boolean isAlternate = false;
1082
1083      int token = parseToken();
1084
1085      if (token == ':')
1086    isAlternate = true;
1087      else if (token == '{')
1088    isAlternate = false;
1089      else {
1090    _peekToken = token;
1091
1092    expect('{');
1093      }
1094
1095      ArrayList JavaDoc<Expr[]> caseList = new ArrayList JavaDoc<Expr[]>();
1096      ArrayList JavaDoc<BlockStatement> blockList = new ArrayList JavaDoc<BlockStatement>();
1097
1098      ArrayList JavaDoc<Integer JavaDoc> fallThroughList = new ArrayList JavaDoc<Integer JavaDoc>();
1099      BlockStatement defaultBlock = null;
1100
1101      while ((token = parseToken()) == CASE || token == DEFAULT) {
1102        Location caseLocation = getLocation();
1103
1104    ArrayList JavaDoc<Expr> valueList = new ArrayList JavaDoc<Expr>();
1105    boolean isDefault = false;
1106      
1107    while (token == CASE || token == DEFAULT) {
1108          if (token == CASE) {
1109        Expr value = parseExpr();
1110
1111        valueList.add(value);
1112      }
1113      else
1114        isDefault = true;
1115
1116      token = parseToken();
1117      if (token == ':') {
1118      }
1119      else if (token == ';') {
1120        // XXX: warning?
1121
}
1122      else
1123        throw error("expected ':' at " + tokenName(token));
1124
1125      token = parseToken();
1126    }
1127
1128    _peekToken = token;
1129
1130    Expr []values = new Expr[valueList.size()];
1131    valueList.toArray(values);
1132
1133    ArrayList JavaDoc<Statement> newBlockList = parseStatementList();
1134
1135    for (int fallThrough : fallThroughList) {
1136      BlockStatement block = blockList.get(fallThrough);
1137
1138      boolean isDefaultBlock = block == defaultBlock;
1139
1140      block = block.append(newBlockList);
1141
1142      blockList.set(fallThrough, block);
1143
1144      if (isDefaultBlock)
1145        defaultBlock = block;
1146    }
1147      
1148    BlockStatement block
1149      = _factory.createBlockImpl(caseLocation, newBlockList);
1150
1151    if (values.length > 0) {
1152      caseList.add(values);
1153
1154      blockList.add(block);
1155    }
1156
1157    if (isDefault)
1158      defaultBlock = block;
1159
1160    if (blockList.size() > 0 &&
1161        ! fallThroughList.contains(blockList.size() - 1)) {
1162      fallThroughList.add(blockList.size() - 1);
1163    }
1164
1165      
1166    if (block.fallThrough() != Statement.FALL_THROUGH)
1167      fallThroughList.clear();
1168      }
1169
1170      _peekToken = token;
1171
1172      if (isAlternate)
1173    expect(ENDSWITCH);
1174      else
1175    expect('}');
1176
1177      return _factory.createSwitch(location, test,
1178                   caseList, blockList,
1179                   defaultBlock);
1180    } finally {
1181      _isTop = oldTop;
1182    }
1183  }
1184
1185  /**
1186   * Parses the 'while' statement
1187   */

1188  private Statement parseWhile()
1189    throws IOException JavaDoc
1190  {
1191    boolean oldTop = _isTop;
1192    _isTop = false;
1193
1194    try {
1195      Location location = getLocation();
1196
1197      expect('(');
1198
1199      Expr test = parseExpr();
1200
1201      expect(')');
1202
1203      Statement block;
1204
1205      int token = parseToken();
1206
1207      if (token == ':') {
1208    block = _factory.createBlock(getLocation(), parseStatementList());
1209
1210    expect(ENDWHILE);
1211      }
1212      else {
1213    _peekToken = token;
1214    
1215    block = parseStatement();
1216      }
1217
1218      return _factory.createWhile(location, test, block);
1219    } finally {
1220      _isTop = oldTop;
1221    }
1222  }
1223
1224  /**
1225   * Parses the 'do' statement
1226   */

1227  private Statement parseDo()
1228    throws IOException JavaDoc
1229  {
1230    boolean oldTop = _isTop;
1231    _isTop = false;
1232
1233    try {
1234      Location location = getLocation();
1235
1236      Statement block = parseStatement();
1237
1238      expect(WHILE);
1239      expect('(');
1240
1241      Expr test = parseExpr();
1242
1243      expect(')');
1244    
1245      return _factory.createDo(location, test, block);
1246    } finally {
1247      _isTop = oldTop;
1248    }
1249  }
1250
1251  /**
1252   * Parses the 'for' statement
1253   */

1254  private Statement parseFor()
1255    throws IOException JavaDoc
1256  {
1257    boolean oldTop = _isTop;
1258    _isTop = false;
1259
1260    try {
1261      Location location = getLocation();
1262
1263      expect('(');
1264
1265      Expr init = null;
1266
1267      int token = parseToken();
1268      if (token != ';') {
1269    _peekToken = token;
1270    init = parseTopCommaExpr();
1271    expect(';');
1272      }
1273
1274      Expr test = null;
1275
1276      token = parseToken();
1277      if (token != ';') {
1278    _peekToken = token;
1279    test = parseTopExpr();
1280    expect(';');
1281      }
1282
1283      Expr incr = null;
1284
1285      token = parseToken();
1286      if (token != ')') {
1287    _peekToken = token;
1288    incr = parseTopCommaExpr();
1289    expect(')');
1290      }
1291
1292      Statement block;
1293
1294      token = parseToken();
1295
1296      if (token == ':') {
1297    block = _factory.createBlock(getLocation(), parseStatementList());
1298
1299    expect(ENDFOR);
1300      }
1301      else {
1302    _peekToken = token;
1303    
1304    block = parseStatement();
1305      }
1306
1307      return _factory.createFor(location, init, test, incr, block);
1308    } finally {
1309      _isTop = oldTop;
1310    }
1311  }
1312
1313  /**
1314   * Parses the 'foreach' statement
1315   */

1316  private Statement parseForeach()
1317    throws IOException JavaDoc
1318  {
1319    boolean oldTop = _isTop;
1320    _isTop = false;
1321
1322    try {
1323      Location location = getLocation();
1324
1325      expect('(');
1326
1327      Expr objExpr = parseTopExpr();
1328
1329      expect(AS);
1330
1331      boolean isRef = false;
1332
1333      int token = parseToken();
1334      if (token == '&')
1335    isRef = true;
1336      else
1337    _peekToken = token;
1338
1339      AbstractVarExpr valueExpr = (AbstractVarExpr) parseLeftHandSide();
1340
1341      AbstractVarExpr keyVar = null;
1342      AbstractVarExpr valueVar;
1343
1344      token = parseToken();
1345
1346      if (token == ARRAY_RIGHT) {
1347    if (isRef)
1348      throw error(L.l("key reference is forbidden in foreach"));
1349    
1350    keyVar = valueExpr;
1351
1352    token = parseToken();
1353
1354    if (token == '&')
1355      isRef = true;
1356    else
1357      _peekToken = token;
1358
1359    valueVar = (AbstractVarExpr) parseLeftHandSide();
1360
1361    token = parseToken();
1362      }
1363      else
1364    valueVar = valueExpr;
1365      
1366
1367      if (token != ')')
1368    throw error(L.l("expected ')' in foreach"));
1369    
1370      Statement block;
1371
1372      token = parseToken();
1373
1374      if (token == ':') {
1375    block = _factory.createBlock(getLocation(), parseStatementList());
1376
1377    expect(ENDFOREACH);
1378      }
1379      else {
1380    _peekToken = token;
1381
1382    block = parseStatement();
1383      }
1384
1385      return _factory.createForeach(location, objExpr, keyVar,
1386                    valueVar, isRef, block);
1387    } finally {
1388      _isTop = oldTop;
1389    }
1390  }
1391
1392  /**
1393   * Parses the try statement
1394   */

1395  private Statement parseTry()
1396    throws IOException JavaDoc
1397  {
1398    boolean oldTop = _isTop;
1399    _isTop = false;
1400
1401    try {
1402      Location location = getLocation();
1403
1404      Statement block = parseStatement();
1405
1406      TryStatement stmt = _factory.createTry(location, block);
1407      
1408      int token = parseToken();
1409
1410      while (token == CATCH) {
1411    expect('(');
1412    
1413    String JavaDoc id = parseIdentifier();
1414
1415    AbstractVarExpr lhs = parseLeftHandSide();
1416    
1417    expect(')');
1418
1419    block = parseStatement();
1420
1421    stmt.addCatch(id, lhs, block);
1422
1423    token = parseToken();
1424      }
1425
1426      _peekToken = token;
1427
1428      return stmt;
1429    } finally {
1430      _isTop = oldTop;
1431    }
1432  }
1433
1434  /**
1435   * Parses a function definition
1436   */

1437  private Function parseFunctionDefinition(int modifiers)
1438    throws IOException JavaDoc
1439  {
1440    boolean oldTop = _isTop;
1441    _isTop = false;
1442    
1443    boolean oldReturnsReference = _returnsReference;
1444    FunctionInfo oldFunction = _function;
1445
1446    boolean isAbstract = (modifiers & M_ABSTRACT) != 0;
1447
1448    if (_quercusClass != null && _quercusClass.isInterface())
1449      isAbstract = true;
1450
1451    try {
1452      _returnsReference = false;
1453
1454      int token = parseToken();
1455
1456      if (token == '&')
1457    _returnsReference = true;
1458      else
1459    _peekToken = token;
1460
1461      String JavaDoc name = parseIdentifier();
1462
1463      if (isAbstract && ! _scope.isAbstract()) {
1464    if (_quercusClass != null)
1465      throw error(L.l("'{0}' may not be abstract because class {1} is not abstract.",
1466              name, _quercusClass.getName()));
1467    else
1468      throw error(L.l("'{0}' may not be abstract. Abstract functions are only allowed in abstract classes.",
1469              name));
1470      }
1471
1472      _function = new FunctionInfo(_quercus, name);
1473      _function.setDeclaringClass(_quercusClass);
1474      _function.setPageStatic(oldTop);
1475      
1476      _function.setReturnsReference(_returnsReference);
1477
1478      Location location = getLocation();
1479
1480      expect('(');
1481
1482      ArrayList JavaDoc<Arg> args = parseFunctionArgDefinition();
1483      
1484      expect(')');
1485      
1486      Function function;
1487      
1488      if (isAbstract) {
1489    expect(';');
1490
1491    function = _factory.createMethodDeclaration(location,
1492                            _quercusClass, name,
1493                            _function, args);
1494      }
1495      else {
1496    expect('{');
1497      
1498    ArrayList JavaDoc<Statement> statementList;
1499
1500    statementList = parseStatementList();
1501    
1502    expect('}');
1503
1504    if (_quercusClass != null)
1505      function = _factory.createObjectMethod(location,
1506                             _quercusClass,
1507                             name, _function,
1508                             args, statementList);
1509    else
1510      function = _factory.createFunction(location, name,
1511                         _function, args,
1512                         statementList);
1513      }
1514
1515      function.setGlobal(oldTop);
1516      function.setStatic((modifiers & M_STATIC) != 0);
1517
1518      _scope.addFunction(name, function);
1519
1520      /*
1521    com.caucho.vfs.WriteStream out = com.caucho.vfs.Vfs.lookup("stdout:").openWrite();
1522    out.setFlushOnNewline(true);
1523    function.debug(new JavaWriter(out));
1524      */

1525
1526      return function;
1527    } finally {
1528      _returnsReference = oldReturnsReference;
1529      _function = oldFunction;
1530      _isTop = oldTop;
1531    }
1532  }
1533
1534  private ArrayList JavaDoc<Arg> parseFunctionArgDefinition()
1535    throws IOException JavaDoc
1536  {
1537    ArrayList JavaDoc<Arg> args = new ArrayList JavaDoc<Arg>();
1538
1539    while (true) {
1540      int token = parseToken();
1541      boolean isReference = false;
1542
1543      // php/076b
1544
// XXX: save arg type for type checking upon function call
1545
String JavaDoc expectedClass = null;
1546      if (token != ')' &&
1547          token != '&' &&
1548          token != '$') {
1549        _peekToken = token;
1550        expectedClass = parseIdentifier();
1551        token = parseToken();
1552      }
1553
1554      if (token == '&') {
1555    isReference = true;
1556    token = parseToken();
1557      }
1558    
1559      if (token != '$') {
1560    _peekToken = token;
1561    break;
1562      }
1563      
1564      String JavaDoc argName = parseIdentifier();
1565      Expr defaultExpr = _factory.createRequired();
1566
1567      token = parseToken();
1568      if (token == '=') {
1569    // XXX: actually needs to be primitive
1570
defaultExpr = parseTerm();
1571    
1572    token = parseToken();
1573      }
1574
1575      Arg arg = new Arg(argName, defaultExpr, isReference);
1576
1577      args.add(arg);
1578
1579      VarInfo var = _function.createVar(argName);
1580      var.setArgument(true);
1581      var.setArgumentIndex(args.size() - 1);
1582
1583      if (isReference)
1584    var.setRefArgument();
1585      
1586      if (token != ',') {
1587    _peekToken = token;
1588    break;
1589      }
1590    }
1591
1592    return args;
1593  }
1594
1595  /**
1596   * Parses the 'return' statement
1597   */

1598  private Statement parseReturn()
1599    throws IOException JavaDoc
1600  {
1601    Location location = getLocation();
1602
1603    int token = parseToken();
1604
1605    switch (token) {
1606    case ';':
1607      _peekToken = token;
1608
1609      return _factory.createReturn(location, _factory.createNull());
1610      
1611    default:
1612      _peekToken = token;
1613
1614      Expr expr = parseTopExpr();
1615
1616      /*
1617      if (_returnsReference)
1618    expr = expr.createRef();
1619      else
1620    expr = expr.createCopy();
1621      */

1622
1623      if (_returnsReference)
1624    return _factory.createReturnRef(location, expr);
1625      else
1626    return _factory.createReturn(location, expr);
1627    }
1628  }
1629
1630  /**
1631   * Parses the 'throw' statement
1632   */

1633  private Statement parseThrow()
1634    throws IOException JavaDoc
1635  {
1636    Location location = getLocation();
1637    
1638    Expr expr = parseExpr();
1639
1640    return _factory.createThrow(location, expr);
1641  }
1642
1643  /**
1644   * Parses a class definition
1645   */

1646  private Statement parseClassDefinition(int modifiers)
1647    throws IOException JavaDoc
1648  {
1649    String JavaDoc name = parseIdentifier();
1650
1651    String JavaDoc parentName = null;
1652
1653    int token = parseToken();
1654    if (token == EXTENDS) {
1655      parentName = parseIdentifier();
1656      token = parseToken();
1657    }
1658
1659    ArrayList JavaDoc<String JavaDoc> ifaceList = new ArrayList JavaDoc<String JavaDoc>();
1660
1661    if (token == IMPLEMENTS) {
1662      do {
1663    ifaceList.add(parseIdentifier());
1664
1665    token = parseToken();
1666      } while (token == ',');
1667    }
1668
1669    _peekToken = token;
1670
1671    InterpretedClassDef oldClass = _quercusClass;
1672    Scope oldScope = _scope;
1673
1674    try {
1675      _quercusClass = oldScope.addClass(name, parentName, ifaceList);
1676
1677      if ((modifiers & M_ABSTRACT) != 0)
1678    _quercusClass.setAbstract(true);
1679      if ((modifiers & M_INTERFACE) != 0)
1680    _quercusClass.setInterface(true);
1681    
1682      _scope = new ClassScope(_quercusClass);
1683
1684      expect('{');
1685
1686      parseClassContents();
1687
1688      expect('}');
1689
1690      return _factory.createClassDef(getLocation(), _quercusClass);
1691    } finally {
1692      _quercusClass = oldClass;
1693      _scope = oldScope;
1694    }
1695  }
1696
1697  /**
1698   * Parses a statement list.
1699   */

1700  private void parseClassContents()
1701    throws IOException JavaDoc
1702  {
1703    while (true) {
1704      int token = parseToken();
1705
1706      switch (token) {
1707      case ';':
1708    break;
1709
1710      case FUNCTION:
1711    {
1712          Function fun = parseFunctionDefinition(0);
1713      fun.setStatic(false);
1714      break;
1715    }
1716
1717      case CLASS:
1718    parseClassDefinition(0);
1719    break;
1720
1721    /* quercus/0260
1722      case VAR:
1723    parseClassVarDefinition(false);
1724    break;
1725    */

1726
1727      case CONST:
1728    parseClassConstDefinition();
1729    break;
1730
1731      case PUBLIC:
1732      case PRIVATE:
1733      case PROTECTED:
1734      case STATIC:
1735      case FINAL:
1736      case ABSTRACT:
1737    {
1738      _peekToken = token;
1739
1740      int modifiers = parseModifiers();
1741      
1742      int token2 = parseToken();
1743
1744      if (token2 == FUNCTION) {
1745        Function fun = parseFunctionDefinition(modifiers);
1746      }
1747      else {
1748        _peekToken = token2;
1749        
1750        parseClassVarDefinition((modifiers & M_STATIC) != 0);
1751      }
1752    }
1753    break;
1754
1755      case IDENTIFIER:
1756    if (_lexeme.equals("var")) {
1757      parseClassVarDefinition(false);
1758    }
1759    else {
1760      _peekToken = token;
1761      return;
1762    }
1763    break;
1764
1765      case -1:
1766      case '}':
1767      default:
1768    _peekToken = token;
1769    return;
1770      }
1771    }
1772  }
1773
1774  /**
1775   * Parses a function definition
1776   */

1777  private void parseClassVarDefinition(boolean isStatic)
1778    throws IOException JavaDoc
1779  {
1780    int token;
1781    
1782    do {
1783      expect('$');
1784      String JavaDoc name = parseIdentifier();
1785
1786      token = parseToken();
1787
1788      Expr expr = null;
1789
1790      if (token == '=') {
1791    expr = parseExpr();
1792      }
1793      else {
1794    _peekToken = token;
1795    expr = _factory.createNull();
1796      }
1797
1798      if (isStatic)
1799    ((ClassScope) _scope).addStaticVar(name, expr);
1800      else
1801    ((ClassScope) _scope).addVar(name, expr);
1802
1803      token = parseToken();
1804    } while (token == ',');
1805
1806    _peekToken = token;
1807  }
1808
1809  /**
1810   * Parses a const definition
1811   */

1812  private void parseClassConstDefinition()
1813    throws IOException JavaDoc
1814  {
1815    int token;
1816    
1817    do {
1818      String JavaDoc name = parseIdentifier();
1819      
1820      expect('=');
1821
1822      Expr expr = parseExpr();
1823
1824      ((ClassScope) _scope).addConstant(name, expr);
1825
1826      token = parseToken();
1827    } while (token == ',');
1828
1829    _peekToken = token;
1830  }
1831
1832  private int parseModifiers()
1833    throws IOException JavaDoc
1834  {
1835    int token;
1836    int modifiers = 0;
1837
1838    while (true) {
1839      token = parseToken();
1840
1841      switch (token) {
1842      case PUBLIC:
1843    modifiers |= M_PUBLIC;
1844    break;
1845
1846      case PRIVATE:
1847    modifiers |= M_PRIVATE;
1848    break;
1849
1850      case PROTECTED:
1851    modifiers |= M_PROTECTED;
1852    break;
1853
1854      case FINAL:
1855    modifiers |= M_FINAL;
1856    break;
1857
1858      case STATIC:
1859    modifiers |= M_STATIC;
1860    break;
1861
1862      case ABSTRACT:
1863    modifiers |= M_ABSTRACT;
1864    break;
1865
1866      default:
1867    _peekToken = token;
1868    return modifiers;
1869      }
1870    }
1871  }
1872
1873  /**
1874   * Parses an expression statement.
1875   */

1876  private Statement parseExprStatement()
1877    throws IOException JavaDoc
1878  {
1879    Location location = getLocation();
1880
1881    Expr expr = parseTopExpr();
1882
1883    Statement statement = _factory.createExpr(location, expr);
1884
1885    int token = parseToken();
1886    _peekToken = token;
1887
1888    switch (token) {
1889    case -1:
1890    case ';':
1891    case '}':
1892    case PHP_END:
1893    case TEXT:
1894    case TEXT_ECHO:
1895      break;
1896
1897    default:
1898      expect(';');
1899      break;
1900    }
1901    
1902    return statement;
1903  }
1904
1905  /**
1906   * Parses a top expression.
1907   */

1908  private Expr parseTopExpr()
1909    throws IOException JavaDoc
1910  {
1911    return parseExpr();
1912  }
1913
1914  /**
1915   * Parses a top expression.
1916   */

1917  private Expr parseTopCommaExpr()
1918    throws IOException JavaDoc
1919  {
1920    return parseCommaExpr();
1921  }
1922
1923  /**
1924   * Parses a comma expression.
1925   */

1926  private Expr parseCommaExpr()
1927    throws IOException JavaDoc
1928  {
1929    Expr expr = parseExpr();
1930
1931    while (true) {
1932      int token = parseToken();
1933
1934      switch (token) {
1935      case ',':
1936    expr = _factory.createComma(expr, parseExpr());
1937    break;
1938      default:
1939    _peekToken = token;
1940    return expr;
1941      }
1942    }
1943  }
1944
1945  /**
1946   * Parses an expression with optional '&'.
1947   */

1948  private Expr parseRefExpr()
1949    throws IOException JavaDoc
1950  {
1951    int token = parseToken();
1952
1953    boolean isRef = token == '&';
1954
1955    if (! isRef)
1956      _peekToken = token;
1957    
1958    Expr expr = parseExpr();
1959
1960    if (isRef)
1961      expr = _factory.createRef(expr);
1962
1963    return expr;
1964  }
1965
1966  /**
1967   * Parses an expression.
1968   */

1969  private Expr parseExpr()
1970    throws IOException JavaDoc
1971  {
1972    return parseWeakOrExpr();
1973  }
1974
1975  /**
1976   * Parses a logical xor expression.
1977   */

1978  private Expr parseWeakOrExpr()
1979    throws IOException JavaDoc
1980  {
1981    Expr expr = parseWeakXorExpr();
1982
1983    while (true) {
1984      int token = parseToken();
1985
1986      switch (token) {
1987      case OR_RES:
1988    expr = _factory.createOr(expr, parseWeakXorExpr());
1989    break;
1990      default:
1991    _peekToken = token;
1992    return expr;
1993      }
1994    }
1995  }
1996
1997  /**
1998   * Parses a logical xor expression.
1999   */

2000  private Expr parseWeakXorExpr()
2001    throws IOException JavaDoc
2002  {
2003    Expr expr = parseWeakAndExpr();
2004
2005    while (true) {
2006      int token = parseToken();
2007
2008      switch (token) {
2009      case XOR_RES:
2010    expr = _factory.createXor(expr, parseWeakAndExpr());
2011    break;
2012      default:
2013    _peekToken = token;
2014    return expr;
2015      }
2016    }
2017  }
2018
2019  /**
2020   * Parses a logical and expression.
2021   */

2022  private Expr parseWeakAndExpr()
2023    throws IOException JavaDoc
2024  {
2025    Expr expr = parseConditionalExpr();
2026
2027    while (true) {
2028      int token = parseToken();
2029
2030      switch (token) {
2031      case AND_RES:
2032    expr = _factory.createAnd(expr, parseConditionalExpr());
2033    break;
2034      default:
2035    _peekToken = token;
2036    return expr;
2037      }
2038    }
2039  }
2040
2041  /**
2042   * Parses a conditional expression.
2043   */

2044  private Expr parseConditionalExpr()
2045    throws IOException JavaDoc
2046  {
2047    Expr expr = parseOrExpr();
2048
2049    while (true) {
2050      int token = parseToken();
2051
2052      switch (token) {
2053      case '?':
2054    Expr trueExpr = parseExpr();
2055    expect(':');
2056    // php/33c1
2057
expr = _factory.createConditional(expr, trueExpr, parseOrExpr());
2058    break;
2059      default:
2060    _peekToken = token;
2061    return expr;
2062      }
2063    }
2064  }
2065
2066  /**
2067   * Parses a logical or expression.
2068   */

2069  private Expr parseOrExpr()
2070    throws IOException JavaDoc
2071  {
2072    Expr expr = parseAndExpr();
2073
2074    while (true) {
2075      int token = parseToken();
2076
2077      switch (token) {
2078      case C_OR:
2079    expr = _factory.createOr(expr, parseAndExpr());
2080    break;
2081      default:
2082    _peekToken = token;
2083    return expr;
2084      }
2085    }
2086  }
2087
2088  /**
2089   * Parses a logical and expression.
2090   */

2091  private Expr parseAndExpr()
2092    throws IOException JavaDoc
2093  {
2094    Expr expr = parseBitOrExpr();
2095
2096    while (true) {
2097      int token = parseToken();
2098
2099      switch (token) {
2100      case C_AND:
2101    expr = _factory.createAnd(expr, parseBitOrExpr());
2102    break;
2103      default:
2104    _peekToken = token;
2105    return expr;
2106      }
2107    }
2108  }
2109
2110  /**
2111   * Parses a bit or expression.
2112   */

2113  private Expr parseBitOrExpr()
2114    throws IOException JavaDoc
2115  {
2116    Expr expr = parseBitXorExpr();
2117
2118    while (true) {
2119      int token = parseToken();
2120
2121      switch (token) {
2122      case '|':
2123    expr = _factory.createBitOr(expr, parseBitXorExpr());
2124    break;
2125      default:
2126    _peekToken = token;
2127    return expr;
2128      }
2129    }
2130  }
2131
2132  /**
2133   * Parses a bit xor expression.
2134   */

2135  private Expr parseBitXorExpr()
2136    throws IOException JavaDoc
2137  {
2138    Expr expr = parseBitAndExpr();
2139
2140    while (true) {
2141      int token = parseToken();
2142
2143      switch (token) {
2144      case '^':
2145    expr = _factory.createBitXor(expr, parseBitAndExpr());
2146    break;
2147      default:
2148    _peekToken = token;
2149    return expr;
2150      }
2151    }
2152  }
2153
2154  /**
2155   * Parses a bit and expression.
2156   */

2157  private Expr parseBitAndExpr()
2158    throws IOException JavaDoc
2159  {
2160    Expr expr = parseEqExpr();
2161
2162    while (true) {
2163      int token = parseToken();
2164
2165      switch (token) {
2166      case '&':
2167    expr = _factory.createBitAnd(expr, parseEqExpr());
2168    break;
2169      default:
2170    _peekToken = token;
2171    return expr;
2172      }
2173    }
2174  }
2175
2176  /**
2177   * Parses a comparison expression.
2178   */

2179  private Expr parseEqExpr()
2180    throws IOException JavaDoc
2181  {
2182    Expr expr = parseCmpExpr();
2183
2184    int token = parseToken();
2185
2186    switch (token) {
2187    case EQ:
2188      return _factory.createEq(expr, parseCmpExpr());
2189      
2190    case NEQ:
2191      return _factory.createNeq(expr, parseCmpExpr());
2192      
2193    case EQUALS:
2194      return _factory.createEquals(expr, parseCmpExpr());
2195      
2196    case NEQUALS:
2197      return _factory.createNot(_factory.createEquals(expr, parseCmpExpr()));
2198      
2199    default:
2200      _peekToken = token;
2201      return expr;
2202    }
2203  }
2204
2205  /**
2206   * Parses a comparison expression.
2207   */

2208  private Expr parseCmpExpr()
2209    throws IOException JavaDoc
2210  {
2211    Expr expr = parseShiftExpr();
2212
2213    int token = parseToken();
2214
2215    switch (token) {
2216    case '<':
2217      return _factory.createLt(expr, parseShiftExpr());
2218
2219    case '>':
2220      return _factory.createGt(expr, parseShiftExpr());
2221
2222    case LEQ:
2223      return _factory.createLeq(expr, parseShiftExpr());
2224
2225    case GEQ:
2226      return _factory.createGeq(expr, parseShiftExpr());
2227
2228    case INSTANCEOF:
2229      Location location = getLocation();
2230
2231      token = parseToken();
2232      _peekToken = token;
2233
2234      if (token == '$')
2235        return _factory.createInstanceOfVar(expr, parseShiftExpr());
2236      else
2237        return _factory.createInstanceOf(expr, parseIdentifier());
2238      
2239    default:
2240      _peekToken = token;
2241      return expr;
2242    }
2243  }
2244
2245  /**
2246   * Parses a left/right shift expression.
2247   */

2248  private Expr parseShiftExpr()
2249    throws IOException JavaDoc
2250  {
2251    Expr expr = parseAddExpr();
2252
2253    while (true) {
2254      int token = parseToken();
2255
2256      switch (token) {
2257      case LSHIFT:
2258    expr = _factory.createLeftShift(expr, parseAddExpr());
2259    break;
2260      case RSHIFT:
2261    expr = _factory.createRightShift(expr, parseAddExpr());
2262    break;
2263      default:
2264    _peekToken = token;
2265    return expr;
2266      }
2267    }
2268  }
2269
2270  /**
2271   * Parses an add/substract expression.
2272   */

2273  private Expr parseAddExpr()
2274    throws IOException JavaDoc
2275  {
2276    Expr expr = parseMulExpr();
2277
2278    while (true) {
2279      int token = parseToken();
2280
2281      switch (token) {
2282      case '+':
2283    expr = _factory.createAdd(expr, parseMulExpr());
2284    break;
2285      case '-':
2286    expr = _factory.createSub(expr, parseMulExpr());
2287    break;
2288      case '.':
2289    expr = _factory.createAppend(expr, parseMulExpr());
2290    break;
2291      default:
2292    _peekToken = token;
2293    return expr;
2294      }
2295    }
2296  }
2297
2298  /**
2299   * Parses a multiplication/division expression.
2300   */

2301  private Expr parseMulExpr()
2302    throws IOException JavaDoc
2303  {
2304    Expr expr = parseAssignExpr();
2305
2306    while (true) {
2307      int token = parseToken();
2308
2309      switch (token) {
2310      case '*':
2311    expr = _factory.createMul(expr, parseAssignExpr());
2312    break;
2313      case '/':
2314    expr = _factory.createDiv(expr, parseAssignExpr());
2315    break;
2316      case '%':
2317    expr = _factory.createMod(expr, parseAssignExpr());
2318    break;
2319      default:
2320    _peekToken = token;
2321    return expr;
2322      }
2323    }
2324  }
2325
2326  /**
2327   * Parses an assignment expression.
2328   */

2329  private Expr parseAssignExpr()
2330    throws IOException JavaDoc
2331  {
2332    Expr expr = parseTerm();
2333
2334    while (true) {
2335      int token = parseToken();
2336
2337      switch (token) {
2338      case '=':
2339    token = parseToken();
2340    
2341    try {
2342      if (token == '&') {
2343        // php/03d6
2344
expr = expr.createAssignRef(this,
2345                                        parseBitOrExpr());
2346      }
2347      else {
2348        _peekToken = token;
2349        expr = expr.createAssign(this, parseConditionalExpr());
2350      }
2351    } catch (QuercusParseException e) {
2352      throw e;
2353    } catch (IOException JavaDoc e) {
2354      throw error(e.getMessage());
2355    }
2356    break;
2357    
2358      case PLUS_ASSIGN:
2359    if (expr.canRead())
2360      expr = expr.createAssign(this,
2361                                   _factory.createAdd(expr.createCopy(_factory),
2362                              parseConditionalExpr()));
2363    else // php/03d4
2364
expr = expr.createAssign(this, parseConditionalExpr());
2365    break;
2366    
2367      case MINUS_ASSIGN:
2368    if (expr.canRead())
2369      expr = expr.createAssign(this,
2370                                   _factory.createSub(expr.createCopy(_factory),
2371                              parseConditionalExpr()));
2372    else
2373      expr = expr.createAssign(this, parseConditionalExpr());
2374    break;
2375    
2376      case APPEND_ASSIGN:
2377    if (expr.canRead())
2378      expr = expr.createAssign(this,
2379                   _factory.createAppend(expr.createCopy(_factory),
2380                                                           parseConditionalExpr()));
2381    else
2382      expr = expr.createAssign(this, parseConditionalExpr());
2383    break;
2384    
2385      case MUL_ASSIGN:
2386    if (expr.canRead())
2387      expr = expr.createAssign(this,
2388                                   _factory.createMul(expr.createCopy(_factory),
2389                                               parseConditionalExpr()));
2390    else
2391      expr = expr.createAssign(this, parseConditionalExpr());
2392    break;
2393    
2394      case DIV_ASSIGN:
2395    if (expr.canRead())
2396      expr = expr.createAssign(this,
2397                                   _factory.createDiv(expr.createCopy(_factory),
2398                                               parseConditionalExpr()));
2399    else
2400      expr = expr.createAssign(this, parseConditionalExpr());
2401    break;
2402    
2403      case MOD_ASSIGN:
2404    if (expr.canRead())
2405      expr = expr.createAssign(this,
2406                                   _factory.createMod(expr.createCopy(_factory),
2407                                               parseConditionalExpr()));
2408    else
2409      expr = expr.createAssign(this, parseConditionalExpr());
2410    break;
2411    
2412      case LSHIFT_ASSIGN:
2413    if (expr.canRead())
2414      expr = expr.createAssign(this,
2415                                   _factory.createLeftShift(expr.createCopy(_factory),
2416                                                     parseConditionalExpr()));
2417    else
2418      expr = expr.createAssign(this, parseConditionalExpr());
2419    break;
2420    
2421      case RSHIFT_ASSIGN:
2422    if (expr.canRead())
2423      expr = expr.createAssign(this,
2424                                   _factory.createRightShift(expr.createCopy(_factory),
2425                                 parseConditionalExpr()));
2426    else
2427      expr = expr.createAssign(this, parseConditionalExpr());
2428    break;
2429    
2430      case AND_ASSIGN:
2431    if (expr.canRead())
2432      expr = expr.createAssign(this,
2433                                   _factory.createBitAnd(expr.createCopy(_factory),
2434                             parseConditionalExpr()));
2435    else
2436      expr = expr.createAssign(this, parseConditionalExpr());
2437    break;
2438    
2439      case OR_ASSIGN:
2440    if (expr.canRead())
2441      expr = expr.createAssign(this,
2442                                   _factory.createBitOr(expr.createCopy(_factory),
2443                            parseConditionalExpr()));
2444    else
2445      expr = expr.createAssign(this, parseConditionalExpr());
2446    break;
2447    
2448      case XOR_ASSIGN:
2449    if (expr.canRead())
2450      expr = expr.createAssign(this,
2451                                   _factory.createBitXor(expr.createCopy(_factory),
2452                                                  parseConditionalExpr()));
2453    else
2454      expr = expr.createAssign(this, parseConditionalExpr());
2455    break;
2456    
2457      default:
2458    _peekToken = token;
2459    return expr;
2460      }
2461    }
2462  }
2463
2464  /**
2465   * Parses a basic term.
2466   *
2467   * <pre>
2468   * term ::= termBase
2469   * ::= term '[' index ']'
2470   * ::= term '{' index '}'
2471   * ::= term '(' index ')'
2472   * </pre>
2473   */

2474  private Expr parseTerm()
2475    throws IOException JavaDoc
2476  {
2477    Expr term = parseTermBase();
2478
2479    while (true) {
2480      int token = parseToken();
2481
2482      switch (token) {
2483      case '[':
2484        {
2485      token = parseToken();
2486      
2487      if (token == ']') {
2488        term = _factory.createArrayTail(term);
2489      }
2490      else {
2491        _peekToken = token;
2492        Expr index = parseExpr();
2493        token = parseToken();
2494
2495        term = _factory.createArrayGet(term, index);
2496      }
2497
2498          if (token != ']')
2499            throw expect("']'", token);
2500        }
2501        break;
2502    
2503      case '{':
2504        {
2505          Expr index = parseExpr();
2506
2507      expect('}');
2508
2509          term = _factory.createCharAt(term, index);
2510        }
2511        break;
2512
2513      case INCR:
2514    term = _factory.createPostIncrement(term, 1);
2515    break;
2516
2517      case DECR:
2518    term = _factory.createPostIncrement(term, -1);
2519    break;
2520
2521      case DEREF:
2522    term = parseDeref(term);
2523        break;
2524
2525      case '(':
2526    _peek = token;
2527    term = parseFunction(term);
2528        break;
2529
2530      default:
2531        _peekToken = token;
2532        return term;
2533      }
2534    }
2535  }
2536
2537  /**
2538   * Parses a basic term.
2539   *
2540   * <pre>
2541   * term ::= termBase
2542   * ::= term '[' index ']'
2543   * ::= term '{' index '}'
2544   * ::= term '->' field;
2545   * </pre>
2546   *
2547   * No function, though.
2548   */

2549  private Expr parseTermDeref()
2550    throws IOException JavaDoc
2551  {
2552    Expr term = parseTermBase();
2553
2554    while (true) {
2555      int token = parseToken();
2556
2557      switch (token) {
2558      case '[':
2559        {
2560      token = parseToken();
2561      
2562      if (token == ']') {
2563        term = _factory.createArrayTail(term);
2564      }
2565      else {
2566        _peekToken = token;
2567        Expr index = parseExpr();
2568        token = parseToken();
2569
2570        term = _factory.createArrayGet(term, index);
2571      }
2572
2573          if (token != ']')
2574            throw expect("']'", token);
2575        }
2576        break;
2577    
2578      case '{':
2579        {
2580          Expr index = parseExpr();
2581
2582      expect('}');
2583
2584          term = _factory.createCharAt(term, index);
2585        }
2586        break;
2587
2588      case INCR:
2589    term = _factory.createPostIncrement(term, 1);
2590    break;
2591
2592      case DECR:
2593    term = _factory.createPostIncrement(term, -1);
2594    break;
2595
2596      case DEREF:
2597    term = parseDeref(term);
2598        break;
2599
2600      default:
2601        _peekToken = token;
2602        return term;
2603      }
2604    }
2605  }
2606  
2607  /**
2608   * Parses a deref
2609   *
2610   * <pre>
2611   * deref ::= term -> IDENTIFIER
2612   * ::= term -> IDENTIFIER '(' args ')'
2613   * </pre>
2614   */

2615  private Expr parseDeref(Expr term)
2616    throws IOException JavaDoc
2617  {
2618    String JavaDoc name = null;
2619    Expr nameExpr = null;
2620
2621    int token = parseToken();
2622    
2623    if (token == '$') {
2624      _peekToken = token;
2625      nameExpr = parseTermBase();
2626
2627      // php/09e0
2628
token = parseToken();
2629      switch (token) {
2630      case '[':
2631    Expr index = parseExpr();
2632
2633    token = parseToken();
2634    if (token != ']')
2635      throw expect("']'", token);
2636
2637    nameExpr = _factory.createArrayGet(nameExpr, index);
2638    break;
2639    
2640      default:
2641    _peekToken = token;
2642    break;
2643      }
2644    }
2645    else if (token == '{') {
2646      nameExpr = parseExpr();
2647      expect('}');
2648    }
2649    else {
2650      _peekToken = token;
2651      name = parseIdentifier();
2652    }
2653
2654    token = parseToken();
2655    if (token == '(') {
2656      ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
2657
2658      parseFunctionArgs(args);
2659
2660      if (nameExpr != null)
2661    return _factory.createVarMethodCall(getLocation(), term,
2662                        nameExpr, args);
2663      /*
2664      else if (term instanceof ThisExpr)
2665    return new ThisMethodCallExpr(getLocation(), term, name, args);
2666      */

2667      else
2668    return _factory.createMethodCall(getLocation(), term, name, args);
2669    }
2670    else if (nameExpr != null) {
2671      _peekToken = token;
2672
2673      return term.createFieldGet(_factory, nameExpr);
2674    }
2675    else {
2676      _peekToken = token;
2677
2678      return term.createFieldGet(_factory, name);
2679    }
2680  }
2681  
2682  /**
2683   * Parses a basic term.
2684   *
2685   * <pre>
2686   * term ::= STRING
2687   * ::= LONG
2688   * ::= DOUBLE
2689   * </pre>
2690   */

2691  private Expr parseTermBase()
2692    throws IOException JavaDoc
2693  {
2694    int token = parseToken();
2695
2696    switch (token) {
2697    case STRING:
2698      return _factory.createString(_lexeme);
2699      
2700    case SYSTEM_STRING:
2701      {
2702    ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
2703    args.add(_factory.createString(_lexeme));
2704    return _factory.createFunction(getLocation(), "shell_exec", args);
2705      }
2706      
2707    case SIMPLE_SYSTEM_STRING:
2708      {
2709    ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
2710    args.add(parseEscapedString(_lexeme, SIMPLE_STRING_ESCAPE, true));
2711    return _factory.createFunction(getLocation(), "shell_exec", args);
2712      }
2713
2714    case COMPLEX_SYSTEM_STRING:
2715      {
2716    ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
2717    args.add(parseEscapedString(_lexeme, COMPLEX_STRING_ESCAPE, true));
2718    return _factory.createFunction(getLocation(), "shell_exec", args);
2719      }
2720      
2721    case SIMPLE_STRING_ESCAPE:
2722    case COMPLEX_STRING_ESCAPE:
2723      return parseEscapedString(_lexeme, token, false);
2724
2725    case BINARY:
2726      {
2727    // XXX: getBytes is incorrect
2728
return _factory.createBinary(_lexeme.getBytes());
2729      }
2730
2731    case SIMPLE_BINARY_ESCAPE:
2732    case COMPLEX_BINARY_ESCAPE:
2733      return parseEscapedString(_lexeme, token, false);
2734
2735    case LONG:
2736      return _factory.createLiteral(LongValue.create(Long.parseLong(_lexeme)));
2737      
2738    case DOUBLE:
2739      return _factory.createLiteral(new DoubleValue(Double.parseDouble(_lexeme)));
2740
2741    case NULL:
2742      return _factory.createNull();
2743
2744    case TRUE:
2745      return _factory.createLiteral(BooleanValue.TRUE);
2746
2747    case FALSE:
2748      return _factory.createLiteral(BooleanValue.FALSE);
2749
2750    case '$':
2751      return parseVariable();
2752
2753      /* quercus/0211
2754    case '&':
2755      {
2756    Expr expr = parseTerm();
2757    
2758    return expr.createRef();
2759      }
2760      */

2761
2762    case '-':
2763      {
2764        Expr expr = parseTerm();
2765
2766        token = parseToken();
2767
2768        if (token == '=') {
2769          token = parseToken();
2770
2771          if (token == '&') {
2772            return _factory.createMinus(expr.createAssignRef(this, parseBitOrExpr()));
2773          }
2774          else {
2775            _peekToken = token;
2776
2777            return _factory.createMinus(expr.createAssign(this, parseConditionalExpr()));
2778          }
2779
2780        }
2781        else {
2782          _peekToken = token;
2783
2784          return _factory.createMinus(expr);
2785        }
2786      }
2787
2788    case '+':
2789    {
2790      Expr expr = parseTerm();
2791
2792      token = parseToken();
2793
2794      if (token == '=') {
2795        token = parseToken();
2796
2797        if (token == '&') {
2798          return _factory.createPlus(expr.createAssignRef(this, parseBitOrExpr()));
2799        }
2800        else {
2801          _peekToken = token;
2802
2803          return _factory.createPlus(expr.createAssign(this, parseConditionalExpr()));
2804        }
2805
2806      }
2807      else {
2808        _peekToken = token;
2809
2810        return _factory.createPlus(expr);
2811      }
2812    }
2813
2814    case '!':
2815      {
2816    // XXX: quercus/03i3 vs quercus/03i4
2817

2818        Expr expr = parseTerm();
2819
2820    token = parseToken();
2821
2822    if (token == '=') {
2823      token = parseToken();
2824
2825      // php/03i6
2826
if (token == '&') {
2827        return _factory.createNot(expr.createAssignRef(this, parseBitOrExpr()));
2828      }
2829      else {
2830        _peekToken = token;
2831    
2832        return _factory.createNot(expr.createAssign(this, parseConditionalExpr()));
2833      }
2834
2835    }
2836    else {
2837      _peekToken = token;
2838      
2839      return _factory.createNot(expr);
2840    }
2841      }
2842
2843    case '~':
2844      {
2845        Expr expr = parseTerm();
2846
2847        return _factory.createBitNot(expr);
2848      }
2849
2850    case '@':
2851      {
2852        Expr expr = parseTerm();
2853
2854    return _factory.createSuppress(expr);
2855      }
2856
2857    case CLONE:
2858      {
2859        Expr expr = parseTerm();
2860
2861    return _factory.createClone(expr);
2862      }
2863
2864    case INCR:
2865      {
2866        Expr expr = parseTerm();
2867
2868        return _factory.createPreIncrement(expr, 1);
2869      }
2870
2871    case DECR:
2872      {
2873        Expr expr = parseTerm();
2874
2875        return _factory.createPreIncrement(expr, -1);
2876      }
2877
2878    case NEW:
2879      return parseNew();
2880
2881    case INCLUDE:
2882      return _factory.createInclude(getLocation(), _sourceFile, parseExpr());
2883    case REQUIRE:
2884      return _factory.createRequire(getLocation(), _sourceFile, parseExpr());
2885    case INCLUDE_ONCE:
2886      return _factory.createIncludeOnce(getLocation(), _sourceFile, parseExpr());
2887    case REQUIRE_ONCE:
2888      return _factory.createRequireOnce(getLocation(), _sourceFile, parseExpr());
2889
2890    case LIST:
2891      return parseList();
2892
2893    case PRINT:
2894      return parsePrintExpr();
2895      
2896    case EXIT:
2897      return parseExit();
2898      
2899    case DIE:
2900      return parseDie();
2901
2902    case IDENTIFIER:
2903      {
2904        if (_lexeme.equals("new"))
2905          return parseNew();
2906
2907        String JavaDoc className = null;
2908        String JavaDoc name = _lexeme;
2909        
2910        token = parseToken();
2911        _peekToken = token;
2912
2913        boolean isInstantiated = false;
2914
2915        if (token == SCOPE) {
2916          _peekToken = -1;
2917
2918          className = name;
2919
2920          if (className.equals("self")) {
2921            isInstantiated = true;
2922            className = _quercusClass.getName();
2923
2924            if (className == null)
2925              throw error(L.l("cannot access self when not in object scope"));
2926          }
2927          else if (className.equals("parent")) {
2928            isInstantiated = true;
2929            className = _quercusClass.getParentName();
2930
2931            if (className == null)
2932              throw error(L.l("object does not have a parent class"));
2933          }
2934
2935          token = parseToken();
2936          if (token == '$')
2937              return parseStaticClassField(className);
2938          else
2939            _peekToken = token;
2940      
2941          name = parseIdentifier();
2942
2943          token = parseToken();
2944          _peekToken = token;
2945
2946        }
2947      
2948        if (token == '(')
2949          return parseFunction(className, name, isInstantiated);
2950        else
2951          return parseConstant(className, name);
2952      }
2953
2954    case '(':
2955      {
2956    Expr expr = parseExpr();
2957
2958    expect(')');
2959
2960    if (expr instanceof ConstExpr) {
2961      String JavaDoc type = ((ConstExpr) expr).getVar();
2962      
2963      if ("bool".equals(type) || "boolean".equals(type))
2964        return _factory.createToBoolean(parseTerm());
2965      else if ("int".equals(type) || "integer".equals(type))
2966        return _factory.createToLong(parseTerm());
2967      else if ("float".equals(type)
2968           || "double".equals(type)
2969           || "real".equals(type))
2970        return _factory.createToDouble(parseTerm());
2971      else if ("string".equals(type))
2972        return _factory.createToString(parseTerm());
2973      else if ("binary".equals(type))
2974        return _factory.createToBinary(parseTerm());
2975      else if ("unicode".equals(type))
2976        return _factory.createToUnicode(parseTerm());
2977      else if ("object".equals(type))
2978        return _factory.createToObject(parseTerm());
2979      else if ("array".equalsIgnoreCase(type))
2980        return _factory.createToArray(parseTerm());
2981    }
2982
2983    return expr;
2984      }
2985
2986    default:
2987      throw error(L.l("{0} is an unexpected token, expected an expression.",
2988              tokenName(token)));
2989    }
2990  }
2991  
2992  /**
2993   * Parses a basic term.
2994   *
2995   * <pre>
2996   * lhs ::= VARIABLE
2997   * ::= lhs '[' expr ']'
2998   * ::= lhs -> FIELD
2999   * </pre>
3000   */

3001  private AbstractVarExpr parseLeftHandSide()
3002    throws IOException JavaDoc
3003  {
3004    int token = parseToken();
3005    AbstractVarExpr lhs = null;
3006
3007    if (token == '$')
3008      lhs = parseVariable();
3009    else
3010      throw error(L.l("expected variable at {0} as left-hand-side",
3011              tokenName(token)));
3012
3013    while (true) {
3014      token = parseToken();
3015
3016      switch (token) {
3017      case '[':
3018        {
3019      token = parseToken();
3020      
3021      if (token == ']') {
3022        lhs = _factory.createArrayTail(lhs);
3023      }
3024      else {
3025        _peekToken = token;
3026        Expr index = parseExpr();
3027        token = parseToken();
3028
3029        lhs = _factory.createArrayGet(lhs, index);
3030      }
3031
3032          if (token != ']')
3033            throw expect("']'", token);
3034        }
3035        break;
3036    
3037      case '{':
3038        {
3039          Expr index = parseExpr();
3040
3041      expect('}');
3042
3043          lhs = _factory.createCharAt(lhs, index);
3044        }
3045        break;
3046
3047      case DEREF:
3048    lhs = (AbstractVarExpr) parseDeref(lhs);
3049        break;
3050    
3051      default:
3052    _peekToken = token;
3053    return lhs;
3054      }
3055    }
3056    
3057      
3058  }
3059
3060  /**
3061   * Parses the next variable
3062   */

3063  private AbstractVarExpr parseVariable()
3064    throws IOException JavaDoc
3065  {
3066    int token = parseToken();
3067
3068    if (token == THIS) {
3069      return _factory.createThis(_quercusClass);
3070    }
3071    else if (token == '$') {
3072      _peekToken = token;
3073
3074      // php/0d6c
3075
return _factory.createVarVar(parseTerm());
3076    }
3077    else if (token == '{') {
3078      AbstractVarExpr expr = _factory.createVarVar(parseExpr());
3079
3080      expect('}');
3081
3082      return expr;
3083    }
3084    else if (_lexeme == null)
3085      throw error(L.l("Expected identifier at '{0}'", tokenName(token)));
3086
3087    return _factory.createVar(_function.createVar(_lexeme));
3088  }
3089
3090  /**
3091   * Parses the next function
3092   */

3093  private Expr parseFunction(String JavaDoc className,
3094                              String JavaDoc name,
3095                              boolean isInstantiated)
3096    throws IOException JavaDoc
3097  {
3098    if (name.equalsIgnoreCase("array"))
3099      return parseArrayFunction();
3100
3101    int token = parseToken();
3102
3103    if (token != '(')
3104      throw error(L.l("Expected '('"));
3105
3106    ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
3107
3108    parseFunctionArgs(args);
3109
3110    if (className == null) {
3111      if (name.equals("each")) {
3112        if (args.size() != 1)
3113          throw error(L.l("each requires a single expression"));
3114
3115        return _factory.createEach(args.get(0));
3116      }
3117
3118      return _factory.createFunction(getLocation(), name, args);
3119    }
3120    else if (isInstantiated)
3121      return _factory.createClassMethod(getLocation(), className, name, args);
3122    else
3123      return _factory.createStaticMethod(getLocation(), className, name, args);
3124  }
3125
3126  /**
3127   * Parses the next constant
3128   */

3129  private Expr parseConstant(String JavaDoc className, String JavaDoc name)
3130  {
3131    if (className != null)
3132      return _factory.createClassConst(className, name);
3133    else if (name.equals("__FILE__"))
3134      return _factory.createString(_parserLocation.getFileName());
3135    else if (name.equals("__LINE__"))
3136      return _factory.createLong(_parserLocation.getLineNumber());
3137    else
3138      return _factory.createConst(name);
3139  }
3140
3141  /**
3142   * Parses the next constant
3143   */

3144  private Expr parseStaticClassField(String JavaDoc className)
3145    throws IOException JavaDoc
3146  {
3147    String JavaDoc var = parseIdentifier();
3148
3149    return _factory.createStaticFieldGet(className, var);
3150  }
3151  
3152  private ArrayList JavaDoc<Expr> parseArgs()
3153    throws IOException JavaDoc
3154  {
3155    ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
3156
3157    parseFunctionArgs(args);
3158
3159    return args;
3160  }
3161  
3162  private void parseFunctionArgs(ArrayList JavaDoc<Expr> args)
3163    throws IOException JavaDoc
3164  {
3165    int token;
3166    
3167    while ((token = parseToken()) > 0 && token != ')') {
3168      boolean isRef = false;
3169      
3170      if (token == '&')
3171    isRef = true;
3172      else
3173    _peekToken = token;
3174
3175      Expr expr = parseExpr();
3176
3177      if (isRef)
3178    expr = expr.createRef(this);
3179      
3180      args.add(expr);
3181
3182      token = parseToken();
3183      if (token == ')')
3184    break;
3185      else if (token != ',')
3186    throw expect("','", token);
3187    }
3188  }
3189
3190  /**
3191   * Parses the next function
3192   */

3193  private Expr parseFunction(Expr name)
3194    throws IOException JavaDoc
3195  {
3196    expect('(');
3197
3198    ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
3199
3200    parseFunctionArgs(args);
3201
3202    return _factory.createVarFunction(getLocation(), name, args);
3203  }
3204
3205  /**
3206   * Parses the new expression
3207   */

3208  private Expr parseNew()
3209    throws IOException JavaDoc
3210  {
3211    int token = parseToken();
3212
3213    String JavaDoc name = null;
3214    Expr nameExpr = null;
3215
3216    if (token == IDENTIFIER)
3217      name = _lexeme;
3218    else {
3219      _peekToken = token;
3220      
3221      // nameExpr = parseTermBase();
3222
nameExpr = parseTermDeref();
3223    }
3224
3225    token = parseToken();
3226    
3227    ArrayList JavaDoc<Expr> args = new ArrayList JavaDoc<Expr>();
3228
3229    if (token != '(')
3230      _peekToken = token;
3231    else {
3232      while ((token = parseToken()) > 0 && token != ')') {
3233    _peekToken = token;
3234
3235    args.add(parseExpr());
3236
3237    token = parseToken();
3238    if (token == ')')
3239      break;
3240    else if (token != ',')
3241      throw error(L.l("expected ','"));
3242      }
3243    }
3244
3245    if (name != null)
3246      return _factory.createNew(getLocation(), name, args);
3247    else
3248      return _factory.createVarNew(getLocation(), nameExpr, args);
3249  }
3250
3251  /**
3252   * Parses the include expression
3253   */

3254  private Expr parseInclude()
3255    throws IOException JavaDoc
3256  {
3257    Expr name = parseExpr();
3258
3259    return _factory.createInclude(getLocation(), _sourceFile, name);
3260  }
3261
3262  /**
3263   * Parses the list(...) = value expression
3264   */

3265  private Expr parseList()
3266    throws IOException JavaDoc
3267  {
3268    ListHeadExpr leftVars = parseListHead();
3269
3270    expect('=');
3271
3272    Expr value = parseConditionalExpr();
3273
3274    return _factory.createList(this, leftVars, value);
3275  }
3276
3277  /**
3278   * Parses the list(...) expression
3279   */

3280  private ListHeadExpr parseListHead()
3281    throws IOException JavaDoc
3282  {
3283    expect('(');
3284
3285    int peek = parseToken();
3286
3287    ArrayList JavaDoc<Expr> leftVars = new ArrayList JavaDoc<Expr>();
3288
3289    while (peek > 0 && peek != ')') {
3290      if (peek == LIST) {
3291    leftVars.add(parseListHead());
3292
3293    peek = parseToken();
3294      }
3295      else if (peek != ',') {
3296    _peekToken = peek;
3297
3298    Expr left = parseTerm();
3299
3300    leftVars.add(left);
3301
3302    left.assign(this);
3303
3304    peek = parseToken();
3305      }
3306      else {
3307    leftVars.add(null);
3308      }
3309
3310      if (peek == ',')
3311    peek = parseToken();
3312      else
3313    break;
3314    }
3315
3316    if (peek != ')')
3317      throw error(L.l("expected ')'"));
3318
3319    return _factory.createListHead(leftVars);
3320  }
3321
3322  /**
3323   * Parses the exit/die expression
3324   */

3325  private Expr parseExit()
3326    throws IOException JavaDoc
3327  {
3328    int token = parseToken();
3329
3330    if (token == '(') {
3331      ArrayList JavaDoc<Expr> args = parseArgs();
3332
3333      if (args.size() > 0)
3334    return _factory.createExit(args.get(0));
3335      else
3336    return _factory.createExit(null);
3337    }
3338    else {
3339      _peekToken = token;
3340      
3341      return _factory.createExit(null);
3342    }
3343  }
3344
3345  /**
3346   * Parses the exit/die expression
3347   */

3348  private Expr parseDie()
3349    throws IOException JavaDoc
3350  {
3351    int token = parseToken();
3352
3353    if (token == '(') {
3354      ArrayList JavaDoc<Expr> args = parseArgs();
3355
3356      if (args.size() > 0)
3357    return _factory.createDie(args.get(0));
3358      else
3359    return _factory.createDie(null);
3360    }
3361    else {
3362      _peekToken = token;
3363      
3364      return _factory.createDie(null);
3365    }
3366  }
3367
3368  /**
3369   * Parses the array() expression
3370   */

3371  private Expr parseArrayFunction()
3372    throws IOException JavaDoc
3373  {
3374    String JavaDoc name = _lexeme;
3375
3376    int token = parseToken();
3377
3378    if (token != '(')
3379      throw error(L.l("Expected '('"));
3380
3381    ArrayList JavaDoc<Expr> keys = new ArrayList JavaDoc<Expr>();
3382    ArrayList JavaDoc<Expr> values = new ArrayList JavaDoc<Expr>();
3383
3384    while ((token = parseToken()) > 0 && token != ')') {
3385      _peekToken = token;
3386
3387      Expr value = parseRefExpr();
3388
3389      token = parseToken();
3390
3391      if (token == ARRAY_RIGHT) {
3392    Expr key = value;
3393
3394    value = parseRefExpr();
3395
3396    keys.add(key);
3397    values.add(value);
3398
3399    token = parseToken();
3400      }
3401      else {
3402    keys.add(null);
3403    values.add(value);
3404      }
3405      
3406      if (token == ')')
3407    break;
3408      else if (token != ',')
3409    throw error(L.l("expected ','"));
3410    }
3411
3412    return _factory.createArrayFun(keys, values);
3413  }
3414
3415  private String JavaDoc parseIdentifier()
3416    throws IOException JavaDoc
3417  {
3418    int token = parseToken();
3419
3420    if (token == IDENTIFIER)
3421      return _lexeme;
3422    else if (FIRST_IDENTIFIER_LEXEME <= token)
3423      return _lexeme;
3424    else
3425      throw error(L.l("expected identifier at {0}.", tokenName(token)));
3426  }
3427
3428  /**
3429   * Parses the next token.
3430   */

3431  private int parseToken()
3432    throws IOException JavaDoc
3433  {
3434    int peekToken = _peekToken;
3435    if (peekToken > 0) {
3436      _peekToken = 0;
3437      return peekToken;
3438    }
3439
3440    while (true) {
3441      int ch = read();
3442
3443      switch (ch) {
3444      case -1:
3445    return -1;
3446
3447      case ' ': case '\t': case '\n': case '\r':
3448    break;
3449
3450      case '#':
3451    while ((ch = read()) != '\n' && ch != '\r' && ch >= 0) {
3452      if (ch != '?') {
3453      }
3454      else if ((ch = read()) != '>') {
3455        _peek = ch;
3456      }
3457      else {
3458        ch = read();
3459        if (ch == '\r')
3460          ch = read();
3461        if (ch != '\n')
3462          _peek = ch;
3463    
3464        return parsePhpText();
3465      }
3466    }
3467    break;
3468
3469      case '"':
3470    return parseEscapedString('"');
3471
3472      case '`':
3473    {
3474      int token = parseEscapedString('`');
3475
3476      switch (token) {
3477      case STRING:
3478        return SYSTEM_STRING;
3479      case SIMPLE_STRING_ESCAPE:
3480        return SIMPLE_SYSTEM_STRING;
3481      case COMPLEX_STRING_ESCAPE:
3482        return COMPLEX_SYSTEM_STRING;
3483      default:
3484        throw new IllegalStateException JavaDoc();
3485      }
3486    }
3487    
3488      case '\'':
3489    parseStringToken('\'');
3490    return STRING;
3491
3492      case ';': case '$': case '(': case ')': case '@':
3493      case '[': case ']': case ',': case '{': case '}':
3494      case '~':
3495    return ch;
3496
3497      case '+':
3498    ch = read();
3499    if (ch == '=')
3500      return PLUS_ASSIGN;
3501    else if (ch == '+')
3502      return INCR;
3503    else
3504      _peek = ch;
3505
3506    return '+';
3507
3508      case '-':
3509    ch = read();
3510    if (ch == '>')
3511      return DEREF;
3512    else if (ch == '=')
3513      return MINUS_ASSIGN;
3514    else if (ch == '-')
3515      return DECR;
3516    else
3517      _peek = ch;
3518    
3519    return '-';
3520
3521      case '*':
3522    ch = read();
3523    if (ch == '=')
3524      return MUL_ASSIGN;
3525    else
3526      _peek = ch;
3527
3528    return '*';
3529
3530      case '/':
3531    ch = read();
3532    if (ch == '=')
3533      return DIV_ASSIGN;
3534    else if (ch == '/') {
3535      while (ch >= 0) {
3536        if (ch == '\n' || ch == '\r') {
3537          break;
3538        }
3539        else if (ch == '?') {
3540          ch = read();
3541
3542          if (ch == '>') {
3543        if ((ch = read()) != '\r')
3544          _peek = ch;
3545        else if ((ch = read()) != '\n')
3546          _peek = ch;
3547        
3548        return parsePhpText();
3549          }
3550        }
3551        else
3552          ch = read();
3553      }
3554      break;
3555    }
3556    else if (ch == '*') {
3557      skipMultilineComment();
3558      break;
3559    }
3560    else
3561      _peek = ch;
3562
3563    return '/';
3564
3565      case '%':
3566    ch = read();
3567    if (ch == '=')
3568      return MOD_ASSIGN;
3569    else if (ch == '>') {
3570      ch = read();
3571      if (ch == '\r')
3572        ch = read();
3573      if (ch != '\n')
3574        _peek = ch;
3575    
3576      return parsePhpText();
3577        }
3578    else
3579      _peek = ch;
3580
3581    return '%';
3582
3583      case ':':
3584    ch = read();
3585    if (ch == ':')
3586      return SCOPE;
3587    else
3588      _peek = ch;
3589    
3590    return ':';
3591    
3592      case '=':
3593    ch = read();
3594    if (ch == '=') {
3595      ch = read();
3596      if (ch == '=')
3597        return EQUALS;
3598      else {
3599        _peek = ch;
3600        return EQ;
3601      }
3602    }
3603    else if (ch == '>')
3604      return ARRAY_RIGHT;
3605    else {
3606      _peek = ch;
3607      return '=';
3608    }
3609    
3610      case '!':
3611    ch = read();
3612    if (ch == '=') {
3613      ch = read();
3614      if (ch == '=')
3615        return NEQUALS;
3616      else {
3617        _peek = ch;
3618        return NEQ;
3619      }
3620    }
3621    else {
3622      _peek = ch;
3623      return '!';
3624    }
3625
3626      case '&':
3627    ch = read();
3628    if (ch == '&')
3629      return C_AND;
3630    else if (ch == '=')
3631      return AND_ASSIGN;
3632    else {
3633      _peek = ch;
3634      return '&';
3635    }
3636
3637      case '^':
3638    ch = read();
3639    if (ch == '=')
3640      return XOR_ASSIGN;
3641    else
3642      _peek = ch;
3643    
3644    return '^';
3645
3646      case '|':
3647    ch = read();
3648    if (ch == '|')
3649      return C_OR;
3650    else if (ch == '=')
3651      return OR_ASSIGN;
3652    else {
3653      _peek = ch;
3654      return '|';
3655    }
3656
3657      case '<':
3658    ch = read();
3659    if (ch == '<') {
3660      ch = read();
3661
3662      if (ch == '=')
3663        return LSHIFT_ASSIGN;
3664      else if (ch == '<') {
3665        return parseHeredocToken();
3666      }
3667      else
3668        _peek = ch;
3669      
3670      return LSHIFT;
3671    }
3672    else if (ch == '=')
3673      return LEQ;
3674    else if (ch == '>')
3675      return NEQ;
3676    else if (ch == '/') {
3677      StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
3678        
3679      if (! parseTextMatch(sb, "script"))
3680        throw error(L.l("expected 'script' at '{0}'", sb));
3681
3682      expect('>');
3683
3684      return parsePhpText();
3685    }
3686    else
3687      _peek = ch;
3688
3689    return '<';
3690
3691      case '>':
3692    ch = read();
3693    if (ch == '>') {
3694      ch = read();
3695
3696      if (ch == '=')
3697        return RSHIFT_ASSIGN;
3698      else
3699        _peek = ch;
3700      
3701      return RSHIFT;
3702    }
3703    else if (ch == '=')
3704      return GEQ;
3705    else
3706      _peek = ch;
3707
3708    return '>';
3709
3710      case '?':
3711    ch = read();
3712    if (ch == '>') {
3713      ch = read();
3714      if (ch == '\r')
3715        ch = read();
3716      if (ch != '\n')
3717        _peek = ch;
3718    
3719      return parsePhpText();
3720        }
3721    else
3722      _peek = ch;
3723
3724    return '?';
3725
3726      case '.':
3727    ch = read();
3728
3729    if (ch == '=')
3730      return APPEND_ASSIGN;
3731    
3732    _peek = ch;
3733    
3734    if ('0' <= ch && ch <= '9')
3735      return parseNumberToken('.');
3736    else
3737      return '.';
3738
3739      case '0': case '1': case '2': case '3': case '4':
3740      case '5': case '6': case '7': case '8': case '9':
3741    return parseNumberToken(ch);
3742    
3743      default:
3744
3745        if (ch == 'b') {
3746          int ch2 = read();
3747
3748          if (ch2 == '\'') {
3749            parseStringToken('\'', false);
3750            return BINARY;
3751          }
3752          else if (ch2 == '"') {
3753
3754            int token = parseEscapedString('"', false);
3755            switch (token) {
3756              case STRING:
3757                return BINARY;
3758              case SIMPLE_STRING_ESCAPE:
3759                return SIMPLE_BINARY_ESCAPE;
3760              case COMPLEX_STRING_ESCAPE:
3761                return COMPLEX_BINARY_ESCAPE;
3762              default:
3763                return token;
3764            }
3765          }
3766          else
3767            _peek = ch2;
3768        }
3769
3770    if ('a' <= ch && ch <= 'z' ||
3771        'A' <= ch && ch <= 'Z' ||
3772        ch == '_') {
3773      _sb.setLength(0);
3774      _sb.append((char) ch);
3775
3776      for (ch = read();
3777           ('a' <= ch && ch <= 'z' ||
3778        'A' <= ch && ch <= 'Z' ||
3779        '0' <= ch && ch <= '9' ||
3780        ch == '_');
3781           ch = read()) {
3782        _sb.append((char) ch);
3783      }
3784
3785      _peek = ch;
3786
3787      _lexeme = _sb.toString();
3788
3789      int reserved = _reserved.get(_lexeme);
3790
3791      if (reserved > 0)
3792        return reserved;
3793
3794      reserved = _insensitiveReserved.get(_lexeme.toLowerCase());
3795      if (reserved > 0)
3796        return reserved;
3797      else
3798        return IDENTIFIER;
3799    }
3800        
3801    throw error("unknown lexeme:" + (char) ch);
3802      }
3803    }
3804  }
3805
3806  /**
3807   * Skips a multiline comment.
3808   */

3809  private void skipMultilineComment()
3810    throws IOException JavaDoc
3811  {
3812    int ch;
3813
3814    while ((ch = read()) >= 0) {
3815      if (ch != '*') {
3816      }
3817      else if ((ch = read()) == '/')
3818    return;
3819      else
3820    _peek = ch;
3821    }
3822  }
3823
3824  /**
3825   * Parses quercus text
3826   */

3827  private int parsePhpText()
3828    throws IOException JavaDoc
3829  {
3830    StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
3831
3832    int ch = read();
3833    while (ch > 0) {
3834      if (ch == '<') {
3835    int ch2;
3836    int ch3;
3837    
3838    if ((ch = read()) == 's' || ch == 'S') {
3839      _peek = ch;
3840      if (parseScriptBegin(sb)) {
3841        return TEXT;
3842      }
3843      ch = read();
3844    }
3845    else if (ch == '%') {
3846      if ((ch = read()) == '=') {
3847        _lexeme = sb.toString();
3848
3849        return TEXT_ECHO;
3850      }
3851      else if (Character.isWhitespace(ch)) {
3852        _lexeme = sb.toString();
3853
3854        return TEXT;
3855      }
3856    }
3857    else if (ch != '?') {
3858      sb.append('<');
3859    }
3860    else if ((ch = read()) == '=') {
3861      _lexeme = sb.toString();
3862
3863      return TEXT_ECHO;
3864    }
3865    else if (Character.isWhitespace(ch)) {
3866      _lexeme = sb.toString();
3867
3868      return TEXT;
3869    }
3870    else if (ch != 'p' && ch != 'P') {
3871      sb.append("<?");
3872    }
3873    else if ((ch2 = read()) != 'h' && ch2 != 'H') {
3874      sb.append("<?");
3875      sb.append((char) ch);
3876
3877      ch = ch2;
3878    }
3879    else if ((ch3 = read()) != 'p' && ch3 != 'P') {
3880      sb.append("<?");
3881      sb.append((char) ch);
3882      sb.append((char) ch2);
3883
3884      ch = ch3;
3885    }
3886    else if (! Character.isWhitespace((ch = read()))) {
3887      sb.append("<?");
3888      sb.append((char) ch);
3889      sb.append((char) ch2);
3890      sb.append((char) ch3);
3891    }
3892    else {
3893      _lexeme = sb.toString();
3894
3895      return TEXT;
3896    }
3897      }
3898      else {
3899    sb.append((char) ch);
3900
3901    ch = read();
3902      }
3903    }
3904    
3905    _lexeme = sb.toString();
3906
3907    return TEXT;
3908  }
3909
3910  /**
3911   * Parses the <script language="quercus"> opening
3912   */

3913  private boolean parseScriptBegin(StringBuilder JavaDoc sb)
3914    throws IOException JavaDoc
3915  {
3916    int begin = sb.length();
3917    
3918    sb.append('<');
3919
3920    if (! parseTextMatch(sb, "script"))
3921      return false;
3922
3923    parseWhitespace(sb);
3924    
3925    if (! parseTextMatch(sb, "language"))
3926      return false;
3927    
3928    parseWhitespace(sb);
3929    
3930    if (! parseTextMatch(sb, "=\"php\""))
3931      return false;
3932
3933    parseWhitespace(sb);
3934
3935    int ch = read();
3936
3937    if (ch == '>') {
3938      sb.setLength(begin);
3939      return true;
3940    }
3941    else {
3942      _peek = ch;
3943      return false;
3944    }
3945  }
3946    
3947  private boolean parseTextMatch(StringBuilder JavaDoc sb, String JavaDoc text)
3948    throws IOException JavaDoc
3949  {
3950    int len = text.length();
3951
3952    for (int i = 0; i < len; i++) {
3953      int ch = read();
3954
3955      if (ch < 0)
3956    return false;
3957
3958      if (Character.toLowerCase(ch) != text.charAt(i)) {
3959    _peek = ch;
3960    return false;
3961      }
3962      else
3963    sb.append((char) ch);
3964    }
3965
3966    return true;
3967  }
3968    
3969  private void parseWhitespace(StringBuilder JavaDoc sb)
3970    throws IOException JavaDoc
3971  {
3972    int ch;
3973
3974    while (Character.isWhitespace((ch = read()))) {
3975      sb.append((char) ch);
3976    }
3977
3978    _peek = ch;
3979  }
3980
3981  /**
3982   * XXX: parse as Unicode if and only if uncode.semantics is on.
3983   */

3984  private void parseStringToken(int end)
3985    throws IOException JavaDoc
3986  {
3987    parseStringToken(end, true);
3988  }
3989
3990  /**
3991   * Parses the next string token.
3992   */

3993  private void parseStringToken(int end, boolean isUnicode)
3994    throws IOException JavaDoc
3995  {
3996    _sb.setLength(0);
3997
3998    int ch;
3999
4000    for (ch = read(); ch >= 0 && ch != end; ch = read()) {
4001      if (ch == '\\') {
4002        ch = read();
4003
4004        if (isUnicode) {
4005          if (ch == 'u') {
4006            _sb.append(Character.toChars(parseUnicodeEscape(false)));
4007            continue;
4008          }
4009          else if (ch == 'U') {
4010            _sb.append(Character.toChars(parseUnicodeEscape(true)));
4011            continue;
4012          }
4013        }
4014
4015    if (end == '"') {
4016      _sb.append('\\');
4017
4018      if (ch >= 0)
4019        _sb.append((char) ch);
4020    }
4021    else {
4022      switch (ch) {
4023      case '\'': case '\\': case '\"':
4024        _sb.append((char) ch);
4025        break;
4026      default:
4027        _sb.append('\\');
4028        _sb.append((char) ch);
4029        break;
4030      }
4031    }
4032      }
4033      else
4034        _sb.append((char) ch);
4035    }
4036
4037    _lexeme = _sb.toString();
4038  }
4039
4040  /**
4041   * Parses the next heredoc token.
4042   */

4043  private int parseHeredocToken()
4044    throws IOException JavaDoc
4045  {
4046    _sb.setLength(0);
4047
4048    int ch;
4049
4050    // eat whitespace
4051
while ((ch = read()) >= 0 && (ch == ' ' || ch == '\t')) {
4052    }
4053    _peek = ch;
4054
4055    while ((ch = read()) >= 0 && ch != '\r' && ch != '\n') {
4056      _sb.append((char) ch);
4057    }
4058
4059    _heredocEnd = _sb.toString();
4060
4061    if (ch == '\n') {
4062    }
4063    else if (ch == '\r') {
4064      ch = read();
4065      if (ch != '\n')
4066    _peek = ch;
4067    }
4068    else
4069      _peek = ch;
4070
4071    return parseEscapedString('"');
4072  }
4073
4074  /**
4075   * Parses the next string
4076   * XXX: parse as Unicode if and only if unicode.semantics is on.
4077   */

4078  private Expr parseEscapedString(String JavaDoc prefix, int token, boolean isSystem)
4079    throws IOException JavaDoc
4080  {
4081    return parseEscapedString(prefix, token, isSystem, true);
4082  }
4083
4084  /**
4085   * Parses the next string
4086   */

4087  private Expr parseEscapedString(String JavaDoc prefix,
4088                                   int token,
4089                                   boolean isSystem,
4090                                   boolean isUnicode)
4091    throws IOException JavaDoc
4092  {
4093    Expr expr;
4094
4095    if (isUnicode)
4096      expr = _factory.createString(prefix);
4097    else {
4098      // XXX: getBytes isn't correct
4099
expr = _factory.createBinary(prefix.getBytes());
4100    }
4101
4102    while (true) {
4103      Expr tail;
4104
4105      if (token == COMPLEX_STRING_ESCAPE ||
4106          token == COMPLEX_BINARY_ESCAPE) {
4107    tail = parseExpr();
4108
4109    expect('}');
4110      }
4111      else if (token == SIMPLE_STRING_ESCAPE ||
4112                token == COMPLEX_BINARY_ESCAPE) {
4113    int ch = read();
4114    
4115    _sb.setLength(0);
4116
4117    for (; ch > 0 && isIdentifierPart((char) ch); ch = read()) {
4118      _sb.append((char) ch);
4119    }
4120
4121    _peek = ch;
4122
4123    String JavaDoc varName = _sb.toString();
4124
4125    if (varName.equals("this"))
4126      tail = _factory.createThis(_quercusClass);
4127    else
4128      tail = _factory.createVar(_function.createVar(varName));
4129
4130    // php/013n
4131
if (((ch = read()) == '[' || ch == '-')) {
4132      if (ch == '[') {
4133        tail = parseSimpleArrayTail(tail);
4134
4135        ch = read();
4136      }
4137      else {
4138        if ((ch = read()) != '>') {
4139          tail = _factory.createAppend(tail, _factory.createString("-"));
4140        }
4141        else if (isIdentifierPart((char) (ch = read()))) {
4142          _sb.clear();
4143          for (; isIdentifierPart((char) ch); ch = read()) {
4144        _sb.append((char) ch);
4145          }
4146
4147          tail = tail.createFieldGet(_factory, _sb.toString());
4148        }
4149        else {
4150          tail = _factory.createAppend(tail, _factory.createString("->"));
4151        }
4152
4153        _peek = ch;
4154      }
4155    }
4156
4157    _peek = ch;
4158      }
4159      else
4160    throw new IllegalStateException JavaDoc();
4161
4162      expr = _factory.createAppend(expr, tail);
4163
4164      if (isSystem)
4165    token = parseEscapedString('`');
4166      else
4167    token = parseEscapedString('"');
4168
4169      if (_sb.length() > 0)
4170    expr = _factory.createAppend(expr,
4171                     _factory.createString(_sb.toString()));
4172
4173      if (token == STRING)
4174    return expr;
4175    }
4176  }
4177  
4178  /**
4179   * Parses the next string
4180   */

4181  private Expr parseSimpleArrayTail(Expr tail)
4182    throws IOException JavaDoc
4183  {
4184    int ch = read();
4185
4186    _sb.clear();
4187
4188    if (ch == '$') {
4189      for (ch = read();
4190       ch > 0 && isIdentifierPart((char) ch);
4191       ch = read()) {
4192    _sb.append((char) ch);
4193      }
4194
4195      VarExpr var = _factory.createVar(_function.createVar(_sb.toString()));
4196
4197      tail = _factory.createArrayGet(tail, var);
4198    }
4199    else if ('0' <= ch && ch <= '9') {
4200      long index = ch - '0';
4201
4202      for (ch = read();
4203       '0' <= ch && ch <= '9';
4204       ch = read()) {
4205    index = 10 * index + ch - '0';
4206      }
4207
4208      tail = _factory.createArrayGet(tail, _factory.createLong(index));
4209    }
4210    else if (isIdentifierPart((char) ch)) {
4211      for (;
4212       ch > 0 && isIdentifierPart((char) ch);
4213       ch = read()) {
4214    _sb.append((char) ch);
4215      }
4216
4217      Expr constExpr = _factory.createConst(_sb.toString());
4218
4219      tail = _factory.createArrayGet(tail, constExpr);
4220    }
4221    else
4222      throw error(L.l("Unexpected character at {0}",
4223              String.valueOf((char) ch)));
4224
4225    if (ch != ']')
4226      throw error(L.l("Expected ']' at {0}",
4227              String.valueOf((char) ch)));
4228
4229    return tail;
4230  }
4231
4232  /**
4233   * XXX: parse as Unicode if and only if unicode.semantics is on.
4234   */

4235  private int parseEscapedString(char end)
4236    throws IOException JavaDoc
4237  {
4238    return parseEscapedString(end, true);
4239  }
4240
4241  /**
4242   * Parses the next string
4243   */

4244  private int parseEscapedString(char end, boolean isUnicode)
4245    throws IOException JavaDoc
4246  {
4247    _sb.setLength(0);
4248    
4249    int ch;
4250
4251    while ((ch = read()) > 0) {
4252      if (_heredocEnd == null && ch == end) {
4253    _lexeme = _sb.toString();
4254    return STRING;
4255      }
4256      else if (ch == '\\') {
4257        ch = read();
4258
4259        switch (ch) {
4260        case '0': case '1': case '2': case '3':
4261          _sb.append((char) parseOctalEscape(ch));
4262          break;
4263        case 't':
4264          _sb.append('\t');
4265          break;
4266        case 'r':
4267          _sb.append('\r');
4268          break;
4269        case 'n':
4270          _sb.append('\n');
4271          break;
4272        case '\\':
4273        case '$':
4274        case '"':
4275        case '`':
4276          _sb.append((char) ch);
4277          break;
4278        case 'x':
4279          _sb.append((char) parseHexEscape());
4280          break;
4281        case 'u':
4282          if (isUnicode)
4283            _sb.append(Character.toChars(parseUnicodeEscape(false)));
4284          else
4285            _sb.append((char) ch);
4286          break;
4287        case 'U':
4288          if (isUnicode)
4289            _sb.append(Character.toChars(parseUnicodeEscape(true)));
4290          else
4291            _sb.append((char) ch);
4292          break;
4293    case '{':
4294      ch = read();
4295      _peek = ch;
4296      if (ch == '$')
4297        _sb.append('{');
4298      else
4299        _sb.append("\\{");
4300      break;
4301        default:
4302          _sb.append('\\');
4303          _sb.append((char) ch);
4304      break;
4305        }
4306      }
4307      else if (ch == '$') {
4308    ch = read();
4309
4310    if (ch == '{') {
4311      _peek = '$';
4312      _lexeme = _sb.toString();
4313      return COMPLEX_STRING_ESCAPE;
4314    }
4315    else if (isIdentifierStart((char) ch)) {
4316      _peek = ch;
4317      _lexeme = _sb.toString();
4318      return SIMPLE_STRING_ESCAPE;
4319    }
4320    else {
4321      _sb.append('$');
4322      _peek = ch;
4323    }
4324      }
4325      else if (ch == '{') {
4326    ch = read();
4327
4328    if (ch == '$') {
4329      _peek = ch;
4330      _lexeme = _sb.toString();
4331      return COMPLEX_STRING_ESCAPE;
4332    }
4333    else {
4334      _peek = ch;
4335      _sb.append('{');
4336    }
4337      }
4338      /* quercus/013c
4339      else if ((ch == '\r' || ch == '\n') && _heredocEnd == null)
4340    throw error(L.l("unexpected newline in string."));
4341      */

4342      else {
4343        _sb.append((char) ch);
4344
4345    if (_heredocEnd == null || ! _sb.endsWith(_heredocEnd)) {
4346    }
4347    else if (_sb.length() == _heredocEnd.length() ||
4348         _sb.charAt(_sb.length() - _heredocEnd.length() - 1) == '\n' ||
4349         _sb.charAt(_sb.length() - _heredocEnd.length() - 1) == '\r') {
4350      _sb.setLength(_sb.length() - _heredocEnd.length());
4351
4352      if (_sb.length() > 0 && _sb.charAt(_sb.length() - 1) == '\n')
4353        _sb.setLength(_sb.length() - 1);
4354      if (_sb.length() > 0 && _sb.charAt(_sb.length() - 1) == '\r')
4355        _sb.setLength(_sb.length() - 1);
4356
4357      _heredocEnd = null;
4358      _lexeme = _sb.toString();
4359      return STRING;
4360    }
4361      }
4362    }
4363
4364    _lexeme = _sb.toString();
4365
4366    return STRING;
4367  }
4368 
4369  private boolean isIdentifierStart(char ch)
4370  {
4371    return (ch >= 'a' && ch <= 'z' ||
4372        ch >= 'A' && ch <= 'Z' ||
4373        ch == '_');
4374  }
4375 
4376  private boolean isIdentifierPart(char ch)
4377  {
4378    return (ch >= 'a' && ch <= 'z' ||
4379        ch >= 'A' && ch <= 'Z' ||
4380        ch >= '0' && ch <= '9' ||
4381        ch == '_');
4382  }
4383
4384  private int parseOctalEscape(int ch)
4385    throws IOException JavaDoc
4386  {
4387    int value = ch - '0';
4388
4389    ch = read();
4390    if (ch < '0' || ch > '7') {
4391      _peek = ch;
4392      return value;
4393    }
4394
4395    value = 8 * value + ch - '0';
4396
4397    ch = read();
4398    if (ch < '0' || ch > '7') {
4399      _peek = ch;
4400      return value;
4401    }
4402
4403    value = 8 * value + ch - '0';
4404
4405    return value;
4406  }
4407
4408  private int parseHexEscape()
4409    throws IOException JavaDoc
4410  {
4411    int value = 0;
4412
4413    int ch = read();
4414      
4415    if ('0' <= ch && ch <= '9')
4416      value = 16 * value + ch - '0';
4417    else if ('a' <= ch && ch <= 'f')
4418      value = 16 * value + 10 + ch - 'a';
4419    else if ('A' <= ch && ch <= 'F')
4420      value = 16 * value + 10 + ch - 'A';
4421    else {
4422      _peek = ch;
4423      return value;
4424    }
4425
4426    ch = read();
4427      
4428    if ('0' <= ch && ch <= '9')
4429      value = 16 * value + ch - '0';
4430    else if ('a' <= ch && ch <= 'f')
4431      value = 16 * value + 10 + ch - 'a';
4432    else if ('A' <= ch && ch <= 'F')
4433      value = 16 * value + 10 + ch - 'A';
4434    else {
4435      _peek = ch;
4436      return value;
4437    }
4438
4439    return value;
4440  }
4441
4442  private int parseUnicodeEscape(boolean isLongForm)
4443    throws IOException JavaDoc
4444  {
4445    int codePoint = parseHexEscape() * 256 + parseHexEscape();
4446
4447    if (isLongForm)
4448      codePoint = codePoint * 256 + parseHexEscape();
4449
4450    return codePoint;
4451  }
4452
4453  /**
4454   * Parses the next number.
4455   */

4456  private int parseNumberToken(int ch)
4457    throws IOException JavaDoc
4458  {
4459    if (ch == '0') {
4460      ch = read();
4461      if (ch == 'x' || ch == 'X')
4462    return parseHex();
4463      else if ('0' <= ch && ch <= '7')
4464    return parseOctal(ch);
4465      else {
4466    _peek = ch;
4467    ch = '0';
4468      }
4469    }
4470    
4471    _sb.setLength(0);
4472
4473    int token = LONG;
4474
4475    for (; '0' <= ch && ch <= '9'; ch = read()) {
4476      _sb.append((char) ch);
4477    }
4478
4479    if (ch == '.') {
4480      token = DOUBLE;
4481      
4482      _sb.append((char) ch);
4483      
4484      for (ch = read(); '0' <= ch && ch <= '9'; ch = read()) {
4485    _sb.append((char) ch);
4486      }
4487    }
4488
4489    if (ch == 'e' || ch == 'E') {
4490      token = DOUBLE;
4491
4492      _sb.append((char) ch);
4493
4494      ch = read();
4495      if (ch == '+' || ch == '-') {
4496    _sb.append((char) ch);
4497    ch = read();
4498      }
4499
4500      if ('0' <= ch && ch <= '9') {
4501    for (; '0' <= ch && ch <= '9'; ch = read()) {
4502      _sb.append((char) ch);
4503    }
4504      }
4505      else
4506    throw error(L.l("illegal exponent"));
4507    }
4508
4509    _peek = ch;
4510
4511    _lexeme = _sb.toString();
4512
4513    return token;
4514  }
4515
4516  /**
4517   * Parses the next as hex
4518   */

4519  private int parseHex()
4520    throws IOException JavaDoc
4521  {
4522    long value = 0;
4523    double dValue = 0;
4524
4525    while (true) {
4526      int ch = read();
4527
4528      if ('0' <= ch && ch <= '9') {
4529    value = 16 * value + ch - '0';
4530    dValue = 16 * dValue + ch - '0';
4531      }
4532      else if ('a' <= ch && ch <= 'f') {
4533    value = 16 * value + ch - 'a' + 10;
4534    dValue = 16 * dValue + ch - 'a' + 10;
4535      }
4536      else if ('A' <= ch && ch <= 'F') {
4537    value = 16 * value + ch - 'A' + 10;
4538    dValue = 16 * dValue + ch - 'A' + 10;
4539      }
4540      else {
4541    _peek = ch;
4542    break;
4543      }
4544    }
4545
4546    if (value == dValue) {
4547      _lexeme = String.valueOf(value);
4548      return LONG;
4549    }
4550    else {
4551      _lexeme = String.valueOf(dValue);
4552
4553      return DOUBLE;
4554    }
4555  }
4556
4557  /**
4558   * Parses the next as octal
4559   */

4560  private int parseOctal(int ch)
4561    throws IOException JavaDoc
4562  {
4563    long value = 0;
4564    double dValue = 0;
4565
4566    while (true) {
4567      if ('0' <= ch && ch <= '7') {
4568    value = 8 * value + ch - '0';
4569    dValue = 8 * dValue + ch - '0';
4570      }
4571      else {
4572    _peek = ch;
4573    break;
4574      }
4575
4576      ch = read();
4577    }
4578
4579    if (value == dValue) {
4580      _lexeme = String.valueOf(value);
4581
4582      return LONG;
4583    }
4584    else {
4585      _lexeme = String.valueOf(dValue);
4586
4587      return DOUBLE;
4588    }
4589  }
4590
4591  private void expect(int expect)
4592    throws IOException JavaDoc
4593  {
4594    int token = parseToken();
4595
4596    if (token != expect)
4597      throw error(L.l("expected {0} at {1}",
4598              tokenName(expect),
4599              tokenName(token)));
4600  }
4601
4602  /**
4603   * Reads the next character.
4604   */

4605  private int read()
4606    throws IOException JavaDoc
4607  {
4608    int peek = _peek;
4609
4610    if (peek >= 0) {
4611      _peek = -1;
4612      return peek;
4613    }
4614
4615    try {
4616      int ch = _is.read();
4617
4618      if (ch == '\r') {
4619    _parserLocation.incrementLineNumber();
4620    _hasCr = true;
4621      }
4622      else if (ch == '\n' && ! _hasCr)
4623    _parserLocation.incrementLineNumber();
4624      else
4625    _hasCr = false;
4626
4627      return ch;
4628    } catch (CharConversionException JavaDoc e) {
4629      throw new QuercusParseException(getFileName() + ":" + getLine() + ": " + e + "\nCheck that the script-encoding setting matches the source file's encoding",
4630                   e);
4631    } catch (IOException JavaDoc e) {
4632      throw new IOExceptionWrapper(getFileName() + ":" + getLine() + ":" + e, e);
4633    }
4634  }
4635
4636  /**
4637   * Returns an error.
4638   */

4639  private IOException JavaDoc expect(String JavaDoc expected, int token)
4640  {
4641    return error(L.l("expected {0} at {1}", expected, tokenName(token)));
4642  }
4643
4644  /**
4645   * Returns an error.
4646   */

4647  public IOException JavaDoc error(String JavaDoc msg)
4648  {
4649    int lineNumber = _parserLocation.getLineNumber();
4650
4651    String JavaDoc []sourceLines = Env.getSourceLine(_sourceFile, lineNumber - 1, 3);
4652
4653    if (sourceLines != null &&
4654    sourceLines.length > 0 &&
4655    sourceLines[0] != null) {
4656      StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
4657
4658      String JavaDoc shortFile = _parserLocation.getFileName();
4659      int p = shortFile.lastIndexOf('/');
4660      if (p > 0)
4661    shortFile = shortFile.substring(p + 1);
4662
4663      sb.append(_parserLocation.toString())
4664        .append(msg)
4665        .append(" in");
4666
4667      for (int i = 0; i < sourceLines.length && sourceLines[i] != null; i++) {
4668    sb.append("\n");
4669        sb.append(shortFile)
4670          .append(":")
4671          .append(lineNumber - 1 + i)
4672          .append(": ")
4673          .append(sourceLines[i]);
4674      }
4675    
4676      return new QuercusParseException(sb.toString());
4677    }
4678    else
4679      return new QuercusParseException(_parserLocation.toString() + msg);
4680  }
4681
4682  /**
4683   * Returns the token name.
4684   */

4685  private String JavaDoc tokenName(int token)
4686  {
4687    switch (token) {
4688    case -1:
4689      return "end of file";
4690      
4691    case '\'':
4692      return "'";
4693
4694    case AS: return "'as'";
4695      
4696    case TRUE: return "true";
4697    case FALSE: return "false";
4698      
4699    case AND_RES: return "'and'";
4700    case OR_RES: return "'or'";
4701    case XOR_RES: return "'xor'";
4702      
4703    case C_AND: return "'&&'";
4704    case C_OR: return "'||'";
4705      
4706    case IF: return "'if'";
4707    case ELSE: return "'else'";
4708    case ELSEIF: return "'elseif'";
4709    case ENDIF: return "'endif'";
4710      
4711    case WHILE: return "'while'";
4712    case ENDWHILE: return "'endwhile'";
4713    case DO: return "'do'";
4714      
4715    case FOR: return "'for'";
4716    case ENDFOR: return "'endfor'";
4717      
4718    case FOREACH: return "'foreach'";
4719    case ENDFOREACH: return "'endforeach'";
4720      
4721    case SWITCH: return "'switch'";
4722    case ENDSWITCH: return "'endswitch'";
4723      
4724    case ECHO: return "'echo'";
4725    case PRINT: return "'print'";
4726      
4727    case LIST: return "'list'";
4728    case CASE: return "'case'";
4729      
4730    case DEFAULT: return "'default'";
4731    case CLASS: return "'class'";
4732    case INTERFACE: return "'interface'";
4733    case EXTENDS: return "'extends'";
4734    case IMPLEMENTS: return "'implements'";
4735    case RETURN: return "'return'";
4736      
4737    case DIE: return "'die'";
4738    case EXIT: return "'exit'";
4739    case THROW: return "'throw'";
4740      
4741    case CLONE: return "'clone'";
4742    case INSTANCEOF: return "'instanceof'";
4743      
4744    case SIMPLE_STRING_ESCAPE: return "string";
4745    case COMPLEX_STRING_ESCAPE: return "string";
4746      
4747    case REQUIRE: return "'require'";
4748    case REQUIRE_ONCE: return "'require_once'";
4749      
4750    case PRIVATE: return "'private'";
4751    case PROTECTED: return "'protected'";
4752    case PUBLIC: return "'public'";
4753    case STATIC: return "'static'";
4754    case FINAL: return "'final'";
4755    case ABSTRACT: return "'abstract'";
4756      
4757    case GLOBAL: return "'global'";
4758      
4759    case FUNCTION: return "'function'";
4760      
4761    case THIS: return "'this'";
4762      
4763    case ARRAY_RIGHT: return "'=>'";
4764    case LSHIFT: return "'<<'";
4765      
4766    case IDENTIFIER:
4767      return "'" + _lexeme + "'";
4768
4769    case LONG:
4770      return "integer (" + _lexeme + ")";
4771
4772    case TEXT:
4773      return "TEXT (token " + token + ")";
4774
4775    case STRING:
4776      return "string(" + _lexeme + ")";
4777
4778    case TEXT_ECHO:
4779      return "<?=";
4780      
4781    default:
4782      if (32 <= token && token < 127)
4783    return "'" + (char) token + "'";
4784      else
4785    return "(token " + token + ")";
4786    }
4787  }
4788
4789  /**
4790   * The location from which the last token was read.
4791   * @return
4792   */

4793  public Location getLocation()
4794  {
4795    return _parserLocation.getLocation();
4796  }
4797
4798  private class ParserLocation {
4799    private int _lineNumber = 1;
4800    private String JavaDoc _fileName;
4801    private String JavaDoc _lastClassName;
4802    private String JavaDoc _lastFunctionName;
4803
4804    private Location _location;
4805
4806    public int getLineNumber()
4807    {
4808      return _lineNumber;
4809    }
4810
4811    public void setLineNumber(int lineNumber)
4812    {
4813      _lineNumber = lineNumber;
4814      _location = null;
4815    }
4816
4817    public void incrementLineNumber()
4818    {
4819      _lineNumber++;
4820      _location = null;
4821    }
4822
4823    public String JavaDoc getFileName()
4824    {
4825      return _fileName;
4826    }
4827
4828    public void setFileName(String JavaDoc fileName)
4829    {
4830      _fileName = fileName;
4831      _location = null;
4832    }
4833
4834    public Location getLocation()
4835    {
4836      String JavaDoc currentFunctionName = _function == null || _function.isPageMain() ? null : _function.getName();
4837      String JavaDoc currentClassName = _quercusClass == null ? null : _quercusClass.getName();
4838
4839      if (_location != null) {
4840        if (!equals(currentFunctionName, _lastFunctionName))
4841          _location = null;
4842        else if (!equals(currentClassName, _lastClassName))
4843          _location = null;
4844      }
4845
4846      if (_location == null)
4847        _location = new Location(_fileName, _lineNumber, currentClassName, currentFunctionName);
4848
4849      _lastFunctionName = currentFunctionName;
4850      _lastClassName = currentClassName;
4851
4852      return _location;
4853    }
4854
4855    private boolean equals(String JavaDoc s1, String JavaDoc s2)
4856    {
4857      return (s1 == null || s2 == null) ? s1 == s2 : s1.equals(s2);
4858    }
4859
4860    public String JavaDoc toString()
4861    {
4862      return _fileName + ":" + _lineNumber + ": ";
4863    }
4864  }
4865
4866  static {
4867    _insensitiveReserved.put("echo", ECHO);
4868    _insensitiveReserved.put("print", PRINT);
4869    _insensitiveReserved.put("if", IF);
4870    _insensitiveReserved.put("else", ELSE);
4871    _insensitiveReserved.put("elseif", ELSEIF);
4872    _insensitiveReserved.put("do", DO);
4873    _insensitiveReserved.put("while", WHILE);
4874    _insensitiveReserved.put("for", FOR);
4875    _insensitiveReserved.put("function", FUNCTION);
4876    _insensitiveReserved.put("class", CLASS);
4877    // quercus/0261
4878
// _insensitiveReserved.put("new", NEW);
4879
_insensitiveReserved.put("return", RETURN);
4880    _insensitiveReserved.put("break", BREAK);
4881    _insensitiveReserved.put("continue", CONTINUE);
4882    // quercus/0260
4883
// _insensitiveReserved.put("var", VAR);
4884
_insensitiveReserved.put("this", THIS);
4885    _insensitiveReserved.put("private", PRIVATE);
4886    _insensitiveReserved.put("protected", PROTECTED);
4887    _insensitiveReserved.put("public", PUBLIC);
4888    _insensitiveReserved.put("and", AND_RES);
4889    _insensitiveReserved.put("xor", XOR_RES);
4890    _insensitiveReserved.put("or", OR_RES);
4891    _insensitiveReserved.put("extends", EXTENDS);
4892    _insensitiveReserved.put("static", STATIC);
4893    _insensitiveReserved.put("include", INCLUDE);
4894    _insensitiveReserved.put("require", REQUIRE);
4895    _insensitiveReserved.put("include_once", INCLUDE_ONCE);
4896    _insensitiveReserved.put("require_once", REQUIRE_ONCE);
4897    _insensitiveReserved.put("unset", UNSET);
4898    _insensitiveReserved.put("foreach", FOREACH);
4899    _insensitiveReserved.put("as", AS);
4900    _insensitiveReserved.put("switch", SWITCH);
4901    _insensitiveReserved.put("case", CASE);
4902    _insensitiveReserved.put("default", DEFAULT);
4903    _insensitiveReserved.put("die", DIE);
4904    _insensitiveReserved.put("exit", EXIT);
4905    _insensitiveReserved.put("global", GLOBAL);
4906    _insensitiveReserved.put("list", LIST);
4907    _insensitiveReserved.put("endif", ENDIF);
4908    _insensitiveReserved.put("endwhile", ENDWHILE);
4909    _insensitiveReserved.put("endfor", ENDFOR);
4910    _insensitiveReserved.put("endforeach", ENDFOREACH);
4911    _insensitiveReserved.put("endswitch", ENDSWITCH);
4912    
4913    _insensitiveReserved.put("true", TRUE);
4914    _insensitiveReserved.put("false", FALSE);
4915    _insensitiveReserved.put("null", NULL);
4916    _insensitiveReserved.put("clone", CLONE);
4917    _insensitiveReserved.put("instanceof", INSTANCEOF);
4918    _insensitiveReserved.put("const", CONST);
4919    _insensitiveReserved.put("final", FINAL);
4920    _insensitiveReserved.put("abstract", ABSTRACT);
4921    _insensitiveReserved.put("throw", THROW);
4922    _insensitiveReserved.put("try", TRY);
4923    _insensitiveReserved.put("catch", CATCH);
4924    _insensitiveReserved.put("interface", INTERFACE);
4925    _insensitiveReserved.put("implements", IMPLEMENTS);
4926  }
4927}
4928
Popular Tags