static byte[] precedence = new byte[MAX_TOKEN + 1];
static boolean[] isRightAssociative = new boolean[MAX_TOKEN + 1];
- static boolean[] mustStartExpression = new boolean[MAX_TOKEN + 1];
- static boolean[] cannotStartExpression = new boolean[MAX_TOKEN + 1];
static {
-
- mustStartExpression[VAR] = true;
- mustStartExpression[IF] = true;
- mustStartExpression[BANG] = true;
- mustStartExpression[BITNOT] = true;
- mustStartExpression[INSTANCEOF] = true;
- mustStartExpression[TYPEOF] = true;
- mustStartExpression[NUMBER] = true;
- mustStartExpression[STRING] = true;
- mustStartExpression[NULL] = true;
- mustStartExpression[TRUE] = true;
- mustStartExpression[FALSE] = true;
- mustStartExpression[Tokens.FUNCTION] = true;
- mustStartExpression[NAME] = true;
- mustStartExpression[LC] = true;
- mustStartExpression[THIS] = true;
-
- cannotStartExpression[OR] = true;
- cannotStartExpression[AND] = true;
- cannotStartExpression[BITOR] = true;
- cannotStartExpression[BITXOR] = true;
- cannotStartExpression[BITAND] = true;
- cannotStartExpression[SHEQ] = true;
- cannotStartExpression[SHNE] = true;
- cannotStartExpression[LSH] = true;
- cannotStartExpression[RSH] = true;
- cannotStartExpression[URSH] = true;
- cannotStartExpression[ADD] = true;
- cannotStartExpression[MUL] = true;
- cannotStartExpression[DIV] = true;
- cannotStartExpression[MOD] = true;
- cannotStartExpression[GT] = true;
- cannotStartExpression[GE] = true;
- cannotStartExpression[EQ] = true;
- cannotStartExpression[NE] = true;
- cannotStartExpression[LT] = true;
- cannotStartExpression[LE] = true;
- cannotStartExpression[DOT] = true;
- cannotStartExpression[HOOK] = true;
- cannotStartExpression[ASSIGN_BITOR] = true;
- cannotStartExpression[ASSIGN_BITXOR] = true;
- cannotStartExpression[ASSIGN_BITAND] = true;
- cannotStartExpression[ASSIGN_LSH] = true;
- cannotStartExpression[ASSIGN_RSH] = true;
- cannotStartExpression[ASSIGN_URSH] = true;
- cannotStartExpression[ASSIGN_ADD] = true;
- cannotStartExpression[ASSIGN_SUB] = true;
- cannotStartExpression[ASSIGN_MUL] = true;
- cannotStartExpression[ASSIGN_DIV] = true;
- cannotStartExpression[ASSIGN_MOD] = true;
-
isRightAssociative[ASSIGN] = true;
precedence[ASSIGN] = 1;
throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOL" : codeToString[op]));
}
- /** parses the largest possible expression */
- public ForthBlock parseExpr() throws IOException { return parseExpr(null, -1); }
-
- /** return the largest expression beginning with prefix containing no operators of precedence below <tt>minPrecedence</tt> */
- public ForthBlock parseExpr(ForthBlock prefix, int minPrecedence) throws IOException {
- return parseExpr(prefix, minPrecedence, new ForthBlock(line, sourceName));
- }
-
/** append the largest expression beginning with prefix containing no operators of precedence below <tt>minPrecedence</tt> */
- public ForthBlock parseExpr(ForthBlock prefix, int minPrecedence, ForthBlock appendTo) throws IOException {
+ 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 {
int tok = getToken();
int curLine = line;
- if (tok == -1) return prefix;
+ if (tok == -1) return null;
if (minPrecedence > 0 && precedence[tok] != 0)
if (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok]))
- { pushBackToken(); return prefix; }
-
- if (prefix != null && mustStartExpression[tok]) { pushBackToken(); return prefix; }
- if (prefix == null && cannotStartExpression[tok]) { pushBackToken(); return prefix; }
+ { pushBackToken(); return null; }
ForthBlock b = appendTo;
switch (tok) {
-
- case NUMBER: return parseExpr(b.add(ForthBlock.LITERAL, number), minPrecedence);
- case STRING: return parseExpr(b.add(ForthBlock.LITERAL, string), minPrecedence);
- case THIS: return parseExpr(b.add(THIS, null), minPrecedence);
- case NULL: return parseExpr(b.add(ForthBlock.LITERAL, null), minPrecedence);
- case TRUE: case FALSE: return parseExpr(b.add(ForthBlock.LITERAL, new Boolean(tok == TRUE)), minPrecedence);
-
- 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, parseExpr(null, precedence[tok - 1]));
- prefix.add(tok - 1);
- prefix.add(b.PUT);
- prefix.add(b.SWAP);
- prefix.add(b.POP);
- return parseExpr(b, minPrecedence);
- }
-
- case INC: case DEC:
- if (prefix == null) {
- // prefix
- ForthBlock subexp = parseExpr(null, precedence[tok]);
- subexp.set(subexp.size() - 1, tok, new Boolean(true));
- b.add(b.EXPR, subexp);
- return parseExpr(b, minPrecedence);
- } else {
- // postfix
- prefix.set(prefix.size() - 1, tok, new Boolean(false));
- b.add(b.EXPR, prefix);
- return parseExpr(b, minPrecedence);
- }
-
- case LP:
- if (prefix == null) { // grouping
- b.add(EXPR, parseExpr());
- consume(RP);
- return parseExpr(b, minPrecedence);
-
- } else { // invocation
- int i = 0;
- b.add(b.EXPR, prefix);
- while(peekToken() != RP) {
- b.add(b.EXPR, parseExpr());
- i++;
- if (peekToken() == RP) break;
- consume(COMMA);
- }
- consume(RP);
- b.add(b.CALL, new Integer(i));
- return parseExpr(b, minPrecedence);
+ 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 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); }
+ 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); }
+ consume(COMMA);
}
-
+ }
+ case SUB: {
+ consume(NUMBER);
+ return continueExpr(b.add(ForthBlock.LITERAL, new Double(number.doubleValue() * -1)), minPrecedence);
+ }
+ case LP: {
+ b.add(EXPR, startExpr());
+ consume(RP);
+ return continueExpr(b, minPrecedence);
+ }
+ 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);
+ }
case BANG: case BITNOT: case INSTANCEOF: case TYPEOF: {
- b.add(b.EXPR, parseExpr(null, precedence[tok]));
+ b.add(b.EXPR, startExpr(precedence[tok]));
b.add(tok);
- return parseExpr(b, minPrecedence);
+ return continueExpr(b, minPrecedence);
}
-
- case SUB:
- if (prefix == null) {
- consume(NUMBER);
- return parseExpr(b.add(ForthBlock.LITERAL, new Double(number.doubleValue() * -1)), minPrecedence);
+ case LC: {
+ b.add(b.OBJECT, null);
+ if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); }
+ 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());
+ b.add(b.PUT);
+ b.add(b.POP);
+ if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); }
+ consume(COMMA);
+ if (peekToken() == RC) { consume(RC); return continueExpr(b, minPrecedence); }
}
- // fall through
- 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: {
- b.add(b.EXPR, prefix);
- b.add(b.EXPR, parseExpr(null, precedence[tok]));
- b.add(tok);
- return parseExpr(b, minPrecedence);
}
-
- 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, parseExpr(null, precedence[tok]));
- return parseExpr(b, minPrecedence);
- }
-
case NAME: {
String name = string;
if (peekToken() == ASSIGN) {
consume(ASSIGN);
b.add(THIS);
b.add(ForthBlock.LITERAL, name);
- b.add(ForthBlock.EXPR, parseExpr(null, minPrecedence));
+ b.add(ForthBlock.EXPR, startExpr(minPrecedence));
b.add(ForthBlock.PUT);
b.add(ForthBlock.SWAP);
b.add(ForthBlock.POP);
b.add(ForthBlock.LITERAL, name);
b.add(ForthBlock.GET);
}
- return parseExpr(b, minPrecedence);
- }
-
- case DOT: {
- consume(NAME);
- String target = string;
- b.add(b.EXPR, prefix);
- if (peekToken() == ASSIGN) {
- consume(ASSIGN);
- ForthBlock val = parseExpr();
- b.add(b.LITERAL, target);
- b.add(b.EXPR, val);
- b.add(b.PUT);
- b.add(b.SWAP);
- b.add(b.POP);
- } else {
- b.add(b.LITERAL, target);
- b.add(b.GET);
- }
- return parseExpr(b, minPrecedence);
- }
-
- case LB: {
- if (prefix == null) {
- b.add(b.ARRAY, new Integer(0));
- int i = 0;
- while(true) {
- ForthBlock e = parseExpr();
- if (e == null && peekToken() == RB) { consume(RB); return parseExpr(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 parseExpr(b, minPrecedence); }
- consume(COMMA);
- }
- } else {
- b.add(b.EXPR, prefix);
- b.add(b.EXPR, parseExpr());
- consume(RB);
- if (peekToken() == ASSIGN) {
- consume(ASSIGN);
- b.add(b.EXPR, parseExpr());
- b.add(b.PUT);
- b.add(b.SWAP);
- b.add(b.POP);
- } else {
- b.add(b.GET);
- }
- return parseExpr(b, minPrecedence);
- }
- }
-
- case LC: {
- b.add(b.OBJECT, null);
- if (peekToken() == RC) { consume(RC); return parseExpr(b, minPrecedence); }
- 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, parseExpr());
- b.add(b.PUT);
- b.add(b.POP);
- if (peekToken() == RC) { consume(RC); return parseExpr(b, minPrecedence); }
- consume(COMMA);
- if (peekToken() == RC) { consume(RC); return parseExpr(b, minPrecedence); }
- }
+ return continueExpr(b, minPrecedence);
}
-
- case HOOK: {
- b.add(b.EXPR, prefix);
- b.add(b.JF, new Integer(3));
- b.add(b.EXPR, parseExpr());
- b.add(b.JMP, new Integer(2));
- consume(COLON);
- b.add(b.EXPR, parseExpr());
- return parseExpr(b, minPrecedence);
- }
-
case Tokens.FUNCTION: {
consume(LP);
int numArgs = 0;
parseStatement(true, b2);
b2.add(b.LITERAL, null);
b2.add(RETURN);
- return parseExpr(b.add(OpCodes.FUNCTION, b2), minPrecedence);
+ return continueExpr(b.add(OpCodes.FUNCTION, b2), minPrecedence);
+ }
+ default: pushBackToken(); return null;
+ }
+ }
+
+
+ /** 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 {
+ int tok = getToken();
+ int curLine = line;
+ if (tok == -1) return prefix;
+ if (minPrecedence > 0 && precedence[tok] != 0)
+ if (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok]))
+ { pushBackToken(); return prefix; }
+
+ if (prefix == null) throw new Error("got null prefix");
+
+ ForthBlock b = appendTo;
+
+ 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);
+ }
+
+ case INC: case DEC: {
+ // postfix
+ prefix.set(prefix.size() - 1, tok, new Boolean(false));
+ b.add(b.EXPR, prefix);
+ return continueExpr(b, minPrecedence);
+ }
+
+ case LP: {
+ // invocation
+ int i = 0;
+ b.add(b.EXPR, prefix);
+ while(peekToken() != RP) {
+ b.add(b.EXPR, startExpr());
+ i++;
+ if (peekToken() == RP) break;
+ consume(COMMA);
+ }
+ consume(RP);
+ b.add(b.CALL, new Integer(i));
+ return continueExpr(b, minPrecedence);
+ }
+
+ 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);
}
+
+ 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);
+ }
+
+ 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);
+ } else {
+ b.add(b.LITERAL, target);
+ b.add(b.GET);
+ }
+ return continueExpr(b, minPrecedence);
+ }
+
+ case LB: {
+ b.add(b.EXPR, prefix);
+ b.add(b.EXPR, startExpr());
+ consume(RB);
+ if (peekToken() == ASSIGN) {
+ consume(ASSIGN);
+ b.add(b.EXPR, startExpr());
+ b.add(b.PUT);
+ b.add(b.SWAP);
+ b.add(b.POP);
+ } else {
+ b.add(b.GET);
+ }
+ return continueExpr(b, minPrecedence);
+ }
+
+ 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));
+ consume(COLON);
+ b.add(b.EXPR, startExpr());
+ return continueExpr(b, minPrecedence);
+ }
+
default: pushBackToken(); return prefix;
}
case THROW: case RETURN: case ASSERT: {
getToken();
if (tok == RETURN && peekToken() == SEMI) b.add(b.LITERAL, null);
- else b.add(b.EXPR, parseExpr());
+ else b.add(b.EXPR, startExpr());
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, parseExpr());
+ b.add(b.EXPR, startExpr());
b.add(b.PUT);
b.add(b.POP);
}
case IF: {
consume(IF);
consume(LP);
- b.add(b.EXPR, parseExpr());
+ b.add(b.EXPR, startExpr());
consume(RP);
b.add(b.JF, new Integer(4));
b.add(b.EXPR, parseStatement());
b.add(loop.LOOP, loop);
loop.add(loop.POP);
- loop.add(loop.EXPR, parseExpr());
+ loop.add(loop.EXPR, startExpr());
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, parseExpr());
+ loop.add(loop.EXPR, startExpr());
consume(RP);
consume(LC);
while(true) {
tok = getToken();
if (tok == CASE) {
loop.add(loop.DUP);
- loop.add(loop.EXPR, parseExpr());
+ 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");
parseStatement(false, loop);
consume(WHILE);
consume(LP);
- loop.add(loop.EXPR, parseExpr());
+ loop.add(loop.EXPR, startExpr());
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, parseExpr());
+ b.add(b.EXPR, startExpr());
b.add(b.PUSHKEYS);
b.add(b.LITERAL, "length");
b.add(b.GET);
b.add(b.SCOPE, b2);
b.add(b.POP);
- ForthBlock e1 = parseExpr();
+ 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 = parseExpr();
+ ForthBlock e2 = startExpr();
consume(SEMI);
- ForthBlock e3 = parseExpr();
+ ForthBlock e3 = startExpr();
consume(RP);
if (e2 == null) e2 = new ForthBlock(curLine, sourceName, b.LITERAL, null);
if (tok == RC && braced) { consume(RC); return; }
// fall through
default: {
- ForthBlock ret = parseExpr();
+ ForthBlock ret = startExpr();
if (ret == null) return;
b.add(b.EXPR, ret);
b.add(b.POP);