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.c520
1 files changed, 337 insertions, 183 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index edf47cf..fbb5435 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -1,214 +1,267 @@
#include "rc.h"
+#include "io.h"
+#include "exec.h"
+#include "fns.h"
+#include "getflags.h"
+#define c0 t->child[0]
+#define c1 t->child[1]
+#define c2 t->child[2]
-#define delcode 100
-#define c0 t->child[0]
-#define c1 t->child[1]
-#define c2 t->child[2]
+int codep, ncode;
-#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)
+#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
+#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
+#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
-static struct
-{
- int cap;
- Code *buf, *ip, *end;
-} code;
+void stuffdot(int);
+char *fnstr(tree*);
+void outcode(tree*, int);
+void codeswitch(tree*, int);
+int iscase(tree*);
+code *codecopy(code*);
+void codefree(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;
+ ncode+=100;
+ codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
+ if(codebuf==0)
+ panic("Can't realloc %d bytes in morecode!",
+ ncode*sizeof codebuf[0]);
+ memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]);
+ return 0;
}
-static
void
-stuffdot(Code *p)
+stuffdot(int a)
{
- int a;
+ if(a<0 || codep<=a)
+ panic("Bad address %d in stuffdot", a);
+ codebuf[a].i = codep;
+}
- 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;
+int
+compile(tree *t)
+{
+ ncode = 100;
+ codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
+ codep = 0;
+ emiti(0); /* reference count */
+ outcode(t, flag['e']?1:0);
+ if(nerror){
+ efree((char *)codebuf);
+ return 0;
+ }
+ readhere();
+ emitf(Xreturn);
+ emitf(0);
+ return 1;
}
-static
void
-rcc(Tree *t, int eflag)
+cleanhere(char *f)
{
- Code *p, *q;
- Tree *tt;
+ emitf(Xdelhere);
+ emits(strdup(f));
+}
- if (!t)
- return;
+char*
+fnstr(tree *t)
+{
+ io *f = openstr();
+ char *v;
+ extern char nl;
+ char svnl = nl;
+ nl=';';
+ pfmt(f, "%t", t);
+ nl = svnl;
+ v = f->strp;
+ f->strp = 0;
+ closeio(f);
+ return v;
+}
- switch(t->type) {
- default:
- pfmt(errio, "bad type %d in rc compiler\n", t->type);
+void
+outcode(tree *t, int eflag)
+{
+ int p, q;
+ tree *tt;
+ if(t==0)
+ return;
+ if(t->type!=NOT && t->type!=';')
+ runq->iflast = 0;
+ switch(t->type){
+ default:
+ pfmt(err, "bad type %d in outcode\n", t->type);
break;
- case Tdol:
+ case '$':
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xdol);
break;
- case Tquote:
+ case '"':
emitf(Xmark);
- rcc(c0, eflag);
- emitf(Xflatten);
+ outcode(c0, eflag);
+ emitf(Xqdol);
break;
- case Tsub:
+ case SUB:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xsub);
break;
- case Tand:
+ case '&':
emitf(Xasync);
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
- case Tsemi:
- rcc(c0, eflag);
- rcc(c1, eflag);
+ case ';':
+ outcode(c0, eflag);
+ outcode(c1, eflag);
break;
- case Tcarot:
+ case '^':
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
- emitf(Xcat);
+ outcode(c0, eflag);
+ emitf(Xconc);
break;
- case Ttick:
- emitf(Xcmdsub);
- p = emiti(0);
- rcc(c0, 0);
- emitf(Xexit);
- stuffdot(p);
+ case '`':
+ emitf(Xbackq);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
- case Tandand:
- rcc(c0, 0);
+ case ANDAND:
+ outcode(c0, 0);
emitf(Xtrue);
p = emiti(0);
- rcc(c1, eflag);
+ outcode(c1, eflag);
stuffdot(p);
break;
- case Targs:
- rcc(c1, eflag);
- rcc(c0, eflag);
+ case ARGLIST:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
break;
- case Tbang:
- rcc(c0, eflag);
- emitf(Xnegate);
+ case BANG:
+ outcode(c0, eflag);
+ emitf(Xbang);
break;
- case Tparen:
- case Tbrace:
- rcc(c0, eflag);
+ case PCMD:
+ case BRACE:
+ outcode(c0, eflag);
break;
- case Tcount:
+ case COUNT:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xcount);
break;
- case Tfunc:
+ case FN:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
if(c1){
- emitf(Xfunc);
+ emitf(Xfn);
p = emiti(0);
emits(fnstr(c1));
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xunlocal); /* get rid of $* */
- emitf(Xkill);
+ emitf(Xreturn);
stuffdot(p);
- } else
- emitf(Xunfunc);
+ }
+ else
+ emitf(Xdelfn);
break;
- case Tif:
- rcc(c0, 0);
+ case IF:
+ outcode(c0, 0);
emitf(Xif);
p = emiti(0);
- rcc(c1, eflag);
- // emitf(Xwastrue);
+ outcode(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);
+ case NOT:
+ if(!runq->iflast)
+ yyerror("`if not' does not follow `if(...)'");
+ emitf(Xifnot);
+ p = emiti(0);
+ outcode(c0, eflag);
+ stuffdot(p);
+ break;
+ case OROR:
+ outcode(c0, 0);
emitf(Xfalse);
p = emiti(0);
- rcc(c1, eflag);
+ outcode(c1, eflag);
stuffdot(p);
break;
- case Tpcmd:
- rcc(c0, eflag);
+ case PAREN:
+ outcode(c0, eflag);
break;
- case Tsimple:
+ case SIMPLE:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xsimple);
if(eflag)
emitf(Xeflag);
break;
- case Tsubshell:
+ case SUBSHELL:
emitf(Xsubshell);
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
if(eflag)
emitf(Xeflag);
break;
- case Tswitch:
+ case SWITCH:
codeswitch(t, eflag);
break;
- case Ttwiddle:
+ case TWIDDLE:
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xmatch);
if(eflag)
emitf(Xeflag);
break;
- case Twhile:
- q = code.ip;
- rcc(c0, 0);
- if(q==code.ip)
+ case WHILE:
+ q = codep;
+ outcode(c0, 0);
+ if(q==codep)
emitf(Xsettrue); /* empty condition == while(true) */
emitf(Xtrue);
p = emiti(0);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xjump);
- emiti(q-code.buf);
+ emiti(q);
stuffdot(p);
break;
- case Twords:
- rcc(c1, eflag);
- rcc(c0, eflag);
+ case WORDS:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
break;
- case Tfor:
+ case FOR:
emitf(Xmark);
if(c1){
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xglob);
- } else{
+ }
+ else{
emitf(Xmark);
emitf(Xword);
emits(strdup("*"));
@@ -216,120 +269,221 @@ rcc(Tree *t, int eflag)
}
emitf(Xmark); /* dummy value for Xlocal */
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xlocal);
p = emitf(Xfor);
q = emiti(0);
- rcc(c2, eflag);
+ outcode(c2, eflag);
emitf(Xjump);
- emiti(p-code.buf);
+ emiti(p);
stuffdot(q);
emitf(Xunlocal);
break;
- case Tword:
+ case WORD:
emitf(Xword);
emits(strdup(t->str));
break;
- case Tdup:
- if(t->redir.type == Rdupfd){
+ case DUP:
+ if(t->rtype==DUPFD){
emitf(Xdup);
- emiti(t->redir.fd[0]);
- emiti(t->redir.fd[1]);
- } else{
+ emiti(t->fd0);
+ emiti(t->fd1);
+ }
+ else{
emitf(Xclose);
- emiti(t->redir.fd[0]);
+ emiti(t->fd0);
}
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xpopredir);
break;
- case Tpipefd:
+ case PIPEFD:
emitf(Xpipefd);
- emiti(t->redir.type);
- p = emiti(0);
- rcc(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ emiti(t->rtype);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ }
break;
- case Tredir:
+ case REDIR:
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xglob);
- switch(t->redir.type){
- case Rappend:
+ switch(t->rtype){
+ case APPEND:
emitf(Xappend);
break;
- case Rwrite:
+ case WRITE:
emitf(Xwrite);
break;
- case Rread:
- case Rhere:
+ case READ:
+ case HERE:
emitf(Xread);
break;
- case Rrdwr:
+ case RDWR:
emitf(Xrdwr);
break;
}
- emiti(t->redir.fd[0]);
- rcc(c1, eflag);
+ emiti(t->fd0);
+ outcode(c1, eflag);
emitf(Xpopredir);
break;
- case Teq:
+ case '=':
tt = t;
- for(;t && t->type==Teq;t = c2);
+ for(;t && t->type=='=';t = c2);
if(t){
- for(t = tt;t->type==Teq;t = c2){
+ for(t = tt;t->type=='=';t = c2){
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xlocal);
}
- rcc(t, eflag);
- for(t = tt; t->type==Teq; t = c2)
+ outcode(t, eflag);
+ for(t = tt; t->type=='='; t = c2)
emitf(Xunlocal);
- } else{
+ }
+ else{
for(t = tt;t;t = c2){
emitf(Xmark);
- rcc(c1, eflag);
+ outcode(c1, eflag);
emitf(Xmark);
- rcc(c0, eflag);
+ outcode(c0, eflag);
emitf(Xassign);
}
}
t = tt; /* so tests below will work */
break;
- case Tpipe:
+ case PIPE:
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);
+ emiti(t->fd0);
+ emiti(t->fd1);
+ if(havefork){
+ p = emiti(0);
+ q = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ q = emiti(0);
+ }
+ outcode(c1, eflag);
+ emitf(Xreturn);
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;
+ if(t->type!=NOT && t->type!=';')
+ runq->iflast = t->type==IF;
+ else if(c0) runq->iflast = c0->type==IF;
+}
+/*
+ * switch code looks like this:
+ * Xmark
+ * (get switch value)
+ * Xjump 1f
+ * out: Xjump leave
+ * 1: Xmark
+ * (get case values)
+ * Xcase 1f
+ * (commands)
+ * Xjump out
+ * 1: Xmark
+ * (get case values)
+ * Xcase 1f
+ * (commands)
+ * Xjump out
+ * 1:
+ * leave:
+ * Xpopm
+ */
+
+void
+codeswitch(tree *t, int eflag)
+{
+ int leave; /* patch jump address to leave switch */
+ int out; /* jump here to leave switch */
+ int nextcase; /* patch jump address to next case */
+ tree *tt;
+ if(c1->child[0]==nil
+ || c1->child[0]->type!=';'
+ || !iscase(c1->child[0]->child[0])){
+ yyerror("case missing in switch");
+ return;
+ }
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xjump);
+ nextcase = emiti(0);
+ out = emitf(Xjump);
+ leave = emiti(0);
+ stuffdot(nextcase);
+ t = c1->child[0];
+ while(t->type==';'){
+ tt = c1;
+ emitf(Xmark);
+ for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
+ emitf(Xcase);
+ nextcase = emiti(0);
+ t = tt;
+ for(;;){
+ if(t->type==';'){
+ if(iscase(c0)) break;
+ outcode(c0, eflag);
+ t = c1;
+ }
+ else{
+ if(!iscase(t)) outcode(t, eflag);
+ break;
+ }
+ }
+ emitf(Xjump);
+ emiti(out);
+ stuffdot(nextcase);
+ }
+ stuffdot(leave);
+ emitf(Xpopm);
}
-Code*
-compile(Tree *t)
+int
+iscase(tree *t)
{
- code.cap = delcode;
- code.buf = code.ip = emalloc(code.cap*sizeof *code.buf);
- code.end = code.ip + code.cap;
+ if(t->type!=SIMPLE)
+ return 0;
+ do t = c0; while(t->type==ARGLIST);
+ return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
+}
- emiti(0);
- rcc(t, 0);
- emitf(Xkill);
- emitf(nil);
+code*
+codecopy(code *cp)
+{
+ cp[0].i++;
+ return cp;
+}
- return code.buf;
+void
+codefree(code *cp)
+{
+ code *p;
+ if(--cp[0].i!=0)
+ return;
+ for(p = cp+1;p->f;p++){
+ if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
+ || p->f==Xrdwr
+ || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
+ || p->f==Xfor || p->f==Xjump
+ || p->f==Xsubshell || p->f==Xtrue) p++;
+ else if(p->f==Xdup || p->f==Xpipefd) p+=2;
+ else if(p->f==Xpipe) p+=4;
+ else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
+ else if(p->f==Xfn){
+ efree(p[2].s);
+ p+=2;
+ }
+ }
+ efree((char *)cp);
}