Charles.Forsyth20060303644188019 years agoHistory
486 lines · 7.6 KB · C
RawDownload
#include "rc.h"#include "y.tab.h" #define	c0	t->child[0]#define	c1	t->child[1]#define	c2	t->child[2]#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*); int	codep, ncode;Code	*codebuf; intmorecode(void){	ncode+=100;	codebuf=realloc(codebuf, ncode*sizeof codebuf[0]);	if(codebuf==0)		panic("Can't realloc %d bytes in morecode!",				ncode*sizeof codebuf[0]);	return 0;	/* not used */} voidstuffdot(int a){	if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);	codebuf[a].i=codep;} intcompile(Tree *t){	ncode=100;	codebuf=malloc(ncode*sizeof codebuf[0]);	codep=0;	emiti(0);			/* reference count */	outcode(t, flag['e']?1:0);	if(nerror){		free(codebuf);		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=f->strp;	f->strp=0;	closeio(f);	return v;} voidoutcode(Tree *t, int eflag){	int p, q;	Tree *tt; 	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);		emits(fnstr(c0));/*		p=emiti(0);		outcode(c0, eflag);		emitf(Xexit);		stuffdot(p);*/		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);		emits(fnstr(c0));/*		p=emiti(0);		outcode(c0, 0);		emitf(Xexit);		stuffdot(p);*/		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 SIMPLE:		emitf(Xmark);		outcode(c0, eflag);		emitf(Xsimple);		if(eflag) emitf(Xeflag);		break;	case SUBSHELL:		emitf(Xsubshell);		emits(fnstr(c0));/*		p=emiti(0);		outcode(c0, eflag);		emitf(Xexit);		stuffdot(p);*/		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;		emitf(Xsettrue);		outcode(c0, 0);		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 { /* t->rtype == CLOSE */			emitf(Xclose);			emiti(t->fd0);		}		outcode(c1, eflag);		emitf(Xpopredir);		break;/*	case PIPEFD:		emitf(Xpipefd);		emiti(t->rtype);		p=emiti(0);		outcode(c0, eflag);		emitf(Xexit);		stuffdot(p);		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;		}		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);			}			t=tt;			outcode(c2, eflag);			for(;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);		emits(fnstr(c0));		q=emiti(0);/*		outcode(c0, eflag);		emitf(Xexit);		stuffdot(p);*/		outcode(c1, 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 */	Tree *tt;	if(c1->child[0]->type!=';'	|| !iscase(c1->child[0]->child[0])){		yyerror("case missing in switch");		return;	}	emitf(Xmark);	outcode(c0, eflag);	emitf(Xjump);	nextcase=emiti(0);	out=emitf(Xjump);	leave=emiti(0);	stuffdot(nextcase);	t=c1->child[0];	while(t->type==';'){		tt=c1;		emitf(Xmark);		for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);		emitf(Xcase);		nextcase=emiti(0);		t=tt;		for(;;){			if(t->type==';'){				if(iscase(c0)) break;				outcode(c0, eflag);				t=c1;			}			else{				outcode(t, eflag);				break;			}		}		emitf(Xjump);		emiti(out);		stuffdot(nextcase);	}	stuffdot(leave);	emitf(Xpopm);} intiscase(Tree *t){	if(t->type!=SIMPLE)		return 0;	do		t=c0;	while(t->type==ARGLIST); 	return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;} Code *codecopy(Code *cp){	cp[0].i++;	return cp;} voidcodefree(Code *cp){	Code *p; 	if(--cp[0].i!=0)		return; 	for(p=cp+1;p->f;){		if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite		|| p->f==Xasync || p->f==Xcase || p->f==Xfalse		|| p->f==Xfor || p->f==Xjump		|| p->f==Xsubshell || p->f==Xtrue)			p+=2;		else if(p->f==Xdup || p->f==Xpipefd)			p+=3;		else if(p->f==Xpipe) {			free(p[3].s);			p+=5;		} else if(p->f==Xword || p->f==Xdelhere || p->f==Xbackq) {			free(p[1].s);			p+=2;		} else if(p->f==Xfn){			free(p[2].s);			p+=3;		} else			p++;	} 	free(cp);}