#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; }