#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)) #define emiti(x) ((code.ip!=code.end || morecode()), code.ip++->i = (x)) #define emits(x) ((code.ip!=code.end || morecode()), code.ip++->s = (x)) 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 '$': emitf(Xmark); rcc(c0, eflag); emitf(Xdol); break; case '"': emitf(Xmark); rcc(c0, eflag); emitf(Xqdol); break; case Tsub: emitf(Xmark); rcc(c0, eflag); emitf(Xmark); rcc(c1, eflag); emitf(Xsub); break; case '&': emitf(Xasync); if(havefork){ p = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); } else emits(fnstr(c0)); break; case ';': rcc(c0, eflag); rcc(c1, eflag); break; case '^': emitf(Xmark); rcc(c1, eflag); emitf(Xmark); rcc(c0, eflag); emitf(Xconc); break; case '`': emitf(Xbackq); if(havefork){ p = emiti(0); rcc(c0, 0); emitf(Xexit); stuffdot(p); } else emits(fnstr(c0)); 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(Xbang); 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(Xfn); p = emiti(0); emits(fnstr(c1)); rcc(c1, eflag); emitf(Xunlocal); /* get rid of $* */ emitf(Xreturn); stuffdot(p); } else emitf(Xdelfn); break; case Tif: rcc(c0, 0); emitf(Xif); p = emiti(0); rcc(c1, eflag); emitf(Xwastrue); stuffdot(p); break; case Telse: if(!runq->iflast) error("`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 Tparen: rcc(c0, eflag); break; case Tsimple: emitf(Xmark); rcc(c0, eflag); emitf(Xsimple); if(eflag) emitf(Xeflag); break; case Tsubshell: emitf(Xsubshell); if(havefork){ p = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); } else emits(fnstr(c0)); 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 Kwhile: 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); 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->rtype==Tdupfd){ emitf(Xdup); emiti(t->fd0); emiti(t->fd1); } else{ emitf(Xclose); emiti(t->fd0); } rcc(c1, eflag); emitf(Xpopredir); break; case Tpipefd: emitf(Xpipefd); emiti(t->rtype); if(havefork){ p = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); } else { emits(fnstr(c0)); } break; case Tredir: emitf(Xmark); rcc(c0, eflag); emitf(Xglob); switch(t->rtype){ case Rappend: emitf(Xappend); break; case Rwrite: emitf(Xwrite); break; case Rread: case Rhere: emitf(Xread); break; case Rrdwr: emitf(Xrdwr); break; } emiti(t->fd0); rcc(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); rcc(c1, eflag); emitf(Xmark); rcc(c0, eflag); emitf(Xlocal); } rcc(t, eflag); for(t = tt; t->type=='='; 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->fd0); emiti(t->fd1); if(havefork){ p = emiti(0); q = emiti(0); rcc(c0, eflag); emitf(Xexit); stuffdot(p); } else { emits(fnstr(c0)); q = emiti(0); } rcc(c1, eflag); emitf(Xreturn); stuffdot(q); emitf(Xpipewait); break; } if(t->type!=Telse && t->type!=';') runq->iflast = t->type==IF; else if(c0) runq->iflast = c0->type==IF; } 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(Xreturn); emitf(nil); return code.buf; }