Add support for char litterals and <<

Also streamline cc.py to do it all:
- cpp
- cc
- as

LD is still a separate step
This commit is contained in:
Paul Mathieu 2021-02-18 21:20:35 -08:00
parent 0b77dc5d20
commit 0157e235e4
2 changed files with 78 additions and 34 deletions

View File

@ -123,7 +123,7 @@ initializer_list: "{" [init_list_field ("," init_list_field)* ","? ] "}"
label: IDENTIFIER
litteral: SIGNED_NUMBER | ESCAPED_STRING | HEX_LITTERAL
litteral: SIGNED_NUMBER | ESCAPED_STRING | HEX_LITTERAL | CHARACTER
field: IDENTIFIER
identifier: IDENTIFIER
?symbol: IDENTIFIER
@ -145,6 +145,7 @@ struct_field: type IDENTIFIER sized_array* ";"
IDENTIFIER: /[_a-zA-Z]\w*/
COMMENT: /\/\/.*/
HEX_LITTERAL: /0x[a-fA-F0-9]+/
CHARACTER: /'[^']'/
%import common.WS

View File

@ -1,11 +1,18 @@
import argparse
import collections
import contextlib
import importlib
import io
import re
import subprocess
import sys
import lark
asmod = importlib.import_module("as")
GRAMMAR_FILE = '/home/paulmathieu/vhdl/bin/cc.ebnf'
CPP = ('cpp', '-P')
class Scope:
@ -91,7 +98,7 @@ class RegBank:
if not self.available:
assert self.vars, "nothing to clean, no more regs :/"
# storing one random var
var = self.vars.keys()[0]
var = list(self.vars.keys())[0]
self.evict(var)
return self.available.pop(0)
@ -267,6 +274,7 @@ class CcTransform(lark.visitors.Transformer):
mul = _binary_op(lambda a, b: a*b)
shl = _binary_op(lambda a, b: a<<b)
CHARACTER = lambda _, x: ord(x[1])
IDENTIFIER = str
SIGNED_NUMBER = int
HEX_LITTERAL = lambda _, x: int(x[2:], 16)
@ -321,26 +329,19 @@ AndOp = make_cpu_bin_op('and')
orOp = make_cpu_bin_op('or')
XorOp = make_cpu_bin_op('xor')
def combo(UnOp2, Op1):
"""Apply UnOp2 on the output of Op1."""
class _C(AsmOp):
scratch_need = max(Op1.scratch_need, UnOp2.scratch_need)
@property
def out(self):
return self.op2.out
def __init__(self, fun, ops):
self.op1 = Op1(fun, ops)
self.op2 = Op2(fun, self.op1.out)
class ShlOp(BinOp):
scratch_need = 3
def synth(self, scratches):
self.op1.synth(scratches)
self.op2.synth(scratches)
return _C
sc0, sc1, sc2 = scratches
return [f'or {sc0}, {self.right}, {self.right}',
f'or {self.dest}, {self.left}, {self.left}',
f'set {sc1}, 1',
f'set {sc2}, 0',
f'cmp {sc0}, {sc2}',
f'beq [pc, 6]',
f'add {self.dest}, {self.dest}, {self.dest}',
f'sub {sc0}, {sc0}, {sc1}',
f'bneq [pc, -6]']
class LtOp(BinOp):
@ -394,11 +395,6 @@ class NeqOp(BinOp):
def synth(self, scratches):
return [f'sub {self.dest}, {self.left}, {self.right}']
EqOp = combo(BoolNot, NeqOp)
LeOp = combo(BoolNot, GtOp)
GeOp = combo(BoolNot, LtOp)
class FnCall(AsmOp):
scratch_need = 1
@ -862,6 +858,13 @@ class CcInterp(lark.visitors.Interpreter):
self.cur_fun.regs.give(right)
return _f
def _combo(uop, bop):
def _f(self, tree):
bop.__get__(self)(tree)
uop.__get__(self)(tree)
return _f
shl = _binary_op(ShlOp)
add = _binary_op(AddOp)
sub = _binary_op(SubOp)
mul = _binary_op(MulOp)
@ -870,6 +873,7 @@ class CcInterp(lark.visitors.Interpreter):
gt = _binary_op(GtOp)
lt = _binary_op(LtOp)
neq = _binary_op(NeqOp)
eq = _combo(bool_not, neq)
def _forward_op(self, tree):
self.visit_children(tree)
@ -968,11 +972,12 @@ def filter_dupes(ops):
continue
yield op
def parse_tree(tree):
def parse_tree(tree, debug=False):
tr = CcTransform()
tree = tr.transform(tree)
# print(tree.pretty())
if debug:
print(tree.pretty())
inte = CcInterp()
inte.visit(tree)
@ -985,13 +990,51 @@ def parse_tree(tree):
return '\n'.join(filter_dupes(out))
def larkparse(f):
def larkparse(f, debug=False):
with open(GRAMMAR_FILE) as g:
asparser = lark.Lark(g.read())
tree = asparser.parse(f.read())
return parse_tree(tree)
data = f.read()
if isinstance(data, bytes):
data = data.decode()
tree = asparser.parse(data)
return parse_tree(tree, debug=debug)
def parse_args():
parser = argparse.ArgumentParser(description='Compile.')
group = parser.add_mutually_exclusive_group()
parser.add_argument('--debug', action='store_true',
help='print the AST')
parser.add_argument('--assembly', '-S', action='store_true',
help='output assembly')
parser.add_argument('--compile', '-c', action='store_true',
help='compile a single file')
parser.add_argument('input', type=argparse.FileType('r'),
default=sys.stdin, help='input file (default: stdin)')
parser.add_argument('--output', '-o', type=argparse.FileType('wb'),
default=sys.stdout.buffer, help='output file')
return parser.parse_args()
def preprocess(fin):
p = subprocess.Popen(CPP, stdin=fin, stdout=subprocess.PIPE)
return p.stdout
def assemble(text, fout):
fin = io.StringIO(text)
asmod.write_obj(fout, *asmod.larkparse(fin))
def main():
args = parse_args()
assy = larkparse(preprocess(args.input), debug=args.debug)
if args.assembly:
args.output.write(assy.encode() + b'\n')
else:
assemble(assy, args.output)
if __name__ == "__main__":
# print(',\n'.join(parse(sys.stdin)))
print(larkparse(sys.stdin))
main()