6.サンプルプログラムのコンパイルと実行
注
以下での操作例は Windowsの場合を示しています。Linux環境ではパス区切り文字など、Windowsとは多少異なる部分もあります。お手数ですがLinux環境についてはWindowsでの操作から推測してお読み願います。
サンプルプログラムの一括コンパイル
pmind¥sample¥ ディレクトリにサンプルプログラムが多数入っています。
このディレクトリにあるプログラムはソースファイルのみなので、動かすにはまず最初にコンパイルする必要があります。コンパイルは個別に mind を起動しても良いのですが、全部まとめてコンパイルするためのバッチファイルを用意してあります。
(強制コンパイル)
makehere force (Windows)
./makehere.sh force (Linux)
で一括コンパイルできます。個別のソースのコンパイル方法は上記バッチファイルを読んで参考にしてください。
ソースプログラムを修正した場合など、2度目以降にコンパイルするには「force」を付けずに以下のように起動してください。内部的に mmake が使われ、修正のあったプログラムのみが再コンパイルされます。
(修正のあったものを再コンパイル)
makehere (Windows)
./makehere.sh (Linux)
sample¥ ディレクトリにあるサンプルプログラム
■
hello.src
既に第3章「Mindの原理(コンパイラの使い方)」の「
簡単なプログラムを実行してみる」において、このソースプログラムをコンパイルする様子が解説されているので、ここでは省きます。
■
shiftargs.src
プログラミングマニュアルの第11章「上級編」での解説になりますが、「起動引数をシフト」という処理単語の簡単な利用方法となります。以下は起動例です。
c:¥pmind¥sample>shiftargs -p abc def ←Linuxでは ./shiftargs -p abc def
↓起動直後
----------起動引数ここから----------
Arg(1)=[-p]
Arg(2)=[abc]
Arg(3)=[def]
----------起動引数ここまで----------
↓最初の起動引数をシフトの後
----------起動引数ここから----------
Arg(1)=[abc]
Arg(2)=[def]
----------起動引数ここまで----------
↓さらに起動引数をシフトの後
----------起動引数ここから----------
Arg(1)=[def]
----------起動引数ここまで----------
■
mtail.src
プログラミングマニュアルの第9章「ファイル操作」の「逆方向に一行読み出し」の節において、
処理単語「逆方向に一行読み出し」のサンプルプログラムを示していますが、そこで掲示したプログラムのソースです。
UNIX系のtailコマンドに相当しますが、Windowsには標準でこのようなコマンドが無いので役に立つと思います。
実行例も含めてそちらで解説されているので、ここでの説明は省きます。
■
revline.src
指定されたテキストファイルを読み込み、先頭行〜末尾行が逆になったものを別のファイルに出力します。
前の mtail.src と同じく、処理単語「逆方向に一行読み出し」のサンプルプログラムになりますが、一つのファイルを読み込み、ある処理を施した後に、別のファイルとして書き出すプログラムの例にもなっています。
以下は起動例です(sampleディレクトリにある 20lines.txt というテキストファイルをサンプルとして使っています)。
c:¥pmind¥sample>revline 20lines.txt 20lines-reverse.txt
20行を書き込みました。
c:¥pmind¥sample>type 20lines-reverse.txt
20行目
19行目
18行目 プログラム起動箇所はLinuxでは ./revline ・・・ とする
17行目
〜略〜
3行目
2行目
1行目
■
mother.src, child.src
mother という親プログラムが、子プロセス child を起動し、両者が立ち上がった状態で親から子へメッセージを送出、逆に子から親へもメッセージを送出し、それぞれのプログラムは受け取ったメッセージをコンソールにモニタ表示します(プロセス間通信のサンプルの1つです)。
親・子の間のメッセージ伝達にはパイプを使います。処理単語「
子をリダイレクトして子プロセス起動」の利用例としてご覧ください。
以下は実行例です。
c:¥pmind¥sample>mother ←Linuxでは ./mother
[親]:起動しました
[親]:子プロセスの起動終わり。プロセスID=80
[親]:子プロセスの標準出力を吸い上げます
[子](標準エラー出力):標準入力から読み出し=[子に渡すデータ1]
[子](標準エラー出力):標準入力から読み出し=[子に渡すデータ2]
[子](標準エラー出力):標準入力から読み出し=[EOF]
[親]:パイプから読み出し→
[[子](標準出力):親へ返すデータ1]
[親]:パイプから読み出し→
[[子](標準出力):親へ返すデータ2]
[親]:パイプから読み出し→
[EOF]
[親]:子プロセス終了を待つ。
[親]:子プロセスの終了を検出した。
上の実行画面を説明します。
親プロセスと子プロセスが同時に実行されるため、両者のメッセージ出力が混ざって表示されることから、いずれのプログラムからの出力かを識別できるよう、
[親]〜
[子]〜
のように印を付けています。
さらに、子からのメッセージ出力は標準出力に出すものと、標準エラー出力に出すものが混ざっているため、これについても、
[子](標準エラー出力)〜
[子](標準出力)〜
のように目印をつけています。
さて前記の実験画面ですが、親から子に渡されたメッセージを子が表示しています。その後、子も親に対してメッセージを送っており、これを親が受け取ったものも表示しています。つまり相互にメッセージ伝達をおこなっていることになります。
このうち、子が出力するメッセージに注目します。
上の画面例で赤色で示した
(実際にこの色が付くわけてはなくマニュアル上で色を付けています) メッセージは、子の出力が直接コンソールに表示されたものです。親の処理によって子の出力はリダイレクトで親に吸い上げられるのですが、標準エラー出力については親に吸い上げられずにコンソールに直接表示されており、そのことを表しています。
一方、緑色で示したメッセージは、子の出力が親に吸い上げられ、親の手によってコンソールに表示されたものです。
次に、もう1つの起動方法で同じ実験をしてみます。(motherの起動引数に"E"を指定しています)
c:¥pmind¥sample>mother E ←Linuxでは ./mother E
[親]:起動しました
[親]:子プロセスの起動終わり。プロセスID=80
[親]:子プロセスの標準出力と標準エラー出力を吸い上げます
[親]:パイプから読み出し→
[[子](標準エラー出力):標準入力から読み出し=[子に渡すデータ1]]
[親]:パイプから読み出し→
[[子](標準エラー出力):標準入力から読み出し=[子に渡すデータ2]]
[親]:パイプから読み出し→
[[子](標準エラー出力):標準入力から読み出し=[EOF]]
[親]:パイプから読み出し→
[[子](標準出力):親へ返すデータ1]
[親]:パイプから読み出し→
[[子](標準出力):親へ返すデータ2]
[親]:パイプから読み出し→
[EOF]
[親]:子プロセス終了を待つ。
[親]:子プロセスの終了を検出した。
motherの起動時に引数"E"を指定したことで、motherは子を起動する際に大域変数「子のエラー出力をリダイレクト要求」をセットします。これにより、子からの出力は、たとえ標準エラー出力であっても親に吸い上げられるようになります。上の画面例で、子からのメッセージ表示がすべて緑色で表示されているのはそのことを示しています。
注
ここから3個のサンプルプログラムはWindows版にのみ添付されているものです。いずれもWindows APIを駆動することで実現していますが、同APIの使い方についてはプログラミングマニュアルの上級編を参照してください。
■
enumdrive.src (Windows版のみに付属)
Windows機の今の有効ドライブを列挙します。Windows API の利用例の一つです。
以下は起動例です。
c:¥pmind¥sample>enumdrive
結果=C D
■
getdrivetype.src (Windows版のみに付属)
Windows機の指定されたドライブの種別を表示します。Windows API の利用例の一つです。
以下は起動例です。
c:¥pmind¥sample>getdrivetype c:
(関数アドレス=7763EF5D)
c: は固定ドライブです
■
windowsdir.src (Windows版のみに付属)
Windowsのシステムディレクトリがどこにあるか表示します。Windows API の利用例の一つです。
以下は起動例です。
c:¥pmind¥sample>windowsdir
Windowsディレクトリ=C:\Windows
sampleF¥ ディレクトリにあるサンプル(小数演算)
このディレクトリにあるサンプルはすべて小数演算の確認用です。どちらから言うと弊社内での動作確認用なのですが、ソースコードの書き方が参考になるかも知れませんので公開します。
動かすにはまず最初にコンパイルする必要があります。コンパイルは個別に mind を起動しても良いのですが、全部まとめてコンパイルするためのバッチファイルを用意してあります。
(強制コンパイル)
makehere force (Windows)
./makehere.sh force (Linux)
で一括コンパイルできます。個別のソースのコンパイル方法は上記バッチファイルを読んで参考にしてください。
ソースプログラムを修正した場合など、2度目以降にコンパイルするには「force」を付けずに以下のように起動してください。内部的に mmake が使われ、修正のあったプログラムのみが再コンパイルされます。
(修正のあったものを再コンパイル)
makehere (Windows)
./makehere.sh (Linux)
以下で個々のソースファイルの説明をおこないます。
■
小数変数.src
倍精度整数と少数変数定義と、それに対して「入れる」「クリア」「増加」「減少」を適用した場合の値の変化を確認するものです。
c:¥pmind¥sampleF>小数変数 ←Linuxでは ./小数変数
倍精度変数の桁上がり無しの増減
倍精度変数1=00000000|00000000
倍精度変数1(3だけ増加)=00000003|00000000
倍精度変数1(3だけ減少)=00000000|00000000
倍精度変数の上位32bitへの桁上がりの有る増減
倍精度変数1=FFFFFFFF|99999999
倍精度変数1(3だけ増加)=00000002|9999999A
倍精度変数1(3だけ減少)=FFFFFFFF|99999999
倍精度変数1(クリア) =00000000|00000000
小数変数1 =1.20000
小数変数1(1.2を3.4だけ増加) =4.60000
小数変数1(それを3.4だけ減少)=1.20000
小数変数1(クリアした) =0.00000
■
小数定数・小数.src
「○○は 少数定数 <Mind式>。」を使った小数の定数定義および、その右辺の式でのコンパイル時演算を確認するものです。式中で演算を表記していますが、これはあくまでコンパイル時演算であって実行時演算ではありません。
詳細については、プログラミングマニュアルの第6章「数値演算」の「
小数の定数としての表記」を参照してください。
c:¥pmind¥sampleF>小数定数・小数 ←Linuxでは ./小数定数・小数
小数定数: 6を 5で 小数まで割る =1.20000e+000
整数定数: 6.0を 2.0で f割り 整数化=3
整数定数: 3.14を 整数化し 4を 加え=7
小数定数: 3.14と 4を 小数化したものを f加え=7.14000e+000
■
数式表現・小数.src
数式表現の中で、いろいろな方法で小数を表記したときの動作確認です。
c:¥pmind¥sampleF>数式表現・小数 ←Linuxでは ./数式表現・小数
[1.2 + 3.0]=4.20000
[1.2 * 3.0]=3.60000
[1.2 / 3.0]=0.40000
[40.2 % 3.0](小数では%は無いため”捨て”が実行される)=40.20000
[40.2 ÷ 3.0]=13.40000
[40.3 ≦ 40.2]=0
[40.2 ≦ 40.2]=1
[40.1 ≦ 40.2]=1
以下は複雑な数式表現
[ 変数1 := 3.1 + 2.3、変数2 := 10 + 6.3 ] を実行した
変数1(5.4のはず)=5.40000 変数2(16.3のはず)=16.30000
〜略〜
■
数値変換・小数.src
小数値を文字列に変換、あるいはその逆の変換をおこなう機能の動作確認用です。
起動引数から小数値を与えるようになっています。仕様はこのプログラムを引数無しで起動したときのヘルプメッセージをご覧ください。
詳細については、プログラミングマニュアルの第6章「数値演算」の「
文字・文字列を数値に変換(小数向け)」および、「
数値を文字・文字列に変換(小数向け)」を参照してください。
以下は実行例です。
c:¥pmind¥sampleF>数値変換・小数 12.3 20 5 ←Linuxでは ./数値変換・小数 12.3 20 5
<小数表記が有れば数値変換>
値=12.30000 合否=1
<数値変換・小数>
値=12.30000 合否=1
-------- 有効な小数表現なので再度文字列に変換する --------
<文字列変換・小数形式>
値を 全桁数と 小数部桁数で 文字列変換・小数形式=[ 12.30000]
<文字列変換・指数形式>
値を 全桁数と 小数部桁数で 文字列変換・指数形式=[ 1.23000e+001]
■
初等関数.src
三角関数、対数、指数などを演算する機能の確認用です。
詳細については、プログラミングマニュアルの第6章「数値演算」の「
初等関数」を参照してください。
c:¥pmind¥sampleF>初等関数 ←Linuxでは ./初等関数
(度←→ラジアン変換)
30.0の radian=0.52360 そのdegree=30.00000 ← 30.0 のはず
90.0の radian=1.57080 そのdegree=90.00000 ← 90.0 のはず
180.0の radian=3.14159 そのdegree=180.00000 ← 180.0 のはず
360.0の radian=6.28319 そのdegree=360.00000 ← 360.0 のはず
(πの値)
π=3.14159
PI=3.14159
[六分のπ := PI / 6.0] を実行したあとの変数”六分のπ”=0.52360
(acos系)
acos(0.5)=1.04720 そのdegree=60.00000 ← 60.0度 のはず
asin(0.5)=0.52360 そのdegree=30.00000 ← 30.0度 のはず
atan(1.73205080)=1.04720 そのdegree=60.00000 ← 60.0度 のはず
〜略〜
■
小数関数.src
文字通り、小数を扱う関数の定義とその動作確認です。
データ型不一致など、わざと文法エラーを検出させるためのソースもコメントアウトして入れてあります。
c:¥pmind¥sampleF>小数関数 ←Linuxでは ./小数関数
[1 + 小数関数(2.1)](4.1のはず)=4.10000
socketlib¥sample¥ ディレクトリにあるサンプル(ソケット通信)
ソケットライブラリ(socketlib¥ ディレクトリに収容)を使った通信をおこなうサンプルプログラムです。
(ライブラリ自身について)
同ライブラリのソースファイルは socketlib¥ にありますが、そのオブジェクトファイル(ライブラリ)は既に lib¥ ディレクトリに入っているため、コンパイル時のライブラリ指定としては(パス無しで)単に socketlib を指定するだけでリンクできます。
(サンプルプログラムについて)
動かすには、さらに下のディレクトリ(socketlib¥sample¥)に入り、コンパイルする必要があります。コンパイルは個別に mind を起動しても良いのですが、全部まとめてコンパイルするためのバッチファイルを用意してあります。
(強制コンパイル)
makehere force (Windows)
./makehere.sh force (Linux)
で一括コンパイルできます。個別のソースのコンパイル方法は上記バッチファイルを読んで参考にしてください。
ソースプログラムを修正した場合など、2度目以降にコンパイルするには「force」を付けずに以下のように起動してください。内部的に mmake が使われ、修正のあったプログラムのみが再コンパイルされます。
(修正のあったものを再コンパイル)
makehere (Windows)
./makehere.sh (Linux)
以下で個々のソースファイルの説明をおこないます。
■
resolv.src
ドメイン名を元にIPアドレスを引く機能の確認をおこないます。処理単語「ホスト名をIPアドレスに変換」を使っています。
c:¥pmind¥socketlib¥sample>resolv www.nhk.or.jp
ホスト名=www.nhk.or.jpを変換する。
IPアドレス=23.67.174.208
(注:Linuxでは ./resolv ・・・ のように起動してください)
■
server.src , client.src
server.src をサーバに見立て、client.src をそのサーバをアクセスするクライアントに見立てて両プログラム間でソケット通信を行います(Webサーバとブラウザとの関係に似ています)。
このサンプルではデータの送信・受信をおこなうタイミングがあらかじめ分かっている、いわば同期式の通信となります。
これらのプログラムを使うには、まずコマンド プロンプト(ターミナル)を2つ開いてください。1番目がserver用、2番目がclient用とします。それぞれ、usemindを(Linuxでは . usemind)実行しておいてください)
まず server側コマンド プロンプトで以下を実行します。(第1引数がホスト名、第2引数がポート番号です。ポート番号は空いたものであれば何でもいいのですが、ここでは3500を指定してみます)
c:¥pmind¥socketlib¥sample>server localhost 3500
ホスト名 localhost 、3500 番ポートで待つ。
listen完。待ちソケット=-376
acceptします
(注:Linuxでは ./server ・・・ のように起動してください)
注:
Windows版では上のようにソケットハンドルが負の値として表示されますがこれで正常です。Winsock API とファイルハンドルを一元処理するため、Mindではソケットハンドルを負の値として記憶しています。
次に client側コマンド プロンプトで同様の起動をおこないます。(引数仕様はserverと同じ)
clientプログラムは起動と同時にserverに接続しますが、同時にserver側もそれを検出して接続し画面にその旨のメッセージを表示します。下に両画面を表示します。
c:¥pmind¥socketlib¥sample>client localhost 3500
ホスト名 localhost に 3500 番ポートで接続。
接続完。ソケット=-376
サーバに送るデータ(終了はEnterのみ):
client
↓↑
c:¥pmind¥socketlib¥sample>server localhost 3500
ホスト名 localhost 、3500 番ポートで待つ。
listen完。待ちソケット=-376
acceptします
accept完。データソケット=-384 ←接続後に表示
クライアントからのデータを待っています。 ←接続後に表示
server
上記のようになれば、serverとclientが接続されたことになります。
このとき、clientではキーボードからの入力待ちです。serverではclientからのデータを待っている状態です。
client側コンソールで「こんにちは」と入力してみます。そのメッセージは直ちにserverに送られ、server側のコンソールにそのメッセージが表示されるはずです。このときserverのコンソールはキー入力待ちになるので、たとえば「ようこそ」と入力すると、今度はそれがclientに送られてそちらで表示されます。以上のやりとりで画面は下のようになります。
c:¥pmind¥socketlib¥sample>client localhost 3500
ホスト名 localhost に 3500 番ポートで接続。
接続完。ソケット=-376
サーバに送るデータ(終了はEnterのみ):こんにちは ←キー入力
サーバからのデータを待っています。 ←clentの応答
client
↓↑
c:¥pmind¥socketlib¥sample>server localhost 3500
ホスト名 localhost 、3500 番ポートで待つ。
listen完。待ちソケット=-376
acceptします
accept完。データソケット=-384
クライアントからのデータを待っています。
データ=こんにちは ←clientから受信したデータ
返すデータ(終了はEnterのみ):ようこそ ←キー入力する
server
↓↑
c:¥pmind¥socketlib¥sample>client localhost 3500
ホスト名 localhost に 3500 番ポートで接続。
接続完。ソケット=-376
サーバに送るデータ(終了はEnterのみ):こんにちは
サーバからのデータを待っています。
サーバからのデータ=ようこそ ←serverから受信したデータ
サーバに送るデータ(終了はEnterのみ): ←キー入力待ち
client
このやりとりを終わらせたいときは、キー入力待ちになっているほうのコンソールで単にEnterを打鍵してください(接続が切れたことは相手側も自動検知するはずです)。
■
chat-server.src , chat-client.src (チャットプログラム)
先に解説した server.src, client.src と同様に、サーバ側とクライアント側で通信をおこなうものですが、こちらではデータの送信・受信があらかじめ決められた順序ではなく、非同期となる点が特徴です。つまり、お互いが好きな時にキー入力してメッセージを送るスタイルとなり(続けて2度送信しても良い)、一般的にチャットをおこなうプログラムはこのような通信になります。
このプログラムを使うには、まずコマンド プロンプト(ターミナル)を2つ開いてください。1番目がserver用、2番目がclient用とします。それぞれ、 usemind を(Linuxでは . usemind を)実行しておいてください)
まず server側で以下を実行します。(第1引数がホスト名、第2引数がポート番号です。ポート番号は空いたものであれば何でもいいのですが、ここでは3500を指定してみます)
c:¥pmind¥socketlib¥sample>chat-server localhost 3500
ホスト名 localhost 、3500 番ポートで待つ。
listen完。待ちソケット=-376
acceptする
(注:Linuxでは ./chat-server ・・・ のように起動してください)
次に client側コマンド プロンプトで同様の起動をおこないます。(引数仕様はserverと同じ)
clientプログラムは起動と同時にserverに接続しますが、同時にserver側もそれを検出して接続し画面にその旨のメッセージを表示します。下に両画面を表示します。
c:¥pmind¥socketlib¥sample>chat-client localhost 3500
ホスト名 localhost に 3500 番ポートで接続。
接続完。ソケット=-376
キーボードから何か入力すると相手側に送信します(終了はEnterのみ)。
相手側から何か受信するとコンソールに表示します。
client
↓↑
c:¥pmind¥socketlib¥sample>chat-server localhost 3500
ホスト名 localhost 、3500 番ポートで待つ。
listen完。待ちソケット=-360
acceptする
accept完。ソケット=-368 ←これ以下は接続後に表示される
待ちソケットをクローズします
接続完。ソケット=-368
キーボードから何か入力すると相手側に送信します(終了はEnterのみ)。
相手側から何か受信するとコンソールに表示します。
listen完。待ちソケット=-376
acceptします
accept完。データソケット=-384
クライアントからのデータを待っています。
server
上記のようになれば、serverとclientが接続されたことになります。
client側、server側ともに、好きなタイミングでキーボードからメッセージを入力してみてください。即座に相手側に伝達され、ごく簡単ながらチャットのシステムになります。
上記のテストではホスト名にlocalhostを指定したので同一PC内での通信でしたが、ホスト名を変えれば遠隔地とも通信ができます。(ネットワーク越しの通信となるのでファイアーウォールの変更が必要となります)
通信を終わらせたいときは、コンソールから単にEnterを打鍵してください(接続が切れたことは相手側も自動検知して通信終了します)。