rminnichmerge57758a716 years agoHistory
580 lines · 9.7 KB · C
RawDownload
#include "rc.h"#include "io.h"#include "exec.h"#include "fns.h"#include "getflags.h"#define	c0	t->child[0]#define	c1	t->child[1]#define	c2	t->child[2]int codep, ncode;int pipep, npipe;#define	emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)#define	emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)#define	emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)   void stuffdot(int);char *fnstr(tree*);void outcode(tree*, int);void codeswitch(tree*, int);int iscase(tree*);code *codecopy(code*);void codefree(code*); intmorecode(void){	ncode+=100;	codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);	if(codebuf==0)		panic("Can't realloc %d bytes in morecode!",				ncode*sizeof codebuf[0]);	return 0;}  voidstuffdot(int a){	if(a<0 || codep<=a)		panic("Bad address %d in stuffdot", a);	codebuf[a].i = codep;} intcompile(tree *t){	ncode = 100; 		if(flag['t'])		tree2dot(err, t);	codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);	codep = 0;	/* XXX: This is bad, it's used in exec but I'm setting it up here	  * because it's were all the per program information is set up.	  * is there a better way?	  */	npipe = 10;	mpstk = (pipes **)emalloc(npipe*sizeof mpstk[0]); 	pipep = 0; 	emiti(0);			/* reference count */	outcode(t, flag['e']?1:0);	if(nerror){		efree((char *)codebuf);		efree((char *)mpstk);		return 0;	}	readhere();	emitf(Xreturn);	emitf(0);		return 1;} voidcleanhere(char *f){	emitf(Xdelhere);	emits(strdup(f));} char*fnstr(tree *t){	io *f = openstr();	char *v;	extern char nl;	char svnl = nl;	nl=';';	pfmt(f, "%t", t);	nl = svnl;	v = (char*)f->strp;	f->strp = 0;	closeio(f);	return v;} voidoutcode(tree *t, int eflag){	int p, q, r;	tree *tt;	int i; 	if(t==0)		return;	if(t->type!=NOT && t->type!=';')		runq->iflast = 0;	switch(t->type){	default:		pfmt(err, "bad type %d in outcode\n", t->type);		break;	case '$':		emitf(Xmark);		outcode(c0, eflag);		emitf(Xdol);		break;	case '"':		emitf(Xmark);		outcode(c0, eflag);		emitf(Xqdol);		break;	case SUB:		emitf(Xmark);		outcode(c0, eflag);		emitf(Xmark);		outcode(c1, eflag);		emitf(Xsub);		break;	case '&':		emitf(Xasync);		if(havefork){			p = emiti(0);			outcode(c0, eflag);			emitf(Xexit);			stuffdot(p);		} else			emits(fnstr(c0));		break;	case ';':		outcode(c0, eflag);		outcode(c1, eflag);		break;	case '^':		emitf(Xmark);		outcode(c1, eflag);		emitf(Xmark);		outcode(c0, eflag);		emitf(Xconc);		break;	case '`':		emitf(Xbackq);		if(havefork){			p = emiti(0);			outcode(c0, 0);			emitf(Xexit);			stuffdot(p);		} else			emits(fnstr(c0));		break;	case ANDAND:		outcode(c0, 0);		emitf(Xtrue);		p = emiti(0);		outcode(c1, eflag);		stuffdot(p);		break;	case ARGLIST:		outcode(c1, eflag);		outcode(c0, eflag);		break;	case BANG:		outcode(c0, eflag);		emitf(Xbang);		break;	case PCMD:	case BRACE:		outcode(c0, eflag);		break;	case COUNT:		emitf(Xmark);		outcode(c0, eflag);		emitf(Xcount);		break;	case FN:		emitf(Xmark);		outcode(c0, eflag);		if(c1){			emitf(Xfn);			p = emiti(0);			emits(fnstr(c1));			outcode(c1, eflag);			emitf(Xunlocal);	/* get rid of $* */			emitf(Xreturn);			stuffdot(p);		}		else			emitf(Xdelfn);		break;	case IF:		outcode(c0, 0);		emitf(Xif);		p = emiti(0);		outcode(c1, eflag);		emitf(Xwastrue);		stuffdot(p);		break;	case NOT:		if(!runq->iflast)			yyerror("`if not' does not follow `if(...)'");		emitf(Xifnot);		p = emiti(0);		outcode(c0, eflag);		stuffdot(p);		break;	case OROR:		outcode(c0, 0);		emitf(Xfalse);		p = emiti(0);		outcode(c1, eflag);		stuffdot(p);		break;	case PAREN:		outcode(c0, eflag);		break;	case FILTER:		// filters can't mark the stack because their argv is created programmatically.		emitf(Xmark);		outcode(c0, eflag);		emitf(Xsimple);		if(eflag)			emitf(Xeflag);		break;		case SIMPLE:		emitf(Xmark);		outcode(c0, eflag);		emitf(Xsimple);		if(eflag)			emitf(Xeflag);		break;	case SUBSHELL:		emitf(Xsubshell);		if(havefork){			p = emiti(0);			outcode(c0, eflag);			emitf(Xexit);			stuffdot(p);		} else			emits(fnstr(c0));		if(eflag)			emitf(Xeflag);		break;	case SWITCH:		codeswitch(t, eflag);		break;	case TWIDDLE:		emitf(Xmark);		outcode(c1, eflag);		emitf(Xmark);		outcode(c0, eflag);		emitf(Xmatch);		if(eflag)			emitf(Xeflag);		break;	case WHILE:		q = codep;		outcode(c0, 0);		if(q==codep)			emitf(Xsettrue);	/* empty condition == while(true) */		emitf(Xtrue);		p = emiti(0);		outcode(c1, eflag);		emitf(Xjump);		emiti(q);		stuffdot(p);		break;	case WORDS:		outcode(c1, eflag);		outcode(c0, eflag);		break;	case FOR:		emitf(Xmark);		if(c1){			outcode(c1, eflag);			emitf(Xglob);		}		else{			emitf(Xmark);			emitf(Xword);			emits(strdup("*"));			emitf(Xdol);		}		emitf(Xmark);		/* dummy value for Xlocal */		emitf(Xmark);		outcode(c0, eflag);		emitf(Xlocal);		p = emitf(Xfor);		q = emiti(0);		outcode(c2, eflag);		emitf(Xjump);		emiti(p);		stuffdot(q);		emitf(Xunlocal);		break;	case WORD:		emitf(Xword);		emits(strdup(t->str));		break;	case DUP:		if(t->rtype==DUPFD){			emitf(Xdup);			emiti(t->fd0);			emiti(t->fd1);		}		else{			emitf(Xclose);			emiti(t->fd0);		}		outcode(c1, eflag);		emitf(Xpopredir);		break;	case PIPEFD:		emitf(Xpipefd);		emiti(t->rtype);		if(havefork){			p = emiti(0);			outcode(c0, eflag);			emitf(Xexit);			stuffdot(p);		} else {			emits(fnstr(c0));		}		break;	case REDIR:		emitf(Xmark);		outcode(c0, eflag);		emitf(Xglob);		switch(t->rtype){		case APPEND:			emitf(Xappend);			break;		case WRITE:			emitf(Xwrite);			break;		case READ:		case HERE:			emitf(Xread);			break;		case RDWR:			emitf(Xrdwr);			break;		}		emiti(t->fd0);		outcode(c1, eflag);		emitf(Xpopredir);		break;	case '=':		tt = t;		for(;t && t->type=='=';t = c2);		if(t){			for(t = tt;t->type=='=';t = c2){				emitf(Xmark);				outcode(c1, eflag);				emitf(Xmark);				outcode(c0, eflag);				emitf(Xlocal);		/* push var for cmd */			}			outcode(t, eflag);			for(t = tt; t->type=='='; t = c2)				emitf(Xunlocal);		}		else{			for(t = tt;t;t = c2){				emitf(Xmark);				outcode(c1, eflag);				emitf(Xmark);				outcode(c0, eflag);				emitf(Xassign);			}		}		t = tt;	/* so tests below will work */		break;	case PIPE:		emitf(Xpipe);		emiti(t->fd0);		emiti(t->fd1);		if(havefork){			p = emiti(0);			q = emiti(0);			outcode(c0, eflag);			emitf(Xexit);			stuffdot(p);		} else {			emits(fnstr(c0));			q = emiti(0);		}		outcode(c1, eflag);		emitf(Xreturn);		stuffdot(q);		emitf(Xpipewait);		break;	case FANIN:		if(flag['g']){ 			t = mkgang(err, t);			emitf(Xmark);			outcode(c0, eflag);			break;		}		emitf(Xfanin);		emiti(t->fd0);		emiti(t->fd1);		if(havefork){			p = emiti(0);			r = emiti(0);			q = emiti(0); 			outcode(c0, eflag);			emitf(Xexit);			stuffdot(p);			outcode(c1, eflag);						emitf(Xexit);			stuffdot(r); 		} else {			emits(fnstr(c0));			q = emiti(0);		}		/* who gets what file descriptor? */		/* need to push all the file descriptors onto the stack as well */		/* how do you get the fds? */		/* I need to get the emitted values */			outcode(c2, eflag);		emitf(Xreturn);		stuffdot(q);		emitf(Xpipewait);		break;			case FANOUT:		emitf(Xfanout);		/* XXX: these are not FDs, they're the 		  * size of each multipipe */		emiti(t->fd0);		emiti(t->fd1);		/* create multipipe and push it. */		if(havefork){			p = emiti(0);			r = emiti(0);			q = emiti(0);			outcode(c0, eflag);			emitf(Xexit);			stuffdot(p);			outcode(c1, eflag);			emitf(Xexit);			stuffdot(r);		} else {			emits(fnstr(c0));			q = emiti(0);		}		outcode(c2, eflag);		emitf(Xreturn);		stuffdot(q);		emitf(Xpipewait);		break; 	}	if(t->type!=NOT && t->type!=';')		runq->iflast = t->type==IF;	else if(c0) runq->iflast = c0->type==IF;}/* * switch code looks like this: *	Xmark *	(get switch value) *	Xjump	1f * out:	Xjump	leave * 1:	Xmark *	(get case values) *	Xcase	1f *	(commands) *	Xjump	out * 1:	Xmark *	(get case values) *	Xcase	1f *	(commands) *	Xjump	out * 1: * leave: *	Xpopm */ voidcodeswitch(tree *t, int eflag){	int leave;		/* patch jump address to leave switch */	int out;		/* jump here to leave switch */	int nextcase;	/* patch jump address to next case */

Lines 1–500 of 580.