Generate a C program (which has a memory error after completion, but still)
[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 "stack.c" %}
44
45 struct Thread;
46 typedef struct Thread Thread;
47 struct Thread {
48   Stack stack;
49   size_t program_counter;
50 };
51
52 void Thread_initialize(Thread* self, size_t program_counter) {
53   Stack_initialize(&(self->stack));
54   self->program_counter = program_counter;
55 }
56
57 void Thread_deinitialize(Thread* self) {
58   Stack_deinitialize(&(self->stack));
59 }
60
61 union Argument;
62 typedef const union Argument Argument;
63 union Argument {
64   size_t label;
65   void* pointer;
66   char* string;
67   int32_t integer;
68 };
69
70 void call(struct Thread* thread, const union Argument argument) {
71   assert(!Stack_isEmpty(&(thread->stack)));
72   Object f = Stack_pop(&(thread->stack));
73
74   switch(f.type) {
75     case BUILTIN:
76       switch(f.value.builtin) {
77         case PRINT:
78           {
79             // TODO Handle multiple arguments
80             assert(!Stack_isEmpty(&(thread->stack)));
81             Object arg = Stack_pop(&(thread->stack));
82
83             switch(arg.type) {
84               case INTEGER:
85                 printf("%i", arg.value.integer);
86                 break;
87
88               case STRING:
89                 printf("%s", arg.value.string);
90                 break;
91
92               default:
93                 assert(0);
94             }
95
96             Stack_push(&(thread->stack), BUILTIN_NIL);
97           }
98           break;
99
100         default:
101           assert(false);
102       }
103       break;
104
105     default:
106       assert(false);
107   }
108 }
109
110 void drop(struct Thread* thread, const union Argument argument) {
111   assert(!Stack_isEmpty(&(thread->stack)));
112   Object result = Stack_pop(&(thread->stack));
113   Object_deinitialize(&result);
114 }
115
116 void end(struct Thread* thread, const union Argument argument) {
117 }
118
119 void push(struct Thread* thread, const union Argument argument) {
120   char* argumentString = argument.string;
121
122   Object result;
123
124   if(strcmp(argumentString, "print") == 0) {
125     result.type = BUILTIN;
126     result.value.builtin = PRINT;
127   } else {
128     assert(false);
129   }
130
131   Stack_push(&(thread->stack), result);
132 }
133
134 void push_integer(struct Thread* thread, const union Argument argument) {
135   Object result;
136   result.type = INTEGER;
137   result.value.integer = argument.integer;
138
139   Stack_push(&(thread->stack), result);
140 }
141
142 void push_string(struct Thread* thread, const union Argument argument) {
143   Object result;
144   result.type = STRING;
145   result.value.string = argument.string;
146
147   Stack_push(&(thread->stack), result);
148 }
149
150 struct Instruction;
151 typedef const struct Instruction Instruction;
152 struct Instruction {
153   void (*instruction)(struct Thread*,const union Argument);
154   Argument argument;
155 };
156
157 {% for label in labels_to_instruction_indices.keys() %}
158 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
159 {% endfor %}
160
161 const Instruction program[] = {
162 {% for instruction in instruction_list %}
163   (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
164 {% endfor %}
165 };
166
167 int main() {
168   Thread thread;
169   Thread_initialize(&thread, 0);
170
171   for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
172     program[thread.program_counter].instruction(
173       &thread,
174       program[thread.program_counter].argument
175     );
176   }
177
178   Thread_deinitialize(&thread);
179
180   return 0;
181 }