在编译器构造中有两个语义分析阶段是否很常见?
Is it common to have two semantic analysis phases within compiler construction?
我一直在用 AST explorer 研究各种语言的语法和 AST 节点。
使用 python,我注意到在解析过程中进行了某种形式的语义分析。例如
x = 2
x = 2
产生以下由 VariableDeclaration
节点和 ExpressionStatement
节点组成的 AST。
所以当第一个x = 2
行被解析时,它会检查一个符号table是否存在x
然后注册它并产生一个VariableDeclaration
节点。然后在解析第二行x = 2
的时候,发现x
已经定义了,产生了一个ExpressionStatement
节点。
然而,当我尝试使用以下语义不正确的代码时:
2 + "string"
它接受代码,并生成一个 ExpressionStatement
节点 - 尽管它在语义上是不正确的,即 int + string
,并且当我尝试使用 [=38] 执行它时正确地产生错误=] 解释器.
这表明语义分析发生了两次:一次是在解析过程中,另一次是在遍历完整的 AST 时。这个假设是否正确?如果是这样,为什么会这样?在解析过程中进行整个语义分析阶段而不是将其拆分会不会更简单?
语句 2 + "string"
中的语义错误在任何语义传递中均未检测到。这是一个运行时错误,当您尝试执行该语句时会报告它。如果语句从不执行,则不报错,执行脚本可以看到
if False:
2 + "string"
print("All good!")
解决第一次使用全局变量作为声明比其他任何事情都更优化,编译器执行多次优化是很常见的。
总是有尝试组合这些多次传递的诱惑,但这是一种错误的经济:遍历 AST 的开销相对较低,而且当代码只尝试做一件事时,它会更清晰、更易于维护。将两个不相关的优化启发式交织在一起是糟糕的设计,就像将任何一组不相关的程序交织在一起一样。
我一直在用 AST explorer 研究各种语言的语法和 AST 节点。 使用 python,我注意到在解析过程中进行了某种形式的语义分析。例如
x = 2
x = 2
产生以下由 VariableDeclaration
节点和 ExpressionStatement
节点组成的 AST。
所以当第一个x = 2
行被解析时,它会检查一个符号table是否存在x
然后注册它并产生一个VariableDeclaration
节点。然后在解析第二行x = 2
的时候,发现x
已经定义了,产生了一个ExpressionStatement
节点。
然而,当我尝试使用以下语义不正确的代码时:
2 + "string"
它接受代码,并生成一个 ExpressionStatement
节点 - 尽管它在语义上是不正确的,即 int + string
,并且当我尝试使用 [=38] 执行它时正确地产生错误=] 解释器.
这表明语义分析发生了两次:一次是在解析过程中,另一次是在遍历完整的 AST 时。这个假设是否正确?如果是这样,为什么会这样?在解析过程中进行整个语义分析阶段而不是将其拆分会不会更简单?
语句 2 + "string"
中的语义错误在任何语义传递中均未检测到。这是一个运行时错误,当您尝试执行该语句时会报告它。如果语句从不执行,则不报错,执行脚本可以看到
if False:
2 + "string"
print("All good!")
解决第一次使用全局变量作为声明比其他任何事情都更优化,编译器执行多次优化是很常见的。
总是有尝试组合这些多次传递的诱惑,但这是一种错误的经济:遍历 AST 的开销相对较低,而且当代码只尝试做一件事时,它会更清晰、更易于维护。将两个不相关的优化启发式交织在一起是糟糕的设计,就像将任何一组不相关的程序交织在一起一样。