/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999-2007 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.
*
* 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 begining 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;
}
}