X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fjs%2FParser.java;h=fa36d6a5accfdbaf7140a613fe1881055bcf5fd7;hb=c3a9a6282c52e242c06d8e47660ab7aea09bdca4;hp=cc55164557e308a5d098566ef8979f3d1147e7c8;hpb=c7958573764aab1b512024456f975bb41f81a7b7;p=org.ibex.core.git diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index cc55164..fa36d6a 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -4,27 +4,19 @@ package org.xwt.js; import org.xwt.util.*; import java.io.*; -/** parses a stream of lexed tokens into ForthBlock's */ -public class Parser extends Lexer implements OpCodes { +/** Parses a stream of lexed tokens into a tree of CompiledFunction's */ +class Parser extends Lexer implements ByteCodes { + // Constructors ////////////////////////////////////////////////////// - public Parser(Reader r, String sourceName, int line) throws IOException { - super(r); - this.sourceName = sourceName; - this.line = line; - } + public Parser(Reader r, String sourceName, int line) throws IOException { super(r, sourceName, line); } /** for debugging */ public static void main(String[] s) throws Exception { - Parser p = new Parser(new InputStreamReader(System.in), "stdin", 0); - while(true) { - ForthBlock block = new ForthBlock(0, "stdin"); - p.parseStatement(false, block); - if (block == null) return; - System.out.println(block); - if (p.peekToken() == -1) return; - } + CompiledFunction block = new CompiledFunction("stdin", 0, new InputStreamReader(System.in), null); + if (block == null) return; + System.out.println(block); } @@ -49,7 +41,7 @@ public class Parser extends Lexer implements OpCodes { precedence[LSH] = precedence[RSH] = precedence[URSH] = 12; precedence[ADD] = precedence[SUB] = 13; precedence[MUL] = precedence[DIV] = precedence[MOD] = 14; - precedence[BITNOT] = precedence[INSTANCEOF] = 15; + precedence[BITNOT] = 15; precedence[INC] = precedence[DEC] = 16; precedence[LP] = 17; precedence[LB] = 18; @@ -62,139 +54,139 @@ public class Parser extends Lexer implements OpCodes { /** gets a token and throws an exception if it is not code */ public void consume(int code) throws IOException { if (getToken() != code) - throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOL" : codeToString[op])); + throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op])); } - /** 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 { - + /** append the largest possible expression containing no operators of precedence below minPrecedence */ + public void startExpr(int minPrecedence, CompiledFunction appendTo) throws IOException { int tok = getToken(); - int curLine = line; - if (tok == -1) return null; - if (minPrecedence > 0 && precedence[tok] != 0) - if (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok])) - { pushBackToken(); return null; } - - ForthBlock b = appendTo; + CompiledFunction 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 -1: return; + case NUMBER: continueExpr(b.add(line, CompiledFunction.LITERAL, number), minPrecedence); return; + case STRING: continueExpr(b.add(line, CompiledFunction.LITERAL, string), minPrecedence); return; + case THIS: continueExpr(b.add(line, TOPSCOPE, null), minPrecedence); return; + case NULL: continueExpr(b.add(line, CompiledFunction.LITERAL, null), minPrecedence); return; + case TRUE: case FALSE: continueExpr(b.add(line, CompiledFunction.LITERAL, new Boolean(tok == TRUE)), minPrecedence); return; case LB: { - b.add(b.ARRAY, new Integer(0)); + b.add(line, ARRAY, new Integer(0)); int i = 0; while(true) { - ForthBlock e = startExpr(); - if (e == null && peekToken() == RB) { consume(RB); return continueExpr(b, minPrecedence); } - b.add(b.LITERAL, new Integer(i++)); - if (e == null) b.add(b.LITERAL, null); - else b.add(b.EXPR, e); - b.add(b.PUT); - b.add(b.POP); - if (peekToken() == RB) { consume(RB); return continueExpr(b, minPrecedence); } + int size = b.size(); + startExpr(-1, b); + if (size == b.size()) + if (peekToken() == RB) { consume(RB); continueExpr(b, minPrecedence); return; } + b.add(line, LITERAL, new Integer(i++)); + if (size == b.size()) b.add(line, LITERAL, null); + b.add(line, PUT); + b.add(line, POP); + 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); + b.add(line, CompiledFunction.LITERAL, new Double(number.doubleValue() * -1)); + continueExpr(b, minPrecedence); + return; } case LP: { - b.add(EXPR, startExpr()); + startExpr(-1, 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])); - b.add(tok); - return continueExpr(b, minPrecedence); + case BANG: case BITNOT: case TYPEOF: { + startExpr(precedence[tok], b); + b.add(line, tok); + continueExpr(b, minPrecedence); + return; } case LC: { - b.add(b.OBJECT, null); - if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); } - while(true) { + b.add(line, OBJECT, null); + if (peekToken() != RC) while(true) { if (peekToken() != NAME && peekToken() != STRING) throw new Error("expected NAME or STRING"); getToken(); - b.add(b.LITERAL, string); + b.add(line, LITERAL, string); consume(COLON); - b.add(b.EXPR, startExpr()); - b.add(b.PUT); - b.add(b.POP); - if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); } + startExpr(-1, b); + b.add(line, PUT); + b.add(line, POP); + if (peekToken() == RC) break; consume(COMMA); - if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); } + if (peekToken() == RC) break; } + consume(RC); + continueExpr(b, minPrecedence); + return; } case NAME: { String name = string; if (peekToken() == ASSIGN) { consume(ASSIGN); - b.add(THIS); - b.add(ForthBlock.LITERAL, name); - b.add(ForthBlock.EXPR, startExpr(minPrecedence)); - b.add(ForthBlock.PUT); - b.add(ForthBlock.SWAP); - b.add(ForthBlock.POP); + b.add(line, TOPSCOPE); + b.add(line, CompiledFunction.LITERAL, name); + startExpr(minPrecedence, b); + b.add(line, CompiledFunction.PUT); + b.add(line, CompiledFunction.SWAP); + b.add(line, CompiledFunction.POP); } else { - b.add(THIS); - b.add(ForthBlock.LITERAL, name); - b.add(ForthBlock.GET); + b.add(line, TOPSCOPE); + b.add(line, CompiledFunction.LITERAL, name); + b.add(line, CompiledFunction.GET); } - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } - case Tokens.FUNCTION: { + case FUNCTION: { consume(LP); int numArgs = 0; - ForthBlock b2 = new ForthBlock(curLine, sourceName); - b2.add(THIS); - b2.add(b.SWAP); - b2.add(b.LITERAL, "arguments"); - b2.add(b.LITERAL, "arguments"); - b2.add(b.DECLARE); - b2.add(b.SWAP); - b2.add(b.PUT); - b2.add(b.SWAP); - b2.add(b.POP); + CompiledFunction b2 = new CompiledFunction(sourceName, line, null); + b2.add(line, TOPSCOPE); + b2.add(line, SWAP); + b2.add(line, LITERAL, "arguments"); + b2.add(line, LITERAL, "arguments"); + b2.add(line, DECLARE); + b2.add(line, SWAP); + b2.add(line, PUT); + b2.add(line, SWAP); + b2.add(line, POP); if (peekToken() == RP) consume(RP); else while(true) { if (peekToken() == COMMA) { - // FIXME: pop an item off the stack here? consume(COMMA); + } else { consume(NAME); // declare the name - b2.add(b.LITERAL, string); - b2.add(b.DECLARE); + b2.add(line, LITERAL, string); + b2.add(line, DECLARE); // retrieve it from the arguments array - b2.add(b.LITERAL, new Integer(numArgs)); - b2.add(b.GET_PRESERVE); - b2.add(b.SWAP); - b2.add(b.POP); + b2.add(line, LITERAL, new Integer(numArgs)); + b2.add(line, GET_PRESERVE); + b2.add(line, SWAP); + b2.add(line, POP); // put it to the current scope - b2.add(THIS); - b2.add(b.SWAP); - b2.add(b.LITERAL, string); - b2.add(b.SWAP); - b2.add(b.PUT); + b2.add(line, TOPSCOPE); + b2.add(line, SWAP); + b2.add(line, LITERAL, string); + b2.add(line, SWAP); + b2.add(line, PUT); // clean the stack - b2.add(b.POP); - b2.add(b.POP); + b2.add(line, POP); + b2.add(line, POP); if (peekToken() == RP) { consume(RP); break; } consume(COMMA); @@ -202,200 +194,199 @@ public class Parser extends Lexer implements OpCodes { numArgs++; } // pop off the arguments array - b2.add(b.POP); + b2.add(line, POP); parseStatement(true, b2); - b2.add(b.LITERAL, null); - b2.add(RETURN); - return continueExpr(b.add(OpCodes.FUNCTION, b2), minPrecedence); + b2.add(line, LITERAL, null); + b2.add(line, RETURN); + continueExpr(b.add(line, NEWFUNCTION, 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(CompiledFunction 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; + CompiledFunction 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])); - prefix.add(tok - 1); - prefix.add(b.PUT); - prefix.add(b.SWAP); - prefix.add(b.POP); - return continueExpr(b, minPrecedence); + startExpr(precedence[tok - 1], b); + prefix.add(line, tok - 1); + prefix.add(line, PUT); + prefix.add(line, SWAP); + prefix.add(line, POP); + 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()); i++; + startExpr(-1, b); if (peekToken() == RP) break; consume(COMMA); } consume(RP); - b.add(b.CALL, new Integer(i)); - return continueExpr(b, minPrecedence); + b.add(line, CALL, new Integer(i)); + 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])); - b.add(tok); - return continueExpr(b, minPrecedence); + startExpr(precedence[tok], b); + b.add(line, tok); + continueExpr(b, minPrecedence); + return; } case OR: case AND: { - 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); + b.add(line, tok == AND ? b.JF : b.JT, new Integer(0)); + int size = b.size(); + startExpr(precedence[tok], b); + b.set(size - 1, new Integer(b.size() - size + 2)); + b.add(line, JMP, new Integer(2)); + b.add(line, LITERAL, tok == AND ? new Boolean(false) : new Boolean(true)); + 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); - b.add(b.PUT); - b.add(b.SWAP); - b.add(b.POP); + b.add(line, LITERAL, target); + startExpr(-1, b); + b.add(line, PUT); + b.add(line, SWAP); + b.add(line, POP); } else { - b.add(b.LITERAL, target); - b.add(b.GET); + b.add(line, LITERAL, target); + b.add(line, GET); } - return continueExpr(b, minPrecedence); + continueExpr(b, minPrecedence); + return; } case LB: { - b.add(b.EXPR, prefix); - b.add(b.EXPR, startExpr()); + startExpr(-1, b); consume(RB); if (peekToken() == ASSIGN) { consume(ASSIGN); - b.add(b.EXPR, startExpr()); - b.add(b.PUT); - b.add(b.SWAP); - b.add(b.POP); + startExpr(-1, b); + b.add(line, PUT); + b.add(line, SWAP); + b.add(line, POP); } else { - b.add(b.GET); + b.add(line, 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(line, JF, new Integer(0)); + int size = b.size(); + startExpr(-1, b); + b.set(size - 1, new Integer(b.size() - size + 2)); + b.add(line, JMP, new Integer(0)); consume(COLON); - b.add(b.EXPR, startExpr()); - return continueExpr(b, minPrecedence); + size = b.size(); + startExpr(-1, b); + b.set(size - 1, new Integer(b.size() - size + 1)); + continueExpr(b, minPrecedence); + return; } - - default: pushBackToken(); return prefix; + default: { pushBackToken(); return; } } } - /** a block is either a single statement or a list of statements surrounded by curly braces; all expressions are also statements */ - public ForthBlock parseStatement() throws IOException { - ForthBlock ret = new ForthBlock(line, sourceName); - ret.add(ret.LITERAL, null); + /** + * a block is either a single statement or a list of statements surrounded by curly braces; + * all expressions are also statements + */ + public CompiledFunction parseStatement() throws IOException { + CompiledFunction ret = new CompiledFunction(sourceName, line, null); + ret.add(line, ret.LITERAL, null); parseStatement(false, ret); if (ret.size() == 1) return null; return ret; } - public void parseStatement(boolean requireBraces) throws IOException { - parseStatement(requireBraces, new ForthBlock(line, sourceName)); - } - public void parseStatement(boolean requireBraces, ForthBlock b) throws IOException { + public void parseStatement(boolean r, CompiledFunction b) throws IOException { parseStatement(r, b, null); } + public void parseStatement(boolean requireBraces, CompiledFunction b, String label) throws IOException { int tok = peekToken(); if (tok == -1) return; + int line = this.line; boolean braced = tok == LC; if (requireBraces && !braced) throw new ParserException("expected {, got " + codeToString[tok]); if (braced) consume(LC); - int curLine = line; while(true) { switch(tok = peekToken()) { case THROW: case RETURN: case ASSERT: { getToken(); - if (tok == RETURN && peekToken() == SEMI) b.add(b.LITERAL, null); - else b.add(b.EXPR, startExpr()); + if (tok == RETURN && peekToken() == SEMI) b.add(line, LITERAL, null); + else startExpr(-1, b); consume(SEMI); - b.add(tok); + b.add(line, tok); break; } case BREAK: case CONTINUE: { getToken(); if (peekToken() == NAME) consume(NAME); - b.add(tok, string); + b.add(line, tok, string); consume(SEMI); break; } - case SEMI: + case SEMI: { consume(SEMI); if (!braced) return; break; + } case VAR: { consume(VAR); - b.add(THIS); // push the current scope + b.add(line, TOPSCOPE); // push the current scope while(true) { consume(NAME); String name = string; - b.add(b.LITERAL, name); // push the name to be declared - b.add(b.DECLARE); // declare it + b.add(line, LITERAL, name); // push the name to be declared + b.add(line, DECLARE); // declare it if (peekToken() == ASSIGN) { // if there is an '=' after the variable name - b.add(b.LITERAL, name); // put the var name back on the stack + b.add(line, LITERAL, name); // put the var name back on the stack consume(ASSIGN); - b.add(b.EXPR, startExpr()); - b.add(b.PUT); - b.add(b.POP); + startExpr(-1, b); + b.add(line, PUT); + b.add(line, POP); } if (peekToken() != COMMA) break; consume(COMMA); } - b.add(b.POP); + b.add(line, POP); if (peekToken() == SEMI) consume(SEMI); break; } @@ -403,107 +394,133 @@ public class Parser extends Lexer implements OpCodes { case IF: { consume(IF); consume(LP); - b.add(b.EXPR, startExpr()); + startExpr(-1, 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(line, JF, new Integer(0)); + int size = b.size(); + parseStatement(false, b); + if (peekToken() == ELSE) { consume(ELSE); - 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.set(size - 1, new Integer(2 + b.size() - size)); + b.add(line, JMP, new Integer(0)); + size = b.size(); + parseStatement(false, b); } + b.set(size - 1, new Integer(1 + b.size() - size)); break; } case WHILE: { consume(WHILE); consume(LP); - ForthBlock loop = new ForthBlock(curLine, sourceName); - b.add(loop.LOOP, loop); - - loop.add(loop.POP); - loop.add(loop.EXPR, startExpr()); - loop.add(loop.JT, new Integer(2)); - loop.add(Lexer.BREAK); + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); + int size = b.size(); + b.add(line, POP); + startExpr(-1, b); + b.add(line, JT, new Integer(2)); + b.add(line, BREAK); consume(RP); - parseStatement(false, loop); - - // if we fall out of the end, definately continue - loop.add(CONTINUE); + parseStatement(false, b); + b.add(line, CONTINUE); // if we fall out of the end, definately continue + b.set(size - 1, new Integer(b.size() - size + 1)); // end of the loop break; } case SWITCH: { consume(SWITCH); consume(LP); - ForthBlock loop = new ForthBlock(curLine, sourceName); - b.add(loop.LOOP, loop); - loop.add(loop.EXPR, startExpr()); + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); + int size0 = b.size(); + startExpr(-1, b); consume(RP); consume(LC); - while(true) { - ForthBlock caseForthBlock; - tok = getToken(); - if (tok == CASE) { - loop.add(loop.DUP); - loop.add(loop.EXPR, startExpr()); - 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) { + while(true) + if (peekToken() == CASE) { + consume(CASE); + b.add(line, DUP); + startExpr(-1, b); + consume(COLON); + b.add(line, EQ); + b.add(line, JF, new Integer(0)); + int size = b.size(); + while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) { + int size2 = b.size(); + parseStatement(false, b); + if (size2 == b.size()) break; + } + b.set(size - 1, new Integer(1 + b.size() - size)); + } else if (peekToken() == DEFAULT) { + consume(DEFAULT); + consume(COLON); + while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) { + int size2 = b.size(); + parseStatement(false, b); + if (size2 == b.size()) break; + } + } else if (peekToken() == RC) { consume(RC); - loop.add(BREAK); + b.add(line, BREAK); break; + } else { + throw new ParserException("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]); } - } + b.add(line, BREAK); + b.set(size0 - 1, new Integer(b.size() - size0 + 1)); // end of the loop break; } case DO: { consume(DO); - ForthBlock loop = new ForthBlock(curLine, sourceName); - b.add(loop.LOOP, loop); - - parseStatement(false, loop); + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); + int size = b.size(); + parseStatement(false, b); consume(WHILE); consume(LP); - loop.add(loop.EXPR, startExpr()); - loop.add(loop.JT, new Integer(2)); - loop.add(Lexer.BREAK); - loop.add(Lexer.CONTINUE); + startExpr(-1, b); + b.add(line, JT, new Integer(2)); + b.add(line, BREAK); + b.add(line, CONTINUE); consume(RP); consume(SEMI); + b.set(size - 1, new Integer(b.size() - size + 1)); // end of the loop break; } case TRY: { - // FIXME: don't just ignore this! // We deliberately allow you to omit braces in catch{}/finally{} if they are single statements... consume(TRY); + b.add(line, TRY); + int size = b.size(); parseStatement(true, b); + b.add(line, POP); // pop the TryMarker + b.add(line, JMP); // jump forward to the end of the catch block + int size2 = b.size(); + b.set(size - 1, new Integer(b.size() - size + 1));// the TRY argument points at the start of the CATCH block if (peekToken() == CATCH) { getToken(); consume(LP); consume(NAME); consume(RP); - parseStatement(); // just discard the catchblock + // FIXME, we need an extra scope here + b.add(line, TOPSCOPE); // the exception is on top of the stack; put it to the variable + b.add(line, SWAP); + b.add(line, LITERAL); + b.add(line, SWAP); + b.add(line, PUT); + b.add(line, POP); + b.add(line, POP); + parseStatement(false, b); } + b.set(size2 - 1, new Integer(b.size() - size2 + 1)); // jump here if no exception was thrown + + // FIXME: not implemented correctly if (peekToken() == FINALLY) { consume(FINALLY); parseStatement(false, b); @@ -511,84 +528,91 @@ public class Parser extends Lexer implements OpCodes { break; } - case FOR: { - consume(FOR); - consume(LP); - - tok = getToken(); - if (tok == VAR) tok = getToken(); - String varName = string; - boolean forIn = peekToken() == IN; - pushBackToken(tok, varName); - - if (forIn) { - consume(NAME); - consume(IN); - b.add(b.EXPR, startExpr()); - b.add(b.PUSHKEYS); - b.add(b.LITERAL, "length"); - b.add(b.GET); - consume(RP); - ForthBlock b2 = new ForthBlock(curLine, sourceName); - b.add(b.SCOPE, b2); - b2.add(b.LITERAL, new Integer(1)); - b2.add(SUB); - b2.add(b.DUP); - b2.add(b.LITERAL, new Integer(0)); - b2.add(LT); - b2.add(b.JT, new Integer(7)); - b2.add(b.GET_PRESERVE); - b2.add(b.LITERAL, varName); - b2.add(b.LITERAL, varName); - b2.add(b.DECLARE); - b2.add(b.PUT); - b2.add(b.EXPR, parseStatement()); - //b2.add(b.LITERAL, null); - break; + case FOR: { + consume(FOR); + consume(LP); - } else { - ForthBlock b2 = new ForthBlock(curLine, sourceName); - 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); - 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.EXPR, e2); - b3.add(b.JT, new Integer(2)); - b3.add(BREAK); - parseStatement(false, b3); - b3.add(BREAK); - break; + tok = getToken(); + boolean hadVar = false; + if (tok == VAR) { hadVar = true; tok = getToken(); } + String varName = string; + boolean forIn = peekToken() == IN; + pushBackToken(tok, varName); + + if (forIn) { + // FIXME: break needs to work in here + consume(NAME); + consume(IN); + startExpr(-1, b); + b.add(line, PUSHKEYS); + b.add(line, LITERAL, "length"); + b.add(line, GET); + consume(RP); + CompiledFunction b2 = new CompiledFunction(sourceName, line, null); + + b.add(line, NEWSCOPE); + + b.add(line, LITERAL, new Integer(1)); + b.add(line, SUB); + b.add(line, DUP); + b.add(line, LITERAL, new Integer(0)); + b.add(line, LT); + b.add(line, JT, new Integer(7)); + b.add(line, GET_PRESERVE); + b.add(line, LITERAL, varName); + b.add(line, LITERAL, varName); + b.add(line, DECLARE); + b.add(line, PUT); + parseStatement(false, b); + + b.add(line, OLDSCOPE); + + break; + + } else { + if (hadVar) pushBackToken(VAR, null); + b.add(line, NEWSCOPE); + + parseStatement(false, b); + CompiledFunction e2 = new CompiledFunction(sourceName, line, null); + startExpr(-1, e2); + consume(SEMI); + if (e2 == null) e2 = new CompiledFunction(sourceName, line, null).add(line, b.LITERAL, Boolean.TRUE); + + if (label != null) b.add(line, LABEL, label); + b.add(line, LOOP); + int size2 = b.size(); + + b.add(line, JT, new Integer(0)); + int size = b.size(); + startExpr(-1, b); + if (b.size() > size) b.add(line, POP); + b.set(size - 1, new Integer(b.size() - size + 1)); + consume(RP); + + b.paste(e2); + b.add(line, JT, new Integer(2)); + b.add(line, BREAK); + parseStatement(false, b); + b.add(line, CONTINUE); + b.set(size2 - 1, new Integer(b.size() - size2 + 1)); // end of the loop + + b.add(line, OLDSCOPE); + break; + } } - } - + case NAME: { consume(NAME); - String name = string; + String possiblyTheLabel = string; if (peekToken() == COLON) { consume(COLON); - b.add(ForthBlock.LABEL, string); + label = possiblyTheLabel; + System.out.println("label == " + label); + parseStatement(false, b, label); break; } else { - pushBackToken(NAME, name); + pushBackToken(NAME, possiblyTheLabel); // fall through to default case } } @@ -597,10 +621,10 @@ 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); - b.add(b.POP); + int size = b.size(); + startExpr(-1, b); + if (size == b.size()) return; + b.add(line, POP); if (peekToken() == SEMI) consume(SEMI); break; } @@ -610,7 +634,7 @@ public class Parser extends Lexer implements OpCodes { } } - class ParserException extends RuntimeException { + private class ParserException extends RuntimeException { public ParserException(String s) { super(sourceName + ":" + line + " " + s); } }