From ef9a1546814c5b02a74f40667ac59d45a9cc06c9 Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Mon, 26 Jul 2021 00:02:14 -0700 Subject: [PATCH] cc: add const arrays (wip) Add a preliminary version of const arrays. It sorta works. Right now this is limited to function-scope const arrays. --- tools/cc.ebnf | 4 ++-- tools/cc.py | 65 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/tools/cc.ebnf b/tools/cc.ebnf index f48a3f4..3d6955f 100644 --- a/tools/cc.ebnf +++ b/tools/cc.ebnf @@ -41,10 +41,10 @@ local_var: type symbol initializer? local_array: type symbol sized_array* (sized_array | empty_array) initializer? ";" empty_array: "[" "]" sized_array: "[" array_size "]" -initializer: "=" (expression | initializer_list) +?initializer: "=" (expression | initializer_list) initializer_list: "{" [init_list_field ("," init_list_field)* ","? ] "}" ?init_list_field: "." field "=" expression - | expression + | prec14_expr // precedence from https://en.cppreference.com/w/c/language/operator_precedence diff --git a/tools/cc.py b/tools/cc.py index 6236b11..be0579f 100644 --- a/tools/cc.py +++ b/tools/cc.py @@ -330,6 +330,7 @@ class Struct: class CType: volatile: bool = False const: bool = False + size: int = 2 @dataclass class StructType(CType): @@ -399,17 +400,11 @@ class CcTransform(lark.visitors.Transformer): if isinstance(typ, str): if typ == 'void': return VoidType() - return PodType(volatile=volat, const=const, pod=typ) + size = 1 if typ == 'char' else 2 + return PodType(volatile=volat, const=const, pod=typ, size=size) else: return typ - def array_item(self, children): - # transform blarg[foo] into *(blarg + foo) because reasons - # TODO: bring this over to the main parser, we need to know the type - # of blarg in order to compute the actual offset - addop = lark.Tree('add', children) - return lark.Tree('dereference', [addop]) - # operations on literals can be done by the compiler add = _binary_op(lambda a, b: a+b) sub = _binary_op(lambda a, b: a-b) @@ -421,6 +416,7 @@ class CcTransform(lark.visitors.Transformer): SIGNED_NUMBER = int HEX_LITTERAL = lambda _, x: int(x[2:], 16) ESCAPED_STRING = lambda _, x: ast.literal_eval(x) + INT = int class AsmOp: @@ -840,7 +836,7 @@ class Delayed(AsmOp): def litt_type(val): if isinstance(val, str): - return PointerType(pointed=PodType(pod='char', const=True)) + return PointerType(pointed=PodType(pod='char', size=1, const=True)) elif isinstance(val, float): return PodType(pod='float', const=True) else: @@ -865,6 +861,7 @@ class CcInterp(lark.visitors.Interpreter): self.next_marker = 0 self.strings = {} self.next_string_token = 0 + self.rodata = {} def _lookup_symbol(self, s): scope = self.cur_scope @@ -900,7 +897,7 @@ class CcInterp(lark.visitors.Interpreter): assert s is not None, f'unknown identifier {ident}' if isinstance(s, FunctionSpec) or ident in self.global_scope.symbols: reg = self.cur_fun.regs.take(reg=reg, orwhatever=True) - return SetAddr(self.cur_fun, [reg, ident]) + return SetAddr(self.cur_fun, [reg, s.name]) else: if s.type.volatile: self._log(f'loading volatile {s}') @@ -957,6 +954,23 @@ class CcInterp(lark.visitors.Interpreter): tree.op = Delayed(delayed) tree.type = litt_type(tree.children[0]) + def array_item(self, tree): + # transform blarg[foo] into *(blarg + foo) because reasons + # TODO: bring this over to the main parser, we need to know the type + # of blarg in order to compute the actual offset + s = self._lookup_symbol(tree.children[0].children[0]) + if s.type.pointed.size == 1: + # easy deref + add + tree.children = [lark.Tree('add', tree.children)] + return self.dereference(tree) + + # everything else is 16 bit, do something like: + # array[index] === *(array + (index << 1)) + add1 = lark.Tree('shl', [tree.children[1], lark.Tree('literal', [1])]) + add2 = lark.Tree('add', [tree.children[0], add1]) + tree.children = [add2] + return self.dereference(tree) + def _assign(self, left, right): self._log(f'assigning {left} = {right}') self.cur_fun.regs.assign(left, right) @@ -1328,11 +1342,35 @@ class CcInterp(lark.visitors.Interpreter): self.cur_scope.symbols[var.name] = var self.cur_fun.locals[var.name] = var if len(tree.children) > 2: - initval = tree.children[2].children[0].op.out + initval = tree.children[2].op.out cleanup = lambda reg: self._synth(Store(self.cur_fun, [reg, var])) self.cur_fun.regs.assign(var, initval, cleanup=cleanup) self._log(f'assigning {var} = {initval}') + def local_array(self, tree): + self.visit_children(tree) + assert self.cur_fun is not None + assert self.cur_scope is not None + var = Variable.from_def(tree) + if var.type.const: + # storing in rodata + assert len(tree.children) > 3 + tok = self.next_string_token + self.next_string_token += 1 + tok = f'_dat{tok}' + assert len(tree.children[3].children) > 0 + fields =[c.children[0] for c in tree.children[3].children] + if tree.children[2].data == 'empty_array': + fieldcount = len(fields) + else: + fieldcount = tree.children[2].children[0] + if len(fields) < fieldcount: + fields += [0] * (fieldcount - len(fields)) + name = tree.children[1] + self.rodata[tok] = (tree.children[0], fields) + var = Variable(PointerType(pointed=litt_type(fields[0])), tok) + self.global_scope.symbols[name] = var + def fun_def(self, tree): prot, body = tree.children fun = Function(prot) @@ -1439,6 +1477,11 @@ def parse_tree(tree, debug=False): nwords = len(dat) // 2 out += [f'.word 0x{d:04x}' for d in struct.unpack(f'>{nwords}H', dat)] out.append('') + for sym, (type, fields) in inte.rodata.items(): + out += [f'.global {sym}', + f'{sym}:'] + out += [f'.word 0x{d:04x}' for d in fields] + out.append('') return '\n'.join(filter_dupes(out))