コンパイラ作成(105) 引数が配列の関数

今回の目標

コマンドライン引数を表示できるように対応するよ。

// コマンドライン

int main(int argc, char *argv[])
{
    for(int i = 0; i < argc; i = i + 1)
        printf("argv[%d]=%s\n", i, argv[i]);
}

関数定義の解析さえ頑張れば大丈夫かな。

function

引数の解析を修正。

    # 引数の処理
    kind, str = @lex.gettoken
    loop do
      if kind == TK::SYMBOL && str == ")" then break end
      if kind == TK::TYPE then
        if str == "extern" then perror "invalid 'extern'" end
        type = str
        kind, str = @lex.gettoken
        loop do
          if kind != TK::SYMBOL || str != "*" then break end
          type += str
          kind, str = @lex.gettoken
        end
        if type == "void" \
           && kind == TK::SYMBOL && str == ")" \
           && paratype == []
        then
          break
        end
        var_name = str
        if kind != TK::ID then
          if type == "void" then
            perror "invalid type 'void'"
          else
            perror "wrong parameter name"
          end
        end
        kind, str = @lex.gettoken
        if kind == TK::SYMBOL && str == "[" then
          kind, str = @lex.gettoken
          if kind != TK::SYMBOL || str != "]" then
            perror
          end
          type += "*"
        end
        paratype << type
        print "para "+var_name+"\n" if $opt_d
        size = sizeof type
        @lvarsize += size
        parametersize << size
        if check_var var_name then perror "redefinition parameter \"" + var_name +"\"" end
        if type == "void" then
          perror "invalid type 'void'"
        end
        set_var var_name, [type,@lvarsize]
      else
        perror
      end
      if kind != TK::SYMBOL || str != ")" then
        kind, str = @lex.gettoken
      end
      if kind == TK::SYMBOL && str == "," then
        kind, str = @lex.gettoken
      end
    end

配列だったら*に変換してるよ。これで問題ないはず。

動作テスト
~/myc$ myc q11.myc
~/myc$ ./q11 abc zxc 123
argv[0]=./q11
argv[1]=abc
argv[2]=zxc
argv[3]=123
~/myc$

大丈夫だね。大分配列の実装できてきたかな。次回は何やろうかな。エラー周りのテストかな。問題なければ配列の初期化に進みたいけど、結構難しいかな。