章节目录

Parser:读出谓词和 if

本节阅读量:

上一节已经确定目标 AST:

1
2
Eq(lhs, rhs)
If(condition, then_branch, else_branch)

第三章的 lexer 不需要新增规则。它仍然只给括号补空格,再按空白切 token。

例如:

1
(if (eq? 0 0) 42 7)

会切成:

1
["(", "if", "(", "eq?", "0", "0", ")", "42", "7", ")"]

eq? 读取两个表达式

1
2
3
4
5
6
7
if (head == "eq?") {
    advance();
    auto lhs = parse_expr();
    auto rhs = parse_expr();
    expect(")", "expected ')' after eq? expression");
    return std::make_unique<EqExpr>(std::move(lhs), std::move(rhs));
}

左右两边都可以是任意表达式。判断某个表达式是不是 0,直接写成:

1
(eq? expr 0)

if 读取三个表达式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
if (head == "if") {
    advance();
    auto condition = parse_expr();
    auto then_branch = parse_expr();
    auto else_branch = parse_expr();
    expect(")", "expected ')' after if expression");
    return std::make_unique<IfExpr>(
        std::move(condition),
        std::move(then_branch),
        std::move(else_branch));
}

parser 必须把 condition、then 和 else 都读完,才能得到完整 AST。但“解析时读出两个分支”不等于“运行时求值两个分支”:parser 在这里不计算 condition,也不做选择,只把三个位置原样保存在 AST 里。

identifier 规则没有变化

普通变量名仍然沿用第二章的 letter+,parser 不需要修改 is_identifier()。

eq? 和 if 都在左括号后的 head 位置按固定形式识别。尤其是 eq?:问号属于这段固定拼写,并没有扩大普通变量名的范围。

这也延续了第二章的解析方式:parser 根据列表 head 判断当前结构,而不是让 lexer 把每个特殊形式变成新的 token 类型。

试一下

1
2
3
4
cd code/03_conditionals
make
./mini ast examples/eq.lang
./mini ast examples/if.lang

if.lang 的输出是:

1
If(Eq(Int(0), Int(0)), Int(42), Int(7))

到这里,新增源码已经能稳定变成 AST。下一节让解释器执行它。


3.2 AST:保存条件与两个分支

上一节

3.4 解释器:先判断,再选择

下一节