parsing - 在编译器构造中有两个语义分析阶段是否很常见?
问题描述
我一直在用AST explorer研究各种语言的语法和 AST 节点。使用 python,我注意到在解析过程中会发生某种形式的语义分析。例如
x = 2
x = 2
产生以下由VariableDeclaration
节点和ExpressionStatement
节点组成的 AST。
因此,当解析第一x = 2
行时,它会检查符号表是否存在,x
然后将其注册并生成一个VariableDeclaration
节点。然后当解析第二x = 2
行时,它发现x
已经定义并生成一个ExpressionStatement
节点。
但是,当我尝试使用以下语义不正确的代码时:
2 + "string"
它接受代码,并产生一个ExpressionStatement
节点——即使它在语义上是不正确的 ie int + string
,当我尝试使用 python 解释器执行它时,它会正确地产生一个错误。
这表明语义分析发生了两次:一次是在解析过程中,另一次是在遍历完整的 AST 时。这个假设正确吗?如果是这样,为什么会这样?在解析期间完成整个语义分析阶段而不是拆分它不是更简单吗?
解决方案
2 + "string"
在任何语义传递中都未检测到语句中的语义错误。这是一个运行时错误,当您尝试执行该语句时会报告它。如果语句从不执行,则不报错,执行脚本可以看到
if False:
2 + "string"
print("All good!")
将全局变量的第一次使用作为声明解决比其他任何事情都更像是一种优化,编译器执行多次优化传递是很常见的。
尝试将这些多遍组合在一起总是很诱人,但这是一种错误的经济:走 AST 的开销相对较低,并且当它只尝试做一件事时代码更清晰且更易于维护。将两个不相关的优化启发式交织在一起是糟糕的设计,就像将任何一组不相关的程序交织在一起一样。
推荐阅读
- rust - 在这个 Docopt 示例中,类型推导是如何工作的?
- c# - Visual Studio 2017 中缺少 Windows 安装程序
- node.js - 如何进行 MongoDB 查询并在部分视图中使用它
- c# - 如何为弹性条件源描述符创建 Nest
- r - R 正则表达式问题:“-\\s[AZ]”小写匹配的大写字母并删除破折号+空格
- python-3.x - 通过具有特定 ulimit 的 python API 运行 docker 容器
- javascript - datepicker 禁用期货日期
- java - 如何在具有密码保护的soapui(使用wsdl)中运行soap服务,就像在服务器中一样?
- python - GroupBy 后无法重命名列
- regression - 残差对拟合值图的解释是什么?