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
|
#include "all.h"
#include "str.h"
static void emit_includes(str *out) {
str_append(out, "#include <stdio.h>\n");
str_append(out, "#include <stdlib.h>\n");
str_append(out, "#include <string.h>\n\n");
}
static void emit_runtime(str *out) {
str_append(
out,
"typedef struct {\n"
" unsigned char *data;\n"
" size_t size;\n"
"} tape_t;\n\n"
"static void tape_init(tape_t *t, size_t initial) {\n"
" t->data = calloc(initial, 1);\n"
" t->size = initial;\n"
"}\n\n"
"static void tape_grow_right(tape_t *t, size_t needed) {\n"
" size_t new_size = t->size;\n"
" while (new_size <= needed) new_size *= 2;\n"
" unsigned char *new_data = calloc(new_size, 1);\n"
" memcpy(new_data, t->data, t->size);\n"
" free(t->data);\n"
" t->data = new_data;\n"
" t->size = new_size;\n"
"}\n\n"
"static void tape_grow_left(tape_t *t, size_t add, size_t *ptr) {\n"
" size_t new_size = t->size + add;\n"
" unsigned char *new_data = calloc(new_size, 1);\n"
" memcpy(new_data + add, t->data, t->size);\n"
" free(t->data);\n"
" t->data = new_data;\n"
" t->size = new_size;\n"
" *ptr += add;\n"
"}\n\n"
"static void tape_move_right(tape_t *t, size_t *ptr, size_t amount) {\n"
" *ptr += amount;\n"
" if (*ptr >= t->size)\n"
" tape_grow_right(t, *ptr);\n"
"}\n\n"
"static void tape_move_left(tape_t *t, size_t *ptr, size_t amount) {\n"
" if (amount > *ptr) {\n"
" size_t need = amount - *ptr;\n"
" size_t add = t->size;\n"
" while (add <= need)\n"
" add *= 2;\n"
" tape_grow_left(t, add, ptr);\n"
" }\n"
" *ptr -= amount;\n"
"}\n\n");
}
static void emit_prelude(str *out) {
str_append(out, "int main(void)\n"
"{\n"
" tape_t tape;\n"
" tape_init(&tape, 32);\n"
" size_t ptr = tape.size / 2;\n\n");
}
static void emit_epilogue(str *out) {
str_append(out, " free(tape.data);\n"
" return 0;\n"
"}\n");
}
static void emit_indent(str *out, int indent) {
for (int i = 0; i < indent; i++)
str_append(out, " ");
}
void emit_node(str *out, ast_node_t *node, int indent) {
for (; node; node = node->next) {
switch (node->type) {
case AST_INC:
emit_indent(out, indent);
str_append(out, "tape.data[ptr] += ");
str_appendf(out, "%d;\n", node->val);
break;
case AST_DEC:
emit_indent(out, indent);
str_append(out, "tape.data[ptr] -= ");
str_appendf(out, "%d;\n", node->val);
break;
case AST_PTR_INC:
emit_indent(out, indent);
str_append(out, "tape_move_right(&tape, &ptr, ");
str_appendf(out, "%d", node->val);
str_append(out, ");\n");
break;
case AST_PTR_DEC:
emit_indent(out, indent);
str_append(out, "tape_move_left(&tape, &ptr, ");
str_appendf(out, "%d", node->val);
str_append(out, ");\n");
break;
case AST_OUT:
emit_indent(out, indent);
str_append(out, "putchar((int)tape.data[ptr]);\n");
break;
case AST_IN:
emit_indent(out, indent);
str_append(out,
"{ int ch = getchar();\n"
" tape.data[ptr] = (ch == EOF) ? 0 : (unsigned char)ch; }\n");
break;
case AST_LOOP:
emit_indent(out, indent);
str_append(out, "while (tape.data[ptr]) {\n");
for (int i = 0; i < node->children.len; i++) {
emit_node(out, node->children._data[i], indent + 1);
}
emit_indent(out, indent);
str_append(out, "}\n");
break;
}
}
}
str gen_code(ast_node_t *ast) {
str out = {0};
emit_includes(&out);
emit_runtime(&out);
emit_prelude(&out);
emit_node(&out, ast, 1);
emit_epilogue(&out);
return out;
}
|