変数
変数の指定方法について
BASIC系の言語での変数の指定方法は、「Dim 変数名 As 型」です。これは以下のように実装します。
もし、コマンドライン¥1が空ならば、 「ファイル名を指定してください」と表示。 終わる。 コマンドライン¥1を開く。 それを表示。 バッファは空。 //変数「空」の中身には何も入っていません 予約名は空。 //予約名 予約名スィッチは、オフ。//現在の位置が予約名の中であるか 文字列中は、いいえ。 //現在の位置が文字列の中であるか 最新命令は、空。 //さっき指定されたばかりの命令 アセンブリは空。 //出力するアセンブリ アセンブリデータは空。 //出力するアセンブリデータ 文字列数は0。 //文字列の数 コマンドライン¥1を開く。 それを文字列分解して、反復 //このようにすれば文字列に変数を埋め込めます もし、バッファが「print」ならば、 最新命令はバッファ。 バッファは空。 //まだ他の場所にprintがあっても //「print(なんとか)print」などとなってしまい //検出できなくなる 違えば、もし、バッファが「msgbox」ならば、 最新命令はバッファ。 バッファは空。 違えば、もし、バッファが「Dim 」ならば、 //Dimのあとに半角スペースを置く(解説参照) 最新命令は「Dim」。 バッファは空。 予約名は「{予約名}{対象}」。 予約名スィッチはオン。 違えば、もし、バッファが「As 」ならば、 //Dim、Asだけでなく予約語の前には半角スペース(解説参照) バッファは空。 予約名は「{予約名}{対象}」。 予約名スィッチはオン。 違えば、もし、対象が「,」&&文字列中がいいえならば、 バッファは「{バッファ}{改行}」。 違えば、もし、対象が「 」&&予約名スィッチがオンならば、 //予約名に半角スペースを入れてはいけないので //半角スペースの部分で分岐 予約名スィッチはオフ。 予約名は「{予約名}{改行}」。 バッファは空。 違えば、もし、対象が「"」ならば、 //「"」は一般的な言語では文字列の最初を表す もし、文字列中がはいならば、 文字列中は、いいえ。 違えば、 文字列中は、はい。 違えば、もし、対象が改行ならば、 バッファを表示。 もし、予約名スィッチがオンならば、 予約名スィッチはオフ。 予約名は「{予約名}{改行}」。 バッファは空。 もし、最新命令が「print」ならば、 アセンブリデータに「STR{文字列数} db "{バッファ}", 0」を配列追加。 アセンブリに「invoke OutputString, offset STR{文字列数}」を配列追加。 文字列数は文字列数+1。 バッファは空。 違えば、もし、最新命令が「msgbox」ならば、 アセンブリデータに「STR{文字列数} db "{バッファ¥0}", 0」を
配列追加。 もし、バッファ¥1が空ならば、 アセンブリに「invoke MessageBoxA, 0, offset STR{文字列数},
offset STR{文字列数}, 0」を配列追加。 違えば、 アセンブリデータに「STR{文字列数+1} db "{バッファ¥1}", 0」
を配列追加。 アセンブリに「invoke MessageBoxA, 0, offset STR{文字列数},
offset STR{文字列数+1}, 0」を配列追加。 文字列数は文字列数+1。 //文字列を1つ多く使ったので 文字列数は文字列数+1。 バッファは空。 違えば、もし、最新命令が「Dim」ならば、 アセンブリデータに「{予約名¥0} dd {予約名¥1}」を配列追加。 予約名は空。 違えば、もし、対象が改行でなければ、 バッファは「{バッファ}{対象}」。 もし、予約名スィッチがオンならば、 予約名は「{予約名}{対象}」。 「.586 .model flat, stdcall include iolib.inc includelib iolib.lib include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib .data {アセンブリデータ} .code _start: {アセンブリ} invoke ExitProcess, 0 end _start 」を「{コマンドライン¥1}.asm」に保存。
「Dim」と「As」で変数名と型を区切っています。こういう時は、文字列を直接区切って配列として結果を返す命令区切るを使った方が楽なのですが、あえてトークンで検査します。
上のソースで「解説参照」としているところを解説します。41行目に 違えば、もし、対象が「 」&&予約名スィッチがオンならば、に注目してください。この後で予約名を区切る処理をしていますね。もし、半角スペースなしで、「Dim」の時点で分岐していたら、この後すぐに半角スペースが来てしまい、78行目と79行目の予約名に文字を追加する処理が行われなくなります。
また、32行目と37行目の予約名は「{予約名}{対象}」。が気になった方もいると思います。「予約名に文字を追加する処理はあとでやるのでは?」という疑問がわくかもしれませんが、プログラム全体をよく見てください。17行目の反復から79行目のソース出力部分直前まで、全部1つの分岐のプロックの中に入っているのです。予約名に文字を追加する処理は、このプロックの中の違う場所で行われていますので、先程の一文を入れないと、予約名の最初の一文字が抜けてしまいます。
では、実行ファイルを作ってコンパイルしてみましょう。今回コンパイルするのは、test3.txtを新しく作って以下の内容を打ったものです。
Dim testdim As Long
最後の改行を忘れずに。コンパイルして出来たアセンブリを見てみましょう。コマンドラインに以下のように打ち込みます。

.586 .model flat, stdcall include iolib.inc includelib iolib.lib include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib .data testdim dd Long .code _start: invoke ExitProcess, 0 end _start
無事、成功しました。でも、これをこのままアセンブルしてはいけません。前にも書きましたが、アセンブリでは「変数名 型 内容」のように変数を定義するルールがあります。ddは数値型の変数にも関わらず、文字列Longを""で囲っていないため、このままではアセンブルエラーが発生する事になります。
該当箇所を修正します。
違えば、もし、最新命令が「msgbox」ならば、
アセンブリデータに「STR{文字列数} db "{バッファ¥0}", 0」を
配列追加。
もし、バッファ¥1が空ならば、
アセンブリに「invoke MessageBoxA, 0, offset STR{文字列数},
offset STR{文字列数}, 0」を配列追加。
違えば、
アセンブリデータに「STR{文字列数+1} db "{バッファ¥1}", 0」を
配列追加。
アセンブリに「invoke MessageBoxA, 0, offset STR{文字列数},
offset STR{文字列数+1}, 0」を配列追加。
文字列数は文字列数+1。 //文字列を1つ多く使ったので
文字列数は文字列数+1。
バッファは空。
違えば、もし、最新命令が「Dim」ならば、
もし、予約名¥1が「Long」ならば、
アセンブリデータに「{予約名¥0} dd 0」を配列追加。
予約名は空。
違えば、もし、対象が改行でなければ、
バッファは「{バッファ}{対象}」。
もし、予約名スィッチがオンならば、
予約名は「{予約名}{対象}」。
ついに100行を超えてしまったので前後を省略しています。これを実行するとちゃんとアセンブルできます。
回末後記
今回回想
今回は、メッセージボックスを通して、関数に複数の引数を指定できるようになりました。また、変数の宣言も実装しました。変数については第1回で説明していますので、そちらも参照してください。
次回予告
次回は変数の中身を指定できるようにします。その後、Win32APIの実装を行います。

配列追加。
文字列数は文字列数+1。
バッファは空。
違えば、もし、最新命令が「msgbox」ならば、
アセンブリデータに「STR{文字列数} db