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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										109
									
								
								tools/cc.py
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								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)
 | 
			
		||||
 | 
			
		||||
        def synth(self, scratches):
 | 
			
		||||
            self.op1.synth(scratches)
 | 
			
		||||
            self.op2.synth(scratches)
 | 
			
		||||
 | 
			
		||||
    return _C
 | 
			
		||||
class ShlOp(BinOp):
 | 
			
		||||
    scratch_need = 3
 | 
			
		||||
    def synth(self, scratches):
 | 
			
		||||
        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