这是一个关于宏的更理论的问题(我认为)。我知道宏获取源代码并生成目标代码,而不需要对其求值,这使得程序员能够创建更多通用的语法结构。如果我必须对这两个宏系统进行分类,我会说有"C风格“宏和"Lisp风格”宏。
似乎调试宏可能有点棘手,因为在运行时,实际运行的代码与源代码不同。
根据预处理的源代码,调试器如何跟踪程序的执行情况?是否有一个特殊的“调试模式”必须设置为捕获有关宏的额外数据?
在C中,我可以理解您会为调试设置编译时间开关,但是解释型语言,如Lisp的某些形式,如何做到这一点呢?
很抱歉没有尝试一下,但是lisp工具链需要比我花更多的时间来弄清楚。
发布于 2010-07-10 02:02:36
我不认为"C风格“和"Lisp风格”的宏在编译方式上有根本的区别。两者都会在编译器看到源代码之前对其进行转换。最大的区别在于,C的宏使用C预处理器(一种较弱的辅助语言,主要用于简单的字符串替换),而Lisp的宏是用Lisp本身编写的(因此完全可以做任何事情)。
(顺便说一句:我已经有一段时间没有见过未编译的Lisp了……当然,自世纪之交以来就没有了。但如果有什么不同的话,那就是被解释似乎会使宏调试问题变得更容易,而不是更难,因为您有更多的信息。)
我同意Michael的观点:我还没有见过处理宏的C语言调试器。使用宏的代码会在任何事情发生之前进行转换。"debug" mode for compiling C code通常只表示它存储functions, types, variables, filenames, and such --我不认为它们中的任何一个存储有关宏的信息。
macroexpand-1 (尽管在C中显然有一种方法可以一次完全地宏解压整个文件)。在编写宏扩展时,您可以在编辑器中查看宏扩展的前后效果。我不记得什么时候遇到过这样的情况,调试到宏定义本身会很有用。这要么是宏定义中的错误,在这种情况下macroexpand-1会立即隔离问题,要么是下面的错误,在这种情况下,正常的调试工具工作得很好,我并不关心调用堆栈的两个帧之间是否发生了宏扩展。
发布于 2010-07-10 05:26:35
在LispWorks中,开发人员可以使用Stepper tool。
LispWorks提供了一个步进器,用户可以单步执行完整的macro expansion process。
发布于 2010-07-10 02:18:50
您真的应该研究一下Racket对使用宏调试代码的支持。正如Ken提到的那样,这种支持有两个方面。一方面是调试宏的问题:在Common Lisp中,最好的方法就是手动展开宏窗体。使用CPP的情况与此类似,但更为原始--您只需通过CPP扩展运行代码并检查结果。但是,这两个都不足以处理更复杂的宏,这就是在球拍中使用macro debugger的动机--它一个接一个地向您展示语法扩展步骤,并为绑定标识符等提供额外的基于gui的指示。
在使用宏方面,side一直比其他Scheme和Lisp实现更先进。其思想是,每个表达式(作为语法对象)都是代码加上包含其源位置的附加数据。这样,当表单是宏时,具有来自宏的部分的扩展代码将具有正确的源位置--来自宏的定义,而不是来自它的使用(表单实际上并不存在)。正如dmitry-vk所提到的,一些Scheme和Lisp实现将使用子窗体的标识来实现有限的for。
https://stackoverflow.com/questions/3214603
复制相似问题