plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

code.c (8518B)


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