|
|
@ -4,22 +4,38 @@ import chocopy.common.analysis.AbstractNodeAnalyzer;
|
|
|
|
import chocopy.common.analysis.SymbolTable;
|
|
|
|
import chocopy.common.analysis.SymbolTable;
|
|
|
|
import chocopy.common.astnodes.ReturnStmt;
|
|
|
|
import chocopy.common.astnodes.ReturnStmt;
|
|
|
|
import chocopy.common.astnodes.Stmt;
|
|
|
|
import chocopy.common.astnodes.Stmt;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.StringLiteral;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.AssignStmt;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.BinaryExpr;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.BooleanLiteral;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.Expr;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.Identifier;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.IntegerLiteral;
|
|
|
|
|
|
|
|
import chocopy.common.astnodes.Literal;
|
|
|
|
import chocopy.common.codegen.*;
|
|
|
|
import chocopy.common.codegen.*;
|
|
|
|
|
|
|
|
import chocopy.common.codegen.Label;
|
|
|
|
|
|
|
|
import chocopy.common.codegen.RiscVBackend.Register;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import chocopy.common.analysis.types.Type;
|
|
|
|
|
|
|
|
|
|
|
|
import static chocopy.common.codegen.RiscVBackend.Register.*;
|
|
|
|
import static chocopy.common.codegen.RiscVBackend.Register.*;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* This is where the main implementation of PA3 will live.
|
|
|
|
* This is where the main implementation of PA3 will live.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* <p>A large part of the functionality has already been implemented in the base class, CodeGenBase.
|
|
|
|
* <p>
|
|
|
|
* Make sure to read through that class, since you will want to use many of its fields and utility
|
|
|
|
* A large part of the functionality has already been implemented in the base
|
|
|
|
* methods in this class when emitting code.
|
|
|
|
* class, CodeGenBase. Make sure to read through that class, since you will want
|
|
|
|
|
|
|
|
* to use many of its fields and utility methods in this class when emitting
|
|
|
|
|
|
|
|
* code.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* <p>Also read the PDF spec for details on what the base class does and what APIs it exposes for
|
|
|
|
* <p>
|
|
|
|
* its sub-class (this one). Of particular importance is knowing what all the SymbolInfo classes
|
|
|
|
* Also read the PDF spec for details on what the base class does and what APIs
|
|
|
|
* contain.
|
|
|
|
* it exposes for its sub-class (this one). Of particular importance is knowing
|
|
|
|
|
|
|
|
* what all the SymbolInfo classes contain.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public class CodeGenImpl extends CodeGenBase {
|
|
|
|
public class CodeGenImpl extends CodeGenBase {
|
|
|
|
|
|
|
|
|
|
|
@ -38,17 +54,19 @@ public class CodeGenImpl extends CodeGenBase {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Emits the top level of the program.
|
|
|
|
* Emits the top level of the program.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* <p>This method is invoked exactly once, and is surrounded by some boilerplate code that: (1)
|
|
|
|
* <p>
|
|
|
|
* initializes the heap before the top-level begins and (2) exits after the top-level ends.
|
|
|
|
* This method is invoked exactly once, and is surrounded by some boilerplate
|
|
|
|
|
|
|
|
* code that: (1) initializes the heap before the top-level begins and (2) exits
|
|
|
|
|
|
|
|
* after the top-level ends.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* <p>You only need to generate code for statements.
|
|
|
|
* <p>
|
|
|
|
|
|
|
|
* You only need to generate code for statements.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param statements top level statements
|
|
|
|
* @param statements top level statements
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
protected void emitTopLevel(List<Stmt> statements) {
|
|
|
|
protected void emitTopLevel(List<Stmt> statements) {
|
|
|
|
StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(null);
|
|
|
|
StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(null);
|
|
|
|
backend.emitADDI(
|
|
|
|
backend.emitADDI(SP, SP, -2 * backend.getWordSize(), "Saved FP and saved RA (unused at top level).");
|
|
|
|
SP, SP, -2 * backend.getWordSize(), "Saved FP and saved RA (unused at top level).");
|
|
|
|
|
|
|
|
backend.emitSW(ZERO, SP, 0, "Top saved FP is 0.");
|
|
|
|
backend.emitSW(ZERO, SP, 0, "Top saved FP is 0.");
|
|
|
|
backend.emitSW(ZERO, SP, 4, "Top saved RA is 0.");
|
|
|
|
backend.emitSW(ZERO, SP, 4, "Top saved RA is 0.");
|
|
|
|
backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Set FP to previous SP.");
|
|
|
|
backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Set FP to previous SP.");
|
|
|
@ -63,10 +81,11 @@ public class CodeGenImpl extends CodeGenBase {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Emits the code for a function described by FUNCINFO.
|
|
|
|
* Emits the code for a function described by FUNCINFO.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* <p>This method is invoked once per function and method definition. At the code generation
|
|
|
|
* <p>
|
|
|
|
* stage, nested functions are emitted as separate functions of their own. So if function `bar`
|
|
|
|
* This method is invoked once per function and method definition. At the code
|
|
|
|
* is nested within function `foo`, you only emit `foo`'s code for `foo` and only emit `bar`'s
|
|
|
|
* generation stage, nested functions are emitted as separate functions of their
|
|
|
|
* code for `bar`.
|
|
|
|
* own. So if function `bar` is nested within function `foo`, you only emit
|
|
|
|
|
|
|
|
* `foo`'s code for `foo` and only emit `bar`'s code for `bar`.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
protected void emitUserDefinedFunction(FuncInfo funcInfo) {
|
|
|
|
protected void emitUserDefinedFunction(FuncInfo funcInfo) {
|
|
|
|
backend.emitGlobalLabel(funcInfo.getCodeLabel());
|
|
|
|
backend.emitGlobalLabel(funcInfo.getCodeLabel());
|
|
|
@ -86,34 +105,30 @@ public class CodeGenImpl extends CodeGenBase {
|
|
|
|
/** An analyzer that encapsulates code generation for statements. */
|
|
|
|
/** An analyzer that encapsulates code generation for statements. */
|
|
|
|
private class StmtAnalyzer extends AbstractNodeAnalyzer<Void> {
|
|
|
|
private class StmtAnalyzer extends AbstractNodeAnalyzer<Void> {
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* The symbol table has all the info you need to determine
|
|
|
|
* The symbol table has all the info you need to determine what a given
|
|
|
|
* what a given identifier 'x' in the current scope is. You can
|
|
|
|
* identifier 'x' in the current scope is. You can use it as follows: SymbolInfo
|
|
|
|
* use it as follows:
|
|
|
|
* x = sym.get("x");
|
|
|
|
* SymbolInfo x = sym.get("x");
|
|
|
|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* A SymbolInfo can be one the following:
|
|
|
|
* A SymbolInfo can be one the following: - ClassInfo: a descriptor for classes
|
|
|
|
* - ClassInfo: a descriptor for classes
|
|
|
|
* - FuncInfo: a descriptor for functions/methods - AttrInfo: a descriptor for
|
|
|
|
* - FuncInfo: a descriptor for functions/methods
|
|
|
|
* attributes - GlobalVarInfo: a descriptor for global variables - StackVarInfo:
|
|
|
|
* - AttrInfo: a descriptor for attributes
|
|
|
|
* a descriptor for variables allocated on the stack, such as locals and
|
|
|
|
* - GlobalVarInfo: a descriptor for global variables
|
|
|
|
* parameters
|
|
|
|
* - StackVarInfo: a descriptor for variables allocated on the stack,
|
|
|
|
|
|
|
|
* such as locals and parameters
|
|
|
|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Since the input program is assumed to be semantically
|
|
|
|
* Since the input program is assumed to be semantically valid and well-typed at
|
|
|
|
* valid and well-typed at this stage, you can always assume that
|
|
|
|
* this stage, you can always assume that the symbol table contains valid
|
|
|
|
* the symbol table contains valid information. For example, in
|
|
|
|
* information. For example, in an expression `foo()` you KNOW that
|
|
|
|
* an expression `foo()` you KNOW that sym.get("foo") will either be
|
|
|
|
* sym.get("foo") will either be a FuncInfo or ClassInfo, but not any of the
|
|
|
|
* a FuncInfo or ClassInfo, but not any of the other infos
|
|
|
|
* other infos and never null.
|
|
|
|
* and never null.
|
|
|
|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The symbol table in funcInfo has already been populated in
|
|
|
|
* The symbol table in funcInfo has already been populated in the base class:
|
|
|
|
* the base class: CodeGenBase. You do not need to add anything to
|
|
|
|
* CodeGenBase. You do not need to add anything to the symbol table. Simply
|
|
|
|
* the symbol table. Simply query it with an identifier name to
|
|
|
|
* query it with an identifier name to get a descriptor for a function, class,
|
|
|
|
* get a descriptor for a function, class, variable, etc.
|
|
|
|
* variable, etc.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The symbol table also maps nonlocal and global vars, so you
|
|
|
|
* The symbol table also maps nonlocal and global vars, so you only need to
|
|
|
|
* only need to lookup one symbol table and it will fetch the
|
|
|
|
* lookup one symbol table and it will fetch the appropriate info for the var
|
|
|
|
* appropriate info for the var that is currently in scope.
|
|
|
|
* that is currently in scope.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** Symbol table for my statements. */
|
|
|
|
/** Symbol table for my statements. */
|
|
|
@ -125,7 +140,10 @@ public class CodeGenImpl extends CodeGenBase {
|
|
|
|
/** The descriptor for the current function, or null at the top level. */
|
|
|
|
/** The descriptor for the current function, or null at the top level. */
|
|
|
|
private final FuncInfo funcInfo;
|
|
|
|
private final FuncInfo funcInfo;
|
|
|
|
|
|
|
|
|
|
|
|
/** An analyzer for the function described by FUNCINFO0, which is null for the top level. */
|
|
|
|
/**
|
|
|
|
|
|
|
|
* An analyzer for the function described by FUNCINFO0, which is null for the
|
|
|
|
|
|
|
|
* top level.
|
|
|
|
|
|
|
|
*/
|
|
|
|
StmtAnalyzer(FuncInfo funcInfo0) {
|
|
|
|
StmtAnalyzer(FuncInfo funcInfo0) {
|
|
|
|
funcInfo = funcInfo0;
|
|
|
|
funcInfo = funcInfo0;
|
|
|
|
if (funcInfo == null) {
|
|
|
|
if (funcInfo == null) {
|
|
|
@ -148,6 +166,56 @@ public class CodeGenImpl extends CodeGenBase {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME: More, of course.
|
|
|
|
// FIXME: More, of course.
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public Void analyze(AssignStmt node) {
|
|
|
|
|
|
|
|
if (sym.getParent() == null) {
|
|
|
|
|
|
|
|
Type t = node.value.getInferredType();
|
|
|
|
|
|
|
|
for(Expr target: node.targets)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GlobalVarInfo gvi=(GlobalVarInfo)sym.get(((Identifier)target).name);
|
|
|
|
|
|
|
|
if(t==Type.INT_TYPE)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
IntegerLiteral lt = (IntegerLiteral)node.value;
|
|
|
|
|
|
|
|
backend.emitLI(Register.A0, lt.value, "Load integer literal "+lt.value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if(t==Type.BOOL_TYPE)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
BooleanLiteral lt = (BooleanLiteral)node.value;
|
|
|
|
|
|
|
|
if(lt.value==true)
|
|
|
|
|
|
|
|
backend.emitLI(Register.A0, 1, "Load boolean literal "+1);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
backend.emitLI(Register.A0, 0, "Load boolean literal "+0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
StringLiteral lt = (StringLiteral)node.value;
|
|
|
|
|
|
|
|
System.out.println(strClass.getClassName()+" "+strClass.getTypeTag()+" "+strClass.getDispatchTableLabel().labelName);
|
|
|
|
|
|
|
|
Label l = constants.getStrConstant(lt.value);
|
|
|
|
|
|
|
|
backend.emitLA(Register.A0, l, "Load string literal");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
backend.emitSW(Register.A0, gvi.getLabel(), Register.T0, "Assign global: "+gvi.getVarName()+"(using tmp register)");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{/* TODO: Assignments inside functions
|
|
|
|
|
|
|
|
for(Expr target: node.targets)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend.emitGlobalLabel("$"+target.kind);
|
|
|
|
|
|
|
|
backend.emitWordLiteral(node.value);
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public Void analyze(BinaryExpr node) {
|
|
|
|
|
|
|
|
// statement
|
|
|
|
|
|
|
|
return defaultAction(node);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|