1 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 ; 49 import java.io.IOException ; 50 import java.io.Reader ; 51 import java.util.ArrayList ; 52 53 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 _is; 193 194 private CharBuffer _sb = new CharBuffer(); 195 196 private int _peekToken = -1; 197 private String _lexeme = ""; 198 private String _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 is) 220 { 221 this(quercus); 222 223 init(sourceFile, is); 224 } 225 226 private void init(Path sourceFile) 227 throws IOException 228 { 229 init(sourceFile, sourceFile.openRead().getReader()); 230 } 231 232 private void init(Path sourceFile, Reader 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 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 encoding) 257 throws IOException 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 encoding, 276 String fileName, 277 int line) 278 throws IOException 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 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 is) 309 throws IOException 310 { 311 return new QuercusParser(quercus, path, is).parse(); 312 } 313 314 public static QuercusProgram parseEval(Quercus quercus, String str) 315 throws IOException 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 str) 325 throws IOException 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 args, String code) 335 throws IOException 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 str) 348 throws IOException 349 { 350 Path path = new StringPath(str); 351 352 return new QuercusParser(quercus, path, new java.io.StringReader (str)).parseExpr(); 353 } 354 355 public static Expr parseDefault(String str) 356 { 357 try { 358 Path path = new StringPath(str); 359 360 return new QuercusParser(null, path, new java.io.StringReader (str)).parseExpr(); 361 } catch (IOException e) { 362 e.printStackTrace(); 363 364 throw new QuercusRuntimeException(e); 365 } 366 } 367 368 371 public String getFileName() 372 { 373 if (_sourceFile == null) 374 return null; 375 else 376 return _sourceFile.getPath(); 377 } 378 379 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 399 { 400 _function = new FunctionInfo(_quercus, "main"); 401 _function.setPageMain(true); 402 403 _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 421 } 422 423 QuercusProgram parseCode() 424 throws IOException 425 { 426 _function = new FunctionInfo(_quercus, "eval"); 427 _function.setGlobal(false); 429 430 Location location = getLocation(); 431 432 ArrayList <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 443 { 444 _function = new FunctionInfo(_quercus, "anonymous"); 445 _function.setGlobal(false); 447 _function.setPageMain(true); 448 449 init(argPath); 450 451 ArrayList <Arg> args = parseFunctionArgDefinition(); 452 453 init(codePath); 454 455 ArrayList <Statement> statementList; 456 457 statementList = parseStatementList(); 458 459 return _factory.createFunction(Location.UNKNOWN, 460 "anonymous", 461 _function, 462 args, 463 statementList); 464 } 465 466 469 Statement parseTop() 470 throws IOException 471 { 472 _isTop = true; 473 474 ArrayList <Statement> statements = new ArrayList <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 495 private ArrayList <Statement> parseStatementList() 496 throws IOException 497 { 498 ArrayList <Statement> statements = new ArrayList <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 break; 567 568 case INTERFACE: 569 parseClassDefinition(M_INTERFACE); 570 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 <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 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 <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 736 private Statement parseStatementImpl(int token) 737 throws IOException 738 { 739 switch (token) { 740 case ECHO: 741 { 742 Location location = getLocation(); 743 744 ArrayList <Statement> statementList = new ArrayList <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 785 } 786 } 787 788 791 private void parseEcho(ArrayList <Statement> statements) 792 throws IOException 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 813 private void createEchoStatements(Location location, 814 ArrayList <Statement> statements, 815 Expr expr) 816 { 817 if (expr == null) { 818 } 820 else if (expr instanceof AppendExpr) { 821 AppendExpr append = (AppendExpr) expr; 822 823 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 846 private Statement parsePrint() 847 throws IOException 848 { 849 return _factory.createExpr(getLocation(), parsePrintExpr()); 850 } 851 852 855 private Expr parsePrintExpr() 856 throws IOException 857 { 858 ArrayList <Expr> args = new ArrayList <Expr>(); 859 args.add(parseTopExpr()); 860 861 return _factory.createFunction(getLocation(), "print", args); 862 } 863 864 867 private Statement parseGlobal() 868 throws IOException 869 { 870 ArrayList <Statement> statementList = new ArrayList <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 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 895 int token = parseToken(); 896 897 if (token != ',') { 898 _peekToken = token; 899 return _factory.createBlock(location, statementList); 900 } 901 } 902 } 903 904 907 private Statement parseStatic() 908 throws IOException 909 { 910 ArrayList <Statement> statementList = new ArrayList <Statement>(); 911 912 Location location = getLocation(); 913 914 while (true) { 915 expect('$'); 916 917 String 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 943 private Statement parseUnset() 944 throws IOException 945 { 946 Location location = getLocation(); 947 948 ArrayList <Statement> statementList = new ArrayList <Statement>(); 949 parseUnset(statementList); 950 951 return _factory.createBlock(location, statementList); 952 } 953 954 957 private void parseUnset(ArrayList <Statement> statementList) 958 throws IOException 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 983 private Statement parseIf() 984 throws IOException 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 1029 private Statement parseAlternateIf(Expr test, Location location) 1030 throws IOException 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 1066 private Statement parseSwitch() 1067 throws IOException 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 <Expr[]> caseList = new ArrayList <Expr[]>(); 1096 ArrayList <BlockStatement> blockList = new ArrayList <BlockStatement>(); 1097 1098 ArrayList <Integer > fallThroughList = new ArrayList <Integer >(); 1099 BlockStatement defaultBlock = null; 1100 1101 while ((token = parseToken()) == CASE || token == DEFAULT) { 1102 Location caseLocation = getLocation(); 1103 1104 ArrayList <Expr> valueList = new ArrayList <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 } 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 <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 1188 private Statement parseWhile() 1189 throws IOException 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 1227 private Statement parseDo() 1228 throws IOException 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 1254 private Statement parseFor() 1255 throws IOException 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 1316 private Statement parseForeach() 1317 throws IOException 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 1395 private Statement parseTry() 1396 throws IOException 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 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 1437 private Function parseFunctionDefinition(int modifiers) 1438 throws IOException 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 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 <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 <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 1525 1526 return function; 1527 } finally { 1528 _returnsReference = oldReturnsReference; 1529 _function = oldFunction; 1530 _isTop = oldTop; 1531 } 1532 } 1533 1534 private ArrayList <Arg> parseFunctionArgDefinition() 1535 throws IOException 1536 { 1537 ArrayList <Arg> args = new ArrayList <Arg>(); 1538 1539 while (true) { 1540 int token = parseToken(); 1541 boolean isReference = false; 1542 1543 String 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 argName = parseIdentifier(); 1565 Expr defaultExpr = _factory.createRequired(); 1566 1567 token = parseToken(); 1568 if (token == '=') { 1569 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 1598 private Statement parseReturn() 1599 throws IOException 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 1622 1623 if (_returnsReference) 1624 return _factory.createReturnRef(location, expr); 1625 else 1626 return _factory.createReturn(location, expr); 1627 } 1628 } 1629 1630 1633 private Statement parseThrow() 1634 throws IOException 1635 { 1636 Location location = getLocation(); 1637 1638 Expr expr = parseExpr(); 1639 1640 return _factory.createThrow(location, expr); 1641 } 1642 1643 1646 private Statement parseClassDefinition(int modifiers) 1647 throws IOException 1648 { 1649 String name = parseIdentifier(); 1650 1651 String parentName = null; 1652 1653 int token = parseToken(); 1654 if (token == EXTENDS) { 1655 parentName = parseIdentifier(); 1656 token = parseToken(); 1657 } 1658 1659 ArrayList <String > ifaceList = new ArrayList <String >(); 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 1700 private void parseClassContents() 1701 throws IOException 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 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 1777 private void parseClassVarDefinition(boolean isStatic) 1778 throws IOException 1779 { 1780 int token; 1781 1782 do { 1783 expect('$'); 1784 String 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 1812 private void parseClassConstDefinition() 1813 throws IOException 1814 { 1815 int token; 1816 1817 do { 1818 String 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 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 1876 private Statement parseExprStatement() 1877 throws IOException 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 1908 private Expr parseTopExpr() 1909 throws IOException 1910 { 1911 return parseExpr(); 1912 } 1913 1914 1917 private Expr parseTopCommaExpr() 1918 throws IOException 1919 { 1920 return parseCommaExpr(); 1921 } 1922 1923 1926 private Expr parseCommaExpr() 1927 throws IOException 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 1948 private Expr parseRefExpr() 1949 throws IOException 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 1969 private Expr parseExpr() 1970 throws IOException 1971 { 1972 return parseWeakOrExpr(); 1973 } 1974 1975 1978 private Expr parseWeakOrExpr() 1979 throws IOException 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 2000 private Expr parseWeakXorExpr() 2001 throws IOException 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 2022 private Expr parseWeakAndExpr() 2023 throws IOException 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 2044 private Expr parseConditionalExpr() 2045 throws IOException 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 expr = _factory.createConditional(expr, trueExpr, parseOrExpr()); 2058 break; 2059 default: 2060 _peekToken = token; 2061 return expr; 2062 } 2063 } 2064 } 2065 2066 2069 private Expr parseOrExpr() 2070 throws IOException 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 2091 private Expr parseAndExpr() 2092 throws IOException 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 2113 private Expr parseBitOrExpr() 2114 throws IOException 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 2135 private Expr parseBitXorExpr() 2136 throws IOException 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 2157 private Expr parseBitAndExpr() 2158 throws IOException 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 2179 private Expr parseEqExpr() 2180 throws IOException 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 2208 private Expr parseCmpExpr() 2209 throws IOException 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 2248 private Expr parseShiftExpr() 2249 throws IOException 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 2273 private Expr parseAddExpr() 2274 throws IOException 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 2301 private Expr parseMulExpr() 2302 throws IOException 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 2329 private Expr parseAssignExpr() 2330 throws IOException 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 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 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 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 2474 private Expr parseTerm() 2475 throws IOException 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 2549 private Expr parseTermDeref() 2550 throws IOException 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 2615 private Expr parseDeref(Expr term) 2616 throws IOException 2617 { 2618 String name = null; 2619 Expr nameExpr = null; 2620 2621 int token = parseToken(); 2622 2623 if (token == '$') { 2624 _peekToken = token; 2625 nameExpr = parseTermBase(); 2626 2627 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 <Expr> args = new ArrayList <Expr>(); 2657 2658 parseFunctionArgs(args); 2659 2660 if (nameExpr != null) 2661 return _factory.createVarMethodCall(getLocation(), term, 2662 nameExpr, args); 2663 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 2691 private Expr parseTermBase() 2692 throws IOException 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 <Expr> args = new ArrayList <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 <Expr> args = new ArrayList <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 <Expr> args = new ArrayList <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 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 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 2818 Expr expr = parseTerm(); 2819 2820 token = parseToken(); 2821 2822 if (token == '=') { 2823 token = parseToken(); 2824 2825 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 className = null; 2908 String 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 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 3001 private AbstractVarExpr parseLeftHandSide() 3002 throws IOException 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 3063 private AbstractVarExpr parseVariable() 3064 throws IOException 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 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 3093 private Expr parseFunction(String className, 3094 String name, 3095 boolean isInstantiated) 3096 throws IOException 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 <Expr> args = new ArrayList <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 3129 private Expr parseConstant(String className, String 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 3144 private Expr parseStaticClassField(String className) 3145 throws IOException 3146 { 3147 String var = parseIdentifier(); 3148 3149 return _factory.createStaticFieldGet(className, var); 3150 } 3151 3152 private ArrayList <Expr> parseArgs() 3153 throws IOException 3154 { 3155 ArrayList <Expr> args = new ArrayList <Expr>(); 3156 3157 parseFunctionArgs(args); 3158 3159 return args; 3160 } 3161 3162 private void parseFunctionArgs(ArrayList <Expr> args) 3163 throws IOException 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 3193 private Expr parseFunction(Expr name) 3194 throws IOException 3195 { 3196 expect('('); 3197 3198 ArrayList <Expr> args = new ArrayList <Expr>(); 3199 3200 parseFunctionArgs(args); 3201 3202 return _factory.createVarFunction(getLocation(), name, args); 3203 } 3204 3205 3208 private Expr parseNew() 3209 throws IOException 3210 { 3211 int token = parseToken(); 3212 3213 String name = null; 3214 Expr nameExpr = null; 3215 3216 if (token == IDENTIFIER) 3217 name = _lexeme; 3218 else { 3219 _peekToken = token; 3220 3221 nameExpr = parseTermDeref(); 3223 } 3224 3225 token = parseToken(); 3226 3227 ArrayList <Expr> args = new ArrayList <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 3254 private Expr parseInclude() 3255 throws IOException 3256 { 3257 Expr name = parseExpr(); 3258 3259 return _factory.createInclude(getLocation(), _sourceFile, name); 3260 } 3261 3262 3265 private Expr parseList() 3266 throws IOException 3267 { 3268 ListHeadExpr leftVars = parseListHead(); 3269 3270 expect('='); 3271 3272 Expr value = parseConditionalExpr(); 3273 3274 return _factory.createList(this, leftVars, value); 3275 } 3276 3277 3280 private ListHeadExpr parseListHead() 3281 throws IOException 3282 { 3283 expect('('); 3284 3285 int peek = parseToken(); 3286 3287 ArrayList <Expr> leftVars = new ArrayList <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 3325 private Expr parseExit() 3326 throws IOException 3327 { 3328 int token = parseToken(); 3329 3330 if (token == '(') { 3331 ArrayList <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 3348 private Expr parseDie() 3349 throws IOException 3350 { 3351 int token = parseToken(); 3352 3353 if (token == '(') { 3354 ArrayList <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 3371 private Expr parseArrayFunction() 3372 throws IOException 3373 { 3374 String name = _lexeme; 3375 3376 int token = parseToken(); 3377 3378 if (token != '(') 3379 throw error(L.l("Expected '('")); 3380 3381 ArrayList <Expr> keys = new ArrayList <Expr>(); 3382 ArrayList <Expr> values = new ArrayList <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 parseIdentifier() 3416 throws IOException 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 3431 private int parseToken() 3432 throws IOException 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 (); 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 sb = new StringBuilder (); 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 3809 private void skipMultilineComment() 3810 throws IOException 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 3827 private int parsePhpText() 3828 throws IOException 3829 { 3830 StringBuilder sb = new StringBuilder (); 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 3913 private boolean parseScriptBegin(StringBuilder sb) 3914 throws IOException 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 sb, String text) 3948 throws IOException 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 sb) 3970 throws IOException 3971 { 3972 int ch; 3973 3974 while (Character.isWhitespace((ch = read()))) { 3975 sb.append((char) ch); 3976 } 3977 3978 _peek = ch; 3979 } 3980 3981 3984 private void parseStringToken(int end) 3985 throws IOException 3986 { 3987 parseStringToken(end, true); 3988 } 3989 3990 3993 private void parseStringToken(int end, boolean isUnicode) 3994 throws IOException 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 4043 private int parseHeredocToken() 4044 throws IOException 4045 { 4046 _sb.setLength(0); 4047 4048 int ch; 4049 4050 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 4078 private Expr parseEscapedString(String prefix, int token, boolean isSystem) 4079 throws IOException 4080 { 4081 return parseEscapedString(prefix, token, isSystem, true); 4082 } 4083 4084 4087 private Expr parseEscapedString(String prefix, 4088 int token, 4089 boolean isSystem, 4090 boolean isUnicode) 4091 throws IOException 4092 { 4093 Expr expr; 4094 4095 if (isUnicode) 4096 expr = _factory.createString(prefix); 4097 else { 4098 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 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 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 (); 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 4181 private Expr parseSimpleArrayTail(Expr tail) 4182 throws IOException 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 4235 private int parseEscapedString(char end) 4236 throws IOException 4237 { 4238 return parseEscapedString(end, true); 4239 } 4240 4241 4244 private int parseEscapedString(char end, boolean isUnicode) 4245 throws IOException 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 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 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 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 4444 { 4445 int codePoint = parseHexEscape() * 256 + parseHexEscape(); 4446 4447 if (isLongForm) 4448 codePoint = codePoint * 256 + parseHexEscape(); 4449 4450 return codePoint; 4451 } 4452 4453 4456 private int parseNumberToken(int ch) 4457 throws IOException 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 4519 private int parseHex() 4520 throws IOException 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 4560 private int parseOctal(int ch) 4561 throws IOException 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 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 4605 private int read() 4606 throws IOException 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 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 e) { 4632 throw new IOExceptionWrapper(getFileName() + ":" + getLine() + ":" + e, e); 4633 } 4634 } 4635 4636 4639 private IOException expect(String expected, int token) 4640 { 4641 return error(L.l("expected {0} at {1}", expected, tokenName(token))); 4642 } 4643 4644 4647 public IOException error(String msg) 4648 { 4649 int lineNumber = _parserLocation.getLineNumber(); 4650 4651 String []sourceLines = Env.getSourceLine(_sourceFile, lineNumber - 1, 3); 4652 4653 if (sourceLines != null && 4654 sourceLines.length > 0 && 4655 sourceLines[0] != null) { 4656 StringBuilder sb = new StringBuilder (); 4657 4658 String 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 4685 private String 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 4793 public Location getLocation() 4794 { 4795 return _parserLocation.getLocation(); 4796 } 4797 4798 private class ParserLocation { 4799 private int _lineNumber = 1; 4800 private String _fileName; 4801 private String _lastClassName; 4802 private String _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 getFileName() 4824 { 4825 return _fileName; 4826 } 4827 4828 public void setFileName(String fileName) 4829 { 4830 _fileName = fileName; 4831 _location = null; 4832 } 4833 4834 public Location getLocation() 4835 { 4836 String currentFunctionName = _function == null || _function.isPageMain() ? null : _function.getName(); 4837 String 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 s1, String s2) 4856 { 4857 return (s1 == null || s2 == null) ? s1 == s2 : s1.equals(s2); 4858 } 4859 4860 public String 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 _insensitiveReserved.put("return", RETURN); 4880 _insensitiveReserved.put("break", BREAK); 4881 _insensitiveReserved.put("continue", CONTINUE); 4882 _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 |