Mercurial > lcfOS
changeset 149:74241ca312cc
Fixes on parser and semantics
author | Windel Bouwman |
---|---|
date | Fri, 01 Mar 2013 11:43:52 +0100 |
parents | e5263f74b287 |
children | 4ae0e02599de |
files | python/c3/astnodes.py python/c3/lexer.py python/c3/parser.py python/c3/semantics.py python/testc3.py |
diffstat | 5 files changed, 100 insertions(+), 74 deletions(-) [+] |
line wrap: on
line diff
--- a/python/c3/astnodes.py Fri Mar 01 10:24:01 2013 +0100 +++ b/python/c3/astnodes.py Fri Mar 01 11:43:52 2013 +0100 @@ -64,7 +64,7 @@ else: return False -class Type: +class Type(Node): def isType(self, b): return isType(self, b) @@ -93,25 +93,21 @@ pass class Constant(Symbol): - def __init__(self, value, typ, name=None, public=False): + def __init__(self, value, name=None): self.name = name self.value = value - self.typ = typ - self.public = public def __repr__(self): return 'CONSTANT {0} = {1}'.format(self.name, self.value) class Variable(Symbol): - def __init__(self, name, typ, public): + def __init__(self, name, typ): self.name = name self.typ = typ - self.public = public self.isLocal = False self.isReadOnly = False self.isParameter = False def __repr__(self): - txt = '[public] ' if self.public else '' - return '{2}VAR {0} : {1}'.format(self.name, self.typ, txt) + return 'VAR {0} : {1}'.format(self.name, self.typ) class Parameter(Node): """ A parameter has a passing method, name and typ """ @@ -135,7 +131,7 @@ self.b = b self.op = op # Operation: '+', '-', '*', '/', 'mod' def __repr__(self): - return 'BINOP {0} {1}'.format(self.op, self.typ) + return 'BINOP {0}'.format(self.op) # Modules class Package(Node): @@ -147,9 +143,9 @@ # Procedure types class Procedure(Symbol): """ Actual implementation of a function """ - def __init__(self, name, typ, block): + def __init__(self, name, typ=None, block=None): self.name = name - self.block = block + self.body = block self.typ = typ def __repr__(self): return 'PROCEDURE {0} {1}'.format(self.name, self.typ) @@ -161,9 +157,11 @@ def __repr__(self): return 'COMPOUND STATEMENT' -class EmptyStatement(Node): +class ReturnStatement(Node): + def __init__(self, expr): + self.expr = expr def __repr__(self): - return 'EMPTY STATEMENT' + return 'RETURN STATEMENT' class Assignment(Node): def __init__(self, lval, rval):
--- a/python/c3/lexer.py Fri Mar 01 10:24:01 2013 +0100 +++ b/python/c3/lexer.py Fri Mar 01 11:43:52 2013 +0100 @@ -10,7 +10,7 @@ keywords = ['and', 'or', 'not','true', 'false', \ 'else', 'if', 'while', 'return', \ - 'public', 'function', 'var', 'type', \ + 'function', 'var', 'type', \ 'import', 'package' ] def tokenize(s):
--- a/python/c3/parser.py Fri Mar 01 10:24:01 2013 +0100 +++ b/python/c3/parser.py Fri Mar 01 11:43:52 2013 +0100 @@ -6,11 +6,6 @@ '<': 20, '>': 20, '==': 20, '<=': 20, '>=': 20, '!=': 20, \ '+': 30, '-': 30, '*': 40, '/': 40 } -def getTokenPrecedence(typ): - if typ in binopPrecs: - return binopPrecs[typ] - return -1 - class Parser: """ Parses sourcecode into an abstract syntax tree (AST) """ def __init__(self, sema, diag): @@ -38,7 +33,9 @@ return self.token.typ @property def PeakPrec(self): - return getTokenPrecedence(self.Peak) + if self.Peak in binopPrecs: + return binopPrecs[self.Peak] + return -1 def hasConsumed(self, typ): if self.Peak == typ: self.Consume(typ) @@ -64,16 +61,18 @@ self.Consume('END') def parseTopLevel(self): - is_public = self.hasConsumed('public') if self.Peak == 'function': - self.parseFunctionDefinition(is_public) + self.parseFunctionDefinition() elif self.Peak == 'var': - self.parseVarDef(is_public) + self.parseVarDef() + self.Consume(';') + else: + self.Error('Expected function or variable') def parseDesignator(self): """ A designator designates an object """ name = self.Consume('ID') - return name + return name.val # Type system def parseType(self): @@ -81,19 +80,25 @@ return d # Variable declarations: - def parseVarDef(self, is_public): + def parseVarDef(self): self.Consume('var') - typ = self.parseType() - ID = self.Consume('ID') - self.Consume(';') - v = Variable(i.name, typename, public=is_public) - self.curScope.add(v) + t = self.parseType() + def parseVar(): + name = self.Consume('ID') + ival = None + if self.hasConsumed('='): + ival = self.parseExpression() + self.sema.actOnVarDef(name.val, name.loc, t, ival) + parseVar() + while self.hasConsumed(','): + parseVar() # Procedures - def parseFunctionDefinition(self, is_pub): + def parseFunctionDefinition(self): self.Consume('function') returntype = self.parseType() - procname = self.Consume('ID') + pname = self.Consume('ID') + self.sema.actOnFuncDef1(pname.val, pname.loc) self.Consume('(') parameters = [] if not self.hasConsumed(')'): @@ -105,9 +110,8 @@ name = self.Consume('ID') parameters.append(astnodes.Parameter(name, typ)) self.Consume(')') - proctyp = astnodes.FunctionType(parameters, returntype) body = self.parseCompoundStatement() - return astnodes.Procedure(procname, proctyp, body) + self.sema.actOnFuncDef2(parameters, returntype, body) # Statements: def parseAssignment(self, lval): @@ -125,48 +129,37 @@ self.Consume(')') return ProcedureCall(procedure, args) - def parseLocal(self, t): - name = self.Consume('ID') - if self.hasConsumed('='): - ival = self.parseExpression() - else: - ival = None - self.sema.actOnLocal(t, name, ival) - def parseLocalDeclaration(self): - self.Consume('var') - t = self.parseType() - self.parseLocal(t) - while self.hasConsumed(','): - self.parseLocal(t) - def parseIfStatement(self): self.Consume('if') self.Consume('(') condition = self.parseExpression() self.Consume(')') - truestatement = self.parseStatement() + yes = self.parseCompoundStatement() if self.hasConsumed('else'): - els = self.parseStatement() - return astnodes.IfStatement(condition, truestatement, els) - return astnodes.IfStatement(condition, truestatement) + no = self.parseCompoundStatement() + return astnodes.IfStatement(condition, yes, no) + return astnodes.IfStatement(condition, yes) def parseWhileStatement(self): self.Consume('while') self.Consume('(') condition = self.parseExpression() self.Consume(')') - statements = self.parseStatement() + statements = self.parseCompoundStatement() + return astnodes.WhileStatement(condition, statements) + def parseReturnStatement(self): self.Consume('return') expr = self.parseExpression() + return astnodes.ReturnStatement(expr) def parseCompoundStatement(self): - self.Consume('{') - statements = [self.parseStatement()] - while self.hasConsumed(';'): + self.Consume('{') + statements = [self.parseStatement()] + while self.hasConsumed(';'): statements.append(self.parseStatement()) - self.Consume('}') - return astnodes.CompoundStatement(statements) + self.Consume('}') + return astnodes.CompoundStatement(statements) def parseStatement(self): # Determine statement type based on the pending token: @@ -177,11 +170,10 @@ elif self.Peak == '{': return self.parseCompoundStatement() elif self.Peak == 'var': - return self.parseLocalDeclaration() + return self.parseVarDef() elif self.Peak == 'return': return self.parseReturnStatement() elif self.Peak == 'ID': - # Assignment or procedure call designator = self.parseDesignator() if self.Peak == '(': return self.parseProcedureCall(designator) @@ -199,7 +191,7 @@ return e elif self.Peak == 'NUMBER': val = self.Consume('NUMBER') - return astnodes.Constant(val, val) + return self.sema.actOnNumber(val.val, val.loc) elif self.Peak == 'ID': d = self.parseDesignator() return d @@ -212,6 +204,6 @@ rhs = self.parsePrimary() while self.PeakPrec > op_prec: rhs = self.parseBinopRhs(rhs, self.PeakPrec) - lhs = astnodes.Binop(lhs, op, rhs) + lhs = self.sema.actOnBinop(lhs, op.typ, rhs, op.loc) return lhs
--- a/python/c3/semantics.py Fri Mar 01 10:24:01 2013 +0100 +++ b/python/c3/semantics.py Fri Mar 01 11:43:52 2013 +0100 @@ -5,6 +5,8 @@ def __init__(self, parent=None): self.symbols = {} self.parent = parent + def __iter__(self): + return iter(self.symbols.values()) def getType(self, name): t = self.getSymbol(name) print(t) @@ -39,11 +41,28 @@ self.mod.loc = loc self.mod.scope = self.curScope = Scope() createBuiltins(self.curScope) - def handleBinop(self, lhs, op, rhs): - pass - def actOnLocal(self, t, name, ival): - s = astnodes.Variable(name, t, False) + def actOnBinop(self, lhs, op, rhs, loc): + bo = astnodes.Binop(lhs, op, rhs) + bo.loc = loc + return bo + def actOnNumber(self, num, loc): + n = astnodes.Constant(num) + n.loc = loc + return n + def actOnVarDef(self, name, loc, t, ival): + s = astnodes.Variable(name, t) + s.loc = loc self.curScope.addSymbol(s) + def actOnFuncDef1(self, name, loc): + self.curFunc = astnodes.Procedure(name) + self.curFunc.loc = loc + self.curScope.addSymbol(self.curFunc) + self.curScope = self.curFunc.scope = Scope(self.curScope) + def actOnFuncDef2(self, parameters, returntype, body): + self.curFunc.body = body + self.curFunc.typ = astnodes.FunctionType(parameters, returntype) + self.curFunc = None + self.curScope = self.curScope.parent def actOnType(self, tok): # Try to lookup type, in case of failure return void pass
--- a/python/testc3.py Fri Mar 01 10:24:01 2013 +0100 +++ b/python/testc3.py Fri Mar 01 11:43:52 2013 +0100 @@ -1,10 +1,14 @@ import c3.parser, c3.semantics from ppci.errors import printError, Diagnostics +import time testsrc = """ package test; -public function void test1() +var u32 a ; +var u32 c, d; + +function void test1() { var u32 b; var int a = 10; @@ -18,20 +22,31 @@ } } -public function int t2(u32 a, u32 b) +function int t2(u32 a, u32 b) { return a + b; a = 2 } +function int t2(u32 a, u32 b) +{ + return a + b; + a = 2 + 33 - 1; + a = a - 2 +} + """ -def printAst(ast): - print(ast) +def printAst(ast, indent=''): + print(indent + str(ast)) + if isinstance(ast, c3.astnodes.Package): + for s in ast.scope: + printAst(s, indent + ' ') + if isinstance(ast, c3.astnodes.Procedure): + for s in ast.scope: + printAst(s, indent + ' ') for c in ast.getChildren(): - printAst(c) - if isinstance(ast, c3.astnodes.Package): - print('PACK', ast.scope) + printAst(c, indent + ' ') def do(): print('[0] source:') @@ -40,8 +55,10 @@ diag = Diagnostics() sema = c3.semantics.Semantics(diag) p = c3.parser.Parser(sema, diag) - + t1 = time.time() p.parseSource(testsrc) + t2 = time.time() + print('parsetime: {0} [s]'.format(t2 - t1)) for d in diag.diags: print('ERROR:', d)