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:
parent
0b77dc5d20
commit
0157e235e4
@ -123,7 +123,7 @@ initializer_list: "{" [init_list_field ("," init_list_field)* ","? ] "}"
|
|||||||
|
|
||||||
|
|
||||||
label: IDENTIFIER
|
label: IDENTIFIER
|
||||||
litteral: SIGNED_NUMBER | ESCAPED_STRING | HEX_LITTERAL
|
litteral: SIGNED_NUMBER | ESCAPED_STRING | HEX_LITTERAL | CHARACTER
|
||||||
field: IDENTIFIER
|
field: IDENTIFIER
|
||||||
identifier: IDENTIFIER
|
identifier: IDENTIFIER
|
||||||
?symbol: IDENTIFIER
|
?symbol: IDENTIFIER
|
||||||
@ -145,6 +145,7 @@ struct_field: type IDENTIFIER sized_array* ";"
|
|||||||
IDENTIFIER: /[_a-zA-Z]\w*/
|
IDENTIFIER: /[_a-zA-Z]\w*/
|
||||||
COMMENT: /\/\/.*/
|
COMMENT: /\/\/.*/
|
||||||
HEX_LITTERAL: /0x[a-fA-F0-9]+/
|
HEX_LITTERAL: /0x[a-fA-F0-9]+/
|
||||||
|
CHARACTER: /'[^']'/
|
||||||
|
|
||||||
|
|
||||||
%import common.WS
|
%import common.WS
|
||||||
|
109
tools/cc.py
109
tools/cc.py
@ -1,11 +1,18 @@
|
|||||||
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import importlib
|
||||||
|
import io
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import lark
|
import lark
|
||||||
|
|
||||||
|
asmod = importlib.import_module("as")
|
||||||
|
|
||||||
GRAMMAR_FILE = '/home/paulmathieu/vhdl/bin/cc.ebnf'
|
GRAMMAR_FILE = '/home/paulmathieu/vhdl/bin/cc.ebnf'
|
||||||
|
CPP = ('cpp', '-P')
|
||||||
|
|
||||||
|
|
||||||
class Scope:
|
class Scope:
|
||||||
@ -91,7 +98,7 @@ class RegBank:
|
|||||||
if not self.available:
|
if not self.available:
|
||||||
assert self.vars, "nothing to clean, no more regs :/"
|
assert self.vars, "nothing to clean, no more regs :/"
|
||||||
# storing one random var
|
# storing one random var
|
||||||
var = self.vars.keys()[0]
|
var = list(self.vars.keys())[0]
|
||||||
self.evict(var)
|
self.evict(var)
|
||||||
return self.available.pop(0)
|
return self.available.pop(0)
|
||||||
|
|
||||||
@ -267,6 +274,7 @@ class CcTransform(lark.visitors.Transformer):
|
|||||||
mul = _binary_op(lambda a, b: a*b)
|
mul = _binary_op(lambda a, b: a*b)
|
||||||
shl = _binary_op(lambda a, b: a<<b)
|
shl = _binary_op(lambda a, b: a<<b)
|
||||||
|
|
||||||
|
CHARACTER = lambda _, x: ord(x[1])
|
||||||
IDENTIFIER = str
|
IDENTIFIER = str
|
||||||
SIGNED_NUMBER = int
|
SIGNED_NUMBER = int
|
||||||
HEX_LITTERAL = lambda _, x: int(x[2:], 16)
|
HEX_LITTERAL = lambda _, x: int(x[2:], 16)
|
||||||
@ -321,26 +329,19 @@ AndOp = make_cpu_bin_op('and')
|
|||||||
orOp = make_cpu_bin_op('or')
|
orOp = make_cpu_bin_op('or')
|
||||||
XorOp = make_cpu_bin_op('xor')
|
XorOp = make_cpu_bin_op('xor')
|
||||||
|
|
||||||
|
class ShlOp(BinOp):
|
||||||
def combo(UnOp2, Op1):
|
scratch_need = 3
|
||||||
"""Apply UnOp2 on the output of Op1."""
|
def synth(self, scratches):
|
||||||
|
sc0, sc1, sc2 = scratches
|
||||||
class _C(AsmOp):
|
return [f'or {sc0}, {self.right}, {self.right}',
|
||||||
scratch_need = max(Op1.scratch_need, UnOp2.scratch_need)
|
f'or {self.dest}, {self.left}, {self.left}',
|
||||||
|
f'set {sc1}, 1',
|
||||||
@property
|
f'set {sc2}, 0',
|
||||||
def out(self):
|
f'cmp {sc0}, {sc2}',
|
||||||
return self.op2.out
|
f'beq [pc, 6]',
|
||||||
|
f'add {self.dest}, {self.dest}, {self.dest}',
|
||||||
def __init__(self, fun, ops):
|
f'sub {sc0}, {sc0}, {sc1}',
|
||||||
self.op1 = Op1(fun, ops)
|
f'bneq [pc, -6]']
|
||||||
self.op2 = Op2(fun, self.op1.out)
|
|
||||||
|
|
||||||
def synth(self, scratches):
|
|
||||||
self.op1.synth(scratches)
|
|
||||||
self.op2.synth(scratches)
|
|
||||||
|
|
||||||
return _C
|
|
||||||
|
|
||||||
|
|
||||||
class LtOp(BinOp):
|
class LtOp(BinOp):
|
||||||
@ -394,11 +395,6 @@ class NeqOp(BinOp):
|
|||||||
def synth(self, scratches):
|
def synth(self, scratches):
|
||||||
return [f'sub {self.dest}, {self.left}, {self.right}']
|
return [f'sub {self.dest}, {self.left}, {self.right}']
|
||||||
|
|
||||||
EqOp = combo(BoolNot, NeqOp)
|
|
||||||
LeOp = combo(BoolNot, GtOp)
|
|
||||||
GeOp = combo(BoolNot, LtOp)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FnCall(AsmOp):
|
class FnCall(AsmOp):
|
||||||
scratch_need = 1
|
scratch_need = 1
|
||||||
@ -862,6 +858,13 @@ class CcInterp(lark.visitors.Interpreter):
|
|||||||
self.cur_fun.regs.give(right)
|
self.cur_fun.regs.give(right)
|
||||||
return _f
|
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)
|
add = _binary_op(AddOp)
|
||||||
sub = _binary_op(SubOp)
|
sub = _binary_op(SubOp)
|
||||||
mul = _binary_op(MulOp)
|
mul = _binary_op(MulOp)
|
||||||
@ -870,6 +873,7 @@ class CcInterp(lark.visitors.Interpreter):
|
|||||||
gt = _binary_op(GtOp)
|
gt = _binary_op(GtOp)
|
||||||
lt = _binary_op(LtOp)
|
lt = _binary_op(LtOp)
|
||||||
neq = _binary_op(NeqOp)
|
neq = _binary_op(NeqOp)
|
||||||
|
eq = _combo(bool_not, neq)
|
||||||
|
|
||||||
def _forward_op(self, tree):
|
def _forward_op(self, tree):
|
||||||
self.visit_children(tree)
|
self.visit_children(tree)
|
||||||
@ -968,11 +972,12 @@ def filter_dupes(ops):
|
|||||||
continue
|
continue
|
||||||
yield op
|
yield op
|
||||||
|
|
||||||
def parse_tree(tree):
|
def parse_tree(tree, debug=False):
|
||||||
tr = CcTransform()
|
tr = CcTransform()
|
||||||
tree = tr.transform(tree)
|
tree = tr.transform(tree)
|
||||||
|
|
||||||
# print(tree.pretty())
|
if debug:
|
||||||
|
print(tree.pretty())
|
||||||
|
|
||||||
inte = CcInterp()
|
inte = CcInterp()
|
||||||
inte.visit(tree)
|
inte.visit(tree)
|
||||||
@ -985,13 +990,51 @@ def parse_tree(tree):
|
|||||||
return '\n'.join(filter_dupes(out))
|
return '\n'.join(filter_dupes(out))
|
||||||
|
|
||||||
|
|
||||||
def larkparse(f):
|
def larkparse(f, debug=False):
|
||||||
with open(GRAMMAR_FILE) as g:
|
with open(GRAMMAR_FILE) as g:
|
||||||
asparser = lark.Lark(g.read())
|
asparser = lark.Lark(g.read())
|
||||||
tree = asparser.parse(f.read())
|
data = f.read()
|
||||||
return parse_tree(tree)
|
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__":
|
if __name__ == "__main__":
|
||||||
# print(',\n'.join(parse(sys.stdin)))
|
main()
|
||||||
print(larkparse(sys.stdin))
|
|
||||||
|
Loading…
Reference in New Issue
Block a user