From 6f2cac23a7e759c464ef52103fac929e1eeb6b10 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Sat, 9 Oct 2021 10:30:50 -0700 Subject: feat(rc): added shell --- sys/cmd/rc/code.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 sys/cmd/rc/code.c (limited to 'sys/cmd/rc/code.c') diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c new file mode 100644 index 0000000..edf47cf --- /dev/null +++ b/sys/cmd/rc/code.c @@ -0,0 +1,335 @@ +#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; +} -- cgit v1.2.1