#3 初期化・終了・begin〜end


 スケルトン編もこれで終わりです。まだ、ファイルの構造ばっかりしか話がないんでここで一気にブロックとユニットファイルの中身を解説しちゃおう。Delphiどころか、プログラムやったこと無い人にもわかって欲しいんで、余談交えて丁寧に語ります。
 しかし、なかなか進まんなぁ。コンテンツ凝りだすとどうしても時間かかるです。くどすぎるかとも思いますが。

「ユニットファイルの中身!」の巻

 プロジェクトファイルの空っぽのメインルーチンに1行付け加えて、以下のコードを置いてください。
 これがプロジェクトのスケルトン・コードです。
ソース3-1:

program TST02;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Jan02 in 'Jan02.pas';

begin
 while true do Janken
end.
 Jankenというコマンドを無限に繰り返しなさいというコードです。余談1へ=>Go!
 さて、プログラムというのは文で出来ています。ここで述べた「文」という語は、僕らが国語でいうような意味でなく、pascalなどのプログラミング言語で意味をもつ単位です。文・式・トークンと述べねばならないことが多いですが、コンパイラが認識する順に理解しましょう。
 文の定義は言語・処理系によりますが、Delphiの「文」は以下の通りです。余談2へ=>Go!

  @「;」セミコロンで区切られた単位(単文)。
  Abeginとend;で囲まれた単位(複文)。
   ただしその中に複数の単文を含むことがある。

 文が文法的にあっているかどうかは別としてコンパイラはこうやってプログラムを区切って理解しようとします。取り出した「文」が言語の仕様に沿って書かれているかどうかをチェックして、あっていれば(何層かの段階を踏んで)バイナリコードに置き換えプログラムが完成します。
 複数の単文をまとめ上げた塊を1つの文に見立てる場合が上のAです。ブロックとか、コード・ブロックといいます。Delphiのブロックはbeginとendで囲みます。end.の直前にendがくると;なしでは済まされないのでbeginとend;で囲みますが、;を入れては行けないものもあるので注意しましょう。
 begin endブロックの使い方を数例あげます。まず一例ですが、上のソース3-1で付け加えたメインルーチンの一文は下のような構造をしています。

 while・・・do<文>

 これ自体が1つの文です。これは・・・に真か偽の値をとる「式」というものが入り、<文>にはそこだけでまた1つの文と見なせるものが入ります。while  do のような形の文は「式」の値によってやることが変わります。一般に制御文といわれているものの一つです。「・・・が真(true)である限り<文>を繰り返しなさい。」という制御文で・・・にtrueを固定値で入れるととまらないプログラムです。ここで「文」は普通コンピュータにとって単位指令ですから、繰り返したいことが命令の組合せだとこのwhile文が使えなくなってしまうわけです。そこで幾つかの文を塊にして一つのブロックにすると
 while・・・do
  begin
   <文1>;
   <文2>;
   <文3>;
  end;

beginからend;で囲まれたブロックを上の<文>に見立て、<文1><文2><文3>の3つの単位指令を繰り返させられるのです。  式とトークンは余談3へ=>Go!

 もう一つブロックの例をあげます。if・・・then<文1>else<文2>の制御文は・・・に真か偽の値をとる「式」が入り、真なら<文1>、偽なら<文2>が実行されます。これも文法的には1つの文しか入れられないので複数の文を入れたいときはbeginとendブロックにして入れます。注意は文1のブロックの最後にend;とセミコロンをつけると上の階層のif文が分割されて、第二の文がelseで始まってしまうのでコンパイラに意味通りません。次のように書きます。
ソース3-2:
if <論理式> then
 begin
 {ブロック1}
 end     //ここは;は駄目。ifが後ろのelseと離れます。
         //単文でも;は入れてはいけません。
else
 begin
 {ブロック2}
 end;    //ここは後ろとの区切りで;を必要とします。
・・・・次の文へ

 制御文の要素としてブロックを入れるとき、;を何処に入れるとコンパイラにどう見えるかを常に注意せねばなりません。

 JankenをこれからユニットJan02.pasに実装していきます。といっても、今は枠組みだけ作ります。
 プログラムは最初、させたいことの前に準備をする必要があります。変数に開始値を与えるだとか、プログラムが動作するためのメモリの領域を確保するだとか動作するときに始めに一回だけやればよいことというものがあります。  ユニットJan02.pasはプロジェクトファイルからすると部品で中身がどうなってるかわからないでも使えることが望ましいですから、Jankenは繰り返し使われるけど初期化は最初に一回だけ自動的に実行されるのがいいです。
 同様に終了処理といい終わるときに必ずやらないといけないこともありえます。例えば「使い終わったメモリ領域を手放して他のプログラムが使えるようにする」とかです。「発つ鳥後を濁さず。」っと。
 こういったことが後で必要になると思われるのでユニットファイルに次のような条件を課します。

  • 1)空の初期化部をもつ。
  • 2)空の終了処理部をもつ。
  • 3)実装が空のJankenという手続きを持つ。
  • 4)Jankenは外部からの呼び出しに応じる。
 「手続き」とは1種のまとまった処理(サブルーチン)だと今は理解していてください。次のページで「関数」と一緒に説明します。
 この1)-4)の要請を満たすソースは次のものです。  これがユニットのスケルトン・コードです。
ソース3-3:

unit Jan02;

interface

procedure Janken;
 {4)これは外部ファイルから、
  呼び出されるために
  必要な宣言。}

implementation

procedure Janken;
begin
 {3)ここにJankenの実装(初期化・終了を除く)。}
end;

initialization
 {1)ここにユニットとしての初期化コードを書く}
finalization
 {2)ここにユニットとしての終了処理コードを書く}
end.
 ここまでで、スケルトンを一旦出来たことにして良いでしょう。
 予約語initializationとfinalizationについて説明しておきます。ユニットファイル全体として、やっておかないといけない初期化処理と終了化処理を書く部分を宣言します。このユニットを利用しているプログラムはどの部品を利用しようがinitialization部に書かれたコードを実行してから動きます。またそのプログラムを右上の×ボタンで「ぶちっ」って終了させても、finalization部のコードを実行して終わります。
 なお、finalizationはend.の前、initialization部はそのまた前に書くことが決まってます。どっちも同時にないのはありですが、どっちかだけならinitialization部のみというのが許されます。つまり、initializationのないfinalizationはありえません。この2つの予約語を後ろの方にこの順に置いておけば、要請1)2)はクリアーです。

 次に要請3)です。手続きの実装はimplementation部に置くのが決まりで引数も戻り値もないものでいいと思いますから、このように書きます。引数と戻り値の規定はシグネチャといいます。手続きや関数はimplementation部にシグネチャを書いてそのすぐ下にbeginとend;で挟まれた実装ブロックを書くのが決まりです。(シグネチャと実装ブロック間にvarとか、また関数や手続きが埋め込まれることもありますが・・・。おいおいやります。)これで3)クリアです。

 ところが、このままではJankenは外から使えません。外から使うにはinterface部に宣言(シグネチャ)だけ、書いておく必要があります。そこで4)です。実装ブロックは下のimplementation部にあるから不要です。使う立場のプロジェクトファイルからは中がどうなっていようと関係ないのです。

 特に初めてプログラムする人にメッセージですが、ごちゃごちゃ考えると難しいですね。ゆっくり追いかけてください。
 また、C/C++やJavaを使う人にはコードの部分に意味を持たせる予約語が目新しいかもしれません。予約語の上と下というスコープの考え方もちょっと独特です。が、慣れるとJavaに似た簡単さが感じられ、出来た物が安定して早く走ります。
 お疲れ様。スケルトン一丁あがりです。
(2004/Jan/04)


ページtopへ

リファレンス

 斜体は節の宣言を示す。例えばvar <変数名>:<型名>;とあれば、varのセクションで繰り返し宣言ができる。
ex.
var
  i,j:integer;
  s:string;
  ・・・・・・・


余談1 元へ 「セミコロン;」
 Jankenの後ろにセミコロンがないのに気づきましたか?写しまちがいじゃないです。C/C++やJavaでは「;」セミコロンは文の終端を示しますが、Delphiでは文の区切りです。beginとend.に囲まれた範囲の最後の文についてはセミコロンつけなくてもいいのです。つけたって構いません。
 また、while true do Janken とdoの後にbeginとend;で括ってないのは繰り返したい処理がJankenの一文で書けているからです。

余談2 元へ 「文の定義あれこれ」
 ちなみに文の定義はC/C++やJavaでは、次のようになります。
  @「;」セミコロンで終わる単位(単文)。
  A{と}で囲まれた単位(複文、複数の単文を含みうる)。

 VBなら、「行が変わるか:で区切られる単位。_でつないて複数行にまたがる文もある。」でしょうか。(ちがうかも。詳しくないんで違ってたらごめんなさい。)

余談3 元へ 「式とトークン」
 「式」と「トークン」は「文」より細かい単位です。まず「式」について。プログラミング言語には演算子と呼ばれる記号が定義されています。(通常は意味が決まっていますが、C++やC#などの言語は定義を追加・拡張(オーバーロード)できます。Delphiはだめです。)この演算子が働く単位や変数・定数など「値をもつ単位」を「式」と言います。たとえば整数の変数a:integer;は整数の値を持ちますし、代入演算子「:=」が作る代入式(a:=3など)は代入された値がその値です。  「トークン」は意味のある最小の単位です。カッコの片割れ「(」「)」とか予約語beginとか、変数、「3」など値をずばり示す部分(<=リテラルといいます。定数は値の決まっている文字でリテラルとは別ですよ。)、演算子などです。
 トークンの間に改行やスペースが何個入ってもいい(コンパイラが無視する)ことはよく覚えていてください。このおかげで、僕らは結構気ままに字下げしたり、コードを整形できるのですが、トークンを途中で改行したらコンパイラには認識されません。。

ページtopへ