1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Turbo Pascal 5.5 の Pascal

Last updated at Posted at 2026-01-03

はじめに

Turbo Pascal 5.5 の Pascal について調べてみました。

image.png

Turbo Pascal は Pascal

Turbo Pascal 5.5 の Pascal は結構 Delphi に近付いてきましたが、クラスライブラリも存在しないので「既存の Turbo Pascal にオブジェクト指向拡張をポン付けしただけ」という印象があります。

Turbo Pascal の文法に関してはマニュアル等の書籍があればそれが一番いいのですが、標準 Pascal や Delphi のドキュメントからもある程度知る事ができます。

See also:

■ 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 でも小さなプログラムならユニットファイルを使わずにプログラムファイルだけでアプリケーションを作る事ができます。

HELLO.PAS
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. を分割してみましょう。

HELLO.PAS
program Hello;

uses          
  Hello_S;    
  
begin         
  HelloProc;  
end.          
HELLO_S.PAS
unit HELLO_S;             

interface                 

procedure HelloProc;      

implementation            

procedure HelloProc;      
begin                     
  Writeln('Hello,world.');
end;                      

end.                      

C 言語で例えると、ユニットの interface セクションが *.himplementation セクションが C 言語の *.c に相当します。

IDE の [Compile | Primary file:]HELLO.PAS を指定して [Compile | Make] を行うと実行形式ファイルが生成されます。

[Run | Run] すると、一瞬で戻ってきてしまいます...

image.png

[Run | User screen] で確認してみると、ちゃんと Hello,world. が表示されていました。

・ユニットの初期化部

Delphi にはユニットの初期化部として initialization がありますが、Turbo Pascal にはそれがありません。

しかしながら、Turbo Pascal のユニットにもちゃんと初期化部があるのです。

HELLO_S.PAS
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() を使いたいのであれば、usesCrt を追加します。

COUNTUP.PAS
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 から、そのユニットに含まれるルーチンを調べてみてください。

image.png

個々のルーチンは解説しませんが、標準ユニットにどんなルーチンが含まれているかを以下にリストアップしておきます。

○ 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}) を使うと、ファイルを指定した位置に挿入する事ができます。

lib.inc
  procedure Hello;
  begin
    Writeln('Hello,world.');
  end;
Prog1.pas
program Prog1;
{$I lib.inc}
begin
  Hello;  
end.

上記ソースは次のように展開されます。

Prog1.pas
program Prog1;
  procedure Hello;
  begin
    Writeln('Hello,world.');
  end;
begin
  Hello;  
end.

Turbo Pascal 3.0 では実行文だけをインクルードファイルにする事が可能でしたが、Turbo Pascal 5.5 ではエラーになります。

lib.inc
  Writeln('Hello,world.');
Prog1.pas
program Prog1;
begin
  {$I lib.inc} (* NG *)
end.

Turbo Pascal 5.5 のインクルードファイルに実行文が含まれる場合には beginend ブロックが必要です。

lib.inc
begin
  Writeln('Hello,world.');
end;
Prog1.pas
program Prog1;
  procedure Hello;
  {$I lib.inc} (* OK *)
begin
  Hello;
end.

こちらも通ります。

lib.inc
begin
  Writeln('Hello,world.');
end.
Prog1.pas
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 ユニットをオーバーレイとして指定しています。

OVRTEST.PAS
{$F+} { FAR Call }
program OVRTEST;              

uses                          
  Overlay, uOVRInit, uOVRFunc;

{$O uOVRFunc} { Overlay Unit }

begin                         
  Hello;                      
end.                          

・uOVRInit.PAS (オーバーレイ初期化用ユニット)

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 変数に結果が返ります。この結果を元にエラー処理を行います。

DOC\OVERLAY.DOC
const
  ovrOk = 0;
  ovrError = -1;
  ovrNotFound = -2;
  ovrNoMemory = -3;
  ovrIOError = -4;
  ovrNoEMSDriver = -5;
  ovrNoEMSMemory = -6;

ユニット初期化部で自動的に初期化が行われますので、この初期化ユニットはプログラムファイルのできるだけ前で uses する必要があります。

このユニットは他のプログラムでも流用可能です。const にある OVR_NAME (と OVR_MAXSIZE) だけは書き替える必要があります。

・uOVRFunc.PAS (オーバーレイユニット)

オーバーレイユニットです。コンパイラ指令があるくらいで、特に変わった所はありません。

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.EXEOVRTEST.OVR が生成されます。

image.png

メイク (またはビルド) すると、プログラムファイルの {$O unitname} で指定されたユニットが集められて OVRTEST.OVR が生成されます。プログラム OVRTEST.EXE にはオーバーレイユニットは含まれません。

Turbo Pascal 3.3 のオーバーレイとは異なり、初期化ルーチンを自前で書かなくてはならないのが多少面倒ですが、一度書いておけば使い回しは利きます。EMS の知識がなくてもオーバーレイ置き場として EMS が利用できるのも大きなメリットです。

あまり意味があるとは思えませんが、実行結果は次のようになります。

image.png

NEC PC-9801 エミュレータで EMS を使いたい場合には FM 音源の ROM を無効にする必要があります。

○ Exec()

Exec() は他の実行形式ファイルを実行する手続きです。usesDos を追加する必要があります。

prog1.pas
program Prog1;
uses
  Dos; 
begin
  Exec('prog2.exe', '');
end.
prog2.pas
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 で実行しないでください。

COUNTUP.PAS
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 の機能を呼び出します。利用するには usesDos を追加する必要があります。

  procedure MsDos(var Regs: Registers);

パラメーターとして register レコード型変数を渡す必要があります。

register レコードについては DOC\DOS.DOC を参照してください。

○ Intr()

割り込みを行います。利用するには usesDos を追加する必要があります。

  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 ではユーザー定義のテキストファイルデバイスドライバを記述する事が可能です。

MYTEXT.PAS
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:

索引

  1. 偽 BNF なので、雰囲気で読んでください。 2

  2. Delphi では予約語ではなく指令です。

  3. TextRec レコードは Dos ユニットで定義されています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?