-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompiler.cpp
More file actions
131 lines (115 loc) · 3.6 KB
/
Copy pathcompiler.cpp
File metadata and controls
131 lines (115 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* Brainfuck Compiler
*
* compiles to x86_64 linux using nasm assembler
*/
#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
using namespace std;
/*=============================================================== */
/* assembly: setup & set RBX register to point to start of tape */
/*=============================================================== */
const string ASM_HEADER = R"(
; --------------
; Brainfuck asm
; --------------
global _start
;===============
section .text
;===============
_start:
mov rbx, tape ; rbx points to beginning of tape
)";
/*=============================================================== */
/* assembly: exit syscall + data section */
/*=============================================================== */
const string ASM_FOOTER = R"(
; exit syscall
mov rax, 60
xor rdi, rdi
syscall
;==============
section .data
;==============
tape: times 30000 db 0
inputBuf: db 0
)";
// parse source code and return vector of commands
vector<char> parse(const char* filename) {
ifstream sourcecode(filename); // open source file
vector<char> commands;
char command;
while (sourcecode >> command) {
if (command != ' ' && command != '\n' && command != '\t')
commands.push_back(command);
}
return commands;
}
void generateASM(vector<char> &commands) {
stack<int> loop_stack;
string loop_id_str, loop_start;
int loop_id = 0;
ofstream asmfile("asm.s");
asmfile << ASM_HEADER;
for (auto &c : commands) {
switch(c) {
case '>':
asmfile << "inc rbx" << endl;
break;
case '<':
asmfile << "dec rbx" << endl;
break;
case '+':
asmfile << "inc byte [rbx]" << endl;
break;
case '-':
asmfile << "dec byte [rbx]" << endl;
break;
case '.':
asmfile << "mov rax, 1" << endl
<< "mov rdi, 1" << endl
<< "mov rsi, rbx" << endl
<< "mov rdx, 1" << endl
<< "syscall" << endl;
break;
case ',':
asmfile << "mov rax, 0" << endl
<< "mov rdi, 0" << endl
<< "mov rsi, inputBuf" << endl
<< "mov rdx, 2" << endl
<< "syscall" << endl;
break;
case '[':
loop_id_str = "loops"+ to_string(loop_id);
loop_stack.push(loop_id);
asmfile << "cmp byte [rbx], 0" << endl
<< "je loope" + to_string(loop_id) << endl
<< loop_id_str << ":" << endl;
loop_id++;
break;
case ']':
loop_id_str = "loope" + to_string(loop_stack.top());
loop_start = "loops" + to_string(loop_stack.top());
loop_stack.pop();
asmfile << "cmp byte [rbx], 0" << endl
<< "jne " << loop_start << endl
<< loop_id_str << ":" << endl;
break;
}
}
// asm footer
asmfile << ASM_FOOTER;
}
int main(int argc, char **argv) {
// make sure source code file name is provided
if (argc != 2) {
cout << "[usage]: ./compiler <source_code>" << endl;
}
// parse & execute source code
auto commands = parse(argv[1]);
generateASM(commands);
// compile & link
system("nasm -felf64 asm.s && ld asm.o -o out && rm asm.o");
return 0;
}