言語実装tips:複数の式をまとめる
2024-12-17
Techこのエントリは言語実装 - Qiita Advent Calendar 2024 - Qiitaの17日目の記事です。
今日は処理系実装上のTipsを一つ紹介します。
例:if式
たとえばC言語みたいに、
if (a) {
b
c
} else {
d
}
のようなif式をもつ言語を作りたいとします。文と式が分かれている言語にする場合、Rustで実装するとこんな感じになるでしょうか。
struct Stmt {
...
ExprStmt(Box<Expr>) //いわゆる式文。
}
struct Expr {
IntLiteral(usize),
...
If {
cond_expr: Box<Expr>,
then_clause: Vec<Stmt>,
else_clause: Vec<Stmt>,
}
}
一方、すべてが式の言語にする場合はどうでしょうか。なんとなく
struct Expr {
IntLiteral(usize),
...
If {
cond_expr: Box<Expr>,
then_clause: Vec<Expr>,
else_clause: Vec<Expr>,
}
}
みたいにthenとelseが複数のExprを持つ感じにしたくなりますが、ここに複文(ならぬ、複式?)を導入して
struct Expr {
IntLiteral(usize),
...
Stmts(Vec<Expr>) //連続した式を順に評価する。最後に評価した値をStmts全体の値とする。
If {
cond_expr: Box<Expr>,
then_clause: Box<Expr>, //単一の式、またはStmtsが入る
else_clause: Box<Expr>, //単一の式、またはStmtsが入る
}
}
のようにするとわりと取り回しが良いです(良かったです)。
注意点
上記の場合、空のStmtsの扱いに注意する必要があります。簡単なのは何からの「ゼロ値」を導入し(C言語のnull、LispやRubyのnil、的な)、空のStmtsを作ろうとしたときは自動的にそれを挿入することです。
この場合意味論としては、例えば
if (x) {
print(x)
} else {
}
というif式は
if (x) {
print(x)
} else {
nil
}
と等価になります。