【发布时间】:2009-11-12 22:52:15
【问题描述】:
Google 的新语言“Go”表示on its website:
该语言的设计易于分析,无需符号表即可解析
我当然不是这些问题的专家,但我认为符号表是所有使用变量的语言的编译器通用的基本结构,而 Go 显然使用变量。我不明白什么?
【问题讨论】:
标签: go symbol-tables
Google 的新语言“Go”表示on its website:
该语言的设计易于分析,无需符号表即可解析
我当然不是这些问题的专家,但我认为符号表是所有使用变量的语言的编译器通用的基本结构,而 Go 显然使用变量。我不明白什么?
【问题讨论】:
标签: go symbol-tables
解析意味着只是弄清楚程序结构:将模块分成语句/声明,将表达式分解为子表达式等。您最终会得到一个树结构,称为“解析树”或“抽象语法”树”(AST)。
显然,C++ 需要一个符号表来进行解析。
本页讨论了一些原因why C++ requires a symbol table for parsing。
当然,解析只是编译的一部分,你需要一个符号表来做一个完整的编译。
但是,解析本身在编写分析工具时很有用(例如,哪个模块导入了哪些模块)。因此,简化解析过程意味着更容易编写代码分析工具。
【讨论】:
@Justice 是对的。稍微扩展一下,在 C 中唯一实际棘手的部分是将类型与变量区分开来。特别是当你看到这个时:
T t;
您需要知道T 是一种合法解析的类型。这是您必须在符号表中查找的内容。只要在解析继续时将类型添加到符号表中,这相对容易弄清楚。您不需要在编译器中做太多额外的工作:T 要么存在于表中,要么不存在。
在 C++ 中,事情要复杂得多,很多。有大量模棱两可或可能模棱两可的结构。最明显的是这个:
B::C (c);
除了不清楚B 是class、typedef 还是namespace,还不清楚C 是一个类型而c 是一个对象该类型,或者如果C 是一个以c 作为参数的函数(或构造函数)(或者即使C 是一个operator() 重载的对象)。您需要符号表来进行解析,尽管仍然可以足够快地继续解析,因为符号的类型在符号表中。
当模板加入时,情况会变得非常非常糟糕。如果C (c) 在模板中,您可能不知道在模板的实际定义中,C 是类型还是函数/对象。这是因为模板可以将C 声明为类型或变量。这意味着您需要符号表,但您没有 一个——而且在实际声明模板之前不能拥有一个。更糟糕的是,仅仅拥有符号的类型并不一定足够:您可能会想出需要符号所代表类型的完整信息的情况,包括大小、对齐方式和其他特定于机器的信息。
所有这些都有几个实际效果。我想说的最重要的两个是:
【讨论】:
解释和编译绝对需要符号表或类似的。几乎所有语言都是如此。
在 C 和 C++ 中,即使是解析语言也需要符号表。
【讨论】:
要解析大多数语言,您需要知道名称何时是变量、类型或函数,以消除某些结构的歧义。 Go 没有这种模棱两可的结构。
例如:
int x = Foo(bar);
Foo 可以是类型或函数,它们由不同的 AST 类型表示。基本上,解析器不必对符号进行查找就知道如何构造 AST。语法和 AST 比大多数语言都简单。真的很酷。
【讨论】:
符号表很慢,通常不需要。所以去选择离开它。其他函数式语言也不需要。 快速查找需要哈希,但要支持嵌套范围,您需要将名称推送/弹出到堆栈中。简单的符号表被实现为线性搜索堆栈,更好的符号表被实现为每个符号一个堆栈的哈希。但是,搜索必须在运行时完成。
词法范围语言的解释和编译绝对不需要符号表或类似的。 只有动态范围的符号才需要符号表, 并且一些具有严格类型语言的编译器需要某种内部符号表来保存类型注释。
在 C 和 C++ 中,即使解析语言也需要符号表,因为您需要存储全局和函数的类型和声明。
词法范围的符号不存储在符号表中,而是存储在块框架中的名称索引列表中,就像在函数式语言中一样。这些索引是在编译时计算的。所以运行时访问是立即的。离开范围会使这些变量无法自动访问,因此您无需从命名空间/符号表中推送/弹出名称。
没有一等函数的函数式语言通常需要将它们的函数名存储在符号表中。作为语言设计者,您尝试将函数绑定到词法,以便能够摆脱符号表中的动态名称查找。
【讨论】: