Mercurial > lcfOS
changeset 309:68b01c8abf8a
Added start of ir read and write
author | Windel Bouwman |
---|---|
date | Fri, 13 Dec 2013 13:51:02 +0100 |
parents | 2e7f55319858 |
children | e95e5572cd6d |
files | examples/pi/add.pi python/ppci/ir.py python/ppci/irutils.py test/testcg.py test/testir.py |
diffstat | 5 files changed, 190 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/pi/add.pi Fri Dec 13 11:53:29 2013 +0100 +++ b/examples/pi/add.pi Fri Dec 13 13:51:02 2013 +0100 @@ -1,3 +1,5 @@ + +module addmod function i32 add(i32 a, i32 b) init:
--- a/python/ppci/ir.py Fri Dec 13 11:53:29 2013 +0100 +++ b/python/ppci/ir.py Fri Dec 13 13:51:02 2013 +0100 @@ -6,16 +6,15 @@ """ Container unit for variables and functions. """ def __init__(self, name): self.name = name - self.funcs = [] + self.functions = [] self.variables = [] def __repr__(self): - return 'IR-module [{0}]'.format(self.name) + return 'module {0}'.format(self.name) - def addFunc(self, f): - self.funcs.append(f) - - addFunction = addFunc + def add_function(self, f): + """ Add a function to this module """ + self.functions.append(f) def addVariable(self, v): self.variables.append(v) @@ -26,7 +25,7 @@ Variables = property(getVariables) def getFunctions(self): - return self.funcs + return self.functions Functions = property(getFunctions) @@ -38,13 +37,6 @@ getFunction = findFunction - def dump(self, indent=' '): - print(self) - for v in self.Variables: - print(indent, v) - for fn in self.Functions: - fn.dump(indent=indent+' ') - # Analysis functions: def check(self): """ Perform sanity check on module """ @@ -54,7 +46,7 @@ class Function: """ Represents a function. """ - def __init__(self, name): + def __init__(self, name, module=None): self.name = name self.entry = Block('{}_entry'.format(name)) self.entry.function = self @@ -64,13 +56,15 @@ self.return_value = Temp('{}_retval'.format(name)) self.arguments = [] self.localvars = [] + if module: + module.add_function(self) def __repr__(self): args = ','.join(str(a) for a in self.arguments) - return 'Function {}({})'.format(self.name, args) + return 'function i32 {}({})'.format(self.name, args) - def addBlock(self, bb): - self.bbs.append(bb) + def add_block(self, bb): + #self.bbs.append(bb) bb.function = self def removeBlock(self, bb): @@ -118,13 +112,6 @@ assert type(l) is LocalVariable self.localvars.append(l) - def dump(self, indent=''): - print(indent+str(self)) - for bb in self.Blocks: - print(indent+' ' + str(bb)) - for ins in bb.Instructions: - print(indent + ' ' * 2 + str(ins)) - class Block: """ @@ -138,7 +125,7 @@ parent = property(lambda s: s.function) def __repr__(self): - return 'Block {0}'.format(self.name) + return '{0}:'.format(self.name) def addInstruction(self, i): i.parent = self @@ -272,10 +259,12 @@ def Mul(a, b): + """ Multiply a by b """ return Binop(a, '*', b) def Div(a, b): + """ Divide a in b pieces """ return Binop(a, '/', b)
--- a/python/ppci/irutils.py Fri Dec 13 11:53:29 2013 +0100 +++ b/python/ppci/irutils.py Fri Dec 13 13:51:02 2013 +0100 @@ -2,7 +2,9 @@ """ Some utilities for ir-code. """ +import re from .ir import Temp, Block, Function, Statement +from . import ir def dumpgv(m, outf): print('digraph G ', file=outf) @@ -22,6 +24,150 @@ print('}', file=outf) +class Writer: + def write(self, ir, f): + """ Write ir-code to file f """ + print(ir, file=f) + for v in ir.Variables: + print(str(v), file=f) + for fn in ir.Functions: + args = ','.join('i32 ' + str(a) for a in fn.arguments) + print('function i32 {}({})'.format(fn.name, args), file=f) + for bb in fn.Blocks: + print(' ' + str(bb), file=f) + for ins in bb.Instructions: + print(' ' + str(ins), file=f) + + +class IrParseException(Exception): + pass + + +class Reader: + def read(self, f): + """ Read ir code from file f """ + # Read lines from the file: + lines = [line.rstrip() for line in f] + + # Create a regular expression for the lexing part: + tok_spec = [ + ('NUMBER', r'\d+'), + ('ID', r'[A-Za-z][A-Za-z\d_]*'), + ('SKIP2', r' '), + ('SKIP1', r' '), + ('OTHER', r'[\.,=:;\-+*\[\]/\(\)]|>|<|{|}|&|\^|\|') + ] + tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec) + gettok = re.compile(tok_re).match + + def tokenize(): + for line in lines: + if not line: + continue # Skip empty lines + mo = gettok(line) + first = True + while mo: + typ = mo.lastgroup + val = mo.group(typ) + if typ == 'ID': + if val in ['function', 'module']: + typ = val + yield (typ, val) + elif typ == 'OTHER': + typ = val + yield (typ, val) + elif typ in ['SKIP1', 'SKIP2']: + if first: + yield (typ, val) + elif typ == 'NUMBER': + yield (typ, int(val)) + else: + raise NotImplementedError(str(typ)) + first = False + pos = mo.end() + mo = gettok(line, pos) + if len(line) != pos: + raise IrParseException('Lex fault') + yield ('eol', 'eol') + yield ('eof', 'eof') + self.tokens = tokenize() + self.token = self.tokens.__next__() + + try: + module = self.parse_module() + return module + except IrParseException as e: + print(e) + + def next_token(self): + t = self.token + if t[0] != 'eof': + self.token = self.tokens.__next__() + return t + + @property + def Peak(self): + return self.token[0] + + def Consume(self, typ): + if self.Peak == typ: + return self.next_token() + else: + raise IrParseException('Expected "{}" got "{}"'.format(typ, self.Peak)) + + def parse_module(self): + """ Entry for recursive descent parser """ + self.Consume('module') + name = self.Consume('ID')[1] + module = ir.Module(name) + self.Consume('eol') + while self.Peak != 'eof': + if self.Peak == 'function': + module.add_function(self.parse_function()) + else: + raise IrParseException('Expected function got {}'.format(self.Peak)) + return module + + def parse_function(self): + self.Consume('function') + self.parse_type() + name = self.Consume('ID')[1] + function = ir.Function(name) + self.Consume('(') + while self.Peak != ')': + self.parse_type() + self.Consume('ID') + if self.Peak != ',': + break + else: + self.Consume(',') + self.Consume(')') + self.Consume('eol') + while self.Peak == 'SKIP1': + function.add_block(self.parse_block()) + return function + + def parse_type(self): + self.Consume('ID') + + def parse_block(self): + self.Consume('SKIP1') + name = self.Consume('ID')[1] + block = ir.Block(name) + self.Consume(':') + self.Consume('eol') + while self.Peak == 'SKIP2': + self.parse_statement() + return block + + def parse_statement(self): + self.Consume('SKIP2') + while self.Peak != 'eol': + # raise NotImplementedError() + self.next_token() + self.Consume('eol') + + # Constructing IR: class NamedClassGenerator: @@ -61,7 +207,7 @@ def newFunction(self, name): f = Function(name) - self.m.addFunc(f) + self.m.add_function(f) return f def newBlock(self):
--- a/test/testcg.py Fri Dec 13 11:53:29 2013 +0100 +++ b/test/testcg.py Fri Dec 13 13:51:02 2013 +0100 @@ -9,7 +9,7 @@ def genTestFunction(): m = ir.Module('tst') f = ir.Function('tst') - m.addFunction(f) + m.add_function(f) return m, f, f.entry
--- a/test/testir.py Fri Dec 13 11:53:29 2013 +0100 +++ b/test/testir.py Fri Dec 13 13:51:02 2013 +0100 @@ -1,6 +1,7 @@ import unittest import os import sys +import io import ppci from ppci import ir from ppci import irutils @@ -79,11 +80,32 @@ self.b.setFunction(f) self.b.setBlock(self.b.newBlock()) v1 = ir.Const(0) - v2 = ir.Const(0) - v3 = ir.Add(v1, v2) + v3 = ir.Add(v1, ir.Const(0)) + +class TestWriter(unittest.TestCase): + def testWrite(self): + writer = irutils.Writer() + module = ir.Module('mod1') + function = ir.Function('func1', module) + f = io.StringIO() + writer.write(module, f) + #print(f.getvalue()) + f2 = io.StringIO(f.getvalue()) + reader = irutils.Reader() + module2 = reader.read(f2) + f = io.StringIO() + writer.write(module2, f) + #print(f.getvalue()) - +class TestReader(unittest.TestCase): + def testAddExample(self): + reader = irutils.Reader() + with open('../examples/pi/add.pi') as f: + m = reader.read(f) + self.assertTrue(m) + #print(m) + if __name__ == '__main__': unittest.main()