Joe*_*ard 1 lisp elisp emacs24
我试图在elisp中创建一个简单的解析器,我遇到了一个问题,我defvar是一个全局的,然后我将setq一个新值放入其中.这是第一次工作.然而,后来setq每次都失败了.
以下代码是问题的简化:
(defvar buf '(BUF))
(defvar head nil)
(defun pparse (seq)
(defun status ()
(princ (format "Parse: %40s || %-20s\n"
(prin1-to-string seq) (prin1-to-string buf))))
(while seq
(status)
(setq head (car seq))
(setq seq (cdr seq))
(cond ((equal "x" head)
(nconc buf (list head)))
((equal "," head)
(setq buf '(BUF))
;;(setcdr buf nil) <- fixes it but doesn't answer my question
)))
(status))
(pparse '("x" "," "x" "," "x" "," "x"))
Run Code Online (Sandbox Code Playgroud)
哪个产生这个输出:
Parse: ("x" "," "x" "," "x" "," "x") || (BUF)
Parse: ("," "x" "," "x" "," "x") || (BUF "x")
Parse: ("x" "," "x" "," "x") || (BUF)
Parse: ("," "x" "," "x") || (BUF "x")
Parse: ("x" "," "x") || (BUF "x")
Parse: ("," "x") || (BUF "x" "x")
Parse: ("x") || (BUF "x" "x")
Parse: nil || (BUF "x" "x" "x")
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,第二列被剪切了一次,但随后每次都会增长.
如果取消注释该setcdr行,则按预期工作(输出如下).你甚至可以转储setq.我理解为什么这会解决它,但不是为什么原始错误发生在第一位.
Parse: ("x" "," "x" "," "x" "," "x") || (BUF)
Parse: ("," "x" "," "x" "," "x") || (BUF "x")
Parse: ("x" "," "x" "," "x") || (BUF)
Parse: ("," "x" "," "x") || (BUF "x")
Parse: ("x" "," "x") || (BUF)
Parse: ("," "x") || (BUF "x")
Parse: ("x") || (BUF)
Parse: nil || (BUF "x")
Run Code Online (Sandbox Code Playgroud)
顺便说一句,即使我关闭词汇范围,行为也是一样的.
你不能改变文字数据,例如'(BUF),并期望理智的结果.在您的代码中,这nconc是一个变异操作.
就"为什么"你看到你所看到的行为而言,这是由于(setq buf '(BUF))表达.每次都将它设置为同一个对象,因为它是一个文字数据 - 你不应该用它来变异nconc.如果您将其更改为(setq buf (list 'BUF)),则每次都会生成一个新对象,您可以放心地使用nconc 它.