はじめに
Delphi を使っていて、何が 標準 Pascal (Standard Pascal) に準拠していて何が準拠していないのかふと知りたくなることがあります。ISO/IEC 7185 の仕様を読めばいいのですが、実際にコードを実行して試したい事がよくあります。
そんな時は ideone で GPC を使ったり、同じく FPC で {$mode ISO}
指令を付けてみたりするのですが、これらは純粋な標準 Pascal ではないので、場合によっては検証にならなかったりします。
純粋な '標準 Pascal' を求めて
Windows 環境で最も簡単に実行できる標準 Pascal は Scott A. Moore 氏が書いた (改修した) Pascal-P5 だと思われます。
Mac や Linux の場合には自前でソースコードをビルドする必要があります。
今回の話題からは外れますが X68000 (Human68K) だと Pure Pascal が標準 Pascal ですね。
環境設定
PASCAL-P5 のアーカイブを解凍したら、bin フォルダにある pcom.exe と pint.exe を適当な場所にコピーします。これが PASCAL-P5 の本体です。
PASCAL-P5 は P-CODE コンパイラです。簡単に言えば PCOM がソースコードを中間コード (P-CODE) 形式にコンパイルし、それを PINT が実行します。PCOM がコンパイラで PINT がインタプリタという訳です。なので、理屈的には PINT さえ移植できればどこでもプログラムを実行できます。
え? Java っぽい? え? .NET っぽい? え? VB っぽい?そうですか...
さて、PCOM は prd
という名前のファイルをソースコードとみなし、コンパイルして prr
という中間形式ファイルを出力します。そして PINT は prr
という名前のファイルを中間形式ファイルとみなして実行します...名前決め打ちなんですよ、面倒ですね。
これを簡単にするバッチファイルもアーカイブの bin フォルダにあるのですが、何故かバッチファイルに cp や mv が使われていて Cygwin がないと動作しません。
バッチファイル
面倒なので 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
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 stop
:continue
echo.
echo Compiling and running %1
echo.
copy %1.pas prd > nul
pcom
move prr %1.p5 > nul
:stop
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
type %1.p5 %2 > prd
:run
pint
if "%3"=="" goto stop
copy prr %3 > nul
:stop
del prd
del prr
p5.bat
ソースコードファイルをコンパイルして実行するバッチファイルです。
@echo off
cls
if not "%1"=="" goto paramok
echo *** Error: Missing parameter
goto stop
:paramok
if exist "%1.pas" 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.
copy %1.pas 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
type %1.p5 %2 > prd
:run
pint
if "%3"=="" goto stop
copy prr %3 > nul
:stop
del prd
del prr
PASCAL-P5 の使い方
まず、サンプルプログラムを用意します。アーカイブの 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 である必要があります。
正しくコンパイルされると fizzbuzz.p5
ファイルが生成されます。これが中間形式ファイルです。
run fizzbuzz
として実行します。拡張子は不要です。一旦中間形式ファイルができてしまえば、実行の都度コンパイルする必要はありません。
p5 fizzbuzz
とすると、コンパイルと実行を連続して行います。
おわりに
目的は達成されました!めでたしめでたし...。
K&R の K の方へ
K&R の K の方が 「Why Pascal is Not My Favorite Programming Language (何故 Pascal はお気に入りのプログラミング言語ではないのか)」 なんてのを書いていましたが Turbo Pascal や Delphi...それ以前の Apple の Pascal ですらその問題の多くは解決しています (好みの問題は残りますが)。
先の論文が書かれたのは 1981 年ですが、
- 1983: Pascal の最初の標準化 / Turbo Pascal 1.0
- 1985: Apple による Object Pascal
- 1990: Pascal 標準化改訂版 / Turbo Pascal 5.5 (Object Pascal)
- 1995: Delphi 1.0
それ以降で (Object) Pascal が進化していないハズもなく。
例えば、論文に書かれていたループの問題についてですが、標準 Pascal だと
program loop(output);
begin
while True do
begin
break;
end;
end.
このような break
を使ったループの脱出はできません。
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