qbe

Internal scc patchset buffer for QBE
Log | Files | Refs | README | LICENSE

minic.y (15819B)


      1 %{
      2 
      3 #include <ctype.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 
      8 enum {
      9 	NString = 32,
     10 	NGlo = 256,
     11 	NVar = 512,
     12 	NStr = 256,
     13 };
     14 
     15 enum { /* minic types */
     16 	NIL,
     17 	INT,
     18 	LNG,
     19 	PTR,
     20 	FUN,
     21 };
     22 
     23 #define IDIR(x) (((x) << 3) + PTR)
     24 #define FUNC(x) (((x) << 3) + FUN)
     25 #define DREF(x) ((x) >> 3)
     26 #define KIND(x) ((x) & 7)
     27 #define SIZE(x)                                    \
     28 	(x == NIL ? (die("void has no size"), 0) : \
     29 	 x == INT ? 4 : 8)
     30 
     31 typedef struct Node Node;
     32 typedef struct Symb Symb;
     33 typedef struct Stmt Stmt;
     34 
     35 struct Symb {
     36 	enum {
     37 		Con,
     38 		Tmp,
     39 		Var,
     40 		Glo,
     41 	} t;
     42 	union {
     43 		int n;
     44 		char v[NString];
     45 	} u;
     46 	unsigned long ctyp;
     47 };
     48 
     49 struct Node {
     50 	char op;
     51 	union {
     52 		int n;
     53 		char v[NString];
     54 		Symb s;
     55 	} u;
     56 	Node *l, *r;
     57 };
     58 
     59 struct Stmt {
     60 	enum {
     61 		If,
     62 		While,
     63 		Seq,
     64 		Expr,
     65 		Break,
     66 		Ret,
     67 	} t;
     68 	void *p1, *p2, *p3;
     69 };
     70 
     71 int yylex(void), yyerror(char *);
     72 Symb expr(Node *), lval(Node *);
     73 void bool(Node *, int, int);
     74 
     75 FILE *of;
     76 int line;
     77 int lbl, tmp, nglo;
     78 char *ini[NGlo];
     79 struct {
     80 	char v[NString];
     81 	unsigned ctyp;
     82 	int glo;
     83 } varh[NVar];
     84 
     85 void
     86 die(char *s)
     87 {
     88 	fprintf(stderr, "error:%d: %s\n", line, s);
     89 	exit(1);
     90 }
     91 
     92 void *
     93 alloc(size_t s)
     94 {
     95 	void *p;
     96 
     97 	p = malloc(s);
     98 	if (!p)
     99 		die("out of memory");
    100 	return p;
    101 }
    102 
    103 unsigned
    104 hash(char *s)
    105 {
    106 	unsigned h;
    107 
    108 	h = 42;
    109 	while (*s)
    110 		h += 11 * h + *s++;
    111 	return h % NVar;
    112 }
    113 
    114 void
    115 varclr()
    116 {
    117 	unsigned h;
    118 
    119 	for (h=0; h<NVar; h++)
    120 		if (!varh[h].glo)
    121 			varh[h].v[0] = 0;
    122 }
    123 
    124 void
    125 varadd(char *v, int glo, unsigned ctyp)
    126 {
    127 	unsigned h0, h;
    128 
    129 	h0 = hash(v);
    130 	h = h0;
    131 	do {
    132 		if (varh[h].v[0] == 0) {
    133 			strcpy(varh[h].v, v);
    134 			varh[h].glo = glo;
    135 			varh[h].ctyp = ctyp;
    136 			return;
    137 		}
    138 		if (strcmp(varh[h].v, v) == 0)
    139 			die("double definition");
    140 		h = (h+1) % NVar;
    141 	} while(h != h0);
    142 	die("too many variables");
    143 }
    144 
    145 Symb *
    146 varget(char *v)
    147 {
    148 	static Symb s;
    149 	unsigned h0, h;
    150 
    151 	h0 = hash(v);
    152 	h = h0;
    153 	do {
    154 		if (strcmp(varh[h].v, v) == 0) {
    155 			if (!varh[h].glo) {
    156 				s.t = Var;
    157 				strcpy(s.u.v, v);
    158 			} else {
    159 				s.t = Glo;
    160 				s.u.n = varh[h].glo;
    161 			}
    162 			s.ctyp = varh[h].ctyp;
    163 			return &s;
    164 		}
    165 		h = (h+1) % NVar;
    166 	} while (h != h0 && varh[h].v[0] != 0);
    167 	return 0;
    168 }
    169 
    170 char
    171 irtyp(unsigned ctyp)
    172 {
    173 	return SIZE(ctyp) == 8 ? 'l' : 'w';
    174 }
    175 
    176 void
    177 psymb(Symb s)
    178 {
    179 	switch (s.t) {
    180 	case Tmp:
    181 		fprintf(of, "%%t%d", s.u.n);
    182 		break;
    183 	case Var:
    184 		fprintf(of, "%%%s", s.u.v);
    185 		break;
    186 	case Glo:
    187 		fprintf(of, "$glo%d", s.u.n);
    188 		break;
    189 	case Con:
    190 		fprintf(of, "%d", s.u.n);
    191 		break;
    192 	}
    193 }
    194 
    195 void
    196 sext(Symb *s)
    197 {
    198 	fprintf(of, "\t%%t%d =l extsw ", tmp);
    199 	psymb(*s);
    200 	fprintf(of, "\n");
    201 	s->t = Tmp;
    202 	s->ctyp = LNG;
    203 	s->u.n = tmp++;
    204 }
    205 
    206 unsigned
    207 prom(int op, Symb *l, Symb *r)
    208 {
    209 	Symb *t;
    210 	int sz;
    211 
    212 	if (l->ctyp == r->ctyp && KIND(l->ctyp) != PTR)
    213 		return l->ctyp;
    214 
    215 	if (l->ctyp == LNG && r->ctyp == INT) {
    216 		sext(r);
    217 		return LNG;
    218 	}
    219 	if (l->ctyp == INT && r->ctyp == LNG) {
    220 		sext(l);
    221 		return LNG;
    222 	}
    223 
    224 	if (op == '+') {
    225 		if (KIND(r->ctyp) == PTR) {
    226 			t = l;
    227 			l = r;
    228 			r = t;
    229 		}
    230 		if (KIND(r->ctyp) == PTR)
    231 			die("pointers added");
    232 		goto Scale;
    233 	}
    234 
    235 	if (op == '-') {
    236 		if (KIND(l->ctyp) != PTR)
    237 			die("pointer substracted from integer");
    238 		if (KIND(r->ctyp) != PTR)
    239 			goto Scale;
    240 		if (l->ctyp != r->ctyp)
    241 			die("non-homogeneous pointers in substraction");
    242 		return LNG;
    243 	}
    244 
    245 Scale:
    246 	sz = SIZE(DREF(l->ctyp));
    247 	if (r->t == Con)
    248 		r->u.n *= sz;
    249 	else {
    250 		if (irtyp(r->ctyp) != 'l')
    251 			sext(r);
    252 		fprintf(of, "\t%%t%d =l mul %d, ", tmp, sz);
    253 		psymb(*r);
    254 		fprintf(of, "\n");
    255 		r->u.n = tmp++;
    256 	}
    257 	return l->ctyp;
    258 }
    259 
    260 void
    261 load(Symb d, Symb s)
    262 {
    263 	char t;
    264 
    265 	fprintf(of, "\t");
    266 	psymb(d);
    267 	t = irtyp(d.ctyp);
    268 	fprintf(of, " =%c load%c ", t, t);
    269 	psymb(s);
    270 	fprintf(of, "\n");
    271 }
    272 
    273 void
    274 call(Node *n, Symb *sr)
    275 {
    276 	Node *a;
    277 	char *f;
    278 	unsigned ft;
    279 
    280 	f = n->l->u.v;
    281 	if (varget(f)) {
    282 		ft = varget(f)->ctyp;
    283 		if (KIND(ft) != FUN)
    284 			die("invalid call");
    285 	} else
    286 		ft = FUNC(INT);
    287 	sr->ctyp = DREF(ft);
    288 	for (a=n->r; a; a=a->r)
    289 		a->u.s = expr(a->l);
    290 	fprintf(of, "\t");
    291 	psymb(*sr);
    292 	fprintf(of, " =%c call $%s(", irtyp(sr->ctyp), f);
    293 	for (a=n->r; a; a=a->r) {
    294 		fprintf(of, "%c ", irtyp(a->u.s.ctyp));
    295 		psymb(a->u.s);
    296 		fprintf(of, ", ");
    297 	}
    298 	fprintf(of, "...)\n");
    299 }
    300 
    301 Symb
    302 expr(Node *n)
    303 {
    304 	static char *otoa[] = {
    305 		['+'] = "add",
    306 		['-'] = "sub",
    307 		['*'] = "mul",
    308 		['/'] = "div",
    309 		['%'] = "rem",
    310 		['&'] = "and",
    311 		['<'] = "cslt",  /* meeeeh, wrong for pointers! */
    312 		['l'] = "csle",
    313 		['e'] = "ceq",
    314 		['n'] = "cne",
    315 	};
    316 	Symb sr, s0, s1, sl;
    317 	int o, l;
    318 	char ty[2];
    319 
    320 	sr.t = Tmp;
    321 	sr.u.n = tmp++;
    322 
    323 	switch (n->op) {
    324 
    325 	case 0:
    326 		abort();
    327 
    328 	case 'o':
    329 	case 'a':
    330 		l = lbl;
    331 		lbl += 3;
    332 		bool(n, l, l+1);
    333 		fprintf(of, "@l%d\n", l);
    334 		fprintf(of, "\tjmp @l%d\n", l+2);
    335 		fprintf(of, "@l%d\n", l+1);
    336 		fprintf(of, "\tjmp @l%d\n", l+2);
    337 		fprintf(of, "@l%d\n", l+2);
    338 		fprintf(of, "\t");
    339 		sr.ctyp = INT;
    340 		psymb(sr);
    341 		fprintf(of, " =w phi @l%d 1, @l%d 0\n", l, l+1);
    342 		break;
    343 
    344 	case 'V':
    345 		s0 = lval(n);
    346 		sr.ctyp = s0.ctyp;
    347 		load(sr, s0);
    348 		break;
    349 
    350 	case 'N':
    351 		sr.t = Con;
    352 		sr.u.n = n->u.n;
    353 		sr.ctyp = INT;
    354 		break;
    355 
    356 	case 'S':
    357 		sr.t = Glo;
    358 		sr.u.n = n->u.n;
    359 		sr.ctyp = IDIR(INT);
    360 		break;
    361 
    362 	case 'C':
    363 		call(n, &sr);
    364 		break;
    365 
    366 	case '@':
    367 		s0 = expr(n->l);
    368 		if (KIND(s0.ctyp) != PTR)
    369 			die("dereference of a non-pointer");
    370 		sr.ctyp = DREF(s0.ctyp);
    371 		load(sr, s0);
    372 		break;
    373 
    374 	case 'A':
    375 		sr = lval(n->l);
    376 		sr.ctyp = IDIR(sr.ctyp);
    377 		break;
    378 
    379 	case '=':
    380 		s0 = expr(n->r);
    381 		s1 = lval(n->l);
    382 		sr = s0;
    383 		if (s1.ctyp == LNG &&  s0.ctyp == INT)
    384 			sext(&s0);
    385 		if (s0.ctyp != IDIR(NIL) || KIND(s1.ctyp) != PTR)
    386 		if (s1.ctyp != IDIR(NIL) || KIND(s0.ctyp) != PTR)
    387 		if (s1.ctyp != s0.ctyp)
    388 			die("invalid assignment");
    389 		fprintf(of, "\tstore%c ", irtyp(s1.ctyp));
    390 		goto Args;
    391 
    392 	case 'P':
    393 	case 'M':
    394 		o = n->op == 'P' ? '+' : '-';
    395 		sl = lval(n->l);
    396 		s0.t = Tmp;
    397 		s0.u.n = tmp++;
    398 		s0.ctyp = sl.ctyp;
    399 		load(s0, sl);
    400 		s1.t = Con;
    401 		s1.u.n = 1;
    402 		s1.ctyp = INT;
    403 		goto Binop;
    404 
    405 	default:
    406 		s0 = expr(n->l);
    407 		s1 = expr(n->r);
    408 		o = n->op;
    409 	Binop:
    410 		sr.ctyp = prom(o, &s0, &s1);
    411 		if (strchr("ne<l", n->op)) {
    412 			sprintf(ty, "%c", irtyp(sr.ctyp));
    413 			sr.ctyp = INT;
    414 		} else
    415 			strcpy(ty, "");
    416 		fprintf(of, "\t");
    417 		psymb(sr);
    418 		fprintf(of, " =%c", irtyp(sr.ctyp));
    419 		fprintf(of, " %s%s ", otoa[o], ty);
    420 	Args:
    421 		psymb(s0);
    422 		fprintf(of, ", ");
    423 		psymb(s1);
    424 		fprintf(of, "\n");
    425 		break;
    426 
    427 	}
    428 	if (n->op == '-'
    429 	&&  KIND(s0.ctyp) == PTR
    430 	&&  KIND(s1.ctyp) == PTR) {
    431 		fprintf(of, "\t%%t%d =l div ", tmp);
    432 		psymb(sr);
    433 		fprintf(of, ", %d\n", SIZE(DREF(s0.ctyp)));
    434 		sr.u.n = tmp++;
    435 	}
    436 	if (n->op == 'P' || n->op == 'M') {
    437 		fprintf(of, "\tstore%c ", irtyp(sl.ctyp));
    438 		psymb(sr);
    439 		fprintf(of, ", ");
    440 		psymb(sl);
    441 		fprintf(of, "\n");
    442 		sr = s0;
    443 	}
    444 	return sr;
    445 }
    446 
    447 Symb
    448 lval(Node *n)
    449 {
    450 	Symb sr;
    451 
    452 	switch (n->op) {
    453 	default:
    454 		die("invalid lvalue");
    455 	case 'V':
    456 		if (!varget(n->u.v))
    457 			die("undefined variable");
    458 		sr = *varget(n->u.v);
    459 		break;
    460 	case '@':
    461 		sr = expr(n->l);
    462 		if (KIND(sr.ctyp) != PTR)
    463 			die("dereference of a non-pointer");
    464 		sr.ctyp = DREF(sr.ctyp);
    465 		break;
    466 	}
    467 	return sr;
    468 }
    469 
    470 void
    471 bool(Node *n, int lt, int lf)
    472 {
    473 	Symb s;
    474 	int l;
    475 
    476 	switch (n->op) {
    477 	default:
    478 		s = expr(n); /* TODO: insert comparison to 0 with proper type */
    479 		fprintf(of, "\tjnz ");
    480 		psymb(s);
    481 		fprintf(of, ", @l%d, @l%d\n", lt, lf);
    482 		break;
    483 	case 'o':
    484 		l = lbl;
    485 		lbl += 1;
    486 		bool(n->l, lt, l);
    487 		fprintf(of, "@l%d\n", l);
    488 		bool(n->r, lt, lf);
    489 		break;
    490 	case 'a':
    491 		l = lbl;
    492 		lbl += 1;
    493 		bool(n->l, l, lf);
    494 		fprintf(of, "@l%d\n", l);
    495 		bool(n->r, lt, lf);
    496 		break;
    497 	}
    498 }
    499 
    500 int
    501 stmt(Stmt *s, int b)
    502 {
    503 	int l, r;
    504 	Symb x;
    505 
    506 	if (!s)
    507 		return 0;
    508 
    509 	switch (s->t) {
    510 	case Ret:
    511 		x = expr(s->p1);
    512 		fprintf(of, "\tret ");
    513 		psymb(x);
    514 		fprintf(of, "\n");
    515 		return 1;
    516 	case Break:
    517 		if (b < 0)
    518 			die("break not in loop");
    519 		fprintf(of, "\tjmp @l%d\n", b);
    520 		return 1;
    521 	case Expr:
    522 		expr(s->p1);
    523 		return 0;
    524 	case Seq:
    525 		return stmt(s->p1, b) || stmt(s->p2, b);
    526 	case If:
    527 		l = lbl;
    528 		lbl += 3;
    529 		bool(s->p1, l, l+1);
    530 		fprintf(of, "@l%d\n", l);
    531 		if (!(r=stmt(s->p2, b)))
    532 		if (s->p3)
    533 			fprintf(of, "\tjmp @l%d\n", l+2);
    534 		fprintf(of, "@l%d\n", l+1);
    535 		if (s->p3)
    536 		if (!(r &= stmt(s->p3, b)))
    537 			fprintf(of, "@l%d\n", l+2);
    538 		return s->p3 && r;
    539 	case While:
    540 		l = lbl;
    541 		lbl += 3;
    542 		fprintf(of, "@l%d\n", l);
    543 		bool(s->p1, l+1, l+2);
    544 		fprintf(of, "@l%d\n", l+1);
    545 		if (!stmt(s->p2, l+2))
    546 			fprintf(of, "\tjmp @l%d\n", l);
    547 		fprintf(of, "@l%d\n", l+2);
    548 		return 0;
    549 	}
    550 }
    551 
    552 Node *
    553 mknode(char op, Node *l, Node *r)
    554 {
    555 	Node *n;
    556 
    557 	n = alloc(sizeof *n);
    558 	n->op = op;
    559 	n->l = l;
    560 	n->r = r;
    561 	return n;
    562 }
    563 
    564 Node *
    565 mkidx(Node *a, Node *i)
    566 {
    567 	Node *n;
    568 
    569 	n = mknode('+', a, i);
    570 	n = mknode('@', n, 0);
    571 	return n;
    572 }
    573 
    574 Node *
    575 mkneg(Node *n)
    576 {
    577 	static Node *z;
    578 
    579 	if (!z) {
    580 		z = mknode('N', 0, 0);
    581 		z->u.n = 0;
    582 	}
    583 	return mknode('-', z, n);
    584 }
    585 
    586 Stmt *
    587 mkstmt(int t, void *p1, void *p2, void *p3)
    588 {
    589 	Stmt *s;
    590 
    591 	s = alloc(sizeof *s);
    592 	s->t = t;
    593 	s->p1 = p1;
    594 	s->p2 = p2;
    595 	s->p3 = p3;
    596 	return s;
    597 }
    598 
    599 Node *
    600 param(char *v, unsigned ctyp, Node *pl)
    601 {
    602 	Node *n;
    603 
    604 	if (ctyp == NIL)
    605 		die("invalid void declaration");
    606 	n = mknode(0, 0, pl);
    607 	varadd(v, 0, ctyp);
    608 	strcpy(n->u.v, v);
    609 	return n;
    610 }
    611 
    612 Stmt *
    613 mkfor(Node *ini, Node *tst, Node *inc, Stmt *s)
    614 {
    615 	Stmt *s1, *s2;
    616 
    617 	if (ini)
    618 		s1 = mkstmt(Expr, ini, 0, 0);
    619 	else
    620 		s1 = 0;
    621 	if (inc) {
    622 		s2 = mkstmt(Expr, inc, 0, 0);
    623 		s2 = mkstmt(Seq, s, s2, 0);
    624 	} else
    625 		s2 = s;
    626 	if (!tst) {
    627 		tst = mknode('N', 0, 0);
    628 		tst->u.n = 1;
    629 	}
    630 	s2 = mkstmt(While, tst, s2, 0);
    631 	if (s1)
    632 		return mkstmt(Seq, s1, s2, 0);
    633 	else
    634 		return s2;
    635 }
    636 
    637 %}
    638 
    639 %union {
    640 	Node *n;
    641 	Stmt *s;
    642 	unsigned u;
    643 }
    644 
    645 %token <n> NUM
    646 %token <n> STR
    647 %token <n> IDENT
    648 %token PP MM LE GE SIZEOF
    649 
    650 %token TVOID TINT TLNG
    651 %token IF ELSE WHILE FOR BREAK RETURN
    652 
    653 %right '='
    654 %left OR
    655 %left AND
    656 %left '&'
    657 %left EQ NE
    658 %left '<' '>' LE GE
    659 %left '+' '-'
    660 %left '*' '/' '%'
    661 
    662 %type <u> type
    663 %type <s> stmt stmts
    664 %type <n> expr exp0 pref post arg0 arg1 par0 par1
    665 
    666 %%
    667 
    668 prog: func prog | fdcl prog | idcl prog | ;
    669 
    670 fdcl: type IDENT '(' ')' ';'
    671 {
    672 	varadd($2->u.v, 1, FUNC($1));
    673 };
    674 
    675 idcl: type IDENT ';'
    676 {
    677 	if ($1 == NIL)
    678 		die("invalid void declaration");
    679 	if (nglo == NGlo)
    680 		die("too many string literals");
    681 	ini[nglo] = alloc(sizeof "{ x 0 }");
    682 	sprintf(ini[nglo], "{ %c 0 }", irtyp($1));
    683 	varadd($2->u.v, nglo++, $1);
    684 };
    685 
    686 init:
    687 {
    688 	varclr();
    689 	tmp = 0;
    690 };
    691 
    692 func: init prot '{' dcls stmts '}'
    693 {
    694 	if (!stmt($5, -1))
    695 		fprintf(of, "\tret 0\n");
    696 	fprintf(of, "}\n\n");
    697 };
    698 
    699 prot: IDENT '(' par0 ')'
    700 {
    701 	Symb *s;
    702 	Node *n;
    703 	int t, m;
    704 
    705 	varadd($1->u.v, 1, FUNC(INT));
    706 	fprintf(of, "export function w $%s(", $1->u.v);
    707 	n = $3;
    708 	if (n)
    709 		for (;;) {
    710 			s = varget(n->u.v);
    711 			fprintf(of, "%c ", irtyp(s->ctyp));
    712 			fprintf(of, "%%t%d", tmp++);
    713 			n = n->r;
    714 			if (n)
    715 				fprintf(of, ", ");
    716 			else
    717 				break;
    718 		}
    719 	fprintf(of, ") {\n");
    720 	fprintf(of, "@l%d\n", lbl++);
    721 	for (t=0, n=$3; n; t++, n=n->r) {
    722 		s = varget(n->u.v);
    723 		m = SIZE(s->ctyp);
    724 		fprintf(of, "\t%%%s =l alloc%d %d\n", n->u.v, m, m);
    725 		fprintf(of, "\tstore%c %%t%d", irtyp(s->ctyp), t);
    726 		fprintf(of, ", %%%s\n", n->u.v);
    727 	}
    728 };
    729 
    730 par0: par1
    731     |                     { $$ = 0; }
    732     ;
    733 par1: type IDENT ',' par1 { $$ = param($2->u.v, $1, $4); }
    734     | type IDENT          { $$ = param($2->u.v, $1, 0); }
    735     ;
    736 
    737 
    738 dcls: | dcls type IDENT ';'
    739 {
    740 	int s;
    741 	char *v;
    742 
    743 	if ($2 == NIL)
    744 		die("invalid void declaration");
    745 	v = $3->u.v;
    746 	s = SIZE($2);
    747 	varadd(v, 0, $2);
    748 	fprintf(of, "\t%%%s =l alloc%d %d\n", v, s, s);
    749 };
    750 
    751 type: type '*' { $$ = IDIR($1); }
    752     | TINT     { $$ = INT; }
    753     | TLNG     { $$ = LNG; }
    754     | TVOID    { $$ = NIL; }
    755     ;
    756 
    757 stmt: ';'                            { $$ = 0; }
    758     | '{' stmts '}'                  { $$ = $2; }
    759     | BREAK ';'                      { $$ = mkstmt(Break, 0, 0, 0); }
    760     | RETURN expr ';'                { $$ = mkstmt(Ret, $2, 0, 0); }
    761     | expr ';'                       { $$ = mkstmt(Expr, $1, 0, 0); }
    762     | WHILE '(' expr ')' stmt        { $$ = mkstmt(While, $3, $5, 0); }
    763     | IF '(' expr ')' stmt ELSE stmt { $$ = mkstmt(If, $3, $5, $7); }
    764     | IF '(' expr ')' stmt           { $$ = mkstmt(If, $3, $5, 0); }
    765     | FOR '(' exp0 ';' exp0 ';' exp0 ')' stmt
    766                                      { $$ = mkfor($3, $5, $7, $9); }
    767     ;
    768 
    769 stmts: stmts stmt { $$ = mkstmt(Seq, $1, $2, 0); }
    770      |            { $$ = 0; }
    771      ;
    772 
    773 expr: pref
    774     | expr '=' expr     { $$ = mknode('=', $1, $3); }
    775     | expr '+' expr     { $$ = mknode('+', $1, $3); }
    776     | expr '-' expr     { $$ = mknode('-', $1, $3); }
    777     | expr '*' expr     { $$ = mknode('*', $1, $3); }
    778     | expr '/' expr     { $$ = mknode('/', $1, $3); }
    779     | expr '%' expr     { $$ = mknode('%', $1, $3); }
    780     | expr '<' expr     { $$ = mknode('<', $1, $3); }
    781     | expr '>' expr     { $$ = mknode('<', $3, $1); }
    782     | expr LE expr      { $$ = mknode('l', $1, $3); }
    783     | expr GE expr      { $$ = mknode('l', $3, $1); }
    784     | expr EQ expr      { $$ = mknode('e', $1, $3); }
    785     | expr NE expr      { $$ = mknode('n', $1, $3); }
    786     | expr '&' expr     { $$ = mknode('&', $1, $3); }
    787     | expr AND expr     { $$ = mknode('a', $1, $3); }
    788     | expr OR expr      { $$ = mknode('o', $1, $3); }
    789     ;
    790 
    791 exp0: expr
    792     |                   { $$ = 0; }
    793     ;
    794 
    795 pref: post
    796     | '-' pref          { $$ = mkneg($2); }
    797     | '*' pref          { $$ = mknode('@', $2, 0); }
    798     | '&' pref          { $$ = mknode('A', $2, 0); }
    799     ;
    800 
    801 post: NUM
    802     | STR
    803     | IDENT
    804     | SIZEOF '(' type ')' { $$ = mknode('N', 0, 0); $$->u.n = SIZE($3); }
    805     | '(' expr ')'        { $$ = $2; }
    806     | IDENT '(' arg0 ')'  { $$ = mknode('C', $1, $3); }
    807     | post '[' expr ']'   { $$ = mkidx($1, $3); }
    808     | post PP             { $$ = mknode('P', $1, 0); }
    809     | post MM             { $$ = mknode('M', $1, 0); }
    810     ;
    811 
    812 arg0: arg1
    813     |               { $$ = 0; }
    814     ;
    815 arg1: expr          { $$ = mknode(0, $1, 0); }
    816     | expr ',' arg1 { $$ = mknode(0, $1, $3); }
    817     ;
    818 
    819 %%
    820 
    821 int
    822 yylex()
    823 {
    824 	struct {
    825 		char *s;
    826 		int t;
    827 	} kwds[] = {
    828 		{ "void", TVOID },
    829 		{ "int", TINT },
    830 		{ "long", TLNG },
    831 		{ "if", IF },
    832 		{ "else", ELSE },
    833 		{ "for", FOR },
    834 		{ "while", WHILE },
    835 		{ "return", RETURN },
    836 		{ "break", BREAK },
    837 		{ "sizeof", SIZEOF },
    838 		{ 0, 0 }
    839 	};
    840 	int i, c, c1, n;
    841 	char v[NString], *p;
    842 
    843 	do {
    844 		c = getchar();
    845 		if (c == '#')
    846 			while ((c = getchar()) != '\n')
    847 				;
    848 		if (c == '\n')
    849 			line++;
    850 	} while (isspace(c));
    851 
    852 
    853 	if (c == EOF)
    854 		return 0;
    855 
    856 
    857 	if (isdigit(c)) {
    858 		n = 0;
    859 		do {
    860 			n *= 10;
    861 			n += c-'0';
    862 			c = getchar();
    863 		} while (isdigit(c));
    864 		ungetc(c, stdin);
    865 		yylval.n = mknode('N', 0, 0);
    866 		yylval.n->u.n = n;
    867 		return NUM;
    868 	}
    869 
    870 	if (isalpha(c)) {
    871 		p = v;
    872 		do {
    873 			if (p == &v[NString-1])
    874 				die("ident too long");
    875 			*p++ = c;
    876 			c = getchar();
    877 		} while (isalpha(c) || c == '_');
    878 		*p = 0;
    879 		ungetc(c, stdin);
    880 		for (i=0; kwds[i].s; i++)
    881 			if (strcmp(v, kwds[i].s) == 0)
    882 				return kwds[i].t;
    883 		yylval.n = mknode('V', 0, 0);
    884 		strcpy(yylval.n->u.v, v);
    885 		return IDENT;
    886 	}
    887 
    888 	if (c == '"') {
    889 		i = 0;
    890 		n = 32;
    891 		p = alloc(n);
    892 		strcpy(p, "{ b \"");
    893 		for (i=5;; i++) {
    894 			c = getchar();
    895 			if (c == EOF)
    896 				die("unclosed string literal");
    897 			if (i+8 >= n) {
    898 				p = memcpy(alloc(n*2), p, n);
    899 				n *= 2;
    900 			}
    901 			p[i] = c;
    902 			if (c == '"' && p[i-1]!='\\')
    903 				break;
    904 		}
    905 		strcpy(&p[i], "\", b 0 }");
    906 		if (nglo == NGlo)
    907 			die("too many globals");
    908 		ini[nglo] = p;
    909 		yylval.n = mknode('S', 0, 0);
    910 		yylval.n->u.n = nglo++;
    911 		return STR;
    912 	}
    913 
    914 	c1 = getchar();
    915 #define DI(a, b) a + b*256
    916 	switch (DI(c,c1)) {
    917 	case DI('!','='): return NE;
    918 	case DI('=','='): return EQ;
    919 	case DI('<','='): return LE;
    920 	case DI('>','='): return GE;
    921 	case DI('+','+'): return PP;
    922 	case DI('-','-'): return MM;
    923 	case DI('&','&'): return AND;
    924 	case DI('|','|'): return OR;
    925 	}
    926 #undef DI
    927 	ungetc(c1, stdin);
    928 
    929 	return c;
    930 }
    931 
    932 int
    933 yyerror(char *err)
    934 {
    935 	die("parse error");
    936 	return 0;
    937 }
    938 
    939 int
    940 main()
    941 {
    942 	int i;
    943 
    944 	of = stdout;
    945 	nglo = 1;
    946 	if (yyparse() != 0)
    947 		die("parse error");
    948 	for (i=1; i<nglo; i++)
    949 		fprintf(of, "data $glo%d = %s\n", i, ini[i]);
    950 	return 0;
    951 }