mirror of
https://github.com/usatiuk/nand2tetris.git
synced 2025-10-28 08:07:49 +01:00
470 lines
16 KiB
C++
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;
|
|
}
|