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@0
|
6 void init(void);
|
nuclear@0
|
7 void expression(void);
|
nuclear@0
|
8 void term(void);
|
nuclear@0
|
9 void factor(void);
|
nuclear@0
|
10 void add(void);
|
nuclear@0
|
11 void sub(void);
|
nuclear@0
|
12 void mul(void);
|
nuclear@0
|
13 void divide(void);
|
nuclear@0
|
14 void get_char(void);
|
nuclear@0
|
15 void match(char c);
|
nuclear@0
|
16 char get_name(void);
|
nuclear@0
|
17 char get_num(void);
|
nuclear@0
|
18 void stop(const char *s, ...);
|
nuclear@0
|
19 void expected(const char *s);
|
nuclear@0
|
20 void emit(const char *fmt, ...);
|
nuclear@0
|
21 void vemit(const char *fmt, va_list ap);
|
nuclear@0
|
22 void emitln(const char *fmt, ...);
|
nuclear@0
|
23 int is_addsub(char c);
|
nuclear@0
|
24
|
nuclear@0
|
25 FILE *infile, *outfile;
|
nuclear@0
|
26 char look;
|
nuclear@0
|
27
|
nuclear@0
|
28 static const char *prologue =
|
nuclear@0
|
29 "\t.globl _start\n"
|
nuclear@0
|
30 "_start:\n"
|
nuclear@0
|
31 "\tcall main\n"
|
nuclear@0
|
32 "\tmov %eax, %ebx\n"
|
nuclear@0
|
33 "\tmov $1, %eax\n"
|
nuclear@0
|
34 "\tint $0x80\n"
|
nuclear@0
|
35 "main:\n"
|
nuclear@0
|
36 "\t# ---- START ----\n";
|
nuclear@0
|
37
|
nuclear@0
|
38 static const char *epilogue = "\t# ---- END ----\n\tret\n";
|
nuclear@0
|
39
|
nuclear@0
|
40 int main(void)
|
nuclear@0
|
41 {
|
nuclear@0
|
42 infile = stdin;
|
nuclear@0
|
43 outfile = stdout;
|
nuclear@0
|
44
|
nuclear@0
|
45 init();
|
nuclear@0
|
46 /* output prologue */
|
nuclear@0
|
47 fputs(prologue, outfile);
|
nuclear@0
|
48
|
nuclear@0
|
49 expression();
|
nuclear@0
|
50
|
nuclear@0
|
51 /* output epilogue */
|
nuclear@0
|
52 fputs(epilogue, outfile);
|
nuclear@0
|
53 return 0;
|
nuclear@0
|
54 }
|
nuclear@0
|
55
|
nuclear@0
|
56 void init(void)
|
nuclear@0
|
57 {
|
nuclear@0
|
58 get_char();
|
nuclear@0
|
59 }
|
nuclear@0
|
60
|
nuclear@0
|
61 void expression(void)
|
nuclear@0
|
62 {
|
nuclear@0
|
63 if(is_addsub(look)) {
|
nuclear@0
|
64 emitln("xor %%eax, %%eax");
|
nuclear@0
|
65 } else {
|
nuclear@0
|
66 term();
|
nuclear@0
|
67 }
|
nuclear@0
|
68
|
nuclear@0
|
69 while(is_addsub(look)) {
|
nuclear@0
|
70 emitln("push %%eax");
|
nuclear@0
|
71 switch(look) {
|
nuclear@0
|
72 case '+':
|
nuclear@0
|
73 add();
|
nuclear@0
|
74 break;
|
nuclear@0
|
75 case '-':
|
nuclear@0
|
76 sub();
|
nuclear@0
|
77 break;
|
nuclear@0
|
78 default:
|
nuclear@0
|
79 expected("addop");
|
nuclear@0
|
80 }
|
nuclear@0
|
81 }
|
nuclear@0
|
82 }
|
nuclear@0
|
83
|
nuclear@0
|
84 void term(void)
|
nuclear@0
|
85 {
|
nuclear@0
|
86 factor();
|
nuclear@0
|
87 while(look == '*' || look == '/') {
|
nuclear@0
|
88 emitln("push %%eax");
|
nuclear@0
|
89 switch(look) {
|
nuclear@0
|
90 case '*':
|
nuclear@0
|
91 mul();
|
nuclear@0
|
92 break;
|
nuclear@0
|
93 case '/':
|
nuclear@0
|
94 divide();
|
nuclear@0
|
95 break;
|
nuclear@0
|
96 default:
|
nuclear@0
|
97 expected("mulop");
|
nuclear@0
|
98 }
|
nuclear@0
|
99 }
|
nuclear@0
|
100 }
|
nuclear@0
|
101
|
nuclear@0
|
102 void factor(void)
|
nuclear@0
|
103 {
|
nuclear@0
|
104 if(look == '(') {
|
nuclear@0
|
105 match('(');
|
nuclear@0
|
106 expression();
|
nuclear@0
|
107 match(')');
|
nuclear@0
|
108 } else {
|
nuclear@0
|
109 emitln("mov $%c, %%eax", get_num());
|
nuclear@0
|
110 }
|
nuclear@0
|
111 }
|
nuclear@0
|
112
|
nuclear@0
|
113 void add(void)
|
nuclear@0
|
114 {
|
nuclear@0
|
115 match('+');
|
nuclear@0
|
116 term();
|
nuclear@0
|
117 emitln("pop %%ebx");
|
nuclear@0
|
118 emitln("add %%ebx, %%eax");
|
nuclear@0
|
119 }
|
nuclear@0
|
120
|
nuclear@0
|
121 void sub(void)
|
nuclear@0
|
122 {
|
nuclear@0
|
123 match('-');
|
nuclear@0
|
124 term();
|
nuclear@0
|
125 emitln("pop %%ebx");
|
nuclear@0
|
126 emitln("sub %%ebx, %%eax");
|
nuclear@0
|
127 emitln("neg %%eax");
|
nuclear@0
|
128 }
|
nuclear@0
|
129
|
nuclear@0
|
130 void mul(void)
|
nuclear@0
|
131 {
|
nuclear@0
|
132 match('*');
|
nuclear@0
|
133 factor();
|
nuclear@0
|
134 emitln("pop %%ebx");
|
nuclear@0
|
135 emitln("imul %%ebx");
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 void divide(void)
|
nuclear@0
|
139 {
|
nuclear@0
|
140 match('/');
|
nuclear@0
|
141 factor();
|
nuclear@0
|
142 emitln("mov %%eax, %%ebx");
|
nuclear@0
|
143 emitln("pop %%eax");
|
nuclear@0
|
144 emitln("idiv %%ebx");
|
nuclear@0
|
145 }
|
nuclear@0
|
146
|
nuclear@0
|
147 void get_char(void)
|
nuclear@0
|
148 {
|
nuclear@0
|
149 look = fgetc(infile);
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 void match(char c)
|
nuclear@0
|
153 {
|
nuclear@0
|
154 if(look == c) {
|
nuclear@0
|
155 get_char();
|
nuclear@0
|
156 } else {
|
nuclear@0
|
157 char s[2] = {0, 0};
|
nuclear@0
|
158 s[0] = c;
|
nuclear@0
|
159 expected(s);
|
nuclear@0
|
160 }
|
nuclear@0
|
161 }
|
nuclear@0
|
162
|
nuclear@0
|
163 char get_name(void)
|
nuclear@0
|
164 {
|
nuclear@0
|
165 char res;
|
nuclear@0
|
166 if(!isalpha(look)) {
|
nuclear@0
|
167 expected("name");
|
nuclear@0
|
168 }
|
nuclear@0
|
169 res = toupper(look);
|
nuclear@0
|
170 get_char();
|
nuclear@0
|
171 return res;
|
nuclear@0
|
172 }
|
nuclear@0
|
173
|
nuclear@0
|
174 char get_num(void)
|
nuclear@0
|
175 {
|
nuclear@0
|
176 char res;
|
nuclear@0
|
177 if(!isdigit(look)) {
|
nuclear@0
|
178 expected("integer");
|
nuclear@0
|
179 }
|
nuclear@0
|
180 res = look;
|
nuclear@0
|
181 get_char();
|
nuclear@0
|
182 return res;
|
nuclear@0
|
183 }
|
nuclear@0
|
184
|
nuclear@0
|
185 void stop(const char *s, ...)
|
nuclear@0
|
186 {
|
nuclear@0
|
187 va_list ap;
|
nuclear@0
|
188
|
nuclear@0
|
189 fprintf(stderr, "error: ");
|
nuclear@0
|
190 va_start(ap, s);
|
nuclear@0
|
191 vfprintf(stderr, s, ap);
|
nuclear@0
|
192 va_end(ap);
|
nuclear@0
|
193 fputc('\n', stderr);
|
nuclear@0
|
194
|
nuclear@0
|
195 abort();
|
nuclear@0
|
196 }
|
nuclear@0
|
197
|
nuclear@0
|
198 void expected(const char *s)
|
nuclear@0
|
199 {
|
nuclear@0
|
200 stop("%s expected", s);
|
nuclear@0
|
201 }
|
nuclear@0
|
202
|
nuclear@0
|
203 void emit(const char *fmt, ...)
|
nuclear@0
|
204 {
|
nuclear@0
|
205 va_list ap;
|
nuclear@0
|
206 va_start(ap, fmt);
|
nuclear@0
|
207 vemit(fmt, ap);
|
nuclear@0
|
208 va_end(ap);
|
nuclear@0
|
209 }
|
nuclear@0
|
210
|
nuclear@0
|
211 void vemit(const char *fmt, va_list ap)
|
nuclear@0
|
212 {
|
nuclear@0
|
213 fputc('\t', outfile);
|
nuclear@0
|
214 vfprintf(outfile, fmt, ap);
|
nuclear@0
|
215 }
|
nuclear@0
|
216
|
nuclear@0
|
217 void emitln(const char *fmt, ...)
|
nuclear@0
|
218 {
|
nuclear@0
|
219 va_list ap;
|
nuclear@0
|
220 va_start(ap, fmt);
|
nuclear@0
|
221 vemit(fmt, ap);
|
nuclear@0
|
222 va_end(ap);
|
nuclear@0
|
223 fputc('\n', outfile);
|
nuclear@0
|
224 }
|
nuclear@0
|
225
|
nuclear@0
|
226
|
nuclear@0
|
227 int is_addsub(char c)
|
nuclear@0
|
228 {
|
nuclear@0
|
229 return c == '+' || c == '-';
|
nuclear@0
|
230 }
|