<4> 動作の概念 (標準 Pascal 範囲内での Delphi 入門)

# 4. 動作の概念
**文 (Statements)** とは動作を記述するもので、**単純文**や**構造文**があります。


## 4.1. 代入文 (Assignment Statement) と式 (Expressions)
**代入文 (Assignment Statement)** は **単純文 \(単文\)** です。単純文とは簡単に言えば **文の中で別の文を実行しない単一の文** です。Pascal での代入文は次のようになります。

```
代入文 = 
  変数 ":=" 式
```

関係演算子の `=` と混同しないように代入記号は `:=` になっています。「何故 `:=` なのか？」と言われても「[数学記号がそうだから](https://ja.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6%E8%A8%98%E5%8F%B7%E3%81%AE%E8%A1%A8)」としか言えません。

**式 (Expressions)** とは、値を返す構文の事です。

```pascal
A := 5;
I := I + 1;
```

標準 Pascal での式の定義は次のようになります。

```
式 =
  単純式 [ "=" | "<>" | "<" | "<=" | ">" | ">=" | "in" 単純式 ].
単純式 =
  [ ("+" | "-") ] 項 { ("+" | "-" | "or") 項 }.
項 = 
  因子 { ("*" | "/" | "div" | "mod" | "and") 因子 }.
因子 =
  符号なし定数 | 限界名 | 変数 | 集合構成子 | 関数呼び出し | "not" 因子 | "(" 式 ")".
符号なし定数 =
  符号なし数　| 文字列 | 定数名 | "nil".
集合構成子 =
  "[" [要素記述 { "," 要素記述 } ] "]".
要素記述 = 
  順序式 [ ".." 順序式 ].
関数呼び出し = 
  関数名 [実パラメータ並び].
```

:::note info
関係演算子 (`=`, `<>`, `<=`, `<`, `>`, `>=`, **in**) は論理型の結果を返します。
:::

式にはいろいろあるので詳しい説明は省きますが、一点だけ。

```pascal
  (X > 0) and (X < 10)
```

このような論理式で X＝0 の場合、`(X < 10)` を評価する必要はないのですが、これを評価するかどうかは処理系依存となります。式全体の結果が既に確定している場合でもすべて評価するのが**完全論理評価**、式を左から順に評価して式の結果が確定した時点で評価を打ち切るのが **短絡論理評価 (ショートサーキット論理評価)** です。

完全論理評価は時として困った問題を引き起こします。例えば `A[]` という配列が 1 から 10 の要素を持っていた場合、

```pascal
  I := 0;
  repeat
    I := I + 1;
  until (I > 10) or (A[I] = 0)
```

I が 11 になった時にも `(A[I] = 0)` が評価され、A[11] を参照してしまいます。Delphi ではブール短絡評価 `{$B-}` 指令により、デフォルトで短絡論理評価となっていますので、A[11] が参照される事はありません。

**See also:**

 - [代入文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#.E4.BB.A3.E5.85.A5.E6.96.87)
 - [代入の互換性 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%9E%8B%E3%81%AE%E4%BA%92%E6%8F%9B%E6%80%A7%E3%81%A8%E5%90%8C%E4%B8%80%E6%80%A7#.E4.BB.A3.E5.85.A5.E3.81.AE.E4.BA.92.E6.8F.9B.E6.80.A7)
 - [演算子 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%BC%8F%EF%BC%88Delphi%EF%BC%89#.E6.BC.94.E7.AE.97.E5.AD.90)
 - [式 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%BC%8F%EF%BC%88Delphi%EF%BC%89)
 - [完全論理評価と短絡論理評価 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%BC%8F%EF%BC%88Delphi%EF%BC%89#.E5.AE.8C.E5.85.A8.E8.AB.96.E7.90.86.E8.A9.95.E4.BE.A1.E3.81.A8.E7.9F.AD.E7.B5.A1.E8.AB.96.E7.90.86.E8.A9.95.E4.BE.A1)
 - [ブール短絡評価（Delphi コンパイラ指令） (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E3%83%96%E3%83%BC%E3%83%AB%E7%9F%AD%E7%B5%A1%E8%A9%95%E4%BE%A1%EF%BC%88Delphi_%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E6%8C%87%E4%BB%A4%EF%BC%89)
 - [Pascal (Delphi) において 1 > 0 という式は、どのように評価されるのか？](https://qiita.com/ht_deko/items/067f81612694f6cd7b79)


## 4.2. 手続き呼び出し文 (Procedure Statement)
**手続き呼び出し文**も単純文です。

例えば標準入力のための Read(), Readln()、標準出力のための Write(), Writeln() は手続きですが、これを記述した文は手続き呼び出し文です。

```pascal
program Hello(output);
begin
  Writeln('Hello, world.');
end;
```

|手続き|説明|
|:---|:---|
|[Read()](http://docwiki.embarcadero.com/Libraries/ja/System.Read)|ファイルからデータを読み込む|
|[Readln()](http://docwiki.embarcadero.com/Libraries/ja/System.Readln)|ファイルからテキストを 1 行読み込む|
|[Write()](http://docwiki.embarcadero.com/Libraries/ja/System.Write)|ファイルにデータを書き込む|
|[Writeln()](http://docwiki.embarcadero.com/Libraries/ja/System.Writeln)|ファイルにテキストを 1 行書き出す|

これらの手続きはファイル変数が指定されていない場合、Read(), Readln() は標準入力からデータを読み込み、Write(), Writeln() は標準出力へデータを出力します。

標準 Pascal の場合、結果が不要でも結果を利用しない関数は呼び出せません。

```pascal
program functiontest(output); 
var
  v: Integer;
  function test: Integer;
  begin
    test := 10;
    v := 5;
  end; { test }
begin
  v := 3;
  test; (* 結果を利用しない関数は呼び出せない *)
  Writeln(v);
end. 
```

この問題を回避するには適当な変数や手続きを用意して読み捨てるのが簡単です。

```pascal
program functiontest(output); 
var
  v: Integer;
  v2: Integer;
  function test: Integer;
  begin
    test := 10;
    v := 5;
  end; { test }
  procedure discard(v: Integer);
  begin
    
  end; { discard }
begin
  v := 3;
  v2 := test;  (* OK *)
  discard(test); (* OK *)
  Writeln(v);
end. 
```

Delphi では拡張構文 `{$X}` がデフォルトで有効 (`{$X+}`) なので、関数の呼び出しを手続きの呼び出しとして使用できます。

**See also:**

 - [拡張構文（Delphi）(DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E6%8B%A1%E5%BC%B5%E6%A7%8B%E6%96%87%EF%BC%88Delphi%EF%BC%89)

## 4.3. 複合文 (Compound Statement) と空文 (Empty Statement)
**複合文 (複文)** は複数の単純文を **begin** と **end** で括ったものです。

```
複合文 = 
  begin 文 {";" 文} end
```

複合文は次のようなコードになります。

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

Pascal におけるセミコロン `;` は文と文を区切る**セパレーター**です。C 言語におけるセミコロンは文末の**ターミネーター**です。Pascal によく似ている [Ada](https://ja.wikipedia.org/wiki/Ada) もセミコロンはターミネーターです。

上記の複合文の改行をなくしてみます。

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

何故最後の `c := 3` の行にセミコロンが不要なのかなんとなく解ったでしょうか？Pascal では次の複合文もエラーにはなりません。

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

これは**空文**があると解釈できます。

```pascal
begin a := 1; b := 2; c := 3; (* ここに空文がある *) end
```

つまり**空の単純文**がある訳です。

:::note info
Pascal のプログラムが `.` (ピリオド) で終わっている事でお解りだとは思いますが、`;` (セミコロン) も英文 (欧文) と同様の使われ方をしています。
:::

**See also:**

 - [セミコロン (Wikipedia)](https://ja.wikipedia.org/wiki/%E3%82%BB%E3%83%9F%E3%82%B3%E3%83%AD%E3%83%B3)
 - [ピリオド (Wikipedia)](https://ja.wikipedia.org/wiki/%E7%B5%82%E6%AD%A2%E7%AC%A6)

## 4.4. 繰り返し文 (Repetitive Statements)
ループ文です。

### 4.4.1. while 文 (While statement)
評価式を判定してから文を実行します。評価式が **True** の間繰り返します。

```
while 文 = 
  while 評価式 do 文
```

先に評価式がきます。単純文の実行はこうなります。

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

複数の文を実行するには、複合文を使います。

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

**See also:**

 - [while 文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#while_.E6.96.87)

### 4.4.2. repeat 文 (Repeat statement )
先に文を実行してから条件を判定します。評価式が **True** になるまで繰り返します。文はセミコロン区切りです。

```
repeat 文 = 
  repeat 文 {";" 文}  until 評価式
```

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

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

**See also:**

 - [repeat 文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#repeat_.E6.96.87)

### 4.4.3. for to do 文 (For statement)
カウンタ用の**制御変数 (Control Variable)** が初期値～終了値の分だけ繰り返します。"初期値 = 終了値" の場合でも 1 回は繰り返すという事です。制御変数は[順序型](https://qiita.com/ht_deko/items/5c04bb2b42947e29d94b#21-%E9%A0%86%E5%BA%8F%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B-%E9%A0%86%E5%BA%8F%E5%9E%8B)である必要があります。

```
for 文 = 
  for 制御変数 ":=" 初期値 to 終了値 do 文
```

単純文の場合は、

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

複数の文を実行するには、複合文を使います。

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

Pascal の **for** 構文は融通が利かず、`初期値 <= 終了値` である必要があります。よって次のコードは正しく実行されません。

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

繰り返しをカウントダウンで使いたい場合には **for** **downto** **do** 構文を使います。

```
for 文 = 
  for 制御変数 ":=" 初期値 downto 終了値 do 文
```


```pascal
  { 正しく実行される例 }
  a := 0;
  for i := 10 downto 1 do (* downto を使う *)
    a := a + i
```

また、制御変数には任意の順序型が使えるため、次のようなコードを書く事も可能です。

```pascal:Alphabet.pas
program Alphabet(output);
var
  c: Char;
begin
  for c := 'A' to 'Z' do
    writeln(c); 
end.
```

結果は次の通りです。

```
A
B
C
︙
Z
```

任意の順序型が使えるという利点を優先したためか、Pascal の **for** 文にはステップ構文もありません。制御変数はループの度に次の値 (**to**) か前の値 (**downto**) になります。

**See also:**

 - [for 文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#for_.E6.96.87)
 - [E2081 for ループ制御変数 '%s' に代入しました (Delphi) (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/E2081_for_%E3%83%AB%E3%83%BC%E3%83%97%E5%88%B6%E5%BE%A1%E5%A4%89%E6%95%B0_%27%25s%27_%E3%81%AB%E4%BB%A3%E5%85%A5%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F_(Delphi))

### (4.4.4.) for in do 文
Delphi (2005 以降) だと **for** **in** **do** 構文で繰り返しコンテナによる反復処理を行えます。

次のパターンで反復処理が可能です。

```pascal
for 要素型 in 配列式 do 文;
for 文字型 in 文字列式 do 文;
for 集合の基底型 in 集合式 do 文;
for 反復型変数 in コレクション式 do 文;
```

データセットを反復処理させる事もできますが、特殊な例なので省きます。

まだ説明されていない型を使っているので、詳細な説明はせずにコード例だけの紹介とします。

**See also:**

 - [for 文を使用したコンテナの反復処理 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#for_.E6.96.87.E3.82.92.E4.BD.BF.E7.94.A8.E3.81.97.E3.81.9F.E3.82.B3.E3.83.B3.E3.83.86.E3.83.8A.E3.81.AE.E5.8F.8D.E5.BE.A9.E5.87.A6.E7.90.86)

#### (4.4.4.1.) 配列式を使った反復処理

```pascal
const
  i_arr: array [0..2] of Integer = (9, 8, 7);
  c_arr: array [0..2] of Char = ('X', 'Y', 'Z');
var
  i: Integer;
  c: Char;
begin
  for i in i_arr do
    Writeln(i);
  for c in c_arr do
    Writeln(c);
end.
```

**See also:**

 - [6.1. 配列型 (Arrays) - <<6> 構造化型の概要と配列型 (標準 Pascal 範囲内での Delphi 入門) (Qiita)](https://qiita.com/ht_deko/items/eedda6d38b6d0887d4ac#61-%E9%85%8D%E5%88%97%E5%9E%8B-arrays)


#### (4.4.4.2.) 文字列式を使った反復処理

```pascal
var
  s: string;
  c: Char;
begin
  s := 'Hello,world.';
  for c in s do
    Writeln(c);
end.
```

**See also:**

 - [(6.2.2.) Delphi の文字列型 (String Types) - <6> 構造化型の概要と配列型 (標準 Pascal 範囲内での Delphi 入門) (Qiita)](https://qiita.com/ht_deko/items/eedda6d38b6d0887d4ac#622-delphi-%E3%81%AE%E6%96%87%E5%AD%97%E5%88%97%E5%9E%8B-string-types)

#### (4.4.4.3.) 集合式を使った反復処理

```pascal
var
  i: Integer;
begin
  for i in [1, 5, 10, 50, 100, 100] do
    Writeln(i);
  Readln;
end.
```

実行結果は次のようになります。

```text
1
5
10
50
100
```

Delphi XE7 以降だと、上記コード中の `[1, 5, 10, 50, 100, 100]` は **配列定数式** と認識されるため、実行結果は次のようになります。

```text
1
5
10
50
100
100
```

Delphi XE7 以降の **for** **in** **do** 構文で反復処理に集合型を使いたい場合には、集合を `(` `)` で括ります。

```pascal
var
  i: Integer;
begin
  for i in ([1, 5, 10, 50, 100, 100]) do
    Writeln(i);
  Readln;
end.
```

上記コードは Delphi XE7 よりも前の Delphi でも問題なく実行できますので、コンパイラバージョンを問わない書き方をしたいのであれば、集合は `(` `)` で括っておくといいかと思います。

**See also:**

 - [<8> 集合型 (標準 Pascal 範囲内での Delphi 入門) (Qiita)](https://qiita.com/ht_deko/items/50bac0de384d66208944)
 - [(6.1.2.2.) 配列定数式 - <6> 構造化型の概要と配列型 (標準 Pascal 範囲内での Delphi 入門) (Qiita)](https://qiita.com/ht_deko/items/eedda6d38b6d0887d4ac#6122-%E9%85%8D%E5%88%97%E5%AE%9A%E6%95%B0%E5%BC%8F-array-constant-expression)

#### (4.4.4.4.) コレクション式を使った反復処理

反復用コレクションは少々複雑です。別記事にサンプルがありますので、そちらを参照してください。

**See also:**

 - [ホクホクのイモを Delphi で書いてみる (Qiita)](https://qiita.com/ht_deko/items/adef65fcb10c0144b3b0)
 - [Delphi 用に FizzBuzz コレクションを作る (Qiita)](https://qiita.com/ht_deko/items/a2016e9e0243e2cf1af6)

### (4.4.5.) break と continue
標準 Pascal にはループを制御するための **Break()** 手続きと **Continue()** 手続きが存在しません。

これらの手続きは繰り返し文の中で作用します。Break() はループを抜ける手続きです。次のコードは 1 から 10 までの値を表示します。

```pascal
program LoopBreak(output);
{$APPTYPE Console}
var
  i: Integer;
begin
  i := 0;
  while True do
  begin
    i := i + 1;
    writeln(i);
    if i >= 10 then
      break;
  end;
end.
```

Continue() は次のループに移動します。次のコードは 1 から 100 までの偶数を表示します。

```pascal
program LoopContinue(output);
{$APPTYPE Console}
var
  i: Integer;
begin
  for i:=1 to 100 do
  begin
    if Odd(i) then
      Continue;
    writeln(i);
  end;
end.
```

**See also:**

 - [Break (DocWiki)](http://docwiki.embarcadero.com/Libraries/ja/System.Break)
 - [Continue (DocWiki)](http://docwiki.embarcadero.com/Libraries/ja/System.Continue)

## 4.5. 条件式 (Conditional Statements)

### 4.5.1. if 文 (If statement )
**if** 文は評価式が **True** の時に文を実行します。評価式が **False** の時には何も実行されないか **else** に続く文が実行されます。

```
if 文 = 
  if 評価式 then 文 [else 文].
```

評価式 は論理型です。評価式の結果が **True** であるなら **then** に続く文を実行します。

```pascal
if a=1 then
  b := 1 
```

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

評価式が **False** の時にも文を実行したいのなら **else** を使います。次の例では評価式が **True** の時に **then** に続く文が実行され、**False** の時には **else** に続く文が実行されます。

```pascal
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
```

空文が許されるので、さらに次のようにも書けます。

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

Pascal におけるセミコロンは文と文を区切るセパレーターなので、最後の文の後ろのセミコロンは付けても付けなくても構いません。

次の図の矩形はすべて文です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/21785/e27012e3-7d9b-6141-fcb8-a7ded93e826f.png)

内側から、緑の矩形が単純文 (代入文)、青の矩形が複合文、赤の矩形が **if** 文です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/21785/1207e236-f00c-e9ff-7277-146cbe141eeb.png)

**See also:**

 - [if 文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#if_.E6.96.87)


### 4.5.2. case 文 (Case statement)
セレクタです。

```
case 文 = 
  case 評価式 of 定数 {, 定数} ":" 文 {"," 定数 {, 定数} ":" 文} end.
```

**選択肢定数**に一致すると、その文を実行し **case** 文の終わりに移動します。

```pascal
  case i of
    1: a := 1;
    2: a := 2;
    3: a := 3 (* <- ここはセミコロンが必須でない *)
  end
```

Delphi だと選択肢定数に一致しなかった時に実行される **else** も使えます。

```
case 文 = 
  case 評価式 of 選択肢定数 {, 選択肢定数} ":" 文 {"," 選択肢定数 {, 選択肢定数} ":" 文} [else 文 {";" 文}] end.
```

**else** 部分にはセミコロンで区切った文が指定できます。

```pascal
  case i of
    1: a := 1;
    2: a := 2;
    3: a := 3 (* <- ここはセミコロンが必須でない *)
  else
    a := 0
  end
```

次の書き方もできますが、ちょっと読みづらいかもしれません。

```pascal
  case i of
    1: a := 1;
    2: a := 2;
    3: a := 3
  else
    begin
      a := 0
    end;
  end;
```

次の図の緑の矩形はすべて文です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/21785/273b910a-5f2a-a1b3-f344-0b685b379d6b.png)

赤の矩形は選択肢定数 (または複数の選択肢定数をカンマで区切った **ケースリスト**) とコロン `:` からなる**ケースラベル**です。ケースラベルとそれに続く文を囲った青い矩形は**ケースセレクタ**です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/21785/df0efefb-e034-2703-d3e6-11bb579b0a41.png)

ケースセレクタもセミコロン区切りです。

Delphi の場合、選択肢定数には[部分範囲型](https://qiita.com/ht_deko/items/335e59857cc78aea951a#52-%E9%83%A8%E5%88%86%E7%AF%84%E5%9B%B2%E5%9E%8B)も使えます。

```pascal
  case i of
    1, 3, 5: 
      a := 1;
    10..20: 
      a := 2;
    50, 75..100: 
      a := 3;
  else
    a := 0
  end;
```

さらに選択肢定数には[定数式](https://qiita.com/ht_deko/items/2d5996cbfc82d734b247#332-%E5%AE%9A%E6%95%B0%E5%BC%8F)が使えます。

```pascal
  case i of
    1 + 2: 
      a := 1;
    Ord('A'): 
      a := 2;
  else
    a := 0
  end;
```

Delphi の **case 文の評価式は 32 ビット以下の順序型** である必要があります。この制限のため、次のようなコードは 64bit アプリケーションにおいて問題が発生する可能性があります。

```pascal
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
  ...

  case Msg.wParam of
    (処理)
  end;

  ...
end;
```

Msg.wparam は NativeUInt 型であり、32bit 環境では UInt32 (Cardinal) ですが、64bit 環境では UInt64 だからです。この問題の簡単な解決方法は、処理を **if 文**で書き換える事です。

**See also:**

 - [case 文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#case_.E6.96.87)

## 4.6. with 文 (With Statement)

**with** 文の詳細については [7.3.](https://qiita.com/ht_deko/items/1d2c85768febc95009bf#73-with-%E6%96%87) 節で。

**See also:**

 - [with  文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#with_.E6.96.87)


## 4.7. goto 文 (Goto Statement)
**goto** 文は単純文で、プログラムの別の場所へジャンプするのに使います。

```
goto 文 = 
  goto ラベル.
```

通常は **if 文**等と組み合わせて使います。

```pascal:GotoTest.pas
program GotoTest(Output);
label
  1, 2,	3, 5, 7, 11, 13, 17, 19, 23;
begin
  goto 17;
1:
  Write('brown ');
  goto 3;
2:
  Write('dog ');
  goto 23;
3:
  Write('fox ');
5:
  Write('jumps '); 
  goto 11;
7:
  Write('lazy ');
  goto 2;
11:
  Write('over ');
  goto 19;
13:
  Write('quick ');
  goto 1;
17:
  Write('The ');
  goto 13;
19:
  Write('the ');
  goto 7;
23:  
  Writeln; 
end.
``` 

上記コードの実行結果は次の通りです。

```
The quick brown fox jumps over the lazy dog
``` 

:::note
標準 Pascal で使えるラベルは数値に限定されますが、**計算型 goto (computed goto)** ではないので、ジャンプ先の指定に変数が使えたりはしません。
:::

**See also:**

 - [goto 文 (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E5%AE%A3%E8%A8%80%E3%81%A8%E6%96%87%EF%BC%88Delphi%EF%BC%89#goto_.E6.96.87)
 - [1.6. ラベル (Labels)](https://qiita.com/ht_deko/items/ce1f56017fb4fcf0302a#16-%E3%83%A9%E3%83%99%E3%83%AB-labels)

### (4.7.1.) Pascal と goto
**goto** 文は例えば多重ループを抜けるのに重宝します。但し、ブロックの内側から外側へ抜けるジャンプは可能ですが、ブロックの内側へ入るようなジャンプはできません。

加えて、Delphi の **goto** は**手続き内 goto (intraprocedural gotos)** であり、手続き/関数の外側へジャンプする事はできません。

**See also:**

 - [Delphi で多重ループを抜ける方法 (Qiita)](https://qiita.com/ht_deko/items/ec4963f6d6ade3db8734)

## (4.8.) 文の正確な定義
Pascal の**文**の正確な定義は次の通りです。

```
文 =
  [ラベル ":"] (単純文 | 複合文).
```

これが何を意味しているのかと言うと、Pascal で**文**と書かれている場所には

 - 単純文 (空文を含む)
 - 複合文
 - ラベル + 単純文
 - ラベル + 複合文

これらのいずれかが記述できるという事です...つまり、**文にはラベルを付けることができます** (ラベルで文を "修飾する" と言います)。Delphi だと次のような記述も可能です。

```pascal:StatementTest1.pas
program StatementTest1(Output);
{$APPTYPE Console}
label
  test;
var
  v: Integer;
begin
  v := 10;

  if Odd(v) then
    goto test;

  if v < 5 then
    test: v := 100; // Statement with Label

  Writeln(v);
end.
```

**case** 文的な記述も可能です。C 言語の **switch** 文をベタ移植する場合には便利かもしれません。

```pascal:StatementTest2.pas
program StatementTest2(Output);
{$APPTYPE Console}
label
  JP1, JP2, JP3;
var
  v: Integer;
begin
  v := 7;

  if Odd(v) then
    goto JP1
  else
    goto JP2;

  JP1:
    begin
       v := 100;
       goto JP3;
    end;
  JP2:
    begin
       v := 200;
       goto JP3;
    end;

  JP3:

  Writeln(v);
end.
```

`StatementTest1.pas` のコードにある **goto** 文の記述 (**then** へのジャンプ) が **"内側のブロックへの goto"** とみなされるかどうかは実装依存だと思われます。

# 索引
[ [← 3. プログラムヘッダと宣言部](https://qiita.com/ht_deko/items/2d5996cbfc82d734b247) ] [ [↑ 目次へ](https://qiita.com/ht_deko/items/e2796788c65c2cda1de5) ] [ [→ 5. 列挙型と部分範囲型](https://qiita.com/ht_deko/items/335e59857cc78aea951a) ] [:sushi:](https://qiita.com/ht_deko/items/2252b6b3079cc834c577)