Mercurial > lcfOS
diff python/c3/parser.py @ 220:3f6c30a5d234
Major change in expression parsing to enable pointers and structs
author | Windel Bouwman |
---|---|
date | Sat, 06 Jul 2013 21:32:20 +0200 |
parents | 1fa3e0050b49 |
children | 848c4b15fd0b |
line wrap: on
line diff
--- a/python/c3/parser.py Sat Jul 06 12:38:09 2013 +0200 +++ b/python/c3/parser.py Sat Jul 06 21:32:20 2013 +0200 @@ -1,11 +1,6 @@ from . import astnodes, lexer from ppci import CompilerError -# binop precedence for expressions: -binopPrecs = {'or': 5, 'and': 10, \ - '<': 20, '>': 20, '==': 20, '<=': 20, '>=': 20, '!=': 20, \ - '+': 30, '-': 30, '*': 40, '/': 40 } - class Parser: """ Parses sourcecode into an abstract syntax tree (AST) """ def __init__(self, diag): @@ -18,27 +13,26 @@ return self.mod except CompilerError as e: self.diag.addDiag(e) + def Error(self, msg): - raise CompilerError(msg, self.token.loc) + raise CompilerError(msg, self.token.loc) + # Lexer helpers: def Consume(self, typ): - if self.Peak == typ: - return self.NextToken() - else: - self.Error('Excected: "{0}", got "{1}"'.format(typ, self.Peak)) + if self.Peak == typ: + return self.NextToken() + else: + self.Error('Excected: "{0}", got "{1}"'.format(typ, self.Peak)) + @property def Peak(self): - return self.token.typ - @property - def PeakPrec(self): - if self.Peak in binopPrecs: - return binopPrecs[self.Peak] - return -1 + return self.token.typ + def hasConsumed(self, typ): - if self.Peak == typ: - self.Consume(typ) - return True - return False + if self.Peak == typ: + self.Consume(typ) + return True + return False def NextToken(self): t = self.token @@ -49,23 +43,24 @@ def initLex(self, source): self.tokens = lexer.tokenize(source) # Lexical stage self.token = self.tokens.__next__() + def addDeclaration(self, decl): self.currentPart.declarations.append(decl) def parseUses(self): + # TODO: parse uses pass def parsePackage(self): - self.Consume('package') - name = self.Consume('ID') - self.Consume(';') - self.mod = astnodes.Package(name.val, name.loc) - self.currentPart = self.mod - self.parseUses() - # TODO: parse uses - while self.Peak != 'END': - self.parseTopLevel() - self.Consume('END') + self.Consume('package') + name = self.Consume('ID') + self.Consume(';') + self.mod = astnodes.Package(name.val, name.loc) + self.currentPart = self.mod + self.parseUses() + while self.Peak != 'END': + self.parseTopLevel() + self.Consume('END') def parseTopLevel(self): if self.Peak == 'function': @@ -127,7 +122,7 @@ v = astnodes.Variable(name.val, t) v.loc = name.loc if self.hasConsumed('='): - v.ival = self.parseExpression() + v.ival = self.Expression() self.addDeclaration(v) parseVar() while self.hasConsumed(','): @@ -140,7 +135,7 @@ def parseConst(): name = self.Consume('ID') self.Consume('=') - val = self.parseExpression() + val = self.Expression() c = astnodes.Constant(name.val, t, val) c.loc = name.loc parseConst() @@ -177,27 +172,11 @@ self.currentPart = savePart # Statements: - def parseAssignment(self, lval): - lval = astnodes.VariableUse(lval, lval.loc) - loc = self.Consume('=').loc - rval = self.parseExpression() - self.Consume(';') - return astnodes.Assignment(lval, rval, loc) - - def parseCall(self, func): - self.Consume('(') - args = [] - if not self.hasConsumed(')'): - args.append(self.parseExpression()) - while self.hasConsumed(','): - args.append(self.parseExpression()) - self.Consume(')') - return astnodes.FunctionCall(func, args, func.loc) def parseIfStatement(self): loc = self.Consume('if').loc self.Consume('(') - condition = self.parseExpression() + condition = self.Expression() self.Consume(')') yes = self.parseCompoundStatement() if self.hasConsumed('else'): @@ -207,88 +186,170 @@ return astnodes.IfStatement(condition, yes, no, loc) def parseWhileStatement(self): - loc = self.Consume('while').loc - self.Consume('(') - condition = self.parseExpression() - self.Consume(')') - statements = self.parseCompoundStatement() - return astnodes.WhileStatement(condition, statements, loc) + loc = self.Consume('while').loc + self.Consume('(') + condition = self.Expression() + self.Consume(')') + statements = self.parseCompoundStatement() + return astnodes.WhileStatement(condition, statements, loc) def parseReturnStatement(self): - self.Consume('return') - expr = self.parseExpression() - self.Consume(';') - return astnodes.ReturnStatement(expr) + loc = self.Consume('return').loc + expr = self.Expression() + self.Consume(';') + return astnodes.ReturnStatement(expr, loc) def parseCompoundStatement(self): - self.Consume('{') - statements = [] - while not self.hasConsumed('}'): - s = self.parseStatement() - if not type(s) is astnodes.EmptyStatement: + self.Consume('{') + statements = [] + while not self.hasConsumed('}'): + s = self.Statement() + if type(s) is astnodes.EmptyStatement: + continue statements.append(s) - return astnodes.CompoundStatement(statements) + return astnodes.CompoundStatement(statements) + + def Statement(self): + # Determine statement type based on the pending token: + if self.Peak == 'if': + return self.parseIfStatement() + elif self.Peak == 'while': + return self.parseWhileStatement() + elif self.Peak == '{': + return self.parseCompoundStatement() + elif self.hasConsumed(';'): + return astnodes.EmptyStatement() + elif self.Peak == 'var': + self.parseVarDef() + return astnodes.EmptyStatement() + elif self.Peak == 'return': + return self.parseReturnStatement() + else: + return self.AssignmentOrCall() + + def AssignmentOrCall(self): + x = self.UnaryExpression() + if self.Peak == '=': + # We enter assignment mode here. + loc = self.Consume('=').loc + rhs = self.Expression() + return astnodes.Assignment(x, rhs, loc) + else: + return x - def parseStatement(self): - # Determine statement type based on the pending token: - if self.Peak == 'if': - return self.parseIfStatement() - elif self.Peak == 'while': - return self.parseWhileStatement() - elif self.Peak == '{': - return self.parseCompoundStatement() - elif self.hasConsumed(';'): - return astnodes.EmptyStatement() - elif self.Peak == 'var': - self.parseVarDef() - return astnodes.EmptyStatement() - elif self.Peak == 'return': - return self.parseReturnStatement() - else: - designator = self.parseDesignator() - if self.Peak == '(': - return self.parseCall(designator) - elif self.Peak == '=': - return self.parseAssignment(designator) - else: - self.Error('Unable to determine statement') + # Expression section: + # We not implement these C constructs: + # a(2), f = 2 + # and this: + # a = 2 < x : 4 ? 1; + + def Expression(self): + exp = self.LogicalAndExpression() + while self.Peak == 'or': + loc = self.Consume('or').loc + e2 = self.LogicalAndExpression() + exp = astnodes.Binop(exp, 'or', e2, loc) + return exp - # Parsing expressions: - def parseExpression(self): - return self.parseBinopRhs(self.parsePrimary(), 0) + def LogicalAndExpression(self): + o = self.EqualityExpression() + while self.Peak == 'and': + loc = self.Consume('and').loc + o2 = self.EqualityExpression() + o = astnodes.Binop(o, 'and', o2, loc) + return o + + def EqualityExpression(self): + ee = self.SimpleExpression() + while self.Peak in ['<', '==', '>']: + op = self.Consume(self.Peak) + ee2 = self.SimpleExpression() + ee = astnodes.Binop(ee, op.typ, ee2, op.loc) + return ee + + def SimpleExpression(self): + e = self.Term() + while self.Peak in ['+', '-']: + op = self.Consume(self.Peak) + e2 = self.Term() + e = astnodes.Binop(e, op.typ, e2, op.loc) + return e - def parsePrimary(self): - if self.hasConsumed('('): - e = self.parseExpression() - self.Consume(')') - return e - elif self.Peak == 'NUMBER': - val = self.Consume('NUMBER') - return astnodes.Literal(val.val, val.loc) - elif self.Peak == 'REAL': - val = self.Consume('REAL') - return astnodes.Literal(val.val, val.loc) - elif self.Peak == 'true': - val = self.Consume('true') - return astnodes.Literal(True, val.loc) - elif self.Peak == 'false': - val = self.Consume('false') - return astnodes.Literal(False, val.loc) - elif self.Peak == 'ID': - d = self.parseDesignator() - if self.Peak == '(': - return self.parseCall(d) - else: + def Term(self): + t = self.Factor() + while self.Peak in ['*', '/']: + op = self.Consume(self.Peak) + t2 = self.Factor() + t = astnodes.Binop(t, op.typ, t2, op.loc) + return t + + def Factor(self): + # TODO: eliminate this step? + return self.CastExpression() + + # Domain of unary expressions: + + def CastExpression(self): + # TODO: cast conflicts with '(' expr ')' + if self.Peak == '(ii': + self.Consume('(') + print('TODO: implement type cast') + #rrrrr + self.parseTypeSpec() + + # Type + self.Consume(')') + ce = self.CastExpression() + return ce + else: + return self.UnaryExpression() + + def UnaryExpression(self): + if self.Peak in ['&', '*']: + op = self.Consume(self.Peak) + ce = self.CastExpression() + return astnodes.Unop(op.typ, ce, op.loc) + else: + return self.PostFixExpression() + + def PostFixExpression(self): + pfe = self.PrimaryExpression() + while self.Peak in ['[', '(', '.', '->']: + if self.hasConsumed('['): + pass + elif self.hasConsumed('('): + # Function call + args = [] + if not self.hasConsumed(')'): + args.append(self.Expression()) + while self.hasConsumed(','): + args.append(self.Expression()) + self.Consume(')') + pfe = astnodes.FunctionCall(pfe, args, pfe.loc) + else: + rrrr + return pfe + + def PrimaryExpression(self): + if self.hasConsumed('('): + e = self.Expression() + self.Consume(')') + return e + elif self.Peak == 'NUMBER': + val = self.Consume('NUMBER') + return astnodes.Literal(val.val, val.loc) + elif self.Peak == 'REAL': + val = self.Consume('REAL') + return astnodes.Literal(val.val, val.loc) + elif self.Peak == 'true': + val = self.Consume('true') + return astnodes.Literal(True, val.loc) + elif self.Peak == 'false': + val = self.Consume('false') + return astnodes.Literal(False, val.loc) + elif self.Peak == 'ID': + d = self.parseDesignator() return astnodes.VariableUse(d, d.loc) - self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak)) + self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak)) - 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 = astnodes.Binop(lhs, op.typ, rhs, op.loc) - return lhs