mirror of
https://github.com/hazemKrimi/jack-vm-translator.git
synced 2026-05-01 18:00:27 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cf2de1aa7 | |||
| 74d4536322 | |||
| 8225957c6a | |||
| 641a4085b7 | |||
| fba936ea53 | |||
| 48b68c0247 | |||
| 1ad35fcc26 | |||
| 27ade5ab88 | |||
| 74982ac6e9 | |||
| 9de4219cef | |||
| e807d05f45 | |||
| 51c7327a65 | |||
| a4e4942069 | |||
| d01abac9e9 | |||
| 8888f7b97a | |||
| c8031fe6c7 | |||
| 74beae32f3 | |||
| a43c055410 | |||
| 90e5112afa | |||
| a1d9a8a29c | |||
| 5986a509e2 | |||
| 595914175b | |||
| 75615a8053 | |||
| 33c2394142 | |||
| f94e7a7b8c | |||
| e2b586e60c | |||
| c892d1dd4e | |||
| 087ad85dc7 | |||
| fb9e783543 |
+1
-3
@@ -1,3 +1 @@
|
|||||||
/.vscode
|
out/
|
||||||
|
|
||||||
*.out
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
CC = g++
|
||||||
|
MODE ?= debug
|
||||||
|
|
||||||
|
ifeq ($(MODE), debug)
|
||||||
|
CFLAGS = -g -Wall -Wextra -DDEBUG
|
||||||
|
else
|
||||||
|
CFLAGS = -O2 -DNDEBUG -Wall -Wextra
|
||||||
|
endif
|
||||||
|
|
||||||
|
TARGET_NAME = vm-translator
|
||||||
|
OUT_DIR = out
|
||||||
|
TARGET = $(OUT_DIR)/$(TARGET_NAME)
|
||||||
|
SRCS = src/main.cpp src/utils.cpp src/code.cpp src/parser.cpp
|
||||||
|
OBJS = $(SRCS:src/%.cpp=$(OUT_DIR)/%.o)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
@mkdir -p $(OUT_DIR)
|
||||||
|
@$(CC) $(CFLAGS) $^ -o $@
|
||||||
|
@echo "Built $(TARGET_NAME): $@"
|
||||||
|
|
||||||
|
$(OUT_DIR)/%.o: src/%.cpp
|
||||||
|
@mkdir -p $(OUT_DIR)
|
||||||
|
@$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf out
|
||||||
|
@echo "Cleaned all builds."
|
||||||
|
|
||||||
|
.PHONY: all run clean
|
||||||
@@ -1,13 +1,43 @@
|
|||||||
# Jack Compiler
|
# Jack VM Translator
|
||||||
|
|
||||||
This is a compiler made as the an assignment for the [Nand To Tetris Course: Part 2](https://nand2tetris.org/project07). It assumes that the jack file does not have errors for now.
|
This is a VM translator made as an assignment for the [Nand To Tetris Course: Part 2](https://nand2tetris.org/project07).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
You need GCC and `make` to develop, build, and run this project.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Clone this repo:
|
||||||
|
|
||||||
To compile the program run the following command:
|
|
||||||
```
|
```
|
||||||
g++ main.cpp -Isrc -std=c++17
|
git clone https://github.com/hazemKrimi/jack-vm-translator
|
||||||
```
|
```
|
||||||
To run the executable against jack vm files run the following command with the path of the file:
|
|
||||||
|
2. To run this against VM files, run the following command with the path of the `.vm` file (or directory):
|
||||||
|
|
||||||
```
|
```
|
||||||
./a.out <path>
|
./out/vm-translator <path_to_vm_file_or_directory>
|
||||||
```
|
```
|
||||||
The file will be written next to the source file.
|
|
||||||
|
The result `.asm` file will be written in the same location as the source file.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
- To build this project run the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
- To build for release run the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
make MODE=release
|
||||||
|
```
|
||||||
|
|
||||||
|
You will find the executable in the `out/` directory.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
You can download VM files to test the translator against from the [Nand To Tetris website](https://www.nand2tetris.org/software).
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
string translateLabel(string label)
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "(" << label << ")" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateGoto(string label)
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@" << label << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateIfGoto(string label)
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@" << label << endl;
|
|
||||||
output << "D;JNE" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
-132
@@ -1,132 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include "types.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "operations.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "branching.h"
|
|
||||||
#include "functions.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
class Code
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
ofstream file;
|
|
||||||
string filename;
|
|
||||||
vector<vector<string>> commands;
|
|
||||||
|
|
||||||
void closeFile()
|
|
||||||
{
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Code(string path, vector<vector<string>> tokens, bool isNew)
|
|
||||||
{
|
|
||||||
size_t slashIndex = path.find_last_of('/');
|
|
||||||
size_t dotIndex = path.find_last_of('.');
|
|
||||||
|
|
||||||
if (slashIndex != string::npos && dotIndex != string::npos)
|
|
||||||
{
|
|
||||||
filename = path.substr(slashIndex + 1, dotIndex - slashIndex - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
closeFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
void translate()
|
|
||||||
{
|
|
||||||
for (const vector<string> &vec : commands)
|
|
||||||
{
|
|
||||||
if (vec.size() == 3)
|
|
||||||
{
|
|
||||||
switch (determineTwoArgumentCommand(vec[0]))
|
|
||||||
{
|
|
||||||
case PUSH:
|
|
||||||
file << translatePush(filename, determineSegment(vec[1]), stoi(vec[2]));
|
|
||||||
break;
|
|
||||||
case FUNCTION:
|
|
||||||
file << translateFunction(vec[1], stoi(vec[2]));
|
|
||||||
break;
|
|
||||||
case CALL:
|
|
||||||
file << translateCall(vec[1], stoi(vec[2]));
|
|
||||||
break;
|
|
||||||
case POP:
|
|
||||||
default:
|
|
||||||
file << translatePop(filename, determineSegment(vec[1]), stoi(vec[2]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (vec.size() == 2)
|
|
||||||
{
|
|
||||||
switch (determineOneArgumentCommand(vec[0]))
|
|
||||||
{
|
|
||||||
case LABEL:
|
|
||||||
file << translateLabel(vec[1]);
|
|
||||||
break;
|
|
||||||
case GOTO:
|
|
||||||
file << translateGoto(vec[1]);
|
|
||||||
break;
|
|
||||||
case IFGOTO:
|
|
||||||
default:
|
|
||||||
file << translateIfGoto(vec[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (vec.size() == 1)
|
|
||||||
{
|
|
||||||
switch (determineNoArgumentCommand(vec[0]))
|
|
||||||
{
|
|
||||||
case ADD:
|
|
||||||
file << translateAdd();
|
|
||||||
break;
|
|
||||||
case SUB:
|
|
||||||
file << translateSub();
|
|
||||||
break;
|
|
||||||
case NEG:
|
|
||||||
file << translateNeg();
|
|
||||||
break;
|
|
||||||
case EQ:
|
|
||||||
file << translateEq();
|
|
||||||
break;
|
|
||||||
case GT:
|
|
||||||
file << translateGt();
|
|
||||||
break;
|
|
||||||
case LT:
|
|
||||||
file << translateLt();
|
|
||||||
break;
|
|
||||||
case AND:
|
|
||||||
file << translateAnd();
|
|
||||||
break;
|
|
||||||
case OR:
|
|
||||||
file << translateOr();
|
|
||||||
break;
|
|
||||||
case NOT:
|
|
||||||
file << translateNot();
|
|
||||||
break;
|
|
||||||
case RETURN:
|
|
||||||
file << translateReturn();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
file << translateNeg();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int callCounter = 1;
|
|
||||||
|
|
||||||
string translateFunction(string name, int args)
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "(" << name << ")" << endl;
|
|
||||||
|
|
||||||
for (int i = 0; i < args; ++i)
|
|
||||||
{
|
|
||||||
output << "@0" << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateCall(string name, int args)
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
string label = name + "$ret" + std::to_string(callCounter);
|
|
||||||
|
|
||||||
callCounter++;
|
|
||||||
|
|
||||||
output << "@" << label << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << 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 << "@C" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@5" << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@C" << endl;
|
|
||||||
output << "M=M-D" << endl;
|
|
||||||
output << "@" << args << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@C" << endl;
|
|
||||||
output << "M=M-D" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@ARG" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@LCL" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@" << name << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
output << "(" << label << ")" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateReturn()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@LCL" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@EF" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@RA" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@5" << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@RA" << endl;
|
|
||||||
output << "M=M-D" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@RA" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@ARG" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@ARG" << endl;
|
|
||||||
output << "D=M+1" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@EF" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@1" << endl;
|
|
||||||
output << "D=D-A" << endl;
|
|
||||||
output << "A=D" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@THAT" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@EF" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@2" << endl;
|
|
||||||
output << "D=D-A" << endl;
|
|
||||||
output << "A=D" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@THIS" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@EF" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@3" << endl;
|
|
||||||
output << "D=D-A" << endl;
|
|
||||||
output << "A=D" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@ARG" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@EF" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@4" << endl;
|
|
||||||
output << "D=D-A" << endl;
|
|
||||||
output << "A=D" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@LCL" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@RA" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "D;JMP" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
string translatePush(string filename, Segment segment, int index)
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
switch (segment)
|
|
||||||
{
|
|
||||||
case LCL:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@LCL" << endl;
|
|
||||||
output << "A=D+M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
break;
|
|
||||||
case ARG:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@ARG" << endl;
|
|
||||||
output << "A=D+M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
break;
|
|
||||||
case THIS:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@THIS" << endl;
|
|
||||||
output << "A=D+M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
break;
|
|
||||||
case THAT:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@THAT" << endl;
|
|
||||||
output << "A=D+M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
break;
|
|
||||||
case POINTER:
|
|
||||||
output << (index == 0 ? "@THIS" : "@THAT") << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
break;
|
|
||||||
case STATIC:
|
|
||||||
output << "@" << filename << "." << index << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
break;
|
|
||||||
case TEMP:
|
|
||||||
output << "@" << index + 5 << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
break;
|
|
||||||
case CONSTANT:
|
|
||||||
default:
|
|
||||||
output << '@' << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translatePop(string filename, Segment segment, int index)
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
switch (segment)
|
|
||||||
{
|
|
||||||
case LCL:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@LCL" << endl;
|
|
||||||
output << "D=D+M" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
break;
|
|
||||||
case ARG:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@ARG" << endl;
|
|
||||||
output << "D=D+M" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
break;
|
|
||||||
case THIS:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@THIS" << endl;
|
|
||||||
output << "D=D+M" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
break;
|
|
||||||
case THAT:
|
|
||||||
output << "@" << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@THAT" << endl;
|
|
||||||
output << "D=D+M" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
break;
|
|
||||||
case POINTER:
|
|
||||||
output << (index == 0 ? "@THIS" : "@THAT") << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
break;
|
|
||||||
case STATIC:
|
|
||||||
output << "@" << filename << "." << index << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
break;
|
|
||||||
case TEMP:
|
|
||||||
output << "@" << index + 5 << endl;
|
|
||||||
output << "D=A" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@ADDR" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
@@ -1,328 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
string translateAdd()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@A" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@A" << endl;
|
|
||||||
output << "M=D+M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateSub()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@S" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@S" << endl;
|
|
||||||
output << "M=D-M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateNeg()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@N" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "M=M-D" << endl;
|
|
||||||
output << "M=M-D" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateEq()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
srand(static_cast<unsigned int>(time(nullptr)));
|
|
||||||
|
|
||||||
string LABEL = generateRandomLabel(8);
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@E" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@E" << endl;
|
|
||||||
output << "M=D-M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@" << LABEL << "_TRUE" << endl;
|
|
||||||
output << "D;JEQ" << endl;
|
|
||||||
output << "@" << LABEL << "_FALSE" << endl;
|
|
||||||
output << "D;JNE" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << "_TRUE)" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=-1" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
output << "@" << LABEL << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << "_FALSE)" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=0" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
output << "@" << LABEL << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << ")" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateGt()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
srand(static_cast<unsigned int>(time(nullptr)));
|
|
||||||
|
|
||||||
string LABEL = generateRandomLabel(8);
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@GT" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@GT" << endl;
|
|
||||||
output << "M=D-M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@" << LABEL << "_TRUE" << endl;
|
|
||||||
output << "D;JGT" << endl;
|
|
||||||
output << "@" << LABEL << "_FALSE" << endl;
|
|
||||||
output << "D;JLT" << endl;
|
|
||||||
output << "@" << LABEL << "_FALSE" << endl;
|
|
||||||
output << "D;JEQ" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << "_TRUE)" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=-1" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
output << "@" << LABEL << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << "_FALSE)" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=0" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
output << "@" << LABEL << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << ")" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateLt()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
srand(static_cast<unsigned int>(time(nullptr)));
|
|
||||||
|
|
||||||
string LABEL = generateRandomLabel(8);
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@LT" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@LT" << endl;
|
|
||||||
output << "M=D-M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
output << "@" << LABEL << "_TRUE" << endl;
|
|
||||||
output << "D;JLT" << endl;
|
|
||||||
output << "@" << LABEL << "_FALSE" << endl;
|
|
||||||
output << "D;JGT" << endl;
|
|
||||||
output << "@" << LABEL << "_FALSE" << endl;
|
|
||||||
output << "D;JEQ" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << "_TRUE)" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=-1" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
output << "@" << LABEL << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << "_FALSE)" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=0" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
output << "@" << LABEL << endl;
|
|
||||||
output << "0;JMP" << endl;
|
|
||||||
|
|
||||||
output << "(" << LABEL << ")" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateAnd()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@AND" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@AND" << endl;
|
|
||||||
output << "M=D&M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateOr()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@OR" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@OR" << endl;
|
|
||||||
output << "M=D|M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
string translateNot()
|
|
||||||
{
|
|
||||||
stringstream output;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M-1" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "D=M" << endl;
|
|
||||||
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "A=M" << endl;
|
|
||||||
output << "M=!D" << endl;
|
|
||||||
output << "@SP" << endl;
|
|
||||||
output << "M=M+1" << endl;
|
|
||||||
|
|
||||||
return output.str();
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <regex>
|
|
||||||
#include <fstream>
|
|
||||||
#include <cctype>
|
|
||||||
#include "types.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
class Parser
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
ifstream file;
|
|
||||||
string vmCode;
|
|
||||||
|
|
||||||
bool isEmptyLine(string text)
|
|
||||||
{
|
|
||||||
for (char c : text)
|
|
||||||
{
|
|
||||||
if (!isspace(c))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeCommentsAndWhitespace()
|
|
||||||
{
|
|
||||||
string text;
|
|
||||||
smatch matched;
|
|
||||||
|
|
||||||
while (getline(file, text))
|
|
||||||
{
|
|
||||||
if (regex_search(text, matched, regex("^(.*)?(\\/\\/.*)")) || isEmptyLine(text))
|
|
||||||
{
|
|
||||||
if (!isEmptyLine(matched[1]))
|
|
||||||
{
|
|
||||||
string command = matched[1];
|
|
||||||
|
|
||||||
trim(command);
|
|
||||||
vmCode.append(command + '\n');
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trim(text);
|
|
||||||
vmCode.append(text + '\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeFile()
|
|
||||||
{
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Parser(string path)
|
|
||||||
{
|
|
||||||
file = ifstream(path);
|
|
||||||
|
|
||||||
removeCommentsAndWhitespace();
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<vector<string>> getCommands()
|
|
||||||
{
|
|
||||||
stringstream vmCodeStream(vmCode);
|
|
||||||
string text;
|
|
||||||
smatch matched;
|
|
||||||
vector<vector<string>> commands;
|
|
||||||
|
|
||||||
while (getline(vmCodeStream, text, '\n'))
|
|
||||||
{
|
|
||||||
vector<string> matchedVector;
|
|
||||||
|
|
||||||
if (regex_search(text, matched, regex("^(.*) (.*) (.*)")))
|
|
||||||
{
|
|
||||||
matchedVector.push_back(matched[1]);
|
|
||||||
matchedVector.push_back(matched[2]);
|
|
||||||
matchedVector.push_back(matched[3]);
|
|
||||||
}
|
|
||||||
else if (regex_search(text, matched, regex("^(.*) (.*)")))
|
|
||||||
{
|
|
||||||
matchedVector.push_back(matched[1]);
|
|
||||||
matchedVector.push_back(matched[2]);
|
|
||||||
}
|
|
||||||
else if (regex_search(text, matched, regex("^(.*)")))
|
|
||||||
{
|
|
||||||
matchedVector.push_back(matched[1]);
|
|
||||||
}
|
|
||||||
commands.push_back(matchedVector);
|
|
||||||
}
|
|
||||||
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
enum Segment
|
|
||||||
{
|
|
||||||
LCL,
|
|
||||||
ARG,
|
|
||||||
THIS,
|
|
||||||
THAT,
|
|
||||||
STATIC,
|
|
||||||
CONSTANT,
|
|
||||||
TEMP,
|
|
||||||
POINTER,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum NoArgumentCommand {
|
|
||||||
ADD,
|
|
||||||
SUB,
|
|
||||||
NEG,
|
|
||||||
EQ,
|
|
||||||
GT,
|
|
||||||
LT,
|
|
||||||
AND,
|
|
||||||
OR,
|
|
||||||
NOT,
|
|
||||||
RETURN,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum OneArgumentCommand {
|
|
||||||
LABEL,
|
|
||||||
GOTO,
|
|
||||||
IFGOTO,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TwoArgumentCommand {
|
|
||||||
PUSH,
|
|
||||||
POP,
|
|
||||||
FUNCTION,
|
|
||||||
CALL
|
|
||||||
};
|
|
||||||
-112
@@ -1,112 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <random>
|
|
||||||
#include <ctime>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
inline void ltrim(string &str) {
|
|
||||||
str.erase(str.begin(), find_if(str.begin(), str.end(), [](unsigned char ch) {
|
|
||||||
return !isspace(ch);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void rtrim(string &str) {
|
|
||||||
str.erase(find_if(str.rbegin(), str.rend(), [](unsigned char ch) {
|
|
||||||
return !isspace(ch);
|
|
||||||
}).base(), str.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void trim(string &str) {
|
|
||||||
rtrim(str);
|
|
||||||
ltrim(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
Segment determineSegment(string segment)
|
|
||||||
{
|
|
||||||
if (segment == "local")
|
|
||||||
return Segment::LCL;
|
|
||||||
if (segment == "argument")
|
|
||||||
return Segment::ARG;
|
|
||||||
if (segment == "this")
|
|
||||||
return Segment::THIS;
|
|
||||||
if (segment == "that")
|
|
||||||
return Segment::THAT;
|
|
||||||
if (segment == "pointer")
|
|
||||||
return Segment::POINTER;
|
|
||||||
if (segment == "static")
|
|
||||||
return Segment::STATIC;
|
|
||||||
if (segment == "temp")
|
|
||||||
return Segment::TEMP;
|
|
||||||
if (segment == "constant")
|
|
||||||
return Segment::CONSTANT;
|
|
||||||
|
|
||||||
return Segment::CONSTANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
string generateRandomLabel(int length) {
|
|
||||||
random_device rd;
|
|
||||||
mt19937 gen(rd());
|
|
||||||
uniform_int_distribution<> dis('A', 'Z');
|
|
||||||
string label;
|
|
||||||
|
|
||||||
for (int i = 0; i < length; ++i) {
|
|
||||||
label += static_cast<char>(dis(gen));
|
|
||||||
}
|
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
NoArgumentCommand determineNoArgumentCommand(string command)
|
|
||||||
{
|
|
||||||
if (command == "add")
|
|
||||||
return NoArgumentCommand::ADD;
|
|
||||||
if (command == "sub")
|
|
||||||
return NoArgumentCommand::SUB;
|
|
||||||
if (command == "neg")
|
|
||||||
return NoArgumentCommand::NEG;
|
|
||||||
if (command == "eq")
|
|
||||||
return NoArgumentCommand::EQ;
|
|
||||||
if (command == "gt")
|
|
||||||
return NoArgumentCommand::GT;
|
|
||||||
if (command == "lt")
|
|
||||||
return NoArgumentCommand::LT;
|
|
||||||
if (command == "and")
|
|
||||||
return NoArgumentCommand::AND;
|
|
||||||
if (command == "or")
|
|
||||||
return NoArgumentCommand::OR;
|
|
||||||
if (command == "not")
|
|
||||||
return NoArgumentCommand::NOT;
|
|
||||||
if (command == "return")
|
|
||||||
return NoArgumentCommand::RETURN;
|
|
||||||
|
|
||||||
return NoArgumentCommand::NEG;
|
|
||||||
}
|
|
||||||
|
|
||||||
OneArgumentCommand determineOneArgumentCommand(string command)
|
|
||||||
{
|
|
||||||
if (command == "label")
|
|
||||||
return OneArgumentCommand::LABEL;
|
|
||||||
if (command == "goto")
|
|
||||||
return OneArgumentCommand::GOTO;
|
|
||||||
if (command == "if-goto")
|
|
||||||
return OneArgumentCommand::IFGOTO;
|
|
||||||
|
|
||||||
return OneArgumentCommand::IFGOTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
TwoArgumentCommand determineTwoArgumentCommand(string command)
|
|
||||||
{
|
|
||||||
if (command == "push")
|
|
||||||
return TwoArgumentCommand::PUSH;
|
|
||||||
if (command == "pop")
|
|
||||||
return TwoArgumentCommand::POP;
|
|
||||||
if (command == "function")
|
|
||||||
return TwoArgumentCommand::FUNCTION;
|
|
||||||
if (command == "call")
|
|
||||||
return TwoArgumentCommand::CALL;
|
|
||||||
|
|
||||||
return TwoArgumentCommand::POP;
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <regex>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <vector>
|
|
||||||
#include "include/parser.h"
|
|
||||||
#include "include/code.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
string constructTranslatedFilePath(string path)
|
|
||||||
{
|
|
||||||
size_t position = path.rfind(".vm");
|
|
||||||
|
|
||||||
return path.replace(position, 3, ".asm");
|
|
||||||
}
|
|
||||||
|
|
||||||
string constructTranslatedDirectoryPath(string path)
|
|
||||||
{
|
|
||||||
string newPath = path;
|
|
||||||
|
|
||||||
size_t position = path.rfind("/");
|
|
||||||
|
|
||||||
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<vector<string>> commands = parser.getCommands();
|
|
||||||
|
|
||||||
string translatedPath = constructTranslatedFilePath(sourcePath);
|
|
||||||
|
|
||||||
Code code(translatedPath, commands, false);
|
|
||||||
|
|
||||||
code.translate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void processDirectory(string sourcePath, vector<string> files)
|
|
||||||
{
|
|
||||||
string translatedPath = constructTranslatedDirectoryPath(sourcePath);
|
|
||||||
bool isNew = true;
|
|
||||||
|
|
||||||
for (const auto &file : files)
|
|
||||||
{
|
|
||||||
Parser parser(file);
|
|
||||||
|
|
||||||
vector<vector<string>> 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<string> 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;
|
|
||||||
}
|
|
||||||
+462
@@ -0,0 +1,462 @@
|
|||||||
|
#include "types.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
static int pushFromDRegisterToStack(std::ostringstream &stream) {
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "M=M+1" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int popFromStackToDRegister(std::ostringstream &stream) {
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "M=M-1" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateStackOperation(std::ostringstream &stream,
|
||||||
|
const std::string fileName, Command cmd) {
|
||||||
|
switch (cmd.segmentType) {
|
||||||
|
case SegmentType::LCL:
|
||||||
|
case SegmentType::ARG:
|
||||||
|
case SegmentType::THIS:
|
||||||
|
case SegmentType::THAT:
|
||||||
|
stream << "@" << cmd.index << std::endl;
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
stream << "@" << cmd.segmentName << std::endl;
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::PUSH) {
|
||||||
|
stream << "A=D+M" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
} else {
|
||||||
|
stream << "D=D+M" << std::endl;
|
||||||
|
stream << "@ADDR" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SegmentType::POINTER:
|
||||||
|
stream << (cmd.index == 0 ? "@THIS" : "@THAT") << std::endl;
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::PUSH) {
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
} else {
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
stream << "@ADDR" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SegmentType::STATIC:
|
||||||
|
stream << "@" << fileName << "." << cmd.index << std::endl;
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::PUSH) {
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
} else {
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
stream << "@ADDR" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SegmentType::TEMP:
|
||||||
|
stream << "@" << cmd.index + 5 << std::endl;
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::PUSH) {
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
} else {
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
stream << "@ADDR" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SegmentType::CONSTANT:
|
||||||
|
if (cmd.commandType == CommandType::POP)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@" << cmd.index << std::endl;
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::PUSH) {
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "M=M+1" << std::endl;
|
||||||
|
} else {
|
||||||
|
stream << "M=M-1" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@ADDR" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateArithmeticBinaryOperation(std::ostringstream &stream,
|
||||||
|
Command cmd) {
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@BINARY_ARITHMETIC" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@BINARY_ARITHMETIC" << std::endl;
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::ADD) {
|
||||||
|
stream << "M=D+M" << std::endl;
|
||||||
|
} else {
|
||||||
|
stream << "M=D-M" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
return pushFromDRegisterToStack(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateArithmeticUnaryOperation(std::ostringstream &stream) {
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@NEGATE" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
stream << "M=M-D" << std::endl;
|
||||||
|
stream << "M=M-D" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
return pushFromDRegisterToStack(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateEqualityOperation(std::ostringstream &stream, Command cmd) {
|
||||||
|
static int equalityCheckLabelCounter = 0;
|
||||||
|
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@EQUALITY_CHECK" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@EQUALITY_CHECK" << std::endl;
|
||||||
|
stream << "M=D-M" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@" << "EQUALITY_CHECK_" << equalityCheckLabelCounter << "_TRUE"
|
||||||
|
<< std::endl;
|
||||||
|
stream << "D;"
|
||||||
|
<< (cmd.commandType == CommandType::GT ? "JGT"
|
||||||
|
: cmd.commandType == CommandType::LT ? "JLT"
|
||||||
|
: "JEQ")
|
||||||
|
<< std::endl;
|
||||||
|
stream << "@" << "EQUALITY_CHECK_" << equalityCheckLabelCounter << "_FALSE"
|
||||||
|
<< std::endl;
|
||||||
|
stream << "0;JMP" << std::endl;
|
||||||
|
|
||||||
|
stream << "(" << "EQUALITY_CHECK_" << equalityCheckLabelCounter << "_TRUE)"
|
||||||
|
<< std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M=-1" << std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "M=M+1" << std::endl;
|
||||||
|
stream << "@" << "EQUALITY_CHECK_" << equalityCheckLabelCounter << std::endl;
|
||||||
|
stream << "0;JMP" << std::endl;
|
||||||
|
|
||||||
|
stream << "(" << "EQUALITY_CHECK_" << equalityCheckLabelCounter << "_FALSE)"
|
||||||
|
<< std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M=0" << std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "M=M+1" << std::endl;
|
||||||
|
stream << "@" << "EQUALITY_CHECK_" << equalityCheckLabelCounter << std::endl;
|
||||||
|
stream << "0;JMP" << std::endl;
|
||||||
|
|
||||||
|
stream << "(" << "EQUALITY_CHECK_" << equalityCheckLabelCounter << ")"
|
||||||
|
<< std::endl;
|
||||||
|
equalityCheckLabelCounter++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateBitwiseBinaryOperation(std::ostringstream &stream,
|
||||||
|
Command cmd) {
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@BINARY_BITWISE" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@BINARY_BITWISE" << std::endl;
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::AND) {
|
||||||
|
stream << "M=D&M" << std::endl;
|
||||||
|
} else {
|
||||||
|
stream << "M=D|M" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
return pushFromDRegisterToStack(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateBistwiseUnaryOperation(std::ostringstream &stream) {
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M=!D" << std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "M=M+1" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateLabel(std::ostringstream &stream, Command cmd) {
|
||||||
|
stream << "(" << cmd.label << ")" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateGoTo(std::ostringstream &stream, Command cmd) {
|
||||||
|
stream << "@" << cmd.label << std::endl;
|
||||||
|
stream << "0;JMP" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateIfGoTo(std::ostringstream &stream, Command cmd) {
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@" << cmd.label << std::endl;
|
||||||
|
stream << "D;JNE" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateFunctionDefinition(std::ostringstream &stream,
|
||||||
|
Command cmd) {
|
||||||
|
stream << "(" << cmd.label << ")" << std::endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < cmd.index; ++i) {
|
||||||
|
stream << "@0" << std::endl;
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
|
||||||
|
if (pushFromDRegisterToStack(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int translateFunctionCall(std::ostringstream &stream, Command cmd) {
|
||||||
|
static int callCounter = 0;
|
||||||
|
std::string returnLabel = cmd.label + "$ret" + std::to_string(callCounter++);
|
||||||
|
|
||||||
|
stream << "@" << returnLabel << std::endl;
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
|
||||||
|
if (pushFromDRegisterToStack(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@LCL" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
if (pushFromDRegisterToStack(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@ARG" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
if (pushFromDRegisterToStack(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@THIS" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
if (pushFromDRegisterToStack(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@THAT" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
|
||||||
|
if (pushFromDRegisterToStack(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@5" << std::endl;
|
||||||
|
stream << "D=D-A" << std::endl;
|
||||||
|
stream << "@" << cmd.index << std::endl;
|
||||||
|
stream << "D=D-A" << std::endl;
|
||||||
|
stream << "@ARG" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@LCL" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@" << cmd.label << std::endl;
|
||||||
|
stream << "0;JMP" << std::endl;
|
||||||
|
stream << "(" << returnLabel << ")" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int translateFunctionReturn(std::ostringstream &stream) {
|
||||||
|
stream << "@LCL" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@FRAME" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@5" << std::endl;
|
||||||
|
stream << "D=A" << std::endl;
|
||||||
|
stream << "@FRAME" << std::endl;
|
||||||
|
stream << "D=M-D" << std::endl;
|
||||||
|
stream << "A=D" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@RETURN_ADDRESS" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@ARG" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@ADDR" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
if (popFromStackToDRegister(stream) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
stream << "@ADDR" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@ARG" << std::endl;
|
||||||
|
stream << "D=M+1" << std::endl;
|
||||||
|
stream << "@SP" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@FRAME" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@1" << std::endl;
|
||||||
|
stream << "D=D-A" << std::endl;
|
||||||
|
stream << "A=D" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@THAT" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@FRAME" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@2" << std::endl;
|
||||||
|
stream << "D=D-A" << std::endl;
|
||||||
|
stream << "A=D" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@THIS" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@FRAME" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@3" << std::endl;
|
||||||
|
stream << "D=D-A" << std::endl;
|
||||||
|
stream << "A=D" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@ARG" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@FRAME" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@4" << std::endl;
|
||||||
|
stream << "D=D-A" << std::endl;
|
||||||
|
stream << "A=D" << std::endl;
|
||||||
|
stream << "D=M" << std::endl;
|
||||||
|
stream << "@LCL" << std::endl;
|
||||||
|
stream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
stream << "@RETURN_ADDRESS" << std::endl;
|
||||||
|
stream << "A=M" << std::endl;
|
||||||
|
stream << "M;JMP" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int translateCommand(std::string &output, const std::string fileName,
|
||||||
|
Command cmd) {
|
||||||
|
std::ostringstream stream;
|
||||||
|
|
||||||
|
stream << "// " << cmd.line << std::endl;
|
||||||
|
stream << std::endl;
|
||||||
|
|
||||||
|
switch (cmd.commandType) {
|
||||||
|
case CommandType::PUSH:
|
||||||
|
case CommandType::POP:
|
||||||
|
translateStackOperation(stream, fileName, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::ADD:
|
||||||
|
case CommandType::SUB:
|
||||||
|
translateArithmeticBinaryOperation(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::NEG:
|
||||||
|
translateArithmeticUnaryOperation(stream);
|
||||||
|
break;
|
||||||
|
case CommandType::EQ:
|
||||||
|
case CommandType::GT:
|
||||||
|
case CommandType::LT:
|
||||||
|
translateEqualityOperation(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::AND:
|
||||||
|
case CommandType::OR:
|
||||||
|
translateBitwiseBinaryOperation(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::NOT:
|
||||||
|
translateBistwiseUnaryOperation(stream);
|
||||||
|
break;
|
||||||
|
case CommandType::LABEL:
|
||||||
|
translateLabel(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::GOTO:
|
||||||
|
translateGoTo(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::IFGOTO:
|
||||||
|
translateIfGoTo(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::FUNCTION:
|
||||||
|
translateFunctionDefinition(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::CALL:
|
||||||
|
translateFunctionCall(stream, cmd);
|
||||||
|
break;
|
||||||
|
case CommandType::RETURN:
|
||||||
|
translateFunctionReturn(stream);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << std::endl;
|
||||||
|
output = stream.str();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
int translateFunctionCall(std::ostringstream&, Command);
|
||||||
|
int translateCommand(std::string&, const std::string, Command);
|
||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "code.hpp"
|
||||||
|
#include "parser.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
int process(std::string inputPath, std::string outputPath,
|
||||||
|
std::ios_base::openmode outputStreamMode, bool &init) {
|
||||||
|
if (!std::filesystem::exists(inputPath)) {
|
||||||
|
std::cerr << "File does not exist!" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream ifs(inputPath);
|
||||||
|
std::ofstream ofs(outputPath, outputStreamMode);
|
||||||
|
std::string fileName = getFileNameFromFilePath(inputPath);
|
||||||
|
std::string line;
|
||||||
|
std::string output;
|
||||||
|
|
||||||
|
if (init) {
|
||||||
|
std::ostringstream initStream;
|
||||||
|
Command cmd;
|
||||||
|
|
||||||
|
initStream << "// " << "SP = 256" << std::endl;
|
||||||
|
initStream << std::endl;
|
||||||
|
|
||||||
|
initStream << "@256" << std::endl;
|
||||||
|
initStream << "D=A" << std::endl;
|
||||||
|
initStream << "@SP" << std::endl;
|
||||||
|
initStream << "M=D" << std::endl;
|
||||||
|
|
||||||
|
cmd.label = "Sys.init";
|
||||||
|
cmd.commandType = CommandType::CALL;
|
||||||
|
cmd.index = 0;
|
||||||
|
|
||||||
|
initStream << std::endl;
|
||||||
|
initStream << "// " << "call Sys.init 0" << std::endl;
|
||||||
|
initStream << std::endl;
|
||||||
|
|
||||||
|
if (translateFunctionCall(initStream, cmd) != 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
initStream << std::endl;
|
||||||
|
|
||||||
|
output = initStream.str();
|
||||||
|
ofs << output;
|
||||||
|
init = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Command> commands;
|
||||||
|
|
||||||
|
while (getline(ifs, line)) {
|
||||||
|
if (cleanupLine(line) != 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
if (isEmptyLine(line))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (parseCommand(commands, line) != 0)
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Command &cmd : commands) {
|
||||||
|
if (translateCommand(output, fileName, cmd) != 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
ofs << output;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifs.close();
|
||||||
|
ofs.close();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
std::cerr << "You must specify an argument for the vm file to translate!"
|
||||||
|
<< std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init = false;
|
||||||
|
|
||||||
|
if (regex_match(argv[1], std::regex("^.+\\.vm")))
|
||||||
|
return process(argv[1], getOutputPath(argv[1]), std::ofstream::trunc, init);
|
||||||
|
|
||||||
|
if (!std::filesystem::is_directory(argv[1])) {
|
||||||
|
std::cerr << "Argument is not a VM file!" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string outputPath = getOutputPath(argv[1]);
|
||||||
|
|
||||||
|
if (std::filesystem::exists(outputPath)) {
|
||||||
|
std::filesystem::remove(outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &entry : std::filesystem::directory_iterator(argv[1])) {
|
||||||
|
if (entry.is_regular_file() && entry.path().filename() == "Sys.vm") {
|
||||||
|
init = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &entry : std::filesystem::directory_iterator(argv[1])) {
|
||||||
|
if (entry.is_regular_file() && entry.path().extension() == ".vm") {
|
||||||
|
if (process(entry.path().string(), outputPath, std::ofstream::app,
|
||||||
|
init) != 0)
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "parser.hpp"
|
||||||
|
|
||||||
|
int parseCommand(std::vector<Command> &commands, std::string line) {
|
||||||
|
std::smatch matched;
|
||||||
|
|
||||||
|
if (regex_search(line, matched, std::regex("^(\\S+)\\s+(\\S+)\\s+(\\S+)$"))) {
|
||||||
|
Command cmd;
|
||||||
|
|
||||||
|
if (matched.ready()) {
|
||||||
|
std::string segment = matched[2];
|
||||||
|
cmd.line = line;
|
||||||
|
cmd.commandType = commandTypes.at(matched[1]);
|
||||||
|
cmd.index = std::stoi(std::string(matched[3]));
|
||||||
|
|
||||||
|
if (cmd.commandType == CommandType::FUNCTION ||
|
||||||
|
cmd.commandType == CommandType::CALL) {
|
||||||
|
cmd.label = matched[2];
|
||||||
|
} else {
|
||||||
|
cmd.segmentType = segmentTypes.at(segment);
|
||||||
|
cmd.segmentName = segmentNames.at(segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.push_back(cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::regex_search(line, matched, std::regex("^(\\S+)\\s+(\\S+)$"))) {
|
||||||
|
Command cmd;
|
||||||
|
|
||||||
|
if (matched.ready()) {
|
||||||
|
cmd.line = line;
|
||||||
|
cmd.commandType = commandTypes.at(matched[1]);
|
||||||
|
cmd.label = matched[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.push_back(cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regex_search(line, matched, std::regex("^(\\S+)$"))) {
|
||||||
|
Command cmd;
|
||||||
|
|
||||||
|
if (matched.ready()) {
|
||||||
|
cmd.line = line;
|
||||||
|
cmd.commandType = commandTypes.at(matched[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.push_back(cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Incorrect vm command: " << line << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
int parseCommand(std::vector<Command>&, std::string);
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#ifndef TYPES
|
||||||
|
|
||||||
|
enum class CommandType {
|
||||||
|
ADD,
|
||||||
|
SUB,
|
||||||
|
NEG,
|
||||||
|
EQ,
|
||||||
|
GT,
|
||||||
|
LT,
|
||||||
|
AND,
|
||||||
|
OR,
|
||||||
|
NOT,
|
||||||
|
PUSH,
|
||||||
|
POP,
|
||||||
|
LABEL,
|
||||||
|
GOTO,
|
||||||
|
IFGOTO,
|
||||||
|
FUNCTION,
|
||||||
|
CALL,
|
||||||
|
RETURN
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SegmentType {
|
||||||
|
LCL,
|
||||||
|
ARG,
|
||||||
|
THIS,
|
||||||
|
THAT,
|
||||||
|
STATIC,
|
||||||
|
CONSTANT,
|
||||||
|
TEMP,
|
||||||
|
POINTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, CommandType> const commandTypes = {
|
||||||
|
{"add", CommandType::ADD},
|
||||||
|
{"sub", CommandType::SUB},
|
||||||
|
{"neg", CommandType::NEG},
|
||||||
|
{"eq", CommandType::EQ},
|
||||||
|
{"gt", CommandType::GT},
|
||||||
|
{"lt", CommandType::LT},
|
||||||
|
{"and", CommandType::AND},
|
||||||
|
{"or", CommandType::OR},
|
||||||
|
{"not", CommandType::NOT},
|
||||||
|
{"push", CommandType::PUSH},
|
||||||
|
{"pop", CommandType::POP},
|
||||||
|
{"label", CommandType::LABEL},
|
||||||
|
{"goto", CommandType::GOTO},
|
||||||
|
{"if-goto", CommandType::IFGOTO},
|
||||||
|
{"function", CommandType::FUNCTION},
|
||||||
|
{"call", CommandType::CALL},
|
||||||
|
{"return", CommandType::RETURN}};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, SegmentType> const segmentTypes = {
|
||||||
|
{"local", SegmentType::LCL}, {"argument", SegmentType::ARG},
|
||||||
|
{"this", SegmentType::THIS}, {"that", SegmentType::THAT},
|
||||||
|
{"static", SegmentType::STATIC}, {"constant", SegmentType::CONSTANT},
|
||||||
|
{"temp", SegmentType::TEMP}, {"pointer", SegmentType::POINTER},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> const segmentNames = {
|
||||||
|
{"local", "LCL"}, {"argument", "ARG"}, {"this", "THIS"},
|
||||||
|
{"that", "THAT"}, {"static", "NONE"}, {"constant", "NONE"},
|
||||||
|
{"temp", "NONE"}, {"pointer", "NONE"},
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::string line;
|
||||||
|
CommandType commandType;
|
||||||
|
SegmentType segmentType;
|
||||||
|
std::string segmentName;
|
||||||
|
std::string label;
|
||||||
|
int index;
|
||||||
|
} Command;
|
||||||
|
|
||||||
|
#define TYPES
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
bool isEmptyLine(const std::string &line) {
|
||||||
|
for (char c : line) {
|
||||||
|
if (!isspace(c))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cleanupLine(std::string &line) {
|
||||||
|
size_t commentStartingPosition = line.find("//");
|
||||||
|
|
||||||
|
if (commentStartingPosition != std::string::npos) {
|
||||||
|
line = line.substr(0, commentStartingPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t firstNonWhiteSpacePosition = line.find_first_not_of(" \t\n\r");
|
||||||
|
|
||||||
|
if (firstNonWhiteSpacePosition == std::string::npos) {
|
||||||
|
line = "";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t lastNonWhiteSpacePosition = line.find_last_not_of(" \t\n\r");
|
||||||
|
line =
|
||||||
|
line.substr(firstNonWhiteSpacePosition,
|
||||||
|
(lastNonWhiteSpacePosition - firstNonWhiteSpacePosition + 1));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFileNameFromFilePath(const std::string &path) {
|
||||||
|
std::string fileName = path.substr(path.find_last_of("/\\") + 1);
|
||||||
|
|
||||||
|
return fileName.substr(0, fileName.find_last_of('.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getOutputPath(const std::string &path) {
|
||||||
|
if (std::filesystem::is_directory(path)) {
|
||||||
|
return path + "/" + path.substr(path.find_last_of("/\\") + 1) + ".asm";
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.substr(0, path.find_last_of('.')) + ".asm";
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
bool isEmptyLine(const std::string&);
|
||||||
|
int cleanupLine(std::string&);
|
||||||
|
std::string getFileNameFromFilePath(const std::string&);
|
||||||
|
std::string getOutputPath(const std::string&);
|
||||||
Reference in New Issue
Block a user