Ostatnio aktywny 3 weeks ago

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

simplest.cpp Surowy 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 if(secondary == snv_state::LITERAL) {
111 secondary = snv_state::VARIABLE;
112 }
113 cursor++;
114 }
115 inline void reset() {
116 clear();
117 cursor = 0;
118 primary = snv_state::INSERT;
119 secondary = snv_state::FETCH;
120 seek('?');
121 if(hook != nullptr) {
122 hook(this);
123 }
124 }
125 inline uint32_t number() {
126 char instruction = program[cursor];
127 if(instruction >= '0' && instruction <= '9') {
128 return instruction - '0';
129 } else if(instruction >= 'a' && instruction <= 'f') {
130 return (instruction - 'a') + 10;
131 } else if(instruction >= 'A' && instruction <= 'F') {
132 return (instruction - 'A') + 10;
133 } else {
134 return 0;
135 }
136 }
137 inline void insert() {
138 uint32_t symbol = number();
139 if(secondary == snv_state::LITERAL) {
140 stacks[stack].push(symbol);
141 } else {
142 if(variables[symbol].bound) {
143 stacks[stack].push(variables[symbol].symbol);
144 } else {
145 stacks[stack].push(0);
146 }
147 }
148 secondary = snv_state::FETCH;
149 cursor++;
150 }
151 inline void match() {
152 if(stacks[stack].empty() || stacks[stack].offset >= stacks[stack].top) {
153 branch();
154 } else {
155 uint32_t symbol = number();
156 if(secondary == snv_state::LITERAL) {
157 if(stacks[stack].peek() != symbol) {
158 branch();
159 } else {
160 stacks[stack].offset++;
161 }
162 } else if(secondary == snv_state::VARIABLE) {
163 if(!variables[symbol].bind(stacks[stack].peek())) {
164 branch();
165 } else {
166 stacks[stack].offset++;
167 }
168 }
169 }
170 secondary = snv_state::FETCH;
171 cursor++;
172 }
173 inline void literal() {
174 if(secondary == snv_state::FETCH) {
175 uint32_t symbol = number();
176 if(primary == snv_state::REMOVE) {
177 stacks[symbol].pop();
178 } else {
179 stack = symbol;
180 secondary = snv_state::LITERAL;
181 }
182 cursor++;
183 return;
184 }
185 if(primary == snv_state::INSERT) {
186 insert();
187 } else {
188 match();
189 }
190 }
191 inline void transition(snv_state state) {
192 primary = state;
193 secondary = snv_state::FETCH;
194 cursor++;
195 }
196 inline void comment() {
197 cursor++; seek('`'); cursor++;
198 }
199 inline bool step() {
200 if(cursor >= length || cursor >= program_size) {
201 return true;
202 }
203 switch(program[cursor]) {
204 case '+': transition(snv_state::INSERT); break;
205 case '?': transition(snv_state::MATCH); break;
206 case '-': transition(snv_state::REMOVE); break;
207 case '$': variable(); break;
208 case '.': reset(); break;
209 case ';': return true;
210 case '`': comment(); break;
211 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
212 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
213 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': literal(); break;
214 default: cursor++;
215 }
216 return false;
217 }
218 inline void run() {
219 bool halt = false;
220 uint64_t steps = 0;
221 while(!halt && steps != limit) {
222 halt = step();
223 steps++;
224 }
225 }
226};