squash all the things

This commit is contained in:
Elizabeth Hunt 2023-04-23 00:24:42 -06:00
parent 5f28f80c4e
commit a1c15f0461
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
42 changed files with 1019 additions and 494 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
**/*.asm
classes

28
.vscode/launch.json vendored
View File

@ -1,28 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Main",
"request": "launch",
"mainClass": "main.Main",
"projectName": "p5-compiler_25e45799"
},
{
"type": "java",
"name": "Main",
"request": "launch",
"mainClass": "Main",
"projectName": "p5-compiler_25e45799"
},
{
"type": "java",
"name": "Current File",
"request": "launch",
"mainClass": "${file}"
}
]
}

View File

@ -1,8 +0,0 @@
{
"java.project.referencedLibraries": [
"lib/**/*.jar",
"antlr-4.9.1-complete.jar"
],
"rpc.enabled": false,
"java.debug.settings.onBuildFailureProceed": true
}

View File

@ -1,13 +0,0 @@
# All program code is placed after the
# .text assembler directive
.text
# Declare main as a global function
.globl main
j main
# All memory structures are placed after the
# .data assembler directive
.data

View File

@ -1,3 +1,5 @@
void main() { void main()
{
println("Hello world"); println("Hello world");
println(7 % 3, "hi");
} }

View File

@ -1,20 +1,22 @@
int fib(int i) { int fib(int i) {
if (i == 0) return 1; if (i == 0)
if (i == 1) return 1; return 1;
return fib(i-1) + fib(i-2); if (i == 1)
return 1;
return fib(i - 1) + fib(i - 2);
} }
void main() { void main() {
println("This program prints the first 11 numbers of the Fibonacci sequence"); println("This program prints the first 11 numbers of the Fibonacci sequence");
println(fib(0)); // 1 println(fib(0)); // 1
println(fib(1)); // 1 println(fib(1)); // 1
println(fib(2)); // 2 println(fib(2)); // 2
println(fib(3)); // 3 println(fib(3)); // 3
println(fib(4)); // 5 println(fib(4)); // 5
println(fib(5)); // 8 println(fib(5)); // 8
println(fib(6)); // 13 println(fib(6)); // 13
println(fib(7)); // 21 println(fib(7)); // 21
println(fib(8)); // 34 println(fib(8)); // 34
println(fib(9)); // 55 println(fib(9)); // 55
println(fib(10)); // 89 println(fib(10)); // 89
} }

View File

@ -1,8 +1,9 @@
void main() { void main()
{
println("This program prints 7 7 7 7 7 (separated by newlines)"); println("This program prints 7 7 7 7 7 (separated by newlines)");
println(7); println(7);
println(3+4); println(3 + 4);
println(14/2); println(14 / 2);
println(7*1); println(7 * 1);
println((7*2)/2); println((7 * 2) / 2);
} }

View File

@ -8,14 +8,14 @@ void main() {
{ {
int a; int a;
a = 5; a = 5;
println(a+b); println(a + b);
{ {
int b; int b;
b = 9; b = 9;
a = -2; a = -2;
println(a+b); println(a + b);
} }
b = 4; b = 4;
} }
println(a+b); println(a + b);
} }

View File

@ -19,7 +19,7 @@ void main() {
if (a == 3) { if (a == 3) {
println("4 correct"); println("4 correct");
} }
if (a >= 4) { if (a != 4) {
println("5 not correct"); println("5 not correct");
} else { } else {
println("5 correct"); println("5 correct");

View File

@ -1,304 +1,342 @@
package submit; package submit;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode; import org.antlr.v4.runtime.tree.TerminalNode;
import parser.CminusBaseVisitor; import parser.CminusBaseVisitor;
import parser.CminusParser; import parser.CminusParser;
import submit.ast.*; import submit.ast.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
public class ASTVisitor extends CminusBaseVisitor<Node> { public class ASTVisitor extends CminusBaseVisitor<Node> {
private final Logger LOGGER; private final Logger LOGGER;
private SymbolTable symbolTable; private SymbolTable symbolTable;
public ASTVisitor(Logger LOGGER) { public ASTVisitor(Logger LOGGER) { this.LOGGER = LOGGER; }
this.LOGGER = LOGGER;
public SymbolTable getSymbolTable() { return symbolTable; }
private VarType getVarType(CminusParser.TypeSpecifierContext ctx) {
final String t = ctx.getText();
return (t.equals("int")) ? VarType.INT
: (t.equals("bool")) ? VarType.BOOL
: VarType.CHAR;
}
@Override
public Node visitProgram(CminusParser.ProgramContext ctx) {
symbolTable = new SymbolTable();
List<Declaration> decls = new ArrayList<>();
for (CminusParser.DeclarationContext d : ctx.declaration()) {
decls.add((Declaration)visitDeclaration(d));
}
return new Program(decls);
}
@Override
public Node visitVarDeclaration(CminusParser.VarDeclarationContext ctx) {
VarType type = getVarType(ctx.typeSpecifier());
List<String> ids = new ArrayList<>();
List<Integer> arraySizes = new ArrayList<>();
for (CminusParser.VarDeclIdContext v : ctx.varDeclId()) {
String id = v.ID().getText();
ids.add(id);
// symbolTable.addSymbol(id, new SymbolInfo(id, type, false));
if (v.NUMCONST() != null) {
arraySizes.add(Integer.parseInt(v.NUMCONST().getText()));
} else {
int offset = symbolTable.addOffset(1);
SymbolInfo symbol = new SymbolInfo(id, type, false, offset);
symbolTable.addSymbol(id, symbol);
arraySizes.add(-1);
}
}
final boolean isStatic = false;
return new VarDeclaration(type, ids, arraySizes, isStatic);
}
@Override
public Node visitFunDeclaration(CminusParser.FunDeclarationContext ctx) {
VarType returnType = null;
if (ctx.typeSpecifier() != null) {
returnType = getVarType(ctx.typeSpecifier());
}
String id = ctx.ID().getText();
symbolTable.addSymbol(id, new SymbolInfo(id, returnType, true));
List<Param> params = new ArrayList<>();
SymbolTable newTable = symbolTable.createChild();
symbolTable = newTable;
if (returnType != null) {
symbolTable.addSymbol("return",
new SymbolInfo("return", returnType, false,
symbolTable.addOffset(1)));
} }
public SymbolTable getSymbolTable() { for (CminusParser.ParamContext p : ctx.param()) {
return symbolTable; params.add((Param)visitParam(p));
} }
private VarType getVarType(CminusParser.TypeSpecifierContext ctx) { CompoundStatement statement =
final String t = ctx.getText(); (CompoundStatement)visitStatement(ctx.statement());
return (t.equals("int")) ? VarType.INT : (t.equals("bool")) ? VarType.BOOL : VarType.CHAR;
}
@Override statement.getSymbolTable().addOtherTableBefore(newTable);
public Node visitProgram(CminusParser.ProgramContext ctx) { symbolTable = newTable.getParent();
symbolTable = new SymbolTable();
List<Declaration> decls = new ArrayList<>();
for (CminusParser.DeclarationContext d : ctx.declaration()) {
decls.add((Declaration) visitDeclaration(d));
}
return new Program(decls);
}
@Override return new FunDeclaration(returnType, id, params, statement);
public Node visitVarDeclaration(CminusParser.VarDeclarationContext ctx) { }
VarType type = getVarType(ctx.typeSpecifier());
List<String> ids = new ArrayList<>();
List<Integer> arraySizes = new ArrayList<>();
for (CminusParser.VarDeclIdContext v : ctx.varDeclId()) {
String id = v.ID().getText();
ids.add(id);
symbolTable.addSymbol(id, new SymbolInfo(id, type, false));
if (v.NUMCONST() != null) {
arraySizes.add(Integer.parseInt(v.NUMCONST().getText()));
} else {
arraySizes.add(-1);
}
}
final boolean isStatic = false;
return new VarDeclaration(type, ids, arraySizes, isStatic);
}
@Override @Override
public Node visitFunDeclaration(CminusParser.FunDeclarationContext ctx) { public Node visitParam(CminusParser.ParamContext ctx) {
VarType returnType = null; VarType type = getVarType(ctx.typeSpecifier());
if (ctx.typeSpecifier() != null) { String id = ctx.paramId().ID().getText();
returnType = getVarType(ctx.typeSpecifier()); symbolTable.addSymbol(
} id, new SymbolInfo(id, type, false, symbolTable.addOffset(1)));
String id = ctx.ID().getText();
List<Param> params = new ArrayList<>();
for (CminusParser.ParamContext p : ctx.param()) {
params.add((Param) visitParam(p));
}
Statement statement = (Statement) visitStatement(ctx.statement());
symbolTable.addSymbol(id, new SymbolInfo(id, returnType, true));
return new FunDeclaration(returnType, id, params, statement);
}
@Override return new Param(type, id, ctx.paramId().children.size() > 1);
public Node visitParam(CminusParser.ParamContext ctx) { }
VarType type = getVarType(ctx.typeSpecifier());
String id = ctx.paramId().ID().getText();
symbolTable.addSymbol(id, new SymbolInfo(id, type, false));
return new Param(type, id, ctx.paramId().children.size() > 1);
}
@Override @Override
public Node visitCompoundStmt(CminusParser.CompoundStmtContext ctx) { public Node visitCompoundStmt(CminusParser.CompoundStmtContext ctx) {
symbolTable = symbolTable.createChild(); SymbolTable child = symbolTable.createChild();
List<Statement> statements = new ArrayList<>(); symbolTable = child;
for (CminusParser.VarDeclarationContext d : ctx.varDeclaration()) {
statements.add((VarDeclaration) visitVarDeclaration(d));
}
for (CminusParser.StatementContext d : ctx.statement()) {
statements.add((Statement) visitStatement(d));
}
symbolTable = symbolTable.getParent();
return new CompoundStatement(statements);
}
@Override List<Statement> statements = new ArrayList<>();
public Node visitExpressionStmt(CminusParser.ExpressionStmtContext ctx) { for (CminusParser.VarDeclarationContext d : ctx.varDeclaration()) {
if (ctx.expression() == null) { statements.add((VarDeclaration)visitVarDeclaration(d));
return Statement.empty();
}
return new ExpressionStatement((Expression) visitExpression(ctx.expression()));
} }
for (CminusParser.StatementContext d : ctx.statement()) {
statements.add((Statement)visitStatement(d));
}
symbolTable = child.getParent();
@Override return new CompoundStatement(statements, child);
public Node visitIfStmt(CminusParser.IfStmtContext ctx) { }
Expression expression = (Expression) visitSimpleExpression(ctx.simpleExpression());
Statement trueStatement = (Statement) visitStatement(ctx.statement(0));
Statement falseStatement = null;
if (ctx.statement().size() > 1) {
falseStatement = (Statement) visitStatement(ctx.statement(1));
}
return new If(expression, trueStatement, falseStatement);
}
@Override @Override
public Node visitWhileStmt(CminusParser.WhileStmtContext ctx) { public Node visitExpressionStmt(CminusParser.ExpressionStmtContext ctx) {
Expression expression = (Expression) visitSimpleExpression(ctx.simpleExpression()); if (ctx.expression() == null) {
Statement statement = (Statement) visitStatement(ctx.statement()); return Statement.empty();
return new While(expression, statement);
} }
return new ExpressionStatement(
(Expression)visitExpression(ctx.expression()));
}
@Override @Override
public Node visitReturnStmt(CminusParser.ReturnStmtContext ctx) { public Node visitIfStmt(CminusParser.IfStmtContext ctx) {
if (ctx.expression() != null) { Expression expression =
return new Return((Expression) visitExpression(ctx.expression())); (Expression)visitSimpleExpression(ctx.simpleExpression());
} Statement trueStatement = (Statement)visitStatement(ctx.statement(0));
return new Return(null); Statement falseStatement = null;
if (ctx.statement().size() > 1) {
falseStatement = (Statement)visitStatement(ctx.statement(1));
} }
return new If(expression, trueStatement, falseStatement);
}
@Override @Override
public Node visitBreakStmt(CminusParser.BreakStmtContext ctx) { public Node visitWhileStmt(CminusParser.WhileStmtContext ctx) {
return new Break(); Expression expression =
} (Expression)visitSimpleExpression(ctx.simpleExpression());
Statement statement = (Statement)visitStatement(ctx.statement());
return new While(expression, statement);
}
@Override @Override
public Node visitExpression(CminusParser.ExpressionContext ctx) { public Node visitReturnStmt(CminusParser.ReturnStmtContext ctx) {
final Node ret; if (ctx.expression() != null) {
CminusParser.MutableContext mutable = ctx.mutable(); return new Return((Expression)visitExpression(ctx.expression()));
CminusParser.ExpressionContext expression = ctx.expression();
if (mutable != null) {
// Assignment
ParseTree operator = ctx.getChild(1);
Mutable lhs = (Mutable) visitMutable(mutable);// new Mutable(mutable.ID().getText(), (Expression)
// visitExpression(mutable.expression()));
Expression rhs = null;
if (expression != null) {
rhs = (Expression) visitExpression(expression);
}
ret = new Assignment(lhs, operator.getText(), rhs);
} else {
ret = visitSimpleExpression(ctx.simpleExpression());
}
return ret;
} }
return new Return(null);
}
@Override @Override
public Node visitOrExpression(CminusParser.OrExpressionContext ctx) { public Node visitBreakStmt(CminusParser.BreakStmtContext ctx) {
List<Node> ands = new ArrayList<>(); return new Break();
for (CminusParser.AndExpressionContext and : ctx.andExpression()) { }
ands.add(visitAndExpression(and));
}
if (ands.size() == 1) {
return ands.get(0);
}
BinaryOperator op = new BinaryOperator((Expression) ands.get(0), "||", (Expression) ands.get(1));
for (int i = 2; i < ands.size(); ++i) {
op = new BinaryOperator(op, "||", (Expression) ands.get(i));
}
return op;
}
@Override @Override
public Node visitAndExpression(CminusParser.AndExpressionContext ctx) { public Node visitExpression(CminusParser.ExpressionContext ctx) {
List<Node> uns = new ArrayList<>(); final Node ret;
for (CminusParser.UnaryRelExpressionContext un : ctx.unaryRelExpression()) { CminusParser.MutableContext mutable = ctx.mutable();
uns.add(visitUnaryRelExpression(un)); CminusParser.ExpressionContext expression = ctx.expression();
} if (mutable != null) {
if (uns.size() == 1) { // Assignment
return uns.get(0); ParseTree operator = ctx.getChild(1);
} Mutable lhs = (Mutable)visitMutable(
BinaryOperator op = new BinaryOperator((Expression) uns.get(0), "&&", (Expression) uns.get(1)); mutable); // new Mutable(mutable.ID().getText(), (Expression)
for (int i = 2; i < uns.size(); ++i) { // visitExpression(mutable.expression()));
op = new BinaryOperator(op, "&&", (Expression) uns.get(i)); Expression rhs = null;
} if (expression != null) {
return op; rhs = (Expression)visitExpression(expression);
}
ret = new Assignment(lhs, operator.getText(), rhs);
} else {
ret = visitSimpleExpression(ctx.simpleExpression());
} }
return ret;
}
@Override @Override
public Node visitUnaryRelExpression(CminusParser.UnaryRelExpressionContext ctx) { public Node visitOrExpression(CminusParser.OrExpressionContext ctx) {
Expression e = (Expression) visitRelExpression(ctx.relExpression()); List<Node> ands = new ArrayList<>();
for (TerminalNode n : ctx.BANG()) { for (CminusParser.AndExpressionContext and : ctx.andExpression()) {
e = new UnaryOperator("!", e); ands.add(visitAndExpression(and));
}
return e;
} }
if (ands.size() == 1) {
return ands.get(0);
}
BinaryOperator op = new BinaryOperator((Expression)ands.get(0), "||",
(Expression)ands.get(1));
for (int i = 2; i < ands.size(); ++i) {
op = new BinaryOperator(op, "||", (Expression)ands.get(i));
}
return op;
}
@Override @Override
public Node visitRelExpression(CminusParser.RelExpressionContext ctx) { public Node visitAndExpression(CminusParser.AndExpressionContext ctx) {
List<Node> uns = new ArrayList<>(); List<Node> uns = new ArrayList<>();
for (CminusParser.SumExpressionContext un : ctx.sumExpression()) { for (CminusParser.UnaryRelExpressionContext un : ctx.unaryRelExpression()) {
uns.add(visitSumExpression(un)); uns.add(visitUnaryRelExpression(un));
}
if (uns.size() == 1) {
return uns.get(0);
}
BinaryOperator op = new BinaryOperator((Expression) uns.get(0), ctx.relop(0).getText(),
(Expression) uns.get(1));
for (int i = 2; i < uns.size(); ++i) {
op = new BinaryOperator(op, ctx.relop(i - 1).getText(), (Expression) uns.get(i));
}
return op;
} }
if (uns.size() == 1) {
return uns.get(0);
}
BinaryOperator op = new BinaryOperator((Expression)uns.get(0), "&&",
(Expression)uns.get(1));
for (int i = 2; i < uns.size(); ++i) {
op = new BinaryOperator(op, "&&", (Expression)uns.get(i));
}
return op;
}
@Override @Override
public Node visitSumExpression(CminusParser.SumExpressionContext ctx) { public Node
List<Node> es = new ArrayList<>(); visitUnaryRelExpression(CminusParser.UnaryRelExpressionContext ctx) {
for (CminusParser.TermExpressionContext e : ctx.termExpression()) { Expression e = (Expression)visitRelExpression(ctx.relExpression());
es.add(visitTermExpression(e)); for (TerminalNode n : ctx.BANG()) {
} e = new UnaryOperator("!", e);
if (es.size() == 1) {
return es.get(0);
}
BinaryOperator op = new BinaryOperator((Expression) es.get(0), ctx.sumop(0).getText(), (Expression) es.get(1));
for (int i = 2; i < es.size(); ++i) {
op = new BinaryOperator(op, ctx.sumop(i - 1).getText(), (Expression) es.get(i));
}
return op;
} }
return e;
}
@Override @Override
public Node visitTermExpression(CminusParser.TermExpressionContext ctx) { public Node visitRelExpression(CminusParser.RelExpressionContext ctx) {
List<Node> es = new ArrayList<>(); List<Node> uns = new ArrayList<>();
for (CminusParser.UnaryExpressionContext e : ctx.unaryExpression()) { for (CminusParser.SumExpressionContext un : ctx.sumExpression()) {
es.add(visitUnaryExpression(e)); uns.add(visitSumExpression(un));
}
if (es.size() == 1) {
return es.get(0);
}
BinaryOperator op = new BinaryOperator((Expression) es.get(0), ctx.mulop(0).getText(), (Expression) es.get(1));
for (int i = 2; i < es.size(); ++i) {
op = new BinaryOperator(op, ctx.mulop(i - 1).getText(), (Expression) es.get(i));
}
return op;
} }
if (uns.size() == 1) {
return uns.get(0);
}
BinaryOperator op = new BinaryOperator(
(Expression)uns.get(0), ctx.relop(0).getText(), (Expression)uns.get(1));
for (int i = 2; i < uns.size(); ++i) {
op = new BinaryOperator(op, ctx.relop(i - 1).getText(),
(Expression)uns.get(i));
}
return op;
}
@Override @Override
public Node visitUnaryExpression(CminusParser.UnaryExpressionContext ctx) { public Node visitSumExpression(CminusParser.SumExpressionContext ctx) {
Node ret = visitFactor(ctx.factor()); List<Node> es = new ArrayList<>();
for (int i = ctx.unaryop().size() - 1; i >= 0; i--) { for (CminusParser.TermExpressionContext e : ctx.termExpression()) {
ret = new UnaryOperator(ctx.unaryop(i).getText(), (Expression) ret); es.add(visitTermExpression(e));
}
return ret;
} }
if (es.size() == 1) {
return es.get(0);
}
BinaryOperator op = new BinaryOperator(
(Expression)es.get(0), ctx.sumop(0).getText(), (Expression)es.get(1));
for (int i = 2; i < es.size(); ++i) {
op = new BinaryOperator(op, ctx.sumop(i - 1).getText(),
(Expression)es.get(i));
}
return op;
}
@Override @Override
public Node visitMutable(CminusParser.MutableContext ctx) { public Node visitTermExpression(CminusParser.TermExpressionContext ctx) {
Expression e = null; List<Node> es = new ArrayList<>();
if (ctx.expression() != null) { for (CminusParser.UnaryExpressionContext e : ctx.unaryExpression()) {
e = (Expression) visitExpression(ctx.expression()); es.add(visitUnaryExpression(e));
}
String id = ctx.ID().getText();
if (symbolTable.find(id) == null) {
LOGGER.warning("Undefined symbol on line " + ctx.getStart().getLine() + ": " + id);
}
return new Mutable(id, e);
} }
if (es.size() == 1) {
return es.get(0);
}
BinaryOperator op = new BinaryOperator(
(Expression)es.get(0), ctx.mulop(0).getText(), (Expression)es.get(1));
for (int i = 2; i < es.size(); ++i) {
op = new BinaryOperator(op, ctx.mulop(i - 1).getText(),
(Expression)es.get(i));
}
return op;
}
@Override @Override
public Node visitImmutable(CminusParser.ImmutableContext ctx) { public Node visitUnaryExpression(CminusParser.UnaryExpressionContext ctx) {
if (ctx.expression() != null) { Node ret = visitFactor(ctx.factor());
return new ParenExpression((Expression) visitExpression(ctx.expression())); for (int i = ctx.unaryop().size() - 1; i >= 0; i--) {
} ret = new UnaryOperator(ctx.unaryop(i).getText(), (Expression)ret);
return visitChildren(ctx);
} }
return ret;
}
@Override @Override
public Node visitCall(CminusParser.CallContext ctx) { public Node visitMutable(CminusParser.MutableContext ctx) {
final String id = ctx.ID().getText(); Expression e = null;
final List<Expression> args = new ArrayList<>(); if (ctx.expression() != null) {
for (CminusParser.ExpressionContext e : ctx.expression()) { e = (Expression)visitExpression(ctx.expression());
args.add((Expression) visitExpression(e));
}
if (symbolTable.find(id) == null) {
LOGGER.warning("Undefined symbol on line " + ctx.getStart().getLine() + ": " + id);
}
return new Call(id, args);
} }
String id = ctx.ID().getText();
if (symbolTable.find(id) == null) {
LOGGER.warning("Undefined symbol on line " + ctx.getStart().getLine() +
": " + id);
}
return new Mutable(id, e);
}
@Override @Override
public Node visitConstant(CminusParser.ConstantContext ctx) { public Node visitImmutable(CminusParser.ImmutableContext ctx) {
final Node node; if (ctx.expression() != null) {
if (ctx.NUMCONST() != null) { return new ParenExpression((Expression)visitExpression(ctx.expression()));
node = new NumConstant(Integer.parseInt(ctx.NUMCONST().getText()));
} else if (ctx.CHARCONST() != null) {
node = new CharConstant(ctx.CHARCONST().getText().charAt(0));
} else if (ctx.STRINGCONST() != null) {
node = new StringConstant(ctx.STRINGCONST().getText());
} else {
node = new BoolConstant(ctx.getText().equals("true"));
}
return node;
} }
return visitChildren(ctx);
}
@Override
public Node visitCall(CminusParser.CallContext ctx) {
final String id = ctx.ID().getText();
final List<Expression> args = new ArrayList<>();
for (CminusParser.ExpressionContext e : ctx.expression()) {
args.add((Expression)visitExpression(e));
}
if (symbolTable.find(id) == null) {
LOGGER.warning("Undefined symbol on line " + ctx.getStart().getLine() +
": " + id);
}
return new Call(id, args);
}
@Override
public Node visitConstant(CminusParser.ConstantContext ctx) {
final Node node;
if (ctx.NUMCONST() != null) {
node = new NumConstant(Integer.parseInt(ctx.NUMCONST().getText()));
} else if (ctx.CHARCONST() != null) {
node = new CharConstant(ctx.CHARCONST().getText().charAt(0));
} else if (ctx.STRINGCONST() != null) {
node = new StringConstant(ctx.STRINGCONST().getText());
} else {
node = new BoolConstant(ctx.getText().equals("true"));
}
return node;
}
} }

View File

@ -57,5 +57,4 @@ public class MIPSResult {
public VarType getType() { public VarType getType() {
return type; return type;
} }
} }

View File

@ -15,112 +15,139 @@ import java.util.Set;
*/ */
public final class RegisterAllocator { public final class RegisterAllocator {
// True if t is used // True if t is used
private final boolean[] t = new boolean[10]; private final boolean[] t = new boolean[10];
private final boolean[] s = new boolean[8]; private final boolean[] s = new boolean[8];
private final Set<String> used = new HashSet<>(); private final Set<String> used = new HashSet<>();
public RegisterAllocator() { public RegisterAllocator() { clearAll(); }
clearAll();
public String getRegisterOrLoadIntoRegister(MIPSResult result,
StringBuilder code) {
if (result.getRegister() != null) {
return result.getRegister();
} }
String reg = result.getAddress();
return this.loadIntoRegister(result, code, reg);
}
public String getT() { public String loadIntoRegister(MIPSResult result, StringBuilder code,
for (int i = 0; i < t.length; ++i) { String register) {
if (!t[i]) { return loadIntoRegisterWithOffset(result, code, register, 0);
t[i] = true; }
String str = "$t" + i;
used.add(str); public String loadIntoRegisterWithOffset(MIPSResult result,
return str; StringBuilder code, String register,
} int offset) {
} code.append(
return null; String.format("lw %s %d(%s)\n", register, offset, result.getAddress()));
return register;
}
public String getT() {
for (int i = 0; i < t.length; ++i) {
if (!t[i]) {
t[i] = true;
String str = "$t" + i;
used.add(str);
return str;
}
} }
return null;
}
// public String getS() { // public String getS() {
// for (int i = 0; i < s.length; ++i) { // for (int i = 0; i < s.length; ++i) {
// if (!s[i]) { // if (!s[i]) {
// s[i] = true; // s[i] = true;
// String str = "$s" + i; // String str = "$s" + i;
// used.add(str); // used.add(str);
// return str; // return str;
// } // }
// } // }
// return null; // return null;
// } // }
// Returns the number of bytes used to save the registers // Returns the number of bytes used to save the registers
public int saveRestore(StringBuilder code, int baseOffset, boolean s_or_t, boolean save) { public int saveRestore(StringBuilder code, int baseOffset, boolean s_or_t,
boolean[] r = s; boolean save) {
String prefix = "$s"; boolean[] r = s;
if (!s_or_t) { String prefix = "$s";
r = t; if (!s_or_t) {
prefix = "$t"; r = t;
} prefix = "$t";
String instruction = "sw";
if (!save) {
instruction = "lw";
}
int offset = 0;
for (int i = 0; i < r.length; ++i) {
if (r[i]) {
offset -= 4;
String str = prefix + i;
code.append(instruction).append(" ").append(str).append(" ").append(offset-baseOffset).append("($sp)\n");
}
}
return -offset;
} }
String instruction = "sw";
// public int saveS(StringBuilder code, int baseOffset) { if (!save) {
// return saveRestore(code, baseOffset, true, true); instruction = "lw";
// }
public int saveT(StringBuilder code, int baseOffset) {
return saveRestore(code, baseOffset, false, true);
} }
int offset = 0;
// public int restoreS(StringBuilder code, int baseOffset) { for (int i = 0; i < r.length; ++i) {
// return saveRestore(code, baseOffset, true, false); if (r[i]) {
// } offset -= 4;
String str = prefix + i;
public int restoreT(StringBuilder code, int baseOffset) { code.append(instruction)
return saveRestore(code, baseOffset, false, false); .append(" ")
.append(str)
.append(" ")
.append(offset - baseOffset)
.append("($sp)\n");
}
} }
return -offset;
}
public List<String> getUsed() { // public int saveS(StringBuilder code, int baseOffset) {
return new ArrayList<>(used); // return saveRestore(code, baseOffset, true, true);
} // }
/** public int saveT(StringBuilder code, int baseOffset) {
* Any time you call this method you should seriously consider adding a return saveRestore(code, baseOffset, false, true);
* corresponding clear() call. }
*
* @return
*/
public String getAny() {
// String availS = getS();
// if (availS != null) {
// return availS;
// }
String t = getT();
if (t == null) {
throw new RuntimeException("Out of registers");
}
return t;
}
public void clear(String reg) { // public int restoreS(StringBuilder code, int baseOffset) {
if (reg.charAt(1) == 's') { // return saveRestore(code, baseOffset, true, false);
s[Integer.parseInt(reg.substring(2))] = false; // }
} else if (reg.charAt(1) == 't') {
t[Integer.parseInt(reg.substring(2))] = false;
} else {
throw new RuntimeException("Unexpected register in clear");
}
}
public void clearAll() { public int restoreT(StringBuilder code, int baseOffset) {
Arrays.fill(t, false); return saveRestore(code, baseOffset, false, false);
Arrays.fill(s, false); }
public List<String> getUsed() { return new ArrayList<>(used); }
/**
* Any time you call this method you should seriously consider adding a
* corresponding clear() call.
*
* @return
*/
public String getAny() {
// String availS = getS();
// if (availS != null) {
// return availS;
// }
String t = getT();
if (t == null) {
throw new RuntimeException("Out of registers");
} }
return t;
}
public void clear(String reg) {
if (reg == null)
return;
if (reg.charAt(1) == 's') {
s[Integer.parseInt(reg.substring(2))] = false;
} else if (reg.charAt(1) == 't') {
t[Integer.parseInt(reg.substring(2))] = false;
} else {
throw new RuntimeException("Unexpected register in clear");
}
}
public void clearAll() {
Arrays.fill(t, false);
Arrays.fill(s, false);
}
} }

View File

@ -16,6 +16,7 @@ public class SymbolInfo {
// In the case of a function, type is the return type // In the case of a function, type is the return type
private final VarType type; private final VarType type;
private final boolean function; private final boolean function;
private int offset;
public SymbolInfo(String id, VarType type, boolean function) { public SymbolInfo(String id, VarType type, boolean function) {
this.id = id; this.id = id;
@ -23,9 +24,20 @@ public class SymbolInfo {
this.function = function; this.function = function;
} }
public SymbolInfo(String id, VarType type, boolean function, int offset) {
this(id, type, function);
this.offset = offset;
}
@Override @Override
public String toString() { public String toString() {
return "<" + id + ", " + type + '>'; return "<" + id + ", " + type + '>';
} }
public VarType getType() { return type; }
public boolean isFunction() { return function; }
public int getOffset() { return offset; }
public void setOffset(int offset) { this.offset = offset; }
} }

View File

@ -3,6 +3,7 @@ package submit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import submit.ast.VarType;
/* /*
* Code formatter project * Code formatter project
@ -17,14 +18,71 @@ public class SymbolTable {
private SymbolTable parent; private SymbolTable parent;
private final List<SymbolTable> children; private final List<SymbolTable> children;
private int offset;
public static int LABEL_IDENTIFIER = 0;
public static String nextId() {
return Integer.toString(SymbolTable.LABEL_IDENTIFIER++);
}
public SymbolTable() { public SymbolTable() {
offset = 0;
table = new HashMap<>(); table = new HashMap<>();
parent = null; parent = null;
children = new ArrayList<>(); children = new ArrayList<>();
this.addGlobalSymbols();
} }
public void addSymbol(String id, SymbolInfo symbol) { public List<String> symbolNames() { return new ArrayList<>(table.keySet()); }
table.put(id, symbol);
public void addGlobalSymbols() {
SymbolInfo println = new SymbolInfo("println", null, true);
this.addSymbol("println", println);
}
public void addSymbol(String id, SymbolInfo symbol) { table.put(id, symbol); }
public int addOffset(int n) {
offset -= 4 * n;
return offset;
}
public int getOffset() { return this.offset; }
// Add symbols in before and reorder offsets such that symbols in before have
// a "higher" offset
public void addOtherTableBefore(SymbolTable before) {
offset = 0;
List<String> thisSymbols = symbolNames();
for (String id : before.symbolNames()) {
SymbolInfo symbol = before.find(id);
if (!symbol.isFunction()) {
addOffset(1);
symbol.setOffset(offset);
}
addSymbol(id, symbol);
}
for (String id : thisSymbols) {
SymbolInfo symbol = table.get(id);
if (!symbol.isFunction()) {
addOffset(1);
table.get(id).setOffset(offset);
}
}
}
public int offsetOf(String id) {
if (table.containsKey(id)) {
return table.get(id).getOffset();
}
if (parent != null) {
return -parent.getOffset() + parent.offsetOf(id);
}
return 0; // This shouldn't happen :D
} }
/** /**
@ -56,8 +114,5 @@ public class SymbolTable {
return child; return child;
} }
public SymbolTable getParent() { public SymbolTable getParent() { return parent; }
return parent;
}
} }

View File

@ -10,6 +10,6 @@ public class AbstractNode implements Node {
public MIPSResult toMIPS(StringBuilder code, StringBuilder data, SymbolTable symbolTable, public MIPSResult toMIPS(StringBuilder code, StringBuilder data, SymbolTable symbolTable,
RegisterAllocator regAllocator) { RegisterAllocator regAllocator) {
return null; return MIPSResult.createVoidResult();
} }
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -30,4 +34,25 @@ public class Assignment extends AbstractNode implements Expression {
} }
} }
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
MIPSResult mut = mutable.toMIPS(code, data, symbolTable, regAllocator);
MIPSResult result = rhs.toMIPS(code, data, symbolTable, regAllocator);
String registerWithAddressOfMutable = mut.getAddress();
if (result.getRegister() != null) {
code.append(String.format("sw %s 0(%s)\n", result.getRegister(),
registerWithAddressOfMutable));
regAllocator.clear(result.getRegister());
} else if (result.getAddress() != null) {
regAllocator.loadIntoRegister(result, code, result.getAddress());
regAllocator.clear(result.getAddress());
}
regAllocator.clear(registerWithAddressOfMutable);
return MIPSResult.createVoidResult();
}
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -13,7 +17,8 @@ public class BinaryOperator extends AbstractNode implements Expression {
private final Expression lhs, rhs; private final Expression lhs, rhs;
private final BinaryOperatorType type; private final BinaryOperatorType type;
public BinaryOperator(Expression lhs, BinaryOperatorType type, Expression rhs) { public BinaryOperator(Expression lhs, BinaryOperatorType type,
Expression rhs) {
this.lhs = lhs; this.lhs = lhs;
this.type = type; this.type = type;
this.rhs = rhs; this.rhs = rhs;
@ -32,4 +37,86 @@ public class BinaryOperator extends AbstractNode implements Expression {
rhs.toCminus(builder, prefix); rhs.toCminus(builder, prefix);
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
MIPSResult left = lhs.toMIPS(code, data, symbolTable, regAllocator);
String leftRegister =
regAllocator.getRegisterOrLoadIntoRegister(left, code);
MIPSResult right = rhs.toMIPS(code, data, symbolTable, regAllocator);
String rightRegister =
regAllocator.getRegisterOrLoadIntoRegister(right, code);
String resultRegister = regAllocator.getAny();
switch (type) {
case PLUS:
code.append(String.format("add %s %s %s\n", resultRegister, leftRegister,
rightRegister));
break;
case MINUS:
code.append(String.format("sub %s %s %s\n", resultRegister, leftRegister,
rightRegister));
break;
case TIMES:
code.append(String.format("mult %s %s\n", leftRegister, rightRegister))
.append(String.format("mflo %s\n", resultRegister));
break;
case DIVIDE:
code.append(String.format("div %s %s\n", leftRegister, rightRegister))
.append(String.format("mflo %s\n", resultRegister));
break;
case MOD:
code.append(String.format("div %s %s\n", leftRegister, rightRegister))
.append(String.format("mfhi %s\n", resultRegister));
break;
case LT:
code.append(String.format("slt %s %s %s\n", resultRegister, leftRegister,
rightRegister))
.append(
String.format("subi %s %s 1\n", resultRegister, resultRegister));
break;
case GT:
code.append(String.format("slt %s %s %s\n", resultRegister, rightRegister,
leftRegister))
.append(
String.format("subi %s %s 1\n", resultRegister, resultRegister));
break;
case LE:
code.append(String.format("slt %s %s %s\n", resultRegister, rightRegister,
leftRegister));
break;
case GE:
code.append(String.format("slt %s %s %s\n", resultRegister, leftRegister,
rightRegister));
break;
case EQ:
code.append(String.format("sub %s %s %s\n", resultRegister, leftRegister,
rightRegister));
break;
case OR:
code.append(String.format("or %s %s %s\n", resultRegister, leftRegister,
rightRegister));
break;
case AND:
code.append(String.format("abs %s %s\n", leftRegister, leftRegister))
.append(String.format("abs %s %s\n", rightRegister, rightRegister))
.append(String.format("add %s %s %s\n", resultRegister, leftRegister,
rightRegister));
break;
case NE:
code.append(String.format("xor %s %s %s\n", resultRegister, leftRegister,
rightRegister))
.append(
String.format("sltiu %s %s 1\n", resultRegister, resultRegister));
default:
break;
}
regAllocator.clear(leftRegister);
regAllocator.clear(rightRegister);
return MIPSResult.createRegisterResult(resultRegister, VarType.INT);
}
} }

View File

@ -10,15 +10,23 @@ package submit.ast;
*/ */
public enum BinaryOperatorType { public enum BinaryOperatorType {
OR("||"), AND("&&"), OR("||"),
LE("<="), LT("<"), GT(">"), GE(">="), EQ("=="), NE("!="), AND("&&"),
PLUS("+"), MINUS("-"), TIMES("*"), DIVIDE("/"), MOD("%"); LE("<="),
LT("<"),
GT(">"),
GE(">="),
EQ("=="),
NE("!="),
PLUS("+"),
MINUS("-"),
TIMES("*"),
DIVIDE("/"),
MOD("%");
private final String value; private final String value;
private BinaryOperatorType(String value) { private BinaryOperatorType(String value) { this.value = value; }
this.value = value;
}
public static BinaryOperatorType fromString(String s) { public static BinaryOperatorType fromString(String s) {
for (BinaryOperatorType at : BinaryOperatorType.values()) { for (BinaryOperatorType at : BinaryOperatorType.values()) {
@ -26,12 +34,12 @@ public enum BinaryOperatorType {
return at; return at;
} }
} }
throw new RuntimeException("Illegal string in OperatorType.fromString(): " + s); throw new RuntimeException("Illegal string in OperatorType.fromString(): " +
s);
} }
@Override @Override
public String toString() { public String toString() {
return value; return value;
} }
} }

View File

@ -9,12 +9,9 @@ package submit.ast;
* @author edwajohn * @author edwajohn
*/ */
public class BoolConstant extends AbstractNode implements Expression { public class BoolConstant extends AbstractNode implements Expression {
private final boolean value; private final boolean value;
public BoolConstant(boolean value) { public BoolConstant(boolean value) { this.value = value; }
this.value = value;
}
public void toCminus(StringBuilder builder, final String prefix) { public void toCminus(StringBuilder builder, final String prefix) {
if (value) { if (value) {
@ -23,5 +20,4 @@ public class BoolConstant extends AbstractNode implements Expression {
builder.append("false"); builder.append("false");
} }
} }
} }

View File

@ -9,10 +9,8 @@ package submit.ast;
* @author edwajohn * @author edwajohn
*/ */
public class Break extends AbstractNode implements Statement { public class Break extends AbstractNode implements Statement {
@Override @Override
public void toCminus(StringBuilder builder, String prefix) { public void toCminus(StringBuilder builder, String prefix) {
builder.append(prefix).append("break;\n"); builder.append(prefix).append("break;\n");
} }
} }

View File

@ -6,12 +6,16 @@ package submit.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
*/ */
public class Call extends AbstractNode implements Expression { public class Call implements Expression {
private final String id; private final String id;
private final List<Expression> args; private final List<Expression> args;
@ -21,6 +25,39 @@ public class Call extends AbstractNode implements Expression {
this.args = new ArrayList<>(args); this.args = new ArrayList<>(args);
} }
private void println(List<MIPSResult> mipsResults, StringBuilder code,
StringBuilder data, SymbolTable symbolTable,
RegisterAllocator regAllocator) {
code.append("# println\n");
for (MIPSResult result : mipsResults) {
if (result.getRegister() == null && result.getAddress() != null) {
if (result.getAddress().startsWith("$")) {
// Hack - might be a register
regAllocator.loadIntoRegister(result, code, "$a0");
} else {
code.append(String.format("la $a0 %s\n", result.getAddress()));
}
} else if (result.getRegister() != null) {
code.append(String.format("move $a0 %s\n", result.getRegister()));
}
if (result.getType() == VarType.INT) {
code.append("li $v0 1\n");
} else if (result.getType() == VarType.CHAR) {
code.append("li $v0 11\n");
} else {
code.append("li $v0 4\n");
}
code.append("syscall\n");
}
// End line with newline
code.append(String.format("la $a0 %s\n", "newline"));
code.append("li $v0 4\n");
code.append("syscall\n");
}
@Override @Override
public void toCminus(StringBuilder builder, String prefix) { public void toCminus(StringBuilder builder, String prefix) {
builder.append(id).append("("); builder.append(id).append("(");
@ -34,4 +71,69 @@ public class Call extends AbstractNode implements Expression {
builder.append(")"); builder.append(")");
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
List<MIPSResult> argMips;
String resultRegister = null;
if (this.id.equals("println")) {
argMips =
args.stream()
.map(e -> e.toMIPS(code, data, symbolTable, regAllocator))
.collect(Collectors.toList());
this.println(argMips, code, data, symbolTable, regAllocator);
} else {
argMips = new ArrayList<MIPSResult>();
String returnAddr = regAllocator.getAny();
code.append(String.format("move %s $ra\n", returnAddr));
int savedRegistersOffset = regAllocator.saveRestore(
code, -symbolTable.getOffset(), false, true);
int argsOffset = symbolTable.getOffset() - savedRegistersOffset;
int i = argsOffset;
for (Expression expression : args) {
MIPSResult mipsResult =
expression.toMIPS(code, data, symbolTable, regAllocator);
argMips.add(mipsResult);
i -= 4;
String reg =
regAllocator.getRegisterOrLoadIntoRegister(mipsResult, code);
code.append(String.format("sw %s %d($sp)\n", reg, i));
regAllocator.clear(reg);
}
code.append(String.format("add $sp $sp %d\n", argsOffset));
code.append(String.format("jal %s\n", id));
code.append(String.format("add $sp $sp %d\n", -argsOffset));
regAllocator.saveRestore(code, -symbolTable.getOffset(), false,
false);
code.append(String.format("# symbol table size - %d\n", i));
resultRegister = regAllocator.getAny();
regAllocator.loadIntoRegisterWithOffset(
MIPSResult.createAddressResult("$sp", VarType.INT), code,
resultRegister, i - 4);
code.append(String.format("move $ra %s\n", returnAddr));
regAllocator.clear(returnAddr);
}
for (MIPSResult arg : argMips)
if (arg.getRegister() != null)
regAllocator.clear(arg.getRegister());
if (resultRegister != null) {
VarType returnType = symbolTable.find(id).getType();
return MIPSResult.createRegisterResult(resultRegister, returnType);
}
return MIPSResult.createVoidResult();
}
} }

View File

@ -9,15 +9,11 @@ package submit.ast;
* @author edwajohn * @author edwajohn
*/ */
public class CharConstant extends AbstractNode implements Expression { public class CharConstant extends AbstractNode implements Expression {
private final char value; private final char value;
public CharConstant(char value) { public CharConstant(char value) { this.value = value; }
this.value = value;
}
public void toCminus(StringBuilder builder, final String prefix) { public void toCminus(StringBuilder builder, final String prefix) {
builder.append("'").append(value).append("'"); builder.append("'").append(value).append("'");
} }
} }

View File

@ -5,6 +5,9 @@
package submit.ast; package submit.ast;
import java.util.List; import java.util.List;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
@ -13,11 +16,16 @@ import java.util.List;
public class CompoundStatement extends AbstractNode implements Statement { public class CompoundStatement extends AbstractNode implements Statement {
private final List<Statement> statements; private final List<Statement> statements;
private SymbolTable symbolTable;
public CompoundStatement(List<Statement> statements) { public CompoundStatement(List<Statement> statements,
SymbolTable symbolTable) {
this.statements = statements; this.statements = statements;
this.symbolTable = symbolTable;
} }
public SymbolTable getSymbolTable() { return symbolTable; }
@Override @Override
public void toCminus(StringBuilder builder, String prefix) { public void toCminus(StringBuilder builder, String prefix) {
builder.append(prefix).append("{\n"); builder.append(prefix).append("{\n");
@ -27,4 +35,25 @@ public class CompoundStatement extends AbstractNode implements Statement {
builder.append(prefix).append("}\n"); builder.append(prefix).append("}\n");
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
code.append("# Entering a new scope.\n");
code.append("# Symbols in symbol table:\n");
for (String name : this.symbolTable.symbolNames())
code.append(
String.format("# %s : %d\n", name, this.symbolTable.offsetOf(name)));
code.append("# Update the stack pointer.\n");
code.append(String.format("addi $sp $sp %d\n", symbolTable.getOffset()));
for (Statement statement : statements)
statement.toMIPS(code, data, this.symbolTable, regAllocator);
code.append("# Exit scope.\n");
code.append(String.format("addi $sp $sp %s\n", -symbolTable.getOffset()));
return MIPSResult.createVoidResult();
}
} }

View File

@ -8,6 +8,4 @@ package submit.ast;
* *
* @author edwajohn * @author edwajohn
*/ */
public interface Declaration extends Statement { public interface Declaration extends Statement {}
}

View File

@ -8,6 +8,4 @@ package submit.ast;
* *
* @author edwajohn * @author edwajohn
*/ */
public interface Expression extends Node { public interface Expression extends Node {}
}

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -23,4 +27,11 @@ public class ExpressionStatement extends AbstractNode implements Statement {
builder.append(";\n"); builder.append(";\n");
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
expression.toMIPS(code, data, symbolTable, regAllocator);
return MIPSResult.createVoidResult();
}
} }

View File

@ -6,6 +6,9 @@ package submit.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
@ -19,7 +22,7 @@ public class FunDeclaration extends AbstractNode implements Declaration {
private final Statement statement; private final Statement statement;
public FunDeclaration(VarType returnType, String id, List<Param> params, public FunDeclaration(VarType returnType, String id, List<Param> params,
Statement statement) { Statement statement) {
this.returnType = returnType; this.returnType = returnType;
this.id = id; this.id = id;
this.params = new ArrayList<>(params); this.params = new ArrayList<>(params);
@ -43,4 +46,20 @@ public class FunDeclaration extends AbstractNode implements Declaration {
statement.toCminus(builder, prefix); statement.toCminus(builder, prefix);
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
code.append(id).append(":\n");
statement.toMIPS(code, data, symbolTable, regAllocator);
if (id.equals("main"))
code.append("li $v0 10\nsyscall\n");
else
code.append("jr $ra\n");
regAllocator.clearAll();
return MIPSResult.createVoidResult();
}
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -14,7 +18,8 @@ public class If extends AbstractNode implements Statement {
private final Statement trueStatement; private final Statement trueStatement;
private final Statement falseStatement; private final Statement falseStatement;
public If(Expression expression, Statement trueStatement, Statement falseStatement) { public If(Expression expression, Statement trueStatement,
Statement falseStatement) {
this.expression = expression; this.expression = expression;
this.trueStatement = trueStatement; this.trueStatement = trueStatement;
this.falseStatement = falseStatement; this.falseStatement = falseStatement;
@ -41,4 +46,37 @@ public class If extends AbstractNode implements Statement {
} }
// builder.append(prefix).append("}"); // builder.append(prefix).append("}");
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
String continueLabel = "if_" + SymbolTable.nextId();
String elseLabel = "else_" + SymbolTable.nextId();
MIPSResult expressionTruthiness =
expression.toMIPS(code, data, symbolTable, regAllocator);
code.append(String.format("bne %s $zero %s\n",
expressionTruthiness.getRegister(), elseLabel));
regAllocator.clear(expressionTruthiness.getRegister());
MIPSResult trueRes =
trueStatement.toMIPS(code, data, symbolTable, regAllocator);
regAllocator.clear(trueRes.getRegister());
code.append(String.format("j %s\n", continueLabel))
.append(String.format("%s:\n", elseLabel));
regAllocator.clear(expressionTruthiness.getRegister());
if (falseStatement != null) {
MIPSResult falseRes =
falseStatement.toMIPS(code, data, symbolTable, regAllocator);
regAllocator.clear(falseRes.getRegister());
}
code.append(String.format("%s:\n", continueLabel));
return MIPSResult.createVoidResult();
}
} }

View File

@ -4,11 +4,15 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
*/ */
public class Mutable extends AbstractNode implements Expression { public class Mutable implements Expression {
private final String id; private final String id;
private final Expression index; private final Expression index;
@ -28,4 +32,14 @@ public class Mutable extends AbstractNode implements Expression {
} }
} }
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
String stackReg = regAllocator.getAny();
code.append(String.format("li %s %d\n", stackReg, symbolTable.offsetOf(id)))
.append(String.format("add %s %s $sp\n", stackReg, stackReg));
return MIPSResult.createAddressResult(stackReg, VarType.INT);
}
} }

View File

@ -5,7 +5,8 @@ import submit.RegisterAllocator;
import submit.SymbolTable; import submit.SymbolTable;
public interface Node { public interface Node {
void toCminus(StringBuilder builder, final String prefix); void toCminus(StringBuilder builder, final String prefix);
MIPSResult toMIPS(StringBuilder code, StringBuilder data, SymbolTable symbolTable, RegisterAllocator regAllocator); MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable, RegisterAllocator regAllocator);
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -12,12 +16,19 @@ public class NumConstant extends AbstractNode implements Expression {
private final int value; private final int value;
public NumConstant(int value) { public NumConstant(int value) { this.value = value; }
this.value = value;
}
public void toCminus(StringBuilder builder, final String prefix) { public void toCminus(StringBuilder builder, final String prefix) {
builder.append(Integer.toString(value)); builder.append(Integer.toString(value));
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
String register = regAllocator.getAny();
code.append(String.format("li %s %d\n", register, value));
return MIPSResult.createRegisterResult(register, VarType.INT);
}
} }

View File

@ -20,17 +20,11 @@ public class Param extends AbstractNode implements Node {
this.array = array; this.array = array;
} }
public VarType getType() { public VarType getType() { return type; }
return type;
}
public String getId() { public String getId() { return id; }
return id;
}
public boolean isArray() { public boolean isArray() { return array; }
return array;
}
public void toCminus(StringBuilder builder, final String prefix) { public void toCminus(StringBuilder builder, final String prefix) {
if (isArray()) { if (isArray()) {
@ -39,5 +33,4 @@ public class Param extends AbstractNode implements Node {
builder.append(type).append(" ").append(id); builder.append(type).append(" ").append(id);
} }
} }
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -23,4 +27,10 @@ public class ParenExpression extends AbstractNode implements Expression {
builder.append(")"); builder.append(")");
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
return expression.toMIPS(code, data, symbolTable, regAllocator);
}
} }

View File

@ -6,6 +6,9 @@ package submit.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
@ -33,4 +36,14 @@ public class Program extends AbstractNode implements Node {
} }
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
data.append("newline: .asciiz \"\\n\"\n");
for (Declaration declaration : declarations)
declaration.toMIPS(code, data, symbolTable, regAllocator);
return MIPSResult.createVoidResult();
}
} }

View File

@ -4,17 +4,18 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
*/ */
public class Return extends AbstractNode implements Statement { public class Return extends AbstractNode implements Statement {
private final Expression expr; private final Expression expr;
public Return(Expression expr) { public Return(Expression expr) { this.expr = expr; }
this.expr = expr;
}
@Override @Override
public void toCminus(StringBuilder builder, String prefix) { public void toCminus(StringBuilder builder, String prefix) {
@ -28,4 +29,19 @@ public class Return extends AbstractNode implements Statement {
} }
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
if (expr != null) {
String reg = regAllocator.getRegisterOrLoadIntoRegister(
expr.toMIPS(code, data, symbolTable, regAllocator), code);
code.append(
String.format("# symbol table size - %d\n", symbolTable.getOffset()));
code.append(
String.format("sw %s %d($sp)\n", reg, symbolTable.getOffset()));
code.append("jr $ra\n");
}
return MIPSResult.createVoidResult();
}
} }

View File

@ -11,6 +11,8 @@ import java.util.ArrayList;
* @author edwajohn * @author edwajohn
*/ */
public interface Statement extends Node { public interface Statement extends Node {
public static CompoundStatement empty() { return new CompoundStatement(new ArrayList<>()); } public static CompoundStatement empty() {
submit.SymbolTable newTable = new submit.SymbolTable();
return new CompoundStatement(new ArrayList<>(), newTable);
}
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -12,12 +16,19 @@ public class StringConstant extends AbstractNode implements Expression {
private final String value; private final String value;
public StringConstant(String value) { public StringConstant(String value) { this.value = value; }
this.value = value;
}
public void toCminus(StringBuilder builder, final String prefix) { public void toCminus(StringBuilder builder, final String prefix) {
builder.append("\"").append(value).append("\""); builder.append("\"").append(value).append("\"");
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
String label = String.format("string_%s", SymbolTable.nextId());
data.append(String.format("%s: .asciiz %s\n", label, value));
return MIPSResult.createAddressResult(label, null);
}
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -23,5 +27,27 @@ public class UnaryOperator extends AbstractNode implements Expression {
builder.append(type); builder.append(type);
expression.toCminus(builder, prefix); expression.toCminus(builder, prefix);
} }
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
MIPSResult result =
expression.toMIPS(code, data, symbolTable, regAllocator);
String reg = regAllocator.getRegisterOrLoadIntoRegister(result, code);
switch (type) {
case NEG:
code.append(String.format("sub %s $zero %s\n", reg, reg));
break;
case NOT:
code.append(String.format("sltu %s $zero %s\n", reg, reg))
.append(String.format("xori %s %s 1\n", reg, reg));
break;
default:
break;
}
return MIPSResult.createRegisterResult(reg, VarType.INT);
}
} }

View File

@ -18,7 +18,8 @@ public class VarDeclaration extends AbstractNode implements Declaration {
private final List<Integer> arraySizes; private final List<Integer> arraySizes;
private final boolean isStatic; private final boolean isStatic;
public VarDeclaration(VarType type, List<String> ids, List<Integer> arraySizes, boolean isStatic) { public VarDeclaration(VarType type, List<String> ids,
List<Integer> arraySizes, boolean isStatic) {
this.type = type; this.type = type;
this.ids = new ArrayList<>(ids); this.ids = new ArrayList<>(ids);
this.arraySizes = arraySizes; this.arraySizes = arraySizes;
@ -35,7 +36,8 @@ public class VarDeclaration extends AbstractNode implements Declaration {
final String id = ids.get(i); final String id = ids.get(i);
final int arraySize = arraySizes.get(i); final int arraySize = arraySizes.get(i);
if (arraySize >= 0) { if (arraySize >= 0) {
builder.append(id).append("[").append(arraySize).append("]").append(", "); builder.append(id).append("[").append(arraySize).append("]").append(
", ");
} else { } else {
builder.append(id).append(", "); builder.append(id).append(", ");
} }
@ -43,5 +45,4 @@ public class VarDeclaration extends AbstractNode implements Declaration {
builder.delete(builder.length() - 2, builder.length()); builder.delete(builder.length() - 2, builder.length());
builder.append(";\n"); builder.append(";\n");
} }
} }

View File

@ -10,13 +10,13 @@ package submit.ast;
*/ */
public enum VarType { public enum VarType {
INT("int"), BOOL("bool"), CHAR("char"); INT("int"),
BOOL("bool"),
CHAR("char");
private final String value; private final String value;
private VarType(String value) { private VarType(String value) { this.value = value; }
this.value = value;
}
public static VarType fromString(String s) { public static VarType fromString(String s) {
for (VarType vt : VarType.values()) { for (VarType vt : VarType.values()) {
@ -31,5 +31,4 @@ public enum VarType {
public String toString() { public String toString() {
return value; return value;
} }
} }

View File

@ -4,6 +4,10 @@
*/ */
package submit.ast; package submit.ast;
import submit.MIPSResult;
import submit.RegisterAllocator;
import submit.SymbolTable;
/** /**
* *
* @author edwajohn * @author edwajohn
@ -28,6 +32,29 @@ public class While extends AbstractNode implements Statement {
} else { } else {
statement.toCminus(builder, prefix + " "); statement.toCminus(builder, prefix + " ");
} }
}
@Override
public MIPSResult toMIPS(StringBuilder code, StringBuilder data,
SymbolTable symbolTable,
RegisterAllocator regAllocator) {
String loopLabel = "while_truthy_" + SymbolTable.nextId();
String finishedLabel = "finished_while_" + SymbolTable.nextId();
code.append(String.format("%s:\n", loopLabel));
MIPSResult expressionTruthiness =
expression.toMIPS(code, data, symbolTable, regAllocator);
code.append(String.format("bne %s $zero %s\n",
expressionTruthiness.getRegister(),
finishedLabel));
MIPSResult inside = statement.toMIPS(code, data, symbolTable, regAllocator);
regAllocator.clear(inside.getRegister());
code.append(String.format("j %s\n", loopLabel))
.append(String.format("%s:\n", finishedLabel));
return MIPSResult.createVoidResult();
} }
} }

7
test.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/zsh
# usage: ./test.sh <test-number>
javac -d classes -cp classes -cp *.jar **/*.java && java -cp "classes:antlr-4.9.1-complete.jar" main.Main data/test$1.c
java -jar data/examples/Mars4_5.jar data/test$1.asm