Course: CSCI 1250

Lesson: Variables, Data Types, and Coding Standards

Description: GitHub

def evaluate_rpn(expression: str) -> float:
    """
    Evaluates a reverse polish notation expression.
 
    :param expression: A string containing a reverse polish notation expression.
    :return: The result of the expression as a float.
    """
 
    stack = []
    tokens = expression.split()
    operations = {
        "+": lambda a, b: a + b,
        "-": lambda a, b: a - b,
        "*": lambda a, b: a * b,
        "/": lambda a, b: a / b,
        "**": lambda a, b: a ** b,
        "//": lambda a, b: a // b,
        "%": lambda a, b: a % b,
    }
 
    for token in tokens:
        if token.isdigit() or (token.replace(".", "", 1).isdigit() and token.count(".") < 2):
            stack.append(float(token))
        else:
            try:
                b = stack.pop()
                a = stack.pop()
                stack.append(operations[token](a, b))
            except (IndexError, KeyError):
                raise ValueError("Invalid expression")
            except:
                raise ValueError("Invalid operation")
 
    if len(stack) != 1:
        raise ValueError("Invalid expression")
 
    return stack[0]
 
 
def colorize(text: str, color_code: str) -> str:
    """
    Wraps the text with ANSI escape codes to apply color.
 
    :param text: The text to colorize.
    :param color_code: The ANSI color code.
    :return: The colorized text.
    """
    return f"\033[{color_code}m{text}\033[0m"
 
 
def string_slicing(str: str, start: int, end: int) -> None:
    """
    Prints the result of slicing the string with the given start and end indices.
 
    :param str: The string to slice.
    :param start: The start index of the slice.
    :param end: The end index of the slice.
    """
    print(f"{str}[{start}:{end}] -> {str[start:end]}")
 
 
# This is outside of main() so it's not indented weirdly
START_MESSAGE = f"""
Reverse Polish Notation (RPN) is a mathematical notation in which every operator follows all of its operands.
It does not need any parentheses; it"s also known as postfix notation.
The supported operations are: +, -, *, /, **, //, %.
 
IE: 2 3 + 5 * => (2 + 3) * 5 = 25
"""
 
 
def main() -> None:
    string_slicing("Reverse Polish Notation", 8, 14)
 
    print(START_MESSAGE)
 
    while True:
        # PEP 8 wants this to be <80 chars so it is split into two lines
        expression = input(
            'Enter a reverse polish notation expression (or type "exit" to quit): '
        )
 
        if expression.lower() == "exit":
            print(colorize("Exiting the program.", "31"))
            break
 
        try:
            result = evaluate_rpn(expression)
            print(
                colorize(f"The result of the expression is: {result}\n", "32"))
        except ValueError as e:
            print(colorize(f"Error: {e}\n", "31"))
 
 
if __name__ == "__main__":
    main()