改めて Delphi の構造化文

 ここにある Tips は "他のサイトのネタとカブらない" ものを気まぐれで載せています。よく躓きそうなものでも、"FAQ サイトではない" という前提に則って掲載されていません。本当に気まぐれですね。

 ...とはいえ、たまには普通の事も書いてみたいと思います。本当に気まぐれですね (w

単純文と複合文

 Delphi...というか Pascal の文法を覚える上で最初に覚えるべきはコレです。まずは単純文を。

a := 1

 a という変数に 1 を代入しているだけですね。Pascal での代入演算子は ":=" です。では、単純文を複数書いてみましょう。

a := 1;
b := 2;
c := 3

 "; (セミコロン)" は文の区切りを表しています。最後の行にセミコロンがありませんが、これはこう解釈します。

a := 1; b := 2; c := 3

 カンマ区切りテキスト (CSV) みたいな感じですね。次は複合文です。

begin
  a := 1;
  b := 2;
  c := 3
end

 複数の単純文を beginend で括ってあるだけです。

begin
  a := 1;
  b := 2;
  c := 3;
end

 単純文の 3 つめの最後にセミコロンを書いてもエラーにはなりません。4 つ目に "空の単純文" があると思えばエラーにならない事が理解できると思います。CSV で考えると

"AAA","BBB","CCC",

 こうなります。単純文だろうが複合文だろうが "文" である という事を頭に入れておいて下さい。単に "文" と言ったら、単純文または複合文を指します。

if 文 と 構造化文

 "文" が理解できればこの後は簡単です。まずは if 文です。if 文の文法はこうです。

if 評価式 then 

 評価式 は Boolean です。評価式の結果が True であるなら "文" を実行します。

if a=1 then
  b := 1 

 a が 1 の時、 b に 1 を代入しています。C 言語等とは異なり、複数の評価式を組み合わせない限り、評価式を () で括る必要はありません。もちろん括っても構いません。評価式が False の時にも "文" を実行したいのなら else を使います。

if 評価式 then 文1 else 文2

 評価式が True の時に "文1" が実行され、False の時に "文2" が実行されます。

if a=1 then 
  b := 1
else
  b := 2

 さて、"Pascal はセミコロンを付ける法則が理解できない" とよく言われるのですが、それは以下のような構文です。

if a=1 then 
  begin
    b := 1;
    c := 1
  end  
else
  begin
    b := 2;
    c := 2
  end

 あなたがコンパイラになったつもりで考えると理解できます。こう考えてみましょう。

if a=1 then 
  begin
    b := 1;
    c := 1
  end
else
  begin
    b := 1;
    c := 1
  end

 緑の箇所は "文1" で、赤の箇所は "文2" です。改行をやめてみると?

if a=1 then begin b := 1 ; c := 1 end else begin b := 1 ; c := 1 end

 規則性が見えてくると思います。ややこしいように見えるのは、"単純文と複合文" の所で書いた "空の単純文" を使う事が多いからです。

if a=1 then 
  begin
    b := 1;
    c := 1;
  end  
else
  begin
    b := 2;
    c := 2;
  end;  

if d=2 then 
  begin
    e := 3;
    f := 3;
  end  
else
  begin
    e := 4;
    f := 4;
  end;  

 if 文の後ろにもセミコロンがありますね。これは "単純文" だろうが "複合文" だろうが "if 文" だろうが、"構造化文" を区切る場合にはセミコロンが必要 というルールです。

if a=1 then begin b := 1 ; c := 1 ; {空の単純文} end else begin b := 2 ; c := 2 ; {空の単純文} end;  
if d=2 then begin e := 3 ; f := 3 ; {空の単純文} end else begin e := 4 ; f := 4 ; {空の単純文} end;
{空の構造化文}  

 構造化文で改行するとこのような解釈になります。通常のコードでは "空の単純文" がふんだんに存在するために規則性を見いだせないだけです。では何故わざわざ "空の単純文" を使うのでしょうか?それは、

begin
  a := 1;
  b := 2
end  

 このようなソースコードで 1 行追加したい場合、2 つめの単純文の後ろに最初からセミコロンがあれば、コピー&ペーストが非常に楽だからです。HTML のスタイルシートを引き合いにしてみると、

a { color: #000000; background-color: #FFFFFF; }

 本来は "background-color" の後のセミコロンは必要ありませんが、大抵付けますよね?それは後から追加するのが簡単になるからです。以上の事から、Pascal では "構造化文" で "インデント (字下げ)" を行うと構造が把握しやすい 事が解ります。

begin
  if a=1 then 
    begin
      b := 1;
      c := 1
    end  
  else
    b := 2;
  if d=2 then 
    f := 3
  else
    begin
      e := 4;
      f := 4
    end
end     

 インデントしないと...

begin
if a=1 then 
begin
b := 1;
c := 1
end  
else
b := 2;
if d=2 then 
f := 3
else
begin
e := 4;
f := 4
end
end     

 何がなんだか判りません。Pascal 初心者の方は begin でインデントをするクセを付けておくといいと思います。それから、中にはこのようなコードを書くヒトもいらっしゃいます。

begin
  if (a = 1then begin
    b := 1;
    c := 1;
  end          
  else
    b := 2;
  if (d = 2then 
    f := 3    // /* ここにセミコロンを付けるとエラーになる。なんで? */
  else begin
    e := 4;
    f := 4;
  end;       // /* ここにセミコロンを付けないと下の if 文が評価されない。 */
  if (g = 3then begin
    h := 5;
    i := 5;
  end
  else begin
    h := 6;
    i := 6;
  end
end 

 アナタは "C / C++ 使い" だと認定されました。オメデトウゴザイマス (^^;A かくいう私も、MS-DOS の頃は "Turbo C++ / Borland C++ / MS C" 使ってましたから気持ちはよーく解ります。

 長々と説明しましたが、要は...

 こういう事です。C / C++ と Pascal ではセミコロンの意味自体が違うのですから、"Pascal のセミコロンの付け方はキモイ" とか言わないで下さい。Pascal に慣れると 、"C / C++ のセミコロンの付け方の方がキモイ" と思えてしまうのですから...えっと、ここはお互い自重しましょうか (w

case 文

 セレクタですね。

case 選択式 of
  11;
  22;
  ...
  n: n;
end  

 または、

case 選択式 of
  11;
  22;
  ...
  n: n;
else
  
end  

 ...となります。ちょっとややこしいのですが、ケースセレクタ ("ケースラベル: 文") も else 部の "文" もセミコロン区切りです。考え方的には、

case 選択式 of ケースセレクタ1 ; ケースセレクタ2 ; ケースセレクタ3 else 文1 ; 文2 end  

 ...なので、

  case i of
    1: a := 1;
    2: a := 2;
    3: a := 3 // <- ここはセミコロンが必須でない事に注目
  else
    a := 0
  end

 とか、

  case i of
    1begin
         a := 1;
         b := 1
       end;  
    2begin
         a := 2;
         b := 2
       end;  
    3begin
         a := 3;
         b := 3
       end // <- ここはセミコロンが必須でない事に注目
  else
    a := 0;
    b := 0
  end

 という事になります。また、

 // 文法エラーの例
  case i of
    1begin
         a := 1;
         b := 1
       end;  
    2begin
         a := 2;
         b := 2
       end;  
    3begin
         a := 3;
         b := 3
       end
  else
    begin // <- 不要
      a := 0;
      b := 0
    end

 else 部に begin は不要です。これでお解りの通り、beginend がワンセットになっている訳ではないので、C / C++ で {} の数を数えるような感じでネストを調べる事はできません。

repeat 文

 ループ構文です。先に文を実行してから条件を判定します。評価式が True になるまで繰り返します。文はセミコロン区切りです。

repeat 1 ; 2 ; ... until 評価式

 以下のコードは変数 a が 9 以上になるまで繰り返されます。

  a := 0;
  b := 0;
  repeat
    a := a + 1;
    b := b + 2
  until a > 9

while 文

 ループ構文です。評価式を判定してから文を実行します。評価式が True の間繰り返します。

while 評価式 do 

 repeat とはちょっと違います。

  a := 0;
  while a < 10 do
    a := a + 1

 または、

  a := 0;
  b := 0;
  while a < 10 do
    begin
      a := a + 1;
      b := b + 2
    end  

 と、なります。while ループで複数の文を実行するには、複合文を使います。whileend ではありません。whilewend でもありません。

for 文

 ループ構文です。カウンタ変数が初期値~終了値の分だけ繰り返します。"初期値 = 終了値" の場合でも 1 回はループするという事です。

for カウンタ変数 := 初期値 to 終了値 do 

 なので、

  a := 0;
  for i := 0 to 9 do
    a := a + i

 または、

  a := 0;
  b := 0;
  for i := 0 to 9 do
    begin
      a := a + i;
      b := b * i
    end  

 と、なります。Pascal の for ループは融通が利かず、"初期値 <= 終了値" である必要があります。よって

  // 正しく実行されない例
  a := 0;
  for i := 10 to 1 do // 終了値よりも開始値が大きい
    a := a + i

 このようなコードは正しく実行されません。ループをカウントダウンで使いたい場合には、

  // 正しく実行される例
  a := 0;
  for i := 10 downto 1 do // downto を使う
    a := a + i

 downto を指定します。文法は同じです。なお、step は用意されていません。

for カウンタ変数 := 初期値 downto 終了値 do 

 お約束ですが、ループ終了後のカウンタ変数の値は不定となります。

その他の文

 簡単な紹介だけに留めます。詳細はヘルプで調べて下さい。

With 文

with オブジェクト1 , オブジェクト2 ..., オブジェクトdo 

 オブジェクトの区切りはカンマです。オブジェクトをカンマで区切った with 文は、以下の with と同等となります。

with オブジェクト1 do
  with オブジェクト2 do
    ...
    with オブジェクトdo
      

for-in-do 文

 "for in do の活用 (Delphi 2005 以降)" を参考にして下さい。

try-except-end 文

 例外処理です。例外が発生した時のみ行う処理を指定できます。

try 例外監視対象処理 except 例外時処理 end 

 "例外監視対象処理 / 例外時処理" 共にセミコロン区切りの文です。

  a := 0;
  try 
    a := 1;
    Image1.LoadFromFile('C:\TEST.BMP')
  except 
    a := 2;
    ShowMessage('Error!') 
  end

try-finally-end 文

 例外処理です。例外が発生しても行う処理を指定できます。

try 例外監視対象処理 finally 例外時処理 end 

 "例外監視対象処理 / 例外時処理" 共にセミコロン区切りの文です。

  a := 0;
  try 
    Bitmap := TBitmap.Create;
    ...
    a := 1  
  finally 
    a := 2;
    Bitmap.Free 
  end

 ざっと構造化文を紹介しましたが、Delphi に慣れている方でも 「文法なんて、そんなの知って...ぇ?」と思うような点があったかもしれませんね。ヘルプやマニュアルでもう一度 Delphi の構文をチェックしてみると、今までに気付かなかった便利な構文があるかも。

See Also:


 BACK