AST:给名字留位置
本节阅读量:上一节说清楚了第二章的规则:
|
|
第一章已经有两个 AST 节点:
|
|
第二章增加两个节点:
|
|
AST 的作用仍然没变:
|
|
ExprKind 增加两类
代码在:
|
|
先看表达式分类:
|
|
解释器和编译器拿到一个通用的 Expr 时,会先看 kind,再用 switch 选择处理规则。
这和第一章一样,只是分类表变长了:
|
|
VarExpr 只保存名字
变量引用的节点很小:
|
|
例如源码:
|
|
对应 AST:
|
|
注意,VarExpr 里没有保存 x 的值。AST 只是结构,不是求值结果。
x 到底是多少,要等后面处理:
|
|
LetExpr 保存名字、value 和 body
let 节点保存三件事:
|
|
例如:
|
|
对应:
|
|
里面三部分是:
|
|
value 和 body 都是 unique_ptr<Expr>,因为它们可以是任意表达式:
|
|
这里的 value 是一个加法表达式:
|
|
为什么不直接替换字符串
看到:
|
|
你可能会想:parser 能不能直接把 body 里的 x 替换成 40?
不要这样做。parser 不知道求值规则,也不应该修改含义。
shadowing 会让字符串替换马上出错:
|
|
这段程序里有两个 x 绑定:
|
|
内层 body 里的 x 应该指向 32,最后那个 x 应该指向 10。
所以 AST 只保留结构:
|
|
哪个 Var(x) 对应哪个绑定,留给解释器和编译器通过环境判断。
观察 AST
运行:
|
|
输出:
|
|
再运行:
|
|
输出类似:
|
|
这说明 parser 已经保留了两个同名绑定的结构。下一节看 parser 怎样读出这些节点。
本节目录