aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/rc/code.c
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-15 16:18:02 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-15 16:18:02 -0700
commitbf03074e346b004659196b6c17eee04dbffd3ac2 (patch)
tree7200db30f1ef7e3661091552932eb304bd4ce9c6 /sys/cmd/rc/code.c
parent566d54fe549286895fdef8aa9f385686405dd290 (diff)
feat(rc): working prototype of input->compile->print loop
Diffstat (limited to 'sys/cmd/rc/code.c')
-rw-r--r--sys/cmd/rc/code.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
new file mode 100644
index 0000000..6deed89
--- /dev/null
+++ b/sys/cmd/rc/code.c
@@ -0,0 +1,164 @@
+#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
+stashaddr(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)
+{
+ int p;
+ Tree *n;
+
+ if(!node)
+ return;
+
+ switch(node->type){
+ default:
+ print(errio, "bad type %d in interpreter walk\n", node->type);
+ break;
+
+ case '$':
+ emitf(Xmark);
+ walk(node->child[0]);
+ emitf(Xdollar);
+ break;
+
+ case '&':
+ emitf(Xasync);
+ p = emiti(0);
+ emitf(Xexit);
+ stashaddr(p);
+ 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 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 Tword:
+ emitf(Xword);
+ emits(strdup(node->str));
+ 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;
+ }
+}
+
+// -----------------------------------------------------------------------
+// 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(errio);
+ print(errio, "%t\n", node);
+
+ interpreter.i = 0;
+ emiti(1); // reference count
+
+ walk(node);
+
+ emitf(Xreturn);
+ emitf(nil);
+
+ compiled = interpreter.code;
+ return 0;
+}