123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- #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;
- #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
- morecode(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;
- }
- 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 = (code *)emalloc(ncode*sizeof codebuf[0]);
- codep = 0;
- emiti(0); /* reference count */
- outcode(t, flag['e']?1:0);
- if(nerror){
- efree((char *)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();
- void *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);
- 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 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){ /* var=value cmd */
- 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); /* gen. code for cmd */
- for(t = tt; t->type == '='; t = c2)
- emitf(Xunlocal); /* pop var */
- }
- else{ /* var=value */
- for(t = tt;t;t = c2){
- emitf(Xmark);
- outcode(c1, eflag);
- emitf(Xmark);
- outcode(c0, eflag);
- emitf(Xassign); /* set var permanently */
- }
- }
- 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;
- }
- 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]==nil
- || 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{
- if(!iscase(t)) 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;p++){
- if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
- || p->f==Xrdwr
- || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
- || p->f==Xfor || p->f==Xjump
- || p->f==Xsubshell || p->f==Xtrue) p++;
- else if(p->f==Xdup || p->f==Xpipefd) p+=2;
- else if(p->f==Xpipe) p+=4;
- else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
- else if(p->f==Xfn){
- efree(p[2].s);
- p+=2;
- }
- }
- efree((char *)cp);
- }
|