import re
# トークナイザー
def tokenize(code):
token_specification = [
('NUMBER', r'\d+'), # 整数
('ID', r'[A-Za-z_]\w*'), # 識別子
('ASSIGN', r'='), # 代入演算子
('END', r';'), # 文の終わり
('OP', r'[+\-*/]'), # 演算子
('NEWLINE', r'\n'), # 改行
('SKIP', r'[ \t]'), # 空白とタブ
('MISMATCH', r'.'), # 一致しない文字
]
tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
get_token = re.compile(tok_regex).finditer
tokens = []
for mo in get_token(code):
kind = mo.lastgroup
value = mo.group()
if kind == 'NUMBER':
value = int(value)
elif kind == 'ID' and value in {'if', 'while', 'def'}:
kind = value.upper()
elif kind == 'SKIP':
continue
elif kind == 'NEWLINE':
value = '\n'
elif kind == 'MISMATCH':
raise RuntimeError(f'{value} unexpected on line {code}')
tokens.append((kind, value))
return tokens
# パーサークラス
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.pos = 0
def parse(self):
statements = []
while self.pos < len(self.tokens):
statement = self.statement()
if statement:
statements.append(statement)
return statements
def statement(self):
if self.pos >= len(self.tokens):
return None
token = self.tokens[self.pos]
if token[0] == 'ID' and self.pos + 1 < len(self.tokens) and self.tokens[self.pos + 1][0] == 'ASSIGN':
return self.assignment()
elif token[0] in {'ID', 'NUMBER'} or (token[0] == 'OP' and token[1] == '-'):
return self.expression()
else:
raise SyntaxError(f'Unexpected token: {token}')
def assignment(self):
id_token = self.tokens[self.pos]
self.pos += 1 # skip ID
self.pos += 1 # skip ASSIGN
expr = self.expression()
self.expect('END')
return ('assign', id_token[1], expr)
def expression(self):
term = self.term()
while self.pos < len(self.tokens) and self.tokens[self.pos][0] == 'OP':
op = self.tokens[self.pos]
self.pos += 1
term = (op[1], term, self.term())
return term
def term(self):
token = self.tokens[self.pos]
if token[0] == 'NUMBER':
self.pos += 1
return token[1]
elif token[0] == 'ID':
self.pos += 1
return ('var', token[1])
else:
raise SyntaxError(f'Unexpected token: {token}')
def expect(self, kind):
if self.pos < len(self.tokens) and self.tokens[self.pos][0] == kind:
self.pos += 1
else:
raise SyntaxError(f'Expected {kind}')
# インタプリタクラス
class Interpreter:
def __init__(self):
self.variables = {}
def evaluate(self, node):
if isinstance(node, int):
return node
elif isinstance(node, tuple):
if node[0] == 'assign':
self.variables[node[1]] = self.evaluate(node[2])
return self.variables[node[1]]
elif node[0] == 'var':
if node[1] in self.variables:
return self.variables[node[1]]
else:
raise NameError(f"Variable '{node[1]}' is not defined")
else:
left = self.evaluate(node[1])
right = self.evaluate(node[2])
if node[0] == '+':
return left + right
elif node[0] == '-':
return left - right
elif node[0] == '*':
return left * right
elif node[0] == '/':
return left / right
return None
# REPL (Read-Eval-Print Loop)
def repl():
interpreter = Interpreter()
while True:
try:
code = input('>>> ')
if code == 'exit':
break
tokens = tokenize(code)
parser = Parser(tokens)
tree = parser.parse()
for statement in tree:
result = interpreter.evaluate(statement)
if result is not None:
print(result)
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
repl()