はじめに
標準 Pascal を実行できる環境が失われつつあるので、Pascal-P5 の実行環境を作ったりしていました。
Pascal-P5 は Scott A. Moore 氏による標準 Pascal 水準 0 に対応した Pascal コンパイラです。Pascal で書かれており、GPC (GNU Pascal) でコンパイルできるようになっています。
P シリーズでは PCOM
が Pascal ソースコードを中間ファイル形式 (疑似アセンブラソース) に変換し、PINT
が 中間ファイルをアセンブルして疑似機械語に変換したもの (メモリ上に生成) を実行しています。
で、Pascal-P5 を調べていると目に付くんですよ、Pascal p5c / p5x が。
Pascal p5c / p5x
Pascal p5c / p5x は Trevor Blight 氏による Pascal コンパイラで、Pascal-P5 がベースになっています。
p5c / p5x は Pascal-P5 と異なり、P コードコンパイラではありません。プログラムとしては PCOM
に相当するものしかなく、疑似アセンブラソースの代わりに gcc のソースコードを吐き出します。これにより、実行形式ファイルを生成する事が可能になっています。
その昔 p2c という C -> Pascalトランスレータがあり、これを使った p2cc というコンパイラがありました。C コンパイラを使って実行形式ファイルを得るという手段は同じなのですが、やっている事が少々異なります。
p5c / p5x はトランスレータではないため、元の Pascal ソースとはかけ離れた C ソースが出力されます。このため、p5c / p5x を Pascal から C 言語への移植に使う用途には向いていません。
Pascal p5c
Pascal p5c は標準 Pascal 水準 1 に対応した Pascal コンパイラです。
C のプリプロセッサが使えるので、インクルードファイルを使う事ができます。
program testReal(output);
#include "sys.inc.pas"
begin
{field width is real digits + sign + '.' + exp width}
writeln('the biggest real is ', REAL_MAX:REAL_DIGITS+7);
end.
Pascal p5x
Pascal p5x は p5c の派生版で、様々な機能拡張が行われています。Pascal p5c のソースコード中にサブフォルダとして含まれています。
拡張された機能は次の通りです。
- 識別子に
_
と$
が利用可能 - 行コメント
//
が利用可能 - 任意の宣言順序
- 定数式のサポート
- コマンドラインパラメータのサポート (
argc()
,argv()
) - 拡張された case 文 (選択肢定数に部分範囲式が利用可能、otherwise 部の追加)
- 2 つ目のパラメータを持つ
succ()
とpred()
1 - 定義済み定数 (
maxreal
,minreal
,epsreal
,maxchar
) 1 - 外部ファイルのアサイン
Assign()
- ファイルに追記するための
Extend()
1 - べき乗演算子
**
- 緩和された定数文字列の代入と比較
- 文字列をダブルクォーテーションで囲むことが可能
- 変数のための external 指令
- 関数及び手続きのための inline 指令
- 16進値を表すためのプレフィクス
$
- ビット操作関数群
- 定義済みの timestamp レコードと
GetTimeStamp()
1 - プログラムを終了させるための
halt()
Pascal p5c / p5x コンパイラの入手
コンパイラはソースコードとして提供されているので、これをビルドする必要があります。
GPC が動作する環境が整っていれば、スクリプト gen
でコンパイラが生成されます。
$ ./gen --notest
うまくビルドできない場合には、環境変数 PATH
と LIBRARY_PATH
の設定を見直してみてください。
--notest
を付けないと、ビルド後にテストが走ります。
p5c の入手
MinGW と WSL2 (ubuntu) でビルドしてみました。
p5c を Windows で動作させるなら、次の 8 ファイルを集めておくと便利です。
ファイル | 説明 |
---|---|
p5c.exe | p5c コンパイラ |
p5c.h | p5c ヘッダファイル |
p5c.c | p5c コンパイラ C 言語ソース |
assert.inc.pas | インクルードファイル: アサーション |
clib.inc.pas | インクルードファイル: 標準 C 関数 |
cstr.inc.pas | インクルードファイル: 標準 C 文字列 |
guide.txt | ドキュメント: p5c ガイド |
README | ドキュメント: p5c Readme |
各ファイルの説明については README
に記載があります。
p5x の入手
こちらも MinGW と WSL2 (ubuntu) でビルドしてみました。
MinGW の方はテストエラーになっていましたが、コンパイラ自体は生成されていました。
p5x を Windows で動作させるなら、次の 10 ファイルを集めておくと便利です。
ファイル | 説明 |
---|---|
p5x.exe | p5x コンパイラ |
p5x.h | p5x ヘッダファイル |
p5x.c | p5x コンパイラ C 言語ソース |
assert.inc.pas | インクルードファイル: アサーション |
clib.inc.pas | インクルードファイル: 標準 C 関数 |
cstr.inc.pas | インクルードファイル: 標準 C 文字列 |
string.inc.pas | インクルードファイル: 文字列ライブラリ |
console.inc.pas | インクルードファイル: Turbo Pascal の crt ユニットに似たライブラリ |
guide.txt | ドキュメント: p5x ガイド |
README | ドキュメント: p5c Readme |
各ファイルの説明については README
に記載があります。
Hello,world.
p5c / p5x で Hello,world.
を出力するプログラムを作ってみます。
Pascal のソースコードはこんな感じです。
program Hello(output);
begin
Writeln('Hello,world.');
end.
p5c の場合
p5c が出力したソースコードは必ず p5c.h
をインクルードするので、gcc の include フォルダにコピーしておくと便利です。
コンパイルは p5c <Pascalソースファイル> <Cソースファイル>
です。
C:\WORK\P5C>p5c hello.pas hello.c
P5c Pascal compiler vs. 1.2
1 program Hello(output);
2 begin
3 Writeln('Hello,world.');
4 end.
Errors in program: 0
Warnings in program: 0
hello.c
が出力されました。トランスレータが吐いたソースではない事が解ります。
/*
* c file Generated by P5c Pascal compiler v 1.2
*/
#define MEMDEBUG
#include <p5c.h>
#if __P5C_H__ - 0 != 100
#error "compiler incompatible with p5c.h"
#endif
struct _PcleanupInf *_Phead=NULL;
static void _Pclose_file(text *const $fp) {
if($fp->f != NULL) {
if($fp->name!=NULL && $fp->flags==-2) putc('\n', $fp->f);
fclose($fp->f);
}
} // _Pclose_file()
static text output_1 = { .name="output", .flags=-1 };
static void _Pexit(void) {
if(output_1.flags==-2) putc('\n', output_1.f);
while(_Phead!=NULL){
_Phead->cuFunc();_Phead=_Phead->link;};
} //_Pexit()
int main( int argc, char* argv[] ) {
output_1.f = stdout;
#if defined(__WIN32__)
setvbuf(stdout, NULL, _IONBF, 0);
#endif
atexit(_Pexit);
({
text *const $fp = &output_1;
/* const string, len is 12 */
fprintf( $fp->f, "%s", "Hello,world." );
$fp->flags = -2;
fprintf( $fp->f, "\n");
$fp->flags = -1;
});
_Preport_mem(_Proot);
exit(EXIT_SUCCESS);
} /* main() */
hello.c
を gcc でコンパイルして hello.exe
を生成し、それを実行してみます。
C:\WORK\P5C>gcc -o hello hello.c -lm
C:\WORK\P5C>hello.exe
Hello,world.
Linux 等の場合には gcc でのコンパイルまで行う pc
スクリプトと、生成された実行形式ファイルの実行まで行う r
スクリプトが利用可能です。
p5x の場合
p5x も p5c の時同様です。ヘッダファイル (p5x.h
) をコピーしておくのを忘れないようにしてください。
ん?
p5c / p5x 共に、コンパイラのソースコードは pcom.pas
です。もちろん内容はそれぞれで異なりますが、これをコンパイルして PCOM(.EXE)
が得られます。これが p5c / p5x コンパイラですね。
その証拠にビルドしたフォルダにある PCOM(.EXE)
を実行すると p5c / p5x コンパイラと表示されます。
では、P5C(.EXE)
や P5X(.EXE)
は PCOM(.EXE)
をリネームしたものなのでしょうか?実はそうではありません。
ビルドスクリプトは pcom.pas
を GPC でコンパイルし、PCOM(.EXE) (p5c / p5x)
を得た後、この PCOM(.EXE) (p5c / p5x)
で pcom.pas
を再度コンパイルし、p5c.c
/ p5x.c
を得て、それを gcc でコンパイルして P5C(.EXE)
/ P5X(.EXE)
を生成しています。
ビルドフォルダには p5c.c
/ p5x.c
が残っていますので、p5c / p5x コンパイラを得るには gcc だけがあればいい事になります。
この用途のための p5c-good.c
がビルドフォルダにあるのですが、p5x フォルダの p5c-good.c
は p5x ではなく p5c コンパイラの C ソースファイルです。p5x.c
を得るには、GPC によるビルドを一度行う必要があります。
つまりは gcc 環境があれば p5c / p5x コンパイラが得られるのか?
「はい、そうです!」...ってだけでは面白くないので 『Embarcadero Dev-C++』 で試してみました。
環境に p5c.h
をコピーするのが面倒だったので、ソースコードを改変してコンパイルしてみました。
/*
* c file Generated by P5c Pascal compiler v 1.2
*/
- #include <p5c.h>
+ #include "p5c.h"
#if __P5C_H__ - 0 != 100
#error "compiler incompatible with p5c.h"
#endif
普通に p5c コンパイラが得られました。64bit gcc コンパイラでコンパイルしたので、この Pascal コンパイラも 64bit コンパイラです。
p5x コンパイラもビルドできました。
p5x コンパイラが得られました。
おわりに
これで GPC が使えなくなったとしても標準 Pascal を試す事ができそうです。
ヨカッタ、ヨカッタ。