nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@3: enum { SYM_VAR, SYM_FUNC }; nuclear@3: nuclear@3: struct symbol { nuclear@3: int type; nuclear@3: char name; nuclear@3: struct symbol *next; nuclear@3: }; nuclear@3: nuclear@0: void init(void); nuclear@0: void expression(void); nuclear@3: void assignment(void); nuclear@0: void term(void); nuclear@0: void factor(void); nuclear@3: void ident(); nuclear@0: void add(void); nuclear@0: void sub(void); nuclear@0: void mul(void); nuclear@0: void divide(void); nuclear@0: void get_char(void); nuclear@0: void match(char c); nuclear@0: char get_name(void); nuclear@0: char get_num(void); nuclear@3: void skip_white(void); nuclear@0: void stop(const char *s, ...); nuclear@0: void expected(const char *s); nuclear@0: void emit(const char *fmt, ...); nuclear@0: void vemit(const char *fmt, va_list ap); nuclear@0: void emitln(const char *fmt, ...); nuclear@0: int is_addsub(char c); nuclear@3: int add_symbol(char c, int type); nuclear@0: nuclear@0: FILE *infile, *outfile; nuclear@0: char look; nuclear@0: nuclear@3: struct symbol *symlist; nuclear@3: nuclear@0: static const char *prologue = nuclear@0: "\t.globl _start\n" nuclear@0: "_start:\n" nuclear@0: "\tcall main\n" nuclear@0: "\tmov %eax, %ebx\n" nuclear@0: "\tmov $1, %eax\n" nuclear@0: "\tint $0x80\n" nuclear@0: "main:\n" nuclear@0: "\t# ---- START ----\n"; nuclear@0: nuclear@0: static const char *epilogue = "\t# ---- END ----\n\tret\n"; nuclear@0: nuclear@0: int main(void) nuclear@0: { nuclear@0: infile = stdin; nuclear@0: outfile = stdout; nuclear@0: nuclear@0: init(); nuclear@0: /* output prologue */ nuclear@0: fputs(prologue, outfile); nuclear@0: nuclear@3: assignment(); nuclear@3: if(look != '\n') { nuclear@3: expected("newline"); nuclear@3: } nuclear@0: nuclear@0: /* output epilogue */ nuclear@0: fputs(epilogue, outfile); nuclear@3: /* write all variable declarations */ nuclear@3: fprintf(outfile, "\t.data\n"); nuclear@3: while(symlist) { nuclear@3: struct symbol *sym = symlist; nuclear@3: symlist = symlist->next; nuclear@3: if(sym->type == SYM_VAR) { nuclear@3: fprintf(outfile, "%c:\t.long 0\n", sym->name); nuclear@3: } nuclear@3: free(sym); nuclear@3: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void init(void) nuclear@0: { nuclear@0: get_char(); nuclear@3: skip_white(); nuclear@0: } nuclear@0: nuclear@0: void expression(void) nuclear@0: { nuclear@0: if(is_addsub(look)) { nuclear@0: emitln("xor %%eax, %%eax"); nuclear@0: } else { nuclear@0: term(); nuclear@0: } nuclear@0: nuclear@0: while(is_addsub(look)) { nuclear@0: emitln("push %%eax"); nuclear@0: switch(look) { nuclear@0: case '+': nuclear@0: add(); nuclear@0: break; nuclear@0: case '-': nuclear@0: sub(); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@3: void assignment(void) nuclear@3: { nuclear@3: char name = get_name(); nuclear@3: match('='); nuclear@3: nuclear@3: if(add_symbol(name, SYM_VAR) == -1) { nuclear@3: stop("variable name '%c' previously defined as another type of symbol\n", name); nuclear@3: } nuclear@3: nuclear@3: expression(); nuclear@3: emitln("mov %%eax, (%c)", name); nuclear@3: } nuclear@3: nuclear@0: void term(void) nuclear@0: { nuclear@0: factor(); nuclear@0: while(look == '*' || look == '/') { nuclear@0: emitln("push %%eax"); nuclear@0: switch(look) { nuclear@0: case '*': nuclear@0: mul(); nuclear@0: break; nuclear@0: case '/': nuclear@0: divide(); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void factor(void) nuclear@0: { nuclear@0: if(look == '(') { nuclear@0: match('('); nuclear@0: expression(); nuclear@0: match(')'); nuclear@3: } else if(isalpha(look)) { nuclear@3: ident(); nuclear@0: } else { nuclear@0: emitln("mov $%c, %%eax", get_num()); nuclear@0: } nuclear@0: } nuclear@0: nuclear@3: void ident() nuclear@3: { nuclear@3: char name = get_name(); nuclear@3: if(look == '(') { nuclear@3: /* function call */ nuclear@3: match('('); nuclear@3: match(')'); nuclear@3: nuclear@3: if(add_symbol(name, SYM_FUNC) == -1) { nuclear@3: stop("function name '%c' previously defined as another type of symbol\n", name); nuclear@3: } nuclear@3: emitln("call %c", name); nuclear@3: } else { nuclear@3: /* variable */ nuclear@3: if(add_symbol(name, SYM_VAR) == -1) { nuclear@3: stop("variable name '%c' previously defined as another type of symbol\n", name); nuclear@3: } nuclear@3: emitln("mov (%c), %%eax", name); nuclear@3: } nuclear@3: } nuclear@3: nuclear@0: void add(void) nuclear@0: { nuclear@0: match('+'); nuclear@0: term(); nuclear@0: emitln("pop %%ebx"); nuclear@0: emitln("add %%ebx, %%eax"); nuclear@0: } nuclear@0: nuclear@0: void sub(void) nuclear@0: { nuclear@0: match('-'); nuclear@0: term(); nuclear@0: emitln("pop %%ebx"); nuclear@0: emitln("sub %%ebx, %%eax"); nuclear@0: emitln("neg %%eax"); nuclear@0: } nuclear@0: nuclear@0: void mul(void) nuclear@0: { nuclear@0: match('*'); nuclear@0: factor(); nuclear@0: emitln("pop %%ebx"); nuclear@0: emitln("imul %%ebx"); nuclear@0: } nuclear@0: nuclear@0: void divide(void) nuclear@0: { nuclear@0: match('/'); nuclear@0: factor(); nuclear@0: emitln("mov %%eax, %%ebx"); nuclear@0: emitln("pop %%eax"); nuclear@0: emitln("idiv %%ebx"); nuclear@0: } nuclear@0: nuclear@0: void get_char(void) nuclear@0: { nuclear@0: look = fgetc(infile); nuclear@0: } nuclear@0: nuclear@0: void match(char c) nuclear@0: { nuclear@0: if(look == c) { nuclear@0: get_char(); nuclear@3: skip_white(); nuclear@0: } else { nuclear@0: char s[2] = {0, 0}; nuclear@0: s[0] = c; nuclear@0: expected(s); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: char get_name(void) nuclear@0: { nuclear@0: char res; nuclear@0: if(!isalpha(look)) { nuclear@0: expected("name"); nuclear@0: } nuclear@0: res = toupper(look); nuclear@0: get_char(); nuclear@3: skip_white(); nuclear@0: return res; nuclear@0: } nuclear@0: nuclear@0: char get_num(void) nuclear@0: { nuclear@0: char res; nuclear@0: if(!isdigit(look)) { nuclear@0: expected("integer"); nuclear@0: } nuclear@0: res = look; nuclear@0: get_char(); nuclear@3: skip_white(); nuclear@0: return res; nuclear@0: } nuclear@0: nuclear@3: void skip_white(void) nuclear@3: { nuclear@3: while(isblank(look)) { nuclear@3: get_char(); nuclear@3: } nuclear@3: } nuclear@3: nuclear@0: void stop(const char *s, ...) nuclear@0: { nuclear@0: va_list ap; nuclear@0: nuclear@0: fprintf(stderr, "error: "); nuclear@0: va_start(ap, s); nuclear@0: vfprintf(stderr, s, ap); nuclear@0: va_end(ap); nuclear@0: fputc('\n', stderr); nuclear@0: nuclear@0: abort(); nuclear@0: } nuclear@0: nuclear@0: void expected(const char *s) nuclear@0: { nuclear@0: stop("%s expected", s); nuclear@0: } nuclear@0: nuclear@0: void emit(const char *fmt, ...) nuclear@0: { nuclear@0: va_list ap; nuclear@0: va_start(ap, fmt); nuclear@0: vemit(fmt, ap); nuclear@0: va_end(ap); nuclear@0: } nuclear@0: nuclear@0: void vemit(const char *fmt, va_list ap) nuclear@0: { nuclear@0: fputc('\t', outfile); nuclear@0: vfprintf(outfile, fmt, ap); nuclear@0: } nuclear@0: nuclear@0: void emitln(const char *fmt, ...) nuclear@0: { nuclear@0: va_list ap; nuclear@0: va_start(ap, fmt); nuclear@0: vemit(fmt, ap); nuclear@0: va_end(ap); nuclear@0: fputc('\n', outfile); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: int is_addsub(char c) nuclear@0: { nuclear@0: return c == '+' || c == '-'; nuclear@0: } nuclear@3: nuclear@3: int add_symbol(char c, int type) nuclear@3: { nuclear@3: struct symbol *sym = symlist; nuclear@3: while(sym) { nuclear@3: if(sym->name == c) { nuclear@3: /* we already have it */ nuclear@3: return sym->type == type ? 0 : -1; nuclear@3: } nuclear@3: sym = sym->next; nuclear@3: } nuclear@3: nuclear@3: if(!(sym = malloc(sizeof *sym))) { nuclear@3: perror("ICE: failed to allocate memory"); nuclear@3: abort(); nuclear@3: } nuclear@3: sym->name = c; nuclear@3: sym->type = type; nuclear@3: sym->next = symlist; nuclear@3: symlist = sym; nuclear@3: return 0; nuclear@3: }