このページではJavaScriptを使用しています。

7.コンパイラ

7-1.はじめに

【Windows版AZ-Prologをお使いの方へ】
「7-2.AZ-Prologコンパイラの概要」で説明していますが、Prologで記述したプログラムの実行モジュールを生成(これをフルコンパイルと呼びます)する場合は、Cコンパイラが必要になります(バイトコードコンパイル(7-2-1参照)のみ利用する場合は不要です)。


Linux版の場合はOS標準のgccを使用しますので特に必要ありませんが、Windows版をお使いの方は、Prologコンパイラを使用する前にCコンパイラをまずインストールします。
「Visual Studio Community」が以下URLから無償で入手できますので、 手順にしたがってインストールしてください。


VS2017のDownLoad:https://www.visualstudio.com/vs/community/

VS2013、2015を既にお使いでライブラリなどをVS2017に更新できないお客様はVS2013用またはVS2015用のAZ-Prologをダウンロードしてください。
インストールする際に「c++によるデスクトップ開発」にチェックを入れてください。

C:¥ProgramData¥Microsoft¥Windows¥Start Menu¥Programs¥Visual Studio 2017¥Visual Studio Tools¥VC から「x86 Native Tools Command Prompt for VS 2017」(32ビット)「x64 Native Tools Command Prompt for VS 2017」(64ビット)を開いてコンパイルすることになるので、インストール後にデスクトップにショートカットを作成しておくと便利です。プロパティの「作業フォルダ」も自分用に変更しておきましょう。


Mac版をお使いの方は、デフォルトではCコンパイラがインストールされていませんので、以下の手順でソフトウェア開発環境を整えます。なお、既にCコンパイラ(gcc,g++)が利用できる場合は下記の作業は必要ありません。

  • AppleサイトよりXcodeをダウンロードしインストールを行う。(GUIベースのインストール)
  • コマンドラインツールのインストール
    ターミナルを開き、以下のコマンドを入力する
    $ xcode-select --install
  • MacPortsのインストール
    3-1. MacPortsサイト(http://www.macports.org)よりPackageをダウンロードする。サイト上で[Mac OS X Package (.pkg) Installer]の該当OSバージョン(v10.9以上)をクリックする。
    3-2. Packageのインストールを行う。ダウンロードしたパッケージ(*.pkg)をダブルクリックしMacPortsインストーラーを起動させ、画面に従い必要な情報を入力し、インストールを実行する。
  • ターミナルを開き、以下のコマンドを入力してソフトウェア及びライブラリ関連の更新を行う。
    $ sudo port selfupdate
    $ sudo port install cmake
    $ sudo port install nkf

7-2.AZ-Prologコンパイラの概要

AZ-Prologコンパイラ(Windows版ではazpc.exe、Linux版またはMac版ではazpc)は、prologで書かれたプログラムを高速で実行したり、実行モジュール(プログラム)を生成したりする目的で使用します。
コンパイラは、インタプリタの一部として組み込まれたシステムではなく、独立したコマンドとして提供されます。
AZ-Prologで提供される各種Prologインタプリタ(標準、CGI用、子プロセス用)は、実はコンパイラによって生成されたものです。
ちなみに、AZ-Prologコンパイラは、Prologで記述されたソースプログラムを自分自身でコンパイルして生成された実行プログラムです。

AZ-Prologコンパイラは、コンパイルオプションの指定で次の2種類のいずれかのコードを出力します。
1) インタープリティブ・バイトコード
2) C言語のソースコード
前者については7-2-1で、後者については7-2-2で、それぞれの概要を説明しています。また、それぞれのコンパイルオプションの処理イメージを表した図を7-2-3で示しています。


7-2-1.インタプリティブバイトコード

インタプリタから直接ロードして実行可能なコードです。
インタプリタに内蔵されているバイトコードエミュレーターが解釈実行します。
バイトコードとは、フルコンパイルイメージのエミュレーションコード(Abstract Machine Code)で、WAM(Warren Abstract Machine)に近いコード体系です。詳細についての説明は省略します。
プログラムをバイトコード化する事で、通常の(「consult」や「restore」により読み込まれた)コードでの実行速度より4倍程度の高速化と領域節約が計れます。
このコンパイルではCコンパイラを必要としません。

7-2-2.C言語のソースコード(フルコンパイル時)

フルコンパイルでは、AZ-PrologコンパイラはC言語のソースコードを出力し、Cコンパイラにより機械語オブジェクトを生成してリンカで結合して実行モジュールを作ります。
これによりインタプリタでの通常コードの実行よりも、10倍前後高速化する事が出来ます。

このフルコンパイルは、主に次の目的で使われます。

  • Prologで記述された述語を組込述語にコンパイル(これを「コンパイル組込述語」と呼びます)し、それを追加した新しいProlog拡張インタプリタを生成する。
  • ユーザが作成したプログラムのスタンドアロンアプリケーション(単独実行プログラム:以下では単に「実行プログラム」と呼んでいます)を生成する。

2.の場合、インタプリタとして使うことはできませんが、「インタプリタコードの読み込み機能」(consult/reconsultはなくても、その省略記法は有効:「7-4.(10)ファイルのインクルード」参照)、「トップレベルの述語呼び出し機能」(7-4.(11)top_level述語の定義」参照)は確保されています。また、組込述語はリンクされませんが、必要な述語は、明示的に宣言(「7-4.(6)bltin宣言」参照)すれば組込むことができます。

1、2のいずれの場合も、述語やプログラムの記述は主にPrologのソースコードですが、所定の形式を踏まえたC言語のソースコードでも記述可能です。Prologのソースコードから生成されたCソースや、最初からC言語で記述されたCソースは、Cコンパイラでコンパイルされ、リンカでAZ-Prologの組込述語ライブラリ・Cコンパイラ標準関数ライブラリ等とリンクされることにより、実行可能なプログラムが生成されます。

言うまでもありませんが、AZ-Prologフルコンパイラが生成したCソースは、テキストエディタで修正・編集することが可能ですし、ユーザが作成したCプログラムとオブジェクトレベルでのリンクも可能です。


7-2-3.AZ-Prologコンパイラの機能フローイメージ
バイトコードコンパイラとインタプリタの機能相関図


AZ-Prologフルコンパイルの処理イメージ

7-3.コンパイル前の諸注意

AZ-Prologコンパイラでは、コンパイル対象のファイルやコンパイラに対する指示をコマンドラインに指定して起動します。これによりエラーがなければ目的のファイルが生成されるわけですが、この時下表のようなファイルも中間ファイルとして生成されます。ファイル名の付け方によっては同名の既存ファイルが破壊される恐れがありますので注意が必要です。
ファイル拡張子「.c」「.obj」はCコンパイラが使用しますし、これら以外にもシステムで使われているもの(「.dll」等))がありますので、特にPrologソースファイル名はそれらと衝突しないように注意してください(実はAZ-Prologには拡張子の制約はありません。でも、Prologソースファイル拡張子は「.pl」とするのが一般的です)。
PrologソースをCソースヘ変換する際、新しいファイル名は拡張子を削除して「.c」を付加したものとなりますので、拡張子のみでソースを区別するようなファイル名の付け方は避けてください。
コンパイルはファイル単位で行われますが、module宣言(7-4.(1)参照)がされている場合はモジュール毎に分割されます。この場合、生成ファイル名は「モジュール名.c」となります。

★コンパイル中に作成される中間ファイル
1.Cソース xxx.pl→xxx.c(モジュール名.c)
2.objectファイル xxx.c→xxx.o(モジュール名.obj)
3.Cコンパイラ起動用 mkazまたはmkaz.cmdバッチファイル
4.リンクファイル
userfile.c

これらの中間ファイルは、全てカレントディレクトリに作成されます。
【注意】

フルコンパイルには、Cコンパイラがインストールされていなければなりません。

7-4.ソースファイルに対する追加記述

インタプリタ上でデバッグの済んだソースプログラムをコンパイルし、新しいPrologインタプリタや実行プログラムを生成する際に、ソースファイルに必要に応じて追加記述をしなければならないものがあります。これらを初めからソースに書いておいてインタプリタでデバッグをしても、まったく支障ありません。

★コマンドで与えるもの
行頭を「:-」で始め、コンパイラに対する宣言や実行時の指示を行います。
(インタプリタでファイルを読み込んだ場合は無視されます。)

(1) module宣言 ファイルのモジュール分割を宣言します。
(2) public宣言 組込述語に登録する述語を宣言します。
(3) publicall宣言 全述語をpublic宣言します。
(4) extern宣言 外部定義述語の参照を宣言します。
(5) mode宣言 述語引数の入出力区分、型宣言をします。
(6) bltin宣言 リンクする組込述語を宣言します。
(7) dynamic 宣言 assert/retractの対象述語を宣言します。
(8) オペレータ宣言 コンパイル時オペレータを宣言します。
(9) 実行時オペレータ宣言 実行時オペレータを宣言します。
(10) 他ファイルのインクルード  実行時のファイルの読み込みを指示します。

拡張インタプリタを生成する際には、1ファイル(宣言がされていれば、1モジュール)に最低1個のpublic宣言がされている必要があります。


★述語の形式で記述するもの
述語名/アリティの述語の定義を与えると言う意味です。
インタプリタで読み込んでも、述語が定義されるだけで、呼び出されはしません。

(11) top_level/0 トップレベル述語の定義を与えます。

単独実行プログラムを作成する時は、起動直後に制御を移される「top_level/0」 の定義をしておきます。定義がないときはAZ-Prolog側で用意されている「top_level」がリンクされます。これはインタプリタとして起動するためのものです。つまり、単独実行プログラム(コンパイラオプション「/i」の指定なし)でありながらtop_level/0を定義しないと、組込述語も使えないPrologインタプリタが起動されることになります。


以下、(1)から(11)まで順に説明していきます。

(1) module宣言
【書 式】
:-module モジュール名. ・・・・・・①
:-module モジュール名/compact. ・・・・・・②
:-module モジュール名/fast. ・・・・・・③

【機 能】

ファイルをモジュールに分割するのに用います。この宣言は新たなモジュールの開始を意味します。次のmodule宣言が現れるか、ファイルの最後に到達すれば、それがこのモジュールの範囲になります。コンパイラはPrologソースファイルをモジュールに分割し、各モジュール名をつけたCソースファイルを生成します。
module宣言の無いファイル、または最初のmodule宣言の前に述語定義が有る場合は、ファイル名がモジュール名として扱われます。
モジュール名はC言語の関数名として妥当なものでなければなりません。(なぜなら、コンパイラはモジュール名をそのまま関数名の一部として使って、初期化関数(モジュールに含まれる組込述語を登録するための関数)を自動的に定義するからです。)

【説 明】
書式① コンパイルの優先指定はデフォルト値(速度/fast、③と同じ)が採用されます。
書式② 生成するコードのサイズ縮小を優先してコンパイルします。
書式③ 生成するコードの実行速度向上を優先してコンパイルします。


生成コードのサイズ縮小/実行速度向上いずれを優先するかは、コンパイル指示コマンド(azpcのコマンドラインの-p以降のオプション)により与えることもできます((「7-5.コンパイラの起動時のオプション」の「Prologコンパイルの形式、モードの指定」参照)。指示コマンドが無い場合はサイズ優先となります。

【記述例】
(ファイル名) myfile.pl
                                    mifile.c
 
:-module my1/fast.
                                   my1.c(速度優先)
 
:-module my2/compact.
                                   my2.c(サイズ優先)

(2) public宣言
【書 式】

:-public 述語名/アリティ.
:-public invisible:述語名/アリティ.

【機 能】

モジュール中に定義が記述されている「述語名/アリティ」の述語を、組込述語として登録することを指示します。


【説 明】

public宣言には次のような目的があります。

public宣言された述語を、他のモジュールからも呼べるようにします。
コンパイルした時、この述語はC言語のpublic関数に変換されます。これにより、他のモジュールでこの述語をextern宣言すれば呼び出せる状態になります。
逆に、public宣言されていない述語はC言語のstatic関数に変換されます。あるモジュールの中だけで呼ばれ、他のモジュールからは呼ばれない述語はpublic宣言しません。それにより、モジュール間の述語名の衝突などを回避することができます。
public宣言された述語を組込述語として登録します。
これにより、インタプリタとして起動した時、トップレベルから呼び出すことが可能になります。登録された述語は自動的にextern宣言されます。


invisible指定を付加した場合は、組込述語としての登録をしません。つまり、①だけが行われることになります。この状態では、インタプリタとして起動した場合、それらの述語は見えません。単独実行プログラムとして動作させる場合は、他のモジュールからもその述語を呼び出すことができます。但し、そのためには呼び出し側のモジュールで同述語をextern宣言する必要があります。
invisible指定なしの通常のpublic宣言では、①に加えて②も行われます。即ち、インタプリタのトップレベルから呼び出すことができます。


【記述例】

:-public my_append/3.
my_append([],L,L).
my_append([A|L],B,[A|BL]):-
    my_append(L,B,LB).


:-extern my_append/3.
reverse([],[]).
reverse([A|B],C):-
    reverse(B,D),
my_append(D,[A],C).
【諸注意】
  • public宣言がされると、その述語はコンパイルリンクする全ファイルから見えますので、同一述語名が複数のファイルでpublic宣言されているとリンク時エラーとなります。
  • 暗黙のpublic宣言:「 top_level/0 」述語の定義もpublic宣言された述語もないソースファイルは、publicall宣言されたものと見なされます。

(3) publicall宣言
【書 式】

:-publicall.


【機 能】

モジュール中に定義されている全ての述語を public 宣言します。
主に、デバッグ時に各々の述語を単体で実行してテストするときなどに使います。
暗黙のpublic宣言:「 top_level/0 」述語の定義もpublic宣言された述語もないソースファイルは、publicall宣言されたものと見なされます。


(4) extern宣言
【書 式】

:-extern 述語/アリティ.
:-extern det:述語/アリティ.
:-extern c:述語/アリティ.


【機 能】

他のモジュールで定義されpublic宣言された述語を、自分のモジュールの中で使うことを宣言します。


【説 明】

コンパイルはモジュール単位に行われます。
同一モジュールに定義されていない述語が呼び出されている場合、それが他のモジュールにある述語なのか、インタプリタコード(実行時にPrologソースをコンサルトする中間言語形式)の述語なのか、コンパイラにはわかりません。extern宣言は、その述語が他モジュールに存在し、コンパイル・リンク可能であることをazpcコンパイラに知らせます。
その場合、述語呼び出しは直接関数呼び出し(C言語レベル)コードに変換されますので、高速になります。
public宣言されている述語であれば、extern宣言をしていなくても、インタプリタコードと同様に呼び出すことはできますが、コンパイル時に組込述語 「call/1」(に相当するC言語の関数)を介した呼び出しコードに変換されますので、直接関数呼び出しより処理効率は落ちます。
extern宣言を行ない、他モジュールでpublic宣言されていなければリンク時にエラーとなります。但し、宣言のみしていて使用していなければ問題はありません。
extern宣言をしていても、自分のモジュール中に同一の述語がある場合は単に無視します。
なお、標準組込述語はすべてextern宣言されています。


「det:」指定を付加すると、決定性述語としてコンパイルされた外部述語であることを宣言し呼び出し、実行が高速化されます。指定しない場合は非決定性述語と見なされ、バックトラック可能な構造の関数に変換されますが、「det:」指定によりこの部分が簡略化されるためです。
「c:」指定は、この述語が実際は直接C言語で書かれたint型の関数であることを示します。C言語で定義された関数がなければ、リンク時にエラーになります。これに関しては、「8-2-3.各関数の定義 (B)テンプレート出力の利用」を参照してください。


(5) mode宣言
【書 式】

:-mode 述語名(引数のモード並び).

引数のモード
入力引数(値をもって呼ばれます)。
出力引数(変数で呼ばれます)。
両用引数。
float 入力引数であり、実数型が必ず渡されます。
integer 入力引数であり、整数型が必ず渡されます。
atom 入力引数であり、アトム型が必ず渡されます。
number 入力引数であり、整数または実数が必ず渡されます。
list 入力引数であり、リスト型が必ず渡されます。
cterm 入力引数であり、複合項が必ず渡されます。

【機 能】

コンパイラの最適化のための指示です。
モード指定と異なった使われ方をした場合、結果は保証されません。
一般に細かく指定することにより高速化されます。
引数の入出力指定と型指定を同時に行うことはできません。後の宣言が優先されます。


【記述例】
 :-mode my_append(+,+,-).
 :-mode safe(list,integer,integer).

(6) bltin宣言
【書 式】

:-bltin 述語名/アリティ.

【機 能】

実行するプログラムに指定の組込述語をリンクする事を明示します。


【説 明】

コンパイル時に/iオプションが付いている場合は、この宣言は不要です。/iが付かない場合でも、ソースコード中で陽に組込述語が呼ばれている場合は、コンパイラが組込述語呼び出しのC言語ソースコードに変換してくれるので、やはりその組込述語のbltin宣言は不要です。
只、ある組込述語の呼び出し形式の項が変数にバインドされ、この変数が組込述語call/1に引数として渡される場合は、コンパイラは組込述語の呼び出しであることが判断できません。そのような場合にこの宣言を用います。


【記述例】
:-bltin read/1.

(7) dynamic宣言
【書 式】

:-dynamic 述語名/アリティ.


【機 能】

述語をコンパイルせず、インタプリタコードのままとします。


【説 明】

「assert」「retract」を前提とした述語の初期値(下の記述例参照)をソースに記述したい場合などに用います。
コンパイルした拡張インタプリタを起動して、「listing/0 」を実行してみると、dynamic宣言した述語だけが表示されます。
暗黙のdynamic宣言:ソースコード解析時に「retract」「clause」など、項として取り扱っている述語は暗黙でシステムがdynamic宣言します。


【記述例】
:-dynamic counter/1.
counter(0).

(8) オペレータ宣言
【書 式】

:-op(強さ,型,アトム).


【機 能】

コンパイル時のオペレータを宣言します。


【説 明】

コンパイルされた実行プログラムでは、このオペレータ宣言は無効です。逆に、インタプリタでコンサルトした場合は、このオペレータ宣言は有効になります。


【記述例】
 :-op(600,fx,#).

(9) 実行時オペレータ宣言
【書 式】

:-run:op(強さ,型,アトム).


【機 能】

実行時のオペレータを宣言します。


【説 明】

この宣言は、コンパイル時に使用するオペレータではなく、コンパイルされた実行プログラムが使用するオペレータを宣言します。


【記述例】
:-run:op(600,fx,#).

(10) ファイルのインクルード
【書 式】

:-[ファイル名].


【機 能】

ファイルの内容を取り込みます。


【説 明】

ファイル名はシングルクォート「'」で囲ったアトムで指定します。
リコンサルト指定(-ファイル名)であっても、コンサルトと同様に扱います。
インクルードされるファイルにmodule宣言が含まれていても、それを無視して現在コンパイル中のモジュールと一体化します。


(11) top_level述語の定義
【書 式】

top_level :- ゴール並び.


【機 能】

コンパイル・リンクされた実行ファイルのトップレベル述語(そのファイルの起動後に直ちに呼び出される述語)を定義します。


【説 明】

コンパイルされたファイルに「 top_level/0 」の定義があると、コンパイラはAZ-Prolog本来のトップレベル述語(インタプリタを起動する)をリンクせずに、この述語と置き換えます。従って、実行プログラムの起動用述語として使います。
「 top_level/0 」の定義は、当然のことながらリンクする全ファイル中で一つだけでないとリンクエラーとなります。
「 top_level/0 」は自動的にpublic宣言されるので、改めてpublic宣言する必要はありません。
「 top_level/0 」が成功または失敗すると、プログラム自体が終了し、OSレベルに戻ります。
実行プログラムが無限ループに入ると、終了できなくなりますので注意してください(インタプリタのようにCTRL-Cでは割り込めません)。以下は、その無限ループに入る例です。


【記述例】
top_level:-repeat,fail.

7-5.コンパイラの起動時のオプション

AZ-Prologコンパイラは、コマンドラインのオプションにより、コンパイルするファイルを指定したり、コンパイラに対する各種指示ができるようになっています。

<例:lisp.plをコンパイルしてlisp (.exe)を生成する場合>
C:¥>azpc  -p lisp.pl  /e lisp

コマンドラインオプションの指定方法は、凡そ以下の通りです。
C:¥>azpc ・・・・(A)・・・・ -p ・・・・(B)・・・・
                                                   
             コンパイラ自身が            コンパイラへの
             使用する領域のサイズ指定    ファイル指定、各種指示 

コマンド azpc と「-p」オプションに挟まれた部分(A)には、コンパイラが実行時に使用するワークエリアのサイズを指定します(省略可能)。また、-pの後に続く行末までの(B)の部分には、コンパイル対象のファイルやコンパイラへの各種指示等を指定します。

以下でA、Bの各部分で指定するオプションについて解説します。

A.コンパイラワークエリア指定
ここで指定するオプションはインタプリタ起動時のワークエリアのサイズ指定と同じです。
通常はデフォルト(指定なし)で十分ですが、大きなPrologプログラム(極端に長いゴール列や引数中の構造体が複雑な場合など)をコンパイルすると、スタック不足、ヒープ不足(7-9.コンパイル時のエラー参照)が生じることがあります。このような時に指定してください。
【書 式】

[-h xx] [-l xx] [-g xx] [-a xx]


xxはセル数を表す数値(キロ単位)。鍵カッコは各オプションが省略可能であることを表します。
各オプションの意味は以下の通りです。

-h ヒープ領域
-l ローカルスタック
-g グローバルスタック
-a アトム領域
ここで指定するオプションはインタプリタ起動時の指定と同じです。詳細はインタプリタの起動時オプションをご覧ください(「3-3-1.ワークエリアのサイズ指定」)。

現在のコンパイラのワークエリアサイズ設定については、azpcを引数なしで実行した時に表示されるヘルプ情報の最後にある以下の情報から知ることができます。

 
== NOW WORK AREA SIZE SETTINGS ===
Atom Area 2000 K-Cells
Heap Area 2048 K-Cells
Local Stack 1024 K-Cells
Global Stack 2048 K-Cells

B.コンパイラへの各種指示

ここで指定するオプションには以下のものがあります。
(1) コンパイルファイル並び
(2) Prologコンパイルの形式、モードの指定
(3) 実行ファイル関係の指定
(4) Cコンパイラへの指示オプション
(5) リンカへの指示オプション
(6) その他コンパイラへの指示

以下、順に説明します。


(1) コンパイルファイル並び

以下のファイル名をスペースで区切って並べます。
・Cソースファイル(拡張子.c)
Cコンパイラでコンパイルされ、リンクされます。
・オブジェクトファイル(Cコンパイル済のファイル)(拡張子.objまたは.o)
単にリンクされます。
・Prologソースファイル(それ以外の任意の拡張子。通常は.pl)
Cソースへの変換を行った上で、Cコンパイル、リンクされます。


(2) Prologコンパイルの形式、モードの指定
/byte Prologソースをインタプリティブバイトコードにコンパイルする。
/bytecode PrologソースをCソースバイトコード(注1)にコンパイルする。
/compact Prologソースをサイズ優先Cソースにコンパイルする(注2)。
/fast Prologソースを実行速度優先Cソースにコンパイルします。
/no_module Prologソース中のmodule宣言を無視させる。
/debug 変換された述語のCソース関数にtraceでステップされるコードを挿入する(注3)。


注1: Cソースバイトコード
Cソースの中にバイトコード(/byteと同様)が埋め込まれまれてコンパイルされます。実行時にはこのバイトコードをバイトコードインタプリタが解釈実行するので、フルコンパイルに比べて遅くなりますが、サイズはよりコンパクトになります。
注2: module宣言での指定の方が優先します。
注3: "[C]Try ....."と表示され、その都度コマンド入力待ちになります。
コンパイルコードからインタプリタコードを呼び出すような処理があり、このインタプリタコードのトレースを行いたい場合にも指定してください。

(3) 実行ファイル関係の指定
/clp_macro ソースファイルにCLPマクロ記述があった場合、これを展開してコンパイルします。
9-3-2.制約論理 組込述語 A(12)決定性述語: macro_consult/1を参照
/curses 画面制御を可能にします。
/dcurses 画面制御を不可能にします(「/i」指定時のコンソールアプリ生成)。
/e ファイル名 生成する実行ファイル名を指定します。デフォルトは「prolog(.exe)」。
/fs_mode0 defaultの素性構造モード(fs_mode=1)で不具合のある場合、素性構造を取り扱わないモードでコンパイルします。
/i 全ての標準組込述語、デバッガを実行プログラムにとりこみます。
/cursesも暗黙で同時指定されます(不要時は「/dcurses」を明示してください)。
拡張インタプリタを生成する場合は、このオプションを指定してください。
/no 生成される実行プログラムの起動時のワークエリア指定を行えないように指定します。
これにより、起動時の引数エリアがすべてパラメータとなります。
起動ディレクトリに「prolog.def」ファイル(「3-3-7.ワークエリアオプション設定ファイル」参照)があれば、これを読込み設定します。「prolog.def」で定義された4個の数値は、「/h /l /g /a」へ割り当てられます。
/noclp コンパイルする述語に制約変数のチェック・動作を含めません。(処理速度が向上します)
/no_exlib 標準で組み込まれるコンパイル組込述語(7-6コンパイル組込述語)の組込をおこないません。
/no_ole OLEオートメーション機能を使わないよう指示します(Windows版のみ)。
/h xx /l xx /g xx
/a xx /s xx
実行ファイルのデフォルトワークエリアの設定。
「heap」「local」「global」「atom」「stack」

※「/s」はマシンスタックサイズ(Kbyte単位)です。デフォルトではlocalスタックと連動したサイズを自動設定します。
※「/s」はWindows版のみ有効です。

(4) Cコンパイラ関連の指示オプション
/cc コンパイラ名 Cコンパイラを指定。
/ccopt 文字列 Cコンパイラに渡すオプションを指定(全ファイルに適用)。
/ccopt_only 文字列 Cソース名 指定Cソースのコンパイル時のみのオプションを指定。

(5) リンカ関連の指示オプション
/lib ライブラリ 基本ライブラリ以外のライブラリ指定。
/linker リンカ名 リンカを指定。
/link_opt 文字列 リンカの出力ファイル指定子を定義。
/link_opt2 文字列 リンカに渡すオプションを指定。
/link_lib ライブラリ 基本ライブラリの代替ライブラリ指定。
/static 静的リンク形式の実行モジュールを生成する場合に指定。
AZ-Prologの静的ライブラリ(Linux版はlibazp.a、Windows版はazp.lib )がリンクされる。

 >azpc -p myprogram.pl /i /e myprolog /static

この形式に拡張機能を組み込む場合は、必要なソースファイルおよび静的ライブラリをコマンドラインに更に指定する(9章拡張機能概要の「9-1-5.拡張機能のスタティックリンク方法」を参照)。prologソース中のdlib_require/1 による動的ライブラリの読み込みはできない。

(6) その他コンパイラへの指示
/lint コンパイル結果を生成せずにプログラムチェックします。
/f ファイル名 {ファイル・パラメータ・指示並び}を記述したファイルを読込む(7-11参照)。
/env ファイル名 Cコンパイル、リンクに先立ち実行されるバッチ等を指定。
Cコンパイラ等の環境設定バッチを用意しこれを指定する。
/log コンパイル過程を「azpc.log」という名前のLogファイルに残します。
/message コンパイル過程のメッセージを出力しない。
/no_mkaz Prologコンパイルのみ。Cコンパイル・リンク用バッチ(mkaz)を生成しない。
/ncc Prologコンパイルとバッチ生成のみ。Cコンパイルリンクをしない。
/NOM 「/no_mkaz」と「/message」をあわせた指示。
#define 文字列=値 文字列を宣言し、値を設定する。文字列は大小文字を区別しない。
#define 文字列 文字列を宣言し、値は空値とする。
#ifdef 文字列 <パラメータ並び> 文字列がそれまでに宣言されていれば、「#else」または「#endif」 が現れるまで <パラメータ並び> が有効。入れ子構造も可。
#else <パラメータ並び> 「#ifdef」 の文字列が宣言されていなければ有効。
#endif 「#ifdef」ブロックを終了する。
$(文字列) 文字列の環境変数または宣言文字列の値で置換。


以上のオプションについては特に並びの順番は問いません。

<例>

C:¥>azpc -p mypro.pl myfile.c myold.obj /e myprolog /i
C:¥>azpc -h 5 -p #define Type1 /f prologmake.txt


7-6.その他諸注意

  • コンパイラに対する生成コードの速度優先/サイズ優先指定は、起動時のオプションより、ソースコードに記述したmodule宣言での指定が優先されます。module宣言そのものを無視するオプション「/no_module」と併用することによって、コンパイルファイル中のモジュール指定、タイプ指定をはずすことができます。Cソース出力(「/fast」「/compact」)は、一般に実行性能は高いのですが、コンパイルできるファイルのサイズがCコンパイラに依存するので、モジュール分割が必要となります。またこの時、モジュール間の呼び出し関係に応じ public宣言とextern宣言が必要となります。
  • コンパイラに渡すファイル名(「*.pl」や 「*.obj」等)についてはいくつでも指示が可能ですが、数が多い場合にはコマンドラインに入力できる文字数を超えてしまうことがあります。この時には「/f」によるファイル指示を行ないます。
  • ワークエリア指定のない場合はデフォルトの値が使われます。スタック等のサイズは、インタプリタ上で組込述語「statistics/0」を使って必要な大きさを割り出します。
  • 「top_level/0」述語と「/i」指示について。
    「 top_level/0 」を定義し、実行プログラムを生成するとき「/i」を指示していないと、必要な組込述語のみをリンクするだけですので実行ファイルが小さくできます。
    拡張Prologインタプリタのトップレベルや、入力値を述語として呼び出す「read(A),call(A)」のように、いかなる組込述語が実行されるかわからないような場合には「/i」を指示しておくべきです。
    トップレベル述語(top_level/0)の定義がなく、「/i」オプションも指定しないと、ファイル中で定義されpublic宣言された組込述語と「halt/0」以外の組込述語は組込まれません。
  • 単独実行プログラムの場合で「d_cursor/2」等のカーソル、スクロール制御を行う場合には、「/curses」オプションを指定してください。
  • ストップキー(CTRL-C)・ブレークキーによる割り込みで実行を中断したときの選択肢は、スタンドアロンプログラムの場合「abort」「continue」と「exit」のみとなります。
    「exit」は処理を中断しOSへ戻ります(「/i」指定の場合「exit」の選択肢はありません)。
    「abort」はエラー255を実行するので、「errorset」で捕捉可能なためユーザーによる制御が可能です。
    「errorset」で捕捉されない場合は「halt」します。
    「continue」は割り込みを取り消します。
【使用例】
C:¥>azpc -p my_append.pl /e prolog /i
「my_append.pl」を組込んだ拡張Prologインタプリタを生成します。
C:¥>azpc -p  lisp.pl  /e azlisp
単独実行プログラム「azlisp」を生成します。
C:¥>azpc -p queen.pl  /byte
インタプリタにロード可能なバイトコードファイル「queen.b」が生成されます。
一度コンパイルしたPrologソースは、「xxx.c」及び「xxx.obj」または、「xxx.b」が生成されていますから、次回からはこれを指定することによってコンパイル時間の短縮がはかれます。

7-7.コンパイルコードとインタプリタコードの動作の違い

コンパイルコード(コンパイルして出来た単独実行プログラム)は、インタプリタ上で動作した場合と異なる動きをすることがあります。

Prologソースコードを書く上での注意点

  • インタプリタ上では、異なる複数のファイルをコンサルトした場合、各ファイルに定義された述語を相互に呼び出すことができますが、コンパイルコードを実行する場合には、モジュール(Cソースでは1ファイルになる)間で相互に明示的なpublic宣言、extern宣言がなされていなければなりません 。
  • 実行中にプログラム自身を操作(追加・削除・組立て・取り出し)する述語では特に動作の違いに注意が必要です。

以下、2について具体的に説明します。


i) 追加、削除、取り出し(assert・retract・abolish)

次のようなプログラムの場合、述語「a/0」が呼ばれると、インタプリタでは「b/0」の3つ目の節がヒープに「assert」されますが、コンパイルコードの場合は「assert」されません。

b:-write(1).
b:-write(2).
a:-b,assert((b:-write(3))),fail. <== これらは全てstatic述語のコンパイルコード

仮にこのプログラムに

:-public b/0.

を追加すると、上記「assert」の場所で“組込述語と同じユーザ述語の「assert」をしようとしている”というエラーになります。
同様に「retract」「abolish」述語で削除しようとした述語が「static」述語であれば失敗し、public宣言されていればエラーとなります。

ii) 組立て(=..)

次のようなプログラムの場合、「=..」(ユニブ)で作った項をコールしようしても失敗します。

a:-A=..[b,X],call(A).
b(1).

この場合は

:-public b/1.

の宣言が必要です。

7-8.インタプリタからのバイトコードコンパイラ起動

下記のようにすると、インタプリタの中からAZ-Prologコンパイラを/byteモードで起動し、コンパイル結果のバイトコードを取り込むことができます。

| ?-compile(ファイル名).↓

Prologのソースファイルをインタプリティブバイトコードに変換し、インタプリタ上にロードします。コンパイラ(azpc)で直接バイトコードコンパイルした場合はバイトコードファイル(拡張子「.b」)が作成されますが、この場合は作成されません。
コンパイラの起動には

  • インタプリタからコンパイラを子タスク(プロセス)として立ち上げるための十分なメモリがあること。
  • コンパイラ(AZPC.EXEまたはazpc)が格納されているディレクトリへのパスが設定されていること。

の2点が必要です。
メモリ不足で立ち上げができない時には、一度OSへ戻って直接AZPCを起動し、バイトコードファイル生成後インタプリタにロードさせなければなりません。

C:¥>azpc -p ファイル名  /byte↓<==  OSから直接AZPCを起動

これ以外に、インタプリタの中からバイトコードコンパイラを起動する方法を次に示します。

| ?-compile_all.↓

ヒープ領域内の全述語を一度中間ファイルへ出力し、ここに含まれる全述語をpublicとしてコンパイルし、インタプリタにロードします。コンパイル結果はメモリ上に展開されますが、この場合もバイトコードファイルは残りません。

既にコンパイルされているバイトコードをロードするには以下のようにします。

| ?-b_load(ファイル名).↓
| ?-b_load(ファイル名並びリスト).↓

ファイルは必ず拡張子「.b」を持つバイトコードファイルでなければなりません。その前提で、拡張子は省略可能です。

<例>

| ?-b_load([azedit,setof]).↓
| ?-b_load(azedit).↓

バイトコードのロードはモジュール(ファイル)単位に行われます。同一名のモジュールが再ロードされたときは、以前に同一モジュール内で定義されていた述語は全てヒープ領域から消去されます。
また、複数モジュールで同じ述語(同一名/アリティ)が定義されている場合、後でロードされたモジュールの述語定義が優先されます。但し、あるpublicな述語(仮にp1)がモジュール内で定義され、かつp1がモジュール内の他の述語(仮にp2)から呼び出されている場合、後で同一述語p1が新しく定義された別モジュールがロードされても、述語p2が呼び出すp1は同じモジュール内の元の定義のままです。コンパイル時にモジュール単位で呼び出し関係が決定してしまっているからです。

<例>

file1.b : reverse/2の定義
                        <==  reverse/2 は my_append/3 を呼び出す。
           my_append/3 の定義
         
file2.b : my_append/3 の別定義
 
| ?-b_load(file1).↓      <==  reverse/2、my_append/3 がロードされる。
| ?-b_load(file2).↓      <==  別の my_append/3 がロードされる。

file1でロードされた「my_append/3」が消去され、file2の「my_append/3」がpiblicになる。
但し「reverse/2」の内部で呼び出される「my_append/3 」は、file1に含まれていたもののままである。
(file1の「my_append/3」は、「reverse/2」に対応する関数内にコードは残っているが、直接呼び出すためのエントリポイントがなくなるため。)

これらの他に、AzEditの中からエディタ上のプログラムをバイトコードコンパイル・ロード出来ます。
詳しくは本マニュアルの「9-11.内蔵エディタ(AzEdit)」を参照してください。

7-9.コンパイル時のエラー

コンパイル実行時にエラーが発生すると、その内容を表示して停止します。 (実際のメッセージは英語です。)


1 コマンドラインエラー(Command Line Error)
コマンドラインの記述に誤りがある。
2 スタック(ヒープ)オーバーフロー
ワークエリアのどれかが不足した→コマンドラインの指定で増やす。
3 シンタクスエラー
ソースファイルにシンタクスエラーがある。このときファイル名、エラー表示節番号(ファイル中の節定義の順位)とその節を表示します。
4 Cコンパイラ・リンカエラー
Cコンパイラ・リンカのマニュアルを参照してください。

7-10.リソースファイル(Windowsのみ)

objディレクトリの中にリソースファイル「prolog.res」が入っています。
これはアイコンのみを含むリソースファイルですが、アプリケーションのコンパイル時に

C:¥>azpc -p ..... /lib  ¥prolog.res

のように指定すれば、作成される実行ファイルのアイコンが「prolog.exe」のアイコンとおなじものになります。

7-11.総括入力ファイルによるAZ-Prolog 各種インタプリタの生成

総括入力ファイルとは、AZ-Prologが提供する各種インタプリタを生成するために、コンパイラazpcのコマンドラインに付加すべき情報(ソースファイル、ライブラリ、その他の指示オプション等)がすべて記述されたファイルです。/fオプションに先行する#defineで宣言された文字列により、情報が取捨選択されるように記述されています。

総括入力ファイル「prolog_exe.txt」は、パッケージの「system/make」に格納されています。
「%」以降は改行までコメントと見做します。


提供される各種インタプリタは、以下の様なコンパイラオプション指定で生成されています。

C:¥>azpc -p #define cgi           /f  prolog_exe.txt  <== ウィンドウアプリケーションインタプリタの生成
C:¥>azpc -p #define win           /f  prolog_exe.txt  <== CGIインタプリタの生成
C:¥>azpc -p                       /f  prolog_exe.txt  <== コンソールアプリケーションインタプリタの生成