Advertisement
Guest User

Untitled

a guest
Apr 21st, 2019
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.64 KB | None | 0 0
  1. # TODO: fix
  2. # GRAMMAR:
  3. # PLUSMINUS := MULDIV +- MULDIV
  4. # MULDIV := CONSTANT */ CONSTANT
  5. # CONSTANT := NUMBER | (PLUSMINUS)
  6.  
  7.  
  8. from enum import auto, Enum
  9.  
  10. class TokenType(Enum):
  11. CONSTANT = auto()
  12. PLUS = auto()
  13. TIMES = auto()
  14. EOF = auto()
  15. MINUS = auto()
  16. SLASH = auto()
  17. OPENPAREN = auto()
  18. CLOSEPAREN = auto()
  19.  
  20. char_to_token_type = {
  21. '+': TokenType.PLUS,
  22. '-': TokenType.MINUS,
  23. '*': TokenType.TIMES,
  24. '/': TokenType.SLASH,
  25. '(': TokenType.OPENPAREN,
  26. ')': TokenType.CLOSEPAREN,
  27. }
  28.  
  29. class Token():
  30. def __init__(self, token_type, position, length):
  31. self.type = token_type
  32. self.position = position
  33. self.length = length
  34.  
  35. def __str__(self):
  36. return f'type {self.type}, position {self.position}, length {self.length}'
  37.  
  38. class Scanner():
  39. def __init__(self, code):
  40. self.code = code
  41. self.position = 0
  42.  
  43. def peek_token(self):
  44. position = self.position
  45. token = self.scan_token()
  46. self.position = position
  47. return token
  48.  
  49. def scan_token(self):
  50. if self.position == len(self.code):
  51. return Token(TokenType.EOF, self.position, 0)
  52.  
  53. # TODO: check for EOF
  54. while self.code[self.position] == ' ':
  55. self.position += 1
  56.  
  57. char = self.code[self.position]
  58. if char in char_to_token_type:
  59. token = Token(char_to_token_type[char], self.position, 1)
  60. self.position += 1
  61. return token
  62.  
  63. start = self.position
  64. while char in '0123456789':
  65. self.position += 1
  66. if self.position == len(self.code):
  67. break
  68. char = self.code[self.position]
  69. if start != self.position:
  70. return Token(TokenType.CONSTANT, start, self.position - start)
  71.  
  72. assert False, 'not recognized token'
  73.  
  74.  
  75.  
  76. class Constant():
  77. def __init__(self, constant):
  78. self.constant = constant
  79.  
  80. class BinaryOperation():
  81. def __init__(self, opcode, lhs, rhs):
  82. self.opcode = opcode
  83. self.lhs = lhs
  84. self.rhs = rhs
  85.  
  86. class Parens():
  87. def __init__(self, value):
  88. self.value = value
  89.  
  90.  
  91. def parse_constant(scanner):
  92. token = scanner.scan_token()
  93. if token.type == TokenType.CONSTANT:
  94. return Constant(float(scanner.code[token.position:token.position + token.length]))
  95. elif token.type == TokenType.OPENPAREN:
  96. node = Parens(parse(scanner))
  97. scanner.scan_token() # eat close paren
  98. return node
  99.  
  100. print(token)
  101. assert False, 'help'
  102.  
  103. def parse_muldiv(scanner):
  104. lhs = parse_constant(scanner)
  105. operation = scanner.peek_token()
  106. while operation.type in [TokenType.TIMES, TokenType.SLASH]:
  107. scanner.scan_token()
  108. rhs = parse_constant(scanner)
  109. lhs = BinaryOperation(operation.type, lhs, rhs)
  110. operation = scanner.peek_token()
  111. return lhs
  112.  
  113. def parse(scanner):
  114. lhs = parse_muldiv(scanner)
  115. operation = scanner.peek_token()
  116. while operation.type in [TokenType.PLUS, TokenType.MINUS]:
  117. scanner.scan_token()
  118. rhs = parse_muldiv(scanner)
  119. lhs = BinaryOperation(operation.type, lhs, rhs)
  120. operation = scanner.peek_token()
  121. return lhs
  122.  
  123.  
  124. def print_ast(node, indent=''):
  125. if type(node) is Constant:
  126. print(f'{indent}Constant {node.constant}')
  127. if type(node) is BinaryOperation:
  128. print(f'{indent}BinaryOperation {node.opcode}')
  129. print_ast(node.lhs, indent + '\t')
  130. print_ast(node.rhs, indent + '\t')
  131.  
  132.  
  133. def interpret_ast(node):
  134. if type(node) is Constant:
  135. return node.constant
  136. elif type(node) is BinaryOperation:
  137. lhs = interpret_ast(node.lhs)
  138. rhs = interpret_ast(node.rhs)
  139. if node.opcode == TokenType.PLUS:
  140. return lhs + rhs
  141. elif node.opcode == TokenType.MINUS:
  142. return lhs - rhs
  143. elif node.opcode == TokenType.TIMES:
  144. return lhs*rhs
  145. elif node.opcode == TokenType.SLASH:
  146. return lhs/rhs
  147. elif type(node) is Parens:
  148. return interpret_ast(node.value)
  149.  
  150.  
  151.  
  152.  
  153.  
  154. while True:
  155. expression = input('Enter an expression to calculate: ')
  156.  
  157. scanner = Scanner(expression)
  158. print('Tokens:')
  159. token = scanner.scan_token()
  160. while token.type != TokenType.EOF:
  161. print(f'\t{token}')
  162. token = scanner.scan_token()
  163.  
  164. # create new scanner because the previous one has reached the end
  165. ast = parse(Scanner(expression))
  166. print_ast(ast)
  167.  
  168. result = interpret_ast(ast)
  169. print(f'The result of expression \'{expression}\' is {result}')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement