Files
nand2tetris/VMTranslator/Writer.cpp

470 lines
16 KiB
C++

#include "Writer.h"
Writer::Writer(std::string file) {
filename = getFileName(file);
classname = getClassName(filename);
outfile.open(file, std::ios::out | std::ios::trunc);
if (!outfile.is_open()) {
throw std::invalid_argument("Can't open output file");
}
}
std::string Writer::getFileName(std::string path) {
int slashPos = path.rfind("/");
return path.substr(slashPos + 1, path.length());
}
std::string Writer::getClassName(std::string filename) {
int dotPos = filename.rfind(".");
return filename.substr(0, dotPos);
}
void Writer::setFile(std::string path) {
filename = getFileName(path);
classname = getClassName(filename);
}
void Writer::close() { outfile.close(); }
void Writer::writeFunction(Command cmd) {
outfile << "(" << cmd.arg1 << ")" << std::endl;
for (int i = 0; i < cmd.arg2; i++) {
writeCmd(Command(CommandType::Push, "constant", 0));
}
functionName = cmd.arg1;
retCounter = 0;
}
void Writer::writeCall(Command cmd) {
std::string retLabel = functionName + "$ret." + std::to_string(retCounter);
// push retAdress
outfile << "@" << retLabel << std::endl;
outfile << "D=A" << std::endl;
outfile << "@SP" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M+1" << std::endl;
outfile << "@LCL" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@SP" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M+1" << std::endl;
outfile << "@ARG" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@SP" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M+1" << std::endl;
outfile << "@THIS" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@SP" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M+1" << std::endl;
outfile << "@THAT" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@SP" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M+1" << std::endl;
outfile << "@SP" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@" << 5 + cmd.arg2 << std::endl;
outfile << "D=D-A" << std::endl;
outfile << "@ARG" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@LCL" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@" << cmd.arg1 << std::endl;
outfile << "-1;JMP" << std::endl;
outfile << "(" << retLabel << ")" << std::endl;
retCounter++;
}
void Writer::writeReturn(Command cmd) {
// endFrame(R13)=LCL
outfile << "@LCL" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R13" << std::endl;
outfile << "M=D" << std::endl;
// retAddr(R14)=*(endFrame-5)
outfile << "@5" << std::endl;
outfile << "A=D-A" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "M=D" << std::endl;
//*ARG = pop()
outfile << "@SP" << std::endl;
outfile << "M=M-1" << std::endl;
outfile << "A=M" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@ARG" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
// SP = ARG+1
outfile << "@ARG" << std::endl;
outfile << "D=M+1" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=D" << std::endl;
// that =*(endFrame-1)
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@1" << std::endl;
outfile << "A=D-A" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@THAT" << std::endl;
outfile << "M=D" << std::endl;
// this=*(endFrame-2)
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@2" << std::endl;
outfile << "A=D-A" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@THIS" << std::endl;
outfile << "M=D" << std::endl;
// ARG=*(endFrame-3)
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@3" << std::endl;
outfile << "A=D-A" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@ARG" << std::endl;
outfile << "M=D" << std::endl;
// LCL=*(endFrame-4)
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@4" << std::endl;
outfile << "A=D-A" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@LCL" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@R14" << std::endl;
outfile << "A=M" << std::endl;
outfile << "0;JMP" << std::endl;
}
void Writer::writeCmd(Command cmd) {
outfile << "// " << cmd << std::endl;
switch (cmd.type) {
case CommandType::Empty:
break;
case CommandType::Add:
case CommandType::Sub:
case CommandType::Neg:
case CommandType::Eq:
case CommandType::Gt:
case CommandType::Lt:
case CommandType::And:
case CommandType::Or:
case CommandType::Not:
writeArith(cmd);
break;
case CommandType::Push:
case CommandType::Pop:
writePushPop(cmd);
break;
case CommandType::IfGoto:
case CommandType::Goto:
case CommandType::Label:
writeBranch(cmd);
break;
case CommandType::Function:
writeFunction(cmd);
break;
case CommandType::Call:
writeCall(cmd);
break;
case CommandType::Return:
writeReturn(cmd);
break;
}
return;
}
void Writer::writeBranch(Command cmd) {
switch (cmd.type) {
case CommandType::IfGoto:
outfile << "@SP" << std::endl;
outfile << "M=M-1" << std::endl;
outfile << "A=M" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@" << functionName << "$" << cmd.arg1 << std::endl;
outfile << "D;JNE" << std::endl;
break;
case CommandType::Goto:
outfile << "@" << functionName << "$" << cmd.arg1 << std::endl;
outfile << "-1;JMP" << std::endl;
break;
case CommandType::Label:
outfile << "(" << functionName << "$" << cmd.arg1 << ")"
<< std::endl;
break;
}
return;
}
void Writer::writeInit() {
outfile << "@256" << std::endl;
outfile << "D=A" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=D" << std::endl;
writeCmd(Command(CommandType::Call, "Sys.init", 0));
}
void Writer::writeArith(Command cmd) {
static int arithCounter = 0;
if (cmd.type != CommandType::Neg && cmd.type != CommandType::Not) {
outfile << "@SP" << std::endl;
outfile << "M=M-1" << std::endl;
outfile << "A=M" << std::endl;
outfile << "D=M" << std::endl;
outfile << "M=0" << std::endl;
outfile << "@R13" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M-1" << std::endl;
outfile << "A=M" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "M=D" << std::endl;
}
switch (cmd.type) {
case CommandType::Add:
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M+D" << std::endl;
break;
case CommandType::Sub:
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M-D" << std::endl;
break;
case CommandType::Neg:
outfile << "@SP" << std::endl;
outfile << "M=M-1" << std::endl;
outfile << "A=M" << std::endl;
outfile << "D=-M" << std::endl;
break;
case CommandType::Not:
outfile << "@SP" << std::endl;
outfile << "M=M-1" << std::endl;
outfile << "A=M" << std::endl;
outfile << "D=!M" << std::endl;
break;
case CommandType::Eq:
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M-D" << std::endl;
outfile << "@T" << arithCounter << std::endl;
outfile << "D;JEQ" << std::endl;
outfile << "@END" << arithCounter << std::endl;
outfile << "D=0;JMP" << std::endl;
outfile << "(T" << arithCounter << ")" << std::endl;
outfile << "D=-1" << std::endl;
break;
case CommandType::Gt:
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M-D" << std::endl;
outfile << "@T" << arithCounter << std::endl;
outfile << "D;JGT" << std::endl;
outfile << "@END" << arithCounter << std::endl;
outfile << "D=0;JMP" << std::endl;
outfile << "(T" << arithCounter << ")" << std::endl;
outfile << "D=-1" << std::endl;
break;
case CommandType::Lt:
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M-D" << std::endl;
outfile << "@T" << arithCounter << std::endl;
outfile << "D;JLT" << std::endl;
outfile << "@END" << arithCounter << std::endl;
outfile << "D=0;JMP" << std::endl;
outfile << "(T" << arithCounter << ")" << std::endl;
outfile << "D=-1" << std::endl;
break;
case CommandType::And:
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M&D" << std::endl;
break;
case CommandType::Or:
outfile << "@R13" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M|D" << std::endl;
break;
}
outfile << "(END" << arithCounter << ")" << std::endl;
outfile << "@SP" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M+1" << std::endl;
arithCounter++;
return;
}
void Writer::writePushPop(Command cmd) {
switch (cmd.type) {
case CommandType::Push:
if (cmd.arg1 == "constant") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
} else if (cmd.arg1 == "local") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@LCL" << std::endl;
outfile << "A=M+D" << std::endl;
outfile << "D=M" << std::endl;
} else if (cmd.arg1 == "argument") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@ARG" << std::endl;
outfile << "A=M+D" << std::endl;
outfile << "D=M" << std::endl;
} else if (cmd.arg1 == "this") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@THIS" << std::endl;
outfile << "A=M+D" << std::endl;
outfile << "D=M" << std::endl;
} else if (cmd.arg1 == "that") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@THAT" << std::endl;
outfile << "A=M+D" << std::endl;
outfile << "D=M" << std::endl;
} else if (cmd.arg1 == "static") {
outfile << "@" << classname << "." << cmd.arg2 << std::endl;
outfile << "D=M" << std::endl;
} else if (cmd.arg1 == "temp") {
outfile << "@R" << 5 + cmd.arg2 << std::endl;
outfile << "D=M" << std::endl;
} else if (cmd.arg1 == "pointer") {
if (cmd.arg2 == 0) {
outfile << "@THIS" << std::endl;
} else if (cmd.arg2 == 1) {
outfile << "@THAT" << std::endl;
}
outfile << "D=M" << std::endl;
}
outfile << "@SP" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@SP" << std::endl;
outfile << "M=M+1" << std::endl;
break;
case CommandType::Pop:
outfile << "@SP" << std::endl;
outfile << "M=M-1" << std::endl;
outfile << "A=M" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R14" << std::endl;
outfile << "M=D" << std::endl;
if (cmd.arg1 == "local") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@LCL" << std::endl;
outfile << "D=M+D" << std::endl;
outfile << "@R15" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R15" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
} else if (cmd.arg1 == "argument") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@ARG" << std::endl;
outfile << "D=M+D" << std::endl;
outfile << "@R15" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R15" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
} else if (cmd.arg1 == "this") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@THIS" << std::endl;
outfile << "D=M+D" << std::endl;
outfile << "@R15" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R15" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
} else if (cmd.arg1 == "that") {
outfile << "@" << cmd.arg2 << std::endl;
outfile << "D=A" << std::endl;
outfile << "@THAT" << std::endl;
outfile << "D=M+D" << std::endl;
outfile << "@R15" << std::endl;
outfile << "M=D" << std::endl;
outfile << "@R14" << std::endl;
outfile << "D=M" << std::endl;
outfile << "@R15" << std::endl;
outfile << "A=M" << std::endl;
outfile << "M=D" << std::endl;
} else if (cmd.arg1 == "static") {
outfile << "@" << classname << "." << cmd.arg2 << std::endl;
outfile << "M=D" << std::endl;
} else if (cmd.arg1 == "temp") {
outfile << "@R" << 5 + cmd.arg2 << std::endl;
outfile << "M=D" << std::endl;
} else if (cmd.arg1 == "pointer") {
if (cmd.arg2 == 0) {
outfile << "@THIS" << std::endl;
} else if (cmd.arg2 == 1) {
outfile << "@THAT" << std::endl;
}
outfile << "M=D" << std::endl;
}
break;
break;
}
return;
}