-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathinterpreter.c
234 lines (227 loc) · 5.93 KB
/
interpreter.c
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#include "AST.h"
#include <strings.h>
#include <stdio.h>
// The current state for the interpreter
struct InterpreterState {
// The local registers
int16_t a[10];
// The global registers
int16_t g[10];
// The current cell value
int16_t v;
// The width of the grid
int16_t width;
// The height of the grid
int16_t height;
// The x coordinate of the current cell
int16_t x;
// The y coordinate of the current cell
int16_t y;
// The grid itself
int16_t *grid;
};
int interpret(struct ASTNode *ast, struct InterpreterState *state);
// Runs a single step
void runOneStep(int16_t *oldgrid, int16_t *newgrid, int16_t width, int16_t height, struct ASTNode **ast, uintptr_t count)
{
struct InterpreterState state = {0};
state.grid = oldgrid;
state.width = width;
state.height = height;
int i=0;
for (int x=0 ; x<width ; x++) {
for (int y=0 ; y<height ; y++,i++) {
state.v = oldgrid[i];
state.x = x;
state.y = y;
bzero(state.a, sizeof(state.a));
for (int step=0 ; step<count ; step++) {
interpret(ast[step], &state);
}
newgrid[i] = state.v;
}
}
}
static void
storeInLValue(uintptr_t reg, int val, struct InterpreterState *state) {
reg >>= 2;
if (reg < 10) {
state->a[reg] = val;
} else if (reg < 20) {
state->g[reg - 10] = val;
} else if (reg == 21) {
state->v = val;
}
}
static int getRValue(uintptr_t val, struct InterpreterState *state) {
// If the low bit is 1, then this is either an immediate or a register
if (val & 1) {
val >>= 1;
// Second lowest bit indicates that this is a register
if (val & 1) {
val >>= 1;
if (val < 10) {
return state->a[val];
}
if (val < 20) {
return state->g[val - 10];
}
// Undefined values
if (val > 21) {
return -1;
}
return state->v;
}
// Literal
return val >> 1;
}
// If the low bit is 0, this is a pointer to an AST node
return interpret((struct ASTNode*)val, state);
}
int interpret(struct ASTNode *ast, struct InterpreterState *state) {
switch (ast->type) {
case NTNeighbours:
// For each of the (valid) neighbours
for (int x = state->x - 1 ; x <= state->x + 1 ; x++) {
if (x < 0 || x >= state->width) continue;
for (int y = state->y - 1 ; y <= state->y + 1 ; y++) {
if (y < 0 || y >= state->height) continue;
if (x == state->x && y == state->y) continue;
for (int i=0 ; i<ast->val[0]; i++) {
state->a[0] = state->grid[x*state->width + y];
interpret(((struct ASTNode**)ast->val[1])[i], state);
}
}
}
break;
case NTRangeMap: {
struct RangeMap *rm = (struct RangeMap*)ast->val[0];
int rvalue = getRValue(rm->value, state);
for (int i=0 ; i<rm->count ; i++) {
struct RangeMapEntry *re = &rm->entries[i];
if ((rvalue >= (re->min >> 2)) && (rvalue <= (re->max >> 2))) {
return getRValue(re->val, state);
}
}
return 0;
}
case NTOperatorAdd:
case NTOperatorSub:
case NTOperatorMul:
case NTOperatorDiv:
case NTOperatorAssign:
case NTOperatorMin:
case NTOperatorMax: {
int lvalue = getRValue(ast->val[0], state);
int rvalue = getRValue(ast->val[1], state);
switch (ast->type) {
case NTOperatorAdd:
rvalue = lvalue + rvalue;
break;
case NTOperatorSub:
rvalue = lvalue - rvalue;
break;
case NTOperatorMul:
rvalue = lvalue * rvalue;
break;
case NTOperatorDiv:
rvalue = lvalue / rvalue;
break;
case NTOperatorMin:
if (rvalue > lvalue)
rvalue = lvalue;
break;
case NTOperatorMax:
if (rvalue < lvalue)
rvalue = lvalue;
default: break;
}
storeInLValue(ast->val[0], rvalue, state);
}
}
return 0;
}
void printAST(struct ASTNode *ast) {
uintptr_t val = (uintptr_t)ast;
if (val & 1) {
val >>= 1;
// Second lowest bit indicates that this is a register
if (val & 1) {
val >>= 1;
if (val < 10) {
printf("a%d ", (int)val);
} else if (val < 20) {
printf("g%d ", (int)val - 10);
return;
} else if (val == 21) {
printf("v ");
}
} else {
// Literal
printf("%d ", (int)val>>1);
}
return;
}
switch (ast->type) {
case NTNeighbours:{
printf("neighbours (\n");
for (int i=0 ; i<ast->val[0]; i++) {
printAST(((struct ASTNode**)ast->val[1])[i]);
}
printf(")\n");
break;
}
case NTRangeMap: {
printf("[ ");
struct RangeMap *rm = (struct RangeMap*)ast->val[0];
printAST((struct ASTNode*)rm->value);
printf("| ");
for (int i=0 ; i<rm->count ; i++) {
struct RangeMapEntry *re = &rm->entries[i];
printf("(");
printAST((struct ASTNode*)re->min);
printf(", ");
printAST((struct ASTNode*)re->max);
printf(") => ");
printAST((struct ASTNode*)re->val);
printf(",");
}
printf(" ]");
break;
}
case NTOperatorAdd:
case NTOperatorSub:
case NTOperatorMul:
case NTOperatorDiv:
case NTOperatorAssign:
case NTOperatorMin:
case NTOperatorMax: {
switch (ast->type) {
case NTOperatorAssign:
printf("= ");
break;
case NTOperatorAdd:
printf("+ ");
break;
case NTOperatorSub:
printf("- ");
break;
case NTOperatorMul:
printf("* ");
break;
case NTOperatorDiv:
printf("/ ");
break;
case NTOperatorMin:
printf("min ");
break;
case NTOperatorMax:
printf("max ");
default: break;
}
printAST((struct ASTNode*)ast->val[0]);
printAST((struct ASTNode*)ast->val[1]);
break;
}
}
}