diff options
Diffstat (limited to 'bytecode/oper.c')
| -rw-r--r-- | bytecode/oper.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/bytecode/oper.c b/bytecode/oper.c new file mode 100644 index 0000000..ed4a681 --- /dev/null +++ b/bytecode/oper.c @@ -0,0 +1,93 @@ +#include <stdbool.h> +#include <stdlib.h> + +#include "encoding.h" +#include "panic.h" +#include "slice.h" +#include "value.h" + +#include "oper.h" + +struct st { + size_t i; + value locals[8]; +}; + +static value read_arg(struct st *s, struct arg arg) +{ + if (arg.constant) { + return arg.constant; + } + return s->locals[arg.local]; +} + +static void alloc(struct st *s, struct op oper) +{ + s->locals[oper.alloc.out] = from_pointer(calloc(to_int(read_arg(s, oper.alloc.size)), sizeof(value))); +} + +static void call(struct st *s) +{ + s->i = to_int(s->locals[0]); +} + +static void poke(struct st *s, struct op oper) +{ + value *p = to_pointer(s->locals[oper.poke.pointer]); + p[oper.poke.offset] = read_arg(s, oper.poke.value); +} + +static void peek(struct st *s, struct op oper) +{ + value *p = to_pointer(read_arg(s, oper.peek.value)); + s->locals[oper.peek.out] = p[oper.peek.offset]; +} + +static void shuf(struct st *s, struct op oper) +{ + s->locals[oper.shuf.out] = read_arg(s, oper.shuf.value); +} + +static void oexit(struct st *s, struct op oper) +{ + exit(to_int(read_arg(s, oper.exit.value))); +} + +static void op(struct st *s, struct op oper) +{ + switch (oper.code) { + case OALLOC: + alloc(s, oper); + break; + case OCALL: + call(s); + break; + case OPOKE: + poke(s, oper); + break; + case OPEEK: + peek(s, oper); + break; + case OSHUF: + shuf(s, oper); + break; + case OEXIT: + oexit(s, oper); + break; + default: + panicf("Invalid op: %x\n", oper.code); + } +} + +void run(struct slice prog) +{ + struct st s = { + .i = 0, + .locals = { 0 }, + }; + while (true) { + struct result oper = parse(slice1(prog, s.i)); + s.i += oper.n; + op(&s, oper.op); + } +} |
