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.
This commit is contained in:
Paul Mathieu 2021-07-26 00:02:14 -07:00
parent e7bab6e9e6
commit ef9a154681
2 changed files with 56 additions and 13 deletions

View File

@ -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

View File

@ -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))