comptut

annotate src/main.c @ 3:f167a743f348

tutor3.txt completed minus the multi-char tokens bit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 15 Mar 2015 13:48:04 +0200
parents 10f07b308aab
children ae1c30fa39f3
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@0 15 void expression(void);
nuclear@3 16 void assignment(void);
nuclear@0 17 void term(void);
nuclear@0 18 void factor(void);
nuclear@3 19 void ident();
nuclear@0 20 void add(void);
nuclear@0 21 void sub(void);
nuclear@0 22 void mul(void);
nuclear@0 23 void divide(void);
nuclear@0 24 void get_char(void);
nuclear@0 25 void match(char c);
nuclear@0 26 char get_name(void);
nuclear@0 27 char get_num(void);
nuclear@3 28 void skip_white(void);
nuclear@0 29 void stop(const char *s, ...);
nuclear@0 30 void expected(const char *s);
nuclear@0 31 void emit(const char *fmt, ...);
nuclear@0 32 void vemit(const char *fmt, va_list ap);
nuclear@0 33 void emitln(const char *fmt, ...);
nuclear@0 34 int is_addsub(char c);
nuclear@3 35 int add_symbol(char c, int type);
nuclear@0 36
nuclear@0 37 FILE *infile, *outfile;
nuclear@0 38 char look;
nuclear@0 39
nuclear@3 40 struct symbol *symlist;
nuclear@3 41
nuclear@0 42 static const char *prologue =
nuclear@0 43 "\t.globl _start\n"
nuclear@0 44 "_start:\n"
nuclear@0 45 "\tcall main\n"
nuclear@0 46 "\tmov %eax, %ebx\n"
nuclear@0 47 "\tmov $1, %eax\n"
nuclear@0 48 "\tint $0x80\n"
nuclear@0 49 "main:\n"
nuclear@0 50 "\t# ---- START ----\n";
nuclear@0 51
nuclear@0 52 static const char *epilogue = "\t# ---- END ----\n\tret\n";
nuclear@0 53
nuclear@0 54 int main(void)
nuclear@0 55 {
nuclear@0 56 infile = stdin;
nuclear@0 57 outfile = stdout;
nuclear@0 58
nuclear@0 59 init();
nuclear@0 60 /* output prologue */
nuclear@0 61 fputs(prologue, outfile);
nuclear@0 62
nuclear@3 63 assignment();
nuclear@3 64 if(look != '\n') {
nuclear@3 65 expected("newline");
nuclear@3 66 }
nuclear@0 67
nuclear@0 68 /* output epilogue */
nuclear@0 69 fputs(epilogue, outfile);
nuclear@3 70 /* write all variable declarations */
nuclear@3 71 fprintf(outfile, "\t.data\n");
nuclear@3 72 while(symlist) {
nuclear@3 73 struct symbol *sym = symlist;
nuclear@3 74 symlist = symlist->next;
nuclear@3 75 if(sym->type == SYM_VAR) {
nuclear@3 76 fprintf(outfile, "%c:\t.long 0\n", sym->name);
nuclear@3 77 }
nuclear@3 78 free(sym);
nuclear@3 79 }
nuclear@0 80 return 0;
nuclear@0 81 }
nuclear@0 82
nuclear@0 83 void init(void)
nuclear@0 84 {
nuclear@0 85 get_char();
nuclear@3 86 skip_white();
nuclear@0 87 }
nuclear@0 88
nuclear@0 89 void expression(void)
nuclear@0 90 {
nuclear@0 91 if(is_addsub(look)) {
nuclear@0 92 emitln("xor %%eax, %%eax");
nuclear@0 93 } else {
nuclear@0 94 term();
nuclear@0 95 }
nuclear@0 96
nuclear@0 97 while(is_addsub(look)) {
nuclear@0 98 emitln("push %%eax");
nuclear@0 99 switch(look) {
nuclear@0 100 case '+':
nuclear@0 101 add();
nuclear@0 102 break;
nuclear@0 103 case '-':
nuclear@0 104 sub();
nuclear@0 105 break;
nuclear@0 106 }
nuclear@0 107 }
nuclear@0 108 }
nuclear@0 109
nuclear@3 110 void assignment(void)
nuclear@3 111 {
nuclear@3 112 char name = get_name();
nuclear@3 113 match('=');
nuclear@3 114
nuclear@3 115 if(add_symbol(name, SYM_VAR) == -1) {
nuclear@3 116 stop("variable name '%c' previously defined as another type of symbol\n", name);
nuclear@3 117 }
nuclear@3 118
nuclear@3 119 expression();
nuclear@3 120 emitln("mov %%eax, (%c)", name);
nuclear@3 121 }
nuclear@3 122
nuclear@0 123 void term(void)
nuclear@0 124 {
nuclear@0 125 factor();
nuclear@0 126 while(look == '*' || look == '/') {
nuclear@0 127 emitln("push %%eax");
nuclear@0 128 switch(look) {
nuclear@0 129 case '*':
nuclear@0 130 mul();
nuclear@0 131 break;
nuclear@0 132 case '/':
nuclear@0 133 divide();
nuclear@0 134 break;
nuclear@0 135 }
nuclear@0 136 }
nuclear@0 137 }
nuclear@0 138
nuclear@0 139 void factor(void)
nuclear@0 140 {
nuclear@0 141 if(look == '(') {
nuclear@0 142 match('(');
nuclear@0 143 expression();
nuclear@0 144 match(')');
nuclear@3 145 } else if(isalpha(look)) {
nuclear@3 146 ident();
nuclear@0 147 } else {
nuclear@0 148 emitln("mov $%c, %%eax", get_num());
nuclear@0 149 }
nuclear@0 150 }
nuclear@0 151
nuclear@3 152 void ident()
nuclear@3 153 {
nuclear@3 154 char name = get_name();
nuclear@3 155 if(look == '(') {
nuclear@3 156 /* function call */
nuclear@3 157 match('(');
nuclear@3 158 match(')');
nuclear@3 159
nuclear@3 160 if(add_symbol(name, SYM_FUNC) == -1) {
nuclear@3 161 stop("function name '%c' previously defined as another type of symbol\n", name);
nuclear@3 162 }
nuclear@3 163 emitln("call %c", name);
nuclear@3 164 } else {
nuclear@3 165 /* variable */
nuclear@3 166 if(add_symbol(name, SYM_VAR) == -1) {
nuclear@3 167 stop("variable name '%c' previously defined as another type of symbol\n", name);
nuclear@3 168 }
nuclear@3 169 emitln("mov (%c), %%eax", name);
nuclear@3 170 }
nuclear@3 171 }
nuclear@3 172
nuclear@0 173 void add(void)
nuclear@0 174 {
nuclear@0 175 match('+');
nuclear@0 176 term();
nuclear@0 177 emitln("pop %%ebx");
nuclear@0 178 emitln("add %%ebx, %%eax");
nuclear@0 179 }
nuclear@0 180
nuclear@0 181 void sub(void)
nuclear@0 182 {
nuclear@0 183 match('-');
nuclear@0 184 term();
nuclear@0 185 emitln("pop %%ebx");
nuclear@0 186 emitln("sub %%ebx, %%eax");
nuclear@0 187 emitln("neg %%eax");
nuclear@0 188 }
nuclear@0 189
nuclear@0 190 void mul(void)
nuclear@0 191 {
nuclear@0 192 match('*');
nuclear@0 193 factor();
nuclear@0 194 emitln("pop %%ebx");
nuclear@0 195 emitln("imul %%ebx");
nuclear@0 196 }
nuclear@0 197
nuclear@0 198 void divide(void)
nuclear@0 199 {
nuclear@0 200 match('/');
nuclear@0 201 factor();
nuclear@0 202 emitln("mov %%eax, %%ebx");
nuclear@0 203 emitln("pop %%eax");
nuclear@0 204 emitln("idiv %%ebx");
nuclear@0 205 }
nuclear@0 206
nuclear@0 207 void get_char(void)
nuclear@0 208 {
nuclear@0 209 look = fgetc(infile);
nuclear@0 210 }
nuclear@0 211
nuclear@0 212 void match(char c)
nuclear@0 213 {
nuclear@0 214 if(look == c) {
nuclear@0 215 get_char();
nuclear@3 216 skip_white();
nuclear@0 217 } else {
nuclear@0 218 char s[2] = {0, 0};
nuclear@0 219 s[0] = c;
nuclear@0 220 expected(s);
nuclear@0 221 }
nuclear@0 222 }
nuclear@0 223
nuclear@0 224 char get_name(void)
nuclear@0 225 {
nuclear@0 226 char res;
nuclear@0 227 if(!isalpha(look)) {
nuclear@0 228 expected("name");
nuclear@0 229 }
nuclear@0 230 res = toupper(look);
nuclear@0 231 get_char();
nuclear@3 232 skip_white();
nuclear@0 233 return res;
nuclear@0 234 }
nuclear@0 235
nuclear@0 236 char get_num(void)
nuclear@0 237 {
nuclear@0 238 char res;
nuclear@0 239 if(!isdigit(look)) {
nuclear@0 240 expected("integer");
nuclear@0 241 }
nuclear@0 242 res = look;
nuclear@0 243 get_char();
nuclear@3 244 skip_white();
nuclear@0 245 return res;
nuclear@0 246 }
nuclear@0 247
nuclear@3 248 void skip_white(void)
nuclear@3 249 {
nuclear@3 250 while(isblank(look)) {
nuclear@3 251 get_char();
nuclear@3 252 }
nuclear@3 253 }
nuclear@3 254
nuclear@0 255 void stop(const char *s, ...)
nuclear@0 256 {
nuclear@0 257 va_list ap;
nuclear@0 258
nuclear@0 259 fprintf(stderr, "error: ");
nuclear@0 260 va_start(ap, s);
nuclear@0 261 vfprintf(stderr, s, ap);
nuclear@0 262 va_end(ap);
nuclear@0 263 fputc('\n', stderr);
nuclear@0 264
nuclear@0 265 abort();
nuclear@0 266 }
nuclear@0 267
nuclear@0 268 void expected(const char *s)
nuclear@0 269 {
nuclear@0 270 stop("%s expected", s);
nuclear@0 271 }
nuclear@0 272
nuclear@0 273 void emit(const char *fmt, ...)
nuclear@0 274 {
nuclear@0 275 va_list ap;
nuclear@0 276 va_start(ap, fmt);
nuclear@0 277 vemit(fmt, ap);
nuclear@0 278 va_end(ap);
nuclear@0 279 }
nuclear@0 280
nuclear@0 281 void vemit(const char *fmt, va_list ap)
nuclear@0 282 {
nuclear@0 283 fputc('\t', outfile);
nuclear@0 284 vfprintf(outfile, fmt, ap);
nuclear@0 285 }
nuclear@0 286
nuclear@0 287 void emitln(const char *fmt, ...)
nuclear@0 288 {
nuclear@0 289 va_list ap;
nuclear@0 290 va_start(ap, fmt);
nuclear@0 291 vemit(fmt, ap);
nuclear@0 292 va_end(ap);
nuclear@0 293 fputc('\n', outfile);
nuclear@0 294 }
nuclear@0 295
nuclear@0 296
nuclear@0 297 int is_addsub(char c)
nuclear@0 298 {
nuclear@0 299 return c == '+' || c == '-';
nuclear@0 300 }
nuclear@3 301
nuclear@3 302 int add_symbol(char c, int type)
nuclear@3 303 {
nuclear@3 304 struct symbol *sym = symlist;
nuclear@3 305 while(sym) {
nuclear@3 306 if(sym->name == c) {
nuclear@3 307 /* we already have it */
nuclear@3 308 return sym->type == type ? 0 : -1;
nuclear@3 309 }
nuclear@3 310 sym = sym->next;
nuclear@3 311 }
nuclear@3 312
nuclear@3 313 if(!(sym = malloc(sizeof *sym))) {
nuclear@3 314 perror("ICE: failed to allocate memory");
nuclear@3 315 abort();
nuclear@3 316 }
nuclear@3 317 sym->name = c;
nuclear@3 318 sym->type = type;
nuclear@3 319 sym->next = symlist;
nuclear@3 320 symlist = sym;
nuclear@3 321 return 0;
nuclear@3 322 }