javassist.compiler.Parser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
/*
* 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;
}
}