Memory management 用解释语言存储变量的数据结构

Memory management 用解释语言存储变量的数据结构,memory-management,data-structures,global-variables,language-design,compiler-construction,Memory Management,Data Structures,Global Variables,Language Design,Compiler Construction,我正在设计自己的实验性脚本语言,目的是将其嵌入到更大的应用程序中 我想做的几乎所有事情都是顺利编程的,但在内存中存储变量的“简单”操作似乎是这里最难的部分。我不知道如何存储它们以允许所有类型检查、全局变量和特殊标志。首先看一个示例代码: a = 1 b = 2 someFunction() print(a) --> This should read the global variable and print `1` a = 3 --> Now `a` shou

我正在设计自己的实验性脚本语言,目的是将其嵌入到更大的应用程序中

我想做的几乎所有事情都是顺利编程的,但在内存中存储变量的“简单”操作似乎是这里最难的部分。我不知道如何存储它们以允许所有类型检查、全局变量和特殊标志。首先看一个示例代码:

a = 1
b = 2

someFunction()
  print(a)   --> This should read the global variable and print `1`
  a = 3      --> Now `a` should become a local variable of this function
                 and the global `a` remain unchanged
  x = 4      --> `x` should always be local of this function
end
我将变量的“局部性”称为它们的
级别
s,因此嵌套块中的变量具有更高的级别。在上述代码中,
a
b
是一级变量。someFunction的局部变量将具有级别2。函数的第一行应该读取全局变量
a
(级别1),但第二行应该创建一个再次称为
a
的变量,但级别2从该点开始将全局变量
a
隐藏起来。第三行应创建级别为2的变量
x
。如何在内存中存储和跟踪所有这些信息

到目前为止我所尝试的:

方法1:以级别数组存储
变量=>值的映射:

variables
{
    level=1 //global variables
    {
        a => 1,
        b => 2
    },
    level=2 //function variables
    {
        a => 3,
        x => 4
    }
}
但这将使变量查找变得非常缓慢,因为必须在所有级别上搜索给定变量

方法2:将(变量、级别)对存储为映射的键:

variables
{
    (a, 1) => 1, //global
    (b, 1) => 2, //global
    (a, 2) => 3, //function
    (x, 2) => 3  //function
}
这与之前的问题相同,因为我们必须尝试对给定变量的所有可能级别进行配对(变量,级别)

我应该使用什么方法来获得最佳内存使用率和最快的访问时间

附加说明:

我知道在其他“真实”语言上如何在堆栈和堆上管理变量,但我发现在解释语言上这样做很棘手。“Lua和Python一定不是这样做的,”我一直认为。如果我错了,请纠正我。我试图将变量存储在映射和内部C++结构中。 最后,这就是我表示变量的方式。您是否认为它很大,并且可以有更高效的内存表示?(我也试着把“级别”作为一个成员放在这里,但它也有同样的问题。)


与数组类似,一件简单的事情是维护一堆贴图。每个映射都包含该范围的绑定。要绑定变量,请将其添加到顶部映射;要查找变量,请从堆栈顶部开始,到达包含该变量绑定的映射时停止。搜索需要一点时间,但是从顶端开始,你只需要搜索直到找到它——在大多数情况下,搜索不会很长


您还可以通过将此逻辑封装在具有本地绑定和用于解析未知变量的继承环境的
环境
类中,使堆栈隐式化。需要进入一个新的领域吗?创建一个以当前环境为基础的新环境,使用它,然后在范围完成时放弃它。根/全局环境只能有一个空的继承环境。这就是我可能会做的。

值得注意的是,如果在函数内部,您无法从调用者函数访问任何变量,则会降低您需要查看的级别数。例如:

variable a;

function one() {
    variable b;
    // in this function, we can see the global a, local b
    two();
}

function two() {
    // in this function, we can see the global a, local c
    // we cannot see the local b of our caller
    variable c;
    while (true) {
        variable d;
        // here we can see local d, local c, global a
    }
}
其思想是函数边界限制变量的可见性,全局范围是“特殊的”

这样说,你可以考虑删除全局变量的特殊性,但是允许代码指定他们想要访问非局部变量

variable a;

function one() {
    global a; // or upvar #0 a;
    variable b;
    // in this function, we can see the global a, local b
    two();
}

function two() {
    // in this function, we can see the local c
    // and the local b of our caller
    // (since we specifically say we want access to "b" one level up)
    upvar 1 b;
    variable c;
}

它一开始看起来很复杂,但一旦习惯了它,就很容易理解(upvar是Tcl编程语言的一种构造)。它允许您访问调用者作用域中的变量,但它避免了一些昂贵的查找,因为它要求您准确地指定该变量的来源(1表示调用堆栈上的一级,2表示调用堆栈上的两级,而#0表示“最上面的调用堆栈,全局调用堆栈”的“特殊”)

我会使用一个映射,将每个变量名称映射到一个变量实例堆栈。在某个级别上创建新变量时,将此变量推送到堆栈上,堆栈上最顶部的元素将保存当前可见的具有此名称的变量实例。您还必须维护每个级别的分配变量列表,以弹出变量离开该级别时可以从堆栈中删除。希望这有意义,我自己从未设计过语言。您可以简单地使用数组堆栈和某种形式的de Bruijn索引。在解释之前,通过解析所有名称执行基本的“编译”步骤。看起来Python就是这样做的:
variable a;

function one() {
    global a; // or upvar #0 a;
    variable b;
    // in this function, we can see the global a, local b
    two();
}

function two() {
    // in this function, we can see the local c
    // and the local b of our caller
    // (since we specifically say we want access to "b" one level up)
    upvar 1 b;
    variable c;
}