aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/rc/code.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/rc/code.c')
-rw-r--r--sys/cmd/rc/code.c335
1 files changed, 335 insertions, 0 deletions
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;
+}