Variables and basic math
[fur] / templates / program2.c
1 #include<assert.h>
2 #include<stdbool.h>
3 #include<stdint.h>
4 #include<stdio.h>
5 #include<stdlib.h>
6 #include<string.h>
7
8 enum Type;
9 typedef enum Type Type;
10 enum Type {
11   BUILTIN,
12   INTEGER,
13   STRING
14 };
15
16 enum Builtin;
17 typedef enum Builtin Builtin;
18 enum Builtin {
19   NIL,
20   PRINT
21 };
22
23 union Value;
24 typedef union Value Value;
25 union Value {
26   Builtin builtin;
27   char* string;
28   int32_t integer;
29 };
30
31 struct Object;
32 typedef struct Object Object;
33 struct Object {
34   Type type;
35   Value value;
36 };
37
38 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
39
40 void Object_deinitialize(Object* self) {
41 }
42
43 {% include "environment.c" %}
44 {% include "stack.c" %}
45
46 struct Thread;
47 typedef struct Thread Thread;
48 struct Thread {
49   Environment* environment;
50   Stack stack;
51   size_t program_counter;
52 };
53
54 void Thread_initialize(Thread* self, size_t program_counter) {
55   self->environment = Environment_construct();
56   Stack_initialize(&(self->stack));
57   self->program_counter = program_counter;
58 }
59
60 void Thread_deinitialize(Thread* self) {
61   Environment_destruct(self->environment);
62   Stack_deinitialize(&(self->stack));
63 }
64
65 union Argument;
66 typedef const union Argument Argument;
67 union Argument {
68   size_t label;
69   void* pointer;
70   char* string;
71   int32_t integer;
72 };
73
74 void call(struct Thread* thread, const union Argument argument) {
75   assert(!Stack_isEmpty(&(thread->stack)));
76   Object f = Stack_pop(&(thread->stack));
77
78   switch(f.type) {
79     case BUILTIN:
80       switch(f.value.builtin) {
81         case PRINT:
82           {
83             // TODO Handle multiple arguments
84             assert(!Stack_isEmpty(&(thread->stack)));
85             Object arg = Stack_pop(&(thread->stack));
86
87             switch(arg.type) {
88               case INTEGER:
89                 printf("%i", arg.value.integer);
90                 break;
91
92               case STRING:
93                 printf("%s", arg.value.string);
94                 break;
95
96               default:
97                 assert(0);
98             }
99
100             Stack_push(&(thread->stack), BUILTIN_NIL);
101           }
102           break;
103
104         default:
105           assert(false);
106       }
107       break;
108
109     default:
110       assert(false);
111   }
112 }
113
114 {% with name='add', operation='+' %}
115   {% include "arithmetic_instruction.c" %}
116 {% endwith %}
117
118
119 void drop(struct Thread* thread, const union Argument argument) {
120   assert(!Stack_isEmpty(&(thread->stack)));
121   Object result = Stack_pop(&(thread->stack));
122   Object_deinitialize(&result);
123 }
124
125 void end(struct Thread* thread, const union Argument argument) {
126 }
127
128 {% with name='idiv', operation='/' %}
129   {% include "arithmetic_instruction.c" %}
130 {% endwith %}
131
132 {% with name='mod', operation='%' %}
133   {% include "arithmetic_instruction.c" %}
134 {% endwith %}
135
136 {% with name='mul', operation='*' %}
137   {% include "arithmetic_instruction.c" %}
138 {% endwith %}
139
140 void pop(struct Thread* thread, const union Argument argument) {
141   char* argumentString = argument.string;
142
143   assert(!Stack_isEmpty(&(thread->stack)));
144   Object result = Stack_pop(&(thread->stack));
145
146   if(strcmp(argumentString, "print") == 0) {
147     assert(false);
148   }
149
150   Environment_set(thread->environment, argumentString, result);
151 }
152
153 void push(struct Thread* thread, const union Argument argument) {
154   char* argumentString = argument.string;
155
156   if(strcmp(argumentString, "print") == 0) {
157     Object result;
158     result.type = BUILTIN;
159     result.value.builtin = PRINT;
160     Stack_push(&(thread->stack), result);
161   } else {
162     Environment_get_Result result = Environment_get(thread->environment, argumentString);
163     if(!result.found) {
164       fprintf(stderr, "Variable `%s` not found", argumentString);
165       assert(false);
166     }
167     Stack_push(&(thread->stack), result.result);
168   }
169 }
170
171 void push_integer(struct Thread* thread, const union Argument argument) {
172   Object result;
173   result.type = INTEGER;
174   result.value.integer = argument.integer;
175
176   Stack_push(&(thread->stack), result);
177 }
178
179 void push_string(struct Thread* thread, const union Argument argument) {
180   Object result;
181   result.type = STRING;
182   result.value.string = argument.string;
183
184   Stack_push(&(thread->stack), result);
185 }
186
187 {% with name='sub', operation='-' %}
188   {% include "arithmetic_instruction.c" %}
189 {% endwith %}
190
191 struct Instruction;
192 typedef const struct Instruction Instruction;
193 struct Instruction {
194   void (*instruction)(struct Thread*,const union Argument);
195   Argument argument;
196 };
197
198 {% for label in labels_to_instruction_indices.keys() %}
199 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
200 {% endfor %}
201
202 const Instruction program[] = {
203 {% for instruction in instruction_list %}
204   (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
205 {% endfor %}
206 };
207
208 int main() {
209   Thread thread;
210   Thread_initialize(&thread, 0);
211
212   for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
213     program[thread.program_counter].instruction(
214       &thread,
215       program[thread.program_counter].argument
216     );
217   }
218
219   Thread_deinitialize(&thread);
220
221   return 0;
222 }