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:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										107
									
								
								tools/cc.py
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								tools/cc.py
									
									
									
									
									
								
							| @@ -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() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user