commit b8f1f048daff1b016c995c02056eff5c2ee08885
parent 69640b8ad79b8112d5ace2409934d3e8eba71c43
Author: tomas <tomas@logand.com>
Date: Tue, 6 Oct 2009 21:08:38 +0200
simplified parser and stream io
Diffstat:
M | wl.java | | | 428 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
1 file changed, 295 insertions(+), 133 deletions(-)
diff --git a/wl.java b/wl.java
@@ -1,10 +1,22 @@
// wl.java -- (c) 2009 Tomas Hlavaty
-import java.util.Stack;
import java.util.HashMap;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
class wl {
+ void dbg(String M) {System.out.println(M);}
+ void dbg(String M, Any E) {System.out.println(M); print(E);}
+ void dbg(String M, Any E, Any F) {System.out.println(M); print(E); print(F);}
+
void err(Object X, String M) {
if(X instanceof Any) throw new RuntimeException(M + ": " + str((Any) X));
throw new RuntimeException(M + ": " + X);
@@ -43,21 +55,42 @@ class wl {
}
// reader
- final static Any Qte = new Any(null, null, null, null);
final static Any Lp = new Any(null, null, null, null);
final static Any Rp = new Any(null, null, null, null);
- String L;
- int N, I, D;
+ final Any Qte = new Any("quote", NIL, NIL, null);
+ final Any Dot = new Any(".", NIL, NIL, null);
+
+ class In {
+ Character c;
+ InputStream s;
+ public In(InputStream S) {c = null; s = S;}
+ }
+
+ final Any In = new Any("*In", null, null, new In(System.in));
+ final Any Out = new Any("*Out", null, null, System.out);
- void init(String L) {this.L = L; this.N = L.length(); this.I = 0; this.D = 0;}
+ Character peek() {
+ In I = (In) In.cxr;
+ try {
+ if(null == I.c) I.c = (char) I.s.read();
+ } catch(Exception e) {}
+ return I.c;
+ }
+ Character xchar() {
+ peek();
+ In I = (In) In.cxr;
+ Character Z = I.c;
+ I.c = null;
+ return Z;
+ }
boolean charIn(Character C, String L) {return 0 <= L.indexOf(C);}
- Character peek() {return this.I < this.N ? this.L.charAt(this.I) : null;}
- Character xchar() {return this.I < this.N ? this.L.charAt(this.I++) : null;}
+
void skip() {
- while(this.I < this.N && charIn(this.L.charAt(this.I), " \t\n\r"))
- this.I++;
+ Character Z;
+ while((Z = peek()) != null && charIn(Z, " \t\n\r"))
+ xchar();
}
void comment() {
while('#' == peek()) {
@@ -114,102 +147,21 @@ class wl {
case '#': comment(); return null;
case '"': xchar(); return text();
case '\'': xchar(); return Qte;
- case '(': xchar(); this.D++; return Lp;
- case ')': xchar(); this.D--; return Rp;
+ case '(': xchar(); return Lp;
+ case ')': xchar(); return Rp;
default: return symbol();
}
}
- // parser
- Any parseBuild(Stack<Any> Os) {
- Any Z = NIL;
- Any Dot = null;
- while(0 < Os.size()) {
- Any X = Os.pop();
- if(Lp == X) return Dot != null ? cons(Dot, cons(Z, NIL)) : Z;
- Dot = null;
- if(X.isSym() && (".".equals(X.nm))) {
- if(Z.isCons() && NIL == Z.cdr) {
- Z = Z.car;
- Dot = X;
- } else err("Bad dotted pair");
- } else if(X == Qte)
- Z = cons(cons(this.Sd.get("quote"), Z.car), Z.cdr);
- else Z = cons(X, Z);
- }
- err("Missing mark");
- return NIL; // make compiler happy:-{
- }
- public Any parse(String L) {
- init(L);
- Stack<Any> Os = new Stack<Any>();
- Os.push(Lp);
- // TODO circular list .
- // TODO interpret while reading ~ for each top-level sexp
- // TODO no wasteful consing
- while(null != peek()) {
- Any X = token();
- if(null != X) {
- if(Rp == X) Os.push(parseBuild(Os));
- else Os.push(X);
- }
- }
- Any Z = parseBuild(Os);
- if(0 < Os.size()) err(Os, "Incomplete input");
- return Z;
- }
-
- // printer
- public String str(Any L) {
- StringBuilder A = new StringBuilder();
- if(L.isSym()) A.append(L.nm);
- else if(L.isInt()) A.append(L.cxr.toString());
- else if(L.isCons()) {
- if(this.Sd.get("quote") == L.car) {
- A.append('\'');
- A.append(str(L.cdr));
- } else {
- A.append('(');
- while(L.isCons()) {
- A.append(str(L.car));
- L = L.cdr;
- if(NIL != L) A.append(' ');
- }
- if(NIL != L) {
- A.append(". ");
- A.append(str(L));
- }
- A.append(')');
- }
- } else if(L.isStr()) {
- A.append('"');
- String S = (String) L.cxr;
- for(int I = 0; I < S.length(); I++) {
- Character C = S.charAt(I);
- if('\\' == C) A.append("\\\\");
- else if('"' == C) A.append("\\\"");
- else A.append(C);
- }
- A.append('"');
- } else err(L, "Don't know how to print");
- return A.toString();
- }
-
-
// evaluator
HashMap<String, Any> Sd = new HashMap<String, Any>();
Any intern(String Nm) {
- if(!this.Sd.containsKey(Nm)) this.Sd.put(Nm, new Any(Nm, NIL, NIL, null));
- return this.Sd.get(Nm);
+ if(!Sd.containsKey(Nm)) Sd.put(Nm, new Any(Nm, NIL, NIL, null));
+ return Sd.get(Nm);
}
- // void def(String Nm, Fn F) {
- // if(this.Sd.containsKey(Nm)) this.Sd.get(Nm).cxr = F;
- // else this.Sd.put(Nm, new Sym(Nm, null, null, F));
- // }
Any run(Any E) {
- System.out.println("run: " + str(E));
Any Z = NIL;
while(NIL != E) {
Z = eval(E.car);
@@ -218,7 +170,7 @@ class wl {
return Z;
}
Any eval(Any E) {
- System.out.println("eval: " + str(E));
+ //dbg("eval", E);
Any Z = NIL;
if(E.isInt()) Z = E;
else if(E.isSym()) Z = E.cdr;
@@ -229,19 +181,28 @@ class wl {
if(X.isFn()) Z = ((Fn) X.cxr).fn(E);
else err(E, "TODO ap"); //Z = ap(E);
} else err(E, "Unexpected function type");
- } else Z = E; // string
- //alert("ev: " + str(E) + " => " + Z);
+ } else if(E.isStr()) Z = E;
+ else err(E, "Don't know how to eval");
+ //dbg("eval", E, Z);
return Z;
}
- void fn(String Nm, Fn F) {this.Sd.put(Nm, new Any(Nm, null, null, F));}
+ void fn(String Nm, Fn F) {
+ Any Z = Sd.get(Nm);
+ if(null != Z) Z.cxr = F;
+ else Sd.put(Nm, new Any(Nm, null, null, F));
+ }
public wl() {
Sd.put("NIL", NIL);
Sd.put("T", T);
-
- fn("run", new Fn() {public Any fn(Any E) {return run(E);}});
- fn("eval", new Fn() {public Any fn(Any E) {return eval(E);}});
+ Sd.put("quote", Qte);
+ Sd.put(".", Dot);
+ Sd.put("*In", In);
+ Sd.put("*Out", Out);
+
+ fn("run", new Fn() {public Any fn(Any E) {return run(E.cdr.car);}});
+ fn("eval", new Fn() {public Any fn(Any E) {return eval(eval(E.cdr.car));}});
fn("quote", new Fn() {public Any fn(Any E) {return E.cdr;}});
fn("car", new Fn() {public Any fn(Any E) {return eval(E.cdr.car).car;}});
fn("cdr", new Fn() {public Any fn(Any E) {return eval(E.cdr.car).cdr;}});
@@ -283,6 +244,18 @@ class wl {
}
return Z;
}});
+ fn("%", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ Any Z = eval(X.car);
+ if(NIL == Z) return NIL;
+ while(NIL != X.cdr) {
+ X = X.cdr;
+ Any Y = eval(X.car);
+ if(NIL == Y) return NIL;
+ Z.cxr = (Integer) Z.cxr % (Integer) Y.cxr;
+ }
+ return Z;
+ }});
fn("loop", new Fn() {public Any fn(Any E) {
// TODO @
while(true) {
@@ -303,27 +276,240 @@ class wl {
return eval(X.car) == eval(X.cdr.car) ? T : NIL;
}});
+ fn("peek", new Fn() {public Any fn(Any E) {
+ Character X = peek();
+ return null == X ? NIL : mkStr(X.toString());
+ }});
+ fn("char", new Fn() {public Any fn(Any E) {
+ Character X = xchar();
+ return null == X ? NIL : mkStr(X.toString());
+ }});
+ fn("skip", new Fn() {public Any fn(Any E) {skip(); return NIL;}});
+ fn("read", new Fn() {public Any fn(Any E) {return read();}});
+ fn("print", new Fn() {public Any fn(Any E) {
+ PrintStream S = (PrintStream) Out.cxr;
+ Any Z = NIL;
+ int I = 0;
+ for(Any X = E.cdr; NIL != X; X = X.cdr) {
+ if(0 < I++) S.print(' ');
+ Z = eval(X.car);
+ print(Z);
+ }
+ return Z;
+ }});
+
fn("in", new Fn() {public Any fn(Any E) {
Any X = E.cdr;
- Any N = eval(E.car);
- String F;
+ Any N = eval(X.car);
+ String F = null;
if(N.isStr()) F = (String) N.cxr;
else if(N.isSym()) F = N.nm;
else err(E, "File name expected");
- //FileInputStream S = new FileInputStream(N);
- //InputStreamReader R = new InputStreamReader(S, "UTF-8");
+ In S = null;
+ try {
+ S = new In(new FileInputStream(F));
+ In I = (In) In.cxr;
+ In.cxr = S;
+ Any Z = run(X.cdr);
+ In.cxr = I;
+ S.s.close();
+ return Z;
+ } catch(FileNotFoundException e) {
+ err(E, "File not found");
+ } catch(IOException e) {
+ err(E, "Error closing input");
+ }
+ return NIL; // make the compiler happy:-{
+ }});
+ fn("out", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ Any N = eval(X.car);
+ String F = null;
+ if(N.isStr()) F = (String) N.cxr;
+ else if(N.isSym()) F = N.nm;
+ else err(E, "File name expected");
+ try {
+ FileOutputStream B = new FileOutputStream(F);
+ PrintStream S = new PrintStream(B);
+ OutputStream O = (OutputStream) Out.cxr;
+ Out.cxr = S;
+ Any Z = run(X.cdr);
+ Out.cxr = O;
+ S.close();
+ return Z;
+ } catch(FileNotFoundException e) {
+ err(E, "File not found");
+ }
+ return NIL; // make the compiler happy:-{
+ }});
+ fn("load", new Fn() {public Any fn(Any E) {
+ Any Z = NIL;
+ for(Any X = E.cdr; NIL != X; X = X.cdr) {
+ Any N = eval(X.car);
+ String F = null;
+ if(N.isStr()) F = (String) N.cxr;
+ else if(N.isSym()) F = N.nm;
+ else err(E, "File name expected");
+ In S = null;
+ try {
+ S = new In(new FileInputStream(F));
+ In I = (In) In.cxr;
+ In.cxr = S;
+ do Z = eval(read());
+ while(null != peek());
+ In.cxr = I;
+ S.s.close();
+ return Z;
+ } catch(FileNotFoundException e) {
+ err(E, "File not found");
+ } catch(IOException e) {
+ err(E, "Error closing input");
+ }
+ }
+ return Z;
+ }});
+
+ fn("def", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ Any N = eval(X.car);
+ if(!N.isSym()) err(E, "Symbol expected");
+ if(!Sd.containsKey(N.nm)) err(E, "Symbol not interned");
+ Any V = eval(X.cdr.car);
+ Sd.get(N.nm).cdr = V;
+ return N;
+ }});
+ fn("val", new Fn() {public Any fn(Any E) {
+ Any Z = NIL;
+ Any X = eval(E.cdr.car);
+ if(X.isSym()) Z = X.cdr;
+ else if(X.isStr()) Z = X;
+ else if(X.isCons()) Z = X.car;
+ else err(E, "Expected sym|str|cell");
+ return Z;
+ }});
+ fn("cons", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ return cons(eval(X.car), eval(X.cdr.car));
+ }});
+
+ fn("gc", new Fn() {public Any fn(Any E) {
+ Runtime r = Runtime.getRuntime();
+ r.gc();
return NIL;
}});
- //FileOutputStream fos = new FileOutputStream("test.txt");
- //OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
+ fn("heap", new Fn() {public Any fn(Any E) {
+ Runtime R = Runtime.getRuntime();
+ long A = R.freeMemory();
+ long B = R.totalMemory();
+ long C = R.maxMemory();
+ long Z = B - A;
+ if(NIL != E.cdr) {
+ if(T == eval(E.cdr.car)) Z = A;
+ else Z = C;
+ }
+ return mkInt("" + Z / (1024 * 1024));
+ }});
}
+ void repl() {
+ PrintStream S = (PrintStream) Out.cxr;
+ do {
+ prompt();
+ Any Z = eval(read());
+ // TODO only on terminal
+ S.print("-> ");
+ print(Z);
+ S.println();
+ } while(null != peek());
+ }
+ void prompt() {
+ // TODO only on terminal
+ PrintStream S = (PrintStream) Out.cxr;
+ S.print(": ");
+ }
+ Any read() {
+ // TODO handle \n from user
+ return read1();
+ }
+ Any read1() {
+ Any Z = token();
+ if(Qte == Z) Z = cons(Qte, read1());
+ else if(Lp == Z) Z = readL();
+ return Z;
+ }
+ Any readL() {
+ // TODO circular list .
+ // TODO cons .
+ Any Z = NIL;
+ Any X;
+ while(null != (X = read1()) && Rp != X)
+ Z = cons(X, Z);
+ return flip(Z);
+ }
+ void print(Any E) {
+ PrintStream S = (PrintStream) Out.cxr;
+ if(E.isSym()) S.print(E.nm);
+ else if(E.isInt()) S.print(E.cxr);
+ else if(E.isCons()) {
+ if(Qte == E.car) {
+ S.print('\'');
+ print(E.cdr);
+ } else {
+ S.print('(');
+ while(E.isCons()) {
+ print(E.car);
+ E = E.cdr;
+ if(NIL != E) S.print(' ');
+ }
+ if(NIL != E) {
+ S.print(". ");
+ print(E);
+ }
+ S.print(')');
+ }
+ } else if(E.isStr()) {
+ S.print('"');
+ String X = (String) E.cxr;
+ for(int I = 0; I < X.length(); I++) {
+ Character C = X.charAt(I);
+ if('\\' == C) S.print("\\\\");
+ else if('"' == C) S.print("\\\"");
+ else S.print(C);
+ }
+ S.print('"');
+ } else err(E, "Don't know how to print");
+ }
+ String str(Any E) {
+ ByteArrayOutputStream B = new ByteArrayOutputStream();
+ PrintStream S = new PrintStream(B);
+ PrintStream O = (PrintStream) Out.cxr;
+ Out.cxr = S;
+ print(E);
+ Out.cxr = O;
+ try {
+ String Z = B.toString("UTF-8");
+ S.close();
+ return Z;
+ } catch(UnsupportedEncodingException e) {
+ err(E, "Unsupported encoding");
+ }
+ return null; // make the compiler happy:-{
+ }
+ Any flip(Any E) {
+ Any Z = NIL;
+ while(E.isCons()) {
+ Any X = E;
+ E = E.cdr;
+ X.cdr = Z;
+ Z = X;
+ }
+ return Z;
+ }
public static void main(String args[]) {
wl X = new wl();
- System.out.println(X.str(X.parse("(- 1 2 3)")));
- System.out.println(X.str(X.run(X.parse("(- 1 2 3)(- 3 5)(/ "))));
+ X.repl();
}
}
@@ -343,29 +529,5 @@ class wl {
// } else throw "Function expected";
// }
-// //def("apply", ap);
-
-// def("val", function(E) {
-// var Z;
-// var X = ev(E.cdr.car);
-// if(typeof X == "number") throw "Variable expected";
-// else if(isSym(X)) Z = X.cdr;
-// else if(isCons(X)) Z = X.car;
-// else Z = X; // string
-// return Z;
-// });
-// def(".cons", function(E) {return cons(ev(E.cdr.car), ev(E.cdr.cdr.car));});
-
-// // TODO def !!!!!!!!!!!!!
-
-// // OK
-
-// // Sd["%"] = function(E) {var X = Os.pop(); Os.push(Os.pop() % X);};
// // Sd["eq"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X == Y);};
// // Sd["lt"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X < Y);};
-
-// // function eq(X, Y) {
-// // if(X === Y) return T;
-// // //if(X == Y) return T;
-// // return NIL;
-// // }