コンパイラ作成(33) 多重代入

今回の目標

今日は多重代入だよ。

// 多重代入
int main()
{
    int a, b, c;
    a = b = c = 6 * 7;
    printf("a = %d\n",a);
    printf("b = %d\n",b);
    printf("c = %d\n",c);
}

前回の変数の初期化より難しいのかな。

expr

まずはここから。

  # 式の構文解析
  def expr2(fkind,fstr,skind,sstr)
    el, kind, str = read_el fkind, fstr, skind, sstr
    puts to_str(el) if $opt_d   # デバッグ用
    el = modify_el el, ["*","/"]
    el = modify_el el, ["+","-"]
    el = modify_el el, ["=="]
    el = modify_el el, ["="], :r_to_l
    puts to_str(el) if $opt_d   # デバッグ用
    codegen_el el
    return kind, str
  end

modify_elの呼び出しを一つ追加。代入演算子は右結合なんで、それをパラメータで指定。

modify_el

ここもちょっとだけ修正。

  # elの変形
  #   [2, +, 3, *, 5]
  #   =>[2, +, [3, *, 5]]
  def modify_el(el, opl, assoc = :l_to_r)
    mel = []
    tel = []
    tel << el.shift
    loop do
      if el == [] then break end
      if opl.include? el[0].str then
        tel << el.shift
        tel << el.shift
      else
        if tel.size == 1 then mel << tel[0] else mel << tel end
        tel = []
        mel << el.shift
        tel << el.shift
      end
    end
    if assoc == :r_to_l then tel = rtol_el tel end
    if tel.size == 1 then mel << tel[0] else mel << tel end
    return mel
  end

引数にassocを追加して、それが:r_to_lだったらrtol_elを呼ぶようにしたよ。そういやRubyのシンボルって使うの初めてだな。最近やっとRubyのコーディングに慣れてきたよ。Rubyは動的型付けでArrayになんでもぶち込めるのが便利だよね。mycではelの管理にこれを活用してる。入れ子になったArrayってようはリスト構造だよね。LISPっぽいよね。elの表示を[]から()にしたら、それこそLISPの世界か。mycを他言語に移植するにはこの辺がネックになるのかな。mycを色々拡張してセルフコンパイルなんてこともちょっと夢想してみたけど難しそうだな。そういやHaskellは静的型付けなんだよなあ。

rtol_el

ここが肝心なところ。

  # 右結合時のelの変形
  def rtol_el(el)
    if el.size <= 3 then return el end
    mel = []
    mel << el.shift
    mel << el.shift
    mel << (rtol_el el)
    return mel
  end

再帰で処理してってる。思ってたほど難しくはなかったね。

動作テスト

今回もデバッグ情報込みで行くよ。

~/myc$ myc -d m15.myc
var a
var b
var c
[a, =, b, =, c, =, 6, *, 7]
[[a, =, [b, =, [c, =, [6, *, 7]]]]]
[a]
[a]
[b]
[b]
[c]
[c]
{"a"=>["int", 4], "b"=>["int", 8], "c"=>["int", 12]}
{"main"=>["int", []]}
~/myc$ ./m15
a = 42
b = 42
c = 42
~/myc$

動いたよ。思った通りにelが変形されてる。厳密にいうと[]が一個多いんだけど、多い分には問題ないからって放置してるよ。
ところでさあ、ググってみたら結構コンパイラ作成してる人多いんだけど、みんな再帰下降で構文解析してるみたいだね。mycみたいに変なことしてるのは俺ぐらいかな。
次は何やろうかな。このところ変数関連ばっかりだったから違うことしたいなあ。