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
|
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include "eval.h"
static int evaluate_type(const struct Node* node, struct Type* out);
static int evaluate_value(const struct Node* node, int64_t* out);
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(const struct Node* node, int64_t* left, int64_t* right)
{
if (evaluate_value(node->first, left))
return 1;
return evaluate_value(node->second, right);
}
static int evaluate_value(const struct Node* node, int64_t* out)
{
int64_t left = 0;
int64_t right = 0;
struct Type type;
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(node, &left, &right))
return 1;
*out = left + right;
return 0;
case VALUE_PRODUCT:
if (evaluate_operands(node, &left, &right))
return 1;
*out = left * right;
return 0;
case VALUE_QUOTIENT:
if (evaluate_operands(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(node->first, &type))
return 1;
// a non-array has no extent, so it gets zero, exactly like the real thing
*out = type.kind == KIND_ARRAY ? type.number : 0;
return 0;
case VALUE_INTEGRAL_CONSTANT: return evaluate_value(node->first, out);
default: break;
}
assert(!"the parser handed a non-value where a value goes");
return 1;
}
static int evaluate_type(const struct Node* node, struct Type* out)
{
out->kind = KIND_VOID;
out->number = 0;
struct Type element;
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(node->first, out);
case TYPE_ARRAY:
// the element type is evaluated for its side of the bargain, then forgotten
if (evaluate_type(node->first, &element) || evaluate_value(node->second, &out->number))
return 1;
out->kind = KIND_ARRAY;
return 0;
case TYPE_DECLTYPE:
if (evaluate_value(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 enum RunStatus emit(const struct Node* node)
{
struct Type type;
if (evaluate_type(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 execute_one(const struct Node* node)
{
switch (node->kind)
{
case STMT_EMIT: return emit(node);
default: break;
}
assert(!"the parser handed a non-statement where a statement goes");
return RUN_FAILED;
}
enum RunStatus execute(const struct Node* statement)
{
while (statement != NULL)
{
enum RunStatus status = execute_one(statement);
if (status != RUN_DONE)
return status;
statement = statement->next;
}
return RUN_DONE;
}
|