こんにちは、高木です。
以前、「PHPで関数の宣言を生成する」で、PHPを使ってC言語の関数宣言を自動生成する話題を取り上げました。今回はその続編で、もう少し細かいところまで踏み込んでみることにします。
「PHPで関数の宣言を生成する」(以下、前回と呼ぶことにします)では、本当にごく簡単な例を紹介しました。C言語だけのことを考えるならそれでもかなりいい線までいくでしょう。ところが、C++では関数テンプレートにすることもあり、あれだけではパラメータが足りません。また、できることなら関数ヘッダも自動生成してしまいたいところです。
まず、関数の情報を表す配列を拡張して、もっと多くの情報を格納できるようにします。前回は関数名は別に与えていましたが、今回は関数名も配列に格納することにします。
今回は、標準C++ライブラリのall_of関数を例として考えてみることにしましょう。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php $all_of_info = [ 'name' => 'all_off', 'specifier' => 'constexpr', 'template' => [ 'InputIterator' => [ 'class', '反復子の型' ], 'Predicate' => [ 'class', '述語の型' ], ], 'type' => [ [ 'first' => [ 'InputIterator', '先頭要素を指す反復子' ], 'last' => [ 'InputIterator', '末尾要素の次を指す反復子' ], 'pred' => [ 'Predicate', '述語' ], ], [ 'bool', '条件を満たす場合はtrue、それ以外はfalse' ], ], ]; |
前回の配列は、今回でいう’type’キーの要素だけでした。その部分も、仮引数や返却値のコメントを格納できるように拡張しています。コメントについては今回は扱いませんが、データ構造としては今後この形をとっていくことにします。
‘type’キー以外にもいくつかのキーを持つ要素が追加になっています。’name’キーは文字通り関数名です。’specifier’キーは記憶クラス指定子や関数指定子などを指定するもので、今回は’constexpr’にしています。’template’キーは文字通りテンプレートにするために必要な情報です。
こうした配列を受け取って関数宣言を生成する関数は次のようになります。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
function make_function_declaration(array $info): string { $name = $info['name']; $specifier = $info['specifier']; $type = $info['type']; // 返却値型の生成 if (count($type) > 1) $return_type = $type[1][0]; else $return_type = 'void'; // 仮引数並びの生成 $parameters = []; foreach ($type[0] as $key => $value) { if (is_array($value[0])) $paremeters[] = "{$value[0][0]} {$key}[{$value[0][1]}]"; else $parameters[] = "{$value[0]} $key"; } if (count($parameters) === 0) $parameter_list = 'void'; else $parameter_list = implode(', ', $parameters); $r = ''; // テンプレートの生成 if (array_key_exists('template', $info)) { $r .= 'template <'; $tparam = []; foreach ($info['template'] as $key => $value) $tparam[] = "{$value[0]} {$key}"; $r .= implode(', ', $tparam) . '>' . PHP_EOL; } // 指定子 if (array_key_exists('specifier', $info)) { $r .= $info['specifier'] . ' '; } return $r . "$return_type $name($parameter_list)"; } ?> |
前回の関数と区別するために、今回は関数名をmake_function_declarationとしました。見通しをよくするためにエラーチェックを省略していることをご了承ください。基本的には前回のmake_signature関数と同じですが、比べてみれば拡張されているところがわかるはずです。
なお、今回はコメントの情報は使用していません。コメントの生成は別の関数で行った方がいいからです。コメントの生成については別の機会に話題にしたいと思います。