9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

code.c (8287B)


      1 #include "rc.h"
      2 #include "io.h"
      3 #include "exec.h"
      4 #include "fns.h"
      5 #include "getflags.h"
      6 #define	c0	t->child[0]
      7 #define	c1	t->child[1]
      8 #define	c2	t->child[2]
      9 int codep, ncode;
     10 #define	emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
     11 #define	emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
     12 #define	emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
     13 void stuffdot(int);
     14 char *fnstr(tree*);
     15 void outcode(tree*, int);
     16 void codeswitch(tree*, int);
     17 int iscase(tree*);
     18 code *codecopy(code*);
     19 void codefree(code*);
     20 
     21 int
     22 morecode(void)
     23 {
     24 	ncode+=100;
     25 	codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
     26 	if(codebuf==0)
     27 		panic("Can't realloc %d bytes in morecode!",
     28 				ncode*sizeof codebuf[0]);
     29 	memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]);
     30 	return 0;
     31 }
     32 
     33 void
     34 stuffdot(int a)
     35 {
     36 	if(a<0 || codep<=a)
     37 		panic("Bad address %d in stuffdot", a);
     38 	codebuf[a].i = codep;
     39 }
     40 
     41 int
     42 compile(tree *t)
     43 {
     44 	ncode = 100;
     45 	codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
     46 	codep = 0;
     47 	emiti(0);			/* reference count */
     48 	outcode(t, flag['e']?1:0);
     49 	if(nerror){
     50 		efree((char *)codebuf);
     51 		return 0;
     52 	}
     53 	readhere();
     54 	emitf(Xreturn);
     55 	emitf(0);
     56 	return 1;
     57 }
     58 
     59 void
     60 cleanhere(char *f)
     61 {
     62 	emitf(Xdelhere);
     63 	emits(strdup(f));
     64 }
     65 
     66 char*
     67 fnstr(tree *t)
     68 {
     69 	io *f = openstr();
     70 	char *v;
     71 	extern char nl;
     72 	char svnl = nl;
     73 	nl=';';
     74 	pfmt(f, "%t", t);
     75 	nl = svnl;
     76 	v = f->strp;
     77 	f->strp = 0;
     78 	closeio(f);
     79 	return v;
     80 }
     81 
     82 void
     83 outcode(tree *t, int eflag)
     84 {
     85 	int p, q;
     86 	tree *tt;
     87 	if(t==0)
     88 		return;
     89 	if(t->type!=NOT && t->type!=';')
     90 		runq->iflast = 0;
     91 	switch(t->type){
     92 	default:
     93 		pfmt(err, "bad type %d in outcode\n", t->type);
     94 		break;
     95 	case '$':
     96 		emitf(Xmark);
     97 		outcode(c0, eflag);
     98 		emitf(Xdol);
     99 		break;
    100 	case '"':
    101 		emitf(Xmark);
    102 		outcode(c0, eflag);
    103 		emitf(Xqdol);
    104 		break;
    105 	case SUB:
    106 		emitf(Xmark);
    107 		outcode(c0, eflag);
    108 		emitf(Xmark);
    109 		outcode(c1, eflag);
    110 		emitf(Xsub);
    111 		break;
    112 	case '&':
    113 		emitf(Xasync);
    114 		if(havefork){
    115 			p = emiti(0);
    116 			outcode(c0, eflag);
    117 			emitf(Xexit);
    118 			stuffdot(p);
    119 		} else
    120 			emits(fnstr(c0));
    121 		break;
    122 	case ';':
    123 		outcode(c0, eflag);
    124 		outcode(c1, eflag);
    125 		break;
    126 	case '^':
    127 		emitf(Xmark);
    128 		outcode(c1, eflag);
    129 		emitf(Xmark);
    130 		outcode(c0, eflag);
    131 		emitf(Xconc);
    132 		break;
    133 	case '`':
    134 		emitf(Xbackq);
    135 		if(havefork){
    136 			p = emiti(0);
    137 			outcode(c0, 0);
    138 			emitf(Xexit);
    139 			stuffdot(p);
    140 		} else
    141 			emits(fnstr(c0));
    142 		break;
    143 	case ANDAND:
    144 		outcode(c0, 0);
    145 		emitf(Xtrue);
    146 		p = emiti(0);
    147 		outcode(c1, eflag);
    148 		stuffdot(p);
    149 		break;
    150 	case ARGLIST:
    151 		outcode(c1, eflag);
    152 		outcode(c0, eflag);
    153 		break;
    154 	case BANG:
    155 		outcode(c0, eflag);
    156 		emitf(Xbang);
    157 		break;
    158 	case PCMD:
    159 	case BRACE:
    160 		outcode(c0, eflag);
    161 		break;
    162 	case COUNT:
    163 		emitf(Xmark);
    164 		outcode(c0, eflag);
    165 		emitf(Xcount);
    166 		break;
    167 	case FN:
    168 		emitf(Xmark);
    169 		outcode(c0, eflag);
    170 		if(c1){
    171 			emitf(Xfn);
    172 			p = emiti(0);
    173 			emits(fnstr(c1));
    174 			outcode(c1, eflag);
    175 			emitf(Xunlocal);	/* get rid of $* */
    176 			emitf(Xreturn);
    177 			stuffdot(p);
    178 		}
    179 		else
    180 			emitf(Xdelfn);
    181 		break;
    182 	case IF:
    183 		outcode(c0, 0);
    184 		emitf(Xif);
    185 		p = emiti(0);
    186 		outcode(c1, eflag);
    187 		emitf(Xwastrue);
    188 		stuffdot(p);
    189 		break;
    190 	case NOT:
    191 		if(!runq->iflast)
    192 			yyerror("`if not' does not follow `if(...)'");
    193 		emitf(Xifnot);
    194 		p = emiti(0);
    195 		outcode(c0, eflag);
    196 		stuffdot(p);
    197 		break;
    198 	case OROR:
    199 		outcode(c0, 0);
    200 		emitf(Xfalse);
    201 		p = emiti(0);
    202 		outcode(c1, eflag);
    203 		stuffdot(p);
    204 		break;
    205 	case PAREN:
    206 		outcode(c0, eflag);
    207 		break;
    208 	case SIMPLE:
    209 		emitf(Xmark);
    210 		outcode(c0, eflag);
    211 		emitf(Xsimple);
    212 		if(eflag)
    213 			emitf(Xeflag);
    214 		break;
    215 	case SUBSHELL:
    216 		emitf(Xsubshell);
    217 		if(havefork){
    218 			p = emiti(0);
    219 			outcode(c0, eflag);
    220 			emitf(Xexit);
    221 			stuffdot(p);
    222 		} else
    223 			emits(fnstr(c0));
    224 		if(eflag)
    225 			emitf(Xeflag);
    226 		break;
    227 	case SWITCH:
    228 		codeswitch(t, eflag);
    229 		break;
    230 	case TWIDDLE:
    231 		emitf(Xmark);
    232 		outcode(c1, eflag);
    233 		emitf(Xmark);
    234 		outcode(c0, eflag);
    235 		emitf(Xmatch);
    236 		if(eflag)
    237 			emitf(Xeflag);
    238 		break;
    239 	case WHILE:
    240 		q = codep;
    241 		outcode(c0, 0);
    242 		if(q==codep)
    243 			emitf(Xsettrue);	/* empty condition == while(true) */
    244 		emitf(Xtrue);
    245 		p = emiti(0);
    246 		outcode(c1, eflag);
    247 		emitf(Xjump);
    248 		emiti(q);
    249 		stuffdot(p);
    250 		break;
    251 	case WORDS:
    252 		outcode(c1, eflag);
    253 		outcode(c0, eflag);
    254 		break;
    255 	case FOR:
    256 		emitf(Xmark);
    257 		if(c1){
    258 			outcode(c1, eflag);
    259 			emitf(Xglob);
    260 		}
    261 		else{
    262 			emitf(Xmark);
    263 			emitf(Xword);
    264 			emits(strdup("*"));
    265 			emitf(Xdol);
    266 		}
    267 		emitf(Xmark);		/* dummy value for Xlocal */
    268 		emitf(Xmark);
    269 		outcode(c0, eflag);
    270 		emitf(Xlocal);
    271 		p = emitf(Xfor);
    272 		q = emiti(0);
    273 		outcode(c2, eflag);
    274 		emitf(Xjump);
    275 		emiti(p);
    276 		stuffdot(q);
    277 		emitf(Xunlocal);
    278 		break;
    279 	case WORD:
    280 		emitf(Xword);
    281 		emits(strdup(t->str));
    282 		break;
    283 	case DUP:
    284 		if(t->rtype==DUPFD){
    285 			emitf(Xdup);
    286 			emiti(t->fd0);
    287 			emiti(t->fd1);
    288 		}
    289 		else{
    290 			emitf(Xclose);
    291 			emiti(t->fd0);
    292 		}
    293 		outcode(c1, eflag);
    294 		emitf(Xpopredir);
    295 		break;
    296 	case PIPEFD:
    297 		emitf(Xpipefd);
    298 		emiti(t->rtype);
    299 		if(havefork){
    300 			p = emiti(0);
    301 			outcode(c0, eflag);
    302 			emitf(Xexit);
    303 			stuffdot(p);
    304 		} else {
    305 			emits(fnstr(c0));
    306 		}
    307 		break;
    308 	case REDIR:
    309 		emitf(Xmark);
    310 		outcode(c0, eflag);
    311 		emitf(Xglob);
    312 		switch(t->rtype){
    313 		case APPEND:
    314 			emitf(Xappend);
    315 			break;
    316 		case WRITE:
    317 			emitf(Xwrite);
    318 			break;
    319 		case READ:
    320 		case HERE:
    321 			emitf(Xread);
    322 			break;
    323 		case RDWR:
    324 			emitf(Xrdwr);
    325 			break;
    326 		}
    327 		emiti(t->fd0);
    328 		outcode(c1, eflag);
    329 		emitf(Xpopredir);
    330 		break;
    331 	case '=':
    332 		tt = t;
    333 		for(;t && t->type=='=';t = c2);
    334 		if(t){
    335 			for(t = tt;t->type=='=';t = c2){
    336 				emitf(Xmark);
    337 				outcode(c1, eflag);
    338 				emitf(Xmark);
    339 				outcode(c0, eflag);
    340 				emitf(Xlocal);
    341 			}
    342 			outcode(t, eflag);
    343 			for(t = tt; t->type=='='; t = c2)
    344 				emitf(Xunlocal);
    345 		}
    346 		else{
    347 			for(t = tt;t;t = c2){
    348 				emitf(Xmark);
    349 				outcode(c1, eflag);
    350 				emitf(Xmark);
    351 				outcode(c0, eflag);
    352 				emitf(Xassign);
    353 			}
    354 		}
    355 		t = tt;	/* so tests below will work */
    356 		break;
    357 	case PIPE:
    358 		emitf(Xpipe);
    359 		emiti(t->fd0);
    360 		emiti(t->fd1);
    361 		if(havefork){
    362 			p = emiti(0);
    363 			q = emiti(0);
    364 			outcode(c0, eflag);
    365 			emitf(Xexit);
    366 			stuffdot(p);
    367 		} else {
    368 			emits(fnstr(c0));
    369 			q = emiti(0);
    370 		}
    371 		outcode(c1, eflag);
    372 		emitf(Xreturn);
    373 		stuffdot(q);
    374 		emitf(Xpipewait);
    375 		break;
    376 	}
    377 	if(t->type!=NOT && t->type!=';')
    378 		runq->iflast = t->type==IF;
    379 	else if(c0) runq->iflast = c0->type==IF;
    380 }
    381 /*
    382  * switch code looks like this:
    383  *	Xmark
    384  *	(get switch value)
    385  *	Xjump	1f
    386  * out:	Xjump	leave
    387  * 1:	Xmark
    388  *	(get case values)
    389  *	Xcase	1f
    390  *	(commands)
    391  *	Xjump	out
    392  * 1:	Xmark
    393  *	(get case values)
    394  *	Xcase	1f
    395  *	(commands)
    396  *	Xjump	out
    397  * 1:
    398  * leave:
    399  *	Xpopm
    400  */
    401 
    402 void
    403 codeswitch(tree *t, int eflag)
    404 {
    405 	int leave;		/* patch jump address to leave switch */
    406 	int out;		/* jump here to leave switch */
    407 	int nextcase;	/* patch jump address to next case */
    408 	tree *tt;
    409 	if(c1->child[0]==nil
    410 	|| c1->child[0]->type!=';'
    411 	|| !iscase(c1->child[0]->child[0])){
    412 		yyerror("case missing in switch");
    413 		return;
    414 	}
    415 	emitf(Xmark);
    416 	outcode(c0, eflag);
    417 	emitf(Xjump);
    418 	nextcase = emiti(0);
    419 	out = emitf(Xjump);
    420 	leave = emiti(0);
    421 	stuffdot(nextcase);
    422 	t = c1->child[0];
    423 	while(t->type==';'){
    424 		tt = c1;
    425 		emitf(Xmark);
    426 		for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
    427 		emitf(Xcase);
    428 		nextcase = emiti(0);
    429 		t = tt;
    430 		for(;;){
    431 			if(t->type==';'){
    432 				if(iscase(c0)) break;
    433 				outcode(c0, eflag);
    434 				t = c1;
    435 			}
    436 			else{
    437 				if(!iscase(t)) outcode(t, eflag);
    438 				break;
    439 			}
    440 		}
    441 		emitf(Xjump);
    442 		emiti(out);
    443 		stuffdot(nextcase);
    444 	}
    445 	stuffdot(leave);
    446 	emitf(Xpopm);
    447 }
    448 
    449 int
    450 iscase(tree *t)
    451 {
    452 	if(t->type!=SIMPLE)
    453 		return 0;
    454 	do t = c0; while(t->type==ARGLIST);
    455 	return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
    456 }
    457 
    458 code*
    459 codecopy(code *cp)
    460 {
    461 	cp[0].i++;
    462 	return cp;
    463 }
    464 
    465 void
    466 codefree(code *cp)
    467 {
    468 	code *p;
    469 	if(--cp[0].i!=0)
    470 		return;
    471 	for(p = cp+1;p->f;p++){
    472 		if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
    473 		|| p->f==Xrdwr
    474 		|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
    475 		|| p->f==Xfor || p->f==Xjump
    476 		|| p->f==Xsubshell || p->f==Xtrue) p++;
    477 		else if(p->f==Xdup || p->f==Xpipefd) p+=2;
    478 		else if(p->f==Xpipe) p+=4;
    479 		else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
    480 		else if(p->f==Xfn){
    481 			efree(p[2].s);
    482 			p+=2;
    483 		}
    484 	}
    485 	efree((char *)cp);
    486 }