From 425ef692da7e74112f88f0b368f3286dba84f846 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Thu, 18 Jun 2020 19:45:40 -0700 Subject: feat: working parser for rc shell language --- sys/cmd/rc/code.c | 356 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 356 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..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; +} -- cgit v1.2.1