Lexical Scoping是如何实现的?

时间:2010-03-05 02:21:02

标签: programming-languages closures compiler-construction lexical-scope

几年前,我开始为一个包含程序员定义函数的域特定语言编写一个解释器。

首先,我使用一组简单的符号表实现了变量范围。但现在我想转向适当的词法范围(可选择闭包)。任何人都可以解释词法范围背后的数据结构和算法吗?

5 个答案:

答案 0 :(得分:10)

要在解释器中获得正确的词法范围和闭包,您需要做的就是遵循以下规则:

  • 在解释器中,变量总是在调用者传入的环境表中查找,或者保存为变量,而不是某些全局的env-stack。您的评估操作的签名类似于eval(expression, env) => value
  • 当解释的代码调用函数时,环境 NOT 传递给该函数。函数应用程序操作的签名类似于apply(function, arguments) => value
  • 当调用解释函数时,其身体被评估的环境是制作函数定义的环境,并且与调用者没有任何关系。因此,如果您有本地函数,那么它是闭包,即包含字段{function definition, env-at-definition-time}的数据结构。

扩展Python-ish语法中的最后一位:

x = 1
return lambda y: x + y

应该像

一样执行
x = 1
return make_closure(<AST for "lambda y: x + y">, {"x": x})

其中第二个dict参数可能只是current-env而不是当时构造的数据结构。 (另一方面,保留整个env而不仅仅是关闭的变量可能意味着程序具有令人惊讶的内存泄漏,因为闭包持有不需要的东西。这在任何“实际”语言实现中都是值得修复的,但不是当你只是试验语言语义时。)

答案 1 :(得分:7)

实现词法范围的方法有很多种。以下是我的一些最爱:

  • 如果您不需要超高性能,请使用纯函数数据结构来实现符号表,并通过包含指向代码的指针和指向符号表的指针的对来表示嵌套函数

  • 如果您需要本机代码速度,我最喜欢的技术将由Simon Marlow和Simon Peyton Jones在Making a Fast Curry中描述。

  • 如果您需要本机代码速度,但是curried函数并不重要,请考虑closure-passing style

答案 2 :(得分:2)

没有一种正确的方法可以做到这一点。重要的是明确说明您要提供的语义,然后数据结构和算法将遵循。

答案 3 :(得分:2)

例如,阅读The implementation of Lua 5.0

答案 4 :(得分:1)

Stroustrup在第一个C ++编译器中实现了这一点,每个范围只有一个符号表,并且一个链接规则向外跟随范围,直到找到定义。这是如何工作的确切取决于您的精确语义。确保先把它们钉在一起。

计算机程序设计艺术第1卷中的Knuth给出了一个Cobol符号表的算法,通过链接进行作用域。