在LISP中,可以定义一个宏,它在相同的堆栈级别扩展,而不是添加到堆栈。在TCL中,可以调用一个过程,然后使用uplevel 1
。我已经看到它在某些情况下会导致显着的减速。我想要的是宏观扩张。这在TCL有售吗?我找不到任何暗示它的确如此。
答案 0 :(得分:1)
由于upvar
,tailcall
和uplevel
提供了一套相当不错的功能,因此宏的使用率不高。特别是,使用label
不会阻止字节码编译(受到一些技术限制,并且允许您使用8.6或更高版本),因此您可以继续使用它而不必担心太多。这并不是说宏无法完成,而是通过在外部引入一个命令来完成它们,这些命令创建了在定义期间对它们执行宏扩展的命令(可能是程序)。一旦你以这种方式工作,你就可以对代码进行相当彻底的重新排列;输入文本根本不需要像Tcl。
Tcler的Wiki上有几页关于这个主题; http://wiki.tcl.tk/3888,http://wiki.tcl.tk/11156等。我编写的一种宏观系统,我正在使用的是tclquadcode。有了这个,我就可以使用伪组装基本块标签作为类似宏的东西:它不仅涉及简单的替换,而是将相关代码重新定位到脚本体的开头,这样我就不需要手动声明前面涉及的变量(我之前发现它非常容易出错并且难以阅读);它内部使用lambda术语而不是作用域范围控制的程序,但鉴于build
是宏,而不是build {
my condBr [my and [my isNumericInt $x] [my isNumericInt $y]] \
$ints $doubles
label ints:
my ret [my add(INT,INT) [my numeric.int $x] [my numeric.int $y]]
label doubles:
set left [my cast(DOUBLE) $x "left"]
set right [my cast(DOUBLE) $y "right"]
my ret [my add(DOUBLE,DOUBLE) $left $right]
}
,差异并不太重要。 Here's an example of use of that code。该代码的相关位是(如果我为可读性做了典型的替换):
apply {{func x y} {
set ints [$func block "ints"]
set doubles [$func block "doubles"]
my SetCurrentBasicBlock [$func getEntryBlock]
my condBr [my and [my isNumericInt $x] [my isNumericInt $y]] \
$ints $doubles
my SetCurrentBasicBlock $ints
my ret [my add(INT,INT) [my numeric.int $x] [my numeric.int $y]]
my SetCurrentBasicBlock $doubles
set left [my cast(DOUBLE) $x "left"]
set right [my cast(DOUBLE) $y "right"]
my ret [my add(DOUBLE,DOUBLE) $left $right]
}} $func $x $y
这内部重写了很多,大概是这样的:
{{1}}
非常近似。由于调试元数据跟踪,生成的代码的真实版本是 lot 更复杂;这是一个非常重要的代码生成。