From b032d1c2f1aacd938b4a823bd400937f8fee0e42 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:00:51 +0000 Subject: [PATCH] 2003/06/07 11:04:13 darcs-hash:20040130070051-2ba56-2190a602c61da80782b142e03cc11e7157b05263.gz --- src/org/xwt/js/ForthBlock.java | 539 ++++++++++++++++++++-------------------- src/org/xwt/js/Parser.java | 256 ++++++++++--------- 2 files changed, 406 insertions(+), 389 deletions(-) diff --git a/src/org/xwt/js/ForthBlock.java b/src/org/xwt/js/ForthBlock.java index 0cc4ed2..4741d76 100644 --- a/src/org/xwt/js/ForthBlock.java +++ b/src/org/xwt/js/ForthBlock.java @@ -18,309 +18,310 @@ class ForthBlock implements OpCodes, Tokens { public int size() { return size; } public void set(int pos, int op_, Object arg_) { op[pos] = op_; arg[pos] = arg_; } + public void paste(ForthBlock other) { for(int i=0; i= 0; j--) arguments.setElementAt(t.pop(), j); - JS.Function f = (JS.Function)t.pop(); - if (f == null) throw new JS.Exn(new EvaluatorException(line, sourceName, "attempted to call null")); - t.push(f.call(arguments)); - break; - } + case GET_PRESERVE: { + Object v = t.pop(); + Object o = t.peek(); + t.push(v); + t.push(doGet(o, v)); + break; + } + + case CALL: { + JS.Array arguments = new JS.Array(); + int numArgs = JS.toNumber(arg[i]).intValue(); + arguments.setSize(numArgs); + for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(t.pop(), j); + JS.Function f = (JS.Function)t.pop(); + if (f == null) throw new JS.Exn(new EvaluatorException(line, sourceName, "attempted to call null")); + t.push(f.call(arguments)); + break; + } - case OpCodes.FUNCTION: { - final ForthBlock myBytes = (ForthBlock)arg[i]; - t.push(new JS.Function() { - public String toString() { return sourceName + ":" + line; } - public String getSourceName() throws JS.Exn { return sourceName; } - public int getLine() throws JS.Exn { return line; } - public Object _call(final JS.Array args) throws JS.Exn { - Function save = JS.getCurrentFunction(); - JS.currentFunction.put(java.lang.Thread.currentThread(), this); - JS.Scope scope = new JS.Scope(s) { - // FIXME - public String getSourceName() { return sourceName; } - public Object get(Object key) throws JS.Exn { - if (key.equals("trapee")) return org.xwt.Trap.currentTrapee(); - else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction; - return super.get(key); - } - }; - Stack t0 = new Stack(); - t0.push(args); - try { - return myBytes.eval(scope, t0); - } catch (ReturnException r) { - return r.retval; - } catch (ControlTransferException c) { - throw new EvaluatorException(line, sourceName, "error, ControlTransferException tried to leave a function: " + c); - } finally { - if (save == null) JS.currentFunction.remove(java.lang.Thread.currentThread()); - else JS.currentFunction.put(java.lang.Thread.currentThread(), save); - } - } - }); - break; - } + case OpCodes.FUNCTION: { + final ForthBlock myBytes = (ForthBlock)arg[i]; + t.push(new JS.Function() { + public String toString() { return sourceName + ":" + line; } + public String getSourceName() throws JS.Exn { return sourceName; } + public int getLine() throws JS.Exn { return line; } + public Object _call(final JS.Array args) throws JS.Exn { + Function save = JS.getCurrentFunction(); + JS.currentFunction.put(java.lang.Thread.currentThread(), this); + JS.Scope scope = new JS.Scope(s) { + // FIXME + public String getSourceName() { return sourceName; } + public Object get(Object key) throws JS.Exn { + if (key.equals("trapee")) return org.xwt.Trap.currentTrapee(); + else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction; + return super.get(key); + } + }; + Stack t0 = new Stack(); + t0.push(args); + try { + return myBytes.eval(scope, t0); + } catch (ReturnException r) { + return r.retval; + } catch (ControlTransferException c) { + throw new EvaluatorException(line, sourceName, "error, ControlTransferException tried to leave a function: " + c); + } finally { + if (save == null) JS.currentFunction.remove(java.lang.Thread.currentThread()); + else JS.currentFunction.put(java.lang.Thread.currentThread(), save); + } + } + }); + break; + } - case Lexer.INC: case Lexer.DEC: { - boolean isPrefix = JS.toBoolean(arg[i]); - Object key = t.pop(); - JS obj = (JS)t.pop(); - Number num = JS.toNumber(obj.get(key)); - Number val = new Double(op[i] == Lexer.INC ? num.doubleValue() + 1.0 : num.doubleValue() - 1.0); - obj.put(key, val); - t.push(isPrefix ? val : num); - break; - } + case Lexer.INC: case Lexer.DEC: { + boolean isPrefix = JS.toBoolean(arg[i]); + Object key = t.pop(); + JS obj = (JS)t.pop(); + Number num = JS.toNumber(obj.get(key)); + Number val = new Double(op[i] == Lexer.INC ? num.doubleValue() + 1.0 : num.doubleValue() - 1.0); + obj.put(key, val); + t.push(isPrefix ? val : num); + break; + } - default: { - Object right = t.pop(); - Object left = t.pop(); - switch(op[i]) { + default: { + Object right = t.pop(); + Object left = t.pop(); + switch(op[i]) { - case Lexer.BITOR: t.push(new Long(JS.toLong(left) | JS.toLong(right))); break; - case Lexer.BITXOR: t.push(new Long(JS.toLong(left) ^ JS.toLong(right))); break; - case Lexer.BITAND: t.push(new Long(JS.toLong(left) & JS.toLong(right))); break; + case Lexer.BITOR: t.push(new Long(JS.toLong(left) | JS.toLong(right))); break; + case Lexer.BITXOR: t.push(new Long(JS.toLong(left) ^ JS.toLong(right))); break; + case Lexer.BITAND: t.push(new Long(JS.toLong(left) & JS.toLong(right))); break; - case Lexer.ADD: { - Object l = left; - Object r = right; - if (l instanceof String || r instanceof String) { - if (l == null) l = "null"; - if (r == null) r = "null"; - if (l instanceof Number && ((Number)l).doubleValue() == ((Number)l).longValue()) - l = new Long(((Number)l).longValue()); - if (r instanceof Number && ((Number)r).doubleValue() == ((Number)r).longValue()) - r = new Long(((Number)r).longValue()); - t.push(l.toString() + r.toString()); break; - } - t.push(new Double(JS.toDouble(l) + JS.toDouble(r))); break; - } - - case Lexer.SUB: t.push(new Double(JS.toDouble(left) - JS.toDouble(right))); break; - case Lexer.MUL: t.push(new Double(JS.toDouble(left) * JS.toDouble(right))); break; - case Lexer.DIV: t.push(new Double(JS.toDouble(left) / JS.toDouble(right))); break; - case Lexer.MOD: t.push(new Double(JS.toDouble(left) % JS.toDouble(right))); break; - - case Lexer.LSH: t.push(new Long(JS.toLong(left) << JS.toLong(right))); break; - case Lexer.RSH: t.push(new Long(JS.toLong(left) >> JS.toLong(right))); break; - case Lexer.URSH: t.push(new Long(JS.toLong(left) >>> JS.toLong(right))); break; - - // FIXME: these need to work on strings - case Lexer.LT: t.push(JS.toDouble(left) < JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - case Lexer.LE: t.push(JS.toDouble(left) <= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - case Lexer.GT: t.push(JS.toDouble(left) > JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - case Lexer.GE: t.push(JS.toDouble(left) >= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - - case Lexer.EQ: - case Lexer.NE: { - // FIXME: should use Javascript coercion-equality rules - Object l = left; - Object r = right; - boolean ret; - if (l == null) { Object tmp = r; r = l; l = tmp; } - if (l == null && r == null) ret = true; - else if (l instanceof Boolean) ret = new Boolean(JS.toBoolean(r)).equals(l); - else if (l instanceof Number) ret = JS.toNumber(r).doubleValue() == JS.toNumber(l).doubleValue(); - else if (l instanceof String) ret = r != null && l.equals(r.toString()); - else ret = l.equals(r); - t.push(new Boolean(op[i] == Lexer.EQ ? ret : !ret)); break; - } + case Lexer.ADD: { + Object l = left; + Object r = right; + if (l instanceof String || r instanceof String) { + if (l == null) l = "null"; + if (r == null) r = "null"; + if (l instanceof Number && ((Number)l).doubleValue() == ((Number)l).longValue()) + l = new Long(((Number)l).longValue()); + if (r instanceof Number && ((Number)r).doubleValue() == ((Number)r).longValue()) + r = new Long(((Number)r).longValue()); + t.push(l.toString() + r.toString()); break; + } + t.push(new Double(JS.toDouble(l) + JS.toDouble(r))); break; + } + + case Lexer.SUB: t.push(new Double(JS.toDouble(left) - JS.toDouble(right))); break; + case Lexer.MUL: t.push(new Double(JS.toDouble(left) * JS.toDouble(right))); break; + case Lexer.DIV: t.push(new Double(JS.toDouble(left) / JS.toDouble(right))); break; + case Lexer.MOD: t.push(new Double(JS.toDouble(left) % JS.toDouble(right))); break; + + case Lexer.LSH: t.push(new Long(JS.toLong(left) << JS.toLong(right))); break; + case Lexer.RSH: t.push(new Long(JS.toLong(left) >> JS.toLong(right))); break; + case Lexer.URSH: t.push(new Long(JS.toLong(left) >>> JS.toLong(right))); break; + + // FIXME: these need to work on strings + case Lexer.LT: t.push(JS.toDouble(left) < JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + case Lexer.LE: t.push(JS.toDouble(left) <= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + case Lexer.GT: t.push(JS.toDouble(left) > JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + case Lexer.GE: t.push(JS.toDouble(left) >= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + + case Lexer.EQ: + case Lexer.NE: { + // FIXME: should use Javascript coercion-equality rules + Object l = left; + Object r = right; + boolean ret; + if (l == null) { Object tmp = r; r = l; l = tmp; } + if (l == null && r == null) ret = true; + else if (l instanceof Boolean) ret = new Boolean(JS.toBoolean(r)).equals(l); + else if (l instanceof Number) ret = JS.toNumber(r).doubleValue() == JS.toNumber(l).doubleValue(); + else if (l instanceof String) ret = r != null && l.equals(r.toString()); + else ret = l.equals(r); + t.push(new Boolean(op[i] == Lexer.EQ ? ret : !ret)); break; + } - default: throw new Error("unknown opcode " + op[i]); - } } - } - if (t.size() != 1) { - for(int i=0; i= 0 ? codeToString[op[i]] : "" + op[i]) + " [" + arg[i] + "]"); - } - throw new EvaluatorException(line, sourceName, "eval() terminated with " + t.size() + " elements on the stack; one expected"); - } - return t.pop(); + default: throw new Error("unknown opcode " + op[i]); + } } + } + if (t.size() != 1) { + for(int i=0; i= 0 ? codeToString[op[i]] : "" + op[i]) + " [" + arg[i] + "]"); + } + throw new EvaluatorException(line, sourceName, "eval() terminated with " + t.size() + " elements on the stack; one expected"); + } + return t.pop(); } public Object doGet(final Object o, final Object v) { - if (o == null) { - throw new EvaluatorException(line, sourceName, "tried to get property \"" + v + "\" from the null value"); - } - if (o instanceof String) { - if (v.equals("length")) return new Integer(((String)o).length()); - else if (v.equals("substring")) return new JS.Function() { - public Object _call(JS.Array args) { - if (args.length() == 1) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue()); - else if (args.length() == 2) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue(), - JS.toNumber(args.elementAt(1)).intValue()); - else throw new Error("String.substring() can only take one or two arguments"); - } - }; - else if (v.equals("toLowerCase")) return new JS.Function() { - public Object _call(JS.Array args) { - return ((String)o).toLowerCase(); - } }; - else if (v.equals("toUpperCase")) return new JS.Function() { - public Object _call(JS.Array args) { - return ((String)o).toString().toUpperCase(); - } }; - else if (v.equals("charAt")) return new JS.Function() { - public Object _call(JS.Array args) { - return ((String)o).charAt(JS.toNumber(args.elementAt(0)).intValue()) + ""; - } }; - else if (v.equals("lastIndexOf")) return new JS.Function() { - public Object _call(JS.Array args) { - if (args.length() != 1) return null; - return new Integer(((String)o).lastIndexOf(args.elementAt(0).toString())); - } }; - else if (v.equals("indexOf")) return new JS.Function() { - public Object _call(JS.Array args) { - if (args.length() != 1) return null; - return new Integer(((String)o).indexOf(args.elementAt(0).toString())); - } }; - throw new Error("Not Implemented: propery " + v + " on String objects"); - } else if (o instanceof Boolean) { - throw new Error("Not Implemented: properties on Boolean objects"); - } else if (o instanceof Number) { - Log.log(this, "Not Implemented: properties on Number objects"); - return null; - //throw new Error("Not Implemented: properties on Number objects"); - } else if (o instanceof JS) { - return ((JS)o).get(v); - } - return null; + if (o == null) { + throw new EvaluatorException(line, sourceName, "tried to get property \"" + v + "\" from the null value"); + } + if (o instanceof String) { + if (v.equals("length")) return new Integer(((String)o).length()); + else if (v.equals("substring")) return new JS.Function() { + public Object _call(JS.Array args) { + if (args.length() == 1) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue()); + else if (args.length() == 2) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue(), + JS.toNumber(args.elementAt(1)).intValue()); + else throw new Error("String.substring() can only take one or two arguments"); + } + }; + else if (v.equals("toLowerCase")) return new JS.Function() { + public Object _call(JS.Array args) { + return ((String)o).toLowerCase(); + } }; + else if (v.equals("toUpperCase")) return new JS.Function() { + public Object _call(JS.Array args) { + return ((String)o).toString().toUpperCase(); + } }; + else if (v.equals("charAt")) return new JS.Function() { + public Object _call(JS.Array args) { + return ((String)o).charAt(JS.toNumber(args.elementAt(0)).intValue()) + ""; + } }; + else if (v.equals("lastIndexOf")) return new JS.Function() { + public Object _call(JS.Array args) { + if (args.length() != 1) return null; + return new Integer(((String)o).lastIndexOf(args.elementAt(0).toString())); + } }; + else if (v.equals("indexOf")) return new JS.Function() { + public Object _call(JS.Array args) { + if (args.length() != 1) return null; + return new Integer(((String)o).indexOf(args.elementAt(0).toString())); + } }; + throw new Error("Not Implemented: propery " + v + " on String objects"); + } else if (o instanceof Boolean) { + throw new Error("Not Implemented: properties on Boolean objects"); + } else if (o instanceof Number) { + Log.log(this, "Not Implemented: properties on Number objects"); + return null; + //throw new Error("Not Implemented: properties on Number objects"); + } else if (o instanceof JS) { + return ((JS)o).get(v); + } + return null; } static class Stack { - public Object[] os = new Object[256]; - private int size = 0; - public void push(Object o) { os[size++] = o; } - public Object pop() { return os[--size]; } - public Object peek() { return os[size - 1]; } - public void swap() { Object temp = os[size - 1]; os[size - 1] = os[size - 2]; os[size - 2] = temp; } - public int size() { return size; } + public Object[] os = new Object[256]; + private int size = 0; + public void push(Object o) { os[size++] = o; } + public Object pop() { return os[--size]; } + public Object peek() { return os[size - 1]; } + public void swap() { Object temp = os[size - 1]; os[size - 1] = os[size - 2]; os[size - 2] = temp; } + public int size() { return size; } } static class EvaluatorException extends RuntimeException { - public EvaluatorException(int line, String sourceName, String s) { super(sourceName + ":" + line + " " + s); } + public EvaluatorException(int line, String sourceName, String s) { super(sourceName + ":" + line + " " + s); } } static abstract class ControlTransferException extends Exception { } static class BreakException extends ControlTransferException { - public String label; - BreakException(String label) { this.label = label; } + public String label; + BreakException(String label) { this.label = label; } } static class ContinueException extends ControlTransferException { - public String label; - ContinueException(String label) { this.label = label; } + public String label; + ContinueException(String label) { this.label = label; } } static class ReturnException extends ControlTransferException { - public Object retval; - ReturnException(Object retval) { this.retval = retval; } + public Object retval; + ReturnException(Object retval) { this.retval = retval; } } } diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index cc55164..f7eb500 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -67,74 +67,83 @@ public class Parser extends Lexer implements OpCodes { /** append the largest expression beginning with prefix containing no operators of precedence below minPrecedence */ public ForthBlock startExpr() throws IOException { return startExpr(-1); } - public ForthBlock startExpr(int minPrecedence) throws IOException { return startExpr(minPrecedence, new ForthBlock(line, sourceName)); } - public ForthBlock startExpr(int minPrecedence, ForthBlock appendTo) throws IOException { + public void startExpr(ForthBlock block) throws IOException { startExpr(-1, block); } + public ForthBlock startExpr(int minPrecedence) throws IOException { + ForthBlock ret = new ForthBlock(line, sourceName); + startExpr(minPrecedence, ret); + return ret.size() == 0 ? null : ret; + } + public void startExpr(int minPrecedence, ForthBlock appendTo) throws IOException { int tok = getToken(); int curLine = line; - if (tok == -1) return null; + if (tok == -1) return; if (minPrecedence > 0 && precedence[tok] != 0) if (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok])) - { pushBackToken(); return null; } + { pushBackToken(); return; } ForthBlock b = appendTo; switch (tok) { - case NUMBER: return continueExpr(b.add(ForthBlock.LITERAL, number), minPrecedence); - case STRING: return continueExpr(b.add(ForthBlock.LITERAL, string), minPrecedence); - case THIS: return continueExpr(b.add(THIS, null), minPrecedence); - case NULL: return continueExpr(b.add(ForthBlock.LITERAL, null), minPrecedence); - case TRUE: case FALSE: return continueExpr(b.add(ForthBlock.LITERAL, new Boolean(tok == TRUE)), minPrecedence); + case NUMBER: continueExpr(b.add(ForthBlock.LITERAL, number), minPrecedence); return; + case STRING: continueExpr(b.add(ForthBlock.LITERAL, string), minPrecedence); return; + case THIS: continueExpr(b.add(THIS, null), minPrecedence); return; + case NULL: continueExpr(b.add(ForthBlock.LITERAL, null), minPrecedence); return; + case TRUE: case FALSE: continueExpr(b.add(ForthBlock.LITERAL, new Boolean(tok == TRUE)), minPrecedence); return; case LB: { b.add(b.ARRAY, new Integer(0)); int i = 0; while(true) { - ForthBlock e = startExpr(); - if (e == null && peekToken() == RB) { consume(RB); return continueExpr(b, minPrecedence); } + int size = b.size(); + startExpr(b); + if (size == b.size()) + if (peekToken() == RB) { consume(RB); continueExpr(b, minPrecedence); return; } b.add(b.LITERAL, new Integer(i++)); - if (e == null) b.add(b.LITERAL, null); - else b.add(b.EXPR, e); + if (size == b.size()) b.add(b.LITERAL, null); b.add(b.PUT); b.add(b.POP); - if (peekToken() == RB) { consume(RB); return continueExpr(b, minPrecedence); } + if (peekToken() == RB) { consume(RB); continueExpr(b, minPrecedence); return; } consume(COMMA); } } case SUB: { consume(NUMBER); - return continueExpr(b.add(ForthBlock.LITERAL, new Double(number.doubleValue() * -1)), minPrecedence); + continueExpr(b.add(ForthBlock.LITERAL, new Double(number.doubleValue() * -1)), minPrecedence); + return; } case LP: { - b.add(EXPR, startExpr()); + startExpr(b); consume(RP); - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case INC: case DEC: { // prefix - ForthBlock subexp = startExpr(precedence[tok]); - subexp.set(subexp.size() - 1, tok, new Boolean(true)); - b.add(b.EXPR, subexp); - return continueExpr(b, minPrecedence); + startExpr(precedence[tok], b); + b.set(b.size() - 1, tok, new Boolean(true)); + continueExpr(b, minPrecedence); + return; } case BANG: case BITNOT: case INSTANCEOF: case TYPEOF: { - b.add(b.EXPR, startExpr(precedence[tok])); + startExpr(precedence[tok], b); b.add(tok); - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case LC: { b.add(b.OBJECT, null); - if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); } + if (peekToken() == RC) { consume(RC); continueExpr(b, minPrecedence); return; } while(true) { if (peekToken() != NAME && peekToken() != STRING) throw new Error("expected NAME or STRING"); getToken(); b.add(b.LITERAL, string); consume(COLON); - b.add(b.EXPR, startExpr()); + startExpr(b); b.add(b.PUT); b.add(b.POP); - if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); } + if (peekToken() == RC) { consume(RC); continueExpr(b, minPrecedence); return; } consume(COMMA); - if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); } + if (peekToken() == RC) { consume(RC); continueExpr(b, minPrecedence); return; } } } case NAME: { @@ -143,7 +152,7 @@ public class Parser extends Lexer implements OpCodes { consume(ASSIGN); b.add(THIS); b.add(ForthBlock.LITERAL, name); - b.add(ForthBlock.EXPR, startExpr(minPrecedence)); + startExpr(minPrecedence, b); b.add(ForthBlock.PUT); b.add(ForthBlock.SWAP); b.add(ForthBlock.POP); @@ -152,7 +161,8 @@ public class Parser extends Lexer implements OpCodes { b.add(ForthBlock.LITERAL, name); b.add(ForthBlock.GET); } - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case Tokens.FUNCTION: { consume(LP); @@ -206,92 +216,87 @@ public class Parser extends Lexer implements OpCodes { parseStatement(true, b2); b2.add(b.LITERAL, null); b2.add(RETURN); - return continueExpr(b.add(OpCodes.FUNCTION, b2), minPrecedence); + continueExpr(b.add(OpCodes.FUNCTION, b2), minPrecedence); + return; } - default: pushBackToken(); return null; + default: pushBackToken(); return; } } - - /** return the largest expression beginning with prefix containing no operators of precedence below minPrecedence */ - public ForthBlock continueExpr(ForthBlock prefix, int minPrecedence) throws IOException { - return continueExpr(prefix, minPrecedence, new ForthBlock(line, sourceName)); - } - public ForthBlock continueExpr(ForthBlock prefix, int minPrecedence, ForthBlock appendTo) throws IOException { + public void continueExpr(ForthBlock prefix, int minPrecedence) throws IOException { int tok = getToken(); int curLine = line; - if (tok == -1) return prefix; + if (tok == -1) return; if (minPrecedence > 0 && precedence[tok] != 0) if (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok])) - { pushBackToken(); return prefix; } + { pushBackToken(); return; } if (prefix == null) throw new Error("got null prefix"); - - ForthBlock b = appendTo; + ForthBlock b = prefix; switch (tok) { case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH: case ASSIGN_ADD: case ASSIGN_SUB: case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: { - b.add(b.EXPR, prefix); prefix.set(prefix.size() - 1, b.GET_PRESERVE, new Boolean(true)); - prefix.add(prefix.EXPR, startExpr(precedence[tok - 1])); + startExpr(precedence[tok - 1], b); prefix.add(tok - 1); prefix.add(b.PUT); prefix.add(b.SWAP); prefix.add(b.POP); - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case INC: case DEC: { // postfix - prefix.set(prefix.size() - 1, tok, new Boolean(false)); - b.add(b.EXPR, prefix); - return continueExpr(b, minPrecedence); + b.set(b.size() - 1, tok, new Boolean(false)); + continueExpr(b, minPrecedence); + return; } case LP: { // invocation int i = 0; - b.add(b.EXPR, prefix); while(peekToken() != RP) { - b.add(b.EXPR, startExpr()); + startExpr(b); i++; if (peekToken() == RP) break; consume(COMMA); } consume(RP); b.add(b.CALL, new Integer(i)); - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case BITOR: case BITXOR: case BITAND: case SHEQ: case SHNE: case LSH: case RSH: case URSH: case ADD: case MUL: case DIV: case MOD: case GT: case GE: case EQ: case NE: case LT: case LE: case SUB: { - b.add(b.EXPR, prefix); - b.add(b.EXPR, startExpr(precedence[tok])); + startExpr(precedence[tok], b); b.add(tok); - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case OR: case AND: { + b.add(tok == AND ? b.JF : b.JT, new Integer(0)); + int size = b.size(); + startExpr(precedence[tok], b); + b.arg[size - 1] = new Integer(b.size() - size + 2); + b.add(b.JMP, new Integer(2)); b.add(b.LITERAL, tok == AND ? new Boolean(false) : new Boolean(true)); - b.add(b.EXPR, prefix); - b.add(tok == AND ? b.JF : b.JT, new Integer(3)); - b.add(b.POP); - b.add(b.EXPR, startExpr(precedence[tok])); - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case DOT: { consume(NAME); String target = string; - b.add(b.EXPR, prefix); if (peekToken() == ASSIGN) { consume(ASSIGN); - ForthBlock val = startExpr(); b.add(b.LITERAL, target); - b.add(b.EXPR, val); + startExpr(b); b.add(b.PUT); b.add(b.SWAP); b.add(b.POP); @@ -299,37 +304,41 @@ public class Parser extends Lexer implements OpCodes { b.add(b.LITERAL, target); b.add(b.GET); } - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case LB: { - b.add(b.EXPR, prefix); - b.add(b.EXPR, startExpr()); + startExpr(b); consume(RB); if (peekToken() == ASSIGN) { consume(ASSIGN); - b.add(b.EXPR, startExpr()); + startExpr(b); b.add(b.PUT); b.add(b.SWAP); b.add(b.POP); } else { b.add(b.GET); } - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case HOOK: { - b.add(b.EXPR, prefix); - b.add(b.JF, new Integer(3)); - b.add(b.EXPR, startExpr()); - b.add(b.JMP, new Integer(2)); + b.add(b.JF, new Integer(0)); + int size = b.size(); + startExpr(b); + b.arg[size - 1] = new Integer(b.size() - size + 2); + b.add(b.JMP, new Integer(0)); consume(COLON); - b.add(b.EXPR, startExpr()); - return continueExpr(b, minPrecedence); + size = b.size(); + startExpr(b); + b.arg[size - 1] = new Integer(b.size() - size + 1); + continueExpr(b, minPrecedence); + return; } - - default: pushBackToken(); return prefix; + default: { pushBackToken(); return; } } } @@ -358,7 +367,7 @@ public class Parser extends Lexer implements OpCodes { case THROW: case RETURN: case ASSERT: { getToken(); if (tok == RETURN && peekToken() == SEMI) b.add(b.LITERAL, null); - else b.add(b.EXPR, startExpr()); + else startExpr(b); consume(SEMI); b.add(tok); break; @@ -388,7 +397,7 @@ public class Parser extends Lexer implements OpCodes { if (peekToken() == ASSIGN) { // if there is an '=' after the variable name b.add(b.LITERAL, name); // put the var name back on the stack consume(ASSIGN); - b.add(b.EXPR, startExpr()); + startExpr(b); b.add(b.PUT); b.add(b.POP); } @@ -403,19 +412,21 @@ public class Parser extends Lexer implements OpCodes { case IF: { consume(IF); consume(LP); - b.add(b.EXPR, startExpr()); + startExpr(b); consume(RP); - b.add(b.JF, new Integer(4)); - b.add(b.EXPR, parseStatement()); - b.add(b.POP); - b.add(b.JMP, new Integer(3)); + + b.add(b.JF, new Integer(0)); + int size = b.size(); + parseStatement(false, b); + if (peekToken() == ELSE) { consume(ELSE); + b.arg[size - 1] = new Integer(2 + b.size() - size); + b.add(b.JMP, new Integer(3)); b.add(b.EXPR, parseStatement()); b.add(b.POP); } else { - b.add(b.JMP, new Integer(1)); // nop - b.add(b.JMP, new Integer(1)); // nop + b.arg[size - 1] = new Integer(1 + b.size() - size); } break; } @@ -427,7 +438,7 @@ public class Parser extends Lexer implements OpCodes { b.add(loop.LOOP, loop); loop.add(loop.POP); - loop.add(loop.EXPR, startExpr()); + startExpr(loop); loop.add(loop.JT, new Integer(2)); loop.add(Lexer.BREAK); consume(RP); @@ -443,33 +454,39 @@ public class Parser extends Lexer implements OpCodes { consume(LP); ForthBlock loop = new ForthBlock(curLine, sourceName); b.add(loop.LOOP, loop); - loop.add(loop.EXPR, startExpr()); + startExpr(loop); consume(RP); consume(LC); - while(true) { - ForthBlock caseForthBlock; - tok = getToken(); - if (tok == CASE) { + while(true) + if (peekToken() == CASE) { + consume(CASE); loop.add(loop.DUP); - loop.add(loop.EXPR, startExpr()); + startExpr(loop); + consume(COLON); loop.add(EQ); - loop.add(loop.JF, new Integer(2)); - } else if (tok != DEFAULT) throw new ParserException("expected CASE or DEFAULT"); - consume(COLON); - ForthBlock b2 = new ForthBlock(curLine, sourceName); - ForthBlock e1 = null; - while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) { - if ((e1 = parseStatement()) == null) break; - b2.add(b.EXPR, e1); - b2.add(b.POP); - } - loop.add(loop.EXPR, b2); - if (peekToken() == RC) { + loop.add(loop.JF, new Integer(0)); + int size = loop.size(); + while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) { + int size2 = loop.size(); + parseStatement(false, loop); + if (size2 == loop.size()) break; + } + loop.arg[size - 1] = new Integer(1 + loop.size() - size); + } else if (peekToken() == DEFAULT) { + consume(DEFAULT); + consume(COLON); + while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) { + int size2 = loop.size(); + parseStatement(false, loop); + if (size2 == loop.size()) break; + } + } else if (peekToken() == RC) { consume(RC); loop.add(BREAK); break; + } else { + throw new ParserException("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]); } - } break; } @@ -481,7 +498,7 @@ public class Parser extends Lexer implements OpCodes { parseStatement(false, loop); consume(WHILE); consume(LP); - loop.add(loop.EXPR, startExpr()); + startExpr(loop); loop.add(loop.JT, new Integer(2)); loop.add(Lexer.BREAK); loop.add(Lexer.CONTINUE); @@ -524,7 +541,7 @@ public class Parser extends Lexer implements OpCodes { if (forIn) { consume(NAME); consume(IN); - b.add(b.EXPR, startExpr()); + startExpr(b); b.add(b.PUSHKEYS); b.add(b.LITERAL, "length"); b.add(b.GET); @@ -543,7 +560,6 @@ public class Parser extends Lexer implements OpCodes { b2.add(b.DECLARE); b2.add(b.PUT); b2.add(b.EXPR, parseStatement()); - //b2.add(b.LITERAL, null); break; } else { @@ -551,26 +567,26 @@ public class Parser extends Lexer implements OpCodes { b.add(b.SCOPE, b2); b.add(b.POP); - ForthBlock e1 = startExpr(); - if (e1 == null) e1 = new ForthBlock(curLine, sourceName, b.LITERAL, null); - - b2.add(b.EXPR, e1); - b2.add(b.POP); + int size = b2.size(); + startExpr(b2); + if (b2.size() - size > 0) b2.add(b.POP); consume(SEMI); ForthBlock e2 = startExpr(); consume(SEMI); - ForthBlock e3 = startExpr(); - consume(RP); if (e2 == null) e2 = new ForthBlock(curLine, sourceName, b.LITERAL, null); - if (e3 == null) e3 = new ForthBlock(curLine, sourceName, b.LITERAL, null); ForthBlock b3 = new ForthBlock(curLine, sourceName); b2.add(b.LOOP, b3); b2.add(b.LITERAL, null); - b3.add(b.JT, new Integer(3)); - b3.add(b.EXPR, e3); - b3.add(b.POP); + + b3.add(b.JT, new Integer(0)); + size = b3.size(); + startExpr(b3); + consume(RP); + if (b3.size() - size > 0) b3.add(b.POP); + b3.arg[size - 1] = new Integer(b3.size() - size + 1); + b3.add(b.EXPR, e2); b3.add(b.JT, new Integer(2)); b3.add(BREAK); @@ -597,9 +613,9 @@ public class Parser extends Lexer implements OpCodes { if (tok == RC && braced) { consume(RC); return; } // fall through default: { - ForthBlock ret = startExpr(); - if (ret == null) return; - b.add(b.EXPR, ret); + int size = b.size(); + startExpr(b); + if (size == b.size()) return; b.add(b.POP); if (peekToken() == SEMI) consume(SEMI); break; -- 1.7.10.4