import re

def is_variable(s):
    # Regular expression to match a valid Python variable name
    pattern = r'^[a-zA-Z_][a-zA-Z0-9_]*$'
    return re.match(pattern, s) is not None

class ExpressionParser:
    def __init__(self, expression):
        self.expression = expression.replace(' ', '')  # Remove spaces for easier parsing
        self.index = 0  # Current position in the string

    def parse(self):
        return self.parse_expression()

    def parse_expression(self):
        nodes = [self.parse_term()]

        while self.peek() is not None and self.peek() in '+-':
            op = self.consume()
            right = self.parse_term()
            if op == '+':
                nodes = [f"[add]({nodes[0]}, {right})"]
            else:  # '-'
                nodes = [f"[minus]({nodes[0]}, {right})"]

        return nodes[0]

    def parse_term(self):
        nodes = [self.parse_factor()]

        while self.peek() is not None and self.peek() in '*/':
            op = self.consume()
            right = self.parse_factor()
            if op == '*':
                nodes = [f"[multiply]({nodes[0]}, {right})"]
            else:  # '/'
                nodes = [f"[divide]({nodes[0]}, {right})"]

        return nodes[0]

    def parse_factor(self):
        if self.peek() is not None and (self.peek().isdigit() or is_variable(self.peek())):
            return self.consume_while(lambda c: c.isdigit() or is_variable(c))
        elif self.peek() == '(':
            self.consume()  # Consume '('
            expr = self.parse_expression()
            self.expect(')')  # Ensure closing ')' is consumed
            return expr
        else:
            raise ValueError(f"Unexpected character: {self.peek()} at index {self.index}")

    def peek(self):
        return self.expression[self.index] if self.index < len(self.expression) else None

    def consume(self):
        if self.index >= len(self.expression):
            raise ValueError("Attempt to consume beyond the end of the expression")
        current = self.expression[self.index]
        self.index += 1
        return current

    def consume_while(self, condition):
        start = self.index
        while self.peek() is not None and condition(self.peek()):
            self.consume()
        return self.expression[start:self.index]

    def expect(self, char):
        if self.peek() == char:
            self.consume()
        else:
            raise ValueError(f"Expected '{char}' but found '{self.peek()}' at index {self.index}")

def convert_expression(expression):
    parser = ExpressionParser(expression)
    return parser.parse()

if __name__ == '__main__':
    print(convert_expression("gnomes_in_first_four_houses = [multiply](number_of_houses - 1, gnomes_per_house_in_first_four)"))
    print(convert_expression("a + b * d - x"))