Mercurial > lcfOS
changeset 334:6f4753202b9a
Added more recipes
author | Windel Bouwman |
---|---|
date | Thu, 13 Feb 2014 22:02:08 +0100 |
parents | dcae6574c974 |
children | 582a1aaa3983 |
files | examples/c3/recipe.yaml examples/c3/startup_stm32f4.asm kernel/recipe.yaml python/asm.py python/asmnodes.py python/parserlib.py python/ppci/asmnodes.py python/ppci/assembler.py python/ppci/buildtasks.py python/ppci/c3/builder.py python/ppci/c3/codegenerator.py python/ppci/c3/parser.py python/ppci/codegen/codegen.py python/ppci/codegen/registerallocator.py python/ppci/common.py python/ppci/linker.py python/ppci/objectfile.py python/ppci/tasks.py python/ppci/transform.py python/target/arminstructions.py python/target/armtarget.py python/target/basetarget.py python/target/msp430.py python/yacc.py python/zcc.py test/testasm.py test/testmsp430asm.py test/testparserlib.py test/testzcc.py user/recipe.yaml |
diffstat | 30 files changed, 484 insertions(+), 495 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/c3/recipe.yaml Thu Feb 13 22:02:08 2014 +0100 @@ -0,0 +1,14 @@ + +link: + inputs: + - assemble: + source: startup_stm32f4.asm + machine: arm + - compile: + sources: [burn2.c3] + includes: [stm32f4xx.c3] + machine: arm + output: burn.elf2 + code: 0x08000000 + data: 0x20000000 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/c3/startup_stm32f4.asm Thu Feb 13 22:02:08 2014 +0100 @@ -0,0 +1,6 @@ + + +DCD 0x20000678 ; Setup stack pointer +DCD 0x08000009 ; Reset vector, jump to address 8 +B main ; Branch to main (this is actually in the interrupt vector) +
--- a/kernel/recipe.yaml Sun Feb 09 15:27:57 2014 +0100 +++ b/kernel/recipe.yaml Thu Feb 13 22:02:08 2014 +0100 @@ -1,13 +1,14 @@ link: inputs: - compile: + - assemble: + source: ../examples/c3/startup_stm32f4.asm + machine: arm + - compile: sources: [memory.c3, kernel.c3, syscall.c3, process.c3, schedule.c3, arch_arm.c3] includes: [] machine: arm output: kernel.elf2 - assemble: - source: boot_arm.asm code: 0x8000 data: 0x9000
--- a/python/asm.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/asm.py Thu Feb 13 22:02:08 2014 +0100 @@ -1,205 +1,7 @@ #!/usr/bin/env python3 -import re import argparse -import pyyacc -from ppci import Token, CompilerError, SourceLocation -from target import Target, Label -from asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber - -def tokenize(s): - """ - Tokenizer, generates an iterator that - returns tokens! - - This GREAT example was taken from python re doc page! - """ - tok_spec = [ - ('REAL', r'\d+\.\d+'), - ('HEXNUMBER', r'0x[\da-fA-F]+'), - ('NUMBER', r'\d+'), - ('ID', r'[A-Za-z][A-Za-z\d_]*'), - ('SKIP', r'[ \t]'), - ('LEESTEKEN', r':=|[\.,=:\-+*\[\]/\(\)]|>=|<=|<>|>|<|}|{'), - ('STRING', r"'.*?'"), - ('COMMENT', r";.*") - ] - tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec) - gettok = re.compile(tok_re).match - line = 1 - pos = line_start = 0 - mo = gettok(s) - while mo is not None: - typ = mo.lastgroup - val = mo.group(typ) - if typ == 'NEWLINE': - line_start = pos - line += 1 - elif typ != 'SKIP': - if typ == 'LEESTEKEN': - typ = val - elif typ == 'NUMBER': - val = int(val) - elif typ == 'HEXNUMBER': - val = int(val[2:], 16) - typ = 'NUMBER' - elif typ == 'REAL': - val = float(val) - elif typ == 'STRING': - val = val[1:-1] - col = mo.start() - line_start - loc = SourceLocation('', line, col, 0) # TODO retrieve length? - yield Token(typ, val, loc) - pos = mo.end() - mo = gettok(s, pos) - if pos != len(s): - col = pos - line_start - loc = SourceLocation('', line, col, 0) - raise CompilerError('Unexpected character {0}'.format(s[pos]), loc) - yield Token('EOF', pyyacc.EOF) - - -class Lexer: - def __init__(self, src): - self.tokens = tokenize(src) - self.curTok = self.tokens.__next__() - - def next_token(self): - t = self.curTok - if t.typ != 'EOF': - self.curTok = self.tokens.__next__() - return t - - -class Parser: - def __init__(self): - # Construct a parser given a grammar: - ident = lambda x: x # Identity helper function - g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}', - pyyacc.EOF]) - g.add_production('asmline', ['asmline2']) - g.add_production('asmline', ['asmline2', 'COMMENT']) - g.add_production('asmline2', ['label', 'instruction']) - g.add_production('asmline2', ['instruction']) - g.add_production('asmline2', ['label']) - g.add_production('asmline2', []) - g.add_production('label', ['ID', ':'], self.p_label) - #g.add_production('label', []) - g.add_production('instruction', ['opcode', 'operands'], self.p_ins_1) - g.add_production('instruction', ['opcode'], self.p_ins_2) - #g.add_production('instruction', []) - g.add_production('opcode', ['ID'], lambda x: x.val) - g.add_production('operands', ['operand'], self.p_operands_1) - g.add_production('operands', ['operands', ',', 'operand'], self.p_operands_2) - g.add_production('operand', ['expression'], ident) - g.add_production('operand', ['[', 'expression', ']'], self.p_mem_op) - g.add_production('operand', ['{', 'listitems', '}'], self.p_list_op) - g.add_production('listitems', ['expression'], self.p_listitems_1) - g.add_production('listitems', ['listitems', ',', 'expression'], self.p_listitems_2) - g.add_production('expression', ['term'], ident) - g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop) - g.add_production('addop', ['-'], lambda x: x.val) - g.add_production('addop', ['+'], lambda x: x.val) - g.add_production('mulop', ['*'], lambda x: x.val) - g.add_production('term', ['factor'], ident) - g.add_production('term', ['term', 'mulop', 'factor'], self.p_binop) - g.add_production('factor', ['ID'], lambda name: ASymbol(name.val)) - g.add_production('factor', ['NUMBER'], lambda num: ANumber(int(num.val))) - g.start_symbol = 'asmline' - self.p = g.genParser() - - # Parser handlers: - def p_ins_1(self, opc, ops): - ins = AInstruction(opc, ops) - self.emit(ins) - - def p_ins_2(self, opc): - self.p_ins_1(opc, []) - - def p_operands_1(self, op1): - return [op1] - - def p_operands_2(self, ops, comma, op2): - assert type(ops) is list - ops.append(op2) - return ops - - def p_listitems_1(self, li1): - return [li1] - - def p_listitems_2(self, lis, comma, li2): - assert type(lis) is list - lis.append(li2) - return lis - - def p_list_op(self, brace_open, lst, brace_close): - return AUnop('{}', lst) - - def p_mem_op(self, brace_open, exp, brace_close): - return AUnop('[]', exp) - - def p_label(self, lname, cn): - lab = ALabel(lname.val) - self.emit(lab) - - def p_binop(self, exp1, op, exp2): - return ABinop(op, exp1, exp2) - - def parse(self, lexer, emitter): - self.emit = emitter - self.p.parse(lexer) - -# Pre construct parser to save time: -asmParser = Parser() - -class Assembler: - def __init__(self, target=None, stream=None): - self.target = target - self.stream = stream - self.restart() - self.p = asmParser - - # Top level interface: - def restart(self): - self.stack = [] - - def emit(self, a): - """ Emit a parsed instruction """ - self.stack.append(a) - - def parse_line(self, line): - """ Parse line into asm AST """ - tokens = Lexer(line) - self.p.parse(tokens, self.emit) - - def assemble(self, asmsrc): - """ Assemble this source snippet """ - for line in asmsrc.split('\n'): - self.assemble_line(line) - - def assemble_line(self, line): - """ - Assemble a single source line. - Do not take newlines into account - """ - self.parse_line(line) - self.assemble_aast() - - def assemble_aast(self): - """ Assemble a parsed asm line """ - if not self.target: - raise CompilerError('Cannot assemble without target') - while self.stack: - vi = self.stack.pop(0) - if type(vi) is AInstruction: - mi = self.target.mapInstruction(vi) - elif type(vi) is ALabel: - mi = Label(vi.name) - else: - raise NotImplementedError('{}'.format(vi)) - if self.stream: - self.stream.emit(mi) - +from ppci.assembler import Assembler if __name__ == '__main__': # When run as main file, try to grab command line arguments:
--- a/python/asmnodes.py Sun Feb 09 15:27:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - -""" Assembler AST nodes """ - -class ANode: - def __eq__(self, other): - return self.__repr__() == other.__repr__() - -class ALabel(ANode): - def __init__(self, name): - self.name = name - def __repr__(self): - return '{0}:'.format(self.name) - - -class AInstruction(ANode): - def __init__(self, mnemonic, operands): - self.mnemonic = mnemonic - self.operands = operands - def __repr__(self): - ops = ', '.join(map(str, self.operands)) - return '{0} {1}'.format(self.mnemonic, ops) - -class AExpression(ANode): - def __add__(self, other): - assert isinstance(other, AExpression) - return ABinop('+', self, other) - def __mul__(self, other): - assert isinstance(other, AExpression) - return ABinop('*', self, other) - -class ABinop(AExpression): - def __init__(self, op, arg1, arg2): - self.op = op - self.arg1 = arg1 - self.arg2 = arg2 - def __repr__(self): - return '{0} {1} {2}'.format(self.op, self.arg1, self.arg2) - -class AUnop(AExpression): - def __init__(self, operation, arg): - self.operation = operation - self.arg = arg - def __repr__(self): - return '{0} {1}'.format(self.operation, self.arg) - -class ASymbol(AExpression): - def __init__(self, name): - self.name = name - def __repr__(self): - return self.name - -class ANumber(AExpression): - def __init__(self, n): - assert type(n) is int - self.n = n - self.number = n - def __repr__(self): - return '{0}'.format(self.n) -
--- a/python/parserlib.py Sun Feb 09 15:27:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ - - - -class Token: - pass - -# Base functions: -class Pbase: - def __init__(self): - self.pa = None - def parse(self, txt): - r = self.do(txt) - if r: - match, rest = r - # Apply action: - if self.ParseAction: - match = self.ParseAction(match) - return match, rest - else: - # TODO: fail in some way - pass - def getParseAction(self): - return self.pa - def setParseAction(self, pa): - self.pa = pa - - ParseAction = property(getParseAction, setParseAction) - -# basic elements: - -class Literal(Pbase): - def __init__(self, s): - super().__init__() - self.pat = s - def do(self, txt): - if txt.startswith(self.pat): - return self.pat, txt[len(self.pat):] - -class Or(Pbase): - def __init__(self, options): - super().__init__() - self.options = options - def do(self, txt): - for option in self.options: - r = option.parse(txt) - if r: - return r - -class And: - def __init__(self, options): - self.options = options - -class Sequence(Pbase): - def __init__(self, seq): - super().__init__() - self.seq = seq - def do(self, txt): - results = [] - for thung in self.seq: - r = thung.parse(txt) - if r: - res, txt = r - results.append(res) - else: - return - return results, txt - -class Optional(Pbase): - def __init__(self, thung): - super().__init__() - self.thung = thung - def do(self, txt): - r = self.thung.do(txt) - if r: - return r - return (0, txt) - -# Contraptions of basic blocks: - -def OneOrMore(): - def __init__(self, thingy): - pass -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/asmnodes.py Thu Feb 13 22:02:08 2014 +0100 @@ -0,0 +1,59 @@ + +""" Assembler AST nodes """ + +class ANode: + def __eq__(self, other): + return self.__repr__() == other.__repr__() + +class ALabel(ANode): + def __init__(self, name): + self.name = name + def __repr__(self): + return '{0}:'.format(self.name) + + +class AInstruction(ANode): + def __init__(self, mnemonic, operands): + self.mnemonic = mnemonic + self.operands = operands + def __repr__(self): + ops = ', '.join(map(str, self.operands)) + return '{0} {1}'.format(self.mnemonic, ops) + +class AExpression(ANode): + def __add__(self, other): + assert isinstance(other, AExpression) + return ABinop('+', self, other) + def __mul__(self, other): + assert isinstance(other, AExpression) + return ABinop('*', self, other) + +class ABinop(AExpression): + def __init__(self, op, arg1, arg2): + self.op = op + self.arg1 = arg1 + self.arg2 = arg2 + def __repr__(self): + return '{0} {1} {2}'.format(self.op, self.arg1, self.arg2) + +class AUnop(AExpression): + def __init__(self, operation, arg): + self.operation = operation + self.arg = arg + def __repr__(self): + return '{0} {1}'.format(self.operation, self.arg) + +class ASymbol(AExpression): + def __init__(self, name): + self.name = name + def __repr__(self): + return self.name + +class ANumber(AExpression): + def __init__(self, n): + assert type(n) is int + self.n = n + self.number = n + def __repr__(self): + return '{0}'.format(self.n) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/assembler.py Thu Feb 13 22:02:08 2014 +0100 @@ -0,0 +1,203 @@ + +import re +import pyyacc +from . import Token, CompilerError, SourceLocation +from target import Target, Label +from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber + +def tokenize(s): + """ + Tokenizer, generates an iterator that + returns tokens! + + This GREAT example was taken from python re doc page! + """ + tok_spec = [ + ('REAL', r'\d+\.\d+'), + ('HEXNUMBER', r'0x[\da-fA-F]+'), + ('NUMBER', r'\d+'), + ('ID', r'[A-Za-z][A-Za-z\d_]*'), + ('SKIP', r'[ \t]'), + ('LEESTEKEN', r':=|[\.,=:\-+*\[\]/\(\)]|>=|<=|<>|>|<|}|{'), + ('STRING', r"'.*?'"), + ('COMMENT', r";.*") + ] + tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec) + gettok = re.compile(tok_re).match + line = 1 + pos = line_start = 0 + mo = gettok(s) + while mo is not None: + typ = mo.lastgroup + val = mo.group(typ) + if typ == 'NEWLINE': + line_start = pos + line += 1 + elif typ != 'SKIP': + if typ == 'LEESTEKEN': + typ = val + elif typ == 'NUMBER': + val = int(val) + elif typ == 'HEXNUMBER': + val = int(val[2:], 16) + typ = 'NUMBER' + elif typ == 'REAL': + val = float(val) + elif typ == 'STRING': + val = val[1:-1] + col = mo.start() - line_start + loc = SourceLocation('', line, col, 0) # TODO retrieve length? + yield Token(typ, val, loc) + pos = mo.end() + mo = gettok(s, pos) + if pos != len(s): + col = pos - line_start + loc = SourceLocation('', line, col, 0) + raise CompilerError('Unexpected character {0}'.format(s[pos]), loc) + yield Token('EOF', pyyacc.EOF) + + +class Lexer: + def __init__(self, src): + self.tokens = tokenize(src) + self.curTok = self.tokens.__next__() + + def next_token(self): + t = self.curTok + if t.typ != 'EOF': + self.curTok = self.tokens.__next__() + return t + + +class Parser: + def __init__(self): + # Construct a parser given a grammar: + ident = lambda x: x # Identity helper function + g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}', + pyyacc.EOF]) + g.add_production('asmline', ['asmline2']) + g.add_production('asmline', ['asmline2', 'COMMENT']) + g.add_production('asmline2', ['label', 'instruction']) + g.add_production('asmline2', ['instruction']) + g.add_production('asmline2', ['label']) + g.add_production('asmline2', []) + g.add_production('label', ['ID', ':'], self.p_label) + #g.add_production('label', []) + g.add_production('instruction', ['opcode', 'operands'], self.p_ins_1) + g.add_production('instruction', ['opcode'], self.p_ins_2) + #g.add_production('instruction', []) + g.add_production('opcode', ['ID'], lambda x: x.val) + g.add_production('operands', ['operand'], self.p_operands_1) + g.add_production('operands', ['operands', ',', 'operand'], self.p_operands_2) + g.add_production('operand', ['expression'], ident) + g.add_production('operand', ['[', 'expression', ']'], self.p_mem_op) + g.add_production('operand', ['{', 'listitems', '}'], self.p_list_op) + g.add_production('listitems', ['expression'], self.p_listitems_1) + g.add_production('listitems', ['listitems', ',', 'expression'], self.p_listitems_2) + g.add_production('expression', ['term'], ident) + g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop) + g.add_production('addop', ['-'], lambda x: x.val) + g.add_production('addop', ['+'], lambda x: x.val) + g.add_production('mulop', ['*'], lambda x: x.val) + g.add_production('term', ['factor'], ident) + g.add_production('term', ['term', 'mulop', 'factor'], self.p_binop) + g.add_production('factor', ['ID'], lambda name: ASymbol(name.val)) + g.add_production('factor', ['NUMBER'], lambda num: ANumber(int(num.val))) + g.start_symbol = 'asmline' + self.p = g.genParser() + + # Parser handlers: + def p_ins_1(self, opc, ops): + ins = AInstruction(opc, ops) + self.emit(ins) + + def p_ins_2(self, opc): + self.p_ins_1(opc, []) + + def p_operands_1(self, op1): + return [op1] + + def p_operands_2(self, ops, comma, op2): + assert type(ops) is list + ops.append(op2) + return ops + + def p_listitems_1(self, li1): + return [li1] + + def p_listitems_2(self, lis, comma, li2): + assert type(lis) is list + lis.append(li2) + return lis + + def p_list_op(self, brace_open, lst, brace_close): + return AUnop('{}', lst) + + def p_mem_op(self, brace_open, exp, brace_close): + return AUnop('[]', exp) + + def p_label(self, lname, cn): + lab = ALabel(lname.val) + self.emit(lab) + + def p_binop(self, exp1, op, exp2): + return ABinop(op, exp1, exp2) + + def parse(self, lexer, emitter): + self.emit = emitter + self.p.parse(lexer) + +# Pre construct parser to save time: +asmParser = Parser() + +class Assembler: + def __init__(self, target=None, stream=None): + self.target = target + self.stream = stream + self.restart() + self.p = asmParser + + # Top level interface: + def restart(self): + self.stack = [] + + def emit(self, a): + """ Emit a parsed instruction """ + self.stack.append(a) + + def parse_line(self, line): + """ Parse line into asm AST """ + tokens = Lexer(line) + self.p.parse(tokens, self.emit) + + def assemble(self, asmsrc): + """ Assemble this source snippet """ + if type(asmsrc) is not str: + asmsrc2 = asmsrc.read() + asmsrc.close() + asmsrc = asmsrc2 + for line in asmsrc.split('\n'): + self.assemble_line(line) + + def assemble_line(self, line): + """ + Assemble a single source line. + Do not take newlines into account + """ + self.parse_line(line) + self.assemble_aast() + + def assemble_aast(self): + """ Assemble a parsed asm line """ + if not self.target: + raise CompilerError('Cannot assemble without target') + while self.stack: + vi = self.stack.pop(0) + if type(vi) is AInstruction: + mi = self.target.mapInstruction(vi) + elif type(vi) is ALabel: + mi = Label(vi.name) + else: + raise NotImplementedError('{}'.format(vi)) + if self.stream: + self.stream.emit(mi)
--- a/python/ppci/buildtasks.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/buildtasks.py Thu Feb 13 22:02:08 2014 +0100 @@ -12,24 +12,33 @@ from .transform import CleanPass, RemoveAddZero from .tasks import Task from . import DiagnosticsManager - +from .assembler import Assembler +from .objectfile import ObjectFile +from .linker import Linker +import outstream class BuildTask(Task): + """ Base task for all kind of weird build tasks """ def __init__(self, name): super().__init__(name) self.logger = logging.getLogger('buildtask') class Assemble(BuildTask): - def __init__(self): + """ Task that can runs the assembler over the source and enters the + output into an object file """ + def __init__(self, source, target, output_object): super().__init__('Assemble') + self.source = source + self.assembler = Assembler(target=target) + self.output = output_object def run(self): - pass + self.assembler.assemble(self.source) class Compile(BuildTask): - """ Task that compiles source to some target """ + """ Task that compiles C3 source for some target into an object file """ def __init__(self, sources, includes, target, output_object): super().__init__('Compile') self.sources = sources @@ -38,7 +47,7 @@ self.output = output_object def run(self): - self.logger.info('Zcc started {}'.format(self.sources)) + self.logger.debug('Compile started') diag = DiagnosticsManager() c3b = Builder(diag, self.target) cg = CodeGenerator(self.target) @@ -48,7 +57,7 @@ return d = {'ircode':ircode} - self.logger.info('Verifying code {}'.format(ircode), extra=d) + self.logger.debug('Verifying code {}'.format(ircode), extra=d) Verifier().verify(ircode) # Optimization passes: @@ -61,23 +70,31 @@ # Code generation: d = {'ircode':ircode} - self.logger.info('Starting code generation for {}'.format(ircode), extra=d) - cg.generate(ircode, self.output) + self.logger.debug('Starting code generation for {}'.format(ircode), extra=d) + o = outstream.TextOutputStream() + cg.generate(ircode, o) - # TODO: fixup references, do this in another way? - self.output.backpatch() if not c3b.ok: diag.printErrors() raise TaskError('Compile errors') class Link(BuildTask): + """ Link together a collection of object files """ def __init__(self, objects, output_file): super().__init__('Link') + self.objects = objects + self.linker = Linker() + self.duration = 0.1337 + + def run(self): + print('LNK') + print('LNK', self.objects) + print('LNK') + print('LNK') + self.linker.link(self.objects) class ObjCopy(Task): pass - -
--- a/python/ppci/c3/builder.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/c3/builder.py Thu Feb 13 22:02:08 2014 +0100 @@ -31,7 +31,7 @@ """ Scope is attached to the correct modules. """ def addScope(self, pkg): - self.logger.info('Adding scoping to package {}'.format(pkg.name)) + self.logger.debug('Adding scoping to package {}'.format(pkg.name)) self.pkg = pkg # Prepare top level scope and set scope to all objects: self.scopeStack = [self.topScope] @@ -40,7 +40,7 @@ self.visit(pkg, self.enterScope, self.quitScope) assert len(self.scopeStack) == 2 - self.logger.info('Resolving imports for package {}'.format(pkg.name)) + self.logger.debug('Resolving imports for package {}'.format(pkg.name)) # Handle imports: for i in pkg.imports: if i not in self.packages: @@ -95,7 +95,7 @@ def build(self, srcs, imps=[]): """ Create IR-code from sources """ - self.logger.info('Building {} source files'.format(len(srcs))) + self.logger.debug('Building {} source files'.format(len(srcs))) iter(srcs) # Check if srcs are iterable iter(imps) self.ok = True
--- a/python/ppci/c3/codegenerator.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/c3/codegenerator.py Thu Feb 13 22:02:08 2014 +0100 @@ -34,7 +34,7 @@ self.pkg = pkg self.intType = pkg.scope['int'] self.boolType = pkg.scope['bool'] - self.logger.info('Generating ir-code for {}'.format(pkg.name), extra={'c3_ast':pkg}) + self.logger.debug('Generating ir-code for {}'.format(pkg.name), extra={'c3_ast':pkg}) self.varMap = {} # Maps variables to storage locations. self.funcMap = {} self.m = ir.Module(pkg.name)
--- a/python/ppci/c3/parser.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/c3/parser.py Thu Feb 13 22:02:08 2014 +0100 @@ -19,7 +19,7 @@ self.diag = diag def parseSource(self, tokens): - self.logger.info('Parsing source') + self.logger.debug('Parsing source') self.tokens = tokens self.token = self.tokens.__next__() try:
--- a/python/ppci/codegen/codegen.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/codegen/codegen.py Thu Feb 13 22:02:08 2014 +0100 @@ -21,20 +21,20 @@ def generateFunc(self, irfunc, outs): """ Generate code for one function into a frame """ - self.logger.info('Generating code for {}'.format(irfunc.name)) + self.logger.debug('Generating code for {}'.format(irfunc.name)) # Create a frame for this function: frame = self.target.FrameClass(irfunc.name) # Canonicalize the intermediate language: canonicalize(irfunc, frame) - self.logger.info('after canonicalize', extra={'irfunc': irfunc}) + self.logger.debug('after canonicalize', extra={'irfunc': irfunc}) self.verifier.verify_function(irfunc) self.ins_sel.munchFunction(irfunc, frame) - self.logger.info('Selected instructions', extra={'ppci_frame': frame}) + self.logger.debug('Selected instructions', extra={'ppci_frame': frame}) # Do register allocation: self.ra.allocFrame(frame) - self.logger.info('Registers allocated, now adding final glue') + self.logger.debug('Registers allocated, now adding final glue') # TODO: Peep-hole here? # Add label and return and stack adjustment: @@ -43,7 +43,7 @@ # Materialize the register allocated instructions into a stream of # real instructions. frame.lower_to(outs) - self.logger.info('Instructions materialized') + self.logger.debug('Instructions materialized') return frame def generate(self, ircode, outs):
--- a/python/ppci/codegen/registerallocator.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/codegen/registerallocator.py Thu Feb 13 22:02:08 2014 +0100 @@ -41,9 +41,9 @@ def Build(self): """ 1. Construct interference graph from instruction list """ self.f.cfg = FlowGraph(self.f.instructions) - self.logger.info('Constructed flowgraph', extra={'ra_cfg':self.f.cfg}) + self.logger.debug('Constructed flowgraph', extra={'ra_cfg':self.f.cfg}) self.f.ig = InterferenceGraph(self.f.cfg) - self.logger.info('Constructed interferencegraph', extra={'ra_ig':self.f.ig}) + self.logger.debug('Constructed interferencegraph', extra={'ra_ig':self.f.ig}) self.Node = self.f.ig.getNode
--- a/python/ppci/common.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/common.py Thu Feb 13 22:02:08 2014 +0100 @@ -58,7 +58,7 @@ self.logger = logging.getLogger('diagnostics') def addSource(self, name, src): - self.logger.info('Adding source {}'.format(name)) + self.logger.debug('Adding source {}'.format(name)) self.sources[name] = src def addDiag(self, d):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/linker.py Thu Feb 13 22:02:08 2014 +0100 @@ -0,0 +1,19 @@ + +from .objectfile import ObjectFile + +class Linker: + def set_symbol(self, sym): + self.dst.add_symbol(sym.name, sym.value) + + def link(self, objs): + self.dst = ObjectFile() + # First copy all sections into output sections: + for iobj in objs: + for sym in iobj.symbols: + print(sym) + self.set_symbol(sym) + # Do relocations: + # TODO + # Check that there are no more unresolved symbols: + # TODO + return self.dst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/objectfile.py Thu Feb 13 22:02:08 2014 +0100 @@ -0,0 +1,32 @@ + +""" +Object files are used to store assembled code. Information contained +is code, symbol table and relocation information. +""" + +class Symbol: + def __init__(self, name, value): + self.name = name + self.value = value + + +class Relocation: + def __init__(self, typ): + pass + + +class Section: + def __init__(self, name): + self.name = name + + +class ObjectFile: + def __init__(self): + self.symbols = {} + self.sections = {} + self.relocations = [] + + def add_symbol(self, name, value): + sym = Symbol(name, value) + self.symbols[name] = sym + return sym
--- a/python/ppci/tasks.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/tasks.py Thu Feb 13 22:02:08 2014 +0100 @@ -1,3 +1,5 @@ + +import logging class TaskError(Exception): pass @@ -10,6 +12,7 @@ self.subtasks = [] self.completed = False self.dependencies = [] + self.duration = 1 def run(self): raise NotImplementedError("Implement this abstract method!") @@ -34,22 +37,34 @@ class TaskRunner: """ Basic task runner that can run some tasks in sequence """ def __init__(self): + self.logger = logging.getLogger('taskrunner') self.task_list = [] def add_task(self, task): self.task_list.append(task) + @property + def total_duration(self): + return sum(t.duration for t in self.task_list) + def run_tasks(self): + passed_time = 0.0 + total_time = self.total_duration try: for t in self.task_list: - #print('Running {}'.format(t.name)) + self.report_progress(passed_time / total_time, t.name) t.fire() + passed_time += t.duration except TaskError as e: print('Error: {}'.format(e)) return 1 + self.report_progress(1, 'OK') return 0 def display(self): """ Display task how they would be run """ for task in self.task_list: print(task) + + def report_progress(self, percentage, text): + self.logger.info('[{:3.1%}] {}'.format(percentage, text))
--- a/python/ppci/transform.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/ppci/transform.py Thu Feb 13 22:02:08 2014 +0100 @@ -12,7 +12,7 @@ def run(self, ir): """ Main entry point for the pass """ - self.logger.info('Running pass {}'.format(type(self))) + self.logger.debug('Running pass {}'.format(self.__class__.__name__)) self.prepare() for f in ir.Functions: self.onFunction(f) @@ -157,7 +157,7 @@ def glue_blocks(self, block1, block2, f): """ Glue two blocks together into the first block """ - self.logger.info('Glueing {} and {}'.format(block1, block2)) + self.logger.debug('Glueing {} and {}'.format(block1, block2)) # Remove the last jump: block1.removeInstruction(block1.LastInstruction)
--- a/python/target/arminstructions.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/target/arminstructions.py Thu Feb 13 22:02:08 2014 +0100 @@ -1,5 +1,5 @@ import struct -from asmnodes import ASymbol, AInstruction, ANumber, AUnop, ABinop +from ppci.asmnodes import ASymbol, AInstruction, ANumber, AUnop, ABinop from .basetarget import Register, Instruction, Target, Label, LabelRef from .basetarget import Imm32, Imm8, Imm7, Imm3
--- a/python/target/armtarget.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/target/armtarget.py Thu Feb 13 22:02:08 2014 +0100 @@ -25,12 +25,3 @@ self.check() self.ins_sel = ArmInstructionSelector() self.FrameClass = ArmFrame - - def startCode(self, outs): - """ Emit some startup code in the output stream """ - outs.selectSection('code') - # assembly glue to make it work: - # TODO: this must be in source code, not in compiler - outs.emit(Dcd(Imm32(0x20000678))) # initial SP - outs.emit(Dcd(Imm32(0x08000009))) # reset vector - outs.emit(B(LabelRef('main')))
--- a/python/target/basetarget.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/target/basetarget.py Thu Feb 13 22:02:08 2014 +0100 @@ -1,4 +1,4 @@ -from asmnodes import ASymbol, AInstruction, ANumber +from ppci.asmnodes import ASymbol, AInstruction, ANumber from ppci import CompilerError """
--- a/python/target/msp430.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/target/msp430.py Thu Feb 13 22:02:08 2014 +0100 @@ -1,5 +1,5 @@ from .basetarget import Register, Instruction, Target -from asmnodes import ASymbol, ANumber +from ppci.asmnodes import ASymbol, ANumber from ppci import CompilerError import struct import types
--- a/python/yacc.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/yacc.py Thu Feb 13 22:02:08 2014 +0100 @@ -1,7 +1,7 @@ #!/usr/bin/python """ -Parser generator utility. This script can generate a python script from a +Parser generator utility. This script can generate a python script from a grammar description. Invoke the script on a grammar specification file: @@ -42,7 +42,7 @@ import types import io import logging -from pyyacc import Grammar, print_grammar +from pyyacc import Grammar class XaccLexer: @@ -244,15 +244,15 @@ # Fill goto table: self.print(' self.goto_table = {}') - for gt in self.goto_table: - to = self.goto_table[gt] - self.print(' self.goto_table[{}] = {}'.format(gt, to)) + for state_number in self.goto_table: + to = self.goto_table[state_number] + self.print(' self.goto_table[{}] = {}'.format(state_number, to)) self.print('') # Generate a function for each action: for rule in self.grammar.productions: - M = len(rule.symbols) - args = ', '.join('arg{}'.format(n + 1) for n in range(M)) + num_symbols = len(rule.symbols) + args = ', '.join('arg{}'.format(n + 1) for n in range(num_symbols)) self.print(' def {}(self, {}):'.format(rule.f_name, args)) if rule.f == None: semantics = 'pass' @@ -260,7 +260,7 @@ semantics = str(rule.f) if semantics.strip() == '': semantics = 'pass' - for n in range(M): + for n in range(num_symbols): semantics = semantics.replace('${}'.format(n + 1), 'arg{}'.format(n + 1)) self.print(' {}'.format(semantics)) self.print('') @@ -298,7 +298,6 @@ # Sequence source through the generator parts: lexer.feed(src) grammar = parser.parse_grammar() - # TODO: optionize this: print_grammar(grammar) generator.generate(grammar, parser.headers, args.output)
--- a/python/zcc.py Sun Feb 09 15:27:57 2014 +0100 +++ b/python/zcc.py Thu Feb 13 22:02:08 2014 +0100 @@ -6,10 +6,10 @@ import logging import yaml -from ppci.buildtasks import Compile +from ppci.buildtasks import Compile, Assemble, Link from ppci.tasks import TaskRunner from ppci.report import RstFormatter -import outstream +from ppci.objectfile import ObjectFile from target.target_list import target_list import ppci @@ -29,7 +29,7 @@ parser = argparse.ArgumentParser(description='lcfos Compiler') parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])', - type=logLevel, default='WARN') + type=logLevel, default='INFO') parser.add_argument('--display-build-steps', action='store_true') sub_parsers = parser.add_subparsers(title='commands', description='possible commands', dest='command') @@ -52,12 +52,21 @@ class RecipeLoader: + """ Loads a recipe into a runner from a dictionary or file """ + def __init__(self): + self.directive_handlers = {} + for a in dir(self): + if a.startswith('handle_'): + f = getattr(self, a) + self.directive_handlers[a[7:]] = f + def load_file(self, recipe_file, runner): """ Loads a recipe dictionary into a task runner """ self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file)) with open(recipe_file, 'r') as f: recipe = yaml.load(f) - self.load_dict(recipe, runner) + self.runner = runner + self.load_dict(recipe) def relpath(self, filename): return os.path.join(self.recipe_dir, filename) @@ -65,24 +74,38 @@ def openfile(self, filename): return open(self.relpath(filename), 'r') - def load_dict(self, recipe, runner): + def handle_compile(self, value): + sources = [self.openfile(s) for s in value['sources']] + includes = [self.openfile(i) for i in value['includes']] + target = targets[value['machine']] + output = ObjectFile() + task = Compile(sources, includes, target, output) + self.runner.add_task(task) + return task + + def handle_assemble(self, value): + asm_src = self.openfile(value['source']) + target = targets[value['machine']] + output = ObjectFile() + task = Assemble(asm_src, target, output) + self.runner.add_task(task) + return task + + def handle_link(self, value): + inputs = value['inputs'] + objs = [] + for i in inputs: + task = self.load_dict(i) + objs.append(task.output) + self.runner.add_task(Link(objs, None)) + + def handle_apps(self, value): + for a in value: + self.load_dict(a) + + def load_dict(self, recipe): for command, value in recipe.items(): - if command == 'compile': - sources = [self.openfile(s) for s in value['sources']] - includes = [self.openfile(i) for i in value['includes']] - target = targets[value['machine']] - output = outstream.TextOutputStream() - runner.add_task(Compile(sources, includes, target, output)) - elif command == 'link': - self.load_dict(value['inputs'], runner) - #runner.add_task(Link()) - elif command == 'assemble': - pass - elif command == 'apps': - for a in value: - self.load_dict(a, runner) - else: - raise NotImplementedError(command) + return self.directive_handlers[command](value) def main(args): @@ -96,8 +119,8 @@ runner = TaskRunner() if args.command == 'compile': tg = targets[args.target] - outs = outstream.TextOutputStream() - runner.add_task(Compile(args.source, args.imp, tg, outs)) + output = ObjectFile() + runner.add_task(Compile(args.source, args.imp, tg, output)) elif args.command == 'recipe': recipe_loader = RecipeLoader() recipe_loader.load_file(args.recipe_file, runner)
--- a/test/testasm.py Sun Feb 09 15:27:57 2014 +0100 +++ b/test/testasm.py Thu Feb 13 22:02:08 2014 +0100 @@ -2,8 +2,8 @@ import unittest, cProfile from ppci import CompilerError -from asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber -from asm import tokenize, Assembler +from ppci.asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber +from ppci.assembler import tokenize, Assembler import outstream from target import Label
--- a/test/testmsp430asm.py Sun Feb 09 15:27:57 2014 +0100 +++ b/test/testmsp430asm.py Thu Feb 13 22:02:08 2014 +0100 @@ -1,8 +1,8 @@ #!/usr/bin/python import unittest -from asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber -from asm import tokenize, Assembler +from ppci.asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber +from ppci.assembler import tokenize, Assembler import outstream from target import Label from target.target_list import msp430target
--- a/test/testparserlib.py Sun Feb 09 15:27:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -import unittest -from parserlib import OneOrMore, Literal, Or, Sequence, Optional - -class ParserCombinatorTestCase(unittest.TestCase): - def test1(self): - #p = Parser() - # parse and interpret: - n40 = Literal('40') - plus = Literal('+') - n2 = Literal('2') - n40.ParseAction = int - plus.ParseAction = replaceWith(0) - n2.ParseAction = int - p = Sequence([n40,plus,n2]) - p.ParseAction = wordsum - - result = p.parse('40+2') - self.assertEqual(42, result[0]) - -def replaceWith(s): - def _repFunc(*args): - return s - return _repFunc - -wordsum = lambda t: sum(t) - -class WordToNumTestCase(unittest.TestCase): - def setUp(self): - numWords = OneOrMore() - def makeLit(s, val): - ret = Literal(s) - ret.ParseAction = replaceWith(val) - return ret - unitDefs = [('zero', 0), ('three', 3), ('one', 1)] - units = Or( [makeLit(s, v) for s, v in unitDefs] ) - tensDefs = [('twenty', 20)] - tens = Or( [makeLit(s, v) for s, v in tensDefs] ) - - numPart = Sequence([Optional(tens), units]) - numPart.ParseAction = wordsum - self.p = numPart - - def check(self, i, o): - result = self.p.parse(i)[0] - self.assertEqual(o, result) - - def test0(self): - self.check('zero', 0) - - def test23(self): - self.check('twentythree', 23) - - @unittest.skip - def test321(self): - # TODO - self.check('three hundred and twenty one', 321) - - -if __name__ == '__main__': - unittest.main()
--- a/test/testzcc.py Sun Feb 09 15:27:57 2014 +0100 +++ b/test/testzcc.py Thu Feb 13 22:02:08 2014 +0100 @@ -61,6 +61,10 @@ def testBurn2(self): self.do(['burn2.c3'], ['stm32f4xx.c3']) + def testBurn2_recipe(self): + recipe = os.path.join(testdir, '..', 'examples', 'c3', 'recipe.yaml') + self.buildRecipe(recipe) + #@unittest.skip('s') def testBurn2WithLogging(self): self.do(['burn2.c3'], ['stm32f4xx.c3'], extra_args=['--report', 'x.rst'])
--- a/user/recipe.yaml Sun Feb 09 15:27:57 2014 +0100 +++ b/user/recipe.yaml Thu Feb 13 22:02:08 2014 +0100 @@ -1,19 +1,25 @@ apps: - - compile: - sources: [lib.c3, ipc.c3, hello.c3] - includes: [] - machine: arm - output: kernel.elf2 + - link: + inputs: + - compile: + sources: [lib.c3, ipc.c3, hello.c3] + includes: [] + machine: arm + output: kernel.elf2 - - compile: - sources: [lib.c3, ipc.c3, screen.c3] - includes: [] - machine: arm - output: kernel.elf2 + - link: + inputs: + - compile: + sources: [lib.c3, ipc.c3, screen.c3] + includes: [] + machine: arm + output: kernel.elf2 - - compile: - sources: [lib.c3, ipc.c3, console.c3] - includes: [] - machine: arm - output: kernel.elf2 + - link: + inputs: + - compile: + sources: [lib.c3, ipc.c3, console.c3] + includes: [] + machine: arm + output: kernel.elf2