コンパイラ作成(98) 配列の宣言

今回の目標

いきなりだけど配列に手を出してみるよ。

// 配列
int main()
{
    int a[10], b;
}

まずは配列変数の宣言から。

Lexer

gettokenの修正。

      # symbolの切り出し
      elsif m = @line[@idx,@line.length]
                .match(/^(==|!=|<=|>=|=|<|>|\+|\-|\*|\/|\%|&|:|,|;|\(|\)|\{|\}|\[|\])/)  then
        str = m.to_s
        @idx += str.length
        return TK::SYMBOL, str
      end

括弧[]をを追加しただけ。

変数宣言
  # 変数宣言の処理
  def var_decl(kind, str)
    basetype = str
    loop do
      type = basetype
      ary = ""
      ary_size = nil
      kind, str = @lex.gettoken
      loop do
        if kind != TK::SYMBOL || str != "*" then break end
        type += str
        kind, str = @lex.gettoken
      end
      if kind != TK::ID then perror end
      var_name = str
      skind, sstr = @lex.gettoken
      if skind == TK::SYMBOL && sstr == "[" then
        ary += sstr
        skind, sstr = @lex.gettoken
        if skind != TK::NUMBER then perror end
        ary += sstr
        ary_size = sstr.to_i
        skind, sstr = @lex.gettoken
        if skind != TK::SYMBOL || sstr != "]" then perror end
        ary += sstr
        skind, sstr = @lex.gettoken
      end
      print "var #{var_name}:#{type}#{ary}\n" if $opt_d
      if ary_size then
        @lvarsize += (sizeof(type) * ary_size)
      else
        @lvarsize += sizeof(type)
      end
      if check_var str then
        perror "redefinition variable \"" + var_name +"\""
      end
      if type == "void" then
        perror "invalid type 'void'"
      end
      set_var var_name, [type+ary,@lvarsize]
      if skind == TK::SYMBOL && sstr == "=" then
        kind, str = expr2 kind, str, skind, sstr;
      else
        kind, str = skind, sstr;
      end
      if kind != TK::SYMBOL || str != "," then break end
    end
    return kind, str
  end

変数の型をどう表現するか悩んだけどint[10]と表わすことにしたよ。扱いやすい形式じゃないから将来見直すかも。配列のサイズ情報は別に持った方が良いかもなあ。悩ましいけどとりあえずこれで実装してみるよ。あと配列の初期化については今のとこ考慮してないよ。多次元配列とかもね。まずは一番シンプルなとこから行くよ。

動作テスト
~/myc$ myc -dc q.myc
var a:int[10]
var b:int
{"a"=>["int[10]", 40], "b"=>["int", 44]}
{"main"=>["int", []]}
~/myc$

ちゃんと40byteの領域が確保されてる。大丈夫そうだね。えーと、次はポインターへの代入とかやってみるかな。割と簡単そうだしね。配列への代入や参照は難しそうだもんなあ。頑張ってちょっとずつ実装してこう。