対応するコミット:
この章では前置演算子として-
をパースします.
Prattパーサの構造を思い出しましょう:
fn parse_expr_bp(input: Input, min_bp: u16) -> Expr {
let expr = if input.is_leading_op() { // 先行演算子で始まるか?
// 先行演算子のパース
} else {
parse_atomic_expr(input) // アトミックな式(リテラルなど)のパース
};
loop {
// 後続演算子が続かない場合はおしまい
if !input.is_following_op() {
return expr;
}
expr = {
// 後続演算子のパース
};
}
}
前置演算子は先行演算子なので,一番最初にパースすることになりますね.
入力から一文字読み取って-
かどうかチェックすることにします.
もし-
だった場合はその分だけ入力を進めてから-
の引数を再帰的にパースします.
最終的には-
を関数とするS式を構築しておしまいです.
一方,-
でない場合はアトミックな式のパースをします.
pub fn parse_expr(input: &mut Input<'_>) -> SExpr {
match input.peek().unwrap() {
'-' => {
input.bump(); // '-'を消費
let following_expr = parse_expr(input); // 演算子の対象を再帰的にパース
SExpr::List(vec![SExpr::Atom("-".into()), following_expr])
}
_ => parse_atom(input),
}
}
テストしてみます.
#[test]
fn test_simple_prefix() {
complete_parse("-8", "(- 8)")
}