+ /** parses the largest possible expression */
+ public Expr parseMaximalExpr() throws IOException { return parseMaximalExpr(null, -1); }
+ public Expr parseMaximalExpr(Expr prefix, int minPrecedence) throws IOException {
+ Expr save = null;
+ do {
+ save = prefix;
+ if (peekToken() == -1) break;
+ prefix = parseSingleExpr(prefix, minPrecedence);
+ if (prefix == null) throw new Error("parseSingleExpr_() returned null");
+ } while (save != prefix);
+ return prefix;
+ }
+
+ /** parses the smallest possible complete expression */
+ public Expr parseSingleExpr() throws IOException { return parseSingleExpr(null, 0); }
+
+ /** parses the smallest possible complete expression beginning with prefix and only using operators with at least minPrecedence */
+ public Expr parseSingleExpr(Expr prefix, int minPrecedence) throws IOException {
+ Expr e1 = null, e2 = null, e3 = null, head = null, tail = null, ret = null;
+
+ int tok = peekToken();
+ if (minPrecedence > 0 && tok < precedence.length && precedence[tok] != 0 && precedence[tok] <= minPrecedence) return prefix;
+ getToken();
+
+ // these case arms match the precedence of operators; each arm is a precedence level.
+ switch (tok) {
+
+ case WITH: throw new Error("XWT does not allow the WITH keyword");
+ case VOID: case RESERVED: throw new Error("reserved word that you shouldn't be using");
+ case NAME: if (prefix != null) { pushBackToken(); return prefix; } else return parseMaximalExpr(new Expr(NAME, string), minPrecedence);
+ case STRING: if (prefix != null) { pushBackToken(); return prefix; } else return new Expr(string);
+ case NUMBER: if (prefix != null) { pushBackToken(); return prefix; } else return new Expr(number);
+ case NULL: case TRUE: case FALSE: case NOP: if (prefix != null) { pushBackToken(); return prefix; } else return new Expr(tok);
+
+ case COMMA: case ASSIGN: case GT: case GE: case OR: case AND:
+ case BITOR: case BITXOR: case BITAND: case EQ: case NE: case LT:
+ case LE: case SHEQ: case SHNE: case LSH: case RSH: case URSH:
+ case ADD: case SUB: case MUL: case DIV: case MOD: case DOT:
+ return new Expr(tok, prefix, parseMaximalExpr(null, precedence[tok]));
+
+ case BITNOT: case INSTANCEOF:
+ if (prefix != null) throw new Error("didn't expect non-null prefix!");
+ return new Expr(tok, parseMaximalExpr(null, precedence[tok]));
+
+ case INC: case DEC:
+ if (prefix == null) {
+ // prefix
+ return new Expr(tok, parseMaximalExpr(null, precedence[tok]));
+ } else {
+ // postfix
+ return new Expr(tok, null, prefix);
+ }
+
+ case LP:
+ if (prefix == null) { // grouping
+ Expr r = parseMaximalExpr();
+ expect(RP);
+ return r;
+
+ } else { // invocation
+ while(peekToken() != RP) {
+ Expr e = parseMaximalExpr(null, precedence[COMMA]);
+ if (head == null) head = tail = e; else tail = tail.next = e;
+ tok = getToken();
+ if (tok == RP) { pushBackToken(); break; }
+ if (tok != COMMA) throw new Error("expected comma or right paren, got " + codeToString[tok]);
+ }
+ getToken();
+ return new Expr(LP, prefix, head);
+ }
+
+ case LB:
+ if (prefix != null) {
+ // subscripting
+ e1 = parseSingleExpr();
+ if (getToken() != RB) throw new Error("expected a right brace");
+ return new Expr(LB, prefix, e1);
+ } else {
+ // array ctor
+ tok = getToken();
+ while(true) {
+ if (tok == RB) return new Expr(LB, prefix, head);
+ if (head == null) head = tail = parseSingleExpr(); else tail = tail.next = parseSingleExpr();
+ tok = getToken();
+ if (tok != COMMA && tok != RP) throw new Error("expected right bracket or comma");
+ }
+ }
+
+ case LC:
+ if (prefix != null) throw new Error("didn't expect non-null prefix");
+ tok = getToken();
+ while(true) {
+ if (tok == RC) return new Expr(LC, head);
+ if (tok != NAME) throw new Error("expecting name");
+ Expr name = parseSingleExpr();
+ if (tok != COLON) throw new Error("expecting colon");
+ e1 = new Expr(COLON, name, parseSingleExpr());
+ if (head == null) head = tail = e1; else tail = tail.next = e1;
+ tok = getToken();
+ if (tok != COMMA && tok != RP) throw new Error("expected right curly or comma");
+ }
+
+ case HOOK:
+ e2 = parseSingleExpr();
+ if (getToken() != COLON) throw new Error("expected colon to close ?: expression");
+ e3 = parseSingleExpr();
+ e2.next = e3;
+ return new Expr(HOOK, prefix, e2);