小编Mar*_*sen的帖子

我怎样才能发现微妙的Lisp语法错误?

我是一个玩弄Lisp的新手(实际上是Emacs Lisp).这很有趣,除非我似乎一次又一次遇到相同的语法错误.

例如,这是我多次遇到过的事情.我有一些cond形式,比如

(cond
 ((foo bar)
  (qux quux))
 ((or corge
      (grault warg))
  (fred)
  (t
   xyzzy)))
Run Code Online (Sandbox Code Playgroud)

并且xyzzy永远不会执行返回的默认子句,因为它实际上嵌套在前一个子句中:

(cond
 ((foo bar)
  (qux quux))
 ((or corge
      (grault warg))
  (fred))
 (t
  xyzzy))
Run Code Online (Sandbox Code Playgroud)

当缩进的差异只有一个空格时,我很难看到这样的错误.这会变得更容易吗?

当(错误的)缩进线与应该缩进的线之间有很大的距离时,我也会遇到问题.let例如,具有大量复杂绑定的unless表单,或具有长条件的表单:

(defun test ()
  (unless (foo bar
               (qux quux)
               (or corge
                   (grault warg)
                   (fred))))
  xyzzy)
Run Code Online (Sandbox Code Playgroud)

事实证明xyzzy,从来没有在unless形式内:

(defun test ()
  (unless (foo bar
               (qux quux)
               (or corge
                   (grault warg)
                   (fred)))
    xyzzy))
Run Code Online (Sandbox Code Playgroud)

我习惯性地自动缩进并使用括号突出显示以避免计算括号.在大多数情况下,它像微风一样,但偶尔,我只通过调试发现我的语法错误.我能做什么?

lisp syntax emacs elisp indentation

16
推荐指数
2
解决办法
1054
查看次数

零或多或一个或多个修饰符和回溯

我正在为我的PEG解析器添加零或多和一个或多个修饰符,这很简单,因为PEG中的回溯非常少.之前的迭代从未被重新考虑过,因此简单的while循环就足够了.

但是,在其他情况下,零或多和一个或多个修饰符确实需要回溯.例如,采用以下正则表达式:

(aa|aaa)+
Run Code Online (Sandbox Code Playgroud)

这种表达应该能够贪婪地匹配七串a的:有几种方式加起来2和3得到7.但到那里,重新考虑早期迭代是必要的.例如,如果表达式a第一次匹配三个,第二次匹配三个a,则只剩下一个a,这是无法匹配的.然而,回溯过去的三个a并匹配两个a,而五个a匹配.然后最后两个a也可以匹配(即3 + 2 + 2 = 7).

幸运的是,正则表达式在匹配字符串后退出搜索.但是EBNF解析器怎么样?如果语法不明确,解析器将使用回溯来查找所有可能的语法树!如果我们有生产

( "aa" | "aaa" )*
Run Code Online (Sandbox Code Playgroud)

一个七字符串a,一个完全回溯解析器将返回所有可能的方式表达7在2和3方面.而这只是七个a:匹配一个稍长的字符串,并且N -ary树的可能性增长另一个层次.考虑N  = 6:

S : ( T )*
  ;

T : A
  | B
  | C
  | D
  | E
  | F
  ;
Run Code Online (Sandbox Code Playgroud)

一个可怕的组合爆炸!

但是真的可以这样吗?EBNF中的零或多和一个或多个修饰符没有限制吗?如上所述实现它们比while()PEG解析器的普通循环要多得多,所以我不得不怀疑......

regex parsing computer-science ebnf backtracking

3
推荐指数
1
解决办法
221
查看次数