# HG changeset patch # User Windel Bouwman # Date 1363961558 -3600 # Node ID 598d3888a11c265ad8594469159063e8daf4ea47 # Parent e023d3ce1d6305a922bfa26ead2224b7d28d7239 Added front class and fided AST view diff -r e023d3ce1d63 -r 598d3888a11c python/astviewer.py --- a/python/astviewer.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/astviewer.py Fri Mar 22 15:12:38 2013 +0100 @@ -2,30 +2,40 @@ from PyQt4.QtGui import * from c3 import Visitor -def astToNamedElement(astNode, parentNode): - """ Helper to convert and AST tree to NamedElement tree: """ - item = QStandardItem(str(astNode)) - item.setData(astNode) - parentNode.appendRow(item) - for c in astNode.getChildren(): - astToNamedElement(c, item) +class AstModelBuilder: + def __init__(self): + self.visitor = Visitor(self.p1, self.p2) + def build(self, pkg): + model = QStandardItemModel() + model.setHorizontalHeaderLabels(['Object', 'Type']) + self.curItem = model.invisibleRootItem() + self.visitor.visit(pkg) + return model + def p1(self, node): + i = QStandardItem(str(node)) + typ = str(node.typ) if hasattr(node, 'typ') else '' + ti = QStandardItem(str(typ)) + ti.setData(node) + i.setData(node) + self.curItem.appendRow([i, ti]) + self.curItem = i + def p2(self, node): + self.curItem = self.curItem.parent() # The actual widget: class AstViewer(QTreeView): sigNodeSelected = pyqtSignal(object) def __init__(self, parent=None): super(AstViewer, self).__init__(parent) - self.setHeaderHidden(True) self.clicked.connect(self.selectHandler) + self.modelBuilder = AstModelBuilder() def setAst(self, ast): """ Create a new model and add all ast elements to it """ - model = QStandardItemModel() print(ast) if ast: - astToNamedElement(ast, model.invisibleRootItem()) - self.setModel(model) - self.expandAll() + self.setModel(self.modelBuilder.build(ast)) + self.expandAll() def selectHandler(self, index): if not index.isValid(): diff -r e023d3ce1d63 -r 598d3888a11c python/c3/__init__.py --- a/python/c3/__init__.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/c3/__init__.py Fri Mar 22 15:12:38 2013 +0100 @@ -7,4 +7,5 @@ from .codegenerator import CodeGenerator from .astprinter import AstPrinter from .visitor import Visitor +from .builder import Builder diff -r e023d3ce1d63 -r 598d3888a11c python/c3/astnodes.py --- a/python/c3/astnodes.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/c3/astnodes.py Fri Mar 22 15:12:38 2013 +0100 @@ -23,14 +23,15 @@ def __init__(self, name): self.name = name def __repr__(self): - return '[TYPE {0}]'.format(self.name) + return '{0}'.format(self.name) class FunctionType(Type): def __init__(self, parameters, returntype): self.parameters = parameters self.returntype = returntype def __repr__(self): - return '[FUNCTYPE {0} RET {1}]'.format(self.parameters, self.returntype) + params = ','.join([str(v) for v in self.parameters]) + return '{1} f({0})'.format(params, self.returntype) class DefinedType(Type): def __init__(self, name, typ): @@ -67,7 +68,7 @@ self.isReadOnly = False self.isParameter = False def __repr__(self): - return 'VAR {0} : {1} usage: {2}'.format(self.name, self.typ, self.References) + return '{0}'.format(self.name) # Procedure types class Function(Symbol): @@ -77,7 +78,7 @@ self.body = block self.typ = typ def __repr__(self): - return 'PROCEDURE {0} {1}'.format(self.name, self.typ) + return '{0}'.format(self.name) # Operations / Expressions: class Unop(Node): diff -r e023d3ce1d63 -r 598d3888a11c python/c3/builder.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/c3/builder.py Fri Mar 22 15:12:38 2013 +0100 @@ -0,0 +1,42 @@ +import ppci +from . import Parser, Semantics, TypeChecker, Analyzer, CodeGenerator, AstPrinter + +class Builder: + def __init__(self, diag): + self.diag = diag + self.sema = Semantics(diag) + self.p = Parser(self.sema, diag) + self.tc = TypeChecker(diag) + self.al = Analyzer(diag) + self.cg = CodeGenerator() + self.ap = AstPrinter() + def build(self, src): + # Store src for later: + self.src = src + print('[0] source:') + print(src) + print('[1] parsing') + self.p.parseSource(src) + ok = len(self.diag.diags) == 0 + if not ok: + return + pkg = self.sema.mod + self.pkg = pkg + self.al.analyzePackage(pkg) + self.tc.checkPackage(pkg) + print('{0} errors'.format(len(self.diag.diags))) + + for d in self.diag.diags: + print('ERROR:') + ppci.printError(src, d) + print('[2] ast:') + self.ap.printAst(pkg) + + #printAst(sema.mod) + + ok = len(self.diag.diags) == 0 + if ok: + print('Generating ir-code') + i = cg.gencode(pkg) + return i + diff -r e023d3ce1d63 -r 598d3888a11c python/c3/parser.py --- a/python/c3/parser.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/c3/parser.py Fri Mar 22 15:12:38 2013 +0100 @@ -126,7 +126,7 @@ # Statements: def parseAssignment(self, lval): - lval = self.sema.actOnVariableUse(lval) + lval = self.sema.actOnVariableUse(lval, lval.loc) loc = self.Consume('=').loc rval = self.parseExpression() self.Consume(';') @@ -143,15 +143,16 @@ return astnodes.ProcedureCall(procedure, args) def parseIfStatement(self): - self.Consume('if') + loc = self.Consume('if').loc self.Consume('(') condition = self.parseExpression() self.Consume(')') yes = self.parseCompoundStatement() if self.hasConsumed('else'): no = self.parseCompoundStatement() - return astnodes.IfStatement(condition, yes, no) - return astnodes.IfStatement(condition, yes, astnodes.EmptyStatement()) + else: + no = astnodes.EmptyStatement() + return self.sema.actOnIfStatement(condition, yes, no, loc) def parseWhileStatement(self): self.Consume('while') @@ -216,7 +217,7 @@ if self.Peak == '(': return self.parseProcedureCall(d) else: - return self.sema.actOnVariableUse(d) + return self.sema.actOnVariableUse(d, d.loc) self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak)) def parseBinopRhs(self, lhs, min_prec): diff -r e023d3ce1d63 -r 598d3888a11c python/c3/semantics.py --- a/python/c3/semantics.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/c3/semantics.py Fri Mar 22 15:12:38 2013 +0100 @@ -55,11 +55,15 @@ n = astnodes.Literal(num) n.loc = loc return n - def actOnVariableUse(self, d): + def actOnVariableUse(self, d, loc): vu = astnodes.VariableUse(d) + vu.loc = loc return vu def actOnAssignment(self, lval, rval, loc): a = astnodes.Assignment(lval, rval) a.loc = loc return a - + def actOnIfStatement(self, cond, yes, no, loc): + i = astnodes.IfStatement(cond, yes, no) + i.loc = loc + return i diff -r e023d3ce1d63 -r 598d3888a11c python/c3/typecheck.py --- a/python/c3/typecheck.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/c3/typecheck.py Fri Mar 22 15:12:38 2013 +0100 @@ -20,8 +20,7 @@ def check2(self, sym): if type(sym) is Function: pass - elif type(sym) is IfStatement: - print(sym.condition) + elif type(sym) in [IfStatement, WhileStatement]: if not equalTypes(sym.condition.typ, boolType): self.diag.error('Condition must be a boolean expression', sym.condition.loc) elif type(sym) is Assignment: @@ -38,7 +37,7 @@ if sym.target: sym.typ = sym.target.typ else: - sym.typ = voidType + sym.typ = intType elif type(sym) is Literal: if type(sym.val) is int: sym.typ = intType @@ -51,18 +50,22 @@ if equalTypes(sym.a.typ, sym.b.typ): sym.typ = sym.a.typ else: - # assume void here? - sym.typ = voidType + # assume void here? TODO: throw exception! + sym.typ = intType self.diag.error('Types unequal', sym.loc) elif sym.op in ['>', '<']: - if equalTypes(sym.a.typ, sym.b.typ): - sym.typ = boolType - else: - sym.typ = voidType + sym.typ = boolType + if not equalTypes(sym.a.typ, sym.b.typ): self.diag.error('Types unequal', sym.loc) else: sym.typ = voidType print('unknown binop', sym.op) + elif type(sym) is Variable: + # check initial value type: + # TODO + pass + elif type(sym) in [EmptyStatement, CompoundStatement, Package]: + pass else: print('Unknown type check', sym) diff -r e023d3ce1d63 -r 598d3888a11c python/ide.py --- a/python/ide.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/ide.py Fri Mar 22 15:12:38 2013 +0100 @@ -14,6 +14,7 @@ from codeedit import CodeEdit stutil = __import__('st-util') import testc3 +import c3 lcfospng = base64.decodestring(b'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A\n/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEhMKBk7B678AAAA/SURBVFjD\n7dbBCQAgDATBi9h/y7EFA4Kf2QLCwH1S6XQu6sqoujublc8BAAAAAAAAAAB8B+zXT6YJAAAAAKYd\nWSgFQNUyijIAAAAASUVORK5CYII=\n') @@ -118,7 +119,6 @@ def __init__(self, parent=None): super(Ide, self).__init__(parent) self.setWindowTitle('LCFOS IDE') - self.compiler = None # TODO icon = QPixmap() icon.loadFromData(lcfospng) self.setWindowIcon(QIcon(icon)) @@ -201,6 +201,7 @@ ce.Source = testc3.testsrc self.diag = ppci.DiagnosticsManager() + self.c3front = c3.Builder(self.diag) # File handling: def newProject(self): @@ -319,9 +320,9 @@ ce = self.activeMdiChild() if not ce: return - if node.location: - row, col = node.location - ce.highlightErrorLocation( row, col ) + if node.loc: + row, col = node.loc.row, node.loc.col + ce.setRowCol( row, col ) else: ce.clearErrors() @@ -340,9 +341,9 @@ if ce: source = ce.Source self.buildOutput.clear() - self.buildOutput.append(str(self.compiler)) - ast = testc3.c3compile(source, self.diag) - #ast = self.compiler.compilesource(source) + self.buildOutput.append('Starting build') + ir = self.c3front.build(source) + ast = self.c3front.pkg print('setting ast', ast) self.astViewer.setAst(ast) self.buildOutput.append("Done!") @@ -351,9 +352,7 @@ print('BUILD project') self.buildOutput.clear() self.diag.diags.clear() - self.buildOutput.append(str(self.compiler)) self.buildFile() - #mods = self.compiler.compileProject(self.project) self.builderrors.setErrorList(self.diag.diags) #self.astViewer.setAst(mods[0]) diff -r e023d3ce1d63 -r 598d3888a11c python/testc3.py --- a/python/testc3.py Mon Mar 18 22:15:57 2013 +0100 +++ b/python/testc3.py Fri Mar 22 15:12:38 2013 +0100 @@ -46,51 +46,22 @@ """ def c3compile(src, diag): - print('[0] source:') - print(src) - print('[1] parsing') # Structures: - sema = c3.Semantics(diag) - p = c3.Parser(sema, diag) - tc = c3.TypeChecker(diag) - al = c3.Analyzer(diag) - cg = c3.CodeGenerator() - ap = c3.AstPrinter() - + builder = c3.Builder(diag) + ir = builder.build(src) + # optional optimize here x86gen = x86.X86CodeGen(diag) - p.parseSource(src) ok = len(diag.diags) == 0 if not ok: + print('Not generating code') return - al.analyzePackage(sema.mod) - tc.checkPackage(sema.mod) - print('{0} errors'.format(len(diag.diags))) - - for d in diag.diags: - print('ERROR:') - ppci.printError(testsrc, d) - print('[2] ast:') - ap.printAst(sema.mod) - - #printAst(sema.mod) - - ok = len(diag.diags) == 0 - if ok: - print('Generating ir-code') - i = cg.gencode(sema.mod) - #ir.printIr(i) - - print('generating x86 code') - - x86gen.genBin(i) - - with open('dummydummy.asm', 'w') as f: - f.write('bits 64\n') - for a in x86gen.asm: - print(a) - f.write(str(a) + '\n') - else: - print('Not generating code') + print('generating x86 code') + x86gen.genBin(ir) + with open('dummydummy.asm', 'w') as f: + f.write('bits 64\n') + for a in x86gen.asm: + print(a) + f.write(str(a) + '\n') def do(): diag = ppci.DiagnosticsManager()