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 }
|