aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/rc/code.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/rc/code.c')
-rw-r--r--src/cmd/rc/code.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/cmd/rc/code.c b/src/cmd/rc/code.c
new file mode 100644
index 0000000..786f284
--- /dev/null
+++ b/src/cmd/rc/code.c
@@ -0,0 +1,277 @@
+#include "rc.h"
+#include "parse.h"
+#include "exec.h"
+
+// -----------------------------------------------------------------------
+// types
+
+struct Interpreter
+{
+ int i, cap;
+ Code *code;
+};
+
+Code *compiled = nil;
+static struct Interpreter interpreter;
+#define emiti(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].i = (x), interpreter.i++)
+#define emitf(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].f = (x), interpreter.i++)
+#define emits(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].s = (x), interpreter.i++)
+
+static
+int
+grow(void)
+{
+ interpreter.cap += 100;
+ interpreter.code = erealloc(interpreter.code, sizeof(*interpreter.code)*interpreter.cap);
+ memset(interpreter.code+interpreter.cap-100, 0, 100*sizeof(*interpreter.code));
+
+ return 0;
+}
+
+static
+void
+storepc(int a)
+{
+ if(interpreter.i <= a || a < 0)
+ fatal("bad address %d in interpreter", a);
+
+ interpreter.code[a].i = interpreter.i;
+}
+
+static
+void
+walk(Tree *node)
+{
+ Tree *n;
+ int addr1, addr2;
+
+ if(!node)
+ return;
+
+ switch(node->type){
+ default:
+ print(shell.err, "bad type %d in interpreter walk\n", node->type);
+ fatal("crashing\n");
+ break;
+
+ case '$':
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xdollar);
+ break;
+
+ case Tcount:
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xcount);
+ break;
+
+ case Tjoin:
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xjoin);
+ break;
+
+ case Tindex:
+ emitf(Xmark);
+ walk(node->child[1]);
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xindex);
+ break;
+
+ case ';':
+ walk(node->child[0]);
+ walk(node->child[1]);
+ break;
+
+ case '^':
+ emitf(Xmark);
+ walk(node->child[1]);
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xconcatenate);
+ break;
+
+ case Tandand:
+ walk(node->child[0]);
+ emitf(Xtrue);
+ addr1 = emiti(0);
+ walk(node->child[1]);
+ storepc(addr1);
+ break;
+
+ case Toror:
+ walk(node->child[0]);
+ emitf(Xfalse);
+ addr1 = emiti(0);
+ walk(node->child[1]);
+ storepc(addr1);
+ break;
+
+ case Targs:
+ walk(node->child[1]);
+ walk(node->child[0]);
+ break;
+
+ case Tparen: case Tblock:
+ walk(node->child[0]);
+ break;
+
+ case Tbasic:
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xbasic);
+ break;
+
+ case Tbang:
+ walk(node->child[0]);
+ emitf(Xbang);
+
+ case Tword:
+ emitf(Xword);
+ emits(strdup(node->str));
+ break;
+
+ case Twords:
+ walk(node->child[1]);
+ walk(node->child[0]);
+ break;
+
+ case '=':
+ for(n=node; node && node->type == '='; node = node->child[2])
+ ;
+ if(node){
+ for(node=n; node->type=='='; node = node->child[2]){
+ emitf(Xmark);
+ walk(node->child[1]);
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xlocal);
+ }
+ walk(node);
+ for(node=n; node->type=='='; node = node->child[2])
+ emitf(Xunlocal);
+ }else{
+ for(node=n; node; node=node->child[2]){
+ emitf(Xmark);
+ walk(node->child[1]);
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xassign);
+ }
+ }
+ node = n;
+ break;
+ /* control structures */
+ case Twhile:
+ addr1 = interpreter.i; // head of loop
+ walk(node->child[0]);
+ if(addr1 == interpreter.i)
+ fatal("TODO");
+ emitf(Xtrue);
+ addr2 = emiti(0); // goto end of loop
+
+ walk(node->child[1]);
+ emitf(Xgoto);
+ emiti(addr1); // goto top of loop
+ storepc(addr2);
+ break;
+
+ case Tfor:
+ emitf(Xmark);
+ if(node->child[1]){ // for( x in X )
+ walk(node->child[1]);
+ // emitf(Xglob)
+ }else{ // for(X)
+ fatal("TODO");
+ }
+ emitf(Xmark); // null initial value for Xlocal
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xlocal);
+
+ addr1 = emitf(Xfor);
+ addr2 = emiti(0);
+
+ walk(node->child[2]);
+ emitf(Xgoto);
+ emiti(addr1);
+ storepc(addr2);
+ emitf(Xunlocal);
+ break;
+
+ /* forks */
+ case '&':
+ emitf(Xasync);
+ addr1 = emiti(0);
+ walk(node->child[0]);
+ emitf(Xexit);
+ storepc(addr1);
+ break;
+
+ case Tsubshell:
+ emitf(Xsubshell);
+ addr1 = emiti(0);
+ walk(node->child[0]);
+ emitf(Xexit);
+ storepc(addr1);
+ break;
+
+ case Tpipe:
+ emitf(Xpipe);
+
+ emiti(node->redir.fd[0]);
+ emiti(node->redir.fd[1]);
+ addr1 = emiti(0);
+ addr2 = emiti(0);
+
+ walk(node->child[0]);
+ emitf(Xexit);
+ storepc(addr1);
+
+ walk(node->child[1]);
+ emitf(Xreturn);
+ storepc(addr2);
+
+ emitf(Xpipewait);
+
+ break;
+ }
+}
+
+// -----------------------------------------------------------------------
+// main exports
+
+void
+freecode(Code *c)
+{
+ if(--c[0].i!=0)
+ return;
+ efree(c);
+}
+
+Code *
+copycode(Code *c)
+{
+ c[0].i++;
+ return c;
+}
+
+int
+compile(Tree *node)
+{
+ flush(shell.err);
+
+ interpreter.i = 0;
+ interpreter.code = emalloc(100*sizeof(*interpreter.code));
+ emiti(0); // reference count: no thread owns code yet
+
+ walk(node);
+
+ emitf(Xreturn);
+ emitf(nil);
+
+ compiled = interpreter.code;
+ return 0;
+}