はじめに
Delphi を使っていて、何が 標準 Pascal (Standard Pascal) に準拠していて何が準拠していないのかふと知りたくなることがあります。ISO/IEC 7185 の仕様を読めばいいのですが、実際にコードを実行して試したい事がよくあります。
そんな時は ideone で GNU Pascal (gpc) を使ったり、同じく Free Pascal (fpc) で 標準 Pascal 互換モード
にしてみたりするのですが、これらは純粋な標準 Pascal ではないので、場合によっては検証にならなかったりします。
純粋な '標準 Pascal' を求めて
Windows 環境で最も簡単に実行できる標準 Pascal は Scott A. Moore 氏が書いた (改修した) Pascal-P5 だと思われます (P4 まではサブセット)。
PASCAL-P シリーズは P-CODE コンパイラです。PCOM / PINT の 2 つのコマンドがあり、PCOM がソースコードを中間ファイル形式にコンパイルし、それを PINT が実行します。PCOM がコンパイラで PINT がインタプリタという訳です。
より正確に言えば、PCOM が Pascal ソースコードを中間ファイル形式 (疑似アセンブラソース) に変換し、PINT が 中間ファイルをアセンブルして疑似機械語に変換したもの (メモリ上に生成) を実行しています。
なので、理屈的には PINT さえ移植できればどこでもプログラムを実行できます。え? Java っぽい? え? .NET っぽい? え? VB っぽい? そうですか...
■ ISO 標準 Pascal を取り巻く状況
Pascal-P5 は ISO 標準 Pascal の仕様でコンパイルされる前提になっていますが、現在では ISO 標準 Pascal を準備する事自体が難しい状況になっています。ISO 標準 Pascal を試すために ISO 標準 Pascal が必要という「鶏が先か卵が先か」という状況です。
GNU Pascal (gpc) は ISO 標準 Pascal の仕様を含んでいますが、32bit 環境しかないために最近の Linux のパッケージには含まれていないことが多いです。Windows 環境への導入も割と面倒です。
Free Pascal (fpc) はマルチプラットフォームで導入も簡単なのですが、Turbo Pascal 寄りであり、ISO 標準 Pascal 互換に近づけるには {$mode ISO}
を指定してコンパイルするか、コンパイルスイッチ -Miso
を付ける必要があります。
幸い、Pascal-P5 のアーカイブには Windows 用の実行可能ファイル (EXE) が含まれているため、Windows 環境ならば割と簡単に ISO 標準 Pascal を試すことができます 1。
■ Window で Pascal-P5 を動かす
環境設定
PASCAL-P5 のアーカイブを解凍したら、bin フォルダにある PCOM.EXE と PINT.EXE を適当な場所にコピーします。これが PASCAL-P5 の本体です 2。
さて、PCOM は prd
という名前のファイルをソースコードとみなし、コンパイルして prr
という中間形式ファイルを出力します。そして PINT は prd
という名前のファイルを中間形式ファイルとみなして実行します...どちらも入力ファイルが prd
で出力ファイルが prr
です。名前決め打ちなんですよ、面倒ですね。
これを簡単にするバッチファイルもアーカイブの bin フォルダにあるのですが、何故かバッチファイルに cp や mv が使われていて Cygwin や MinGW がないと動作しません。
スクリプト (バッチ) ファイル
面倒なので Cygwin が不要なようにバッチファイルを書きました。以下の 4 つのファイルを pcom.exe / pint.exe と同じ場所に保存してください。
・setpath.bat
カレントディレクトリを環境変数 PATH に設定するバッチファイルです。
@echo off
cls
set PATH=%CD%;%PATH%
echo %PATH%
・compile.bat
ソースファイルをコンパイルして中間形式ファイルを出力するバッチファイルです。
@echo off
cls
if not "%1"=="" goto paramok
echo *** Error: Missing parameter
goto exit
:paramok
if exist "%1.pas" goto fileexists
if exist "%1.dpr" goto fileexists
echo *** Error: Missing %1.pas file
goto exit
:fileexists
if "%2"=="" goto continue
if exist "%2" goto continue
echo *** Error: Missing %2 input file
goto exit
:continue
echo.
echo Compiling and running %1
echo.
if exist "%1.pas" copy %1.pas prd > nul
if exist "%1.dpr" copy %1.dpr prd > nul
pcom
move prr %1.p5 > nul
:stop
if exist prd del prd
:exit
・run.bat
中間形式ファイルを解釈して実行するバッチファイルです。
@echo off
cls
if not "%1"=="" goto paramok
echo *** Error: Missing parameter
goto exit
:paramok
if exist "%1.p5" goto fileexists
echo *** Error: Missing %1.p5 file
goto exit
:fileexists
if not "%2"=="" goto useinputfile
copy %1.p5 prd > nul
goto run
:useinputfile
rem The input file, if it exists, gets put on the end of the intermediate
echo ? >> %1.p5
type %1.p5 %2 > prd
:run
pint
if "%3"=="" goto stop
copy prr %3 > nul
:stop
if exist prd del prd
if exist prr del prr
:exit
・p5.bat
ソースコードファイルをコンパイルして実行するバッチファイルです。
@echo off
cls
if not "%1"=="" goto paramok
echo *** Error: Missing parameter
goto stop
:paramok
if exist "%1.pas" goto fileexists
if exist "%1.dpr" goto fileexists
echo *** Error: Missing %1.pas file
goto stop
:fileexists
if "%2"=="" goto continue
if exist "%2" goto continue
echo *** Error: Missing %2 input file
goto stop
:continue
echo.
echo Compiling and running %1
echo.
if exist "%1.pas" copy %1.pas prd > nul
if exist "%1.dpr" copy %1.dpr prd > nul
pcom
move prr %1.p5 > nul
if not "%2"=="" goto useinputfile
copy %1.p5 prd > nul
goto run
:useinputfile
rem The input file, if it exists, gets put on the end of the intermediate
echo ? >> %1.p5
type %1.p5 %2 > prd
:run
pint
if "%3"=="" goto stop
copy prr %3 > nul
:stop
if exist prd del prd
if exist prr del prr
:exit
PASCAL-P5 の使い方 (Windows)
まず、サンプルプログラムを用意します。アーカイブの sample-programs
フォルダにもサンプルがありますが、今回は FizzBuzz を用意してみました。
program FizzBuzz(output);
var
i: Integer;
begin
for i:=1 to 100 do
begin
if ((i mod 3) + (i mod 5)) = 0 then
Writeln('Fizz Buzz')
else if (i mod 3) = 0 then
Writeln('Fizz')
else if (i mod 5) = 0 then
Writeln('Buzz')
else
Writeln(i);
end;
end.
まず、PASCAL-P5 (とバッチファイル) を格納したフォルダへ移動します。
アドレスバーに CMD
と入力し〔Enter〕キーを押し、
カレントディレクトリでコマンドプロンプトを開きます。
先程の FizzBuzz.pas が違うフォルダにあるのであれば setpath
を実行して PASCAL-P5 にパスを通しておきます。
compile fizzbuzz
としてコンパイルします。ここでの拡張子の入力は不要ですが、ソースファイル名は *.pas である必要があります 3。
正しくコンパイルされると fizzbuzz.p5
ファイルが生成されます。これが中間形式ファイルです。
run fizzbuzz
として実行します。拡張子は不要です。一旦中間形式ファイルができてしまえば、実行の都度コンパイルする必要はありません。
p5 fizzbuzz
とすると、コンパイルと実行を連続して行います。
外部ファイルの扱い方
PASCAL-P5 では、任意の外部ファイルを扱えませんが、2 つの外部テキストファイルを扱う事ができます。但し理屈的に、プログラムで書き出したファイルを同じプログラムで読み込めないという制約があります。
外部ファイル | 説明 |
---|---|
prd | 読み込み専用の外部ファイル |
prr | 書き込み専用の外部ファイル |
PASCAL-P5 のコンパイラである PCOM は、次のような動作になっています。
-
prd
という名前のファイルをソースファイル (Pascal) として扱う。 -
prr
という名前でコンパイルされた中間ファイルを出力する。
PASCAL-P5 のインタプリタである PINT は、次のような動作になっています。
-
prd
という名前のファイルを中間形式ファイルとして扱う。 -
prr
という名前で出力ファイルを出力する。
少しややこしいのですが、コンパイラ (PCOM) もインタプリタ (PINT) も入力ファイル prd
と、出力ファイル prr
という 2 つの外部ファイルしか扱えないという事です。
インタプリタ実行用バッチファイル run.bat
は外部ファイルを扱えるようになっています。
run.bat "プログラム (中間形式ファイル)" <"入力ファイル" <"出力ファイル">>
入力ファイルがある場合、それを中間形式ファイルの後ろにマージします。
・ファイル入力
例えば次のファイルがあったとします。
Hello,world.
BlaisePascal
次のプログラムは入力ファイルを標準出力に出力します。
program ReadFile(output, prd);
var
C: Char;
begin
Reset(prd);
while not Eof(prd) do
begin
while not Eoln(prd) do
begin
Read(prd, C);
Write(C);
end;
Readln(prd);
Writeln;
end;
end.
次のようにすると入力ファイル hello.txt
を受け取ります。
run ReadFile hello.txt
但し、中間ファイルとマージしているため、中間ファイルの内容も表示してしまいます。
バッチファイルは中間ファイルと入力ファイルをマージする時に ?
を挟み込んでいますから、これを目印に中間ファイルを読み飛ばす事は可能です。
program ReadFile(output, prd);
label
1;
var
C: Char;
begin
Reset(prd);
{ Skip Intermediate File }
while not Eof(prd) do
begin
Read(prd, C);
if C = '?' then
begin
Readln(prd);
goto 1;
end;
end;
1:
while not Eof(prd) do
begin
while not Eoln(prd) do
begin
Read(prd, C);
Write(C);
end;
Readln(prd);
Writeln;
end;
end.
今度は入力ファイルだけが処理されています。
・ファイル出力
次のプログラムはテキストファイルを出力します。
program WriteFile(prr);
begin
Rewrite(prr);
Writeln(prr, 'Hello,world.');
Writeln(prr, 'BlaisePascal');
end.
次のようにすると入力ファイルなし (NUL) で、hello.txt
を出力します。
run WriteFile NUL hello.txt
Hello,world.
BlaisePascal
■ pcom と pint をソースコードからビルドする際の注意事項
独自ビルドする場合には、doc
フォルダにある the_p5_compiler.pdf に軽く目を通しておいてください。本記事の手順はドキュメント記載の手順と異なる場合があります。
コンパイルが通り、pcom
を単独で実行した際に、次のような表示になるのであれば、後述するソースコードの修正が必要です。
P5 Pascal compiler vs. 1.3
Pascal-P5 complies with the requirements of level 0 of ISO/IEC 7185.
i
i Pascal intermediate file Generated by P5 Pascal compiler vs. 1.3
i
o a-b-c+d+e-f-g-h-i-j-k-l+m-n-o-p-q-r+s-t-u+v+w-x-y-z-
i i i o...
と続くこのファイルはコンパイラが吐く中間形式ファイルで、これをファイルではなく標準出力 (画面) に出力してしまっています。
最新版 (v1.4) のソースは GPC 以外でコンパイルする事が困難になっています (GPC も一緒に置いてありますが...)。
v1.3 のアーカイブが DL できなくなってしまったようなので、https://ayera.dl.sourceforge.net/project/pascalp5/pascal-p5.tar.gz を https://ht-deko.com/software/pascal-p5.tar.gz にミラーしておきました。
FPC でビルドする/した際の注意点
FPC のバージョンによっては EOF()
の解釈が標準 Pascal と異なるため、2 つの問題が発生します。
- ソースコードのピリオドの後に任意の 1 バイトが必要。
- PINT が
End of file
のエラーを出力する事がある。
前者は次のコードでエラーが出ます。
program Hello(Output);
begin
Writeln('Hello, world.');
end.
Error numbers in listing:
-------------------------
6 Illigal symbol
22 '.' expected
ピリオドの後に任意の一文字があれば問題を回避できますので、ピリオドの後で改行しておくといいでしょう。CP/M ファイルのように、ファイル終端として 0x1A を追加してもいいと思います。
後者は PINT.PAS
を一部書き換える必要があります。2332 行付近にある次のコードを
{ FPC has an error where it indicates EOF 1 byte
before the end of the file. A workaround is to
comment the EOF check out, but note that this
is not permanent, since it compromises error
checking. }
if eof(bfiltable[fn]) then
errori('End of file ');
コメントアウトします。
{ FPC has an error where it indicates EOF 1 byte
before the end of the file. A workaround is to
comment the EOF check out, but note that this
is not permanent, since it compromises error
checking. }
{
if eof(bfiltable[fn]) then
errori('End of file ');
}
Windows 11 の WSL2 (Ubuntu 20.04.3 LTS) にインストールした fpc (3.0.4+dfsg-23 [2019/11/25] for x86_6) では EOF() の問題は発生しませんでした。
現状 (2021/10 現在) では、Windows / macOS / Linux で修正箇所は同一になっていると思います。
■ Windows の場合 (fpc でコンパイルする場合)
Windows 環境で Free Pascal (fpc) を用いてソースコードから Pascal-P5 をビルドする手順です。
Windows 10 1803 以降で作業する事を想定しています。FreePascal (または Lazarus) は適当な場所にインストールしておいてください。
環境設定
アーカイブを DL して解凍しておきます。
C:\> mkdir c:\tmp
C:\> cd C:\tmp
C:\tmp> curl -OL https://ht-deko.com/software/pascal-p5.tar.gz
C:\tmp> tar -zxvf pascal-p5.tar.gz
C:\tmp> cd Pascal-p5\source
C:\tmp\Pascal-p5\source>
コンパイル
アーカイブに最初から入っているバイナリと同じ挙動にするにはソースコードの修正が必要なようです。
note: 当方の環境には Lazarus がインストールされており、それに含まれる fpc をコンパイルに使ったのですが、バージョンは 3.0.4 [2018/5/19]
でした。{$mode ISO}
は効くようですが、外部ファイルとの関連付けに assign() が必要な感じです。
・pcom.pas の修正
任意のエディタで pcom.pas を開いてください。
C:\> micro pcom.pas
Assign の処理を追加します (Line: 5986 付近)。追加場所は (*initialize*)
で検索してください。
write('P5 Pascal compiler vs. ', majorver:1, '.', minorver:1);
if experiment then write('.x');
writeln;
writeln('Pascal-P5 complies with the requirements of level 0 of ISO/IEC 7185.');
writeln;
(*initialize*)
(************)
{$ifdef fpc} // <- 追加
assign(prd, 'prd'); // <- 追加
assign(prr, 'prr'); // <- 追加
{$endif} // <- 追加
initscalars; initsets; inittables;
・pint.pas の修正
任意のエディタで pint.pas を開いてください。
C:\> micro pcom.pas
Assign の処理を追加します (Line: 2432 付近)。追加場所は P5 Pascal interpreter
で検索してください。
write('P5 Pascal interpreter vs. ', majorver:1, '.', minorver:1);
if experiment then write('.x');
writeln;
writeln;
{$ifdef fpc} // <- 追加
assign(prd, 'prd'); // <- 追加
assign(prr, 'prr'); // <- 追加
{$endif} // <- 追加
{ !!! remove this next statement for self compile }
{elide}rewrite(prr);{noelide}
修正が終わったら fpc.exe にパスを通します。
C:\tmp\Pascal-p5\source> set path=<fpc.exe のある場所>;%PATH%
コンパイルします。
C:\tmp\Pascal-p5\source> fpc -Miso -v0 pcom.pas
C:\tmp\Pascal-p5\source> fpc -Miso -v0 pint.pas
pcom.exe と pint.exe が生成されていると思うので、これをコピーして使います。
■ Windows の場合 (gpc でコンパイルする場合)
Windows 環境で GNU Pascal (gpc) を用いてソースコードから Pascal-P5 をビルドする手順です。
MinGW と GPC の環境設定を行います。『Pascal 日和』 さんの記事を参考にしてください。
GPC の環境設定がうまくいかない場合には IDE (Dev-Pascal) 付きの Dev+GNU Pascal 1.9.4.13 + GPC 20070904 + Mingw runtimes + GCC (3.4.5) support files
をインストールしてみてください。
環境設定
アーカイブを DL して解凍しておきます。
C:\> mkdir c:\tmp
C:\> cd C:\tmp
C:\tmp> curl -OL https://ht-deko.com/software/pascal-p5.tar.gz
C:\tmp> tar -zxvf pascal-p5.tar.gz
C:\tmp> cd Pascal-p5
コンパイル
設定が正しく完了していれば、ドキュメントにあるように、
C:\tmp\Pascal-p5> setpath
C:\tmp\Pascal-p5> configure
C:\tmp\Pascal-p5> make
と実行するだけです。実行ファイルは Pascal-p5\bin
フォルダに生成されます。
最新版のソースだと cc.exe
がなくて spew.c
がコンパイルできないかもしれません。spew.exe が不要なら放置で、必要なら MinGW の bin フォルダにある gcc.exe をコピーして cc.exe にリネームしたものを置いておくといいでしょう。
■ macOS の場合 (fpc でコンパイルする場合)
macOS 環境で Free Pascal (fpc) を用いてソースコードから Pascal-P5 をビルドする手順です。
事前に Xcode はインストールされているものとします。当方の環境は macOS High Sierra (10.13.6) / Mac Mini (Mid 2011) です。
環境設定
まずはパッケージャ Homebrew を導入します。
サイトの説明にあるように、ターミナルで以下のスクリプトを実行します。
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Homebrew の導入が終わったら fpc
をインストールします。
$ brew install fpc
PASCAL-P5 のアーカイブを DL して解凍します。
$ cd /tmp
$ curl -OL https://ht-deko.com/software/pascal-p5.tar.gz
$ tar -zxvf pascal-p5.tar.gz
$ cd Pascal-p5/source/
コンパイル
Windows 用バイナリと同じ挙動にするにはソースコードの修正が必要なようです。
note: Homebrew でインストールされた fpc は 3.0.4 [2018/10/2]
でした。{$mode ISO}
は効くようですが、外部ファイルとの関連付けに assign() が必要な感じです。
・pcom.pas の修正
任意のエディタで pcom.pas を開いてください。
$ nano pcom.pas
Assign の処理を追加します (Line: 5986 付近)。追加場所は (*initialize*)
で検索してください。
write('P5 Pascal compiler vs. ', majorver:1, '.', minorver:1);
if experiment then write('.x');
writeln;
writeln('Pascal-P5 complies with the requirements of level 0 of ISO/IEC 7185.');
writeln;
(*initialize*)
(************)
{$ifdef fpc} // <- 追加
assign(prd, 'prd'); // <- 追加
assign(prr, 'prr'); // <- 追加
{$endif} // <- 追加
initscalars; initsets; inittables;
・pint.pas の修正
任意のエディタで pint.pas を開いてください。
$ nano pint.pas
Assign の処理を追加します (Line: 2432 付近)。追加場所は P5 Pascal interpreter
で検索してください。
write('P5 Pascal interpreter vs. ', majorver:1, '.', minorver:1);
if experiment then write('.x');
writeln;
writeln;
{$ifdef fpc} // <- 追加
assign(prd, 'prd'); // <- 追加
assign(prr, 'prr'); // <- 追加
{$endif} // <- 追加
{ !!! remove this next statement for self compile }
{elide}rewrite(prr);{noelide}
・コンパイル
pcom.pas と pint.pas を Free Pascal でコンパイルします。{$mode ISO}
オプションを付けます。
$ fpc -Miso -v0 -Px86_64 pcom.pas
$ fpc -Miso -v0 -Px86_64 pint.pas
エラーが出るようなら、環境変数 MACOSX_DEPLOYMENT_TARGET
にバージョンを明示的に指定してコンパイルします。
$ MACOSX_DEPLOYMENT_TARGET=10.13 fpc -Miso -v0 -Px86_64 pcom.pas
$ MACOSX_DEPLOYMENT_TARGET=10.13 fpc -Miso -v0 -Px86_64 pint.pas
バイナリを ~/p5/ にコピーします 4。
$ mkdir ~/p5
$ cp pcom pint ~/p5/
もうソースコードは不要です。
$ cd /tmp
$ rm -Rf Pascal-P5/
$ rm -f pascal-p5.tar.gz
スクリプトファイル
スクリプトファイルを適当な場所 (~\p5) に作成します。
$ cd ~/p5/
スクリプトファイルは Linux と共通です。compile / run / p5 を作成してください。
・パーミッション変更
スクリプトを実行できるようにパーミッションを変更しておきます。
$ chmod 755 compile run p5
PASCAL-P5 の使い方 (macOS)
Linux の場合と同じです。まずは hello.pas を ~/p5/
に作成します。
$ nano hello.pas
program Hello(Output);
begin
writeln('Hello, world.');
end.
$ ./compile hello
$ ./run hello
または
$ ./p5 hello
でコンパイルして実行します。
あまり macOS に詳しくないのでスクリプトは適当でないかもしれません。
■ macOS の場合 (gpc でコンパイルする場合)
2021/10 現在、macOS (64bit) で動作する GNU Pascal (gpc) は存在しません。
macOS は 10.15 Catalina 以降、32bit アプリケーションが動作しません。
■ Linux の場合 (FPC でコンパイルする場合)
Linux 環境で Free Pascal (fpc) を用いてソースコードから Pascal-P5 をビルドする手順です。
アーカイブの \pascal-p5.tar\Pascal-p5\gpc\linux_X86
に Ubuntu (x86) 用のバイナリが一応含まれてはいるのですが、32bit バイナリなので WSL とかでは動作しません。
環境設定
Free Pascal をインストールしておきます。
$ sudo apt-get install fpc
PASCAL-P5 のアーカイブを解凍します。
$ cd /tmp
$ curl -OL https://ht-deko.com/software/pascal-p5.tar.gz
$ tar -zxvf pascal-p5.tar.gz
$ cd Pascal-p5/source/
コンパイル
Windows 用バイナリと同じ挙動にするにはソースコードの修正が必要かもしれません。
Note: 検証に使った WSL 用の 3.0.0+dfsg-2 [2016/01/28]
では以下の修正が必要でした。少なくともプログラムヘッダに対しては {$mode ISO}
が効かない感じです。
Note: WSL をアップデートして 3.0.4+dfsg-18ubuntu2 [2018/08/29]
で試してみたら、ソースコードの修正は一切不要でした。プログラムヘッダに対して {$mode ISO}
が効くようで、標準 Pascal と同じ解釈になっています。
Note: Windows 11 の WSL2 上の fpc 3.0.4+dfsg-23 [2019/11/25]
で試してみたら、{$mode ISO}
は効くようですが、外部ファイルとの関連付けに assign() が必要な感じです。修正点は macOS の場合と同じです (pcom / pint 共に 1. の修正は不要)。
・pcom.pas の修正
任意のエディタで pcom.pas を開いてください。
$ nano pcom.pas
1. {elide}
の行を削除します (Line: 394)。!!! remove
で検索するとみつかります。この修正は fpc のバージョンによっては不要です。
{ !!! remove this statement for self compile }
{elide}prd,prr: text;{noelide} { output code file } // <- この行を削除
2. Assign の処理を追加します (Line: 5986 付近)。追加場所は (*initialize*)
で検索してください。
write('P5 Pascal compiler vs. ', majorver:1, '.', minorver:1);
if experiment then write('.x');
writeln;
writeln('Pascal-P5 complies with the requirements of level 0 of ISO/IEC 7185.');
writeln;
(*initialize*)
(************)
{$ifdef fpc} // <- 追加
assign(prd, 'prd'); // <- 追加
assign(prr, 'prr'); // <- 追加
{$endif} // <- 追加
initscalars; initsets; inittables;
・pint.pas の修正
任意のエディタで pint.pas を開いてください。
$ nano pint.pas
1. {elide}
の行を削除します (Line: 317)。!!! remove
で検索するとみつかります。この修正は fpc のバージョンによっては不要です。
{ !!! remove this next statement for self compile }
{elide}prd,prr : text;{noelide}(*prd for read only, prr for write only *) // <- この行を削除
2. Assign の処理を追加します (Line: 2432 付近)。追加場所は P5 Pascal interpreter
で検索してください。
write('P5 Pascal interpreter vs. ', majorver:1, '.', minorver:1);
if experiment then write('.x');
writeln;
writeln;
{$ifdef fpc} // <- 追加
assign(prd, 'prd'); // <- 追加
assign(prr, 'prr'); // <- 追加
{$endif} // <- 追加
{ !!! remove this next statement for self compile }
{elide}rewrite(prr);{noelide}
・コンパイル
pcom.pas と pint.pas を Free Pascal でコンパイルします。{$mode ISO}
オプションを付けます。
$ fpc -Miso -v0 pcom.pas
$ fpc -Miso -v0 pint.pas
~/p5/ にバイナリをコピーしておきます 5。
$ mkdir ~/p5
$ cp pcom pint ~/p5/
もうソースコードは不要です。
$ cd /tmp
$ rm -Rf Pascal-P5/
$ rm -f pascal-p5.tar.gz
スクリプトファイル
スクリプトファイルを適当な場所 (~\p5) に作成します。Windows 用と同じ使い方ができるスクリプトファイルです。
$ cd ~/p5/
・compile
ソースファイルをコンパイルして P-CODE 形式ファイルを出力するスクリプトファイルです。
#!/bin/bash
#
# Compile file in batch mode using FPC Pascal.
#
# Runs a compile with the input and output coming from/
# going to files.
#
# Execution:
#
# Compile <file>
#
# <file> is the filename without extention.
#
# The files are:
#
# <file>.pas - The Pascal source file
# <file>.p5 - The intermediate file produced
# <file>.err - The errors output from the compiler
#
# Note that the l+ option must be specified to get a full
# listing in the .err file (or just a lack of l-).
#
if [ -z "$1" ]
then
echo "*** Error: Missing parameter"
exit 1
fi
if [ ! -f $1.pas ]
then
echo "*** Error: Missing $1.pas file"
exit 1
fi
cp $1.pas prd
rm -f $1.p5
./pcom | tee $1.err
rm -f prd
#
# The status of the compile is not returned, so convert a non-zero
# error message to fail status
#
grep -q "Errors in program: 0" $1.err
rc=$?
if [[ $rc != 0 ]] ; then
rm -f prr
exit 1
fi
#
# Move the prr file to <file.p5>
#
rm -f $1.p5 $1.err prd
mv prr $1.p5
・run
P-CODE 形式ファイルを解釈して実行するスクリプトファイルです。
#!/bin/bash
#
# Run a Pascal file in batch mode using FPC Pascal
#
# Runs a Pascal intermediate in batch mode.
#
# Execution:
#
# run <file>
#
# <file> is the filename without extention.
#
# The files are:
#
# <file>.p5 - The intermediate file
# <file>.inp - The input file to the program
#
if [ -z "$1" ]
then
echo "*** Error: Missing parameter"
exit 1
fi
if [ ! -f $1.p5 ]
then
echo "*** Error: Missing $1.p5 file"
exit 1
fi
cp $1.p5 prd
if [ -f $1.inp ]
then
./pint < $1.inp
else
./pint
fi
rm -f prd prr
・p5
ソースコードファイルをコンパイルして実行するスクリプトファイルです。
#!/bin/bash
#
# Compile with P5 using FPC Pascal
#
# Execute with:
#
# p5 <file>
#
# Where <file> is the name of the source file without
# extention. The Pascal file is compiled and run.
# Any compiler errors are output to the screen. Input
# and output to and from the running program are from
# the console, but output to the prr file is placed
# in <file>.out.
# The intermediate code is placed in <file>.p5.
#
if [ -z "$1" ]
then
echo "*** Error: Missing parameter"
exit 1
fi
if [ ! -f $1.pas ]
then
echo "*** Error: Missing $1.pas file"
exit 1
fi
echo
echo Compiling and running $1
echo
cp $1.pas prd
./pcom | tee $1.err
rm -f prd
grep -q "Errors in program: 0" $1.err
rc=$?
if [[ $rc != 0 ]] ; then
rm -f prr
exit 1
fi
rm -f $1.p5 $1.err prd
mv prr $1.p5
cp $1.p5 prd
./pint
rm -f prd prr
・パーミッション変更
スクリプトを実行できるようにパーミッションを変更しておきます。
$ chmod 755 compile run p5
PASCAL-P5 の使い方 (Linux)
hello.pas を ~/p5/
に作成します。
$ nano hello.pas
program Hello(Output);
begin
writeln('Hello, world.');
end.
$ ./compile hello
$ ./run hello
または
$ ./p5 hello
でコンパイルして実行します。
あまり Linux に詳しくないのでスクリプトは適当でないかもしれません。
■ Linux の場合 (gpc でコンパイルする場合)
Linux 環境で GNU Pascal (gpc) を用いてソースコードから Pascal-P5 をビルドする手順です。
GNU Pascal の RPM は以下にあります。RPM が使えるディストリビューションなら、パッケージとして gpc が登録されていなくても導入はそれほど難しくありません。
rpm | 説明 |
---|---|
gpc-20070904*.x86_64.rpm | 64bit Linux 用の RPM |
gpc-20070904*.i686.rpm | 32bit Linux 用の RPM |
CentOS 6 (32bit) の VM があったので試してみました。
$cd /tmp
$curl -OL <目的の RPM>
$rpm -ivh gpc*
無事 GNU Pascal を導入できました。
環境設定
アーカイブを DL して解凍しておきます。
$ cd /tmp
$ curl -OL https://ht-deko.com/software/pascal-p5.tar.gz
$ tar -zxvf pascal-p5.tar.gz
$ cd Pascal-p5/source/
コンパイル
pcom.pas と pint.pas を GNU Pascal でコンパイルします。ソースコードの修正は不要です。
$gpc --classic-pascal-level-0 --no-warnings --transparent-file-names --no-range-checking -o pcom pcom.pas
$gpc --classic-pascal-level-0 --no-warnings --transparent-file-names --no-range-checking -o pint pint.pas
pcom と pint が生成されていると思うので、これをコピーして使います。スクリプトは fpc の場合と同じです。
Note: Pascal-p5
フォルダで ./setpath
.configure
make
すると Pascal-p5/bin/
フォルダに pcom と pint が生成されます。スクリプトも Pascal-p5/bin/
フォルダにあるものがそのまま使えますが、改行コードが CR+LF なので、nkf などを使って LF に変換しないとエラーになります。
$sudo yum install nkf
$cd /tmp/Pascal-p5/bin/
$nkf -Lu --overwrite compile run p5
また、Pascal-p5/bin/
にあるスクリプトは pcom / pint にパスが通ってる前提なのと、compile と run は結果が画面にエコーされないのと、run は入力ファイルがなくても *.inp ファイルを要求するので注意が必要です。
$export PATH="/tmp/Pascal-p5/bin/:$PATH"
$./compile hello
$cat hello.err
$touch hello.inp
$./run hello
$cat hello.lst
■ X68000 の場合
今回の趣旨からはちょっと外れますが X68000 (Human68K) だと Pure Pascal が標準 Pascal ですね。
■ Delphi で Pascal-P5 をビルド
Delphi でビルドできたので、別記事にまとめました。
これで 64bit バイナリが生成できますね。
■ Pascal IDE (Windows)
Pascal-P5 を簡単に扱えるようにするための IDE を作りました。
Linux とかだとシェルスクリプトで作れそうな IDE ですが、こんなものでもあると便利です。
See also:
- Turbo Pascal 3.0.x の使い方 (Qiita)
- テキストエディタ Micro を Delphi 互換のキーバインドで使う (Qiita)
- Windows Terminal を DOS IDE ランチャーとして使う (Qiita)
おわりに
とりあえず、目的は達成されました!めでたしめでたし...。
K&R の K の方へ
K&R の K の方が 「Why Pascal is Not My Favorite Programming Language (何故 Pascal はお気に入りのプログラミング言語ではないのか)」 なんてのを書いていましたが Turbo Pascal や Delphi...それ以前の Apple の Pascal ですらその問題の多くは解決しています (好みの問題は残りますが)。
先の論文が書かれたのは 1981 年ですが、
- 1983: Pascal 最初の ISO 規格化 / Turbo Pascal 1.0 / Apple Lisa Clascal
- 1985: Apple による Object Pascal
- 1989: Turbo Pascal 5.5 (Object Pascal)
- 1990: ISO 標準 Pascal 改訂
- 1991: ISO 拡張 Pascal 規格化
- 1993: Pascal へのオブジェクト拡張 (ドラフト)
- 1995: Delphi 1.0 (Object Pascal)
それ以降で (Object) Pascal が進化していないハズもなく。
例えば、論文に書かれていたループの問題についてですが、標準 Pascal だと
program loop(output);
begin
while True do
begin
break;
end;
end.
Delphi とかだと普通にできます。
Linux の L の方へ
Linux の L の方の Pascal 嫌いという話についても古い Pascal に基づくものなので的外れな指摘もあるかと思います。
例えば
Of course, in stupid languages like Pascal,
where labels cannot be descriptive, goto's can be bad.
program labeltest(output);
label
jump;
begin
goto jump;
writeln('Hello');
jump:
writeln('World');
end.
確かに標準 Pascal だとラベルに任意の名前を付ける事はできず、符号なしの 4 桁以下の整数を指定する必要がありますが、
Delphi ならラベルに識別子が使えます (符号なしの整数も使えます)。
古い Pascal しか知らないと**「Pascal...面倒くさいよね!」**という意見が出てしまうのもわからなくはないですが、Delphi 等のモダンな (Object) Pascal が面倒くさい訳ではありません。
そして最新版の Delphi
魔改造 Pascal である Delphi には無償版 (Community Edition) もあるので、K の方や L の方が言ってた事が今でも正しい指摘なのかどうかをぜひ試してみてください。
... Delphi 使いは逆に標準 Pascal を触ってみて Delphi の有難みを知ってください (w
-
Pascal-P5 の fpc / gpc フォルダには Linux (Intel x86) 用のバイナリも含まれているのですが 32bit バイナリなので、例えば WSL の Ubuntu 等では実行できません。 ↩
-
GNU Pascal でコンパイルされているようです。最新版のツリーには最新版でコンパイルされた EXE が含まれていないかもしれません (古いバイナリなら gpc\windows_X86 にあります)。 ↩
-
バッチファイルは *.dpr も許容するようにしてあります。 ↩
-
/usr/bin/ へコピーする予定でしたが、最近の macOS はウルサクなったみたいなのでこうしました。 ↩
-
当初は /usr/bin/ へコピーするようにしていましたが、Windows や macOS と同じ構成にするために ~/p5/ にバイナリとスクリプトを集めるように変更しました。 ↩