- 目次ページに戻る / 前 / 次
- 前回からの差分をまとめて見る
step 60
stmt_rest ではなく stmt を渡す
前々から気にはなっていたけど後回しにしていたものを片付けるシリーズです。
例として gen_call
を見てみます。
def gen_call(fn_arg_names, lvar_names, stmt_rest) fn_name, *fn_args = stmt_rest # ... end # 呼び出し側 def gen_stmt(fn_arg_names, lvar_names, stmt) stmt_head, *stmt_rest = stmt case stmt_head when "call" gen_call(fn_arg_names, lvar_names, stmt_rest) # ...
stmt
(文に対応するデータ)の先頭の要素は文の種類を表しているわけですが、
「これは○○文だな」と判断するためにその先頭要素を使っているのは呼び出し側であって、
呼び出した先では不要です。
不要なものは渡さなくていいんじゃないか、という(ぼんやりした)理由により
このような作りになっていました。
しかし、だんだん不都合の方が気になってきました。
stmt_rest
ってなんやねん問題- 「先頭の要素を除いた残りです」と説明すれば済むので、大して難しい話ではない。ないんだけど、その説明すらも不要にできれば、より簡素にできて良い。
- 移植性
- stmt をそのまま渡す方式の方が他の言語への移植が楽
というわけで、先頭を除いた残りだけ渡すのをやめ、 文のデータ全体をそのまま渡すようにしました。 渡された側では単純に先頭の要素を無視することに。
def gen_call(fn_arg_names, lvar_names, stmt) _, *funcall = stmt # ... end def gen_stmt(fn_arg_names, lvar_names, stmt) case stmt[0] when "call" gen_call(fn_arg_names, lvar_names, stmt) # ...
○○文を処理するメソッドに○○文のデータをそのまま渡すようになりました。やっぱりこの方が単純で分かりやすいように思います。
トップレベルでのVMコメントの廃止
トップレベルで _cmt
を使えるようになっていましたが、そうする必要がなかったので廃止。
==, != をそのまま使う
パース時にそれぞれ eq
, neq
に変換していましたが、
あらためて考えると不要な変換と思えたので
+
, *
と同様に ==
, !=
とするように。
さらにリファクタリングすれば parse_expr_right
をコンパクトにできる状態になっていますが、今回の差分が分かりにくくなるので次回に先送りします。
Token#kind にリネーム
Token#type
から Token#kind
に変更しました。
他の処理系や解説などを見ていると、これは kind という名前にしているものが多いようなんですよね。 いわゆる型と混同しないように type という名前を避けているのか、単に慣習的なものなのか、はたまた英語的に kind の方が適切なのか……みたいな推測をしてますが、はっきりした理由は把握していません。
step 61
気になっていた細かい部分をまとめて修正しました。 リファクタリングのみなのでページを分けずに続けて書きます。
変更後の行数はこんな感じ。
$ LANG=C wc -l vg*.rb 66 vgasm.rb 381 vgcodegen.rb 58 vglexer.rb 380 vgparser.rb 447 vgvm.rb 1332 total
二項演算子まわりの整理
step 60 の変更により変換処理が不要になったので case を削除。
修正前:
def parse_expr expr = _parse_expr_factor() while binary_op?(peek()) op = case peek().value when "+" then "+" when "*" then "*" when "==" then "==" when "!=" then "!=" else raise ParseError, "must not happen" end $pos += 1 expr_r = _parse_expr_factor() expr = [op.to_sym, expr, expr_r] end expr end
修正後:
def parse_expr expr = _parse_expr_factor() while binary_op?(peek()) op = peek().value $pos += 1 expr_r = _parse_expr_factor() expr = [op.to_sym, expr, expr_r] end expr end
すっきりしました。
vgcodegen.rb にリネーム
cg
という名前を見て code generator の略だとすぐ分かる人はいなさそう、このように略している例を見ない、ということで、一般的ですぐ分かる名前に変更。
変数名・メソッド名などのリネーム、コメントの整理
気になっていた箇所をまとめて修正。