我正在尝试为支持嵌套函数的语言编写编译器,例如:
func a()
int x;
func b()
int y;
{
// code of func b - both x and y are visible here
}
{
// code of func a - only x is visible here
}
我在c ++中使用LLVM API来编译代码。我的问题是我不知道如何使变量x在函数b中可见,因为据我所知llvm不支持嵌套函数。到目前为止,我声明变量的方式是该函数:
static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName, Type *T) {
IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
return TmpB.CreateAlloca(T, 0, VarName.c_str());
}
如llvm教程https://llvm.org/docs/tutorial/LangImpl07.html#adjusting-existing-variables-for-mutation中所示。
当使用此声明并尝试在嵌套函数中使用外部变量时,会弹出此错误:指令不能支配所有用途!。
有办法解决这个问题吗?
答案 0 :(得分:0)
C ++不支持该功能。
如果您希望以这种方式从嵌套函数或任何其他函数访问变量,请传递对其的引用。 :)
答案 1 :(得分:0)
LLVM支持结构,对吗?这就是典型的编译器的作用。
您需要使用引用的每个外部变量生成的字段来创建匿名结构。然后,创建一个与b()
对应的匿名函数,该函数以该结构作为参数并对其进行操作。基本上,您将b()
变成了常规的顶层函数。最后,您对a()
代码进行了转换,以使其创建struct实例并调用匿名函数。在这一点上,进一步的优化是可能的。要做好准备:这一点都不容易,这可能是代码转换的非常高级的主题。
例如
func a()
int x = 1;
func b() {
return x+1;
}
return b() + 2;
}
成为
struct tmp {
int tmpx; // reference or value?
}
func tmp_b(tmp& instance) {
instance.tmpx += 1;
return instance.tmpx;
}
func a() {
int x = 1;
tmp instance(tmpx = x); // should it go by reference or value?
return tmp_b(instance) + 2;
}
您也可以将b()
转换为b(int x)
顶级函数。但是这种方法不太灵活。还是根据上下文使用两种方法,为什么不呢?
请注意,如果您的语言通过方法和/或运算符(在这种情况下称为运算符)重载来支持适当的类,那么所有这些操作都可以简化。