Homework B (benchmarks)
This commit is contained in:
parent
72cc3206c4
commit
76fbabdf53
141 changed files with 7540 additions and 2032 deletions
File diff suppressed because it is too large
Load diff
51
src/cd/ir/AstReplaceVisitor.java
Executable file
51
src/cd/ir/AstReplaceVisitor.java
Executable file
|
@ -0,0 +1,51 @@
|
|||
package cd.ir;
|
||||
|
||||
|
||||
import cd.ir.Ast.Expr;
|
||||
import cd.ir.Symbol.PrimitiveTypeSymbol;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A visitor that replaces AST nodes in toBeReplaced
|
||||
* used in ConstantAnalysis, deletes all the variables that have a constant value and replace them with a constant
|
||||
*/
|
||||
|
||||
public class AstReplaceVisitor extends AstRewriteVisitor<Ast> {
|
||||
|
||||
// use this information to replace each Var node with it's correct constant value
|
||||
public Map<Ast.Expr, Ast.LeafExpr> toBeReplaced;
|
||||
public Map<Expr, Integer> initializePositions;
|
||||
public int currentPosition;
|
||||
|
||||
|
||||
public Ast.LeafExpr getReplacement(Ast.Var arg) {
|
||||
|
||||
// Var was declared constant but initialization happens later
|
||||
// replace it with IntConst or BooleanConst and their default value
|
||||
if (toBeReplaced.containsKey(arg) && currentPosition <= initializePositions.get(arg)) {
|
||||
//if (toBeReplaced.containsKey(arg)) {
|
||||
Ast.LeafExpr leafEpr = (Ast.LeafExpr) arg;
|
||||
if (leafEpr.type == PrimitiveTypeSymbol.intType) {
|
||||
return new Ast.IntConst(0);
|
||||
} else {
|
||||
return new Ast.BooleanConst(false);
|
||||
}
|
||||
}
|
||||
// Var was declared constant and initialization already happened
|
||||
else if (toBeReplaced.containsKey(arg) && currentPosition > initializePositions.get(arg)) {
|
||||
return toBeReplaced.get(arg);
|
||||
}
|
||||
// Var was not declared to be a constant
|
||||
else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Ast var(Ast.Var ast, Void arg) {
|
||||
return getReplacement(ast);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -19,13 +19,14 @@ public class AstRewriteVisitor<A> extends AstVisitor<Ast, A> {
|
|||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when a node is replaced. Subclasses can override it to do some
|
||||
* bookkeeping.
|
||||
* <p>
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
protected void nodeReplaced(Ast oldNode, Ast newNode) {}
|
||||
protected void nodeReplaced(Ast oldNode, Ast newNode) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,18 +4,21 @@ import cd.ir.Ast.Decl;
|
|||
import cd.ir.Ast.Expr;
|
||||
import cd.ir.Ast.Stmt;
|
||||
|
||||
/** A visitor that visits any kind of node */
|
||||
public class AstVisitor<R,A> extends ExprVisitor<R,A> {
|
||||
|
||||
/**
|
||||
* Recurse and process {@code ast}. It is preferred to
|
||||
/**
|
||||
* A visitor that visits any kind of node
|
||||
*/
|
||||
public class AstVisitor<R, A> extends ExprVisitor<R, A> {
|
||||
|
||||
/**
|
||||
* Recurse and process {@code ast}. It is preferred to
|
||||
* call this rather than calling accept directly, since
|
||||
* it can be overloaded to introduce memoization,
|
||||
* for example. */
|
||||
* it can be overloaded to introduce memoization,
|
||||
* for example.
|
||||
*/
|
||||
public R visit(Ast ast, A arg) {
|
||||
return ast.accept(this, arg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides {@link ExprVisitor#visitChildren(Expr, Object)} and
|
||||
* delegates to the more general {@link #visitChildren(Ast, Object)}
|
||||
|
@ -26,11 +29,11 @@ public class AstVisitor<R,A> extends ExprVisitor<R,A> {
|
|||
public final R visitChildren(Expr ast, A arg) {
|
||||
return visitChildren((Ast) ast, arg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A handy function which visits the children of {@code ast},
|
||||
* providing "arg" to each of them. It returns the result of
|
||||
* the last child in the list. It is invoked by the method
|
||||
* the last child in the list. It is invoked by the method
|
||||
* {@link #dflt(Ast, Object)} by default.
|
||||
*/
|
||||
public R visitChildren(Ast ast, A arg) {
|
||||
|
@ -39,35 +42,39 @@ public class AstVisitor<R,A> extends ExprVisitor<R,A> {
|
|||
lastValue = visit(child, arg);
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* The default action for default actions is to call this,
|
||||
* which simply recurses to any children. Also called
|
||||
* by seq() by default. */
|
||||
* by seq() by default.
|
||||
*/
|
||||
protected R dflt(Ast ast, A arg) {
|
||||
return visitChildren(ast, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default action for statements is to call this */
|
||||
|
||||
/**
|
||||
* The default action for statements is to call this
|
||||
*/
|
||||
protected R dfltStmt(Stmt ast, A arg) {
|
||||
return dflt(ast, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default action for expressions is to call this */
|
||||
|
||||
/**
|
||||
* The default action for expressions is to call this
|
||||
*/
|
||||
@Override
|
||||
protected R dfltExpr(Expr ast, A arg) {
|
||||
return dflt(ast, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* The default action for AST nodes representing declarations
|
||||
* is to call this function */
|
||||
* is to call this function
|
||||
*/
|
||||
protected R dfltDecl(Decl ast, A arg) {
|
||||
return dflt(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R assign(Ast.Assign ast, A arg) {
|
||||
return dfltStmt(ast, arg);
|
||||
}
|
||||
|
@ -79,23 +86,23 @@ public class AstVisitor<R,A> extends ExprVisitor<R,A> {
|
|||
public R builtInWriteln(Ast.BuiltInWriteln ast, A arg) {
|
||||
return dfltStmt(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R classDecl(Ast.ClassDecl ast, A arg) {
|
||||
return dfltDecl(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R methodDecl(Ast.MethodDecl ast, A arg) {
|
||||
return dfltDecl(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R varDecl(Ast.VarDecl ast, A arg) {
|
||||
return dfltDecl(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R ifElse(Ast.IfElse ast, A arg) {
|
||||
return dfltStmt(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R returnStmt(Ast.ReturnStmt ast, A arg) {
|
||||
return dfltStmt(ast, arg);
|
||||
}
|
||||
|
@ -107,11 +114,11 @@ public class AstVisitor<R,A> extends ExprVisitor<R,A> {
|
|||
public R nop(Ast.Nop ast, A arg) {
|
||||
return dfltStmt(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R seq(Ast.Seq ast, A arg) {
|
||||
return dflt(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R whileLoop(Ast.WhileLoop ast, A arg) {
|
||||
return dfltStmt(ast, arg);
|
||||
}
|
||||
|
|
113
src/cd/ir/BasicBlock.java
Normal file
113
src/cd/ir/BasicBlock.java
Normal file
|
@ -0,0 +1,113 @@
|
|||
package cd.ir;
|
||||
|
||||
import cd.ir.Ast.Expr;
|
||||
import cd.ir.Ast.Stmt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Node in a control flow graph. New instances should be created
|
||||
* via the methods in {@link ControlFlowGraph}.
|
||||
* Basic blocks consist of a list of statements ({@link #stmts}) which are
|
||||
* executed at runtime. When the basic block ends, control flows into its
|
||||
* {@link #successors}. If the block has more than one successor, it must also
|
||||
* have a non-{@code null} value for {@link #condition}, which describes an expression
|
||||
* that will determine which successor to take. Basic blocks also have fields
|
||||
* for storing the parent and children in the dominator tree. These are generally computed
|
||||
* in a second pass once the graph is fully built.
|
||||
* <p>
|
||||
* Your team will have to write code that builds the control flow graph and computes the
|
||||
* relevant dominator information.
|
||||
*/
|
||||
public class BasicBlock {
|
||||
|
||||
/**
|
||||
* Unique numerical index assigned by CFG builder between 0 and the total number of
|
||||
* basic blocks. Useful for indexing into arrays and the like.
|
||||
*/
|
||||
public final int index;
|
||||
|
||||
/**
|
||||
* List of predecessor blocks in the flow graph (i.e., blocks for
|
||||
* which {@code this} is a successor).
|
||||
*/
|
||||
public final List<BasicBlock> predecessors = new ArrayList<BasicBlock>();
|
||||
|
||||
/**
|
||||
* List of successor blocks in the flow graph (those that come after the
|
||||
* current block). This list is always either of size 0, 1 or 2: 1 indicates
|
||||
* that control flow continues directly into the next block, and 2 indicates
|
||||
* that control flow goes in one of two directions, depending on the
|
||||
* value that results when {@link #condition} is evaluated at runtime.
|
||||
* If there are two successors, then the 0th entry is taken when {@code condition}
|
||||
* evaluates to {@code true}.
|
||||
*
|
||||
* @see #trueSuccessor()
|
||||
* @see #falseSuccessor()
|
||||
*/
|
||||
public final List<BasicBlock> successors = new ArrayList<BasicBlock>();
|
||||
|
||||
/**
|
||||
* List of statements in this basic block.
|
||||
*/
|
||||
public final List<Stmt> stmts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* If non-null, indicates that this basic block should have
|
||||
* two successors. Control flows to the first successor if
|
||||
* this condition evaluates at runtime to true, otherwise to
|
||||
* the second successor. If null, the basic block should have
|
||||
* only one successor.
|
||||
*/
|
||||
public Expr condition;
|
||||
|
||||
/**
|
||||
* Parent of this basic block in the dominator tree (initially null until computed).
|
||||
* Otherwise known as the immediate dominator.
|
||||
*/
|
||||
public BasicBlock dominatorTreeParent = null;
|
||||
|
||||
/**
|
||||
* Children of this basic block in the dominator tree (initially empty until
|
||||
* computed).
|
||||
*/
|
||||
public final List<BasicBlock> dominatorTreeChildren = new ArrayList<BasicBlock>();
|
||||
|
||||
/**
|
||||
* Contains the dominance frontier of this block. A block b is in the dominance
|
||||
* frontier of another block c if c does not dominate b, but c DOES dominate a
|
||||
* predecessor of b.
|
||||
*/
|
||||
public final Set<BasicBlock> dominanceFrontier = new HashSet<BasicBlock>();
|
||||
|
||||
public BasicBlock(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public BasicBlock trueSuccessor() {
|
||||
assert this.condition != null;
|
||||
return this.successors.get(0);
|
||||
}
|
||||
|
||||
public BasicBlock falseSuccessor() {
|
||||
assert this.condition != null;
|
||||
return this.successors.get(1);
|
||||
}
|
||||
|
||||
public <A, B> A accept(AstVisitor<A, B> visitor, B arg) {
|
||||
A lastA = null;
|
||||
for (Stmt stmt : stmts)
|
||||
lastA = visitor.visit(stmt, arg);
|
||||
if (condition != null)
|
||||
lastA = visitor.visit(condition, arg);
|
||||
return lastA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BB" + index;
|
||||
}
|
||||
}
|
135
src/cd/ir/CompileTimeEvaluator.java
Normal file
135
src/cd/ir/CompileTimeEvaluator.java
Normal file
|
@ -0,0 +1,135 @@
|
|||
package cd.ir;
|
||||
|
||||
import cd.ir.Ast.BinaryOp;
|
||||
import cd.ir.Ast.BooleanConst;
|
||||
import cd.ir.Ast.Expr;
|
||||
import cd.ir.Ast.UnaryOp;
|
||||
import cd.ir.Symbol.VariableSymbol;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static cd.Config.FALSE;
|
||||
import static cd.Config.TRUE;
|
||||
|
||||
/**
|
||||
* A visitor that only visits {@link Expr} nodes.
|
||||
* calculates the compile time value of an rhs in an assignment statement or the boolean value of a condition
|
||||
*/
|
||||
public class CompileTimeEvaluator extends ExprVisitor<Integer, Map<VariableSymbol, Integer>> {
|
||||
|
||||
// if the expression contains non constant variables, field or index; or if the expression is a read()
|
||||
// no compile Time value can be computed
|
||||
private boolean failedToEvaluate;
|
||||
|
||||
public Optional<Integer> calc(Ast.Expr ast) {
|
||||
return calc(ast, new HashMap<>());
|
||||
}
|
||||
|
||||
public Optional<Integer> calc(Ast.Expr ast, Map<VariableSymbol, Integer> constantMap) {
|
||||
try {
|
||||
failedToEvaluate = false;
|
||||
Integer result = visit(ast, constantMap);
|
||||
if (failedToEvaluate)
|
||||
return Optional.empty();
|
||||
else
|
||||
return Optional.of(result);
|
||||
} catch (ArithmeticException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer dfltExpr(Expr ast, Map<VariableSymbol, Integer> arg) {
|
||||
failedToEvaluate = true;
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer binaryOp(BinaryOp ast, Map<VariableSymbol, Integer> arg) {
|
||||
boolean tempResult;
|
||||
int left = visit(ast.left(), arg);
|
||||
int right = visit(ast.right(), arg);
|
||||
|
||||
switch (ast.operator) {
|
||||
case B_TIMES:
|
||||
return left * right;
|
||||
case B_PLUS:
|
||||
return left + right;
|
||||
case B_MINUS:
|
||||
return left - right;
|
||||
case B_DIV:
|
||||
return left / right;
|
||||
case B_MOD:
|
||||
return left % right;
|
||||
case B_AND:
|
||||
tempResult = (left == TRUE) && (right == TRUE);
|
||||
break;
|
||||
case B_OR:
|
||||
tempResult = (left == TRUE) || (right == TRUE);
|
||||
break;
|
||||
case B_EQUAL:
|
||||
tempResult = left == right;
|
||||
break;
|
||||
case B_NOT_EQUAL:
|
||||
tempResult = left != right;
|
||||
break;
|
||||
case B_LESS_THAN:
|
||||
tempResult = left < right;
|
||||
break;
|
||||
case B_LESS_OR_EQUAL:
|
||||
tempResult = left <= right;
|
||||
break;
|
||||
case B_GREATER_THAN:
|
||||
tempResult = left > right;
|
||||
break;
|
||||
case B_GREATER_OR_EQUAL:
|
||||
tempResult = left >= right;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Invalid binary operator");
|
||||
}
|
||||
return tempResult ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer unaryOp(UnaryOp ast, Map<VariableSymbol, Integer> arg) {
|
||||
int result = visit(ast.arg(), arg);
|
||||
|
||||
switch (ast.operator) {
|
||||
case U_PLUS:
|
||||
return result;
|
||||
case U_MINUS:
|
||||
return -result;
|
||||
case U_BOOL_NOT:
|
||||
return result == FALSE ? TRUE : FALSE;
|
||||
default:
|
||||
throw new RuntimeException("Invalid unary operator");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer booleanConst(BooleanConst ast, Map<VariableSymbol, Integer> arg) {
|
||||
return ast.value ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer intConst(Ast.IntConst ast, Map<VariableSymbol, Integer> arg) {
|
||||
return ast.value;
|
||||
}
|
||||
|
||||
// check if a given Variable has a constant value
|
||||
@Override
|
||||
public Integer var(Ast.Var ast, Map<VariableSymbol, Integer> arg) {
|
||||
if (arg.containsKey(ast.sym)) {
|
||||
return arg.get(ast.sym);
|
||||
} else {
|
||||
failedToEvaluate = true;
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
61
src/cd/ir/ControlFlowGraph.java
Normal file
61
src/cd/ir/ControlFlowGraph.java
Normal file
|
@ -0,0 +1,61 @@
|
|||
package cd.ir;
|
||||
|
||||
import cd.ir.Ast.Expr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the control flow graph of a single method.
|
||||
*/
|
||||
public class ControlFlowGraph {
|
||||
public BasicBlock start, end;
|
||||
public final List<BasicBlock> allBlocks = new ArrayList<BasicBlock>();
|
||||
|
||||
public int count() {
|
||||
return allBlocks.size();
|
||||
}
|
||||
|
||||
public BasicBlock newBlock() {
|
||||
BasicBlock blk = new BasicBlock(count());
|
||||
allBlocks.add(blk);
|
||||
return blk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of basic blocks that do not yet have successors,
|
||||
* merges their control flows into a single successor and returns
|
||||
* the new successor.
|
||||
*/
|
||||
public BasicBlock join(BasicBlock... pred) {
|
||||
BasicBlock result = newBlock();
|
||||
for (BasicBlock p : pred) {
|
||||
assert p.condition == null;
|
||||
assert p.successors.size() == 0;
|
||||
p.successors.add(result);
|
||||
result.predecessors.add(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates {@code blk} so that it evaluates {@code cond},
|
||||
* and creates two new basic blocks, one for the case where
|
||||
* the result is true, and one for the case where the result is
|
||||
* false.
|
||||
*/
|
||||
public void terminateInCondition(BasicBlock blk, Expr cond) {
|
||||
assert blk.condition == null;
|
||||
assert blk.successors.size() == 0;
|
||||
blk.condition = cond;
|
||||
blk.successors.add(newBlock());
|
||||
blk.successors.add(newBlock());
|
||||
blk.trueSuccessor().predecessors.add(blk);
|
||||
blk.falseSuccessor().predecessors.add(blk);
|
||||
}
|
||||
|
||||
public void connect(BasicBlock from, BasicBlock to) {
|
||||
to.predecessors.add(from);
|
||||
from.successors.add(to);
|
||||
}
|
||||
}
|
|
@ -5,16 +5,17 @@ import cd.ir.Ast.Expr;
|
|||
/**
|
||||
* A visitor that only visits {@link Expr} nodes.
|
||||
*/
|
||||
public class ExprVisitor<R,A> {
|
||||
/**
|
||||
* Recurse and process {@code ast}. It is preferred to
|
||||
public class ExprVisitor<R, A> {
|
||||
/**
|
||||
* Recurse and process {@code ast}. It is preferred to
|
||||
* call this rather than calling accept directly, since
|
||||
* it can be overloaded to introduce memoization,
|
||||
* for example. */
|
||||
* it can be overloaded to introduce memoization,
|
||||
* for example.
|
||||
*/
|
||||
public R visit(Expr ast, A arg) {
|
||||
return ast.accept(this, arg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Visits all children of the expression. Relies on the fact
|
||||
* that {@link Expr} nodes only contain other {@link Expr} nodes.
|
||||
|
@ -22,18 +23,19 @@ public class ExprVisitor<R,A> {
|
|||
public R visitChildren(Expr ast, A arg) {
|
||||
R lastValue = null;
|
||||
for (Ast child : ast.children())
|
||||
lastValue = visit((Expr)child, arg);
|
||||
lastValue = visit((Expr) child, arg);
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* The default action for default actions is to call this,
|
||||
* which simply recurses to any children. Also called
|
||||
* by seq() by default. */
|
||||
* by seq() by default.
|
||||
*/
|
||||
protected R dfltExpr(Expr ast, A arg) {
|
||||
return visitChildren(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R binaryOp(Ast.BinaryOp ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
@ -41,15 +43,15 @@ public class ExprVisitor<R,A> {
|
|||
public R booleanConst(Ast.BooleanConst ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R builtInRead(Ast.BuiltInRead ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R cast(Ast.Cast ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R field(Ast.Field ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
@ -61,7 +63,7 @@ public class ExprVisitor<R,A> {
|
|||
public R intConst(Ast.IntConst ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R methodCall(Ast.MethodCallExpr ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
@ -73,7 +75,7 @@ public class ExprVisitor<R,A> {
|
|||
public R newArray(Ast.NewArray ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
||||
|
||||
public R nullConst(Ast.NullConst ast, A arg) {
|
||||
return dfltExpr(ast, arg);
|
||||
}
|
||||
|
|
|
@ -1,43 +1,45 @@
|
|||
package cd.ir;
|
||||
|
||||
import cd.backend.codegen.AstCodeGenerator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Symbol {
|
||||
|
||||
|
||||
public final String name;
|
||||
|
||||
|
||||
public static abstract class TypeSymbol extends Symbol {
|
||||
|
||||
|
||||
public TypeSymbol(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public abstract boolean isReferenceType();
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public abstract TypeSymbol getSuperType();
|
||||
|
||||
|
||||
public boolean isSuperTypeOf(TypeSymbol sub) {
|
||||
// "void" is not a subtype of any type not even itself
|
||||
if(this == PrimitiveTypeSymbol.voidType || sub == PrimitiveTypeSymbol.voidType)
|
||||
return false;
|
||||
|
||||
// "void" is not a subtype of any type not even itself
|
||||
if (this == PrimitiveTypeSymbol.voidType || sub == PrimitiveTypeSymbol.voidType)
|
||||
return false;
|
||||
|
||||
if (sub == this)
|
||||
return true;
|
||||
|
||||
|
||||
if (this instanceof PrimitiveTypeSymbol || sub instanceof PrimitiveTypeSymbol)
|
||||
return false; // no hierarchy with primitive types
|
||||
|
||||
|
||||
if (sub == ClassSymbol.nullType && this.isReferenceType())
|
||||
return true;
|
||||
|
||||
|
||||
TypeSymbol curr = sub;
|
||||
while (curr != null) {
|
||||
if (curr == this)
|
||||
|
@ -46,94 +48,106 @@ public abstract class Symbol {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class PrimitiveTypeSymbol extends TypeSymbol {
|
||||
|
||||
/** Symbols for the built-in primitive types */
|
||||
|
||||
/**
|
||||
* Symbols for the built-in primitive types
|
||||
*/
|
||||
public static final PrimitiveTypeSymbol intType = new PrimitiveTypeSymbol("int");
|
||||
public static final PrimitiveTypeSymbol voidType = new PrimitiveTypeSymbol("void");
|
||||
public static final PrimitiveTypeSymbol booleanType = new PrimitiveTypeSymbol("boolean");
|
||||
|
||||
public PrimitiveTypeSymbol(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReferenceType() {
|
||||
public boolean isReferenceType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeSymbol getSuperType() {
|
||||
public TypeSymbol getSuperType() {
|
||||
throw new RuntimeException("should not call this on PrimitiveTypeSymbol");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ArrayTypeSymbol extends TypeSymbol {
|
||||
public final TypeSymbol elementType;
|
||||
|
||||
|
||||
public ArrayTypeSymbol(TypeSymbol elementType) {
|
||||
super(elementType.name+"[]");
|
||||
super(elementType.name + "[]");
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isReferenceType() {
|
||||
public boolean isReferenceType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeSymbol getSuperType() {
|
||||
public TypeSymbol getSuperType() {
|
||||
return ClassSymbol.objectType;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class ClassSymbol extends TypeSymbol {
|
||||
public final Ast.ClassDecl ast;
|
||||
public ClassSymbol superClass;
|
||||
public final VariableSymbol thisSymbol =
|
||||
new VariableSymbol("this", this);
|
||||
public final Map<String, VariableSymbol> fields =
|
||||
new HashMap<String, VariableSymbol>();
|
||||
new VariableSymbol("this", this);
|
||||
public final Map<String, VariableSymbol> fields =
|
||||
new HashMap<String, VariableSymbol>();
|
||||
public final Map<String, MethodSymbol> methods =
|
||||
new HashMap<String, MethodSymbol>();
|
||||
new HashMap<String, MethodSymbol>();
|
||||
|
||||
/** Symbols for the built-in Object and null types */
|
||||
public int totalMethods = -1;
|
||||
|
||||
public int totalFields = -1;
|
||||
|
||||
public int sizeof = -1;
|
||||
|
||||
/**
|
||||
* Symbols for the built-in Object and null types
|
||||
*/
|
||||
public static final ClassSymbol nullType = new ClassSymbol("<null>");
|
||||
public static final ClassSymbol objectType = new ClassSymbol("Object");
|
||||
|
||||
public static final ClassSymbol objectType = new ClassSymbol("Object");
|
||||
|
||||
public ClassSymbol(Ast.ClassDecl ast) {
|
||||
super(ast.name);
|
||||
this.ast = ast;
|
||||
}
|
||||
|
||||
/** Used to create the default {@code Object}
|
||||
* and {@code <null>} types */
|
||||
|
||||
/**
|
||||
* Used to create the default {@code Object}
|
||||
* and {@code <null>} types
|
||||
*/
|
||||
public ClassSymbol(String name) {
|
||||
super(name);
|
||||
this.ast = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isReferenceType() {
|
||||
public boolean isReferenceType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeSymbol getSuperType() {
|
||||
public TypeSymbol getSuperType() {
|
||||
return superClass;
|
||||
}
|
||||
|
||||
|
||||
public VariableSymbol getField(String name) {
|
||||
VariableSymbol fsym = fields.get(name);
|
||||
if (fsym == null && superClass != null)
|
||||
return superClass.getField(name);
|
||||
return fsym;
|
||||
}
|
||||
|
||||
|
||||
public MethodSymbol getMethod(String name) {
|
||||
MethodSymbol msym = methods.get(name);
|
||||
if (msym == null && superClass != null)
|
||||
|
@ -143,32 +157,53 @@ public abstract class Symbol {
|
|||
}
|
||||
|
||||
public static class MethodSymbol extends Symbol {
|
||||
|
||||
|
||||
public final Ast.MethodDecl ast;
|
||||
public final Map<String, VariableSymbol> locals =
|
||||
new HashMap<String, VariableSymbol>();
|
||||
new HashMap<String, VariableSymbol>();
|
||||
public final List<VariableSymbol> parameters =
|
||||
new ArrayList<VariableSymbol>();
|
||||
|
||||
new ArrayList<VariableSymbol>();
|
||||
|
||||
public TypeSymbol returnType;
|
||||
|
||||
|
||||
public ClassSymbol owner;
|
||||
|
||||
public int vtableIndex = -1;
|
||||
|
||||
public MethodSymbol overrides;
|
||||
|
||||
public MethodSymbol(Ast.MethodDecl ast) {
|
||||
super(ast.name);
|
||||
this.ast = ast;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString() {
|
||||
return name + "(...)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class VariableSymbol extends Symbol {
|
||||
|
||||
public static enum Kind { PARAM, LOCAL, FIELD };
|
||||
|
||||
public static enum Kind {PARAM, LOCAL, FIELD}
|
||||
|
||||
;
|
||||
public final TypeSymbol type;
|
||||
public final Kind kind;
|
||||
|
||||
|
||||
/**
|
||||
* Meaning depends on the kind of variable, but generally refers
|
||||
* to the offset in bytes from some base ptr to where the variable
|
||||
* is found.
|
||||
* <ul>
|
||||
* <li>{@code PARAM}, {@code LOCAL}: Offset from BP
|
||||
* <li>{@code FIELD}: Offset from object
|
||||
* <li>{@code CONSTANT}: N/A
|
||||
* </ul>
|
||||
* Computed in {@link AstCodeGenerator}.
|
||||
*/
|
||||
public int offset = -1;
|
||||
|
||||
public VariableSymbol(String name, TypeSymbol type) {
|
||||
this(name, type, Kind.PARAM);
|
||||
}
|
||||
|
@ -176,11 +211,11 @@ public abstract class Symbol {
|
|||
public VariableSymbol(String name, TypeSymbol type, Kind kind) {
|
||||
super(name);
|
||||
this.type = type;
|
||||
this.kind = kind;
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue