SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

MASMとなでしこによるオリジナルコンパイラの制作

MASMとなでしこによるオリジナルコンパイラの制作 4

メッセージボックス関数の拡張と変数の宣言の実装

変数

変数の指定方法について

 BASIC系の言語での変数の指定方法は、「Dim 変数名 As 型」です。これは以下のように実装します。

build.nako
もし、コマンドライン¥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を新しく作って以下の内容を打ったものです。

build\test3.txt(最後に改行を付加)
Dim testdim As Long

 最後の改行を忘れずに。コンパイルして出来たアセンブリを見てみましょう。コマンドラインに以下のように打ち込みます。

コマンドライン
コマンドライン
typeコマンド(上の画像で1:の)
.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を""で囲っていないため、このままではアセンブルエラーが発生する事になります。

 該当箇所を修正します。

build.nako(一部)
 違えば、もし、最新命令が「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の実装を行います。

次の記事

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
MASMとなでしこによるオリジナルコンパイラの制作連載記事一覧

もっと読む

この記事の著者

KMY(かみぃ)

とあるごく平凡な中学生。兵庫県在住。日本語プログラミング言語「なでしこ」に惹かれ、たくさんのプログラムを作り利用している。なでしこ以外にも、他の言語を心得ており、HTMLがなでしこの次に得意であり、Perlが第3位(かも)。ベクターにも多彩な作品を残している。作文がど苦手。KMYpage

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/996 2008/08/26 14:03

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー