def _reduceAst(self): if len(self.stack) < 4: return False last = self.stack[-1] last1 = self.stack[-2] last2 = self.stack[-3] last3 = self.stack[-4] if last3.precedence == 0xf and last2.hasAst( ) and last1.operator == ')': func = BUILTIN_FUNCTIONS.get(last3.operator) # take into account sign before brace... if func != None: ast2 = last2.getAst() if last3.operator == "root": if type(ast2) != tuple or len(ast2) != 2: raise ParseException( "root must have exaclty two positional arguments.", self.formula, self.position) # root operator if last3.value < 0.0: last2.ast = ast.AstNegation( ast.AstRoot(ast2[1], ast2[0])) else: last2.ast = ast.AstRoot(ast2[1], ast2[0]) else: if type(ast2) == tuple: raise ParseException( "builtin function must not have more than one positional argument.", self.formula, self.position) # builtin function if last3.value < 0.0: last2.ast = ast.AstNegation( ast.AstFunctionCall(last3.operator, ast2)) else: last2.ast = ast.AstFunctionCall(last3.operator, ast2) else: # open brace with negation if last3.value < 0.0: last2.ast = ast.AstNegation(last2.getAst()) # x( <number> ) yyy -> x( <number> yyy self.stack.pop(-2) # x( <number> yyy -> <number> yyy self.stack.pop(-3) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduceAst(parentheses): stack is now %s" % self.stack) return True # <number> <op1> <number> <op2> if last3.hasAst() and last1.hasAst(): # <op1> has a lower precedence than pending <op2>, do nothing if last2.precedence < last.precedence: return False # exponentiation is right-associative. if last.precedence == 3 and last2.precedence == 3: return False if last2.operator == ',': ast3 = last3.getAst() if type(ast3) == tuple: last3.ast = ast3 + (last1.getAst(), ) else: last3.ast = (ast3, last1.getAst()) elif last2.operator == '+' or last2.operator == '-' or last2.operator == '*' or last2.operator == '/' or last2.operator == '^': last3.ast = ast.AstBinaryOperator(last3.getAst(), last2.operator, last1.getAst()) else: return False # <number> <op1> <number> <op2> -> <number> <op2> -> self.stack.pop(-2) self.stack.pop(-2) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduceAst(binary): stack is now %s" % self.stack) return True return False
def _reduce(self): if len(self.stack) < 4: return False last = self.stack[-1] last1 = self.stack[-2] last2 = self.stack[-3] last3 = self.stack[-4] if last3.precedence == 0xf and last2.isNumber( ) and last1.operator == ')': func = BUILTIN_FUNCTIONS.get(last3.operator) # take into account sign before brace... if func != None: # builtin function if type(last2.value) == tuple: # multi-arg functions. last2.value = last3.value * func(*last2.value) else: last2.value = last3.value * func(last2.value) else: # opening brace last2.value *= last3.value # x( <number> ) yyy -> x( <number> yyy self.stack.pop(-2) # x( <number> yyy -> <number> yyy self.stack.pop(-3) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduce(parentheses): stack is now %s" % self.stack) return True # <number> <op1> <number> <op2> if last3.isNumber() and last1.isNumber(): # <op1> has a lower precedence than pending <op2>, do nothing if last2.precedence < last.precedence: return False # exponentiation is right-associative. if last.precedence == 3 and last2.precedence == 3: return False if last2.operator == ',': if type(last3.value) == tuple: last3.value += (last1.value, ) else: last3.value = (last3.value, last1.value) elif last2.operator == '+': last3.value += last1.value elif last2.operator == '-': last3.value -= last1.value elif last2.operator == '*': last3.value *= last1.value elif last2.operator == '/': last3.value /= last1.value elif last2.operator == '^': last3.value = math.pow(last3.value, last1.value) else: return False # <number> <op1> <number> <op2> -> <number> <op2> -> self.stack.pop(-2) self.stack.pop(-2) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduce(binary): stack is now %s" % self.stack) return True return False
def _pushToken(self): c = self._skipWhite() if c == None: self.stack.append(Token.newEOS()) if (log.isEnabledFor(logging.DEBUG)): log.debug("_pushToken(EOS): stack is now %s" % self.stack) return False token = None sign = 1.0 if c == "(": token = Token.newOpeningParentheses(sign) c = self._advance() elif c == ")": token = Token.newClosingParentheses() c = self._advance() elif c == ",": token = Token.newOperator(c, 0) c = self._advance() elif c == "^": token = Token.newOperator(c, 3) c = self._advance() elif c == "/" or c == "*": token = Token.newOperator(c, 2) c = self._advance() elif c == "+": token = Token.newOperator(c, 1) c = self._advance() elif c == "-": # check, whether this is a sign after an operator or at the start of an expression. if (len(self.stack) <= 0 or self.stack[-1].precedence > 0): c = self._advance() if c != None: c = self._skipWhite() if c == None: raise ParseException( "Unexpected end of formula after minus sign.", self.formula, self.position) sign = -1.0 if c == '-': raise ParseException( "Formula contains superfluous minus signs.", self.formula, self.position) if c == '(': token = Token.newOpeningParentheses(sign) c = self._advance() else: # binary minus operator. token = Token.newOperator(c, 1) c = self._advance() if token == None: # check for identifier if c in string.ascii_letters or c in GREEK_LETTERS or c == "_": spos = self.position c = self._advance() # valid variable names are _asdf123 ___3 _asd2_3d while (c != None and (c in string.ascii_letters or c in GREEK_LETTERS or c == '_' or c in string.digits)): c = self._advance() variable = self.formula[spos:self.position] # FIXME check for builtin function func = BUILTIN_FUNCTIONS.get(variable) if func == None: if self.variables == None: # AST parsing token = Token.newVariable(variable, sign) else: # classical, immediate evaluation value = self.variables.get(variable) if value == None: raise ParseException( "Formula contains unknown variable [%s]." % variable, self.formula, self.position) token = Token.newNumber(value * sign) else: c = self._skipWhite() if c != "(": raise ParseException( "Formula does not contain an openeing paraentheses after builin function [%s]." % variable, self.formula, self.position) c = self._advance() token = Token.newBuiltin(variable, sign) elif c in string.digits or c == ".": spos = self.position ndigits = 0 # number befor the decimal point while (c != None and c in string.digits): c = self._advance() ndigits += 1 # decimal point present? if (self.position < len(self.formula) and c == '.'): c = self._advance() # digits after the decimal point while (c != None and c in string.digits): c = self._advance() ndigits += 1 # no digits so far if ndigits == 0: raise ParseException("Formula contains a plain dot.", self.formula, self.position) # check for exponent if c == 'E' or c == 'e': edigits = 0 # check for sign of exponent c = self._advance() if c == '+' or c == '-': c = self._advance() # digits after the decimal point while (c != None and c in string.digits): c = self._advance() edigits += 1 if edigits == 0: raise ParseException( "Formula contains number with no digist after exponent.", self.formula, self.position) numberString = self.formula[spos:self.position] token = Token.newNumber(float(numberString) * sign) else: raise ParseException( "Formula contains unexpected character [%s]." % c, self.formula, self.position) self.stack.append(token) if (log.isEnabledFor(logging.DEBUG)): log.debug("_pushToken: stack is now %s" % self.stack) return True
def _reduceAst(self): if len(self.stack)<4: return False last = self.stack[-1]; last1 = self.stack[-2]; last2 = self.stack[-3]; last3 = self.stack[-4]; if last3.precedence == 0xf and last2.hasAst() and last1.operator == ')': func = BUILTIN_FUNCTIONS.get(last3.operator) # take into account sign before brace... if func != None: ast2 = last2.getAst() if last3.operator == "root": if type(ast2) != tuple or len(ast2) != 2: raise ParseException("root must have exaclty two positional arguments.",self.formula,self.position); # root operator if last3.value < 0.0 : last2.ast = ast.AstNegation(ast.AstRoot(ast2[1],ast2[0])) else: last2.ast = ast.AstRoot(ast2[1],ast2[0]) else: if type(ast2) == tuple: raise ParseException("builtin function must not have more than one positional argument.",self.formula,self.position); # builtin function if last3.value < 0.0 : last2.ast = ast.AstNegation(ast.AstFunctionCall(last3.operator,ast2)) else: last2.ast = ast.AstFunctionCall(last3.operator,ast2) else: # open brace with negation if last3.value < 0.0 : last2.ast = ast.AstNegation(last2.getAst()) # x( <number> ) yyy -> x( <number> yyy self.stack.pop(-2) # x( <number> yyy -> <number> yyy self.stack.pop(-3) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduceAst(parentheses): stack is now %s"%self.stack) return True # <number> <op1> <number> <op2> if last3.hasAst() and last1.hasAst() : # <op1> has a lower precedence than pending <op2>, do nothing if last2.precedence < last.precedence: return False # exponentiation is right-associative. if last.precedence == 3 and last2.precedence == 3: return False if last2.operator == ',': ast3 = last3.getAst() if type(ast3) == tuple: last3.ast = ast3 + (last1.getAst(),) else: last3.ast = (ast3,last1.getAst()) elif last2.operator == '+' or last2.operator == '-' or last2.operator == '*' or last2.operator == '/'or last2.operator == '^': last3.ast = ast.AstBinaryOperator(last3.getAst(),last2.operator,last1.getAst()); else: return False # <number> <op1> <number> <op2> -> <number> <op2> -> self.stack.pop(-2) self.stack.pop(-2) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduceAst(binary): stack is now %s"%self.stack) return True return False
def _reduce(self): if len(self.stack)<4: return False last = self.stack[-1]; last1 = self.stack[-2]; last2 = self.stack[-3]; last3 = self.stack[-4]; if last3.precedence == 0xf and last2.isNumber() and last1.operator == ')': func = BUILTIN_FUNCTIONS.get(last3.operator) # take into account sign before brace... if func != None: # builtin function if type(last2.value) == tuple: # multi-arg functions. last2.value = last3.value * func(*last2.value) else: last2.value = last3.value * func(last2.value) else: # opening brace last2.value *= last3.value; # x( <number> ) yyy -> x( <number> yyy self.stack.pop(-2) # x( <number> yyy -> <number> yyy self.stack.pop(-3) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduce(parentheses): stack is now %s"%self.stack) return True # <number> <op1> <number> <op2> if last3.isNumber() and last1.isNumber() : # <op1> has a lower precedence than pending <op2>, do nothing if last2.precedence < last.precedence: return False # exponentiation is right-associative. if last.precedence == 3 and last2.precedence == 3: return False if last2.operator == ',': if type(last3.value) == tuple: last3.value += (last1.value,) else: last3.value = (last3.value,last1.value) elif last2.operator == '+': last3.value += last1.value elif last2.operator == '-': last3.value -= last1.value elif last2.operator == '*': last3.value *= last1.value; elif last2.operator == '/': last3.value /= last1.value; elif last2.operator == '^': last3.value = math.pow(last3.value,last1.value); else: return False # <number> <op1> <number> <op2> -> <number> <op2> -> self.stack.pop(-2) self.stack.pop(-2) if (log.isEnabledFor(logging.DEBUG)): log.debug("_reduce(binary): stack is now %s"%self.stack) return True return False
def _pushToken(self): c = self._skipWhite() if c == None: self.stack.append(Token.newEOS()) if (log.isEnabledFor(logging.DEBUG)): log.debug("_pushToken(EOS): stack is now %s"%self.stack) return False token = None sign = 1.0 if c == "(": token = Token.newOpeningParentheses(sign) c = self._advance() elif c == ")": token = Token.newClosingParentheses() c = self._advance() elif c == ",": token = Token.newOperator(c,0) c = self._advance() elif c == "^": token = Token.newOperator(c,3) c = self._advance() elif c == "/" or c == "*": token = Token.newOperator(c,2) c = self._advance() elif c == "+": token = Token.newOperator(c,1) c = self._advance() elif c == "-": # check, whether this is a sign after an operator or at the start of an expression. if (len(self.stack) <= 0 or self.stack[-1].precedence > 0): c = self._advance() if c != None: c = self._skipWhite() if c == None: raise ParseException("Unexpected end of formula after minus sign.",self.formula,self.position) sign = -1.0; if c=='-': raise ParseException("Formula contains superfluous minus signs.",self.formula,self.position) if c=='(': token = Token.newOpeningParentheses(sign); c = self._advance() else: # binary minus operator. token = Token.newOperator(c,1) c = self._advance() if token == None: # check for identifier if c in string.ascii_letters or c in GREEK_LETTERS or c == "_": spos = self.position c = self._advance() # valid variable names are _asdf123 ___3 _asd2_3d while (c != None and (c in string.ascii_letters or c in GREEK_LETTERS or c == '_' or c in string.digits)): c = self._advance() variable = self.formula[spos:self.position] # FIXME check for builtin function func = BUILTIN_FUNCTIONS.get(variable) if func == None: if self.variables == None: # AST parsing token = Token.newVariable(variable,sign) else: # classical, immediate evaluation value = self.variables.get(variable) if value == None: raise ParseException("Formula contains unknown variable [%s]."%variable,self.formula,self.position) token = Token.newNumber(value*sign) else: c = self._skipWhite() if c != "(": raise ParseException("Formula does not contain an openeing paraentheses after builin function [%s]."%variable,self.formula,self.position) c = self._advance() token = Token.newBuiltin(variable,sign) elif c in string.digits or c == ".": spos = self.position ndigits = 0 # number befor the decimal point while (c != None and c in string.digits): c = self._advance() ndigits += 1 # decimal point present? if (self.position < len(self.formula) and c == '.'): c = self._advance() # digits after the decimal point while (c != None and c in string.digits): c = self._advance() ndigits += 1 # no digits so far if ndigits == 0: raise ParseException("Formula contains a plain dot.",self.formula,self.position) # check for exponent if c == 'E' or c == 'e': edigits = 0 # check for sign of exponent c = self._advance() if c == '+' or c == '-': c = self._advance() # digits after the decimal point while (c != None and c in string.digits): c = self._advance() edigits += 1 if edigits == 0: raise ParseException("Formula contains number with no digist after exponent.",self.formula,self.position) numberString = self.formula[spos:self.position] token = Token.newNumber(float(numberString)*sign) else: raise ParseException("Formula contains unexpected character [%s]."%c,self.formula,self.position) self.stack.append(token) if (log.isEnabledFor(logging.DEBUG)): log.debug("_pushToken: stack is now %s"%self.stack) return True