コンパイラ作成(25) 関数名のチェック

今回の目標

前回同様、コンパイルエラーの検出。

// 関数の呼び出し
int main()
{
    print(answer());
}

int answer()
{
    //  Answer to the Ultimate Question of Life, the Universe, and Everything
    return 42;
}

int answer()
{
    //  Answer to the Ultimate Question of Life, the Universe, and Everything
    return 42;
}

関数名の重複をチェックしてコンパイルエラーに。

@functions

Hashを使ってデータを管理していくよ。

  # コンストラクタ
  def initialize(fname)
    @fname = fname                        # ソースファイルのファイル名
    @asmfname = fname.sub(/\.myc$/,'.s')  # アセンブリコードのファイル名
    @exefname = fname.sub(/\.myc$/,'')    # 実行ファイル名
#   print "asmfname=",@asmfname,"\n"
    @lex = Lexer.new(@fname)
    @funcname = nil
    @literalcnt = 0
    @literaltable = []
    @needprint = false
    @functions = Hash.new
  end

Parserクラスのinitializeで初期化。

function

functionメソッドで登録していくよ。

  # 関数の構文解析
  def function()
    rettype = nil
    kind, str = @lex.gettoken
    if kind == 	TK::RESERVE && str == "int" then
      rettype = str
      kind, str = @lex.gettoken
    end
    if kind == TK::EOF then return false end
    if kind != TK::ID then perror "expected identifier" end
    @funcname = str
    kind, str = @lex.gettoken
    if kind != TK::SYMBOL || str != "(" then perror end
    kind, str = @lex.gettoken
    if kind != TK::SYMBOL || str != ")" then perror end
    codegen ".global "+@funcname
    codegen @funcname+":"
    kind, str = @lex.gettoken
    if kind != TK::SYMBOL || str != "{" then perror end
    while statement do
    end
    codegen "  ret"
    if @functions[@funcname] != nil then perror "redefinition of \"" + @funcname + "\"" end
    @functions[@funcname] = [rettype,[]]
    @funcname = nil
    return true
  end

関数名をkey、関数の戻り値の型をvalueとしてはHashに登録していってる。既に登録されてたらコンパイルエラーだよ。valueの中の空リストは関数の引数の型をリストにしたものなんだけど、今はまだ引数のある関数には対応できてないんで単に空リストになってる。これで関数の戻り値の型を持てたので、本当はreturn文で型があってるかチェックすべきなんだけどまだやってないよ。int型以外の値を返せないからね。やんなきゃいけないことが多いなあ。

動作チェック

えい!

~/myc$ myc err8.myc
err8.myc:16:15 error: redefinition of "answer"
~/myc$

よしよし。うまくいったよ。型情報の持ち方だけど、何も考えずに安易な方法にしちゃったんで、将来見直しが必要かもなあ。文字列でintって単純に表わしてるけど、これだと複雑な型だと表わせないよなあ。配列、ポインタ、構造体。こういうのサポートするときもう一回良く考えよう。
二回続けて落穂ひろいしたけど、次回は何か新しいことしたいなあ。