comptut

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