gen: use regop() for shift instructions
[neatcc.git] / cc.c
blob5102528a81bbba1577e0ddc00621d46032dd21d8
1 #include <fcntl.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include "gen.h"
8 #include "tok.h"
10 #define MAXLOCALS (1 << 10)
11 #define MAXARGS (1 << 5)
12 #define print(s) write(2, (s), strlen(s));
14 #define TYPE_BT(t) ((t)->ptr ? 8 : (t)->bt)
15 #define TYPE_SZ(t) ((t)->ptr ? 8 : (t)->bt & BT_SZMASK)
16 #define TYPE_DEREF_BT(t) ((t)->ptr > 1 ? 8 : (t)->bt)
17 #define TYPE_DEREF_SZ(t) ((t)->ptr > 1 ? 8 : (t)->bt & BT_SZMASK)
19 #define T_ARRAY 0x01
21 struct type {
22 unsigned bt;
23 unsigned flags;
24 int ptr;
27 /* type stack */
28 static struct type ts[MAXTMP];
29 static int nts;
31 static void ts_push_bt(unsigned bt)
33 ts[nts].ptr = 0;
34 ts[nts].flags = 0;
35 ts[nts++].bt = bt;
38 static void ts_push(struct type *type)
40 ts[nts++] = *type;
43 static void ts_pop(struct type *type)
45 nts--;
46 if (type)
47 *type = ts[nts];
50 static struct local {
51 char name[NAMELEN];
52 long addr;
53 struct type type;
54 } locals[MAXLOCALS];
55 static int nlocals;
57 static void local_add(char *name, long addr, struct type type)
59 strcpy(locals[nlocals].name, name);
60 locals[nlocals].addr = addr;
61 locals[nlocals].type = type;
62 nlocals++;
65 static void die(char *s)
67 print(s);
68 exit(1);
71 static int tok_jmp(int tok)
73 if (tok_see() != tok)
74 return 1;
75 tok_get();
76 return 0;
79 static void tok_expect(int tok)
81 if (tok_get() != tok)
82 die("syntax error\n");
85 static void readexpr(void);
87 static int basetype(struct type *type)
89 int sign = 1;
90 int size = 4;
91 int done = 0;
92 int i = 0;
93 while (!done) {
94 switch (tok_see()) {
95 case TOK_VOID:
96 sign = 0;
97 size = 0;
98 done = 1;
99 break;
100 case TOK_INT:
101 done = 1;
102 break;
103 case TOK_CHAR:
104 size = 1;
105 done = 1;
106 break;
107 case TOK_SHORT:
108 size = 2;
109 break;
110 case TOK_LONG:
111 size = 8;
112 break;
113 case TOK_UNSIGNED:
114 sign = 0;
115 break;
116 case TOK_ENUM:
117 case TOK_STRUCT:
118 tok_expect(TOK_NAME);
119 done = 1;
120 break;
121 default:
122 if (!i)
123 return 1;
124 done = 1;
125 continue;
127 i++;
128 tok_get();
130 type->bt = size | (sign ? BT_SIGNED : 0);
131 type->ptr = 0;
132 return 0;
135 static void readptrs(struct type *type)
137 while (!tok_jmp('*'))
138 type->ptr++;
141 static int readtype(struct type *type)
143 if (basetype(type))
144 return 1;
145 readptrs(type);
146 return 0;
149 static void readprimary(void)
151 int i;
152 if (!tok_jmp(TOK_NUM)) {
153 ts_push_bt(4 | BT_SIGNED);
154 o_num(atoi(tok_id()), 4 | BT_SIGNED);
155 return;
157 if (!tok_jmp(TOK_NAME)) {
158 for (i = 0; i < nlocals; i++) {
159 struct type *t = &locals[nlocals - 1].type;
160 if (!strcmp(locals[i].name, tok_id())) {
161 ts_push(t);
162 o_local(locals[i].addr, TYPE_BT(t));
163 if (t->flags & T_ARRAY)
164 o_addr();
165 return;
168 ts_push_bt(8);
169 o_symaddr(tok_id(), 8);
170 return;
172 if (!tok_jmp('(')) {
173 readexpr();
174 tok_expect(')');
175 return;
179 static void readpost(void)
181 readprimary();
182 if (!tok_jmp('[')) {
183 struct type t1;
184 ts_pop(&t1);
185 readexpr();
186 ts_pop(NULL);
187 tok_expect(']');
188 o_arrayderef(TYPE_DEREF_BT(&t1));
189 t1.ptr--;
190 ts_push(&t1);
191 return;
193 if (!tok_jmp('(')) {
194 int argc = 0;
195 unsigned bt[MAXARGS];
196 if (tok_see() != ')') {
197 readexpr();
198 bt[argc++] = 4 | BT_SIGNED;
199 ts_pop(NULL);
201 while (!tok_jmp(',')) {
202 readexpr();
203 bt[argc++] = 4 | BT_SIGNED;
204 ts_pop(NULL);
206 tok_expect(')');
207 ts_pop(NULL);
208 o_call(argc, bt, 4 | BT_SIGNED);
209 ts_push_bt(4 | BT_SIGNED);
213 static void readpre(void)
215 if (!tok_jmp('&')) {
216 struct type type;
217 readpost();
218 ts_pop(&type);
219 type.ptr++;
220 ts_push(&type);
221 o_addr();
222 return;
224 if (!tok_jmp('*')) {
225 struct type type;
226 readpost();
227 ts_pop(&type);
228 type.ptr--;
229 ts_push(&type);
230 o_deref(TYPE_BT(&type));
231 return;
233 readpost();
236 static void shifts(int n)
238 int i = -1;
239 while (i++ < 16)
240 if (n == 1 << i)
241 break;
242 return i;
245 static void ts_binop(void (*o_sth)(void))
247 struct type t1, t2;
248 ts_pop(&t1);
249 ts_pop(&t2);
250 if (t1.ptr && !t2.ptr) {
251 struct type t = t2;
252 t2 = t1;
253 t1 = t;
254 o_tmpswap();
256 if (!t1.ptr && t2.ptr)
257 if (TYPE_DEREF_SZ(&t2) > 1) {
258 o_num(shifts(TYPE_DEREF_SZ(&t2)), 1);
259 o_shl();
261 o_sth();
262 if (t1.ptr && t2.ptr) {
263 o_num(shifts(TYPE_DEREF_SZ(&t1)), 1);
264 o_shr();
265 ts_push_bt(4 | BT_SIGNED);
266 } else {
267 ts_push(&t2);
271 static void readadd(void)
273 readpre();
274 while (1) {
275 if (!tok_jmp('+')) {
276 readpre();
277 ts_binop(o_add);
278 continue;
280 if (!tok_jmp('-')) {
281 readpre();
282 ts_binop(o_sub);
283 continue;
285 break;
289 static void readcexpr(void)
291 readadd();
292 if (!tok_jmp('?')) {
293 long l2;
294 long l1 = o_jzstub();
295 readadd();
296 l2 = o_jmpstub();
297 tok_expect(':');
298 o_filljmp(l1);
299 /* this is needed to fix tmp stack position */
300 o_droptmp(1);
301 readadd();
302 o_filljmp(l2);
306 static void readexpr(void)
308 readcexpr();
309 if (!tok_jmp('=')) {
310 readexpr();
311 o_assign(4 | BT_SIGNED);
315 static void readstmt(void)
317 struct type base = {0};
318 o_droptmp(-1);
319 nts = 0;
320 if (!tok_jmp('{')) {
321 while (tok_jmp('}'))
322 readstmt();
323 return;
325 if (!basetype(&base)) {
326 struct type type = base;
327 char name[NAMELEN];
328 int n = 1;
329 readptrs(&type);
330 tok_expect(TOK_NAME);
331 strcpy(name, tok_id());
332 if (!tok_jmp('[')) {
333 tok_expect(TOK_NUM);
334 n = atoi(tok_id());
335 type.ptr++;
336 type.flags = T_ARRAY;
337 tok_expect(']');
339 local_add(name, o_mklocal(TYPE_SZ(&type) * n), type);
340 /* initializer */
341 if (!tok_jmp('=')) {
342 struct type *t = &locals[nlocals - 1].type;
343 o_local(locals[nlocals - 1].addr, TYPE_BT(t));
344 readexpr();
345 ts_pop(NULL);
346 ts_push_bt(TYPE_BT(t));
347 o_assign(TYPE_BT(t));
348 tok_expect(';');
350 return;
352 if (!tok_jmp(TOK_IF)) {
353 long l1, l2;
354 tok_expect('(');
355 readexpr();
356 tok_expect(')');
357 l1 = o_jzstub();
358 readstmt();
359 if (!tok_jmp(TOK_ELSE)) {
360 l2 = o_jmpstub();
361 o_filljmp(l1);
362 readstmt();
363 o_filljmp(l2);
364 } else {
365 o_filljmp(l1);
367 return;
369 if (!tok_jmp(TOK_WHILE)) {
370 long l1, l2;
371 l1 = o_mklabel();
372 tok_expect('(');
373 readexpr();
374 tok_expect(')');
375 l2 = o_jzstub();
376 readstmt();
377 o_jz(l1);
378 o_filljmp(l2);
379 return;
381 if (!tok_jmp(TOK_RETURN)) {
382 int ret = tok_see() != ';';
383 if (ret)
384 readexpr();
385 tok_expect(';');
386 o_ret(4 | BT_SIGNED);
387 return;
389 readexpr();
390 tok_expect(';');
393 static void readdecl(void)
395 char name[NAMELEN];
396 struct type type;
397 readtype(&type);
398 tok_expect(TOK_NAME);
399 strcpy(name, tok_id());
400 if (!tok_jmp(';'))
401 return;
402 if (!tok_jmp('(')) {
403 /* read args */
404 char args[MAXARGS][NAMELEN];
405 struct type types[MAXARGS];
406 int nargs = 0;
407 int i;
408 while (tok_see() != ')') {
409 readtype(&types[nargs]);
410 if (!tok_jmp(TOK_NAME))
411 strcpy(args[nargs++], tok_id());
412 if (tok_jmp(','))
413 break;
415 tok_expect(')');
416 if (!tok_jmp(';'))
417 return;
418 o_func_beg(name);
419 for (i = 0; i < nargs; i++)
420 local_add(args[i], o_arg(i, TYPE_BT(&types[i])),
421 types[i]);
422 readstmt();
423 o_func_end();
424 return;
426 die("syntax error\n");
429 static void parse(void)
431 while (tok_see() != TOK_EOF)
432 readdecl();
435 int main(int argc, char *argv[])
437 char obj[128];
438 char *src = argv[1];
439 int ifd, ofd;
440 ifd = open(src, O_RDONLY);
441 tok_init(ifd);
442 close(ifd);
443 parse();
445 strcpy(obj, src);
446 obj[strlen(obj) - 1] = 'o';
447 ofd = open(obj, O_WRONLY | O_TRUNC | O_CREAT, 0600);
448 out_write(ofd);
449 close(ofd);
450 return 0;