第2節では、nakomakeのプログラムソースそのものの解説をします。なでしこの実行ファイル作成を支援するコマンドラインツールnakomakeの使い方や仕様などの詳しいことは、前節「1. 使い方 - nakomake」を参照してください。なお、プログラムのソースコードは、以下から入手することができます:
- Site Untitled - nako倉庫 - nakomake.zip
- プログラム掲示板(公式) - nakomake
第2節では、nakomakeのプログラムソースそのものの解説をします。なでしこの実行ファイル作成を支援するコマンドラインツールnakomakeの使い方や仕様などの詳しいことは、前節「1. 使い方 - nakomake」を参照してください。なお、プログラムのソースコードは、以下から入手することができます:
nakomakeはコマンドラインツールなので、コマンドラインから入力を受け取る必要があります。その内容は、変数「コマンドライン
」で配列として取得することができます。
コマンドライン[0]
にはプログラム自分自身(実行ファイル)のパスが入っています。つまり、スクリプトとして実行(.nakoファイルをダブルクリックorなでしこエディタから実行)した時は、フロントエンドである vnako.exe や cnako.exe のパスが入っています。しかし、実行ファイルにして実行した時は、その実行ファイル自身の名前になります。 nakomake はコマンドラインから呼び出して使うことを想定しているので、後者になります。
コマンドライン[1]
以降には、コマンドラインから実行する時に後ろにつけるオプションが入ります。例えば、次のように nakomake.exe を呼び出したとします:
nakomake.exe test.nako -import "data.nako,image.png" -e > make.nako
このとき、変数「コマンドライン
」の内容は次のようになります:
インデックス | 文字列データ |
---|---|
0 | path\to\nakomake.exe |
1 | test.nako |
2 | -import |
3 | data.nako,image.png |
4 | -e |
基本的に、スペース区切りでデータが入っていることが分かります。文字列を指定するダブルクォーテーション「"」や、標準出力の内容をファイル出力する「> make.nako」など、コマンドプロンプト側がカバーする部分は変数「コマンドライン
」の中に表れていないことに注意してください。
以上を踏まえた上で、コマンドラインのオプション設定を受け取るためのプログラムを考えてみましょう。まず、コマンドラインから受け取る必要のあるデータは次の通り:
入力ファイルや引数付きオプションなどの細かい場合分けを上手くやるにはただの反復構文では難しそうです。そこで、コマンドライン配列をスタック[*1]にして扱います。
STACKとは配列=コマンドライン POP() ※コマンドライン[0]はプログラム自身のパスなので不要 ●POP() STACKの0を配列切り取り ●PUSH(E) STACKの0にEを配列挿入 ●TOP() STACK[0]を戻す
そして、STACK
が空でない間コマンドラインのデータを読み込み続けるループを作り、その中で条件分岐します。
TOP()が空でない 間 対象=POP() もし対象が`file`オプションならば POP()にターゲット設定 違えば、もし対象が`type`オプションならば POP()にタイプ設定 違えば、もし対象が`plug-ins`オプションならば POP()にプラグイン設定 違えば、もし対象が`import`オプションならば POP()にインポート設定 違えば、もし対象が`runtime`オプションならば POP()にランタイム設定 違えば、もし対象が`output`オプションならば POP()にアウトプット設定 違えば、もし対象が`encrypt`オプションならば 暗号化処理は必要 違えば、もし対象が`noexe`オプションならば 実行ファイル作成処理は不要 違えば、もし対象が`deltemp`オプションならば 一時ファイル削除処理は必要 違えば、もし対象がヘルプオプションならば マニュアル表示 終わる 違えば 対象にターゲット設定
読みこんだデータがどのオプションに一致するか判定し、引数付きオプションの場合はデータを POP()
で更に一つ取りだして設定処理を行います。引数なしオプションなら何も POP()
せずに必要な設定フラグを書き換えています。
ここで、文字列が「-option」「-o」「-Option」などのオプション形式になっているか判定するユーザ定義命令「オプション」は、次のようになっています:
●オプション({文字列}ARGが{文字列}OPT) ARG=ARGを小文字変換 OPT=`-`&(OPTを小文字変換) もしARGがOPTならば はいを戻す 違えば、もしARGが(OPTの2文字左部分)ならば はいを戻す 違えば いいえを戻す
意外と知られていませんが、引数を助詞なしで定義すればこのようにリテラルに続けて命令を書くことができます。
なでしこの実行ファイルは、フロントエンドとソースコードの梱包方式を取っています。梱包されるファイルは以下の通り:
但し、デラックス版でない普通のフリー版なでしこでは plug-ins を梱包することはできません。
なでしこの実行ファイルを作成するには、上記の plug-ins 以外のファイルをひとまとめにしたパックファイルを作ることになります。なでしこには、そのためのパックファイル関連の命令が用意されています:
「パックファイル作成」命令は、"AをBにパックファイル作成"と使います。Aは、「{梱包する元ファイル}={梱包名}={暗号化するなら1しないなら0}」という形式の文字列で指定します。複数梱包するなら改行して続けます(あるいは配列)。Bには作成先のパックファイルを指定します。
梱包で最も重要な決まりごとが、プログラム本体の
「{RUNTIME}lib\vnako.nako=vnako.nako=0」をパックリストに配列追加
nakomake では、処理内容をそのまま「なでしこ」のプログラム形式で標準出力しています。これによって、出力結果を".nako"ファイルとして保存すれば、同じ実行ファイル化の作業を行いたい時、そのファイルを実行するだけで済みます。
では、ログ(記録)を出力したりするにはどうすればいいでしょうか?命令を実行する時に逐一その内容を表示するようにプログラムを組む?いいえ、そんな必要はありません。命令を上書きすればいいのです[*2]。具体的には、次のようにします。
●フォルダ作成(Sに|Sへ|Sの) 「『{S}』へフォルダ作成。」と表示 Sへシステム:フォルダ作成
このように、「なでしこ」の命令は、柔軟にユーザ定義命令で上書きできるようになっています。「しかし上書きしたら元の命令が使えなくなるじゃないか!」と思うかもしれませんが、そんなことはありません。なでしこにはきちんと名前空間(ネームスペース)の仕組みがあるのです。
上のプログラムを見てみると、新しい"フォルダ作成"命令の中で、"システム:フォルダ作成"という命令を実行しています。この"システム:"というのが名前空間の指定です。
なでしこで最初から使える命令は、全て"システム"という名前空間に属しています。一方ユーザ定義命令は、プログラムファイル名の名前空間に属するようになっています。そして名前空間は、前者よりも後者の方が優先順位が高くなっています。
従って、"上書き"と言ってもあくまで別の所に命令ができるだけであって、何も問題ない訳です。
では、なぜ上書きすると良いのでしょうか?
まず1つ目は、同じ名前で命令を利用できるということです。もし"上書き"できなかったとすると、重複しないよう別の名前を作ることになります:
●俺フォルダ作成(Sに|Sへ|Sの) 「『{S}』へフォルダ作成。」と表示 Sへフォルダ作成
ほとんど同じことをしていてオマケ程度の"付加処理"が付くだけなのに、実際使う時にいちいちその別名を思い出したりするのは面倒です。
もう1つの利点はその"付加処理"にあります。"付加処理"が本来の処理に影響しないオマケであるということは、"上書き定義"を完全に取り除いてしまっても元々の命令が呼び出されるだけで、本来の処理に影響しないということです。
さらに、関数の上書き定義を別ファイル化して取り込むようにするなどの工夫をしておけば、プログラム本来の処理を見失わず、ログを取ったりデバッグしたりの切り替えが安全かつ簡単にできるでしょう。
また"付加処理"以外にも、命令の上書きは他にも様々な用途で使えます。例えばある処理を割りこませたり、ファイルの存在判定などエラーチェックを任せると言った使い方もできるでしょう。色々応用してみてください。
PUSH
、配列の"頭"を取り出す(配列から削除してその値を利用する)ことを POP
と言います。今回は簡単のために"頭"を"0番目"にしていますが、通常、配列をスタックのように用いる場合は、高速に処理できるよう配列の末尾(配列要素数-1番目)を"頭"にします。まぁ、そもそも今回のプログラムでは PUSH
は使っていませんが、ね。