-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbf.ice
160 lines (147 loc) · 5.5 KB
/
bf.ice
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
// A brainf*** interpreter, written in icelang
// https://en.wikipedia.org/wiki/Brainf***
// Executes a brainf*** program
fn execute(program) {
// Initialize the program state
let data = [];
loop 30000 {
push(data, 8x00);
};
let data_ptr = 0;
let instruction_ptr = 0;
let bracket_stack = [];
let stdin_buff = [];
// Execute the program
while instruction_ptr < len(program) {
// Execute the current instruction
match program[instruction_ptr] {
">" => {
data_ptr += 1;
while data_ptr >= len(data) {
push(data, 0);
};
},
"<" => {
data_ptr -= 1;
if data_ptr < 0 {
println();
println("Something went wrong: memory underflow");
return;
};
},
"+" => { data[data_ptr] += 8d1 },
"-" => { data[data_ptr] -= 8d1 },
"." => { print(from_codepoint(data[data_ptr])) },
"," => {
if stdin_buff != null && len(stdin_buff) == 0 {
let next_line = input();
if next_line == null {
stdin_buff = null;
}
else {
for character in next_line {
push(stdin_buff, character);
};
push(stdin_buff, "\n");
};
};
// If we've reached the end of stdin, leave the data unchanged
if stdin_buff != null {
let next_char = to_codepoint(pop_start(stdin_buff));
if next_char > 255 {
println();
println("Something went wrong: non-ASCII input character");
return;
};
data[data_ptr] = byte(next_char);
};
},
"[" => {
if data[data_ptr] == 8b0 {
// Advance to the matching "]"
let bracket_depth = 1;
loop {
instruction_ptr += 1;
if instruction_ptr >= len(program) {
println();
println("Something went wrong: unbalanced brackets");
return;
};
match program[instruction_ptr] {
"[" => { bracket_depth += 1 },
"]" => {
bracket_depth -= 1;
if bracket_depth == 0 {
break;
};
},
};
}
}
else {
push(bracket_stack, instruction_ptr);
};
},
"]" => {
let start_bracket_ptr = pop(bracket_stack);
if start_bracket_ptr == null {
println();
println("Something went wrong: unbalanced brackets");
return;
};
// This was the first ever bug in an icelang program :)
// I intended to jump back to the start bracket, and
// skipped the zero check because I assumed if the
// current byte is zero, it's okay to just jump back to
// the "[" and we'll just see the zero then and skip
// forward again past this "]"... problem is, I forgot
// about that assumption when I was considering where to
// jump back to. I knew the instruction_ptr would be
// incremented at the end of this iteration of the loop,
// so I figured we'll just jump back to the matching "["
// and the incrementing will bring us to the first
// instruction at the start of the "[]" loop... perfect!
// ...except now both ends of the "[]" loop are assuming
// the other end did the zero check, and it's never
// happening. Oops!
instruction_ptr = start_bracket_ptr;
// Let's add a continue to skip incrementing the
// instruction_ptr (that way, we'll jump back exactly to
// the "[" and not the next instruction after it)
continue;
},
};
// Advance to the next instruction
instruction_ptr += 1;
};
if len(bracket_stack) > 0 {
println();
println("Something went wrong: unbalanced brackets");
return;
};
};
fn main() {
// Get the file path to the brainf*** source file from the user
let file_path;
let program_args = args();
if len(program_args) > 1 {
file_path = program_args[1];
}
else {
print("Enter the path to a brainf*** source file: ");
file_path = input();
if file_path == null {
println("Failed to read file path from stdin");
return;
};
};
// Read the brainf*** source file into a string
let code = read_file(file_path);
if code == null {
println(f"Failed to read file: {file_path}");
return;
};
// Interpret the brainf*** code
execute(code);
};
main();