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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
|
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "eval.h"
static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out);
static int evaluate_value(struct Machine* machine, const struct Node* node, int64_t* out);
static int evaluate_condition(struct Machine* machine, const struct Node* node, bool* out);
void machine_init(struct Machine* machine)
{
memset(machine, 0, sizeof *machine);
}
static struct Variable* find_variable(struct Machine* machine, const char* name)
{
for (size_t index = 0; index < VARIABLES_MAX; index++)
{
struct Variable* variable = &machine->variables[index];
if (variable->declared && strcmp(variable->name, name) == 0)
return variable;
}
return NULL;
}
static bool bind_variable(struct Machine* machine, const char* name, int64_t value)
{
for (size_t index = 0; index < VARIABLES_MAX; index++)
{
struct Variable* variable = &machine->variables[index];
if (variable->declared)
continue;
(void)snprintf(variable->name, sizeof variable->name, "%s", name);
variable->value = value;
variable->declared = true;
return true;
}
return false;
}
static int complain(const struct Node* node, const char* message)
{
(void)fprintf(stderr, "line %d: %s\n", node->line, message);
return 1;
}
static int evaluate_operands(struct Machine* machine, const struct Node* node, int64_t* left,
int64_t* right)
{
if (evaluate_value(machine, node->first, left))
return 1;
return evaluate_value(machine, node->second, right);
}
static int evaluate_value(struct Machine* machine, const struct Node* node, int64_t* out)
{
int64_t left = 0;
int64_t right = 0;
struct Type type;
struct Variable* variable = NULL;
bool truth = false;
switch (node->kind)
{
case VALUE_DIFFERENCE:
*out = (int64_t)node->first->character - (int64_t)node->second->character;
return 0;
case VALUE_SUM:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left + right;
return 0;
case VALUE_PRODUCT:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left * right;
return 0;
case VALUE_QUOTIENT:
if (evaluate_operands(machine, node, &left, &right))
return 1;
if (right == 0)
return complain(node, "division by zero");
*out = left / right;
return 0;
case VALUE_EXTENT:
case VALUE_TUPLE_SIZE:
if (evaluate_type(machine, node->first, &type))
return 1;
*out = type.kind == KIND_ARRAY ? type.number : 0;
return 0;
case VALUE_INTEGRAL_CONSTANT: return evaluate_value(machine, node->first, out);
case VALUE_VARIABLE:
variable = find_variable(machine, node->name);
if (variable == NULL)
return complain(node, "that name was never declared");
*out = variable->value;
return 0;
case VALUE_CONDITIONAL:
if (evaluate_condition(machine, node->first, &truth))
return 1;
return evaluate_value(machine, truth ? node->second : node->third, out);
default: break;
}
assert(!"the parser handed a non-value where a value goes");
return 1;
}
static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out)
{
out->kind = KIND_VOID;
out->number = 0;
struct Type element;
bool truth = false;
switch (node->kind)
{
case TYPE_VOID: return 0;
case TYPE_INT32: out->kind = KIND_INT32; return 0;
case TYPE_BYTE: out->kind = KIND_BYTE; return 0;
case TYPE_SIZE: out->kind = KIND_SIZE; return 0;
case TYPE_REMOVE_CV: return evaluate_type(machine, node->first, out);
case TYPE_ARRAY:
if (evaluate_type(machine, node->first, &element) ||
evaluate_value(machine, node->second, &out->number))
return 1;
out->kind = KIND_ARRAY;
return 0;
case TYPE_CONDITIONAL:
if (evaluate_condition(machine, node->first, &truth))
return 1;
return evaluate_type(machine, truth ? node->second : node->third, out);
case TYPE_DECLTYPE:
if (evaluate_value(machine, node->first, &out->number))
return 1;
out->kind = KIND_VALUE;
return 0;
default: break;
}
assert(!"the parser handed a non-type where a type goes");
return 1;
}
static bool same_type(const struct Type* left, const struct Type* right)
{
return left->kind == right->kind && left->number == right->number;
}
static int evaluate_condition(struct Machine* machine, const struct Node* node, bool* out)
{
int64_t left = 0;
int64_t right = 0;
struct Type left_type;
struct Type right_type;
*out = false;
switch (node->kind)
{
case COND_TRUE: *out = true; return 0;
case COND_FALSE: return 0;
case COND_IS_SAME:
if (evaluate_type(machine, node->first, &left_type) ||
evaluate_type(machine, node->second, &right_type))
return 1;
*out = same_type(&left_type, &right_type);
return 0;
case COND_EQUAL:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left == right;
return 0;
case COND_LESS:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left < right;
return 0;
default: break;
}
assert(!"the parser handed a non-condition where a condition goes");
return 1;
}
static enum RunStatus declare(struct Machine* machine, const struct Node* node)
{
if (find_variable(machine, node->name) != NULL)
{
(void)complain(node, "already declared, and there is no changing that");
return RUN_FAILED;
}
struct Type type;
if (evaluate_type(machine, node->first, &type))
return RUN_FAILED;
if (type.kind != KIND_VALUE)
{
(void)complain(node, "that type carries no value, decltype something");
return RUN_FAILED;
}
if (!bind_variable(machine, node->name, type.number))
{
(void)complain(node, "too many variables, this was never meant to scale");
return RUN_FAILED;
}
return RUN_DONE;
}
static enum RunStatus undeclare(struct Machine* machine, const struct Node* node)
{
struct Variable* variable = find_variable(machine, node->name);
if (variable == NULL)
{
(void)complain(node, "cannot undeclare what was never declared");
return RUN_FAILED;
}
variable->declared = false;
return RUN_DONE;
}
static enum RunStatus emit(struct Machine* machine, const struct Node* node)
{
struct Type type;
if (evaluate_type(machine, node->first, &type))
return RUN_FAILED;
switch (type.kind)
{
case KIND_VOID: break;
case KIND_INT32: (void)printf("int32_t\n"); break;
case KIND_BYTE: (void)printf("byte\n"); break;
case KIND_SIZE: (void)printf("size_t\n"); break;
case KIND_ARRAY: (void)printf("array[%" PRId64 "]\n", type.number); break;
case KIND_VALUE: (void)printf("%" PRId64 "\n", type.number); break;
}
return RUN_DONE;
}
static enum RunStatus enable_if(struct Machine* machine, const struct Node* node)
{
bool truth = false;
if (evaluate_condition(machine, node->first, &truth))
return RUN_FAILED;
if (!truth)
return RUN_DONE;
return execute(machine, node->body);
}
static enum RunStatus static_assert_statement(struct Machine* machine, const struct Node* node)
{
bool truth = false;
if (evaluate_condition(machine, node->first, &truth))
return RUN_FAILED;
if (!truth)
{
(void)complain(node, "static assertion failed, at runtime, which is the best time");
return RUN_FAILED;
}
return RUN_DONE;
}
static enum RunStatus execute_one(struct Machine* machine, const struct Node* node)
{
switch (node->kind)
{
case STMT_DECLARE: return declare(machine, node);
case STMT_UNDECLARE: return undeclare(machine, node);
case STMT_ENABLE_IF: return enable_if(machine, node);
case STMT_EMIT: return emit(machine, node);
case STMT_STATIC_ASSERT: return static_assert_statement(machine, node);
default: break;
}
assert(!"the parser handed a non-statement where a statement goes");
return RUN_FAILED;
}
enum RunStatus execute(struct Machine* machine, const struct Node* statement)
{
while (statement != NULL)
{
enum RunStatus status = execute_one(machine, statement);
if (status != RUN_DONE)
return status;
statement = statement->next;
}
return RUN_DONE;
}
|