package pascalcompiler.codegenerator;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import pascalcompiler.parser.IdInformation;
import pascalcompiler.parser.SymbolTable;
import pascalcompiler.scanner.PascalToken;
import pascalcompiler.syntaxtree.*;
/**
* This class creates the MIPS code based off of the Pascal syntax tree that
* is passed to it.
* @author Travis
*/
public class CodeGenerator {
private int currentTRegister = 0;
private int currentSRegister = 0;
private int ifNumber = 1;
private int whileNumber = 1;
private SymbolTable table;
/**
* Starts the code from the root node by writing the outline of the
* assembly code, and telling the root node to write its answer into $s0.
*
* @param root The root node of the equation to be written
* @param idTable
* @return A String of the assembly code.
*/
public String writeCodeForRoot( ProgramNode root, SymbolTable idTable) {
String a = null;
String result = "";
table = idTable;
StringBuilder code = new StringBuilder();
IdInformation element;
result += String.format("%-20s%s", "newLine"+":", ".asciiz \"\\n\"\n");
Enumeration e = idTable.getTable().elements();
//Writes global variables to .data section (all variables are global)
while (e.hasMoreElements()) {
element = (IdInformation)e.nextElement();
if (element.getKind() == PascalToken.VAR) {
result += String.format("%-20s%s", element.getName()+":", ".word 0\n");
}
}
code.append("#Program Name: " + root.getName() + "\n");
code.append(".data \n");
code.append(result);
code.append("\n\n");
code.append(".text\nmain:\n");
code.append(writeCode(root.getCompoundStatement()));
code.append( "li $v0, 10\n");
code.append( "syscall\n");
code.append("\n\n#SubProgram Declarations\n");
code.append(writeCode(root.getSubDeclarations()));
return (code.toString());
}
/**
* Generates the MIPS assembly code for all the sub programs defined in a
* Pascal program.
* @param subPrograms
* @return
*/
public String writeCode(SubProgramDeclarationsNode subPrograms) {
String code = "";
SubProgramNode currentProgram = null;
ArrayList<SubProgramNode> list = subPrograms.getSubPrograms();
Iterator<SubProgramNode> i = list.iterator();
while (i.hasNext()) {
currentProgram = i.next();
code += writeCode(currentProgram);
}
return code;
}
/**
* Generates the MIPS assembly code for a specified sub program.
* @param subProgram
* @return
*/
public String writeCode(SubProgramNode subProgram) {
String code = null;
if (subProgram instanceof FunctionDeclarationNode) {
code = writeCode((FunctionDeclarationNode)subProgram);
}
else if (subProgram instanceof ProcedureDeclarationNode) {
code = writeCode((ProcedureDeclarationNode)subProgram);
}
return code;
}
/**
* Generates the MIPS assembly code for a procedure defined in Pascal.
* @param procedure
* @return
*/
public String writeCode(ProcedureDeclarationNode procedure) {
String code = procedure.getName() + ":\n";
code += "addi $sp, $sp, -4\n";
code += "sw $ra, 0($sp)\n";
ArrayList<VariableNode> list = (procedure.getArguments()).getArguments();
int aRegister = 0;
String aReg = "$a";
String aTemp;
String currentVar;
Iterator i = list.iterator();
while (i.hasNext()) {
currentVar = ((VariableNode)i.next()).getName();
code += "sw " + aReg + aRegister++ + ", " + currentVar + "\n";
}
code += writeCode(procedure.getCompoundStatement());
code += "lw $ra, 0($sp)\n";
code += "addi $sp, $sp, 4\n";
code += "jr $ra\n\n";
return code;
}
/**
* Generates the MIPS assembly code for the variables declared in a Pascal
* program.
* @param node
* @return
*/
public String writeCode(DeclarationsNode node) {
String code = "";
ArrayList<VariableNode> declarations = null;
VariableNode tempVar = null;
declarations = node.getDeclarations();
Iterator<VariableNode> variableIterator = declarations.iterator();
while (variableIterator.hasNext()) {
tempVar = variableIterator.next();
if(tempVar.getType() == PascalToken.INTEGER) {
code += tempVar.getName() + ":";
code += " .word 0 \n";
}
else if (tempVar.getType() == PascalToken.REAL) {
code += "\n";
}
}
return code;
}
/**
* Determines the instance of the statement node and then writes MIPS code
* for that particular instance.
* @param node
* @return
*/
public String writeCode(StatementNode node) {
String code = "";
if(node instanceof VarAssignStatement) {
VarAssignStatement statement = (VarAssignStatement)node;
if (statement.isVariable(table)) {
code += writeCode((VarAssignStatement)node, "$s0");
}
else if (statement.isFunction(table)) {
code += writeCode((VarAssignStatement)node, "$v0");
}
}
else if (node instanceof CompoundStatementNode) {
code += writeCode((CompoundStatementNode)node);
}
else if (node instanceof ProcedureStatement) {
code += writeCode((ProcedureStatement)node);
}
else if (node instanceof IfStatement) {
code += writeCode((IfStatement)node);
}
else if (node instanceof WhileStatement) {
code += writeCode((WhileStatement)node);
}
else if (node instanceof WriteStatementNode) {
code += writeCode((WriteStatementNode)node);
}
return code;
}
/**
* Generates MIPS assembly code for a block of statements.
* @param node
* @return
*/
public String writeCode(CompoundStatementNode node) {
String code = "";
ArrayList<StatementNode> statements = null;
StatementNode tempStatement = null;
statements = node.getStatements();
Iterator<StatementNode> variableIterator = statements.iterator();
int tempTreg = this.currentTRegister;
while (variableIterator.hasNext()) {
tempStatement = variableIterator.next();
code += writeCode(tempStatement);
this.currentTRegister = tempTreg;
}// end while
return code;
}
/**
* Generates MIPS assembly code, so the result of a mathematical expression
* is printed to the screen.
* @param statement
* @return
*/
public String writeCode(WriteStatementNode statement) {
String answer = "";
answer += writeCode(statement.getExpression(),"$a0");
answer += "addi $v0, $zero, 1\n";
answer += "syscall\n";
answer += "li $v0, 4\n";
answer += "la $a0, newLine\n";
answer += "syscall\n";
return answer;
}
/**
* Generates MIPS assembly code for a while statement.
* @param statement
* @return
*/
public String writeCode(WhileStatement statement) {
String code = "\n", tReg1 = "$t", tReg2 = "$t";
String beginWhile = "BeginWhile" + this.whileNumber;
String endWhile = "EndWhile" + this.whileNumber++;
code += beginWhile + ":\n";
EquationNode expression = statement.getExpression();
if (expression instanceof OperationNode) {
PascalToken relop = ((OperationNode)expression).getOperation();
if (isRelationalOperator(relop)){
EquationNode left = ((OperationNode)expression).getLeft();
EquationNode right = ((OperationNode)expression).getRight();
int temp = this.currentTRegister;
tReg1 += this.currentTRegister++;
tReg2 += this.currentTRegister++;
this.currentTRegister = temp;
code += writeCode(left, tReg1);
code += writeCode(right, tReg2);
if( relop == PascalToken.LESS_THAN) {
code += "slt " + tReg1 + ", " + tReg1 + ", " + tReg2 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + endWhile + "\n";
}
else if( relop == PascalToken.GREATER_THAN) {
code += "slt " + tReg1 + ", " + tReg2 + ", " + tReg1 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + endWhile + "\n";
}
else if ( relop == PascalToken.LESS_THAN_EQUAL) {
code += "addi " + tReg2 + ", " + "1\n";
code += "slt " + tReg1 + ", " + tReg1 + ", " + tReg2 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + endWhile + "\n";
}
else if ( relop == PascalToken.GREATER_THAN_EQUAL) {
code += "addi " + tReg1 + ", " + "1\n";
code += "slt " + tReg1 + ", " + tReg2 + ", " + tReg1 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + endWhile + "\n";
}
else if ( relop == PascalToken.EQUALS) {
code += "bne " + tReg1 + ", " + tReg2 + ", " + endWhile + "\n";
}
else if ( relop == PascalToken.NOT_EQUAL) {
code += "beq " + tReg1 + ", " + tReg2 + ", " + endWhile + "\n";
}
}
else if (isArithmeticOperator(relop)) {
tReg1 += this.currentTRegister;
code += writeCode(expression, tReg1);
code += "beq " + tReg1 + ", " + "$zero" + ", " + endWhile + "\n";
}
}
StatementNode thenStatement = statement.getStatement();
if (thenStatement != null) {
code += writeCode(statement.getStatement());
}
code += "j " + beginWhile + "\n";
// Printing exit if statement
code += endWhile + ":\n";
return code;
}
/**
* Generates MIPS assembly code for an IfStatement.
* @param statement
* @return
*/
public String writeCode(IfStatement statement) {
String code = "\n", tReg1 = "$t", tReg2 = "$t";
String ifElse = "Else" + this.ifNumber;
String ifExit = "Exit" + this.ifNumber++;
EquationNode expression = statement.getExpression();
if (expression instanceof OperationNode) {
PascalToken relop = ((OperationNode)expression).getOperation();
if (isRelationalOperator(relop)){
EquationNode left = ((OperationNode)expression).getLeft();
EquationNode right = ((OperationNode)expression).getRight();
int temp = this.currentTRegister;
tReg1 += this.currentTRegister++;
tReg2 += this.currentTRegister++;
this.currentTRegister = temp;
code += writeCode(left, tReg1);
code += writeCode(right, tReg2);
if( relop == PascalToken.LESS_THAN) {
code += "slt " + tReg1 + ", " + tReg1 + ", " + tReg2 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + ifElse + "\n";
}
else if( relop == PascalToken.GREATER_THAN) {
code += "slt " + tReg1 + ", " + tReg2 + ", " + tReg1 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + ifElse + "\n";
}
else if ( relop == PascalToken.LESS_THAN_EQUAL) {
code += "addi " + tReg2 + ", " + "1\n";
code += "slt " + tReg1 + ", " + tReg1 + ", " + tReg2 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + ifElse + "\n";
}
else if ( relop == PascalToken.GREATER_THAN_EQUAL) {
code += "addi " + tReg1 + ", " + "1\n";
code += "slt " + tReg1 + ", " + tReg2 + ", " + tReg1 + "\n";
code += "beq " + tReg1 + ", " + "$zero" + ", " + ifElse + "\n";
}
else if ( relop == PascalToken.EQUALS) {
code += "bne " + tReg1 + ", " + tReg2 + ", " + ifElse + "\n";
}
else if ( relop == PascalToken.NOT_EQUAL) {
code += "beq " + tReg1 + ", " + tReg2 + ", " + ifElse + "\n";
}
}
else if (isArithmeticOperator(relop)) {
tReg1 += this.currentTRegister;
code += writeCode(expression, tReg1);
code += "beq " + tReg1 + ", " + "$zero" + ", " + ifElse + "\n";
}
}
//Otherwise expression is a value node (so far), could be an array or function
else if (expression instanceof ValueNode) {
tReg1 += this.currentTRegister;
code += writeCode(expression, tReg1);
code += "beq " + tReg1 + ", " + "$zero" + ", " + ifElse + "\n";
}
// end of ifExpression to MIPS
// Printing then statement
StatementNode thenStatement = statement.getThenStatement();
if (thenStatement != null) {
code += writeCode(statement.getThenStatement());
}
code += "j " + ifExit + "\n";
code += ifElse + ":\n";
// Printing else statement
StatementNode elseStatement = statement.getElseStatement();
if (elseStatement != null) {
code += writeCode(statement.getElseStatement());
}
// Printing exit if statement
code += ifExit + ":\n";
return (code += "\n");
}
/**
* Generates MIPS assembly code for a variable assignment statement.
* @param statement
* @param reg
* @return
*/
public String writeCode(VarAssignStatement statement, String reg) {
String code = "";
if (statement != null) {
EquationNode equation = statement.getExpression();
String varName = statement.getVarName();
if (equation != null && varName != null) {
code += writeCode(equation, reg);
if (statement.isVariable(table)) {
code += "sw $s0, " + varName + "\n";
}
}
}
return code;
}
/**
* Generates MIPS assembly code for a procedure statement.
* @param statement
* @return
*/
public String writeCode(ProcedureStatement statement) {
String code = "";
int aRegister = 0;
String aReg = "$a";
String aTemp;
ArrayList<EquationNode> parameterList = statement.getExpressions();
Iterator i = parameterList.iterator();
while (i.hasNext()) {
aTemp = aReg + aRegister++;
code += writeCode((EquationNode)i.next(),aTemp);
}
code += "jal " + statement.getName() + "\n";
return code;
}
/**
* Generates MIPS assembly code for a mathematical expression.
* @param node
* @param reg
* @return
*/
public String writeCode( EquationNode node, String reg) {
String nodeCode = null;
if( node instanceof OperationNode) {
nodeCode = writeCode( (OperationNode)node, reg);
}
else if( node instanceof ValueNode) {
nodeCode = writeCode( (ValueNode)node, reg);
}
else if( node instanceof FunctionExpressionNode) {
nodeCode = writeCode( (FunctionExpressionNode)node, reg);
}
return( nodeCode);
}
/**
* Generates MIPS assembly code for a function call inside a statement.
* @param function
* @param reg The name of MIPS register
* @return
*/
public String writeCode(FunctionExpressionNode function, String reg) {
String code = "";
int aRegister = 0;
String aReg = "$a";
String aTemp;
ArrayList<EquationNode> parameterList = function.getParameters();
Iterator i = parameterList.iterator();
while (i.hasNext()) {
aTemp = aReg + aRegister++;
code += writeCode((EquationNode)i.next(),aTemp);
}
code += "jal " + function.getName() + "\n";
code += "add " + reg + ", $v0, $zero\n";
return code;
}
/**
* Generates MIPS assembly code for a function definition.
* @param function
* @return
*/
public String writeCode(FunctionDeclarationNode function) {
String code = function.getName() + ":\n";
code += "addi $sp, $sp, -4\n";
code += "sw $ra, 0($sp)\n";
ArrayList<VariableNode> list = (function.getArguments()).getArguments();
int aRegister = 0;
String aReg = "$a";
String aTemp;
String currentVar;
Iterator i = list.iterator();
while (i.hasNext()) {
currentVar = ((VariableNode)i.next()).getName();
code += "sw " + aReg + aRegister++ + ", " + currentVar + "\n";
}
//Iterate through compound statement and write last expression in $v0
code += writeCode(function.getCompoundStatement());
code += "lw $ra, 0($sp)\n";
code += "addi $sp, $sp, 4\n";
code += "jr $ra\n\n";
return code;
}
/**
* Writes code for an operations node.
* The code is written by gathering the child nodes' answers into
* a pair of registers, and then executing the op on those registers,
* placing the result in the given result register.
* @param opNode The operation node to perform.
* @param resultRegister The register in which to put the result.
* @return The code which executes this operation.
*/
public String writeCode( OperationNode opNode, String resultRegister)
{
String code;
EquationNode left = opNode.getLeft();
String leftRegister = "$t" + currentTRegister++;
code = writeCode( left, leftRegister);
EquationNode right = opNode.getRight();
String rightRegister = "$t" + currentTRegister++;
code += writeCode( right, rightRegister);
PascalToken kindOfOp = opNode.getOperation();
if( kindOfOp == PascalToken.PLUS)
{
// add resultregister, left, right
code += "add " + resultRegister + ", " + leftRegister +
", " + rightRegister + "\n";
}
if( kindOfOp == PascalToken.MINUS)
{
// add resultregister, left, right
code += "sub " + resultRegister + ", " + leftRegister +
", " + rightRegister + "\n";
}
if( kindOfOp == PascalToken.MULTIPLY)
{
code += "mult " + leftRegister + ", " + rightRegister + "\n";
code += "mflo " + resultRegister + "\n";
}
if( kindOfOp == PascalToken.DIVIDE)
{
code += "div " + leftRegister + ", " + rightRegister + "\n";
code += "mflo " + resultRegister + "\n";
}
if( kindOfOp == PascalToken.MOD)
{
code += "div " + leftRegister + ", " + rightRegister + "\n";
code += "mfhi " + resultRegister + "\n";
}
return( code);
}
/**
* Writes code for a value node.
* The code is written by executing an add immediate with the value
* into the destination register.
* Writes code that looks like addi $reg, $zero, value
* @param valNode The node containing the value.
* @param resultRegister The register in which to put the value.
* @return The code which executes this value node.
*/
public String writeCode( ValueNode valNode, String resultRegister)
{
String code;
String value = valNode.getAttribute();
if (valNode.isID()) {
code = "lw " + resultRegister + ", " + valNode.getAttribute() + "\n";
}
else {
code = "addi " + resultRegister + ", $zero, " + value + "\n";
}
return( code);
}
/**
* Returns true if the token is a relational operator.
* @param token
* @return
*/
public boolean isRelationalOperator(PascalToken token) {
boolean answer = false;
if (token == PascalToken.EQUALS
|| token == PascalToken.NOT_EQUAL
|| token == PascalToken.GREATER_THAN
|| token == PascalToken.GREATER_THAN_EQUAL
|| token == PascalToken.LESS_THAN
|| token == PascalToken.LESS_THAN_EQUAL) {
answer = true;
}
return answer;
}
/**
* Returns true if the token is an arithmetic operator.
* @param token
* @return
*/
public boolean isArithmeticOperator(PascalToken token) {
boolean answer = false;
if (token == PascalToken.PLUS
|| token == PascalToken.MINUS
|| token == PascalToken.MULTIPLY
|| token == PascalToken.DIVIDE) {
answer = true;
}
return answer;
}
}