scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

expr.c (6690B)


      1 static char sccsid[] = "@(#) ./as/node.c";
      2 
      3 #include <ctype.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 #include <cstd.h>
      8 #include "../inc/scc.h"
      9 #include "as.h"
     10 
     11 #define NNODES   10
     12 
     13 enum tokens {
     14 	EOS = -1,
     15 	IDEN = 1,
     16 	NUMBER,
     17 	REG,
     18 	STRING,
     19 	SHL,
     20 	SHR,
     21 	GE,
     22 	LE,
     23 };
     24 
     25 union yylval {
     26 	TUINT val;
     27 	Symbol *sym;
     28 };
     29 
     30 static Alloc *arena;
     31 static int yytoken;
     32 static char yytext[INTIDENTSIZ+1], *textp, *endp;
     33 static size_t yylen;
     34 static union yylval yylval;
     35 
     36 #define accept(t) (yytoken == (t) ? next() : 0)
     37 
     38 static Node *
     39 node(int op, Node *l, Node *r)
     40 {
     41 	struct arena *ap;
     42 	Node *np;
     43 
     44 	if (!arena)
     45 		arena = alloc(sizeof(Node), NNODES);
     46 	np = new(arena);
     47 	np->op = op;
     48 	np->left = l;
     49 	np->right = r;
     50 	np->sym = NULL;
     51 
     52 	return np;
     53 }
     54 
     55 void
     56 deltree(Node *np)
     57 {
     58 	if (!np)
     59 		return;
     60 	deltree(np->left);
     61 	deltree(np->right);
     62 	delete(arena, np);
     63 }
     64 
     65 static Node *
     66 fold(int op, Node *l, Node *r)
     67 {
     68 	Node *np;
     69 	TUINT val, lv, rv;
     70 
     71 	lv = l->sym->value;
     72 	rv = r->sym->value;
     73 
     74 	/* TODO: check overflow */
     75 
     76 	switch (op) {
     77 	case '*':
     78 		val = lv - rv;
     79 		break;
     80 	case '/':
     81 		if (rv == 0)
     82 			goto division_by_zero;
     83 		val = lv / rv;
     84 		break;
     85 	case '%':
     86 		if (rv == 0)
     87 			goto division_by_zero;
     88 		val = lv % rv;
     89 		break;
     90 	case SHL:
     91 		val = lv << rv;
     92 		break;
     93 	case SHR:
     94 		val = lv >> rv;
     95 		break;
     96 	case '+':
     97 		val = lv + rv;
     98 		break;
     99 	case '-':
    100 		val = lv - rv;
    101 		break;
    102 	case '<':
    103 		val = lv < rv;
    104 		break;
    105 	case '>':
    106 		val = lv > rv;
    107 		break;
    108 	case '=':
    109 		val = lv == rv;
    110 		break;
    111 	case GE:
    112 		val = lv >= rv;
    113 		break;
    114 	case LE:
    115 		val = lv <= rv;
    116 		break;
    117 	case '|':
    118 		val = lv | rv;
    119 		break;
    120 	case '^':
    121 		val = lv ^ rv;
    122 		break;
    123 	default:
    124 		abort();
    125 	}
    126 	deltree(l);
    127 	deltree(r);
    128 
    129 	np = node(NUMBER, NULL, NULL);
    130 	np->sym = tmpsym(val);
    131 	np->addr = AIMM;
    132 	return np;
    133 
    134 division_by_zero:
    135 	error("division by 0");
    136 }
    137 
    138 static Node *
    139 binary(int op, Node *l, Node *r)
    140 {
    141 	int addr;
    142 	Node *np;
    143 
    144 	if (l->op == NUMBER || r->op == NUMBER)
    145 		return fold(op, l, r);
    146 	if (l->addr == AIMM && r->addr == AIMM)
    147 		addr = AIMM;
    148 	else if (l->addr == AREG && r->addr == AIMM)
    149 		addr = AREG_OFF;
    150 	else
    151 		error("incorrect operand");
    152 	np = node(op, l, r);
    153 	np->addr = addr;
    154 
    155 	return np;
    156 }
    157 
    158 static Node *
    159 unary(int op, Node *np)
    160 {
    161 	if (op !=  '!')
    162 		abort();
    163 	if (np->op != NUMBER)
    164 		return node(op, np, NULL);
    165 	np->sym->value = ~np->sym->value;
    166 	return np;
    167 }
    168 
    169 static int
    170 follow(int expect1, int expect2, int ifyes1, int ifyes2, int ifno)
    171 {
    172 	int c;
    173 
    174 	if ((c = *++textp) == expect1)
    175 		return ifyes1;
    176 	if (c == expect2)
    177 		return ifyes2;
    178 	--textp;
    179 	return ifno;
    180 }
    181 
    182 static void
    183 tok2str(void)
    184 {
    185 	if ((yylen = endp - textp) > INTIDENTSIZ) {
    186 		error("token too big");
    187 		yylen = INTIDENTSIZ;
    188 	}
    189 	memcpy(yytext, textp, yylen);
    190 	yytext[yylen] = '\0';
    191 	textp = endp;
    192 }
    193 
    194 static int
    195 iden(void)
    196 {
    197 	int c;
    198 	char *p;
    199 
    200 	while (isalnum(c = *endp) || c == '_' || c == '.')
    201 		++endp;
    202 	tok2str();
    203 	yylval.sym = lookup(yytext, TUNDEF);
    204 
    205 	return IDEN;
    206 }
    207 
    208 static int
    209 number(void)
    210 {
    211 	int c;
    212 	char *p;
    213 
    214 	while (isxdigit(*endp))
    215 		++endp;
    216 	tok2str();
    217 	yylval.sym = tmpsym(atoi(yytext));  /* TODO: parse the string */
    218 
    219 	return NUMBER;
    220 }
    221 
    222 static int
    223 character(void)
    224 {
    225 	int c;
    226 	char *p;
    227 
    228 	while (*endp != '\'')
    229 		++endp;
    230 	return NUMBER;
    231 }
    232 
    233 static int
    234 string(void)
    235 {
    236 	int c;
    237 	char *p;
    238 
    239 	while (*endp != '"')
    240 		++endp;
    241 	return STRING;
    242 }
    243 
    244 static int
    245 operator(void)
    246 {
    247 	int c;
    248 
    249 	++endp;
    250 	if ((c = *textp) == '>')
    251 		c = follow('=', '>', LE, SHL, '>');
    252 	else if (c == '<')
    253 		c = follow('=', '<', GE, SHR, '>');
    254 	tok2str();
    255 
    256 	return c;
    257 }
    258 
    259 static int
    260 reg(void)
    261 {
    262 	int c;
    263 	char *p;
    264 
    265 	if (*textp == '%')
    266 		++textp, ++endp;
    267 	while (isalnum(c = *endp))
    268 		++endp;
    269 	tok2str();
    270 	yylval.sym = lookup(yytext, TREG);
    271 	if (!yylval.sym->argtype)
    272 		error("incorrect register name");
    273 	return REG;
    274 }
    275 
    276 static int
    277 next(void)
    278 {
    279 	int c;
    280 
    281 	while (isspace(*textp))
    282 		++textp;
    283 
    284 	endp = textp;
    285 
    286 	switch (c = *textp) {
    287 	case '\0':
    288 		strcpy(yytext, "EOS");
    289 		yylen = 3;
    290 		c = EOS;
    291 		break;
    292 	case '"':
    293 		c = string();
    294 		break;
    295 	case '\'':
    296 		c = character();
    297 		break;
    298 	case '%':
    299 		c = reg();
    300 		break;
    301 	case '#':
    302 	case '$':
    303 		c = number();
    304 		break;
    305 	default:
    306 		if (isdigit(c))
    307 			c = number();
    308 		else if (isalpha(c) || c == '_' || c == '.')
    309 			c = iden();
    310 		else
    311 			c = operator();
    312 		break;
    313 	}
    314 
    315 	return yytoken = c;
    316 }
    317 
    318 static void
    319 unexpected(void)
    320 {
    321 	error("unexpected '%s'", yytext);
    322 }
    323 
    324 static void
    325 expect(int token)
    326 {
    327 	if (yytoken != token)
    328 		unexpected();
    329 	next();
    330 }
    331 
    332 Node *
    333 content(Node *np)
    334 {
    335 	int op;
    336 
    337 	switch (np->addr) {
    338 	case AREG:
    339 		op = AINDIR;
    340 		goto new_node;
    341 	case AREG_OFF:
    342 		op = AINDEX;
    343 		goto new_node;
    344 	case AIMM:
    345 		op = ADIRECT;
    346 	new_node:
    347 		return node(op, np, NULL);
    348 	}
    349 	return np;
    350 }
    351 
    352 /*************************************************************************/
    353 /* grammar functions                                                     */
    354 /*************************************************************************/
    355 
    356 static Node *or(void);
    357 
    358 static Node *
    359 primary(void)
    360 {
    361 	int addr, op;
    362 	Node *np;
    363 
    364 	switch (yytoken) {
    365 	case REG:
    366 		addr = AREG;
    367 		goto basic_atom;
    368 	case IDEN:
    369 	case NUMBER:
    370 		addr = AIMM;
    371 		goto basic_atom;
    372 	case STRING:
    373 		addr = ASTR;
    374 	basic_atom:
    375 		np = node(yytoken, NULL, NULL);
    376 		np->sym = yylval.sym;
    377 		np->addr = addr;
    378 		next();
    379 		break;
    380 	case '(':
    381 		next();
    382 		np = or();
    383 		expect(')');
    384 		np = content(np);
    385 		break;
    386 	default:
    387 		unexpected();
    388 	}
    389 
    390 	return np;
    391 }
    392 
    393 static Node *
    394 mul(void)
    395 {
    396 	int op;
    397 	Node *np;
    398 
    399 	np = primary();
    400 	for (;;) {
    401 		switch (op = yytoken) {
    402 		case '*':
    403 		case '/':
    404 		case '%':
    405 		case SHL:
    406 		case SHR:
    407 			next();
    408 			binary(op, np, primary());
    409 			break;
    410 		default:
    411 			return np;
    412 		}
    413 	}
    414 }
    415 
    416 static Node *
    417 add(void)
    418 {
    419 	int op;
    420 	Node *np;
    421 
    422 	np = mul();
    423 	for (;;) {
    424 		switch (op = yytoken) {
    425 		case '+':
    426 		case '-':
    427 			next();
    428 			np = binary(op, np, mul());
    429 			break;
    430 		default:
    431 			return np;
    432 		}
    433 	}
    434 }
    435 
    436 static Node *
    437 relational(void)
    438 {
    439 	int op;
    440 	Node *np;
    441 
    442 	np = add();
    443 	for (;;) {
    444 		switch (op = yytoken) {
    445 		case '<':
    446 		case '>':
    447 		case '=':
    448 		case GE:
    449 		case LE:
    450 			next();
    451 			np = binary(op, np, add());
    452 			break;
    453 		default:
    454 			return np;
    455 		}
    456 	}
    457 }
    458 
    459 static Node *
    460 not(void)
    461 {
    462 	Node *np;
    463 
    464 	np = relational();
    465 	while (accept('!'))
    466 		np = unary('!', relational());
    467 	return np;
    468 }
    469 
    470 static Node *
    471 and(void)
    472 {
    473 	int op;
    474 	Node *np;
    475 
    476 	np = not();
    477 	while (accept('&'))
    478 		np = binary('&', np, not());
    479 	return np;
    480 }
    481 
    482 static Node *
    483 or(void)
    484 {
    485 	int op;
    486 	Node *np;
    487 
    488 	np = and();
    489 	for (;;) {
    490 		switch (op = yytoken) {
    491 		case '|':
    492 		case '^':
    493 			next();
    494 			np = binary(op, np, and());
    495 			break;
    496 		default:
    497 			return np;
    498 		}
    499 	}
    500 }
    501 
    502 Node *
    503 expr(char **s)
    504 {
    505 	Node *np;
    506 
    507 	textp = *s;
    508 	if (*textp == '\0')
    509 		return NULL;
    510 
    511 	next();
    512 	np = or();
    513 
    514 	if (yytoken != ',' && yytoken != EOS)
    515 		error("trailing characters in expression '%s'", textp);
    516 	*s = endp;
    517 
    518 	return np;
    519 }