Я создаю очень простой интерпретатор Лиспа. Похож на тот отсюда. Вот что у меня есть для части синтаксического анализа, то есть все, от «текст передан в программу» до «ast построен». Как это выглядит ниже? Что можно улучшить? Самым сложным для меня было рекурсивное read_from_tokens функция.
import re
Symbol = str
def pops(L, d=None):
"Pop from the left of the list, or return the default."
return L.pop(0) if L else d
def parse(program):
"Read a Scheme expression from a string and return tokens in AST."
program = preprocess(program)
assert program.count(')') == program.count('('), "Mismatched parens"
return read_from_tokens(tokenize(program))
def preprocess(s):
"Replace comments with a single space."
return re.sub(r';.+', ' ', s)
def tokenize(s):
"Convert a string into a list of tokens."
return s.replace('(', ' ( ').replace(')', ' ) ').split()
def atom(token):
"Return a number (only accepted literal) or a symbol."
try:
return int(token) if token.isdigit() else float(token)
except ValueError:
return Symbol(token)
def read_from_tokens(tokens):
"Read one or more expression from a sequence of tokens. Returns a list of lists."
L = []
while (token := pops(tokens, ')')) != ')':
L.append(atom(token) if token!='(' else read_from_tokens(tokens))
return L
if __name__ == '__main__':
print (parse("(define (+ 2 2) 10) (* pi (* r r))"))
print (parse("(define r 10)"))
print (parse("(* pi (* (+ 1 1) r))"))
