オリジナルコマンド実装
サンプルプログラムにコマンド(命令語)を追加してみます。
analyzer.vcproj をビルドする環境が必要です。プロジェクトは
VisualStudio用 なのでVisualStudioフリー版をお奨めします。
解析ルーチンにコマンド実装
編集するのは下のファイルです。
sample/script/mlc.ini
そのファイルの一番最後、
ここに一行加えます。
そこでどんなコマンドを追加するかですが PRINT があるので
値を入力できるようにしてみたいと思います。
INPUT というコマンドを追加します。
PRINT の見よう見まねで追加しました。
連番っぽいので
0x0011 の箇所だけ 0x0012
に書き換えておきます。
ここでは細かい理屈は抜きにしてどんどん進めていきます。
sample/sample/tool/compiler.exe
を起動します。
これがスクリプトコンパイラ「猫の手」の実行ファイルです。
前章でもバッチファイルからコマンドラインで起動していたのがこれです。
メニューから「書式ファイルコンバート」を選択
「プロトタイプ宣言ソース出力」ボタンを押します。
押すとOKのダイアログが出るので「OK」ボタンで閉じます。
この動作はコンパイルと同様コマンドラインからも行うことが出来ます。
sample/script/vaiss.cpp を開いてみます。
末尾に先ほど追加した名前と同じ関数が追加されています。
これに必要な修正を加えていきます。
数値の入力と言えばscanf です。
このように修正しました。
scanf, printf
の前後にあるのはアプリケーションからスクリプトで指定した変数にアクセスするためのお決まりです。
専用の関数が用意されているのでそれを呼ぶだけです。
詳細は後にまとめて解説するのでここでは流します。
analyzer.vcproj
をビルドします。
これだけでビルドを通るはずです
通らない場合はまず修正前の状態でビルドを通るかを確認してください。
サンプルには料理番組のように既に上記の修正でビルドした解析プログラムが sample2 フォルダに用意してあります。
sample2/sample/exec02.bat で確認できます。スクリプト実行
そしてアプリケーションを修正しただけでは何も変わりません。
前章のスクリプト sample01.mlc に手を加えてみます。
固定値だった変数a
を入力できるようにしました。
これだけではつまらないのでもう少し変えてみます。
jmp 命令を使って何度も入力できるようにしました。
BASICやC言語で言う
goto と同じものです。
最後の行で入力されたものが 0 でなければ loop というラベルに戻るようにしています。
実行テストするには上記の修正を加えたソースが必要ですが、ここでも既にビルド、スクリプトコンパイルした
analyzer02.exe
と sample02.bin が用意されています。
exec02.bat で実行することが出来ます。
このバッチにはコンパイルする工程が入っていませんので自分で修正してテストする際には新たにバッチを作成してください。
入力した値が 5 の時は 50。4 の時は 4。 3 の時も 3。
0 を入力するとループを抜けて終了しました。
引数取得
先ほどすっ飛ばした引数(パラメータ)についての解説です。
引数の種類や変数に対してどのようにアクセスしているのかについては後ろの章
で解説しています。
ここでは単純なコマンド追加に必要な事のみ解説します。
コマンドには多くの場合、引数が指定できます。
引数を使うために必要な事柄は
このコマンドにはどんな引数が指定できるのか?を決める事と
解析ルーチン上で指定された引数の値を取得する、または与える
という事です。
このコマンドにはどんな引数が指定できるのか?
は前述の
で指定しています。
PRINT の引数は SCR_COM_PRINT の行の末尾 8, 0 の部分です。
mlc.ini のコメントに
引数 8:レジスタ
とありますね。
0 は終端なのでこの PRINT コマンドは レジスタ(変数)を1つ指定できる、という事です。
解析ルーチン上で指定された引数の値を取得する
には
scr_com_print()
関数を#define SCR_COM_PRINT 0x0011 // 0 8,8,0
だと2つ指定できます。
取得する時は
int val1 =
get_register();
int val2 =
get_register();
と2つ続けます。
PRINT( 123, 456
)
というスクリプトを書くと
val1 には 123 val2 には 456
が格納されます。
そしてまたは与えるの部分は INPUT でやっている事ですね。
mlc.ini の設定は同じです。
解析ルーチンソースです。
CFPC::REGISTER_DATA が変数情報を扱うための構造体です。
regist_register()
で変数を取得します。
この時、
int iVal =
regist_register();
とすると、その時、変数に格納されている値を得る事が出来ます。
他の変数と混ぜる場合、
#define SCR_COM_INPUTADD 0x0012 // 0 8,8,8,0
変数を指定して、真ん中の変数に値を返したい場合は
int val1 =
get_register();
regist_register();
int val2 =
get_register();
のように書きます。
そして必要な処理の後、
set_register( &cReg, iVal
);
とすれば、iVal の値が取得した変数に格納されます。
章締
以上がオリジナルのコマンドを追加して実行するまでの手順です。
スクリプトシステムではアプリケーション側に機能を組み込んで実行ファイルを更新する事と、
スクリプトにコマンドを記述してコンパイルする事が必要です。
これだけでは何か手間が2倍になっただけのようにも感じますが
スクリプトを記述するものが別の人間だったり、あるいはカスタマイズを簡単にする必要があったりする時にも重要になります。
また、通常プログラムではアルゴリズムの制御だけでなく描画やシステムの制御(複数のアルゴリズムが同時に進行する場合)なども考慮しなくてはなりませんが
アルゴリズムの制御部分のみをスクリプトに逃がす事でカスタマイズが簡単になり、生産性が上がります。
このスクリプトシステムというものは比較的高度なものに分類されます。
近年プログラムの敷居が下がり「プログラムを組める」という人は増えてきました。
しかし「スクリプトシステムが使える」という人は稀です。
「スクリプトシステムが使える」という事は「プログラムの構造を理解できる」事ではなく「どこをスクリプト化すれば効率が良いのかを見極められる」という事です。
それは使って慣れるしかありません。
基本機能と、上記で解説した追加した機能を構造的にわけているので
C++の特性を知るのにも適していると思います。
次章からは内部構造にもう少し踏み込んで解説していきます。