diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-07-09 15:43:10 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-07-09 15:43:10 +0300 |
| commit | 7f1f9ec8e75b3627b795ddecd7e391a5ebe95528 (patch) | |
| tree | 88efbff4d9d64f6589687a59224d245e00975d0d | |
| parent | 2432cb953afa8ec3063307e3a788d7126b97318b (diff) | |
| download | bcgen-7f1f9ec8e75b3627b795ddecd7e391a5ebe95528.tar.gz bcgen-7f1f9ec8e75b3627b795ddecd7e391a5ebe95528.zip | |
change so that bcode.h and bcode.c are generated
| -rw-r--r-- | .gitignore | 3 | ||||
| -rwxr-xr-x | bcgen | 372 | ||||
| -rw-r--r-- | bcode.c | 116 | ||||
| -rw-r--r-- | bcode.h | 41 | ||||
| -rw-r--r-- | example/Makefile | 8 | ||||
| -rw-r--r-- | example/main.c | 6 | ||||
| -rw-r--r-- | example/rules.py | 3 |
7 files changed, 277 insertions, 272 deletions
@@ -1,3 +1,4 @@ -gen/* *.o +example/bcode.c +example/bcode.h example/exec @@ -3,6 +3,169 @@ import sys import pathlib +bcode_header_fmt = ''' +#ifndef BCGEN_BCODE_H +#define BCGEN_BCODE_H + +#include <stddef.h> + +typedef unsigned long ubcval_t; +typedef signed long sbcval_t; +typedef float fbcval_t; +typedef double dbcval_t; +typedef size_t bcreloc_t; + +typedef union {{ + ubcval_t r; + sbcval_t s; + fbcval_t f; + dbcval_t d; +}} bcval_t; + +struct run_state {{ + void* (*op); + bcval_t *imm; +}}; + +struct compile_state {{ + struct run_state s; + void* (*labels); + size_t size; + size_t pc; +}}; + +{} + +ubcval_t run(struct compile_state *cs); +void init(struct compile_state *cs); +void end(struct compile_state *cs); +void destroy(struct compile_state *cs); + +bcval_t label(struct compile_state *cs); +void patch(struct compile_state *cs, bcreloc_t reloc, bcval_t imm); + +#endif /* BCGEN_BCODE_H */ +''' + +bcode_src_fmt = ''' +#include <stdlib.h> +#include <assert.h> +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +#include "bcode.h" + +{} + +enum bcode_insn {{ + END, + {} +}}; + +static void append(struct compile_state *cs, enum bcode_insn label, bcval_t imm) +{{ + assert(cs->labels); + + if (cs->pc == cs->size) {{ + cs->size *= 2; + /* better memory checks could be a good idea */ + void *p = realloc(cs->s.op, cs->size * sizeof(*cs->s.op)); + assert(p); + + p = realloc(cs->s.imm, cs->size * sizeof(*cs->s.imm)); + assert(p); + }} + + struct run_state *s = &cs->s; + s->op[cs->pc] = cs->labels[label]; + s->imm[cs->pc] = imm; + cs->pc++; +}} + +#define RELOC cs->pc +#define PUSH_OP(label) append(cs, label, (bcval_t){{ .r = 0 }}) +#define PUSH_IMM_OP(label, imm) append(cs, label, (bcval_t){{ .r = imm }}) +#define PUSH_DIMM_OP(label, dimm) append(cs, label, (bcval_t){{ .d = dimm }}) + +{} +{} + +#define IMM s.imm[pc].r +#define SIMM s.imm[pc].s +#define FIMM s.imm[pc].f +#define DIMM s.imm[pc].d + +#define NEXT_INSN goto *s.op[++pc] +#define JUMP(i) goto *s.op[pc = (i)] + +static ubcval_t _run(struct compile_state *cs, bool init) +{{ + static void *labels[] = {{ + [END] = &&end, + {} + }}; + + if (init) {{ + cs->labels = labels; + return 0; + }} + +{} +{} + + const struct run_state s = cs->s; + size_t pc = 0; + JUMP(pc); + +{} + +end: /* we assume there's always at least one general register */ + return r0; +}} + +ubcval_t run(struct compile_state *cs) +{{ + return _run(cs, false); +}} + +void init(struct compile_state *cs) +{{ + cs->labels = NULL; + cs->size = 16; + + cs->s.imm = malloc(cs->size * sizeof(*cs->s.imm)); + assert(cs->s.imm); + + cs->s.op = malloc(cs->size * sizeof(*cs->s.op)); + assert(cs->s.op); + + cs->pc = 0; + _run(cs, true); +}} + +void end(struct compile_state *cs) +{{ + PUSH_OP(END); +}} + +bcval_t label(struct compile_state *cs) +{{ + return (bcval_t){{.r = cs->pc}}; +}} + +void patch(struct compile_state *cs, bcreloc_t reloc, bcval_t imm) +{{ + cs->s.imm[reloc] = imm; +}} + +void destroy(struct compile_state *cs) +{{ + free(cs->s.op); + free(cs->s.imm); +}} +''' + def check_fmt(fmt): # todo: should sign value be encoded in the registers? assert(len(fmt) == 6) @@ -24,18 +187,6 @@ def gen_label(name, r0, r1, r2, r3): def gen_enum(name, r0, r1, r2, r3): return gen_label(name, r0, r1, r2, r3).upper() -def gen_exec_instance(f, name, r0, r1, r2, r3): - label = gen_label(name, r0, r1, r2, r3) + ': ' - macro = '{}({}, {}, {}, {}); '.format(name.upper(), r0, r1, r2, r3) - next = 'NEXT_INSN;' - f.write(label + macro + next + '\n') - -# gen should maybe just generate the string and print_ would print it? -def gen_static_instance(f, name, r0, r1, r2, r3): - label = gen_label(name, r0, r1, r2, r3) - enum = gen_enum(name, r0, r1, r2, r3) - f.write('[' + enum + '] = &&' + label + ',\n') - def gen_params(fmt): n = 0 r = "" @@ -70,75 +221,68 @@ def gen_cond(r, i): return 'a' + str(i) + ' == ' + r[1:] -def gen_select_instance(f, name, r0, r1, r2, r3): - c0 = gen_cond(r0, 0) - c1 = gen_cond(r1, 1) - c2 = gen_cond(r2, 2) - c3 = gen_cond(r3, 3) - cond = c0 + ' && ' + c1 + ' && ' + c2 + ' && ' + c3 - action = 'label = ' + gen_enum(name, r0, r1, r2, r3) + ';' - f.write('else if (' + cond + ') {' + action + '}\n') - -def gen_enum_instance(f, name, r0, r1, r2, r3): - enum = gen_enum(name, r0, r1, r2, r3) - f.write(enum + ',\n') - class BCGen: def __init__(self, r = 3, f = 3, extra='', head=''): self.r = r self.f = f - # make sure gen dir exists - pathlib.Path('gen').mkdir(exist_ok=True) - - # clear out files - with open('gen/body.inc', 'w') as inc: - pass + self.extra = extra + self.head = head - with open('gen/macro.inc', 'w') as inc: - pass + gregs = ['ubcval_t r' + str(i) + ' = 0;\n' for i in range(r)] + fregs = ['dbcval_t f' + str(i) + ' = 0;\n' for i in range(f)] - with open('gen/static.inc', 'w') as inc: - pass + self.regs = '' + self.body = '' + self.enum = '' + self.macro = '' + self.static = '' + self.select = '' + self.select_header = '' - with open('gen/select.inc', 'w') as inc: - pass + for g in gregs: + self.regs += g - with open('gen/enum.inc', 'w') as inc: - pass + for f in fregs: + self.regs += f - with open('gen/select.h', 'w') as h: - pass + def gen_exec_instance(self, name, r0, r1, r2, r3): + label = gen_label(name, r0, r1, r2, r3) + ': ' + macro = '{}({}, {}, {}, {}); '.format(name.upper(), r0, r1, r2, r3) + next = 'NEXT_INSN;' + self.body += label + macro + next + '\n' - with open('gen/extra.inc', 'w') as inc: - inc.write(extra) + # gen should maybe just generate the string and print_ would print it? + def gen_static_instance(self, name, r0, r1, r2, r3): + label = gen_label(name, r0, r1, r2, r3) + enum = gen_enum(name, r0, r1, r2, r3) + self.static += '[' + enum + '] = &&' + label + ',\n' - with open('gen/head.inc', 'w') as inc: - inc.write(head) + def gen_select_instance(self, name, r0, r1, r2, r3): + c0 = gen_cond(r0, 0) + c1 = gen_cond(r1, 1) + c2 = gen_cond(r2, 2) + c3 = gen_cond(r3, 3) + cond = c0 + ' && ' + c1 + ' && ' + c2 + ' && ' + c3 + action = 'label = ' + gen_enum(name, r0, r1, r2, r3) + ';' + self.select += 'else if (' + cond + ') {' + action + '}\n' - with open('gen/regs.inc', 'w') as inc: - gregs = ['ubcval_t r' + str(i) + ' = 0;\n' for i in range(r)] - fregs = ['dbcval_t f' + str(i) + ' = 0;\n' for i in range(f)] - - for g in gregs: - inc.write(g); - - for f in fregs: - inc.write(f) + def gen_enum_instance(self, name, r0, r1, r2, r3): + enum = gen_enum(name, r0, r1, r2, r3) + self.enum += enum + ',\n' def gen_macro(self, name, fmt, body): - with open('gen/macro.inc', 'a') as f: - name = name.upper() + name = name.upper() - p0 = param(fmt, 0) - p1 = param(fmt, 1) - p2 = param(fmt, 2) - p3 = param(fmt, 3) + p0 = param(fmt, 0) + p1 = param(fmt, 1) + p2 = param(fmt, 2) + p3 = param(fmt, 3) - macro = '#define {}({}, {}, {}, {}) {}\n'.format( - name, p0, p1, p2, p3, body.replace('\n', '')) + macro = '#define {}({}, {}, {}, {}) {}\n'.format( + name, p0, p1, p2, p3, body.replace('\n', '')) - f.write(macro) + self.macro += macro def place(self, fmt, i): c = fmt[i + 1] @@ -151,60 +295,56 @@ class BCGen: return [""] def gen_body(self, name, fmt): - with open('gen/body.inc', 'a') as f: - for r0 in self.place(fmt, 0): - for r1 in self.place(fmt, 1): - for r2 in self.place(fmt, 2): - for r3 in self.place(fmt, 3): - gen_exec_instance(f, name, r0, r1, r2, r3) + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + self.gen_exec_instance(name, r0, r1, r2, r3) def gen_static(self, name, fmt): - with open('gen/static.inc', 'a') as f: - for r0 in self.place(fmt, 0): - for r1 in self.place(fmt, 1): - for r2 in self.place(fmt, 2): - for r3 in self.place(fmt, 3): - gen_static_instance(f, name, r0, r1, r2, r3) + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + self.gen_static_instance(name, r0, r1, r2, r3) def gen_select(self, name, fmt): - with open('gen/select.h', 'a') as f: - sign = gen_signature(name, fmt) - f.write(sign + ';\n') + sign = gen_signature(name, fmt) + self.select_header += sign + ';\n' + + sign = gen_signature(name, fmt) + self.select += sign + '\n' + self.select += '{\nenum bcode_insn label = 0;\n' + if fmt[0] == 'r': + self.select += 'bcreloc_t reloc = RELOC;\n' - with open('gen/select.inc', 'a') as f: - sign = gen_signature(name, fmt) - f.write(sign + '\n') - f.write('{\nenum bcode_insn label = 0;\n') - if fmt[0] == 'r': - f.write('bcreloc_t reloc = RELOC;\n') - # kind of ugly but simplifies gen_select_instance a fair bit - f.write('if (0) {}\n') + # kind of ugly but simplifies gen_select_instance a fair bit + self.select += 'if (0) {}\n' - for r0 in self.place(fmt, 0): - for r1 in self.place(fmt, 1): - for r2 in self.place(fmt, 2): - for r3 in self.place(fmt, 3): - gen_select_instance(f, name, r0, r1, r2, r3) + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + self.gen_select_instance(name, r0, r1, r2, r3) - if fmt[5] == 'I': - f.write('PUSH_IMM_OP(label, imm);\n') - elif fmt[5] == 'D': - f.write('PUSH_DIMM_OP(label, dimm);\n') - else: - f.write('PUSH_OP(label);\n') + if fmt[5] == 'I': + self.select += 'PUSH_IMM_OP(label, imm);\n' + elif fmt[5] == 'D': + self.select += 'PUSH_DIMM_OP(label, dimm);\n' + else: + self.select += 'PUSH_OP(label);\n' - if fmt[0] == 'r': - f.write('return reloc;\n') + if fmt[0] == 'r': + self.select += 'return reloc;\n' - f.write('}\n') + self.select += '}\n' def gen_enum(self, name, fmt): - with open('gen/enum.inc', 'a') as f: - for r0 in self.place(fmt, 0): - for r1 in self.place(fmt, 1): - for r2 in self.place(fmt, 2): - for r3 in self.place(fmt, 3): - gen_enum_instance(f, name, r0, r1, r2, r3) + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + self.gen_enum_instance(name, r0, r1, r2, r3) def rule(self, name, fmt, body): @@ -215,5 +355,25 @@ class BCGen: self.gen_body(name, fmt) self.gen_enum(name, fmt) + def write(self, name='bcode'): + with open(name + '.h', 'w') as f: + f.write(bcode_header_fmt.format( + self.select_header + )) + + with open(name + '.c', 'w') as f: + # unsure if this is the best way to handle format strings, but I guess + # it works for now + f.write(bcode_src_fmt.format( + self.head, + self.enum, + self.select, + self.macro, + self.static, + self.regs, + self.extra, + self.body + )) + assert(len(sys.argv) == 2) exec(open(sys.argv[1]).read()) diff --git a/bcode.c b/bcode.c deleted file mode 100644 index 2f67250..0000000 --- a/bcode.c +++ /dev/null @@ -1,116 +0,0 @@ -#include <stdlib.h> -#include <assert.h> -#include <stdint.h> -#include <stddef.h> -#include <stdbool.h> - -#include "bcode.h" - -#include "gen/head.inc" - -enum bcode_insn { - END, -#include "gen/enum.inc" -}; - -static void append(struct compile_state *cs, enum bcode_insn label, bcval_t imm) -{ - assert(cs->labels); - - if (cs->pc == cs->size) { - cs->size *= 2; - /* better memory checks could be a good idea */ - void *p = realloc(cs->s.op, cs->size * sizeof(*cs->s.op)); - assert(p); - - p = realloc(cs->s.imm, cs->size * sizeof(*cs->s.imm)); - assert(p); - } - - struct run_state *s = &cs->s; - s->op[cs->pc] = cs->labels[label]; - s->imm[cs->pc] = imm; - cs->pc++; -} - -#define RELOC cs->pc -#define PUSH_OP(label) append(cs, label, (bcval_t){ .r = 0 }) -#define PUSH_IMM_OP(label, imm) append(cs, label, (bcval_t){ .r = imm }) -#define PUSH_DIMM_OP(label, dimm) append(cs, label, (bcval_t){ .d = dimm }) - -#include "gen/select.inc" -#include "gen/macro.inc" - -#define IMM s.imm[pc].r -#define SIMM s.imm[pc].s -#define FIMM s.imm[pc].f -#define DIMM s.imm[pc].d - -#define NEXT_INSN goto *s.op[++pc] -#define JUMP(i) goto *s.op[pc = (i)] - -static ubcval_t _run(struct compile_state *cs, bool init) -{ - static void *labels[] = { - [END] = &&end, -#include "gen/static.inc" - }; - - if (init) { - cs->labels = labels; - return 0; - } - -#include "gen/regs.inc" -#include "gen/extra.inc" - - const struct run_state s = cs->s; - size_t pc = 0; - JUMP(pc); - -#include "gen/body.inc" - -end: /* we assume there's always at least one general register */ - return r0; -} - -ubcval_t run(struct compile_state *cs) -{ - return _run(cs, false); -} - -void init(struct compile_state *cs) -{ - cs->labels = NULL; - cs->size = 16; - - cs->s.imm = malloc(cs->size * sizeof(*cs->s.imm)); - assert(cs->s.imm); - - cs->s.op = malloc(cs->size * sizeof(*cs->s.op)); - assert(cs->s.op); - - cs->pc = 0; - _run(cs, true); -} - -void end(struct compile_state *cs) -{ - PUSH_OP(END); -} - -bcval_t label(struct compile_state *cs) -{ - return (bcval_t){.r = cs->pc}; -} - -void patch(struct compile_state *cs, bcreloc_t reloc, bcval_t imm) -{ - cs->s.imm[reloc] = imm; -} - -void destroy(struct compile_state *cs) -{ - free(cs->s.op); - free(cs->s.imm); -} diff --git a/bcode.h b/bcode.h deleted file mode 100644 index a42f2f9..0000000 --- a/bcode.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef BCGEN_BCODE_H -#define BCGEN_BCODE_H - -#include <stddef.h> - -typedef unsigned long ubcval_t; -typedef signed long sbcval_t; -typedef float fbcval_t; -typedef double dbcval_t; -typedef size_t bcreloc_t; - -typedef union { - ubcval_t r; - sbcval_t s; - fbcval_t f; - dbcval_t d; -} bcval_t; - -struct run_state { - void* (*op); - bcval_t *imm; -}; - -struct compile_state { - struct run_state s; - void* (*labels); - size_t size; - size_t pc; -}; - -#include "gen/select.h" - -ubcval_t run(struct compile_state *cs); -void init(struct compile_state *cs); -void end(struct compile_state *cs); -void destroy(struct compile_state *cs); - -bcval_t label(struct compile_state *cs); -void patch(struct compile_state *cs, bcreloc_t reloc, bcval_t imm); - -#endif /* BCGEN_BCODE_H */ diff --git a/example/Makefile b/example/Makefile index 0bce1ec..d9b0158 100644 --- a/example/Makefile +++ b/example/Makefile @@ -5,13 +5,11 @@ all: exec exec: bcode.o main.o $(CC) $(CFLAGS) $^ -o $@ -bcode.o: ../bcode.c +bcode.o: bcode.c $(CC) $(CFLAGS) -c $^ -o $@ -../bcode.c: ../gen/select.h -../gen/select.h: rules.py - cd .. && ./bcgen example/rules.py - touch ../bcode.c # just to get make to wake up +bcode.c: rules.py + ../bcgen rules.py .PHONY: clean clean: diff --git a/example/main.c b/example/main.c index 7ca152b..7e086a7 100644 --- a/example/main.c +++ b/example/main.c @@ -1,5 +1,5 @@ #include <stdio.h> -#include "../bcode.h" +#include "bcode.h" int main() { @@ -10,10 +10,10 @@ int main() select_movi(&cs, 1, 1000000000); // limit select_movi(&cs, 0, 0); // total - breg_t l = label(&cs); // top + bcval_t l = label(&cs); // top select_addr(&cs, 0, 0, 2); // add iter to total select_addi(&cs, 2, 2, 1); - breloc_t r = select_bltr(&cs, 2, 1, 0); // 0 is placeholder value, + bcreloc_t r = select_bltr(&cs, 2, 1, 0); // 0 is placeholder value, // should maybe add in an // UNDEFINED macro or something end(&cs); diff --git a/example/rules.py b/example/rules.py index 9c8d62e..90d35b1 100644 --- a/example/rules.py +++ b/example/rules.py @@ -1,5 +1,8 @@ g = BCGen(r = 7, f = 0) + g.rule('addr', '_RRR__', 'R0 = R1 + R2;') g.rule('addi', '_RR__I', 'R0 = R1 + IMM;') g.rule('movi', '_R___I', 'R0 = IMM;') g.rule('bltr', 'rRR__I', 'if (R0 < R1) JUMP(IMM);') + +g.write() |
