def calc(text: str): """Read and evaluate a single line formula.""" try: tokens = lex.TokenStream(io.StringIO(text)) stack = [] while tokens.has_more(): tok = tokens.take() if tok.kind == lex.TokenCat.INT: stack.append(expr.IntConst(int(tok.value))) elif tok.kind == lex.TokenCat.PLUS: right = stack.pop() left = stack.pop() stack.append(expr.Plus(left, right)) except lex.LexicalError as e: print(f"*** Lexical error {e}") return except IndexError: # Stack underflow means the expression was imbalanced print(f"*** Imbalanced RPN expression, missing operand at {tok.value}") return if len(stack) == 0: print("(No expression)") else: # For a balanced expression there will be one Expr object # on the stack, but if there are more we'll just print # each of them for exp in stack: print(f"{exp} => {exp.eval()}")
def expr(self, node) -> expr.Expr: # if node is None: # return expr.UnspecifiedExpr() # else: # #print('NODE', node, self.datum(node)) # return self.datum(node).expr(self, node) #HACK Should do this by inheritance, but it's pretty readable #having it all here. if self.is_of_class(node, 'Plus'): return expr.Plus(*(self.expr(rand) for rand in self.neighbors(node, 'operands'))) elif self.is_of_class(node, 'Minus'): return expr.Minus(self.neighbor(node, 'minuend'), self.neighbor(node, 'subtrahend')) elif self.is_of_class(node, 'Times'): return expr.Times(*(self.expr(rand) for rand in self.neighbors(node, 'operands'))) #TODO Div elif self.is_of_class(node, 'Block'): return self.expr(self.neighbor(node, 'source')) elif self.is_of_class(node, 'Number'): return expr.Number(self.value_of(node)) else: return expr.UnspecifiedExpr()