-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinterp.cpp
More file actions
204 lines (184 loc) · 6.19 KB
/
Copy pathinterp.cpp
File metadata and controls
204 lines (184 loc) · 6.19 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/* Brainfuck Interpreter
*
* Brainfuck operates on an array of memory cells, also referred to as the tape,
* each initially set to zero. There is a pointer, initially pointing to the
* first memory cell.
*
* Commands
* > Move the pointer to the right
* < Move the pointer to the left
* + Increment the memory cell under the pointer
* - Decrement the memory cell under the pointer
* . Output the character signified by the cell at the pointer
* , Input a character and store it in the cell at the pointer
* [ Jump past the matching ] if the cell under the pointer is 0
* ] Jump back to the matching [ if the cell under the pointer is nonzero
*/
#include <iostream>
#include <fstream>
#include <vector>
#define RESET "\033[0m" /* Reset terminal output color */
#define CYAN "\033[36m" /* Cyan */
#define GREEN "\033[32m" /* Green */
using namespace std;
const int TAPE_SIZE = 30000; // number of cells on tape, 30000 is from
// Urban Müller's o.g implementation
const string REPL_MESSAGE = "brainfuck repl\n";
unsigned char tape[TAPE_SIZE]; // memory tape
unsigned char* mem_ptr = &tape[0]; // points to current cell
bool REPL_MODE; // true if repl is running
// set all memory cells to 0
void init_tape() {
for (int i = 0; i < TAPE_SIZE; i++)
tape[i] = 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;
}
// read one byte of input store at current cell
// (to input a number use backslash e.g \65)
void read_input(unsigned char *mem_ptr) {
unsigned char c;
cin >> c;
if (c == '\\') {
int d;
cin >> d;
*mem_ptr = d;
}
}
// execute commands
void execute(vector<char> &commands) {
int bal;
for (unsigned int p = 0; p < commands.size(); p++) {
switch(commands[p]) {
// move pointer right
case '>':
mem_ptr++;
break;
// move pointer left
case '<':
mem_ptr--;
break;
// increment current memory cell
case '+':
(*mem_ptr)++;
break;
// decrement current memeory cell
case '-':
(*mem_ptr)--;
break;
// output current memory cell
case '.':
cout << *mem_ptr;
if (REPL_MODE) cout << endl;
break;
// get input and store in current memory cell
case ',':
read_input(mem_ptr);
break;
// Jump past the matching ] if the cell under the pointer is 0
case '[':
bal = 1;
if (*mem_ptr == 0) {
do {
p++;
if (commands[p] == '[') bal++;
else if (commands[p] == ']') bal--;
} while (bal != 0);
}
break;
// Jump back to the matching [ if the cell under the pointer is
// nonzero
case ']':
bal = 0;
do {
if (commands[p] == '[') bal++;
else if (commands[p] == ']') bal--;
p--;
} while (bal != 0);
break;
defualt:
cout << "invalid char: " << commands[p] << endl;
}
}
}
// outputs 8 bytes of tape contents in hex
// indicates the current cell
void show_tape() {
int cell_index = mem_ptr - &tape[0];
const char* indices = " %d %d %d %d %d %d %d %d\n";
const char* buckets = "| %02X | %02X | %02X | %02X | %02X | %02X | %02X | %02X |\n";
if (cell_index < 4) {
printf(indices,0,1,2,3,4,5,6,7);
cout << "+---------------------------------------+" << endl;
printf(buckets,tape[0],tape[1],tape[2],tape[3],tape[4],
tape[5],tape[6],tape[7],tape[8]);
cout << "+---------------------------------------+" << endl;
cout << " ";
for (int i = 0; i < cell_index; i++) {
cout << " ";
}
} else {
printf(indices,(cell_index-4),(cell_index-3), (cell_index-2), (cell_index-1),
(cell_index),(cell_index+1),(cell_index+2),(cell_index+3));
cout << "+---------------------------------------+" << endl;
printf(buckets,*(mem_ptr-4),*(mem_ptr-3), *(mem_ptr-2), *(mem_ptr-1),
*(mem_ptr), *(mem_ptr+1), *(mem_ptr+2), *(mem_ptr+3));
cout << "+---------------------------------------+" << endl;
cout << " ";
for (int i = 0; i < 4; i++) {
cout << " ";
}
}
cout << GREEN << "^ cell " << cell_index << RESET << endl;
}
// execute special repl commands (prefixed with '!')
void execute_repl_command(string &command) {
if (command == "!tape" || command == "!t")
show_tape();
else if (command == "!clear" || command == "!c")
system("clear");
else if (command == "!quit" || command == "!q")
exit(0);
}
// repl loop
// prefix special commands with !
// !quit or !q to exit loop
void repl() {
REPL_MODE = true;
bool done = false;
cout << REPL_MESSAGE;
string buffer;
do {
cout << "> ";
cin >> buffer;
if (buffer[0] == '!') {
execute_repl_command(buffer);
} else {
vector<char> commands(buffer.begin(), buffer.end());
execute(commands);
}
} while (!done);
}
int main(int argc, char **argv) {
if (argc == 1) {
repl();
return 0;
}
// make sure source code file name is provided
if (argc != 2) {
cout << "[usage]: ./brainfuck <source_code>" << endl;
}
// parse & execute source code
auto commands = parse(argv[1]);
execute(commands);
return 0;
}