]> pd.if.org Git - lice/blob - gen.c
autocommit for files dated 2014-11-17 20:15:26
[lice] / gen.c
1 /*
2  * File: gen.c
3  *  Common code generator facilities.
4  */
5 #include <stdarg.h>
6 #include <stdio.h>
7
8 #include "gen.h"
9 #include "lice.h"
10
11 char *gen_label_break           = NULL;
12 char *gen_label_continue        = NULL;
13 char *gen_label_switch          = NULL;
14 char *gen_label_break_backup    = NULL;
15 char *gen_label_continue_backup = NULL;
16 char *gen_label_switch_backup   = NULL;
17
18 static void gen_emit_emitter(bool indent, const char *fmt, va_list list) {
19     if (indent)
20         fputc('\t', stdout);
21
22     va_list va;
23     va_copy(va, list);
24     vprintf(fmt, va);
25     va_end(va);
26
27     fputc('\n', stdout);
28 }
29
30 void gen_emit(const char *fmt, ...) {
31     va_list va;
32     va_start(va, fmt);
33     gen_emit_emitter(true, fmt, va);
34     va_end(va);
35 }
36
37 void gen_emit_inline(const char *fmt, ...) {
38     va_list va;
39     va_start(va, fmt);
40     gen_emit_emitter(false, fmt, va);
41     va_end(va);
42 }
43
44 void gen_jump_backup(void) {
45     gen_label_break_backup    = gen_label_break;
46     gen_label_continue_backup = gen_label_continue;
47 }
48
49 void gen_jump_save(char *lbreak, char *lcontinue) {
50     gen_jump_backup();
51
52     gen_label_break           = lbreak;
53     gen_label_continue        = lcontinue;
54 }
55
56 void gen_jump_restore(void) {
57     gen_label_break    = gen_label_break_backup;
58     gen_label_continue = gen_label_continue_backup;
59 }
60
61 void gen_jump(const char *label) {
62     if (!label)
63         compile_ice("gen_jump");
64
65     gen_emit("jmp %s", label);
66 }
67
68 void gen_label(const char *label) {
69     gen_emit("%s:", label);
70 }
71
72 /*
73  * Some expressions are architecture-independent thanks to generic generation
74  * functions.
75  */
76 static void gen_statement_switch(ast_t *ast) {
77     gen_label_switch_backup = gen_label_switch;
78     gen_label_break_backup  = gen_label_break;
79     gen_expression(ast->switchstmt.expr);
80     gen_label_switch = ast_label();
81     gen_label_break  = ast_label();
82     gen_jump(gen_label_switch);
83     if (ast->switchstmt.body)
84         gen_expression(ast->switchstmt.body);
85     gen_label(gen_label_switch);
86     gen_label(gen_label_break);
87     gen_label_switch = gen_label_switch_backup;
88     gen_label_break  = gen_label_break_backup;
89 }
90
91 static void gen_statement_do(ast_t *ast) {
92     char *begin = ast_label();
93     char *end   = ast_label();
94     gen_jump_save(end, begin);
95     gen_label(begin);
96     gen_expression(ast->forstmt.body);
97     gen_expression(ast->forstmt.cond);
98     gen_je(end);
99     gen_jump(begin);
100     gen_label(end);
101     gen_jump_restore();
102 }
103
104 static void gen_statement_compound(ast_t *ast) {
105     for (list_iterator_t *it = list_iterator(ast->compound); !list_iterator_end(it); )
106         gen_expression(list_iterator_next(it));
107 }
108
109 static void gen_statement_goto(ast_t *ast) {
110     gen_jump(ast->gotostmt.where);
111 }
112
113 static void gen_statement_label(ast_t *ast) {
114     if (ast->gotostmt.where)
115         gen_label(ast->gotostmt.where);
116 }
117
118 static void gen_statement_cond(ast_t *ast) {
119     gen_expression(ast->ifstmt.cond);
120     char *ne = ast_label();
121     gen_je(ne);
122     if (ast->ifstmt.then)
123         gen_expression(ast->ifstmt.then);
124     if (ast->ifstmt.last) {
125         char *end = ast_label();
126         gen_jump(end);
127         gen_label(ne);
128         gen_expression(ast->ifstmt.last);
129         gen_label(end);
130     } else {
131         gen_label(ne);
132     }
133 }
134
135 static void gen_statement_for(ast_t *ast) {
136     if (ast->forstmt.init)
137         gen_expression(ast->forstmt.init);
138     char *begin = ast_label();
139     char *step  = ast_label();
140     char *end   = ast_label();
141     gen_jump_save(end, step);
142     gen_label(begin);
143     if (ast->forstmt.cond) {
144         gen_expression(ast->forstmt.cond);
145         gen_je(end);
146     }
147     gen_expression(ast->forstmt.body);
148     gen_label(step);
149     if (ast->forstmt.step)
150         gen_expression(ast->forstmt.step);
151     gen_jump(begin);
152     gen_label(end);
153     gen_jump_restore();
154 }
155
156 static void gen_statement_while(ast_t *ast) {
157     char *begin = ast_label();
158     char *end   = ast_label();
159     gen_jump_save(end, begin);
160     gen_label(begin);
161     gen_expression(ast->forstmt.cond);
162     gen_je(end);
163     gen_expression(ast->forstmt.body);
164     gen_jump(begin);
165     gen_label(end);
166     gen_jump_restore();
167 }
168
169 static void gen_statement_return(ast_t *ast) {
170     if (ast->returnstmt) {
171         gen_expression(ast->returnstmt);
172         gen_boolean_maybe(ast->returnstmt->ctype);
173     }
174     gen_return();
175 }
176
177 static void gen_statement_break(void) {
178     gen_jump(gen_label_break);
179 }
180
181 static void gen_statement_continue(void) {
182     gen_jump(gen_label_continue);
183 }
184
185 static void gen_statement_default(void) {
186     gen_label(gen_label_switch);
187     gen_label_switch = ast_label();
188 }
189
190 static void gen_comma(ast_t *ast) {
191     gen_expression(ast->left);
192     gen_expression(ast->right);
193 }
194
195 static void gen_data_bss(ast_t *ast) {
196     gen_emit(".data");
197     if (!ast->decl.var->ctype->isstatic)
198         gen_emit(".global %s", ast->decl.var->variable.name);
199     gen_emit(".lcomm %s, %d", ast->decl.var->variable.name, ast->decl.var->ctype->size);
200 }
201
202 static void gen_data_global(ast_t *variable) {
203     if (variable->decl.init)
204         gen_data(variable, 0, 0);
205     else
206         gen_data_bss(variable);
207 }
208
209 static void gen_declaration_initialization(list_t *init, int offset) {
210     for (list_iterator_t *it = list_iterator(init); !list_iterator_end(it); ) {
211         ast_t *node = list_iterator_next(it);
212         if (node->init.value->type == AST_TYPE_LITERAL && node->init.type->bitfield.size <= 0)
213             gen_literal_save(node->init.value, node->init.type, node->init.offset + offset);
214         else {
215             gen_expression(node->init.value);
216             gen_save_local(node->init.type, node->init.offset + offset);
217         }
218     }
219 }
220
221 static void gen_declaration(ast_t *ast) {
222     if (!ast->decl.init)
223         return;
224
225     gen_zero(ast->decl.var->variable.off, ast->decl.var->variable.off + ast->decl.var->ctype->size);
226     gen_declaration_initialization(ast->decl.init, ast->decl.var->variable.off);
227 }
228
229 void gen_ensure_lva(ast_t *ast) {
230     if (ast->variable.init) {
231         gen_zero(ast->variable.off, ast->variable.off + ast->ctype->size);
232         gen_declaration_initialization(ast->variable.init, ast->variable.off);
233     }
234     ast->variable.init = NULL;
235 }
236
237 void gen_expression(ast_t *ast) {
238     if (!ast) return;
239
240     switch (ast->type) {
241         case AST_TYPE_STATEMENT_IF:             gen_statement_cond(ast);         break;
242         case AST_TYPE_EXPRESSION_TERNARY:       gen_statement_cond(ast);         break;
243         case AST_TYPE_STATEMENT_FOR:            gen_statement_for(ast);          break;
244         case AST_TYPE_STATEMENT_WHILE:          gen_statement_while(ast);        break;
245         case AST_TYPE_STATEMENT_DO:             gen_statement_do(ast);           break;
246         case AST_TYPE_STATEMENT_COMPOUND:       gen_statement_compound(ast);     break;
247         case AST_TYPE_STATEMENT_SWITCH:         gen_statement_switch(ast);       break;
248         case AST_TYPE_STATEMENT_GOTO:           gen_statement_goto(ast);         break;
249         case AST_TYPE_STATEMENT_LABEL:          gen_statement_label(ast);        break;
250         case AST_TYPE_STATEMENT_RETURN:         gen_statement_return(ast);       break;
251         case AST_TYPE_STATEMENT_BREAK:          gen_statement_break();           break;
252         case AST_TYPE_STATEMENT_CONTINUE:       gen_statement_continue();        break;
253         case AST_TYPE_STATEMENT_DEFAULT:        gen_statement_default();         break;
254         case AST_TYPE_CALL:                     gen_function_call(ast);          break;
255         case AST_TYPE_POINTERCALL:              gen_function_call(ast);          break;
256         case AST_TYPE_LITERAL:                  gen_literal(ast);                break;
257         case AST_TYPE_STRING:                   gen_literal_string(ast);         break;
258         case AST_TYPE_VAR_LOCAL:                gen_variable_local(ast);         break;
259         case AST_TYPE_VAR_GLOBAL:               gen_variable_global(ast);        break;
260         case AST_TYPE_DECLARATION:              gen_declaration(ast);            break;
261         case AST_TYPE_DEREFERENCE:              gen_dereference(ast);            break;
262         case AST_TYPE_ADDRESS:                  gen_address(ast->unary.operand); break;
263         case AST_TYPE_STATEMENT_CASE:           gen_case(ast);                   break;
264         case AST_TYPE_VA_START:                 gen_va_start(ast);               break;
265         case AST_TYPE_VA_ARG:                   gen_va_arg(ast);                 break;
266         case '!':                               gen_not(ast);                    break;
267         case AST_TYPE_NEGATE:                   gen_negate(ast);                 break;
268         case AST_TYPE_AND:                      gen_and(ast);                    break;
269         case AST_TYPE_OR:                       gen_or(ast);                     break;
270         case AST_TYPE_POST_INCREMENT:           gen_postfix(ast, "add");         break;
271         case AST_TYPE_POST_DECREMENT:           gen_postfix(ast, "sub");         break;
272         case AST_TYPE_PRE_INCREMENT:            gen_prefix (ast, "add");         break;
273         case AST_TYPE_PRE_DECREMENT:            gen_prefix (ast, "sub");         break;
274         case AST_TYPE_EXPRESSION_CAST:          gen_cast(ast);                   break;
275         case AST_TYPE_STRUCT:                   gen_struct(ast);                 break;
276         case '&':                               gen_bitandor(ast);               break;
277         case '|':                               gen_bitandor(ast);               break;
278         case '~':                               gen_bitnot(ast);                 break;
279         case ',':                               gen_comma(ast);                  break;
280         case '=':                               gen_assign(ast);                 break;
281         case AST_TYPE_CONVERT:                  gen_conversion(ast);             break;
282         case AST_TYPE_STATEMENT_GOTO_COMPUTED:  gen_goto_computed(ast);          break;
283         case AST_TYPE_STATEMENT_LABEL_COMPUTED: gen_address_label(ast);          break;
284         default:
285             gen_binary(ast);
286     }
287 }
288
289 void gen_toplevel(ast_t *ast) {
290     gen_function(ast);
291     if (ast->type == AST_TYPE_FUNCTION) {
292         gen_function_prologue(ast);
293         gen_expression(ast->function.body);
294         gen_function_epilogue();
295     } else if (ast->type == AST_TYPE_DECLARATION) {
296         gen_data_global(ast);
297     }
298 }