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,也不选择分支。它只把三个位置原样保存在 AST 里。

identifier 规则没有变化

普通变量名仍然是一个或多个字母:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
bool is_identifier(const std::string& text) {
    if (text.empty()) {
        return false;
    }

    for (char c : text) {
        if (!std::isalpha(static_cast<unsigned char>(c))) {
            return false;
        }
    }
    return true;
}

eq? 只在左括号后的 head 位置作为固定形式识别,并没有扩大普通变量名的范围。

试一下

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 解释器:先判断,再选择

下一节