/** append the largest expression beginning with prefix containing no operators of precedence below <tt>minPrecedence</tt> */
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: {
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);
b.add(ForthBlock.LITERAL, name);
b.add(ForthBlock.GET);
}
- return continueExpr(b, minPrecedence);
+ continueExpr(b, minPrecedence);
+ return;
}
case Tokens.FUNCTION: {
consume(LP);
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 <tt>minPrecedence</tt> */
- 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);
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; }
}
}
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;
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);
}
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;
}
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);
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;
}
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);
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);
b2.add(b.DECLARE);
b2.add(b.PUT);
b2.add(b.EXPR, parseStatement());
- //b2.add(b.LITERAL, null);
break;
} else {
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);
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;