Mercurial > lcfOS
diff python/c3/parser.py @ 213:003c8a976fff
Merge of semantics and parser again ..
author | Windel Bouwman |
---|---|
date | Fri, 05 Jul 2013 11:18:48 +0200 |
parents | 46d62dadd61b |
children | c1ccb1cb4cef |
line wrap: on
line diff
--- a/python/c3/parser.py Sun Jun 30 19:00:41 2013 +0200 +++ b/python/c3/parser.py Fri Jul 05 11:18:48 2013 +0200 @@ -1,4 +1,4 @@ -from . import astnodes, lexer, semantics +from . import astnodes, lexer from ppci import CompilerError # binop precedence for expressions: @@ -7,140 +7,173 @@ '+': 30, '-': 30, '*': 40, '/': 40 } class Parser: - """ Parses sourcecode into an abstract syntax tree (AST) """ - def __init__(self, diag): - self.sema = semantics.Semantics(diag) - self.diag = diag - def parseSource(self, source): + """ Parses sourcecode into an abstract syntax tree (AST) """ + def __init__(self, diag): + self.diag = diag + + def parseSource(self, source): self.initLex(source) - self.sema.reinit() try: self.parsePackage() - return self.sema.mod + return self.mod except CompilerError as e: self.diag.addDiag(e) - def Error(self, msg): + def Error(self, msg): raise CompilerError(msg, self.token.loc) - # Lexer helpers: - def Consume(self, typ): + # Lexer helpers: + def Consume(self, typ): if self.Peak == typ: return self.NextToken() else: self.Error('Excected: "{0}", got "{1}"'.format(typ, self.Peak)) - @property - def Peak(self): + @property + def Peak(self): return self.token.typ - @property - def PeakPrec(self): + @property + def PeakPrec(self): if self.Peak in binopPrecs: return binopPrecs[self.Peak] return -1 - def hasConsumed(self, typ): + def hasConsumed(self, typ): if self.Peak == typ: self.Consume(typ) return True return False - def NextToken(self): + + def NextToken(self): t = self.token if t.typ != 'END': self.token = self.tokens.__next__() return t - def initLex(self, source): + + def initLex(self, source): self.tokens = lexer.tokenize(source) # Lexical stage self.token = self.tokens.__next__() - def skipToSemi(self, tt): - while self.Peak != tt and self.Peak != 'END': - self.NextToken() - if self.Peak == tt: - self.Consume(tt) - - def parsePackage(self): + + def parseUses(self): + pass + + def parsePackage(self): self.Consume('package') name = self.Consume('ID') self.Consume(';') - self.sema.handlePackage(name.val, name.loc) + self.mod = astnodes.Package(name.val, name.loc) + self.parseUses() # TODO: parse uses while self.Peak != 'END': self.parseTopLevel() self.Consume('END') - def parseTopLevel(self): + def parseTopLevel(self): if self.Peak == 'function': - self.parseFunctionDefinition() + self.parseFunctionDef() elif self.Peak == 'var': self.parseVarDef() elif self.Peak == 'const': self.parseConstDef() + elif self.Peak == 'type': + self.parseTypeDef() else: - self.Error('Expected function or variable') + self.Error('Expected function, var, const or type') - def parseDesignator(self): + def parseDesignator(self): """ A designator designates an object """ name = self.Consume('ID') - return self.sema.actOnDesignator(name.val, name.loc) - - # Type system - def parseType(self): - d = self.parseDesignator() + d = astnodes.Designator(name.val, name.loc) return d - # Variable declarations: - def parseVarDef(self): + # Type system + def parseTypeSpec(self): + # For now, do simple type spec, just parse an ID: + return self.parseDesignator() + if self.Peak == 'struct': + self.Consume('struct') + self.Consume('{') + mems = [] + while self.Peak != '}': + mem_t = self.parseTypeSpec() + mem_n = self.Consume('ID') + mems.append((mem_t, mem_n)) + while self.hasConsumed(','): + mem_n = self.Consume('ID') + mems.append((mem_t, mem_n)) + self.Consume(';') + self.Consume('}') + theT = astnodes.StructureType(mems) + else: + theT = self.parseDesignator() + # Check for pointer suffix: + while self.hasConsumed('*'): + theT = astnodes.PointerType(theT) + return theT + + def parseTypeDef(self): + self.Consume('type') + newtype = self.parseTypeSpec() + typename = self.Consume('ID') + # TODO: action here :) + self.Consume(';') + return astnodes.DefinedType(typename, newtype) + + # Variable declarations: + def parseVarDef(self): self.Consume('var') - t = self.parseType() + t = self.parseTypeSpec() def parseVar(): name = self.Consume('ID') - ival = None + v = astnodes.Variable(name.val, t) + v.loc = name.loc if self.hasConsumed('='): - ival = self.parseExpression() - self.sema.actOnVarDef(name.val, name.loc, t, ival) + v.ival = self.parseExpression() parseVar() while self.hasConsumed(','): parseVar() self.Consume(';') - def parseConstDef(self): + def parseConstDef(self): self.Consume('const') - t = self.parseType() + t = self.parseTypeSpec() def parseConst(): name = self.Consume('ID') self.Consume('=') val = self.parseExpression() - self.sema.actOnConstDef(name.val, name.loc, t, val) + c = astnodes.Constant(name.val, t, val) + c.loc = name.loc parseConst() while self.hasConsumed(','): parseConst() self.Consume(';') - # Procedures - def parseFunctionDefinition(self): - self.Consume('function') - returntype = self.parseType() - pname = self.Consume('ID') - self.sema.actOnFuncDef1(pname.val, pname.loc) + # Procedures + def parseFunctionDef(self): + loc = self.Consume('function').loc + returntype = self.parseTypeSpec() + fname = self.Consume('ID').val + f = astnodes.Function(fname, loc) self.Consume('(') parameters = [] if not self.hasConsumed(')'): def parseParameter(): - typ = self.parseType() + typ = self.parseTypeSpec() name = self.Consume('ID') - parameters.append(self.sema.actOnParameter(name.val, name.loc, typ)) + param = astnodes.Variable(name.val, typ) + param.loc = name.loc + parameters.append(param) parseParameter() while self.hasConsumed(','): parseParameter() self.Consume(')') body = self.parseCompoundStatement() - self.sema.actOnFuncDef2(parameters, returntype, body) - # Statements: - def parseAssignment(self, lval): - lval = self.sema.actOnVariableUse(lval, lval.loc) + # Statements: + def parseAssignment(self, lval): + lval = astnodes.VariableUse(lval, lval.loc) loc = self.Consume('=').loc rval = self.parseExpression() self.Consume(';') - return self.sema.actOnAssignment(lval, rval, loc) + return astnodes.Assignment(lval, rval, loc) - def parseProcedureCall(self, func): + def parseCall(self, func): self.Consume('(') args = [] if not self.hasConsumed(')'): @@ -148,9 +181,9 @@ while self.hasConsumed(','): args.append(self.parseExpression()) self.Consume(')') - return self.sema.actOnFunctionCall(func, args, func.loc) + return astnodes.FunctionCall(func, args, func.loc) - def parseIfStatement(self): + def parseIfStatement(self): loc = self.Consume('if').loc self.Consume('(') condition = self.parseExpression() @@ -160,23 +193,23 @@ no = self.parseCompoundStatement() else: no = astnodes.EmptyStatement() - return self.sema.actOnIfStatement(condition, yes, no, loc) + return astnodes.IfStatement(condition, yes, no, loc) - def parseWhileStatement(self): - self.Consume('while') + def parseWhileStatement(self): + loc = self.Consume('while').loc self.Consume('(') condition = self.parseExpression() self.Consume(')') statements = self.parseCompoundStatement() - return astnodes.WhileStatement(condition, statements) + return astnodes.WhileStatement(condition, statements, loc) - def parseReturnStatement(self): + def parseReturnStatement(self): self.Consume('return') expr = self.parseExpression() self.Consume(';') return astnodes.ReturnStatement(expr) - def parseCompoundStatement(self): + def parseCompoundStatement(self): self.Consume('{') statements = [] while not self.hasConsumed('}'): @@ -185,7 +218,7 @@ statements.append(s) return astnodes.CompoundStatement(statements) - def parseStatement(self): + def parseStatement(self): # Determine statement type based on the pending token: if self.Peak == 'if': return self.parseIfStatement() @@ -200,49 +233,51 @@ return astnodes.EmptyStatement() elif self.Peak == 'return': return self.parseReturnStatement() - elif self.Peak == 'ID': + else: designator = self.parseDesignator() if self.Peak == '(': - return self.parseProcedureCall(designator) + return self.parseCall(designator) elif self.Peak == '=': return self.parseAssignment(designator) - self.Error('Unable to determine statement') + else: + self.Error('Unable to determine statement') - # Parsing expressions: - def parseExpression(self): + # Parsing expressions: + def parseExpression(self): return self.parseBinopRhs(self.parsePrimary(), 0) - def parsePrimary(self): + + def parsePrimary(self): if self.hasConsumed('('): e = self.parseExpression() self.Consume(')') return e elif self.Peak == 'NUMBER': val = self.Consume('NUMBER') - return self.sema.actOnNumber(val.val, val.loc) + return astnodes.Literal(val.val, val.loc) elif self.Peak == 'REAL': val = self.Consume('REAL') - return self.sema.actOnNumber(val.val, val.loc) + return astnodes.Literal(val.val, val.loc) elif self.Peak == 'true': val = self.Consume('true') - return self.sema.actOnNumber(True, val.loc) + return astnodes.Literal(True, val.loc) elif self.Peak == 'false': val = self.Consume('false') - return self.sema.actOnNumber(False, val.loc) + return astnodes.Literal(False, val.loc) elif self.Peak == 'ID': d = self.parseDesignator() if self.Peak == '(': - return self.parseProcedureCall(d) + return self.parseCall(d) else: - return self.sema.actOnVariableUse(d, d.loc) + return astnodes.VariableUse(d, d.loc) self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak)) - def parseBinopRhs(self, lhs, min_prec): + def parseBinopRhs(self, lhs, min_prec): while self.PeakPrec >= min_prec: op_prec = self.PeakPrec op = self.Consume(self.Peak) rhs = self.parsePrimary() while self.PeakPrec > op_prec: rhs = self.parseBinopRhs(rhs, self.PeakPrec) - lhs = self.sema.actOnBinop(lhs, op.typ, rhs, op.loc) + lhs = astnodes.Binop(lhs, op.typ, rhs, op.loc) return lhs