import sys STATE_OPERATOR, STATE_NAME, *_ = range(100) ( LEFT_PARENTHESIS, RIGHT_PARENTHESIS, NUMBER, OPERATOR, *_ ) = range(100) UNARY = "unary" PRECEDENCE = { "+": 10, "-": 10, "*": 20, "^": 30, UNARY: 40, } unary_operators = { "-": lambda a: -a, "+": lambda a: a } operators = { "+": lambda a, b: a + b, "-": lambda a, b: a - b, "*": lambda a, b: a * b, "^": lambda a, b: a ** b, } OPERATOR_SYMBOLS = "*+-/%&~^|#$.:<=>@" NUMBER_SYMBOLS = "0123456789" NAME_SYMBOLS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!?" class ParserError(Exception): pass class Node: def __init__(self, node_type, value=None, subtype=None): self.type = node_type self.value = value self.subtype = subtype self.parent = None self.right = None self.left = None def __eq__(self, other): return self.type == other.type and self.value == other.value def __repr__(self): if self.type == LEFT_PARENTHESIS: return "Node(LEFT_PARENTHESIS)" if self.type == RIGHT_PARENTHESIS: return "Node(RIGHT_PARENTHESIS)" if self.type == NUMBER: return f"Node({self.value})" if self.type == OPERATOR: return f"Node({self.subtype})" __str__ = __repr__ class Token: def __init__(self, node_type, value=None, subtype=None): self.type = node_type self.value = value self.subtype = subtype def __eq__(self, other): return self.type == other.type and self.value == other.value def __repr__(self): if self.type == LEFT_PARENTHESIS: return "Token(LEFT_PARENTHESIS)" if self.type == RIGHT_PARENTHESIS: return "Token(RIGHT_PARENTHESIS)" if self.type == NUMBER: return f"Token({self.value})" if self.type == OPERATOR: return f"Token({self.subtype})" __str__ = __repr__ def parse_operator(line, start): operator = "" i = start while i < len(line) and line[i] in OPERATOR_SYMBOLS: operator += line[i] i += 1 return operator, i - 1 def parse_number(line, start): number = "" if line[start] in "+-": number += line[start] start += 1 i = start while i < len(line) and line[i] in NUMBER_SYMBOLS: number += line[i] i += 1 return float(number), i - 1 def tokenize(line): state = STATE_NAME tokens = [] i = 0 while i < len(line): char = line[i] if char == "(": tokens.append(Token(LEFT_PARENTHESIS, None)) state = STATE_NAME elif char == ")": tokens.append(Token(RIGHT_PARENTHESIS, None)) state = STATE_OPERATOR elif char in OPERATOR_SYMBOLS: if state == STATE_OPERATOR: val, i = parse_operator(line, i) tokens.append(Token(OPERATOR, subtype=val)) state = STATE_NAME elif state == STATE_NAME: val, i = parse_operator(line, i) tokens.append(Token(OPERATOR, subtype=UNARY, value=val)) state = STATE_NAME elif char in "-+0123456789": val, i = parse_number(line, i) tokens.append(Token(NUMBER, val)) state = STATE_OPERATOR elif char != " ": raise ValueError("Line is not a valid expression") i += 1 return tokens def parse_parenthesis(tokens, start): end = start depth = 0 while True: token = tokens[end] if token.type == RIGHT_PARENTHESIS: depth -= 1 if token.type == LEFT_PARENTHESIS: depth += 1 if depth == 0 and token.type == RIGHT_PARENTHESIS: break end += 1 node = build_tree(tokens[start + 1: end]) return node, end def build_tree(tokens): i = 0 current_node = None while i < len(tokens): token = tokens[i] if token.type in [LEFT_PARENTHESIS, NUMBER] or token.subtype == UNARY: if token.type == LEFT_PARENTHESIS: node, i = parse_parenthesis(tokens, i) elif token.type == NUMBER: node = Node(NUMBER, token.value) elif token.subtype == UNARY: node = Node(OPERATOR, subtype=UNARY) node.left = Node(OPERATOR, subtype=token.value) if current_node is None: current_node = node elif current_node.type == NUMBER: raise ValueError("Not a valid expression") elif current_node.type == OPERATOR: if current_node.left is None: current_node.left = node node.parent = current_node elif current_node.right is None: current_node.right = node node.parent = current_node current_node = node else: raise ValueError("Not a valid expression") elif token.type == OPERATOR: node = Node(token.type, subtype=token.subtype, value=token.value) if current_node is None: raise ValueError("Not a valid expression") elif current_node.type in [NUMBER, OPERATOR]: while current_node.parent is not None: if PRECEDENCE[current_node.parent.subtype] < PRECEDENCE[node.subtype]: node.parent = current_node.parent if node.parent is not None: node.parent.right = node break current_node = current_node.parent current_node.parent = node node.left = current_node current_node = node else: raise ValueError("Not a valid expression") i += 1 while current_node.parent is not None: current_node = current_node.parent return current_node def expr_eval(node): if node.type == NUMBER: return node.value elif node.type == OPERATOR: if node.subtype == UNARY: return unary_operators.get(node.left.subtype)(expr_eval(node.right)) else: return operators.get(node.subtype)(expr_eval(node.left), expr_eval(node.right)) def main(*argv): data = argv[0] # data = "2 + 3 * -4" # data = "(3 + 3 * 2) * -4" tokens = tokenize(data) # print(tokens) node1 = build_tree(tokens) print(expr_eval(node1)) print("hooy") if __name__ == "__main__": main(*sys.argv[1:])