/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later, * or the Apache License Version 2.0. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */ package javassist.compiler; import javassist.compiler.ast.*; public final class Parser implements TokenId { private Lex lex; public Parser(Lex lex) { this.lex = lex; } public boolean hasMore() { return lex.lookAhead() >= 0; } /* member.declaration * : method.declaration | field.declaration */ public ASTList parseMember(SymbolTable tbl) throws CompileError { ASTList mem = parseMember1(tbl); if (mem instanceof MethodDecl) return parseMethod2(tbl, (MethodDecl)mem); else return mem; } /* A method body is not parsed. */ public ASTList parseMember1(SymbolTable tbl) throws CompileError { ASTList mods = parseMemberMods(); Declarator d; boolean isConstructor = false; if (lex.lookAhead() == Identifier && lex.lookAhead(1) == '(') { d = new Declarator(VOID, 0); isConstructor = true; } else d = parseFormalType(tbl); if (lex.get() != Identifier) throw new SyntaxError(lex); String name; if (isConstructor) name = MethodDecl.initName; else name = lex.getString(); d.setVariable(new Symbol(name)); if (isConstructor || lex.lookAhead() == '(') return parseMethod1(tbl, isConstructor, mods, d); else return parseField(tbl, mods, d); } /* field.declaration * : member.modifiers * formal.type Identifier * [ "=" expression ] ";" */ private FieldDecl parseField(SymbolTable tbl, ASTList mods, Declarator d) throws CompileError { ASTree expr = null; if (lex.lookAhead() == '=') { lex.get(); expr = parseExpression(tbl); } int c = lex.get(); if (c == ';') return new FieldDecl(mods, new ASTList(d, new ASTList(expr))); else if (c == ',') throw new CompileError( "only one field can be declared in one declaration", lex); else throw new SyntaxError(lex); } /* method.declaration * : member.modifiers * [ formal.type ] * Identifier "(" [ formal.parameter ( "," formal.parameter )* ] ")" * array.dimension * [ THROWS class.type ( "," class.type ) ] * ( block.statement | ";" ) * * Note that a method body is not parsed. */ private MethodDecl parseMethod1(SymbolTable tbl, boolean isConstructor, ASTList mods, Declarator d) throws CompileError { if (lex.get() != '(') throw new SyntaxError(lex); ASTList parms = null; if (lex.lookAhead() != ')') while (true) { parms = ASTList.append(parms, parseFormalParam(tbl)); int t = lex.lookAhead(); if (t == ',') lex.get(); else if (t == ')') break; } lex.get(); // ')' d.addArrayDim(parseArrayDimension()); if (isConstructor && d.getArrayDim() > 0) throw new SyntaxError(lex); ASTList throwsList = null; if (lex.lookAhead() == THROWS) { lex.get(); while (true) { throwsList = ASTList.append(throwsList, parseClassType(tbl)); if (lex.lookAhead() == ',') lex.get(); else break; } } return new MethodDecl(mods, new ASTList(d, ASTList.make(parms, throwsList, null))); } /* Parses a method body. */ public MethodDecl parseMethod2(SymbolTable tbl, MethodDecl md) throws CompileError { Stmnt body = null; if (lex.lookAhead() == ';') lex.get(); else { body = parseBlock(tbl); if (body == null) body = new Stmnt(BLOCK); } md.sublist(4).setHead(body); return md; } /* member.modifiers * : ( FINAL | SYNCHRONIZED | ABSTRACT * | PUBLIC | PROTECTED | PRIVATE | STATIC * | VOLATILE | TRANSIENT | STRICT )* */ private ASTList parseMemberMods() { int t; ASTList list = null; while (true) { t = lex.lookAhead(); if (t == ABSTRACT || t == FINAL || t == PUBLIC || t == PROTECTED || t == PRIVATE || t == SYNCHRONIZED || t == STATIC || t == VOLATILE || t == TRANSIENT || t == STRICT) list = new ASTList(new Keyword(lex.get()), list); else break; } return list; } /* formal.type : ( build-in-type | class.type ) array.dimension */ private Declarator parseFormalType(SymbolTable tbl) throws CompileError { int t = lex.lookAhead(); if (isBuiltinType(t) || t == VOID) { lex.get(); // primitive type int dim = parseArrayDimension(); return new Declarator(t, dim); } else { ASTList name = parseClassType(tbl); int dim = parseArrayDimension(); return new Declarator(name, dim); } } private static boolean isBuiltinType(int t) { return (t == BOOLEAN || t == BYTE || t == CHAR || t == SHORT || t == INT || t == LONG || t == FLOAT || t == DOUBLE); } /* formal.parameter : formal.type Identifier array.dimension */ private Declarator parseFormalParam(SymbolTable tbl) throws CompileError { Declarator d = parseFormalType(tbl); if (lex.get() != Identifier) throw new SyntaxError(lex); String name = lex.getString(); d.setVariable(new Symbol(name)); d.addArrayDim(parseArrayDimension()); tbl.append(name, d); return d; } /* statement : [ label ":" ]* labeled.statement * * labeled.statement * : block.statement * | if.statement * | while.statement * | do.statement * | for.statement * | switch.statement * | try.statement * | return.statement * | thorw.statement * | break.statement * | continue.statement * | declaration.or.expression * | ";" * * This method may return null (empty statement). */ public Stmnt parseStatement(SymbolTable tbl) throws CompileError { int t = lex.lookAhead(); if (t == '{') return parseBlock(tbl); else if (t == ';') { lex.get(); return new Stmnt(BLOCK); // empty statement } else if (t == Identifier && lex.lookAhead(1) == ':') { lex.get(); // Identifier String label = lex.getString(); lex.get(); // ':' return Stmnt.make(LABEL, new Symbol(label), parseStatement(tbl)); } else if (t == IF) return parseIf(tbl); else if (t == WHILE) return parseWhile(tbl); else if (t == DO) return parseDo(tbl); else if (t == FOR) return parseFor(tbl); else if (t == TRY) return parseTry(tbl); else if (t == SWITCH) return parseSwitch(tbl); else if (t == SYNCHRONIZED) return parseSynchronized(tbl); else if (t == RETURN) return parseReturn(tbl); else if (t == THROW) return parseThrow(tbl); else if (t == BREAK) return parseBreak(tbl); else if (t == CONTINUE) return parseContinue(tbl); else return parseDeclarationOrExpression(tbl, false); } /* block.statement : "{" statement* "}" */ private Stmnt parseBlock(SymbolTable tbl) throws CompileError { if (lex.get() != '{') throw new SyntaxError(lex); Stmnt body = null; SymbolTable tbl2 = new SymbolTable(tbl); while (lex.lookAhead() != '}') { Stmnt s = parseStatement(tbl2); if (s != null) body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s)); } lex.get(); // '}' if (body == null) return new Stmnt(BLOCK); // empty block else return body; } /* if.statement : IF "(" expression ")" statement * [ ELSE statement ] */ private Stmnt parseIf(SymbolTable tbl) throws CompileError { int t = lex.get(); // IF ASTree expr = parseParExpression(tbl); Stmnt thenp = parseStatement(tbl); Stmnt elsep; if (lex.lookAhead() == ELSE) { lex.get(); elsep = parseStatement(tbl); } else elsep = null; return new Stmnt(t, expr, new ASTList(thenp, new ASTList(elsep))); } /* while.statement : WHILE "(" expression ")" statement */ private Stmnt parseWhile(SymbolTable tbl) throws CompileError { int t = lex.get(); // WHILE ASTree expr = parseParExpression(tbl); Stmnt body = parseStatement(tbl); return new Stmnt(t, expr, body); } /* do.statement : DO statement WHILE "(" expression ")" ";" */ private Stmnt parseDo(SymbolTable tbl) throws CompileError { int t = lex.get(); // DO Stmnt body = parseStatement(tbl); if (lex.get() != WHILE || lex.get() != '(') throw new SyntaxError(lex); ASTree expr = parseExpression(tbl); if (lex.get() != ')' || lex.get() != ';') throw new SyntaxError(lex); return new Stmnt(t, expr, body); } /* for.statement : FOR "(" decl.or.expr expression ";" expression ")" * statement */ private Stmnt parseFor(SymbolTable tbl) throws CompileError { Stmnt expr1, expr3; ASTree expr2; int t = lex.get(); // FOR SymbolTable tbl2 = new SymbolTable(tbl); if (lex.get() != '(') throw new SyntaxError(lex); if (lex.lookAhead() == ';') { lex.get(); expr1 = null; } else expr1 = parseDeclarationOrExpression(tbl2, true); if (lex.lookAhead() == ';') expr2 = null; else expr2 = parseExpression(tbl2); if (lex.get() != ';') throw new CompileError("; is missing", lex); if (lex.lookAhead() == ')') expr3 = null; else expr3 = parseExprList(tbl2); if (lex.get() != ')') throw new CompileError(") is missing", lex); Stmnt body = parseStatement(tbl2); return new Stmnt(t, expr1, new ASTList(expr2, new ASTList(expr3, body))); } /* switch.statement : SWITCH "(" expression ")" "{" switch.block "}" * * swtich.block : ( switch.label statement* )* * * swtich.label : DEFAULT ":" * | CASE const.expression ":" */ private Stmnt parseSwitch(SymbolTable tbl) throws CompileError { int t = lex.get(); // SWITCH ASTree expr = parseParExpression(tbl); Stmnt body = parseSwitchBlock(tbl); return new Stmnt(t, expr, body); } private Stmnt parseSwitchBlock(SymbolTable tbl) throws CompileError { if (lex.get() != '{') throw new SyntaxError(lex); SymbolTable tbl2 = new SymbolTable(tbl); Stmnt s = parseStmntOrCase(tbl2); if (s == null) throw new CompileError("empty switch block", lex); int op = s.getOperator(); if (op != CASE && op != DEFAULT) throw new CompileError("no case or default in a switch block", lex); Stmnt body = new Stmnt(BLOCK, s); while (lex.lookAhead() != '}') { Stmnt s2 = parseStmntOrCase(tbl2); if (s2 != null) { int op2 = s2.getOperator(); if (op2 == CASE || op2 == DEFAULT) { body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s2)); s = s2; } else s = (Stmnt)ASTList.concat(s, new Stmnt(BLOCK, s2)); } } lex.get(); // '}' return body; } private Stmnt parseStmntOrCase(SymbolTable tbl) throws CompileError { int t = lex.lookAhead(); if (t != CASE && t != DEFAULT) return parseStatement(tbl); lex.get(); Stmnt s; if (t == CASE) s = new Stmnt(t, parseExpression(tbl)); else s = new Stmnt(DEFAULT); if (lex.get() != ':') throw new CompileError(": is missing", lex); return s; } /* synchronized.statement : * SYNCHRONIZED "(" expression ")" block.statement */ private Stmnt parseSynchronized(SymbolTable tbl) throws CompileError { int t = lex.get(); // SYNCHRONIZED if (lex.get() != '(') throw new SyntaxError(lex); ASTree expr = parseExpression(tbl); if (lex.get() != ')') throw new SyntaxError(lex); Stmnt body = parseBlock(tbl); return new Stmnt(t, expr, body); } /* try.statement * : TRY block.statement * [ CATCH "(" class.type Identifier ")" block.statement ]* * [ FINALLY block.statement ]* */ private Stmnt parseTry(SymbolTable tbl) throws CompileError { lex.get(); // TRY Stmnt block = parseBlock(tbl); ASTList catchList = null; while (lex.lookAhead() == CATCH) { lex.get(); // CATCH if (lex.get() != '(') throw new SyntaxError(lex); SymbolTable tbl2 = new SymbolTable(tbl); Declarator d = parseFormalParam(tbl2); if (d.getArrayDim() > 0 || d.getType() != CLASS) throw new SyntaxError(lex); if (lex.get() != ')') throw new SyntaxError(lex); Stmnt b = parseBlock(tbl2); catchList = ASTList.append(catchList, new Pair(d, b)); } Stmnt finallyBlock = null; if (lex.lookAhead() == FINALLY) { lex.get(); // FINALLY finallyBlock = parseBlock(tbl); } return Stmnt.make(TRY, block, catchList, finallyBlock); } /* return.statement : RETURN [ expression ] ";" */ private Stmnt parseReturn(SymbolTable tbl) throws CompileError { int t = lex.get(); // RETURN Stmnt s = new Stmnt(t); if (lex.lookAhead() != ';') s.setLeft(parseExpression(tbl)); if (lex.get() != ';') throw new CompileError("; is missing", lex); return s; } /* throw.statement : THROW expression ";" */ private Stmnt parseThrow(SymbolTable tbl) throws CompileError { int t = lex.get(); // THROW ASTree expr = parseExpression(tbl); if (lex.get() != ';') throw new CompileError("; is missing", lex); return new Stmnt(t, expr); } /* break.statement : BREAK [ Identifier ] ";" */ private Stmnt parseBreak(SymbolTable tbl) throws CompileError { return parseContinue(tbl); } /* continue.statement : CONTINUE [ Identifier ] ";" */ private Stmnt parseContinue(SymbolTable tbl) throws CompileError { int t = lex.get(); // CONTINUE Stmnt s = new Stmnt(t); int t2 = lex.get(); if (t2 == Identifier) { s.setLeft(new Symbol(lex.getString())); t2 = lex.get(); } if (t2 != ';') throw new CompileError("; is missing", lex); return s; } /* declaration.or.expression * : [ FINAL ] built-in-type array.dimension declarators * | [ FINAL ] class.type array.dimension declarators * | expression ';' * | expr.list ';' if exprList is true * * Note: FINAL is currently ignored. This must be fixed * in future. */ private Stmnt parseDeclarationOrExpression(SymbolTable tbl, boolean exprList) throws CompileError { int t = lex.lookAhead(); while (t == FINAL) { lex.get(); t = lex.lookAhead(); } if (isBuiltinType(t)) { t = lex.get(); int dim = parseArrayDimension(); return parseDeclarators(tbl, new Declarator(t, dim)); } else if (t == Identifier) { int i = nextIsClassType(0); if (i >= 0) if (lex.lookAhead(i) == Identifier) { ASTList name = parseClassType(tbl); int dim = parseArrayDimension(); return parseDeclarators(tbl, new Declarator(name, dim)); } } Stmnt expr; if (exprList) expr = parseExprList(tbl); else expr = new Stmnt(EXPR, parseExpression(tbl)); if (lex.get() != ';') throw new CompileError("; is missing", lex); return expr; } /* expr.list : ( expression ',')* expression */ private Stmnt parseExprList(SymbolTable tbl) throws CompileError { Stmnt expr = null; for (;;) { Stmnt e = new Stmnt(EXPR, parseExpression(tbl)); expr = (Stmnt)ASTList.concat(expr, new Stmnt(BLOCK, e)); if (lex.lookAhead() == ',') lex.get(); else return expr; } } /* declarators : declarator [ ',' declarator ]* ';' */ private Stmnt parseDeclarators(SymbolTable tbl, Declarator d) throws CompileError { Stmnt decl = null; for (;;) { decl = (Stmnt)ASTList.concat(decl, new Stmnt(DECL, parseDeclarator(tbl, d))); int t = lex.get(); if (t == ';') return decl; else if (t != ',') throw new CompileError("; is missing", lex); } } /* declarator : Identifier array.dimension [ '=' initializer ] */ private Declarator parseDeclarator(SymbolTable tbl, Declarator d) throws CompileError { if (lex.get() != Identifier || d.getType() == VOID) throw new SyntaxError(lex); String name = lex.getString(); Symbol symbol = new Symbol(name); int dim = parseArrayDimension(); ASTree init = null; if (lex.lookAhead() == '=') { lex.get(); init = parseInitializer(tbl); } Declarator decl = d.make(symbol, dim, init); tbl.append(name, decl); return decl; } /* initializer : expression | array.initializer */ private ASTree parseInitializer(SymbolTable tbl) throws CompileError { if (lex.lookAhead() == '{') return parseArrayInitializer(tbl); else return parseExpression(tbl); } /* array.initializer : * '{' (( array.initializer | expression ) ',')* '}' */ private ArrayInit parseArrayInitializer(SymbolTable tbl) throws CompileError { lex.get(); // '{' ASTree expr = parseExpression(tbl); ArrayInit init = new ArrayInit(expr); while (lex.lookAhead() == ',') { lex.get(); expr = parseExpression(tbl); ASTList.append(init, expr); } if (lex.get() != '}') throw new SyntaxError(lex); return init; } /* par.expression : '(' expression ')' */ private ASTree parseParExpression(SymbolTable tbl) throws CompileError { if (lex.get() != '(') throw new SyntaxError(lex); ASTree expr = parseExpression(tbl); if (lex.get() != ')') throw new SyntaxError(lex); return expr; } /* expression : conditional.expr * | conditional.expr assign.op expression (right-to-left) */ public ASTree parseExpression(SymbolTable tbl) throws CompileError { ASTree left = parseConditionalExpr(tbl); if (!isAssignOp(lex.lookAhead())) return left; int t = lex.get(); ASTree right = parseExpression(tbl); return AssignExpr.makeAssign(t, left, right); } private static boolean isAssignOp(int t) { return t == '=' || t == MOD_E || t == AND_E || t == MUL_E || t == PLUS_E || t == MINUS_E || t == DIV_E || t == EXOR_E || t == OR_E || t == LSHIFT_E || t == RSHIFT_E || t == ARSHIFT_E; } /* conditional.expr (right-to-left) * : logical.or.expr [ '?' expression ':' conditional.expr ] */ private ASTree parseConditionalExpr(SymbolTable tbl) throws CompileError { ASTree cond = parseBinaryExpr(tbl); if (lex.lookAhead() == '?') { lex.get(); ASTree thenExpr = parseExpression(tbl); if (lex.get() != ':') throw new CompileError(": is missing", lex); ASTree elseExpr = parseExpression(tbl); return new CondExpr(cond, thenExpr, elseExpr); } else return cond; } /* logical.or.expr 10 (operator precedence) * : logical.and.expr * | logical.or.expr OROR logical.and.expr left-to-right * * logical.and.expr 9 * : inclusive.or.expr * | logical.and.expr ANDAND inclusive.or.expr * * inclusive.or.expr 8 * : exclusive.or.expr * | inclusive.or.expr "|" exclusive.or.expr * * exclusive.or.expr 7 * : and.expr * | exclusive.or.expr "^" and.expr * * and.expr 6 * : equality.expr * | and.expr "&" equality.expr * * equality.expr 5 * : relational.expr * | equality.expr (EQ | NEQ) relational.expr * * relational.expr 4 * : shift.expr * | relational.expr (LE | GE | "<" | ">") shift.expr * | relational.expr INSTANCEOF class.type ("[" "]")* * * shift.expr 3 * : additive.expr * | shift.expr (LSHIFT | RSHIFT | ARSHIFT) additive.expr * * additive.expr 2 * : multiply.expr * | additive.expr ("+" | "-") multiply.expr * * multiply.expr 1 * : unary.expr * | multiply.expr ("*" | "/" | "%") unary.expr */ private ASTree parseBinaryExpr(SymbolTable tbl) throws CompileError { ASTree expr = parseUnaryExpr(tbl); for (;;) { int t = lex.lookAhead(); int p = getOpPrecedence(t); if (p == 0) return expr; else expr = binaryExpr2(tbl, expr, p); } } private ASTree parseInstanceOf(SymbolTable tbl, ASTree expr) throws CompileError { int t = lex.lookAhead(); if (isBuiltinType(t)) { lex.get(); // primitive type int dim = parseArrayDimension(); return new InstanceOfExpr(t, dim, expr); } else { ASTList name = parseClassType(tbl); int dim = parseArrayDimension(); return new InstanceOfExpr(name, dim, expr); } } private ASTree binaryExpr2(SymbolTable tbl, ASTree expr, int prec) throws CompileError { int t = lex.get(); if (t == INSTANCEOF) return parseInstanceOf(tbl, expr); ASTree expr2 = parseUnaryExpr(tbl); for (;;) { int t2 = lex.lookAhead(); int p2 = getOpPrecedence(t2); if (p2 != 0 && prec > p2) expr2 = binaryExpr2(tbl, expr2, p2); else return BinExpr.makeBin(t, expr, expr2); } } // !"#$%&'( )*+,-./0 12345678 9:;<=>? private static final int[] binaryOpPrecedence = { 0, 0, 0, 0, 1, 6, 0, 0, 0, 1, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0 }; private int getOpPrecedence(int c) { if ('!' <= c && c <= '?') return binaryOpPrecedence[c - '!']; else if (c == '^') return 7; else if (c == '|') return 8; else if (c == ANDAND) return 9; else if (c == OROR) return 10; else if (c == EQ || c == NEQ) return 5; else if (c == LE || c == GE || c == INSTANCEOF) return 4; else if (c == LSHIFT || c == RSHIFT || c == ARSHIFT) return 3; else return 0; // not a binary operator } /* unary.expr : "++"|"--" unary.expr | "+"|"-" unary.expr | "!"|"~" unary.expr | cast.expr | postfix.expr unary.expr.not.plus.minus is a unary expression starting without "+", "-", "++", or "--". */ private ASTree parseUnaryExpr(SymbolTable tbl) throws CompileError { int t; switch (lex.lookAhead()) { case '+' : case '-' : case PLUSPLUS : case MINUSMINUS : case '!' : case '~' : t = lex.get(); if (t == '-') { int t2 = lex.lookAhead(); switch (t2) { case LongConstant : case IntConstant : case CharConstant : lex.get(); return new IntConst(-lex.getLong(), t2); case DoubleConstant : case FloatConstant : lex.get(); return new DoubleConst(-lex.getDouble(), t2); default : break; } } return Expr.make(t, parseUnaryExpr(tbl)); case '(' : return parseCast(tbl); default : return parsePostfix(tbl); } } /* cast.expr : "(" builtin.type ("[" "]")* ")" unary.expr | "(" class.type ("[" "]")* ")" unary.expr2 unary.expr2 is a unary.expr beginning with "(", NULL, StringL, Identifier, THIS, SUPER, or NEW. Either "(int.class)" or "(String[].class)" is a not cast expression. */ private ASTree parseCast(SymbolTable tbl) throws CompileError { int t = lex.lookAhead(1); if (isBuiltinType(t) && nextIsBuiltinCast()) { lex.get(); // '(' lex.get(); // primitive type int dim = parseArrayDimension(); if (lex.get() != ')') throw new CompileError(") is missing", lex); return new CastExpr(t, dim, parseUnaryExpr(tbl)); } else if (t == Identifier && nextIsClassCast()) { lex.get(); // '(' ASTList name = parseClassType(tbl); int dim = parseArrayDimension(); if (lex.get() != ')') throw new CompileError(") is missing", lex); return new CastExpr(name, dim, parseUnaryExpr(tbl)); } else return parsePostfix(tbl); } private boolean nextIsBuiltinCast() { int t; int i = 2; while ((t = lex.lookAhead(i++)) == '[') if (lex.lookAhead(i++) != ']') return false; return lex.lookAhead(i - 1) == ')'; } private boolean nextIsClassCast() { int i = nextIsClassType(1); if (i < 0) return false; int t = lex.lookAhead(i); if (t != ')') return false; t = lex.lookAhead(i + 1); return t == '(' || t == NULL || t == StringL || t == Identifier || t == THIS || t == SUPER || t == NEW || t == TRUE || t == FALSE || t == LongConstant || t == IntConstant || t == CharConstant || t == DoubleConstant || t == FloatConstant; } private int nextIsClassType(int i) { int t; while (lex.lookAhead(++i) == '.') if (lex.lookAhead(++i) != Identifier) return -1; while ((t = lex.lookAhead(i++)) == '[') if (lex.lookAhead(i++) != ']') return -1; return i - 1; } /* array.dimension : [ "[" "]" ]* */ private int parseArrayDimension() throws CompileError { int arrayDim = 0; while (lex.lookAhead() == '[') { ++arrayDim; lex.get(); if (lex.get() != ']') throw new CompileError("] is missing", lex); } return arrayDim; } /* class.type : Identifier ( "." Identifier )* */ private ASTList parseClassType(SymbolTable tbl) throws CompileError { ASTList list = null; for (;;) { if (lex.get() != Identifier) throw new SyntaxError(lex); list = ASTList.append(list, new Symbol(lex.getString())); if (lex.lookAhead() == '.') lex.get(); else break; } return list; } /* postfix.expr : number.literal * | primary.expr * | method.expr * | postfix.expr "++" | "--" * | postfix.expr "[" array.size "]" * | postfix.expr "." Identifier * | postfix.expr ( "[" "]" )* "." CLASS * | postfix.expr "#" Identifier * * "#" is not an operator of regular Java. It separates * a class name and a member name in an expression for static member * access. For example, * java.lang.Integer.toString(3) in regular Java * can be written like this: * java.lang.Integer#toString(3) for this compiler. */ private ASTree parsePostfix(SymbolTable tbl) throws CompileError { int token = lex.lookAhead(); switch (token) { // see also parseUnaryExpr() case LongConstant : case IntConstant : case CharConstant : lex.get(); return new IntConst(lex.getLong(), token); case DoubleConstant : case FloatConstant : lex.get(); return new DoubleConst(lex.getDouble(), token); default : break; } String str; ASTree index; ASTree expr = parsePrimaryExpr(tbl); int t; while (true) { switch (lex.lookAhead()) { case '(' : expr = parseMethodCall(tbl, expr); break; case '[' : if (lex.lookAhead(1) == ']') { int dim = parseArrayDimension(); if (lex.get() != '.' || lex.get() != CLASS) throw new SyntaxError(lex); expr = parseDotClass(expr, dim); } else { index = parseArrayIndex(tbl); if (index == null) throw new SyntaxError(lex); expr = Expr.make(ARRAY, expr, index); } break; case PLUSPLUS : case MINUSMINUS : t = lex.get(); expr = Expr.make(t, null, expr); break; case '.' : lex.get(); t = lex.get(); if (t == CLASS) { expr = parseDotClass(expr, 0); } else if (t == Identifier) { str = lex.getString(); expr = Expr.make('.', expr, new Member(str)); } else throw new CompileError("missing member name", lex); break; case '#' : lex.get(); t = lex.get(); if (t != Identifier) throw new CompileError("missing static member name", lex); str = lex.getString(); expr = Expr.make(MEMBER, new Symbol(toClassName(expr)), new Member(str)); break; default : return expr; } } } /* Parse a .class expression on a class type. For example, * String.class => ('.' "String" "class") * String[].class => ('.' "[LString;" "class") */ private ASTree parseDotClass(ASTree className, int dim) throws CompileError { String cname = toClassName(className); if (dim > 0) { StringBuffer sbuf = new StringBuffer(); while (dim-- > 0) sbuf.append('['); sbuf.append('L').append(cname.replace('.', '/')).append(';'); cname = sbuf.toString(); } return Expr.make('.', new Symbol(cname), new Member("class")); } /* Parses a .class expression on a built-in type. For example, * int.class => ('#' "java.lang.Integer" "TYPE") * int[].class => ('.' "[I", "class") */ private ASTree parseDotClass(int builtinType, int dim) throws CompileError { if (dim > 0) { String cname = CodeGen.toJvmTypeName(builtinType, dim); return Expr.make('.', new Symbol(cname), new Member("class")); } else { String cname; switch(builtinType) { case BOOLEAN : cname = "java.lang.Boolean"; break; case BYTE : cname = "java.lang.Byte"; break; case CHAR : cname = "java.lang.Character"; break; case SHORT : cname = "java.lang.Short"; break; case INT : cname = "java.lang.Integer"; break; case LONG : cname = "java.lang.Long"; break; case FLOAT : cname = "java.lang.Float"; break; case DOUBLE : cname = "java.lang.Double"; break; case VOID : cname = "java.lang.Void"; break; default : throw new CompileError("invalid builtin type: " + builtinType); } return Expr.make(MEMBER, new Symbol(cname), new Member("TYPE")); } } /* method.call : method.expr "(" argument.list ")" * method.expr : THIS | SUPER | Identifier * | postfix.expr "." Identifier * | postfix.expr "#" Identifier */ private ASTree parseMethodCall(SymbolTable tbl, ASTree expr) throws CompileError { if (expr instanceof Keyword) { int token = ((Keyword)expr).get(); if (token != THIS && token != SUPER) throw new SyntaxError(lex); } else if (expr instanceof Symbol) // Identifier ; else if (expr instanceof Expr) { int op = ((Expr)expr).getOperator(); if (op != '.' && op != MEMBER) throw new SyntaxError(lex); } return CallExpr.makeCall(expr, parseArgumentList(tbl)); } private String toClassName(ASTree name) throws CompileError { StringBuffer sbuf = new StringBuffer(); toClassName(name, sbuf); return sbuf.toString(); } private void toClassName(ASTree name, StringBuffer sbuf) throws CompileError { if (name instanceof Symbol) { sbuf.append(((Symbol)name).get()); return; } else if (name instanceof Expr) { Expr expr = (Expr)name; if (expr.getOperator() == '.') { toClassName(expr.oprand1(), sbuf); sbuf.append('.'); toClassName(expr.oprand2(), sbuf); return; } } throw new CompileError("bad static member access", lex); } /* primary.expr : THIS | SUPER | TRUE | FALSE | NULL * | StringL * | Identifier * | NEW new.expr * | "(" expression ")" * | builtin.type ( "[" "]" )* "." CLASS * * Identifier represents either a local variable name, a member name, * or a class name. */ private ASTree parsePrimaryExpr(SymbolTable tbl) throws CompileError { int t; String name; Declarator decl; ASTree expr; switch (t = lex.get()) { case THIS : case SUPER : case TRUE : case FALSE : case NULL : return new Keyword(t); case Identifier : name = lex.getString(); decl = tbl.lookup(name); if (decl == null) return new Member(name); // this or static member else return new Variable(name, decl); // local variable case StringL : return new StringL(lex.getString()); case NEW : return parseNew(tbl); case '(' : expr = parseExpression(tbl); if (lex.get() == ')') return expr; else throw new CompileError(") is missing", lex); default : if (isBuiltinType(t) || t == VOID) { int dim = parseArrayDimension(); if (lex.get() == '.' && lex.get() == CLASS) return parseDotClass(t, dim); } throw new SyntaxError(lex); } } /* new.expr : class.type "(" argument.list ")" * | class.type array.size [ array.initializer ] * | primitive.type array.size [ array.initializer ] */ private NewExpr parseNew(SymbolTable tbl) throws CompileError { ArrayInit init = null; int t = lex.lookAhead(); if (isBuiltinType(t)) { lex.get(); ASTList size = parseArraySize(tbl); if (lex.lookAhead() == '{') init = parseArrayInitializer(tbl); return new NewExpr(t, size, init); } else if (t == Identifier) { ASTList name = parseClassType(tbl); t = lex.lookAhead(); if (t == '(') { ASTList args = parseArgumentList(tbl); return new NewExpr(name, args); } else if (t == '[') { ASTList size = parseArraySize(tbl); if (lex.lookAhead() == '{') init = parseArrayInitializer(tbl); return NewExpr.makeObjectArray(name, size, init); } } throw new SyntaxError(lex); } /* array.size : [ array.index ]* */ private ASTList parseArraySize(SymbolTable tbl) throws CompileError { ASTList list = null; while (lex.lookAhead() == '[') list = ASTList.append(list, parseArrayIndex(tbl)); return list; } /* array.index : "[" [ expression ] "]" */ private ASTree parseArrayIndex(SymbolTable tbl) throws CompileError { lex.get(); // '[' if (lex.lookAhead() == ']') { lex.get(); return null; } else { ASTree index = parseExpression(tbl); if (lex.get() != ']') throw new CompileError("] is missing", lex); return index; } } /* argument.list : "(" [ expression [ "," expression ]* ] ")" */ private ASTList parseArgumentList(SymbolTable tbl) throws CompileError { if (lex.get() != '(') throw new CompileError("( is missing", lex); ASTList list = null; if (lex.lookAhead() != ')') for (;;) { list = ASTList.append(list, parseExpression(tbl)); if (lex.lookAhead() == ',') lex.get(); else break; } if (lex.get() != ')') throw new CompileError(") is missing", lex); return list; } }