-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy path1_handmade.py
123 lines (100 loc) · 3.17 KB
/
1_handmade.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
from enum import Enum
class Token:
class Type(Enum):
INTEGER = 0
PLUS = 1
MINUS = 2
LPAREN = 3
RPAREN = 4
def __init__(self, type, text):
self.type = type
self.text = text
def __str__(self):
return f'`{self.text}`'
def lex(input):
result = []
i = 0
while i < len(input):
if input[i] == '+':
result.append(Token(Token.Type.PLUS, '+'))
elif input[i] == '-':
result.append(Token(Token.Type.MINUS, '-'))
elif input[i] == '(':
result.append(Token(Token.Type.LPAREN, '('))
elif input[i] == ')':
result.append(Token(Token.Type.RPAREN, ')'))
else: # must be a number
digits = [input[i]]
for j in range(i + 1, len(input)):
if input[j].isdigit():
digits.append(input[j])
i += 1
else:
result.append(Token(Token.Type.INTEGER,
''.join(digits)))
break
i += 1
return result
# ↑↑↑ lexing ↑↑↑
# ↓↓↓ parsing ↓↓↓
class Integer:
def __init__(self, value):
self.value = value
class BinaryOperation:
class Type(Enum):
ADDITION = 0
SUBTRACTION = 1
def __init__(self):
self.type = None
self.left = None
self.right = None
@property
def value(self):
if self.type == self.Type.ADDITION:
return self.left.value + self.right.value
elif self.type == self.Type.SUBTRACTION:
return self.left.value - self.right.value
def parse(tokens):
result = BinaryOperation()
have_lhs = False
i = 0
while i < len(tokens):
token = tokens[i]
if token.type == Token.Type.INTEGER:
integer = Integer(int(token.text))
if not have_lhs:
result.left = integer
have_lhs = True
else:
result.right = integer
elif token.type == Token.Type.PLUS:
result.type = BinaryOperation.Type.ADDITION
elif token.type == Token.Type.MINUS:
result.type = BinaryOperation.Type.SUBTRACTION
elif token.type == Token.Type.LPAREN: # note: no if for RPAREN
j = i
while j < len(tokens):
if tokens[j].type == Token.Type.RPAREN:
break
j += 1
# preprocess subexpression
subexpression = tokens[i + 1:j]
element = parse(subexpression)
if not have_lhs:
result.left = element
have_lhs = True
else:
result.right = element
i = j # advance
i += 1
return result
def eval(input):
tokens = lex(input)
print(' '.join(map(str, tokens)))
parsed = parse(tokens)
print(f'{input} = {parsed.value}')
if __name__ == '__main__':
eval('(13+4)-(12+1)')
eval('1+(3-4)')
# this won't work
eval('1+2+(3-4)')