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:
parent
e7bab6e9e6
commit
ef9a154681
@ -41,10 +41,10 @@ local_var: type symbol initializer?
|
|||||||
local_array: type symbol sized_array* (sized_array | empty_array) initializer? ";"
|
local_array: type symbol sized_array* (sized_array | empty_array) initializer? ";"
|
||||||
empty_array: "[" "]"
|
empty_array: "[" "]"
|
||||||
sized_array: "[" array_size "]"
|
sized_array: "[" array_size "]"
|
||||||
initializer: "=" (expression | initializer_list)
|
?initializer: "=" (expression | initializer_list)
|
||||||
initializer_list: "{" [init_list_field ("," init_list_field)* ","? ] "}"
|
initializer_list: "{" [init_list_field ("," init_list_field)* ","? ] "}"
|
||||||
?init_list_field: "." field "=" expression
|
?init_list_field: "." field "=" expression
|
||||||
| expression
|
| prec14_expr
|
||||||
|
|
||||||
// precedence from https://en.cppreference.com/w/c/language/operator_precedence
|
// precedence from https://en.cppreference.com/w/c/language/operator_precedence
|
||||||
|
|
||||||
|
65
tools/cc.py
65
tools/cc.py
@ -330,6 +330,7 @@ class Struct:
|
|||||||
class CType:
|
class CType:
|
||||||
volatile: bool = False
|
volatile: bool = False
|
||||||
const: bool = False
|
const: bool = False
|
||||||
|
size: int = 2
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class StructType(CType):
|
class StructType(CType):
|
||||||
@ -399,17 +400,11 @@ class CcTransform(lark.visitors.Transformer):
|
|||||||
if isinstance(typ, str):
|
if isinstance(typ, str):
|
||||||
if typ == 'void':
|
if typ == 'void':
|
||||||
return VoidType()
|
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:
|
else:
|
||||||
return typ
|
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
|
# operations on literals can be done by the compiler
|
||||||
add = _binary_op(lambda a, b: a+b)
|
add = _binary_op(lambda a, b: a+b)
|
||||||
sub = _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
|
SIGNED_NUMBER = int
|
||||||
HEX_LITTERAL = lambda _, x: int(x[2:], 16)
|
HEX_LITTERAL = lambda _, x: int(x[2:], 16)
|
||||||
ESCAPED_STRING = lambda _, x: ast.literal_eval(x)
|
ESCAPED_STRING = lambda _, x: ast.literal_eval(x)
|
||||||
|
INT = int
|
||||||
|
|
||||||
|
|
||||||
class AsmOp:
|
class AsmOp:
|
||||||
@ -840,7 +836,7 @@ class Delayed(AsmOp):
|
|||||||
|
|
||||||
def litt_type(val):
|
def litt_type(val):
|
||||||
if isinstance(val, str):
|
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):
|
elif isinstance(val, float):
|
||||||
return PodType(pod='float', const=True)
|
return PodType(pod='float', const=True)
|
||||||
else:
|
else:
|
||||||
@ -865,6 +861,7 @@ class CcInterp(lark.visitors.Interpreter):
|
|||||||
self.next_marker = 0
|
self.next_marker = 0
|
||||||
self.strings = {}
|
self.strings = {}
|
||||||
self.next_string_token = 0
|
self.next_string_token = 0
|
||||||
|
self.rodata = {}
|
||||||
|
|
||||||
def _lookup_symbol(self, s):
|
def _lookup_symbol(self, s):
|
||||||
scope = self.cur_scope
|
scope = self.cur_scope
|
||||||
@ -900,7 +897,7 @@ class CcInterp(lark.visitors.Interpreter):
|
|||||||
assert s is not None, f'unknown identifier {ident}'
|
assert s is not None, f'unknown identifier {ident}'
|
||||||
if isinstance(s, FunctionSpec) or ident in self.global_scope.symbols:
|
if isinstance(s, FunctionSpec) or ident in self.global_scope.symbols:
|
||||||
reg = self.cur_fun.regs.take(reg=reg, orwhatever=True)
|
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:
|
else:
|
||||||
if s.type.volatile:
|
if s.type.volatile:
|
||||||
self._log(f'loading volatile {s}')
|
self._log(f'loading volatile {s}')
|
||||||
@ -957,6 +954,23 @@ class CcInterp(lark.visitors.Interpreter):
|
|||||||
tree.op = Delayed(delayed)
|
tree.op = Delayed(delayed)
|
||||||
tree.type = litt_type(tree.children[0])
|
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):
|
def _assign(self, left, right):
|
||||||
self._log(f'assigning {left} = {right}')
|
self._log(f'assigning {left} = {right}')
|
||||||
self.cur_fun.regs.assign(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_scope.symbols[var.name] = var
|
||||||
self.cur_fun.locals[var.name] = var
|
self.cur_fun.locals[var.name] = var
|
||||||
if len(tree.children) > 2:
|
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]))
|
cleanup = lambda reg: self._synth(Store(self.cur_fun, [reg, var]))
|
||||||
self.cur_fun.regs.assign(var, initval, cleanup=cleanup)
|
self.cur_fun.regs.assign(var, initval, cleanup=cleanup)
|
||||||
self._log(f'assigning {var} = {initval}')
|
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):
|
def fun_def(self, tree):
|
||||||
prot, body = tree.children
|
prot, body = tree.children
|
||||||
fun = Function(prot)
|
fun = Function(prot)
|
||||||
@ -1439,6 +1477,11 @@ def parse_tree(tree, debug=False):
|
|||||||
nwords = len(dat) // 2
|
nwords = len(dat) // 2
|
||||||
out += [f'.word 0x{d:04x}' for d in struct.unpack(f'>{nwords}H', dat)]
|
out += [f'.word 0x{d:04x}' for d in struct.unpack(f'>{nwords}H', dat)]
|
||||||
out.append('')
|
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))
|
return '\n'.join(filter_dupes(out))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user