#include "rc.h" #define delcode 100 #define c0 t->child[0] #define c1 t->child[1] #define c2 t->child[2] #define emitf(x) ((code.ip!=code.end || morecode()), code.ip++->f = (x), code.ip) #define emiti(x) ((code.ip!=code.end || morecode()), code.ip++->i = (x), code.ip) #define emits(x) ((code.ip!=code.end || morecode()), code.ip++->s = (x), code.ip) static struct { int cap; Code *buf, *ip, *end; } code; static int morecode(void) { code.cap += delcode; code.buf = erealloc(code.buf, code.cap*sizeof(*code.buf)); code.end = code.ip + delcode; memset(code.ip, 0, delcode*sizeof(*code.buf)); return 0; } static void stuffdot(Code *p) { int a; a = p - code.buf; if (code.ip <= p || p < code.buf) panic("bad address %d in stuffdot", a); code.buf[a].i = code.ip-code.buf; } static void rcc(Tree *t, int eflag) { Code *p, *q; Tree *tt; if (!t) return; switch(t->type) { default: pfmt(errio, "bad type %d in rc compiler\n", t->type); break; case Tdol: emitf(Xmark); rcc(c0, eflag); emitf(Xdol); break; case Tquote: emitf(Xmark); rcc(c0, eflag); emitf(Xflatten); break; case Tsub: emitf(Xmark); rcc(c0, eflag); emitf(Xmark); rcc(c1, eflag); emitf(Xsub); break; case Tand: emitf(Xasync); p = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); break; case Tsemi: rcc(c0, eflag); rcc(c1, eflag); break; case Tcarot: emitf(Xmark); rcc(c1, eflag); emitf(Xmark); rcc(c0, eflag); emitf(Xcat); break; case Ttick: emitf(Xcmdsub); p = emiti(0); rcc(c0, 0); emitf(Xexit); stuffdot(p); break; case Tandand: rcc(c0, 0); emitf(Xtrue); p = emiti(0); rcc(c1, eflag); stuffdot(p); break; case Targs: rcc(c1, eflag); rcc(c0, eflag); break; case Tbang: rcc(c0, eflag); emitf(Xnegate); break; case Tparen: case Tbrace: rcc(c0, eflag); break; case Tcount: emitf(Xmark); rcc(c0, eflag); emitf(Xcount); break; case Tfunc: emitf(Xmark); rcc(c0, eflag); if(c1){ emitf(Xfunc); p = emiti(0); emits(fnstr(c1)); rcc(c1, eflag); emitf(Xunlocal); /* get rid of $* */ emitf(Xkill); stuffdot(p); } else emitf(Xunfunc); break; case Tif: rcc(c0, 0); emitf(Xif); p = emiti(0); rcc(c1, eflag); // emitf(Xwastrue); stuffdot(p); break; // case Telse: // if(!runq->iflast) // rcerror("`else' does not follow `if(...)'"); // emitf(Xelse); // p = emiti(0); // rcc(c0, eflag); // stuffdot(p); // break; case Toror: rcc(c0, 0); emitf(Xfalse); p = emiti(0); rcc(c1, eflag); stuffdot(p); break; case Tpcmd: rcc(c0, eflag); break; case Tsimple: emitf(Xmark); rcc(c0, eflag); emitf(Xsimple); if(eflag) emitf(Xeflag); break; case Tsubshell: emitf(Xsubshell); p = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); if(eflag) emitf(Xeflag); break; case Tswitch: codeswitch(t, eflag); break; case Ttwiddle: emitf(Xmark); rcc(c1, eflag); emitf(Xmark); rcc(c0, eflag); emitf(Xmatch); if(eflag) emitf(Xeflag); break; case Twhile: q = code.ip; rcc(c0, 0); if(q==code.ip) emitf(Xsettrue); /* empty condition == while(true) */ emitf(Xtrue); p = emiti(0); rcc(c1, eflag); emitf(Xjump); emiti(q-code.buf); stuffdot(p); break; case Twords: rcc(c1, eflag); rcc(c0, eflag); break; case Tfor: emitf(Xmark); if(c1){ rcc(c1, eflag); emitf(Xglob); } else{ emitf(Xmark); emitf(Xword); emits(strdup("*")); emitf(Xdol); } emitf(Xmark); /* dummy value for Xlocal */ emitf(Xmark); rcc(c0, eflag); emitf(Xlocal); p = emitf(Xfor); q = emiti(0); rcc(c2, eflag); emitf(Xjump); emiti(p-code.buf); stuffdot(q); emitf(Xunlocal); break; case Tword: emitf(Xword); emits(strdup(t->str)); break; case Tdup: if(t->redir.type == Rdupfd){ emitf(Xdup); emiti(t->redir.fd[0]); emiti(t->redir.fd[1]); } else{ emitf(Xclose); emiti(t->redir.fd[0]); } rcc(c1, eflag); emitf(Xpopredir); break; case Tpipefd: emitf(Xpipefd); emiti(t->redir.type); p = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); break; case Tredir: emitf(Xmark); rcc(c0, eflag); emitf(Xglob); switch(t->redir.type){ case Rappend: emitf(Xappend); break; case Rwrite: emitf(Xwrite); break; case Rread: case Rhere: emitf(Xread); break; case Rrdwr: emitf(Xrdwr); break; } emiti(t->redir.fd[0]); rcc(c1, eflag); emitf(Xpopredir); break; case Teq: tt = t; for(;t && t->type==Teq;t = c2); if(t){ for(t = tt;t->type==Teq;t = c2){ emitf(Xmark); rcc(c1, eflag); emitf(Xmark); rcc(c0, eflag); emitf(Xlocal); } rcc(t, eflag); for(t = tt; t->type==Teq; t = c2) emitf(Xunlocal); } else{ for(t = tt;t;t = c2){ emitf(Xmark); rcc(c1, eflag); emitf(Xmark); rcc(c0, eflag); emitf(Xassign); } } t = tt; /* so tests below will work */ break; case Tpipe: emitf(Xpipe); emiti(t->redir.fd[0]); emiti(t->redir.fd[1]); p = emiti(0); q = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); rcc(c1, eflag); emitf(Xkill); stuffdot(q); emitf(Xpipewait); break; } if(t->type!=Telse && t->type!=Tsemi) shell->iflast = t->type==Tif; else if (c0) shell->iflast = c0->type==Tif; } Code* compile(Tree *t) { code.cap = delcode; code.buf = code.ip = emalloc(code.cap*sizeof *code.buf); code.end = code.ip + code.cap; emiti(0); rcc(t, 0); emitf(Xkill); emitf(nil); return code.buf; }