彷徨えるフジワラ

年がら年中さまよってます

DTrace で const 指定が無視される件 - その3

さて、const の文法的解釈もわかったことで、早速 const 対応修正を入れて動作確認をしてみるものの、どうにも思ったように動かない。

挙動を細かく調べて見ると、どうやら構文解析の際に、問答無用で const 修飾に伴う dt_decl_attr(DT_DA_CONST) 発行が先行してしまう模様。むぅ〜?どういうことだ?

あーだこーだ諸々確認してやっとわかった。っつーか気が付いた。

構文定義的に "const"(DT_KEY_CONST) は type_qualifier として定義されているのだが:

type_qualifier:
      DT_KEY_CONST { $$ = dt_decl_attr(DT_DA_CONST); }
    | DT_KEY_RESTRICT { $$ = dt_decl_attr(DT_DA_RESTRICT); }
    | DT_KEY_VOLATILE { $$ = dt_decl_attr(DT_DA_VOLATILE); }
    ;

type_qualifier_list:
      type_qualifier
    | type_qualifier_list type_qualifier { $$ = $2; }
    ;

型宣言で "*"(DT_TOK_MUL) が絡む、いわゆるポインタ参照の構文定義は以下のようになっている。

pointer:
      DT_TOK_MUL { $$ = dt_decl_ptr(); }
    | DT_TOK_MUL type_qualifier_list { $$ = dt_decl_ptr(); }
    | DT_TOK_MUL pointer { $$ = dt_decl_ptr(); }
    | DT_TOK_MUL type_qualifier_list pointer { $$ = dt_decl_ptr(); }
    ;

つまり、"* const *" や "** const" という型宣言では:

DT_TOK_MUL("*") トークンが pointer 構文の要素として認識されるよりも、DT_KEY_CONST("const") トークンが type_qualifier 構文の要素として認識される方が先。

解釈の実施は、記述の後方から逆向き。

という要領で処理が進むため、"*" の後に記述されているにも関わらず、"const" に関する処理の方が先に実施されてしまうわけだ。

コンパイラを実装する場合は、普通は構文木を構築するので、木構造の各ノードがどういった順序で作成されようが構わないのだけれど、DTrace では構文要素が確定する都度処理を実施してしまうので、こういった問題が発生してしまうのだな。

上記の構文定義の問題は、DT_TOK_MUL の確定による dt_decl_ptr 実施が、DT_TOK_MUL 以降の要素を修飾する DT_KEY_CONST による type_qualifier の確定に先行されてしまう点にある。既に型情報管理スタックに dt_decl_attr() による const 情報が積まれてしまっているのだ。

っつーことは、型情報管理スタックに割り込みさせられれば何とかなるのかな?という安直な発想で修正をしてみる。

pointer:
      DT_TOK_MUL { $$ = dt_decl_ptr(NULL); }
    | DT_TOK_MUL type_qualifier_list { $$ = dt_decl_ptr($2); }
    | DT_TOK_MUL pointer { $$ = dt_decl_ptr($2); }
    | DT_TOK_MUL type_qualifier_list pointer { $$ = dt_decl_ptr($2); }
    ;

引数無しだった dt_decl_ptr() に引数を追加し、指定された要素まで型情報管理スタックを遡った位置に dt_decl_ptr() で積む予定だった情報を挿入する、という挙動に変えてみた。

さて、実行してみると....おぉ、動く動く!良い感じじゃないですか!

※ 2010/05/31 追記

最終的な修正内容等は、bugID 6954983 として参照可能