diff --git a/README.md b/README.md index 2dfe709..c921917 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This is a VM Translator made as the an assignment for the [Nand To Tetris Course To compile the program run the following command: ``` -g++ main.cpp -Isrc +g++ main.cpp -Isrc -std=c++17 ``` To run the executable against jack vm files run the following command with the path of the file: ``` diff --git a/include/code.h b/include/code.h index 79e9a03..87991e8 100644 --- a/include/code.h +++ b/include/code.h @@ -23,7 +23,7 @@ private: } public: - Code(string path, vector> tokens) + Code(string path, vector> tokens, bool isNew) { size_t slashIndex = path.find_last_of('/'); size_t dotIndex = path.find_last_of('.'); @@ -33,8 +33,16 @@ public: filename = path.substr(slashIndex + 1, dotIndex - slashIndex - 1); } - file = ofstream(path); + file = ofstream(path, isNew ? ios_base::out : ios_base::app); commands = tokens; + + if (isNew) { + file << "@256" << endl; + file << "D=A" << endl; + file << "@SP" << endl; + file << "M=D" << endl; + file << translateCall("Sys.init", 0); + } } ~Code() diff --git a/include/functions.h b/include/functions.h index eeffabd..a932cf6 100644 --- a/include/functions.h +++ b/include/functions.h @@ -4,12 +4,14 @@ using namespace std; -string translateFunction(string name, int args) { +string translateFunction(string name, int args) +{ stringstream output; output << "(" << name << ")" << endl; - for (int i = 0; i < args; ++i) { + for (int i = 0; i < args; i++) + { output << "@0" << endl; output << "D=A" << endl; output << "@SP" << endl; @@ -22,10 +24,10 @@ string translateFunction(string name, int args) { return output.str(); } -string translateCall(string name, int args) { +string translateCall(string name, int args) +{ stringstream output; string label = name + "$ret" + generateRandomLabel(3); - vector frame = { "LCL", "ARG", "THIS", "THAT" }; output << "@" << label << endl; output << "D=A" << endl; @@ -35,20 +37,38 @@ string translateCall(string name, int args) { output << "@SP" << endl; output << "M=M+1" << endl; - for (const string &segment : frame) { - output << "@" << segment << endl; - output << "D=M" << endl; - output << "@SP" << endl; - output << "A=M" << endl; - output << "M=D" << endl; - output << "@SP" << endl; - output << "M=M+1" << endl; - } - - output << "@SP" << endl; - output << "D=M" << endl; output << "@LCL" << endl; + output << "D=M" << endl; + output << "@SP" << endl; + output << "A=M" << endl; output << "M=D" << endl; + output << "@SP" << endl; + output << "M=M+1" << endl; + + output << "@ARG" << endl; + output << "D=M" << endl; + output << "@SP" << endl; + output << "A=M" << endl; + output << "M=D" << endl; + output << "@SP" << endl; + output << "M=M+1" << endl; + + output << "@THIS" << endl; + output << "D=M" << endl; + output << "@SP" << endl; + output << "A=M" << endl; + output << "M=D" << endl; + output << "@SP" << endl; + output << "M=M+1" << endl; + + output << "@THAT" << endl; + output << "D=M" << endl; + output << "@SP" << endl; + output << "A=M" << endl; + output << "M=D" << endl; + output << "@SP" << endl; + output << "M=M+1" << endl; + output << "@SP" << endl; output << "D=M" << endl; output << "@R" << endl; @@ -64,7 +84,11 @@ string translateCall(string name, int args) { output << "D=M" << endl; output << "@ARG" << endl; output << "M=D" << endl; - output << "@R" << endl; + + output << "@SP" << endl; + output << "D=M" << endl; + output << "@LCL" << endl; + output << "M=D" << endl; output << "@" << name << endl; output << "0;JMP" << endl; @@ -73,7 +97,8 @@ string translateCall(string name, int args) { return output.str(); } -string translateReturn() { +string translateReturn() +{ stringstream output; string cleanupLabel = "cleanup$ret" + generateRandomLabel(3); string endLabel = "end$ret" + generateRandomLabel(3); @@ -119,7 +144,7 @@ string translateReturn() { output << "D=M" << endl; output << "@THAT" << endl; output << "M=D" << endl; - + output << "@END_FRAME" << endl; output << "D=M" << endl; output << "@2" << endl; @@ -128,7 +153,7 @@ string translateReturn() { output << "D=M" << endl; output << "@THIS" << endl; output << "M=D" << endl; - + output << "@END_FRAME" << endl; output << "D=M" << endl; output << "@3" << endl; diff --git a/main.cpp b/main.cpp index 5b657a9..ec9c8b5 100644 --- a/main.cpp +++ b/main.cpp @@ -1,39 +1,111 @@ #include #include +#include +#include #include "include/parser.h" #include "include/code.h" using namespace std; +namespace fs = std::filesystem; -string constructTranslatedPath(string path) { +string constructTranslatedFilePath(string path) +{ size_t position = path.rfind(".vm"); return path.replace(position, 3, ".asm"); } -int main(int argc, char* argv[]) +string constructTranslatedDirectoryPath(string path) { - if (!argv[1]) { - cout << "You must specify a vm file path!" << endl; - return 1; - } + string newPath = path; - string sourcePath = argv[1]; + size_t position = path.rfind("/"); - if (!regex_match(sourcePath, regex("^.+\\.vm"))) { - cout << "Wrong file extension!" << endl; - return 1; + if (position != string::npos && position == path.size() - 1) + { + newPath = path.replace(position, 1, ""); } + size_t slashIndex = path.find_last_of('/'); + + newPath += "/" + path.substr(slashIndex + 1); + + return newPath + ".asm"; +} + +void processFile(string sourcePath) +{ Parser parser(sourcePath); vector> commands = parser.getCommands(); - - string translatedPath = constructTranslatedPath(sourcePath); - Code code(translatedPath, commands); + string translatedPath = constructTranslatedFilePath(sourcePath); + + Code code(translatedPath, commands, false); code.translate(); - +} + +void processDirectory(string sourcePath, vector files) +{ + string translatedPath = constructTranslatedDirectoryPath(sourcePath); + bool isNew = true; + + for (const auto &file : files) + { + Parser parser(file); + + vector> commands = parser.getCommands(); + + Code code(translatedPath, commands, isNew); + + code.translate(); + + isNew = false; + } +} + +int main(int argc, char *argv[]) +{ + if (!argv[1]) + { + cout << "You must specify a vm file path!" << endl; + return 1; + } + + string sourcePath = argv[1]; + + if (!regex_match(sourcePath, regex("^.+\\.vm"))) + { + if (!fs::is_directory(sourcePath)) + { + cerr << "Error: " << sourcePath << " is not a directory.\n"; + return 1; + } + + vector vmFiles; + + for (const auto &entry : fs::directory_iterator(sourcePath)) + { + if (entry.is_regular_file() && entry.path().extension() == ".vm") + { + vmFiles.push_back(entry.path().string()); + } + } + + if (vmFiles.empty()) + { + cout << "Directory does not contain vm files!" << sourcePath << "\n"; + } + else + { + processDirectory(sourcePath, vmFiles); + } + } + else + { + processFile(sourcePath); + } + return 0; } \ No newline at end of file