1 3 5 22 23 package edu.neu.ccs.jmk; 24 25 import java.io.*; 26 import java.util.Vector ; 27 28 36 final class Loader 37 { 38 private Make make; 39 private File file; private LineNumberReader in; 41 private GlobalTable table; private PrintWriter out; 43 private boolean verbose; 44 45 Loader(Make make, Reader in) { 46 this.make = make; 47 out = make.getOut(); 48 verbose = make.isVerbose(); 49 file = make.getFile(); 50 this.in = new LineNumberReader(in); 51 table = new GlobalTable(); 52 } 53 54 private Loader(Make make, File file, Reader in, 57 GlobalTable table) { 58 this.make = make; 59 out = make.getOut(); 60 verbose = make.isVerbose(); 61 this.file = file; 62 this.in = new LineNumberReader(in); 63 this.table = table; 64 } 65 66 private boolean conditionTrue = true; 68 69 74 void load() 75 throws ParseError 76 { 77 try { 78 int token = scan(); 79 if (token == EOF_TOKEN) { 80 String msg = "No input found"; 81 throw new ParseError(file, in.getLineNumber(), msg); 82 } 83 do { 84 decl(token); 85 token = scan(); 86 } 87 while (token != EOF_TOKEN); 88 } 89 finally { try { 91 in.close(); 92 } 93 catch (IOException ex) { 94 } 95 } 96 } 97 98 private void decl(int token) 100 throws ParseError 101 { 102 switch (token) { 103 case IDENTIFIER_TOKEN: Global var = table.get(string); 105 int saw = peek(); 106 if (saw == '=') { 107 drop(); assign(var); 109 } 110 else 111 rule(append(var, null, null)); 112 break; 113 case INCLUDE_TOKEN: 114 include(); 115 break; 116 case IF_TOKEN: 117 conditional(); 118 break; 119 default: 120 if (tokenStartsItem(token)) 121 rule(list(token, null, null)); 122 else { 123 String msg = "Expecting an item, " 124 + "an include, or a conditional, but found "; 125 throw new ParseError(file, in.getLineNumber(), 126 msg + token2string(token)); 127 } 128 } 129 } 130 131 private void assign(Global var) 133 throws ParseError 134 { 135 int token = scan(); 136 Expression exp; 137 if (token == ';') 138 exp = new Nil(); 139 else if (token == FUNCTION_TOKEN) { 140 String name = var.getIdentifier(); 141 CompEnv env = new CompEnv(null, new String [] { name }); 142 exp = new Letrec(funct(name, env), new Lexical(name, 0, 0)); 143 token = scan(); 144 } 145 else { 146 exp = list(token, var.getIdentifier(), null); 147 token = scan(); 148 } 149 if (token != ';') 150 expecting(';', token); 151 if (conditionTrue) { 152 Value val; 153 try { 154 val = exp.eval(null, null); 155 } 156 catch (Exception ex) { 157 String msg = "Exception: " + ex.getMessage(); 158 throw new ParseError(file, in.getLineNumber(), msg); 159 } 160 var.setValue(val); 161 if (verbose) { 162 out.print(var.getIdentifier() + " ="); 163 showValue(val); 164 out.println(";"); 165 } 166 } 167 } 168 169 private void showValue(Value v) { 171 if (StringList.isStringList(v)) 172 for (StringList sl = (StringList)v; sl != null; sl = sl.getRest()) { 173 String term = unscanString(sl.getString()); 174 out.print(" " + term); 175 } 176 else if (v instanceof Function) { 177 out.print(" [function"); 178 String name = ((Function)v).getName(); 179 if (name != null) 180 out.print(" " + name); 181 out.print("]"); 182 } 183 else 184 out.print(" " + v); 185 } 186 187 189 private Expression listEnd(int token, String name, 191 CompEnv env, int end) 192 throws ParseError 193 { 194 if (token == end) 195 return new Nil(); 196 else { 197 Expression exp = list(token, name, env); 198 token = scan(); 199 if (token == end) 200 return exp; 201 else 202 return expecting(end, token); 203 } 204 } 205 206 private Expression list(int token, String name, CompEnv env) 208 throws ParseError 209 { 210 return append(item(token, name, env), name, env); 211 } 212 213 private Expression append(Expression exp, String name, CompEnv env) 215 throws ParseError 216 { 217 int token = peek(); 218 if (!tokenStartsItem(token)) 219 return exp; 220 else { 221 Vector v = new Vector (); 222 v.addElement(exp); 223 do { 224 drop(); 225 v.addElement(item(token, name, env)); 226 token = peek(); 227 } 228 while (tokenStartsItem(token)); 229 Expression[] exps = new Expression[v.size()]; 230 v.copyInto(exps); 231 return new Append(exps); 232 } 233 } 234 235 237 private Expression item(int token, String name, CompEnv env) 239 throws ParseError 240 { 241 switch(token) { 242 case STRING_TOKEN: 243 return new Constant(string); 244 case IDENTIFIER_TOKEN: 245 return ident(string, env); 246 case '(': 247 return call(name, env); 248 case '{': 249 Expression exp = block(name, env); 250 token = scan(); 251 if (token == '}') 252 return exp; 253 else 254 return expecting('}', token); 255 case IF_TOKEN: 256 return cond(name, env); 257 case FUNCTION_TOKEN: 258 return funct(name, env); 259 case DO_TOKEN: 260 return loop(name, env); 261 default: 262 String msg = "Expecting an item, but found " + token2string(token); 263 throw new ParseError(file, in.getLineNumber(), msg); 264 } 265 } 266 267 private boolean tokenStartsItem(int token) { 268 switch(token) { 269 case STRING_TOKEN: 270 case IDENTIFIER_TOKEN: 271 case '(': 272 case '{': 273 case IF_TOKEN: 274 case FUNCTION_TOKEN: 275 case DO_TOKEN: 276 return true; 277 default: 278 return false; 279 } 280 } 281 282 private Expression ident(String identifier, CompEnv env) { 284 int up = 0; 285 for (; env != null; env = env.parent) { 286 for (int offset = 0; offset < env.rib.length; offset++) 287 if (identifier == env.rib[offset]) 288 return new Lexical(identifier, up, offset); 289 up++; 290 } 291 return table.get(identifier); 292 } 293 294 private Expression call(String name, CompEnv env) 296 throws ParseError 297 { 298 Expression op = item(scan(), name, env); 299 Vector v = new Vector (); 300 for (;;) { 301 int token = scan(); 302 if (tokenStartsItem(token)) { 303 v.addElement(list(token, name, env)); 304 token = scan(); 305 } 306 else 307 v.addElement(new Nil()); 308 if (token == ')') { 309 Expression exps[] = new Expression[v.size()]; 310 v.copyInto(exps); 311 return new Call(op, exps); 312 } 313 else if (token != ',') 314 return expecting(',', token); 315 } 316 } 317 318 private Expression block(String name, CompEnv env) 320 throws ParseError 321 { 322 int token = peek(); 323 if (!tokenStartsItem(token)) 324 return new Nil(); 325 drop(); 326 if (token == IDENTIFIER_TOKEN) { 327 String identifier = string; 328 token = peek(); 329 if (token == '=') { 330 drop(); 331 token = scan(); 332 CompEnv newenv = new CompEnv(env, new String [] { identifier }); 333 if (token == ';') 334 return new Let(new Nil(), block(name, newenv)); 335 else if (token == FUNCTION_TOKEN) { 336 Expression exp = funct(identifier, newenv); 337 token = scan(); 338 if (token != ';') 339 return expecting(';', token); 340 else 341 return new Letrec(exp, block(name, newenv)); 342 } 343 else { 344 Expression exp = list(token, identifier, env); 345 token = scan(); 346 if (token != ';') 347 return expecting(';', token); 348 else 349 return new Let(exp, block(name, newenv)); 350 } 351 } 352 else 353 return append(ident(identifier, env), name, env); 354 } 355 else 356 return list(token, name, env); 357 } 358 359 private Expression cond(String name, CompEnv env) 361 throws ParseError 362 { 363 Expression exp = listEnd(scan(), name, env, THEN_TOKEN); 364 Expression conseq = block(name, env); 365 int token = scan(); 366 if (token != ELSE_TOKEN) 367 return expecting(ELSE_TOKEN, token); 368 Expression altern = block(name, env); 369 token = scan(); 370 if (token == END_TOKEN) 371 return new If(exp, conseq, altern); 372 else 373 return expecting(END_TOKEN, token); 374 } 375 376 private Expression funct(String name, CompEnv env) 378 throws ParseError 379 { 380 int token = scan(); 381 if (token != '(') 382 return expecting('(', token); 383 token = scan(); 384 if (token != IDENTIFIER_TOKEN) 385 return expecting(IDENTIFIER_TOKEN, token); 386 Vector v = new Vector (); 387 v.addElement(string); 388 for (;;) { 389 token = scan(); 390 if (token == ')') { 391 String ids[] = new String [v.size()]; 392 v.copyInto(ids); 393 CompEnv newenv = new CompEnv(env, ids); 394 Expression body = block(name, newenv); 395 token = scan(); 396 if (token != END_TOKEN) 397 return expecting(END_TOKEN, token); 398 else 399 return new Lambda(name, ids.length, body); 400 } 401 else if (token != ',') 402 return expecting(',', token); 403 token = scan(); 404 if (token != IDENTIFIER_TOKEN) 405 return expecting(IDENTIFIER_TOKEN, token); 406 v.addElement(string); 407 } 408 } 409 410 private Expression loop(String name, CompEnv env) 412 throws ParseError 413 { 414 int token = scan(); 415 if (token != IDENTIFIER_TOKEN) 416 return expecting(IDENTIFIER_TOKEN, token); 417 String label = string; 418 CompEnv callEnv = new CompEnv(env, new String [] { label }); 419 token = scan(); 420 if (token != '(') 421 return expecting('(', token); 422 Vector str = new Vector (); 423 Vector inits = new Vector (); 424 token = scan(); 425 if (token != IDENTIFIER_TOKEN) 426 return expecting(IDENTIFIER_TOKEN, token); 427 str.addElement(string); 428 token = scan(); 429 if (token != '=') 430 return expecting('=', token); 431 token = scan(); 432 if (token == ')' || token == ',') 433 inits.addElement(new Nil()); 434 else { 435 inits.addElement(list(token, name, callEnv)); 436 token = scan(); 437 } 438 for (;;) { 439 if (token == ')') { 440 String ids[] = new String [str.size()]; 441 str.copyInto(ids); 442 CompEnv newenv = new CompEnv(callEnv, ids); 443 Expression body = block(name, newenv); 444 token = scan(); 445 if (token != END_TOKEN) 446 return expecting(END_TOKEN, token); 447 Expression exp = new Lambda(label, ids.length, body); 448 Expression exps[] = new Expression[inits.size()]; 449 inits.copyInto(exps); 450 return new Letrec(exp, new Call(new Lexical(name, 0, 0), exps)); 451 } 452 else if (token != ',') 453 return expecting(',', token); 454 token = scan(); 455 if (token != IDENTIFIER_TOKEN) 456 return expecting(IDENTIFIER_TOKEN, token); 457 str.addElement(string); 458 token = scan(); 459 if (token != '=') 460 return expecting('=', token); 461 token = scan(); 462 if (token == ')' || token == ',') 463 inits.addElement(new Nil()); 464 else { 465 inits.addElement(list(token, name, callEnv)); 466 token = scan(); 467 } 468 } 469 } 470 471 private Expression expecting(int wanted, int got) 472 throws ParseError 473 { 474 String msg = "Expecting " + token2string(wanted) 475 + ", but found " + token2string(got); 476 throw new ParseError(file, in.getLineNumber(), msg); 477 } 478 479 private StringList evalStringList(Expression exp) 480 throws ParseError 481 { 482 Value value; 483 try { 484 value = exp.eval(null, null); 485 } 486 catch (Exception ex) { 487 String msg = "Exception: " + ex.getMessage(); 488 throw new ParseError(file, in.getLineNumber(), msg); 489 } 490 if (StringList.isStringList(value)) 491 return (StringList)value; 492 else { 493 String msg = "Expression did not evaluate to a string list"; 494 throw new ParseError(file, in.getLineNumber(), msg); 495 } 496 } 497 498 private void rule(Expression exp) 500 throws ParseError 501 { 502 int lineNumber = in.getLineNumber(); 503 StringList targets = evalStringList(exp); 504 int token = scan(); 505 if (token != ':') 506 expecting(':', token); 507 String [] prerequisites = prerequisiteList(); 508 Command[] commands = commandList(); 509 510 if (conditionTrue) 511 for (; targets != null; targets = targets.getRest()) 512 make.addRule(targets.getString(), 513 prerequisites, 514 commands, 515 lineNumber); 516 } 517 518 private String [] prerequisiteList() 520 throws ParseError 521 { 522 Expression exp = listEnd(scan(), null, null, ';'); 523 StringList val = evalStringList(exp); 524 return StringList.list2array(val); 525 } 526 527 private Command[] commandList() 529 throws ParseError 530 { 531 int token = peek(); 532 if (token != '{') 533 return new Command[0]; 534 drop(); 535 Vector v = new Vector (); for (;;) { 537 token = scan(); 538 switch (token) { 539 case '}': Command[] cmds = new Command[v.size()]; 541 v.copyInto(cmds); 542 return cmds; 543 case IDENTIFIER_TOKEN: v.addElement(commandItem(string)); 545 break; 546 case '-': 547 token = scan(); 548 if (token == IDENTIFIER_TOKEN) { 549 Command cmd = commandItem(string); 550 cmd.setIgnore(true); 551 v.addElement(cmd); 552 break; 553 } 554 default: 556 String msg = "Expecting an identifier, "; 557 throw new ParseError(file, in.getLineNumber(), 558 msg + token2string(token)); 559 } 560 } 561 } 562 563 565 private final static ExecOperator exec = new ExecOperator(); 566 567 private final static FileOperator delete = new FileOperator() { 568 boolean exec(File arg, PrintWriter out) { 569 return arg.delete(); 570 } 571 public String getName() { 572 return "delete"; 573 } 574 }; 575 576 private final static FileOperator delall = new FileOperator() { 578 boolean exec(File arg, PrintWriter out) { 579 if (arg.isDirectory()) { 580 String [] file = arg.list(); 581 for (int i = 0; i < file.length; i++) { 582 File f = new File(arg, file[i]); 583 if (!exec(f, out)) 584 return false; 585 } 586 } 587 return arg.delete(); 588 } 589 public String getName() { 590 return "delall"; 591 } 592 }; 593 594 private final static FileOperator mkdir = new FileOperator() { 595 boolean exec(File arg, PrintWriter out) { 596 return arg.mkdir(); 597 } 598 public String getName() { 599 return "mkdir"; 600 } 601 }; 602 603 private final static FileOperator mkdirs = new FileOperator() { 604 boolean exec(File arg, PrintWriter out) { 605 return arg.mkdirs(); 606 } 607 public String getName() { 608 return "mkdirs"; 609 } 610 }; 611 612 private final static BinaryFileOperator rename = new BinaryFileOperator() { 613 boolean exec(File arg1, File arg2, PrintWriter out) { 614 if (arg1.equals(arg2)) 615 return false; 616 return arg1.renameTo(arg2); 617 } 618 public String getName() { 619 return "rename"; 620 } 621 }; 622 623 private final static BinaryFileOperator copy = new BinaryFileOperator() { 624 boolean exec(File arg1, File arg2, PrintWriter out) { 625 if (arg1.equals(arg2)) 626 return false; 627 try { 628 int bufferSize = 8192; 629 byte[] buffer = new byte[bufferSize]; 630 FileInputStream src = new FileInputStream(arg1); 631 FileOutputStream dst = new FileOutputStream(arg2); 632 for (;;) { 633 int n = src.read(buffer); 634 if (n == -1) { 635 src.close(); 636 dst.close(); 637 return true; 638 } 639 dst.write(buffer, 0, n); 640 } 641 } 642 catch (FileNotFoundException ex) { 643 out.println("Cannot open " + ex.getMessage()); 644 return false; 645 } 646 catch (IOException ex) { 647 out.println(ex.toString()); 648 return false; 649 } 650 } 651 public String getName() { 652 return "copy"; 653 } 654 }; 655 656 private final static CreateOperator create = new CreateOperator(); 657 658 private final static NoteOperator note = new NoteOperator(); 659 660 private final static ClassOperator classOperator = new ClassOperator(); 661 662 private Command commandItem(String operatorName) 664 throws ParseError 665 { 666 Operator operator; 667 if (operatorName.equals(exec.getName())) 668 operator = exec; 669 else if (operatorName.equals(delete.getName())) 670 operator = delete; 671 else if (operatorName.equals(delall.getName())) 672 operator = delall; 673 else if (operatorName.equals(mkdir.getName())) 674 operator = mkdir; 675 else if (operatorName.equals(mkdirs.getName())) 676 operator = mkdirs; 677 else if (operatorName.equals(rename.getName())) 678 operator = rename; 679 else if (operatorName.equals(copy.getName())) 680 operator = copy; 681 else if (operatorName.equals(create.getName())) 682 operator = create; 683 else if (operatorName.equals(note.getName())) 684 operator = note; 685 else if (operatorName.equals(classOperator.getName())) 686 operator = classOperator; 687 else { 688 String msg = "Unrecognized command operator: " + operatorName; 689 throw new ParseError(file, in.getLineNumber(), msg); 690 } 691 CompEnv commandEnv = new CompEnv(null, Command.commandArgs); 693 Expression exp = listEnd(scan(), null, commandEnv, ';'); 694 Function fun = new Closure(null, Command.commandArgs.length, exp, null); 695 return new Command(operator, fun); 696 } 697 698 private void include() 700 throws ParseError 701 { 702 Expression exp = listEnd(scan(), null, null, ';'); 703 StringList val = evalStringList(exp); 704 if (conditionTrue) { 705 if (verbose) { 706 out.print(INCLUDE_WORD); 707 showValue(val); 708 out.println(";"); 709 } 710 String parent = file.getParent(); for (; val != null; val = val.getRest()) { 712 String incName = StringUtils.localizePaths(val.getString()); 713 File incFile = new File(incName); 714 String incDir = null; 715 if (parent != null && !incFile.isAbsolute()) { 716 incDir = parent; 717 incFile = new File(incDir, incName); 718 } 719 try { 720 FileReader incIn = new FileReader(incFile); 721 new Loader(make, incFile, incIn, table).load(); 722 } 723 catch (FileNotFoundException ex) { 724 String msg ="Cannot find include file " + incName; 725 if (incDir != null) 726 msg += " in directory " + incDir; 727 throw new ParseError(file, in.getLineNumber(), msg); 728 } 729 } 730 } 731 } 732 733 private void conditional() 736 throws ParseError 737 { 738 boolean changeSense = conditionTrue; 739 boolean elseSeen = false; 740 Expression exp = listEnd(scan(), null, null, THEN_TOKEN); 741 StringList val = evalStringList(exp); 742 String msg; 743 if (verbose && changeSense) { 744 out.print(IF_WORD); 745 showValue(val); 746 out.println(" " + THEN_WORD); 747 } 748 if (changeSense) 749 conditionTrue = val != null; for (;;) { 751 int token = scan(); 752 switch (token) { 753 case EOF_TOKEN: 754 if (elseSeen) 755 msg = "Expecting " + END_WORD + ", "; 756 else 757 msg = "Expecting " + END_WORD + " or " + ELSE_WORD + ", "; 758 throw new ParseError(file, in.getLineNumber(), 759 msg + token2string(token)); 760 case END_TOKEN: conditionTrue = changeSense; 762 if (verbose && changeSense) 763 out.println(END_WORD); 764 return; 765 case ELSE_TOKEN: if (elseSeen) { 767 msg = "Expecting " + END_WORD + ", "; 768 throw new ParseError(file, in.getLineNumber(), 769 msg + token2string(token)); 770 } 771 elseSeen = true; 772 if (verbose && changeSense) 773 out.println(ELSE_WORD); 774 if (changeSense) 775 conditionTrue = !conditionTrue; 776 break; 777 default: 778 decl(token); } 780 } 781 } 782 783 private String token2string(int token) { 785 switch (token) { 786 case EOF_TOKEN: 787 return "[EOF]"; 788 case STRING_TOKEN: 789 return "string " + unscanString(string); 790 case IDENTIFIER_TOKEN: 791 return "identifier " + string; 792 case INCLUDE_TOKEN: 793 return "the reserved word " + INCLUDE_WORD; 794 case IF_TOKEN: 795 return "the reserved word " + IF_WORD; 796 case THEN_TOKEN: 797 return "the reserved word " + THEN_WORD; 798 case ELSE_TOKEN: 799 return "the reserved word " + ELSE_WORD; 800 case END_TOKEN: 801 return "the reserved word " + END_WORD; 802 case FUNCTION_TOKEN: 803 return "the reserved word " + FUNCTION_WORD; 804 case DO_TOKEN: 805 return "the reserved word " + DO_WORD; 806 default: return "'" + (char)token + "'"; 808 } 809 } 810 811 private static String unscanString(String s) { 812 if (s.indexOf('\\') < 0 && s.indexOf('"') < 0) 813 return "\"" + s + "\""; 814 StringBuffer sb = new StringBuffer (); 816 sb.append('"'); 817 for (int i = 0; i < s.length(); i++) { 818 char ch = s.charAt(i); 819 switch (ch) { 820 case '\\': 821 case '"': 822 sb.append('\\'); 823 default: 825 sb.append(ch); 826 } 827 } 828 sb.append('"'); 829 return sb.toString(); 830 } 831 832 835 836 840 private final static int EOF_TOKEN = -1; 842 private final static int STRING_TOKEN = -2; 843 private final static int IDENTIFIER_TOKEN = -3; 844 private final static int INCLUDE_TOKEN = -4; 845 private final static int IF_TOKEN = -5; 846 private final static int THEN_TOKEN = -6; 847 private final static int ELSE_TOKEN = -7; 848 private final static int END_TOKEN = -8; 849 private final static int FUNCTION_TOKEN = -9; 850 private final static int DO_TOKEN = -10; 851 852 private final static String INCLUDE_WORD = "include"; 854 private final static String IF_WORD = "if"; 855 private final static String THEN_WORD = "then"; 856 private final static String ELSE_WORD = "else"; 857 private final static String END_WORD = "end"; 858 private final static String FUNCTION_WORD = "function"; 859 private final static String DO_WORD = "do"; 860 861 private String string; 864 865 private int savedToken; 866 private boolean isTokenSaved = false; 867 868 873 private int peek() 874 throws ParseError 875 { 876 if (!isTokenSaved) { 877 savedToken = scan(); 878 isTokenSaved = true; 879 } 880 return savedToken; 881 } 882 883 886 private void drop() { 887 isTokenSaved = false; 888 } 889 890 private boolean isCharPushedBack = false; 893 private int pushedBackChar; 894 895 900 private int scan() 901 throws ParseError 902 { 903 try { 904 if (isTokenSaved) { isTokenSaved = false; return savedToken; } 908 909 int ch; 910 if (isCharPushedBack) { ch = pushedBackChar; isCharPushedBack = false; } 914 else 915 ch = in.read(); 916 917 for (;;) { if (ch == -1) 919 return EOF_TOKEN; 920 if (!Character.isWhitespace((char)ch)) 921 break; 922 ch = in.read(); 923 } 924 925 switch (ch) { 926 case ',': 927 case ';': 928 case ':': 929 case '-': 930 case '=': 931 case '(': 932 case ')': 933 case '{': 934 case '}': 935 return ch; 936 case '@': 937 string = "@"; 938 return IDENTIFIER_TOKEN; 939 case '<': 940 string = "<"; 941 return IDENTIFIER_TOKEN; 942 case '?': 943 string = "?"; 944 return IDENTIFIER_TOKEN; 945 case '%': 946 string = "%"; 947 return IDENTIFIER_TOKEN; 948 case '#': if (in.readLine() == null) return EOF_TOKEN; 951 else 952 return scan(); case '"': return readString(); 955 default: if (!Character.isJavaIdentifierStart((char)ch)) 957 throw new ParseError(file, in.getLineNumber(), 958 "Unrecognized character " + (char)ch); 959 return readIdentifier(ch); 960 } 961 } 962 catch (IOException ex) { 963 String msg = "I/O exception: " + ex.getMessage(); 964 throw new ParseError(file, in.getLineNumber(), msg); 965 } 966 } 967 968 private int readString() 969 throws IOException, ParseError 970 { 971 StringBuffer sb = new StringBuffer (); 972 for (;;) { 973 int ch = in.read(); 974 switch (ch) { 975 case -1: 976 throw new ParseError(file, in.getLineNumber(), 977 "EOF in string"); 978 case '"': 979 string = sb.toString(); 980 return STRING_TOKEN; 981 case '\n': 982 throw new ParseError(file, in.getLineNumber(), 983 "newline in string"); 984 985 case '\\': ch = in.read(); switch (ch) { 988 case '"': 989 break; case '\\': 991 break; 992 case -1: throw new ParseError(file, in.getLineNumber(), 994 "EOF in string"); 995 case '\n': 996 throw new ParseError(file, in.getLineNumber(), 997 "newline in string"); 998 default: 999 throw new ParseError(file, in.getLineNumber(), 1000 "Cannot escape " + (char)ch); 1001 } 1002 default: 1004 sb.append((char)ch); 1005 } 1006 } 1007 } 1008 1009 private int readIdentifier(int ch) 1010 throws IOException 1011 { 1012 StringBuffer ib = new StringBuffer (); 1013 ib.append((char)ch); 1014 for (;;) { 1015 ch = in.read(); 1016 if (ch != -1 && Character.isJavaIdentifierPart((char)ch)) 1017 ib.append((char)ch); 1018 else { 1019 isCharPushedBack = true; 1020 pushedBackChar = ch; string = ib.toString().intern(); 1022 if (string == INCLUDE_WORD) return INCLUDE_TOKEN; 1024 else if (string == IF_WORD) 1025 return IF_TOKEN; 1026 else if (string == THEN_WORD) 1027 return THEN_TOKEN; 1028 else if (string == ELSE_WORD) 1029 return ELSE_TOKEN; 1030 else if (string == END_WORD) 1031 return END_TOKEN; 1032 else if (string == FUNCTION_WORD) 1033 return FUNCTION_TOKEN; 1034 else if (string == DO_WORD) 1035 return DO_TOKEN; 1036 else 1037 return IDENTIFIER_TOKEN; 1038 } 1039 } 1040 } 1041 1042 1045 1046 1049 private static class CompEnv 1052 { 1053 final CompEnv parent; 1054 final String [] rib; 1055 1056 CompEnv(CompEnv parent, String [] rib) { 1057 this.parent = parent; 1058 this.rib = rib; 1059 } 1060 } 1061 1062 1065 1066 private static class Constant 1068 extends Expression 1069 { 1070 private final String string; 1071 1072 Constant(String string) { 1073 this.string = string; 1074 } 1075 1076 Value eval(Environment env, StringList list) { 1077 return new StringList(string, list); 1078 } 1079 } 1080 1081 private static class Lexical 1083 extends Expression 1084 { 1085 private final String identifier; 1086 private final int up; 1087 private final int offset; 1088 1089 Lexical (String identifier, int up, int offset) { 1090 this.identifier = identifier; 1091 this.up = up; 1092 this.offset = offset; 1093 } 1094 1095 Value eval(Environment env, StringList list) 1096 throws StringListCastException 1097 { 1098 Value value = Environment.lookup(env, up, offset); 1099 if (list == null) 1100 return value; 1101 else if (StringList.isStringList(value)) 1102 return StringList.append((StringList)value, list); 1103 else { 1104 String msg = "Append error: the value in " + identifier + 1105 " is not a string list"; 1106 throw new StringListCastException(msg); 1107 } 1108 } 1109 } 1110 1111 private static class Call 1113 extends Expression 1114 { 1115 private final Expression operator; 1116 private final Expression[] operands; 1117 1118 Call(Expression operator, Expression[] operands) { 1119 this.operator = operator; 1120 this.operands = operands; 1121 } 1122 1123 Value eval(Environment env, StringList list) 1124 throws Exception 1125 { 1126 int nargs = operands.length; 1127 Value[] args = new Value[nargs]; 1128 for (int i = 0; i < nargs; i++) 1129 args[i] = operands[i].eval(env, null); 1130 Value op = operator.eval(env, null); 1131 if (op instanceof Function) 1132 return ((Function)op).invoke(args, list); 1133 else { 1134 String msg = "Call error: operator not a function"; 1135 throw new FunctionCastException(msg); 1136 } 1137 } 1138 } 1139 1140 private static class Let 1142 extends Expression 1143 { 1144 private final Expression exp; 1145 private final Expression body; 1146 1147 Let(Expression exp, Expression body) { 1148 this.exp = exp; 1149 this.body = body; 1150 } 1151 1152 Value eval(Environment env, StringList list) 1153 throws Exception 1154 { 1155 Value value = exp.eval(env, null); 1156 Value[] rib = new Value[] { value }; 1157 Environment newenv = new Environment(env, rib); 1158 return body.eval(newenv, list); 1159 } 1160 } 1161 1162 private static class Letrec 1164 extends Expression 1165 { 1166 private final Expression exp; 1167 private final Expression body; 1168 1169 Letrec(Expression exp, Expression body) { 1170 this.exp = exp; 1171 this.body = body; 1172 } 1173 1174 Value eval(Environment env, StringList list) 1175 throws Exception 1176 { 1177 Value[] rib = new Value[1]; 1178 Environment newenv = new Environment(env, rib); 1179 rib[0] = exp.eval(newenv, null); 1180 return body.eval(newenv, list); 1181 } 1182 } 1183 1184 private static class If 1186 extends Expression 1187 { 1188 private final Expression condition; 1189 private final Expression consequent; 1190 private final Expression alternative; 1191 1192 If(Expression condition, Expression consequent, Expression alternative) { 1193 this.condition = condition; 1194 this.consequent = consequent; 1195 this.alternative = alternative; 1196 } 1197 1198 Value eval(Environment env, StringList list) 1199 throws Exception 1200 { 1201 Value cond = condition.eval(env, null); 1202 if (StringList.isStringList(cond)) { 1203 if (cond != null) 1204 return consequent.eval(env, list); 1205 else 1206 return alternative.eval(env, list); 1207 } 1208 else { 1209 String msg = "If error: the condition is not a string list"; 1210 throw new StringListCastException(msg); 1211 } 1212 } 1213 } 1214 1215 private static class Lambda 1217 extends Expression 1218 { 1219 private final String name; 1220 private final int nargs; 1221 private final Expression body; 1222 1223 Lambda(String name, int nargs, Expression body) { 1224 this.name = name; 1225 this.nargs = nargs; 1226 this.body = body; 1227 } 1228 1229 Value eval(Environment env, StringList list) 1230 throws StringListCastException 1231 { 1232 if (list == null) 1233 return new Closure(name, nargs, body, env); 1234 else { 1235 String msg = 1236 "Append error: a function cannot be appended to a string list"; 1237 throw new StringListCastException(msg); 1238 } 1239 } 1240 } 1241 1242 private static class Closure 1244 implements Function 1245 { 1246 private final String name; 1247 private final int nargs; 1248 private final Expression body; 1249 private final Environment env; 1250 1251 Closure(String name, int nargs, Expression body, Environment env) { 1252 this.name = name; 1253 this.nargs = nargs; 1254 this.body = body; 1255 this.env = env; 1256 } 1257 1258 public String getName() { 1259 return name; 1260 } 1261 1262 public Value invoke(Value[] args, StringList list) 1263 throws Exception 1264 { 1265 if (nargs == args.length) { 1266 Environment newenv = new Environment(env, args); 1267 return body.eval(newenv, list); 1268 } 1269 else { 1270 String msg = "Arg count error: expecting " + nargs + 1271 " but got " + args.length + " arguments"; 1272 throw new WrongArgCountException(msg); 1273 } 1274 } 1275 } 1276 1277 private static class Nil 1279 extends Expression 1280 { 1281 Nil() { 1282 } 1283 1284 Value eval(Environment env, StringList list) 1285 { 1286 return list; 1287 } 1288 } 1289 1290 private static class Append 1292 extends Expression 1293 { 1294 private final Expression[] exps; 1295 1296 Append(Expression[] exps) { 1297 this.exps = exps; 1298 } 1299 1300 Value eval(Environment env, StringList list) 1301 throws Exception 1302 { 1303 int nexps = exps.length; 1304 switch (nexps) { 1305 case 0: 1306 return list; 1307 case 1: 1308 return exps[0].eval(env, list); 1309 default: for (nexps--; nexps >= 0; nexps--) { 1311 Value value = exps[nexps].eval(env, list); 1312 if (StringList.isStringList(value)) 1313 list = (StringList)value; 1314 else { 1315 String msg = "Append error: a value in a list was not a string"; 1316 throw new StringListCastException(msg); 1317 } 1318 } 1319 return list; 1320 } 1321 } 1322 } 1323} 1324 | Popular Tags |