当您看到“(”并使用“)”关闭它时,如何创建一个新列表。口齿不清 Python
How to make a new List when you see a "(" and close it using ")". Lisp to Python
我想做一个 Lisp 解释器,我只是在标记化后努力翻译它。所以在标记化之后,我的列表看起来像这样。
tokenized = ["(", "car", "'","(", "20", "40", "60", ")", ")"]
我想要的是将它翻译成看起来像这样的东西
translated = [["CAR", "'", [20, 40, 60]]]
我需要一种在看到“(”时创建新列表并在看到“)”时关闭它的方法。让我知道是否需要更好地解释它,我不擅长解释。
好的,所以这就像递归下降解析器一样工作。每次它看到一个左括号,它都会创建一个新的 list
,将其附加到输出列表并向下递归,但使用新列表。每次它看到一个右括号时,它只是 returns 到它之前的位置。递归的基本情况是到达要解析的项目的末尾:
def rdp(items):
it = iter(items)
def inner(it, out):
while True:
token = next(it)
if token == '(':
nxt = []
out.append(nxt)
inner(it, nxt)
continue
elif token == ')':
return
out.append(token)
nxt = []
try:
inner(it, nxt)
except StopIteration:
pass
return nxt
tokenized = ["(", "car", "'","(", "20", "40", "60", ")", ")"]
translated = rdp(tokenized)
按要求输出
注意: 我刚刚编辑它以将 try:except:
移到 inner()
递归函数之外以避免重复异常。
我会用 Lisp 给你一个答案(我假设严格的从左到右顺序求值):
(define (relist tokens)
(let ((tok #f))
(define (get)
(set! tok (car tokens))
(set! tokens (cdr tokens))
tok)
(define (go)
(cond
((null? tokens)
'()) ; we're done
((eq? (get) ")")
'()) ; done with this level
((eq? tok "(")
(cons (go) ; open new
(go))) ; level
(else
(cons tok ; go on with
(go))))) ; this level
(go)))
;; testing in DrRacket:
(relist '[1 2 "(" 3 "(" 4 ")" ")" 5]) ;=> '(1 2 (3 (4)) 5)
(relist '[1 2 "(" 3 "(" 4 ")" 5]) ;=> '(1 2 (3 (4) 5))
变量tok
是函数的局部变量。它的范围在这里包括所有内部函数定义以及函数体。
go
的所有调用通过调用 get
.
与相同的输入流(列表)tokens
一起工作并向前推进
当收到打开新子列表的信号时,令牌 "("
,我们通过递归 non-tail 调用 go
(忽略令牌本身)当然)。
否则我们只是使用接收到的令牌并继续,这表示为 go
的尾部调用(两者,在两种情况下)。您自然会用 Python 原生的其他方式来表达这一点。我只是想向您展示它的基本最小结构,在 Lisp 中很好地看到。
我想做一个 Lisp 解释器,我只是在标记化后努力翻译它。所以在标记化之后,我的列表看起来像这样。
tokenized = ["(", "car", "'","(", "20", "40", "60", ")", ")"]
我想要的是将它翻译成看起来像这样的东西
translated = [["CAR", "'", [20, 40, 60]]]
我需要一种在看到“(”时创建新列表并在看到“)”时关闭它的方法。让我知道是否需要更好地解释它,我不擅长解释。
好的,所以这就像递归下降解析器一样工作。每次它看到一个左括号,它都会创建一个新的 list
,将其附加到输出列表并向下递归,但使用新列表。每次它看到一个右括号时,它只是 returns 到它之前的位置。递归的基本情况是到达要解析的项目的末尾:
def rdp(items):
it = iter(items)
def inner(it, out):
while True:
token = next(it)
if token == '(':
nxt = []
out.append(nxt)
inner(it, nxt)
continue
elif token == ')':
return
out.append(token)
nxt = []
try:
inner(it, nxt)
except StopIteration:
pass
return nxt
tokenized = ["(", "car", "'","(", "20", "40", "60", ")", ")"]
translated = rdp(tokenized)
按要求输出
注意: 我刚刚编辑它以将 try:except:
移到 inner()
递归函数之外以避免重复异常。
我会用 Lisp 给你一个答案(我假设严格的从左到右顺序求值):
(define (relist tokens)
(let ((tok #f))
(define (get)
(set! tok (car tokens))
(set! tokens (cdr tokens))
tok)
(define (go)
(cond
((null? tokens)
'()) ; we're done
((eq? (get) ")")
'()) ; done with this level
((eq? tok "(")
(cons (go) ; open new
(go))) ; level
(else
(cons tok ; go on with
(go))))) ; this level
(go)))
;; testing in DrRacket:
(relist '[1 2 "(" 3 "(" 4 ")" ")" 5]) ;=> '(1 2 (3 (4)) 5)
(relist '[1 2 "(" 3 "(" 4 ")" 5]) ;=> '(1 2 (3 (4) 5))
变量tok
是函数的局部变量。它的范围在这里包括所有内部函数定义以及函数体。
go
的所有调用通过调用 get
.
tokens
一起工作并向前推进
当收到打开新子列表的信号时,令牌 "("
,我们通过递归 non-tail 调用 go
(忽略令牌本身)当然)。
否则我们只是使用接收到的令牌并继续,这表示为 go
的尾部调用(两者,在两种情况下)。您自然会用 Python 原生的其他方式来表达这一点。我只是想向您展示它的基本最小结构,在 Lisp 中很好地看到。