Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # TODO: fix
- # GRAMMAR:
- # PLUSMINUS := MULDIV +- MULDIV
- # MULDIV := CONSTANT */ CONSTANT
- # CONSTANT := NUMBER | (PLUSMINUS)
- from enum import auto, Enum
- class TokenType(Enum):
- CONSTANT = auto()
- PLUS = auto()
- TIMES = auto()
- EOF = auto()
- MINUS = auto()
- SLASH = auto()
- OPENPAREN = auto()
- CLOSEPAREN = auto()
- char_to_token_type = {
- '+': TokenType.PLUS,
- '-': TokenType.MINUS,
- '*': TokenType.TIMES,
- '/': TokenType.SLASH,
- '(': TokenType.OPENPAREN,
- ')': TokenType.CLOSEPAREN,
- }
- class Token():
- def __init__(self, token_type, position, length):
- self.type = token_type
- self.position = position
- self.length = length
- def __str__(self):
- return f'type {self.type}, position {self.position}, length {self.length}'
- class Scanner():
- def __init__(self, code):
- self.code = code
- self.position = 0
- def peek_token(self):
- position = self.position
- token = self.scan_token()
- self.position = position
- return token
- def scan_token(self):
- if self.position == len(self.code):
- return Token(TokenType.EOF, self.position, 0)
- # TODO: check for EOF
- while self.code[self.position] == ' ':
- self.position += 1
- char = self.code[self.position]
- if char in char_to_token_type:
- token = Token(char_to_token_type[char], self.position, 1)
- self.position += 1
- return token
- start = self.position
- while char in '0123456789':
- self.position += 1
- if self.position == len(self.code):
- break
- char = self.code[self.position]
- if start != self.position:
- return Token(TokenType.CONSTANT, start, self.position - start)
- assert False, 'not recognized token'
- class Constant():
- def __init__(self, constant):
- self.constant = constant
- class BinaryOperation():
- def __init__(self, opcode, lhs, rhs):
- self.opcode = opcode
- self.lhs = lhs
- self.rhs = rhs
- class Parens():
- def __init__(self, value):
- self.value = value
- def parse_constant(scanner):
- token = scanner.scan_token()
- if token.type == TokenType.CONSTANT:
- return Constant(float(scanner.code[token.position:token.position + token.length]))
- elif token.type == TokenType.OPENPAREN:
- node = Parens(parse(scanner))
- scanner.scan_token() # eat close paren
- return node
- print(token)
- assert False, 'help'
- def parse_muldiv(scanner):
- lhs = parse_constant(scanner)
- operation = scanner.peek_token()
- while operation.type in [TokenType.TIMES, TokenType.SLASH]:
- scanner.scan_token()
- rhs = parse_constant(scanner)
- lhs = BinaryOperation(operation.type, lhs, rhs)
- operation = scanner.peek_token()
- return lhs
- def parse(scanner):
- lhs = parse_muldiv(scanner)
- operation = scanner.peek_token()
- while operation.type in [TokenType.PLUS, TokenType.MINUS]:
- scanner.scan_token()
- rhs = parse_muldiv(scanner)
- lhs = BinaryOperation(operation.type, lhs, rhs)
- operation = scanner.peek_token()
- return lhs
- def print_ast(node, indent=''):
- if type(node) is Constant:
- print(f'{indent}Constant {node.constant}')
- if type(node) is BinaryOperation:
- print(f'{indent}BinaryOperation {node.opcode}')
- print_ast(node.lhs, indent + '\t')
- print_ast(node.rhs, indent + '\t')
- def interpret_ast(node):
- if type(node) is Constant:
- return node.constant
- elif type(node) is BinaryOperation:
- lhs = interpret_ast(node.lhs)
- rhs = interpret_ast(node.rhs)
- if node.opcode == TokenType.PLUS:
- return lhs + rhs
- elif node.opcode == TokenType.MINUS:
- return lhs - rhs
- elif node.opcode == TokenType.TIMES:
- return lhs*rhs
- elif node.opcode == TokenType.SLASH:
- return lhs/rhs
- elif type(node) is Parens:
- return interpret_ast(node.value)
- while True:
- expression = input('Enter an expression to calculate: ')
- scanner = Scanner(expression)
- print('Tokens:')
- token = scanner.scan_token()
- while token.type != TokenType.EOF:
- print(f'\t{token}')
- token = scanner.scan_token()
- # create new scanner because the previous one has reached the end
- ast = parse(Scanner(expression))
- print_ast(ast)
- result = interpret_ast(ast)
- print(f'The result of expression \'{expression}\' is {result}')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement