from scanner import * import math """ Grammar rules: S -> F $ F -> T Ftail Ftail -> eps | + T Ftail | - T Ftail T -> M Ttail Ttail -> eps | * M Ttail | / M Ttail M -> E | Func E -> x | number | ( F ) Func -> name ( F ) """ class ExprParser: stdFunc = { "sin" : math.sin, "cos" : math.cos, "exp" : math.exp, "log" : math.log, "atan": math.atan } def __init__(self): self.stack = [] # S -> F $ def parse(self, formula): self.tokenList = scanText(formula) self.pos = 0 self.rpn = [] self.processF() self.skipToken(Token.ENDLINE) # F -> T Ftail def processF(self): self.processT() self.processFtail() # Ftail -> eps | + T Ftail | - T Ftail def processFtail(self): if self.tokenList[self.pos].token == Token.PLUS: self.skipToken(Token.PLUS) self.processT() self.rpn.append(Token(Token.PLUS)) self.processFtail() elif self.tokenList[self.pos].token == Token.MINUS: self.skipToken(Token.MINUS) self.processT() self.rpn.append(Token(Token.MINUS)) self.processFtail() else: pass # T -> M Ttail def processT(self): self.processM() self.processTtail() # Ttail -> eps | * M Ttail | / M Ttail def processTtail(self): if self.tokenList[self.pos].token == Token.MUL: self.skipToken(Token.MUL) self.processM() self.rpn.append(Token(Token.MUL)) self.processTtail() elif self.tokenList[self.pos].token == Token.DIV: self.skipToken(Token.DIV) self.processM() self.rpn.append(Token(Token.DIV)) self.processTtail() else: pass # M -> E | Func def processM(self): if self.tokenList[self.pos].token == Token.NAME: self.processFunc() else: self.processE() # E -> x | number | ( F ) def processE(self): if self.tokenList[self.pos].token == Token.X: self.skipToken(Token.X) self.rpn.append(Token(Token.X)) elif self.tokenList[self.pos].token == Token.NUMBER: self.rpn.append(self.tokenList[self.pos]) self.skipToken(Token.NUMBER) elif self.tokenList[self.pos].token == Token.LPAR: self.skipToken(Token.LPAR) self.processF() self.skipToken(Token.RPAR) else: raise SyntaxError(str(self.tokenList[self.pos])) # Func -> name ( F ) def processFunc(self): func = self.tokenList[self.pos] self.skipToken(Token.NAME) self.skipToken(Token.LPAR) self.processF() self.skipToken(Token.RPAR) self.rpn.append(func) def skipToken(self, tokenType): if self.pos >= len(self.tokenList): raise SyntaxError("End of formula reached") if tokenType != self.tokenList[self.pos].token: raise SyntaxError(str(self.tokenList[self.pos])) self.pos += 1 def evaluate(self, x = 0.): self.stack.clear() for t in self.rpn: if t.token == Token.NUMBER: self.stack.append(t) elif t.token == Token.PLUS: b = self.stack.pop() a = self.stack.pop() res = a.value + b.value self.stack.append(Token(value=res)) elif t.token == Token.MINUS: b = self.stack.pop() a = self.stack.pop() res = a.value - b.value self.stack.append(Token(value=res)) elif t.token == Token.MUL: b = self.stack.pop() a = self.stack.pop() res = a.value * b.value self.stack.append(Token(value=res)) elif t.token == Token.DIV: b = self.stack.pop() a = self.stack.pop() res = a.value / b.value self.stack.append(Token(value=res)) elif t.token == Token.X: self.stack.append(Token(value=x)) elif t.token == Token.NAME: # Compute a standard function a = self.stack.pop() res = 0. if t.text in ExprParser.stdFunc: res = ExprParser.stdFunc[t.text](a.value) self.stack.append(Token(value=res)) else: assert(False), "Incorrect token in rpn" a = self.stack.pop() return a.value