首页 > 解决方案 > 在编译器构造中有两个语义分析阶段是否很常见?

问题描述

我一直在用AST explorer研究各种语言的语法和 AST 节点。使用 python,我注意到在解析过程中会发生某种形式的语义分析。例如

x = 2
x = 2

产生以下由VariableDeclaration节点和ExpressionStatement节点组成的 AST。

Python AST

因此,当解析第一x = 2行时,它会检查符号表是否存在,x然后将其注册并生成一个VariableDeclaration节点。然后当解析第二x = 2行时,它发现x已经定义并生成一个ExpressionStatement节点。

但是,当我尝试使用以下语义不正确的代码时:

2 + "string"

它接受代码,并产生一个ExpressionStatement节点——即使它在语义上是不正确的 ie int + string,当我尝试使用 python 解释器执行它时,它会正确地产生一个错误。

这表明语义分析发生了两次:一次是在解析过程中,另一次是在遍历完整的 AST 时。这个假设正确吗?如果是这样,为什么会这样?在解析期间完成整个语义分析阶段而不是拆分它不是更简单吗?

标签: parsingabstract-syntax-treesemantic-analysis

解决方案


2 + "string"在任何语义传递中都未检测到语句中的语义错误。这是一个运行时错误,当您尝试执行该语句时会报告它。如果语句从不执行,则不报错,执行脚本可以看到

    if False:
        2 + "string"
    print("All good!")

将全局变量的第一次使用作为声明解决比其他任何事情都更像是一种优化,编译器执行多次优化传递是很常见的。

尝试将这些多遍组合在一起总是很诱人,但这是一种错误的经济:走 AST 的开销相对较低,并且当它只尝试做一件事时代码更清晰且更易于维护。将两个不相关的优化启发式交织在一起是糟糕的设计,就像将任何一组不相关的程序交织在一起一样。


推荐阅读