aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-07-09 15:43:10 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2023-07-09 15:43:10 +0300
commit7f1f9ec8e75b3627b795ddecd7e391a5ebe95528 (patch)
tree88efbff4d9d64f6589687a59224d245e00975d0d
parent2432cb953afa8ec3063307e3a788d7126b97318b (diff)
downloadbcgen-7f1f9ec8e75b3627b795ddecd7e391a5ebe95528.tar.gz
bcgen-7f1f9ec8e75b3627b795ddecd7e391a5ebe95528.zip
change so that bcode.h and bcode.c are generated
-rw-r--r--.gitignore3
-rwxr-xr-xbcgen372
-rw-r--r--bcode.c116
-rw-r--r--bcode.h41
-rw-r--r--example/Makefile8
-rw-r--r--example/main.c6
-rw-r--r--example/rules.py3
7 files changed, 277 insertions, 272 deletions
diff --git a/.gitignore b/.gitignore
index 9feb4eb..3c30f65 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-gen/*
*.o
+example/bcode.c
+example/bcode.h
example/exec
diff --git a/bcgen b/bcgen
index 0c9d5aa..7547886 100755
--- a/bcgen
+++ b/bcgen
@@ -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()