diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /utils/rcsh/code.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'utils/rcsh/code.c')
| -rw-r--r-- | utils/rcsh/code.c | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/utils/rcsh/code.c b/utils/rcsh/code.c new file mode 100644 index 00000000..06aea6ff --- /dev/null +++ b/utils/rcsh/code.c @@ -0,0 +1,486 @@ +#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; + +int +morecode(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 */ +} + +void +stuffdot(int a) +{ + if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a); + codebuf[a].i=codep; +} + +int +compile(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; +} + +void +cleanhere(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; +} + +void +outcode(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 + */ +void +codeswitch(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); +} + +int +iscase(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; +} + +void +codefree(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); +} |
