# HG changeset patch # User John Tsiombikas # Date 1426420084 -7200 # Node ID f167a743f34820cb29fc2f2e55fbae07f809b31c # Parent db0630e6a97bcaed8e623c64be2c5f18ea779bb4 tutor3.txt completed minus the multi-char tokens bit diff -r db0630e6a97b -r f167a743f348 src/main.c --- a/src/main.c Sun Mar 15 05:56:33 2015 +0200 +++ b/src/main.c Sun Mar 15 13:48:04 2015 +0200 @@ -3,10 +3,20 @@ #include #include +enum { SYM_VAR, SYM_FUNC }; + +struct symbol { + int type; + char name; + struct symbol *next; +}; + void init(void); void expression(void); +void assignment(void); void term(void); void factor(void); +void ident(); void add(void); void sub(void); void mul(void); @@ -15,16 +25,20 @@ void match(char c); char get_name(void); char get_num(void); +void skip_white(void); void stop(const char *s, ...); void expected(const char *s); void emit(const char *fmt, ...); void vemit(const char *fmt, va_list ap); void emitln(const char *fmt, ...); int is_addsub(char c); +int add_symbol(char c, int type); FILE *infile, *outfile; char look; +struct symbol *symlist; + static const char *prologue = "\t.globl _start\n" "_start:\n" @@ -46,16 +60,30 @@ /* output prologue */ fputs(prologue, outfile); - expression(); + assignment(); + if(look != '\n') { + expected("newline"); + } /* output epilogue */ fputs(epilogue, outfile); + /* write all variable declarations */ + fprintf(outfile, "\t.data\n"); + while(symlist) { + struct symbol *sym = symlist; + symlist = symlist->next; + if(sym->type == SYM_VAR) { + fprintf(outfile, "%c:\t.long 0\n", sym->name); + } + free(sym); + } return 0; } void init(void) { get_char(); + skip_white(); } void expression(void) @@ -75,12 +103,23 @@ case '-': sub(); break; - default: - expected("addop"); } } } +void assignment(void) +{ + char name = get_name(); + match('='); + + if(add_symbol(name, SYM_VAR) == -1) { + stop("variable name '%c' previously defined as another type of symbol\n", name); + } + + expression(); + emitln("mov %%eax, (%c)", name); +} + void term(void) { factor(); @@ -93,8 +132,6 @@ case '/': divide(); break; - default: - expected("mulop"); } } } @@ -105,11 +142,34 @@ match('('); expression(); match(')'); + } else if(isalpha(look)) { + ident(); } else { emitln("mov $%c, %%eax", get_num()); } } +void ident() +{ + char name = get_name(); + if(look == '(') { + /* function call */ + match('('); + match(')'); + + if(add_symbol(name, SYM_FUNC) == -1) { + stop("function name '%c' previously defined as another type of symbol\n", name); + } + emitln("call %c", name); + } else { + /* variable */ + if(add_symbol(name, SYM_VAR) == -1) { + stop("variable name '%c' previously defined as another type of symbol\n", name); + } + emitln("mov (%c), %%eax", name); + } +} + void add(void) { match('+'); @@ -153,6 +213,7 @@ { if(look == c) { get_char(); + skip_white(); } else { char s[2] = {0, 0}; s[0] = c; @@ -168,6 +229,7 @@ } res = toupper(look); get_char(); + skip_white(); return res; } @@ -179,9 +241,17 @@ } res = look; get_char(); + skip_white(); return res; } +void skip_white(void) +{ + while(isblank(look)) { + get_char(); + } +} + void stop(const char *s, ...) { va_list ap; @@ -228,3 +298,25 @@ { return c == '+' || c == '-'; } + +int add_symbol(char c, int type) +{ + struct symbol *sym = symlist; + while(sym) { + if(sym->name == c) { + /* we already have it */ + return sym->type == type ? 0 : -1; + } + sym = sym->next; + } + + if(!(sym = malloc(sizeof *sym))) { + perror("ICE: failed to allocate memory"); + abort(); + } + sym->name = c; + sym->type = type; + sym->next = symlist; + symlist = sym; + return 0; +}