Mercurial > lcfOS
changeset 308:2e7f55319858
Merged analyse into codegenerator
author | Windel Bouwman |
---|---|
date | Fri, 13 Dec 2013 11:53:29 +0100 |
parents | e609d5296ee9 |
children | 68b01c8abf8a |
files | doc/compiler.rst kernel/kernel.c3 kernel/schedule.c3 kernel/syscall.c3 python/ppci/c3/analyse.py python/ppci/c3/astnodes.py python/ppci/c3/builder.py python/ppci/c3/codegenerator.py python/ppci/c3/parser.py test/testc3.py |
diffstat | 10 files changed, 272 insertions(+), 250 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/compiler.rst Thu Dec 12 20:42:56 2013 +0100 +++ b/doc/compiler.rst Fri Dec 13 11:53:29 2013 +0100 @@ -52,13 +52,11 @@ 1 [label="source text"] 10 [label="lexer" ] 20 [label="parser" ] - 30 [label="semantic checks" ] 40 [label="code generation"] 99 [label="IR-code object"] 1 -> 10 10 -> 20 - 20 -> 30 - 30 -> 40 [label="AST tree"] + 20 -> 40 [label="AST tree"] 40 -> 99 } @@ -66,10 +64,6 @@ .. autoclass:: ppci.c3.Parser -.. autoclass:: ppci.c3.Analyzer - -.. autoclass:: ppci.c3.TypeChecker - .. autoclass:: ppci.c3.CodeGenerator .. autoclass:: ppci.c3.Builder
--- a/kernel/kernel.c3 Thu Dec 12 20:42:56 2013 +0100 +++ b/kernel/kernel.c3 Fri Dec 13 11:53:29 2013 +0100 @@ -8,7 +8,7 @@ // Main entry point of the kernel: function void start() { - process:init(); + process.init(); //memory:init(); @@ -20,6 +20,6 @@ function void panic() { - arch:halt(); + arch.halt(); }
--- a/kernel/schedule.c3 Thu Dec 12 20:42:56 2013 +0100 +++ b/kernel/schedule.c3 Fri Dec 13 11:53:29 2013 +0100 @@ -3,11 +3,11 @@ import process; -var process:process_t *current; +var process.process_t *current; function void executeNext() { - var process:process_t *old; + var process.process_t *old; if (old != current) {
--- a/kernel/syscall.c3 Thu Dec 12 20:42:56 2013 +0100 +++ b/kernel/syscall.c3 Fri Dec 13 11:53:29 2013 +0100 @@ -21,8 +21,8 @@ if (callId == 1) { handle_send_msg(); - var process:process_t* proc; - proc = process:byId(a); + var process.process_t* proc; + proc = process.byId(a); // proc.setMessage(); // scheduler.current.setState(Sleep); } @@ -36,7 +36,7 @@ { if (callId == 3) { - //arch:reboot(); + //arch.reboot(); } else { @@ -57,6 +57,6 @@ { // Block until we have a message //currentProc->setState(Sleep); - //scheduler:executeNext(); + //scheduler.executeNext(); }
--- a/python/ppci/c3/analyse.py Thu Dec 12 20:42:56 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -import logging -from .visitor import Visitor, AstPrinter -from .astnodes import * -from .scope import Scope - - -class C3Pass: - def __init__(self, diag): - self.diag = diag - self.logger = logging.getLogger('c3') - self.visitor = Visitor() - - def error(self, msg, loc=None): - self.pkg.ok = False - self.diag.error(msg, loc) - - def visit(self, pkg, pre, post): - self.visitor.visit(pkg, pre, post) - - -class ScopeFiller(C3Pass): - scoped_types = [Package, Function] - def __init__(self, diag, topScope, packages): - super().__init__(diag) - self.topScope = topScope - self.packages = packages - - """ Scope is attached to the correct modules. """ - def addScope(self, pkg): - self.logger.info('Adding scoping to package {}'.format(pkg.name)) - self.pkg = pkg - # Prepare top level scope and set scope to all objects: - self.scopeStack = [self.topScope] - modScope = Scope(self.CurrentScope) - self.scopeStack.append(modScope) - self.visit(pkg, self.enterScope, self.quitScope) - assert len(self.scopeStack) == 2 - - self.logger.info('Resolving imports for package {}'.format(pkg.name)) - # Handle imports: - for i in pkg.imports: - if i not in self.packages: - self.error('Cannot import {}'.format(i)) - continue - pkg.scope.addSymbol(self.packages[i]) - - @property - def CurrentScope(self): - return self.scopeStack[-1] - - def addSymbol(self, sym): - if self.CurrentScope.hasSymbol(sym.name): - self.error('Redefinition of {0}'.format(sym.name), sym.loc) - else: - self.CurrentScope.addSymbol(sym) - - def enterScope(self, sym): - # Attach scope to references: - if type(sym) is Identifier: - sym.scope = self.CurrentScope - - # Add symbols to current scope: - if isinstance(sym, Symbol): - self.addSymbol(sym) - sym.scope = self.CurrentScope - - # Create subscope for items creating a scope: - if type(sym) in self.scoped_types: - newScope = Scope(self.CurrentScope) - self.scopeStack.append(newScope) - sym.innerScope = self.CurrentScope - - def quitScope(self, sym): - # Pop out of scope: - if type(sym) in self.scoped_types: - self.scopeStack.pop(-1)
--- a/python/ppci/c3/astnodes.py Thu Dec 12 20:42:56 2013 +0100 +++ b/python/ppci/c3/astnodes.py Fri Dec 13 11:53:29 2013 +0100 @@ -15,7 +15,7 @@ # Variables, parameters, local variables, constants and named types: class Symbol(Node): - """ Symbol is the base class for all named things like variables, + """ Symbol is the base class for all named things like variables, functions, constants and types and modules """ def __init__(self, name): self.name = name @@ -47,7 +47,7 @@ class NamedType(Type, Symbol): - """ Some types are named, for example a user defined type (typedef) + """ Some types are named, for example a user defined type (typedef) and built in types. That is why this class derives from both Type and Symbol. """ def __init__(self, name):
--- a/python/ppci/c3/builder.py Thu Dec 12 20:42:56 2013 +0100 +++ b/python/ppci/c3/builder.py Fri Dec 13 11:53:29 2013 +0100 @@ -2,9 +2,82 @@ from .lexer import Lexer from .parser import Parser from .codegenerator import CodeGenerator -from .analyse import ScopeFiller -from .scope import createTopScope -from .visitor import AstPrinter +from .scope import createTopScope, Scope +from .visitor import AstPrinter, Visitor +from .astnodes import Package, Function, Identifier, Symbol + + +class C3Pass: + def __init__(self, diag): + self.diag = diag + self.logger = logging.getLogger('c3') + self.visitor = Visitor() + + def error(self, msg, loc=None): + self.pkg.ok = False + self.diag.error(msg, loc) + + def visit(self, pkg, pre, post): + self.visitor.visit(pkg, pre, post) + + +class ScopeFiller(C3Pass): + scoped_types = [Package, Function] + + def __init__(self, diag, topScope, packages): + super().__init__(diag) + self.topScope = topScope + self.packages = packages + + """ Scope is attached to the correct modules. """ + def addScope(self, pkg): + self.logger.info('Adding scoping to package {}'.format(pkg.name)) + self.pkg = pkg + # Prepare top level scope and set scope to all objects: + self.scopeStack = [self.topScope] + modScope = Scope(self.CurrentScope) + self.scopeStack.append(modScope) + self.visit(pkg, self.enterScope, self.quitScope) + assert len(self.scopeStack) == 2 + + self.logger.info('Resolving imports for package {}'.format(pkg.name)) + # Handle imports: + for i in pkg.imports: + if i not in self.packages: + self.error('Cannot import {}'.format(i)) + continue + pkg.scope.addSymbol(self.packages[i]) + + @property + def CurrentScope(self): + return self.scopeStack[-1] + + def addSymbol(self, sym): + if self.CurrentScope.hasSymbol(sym.name): + self.error('Redefinition of {0}'.format(sym.name), sym.loc) + else: + self.CurrentScope.addSymbol(sym) + + def enterScope(self, sym): + # Attach scope to references: + if type(sym) is Identifier: + sym.scope = self.CurrentScope + + # Add symbols to current scope: + if isinstance(sym, Symbol): + self.addSymbol(sym) + sym.scope = self.CurrentScope + + # Create subscope for items creating a scope: + if type(sym) in self.scoped_types: + newScope = Scope(self.CurrentScope) + self.scopeStack.append(newScope) + sym.innerScope = self.CurrentScope + + def quitScope(self, sym): + # Pop out of scope: + if type(sym) in self.scoped_types: + self.scopeStack.pop(-1) class Builder:
--- a/python/ppci/c3/codegenerator.py Thu Dec 12 20:42:56 2013 +0100 +++ b/python/ppci/c3/codegenerator.py Fri Dec 13 11:53:29 2013 +0100 @@ -1,18 +1,13 @@ import logging from .. import ir from .. import irutils -from .astnodes import Symbol, Package, Variable, Function -from .astnodes import Statement, Empty, Compound, If, While, Assignment -from .astnodes import ExpressionStatement, Return -from .astnodes import Expression, Binop, Unop, Identifier, Deref, Member -from .astnodes import Expression, FunctionCall, Literal, TypeCast -from .astnodes import Type, DefinedType, BaseType, PointerType, StructureType - -from ppci import CompilerError +from . import astnodes as ast class SemanticError(Exception): + """ Error thrown when a semantic issue is observed """ def __init__(self, msg, loc): + super().__init__() self.msg = msg self.loc = loc @@ -33,8 +28,9 @@ self.diag = diag def gencode(self, pkg): + """ Generate code for a single module """ self.prepare() - assert type(pkg) is Package + assert type(pkg) is ast.Package self.pkg = pkg self.intType = pkg.scope['int'] self.boolType = pkg.scope['bool'] @@ -42,16 +38,6 @@ self.varMap = {} # Maps variables to storage locations. self.funcMap = {} self.m = ir.Module(pkg.name) - self.genModule(pkg) - return self.m - - def error(self, msg, loc=None): - self.pkg.ok = False - self.diag.error(msg, loc) - - # inner helpers: - def genModule(self, pkg): - # Take care of forward declarations: try: for s in pkg.innerScope.Functions: f = self.newFunction(s.name) @@ -59,15 +45,20 @@ for v in pkg.innerScope.Variables: self.varMap[v] = self.newTemp() for s in pkg.innerScope.Functions: - self.genFunction(s) + self.gen_function(s) except SemanticError as e: self.error(e.msg, e.loc) + return self.m + + def error(self, msg, loc=None): + self.pkg.ok = False + self.diag.error(msg, loc) def checkType(self, t): """ Verify the type is correct """ t = self.theType(t) - def genFunction(self, fn): + def gen_function(self, fn): # TODO: handle arguments f = self.funcMap[fn] f.return_value = self.newTemp() @@ -81,43 +72,42 @@ # TODO: handle parameters different if sym.isParameter: self.checkType(sym.typ) - v = ir.Parameter(sym.name) - f.addParameter(v) + variable = ir.Parameter(sym.name) + f.addParameter(variable) elif sym.isLocal: self.checkType(sym.typ) - v = ir.LocalVariable(sym.name) - f.addLocal(v) - elif isinstance(sym, Variable): + variable = ir.LocalVariable(sym.name) + f.addLocal(variable) + elif isinstance(sym, ast.Variable): self.checkType(sym.typ) - v = ir.LocalVariable(sym.name) - f.addLocal(v) + variable = ir.LocalVariable(sym.name) + f.addLocal(variable) else: - #v = self.newTemp() raise NotImplementedError('{}'.format(sym)) - self.varMap[sym] = v + self.varMap[sym] = variable self.genCode(fn.body) - # Set the default return value to zero: - # TBD: this may not be required? self.emit(ir.Move(f.return_value, ir.Const(0))) self.emit(ir.Jump(f.epiloog)) self.setFunction(None) def genCode(self, code): + """ Wrapper around gen_stmt to catch errors """ try: - self.genStmt(code) + self.gen_stmt(code) except SemanticError as e: self.error(e.msg, e.loc) - def genStmt(self, code): - assert isinstance(code, Statement) + def gen_stmt(self, code): + """ Generate code for a statement """ + assert isinstance(code, ast.Statement) self.setLoc(code.loc) - if type(code) is Compound: + if type(code) is ast.Compound: for s in code.statements: self.genCode(s) - elif type(code) is Empty: + elif type(code) is ast.Empty: pass - elif type(code) is Assignment: + elif type(code) is ast.Assignment: lval = self.genExprCode(code.lval) rval = self.genExprCode(code.rval) if not self.equalTypes(code.lval.typ, code.rval.typ): @@ -126,13 +116,13 @@ if not code.lval.lvalue: raise SemanticError('No valid lvalue {}'.format(code.lval), code.lval.loc) self.emit(ir.Move(lval, rval)) - elif type(code) is ExpressionStatement: + elif type(code) is ast.ExpressionStatement: self.emit(ir.Exp(self.genExprCode(code.ex))) - elif type(code) is If: + elif type(code) is ast.If: bbtrue = self.newBlock() bbfalse = self.newBlock() te = self.newBlock() - self.genCondCode(code.condition, bbtrue, bbfalse) + self.gen_cond_code(code.condition, bbtrue, bbfalse) self.setBlock(bbtrue) self.genCode(code.truestatement) self.emit(ir.Jump(te)) @@ -140,19 +130,19 @@ self.genCode(code.falsestatement) self.emit(ir.Jump(te)) self.setBlock(te) - elif type(code) is Return: + elif type(code) is ast.Return: re = self.genExprCode(code.expr) self.emit(ir.Move(self.fn.return_value, re)) self.emit(ir.Jump(self.fn.epiloog)) b = self.newBlock() self.setBlock(b) - elif type(code) is While: + elif type(code) is ast.While: bbdo = self.newBlock() bbtest = self.newBlock() te = self.newBlock() self.emit(ir.Jump(bbtest)) self.setBlock(bbtest) - self.genCondCode(code.condition, bbdo, te) + self.gen_cond_code(code.condition, bbdo, te) self.setBlock(bbdo) self.genCode(code.statement) self.emit(ir.Jump(bbtest)) @@ -160,26 +150,27 @@ else: raise NotImplementedError('Unknown stmt {}'.format(code)) - def genCondCode(self, expr, bbtrue, bbfalse): - # Implement sequential logical operators - if type(expr) is Binop: + def gen_cond_code(self, expr, bbtrue, bbfalse): + """ Generate conditional logic. + Implement sequential logical operators. """ + if type(expr) is ast.Binop: if expr.op == 'or': l2 = self.newBlock() - self.genCondCode(expr.a, bbtrue, l2) - if not equalTypes(expr.a.typ, self.boolType): + self.gen_cond_code(expr.a, bbtrue, l2) + if not self.equalTypes(expr.a.typ, self.boolType): raise SemanticError('Must be boolean', expr.a.loc) self.setBlock(l2) - self.genCondCode(expr.b, bbtrue, bbfalse) - if not equalTypes(expr.b.typ, self.boolType): + self.gen_cond_code(expr.b, bbtrue, bbfalse) + if not self.equalTypes(expr.b.typ, self.boolType): raise SemanticError('Must be boolean', expr.b.loc) elif expr.op == 'and': l2 = self.newBlock() - self.genCondCode(expr.a, l2, bbfalse) - if not equalTypes(expr.a.typ, self.boolType): + self.gen_cond_code(expr.a, l2, bbfalse) + if not self.equalTypes(expr.a.typ, self.boolType): self.error('Must be boolean', expr.a.loc) self.setBlock(l2) - self.genCondCode(expr.b, bbtrue, bbfalse) - if not equalTypes(expr.b.typ, self.boolType): + self.gen_cond_code(expr.b, bbtrue, bbfalse) + if not self.equalTypes(expr.b.typ, self.boolType): raise SemanticError('Must be boolean', expr.b.loc) elif expr.op in ['==', '>', '<', '!=', '<=', '>=']: ta = self.genExprCode(expr.a) @@ -191,20 +182,21 @@ else: raise NotImplementedError('Unknown condition {}'.format(expr)) expr.typ = self.boolType - elif type(expr) is Literal: + elif type(expr) is ast.Literal: + self.genExprCode(expr) if expr.val: self.emit(ir.Jump(bbtrue)) else: self.emit(ir.Jump(bbfalse)) - expr.typ = self.boolType else: raise NotImplementedError('Unknown cond {}'.format(expr)) if not self.equalTypes(expr.typ, self.boolType): self.error('Condition must be boolean', expr.loc) def genExprCode(self, expr): - assert isinstance(expr, Expression) - if type(expr) is Binop: + """ Generate code for an expression. Return the generated ir-value """ + assert isinstance(expr, ast.Expression) + if type(expr) is ast.Binop: expr.lvalue = False if expr.op in ['+', '-', '*', '/', '<<', '>>', '|', '&']: ra = self.genExprCode(expr.a) @@ -213,15 +205,14 @@ self.equalTypes(expr.b.typ, self.intType): expr.typ = expr.a.typ else: - # assume void here? TODO: throw exception! raise SemanticError('Can only add integers', expr.loc) else: raise NotImplementedError("Cannot use equality as expressions") return ir.Binop(ra, expr.op, rb) - elif type(expr) is Unop: + elif type(expr) is ast.Unop: if expr.op == '&': ra = self.genExprCode(expr.a) - expr.typ = PointerType(expr.a.typ) + expr.typ = ast.PointerType(expr.a.typ) if not expr.a.lvalue: raise SemanticError('No valid lvalue', expr.a.loc) expr.lvalue = False @@ -229,50 +220,46 @@ return ra.e else: raise NotImplementedError('Unknown unop {0}'.format(expr.op)) - elif type(expr) is Identifier: + elif type(expr) is ast.Identifier: # Generate code for this identifier. expr.lvalue = True tg = self.resolveSymbol(expr) expr.kind = type(tg) expr.typ = tg.typ # This returns the dereferenced variable. - if type(tg) is Variable: - # TODO: now parameters are handled different. Not nice? + if isinstance(tg, ast.Variable): return ir.Mem(self.varMap[tg]) else: - return ir.Mem(self.varMap[tg]) - elif type(expr) is Deref: + raise NotImplementedError(str(tg)) + elif type(expr) is ast.Deref: # dereference pointer type: addr = self.genExprCode(expr.ptr) ptr_typ = self.theType(expr.ptr.typ) expr.lvalue = True - if type(ptr_typ) is PointerType: + if type(ptr_typ) is ast.PointerType: expr.typ = ptr_typ.ptype return ir.Mem(addr) else: raise SemanticError('Cannot deref non-pointer', expr.loc) - expr.typ = self.intType - return ir.Mem(ir.Const(0)) - elif type(expr) is Member: + elif type(expr) is ast.Member: base = self.genExprCode(expr.base) expr.lvalue = expr.base.lvalue basetype = self.theType(expr.base.typ) - if type(basetype) is StructureType: + if type(basetype) is ast.StructureType: if basetype.hasField(expr.field): expr.typ = basetype.fieldType(expr.field) else: raise SemanticError('{} does not contain field {}' - .format(basetype, expr.field), expr.loc) + .format(basetype, expr.field), expr.loc) else: - raise SemanticError('Cannot select field {} of non-structure type {}' - .format(sym.field, basetype), sym.loc) + raise SemanticError('Cannot select {} of non-structure type {}' + .format(expr.field, basetype), expr.loc) assert type(base) is ir.Mem, type(base) - base = base.e bt = self.theType(expr.base.typ) offset = ir.Const(bt.fieldOffset(expr.field)) - return ir.Mem(ir.Add(base, offset)) - elif type(expr) is Literal: + return ir.Mem(ir.Add(base.e, offset)) + elif type(expr) is ast.Literal: expr.lvalue = False typemap = {int: 'int', float: 'double', bool: 'bool'} if type(expr.val) in typemap: @@ -280,55 +267,59 @@ else: raise SemanticError('Unknown literal type {}'.format(expr.val)) return ir.Const(expr.val) - elif type(expr) is TypeCast: - # TODO: improve this mess: - ar = self.genExprCode(expr.a) - ft = self.theType(expr.a.typ) - tt = self.theType(expr.to_type) - if isinstance(ft, PointerType) and isinstance(tt, PointerType): - expr.typ = expr.to_type - return ar - elif type(ft) is BaseType and ft.name == 'int' and \ - isinstance(tt, PointerType): - expr.typ = expr.to_type - return ar - else: - self.error('Cannot cast {} to {}' - .format(ft, tt), expr.loc) - expr.typ = self.intType - return ir.Const(0) - elif type(expr) is FunctionCall: - # Evaluate the arguments: - args = [self.genExprCode(e) for e in expr.args] - # Check arguments: - if type(expr.proc) is Identifier: - tg = self.resolveSymbol(expr.proc) - else: - raise Exception() - assert type(tg) is Function - ftyp = tg.typ - fname = tg.name - ptypes = ftyp.parametertypes - if len(expr.args) != len(ptypes): - raise SemanticError('Function {2}: {0} arguments required, {1} given' - .format(len(ptypes), len(expr.args), fname), expr.loc) - for arg, at in zip(expr.args, ptypes): - if not self.equalTypes(arg.typ, at): - raise SemanticError('Got {0}, expected {1}' - .format(arg.typ, at), arg.loc) - # determine return type: - expr.typ = ftyp.returntype - return ir.Call(fname, args) + elif type(expr) is ast.TypeCast: + return self.gen_type_cast(expr) + elif type(expr) is ast.FunctionCall: + return self.gen_function_call(expr) else: raise NotImplementedError('Unknown expr {}'.format(expr)) + def gen_type_cast(self, expr): + """ Generate code for type casting """ + ar = self.genExprCode(expr.a) + from_type = self.theType(expr.a.typ) + to_type = self.theType(expr.to_type) + if isinstance(from_type, ast.PointerType) and isinstance(to_type, ast.PointerType): + expr.typ = expr.to_type + return ar + elif type(from_type) is ast.BaseType and from_type.name == 'int' and \ + isinstance(to_type, ast.PointerType): + expr.typ = expr.to_type + return ar + else: + raise SemanticError('Cannot cast {} to {}' + .format(from_type, to_type), expr.loc) + + def gen_function_call(self, expr): + """ Generate code for a function call """ + # Evaluate the arguments: + args = [self.genExprCode(e) for e in expr.args] + # Check arguments: + tg = self.resolveSymbol(expr.proc) + if type(tg) is not ast.Function: + raise SemanticError('cannot call {}'.format(tg)) + ftyp = tg.typ + fname = tg.name + ptypes = ftyp.parametertypes + if len(expr.args) != len(ptypes): + raise SemanticError('{} requires {} arguments, {} given' + .format(fname, len(ptypes), len(expr.args)), expr.loc) + for arg, at in zip(expr.args, ptypes): + if not self.equalTypes(arg.typ, at): + raise SemanticError('Got {}, expected {}' + .format(arg.typ, at), arg.loc) + # determine return type: + expr.typ = ftyp.returntype + return ir.Call(fname, args) + def resolveSymbol(self, sym): - assert type(sym) in [Identifier, Member] - if type(sym) is Member: + if type(sym) is ast.Member: base = self.resolveSymbol(sym.base) + if type(base) is not ast.Package: + raise SemanticError('Base is not a package', sym.loc) scope = base.innerScope name = sym.field - elif type(sym) is Identifier: + elif type(sym) is ast.Identifier: scope = sym.scope name = sym.target else: @@ -337,23 +328,20 @@ s = scope[name] else: raise SemanticError('{} undefined'.format(name), sym.loc) - assert isinstance(s, Symbol) + assert isinstance(s, ast.Symbol) return s def theType(self, t): """ Recurse until a 'real' type is found """ - if type(t) is DefinedType: + if type(t) is ast.DefinedType: t = self.theType(t.typ) - elif type(t) is Identifier: + elif type(t) in [ast.Identifier, ast.Member]: t = self.theType(self.resolveSymbol(t)) - elif type(t) is Member: - # Possible when using types of modules: - t = self.theType(self.resolveSymbol(t)) - elif isinstance(t, Type): + elif isinstance(t, ast.Type): pass else: raise NotImplementedError(str(t)) - assert isinstance(t, Type) + assert isinstance(t, ast.Type) return t def equalTypes(self, a, b): @@ -361,15 +349,15 @@ # Recurse into named types: a = self.theType(a) b = self.theType(b) - assert isinstance(a, Type) - assert isinstance(b, Type) + assert isinstance(a, ast.Type) + assert isinstance(b, ast.Type) if type(a) is type(b): - if type(a) is BaseType: + if type(a) is ast.BaseType: return a.name == b.name - elif type(a) is PointerType: + elif type(a) is ast.PointerType: return self.equalTypes(a.ptype, b.ptype) - elif type(a) is StructureType: + elif type(a) is ast.StructureType: if len(a.mems) != len(b.mems): return False return all(self.equalTypes(am.typ, bm.typ) for am, bm in
--- a/python/ppci/c3/parser.py Thu Dec 12 20:42:56 2013 +0100 +++ b/python/ppci/c3/parser.py Fri Dec 13 11:53:29 2013 +0100 @@ -346,26 +346,27 @@ def PostFixExpression(self): pfe = self.PrimaryExpression() - if self.hasConsumed('('): - # Function call - args = [] - if not self.hasConsumed(')'): - args.append(self.Expression()) - while self.hasConsumed(','): + while self.Peak in ['[', '.', '->', '(']: + if self.hasConsumed('['): + raise NotImplementedError('Array not yet implemented') + elif self.hasConsumed('->'): + field = self.Consume('ID') + pfe = Deref(pfe, pfe.loc) + pfe = Member(pfe, field.val, field.loc) + elif self.hasConsumed('.'): + field = self.Consume('ID') + pfe = Member(pfe, field.val, field.loc) + elif self.hasConsumed('('): + # Function call + args = [] + if not self.hasConsumed(')'): args.append(self.Expression()) - self.Consume(')') - pfe = FunctionCall(pfe, args, pfe.loc) - else: - while self.Peak in ['[', '.', '->']: - if self.hasConsumed('['): - raise NotImplementedError('Array not yet implemented') - elif self.hasConsumed('->'): - field = self.Consume('ID') - pfe = Deref(pfe, pfe.loc) - pfe = Member(pfe, field.val, field.loc) - elif self.hasConsumed('.'): - field = self.Consume('ID') - pfe = Member(pfe, field.val, field.loc) + while self.hasConsumed(','): + args.append(self.Expression()) + self.Consume(')') + pfe = FunctionCall(pfe, args, pfe.loc) + else: + raise Exception() return pfe def PrimaryExpression(self):
--- a/test/testc3.py Thu Dec 12 20:42:56 2013 +0100 +++ b/test/testc3.py Fri Dec 13 11:53:29 2013 +0100 @@ -237,6 +237,36 @@ """ self.expectOK(snippet) + def testAndCondition(self): + snippet = """ + module tst; + function void t() { + if (4 > 3 and 1 < 10) { + } + } + """ + self.expectOK(snippet) + + def testOrCondition(self): + snippet = """ + module tst; + function void t() { + if (3 > 4 or 3 < 10) { + } + } + """ + self.expectOK(snippet) + + def testNonBoolCondition(self): + snippet = """ + module tst; + function void t() { + if (3) { + } + } + """ + self.expectErrors(snippet, [4]) + def testTypeDef(self): snippet = """ module testtypedef; @@ -284,6 +314,17 @@ """ self.expectOK(snippet) + def testStruct2(self): + """ Select struct member from non struct type """ + snippet = """ + module teststruct1; + function void t() { + var int a; + a.z = 2; + } + """ + self.expectErrors(snippet, [5]) + def testStructCall(self): snippet = """ module teststruct1; @@ -293,7 +334,7 @@ a.x(9); } """ - self.expectOK(snippet) + self.expectErrors(snippet, [6]) def testPointerType1(self): snippet = """ @@ -304,6 +345,7 @@ var int a; pa = &a; *pa = 22; + a = *pa + *pa * 8; } """ self.expectOK(snippet) @@ -374,7 +416,7 @@ *cast<gpio>(*a); } """ - self.expectErrors(snippet, [7, 7]) + self.expectErrors(snippet, [7]) def testComplexType(self): snippet = """