Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import string
- class ProjectorError(Exception):
- def __str__(self):
- return "Unknown error"
- class InvalidSymbolError(ProjectorError):
- def __init__(self, symbol):
- self.symbol = symbol
- def __str__(self):
- return f"Invalid symbol '{self.symbol}'"
- class UnmatchedParenthesesError(ProjectorError):
- def __init__(self, opening_index):
- self.opening_index = opening_index
- def __str__(self):
- return f"Unmatched parentheses at {self.opening_index}"
- class OperatorAbsentError(ProjectorError):
- def __str__(self):
- return "Expected operator after value"
- class ValueToken:
- def __init__(self, value):
- self.value = value
- def __str__(self):
- return f"<Token: VAL> {self.value}"
- class OperatorToken:
- def __init__(self, symbol):
- self.symbol = symbol
- match symbol:
- case '*': self.precedence = 5
- case '/': self.precedence = 4
- case '+': self.precedence = 3
- case '-': self.precedence = 2
- case '=': self.precedence = 1
- case _: self.precedence = 0
- def __str__(self):
- return f"<Token: OP> {self.symbol}"
- class IntegerToken(ValueToken):
- def __init__(self, value):
- super().__init__(value)
- def __str__(self):
- return f"<Token: INT> {self.value}"
- class OperatorAddToken(OperatorToken):
- def __init__(self):
- super().__init__('+')
- class OperatorSubToken(OperatorToken):
- def __init__(self):
- super().__init__('-')
- class OperatorMulToken(OperatorToken):
- def __init__(self):
- super().__init__('*')
- class OperatorDivToken(OperatorToken):
- def __init__(self):
- super().__init__('/')
- class OperatorAssignToken(OperatorToken):
- def __init__(self):
- super().__init__('=')
- class TokenGroup:
- def __init__(self, token_list = []):
- self.token_list = token_list
- self.operative, self.nested = get_token_list_attributes(token_list)
- def __len__(self):
- return len(self.token_list)
- def __str__(self, indent_level=0):
- hash_signature = str(hash(self))
- indent_padding = indent_level * '\t'
- group_string = f"{indent_padding}<Token: GRP -- {hash_signature}"
- if self.operative: group_string += " (operative)"
- if self.nested: group_string += " (nested)"
- for token in self.token_list:
- if isinstance(token, TokenGroup):
- subgroup_string = token.__str__(indent_level + 1)
- group_string += f"\n{subgroup_string}"
- else:
- group_string += f"\n{indent_padding}\t{str(token)}"
- group_string += f"\n{indent_padding}{hash_signature} -- >"
- return group_string
- class ValueExpression:
- def __init__(self, value_token):
- self.value_token = value_token
- class OperationExpression:
- def __init__(self, operator_token, left=None, right=None):
- self.operator_token = operator_token
- self.left = left
- self.right = right
- def get_next_operator_index(token_group):
- operator_precedence = 0
- operator_index = -1
- for index, token in enumerate(token_group.token_list):
- if isinstance(token, OperatorToken) and \
- token.precedence > operator_precedence:
- operator_index = index
- operator_precedence = token.precedence
- return operator_index
- def get_token_list_attributes(token_list):
- operative = False
- nested = False
- for token in token_list:
- if isinstance(token, OperatorToken): operative = True
- elif isinstance(token, TokenGroup): nested = True
- if operative and nested: break
- return operative, nested
- def extract_integer(expression, starting_index):
- number_string = expression[starting_index]
- if starting_index < len(expression) - 1:
- for character in expression[starting_index + 1 :]:
- if character not in string.digits: break
- number_string += character
- return number_string
- def extract_group(expression, opening_index):
- if opening_index == len(expression) - 1:
- raise UnmatchedParenthesesError(opening_index)
- closing_index = expression.rfind(')', opening_index + 1)
- if closing_index == -1:
- raise UnmatchedParenthesesError(opening_index)
- token_list = tokenize(expression[opening_index + 1 : closing_index])
- return TokenGroup(token_list), closing_index
- def tokenize(expression):
- token_list = []
- index = 0
- while index < len(expression):
- if expression[index] == '(':
- token_group, index = extract_group(expression, index)
- token_list.append(token_group)
- elif expression[index] in string.digits:
- number_string = extract_integer(expression, index)
- index += len(number_string) - 1
- token_list.append(IntegerToken(number_string))
- elif expression[index] == '+':
- token_list.append(OperatorAddToken())
- elif expression[index] == '-':
- token_list.append(OperatorSubToken())
- elif expression[index] == '*':
- token_list.append(OperatorMulToken())
- elif expression[index] == '/':
- token_list.append(OperatorDivToken())
- elif expression[index] == '=':
- token_list.append(OperatorAssignToken())
- else:
- raise InvalidSymbolError(expression[index])
- index += 1
- return token_list
- def parse(token_group):
- execution_tree = None
- if not token_group.operative:
- if len(token_group) > 1:
- raise OperatorAbsentError
- if isinstance(token_group[0], TokenGroup):
- execution_tree = parse(token_group[0])
- else:
- execution_tree = ValueExpression(token_group[0])
- else:
- operator_index = get_next_operator_index(token_group)
- operator = token_group.token_list[operator_index]
- return execution_tree
- def evaluate(execution_tree):
- result = 0
- return result
- def main():
- try:
- expression = input("ProjectOr expression: ").replace(' ', '')
- token_list = tokenize(expression)
- execution_tree = parse(TokenGroup(token_list))
- result = evaluate(execution_tree)
- print(result)
- except ProjectorError as ex:
- print(ex)
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement