Compiler construction 在Common Lisp中,“tagbody”和“go”是如何在hood下实现的?
如何在Common Lisp中实现Compiler construction 在Common Lisp中,“tagbody”和“go”是如何在hood下实现的?,compiler-construction,common-lisp,Compiler Construction,Common Lisp,如何在Common Lisp中实现tagbody和go?它是某种形式的setjmp/longjmp,还是有一种更优雅的处理方式 我正在编写一种用C语言实现的lispy语言,希望有类似这样的语言。从实现的角度来看,如果您正在解释一个类似Lisp的程序,您可能会执行以下操作: 输入tagbody后,开始一个目的地表。(符号地图)→地址对) 迭代标记体中的每个表单 如果(symbolp此元素),则将地址(指向该表单的指针)存储到表中 否则,(评估此元素)与往常一样 遇到go表单时,查找目标符号,并(
tagbody
和go
?它是某种形式的setjmp/longjmp,还是有一种更优雅的处理方式
我正在编写一种用C语言实现的lispy语言,希望有类似这样的语言。从实现的角度来看,如果您正在解释一个类似Lisp的程序,您可能会执行以下操作:
- 输入
后,开始一个目的地表。(符号地图)→地址对)tagbody
- 迭代
标记体中的每个表单
,则将地址(指向该表单的指针)存储到表中如果(symbolp此元素)
- 否则,
与往常一样(评估此元素)
- 遇到
表单时,查找目标符号,并(破坏性地)将程序的“当前指令”指针更改为该值。然后,跳转到例程获取下一条指令go
- 退出标记体时,只需放弃目标表即可
go
标记是与变量、函数、类等分离的名称空间
@jlahd是正确的,它实际上与C中的(有限范围)
goto
完全相同,但是如果您解释代码,实际上将用存储的值覆盖“程序计数器”指针 将通用Lisp的go
简化为其他语言goto
是太简单了
在Common Lisp中,go
可以展开堆栈。例如:
(tagbody
(mapc #'(lambda (el1 el2)
(format t "el1: ~a, el2: ~a~%" el1 el2)
(when (or (null el1) (null el2))
(go stop)))
list1
list2)
stop)
如果您是用C语言实现Common Lisp,那么非展开的go
可能是常规的goto
,但展开的go
需要setjmp
/longjmp
或等效功能,具有适当的堆栈展开,如果需要,还需要常规的goto
,即,如果标记的Lisp表单不是setjmp
之后的C语句或表达式
如果您有足够的时间对其进行抽象,您可能会希望使用操作系统的异常处理。如果您以后想与其他语言的特征(如C++异常)集成,则可能会更好地得到回报,并且平台可能已经有一个处理程序栈,因此运行<代码> unWravy保护< /COD>清理窗体自动达到某个堆栈帧。
如果您想让它以最小的工作量保持可移植性,您可以管理一个线程本地堆栈setjmp
上下文,其中longjmp
到具有足够信息的最新上下文,以保持longjmp
一直运行unwind protect
清理表单。通过这种方式,您可能仍然希望使用平台的异常处理功能,但只需要设置从/到外部调用的展开帧