はじめに
Turbo Pascal 5.5 の Pascal について調べてみました。
Turbo Pascal は Pascal
Turbo Pascal 5.5 の Pascal は結構 Delphi に近付いてきましたが、クラスライブラリも存在しないので「既存の Turbo Pascal にオブジェクト指向拡張をポン付けしただけ」という印象があります。
Turbo Pascal の文法に関してはマニュアル等の書籍があればそれが一番いいのですが、標準 Pascal や Delphi のドキュメントからもある程度知る事ができます。
See also:
- PUG BOOKS の Turbo Pascal 関連書籍を読んでみる (Qiita)
- イロイロな出版社から出ている Turbo Pascal 関連書籍を読んでみる (Qiita)
- 標準 Pascal の規格票と解説書を読んでみる (Qiita)
- 標準 Pascal 範囲内での Delphi 入門 (Qiita)
- Delphi と標準 Pascal の比較 (Qiita)
- Delphi 言語ガイド (Embarcadero)
■ Turbo Pascal 3.0 と Turbo Pascal 5.5 の違い
標準 Pascal と Turbo Pascal 3.0 の違いについては以下の記事を参照してください。
Turbo Pascal 3.0 と Turbo Pascal 5.5 の言語関係の違いは次の通りです。
- program 名はユニークである必要があります。program 名はラベルではなくなりました。
- uses 句 (ユニット) が使えるようになりました。
- インクルードファイルのネスト (8 レベル) が可能になりました。
- いくつかの型、定数、ルーチンは別ユニットに移動しました。このため、uses 句にユニットを記述しないと使えない機能が出てきました。
- 使われないルーチンがリンクされなくなりました (スマートリンカ)。
- コンパイラ指令が刷新されました。Turbo Pascal 3.0 とは意味の異なるものも多いです。
-
{$IFDEF}コンパイラ指令が使えるようになりました。 - 論理式の評価はデフォルトでショートサーキット評価 (
{$B-}) になりました。 - Delphi の ShortString 相当の String が使えるようになりました。Turbo Pascal 3.0 では
String[80]のように長さを指定するユーザー定義型でした。 - 整数型に ShortInt (Int8) / Word (UInt16) / LongInt (Int32) が追加されました。
- 実数型に IEEE 浮動小数点型 (Single / Double / Extended / Comp 型) が追加されました。エミュレーションにより 8087 を搭載していなくても利用可能です。
- 汎用ポインタ型 Pointer が追加されました。
- 型キャストが強化され、構造が同じであれば型キャストが可能になりました。
- Addr() の代わりに使える @ 演算子が追加されました。
- Inc() と Dec() が使えるようになりました。
- Execute() / Chain() が使えなくなりました (Exec() は使えます)。
- ユニット単位のオーバーレイが利用可能になりました。Turbo Pascal 3.0 のオーバーレイとは使用方法が異なります。
- オーバーレイが EMS (Expanded Memory Specification) をサポートするようになりました。
- Borland Graphics Interface (BGI) に対応しました。
- オブジェクト指向拡張が施されました (Object 型)。
■ プログラムとユニット
コードの先頭が program で始まる主ファイルがプログラムファイルで、コードの先頭が unit で始まる副ファイルがユニットファイルです。両方をひっくるめてモジュールと呼びます。
| モジュールの種類 | ファイルの目的 | コードの先頭 | 拡張子 (TP/Delphi) |
バイナリ |
|---|---|---|---|---|
| 主ファイル | プログラム | program | *.PAS / *.DPR | *.EXE |
| 副ファイル | ユニット | unit | *.PAS / *.PAS | *.TPU |
バージョン 3.0 以前の Turbo Pascal にはユニットが存在しませんでした。バージョン 5.5 でも小さなプログラムならユニットファイルを使わずにプログラムファイルだけでアプリケーションを作る事ができます。
program Hello;
begin
Writeln('Hello,world.');
end.
○ プログラムの定義
プログラムは次のように定義されています 1。
プログラム =
[プログラムヘッダ ";"]
[uses 節]
プログラムブロック ".".
プログラムヘッダ =
"program" 識別子 ["(" プログラムパラメータ ")"]
プログラムパラメータ =
識別子リスト
uses 節 =
"uses" 識別子リスト ";"
プログラムブロック =
[ラベル宣言部 (label)]
[定数定義部 (const)]
[型定義部 (type)]
[変数宣言部 (var)]
[手続き・関数宣言部 (procedure / function)]
実行部 (begin~end).
○ ユニットの定義
ユニットは次のように定義されています 1。
ユニット =
"unit" 識別子 ";"
インターフェイス部
実現部
[初期化部]
"end" ".".
インターフェイス部 =
"interface"
[uses 節]
[宣言部].
実現部 =
"implementation"
[uses 節]
[宣言部].
初期化部 =
["begin" 文リスト].
○ プログラムの分割
先程の Hello,world. を分割してみましょう。
program Hello;
uses
Hello_S;
begin
HelloProc;
end.
unit HELLO_S;
interface
procedure HelloProc;
implementation
procedure HelloProc;
begin
Writeln('Hello,world.');
end;
end.
C 言語で例えると、ユニットの interface セクションが *.h、implementation セクションが C 言語の *.c に相当します。
IDE の [Compile | Primary file:] に HELLO.PAS を指定して [Compile | Make] を行うと実行形式ファイルが生成されます。
[Run | Run] すると、一瞬で戻ってきてしまいます...
[Run | User screen] で確認してみると、ちゃんと Hello,world. が表示されていました。
・ユニットの初期化部
Delphi にはユニットの初期化部として initialization がありますが、Turbo Pascal にはそれがありません。
しかしながら、Turbo Pascal のユニットにもちゃんと初期化部があるのです。
unit HELLO_S;
interface
procedure HelloProc;
implementation
procedure HelloProc;
begin
Writeln('Hello,world.');
end;
begin
Writeln('Init'); { ここが初期化部 }
end.
ユニットを上記のように改変して実行すると、
Init
Hello,world.
と表示されます。
Delphi にも initialization ではない初期化部はちゃんと残っています。ライブラリ (コードの先頭が Library で始まる) の初期化もこの方法で行います。
○ 標準ユニット
Turbo Pascal 5.5 には次の標準ユニットが用意されています。
・IBM PC
Crt Dos Graph Graph3 Overlay
Printer System Turbo3
・NEC PC-9801
Crt Dos Graph Overlay Printer
System Turbo3
System ユニット以外で定義されている定数、データ、型、変数、手続き、関数を利用したい場合には uses にユニットを追加する必要があります。
例えば Delay() を使いたいのであれば、uses に Crt を追加します。
program COUNTUP;
uses
Crt;
var
i: Integer;
begin
for i:=1 to 10 do
begin
Writeln(i);
Delay(1000);
end;
end.
標準ユニットの概要は DOC フォルダにあるインターフェイスユニットを読むと理解が早いと思います。
- インターフェイスユニットはユニットから implementation セクション以下を除外した、C 言語のヘッダーファイル的なものです。
- Turbo Pascal / Delphi の場合、プログラムからは利用できない/されない単なるドキュメントです。一般的にバイナリで提供されるライブラリとセットで配布されます。
- Turbo Pascal 6.0 以降、インターフェイスユニットの拡張子は
*.INTに変更されています。
■ 予約語 (Reserved word)
バージョン 5.5 時点の予約語は次の通りです。
absolute and array begin case
const constructor destructor div do
downto else end external file
for forward function goto if
implementation in inline interface interrupt
label mod nil not object
of or packed procedure program
record repeat set shl shr
string then to type unit
until uses var virtual while
with xor
■ 指令 (Directive)
バージョン 5.5 時点の指令は次の通りです。
external inline interrupt
標準 Pascal で指令の forward は Turbo Pascal 5.5 では予約語です。
■ ルーチン
Turbo Pascal 5.5 で使えるルーチンについては『リファレンスガイド』を参照するか、ヘルプを参考にしてください。
IDE の任意の場所で〔F1〕〔F1〕と押すとヘルプのインデックスが表示されるので Units から、そのユニットに含まれるルーチンを調べてみてください。
個々のルーチンは解説しませんが、標準ユニットにどんなルーチンが含まれているかを以下にリストアップしておきます。
○ System 名前空間
System ユニット内のルーチンです。
Abs Addr Append ArcTan Assign
BlockRead BlockWrite ChDir Chr Close
Concat Copy Cos CSeg Dec
Delete Dispose DSeg Eof Eoln
Erase Exit Exp FilePos FileSize
FillChar Flush Frac FreeMem GetDir
GetMem Halt Hi Inc Insert
Int IOResult Length Ln Lo
Mark MaxAvail MemAvail MkDir Move
New Odd Ofs Ord ParamCount
ParamStr Pi Pos Pred Ptr
Random Randomize Read ReadLn Release
Rename Reset Rewrite RmDir Round
RunError Seek SeekEof SeekEoln Seg
SetTextBuf Sin SizeOf SPtr Sqr
Sqrt SSeg Str Succ Swap
Trunc Truncate UpCase Val Write
WriteLn
System ユニット内のルーチンを使うために uses 句に System を追加する必要はありません。
○ Crt 名前空間
Crt ユニット内のルーチンです。
AssignCrt ClrEol ClrScr Delay DelLine
GotoXY HighVideo InsLine KeyPressed LowVideo
NormVideo NoSound ReadKey Sound TextBackground
TextColor TextMode WhereX WhereY Window
・ NEC PC-9801 固有
Beep TextBank TextBlink TextCursor TextVertical
TextReverse TextUnder
このユニットに含まれるルーチンは同名であっても IBM PC と NEC PC-9801 で動作が異なる事があります。
○ Dos 名前空間
Dos ユニット内のルーチンです。
DiskFree DiskSize DosExitCode DosVersion EnvCount
EnvStr Exec FExpand FindFirst FindNext
FSearch FSplit GetCBreak GetDate GetEnv
GetFAttr GetFTime GetIntVec GetTime GetVerify
Intr Keep MsDos PackTime SetCBreak
SetDate SetFAttr SetFTime SetIntVec SetTime
SetVerify SwapVectors UnpackTime
○ Graph 名前空間
Graph ユニット内のルーチンです。
Arc Bar Bar3D Circle ClearDevice
ClearViewPort CloseGraph DetectGraph Drawpoly Ellipse
FillEllipse FillPoly FloodFill GetArcCoords GetAspectRatio
GetBkColor GetColor GetDefaultPalette GetDriverName GetFillPattern
GetFillSettings GetGraphMode GetImage GetLineSettings GetMaxColor
GetMaxMode GetMaxX GetMaxY GetModeName GetModeRange
GetPalette GetPaletteSize GetPixel GetTextSettings GetViewSettings
GetX GetY GraphDefaults GraphErrorMsg GraphResult
ImageSize InitGraph InstallUserDriver InstallUserFont Line
LineRel LineTo MoveRel MoveTo OutText
OutTextXY PieSlice PutImage PutPixel Rectangle
RegisterBGIdriver RegisterBGIfont RestoreCrtMode Sector SetActivePage
SetAllPalette SetAspectRatio SetBkColor SetColor SetFillPattern
SetFillStyle SetGraphBufSize SetGraphMode SetLineStyle SetPalette
SetRGBPalette SetTextJustify SetTextStyle SetUserCharSize SetViewPort
SetVisualPage SetWriteMode TextHeight TextWidth
○ Overlay 名前空間
Overlay ユニット内のルーチンです。
OvrClearBuf OvrGetBuf OvrGetRetry OvrInit OvrInitEMS
OvrSetBuf OvrSetRetry
○ Printer 名前空間
Printer ユニット内にルーチンはありません。
○ Turbo3 名前空間 / Graph3 名前空間
Turbo3 ユニットと Graph3 ユニット (IBM PC のみ) は Turbo Pascal 3.0 互換ユニットです。バージョン 3.0 の記事を参考にしてください。
Turbo Pascal 3.0 互換ユニットは Crt ユニットに依存しています。
■ コンパイラ指令
{$ で始まるコメントのようなものはコンパイラ指令です。C 言語の #pragma に相当します。
以下に Turbo Pascal 3.0 で有効なコンパイラ指令を示します。太字のコンパイラ指令はデフォルトの動作です。
○ スイッチ指令
| 指令 | 構文 | 説明 |
|---|---|---|
| データのアライメント | {$A+} または {$A-} | {$A+}: ワードアライメント {$A-}: バイトアライメント |
| 論理式の評価 | {$B+} または {$B-} | {$B+}: 完全式評価 {$B-}: ショートサーキット評価 |
| デバッグ情報 | {$D+} または {$D-} | {$D+}: デバッグ情報を含める {$D-}: デバッグ情報を含めない |
| エミュレーション | {$E+} または {$E-} | {$E+}: 8087 が存在しなければエミュレーションを行う {$E-}: 8087 が存在しなければエミュレーションを行わない |
| FAR コールの強制 | {$F+} または {$F-} | {$F+}: FAR コール {$F-}: NEAR コール |
| 入出力チェック | {$I+} または {$I-} | {$I+}: I/O 手続きの結果のチェックを行う {$I-}: I/O 手続きの結果のチェックを行わない |
| ローカルシンボル情報 | {$L+} または {$L-} | {$L+}: ローカルシンボル情報を生成する {$L-}: ローカルシンボル情報を生成しない |
| 数値演算 | {$N+} または {$N-} | {$N+}: 8087 {$N-}: エミュレーション |
| オーバーレイコードの生成 | {$O+} または {$O-} | {$O+}: オーバーレイコードを生成する {$O-}: オーバーレイコードを生成しない |
| 範囲チェック | {$R+} または {$R-} | 配列や文字列の宣言した添字の範囲または順序型の範囲を超えて操作した時にエラーを出す {$R+} or 出さない {$R-} |
| スタックオーバーフローのチェック | {$S+} または {$S-} | {$S+}: スタックオーバーフローのチェック を行う {$S-}: スタックオーバーフローのチェックを行わない |
| 文字列型変数チェック | {$V+} または {$V-} | 手続き・関数の var パラメータに渡された文字列型変数の長さをチェックする {$V+} or しない {$V-} |
○ パラメータ指令
| 指令 | 構文 | 説明 |
|---|---|---|
| ファイルのインクルード | {$I ファイル名} | インクルードファイルを指定する。拡張子を省略した場合は *.PAS とみなされる。$I とファイル名の間にはスペースが必要 |
| オブジェクトファイルのリンク | {$L ファイル名} | オブジェクトファイルを指定する。拡張子を省略した場合は *.OBJ とみなされる。$L とファイル名の間にはスペースが必要 |
| メモリの割り当てサイズ | {$M スタックサイズ,最小ヒープ,最大ヒープ} | それぞれのメモリ割り当てサイズを指定する。デフォルトは {$M 16384,0,655360} |
| オーバーレイユニット名 | {$O ユニット名} | 指定されたユニットをオーバーレイにする。プログラムファイル (主ファイル) で利用可能。$O とユニット名の間にはスペースが必要 |
■ 高度な使い方
○ オブジェクト指向拡張
Turbo Pascal 5.5 で追加された object 型の使い方に関しては、次の記事を参考にしてください。
OOPDEMOS.DOC はオブジェクト指向プログラミングのサンプルコード解説です。
オブジェクト指向拡張 (Object-Oriented Extensions) されていても、Turbo Pascal は Object Pascal ではありません。
○ 条件コンパイル
Turbo Pascal 5.5 では条件コンパイルが可能です。以下に利用可能なコンパイラ指令を列挙します。
| 構文 | 説明 |
|---|---|
| {$DEFINE name} | 条件シンボルを定義します |
| {$UNDEF name} | 定義された条件シンボルを解除します |
| {$IFDEF name} | name が定義されている場合、続くコードをコンパイルします |
| {$IFNDEF name} | name が定義されていない場合、続くコードをコンパイルします |
| {$IFOPT switch} | 指定されたスイッチ指令の条件の時、続くコードをコンパイルします |
| {$ELSE} | 最も近い {$IFxxx} と {$ENDIF} 間のソースコードをコンパイルする部分としない部分に分割します |
| {$ENDIF} | {$IFxxx} で始まった条件コンパイル部の終わりを示します |
定義済の条件シンボルには次のものがあります:
VER55 MSDOS CPU86 CPU87
CPU87 はコンパイル環境で 8087 が利用可能な場合に定義されます。
条件コンパイル部は 16 レベルまでネスト可能です。
See also:
○ システム変数
Turbo Pascal 5.5 にはいくつかのシステム変数があります。
| 変数 | 説明 |
|---|---|
| mem[] | メモリアクセス用バイト配列 |
| memW[] | メモリアクセス用ワード配列 |
| memL[] | メモリアクセス用ロングイント配列 |
| port[] | ポートアクセス用バイト配列 |
| portW[] | ポートアクセス用ワード配列 |
○ 絶対変数
予約語 absolute 2 を使って、変数を特定のメモリアドレスに置くように指定する事ができます。
var
abc: Integer absolute $0000:$00EE;
○ 絶対アドレス関数
| 関数名 | 説明 |
|---|---|
| Addr(Name) | Name で示される変数の第 1 バイトのアドレスを返す |
| Ofs(Name) | Name で示される変数, 手続き, 関数の第 1 バイトが存在するセグメント内でのオフセットを返す |
| Seg(Name) | Name で示される変数, 手続き, 関数の第 1 バイトを含むセグメントのアドレスを返す |
| CSeg | コードセグメントのベースアドレスを返す |
| DSeg | データセグメントのベースアドレスを返す |
| SSeg | スタックセグメントのベースアドレスを返す |
| Ptr(segs, ofs) | セグメントのベースアドレスとオフセットアドレスをポインタ型の値に変換する |
| SPtr | スタックポインタが指しているスタックセグメントのセグメント内でのオフセットを返す |
See Also:
○ ポインタ型への値の代入
Ptr() は整数値のペア (セグメントアドレス、オフセットアドレス) をポインタに変換できます。ポインタが示すアドレスを逆に変換しようとすると 2 つの値が必要となるため、変換に Ord() を使う事はできません。
var
PB: ^Byte;
begin
PB := Ptr(Seg(PB^), $100);
Writeln(Seg(PB^), ':', Ofs(PB^));
Writeln('Memory: ', PB^);
end;
○ 配列 mem[]
配列 mem[] はメモリにアクセスするのに使われます。配列の要素は byte 型です。
value := mem[$FCA9];
mem[$FCA9] := value;
配列の要素が word 型の memW[] と LongInt 型の memL[] も用意されています。
value := memW[$0000:$0081];
memW[Seg(Var):Ofs(Var)] := value;
○ 配列 port[]
配列 port[] は I/O ポートにアクセスするのに使われます。配列の要素は byte 型です。
value := port[98];
port[98] := value;
配列の要素が Integer 型の portW[] も用意されています。
value := portW[10];
portW[10] := value;
○ インクルードファイル
インクルードファイル コンパイラ指令 ({$I}) を使うと、ファイルを指定した位置に挿入する事ができます。
procedure Hello;
begin
Writeln('Hello,world.');
end;
program Prog1;
{$I lib.inc}
begin
Hello;
end.
上記ソースは次のように展開されます。
program Prog1;
procedure Hello;
begin
Writeln('Hello,world.');
end;
begin
Hello;
end.
Turbo Pascal 3.0 では実行文だけをインクルードファイルにする事が可能でしたが、Turbo Pascal 5.5 ではエラーになります。
Writeln('Hello,world.');
program Prog1;
begin
{$I lib.inc} (* NG *)
end.
Turbo Pascal 5.5 のインクルードファイルに実行文が含まれる場合には begin ~ end ブロックが必要です。
begin
Writeln('Hello,world.');
end;
program Prog1;
procedure Hello;
{$I lib.inc} (* OK *)
begin
Hello;
end.
こちらも通ります。
begin
Writeln('Hello,world.');
end.
program Prog1;
{$I lib.inc} (* OK *)
・Turbo Pascal 5.5 ではインクルードファイルを 8 段までネストできます。
・ソースファイルの分割を行う古い方法です。Turbo Pascal 5.5 ではユニットによるソースファイル分割をオススメします。
See Also:
○ オーバーレイ
Turbo Pascal 5.5 ではユニット単位のオーバーレイが使えます。
- ユニットにコンパイラ指令
{$O+}があるとオーバーレイ可能となる。 - オーバーレイを利用するプログラムのプログラムファイルとすべてのユニットファイルはコンパイラ指令
{$F+}(FAR 呼び出し) を指定する必要がある。 - EMS があればオーバーレイを EMS へロードする事も可能。
- オーバーレイは EXE の出力先が
memoryだと使えない。 - 標準ユニットでは唯一
Dosだけがオーバーレイ可能。
以下、ユニットをオーバーレイとして使うサンプルコードです。
Turbo Pascal 3.0 にあったオーバーレイとは使い方が異なります。サンプルプログラムの OVRDEMO.PAS も参考にしてみてください。
・OVRTEST.PAS (プログラムファイル)
OVRTEST.PAS は、プログラムファイルです。uOVRFunc ユニットをオーバーレイとして指定しています。
{$F+} { FAR Call }
program OVRTEST;
uses
Overlay, uOVRInit, uOVRFunc;
{$O uOVRFunc} { Overlay Unit }
begin
Hello;
end.
・uOVRInit.PAS (オーバーレイ初期化用ユニット)
uOVRInit.PAS は、オーバーレイ初期化用ユニットです。
{$F+} { FAR Call }
unit uOVRInit;
interface
implementation
uses
Overlay;
const
OVR_NAME = 'OVRTEST.OVR';
OVR_MAXSIZE = 80000;
var
OvrName: string[79];
Size: LongInt;
begin
{ Initialize }
OvrName := OVR_NAME;
repeat
OvrInit(OvrName);
if OvrResult = ovrNotFound then
begin
Writeln('Overlay file not found: ', OvrName, '.');
Write('Enter correct overlay file name: ');
Readln(OvrName);
end;
until OvrResult <> OvrNotFound;
if OvrResult <> ovrOk then
begin
Writeln('Overlay manager error.');
Halt(1);
end;
OvrInitEMS;
if OvrResult <> ovrOk then
begin
case ovrResult of
ovrIOError:
Write('Overlay file I/O error');
ovrNoEMSDriver:
Write('EMS driver not installed');
ovrNoEMSMemory:
Write('Not enough EMS Memory');
end;
Write('. Press [RETURN] ...');
Readln;
end;
OvrSetBuf(OVR_MAXSIZE);
end.
オーバーレイ初期化で使われているルーチンは次の通りです。
| ルーチン | 説明 |
|---|---|
| OvrInit(Filename) | オーバーレイマネージャを初期化し、オーバーレイファイルをオープンします。 |
| OvrInitEMS() | 可能であればオーバーレイを EMS にロードします |
| OvrSetBuf(BufSize) | オーバーレイバッファサイスを指定します |
他にも次のような関連ルーチンがあります。
| ルーチン | 説明 |
|---|---|
| OvrGetBuf() | 現在のオーバーレイバッファサイスを取得します |
| OvrClearBuf() | オーバーレイバッファをクリアします |
各種オーバーレイルーチンを呼び出すと OvrResult 変数に結果が返ります。この結果を元にエラー処理を行います。
const
ovrOk = 0;
ovrError = -1;
ovrNotFound = -2;
ovrNoMemory = -3;
ovrIOError = -4;
ovrNoEMSDriver = -5;
ovrNoEMSMemory = -6;
ユニット初期化部で自動的に初期化が行われますので、この初期化ユニットはプログラムファイルのできるだけ前で uses する必要があります。
このユニットは他のプログラムでも流用可能です。const にある OVR_NAME (と OVR_MAXSIZE) だけは書き替える必要があります。
・uOVRFunc.PAS (オーバーレイユニット)
オーバーレイユニットです。コンパイラ指令があるくらいで、特に変わった所はありません。
{$O+, F+} { Overlay unit, FAR call }
unit uOVRFunc;
interface
uses
Crt;
procedure Hello;
implementation
procedure Hello;
begin
Writeln('Hello, world.');
end;
end.
・動作確認
OVRTEST.PAS を Primary File に指定して [Compile | Make] すると OVRTEST.EXE と OVRTEST.OVR が生成されます。
メイク (またはビルド) すると、プログラムファイルの {$O unitname} で指定されたユニットが集められて OVRTEST.OVR が生成されます。プログラム OVRTEST.EXE にはオーバーレイユニットは含まれません。
Turbo Pascal 3.3 のオーバーレイとは異なり、初期化ルーチンを自前で書かなくてはならないのが多少面倒ですが、一度書いておけば使い回しは利きます。EMS の知識がなくてもオーバーレイ置き場として EMS が利用できるのも大きなメリットです。
あまり意味があるとは思えませんが、実行結果は次のようになります。
NEC PC-9801 エミュレータで EMS を使いたい場合には FM 音源の ROM を無効にする必要があります。
○ Exec()
Exec() は他の実行形式ファイルを実行する手続きです。uses に Dos を追加する必要があります。
program Prog1;
uses
Dos;
begin
Exec('prog2.exe', '');
end.
program Prog2;
begin
Writeln('Hello,world.');
end.
Turbo Pascal 3.0 にあった Execute() とは使い方が異なります。
○ インライン機械語
inline() の中に / で区切った コード を記述する事ができます。
コードに付ける < と > はサイズ指定子です。例えば <$1234 は 1 バイトの $34 を表し、>$56 は 1 ワードの $5600 を表します (サイズが変更される 8 ビットのシフト)。+ と - による演算が可能なコードもあります。
procedure FillWord(var Dest; Count: Word; Data: Word);
begin
inline(
$C4/$7E/Dest/ { LES DI,Dest[BP] }
$8B/$4E/Count/ { MOV CX,Count[BP]}
$8B/$46/Data/ { MOV AX,Data[BP] }
$FC/ { CLD }
$F3/$AB); { REP STOSW }
end;
Turbo Pascal 5.5 ではロケーションカウンタ (*) は利用できません。
○ inline 指令
Turbo Pascal 5.5 には inline 指令もあります。
procedure DisableInterrupts; inline($FA); { CLI }
procedure EnableInterrupts; inline($FB); { STI }
これは全体がインライン機械語で書かれた短い手続きや関数となります。
inline 指令を使った手続きや関数に対して @演算子, Addr, Ofs, Seg を使う事はできません。
○ 割り込み手続き
割り込み手続きは interrupt 指令を指定した特殊な手続きです。割り込みハンドラーを書くためにあります。次のような手続きヘッダーである必要があります。
procedure IntProc(Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP: Word); interrupt;
パラメーターは右からであれば一部または全部を省略できます。
procedure IntProc(Flags, CS, IP, AX, BX, CX, DX, SI: Word); interrupt; { OK }
procedure IntProc(Flags, CS, IP, AX, BP: Word); interrupt; { NG }
procedure IntProc; interrupt; { OK }
以下はタイマー割り込みでカウントアップ表示する例です。
IBM PC 用です。NEC PC-9801 で実行しないでください。
program CountUp;
uses
Crt, Dos;
const
LOOP = 18;
INT_NO = $1C;
var
OldInt: Pointer;
Tick: Word;
Count: Word;
Upd: Boolean;
procedure OnTimer; interrupt;
begin
Inc(Tick);
if Tick >= LOOP then
begin
Tick := 0;
Inc(Count);
Upd := True;
end;
end; { OnTimer() }
begin
Tick := 0;
Count := 0;
Upd := False;
GetIntVec(INT_NO, OldInt);
SetIntVec(INT_NO, @OnTimer);
Writeln('Press [Enter] to exit.');
repeat
if Upd then
begin
Upd := False;
Writeln('Count = ', Count);
end;
until KeyPressed and (ReadKey = #13);
SetIntVec(INT_NO, OldInt);
end.
ざっくり言うと、
-
GetIntVec()で現在の割り込みベクターを取得 - 取得した割り込みベクターを退避
-
SetIntVec()で割り込みベクターに割り込みハンドラー (割り込み手続き OnTimer) を設定 - 55ms おきに OnTimer 割り込みハンドラーが呼ばれる
- 使い終わったら再度
SetIntVec()で退避した割り込みベクターを設定
という処理になっています。
○ 外部副プログラム
Turbo Pascal ではアセンブラで書かれたライブラリ (オブジェクトファイル) をコンパイラ指令 {$L} により静的リンクする事ができます。
DSKRESET.OBJ にある DiskReset() 手続きを呼び出せるようにするには external を付けて宣言します。
{$L DSKRESET}
...
procedure DiskReset; external;
Turbo Pascal 5.0 以降の Professional 版には Turbo Assembler がバンドルされています。
○ MsDos()
DOS の機能を呼び出します。利用するには uses に Dos を追加する必要があります。
procedure MsDos(var Regs: Registers);
パラメーターとして register レコード型変数を渡す必要があります。
register レコードについては DOC\DOS.DOC を参照してください。
○ Intr()
割り込みを行います。利用するには uses に Dos を追加する必要があります。
procedure Intr(IntNo: byte; var Regs: Registers);
IntNo に割り込み番号をセットして Intr() を実行すると、register レコード型変数に結果が返ります。
var
Regs: register;
begin
Intr($21, Regs);
end;
register レコードについては DOC\DOS.DOC を参照してください。
○ ユーザー定義のテキストファイルデバイスドライバ
Turbo Pascal 5.5 ではユーザー定義のテキストファイルデバイスドライバを記述する事が可能です。
unit MyText;
interface
uses
Dos;
procedure MyAssign(var F: text);
implementation
{$F+}
function MyOpen(var F: text): Integer;
begin
{ 処理 }
end;
function MyInOut(var F: text): Integer;
begin
{ 処理 }
end;
function MyFlush(var F: text): Integer;
begin
{ 処理 }
end;
function MyClose(var F: text): Integer;
begin
{ 処理 }
end;
{$F-}
procedure MyAssign(var F: text);
begin
with TextRec(F) do
begin
Mode := fmClosed;
BufSize := SizeOf(Buffer);
BufPtr := @Buffer;
OpenFunc := @MyOpen;
InOutFunc := @MyInOut;
FlushFunc := @MyFlush;
CloseFunc := @MyClose;
Name[0] := #0;
end;
end;
end.
- 独自の
Assign()手続きを作成、パラメータに指定されたテキストファイル型を TextRec レコード 3 でキャストしてパラメータを設定するようにする。 -
TextRec(F).OpenFunc:
Reset() / ReWrite() / Append()がテキストファイルをオープンする時に呼び出される Open 関数を指定する。 -
TextRec(F).InOutFunc:
Read() / Readln() / Write() / Writeln() / Eof() / Eoln() / SeekEof() / SeekEoln() / Closeがテキストファイルへの入出力を行う時に呼び出される InOut 関数を指定する。 -
TextRec(F).FlushFunc:
Read() / Readln() / Write() / Writeln()の処理の最後に呼び出される Flush 関数を指定する。 -
TextRec(F).CloseFunc:
Close()がテキストファイルをクローズする時に呼び出される Open 関数を指定する。
program MyTest;
uses
MyText;
var
F: text;
begin
MyAssign(F);
ReWrite(F);
Writeln(F, 'Hello,world.');
Close(F);
end.
使う時は Assign() の代わりに MyAssign() を呼ぶだけです。
詳細については『リファレンスガイド (製品マニュアル)』 を参照してください。
See also:
○ 終了手続き
Delphi の finalization とはちょっと違いますが、Turbo Pascal 5.5 では ExitProc 変数を書き替える事で終了処理を行う事ができます。
program TEST;
var
OrgProc: Pointer;
{$F+}
procedure OnTerminate;
begin
ExitProc := OrgProc;
...
end;
{$F-}
begin
OrgProc := ExitProc;
ExitProc := @OnTerminate;
...
end.
こうして書き替えられた終了手続きは、Halt() が呼ばれた時や実行時エラーが発生した時でも実行されます。
おわりに
Turbo Pascal 5.5 にはオブジェクト指向が導入されていますが、クラスライブラリが用意されていないので Object 型の使い所が難しく思えます。
See Also:
索引
-
Turbo Pascal 5.5 の使い方
- Turbo Pascal 5.5 の Pascal
- Turbo Pascal 5.5 のキーボードショートカット




