-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbf0x.hpp
192 lines (162 loc) · 5.51 KB
/
bf0x.hpp
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
#ifndef INCLUDED_BF0X_HPP
#define INCLUDED_BF0X_HPP
#include <iostream>
#ifdef DEBUG
# define BF0X_TRACE(c) (std::cout << "\033[2m" << c << "\033[0m")
#else
# define BF0X_TRACE(c)
#endif
namespace bf0x {
struct state {
char data[65536];
unsigned int pos;
state()
: data()
, pos(0) {
}
};
// A stack of interpreter templates structure
template <template <class, char...> class... blocks> struct bstack;
template <template <class, char...> class head, template <class, char...> class... tail>
struct bstack<head, tail...> {
enum { size = bstack<tail...>::size+1 };
// Instantiate top of the stack
template <char... chars> struct top {
typedef head<bstack, chars...> type;
};
// Pop the top
typedef bstack<tail...> pop;
// Push on the stack
template <template <class, char...> class pushed> struct push {
typedef bstack<pushed, head, tail...> type;
};
};
// Empty stack specialization
template <> struct bstack <> {
enum { size = 0 };
template <template <class, char...> class pushed> struct push {
typedef bstack<pushed> type;
};
};
// Syntactic sugar
template <class bstack, char... chars>
struct top {
typedef typename bstack::template top<chars...>::type type;
};
template <class, char...> struct interpreter;
template <class, char...> struct loop_interpreter;
template <class, char...> struct tail_interpreter;
template <class stack> struct interpreter<stack> {
static void exec(state&) {}
};
template <class stack> struct tail_interpreter<stack> {
static void exec(state&) {}
};
template <class stack> struct loop_interpreter<stack> {
static void exec(state&) {}
};
// The basic parsing functions :
// - pop a char from the tail
// - execute corresponding code
// - parse the rest with the top-of-stack interpreter
template <class bstack, char c, char... tail> struct interpreter<bstack, c, tail...> {
static void exec(state& st) {
// Ignore unknown chars
top<bstack, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct interpreter<bstack, '>', tail...> {
static void exec(state& st) {
BF0X_TRACE('>');
st.pos++;
top<bstack, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct interpreter<bstack, '<', tail...> {
static void exec(state& st) {
BF0X_TRACE('<');
st.pos--;
top<bstack, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct interpreter<bstack, '+', tail...> {
static void exec(state& st) {
BF0X_TRACE('+');
st.data[st.pos]++;
top<bstack, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct interpreter<bstack, '-', tail...> {
static void exec(state& st) {
BF0X_TRACE('-');
st.data[st.pos]--;
top<bstack, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct interpreter<bstack, '.', tail...> {
static void exec(state& st) {
BF0X_TRACE('.');
std::cout.put(st.data[st.pos]);
top<bstack, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct interpreter<bstack, ',', tail...> {
static void exec(state& st) {
BF0X_TRACE(',');
std::cin.get(st.data[st.pos]);
top<bstack, tail...>::type::exec(st);
}
};
// A slightly more complex case, we want to do compile-time detection of
// loop pattern (aka. balanced brackets)
// We parse inside of the loop with one parser and outside with another
template <class bstack, char... tail> struct interpreter<bstack, '[', tail...> {
static void exec(state& st) {
BF0X_TRACE("[\n");
while (st.data[st.pos]) {
for (int i=0; i<bstack::size; ++i) BF0X_TRACE(" ");
top<typename bstack::template push<loop_interpreter>::type
, tail...>::type::exec(st);
}
for (int i=0; i<bstack::size-1; ++i) BF0X_TRACE(" ");
BF0X_TRACE("]");
top<typename bstack::template push<tail_interpreter>::type
, tail...>::type::exec(st);
}
};
// We can use the default interpreter implementation for evaluating since
// interpreter code take care of using the top-of-stack for parsing next
// char, which will correctly call loop_interpreter for next-char
template <class bstack, char c, char... tail> struct loop_interpreter<bstack, c, tail...> {
// let the base interpreter interpret this char
static void exec(state& st) {
interpreter<bstack, c, tail...>::exec(st);
}
};
template <class bstack, char... tail> struct loop_interpreter<bstack, ']', tail...> {
// stop interpretation at ']'
static void exec(state&) {
BF0X_TRACE('\n');
}
};
template <class bstack, char c, char... tail> struct tail_interpreter<bstack, c, tail...> {
static void exec(state& st) {
// ignore char and continue parsing using itself
top<bstack, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct tail_interpreter<bstack, '[', tail...> {
// push down one more interpreter to count balanced brackets
static void exec(state& st) {
top<typename bstack::template push<bf0x::tail_interpreter>::type
, tail...>::type::exec(st);
}
};
template <class bstack, char... tail> struct tail_interpreter<bstack, ']', tail...> {
// pop itself from the interpreter stack and let the parent parse the rest
static void exec(state& st) {
top<typename bstack::pop, tail...>::type::exec(st);
}
};
}
#endif