comptut

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