view python/zcc.py @ 329:8f6f3ace4e78

Added build tasks
author Windel Bouwman
date Wed, 05 Feb 2014 21:29:31 +0100
parents e9fe6988497c
children a78b41ff6ad2
line wrap: on
line source

#!/usr/bin/env python

import sys
import argparse
import logging

from ppci.c3 import AstPrinter
from ppci.buildtasks import Compile
from ppci.tasks import TaskRunner
import outstream
from utils import HexFile
import target
from target.target_list import target_list
from ppci import irutils
import io


logformat='%(asctime)s|%(levelname)s|%(name)s|%(message)s'


def logLevel(s):
    """ Converts a string to a valid logging level """
    numeric_level = getattr(logging, s.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError('Invalid log level: {}'.format(s))
    return numeric_level


class RstFormatter(logging.Formatter):
    """ Formatter that tries to create an rst document """
    def __init__(self):
        super().__init__(fmt=logformat)

    def format(self, record):
        s = super().format(record)
        s += '\n'
        if hasattr(record, 'c3_ast'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            AstPrinter().printAst(record.c3_ast, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ircode'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            Writer('  ').write(record.ircode, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'irfunc'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            Writer('  ').write_function(record.irfunc, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ppci_frame'):
            f = io.StringIO()
            frame = record.ppci_frame
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            print('  {}'.format(frame.name), file=f)
            for i in frame.instructions:
                print('   {}'.format(i),file=f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ra_cfg'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. graphviz::', file=f)
            print('', file=f)
            print('  digraph G {', file=f)
            print('    size="8,80";', file=f)
            cfg = record.ra_cfg
            cfg.to_dot(f)
            print('  }', file=f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'ra_ig'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. graphviz::', file=f)
            print('', file=f)
            print('  digraph G {', file=f)
            print('    ratio="compress";', file=f)
            print('    size="8,80";', file=f)
            ig = record.ra_ig
            ig.to_dot(f)
            print('  }', file=f)
            print('', file=f)
            s += '\n' + f.getvalue()
        if hasattr(record, 'zcc_outs'):
            f = io.StringIO()
            print('', file=f)
            print('', file=f)
            print('.. code::', file=f)
            print('', file=f)
            outstream.OutputStreamWriter('  ').dump(record.zcc_outs, f)
            print('', file=f)
            s += '\n' + f.getvalue()
        return s


targets = {t.name: t for t in target_list}
targetnames = list(targets.keys())

# Parse arguments:
parser = argparse.ArgumentParser(description='lcfos Compiler')
parser.add_argument('source', type=argparse.FileType('r'), \
  help='the source file to build', nargs="+")
parser.add_argument('-i', '--imp', type=argparse.FileType('r'), \
  help='Possible import module', action='append', default=[])

#sub_parsers = parser.add_subparsers()
#recipe = sub_parsers.add_parser('recipe')
parser.add_argument('--optimize', action='store_true', help="Optimize")
parser.add_argument('--target', help="Backend selection",
    choices=targetnames, required=True)
parser.add_argument('-o', '--output', help='Output file', metavar='filename')
parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])',
                    type=logLevel, default='WARN')
parser.add_argument('--report', 
            help='Specify a file to write the compile report to',
            type=argparse.FileType('w'))


def main(args):
    # Configure some logging:
    logging.getLogger().setLevel(logging.DEBUG)
    ch = logging.StreamHandler()
    ch.setFormatter(logging.Formatter(logformat))
    ch.setLevel(args.log)
    logging.getLogger().addHandler(ch)
    if args.report:
        fh = logging.StreamHandler(stream=args.report)
        fh.setFormatter(RstFormatter())
        logging.getLogger().addHandler(fh)

    tg = targets[args.target]
    outs = outstream.TextOutputStream()

    tr = TaskRunner()
    tr.add_task(Compile(args.source, args.imp, tg, outs))

    res = tr.run_tasks()
    if res > 0:
        return 1
    logging.info('Assembly created', extra={'zcc_outs':outs})

    code_bytes = outs.sections['code'].to_bytes()
    if args.output:
        output_filename = args.output
        with open(output_filename, 'wb') as f:
            f.write(code_bytes)

    if args.report:
        logging.getLogger().removeHandler(fh)
    logging.getLogger().removeHandler(ch)
    return 0


if __name__ == '__main__':
    arguments = parser.parse_args()
    sys.exit(main(arguments))