comptut

annotate src/main.c @ 4:ae1c30fa39f3

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