summaryrefslogtreecommitdiff
path: root/utils/rcsh/code.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /utils/rcsh/code.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'utils/rcsh/code.c')
-rw-r--r--utils/rcsh/code.c486
1 files changed, 486 insertions, 0 deletions
diff --git a/utils/rcsh/code.c b/utils/rcsh/code.c
new file mode 100644
index 00000000..06aea6ff
--- /dev/null
+++ b/utils/rcsh/code.c
@@ -0,0 +1,486 @@
+#include "rc.h"
+#include "y.tab.h"
+
+#define c0 t->child[0]
+#define c1 t->child[1]
+#define c2 t->child[2]
+#define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f=(x), codep++)
+#define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i=(x), codep++)
+#define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s=(x), codep++)
+
+void stuffdot(int);
+char *fnstr(Tree*);
+void outcode(Tree*, int);
+void codeswitch(Tree*, int);
+int iscase(Tree*);
+Code *codecopy(Code*);
+void codefree(Code*);
+
+int codep, ncode;
+Code *codebuf;
+
+int
+morecode(void)
+{
+ ncode+=100;
+ codebuf=realloc(codebuf, ncode*sizeof codebuf[0]);
+ if(codebuf==0)
+ panic("Can't realloc %d bytes in morecode!",
+ ncode*sizeof codebuf[0]);
+ return 0; /* not used */
+}
+
+void
+stuffdot(int a)
+{
+ if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);
+ codebuf[a].i=codep;
+}
+
+int
+compile(Tree *t)
+{
+ ncode=100;
+ codebuf=malloc(ncode*sizeof codebuf[0]);
+ codep=0;
+ emiti(0); /* reference count */
+ outcode(t, flag['e']?1:0);
+ if(nerror){
+ free(codebuf);
+ return 0;
+ }
+/* readhere(); */
+ emitf(Xreturn);
+ emitf(0);
+ return 1;
+}
+
+void
+cleanhere(char *f)
+{
+ emitf(Xdelhere);
+ emits(strdup(f));
+}
+
+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;
+}
+
+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 '$':
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xdol);
+ break;
+ case '"':
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xqdol);
+ break;
+ case SUB:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xsub);
+ break;
+ case '&':
+ emitf(Xasync);
+ emits(fnstr(c0));
+/*
+ p=emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ break;
+ case ';':
+ outcode(c0, eflag);
+ outcode(c1, eflag);
+ break;
+ case '^':
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xconc);
+ break;
+ case '`':
+ emitf(Xbackq);
+ emits(fnstr(c0));
+/*
+ p=emiti(0);
+ outcode(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ break;
+ case ANDAND:
+ outcode(c0, 0);
+ emitf(Xtrue);
+ p=emiti(0);
+ outcode(c1, eflag);
+ stuffdot(p);
+ break;
+ case ARGLIST:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
+ break;
+ case BANG:
+ outcode(c0, eflag);
+ emitf(Xbang);
+ break;
+ case PCMD:
+ case BRACE:
+ outcode(c0, eflag);
+ break;
+ case COUNT:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xcount);
+ break;
+ case FN:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ if(c1){
+ emitf(Xfn);
+ p=emiti(0);
+ emits(fnstr(c1));
+ outcode(c1, eflag);
+ emitf(Xunlocal); /* get rid of $* */
+ emitf(Xreturn);
+ stuffdot(p);
+ }
+ else
+ emitf(Xdelfn);
+ break;
+ case IF:
+ outcode(c0, 0);
+ emitf(Xif);
+ p=emiti(0);
+ outcode(c1, eflag);
+ emitf(Xwastrue);
+ stuffdot(p);
+ break;
+ 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);
+ outcode(c1, eflag);
+ stuffdot(p);
+ break;
+ case PAREN:
+ outcode(c0, eflag);
+ break;
+ case SIMPLE:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xsimple);
+ if(eflag) emitf(Xeflag);
+ break;
+ case SUBSHELL:
+ emitf(Xsubshell);
+ emits(fnstr(c0));
+/*
+ p=emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ if(eflag) emitf(Xeflag);
+ break;
+ case SWITCH:
+ codeswitch(t, eflag);
+ break;
+ case TWIDDLE:
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xmatch);
+ if(eflag) emitf(Xeflag);
+ break;
+ case WHILE:
+ q=codep;
+ emitf(Xsettrue);
+ outcode(c0, 0);
+ emitf(Xtrue);
+ p=emiti(0);
+ outcode(c1, eflag);
+ emitf(Xjump);
+ emiti(q);
+ stuffdot(p);
+ break;
+ case WORDS:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
+ break;
+ case FOR:
+ emitf(Xmark);
+ if(c1){
+ outcode(c1, eflag);
+ emitf(Xglob);
+ }
+ else{
+ emitf(Xmark);
+ emitf(Xword);
+ emits(strdup("*"));
+ emitf(Xdol);
+ }
+ emitf(Xmark); /* dummy value for Xlocal */
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xlocal);
+ p=emitf(Xfor);
+ q=emiti(0);
+ outcode(c2, eflag);
+ emitf(Xjump);
+ emiti(p);
+ stuffdot(q);
+ emitf(Xunlocal);
+ break;
+ case WORD:
+ emitf(Xword);
+ emits(strdup(t->str));
+ break;
+ case DUP:
+ if(t->rtype==DUPFD) {
+ emitf(Xdup);
+ emiti(t->fd0);
+ emiti(t->fd1);
+ } else { /* t->rtype == CLOSE */
+ emitf(Xclose);
+ emiti(t->fd0);
+ }
+ outcode(c1, eflag);
+ emitf(Xpopredir);
+ break;
+/*
+ case PIPEFD:
+ emitf(Xpipefd);
+ emiti(t->rtype);
+ p=emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ break;
+*/
+ case REDIR:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xglob);
+ switch(t->rtype){
+ case APPEND:
+ emitf(Xappend);
+ break;
+ case WRITE:
+ emitf(Xwrite);
+ break;
+ case READ:
+ case HERE:
+ emitf(Xread);
+ break;
+ }
+ emiti(t->fd0);
+ outcode(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);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xlocal);
+ }
+ t=tt;
+ outcode(c2, eflag);
+ for(;t->type=='=';t=c2)
+ emitf(Xunlocal);
+ }
+ else{
+ for(t=tt;t;t=c2){
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xassign);
+ }
+ }
+ t=tt; /* so tests below will work */
+ break;
+ case PIPE:
+ emitf(Xpipe);
+ emiti(t->fd0);
+ emiti(t->fd1);
+ emits(fnstr(c0));
+ q=emiti(0);
+/*
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ outcode(c1, eflag);
+ emitf(Xreturn);
+ stuffdot(q);
+ emitf(Xpipewait);
+ break;
+ }
+ 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]->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{
+ outcode(t, eflag);
+ break;
+ }
+ }
+ emitf(Xjump);
+ emiti(out);
+ stuffdot(nextcase);
+ }
+ stuffdot(leave);
+ emitf(Xpopm);
+}
+
+int
+iscase(Tree *t)
+{
+ if(t->type!=SIMPLE)
+ return 0;
+ do
+ t=c0;
+ while(t->type==ARGLIST);
+
+ return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
+}
+
+Code *
+codecopy(Code *cp)
+{
+ cp[0].i++;
+ return cp;
+}
+
+void
+codefree(Code *cp)
+{
+ Code *p;
+
+ if(--cp[0].i!=0)
+ return;
+
+ for(p=cp+1;p->f;){
+ if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
+ || p->f==Xasync || p->f==Xcase || p->f==Xfalse
+ || p->f==Xfor || p->f==Xjump
+ || p->f==Xsubshell || p->f==Xtrue)
+ p+=2;
+ else if(p->f==Xdup || p->f==Xpipefd)
+ p+=3;
+ else if(p->f==Xpipe) {
+ free(p[3].s);
+ p+=5;
+ } else if(p->f==Xword || p->f==Xdelhere || p->f==Xbackq) {
+ free(p[1].s);
+ p+=2;
+ } else if(p->f==Xfn){
+ free(p[2].s);
+ p+=3;
+ } else
+ p++;
+ }
+
+ free(cp);
+}