最終更新 3 weeks ago

The simplest Nova implementation I've got (so far) in C++.

修正履歴 bef05eca225876fee26cdd81d46fc1967c606d8b

simplest.cpp Raw Playground
1enum snv_state {
2 // Primary states.
3 INSERT, MATCH, REMOVE,
4 // Secondary states.
5 FETCH, LITERAL, VARIABLE
6};
7
8template<uint32_t size>
9struct snv_stack {
10 uint32_t data[size] = {};
11 uint8_t top = 0;
12 uint8_t offset = 0;
13 inline void push(uint32_t symbol) {
14 if(!full()) {
15 data[top] = symbol;
16 top++;
17 }
18 }
19 inline uint32_t pop() {
20 uint32_t result = 0;
21 if(!empty()) {
22 result = data[top];
23 top--;
24 }
25 return result;
26 }
27 inline uint32_t peek() {
28 if(!empty() && offset < top) {
29 return data[(top - 1) - offset];
30 }
31 return 0;
32 }
33 inline bool empty() {
34 return top == 0;
35 }
36 inline bool full() {
37 return top >= size;
38 }
39 inline void reset() {
40 offset = 0;
41 }
42 inline void clear() {
43 top = 0;
44 offset = 0;
45 }
46};
47
48struct snv_variable {
49 uint32_t symbol = 0;
50 bool bound = false;
51 inline void clear() {
52 symbol = 0;
53 bound = false;
54 }
55 inline bool bind(uint32_t symbol) {
56 if(bound) {
57 return symbol == this->symbol;
58 }
59 this->symbol = symbol;
60 bound = true;
61 return true;
62 }
63};
64
65template<uint32_t stack_size, uint32_t stack_count, uint32_t variable_count, uint32_t program_size>
66struct snv_core {
67 snv_stack<stack_size> stacks[stack_count] = {};
68 snv_variable variables[variable_count] = {};
69 char program[program_size] = {};
70 snv_state primary = snv_state::INSERT;
71 snv_state secondary = snv_state::FETCH;
72 void (*hook)(snv_core*) = nullptr;
73 uint64_t limit = ~0;
74 uint32_t length = 0;
75 uint32_t stack = 0;
76 uint32_t cursor = 0;
77 uint32_t last = program_size;
78 snv_core(const char* program) {
79 uint32_t cursor = 0;
80 while(cursor < program_size && program[cursor] != '\0') {
81 this->program[cursor] = program[cursor];
82 cursor++;
83 }
84 length = cursor;
85 }
86 inline void seek(char instruction) {
87 while(cursor < program_size) {
88 if(cursor == '`' && instruction != '`') {
89 cursor++; seek('`'); cursor++;
90 } else if(program[cursor] == instruction || instruction == ';') {
91 break;
92 } else {
93 cursor++;
94 }
95 }
96 }
97 inline void clear() {
98 for(uint8_t variable = 0; variable < variable_count; variable++) {
99 variables[variable].clear();
100 }
101 for(uint8_t stack = 0; stack < stack_count; stack++) {
102 stacks[stack].reset();
103 }
104 }
105 inline void branch() {
106 clear();
107 seek('.');
108 }
109 inline void variable() {
110 Serial.printf("VARIABLE! %c %d\n", program[cursor], cursor);
111 if(secondary == snv_state::LITERAL) {
112 secondary = snv_state::VARIABLE;
113 }
114 cursor++;
115 }
116 inline void reset() {
117 clear();
118 cursor = 0;
119 primary = snv_state::INSERT;
120 secondary = snv_state::FETCH;
121 seek('?');
122 if(hook != nullptr) {
123 hook(this);
124 }
125 }
126 inline uint32_t number() {
127 char instruction = program[cursor];
128 if(instruction >= '0' && instruction <= '9') {
129 return instruction - '0';
130 } else if(instruction >= 'a' && instruction <= 'f') {
131 return (instruction - 'a') + 10;
132 } else if(instruction >= 'A' && instruction <= 'F') {
133 return (instruction - 'A') + 10;
134 } else {
135 return 0;
136 }
137 }
138 inline void insert() {
139 uint32_t symbol = number();
140 Serial.printf("INSERT! %c %d\n", program[cursor], cursor);
141 if(secondary == snv_state::LITERAL) {
142 stacks[stack].push(symbol);
143 } else {
144 if(variables[symbol].bound) {
145 stacks[stack].push(variables[symbol].symbol);
146 } else {
147 stacks[stack].push(0);
148 }
149 }
150 secondary = snv_state::FETCH;
151 cursor++;
152 }
153 inline void match() {
154 Serial.printf("MATCH! %c %d\n", program[cursor], cursor);
155 if(stacks[stack].empty() || stacks[stack].offset >= stacks[stack].top) {
156 branch();
157 } else {
158 uint32_t symbol = number();
159 if(secondary == snv_state::LITERAL) {
160 if(stacks[stack].peek() != symbol) {
161 branch();
162 } else {
163 stacks[stack].offset++;
164 }
165 } else if(secondary == snv_state::VARIABLE) {
166 if(!variables[symbol].bind(stacks[stack].peek())) {
167 branch();
168 } else {
169 stacks[stack].offset++;
170 }
171 }
172 }
173 secondary = snv_state::FETCH;
174 cursor++;
175 }
176 inline void literal() {
177 Serial.printf("LITERAL! %c %d\n", program[cursor], cursor);
178 if(secondary == snv_state::FETCH) {
179 uint32_t symbol = number();
180 if(primary == snv_state::REMOVE) {
181 stacks[symbol].pop();
182 } else {
183 stack = symbol;
184 secondary = snv_state::LITERAL;
185 }
186 cursor++;
187 return;
188 }
189 if(primary == snv_state::INSERT) {
190 insert();
191 } else {
192 match();
193 }
194 }
195 inline void transition(snv_state state) {
196 Serial.printf("TRANSITION! %c %d\n", program[cursor], cursor);
197 primary = state;
198 secondary = snv_state::FETCH;
199 cursor++;
200 }
201 inline void comment() {
202 Serial.printf("COMMENT! %c %d\n", program[cursor], cursor);
203 cursor++; seek('`'); cursor++;
204 }
205 inline bool step() {
206 if(cursor >= length || cursor >= program_size) {
207 return true;
208 }
209 Serial.printf("%d [%c]\n", cursor, program[cursor]);
210 print();
211 switch(program[cursor]) {
212 case '+': transition(snv_state::INSERT); break;
213 case '?': transition(snv_state::MATCH); break;
214 case '-': transition(snv_state::REMOVE); break;
215 case '$': variable(); break;
216 case '.': reset(); break;
217 case ';': return true;
218 case '`': comment(); break;
219 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
220 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
221 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': literal(); break;
222 default: cursor++;
223 }
224 return false;
225 }
226 inline void run() {
227 bool halt = false;
228 uint64_t steps = 0;
229 while(!halt && steps != limit) {
230 halt = step();
231 steps++;
232 }
233 }
234};