summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/compiler.lm424
-rw-r--r--src/compiler/expr.lm4
-rw-r--r--src/compiler/native.c80
3 files changed, 382 insertions, 126 deletions
diff --git a/src/compiler/compiler.lm b/src/compiler/compiler.lm
index 3571527..d0864b4 100644
--- a/src/compiler/compiler.lm
+++ b/src/compiler/compiler.lm
@@ -40,7 +40,7 @@ context fspec
def declaration
value:int
- [name:reference::variable::type `= expr::enum::type] { lhs.value = const_int_expr(r3.collapsed) enum_set(lhs.value) enum_inc() }
+ [name:reference::variable::type `= expr::enum::type] commit { lhs.value = const_int_expr(r3.collapsed) enum_set(lhs.value) enum_inc() }
| [name:reference::variable::type] { lhs.value = enum_get() enum_inc() }
def item
@@ -81,14 +81,13 @@ context fspec
context select
lex
ignore / '//' [^\n]* '\n' | space+ /
- literal `( `) `{ `} `*
+ literal `( `) `{ `} `* `:
end
literal `select
def item
- [`* `) data:declaration::type]
- | [expr:expr::paren::type `) data:declaration::type]
+ [expr:expr::select::type `) data:declaration::type]
def type
name:str
@@ -105,7 +104,7 @@ context fspec
lex
ignore / '//' [^\n]* '\n' | space+ /
literal `: `[ `] `| `;
- token VISUAL / 'nul' | 'dec' | 'hex' | 'str' /
+ token VISUAL / 'nul' | 'dec' | 'hex' | 'str' | 'flt' /
end
literal `enum `struct
@@ -116,39 +115,12 @@ context fspec
def filter
[`| function:reference::function::type]
- def subscript
+ def dimension
[`[ expr:expr::bracket::type `: slice:expr::bracket::type `]]
| [`[ expr:expr::bracket::type `]]
def extra
- # if set, this field has trivial length, otherwise need to read subscripts
- length:collapser::collapsed
- [subscript:subscript* filter:filter* visual:visual?] {
- f:str = ''
- has_slice:bool
- for l:subscript in repeat(r1) {
- if (l.slice) {
- f = ''
- has_slice = true
- break
- }
-
- if (f != '')
- f = f + '*'
-
- if (l.expr.collapsed.result.value) {
- f = f + '(' + $l.expr.collapsed.result.value + ')'
- } else {
- f = f + '(' + $l.expr.collapsed + ')'
- }
- }
-
- if (f == '' && !has_slice)
- f = '1'
-
- if (f != '')
- lhs.length = collapser::stream(f)
- }
+ [dimension:dimension* filter:filter* visual:visual?]
def type
# enum name <primitive> name <extra>;
@@ -170,6 +142,8 @@ context fspec
| [container:container::type name:reference::variable::type extra:extra `;]
# (enum|struct) name { ... } <filters>;
| [container:container::type filter:filter* `;]
+ # name(...);
+ | [function:reference::function::type `;]
end
def source
@@ -211,14 +185,18 @@ pop_scope()
}
any
+lookup_in_scope_no_error(type:str, name:str, s:scope)
+{
+ cmap:map<str, any> = s->names->find(type)
+ if (cmap) return cmap->find(name)
+ return nil
+}
+
+any
lookup_no_error(type:str, name:str) {
for s:scope in g_scopes {
- cmap:map<str, any> = s->names->find(type)
- if (cmap) {
- var:any = cmap->find(name)
- if (var)
- return var
- }
+ v:any = lookup_in_scope_no_error(type, name, s)
+ if (v) return v
}
return nil
}
@@ -249,9 +227,10 @@ insert(type:str, name:str, var:any)
}
any
-lookup(type:str, name:str)
+lookup(type:str, name:str, s:scope)
{
- r:any = lookup_no_error(type, name)
+ r:any = nil
+ if (s) r = lookup_in_scope_no_error(type, name, s) else r = lookup_no_error(type, name)
if (!r) {
print('`', type, ' ', name, '` is not declared in this or outer scope!\n')
exit(1)
@@ -259,119 +238,324 @@ lookup(type:str, name:str)
return r
}
-str
-container_name_str(s:str) { if (!s) return '<anon>' return s }
+global g_cscope:map<any, scope> = new map<any, scope>()
+global g_regs:map<any, int> = new map<any, int>()
+global g_offs:map<any, int> = new map<any, int>()
+global g_ops:map<str, int> = new map<str, int>()
+global g_visuals:map<str, int> = new map<str, int>()
+global g_types:map<str, int> = new map<str, int>()
+
+g_ops->insert('-#', 0)
+g_ops->insert('!', 1)
+g_ops->insert('~', 2)
+g_ops->insert('*', 3)
+g_ops->insert('/', 4)
+g_ops->insert('%', 5)
+g_ops->insert('#+', 6)
+g_ops->insert('#-', 7)
+g_ops->insert('<<', 8)
+g_ops->insert('>>', 9)
+g_ops->insert('<', 10)
+g_ops->insert('<=', 11)
+g_ops->insert('==', 12)
+g_ops->insert('!=', 13)
+g_ops->insert('&', 14)
+g_ops->insert('|', 15)
+g_ops->insert('^', 16)
+g_ops->insert('&&', 17)
+g_ops->insert('||', 18)
+g_ops->insert(':', 19)
+g_ops->insert(']', 20)
+
+g_visuals->insert('nul', 0)
+g_visuals->insert('dec', 1)
+g_visuals->insert('hex', 2)
+g_visuals->insert('str', 3)
+g_visuals->insert('flt', 4)
+
+g_types->insert('enum', 0)
+g_types->insert('struct', 1)
+g_types->insert('select', 2) # UNION
+
+global INS_VERSION:int = 0
+global INS_REG:int = 1
+global INS_PUSH:int = 2
+global INS_PUSHR:int = 3
+global INS_STORE:int = 4
+global INS_OP:int = 5
+global INS_QUEUE:int = 6
+global INS_IO:int = 7
+global INS_EXEC:int = 8
+global INS_CALL:int = 9
+global INS_JMP:int = 10
+global INS_JMPIF:int = 11
+
+int insbuf_written() = c_insbuf_written
+str flush_insbuf() = c_flush_insbuf
+void write_ins(ins:int, num:int) = c_write_ins
+void write_ins_with_data(ins:int, data:str) = c_write_ins_with_data
+
+global g_regc:int = 1
+
+void
+new_reg(v:any, data:str)
+{
+ if (g_regs->find(v)) {
+ print('Register for `', $v, '` already exists!\n')
+ exit(1)
+ }
-str
-signed_str(s:bool) { if (s) return 'signed' return 'unsigned' }
+ if (!data) data = ''
+ write_ins_with_data(INS_REG, data)
+ print(flush_insbuf())
+ g_regs->insert(v, g_regc)
+ g_regc = g_regc + 1
+}
-global INDSTP:str = '░ '
+void
+write_data_if_not_there(v:str)
+{
+ if (!g_regs->find(v))
+ new_reg(v, v)
+}
void
-print_declaration(d:fspec::declaration::type, ind:str)
+find_data_in(s:any)
{
- insert('variable', $d.name, d)
- print(ind, 'variable `', $d.name, "` that's ")
+ for v:string::type in s
+ write_data_if_not_there(v.raw)
+ for v:reference::function::type in s
+ write_data_if_not_there($v.name)
+}
- c:fspec::container::type
- if (d.cref) c = lookup($d.cref, $d.parent) else c = d.container
+write_ins(INS_VERSION, 1)
+for e:expr::paren::type in source
+ find_data_in(e.collapsed)
+for e:expr::bracket::type in source
+ find_data_in(e.collapsed)
+for e:expr::arg::type in source
+ find_data_in(e.collapsed)
+for f:reference::function::type in source
+ write_data_if_not_there($f.name)
+for d:fspec::declaration::type in source {
+ if (d.name)
+ write_data_if_not_there($d.name)
+ if (d.container && d.container.data.name)
+ write_data_if_not_there($d.container.data.name)
+}
- if (c) {
- print('`', c.data.type, ' ', container_name_str(c.data.name), '` ')
+global g_fcr:int = g_regc
+write_ins_with_data(INS_REG, '')
+g_regc = g_regc + 1
- if (c.data.select)
- print('with expression `', $c.data.select, '` ')
+void
+write_expr(expr:collapser::reducer::collapsed)
+{
+ for o:collapser::reducer::operation in repeat(expr) {
+ for v:collapser::reducer::value in child(o) {
+ if (v.number) {
+ write_ins(INS_PUSH, v.number.value)
+ } else if (v.string) {
+ write_ins(INS_PUSHR, g_regs->find(v.string.raw))
+ } else if (v.reference) {
+ if (v.reference.variable) {
+ write_ins(INS_PUSHR, g_regs->find(lookup('variable', $v.reference.variable.name, nil)))
+ } else if (v.reference.function) {
+ if ($v.reference.function.name != 'until') {
+ for a:expr::arg::type in v.reference.function
+ write_expr(a.collapsed.result)
+ write_ins(INS_CALL, g_regs->find($v.reference.function.name))
+ }
+ }
+ }
+ }
+ for vop:collapser::reducer::valueop in child(o) {
+ if ($vop.op == '.') {
+ s:scope = nil
+ d:fspec::declaration::type = nil
+ off:int = 0
+ for r:reference::variable::type in vop {
+ d = lookup('variable', $r.name, s)
+ if (d.container) {
+ s = g_cscope->find(%d.container)
+ off = g_offs->find(%d.container)
+ }
+ }
+ write_ins(INS_PUSHR, off + g_regs->find(%d))
+ } else {
+ write_ins(INS_OP, g_ops->find($vop.op))
+ }
+ }
}
+}
- if (d.primitive)
- print(d.primitive.bits, ' bits and ', signed_str(d.primitive.signed))
+void
+write_postexpr(expr:collapser::reducer::collapsed, start:int)
+{
+ for o:collapser::reducer::operation in repeat(expr) {
+ for v:collapser::reducer::value in child(o) {
+ if (v.reference && v.reference.function) {
+ if ($v.reference.function.name == 'until') {
+ for a:expr::arg::type in v.reference.function
+ write_expr(a.collapsed.result)
+ write_ins(INS_OP, g_ops->find('!'))
+ write_ins(INS_JMPIF, start)
+ }
+ }
+ }
+ }
+}
- print('\n')
+void
+write_declaration(d:fspec::declaration::type, index:int)
+{
+ if (!d.name) {
+ print('something went wrong!\n')
+ exit(1)
+ }
+ c:fspec::container::type = d.container
+ if (d.cref) c = lookup($d.cref, $d.parent, nil)
+
+ locs:map<any, int> = new map<any, int>()
if (d.extra) {
- if (d.extra.length) {
- if (!d.extra.length.result.value || d.extra.length.result.value.reference) {
- print(ind, INDSTP, 'it has a variable length that needs to be computed with formula `', $d.extra.length, '`\n')
- } else {
- if (d.extra.length.result.value.number) {
- print(ind, INDSTP, 'it has a constant length of ', $d.extra.length.result.value, '\n')
- } else if (d.extra.length.result.value.string) {
- print(ind, INDSTP, ' its length will increase until pattern `', d.extra.length.result.value.string.escaped, '` has been read from stream\n')
- }
- }
- } else {
- print(ind, INDSTP, 'the subscripts contain slices, and thus needs some runtime loops to be computed\n')
+ for l:fspec::declaration::dimension in repeat(d.extra.dimension) {
+ locs->insert(%l, insbuf_written())
+ write_expr(l.expr.collapsed.result)
}
- for f:fspec::declaration::filter in repeat(d.extra.filter)
- print(ind, INDSTP, 'it needs to be filtered with `', $f.function, '`\n')
+ #for f:fspec::declaration::filter in repeat(d.extra.filter) {
+ # for a:expr::arg::type in f
+ # write_expr(a.collapsed.result)
+ # write_ins(INS_CALL, g_regs->find($f.function.name))
+ #}
+ }
+
+ if (!c) {
+ write_ins(INS_PUSHR, g_fcr)
+ write_ins(INS_PUSH, index)
+ write_ins(INS_OP, g_ops->find('#+'))
+ write_ins(INS_IO, d.primitive.bits)
+ } else {
+ write_ins(INS_PUSH, g_offs->find(%c))
+ write_ins(INS_STORE, g_fcr)
+ write_ins(INS_EXEC, g_regs->find(%c))
+ }
- for v:fspec::declaration::visual in child(d.extra.visual)
- print(ind, INDSTP, 'it should be visualized as `', $v.name, '`\n')
+ if (d.extra) {
+ for l:fspec::declaration::dimension in repeat(d.extra.dimension)
+ write_postexpr(l.expr.collapsed.result, locs->find(%l))
}
}
void
-walk(d:fspec::declaration::type, ind:str)
+walk1(d:fspec::declaration::type)
{
if (!d.container) {
print('something went wrong!\n')
exit(1)
}
- s:fspec::container::type = d.container
- insert($s.data.type, s.data.name, s)
+ for i:fspec::container::strukt::item in repeat(d.container.data.items)
+ if (i.data.container)
+ walk1(i.data)
- if (d.name) {
- print_declaration(d, ind)
- ind = ind + INDSTP
- print(ind, 'and it contains\n')
- } else {
- print(ind, 'container `', s.data.type, ' ', container_name_str(s.data.name), '`')
- if ($d.filter != '') {
- print('\n')
- ind = ind + INDSTP
- for f:fspec::declaration::filter in repeat(d.filter)
- print(ind, 'it needs to be filtered with `', $f.function, '`\n')
- print(ind, 'and it contains\n')
- } else {
- print(' that contains\n')
- }
+ for i:fspec::container::select::item in repeat(d.container.data.items)
+ if (i.data.container)
+ walk1(i.data)
+
+ g_offs->insert(%d.container, g_regc)
+
+ for i:fspec::container::enum::item in repeat(d.container.data.items) {
+ # somehow need to get this constant time (not reg)
}
- if ($s.data.type == 'enum') {
- for i:fspec::container::enum::item in repeat(s.data.items) {
- print(ind, INDSTP, 'constant `', $i.decl.name, '` which value is ', $i.decl.value, '\n')
- insert('variable', $i.decl.name, i)
- }
- } else if ($s.data.type == 'struct') {
+ for i:fspec::container::strukt::item in repeat(d.container.data.items) {
+ if (i.data.primitive)
+ new_reg(%i.data, nil)
+ }
+
+ for i:fspec::container::select::item in repeat(d.container.data.items) {
+ if (i.data.primitive)
+ new_reg(%i.data, nil)
+ }
+}
+
+void
+walk2(d:fspec::declaration::type)
+{
+ if (!d.container) {
+ print('something went wrong!\n')
+ exit(1)
+ }
+
+ insert($d.container.data.type, d.container.data.name, %d.container)
+
+ if ($d.container.data.type != 'enum')
push_scope()
- for i:fspec::container::strukt::item in repeat(s.data.items) {
- if (i.data.container)
- walk(i.data, ind + INDSTP)
- else
- print_declaration(i.data, ind + INDSTP)
+
+ for i:fspec::container::enum::item in repeat(d.container.data.items)
+ insert('variable', $i.decl.name, %i.decl)
+
+ for i:fspec::container::strukt::item in repeat(d.container.data.items) {
+ if (i.data.container)
+ walk2(i.data)
+ if (i.data.name)
+ insert('variable', $i.data.name, %i.data)
+ }
+
+ for i:fspec::container::select::item in repeat(d.container.data.items) {
+ if (i.data.container)
+ walk2(i.data)
+ if (i.data.name)
+ insert('variable', $i.data.name, %i.data)
+ }
+
+ if (!d.name) {
+ write_ins(INS_PUSH, g_offs->find(%d.container))
+ write_ins(INS_STORE, g_fcr)
+ }
+
+ index:int = 0
+ for i:fspec::container::strukt::item in repeat(d.container.data.items)
+ if (i.data.name) {
+ write_declaration(i.data, index)
+ index = index + 1
+ } else if (i.data.function) {
+ for a:expr::arg::type in i.data.function
+ write_expr(a.collapsed.result)
+ write_ins(INS_CALL, g_regs->find($i.data.function.name))
}
- pop_scope()
- } else if ($s.data.type == 'select') {
- ind = ind + INDSTP
- push_scope()
- for i:fspec::container::select::item in repeat(s.data.items) {
- if (i.expr)
- print(ind, 'in case of (', $i.expr, ')\n')
- else
- print(ind, 'or otherwise\n')
-
- if (i.data.container)
- walk(i.data, ind + INDSTP)
- else
- print_declaration(i.data, ind + INDSTP)
+
+ for i:fspec::container::select::item in repeat(d.container.data.items) {
+ if (i.data.name) {
+ if (i.expr) {
+ write_expr(d.container.data.select.collapsed.result)
+ write_expr(i.expr.collapsed.result)
+ write_ins(INS_OP, g_ops->find('=='))
+ }
+ write_declaration(i.data, index)
+ index = index + 1
}
- pop_scope()
}
+
+ if (insbuf_written()) {
+ new_reg(%d.container, flush_insbuf())
+ print(flush_insbuf())
+ }
+
+ g_cscope->insert(%d, g_scopes->top)
+
+ if ($d.container.data.type != 'enum')
+ pop_scope()
}
+for d:fspec::declaration::type in repeat(source.items)
+ walk1(d)
+
push_scope()
for d:fspec::declaration::type in repeat(source.items)
- walk(d, '')
+ walk2(d)
pop_scope()
+
+print(flush_insbuf())
diff --git a/src/compiler/expr.lm b/src/compiler/expr.lm
index feff7af..7c650b4 100644
--- a/src/compiler/expr.lm
+++ b/src/compiler/expr.lm
@@ -37,9 +37,9 @@ context expr
def type
collapsed:collapser::collapsed
- [syntax+] {
+ [syntax+] commit {
lhs.collapsed = collapser::stream($r1)
- if (!lhs.collapsed) reject
+ if (!lhs.collapsed && $r1 != '*') reject
}
end
diff --git a/src/compiler/native.c b/src/compiler/native.c
index d0ca252..bbb0060 100644
--- a/src/compiler/native.c
+++ b/src/compiler/native.c
@@ -81,8 +81,7 @@ c_op_stack_top(program_t *prg, tree_t **sp, value_t a)
return NULL;
const union opstr op = { .u8 = stack->data[stack->index - 1] };
- tree_t *s = construct_string(prg, colm_string_alloc_pointer(prg, opstr_lookup + op.offset, 1 + op.size));
- return (str_t*)upref(prg, s);
+ return (str_t*)upref(prg, construct_string(prg, colm_string_alloc_pointer(prg, opstr_lookup + op.offset, 1 + op.size)));
}
value_t
@@ -111,6 +110,77 @@ c_op_stack_pop(program_t *prg, tree_t **sp, value_t a)
return r;
}
+static uint8_t
+bits_for_n(const uint8_t n, const uint8_t used)
+{
+ return 16 * (1 << n) - used;
+}
+
+static uint8_t
+n_for_v(const uint64_t v, const uint8_t used)
+{
+ const uint8_t bits = __builtin_ctzl((v ? v : 1));
+ if (used <= 16 && bits < bits_for_n(0, used))
+ return 0;
+ else if (used <= 32 && bits < bits_for_n(1, used))
+ return 1;
+ else if (used <= 64 && bits < bits_for_n(2, used))
+ return 2;
+
+ errx(EXIT_FAILURE, "numbers over 57 bits not supported right now.. sorry :D");
+ return 3;
+}
+
+static void
+vle_instruction(const uint8_t name, const uint64_t v, uint8_t out[16], uint8_t *out_written)
+{
+ assert(out && out_written);
+ const union {
+ struct { unsigned name:5; unsigned n:2; uint64_t v:57; } ins;
+ uint8_t v[16];
+ } u = { .ins = { .name = name, .n = n_for_v(v, 7), .v = v } };
+ *out_written = sizeof(uint16_t) * (1 << u.ins.n);
+ memcpy(out, u.v, *out_written);
+}
+
+struct insbuf {
+ uint8_t data[sizeof(uint16_t) * 1024];
+ size_t written;
+} insbuf = {0};
+
+str_t*
+c_flush_insbuf(program_t *prg, tree_t **sp)
+{
+ tree_t *s = upref(prg, construct_string(prg, string_alloc_full(prg, insbuf.data, insbuf.written)));
+ insbuf.written = 0;
+ return (str_t*)s;
+}
+
+int
+c_insbuf_written(program_t *prg, tree_t **sp)
+{
+ return insbuf.written;
+}
+
+void
+c_write_ins(program_t *prg, tree_t **sp, value_t a, value_t b)
+{
+ uint8_t out[16], written;
+ vle_instruction(a, b, out, &written);
+ memcpy(&insbuf.data[insbuf.written], out, written);
+ insbuf.written += written;
+}
+
+void
+c_write_ins_with_data(program_t *prg, tree_t **sp, value_t a, str_t *b)
+{
+ assert(b);
+ c_write_ins(prg, sp, a, b->value->length);
+ memcpy(&insbuf.data[insbuf.written], b->value->data, b->value->length);
+ insbuf.written += b->value->length;
+ colm_tree_downref(prg, sp, (tree_t*)b);
+}
+
value_t
c_strtoull(program_t *prg, tree_t **sp, str_t *a, value_t b)
{
@@ -131,6 +201,8 @@ str_t*
c_esc2chr(program_t *prg, tree_t **sp, str_t *a)
{
assert(a);
+ const char hay = *a->value->data;
+ colm_tree_downref(prg, sp, (tree_t*)a);
static const struct { const char e, v; } map[] = {
{ .e = 'a', .v = '\a' },
@@ -147,14 +219,14 @@ c_esc2chr(program_t *prg, tree_t **sp, str_t *a)
};
for (size_t i = 0; i < ARRAY_SIZE(map); ++i) {
- if (*a->value->data != map[i].e)
+ if (hay != map[i].e)
continue;
tree_t *s = construct_string(prg, colm_string_alloc_pointer(prg, &map[i].v, 1));
return (str_t*)upref(prg, s);
}
- errx(EXIT_FAILURE, "%s: unknown escape character `%c`", __func__, *a->value->data);
+ errx(EXIT_FAILURE, "%s: unknown escape character `%c`", __func__, hay);
return NULL;
}