Mercurial > lcfOS
view python/ppci/frontends/ks/parser.py @ 98:3f772feb12ef
movage
author | windel |
---|---|
date | Mon, 24 Dec 2012 13:57:00 +0100 |
parents | python/ppci/frontends/ksparser.py@a350055d6119 |
children | fe145e42259d |
line wrap: on
line source
""" This module define a grammar for the 'K#' language. """ from .nodes import * from .errors import CompilerException, Error from .modules import loadModule from .display import printNode from .builtin import * from . import assembler class Grammar: # TODO: implement some base class? pass class Parser: #TODO pass class KsParser(Parser): def __init__(self): self.loadGrammar(KsGrammar) # For now, try to parse an expression as test case: class KsGrammer(Grammar): def __init__(self): pass # Parsing expressions: """ grammar of expressions: expression = term { addoperator term } addoperator = '+' | '-' term = factor { muloperator factor } muloperator = '*' | '/' factor = number | "(" expression ")" """ @rule(Term) def Expression1(self, term): return Expression(term) @rule(Term, AddOperator, Term) def Expression2(self, term1, op, term2): return Expression(term1, op, term2) # Parsing arithmatic expressions: def parseTerm(self): a = self.parseFactor() while self.token.typ in ['*', '/', 'mod', 'div', 'and']: loc = self.getLocation() op = self.Consume() b = self.parseTerm() # Type determination and checking: if op in ['mod', 'div']: if not isType(a.typ, integer): self.Error('First operand should be integer, not {0}'.format(a.typ)) if not isType(b.typ, integer): self.Error('Second operand should be integer, not {0}'.format(b.typ)) typ = integer elif op == '*': if isType(a.typ, integer) and isType(b.typ, integer): typ = integer elif isType(a.typ, real) or isType(b.typ, real): if isType(a.typ, integer): # Automatic type cast a = Unop(a, 'INTTOREAL', real) if isType(b.typ, integer): b = Unop(b, 'INTTOREAL', real) if not isType(a.typ, real): self.Error('first operand must be a real!') if not isType(b.typ, real): self.Error('second operand must be a real!') typ = real else: self.Error('Unknown operands for multiply: {0}, {1}'.format(a, b)) elif op == '/': # Division always yields a real result, for integer division use div if isType(a.typ, integer): # Automatic type cast a = Unop(a, 'INTTOREAL', real) if isType(b.typ, integer): b = Unop(b, 'INTTOREAL', real) if not isType(a.typ, real): self.Error('first operand must be a real!') if not isType(b.typ, real): self.Error('second operand must be a real!') typ = real elif op == 'and': if not isType(a.typ, boolean): self.Error('First operand of and must be boolean') if not isType(b.typ, boolean): self.Error('Second operand of and must be boolean') typ = boolean else: self.Error('Unknown operand {0}'.format(op)) a = self.setLocation(Binop(a, op, b, typ), loc) return a @rule( def parseFactor(self): if self.hasConsumed('('): e = self.parseExpression() self.Consume(')') return e elif self.token.typ == 'NUMBER': loc = self.getLocation() val = self.Consume('NUMBER') return self.setLocation(Constant(val, integer), loc) elif self.token.typ == 'REAL': loc = self.getLocation() val = self.Consume('REAL') return self.setLocation(Constant(val, real), loc) elif self.token.typ == 'CHAR': val = self.Consume('CHAR') return Constant(val, char) elif self.token.typ in ['true', 'false']: val = self.Consume() val = True if val == 'true' else False return Constant(val, boolean) elif self.hasConsumed('nil'): return Constant(0, NilType()) elif self.hasConsumed('not'): f = self.parseFactor() if not isType(f.typ, boolean): self.Error('argument of boolean negation must be boolean type') return Unop(f, 'not', boolean) elif self.token.typ == 'ID': designator = self.parseDesignator() # TODO: handle functions different here? if self.token.typ == '(' and type(designator.typ) is ProcedureType: return self.parseProcedureCall(designator) else: return designator else: self.Error('Expected NUMBER, ID or ( expr ), got'+str(self.token)) def parseSimpleExpression(self): """ Arithmatic expression """ if self.token.typ in ['+', '-']: # Handle the unary minus op = self.Consume() a = self.parseTerm() typ = a.typ if not isType(typ,real) and not isType(typ, integer): self.Error('Unary minus or plus can be only applied to real or integers') if op == '-': a = Unop(a, op, typ) else: a = self.parseTerm() while self.token.typ in ['+', '-', 'or']: loc = self.getLocation() op = self.Consume() b = self.parseTerm() if op in ['+', '-']: if isType(a.typ, real) or isType(b.typ, real): typ = real if isType(a.typ, integer): # Automatic type cast a = Unop(a, 'INTTOREAL', real) if not isType(a.typ, real): self.Error('first operand must be a real!') if isType(b.typ, integer): b = Unop(b, 'INTTOREAL', real) if not isType(b.typ, real): self.Error('second operand must be a real!') elif isType(a.typ, integer) and isType(b.typ, integer): typ = integer else: self.Error('Invalid types {0} and {1}'.format(a.typ, b.typ)) elif op == 'or': if not isType(a.typ, boolean): self.Error('first operand must be boolean for or operation') if not isType(b.typ, boolean): self.Error('second operand must be boolean for or operation') typ = boolean else: self.Error('Unknown operand {0}'.format(op)) a = self.setLocation(Binop(a, op, b, typ), loc) return a