aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/rc/code.c
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-18 19:45:40 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-18 19:45:40 -0700
commit425ef692da7e74112f88f0b368f3286dba84f846 (patch)
treed45729e90010e8d8c539031c3b72165f6884575d /sys/cmd/rc/code.c
parent0522b4bf4e125b7ceb67f7177db692aed3a0ebf9 (diff)
feat: working parser for rc shell language
Diffstat (limited to 'sys/cmd/rc/code.c')
-rw-r--r--sys/cmd/rc/code.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
new file mode 100644
index 0000000..f38dd43
--- /dev/null
+++ b/sys/cmd/rc/code.c
@@ -0,0 +1,356 @@
+#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);
+ codebuf[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 Asub:
+ 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 Aandand:
+ rcc(c0, 0);
+ emitf(Xtrue);
+ p = emiti(0);
+ rcc(c1, eflag);
+ stuffdot(p);
+ break;
+ case Aargs:
+ rcc(c1, eflag);
+ rcc(c0, eflag);
+ break;
+ case Kbang:
+ rcc(c0, eflag);
+ emitf(Xbang);
+ break;
+ case Aparen:
+ case Abrace:
+ rcc(c0, eflag);
+ break;
+ case Acount:
+ emitf(Xmark);
+ rcc(c0, eflag);
+ emitf(Xcount);
+ break;
+ case Kfunc:
+ 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 Kif:
+ rcc(c0, 0);
+ emitf(Xif);
+ p = emiti(0);
+ rcc(c1, eflag);
+ emitf(Xwastrue);
+ stuffdot(p);
+ break;
+ case Kelse:
+ if(!runq->iflast)
+ error("`else' does not follow `if(...)'");
+ emitf(Xelse);
+ p = emiti(0);
+ rcc(c0, eflag);
+ stuffdot(p);
+ break;
+ case Aoror:
+ rcc(c0, 0);
+ emitf(Xfalse);
+ p = emiti(0);
+ rcc(c1, eflag);
+ stuffdot(p);
+ break;
+ case Aparen:
+ rcc(c0, eflag);
+ break;
+ case Asimple:
+ emitf(Xmark);
+ rcc(c0, eflag);
+ emitf(Xsimple);
+ if(eflag)
+ emitf(Xeflag);
+ break;
+ case Ksubsh:
+ emitf(Xsubshell);
+ if(havefork){
+ p = emiti(0);
+ rcc(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
+ if(eflag)
+ emitf(Xeflag);
+ break;
+ case Kswitch:
+ codeswitch(t, eflag);
+ break;
+ case Ktwiddle:
+ 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 Awords:
+ rcc(c1, eflag);
+ rcc(c0, eflag);
+ break;
+ case Kfor:
+ 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 Aword:
+ emitf(Xword);
+ emits(strdup(t->str));
+ break;
+ case Adup:
+ if(t->rtype==Adupfd){
+ emitf(Xdup);
+ emiti(t->fd0);
+ emiti(t->fd1);
+ }
+ else{
+ emitf(Xclose);
+ emiti(t->fd0);
+ }
+ rcc(c1, eflag);
+ emitf(Xpopredir);
+ break;
+ case Apipefd:
+ emitf(Xpipefd);
+ emiti(t->rtype);
+ if(havefork){
+ p = emiti(0);
+ rcc(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ }
+ break;
+ case Aredir:
+ 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 Apipe:
+ 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!=Kelse && 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;
+}