我正在编写一个编译器,我需要将Mini Pascal (Pascal的简单版本)转换为Jasmin字节代码。
-
但是我如何声明嵌套函数用茉莉花语吗?
-
因为
?function tt(I): I
只能传递一个整数(这是rr
)我如何转移变量d
fromfunctionss
函数tt
c++(自己翻译自Mini Pascal):
#include <iostream>
using namespace std;
int a, b;
int ss(int rr)
{
int d;
int tt(int rr)
{
int e;
e = rr * 3;
return rr + d - e + b;
}
d = rr - 4;
return tt(rr);
}
int main()
{
b = -5;
a = ss(3);
cout << a;
return 0;
}
迷你帕斯卡:
PROGRAM test_nested_function(input, output, error);
VAR a, b : INTEGER;
FUNCTION ss(rr :INTEGER) : INTEGER;
VAR d : INTEGER;
FUNCTION tt(rr : INTEGER) : INTEGER;
VAR e : INTEGER;
BEGIN
e := rr * 3;
tt := rr + d - e + b;
END;
BEGIN
d := rr - 4;
ss := tt(rr)
END;
BEGIN
b := -5;
a := ss(3);
writelnI(a)
END.
当你从一种有闭包的语言翻译到另一种没有闭包的语言时,你必须以某种方式保留对外部函数的引用。一般来说,有两种方法:嵌套闭包和平面闭包。需要注意的重要一点是,在这两种情况下,闭包都是而不是一个普通的顶级函数。它是一个可以调用的结构体
<标题>嵌套闭包在嵌套闭包中,嵌套函数只是维护对封闭作用域的引用,作为指向某个抽象数据结构的指针。因此,tt
维护对ss
的引用(在摘要中),然后可以通过ss.d
访问d
变量。Java伪代码:
public class SsStructure {
private int rr;
private int d;
public SsStructure(int rr) {
this.rr = rr;
this.d = 0;
}
}
public class TtStructure {
private SsStructure closure;
public TtStructure(SsStructure closure) {
this.closure = closure;
}
public int call(int rr) {
...
}
}
public class Main {
public static int ss(int rr) {
SsStructure ss = new SsStructure(rr);
TtStructure tt = new TtStructure(ss);
ss.d = ss.rr - 4;
return tt.call(ss.rr - 4);
}
}
在这个模型中,你的ss
函数在你的程序中得到一个闭包框架。它的所有局部变量(或者至少是闭包所需的那些)都被放入该结构中,而不是声明为实际的局部变量。然后该闭包结构被传递给任何需要它的嵌套函数。
如果函数嵌套在多层深处,那么闭包维护对直接封闭作用域的引用。如果它需要访问存在于闭包堆栈上多层的变量,它将通过间接引用来实现,因为每个闭包框架保留对其自己的封闭范围的引用。
<标题>平闭包使用平面闭包,嵌套函数从封闭作用域接收实际具体变量的副本。您的tt
仍然是一个结构,但不是存储对其他ss
结构的引用,而是获得实际需要的int
。
public class TtStructure {
private int d;
public TtStructure(int d) {
this.d = d;
}
public int call(int rr) {
...
}
}
public class Main {
public static int ss(int rr) {
int d = rr - 4;
TtStructure tt = new TtStructure(d);
return tt.call(rr - 4);
}
}
这是一种更节省空间的方法。不是到处存储一堆指针,而是只存储实际数据和需要的数据。此外,如果您有嵌套的闭包,您可以在创建这些专门的结构时自动将它们平面化,这样就减少了间接性。
但是,如果使用可变闭包,则必须小心。如果你有一个final
变量,那么就没有问题。事实上,这正是Java语言禁止关闭非final
变量的原因。
如果你想在闭包中允许可变变量,你需要显式地添加一个间接层。这可以是一个存储一个实例变量的简单类,然后您可以在封闭范围和闭包中使用该变量。
public class Cell<T> {
public T impl;
public Cell(T impl) {
this.impl = impl;
}
}
如果(a)在闭包中使用,和(b)在任何点重新赋值,则需要将任何局部变量包装在Cell<T>
中。final
类型的变量(因此永远不会重新赋值)不需要包装,那些只在局部使用的变量(永远不会在闭包中使用)也不需要包装。