comptut

view src/main.c @ 5:bebbe71ba949

mostly completed tutor5.txt, without the hundred different looping constructs, which I don't care about
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 16 Mar 2015 01:06:49 +0200
parents ae1c30fa39f3
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <stdarg.h>
6 enum { SYM_VAR, SYM_FUNC };
8 struct symbol {
9 int type;
10 char name;
11 struct symbol *next;
12 };
14 void init(void);
15 void program(void);
16 void block(int brklb);
17 void doif(int brklb);
18 void dowhile(void);
19 void dobreak(int brklb);
20 void condition(void);
21 void expression(void);
22 void assignment(void);
23 void term(void);
24 void factor(void);
25 void ident(void);
26 void add(void);
27 void sub(void);
28 void mul(void);
29 void divide(void);
30 void get_char(void);
31 void match(char c);
32 char get_name(void);
33 char get_num(void);
34 void skip_white(void);
35 void stop(const char *s, ...);
36 void expected(const char *s);
37 void emit(const char *fmt, ...);
38 void vemit(const char *fmt, va_list ap);
39 void emitln(const char *fmt, ...);
40 int is_addsub(char c);
41 int add_symbol(char c, int type);
42 int newlabel(void);
43 const char *labelstr(int lb);
44 void postlabel(int lb);
45 void other(void);
47 FILE *infile, *outfile;
48 char look;
50 struct symbol *symlist;
52 static const char *prologue =
53 "\t.globl _start\n"
54 "_start:\n"
55 "\tcall main\n"
56 "\tmov %eax, %ebx\n"
57 "\tmov $1, %eax\n"
58 "\tint $0x80\n"
59 "main:\n"
60 "\t# ---- START ----\n";
62 static const char *epilogue = "\t# ---- END ----\n\tret\n";
64 int main(void)
65 {
66 infile = stdin;
67 outfile = stdout;
69 init();
70 /* output prologue */
71 fputs(prologue, outfile);
73 program();
75 /* output epilogue */
76 fputs(epilogue, outfile);
77 /* write all variable declarations */
78 fprintf(outfile, "\t.data\n");
79 while(symlist) {
80 struct symbol *sym = symlist;
81 symlist = symlist->next;
82 if(sym->type == SYM_VAR) {
83 fprintf(outfile, "%c:\t.long 0\n", sym->name);
84 }
85 free(sym);
86 }
87 return 0;
88 }
90 void init(void)
91 {
92 get_char();
93 skip_white();
94 }
96 void program(void)
97 {
98 block(-1);
99 if(look != 'e') {
100 expected("End");
101 }
102 emitln("# END");
103 }
105 void other(void)
106 {
107 emitln("%c", get_name());
108 }
110 void block(int brklb)
111 {
112 while(look != 'e' && look != 'l') {
113 switch(look) {
114 case 'i':
115 doif(brklb);
116 break;
118 case 'w':
119 dowhile();
120 break;
122 case 'b':
123 dobreak(brklb);
124 break;
126 default:
127 other();
128 break;
129 }
130 }
131 }
133 void doif(int brklb)
134 {
135 int lb1, lb2;
137 match('i');
138 condition();
140 lb1 = newlabel();
141 lb2 = lb1;
143 emitln("jz %s", labelstr(lb1));
144 block(brklb);
146 if(look == 'l') {
147 match('l');
148 lb2 = newlabel();
149 emitln("jmp %s", labelstr(lb2));
150 postlabel(lb1);
151 block(brklb);
152 }
153 match('e');
154 postlabel(lb2);
155 }
157 void dowhile(void)
158 {
159 int lbtop, lbend;
161 match('w');
162 lbtop = newlabel();
163 lbend = newlabel();
164 postlabel(lbtop);
165 condition();
166 emitln("jz %s", labelstr(lbend));
167 block(lbend);
168 match('e');
169 emitln("jmp %s", labelstr(lbtop));
170 postlabel(lbend);
171 }
173 void dobreak(int brklb)
174 {
175 match('b');
176 if(brklb == -1) {
177 stop("invalid break, not in loop");
178 }
179 emitln("jmp %s", labelstr(brklb));
180 }
182 void condition(void)
183 {
184 emitln("<condition>");
185 }
187 void expression(void)
188 {
189 if(is_addsub(look)) {
190 emitln("xor %%eax, %%eax");
191 } else {
192 term();
193 }
195 while(is_addsub(look)) {
196 emitln("push %%eax");
197 switch(look) {
198 case '+':
199 add();
200 break;
201 case '-':
202 sub();
203 break;
204 }
205 }
206 }
208 void assignment(void)
209 {
210 char name = get_name();
211 match('=');
213 if(add_symbol(name, SYM_VAR) == -1) {
214 stop("variable name '%c' previously defined as another type of symbol\n", name);
215 }
217 expression();
218 emitln("mov %%eax, (%c)", name);
219 }
221 void term(void)
222 {
223 factor();
224 while(look == '*' || look == '/') {
225 emitln("push %%eax");
226 switch(look) {
227 case '*':
228 mul();
229 break;
230 case '/':
231 divide();
232 break;
233 }
234 }
235 }
237 void factor(void)
238 {
239 if(look == '(') {
240 match('(');
241 expression();
242 match(')');
243 } else if(isalpha(look)) {
244 ident();
245 } else {
246 emitln("mov $%c, %%eax", get_num());
247 }
248 }
250 void ident(void)
251 {
252 char name = get_name();
253 if(look == '(') {
254 /* function call */
255 match('(');
256 match(')');
258 if(add_symbol(name, SYM_FUNC) == -1) {
259 stop("function name '%c' previously defined as another type of symbol\n", name);
260 }
261 emitln("call %c", name);
262 } else {
263 /* variable */
264 if(add_symbol(name, SYM_VAR) == -1) {
265 stop("variable name '%c' previously defined as another type of symbol\n", name);
266 }
267 emitln("mov (%c), %%eax", name);
268 }
269 }
271 void add(void)
272 {
273 match('+');
274 term();
275 emitln("pop %%ebx");
276 emitln("add %%ebx, %%eax");
277 }
279 void sub(void)
280 {
281 match('-');
282 term();
283 emitln("pop %%ebx");
284 emitln("sub %%ebx, %%eax");
285 emitln("neg %%eax");
286 }
288 void mul(void)
289 {
290 match('*');
291 factor();
292 emitln("pop %%ebx");
293 emitln("imul %%ebx");
294 }
296 void divide(void)
297 {
298 match('/');
299 factor();
300 emitln("mov %%eax, %%ebx");
301 emitln("pop %%eax");
302 emitln("idiv %%ebx");
303 }
305 void get_char(void)
306 {
307 look = fgetc(infile);
308 }
310 void match(char c)
311 {
312 if(look == c) {
313 get_char();
314 skip_white();
315 } else {
316 char s[2] = {0, 0};
317 s[0] = c;
318 expected(s);
319 }
320 }
322 char get_name(void)
323 {
324 char res;
325 if(!isalpha(look)) {
326 expected("name");
327 }
328 res = toupper(look);
329 get_char();
330 skip_white();
331 return res;
332 }
334 char get_num(void)
335 {
336 char res;
337 if(!isdigit(look)) {
338 expected("integer");
339 }
340 res = look;
341 get_char();
342 skip_white();
343 return res;
344 }
346 void skip_white(void)
347 {
348 while(isblank(look)) {
349 get_char();
350 }
351 }
353 void stop(const char *s, ...)
354 {
355 va_list ap;
357 fprintf(stderr, "error: ");
358 va_start(ap, s);
359 vfprintf(stderr, s, ap);
360 va_end(ap);
361 fputc('\n', stderr);
363 abort();
364 }
366 void expected(const char *s)
367 {
368 stop("%s expected", s);
369 }
371 void emit(const char *fmt, ...)
372 {
373 va_list ap;
374 va_start(ap, fmt);
375 vemit(fmt, ap);
376 va_end(ap);
377 }
379 void vemit(const char *fmt, va_list ap)
380 {
381 fputc('\t', outfile);
382 vfprintf(outfile, fmt, ap);
383 }
385 void emitln(const char *fmt, ...)
386 {
387 va_list ap;
388 va_start(ap, fmt);
389 vemit(fmt, ap);
390 va_end(ap);
391 fputc('\n', outfile);
392 }
395 int is_addsub(char c)
396 {
397 return c == '+' || c == '-';
398 }
400 int add_symbol(char c, int type)
401 {
402 struct symbol *sym = symlist;
403 while(sym) {
404 if(sym->name == c) {
405 /* we already have it */
406 return sym->type == type ? 0 : -1;
407 }
408 sym = sym->next;
409 }
411 if(!(sym = malloc(sizeof *sym))) {
412 perror("ICE: failed to allocate memory");
413 abort();
414 }
415 sym->name = c;
416 sym->type = type;
417 sym->next = symlist;
418 symlist = sym;
419 return 0;
420 }
422 int newlabel(void)
423 {
424 static int n;
425 return n++;
426 }
428 const char *labelstr(int lb)
429 {
430 static char buf[16];
431 sprintf(buf, "L%02d", lb);
432 return buf;
433 }
435 void postlabel(int lb)
436 {
437 fprintf(outfile, "%s:\n", labelstr(lb));
438 }