51
25 3 PASCAL 入門 3.1 ここでの目的 ここ PASCAL をするが, PASCAL いてプログラムが けるように るこ , PASCAL , アルゴリズムを 確に きるようにする ある. またプログラム , だけが く他 めるように, わかり すく ある. これら において学 待したい. 3.2 PASCAL をはじめる前に PASCAL によるプログラミングを じめる , けるため 意をする. , トラブルを するため きる った がよい. 各ファイルに , がわかるよう ファイル をつけるこ . 各プログラム にサブデ ィレクト リを するこ ましい. test.p , プログラム .p したファイル けるこ . ったファイル するこ . また, プログラムソースを すくするために, げ 」をきちん するこ . 3.3 PASCAL のプログラムの書き方・実行の方法 コード を するに . 1. エデ ィタ (Mule ) して, プログラムソースを . 2. コンパイラを して, コード を する. 3. した コード を する. , Mule して, hello.p いうプログラムソースを した , これをコンパイルするに , ようにする. % pc hello.p -o hello -o hello いう , コード を hello いう するこ している. , -o hello いう , コンパイラ a.out いう コード を する. ここ した hello するに % ./hello する. ここ , ./ をわざわざ しているこ 意せよ 1 . Exercise 3.3.1 test.p いうプログラムを 1 UNIX カレントディレクトリ デフォールト コマンドサーチパスに ってい いし, ましい.

3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

  • Upload
    hadien

  • View
    228

  • Download
    9

Embed Size (px)

Citation preview

Page 1: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

25

第3章 PASCAL 入門

3.1 ここでの目的

ここでは PASCAL の文法を中心に解説をするが, 単に PASCAL を用いてプログラムが書けるようにな

ることが目的なのではなく, PASCAL の言語構造を理解し, アルゴリズムを正確に記述できるようにする

ことが重要である.

またプログラムは, 自分自身だけが読むものではなく他人にも読めるように, わかりやすく簡潔に書くべ

きである. これらのことを念頭において学ぶことを期待したい.

3.2 PASCAL をはじめる前に

PASCAL によるプログラミングをはじめる前に, 後の混乱を避けるための注意をする. 以下の注意書き

は, 無用なトラブルを回避するためできる限り守った方がよい.

• 各ファイルには, その中身がわかるような簡潔なファイル名をつけること.

• 各プログラム毎にサブディレクトリを作成することが望ましい.

• test.p など, 既存のプログラム名に .p を付加したファイル名は避けること.

• 不要になったファイルは削除すること.

また,プログラムソースを見やすくするために,「字下げ」をきちんとすること.

3.3 PASCAL のプログラムの書き方・実行の方法

実行コードを作成するには以下の手順で行なう.

1. エディタ (Mule など)を利用して,プログラムソースを書く.

2. コンパイラを起動して, 実行コードを作成する.

3. 作成した実行コードを実行する.

例えば, Mule を利用して, hello.p というプログラムソースを作成した時, これをコンパイルするには, 以

下のようにする.

% pc hello.p -o hello

最後の -o hello という部分は, 実行コードを hello という名前で作成することを指示している. もし, -o

hello という部分を省くと, コンパイラは a.out という名前で実行コードを作成する.

ここで作成した hello を実行するには

% ./hello

とする. ここで, ./ をわざわざ指定していることに注意せよ1 .

Exercise 3.3.1 test.p というプログラムを1 UNIX ではカレントディレクトリはデフォールトではコマンドサーチパスには入っていないし, 入れない方が望ましい.

Page 2: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

26 理学部数理学科計算機

% pc test.p -o test

として, 作成して,

% test

とすると, どのようなことが起こるか. それは何故か?

3.3.1 PASCAL の処理系について

講義で利用する PASCAL の処理系は SPARCompiler と呼ばれる SUN MicroSystems が作成したもの

である. この処理系は, ANSI の規格以上の機能を持っているので, ここで作成したプログラムが他の処理

系の上で実行できないこともあり得る.

この講義では, PASCAL の標準仕様内のものと, SPARCompiler 独自のものを区別して利用する. 本来,

標準仕様の内部で利用することが望ましいが, 種々の理由により, 独自拡張の部分も利用する.

3.4 PASCAL の基本的な注意

3.4.1 PASCAL Program の基本的な構造

PASCAL のプログラムは, コメント(注釈), 頭書き,ブロックから構成されている. 頭書きは,プログ

ラムに名前を与え, プログラムのパラメタを並べて書く. ブロックは, 次の6つのセクションにわかれ, 最

後のセクション以外は空でも良いが, セクションは必ず次の順序で書かなければならない.

1. 名札宣言

2. 定数定義

3. 型定義

4. 変数定義

5. 手続きと関数の宣言

6. 文

それぞれの文は ; で終るか, begin と end で囲まれた文の集まりである複合文 で構成されている. ここ

で, C との違いは, ; は文の分離記号であり, 文の終端記号ではない.

3.4.2 Bachus-Naur formula

PASCAL の場合, その構文は Bachus-Naur formula (BNF) と呼ばれるメタ言語によって記述できる.

BNF においては,

::= | { }

は BNF による形式化のメタ記号に属し, PASCAL の記号ではない. {} はその記号の中の0回以上の繰り

返しを表す.

上に述べたプログラムの構造を BNF を利用して記述してみると

Id: P1.tex,v 1.3 2000/04/21 02:09:32 naito Exp

Page 3: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 27

〈プログラム 〉 ::= 〈プログラムの頭書き 〉 〈ブロック 〉 .

〈プログラムの頭書き 〉 ::= program 〈名前 〉 ( 〈ファイル名 〉 { , 〈ファイル名 〉 } ) ;

〈ファイル名 〉 ::= 〈名前 〉

〈名前 〉 ::= 〈英字 〉 { 〈英数字 〉 }

〈英数字 〉 ::= 〈英字 〉 | 〈数字 〉

〈ブロック 〉 ::=

〈名札宣言部 〉 〈定数定義部 〉 〈型宣言部 〉 〈変数宣言部 〉 〈手続きと関数の宣言部 〉 〈文の部 〉

のようになる.

3.4.3 PASCAL で利用できる文字

PASCAL では, 英文字, 数字, 空白文字(スペース, タブなど), 記号文字, 改行文字などが利用できる.

記号文字には特別な意味があることが多いので, 注意すること. また 標準の PASCAL では, 大文字と小文

字は区別されない2 . また, PASCAL のコンパイラにおいて, 日本語が利用できるといっても, 変数名など

に日本語が利用できるわけではないので注意すること.

また, 以下のものは全て空白と見なして無視される.

• 空白文字, 改行文字, タブ, 改ページ記号, コメント.

3.4.4 コメント

コメントとは,プログラミングの補助となるようソースプログラム中に書かれた注釈部分のこと. コンパ

イラは単にこれを無視するので,プログラムには影響を与えない. コメントは, { ではじまり, } で終る. ま

た, { } が利用できないシステムの場合には, (* と *) の対を利用することができる. コメントは入れ子に

はできない3 . 即ち, コメントの中にコメントを入れることはできない.

3.4.5 名前

名前とは, 定数, 型, 変数, 手続き, 関数を表すための名称である. 標準的な PASCAL においては, 名前

の長さには制限はない. また, 名前はどの予約語とも異なった綴りでなくてはならない.

3.4.5.1 特殊記号

特殊記号とは, 英数字以外のうち, PASCAL の文法上特殊な意味を持つものである. 標準 PASCAL の特

殊記号は以下のものである.

〈特殊記号 〉 ::=

+| - | * | / | = | < | > | [ | ] | . | , | := | ; | ; | ( | ) | <> | <= | >= | .. |^| 〈予約語 〉

また SPARCompiler においては, 次の特殊記号が定義されている.

~ & | ! # %

2 今回利用する SPARCompiler では, default では大文字と小文字を区別しているので注意すること. しかしながら, 標準の範囲内で全てを小文字で記述するという考え方をしたほうがよい.3 SPARCompiler においては, /* , */ の対, " で囲まれた部分もコメントとみなされる. その際, 異なった記号によるコメントは

入れ子にできる.

Id: P1.tex,v 1.3 2000/04/21 02:09:32 naito Exp

Page 4: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

28 理学部数理学科計算機

したがって, SPRACompiler での特殊記号の定義は次のようになる.

〈特殊記号 〉 ::=

+| - | * | / | = | < | > | [ | ] | . | , | := | ; | ; | ( | ) | <> | <= | >= | .. |^|~|&| | | ! |#|%| 〈予約語 〉

3.4.5.2 予約語

以下の名前は予約語と呼ばれ, 特別な意味を持ち, 他の名前として利用できない.

and array begin case const div do downto elsefile for forward function goto if in label main mod nil notof or packed procedure program record repeat set then totype until var while with

また, SPARCompiler においては, 次の名前も予約語となっている.

define extern external module otherwiseprivate public static univ

PASCAL においては, 名前の一部に $, _ を使うことできるが, これらの文字を名前の先頭におくことは,

system が既に利用している名前と衝突することが多いので, できる限り避けることが望ましい.

以下の名前は標準 PASCAL において既に使われている名前である.

abs arctan boolean char chr cos dispose eof eoln expfalse get input integer ln maxint new odd ord outputpage pred put read readln real reset rewrite roundsin sqr sqrt succ text true trunc write writeln

また, SPARCompiler においては, 次の名前が既に使われている

FALSE TRUE addr alfa argc argv arshft asl asrassert bell card clock close date discard double exitexpo firstof flush getenv getfile halt in_range index integer16integer32 intset land lastof length linelimit lnot longreal lorlshft lsl lsr max maxchar message min minchar minintnext null open pack random remove return rshft seedshortreal single sizeof stlimit string substr sysclock tab timetrim univ_ptr unpack varying wallclock xor

3.4.5.3 数

PASCAL における数は整数と実数4 のデータ型からなる. それぞれは, 次のように定義される.

〈数字列 〉 ::= 〈数字 〉 { 〈数字 〉 }

〈符号なし整数 〉 ::= 〈数字列 〉

〈符号なし実数 〉 ::= 〈符号なし整数 〉 . 〈数字列 〉

| 〈符号なし整数 〉 . 〈数字列 〉 E 〈桁移動子 〉 〈符号なし整数 〉 E 〈桁移動子 〉

〈符号なし数 〉 ::= 〈符号なし整数 〉 | 〈符号なし実数 〉

〈桁移動子 〉 ::= 〈符号なし整数 〉 | 〈符号 〉 〈符号なし整数 〉

〈符号 〉 ::= +| -

これらの例としては,

1 100 0.1 5E-3 87.35E+8

4 正確には, 「整数と呼ばれるデータ型と実数と呼ばれるデータ型」.

Id: P1.tex,v 1.3 2000/04/21 02:09:32 naito Exp

Page 5: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 29

などがあり, 87.35E+8 とは, 87.35 を 10(+8) 乗したもののことである.

また, SPARCompiler においては, 2 から 36 進数の表現をすることができる. それは, 次のように表現

される

〈拡張された数字列 〉 ::= 〈英数字 〉 { 〈英数字 〉 }

〈BASE〉 ::= 〈英数字 〉

〈符号なし BASE進数 〉 ::= 〈BASE〉 # 〈拡張された数字列 〉

〈符号なし数 〉 ::= 〈符号なし整数 〉 | 〈符号なし BASE進数 〉 | 〈符号なし実数 〉

ここで, 11 から 36 を表すには A から Z を用いる.

また符号なし整数は [0,maxint] の範囲内になければならない.

3.4.5.4 文字列

文字の列を ’ で囲んだものを文字列と呼ぶ. 2個以上の文字列要素を含んだ文字列は, 同じ個数の成分

を持った文字列型の値を表したものである.

〈文字列 〉 ::= ’ 〈文字 〉 〈文字 〉 ’

また, ’ 自身を文字列に入れるには ’’ とする.

3.4.5.5 定数の定義

定数を定義することは, 定数と同義な名前を定義することである.

〈定数名 〉 ::= 〈名前 〉

〈定数 〉 ::= 〈符号なし数 〉 | 〈符号 〉 〈符号なし数 〉 | 〈定数名 〉 | 〈符号 〉 〈定数名 〉 | 〈文字列 〉

〈定数定義 〉 ::= 〈名前 〉 = 〈定数 〉

3.4.6 式

PASCALにおける式とは, 計算規則を表す構成要素である. 式は, その変数が使用時に不定である場合を

除いて, ある値を表す. それを式の値と呼ぶ. 式は演算子と被演算子(変数, 定数, 関数)からなる. また,

演算子には優先順位が付けられている.

Example 3.4.1 次のようなものは式である.

x15sin(x+y)x*yx+y-xx = 1.5

式の構文, 演算子, 優先順位とは後ほど述べることにする.

Id: P1.tex,v 1.3 2000/04/21 02:09:32 naito Exp

Page 6: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

30 理学部数理学科計算機

3.4.7 文

文とは, PASCALプログラムの基本的な単位になるもので, アルゴリズム上の動作単位を表す. また, 記

号 ; は文の区切りを表している.

Example 3.4.2 次は文である.

x := y + z

また, 何も書かれていない文(空文)も存在する.

また, begin と end によって文の集まりを一つの文(複合文)にすることができる.

Example 3.4.3 次は一つの複合文である.

begina := b ;c := d ;

end

3.5 最も簡単なプログラム

はじめに最も簡単と思われるプログラムを書いてみよう.

プログラムを実行すると画面に何かを表示するものである.

Example 3.5.1 もっとも簡単なプログラムの例

{Program 1Hello World. を出力する.

}program Hello_World (output) ;

beginwriteln(’Hello World.’)

end.

以下では, このプログラムの内容を説明する. (ただし, コメント, 空白行は行数として数えない.)

1行目program Hello_World (output) ;

この行がプログラムの頭書きである. プログラムの名前として, Hello_World とした. また, このプログラ

ム中で利用されるパラメタ(関数)として, この場合出力しか行なわないので, output とだけ指定してあ

る. もし, 入力も行なう時には, input も指定しなくてはならない.

2行目と4行目beginend.

で囲まれた部分が「文」となっている. PASCAL においては, 「文の部」の最後の end の後には . をつ

けることに注意しよう. これは, . で文が全て終了することを表している.

Id: P2.tex,v 1.2 2000/04/21 02:10:17 naito Exp

Page 7: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 31

3行目writeln(’Hello World.’)

ここで利用された writeln という手続きは, その引数として, 文字列をとり, その文字列を標準出力に出力

する5 . その際, 出力した文字列の最後に改行文字を出力する. ここで, この文には ; をつける必要がない

ことに注意. begin と end は文をまとめて複合文にするのであるから, わざわざ文の区切り記号である ;

をつける必要はない. もし, つけたとすると, その後に空文があると理解できる.

C で記述されたプログラムなどは, システムに対して戻り値を与えることができる. しかしながら,

PASCAL の言語仕様にはそのようなものは存在しない.

Exercise 3.5.1 Program 1 を真似て, 次のような出力を得るプログラムを書け.

各自の学籍番号 (改行)各自の名前 (改行)何でも好きなこと (改行)

3.6 プログラムの宣言部

Section 3.4.1 で, PASCAL のプログラムは「頭書き」と「ブロック」からなることを述べた. ここでは,

「ブロック」の宣言部がどのようになっているかを見てみよう. BNF による「プログラム」の定義は, 以下

のようになっていた.

〈プログラム 〉 ::= 〈プログラムの頭書き 〉 〈ブロック 〉 .

〈プログラムの頭書き 〉 ::= program 〈名前 〉 ( 〈プログラム引数 〉 { , 〈プログラム引数 〉 } ) ;

〈プログラム引数 〉 ::= 〈名前 〉

〈名前 〉 ::= 〈英字 〉 { 〈英数字 〉 }

〈英数字 〉 ::= 〈英字 〉 | 〈数字 〉

〈ブロック 〉 ::=

〈名札宣言部 〉 〈定数定義部 〉 〈型宣言部 〉 〈変数宣言部 〉 〈手続きと関数の宣言部 〉 〈文の部 〉

以下では, 頭書き, 名札宣言部, 定数定義部, 型宣言部, 変数宣言部の文法を述べておく.

3.6.1 頭書き

頭書きにおける「プログラム名」はプログラム中においては何の意味も持たない. 「プログラム引数」に

は, PASCAL 内部で定義されたもの以外のもの(例えば関数, ファイル名)とプログラムとの結び付きを

要求するものの名称を書いておく. それぞれが, どんな型もののであるかは, 標準名称 input と output を

除いて,プログラムブロックの変数宣言部に記述しておかなくてはならない.

手続き readln, writeln 等を標準入力・標準出力に利用する時には, それぞれ input, output を記述し

ておかなくてはならない.

3.6.2 名札宣言部

プログラム中には後から参照ができるように, 名札を書くことができる. プログラム中で利用する名札

は, 使用する前に名札宣言部において宣言6 をしておかなくてはならない.

5 ここの解説は本当は正しくない. この手続きは「テキスト」ファイルという型の変数に対して動作が定義されているもので, より一般的な記述法がある.6 一般に宣言とは,プログラム中で実際に実行される文ではなく, それ以降に利用する識別子等を定義することをいう.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 8: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

32 理学部数理学科計算機

しかしながら, PASCAL においては名札は goto 文の目印として利用されるだけであり, PASCAL の構

造上, ほとんど goto 文は利用しないので, 事実上名札は利用しない.

名札宣言部は以下のような構文である.

〈名札定義部 〉 ::= 〈空 〉 | label 〈名札 〉 { , 〈名札 〉 } ;

〈名札 〉 ::= 〈数字列 〉

と定義され, 数字列の値は [0, 9999] の範囲内になければならない. さらに, 名札の数字列は, 数値として

同じものであれば, 同じ名札とみなす. すなわち, 7 と 007 は同じ名札を表している.

3.6.3 定数定義部

定数定義部の構文は以下の通りである.

〈定数定義部 〉 ::= 〈空 〉 | const 〈名前 〉 = 〈定数 〉 ; { 〈名前 〉 = 〈定数 〉 ; }

ここで定義した名前(定数名)はその定数と同義語になる. また, 定数とは次のように定義されている.

〈定数 〉 ::= 〈符号なし数 〉 | 〈符号 〉 〈符号なし数 〉 | 〈定数名 〉 | 〈符号 〉 〈定数名 〉 | 〈文字列 〉

〈定数名 〉 ::= 〈名前 〉

すなわち, 定数としてとり得るものは,(符号がついても良い)数, すでに定義されている定数名, もしく

は, 文字列であることがわかる.

Example 3.6.1 次は正しい定数定義である.

const a = 32 ; b = 1.0 ; c = -2.0 ; d = a ; e = -b ; f = ’-----’ ;

3.6.4 型定義部

PASCAL のデータ型は, 変数の宣言において直接記述しても良いし, 型名で参照しても良い. PASCAL

ではすでに定義されている型から新しい型をつくり出す手続きが定義されている. これが型定義である.

〈型定義部 〉 ::= type 〈名前 〉 = 〈型 〉 ; { 〈名前 〉 = 〈型 〉 ; }

〈型 〉 ::= 〈単純型 〉 | 〈構造つきの型 〉 | 〈ポインタ型 〉

この右辺に現れたものは後ほど定義する. また, Example についても, 後ほど説明する.

3.6.5 変数宣言部

PASCAL のプログラム中に現れる全ての変数は必ず変数宣言しなくてはならない. また, 変数はプログ

ラム中で現れる前に, 変数を利用する前に宣言しなくてはならない.

〈変数宣言部 〉 ::= var 〈名前 〉 { , 〈名前 〉 } : 〈型 〉 ; { 〈名前 〉 { , 〈名前 〉 } : 〈型 〉 ; }

Example 3.6.2 以下は正しい変数の宣言である.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 9: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 33

var a, b : integer ;c, d : real ;e : Boolean ;f : char ;

これは, 文法的には, 名前と型を結び付けている(結合)と考えられる. この結合は, その名前を従属する

ブロックで再定義しない限り, その宣言を含むブロック全体で有効である.

また, 同一のレベルで, 同一の有効範囲内においては, 単一の名前は一度しか宣言できない.

3.7 変数とは

変数とは, 識別子によって区別された初期化, 代入などが許される記憶領域のことである. PASCAL の変

数は, 型定義部の定義に述べた通り, 「単純型」, 「構造つきの型」, 「ポインタ型」に分類される. また,

変数定義部の説明で述べた通り, 変数はプログラム中で現れる前に, 変数を利用する前に宣言しなくてはな

らないし, その名前を従属するブロックで再定義しない限り, その宣言を含むブロック全体で有効である.

すなわち, 変数は宣言しなくては利用できなくて, その名前は, より小さなブロックで再定義しない限り有

効である. これは, 変数の「記憶クラス」,「スコープ」,「寿命」と呼ばれる考え方であり, これに関して

は後ほど詳しく述べる.

ここでは,「単純型」のみを扱い, その他の型については後ほど述べることにする.

3.7.1 変数の初期値

PASCAL では全ての変数は, 宣言されただけでは値は定まらない. しかも, 標準的な PASCAL において

は, 変数の宣言と同時に明示的な初期化は行なわれない. したがって, 明示的な初期化の方法としては,

var a,b : integer ;begina := 1 ;b := 1

end ;

といった方法をとらなくてはならない.

しかしながら, SPARCompiler においては, 変数の宣言と同時に明示的な初期化を行なうことができる.

var a,b : integer := 1 ;

このように, 宣言と同時に初期化することもできる. しかしながら, 下の例の場合, 変数 a, b の初期化は

実行時にただ一度だけ行なわれるが, 上の例の場合は, 文を実行されるたびに値が代入されることに注意.

3.7.2 単純型

PASCAL において, 単純型は次のように定義されている.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 10: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

34 理学部数理学科計算機

〈単純型 〉 ::= 〈順序型 〉 | 〈実数型名 〉

〈順序型 〉 ::= 〈書下し順序型 〉 | 〈順序型名 〉

〈書下し順序型 〉 ::= 〈列挙型 〉 | 〈部分範囲型 〉

〈順序型名 〉 ::= 〈型名 〉

〈実数型名 〉 ::= 〈型名 〉

〈列挙型 〉 ::= ( 〈名前 〉 { , 〈名前 〉 } )

〈部分範囲型 〉 ::= 〈定数 〉 .. 〈定数 〉

3.7.2.1 列挙型

列挙型は名前を列挙することによって, 値の順序集合を定義する. 値はそれらの名前が表し, その名称を

列挙した時の並べ方によって, その値の順序が決まる.

Example 3.7.1 次の例は正しい列挙型の定義である.

type color = (white, red, blue, yellow, green, black) ;day = (mon, tue, wed, thr, fri, sat, sun) ;

Example 3.7.2 次の例は間違った列挙型の定義である.

type workday = (mon, tue, wed, thr, fri, sat, sun) ;free = (sat, sun) ;

ここでは, sat の型が曖昧なので, 間違っている.

列挙型の値の順序数は, 名前の順序にしたがって 0 から始まる連続した非負整数値への写像によって決ま

る. したがって, 次に述べる整数型の範囲を越える数の要素を持った列挙型は定義することができない.

また, 順序型に対して, 次の関数を適用することができる.

succ 列挙中の後続値.

pred 列挙中の先行値.

SPARCompiler においては, firstof など, 順序型に適用可能な関数もいくつか用意されている.

3.7.2.2 標準の型

標準の PASCAL においては, 標準の単純型として, 次のものが定義されている.

整数 値は処理系が定義した整数の部分集合. その値は整数.

実数 値は処理系が定義した実数の部分集合. その値は実数で表す.

論理数 値は名前 true と false によって表示される真理値である.

文字 値は処理系が定義した文字集合. それらは文字自身を引用符で囲んで表す.

3.7.2.3 部分範囲型

部分範囲型は, すでに定義されている順序型の部分集合として, その最大値と最小値を指定することに

よって定義される. 両方の定数の値は同一の順序型でなくてはならない. その順序型のことを, 部分範囲型

の親の型という. 最小値は最大値よりも小さいか等しくなくてはならない.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 11: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 35

Example 3.7.3 次は正しい部分範囲型の変数の定義である.

var a : 1..10 ;b : -20..30 ;

これらはいずれも整数の部分範囲型の変数として定義されている.

Example 3.7.4 次は正しい部分範囲型の定義である.

type days = (mon,tue,wed,thr,fri,sat,sun) ;workd = mon..fri ;letter = ’a’..’z’ ;

はじめの定義は列挙型の定義であるが, 2番めのものは型 days の部分範囲として定義されている.

部分範囲型として定義された変数に代入する際には, それを越えた範囲の代入を行なうと実行不可能にな

る可能性がある.

3.7.2.4 整数

整数を表す型は integer であり, それが表す整数の範囲, そのメモリ内での表現方法は処理系ごとに定

義されている. 整数型の値の順序数は, その値そのものである. これを整数型と呼ぶ.

3.7.2.5 実数

実数を表す型は real であり, それが表す実数の部分集合, そのメモリ内での表現方法は処理系ごとに定

義されている. これを実数型と呼ぶ.

3.7.2.6 論理数

論理数を表す型は Boolean であり, これは標準的に

type Boolean = (false, true) ;

で定義されている. すなわち, 標準名 false と true が定義され, さらに, false < true となる順序が入っ

ている. これを論理型 と呼ぶ.

3.7.2.7 文字

文字を表す型は char であり, それが表す文字集合, そのメモリ内での表現は処理系に依存する. これを

文字型と呼ぶ.

文字型が表現する文字集合に対しては, 少なくとも, 以下のものを含む.

• 大文字の英字.

• 10進の数字.

• 空白文字.

それ以外にも, 特殊記号等を含んでいるのが普通である7 . この時, 文字に対する順序数は, 0 から始まる連

続した非負整数値に写像される. この写像は次の性質を満たす.

7 通常, よほどのことがない限り, ASCII 文字集合と等価であると思って間違いないだろう.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 12: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

36 理学部数理学科計算機

• 数字の 0 から 9 を表現する文字の値は, 数の順に順序付けられ連続.

• 大文字の A から Z を表現する文字の値は,(使用可能な時には)アルファベット順であるが, 連続と

は限らない.

• 小文字の a から z を表現する文字の値は,(使用可能な時には)アルファベット順であるが, 連続と

は限らない.

文字型に対しては, 2つの標準関数がある. これらはいずれも文字集合から自然数の部分集合の間の単射

な写像である.

ord 処理系に依存した文字の順序集合において, 文字の順序数を表す.

chr chr(i) は順序数 i をもつ文字を表す.

この2つの関数は互いに逆写像の関係にある. しかも, 文字型は順序型であるので, 標準関数 pred, succ

を利用することができるが,

pred(c) = chr(ord(c)-1)succ(c) = chr(ord(c)+1)

が成り立つ.

3.7.2.8 型の適合性

次の4つのいずれかが成り立つ時, 型 T1 と T2 は適合するという.

(a) T1 と T2 は同じ型である.

(b) T1 が T2 の部分範囲型であるか, T2 が T1 の部分範囲型であるか, T1 と T2 の両方が同じ親の型の

部分範囲型.

(c) T1 と T2 が基底型の適合する集合型であって, 両方とも詰めありか, 両方とも詰めなしである.

(d) T1 と T2 が同数の成分を持つ文字列型である.

3.7.3 変数と記憶領域

変数は宣言と同時に対応する記憶領域が確保される. しかしながら, それぞれの型に対して, どれだけの

記憶領域が確保されるかは処理系に依存している.

3.7.3.1 文字型

文字型を表す記憶領域は, 通常その処理系の扱う文字集合を表すのに必要十分な量が利用される. SPAR-

Compiler の場合, ASCII 文字集合を利用しているので, 文字型の変数の記憶領域は1バイト=8ビットで

ある.

SPARCompiler において, minchar, maxchar, bell, tab と書かれる文字定数が定義されている. それら

の順序数は10進数で

minchar 0,

maxchar 255,

bell 7,

tab 9

である.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 13: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 37

3.7.3.2 整数型

整数型を表す記憶領域は, 文字型の表すそれの整数倍であることが普通である. 特に, 処理系の設計上, 1

バイト, 2バイト, 4バイトなどの 2n バイトを利用することが多い.

SPARCompiler の場合, 整数型の変数の記憶領域は4バイト=32バイトである. この値は, コンパイル

時において -xl オプションを利用すると2バイト=16バイトとなる. このようなコンパイル時における

依存性を避けるため, SPARCompilerにおいては, integer16, integer32 と書かれるそれぞれ16ビット,

32ビット長に固定された整数型が定義されている.

また, maxint, minint と書かれる整数定数が定義され( maxint は標準 PASCAL の範囲で定義されて

いる.)それぞれ, integer 型の表す最大の整数, 最小の整数を表現する.

また, PASCAL においては, C で利用される「符号なし整数」の型は定義されていないが, 部分範囲型を

利用することにより,「符号なし整数」型を定義することも可能である.

3.7.3.2.1 整数の内部表現 整数型の変数の内部での表現は, Section 1.4 で述べた表現がとられているこ

とが多い.

3.7.3.3 実数型

実数型を表す記憶領域は, 文字型の表すそれの整数倍であることが普通である. 特に, 処理系の設計上, 4

バイト, 8バイトなどの 2n バイトを利用することが多い.

SPARCompiler の場合, 実数型 real の変数の記憶領域は8バイト=64ビットである. この値は, コ

ンパイル時において -xl オプションを利用すると4バイト=32ビットとなる. このようなコンパイル時

における依存性を避けるため, SPARCompiler においては, single, shortreal, double, longreal と書

かれるそれぞれ32ビット, 32ビット, 64ビット, 64ビット長に固定された実数型が定義されている.

これらの数を表す表現方法は, 実際には浮動小数点数として表されている. (10を底とする)浮動小数

点数とは, 以下のような型で表現された数のことである.

(0でない1桁の数).<仮数部> × 10^<指数部>

ここで, 任意の 0 でない実数は, このような表示が可能であることに注意せよ. (もちろん, その表示は有

限小数と仮定すれば一意的である.)

3.7.3.3.1 実数型の内部表現 実数型の変数の内部での表現は, Section 1.4 で述べた表現がとられている

ことが多い.

オーバーフロー, アンダーフローをした数の演算, 比較等の結果がどうなるかは規格では定められていな

い. しかし, それぞれの処理系によって規定されている.

3.7.3.4 列挙型

列挙型の変数の記憶領域は, 整数のそれに準じている.

3.8 いくつかの用語

3.8.1 誤り

プログラムの規則に対する違反には次の2種類がある.

• 宣言のない変数の使用等, コンパイル時に検出できる違反.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 14: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

38 理学部数理学科計算機

• 配列の添字の範囲の逸脱等, 実行時でないと検出できない違反.

ここでは,「誤り」という言葉は, 後者の意味で用いる.

3.8.2 不定

変数や駆動結果に値が与えられていないものを「不定」と呼ぶ. 一般に「不定」といった時には, 変数が

値を持っているが, それがどんな値かわからないという意味で利用するが, PASCAL における「不定」と

はもっと強い意味で, 不定の変数に対して比較 x = x を行なうと誤りとなることを意味する.

3.8.3 処理系依存と処理系定義

PASCAL における処理系定義, 処理系依存とは, 言語仕様の中では決めることができず, 各処理系に対し

て自由度を与えなくてはならない部分を示している.

処理系定義とは, 各処理系がその処理系の中では定義が与えられているものを指す. 一方, 処理系依存と

は, 一つの処理系の中でも, その意味を決められないものを表す.

処理系定義の例には次のようなものがある.

• 文字列用の文字の値.

• 実数型の値.

• 文字値の順序数.

この他にも多くの可能性がある.

一方, 処理系依存の例は,

• 演算子のオペランドの評価順序.

• 関数の実引数の評価順序.

• 代入文の左辺と右辺の評価順序.

などがある.

3.9 標準関数と演算子

3.9.1 標準関数

ここまでに述べたもの以外にも, PASCAL で標準的に定義されている関数がある. それらについては,

Jensen-Wirth の付録参照のこと. また, SPARCompiler 独自の関数も数多く定義されている. これらに関

しては, SPARCompiler のマニュアルを参照されたい.

3.9.2 演算子

標準 PASCAL における演算子は, その被演算子の型, 結果の型に応じて, 代入演算子, 算術演算子, 関係

演算子, 論理演算子, 集合演算子に分類される.

全ての二項演算において, 被演算子の評価順序は, 処理系依存である.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 15: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 39

3.9.2.1 代入文

代入の演算子 := を利用した文を代入文と呼ぶ. この被演算子は, その左辺であり, 右辺の値を左辺に代入

する. この時, 被演算子の型は, ファイル型を除く全ての型で有効である. 代入文の構造は次で定義される.

〈代入文 〉 ::= 〈変数 〉 := 〈式 〉 | 〈関数名 〉 := 〈式 〉

3.9.2.1.1 代入可能性 次の5つのうちいずれかが成り立つ時, 型 T2 の値は, 型 T1 に対して代入可能

であるという.

(a) T1 と T2 が同じ型で, その型がファイル型の成分として許されている.

(b) T1 が実数型で T2 が整数型である.

(c) T1 と T2 が適合する順序型で, T2 の値が型 T1 の定める区間内にある.

(d) T1 と T2 が集合型で, T2 の値の全ての元が, 型 T1 の基底型が定める区間内にある.

(e) T1 と T2 が適合する文字列型である.

型 T2 が型 T1 に対して代入可能である時に限り, 型 T1 を持つ変数に型 T2 を持つ値を代入すること

ができる.

代入とは「値を与える」ことであり, 値が不定なものを代入することは誤りである.

3.9.2.2 否定演算子

否定演算子 not は, 一つの論理型の被演算子を持ち, 被演算子の否定を表す.

〈否定演算子 〉 ::= not

3.9.2.3 乗法演算子

乗法演算子とは次で定義されている.

〈乗法演算子 〉 ::= * | / | div | mod | and

それぞれの演算は次のようなものである.

演算子 操作 被演算子の型 結果の型

* 乗算 実数型, 整数型 実数型, 整数型

積集合 任意の集合型 被演算子の型

/ 除算 実数型, 整数型 実数型

div 小数点以下切捨ての除算 整数型 整数型

mod 余り 整数型 整数型

and 論理積 論理型 論理型

ここで, 除算が / と div の2種類があることに注意せよ.

3.9.2.3.1 除算の規定 除算 / においては, x/y の時, y が 0 であれば, それは誤りであり, y が 0 でな

い時, x/y は, x と y で割った結果である.

除算 x div y は, y が 0 であれば誤りであり, そうでなければ, 次の結果を満たす.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 16: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

40 理学部数理学科計算機

abs(i) - abs(j) < abs((i div j) * j) ≤ abs(i)

ここで,標準関数 absは,整数型の引数をとり,その絶対値を整数型として返す. ただし, abs(i) < abs(j)

ならば i div j は 0 である.

剰余 i mod j は, j が 0または負の時には誤りである. そうでなければ, i mod j は次の2つの式を満

たす.

• i mod j = j - (k*j) ただし, k は整数.

• 0 ≤ i mod j < j

したがって, i ≥ 0, j > 0 の時に限って, (i div j) * i + i mod j = i が成り立つ.

3.9.2.4 加法演算子

加法演算子とは次で定義されている.

〈加法演算子 〉 ::= +| - | or

それぞれの演算は次のようなものである.

演算子 操作 被演算子の型 結果の型

+ 加算 実数型, 整数型 実数型, 整数型

和集合 任意の集合型 被演算子の型

- 減算 実数型, 整数型 実数型

差集合 任意の集合型 被演算子の型

or 論理和 論理型 論理型

この時, +, - に関しては, 一つの被演算数しか持たない時には, - は符号の反転を表し, + は恒等変換を

表す.

3.9.2.5 関係演算子

関係演算子とは, 2つの被演算子の間の関係を判定するもので, 次で定義されている.

〈関係演算子 〉 ::= = | <> | < | > | <= | >= | in

それぞれの演算は次のようなものである.

演算子 被演算子の型 結果の型

in 左被演算子:任意の順序型 T 論理型

右被演算子:正規 T 集合型 論理型

=, <> 任意の単純型, ポインタ型, 文字列型, 正規 T 集合型 論理型

<, > 任意の単純型, 文字列型 論理型

<=, >= 任意の単純型, 文字列型, 正規 T 集合型 論理型

演算子 <>, <=, >= はそれぞれ, 等しくない, 等しいか小さい, 等しいか大きいを表す. また, <=, >= が集合

型に適用された時には, 集合の包含関係を表す.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 17: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 41

さらに, p, q が論理式(論理型の値を持つ式)であれば, p=q は論理式の同値性を表す. また, p<=q は, p

ならば q であることを表す. これは, false < true であることから計算される. 論理型の変数に対する

<> は排他的論理和と同義である.

また, 関係演算子を文字列に適用した場合には, いわゆる辞書式順序によって比較が行なわれる.

3.9.2.6 算術演算子と型変換

算術演算子とは, 乗法演算子, 加法演算子のうち, 被演算子として, 整数型または実数型を持つものであ

る. この時, 被演算子として, 整数型もしくは実数型となっているものに対しては, その演算結果は, 両方

の被演算子が整数型であれば, 整数型となり, そうでなければ実数型となる. また, 実数型の変数と整数型

の変数の算術演算を行なう時には, 整数型の変数は, 実数型の値へと自動的に変換を受ける. この型変換は,

PASCAL における自動型変換の唯一の例である. その他の型の間の変換は, 明示的に変換関数を用いなけ

ればならない.

整数型の処理系定義の値 maxint は, 次の条件を満足する.

• 区間 [-maxint, maxint] の中の値は, 全て整数型で表すことができる.

• その区間内の2つの整数値に対する2項算術演算は, その結果も区間内に収まるならば, 整数計算に

おける正しい数学的演算を行なう.

• この区間内の2つの整数値に対する2項関係演算は, 整数計算における正しい数学的演算を行なう.

この規則に当てはまらないものに関しては誤りである.

3.9.2.6.1 変換関数

trunc(x) 式 x の値は実数型. 結果の型は整数型である. trunc(x) の結果は, x が正または0であれば,

0 ≤ x - trunc(x) < 1 を, そうでなければ, −1 < x + trunc(x) ≤ 0 を満たす. そのような値が存

在しなければ, 誤りである. 例えば, trunc(3.5) = 3, trunc(-3.5) = −3 である.

round(x) 式 x の値は実数型. 結果の型は整数型である. round(x) の結果は, x が正または0であれば,

round(x) は trunc(x+0.5) と等価. そうでなければ, round(x) は trunc(x-0.5) と等価である.

そのような値が存在しなければ, 誤りである. 例えば, round(3.5) = 4 である.

ここで, round(-3.5) を考えてみよう. 実数型の値の与え方は, 処理系定義であるので, 実際に 3.5 の値が

3.4999 · · · となってしまうかも知れない. このようなことがありうるので, 注意しなくてはならない.

3.9.3 演算子の優先順位と式

ここで定義した演算子に対しては, その優先順位が定められ, それによって「式」が定義される. 演算子

の優先順位は, 否定演算子, 乗法演算子, 加法演算子, 関係演算子の順に低くなり, 優先順位を持つ演算子の

列は, 左から右に向かって実行される. この場合, 被演算子(オペランド)の評価順序は処理系依存なので,

注意しなくてはならない. (一般に, 式の出現ごとにも異なることがありうる.)これを構文として定義す

ると, 以下のようになる.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 18: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

42 理学部数理学科計算機

〈符号なし定数 〉 ::= 〈符号なし数 〉 | 〈文字列 〉 | 〈定数名 〉 | nil

〈因子 〉 ::= 〈変数 〉 | 〈符号なし定数 〉 | 〈関数呼びだし 〉 | 〈集合 〉 | ( 〈式 〉 ) | not 〈因子 〉

〈集合 〉 ::= [ 〈要素の並び 〉 ]

〈要素の並び 〉 ::= 〈要素 〉 { , 〈要素 〉 }| 〈空 〉

〈要素 〉 ::= 〈式 〉 | 〈式 〉 .. 〈式 〉

〈項 〉 ::= 〈因子 〉 | 〈項 〉 〈乗法演算子 〉 〈因子 〉

〈単純式 〉 ::= 〈項 〉 | 〈単純式 〉 〈加法演算子 〉 〈項 〉 | 〈加法演算子 〉 〈項 〉

〈式 〉 ::= 〈単純式 〉 | 〈単純式 〉 〈関係演算子 〉 〈単純式 〉

ここで, 集合の構成要素となる式は, 全てその集合の基底の型と同一でなくてはならない. [] は空集合を

表し, [x..y] は, 区間 x から y の全ての要素からなる集合を表す.

Example 3.9.1 因子とは,

x15(x+y+z)not p[red,black,green][1..10]

などである. また, 項とは

x*yp or q(x<=y) and (y<z)

などである. 単純式とは

x+y-xi*j-1

などである. 式とは

x = 1.5p<=q(i<j)=(j<k)c in h

である.

この定義により, もっとも優先順位が高いのが not であり, 優先順位がもっとも低いのが関係演算子であ

ることがわかる. もちろん, () を用いることにより, 先に優先順位の低い式を実行することができる.

この定義によると, 式を評価する際には全ての単純式が左から右に向かって評価されることになる.

Example 3.9.2 次のような場合を考えてみよう.

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

この時,

(a > b) and (c < d)

を左から右に評価すると, a > b を評価して, その値が false であることがわかる. したがって, and の

第2被演算子が何であっても, この式の値は false であることがわかる.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 19: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 43

【重要な注意】 PASCAL においては, 二項演算子の評価順序は規定されていない. その意味は, 書かれて

いる順序で評価しても良いし, 逆順に評価しても良いし, 並列に同時に評価しても良い. それどころか, 出

現するたびに評価順序も異なることがある.

一方 C においては, 式の評価順序は確定していて, さらに, 式の値が定まった時点で式の評価を終る. こ

れを短絡評価と呼ぶ. PASCAL においては最後まで式の評価が行なわれるかどうかは不確定である.

また, C とは優先順位が異なることに注意せよ. 例えば, 上と同じことを C では,

a > b && c < d

と書けるが, PASCAL では, and の優先順位が >, < よりも高いので, このままでは文法エラーとなる.

3.9.4 非標準の演算子

SPARCompiler では, 次の演算子が定義されている8 .

演算子 操作 被演算子の型 結果の型

~ bitwise not 整数型 整数型

& bitwise and 整数型 整数型

| bitwise or 整数型 整数型

! bitwise or 整数型 整数型

ここで, bitwise not は否定演算子, bitwise and は乗法演算子, bitwise or は加法演算子として定義されて

いる

3.9.5 非標準の関数など

SPARCompiler では, 次の関数が定義されている9 .

関数名 動作

asl 整数型の変数の左算術シフト

asr 整数型の変数の右算術シフト

lsl 整数型の変数の左論理シフト

lsr 整数型の変数の右論理シフト

3.9.5.1 シフト

整数型の変数に対するシフトとは, 次のようなものである. 前に述べた通り, 整数型の変数は2進数で表

現され, 先頭のビットは符号を表している. その変数を左(右)に 1 シフトするとは, ビット列として各

ビットを左(右)に 1 ずらすことをいう. したがって, 符号ビットを無視すれば, 左に 1 シフトするとは,

その整数に 2 を掛けることに等しく, 右に 1 シフトするとは, 2 で割った商を求めることに等しい.

しかしながら, 先頭に符号ビットがついているので, それらの扱いが問題となるため, 算術シフト, 論理シ

フトの2種類がある. 算術シフトとは, 符号ビットを保存したシフトである.

Example 3.9.3 以下は, それぞれの16ビット整数を右に 1 算術シフトした結果である.

8 その他にも2つほどあるのだが.9 これ以外にもいくつかあるので, それらは SPARCompiler のマニュアルを参照.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 20: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

44 理学部数理学科計算機

シフトする前 シフトした後

1111 1111 1111 1000 1111 1111 1111 1100

0000 0000 0000 1000 0000 0000 0000 0100

同様に算術左シフトとは, 符号を保存して左に 1 シフトする.

Example 3.9.4 以下は, それぞれの16ビット整数を左に 1 算術シフトした結果である.

シフトする前 シフトした後

1111 1111 1111 1000 1111 1111 1111 0000

0000 0000 0000 1000 0000 0000 0001 0000

一方, 論理シフトとは, 符号ビットも含めてシフトする方法である.

Example 3.9.5 以下は, それぞれの16ビット整数を右に 1 論理シフトした結果である.

シフトする前 シフトした後

1111 1111 1111 1000 0111 1111 1111 1100

1000 0000 0000 1000 0100 0000 0000 0100

Example 3.9.6 以下は, それぞれの16ビット整数を左に 1 論理シフトした結果である.

シフトする前 シフトした後

1111 1111 1111 1000 1111 1111 1111 0000

0100 0000 0000 1000 1000 0000 0001 0000

3.10 いくつかのプログラム

ここまででは, 変数の値を表示する方法は述べていなかった. それをするためには, writeln 手続きを

使う.

Example 3.10.1 その利用法は, 次の通りである.

program print_example (output) ;vara : char ;b,c : integer ;x : real ;

begina := ’a’ ;b := 1 ;c := 2 ;x := 1.0 ;writeln(’a = ’,a) ;writeln(’b = ’,b,’ c = ’,c) ;writeln(’b div c = ’,b div c) ;writeln(’b / c = ’,b/c) ;writeln(’x = ’,x)

end.

writeln 手続きの出力の形式については, SPARCompiler の writeln の項を参照せよ. 特に実数の出力

の形式には注意しなくてはならない.

Id: P3.tex,v 1.3 2000/04/21 02:12:24 naito Exp

Page 21: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 45

Exercise 3.10.1 色々な型の演算の値を出力するプログラムを書け.

Exercise 3.10.2 integer 型で表現される最大の数に 1 を加えたらどうなるかを考察せよ.

Exercise 3.10.3 正の浮動小数点数の小数点以下を四捨五入した値を求めるプログラムを書け.

Exercise 3.10.4 正の浮動小数点数の小数点以下第2桁めを四捨五入した値を求めるプログラムを書け.

この際, writeln が浮動小数点数をどのように表示するかを確かめよ. 一般に, 出力関数がどのような仕様

になっているかは処理系依存なので, 浮動小数点数を利用する前に, その辺を確かめておく必要がある.

Exercise 3.10.5 AND, OR, NOT から XOR を作れ.

3.11 文

文とはアルゴリズム上の動作を表す. 文は実行されるものである.

〈文 〉 ::= { 〈ラベル 〉 : } 〈単純文 〉 | 〈構造文 〉

3.11.1 単純文

単純文とは, 他の文を含まないものであり, 空文とは字句を含まない, すなわち, 何もしない文である.

〈単純文 〉 ::= 〈空文 〉 | 〈代入文 〉 | 〈手続き呼びだし文 〉 | 〈goto 文 〉

〈空文 〉 ::=

代入文は前に解説した. 手続き呼びだし文に関しては, 後で説明する.

3.11.1.1 goto 文

goto 文の構文は以下の通りである.

〈goto 文 〉 ::= goto 〈ラベル 〉

しかしながら, goto 文は PASCAL においては, 非常に特別な場合以外には利用しないので, ここでは解

説しない.

3.11.2 構造文

構造文は, 以下の構文を持つ.

〈構造文 〉 ::= 〈複合文 〉 | 〈条件文 〉 | 〈繰り返し文 〉 | 〈with 文 〉

〈文の列 〉 ::= 〈文 〉 { ; 〈文 〉 }

ここで, 文の列は, そこに含まれる文を文面上の順序にしたがって実行する. ただし, goto 文の実行によっ

て変更された場合を除く.

Id: P4.tex,v 1.2 2000/04/21 02:13:09 naito Exp

Page 22: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

46 理学部数理学科計算機

3.11.2.1 複合文

複合文とは, 文の列の実行を指定する.

〈複合文 〉 ::= begin 〈文の列 〉 end

Example 3.11.1 次は複合文である.

begin z := x ; x := y end

3.11.2.2 条件文

条件文は以下の構文を持つ.

〈条件文 〉 ::= 〈if 文 〉 | 〈case 文 〉

3.11.2.3 if 文

if 文とは, 論理式の値によって制御を分岐させるものである.

〈if 文 〉 ::= if 〈論理式 〉 then 〈文 〉 { 〈else 部 〉 }

〈else 部 〉 ::= else 〈文 〉

ここで, if 文の「論理式」の値が true であれば, if 文の「文」が実行される. 「論理式」の値が false の

場合には, if 文の「文」は実行されず, else 部があればその「文」が実行される.

else 部を持たない if 文の直後には字句 else は現れてはならない. これは,

if e1 then if e2 then s1 else s2

if e1 thenbegin if e2 then s2 else s2 end

と解釈するという意味である.

Example 3.11.2 以下は正しい if 文の例である.

if x <> 1.5 then z := x + y else z := 1.5 ;

if x <> 1.5 then z:= x + y

if x <> 1.5 thenif y <> 2.0 thenz:= x + y

else z := yelse z := x

Id: P4.tex,v 1.2 2000/04/21 02:13:09 naito Exp

Page 23: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 47

3.11.2.4 case 文

case 文とは, そこに現れた「選択定数」の値によって, 選択肢を実行する分岐文である.

〈case 文 〉 ::= case 〈選択式 〉 of 〈選択肢 〉 { ; 〈選択肢 〉 } end

〈選択肢 〉 ::= 〈選択定数並び 〉 : 〈文 〉

〈選択式 〉 ::= 〈式 〉

〈選択定数並び 〉 ::= 〈選択定数 〉 { , 〈選択定数 〉 }

〈選択定数 〉 ::= 〈定数 〉

Example 3.11.3 次が case 文の例である.

case x of1: y := x ;2: z := x ;3,4: w := x

end

ここで, case 文に入る時には,「選択式」の値が「選択定数」のいずれかに一致しなくてはならない. そう

でなければ誤りである.

3.11.3 繰り返し文

繰り返し文とは, 指定の条件の下に, 文を繰り返し実行することを指定する.

〈繰り返し文 〉 ::= 〈repeat 文 〉 | 〈while 文 〉 | 〈for 文 〉

3.11.3.1 repeat 文

〈repeat 文 〉 ::= repeat 〈文の列 〉 until 〈論理式 〉

repeat 文の文の列は, 文の列の実行の後に論理式が true となるまで繰り返し実行される. 論理式が文の

列の実行の後に評価されるので, 少なくとも1回は文の列は実行される.

Example 3.11.4 次のプログラムは, 1 から 10 までの和をとる文である.

program sum ;var i,j : integer ;

begini := 0 ; j := 1 ;repeati := i + j ;j := j+1 ;

until j = 11 ;end.

Id: P4.tex,v 1.2 2000/04/21 02:13:09 naito Exp

Page 24: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

48 理学部数理学科計算機

3.11.3.2 while 文

〈while 文 〉 ::= while 〈論理式 〉 do 〈文 〉

while 文

while b do body

beginif b thenrepeat bodyuntil not(b)

end

と等価である. すなわち, 論理式が最初に評価され, true であれば, 文が実行され, false ならば実行はさ

れない. したがって,「文の列」は一度も実行されないことがある.

Example 3.11.5 次のプログラムは, 1 から 10 までの和をとる文である.

program sum ;var i,j : integer ;

begini := 0 ; j := 1 ;while j <= 10 do begini := i + j ;j := j+1 ;

endend.

3.11.3.3 for 文

for 文とは, 制御変数が表す変数に一連の値を与えながら文を繰り返し実行することを指定する.

〈for 文 〉 ::= for 〈制御変数 〉 := 〈初期値 〉 { to | downto } 〈終値 〉 do 〈文 〉

〈制御変数 〉 ::= 〈純変数 〉

〈初期値 〉 ::= 〈式 〉

〈終値 〉 ::= 〈式 〉

〈純変数 〉 ::= 〈変数名 〉

for 文は, 以下の制限を持つ.

• 制御変数はその for 文を直接に含むブロック内の変数宣言部で宣言されたものを名称とする変数でな

ければならない.

• 制御変数の型は順序型でなければならない. 初期値, 終値はその型に適合しなければならない.

• for 文の文が1回でも実行されるなら, 初期値と終値は制御変数の型に対して代入可能でなければな

らない.

また, for 文の実行後, その制御変数の値は不定となる. ただし, goto 文で抜け出した場合は除く.

for 文の内部の文 S で制御変数 V に対して, つぎに挙げることをしてはならない.

• S が代入文であり, V に値を代入する.

• S が for 文であり, V は S の制御変数である.

Id: P4.tex,v 1.2 2000/04/21 02:13:09 naito Exp

Page 25: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 49

• S が関数の実引数である.

• S が手続き read または readln の実引数である.

これらの制約を除けば,

for v := e1 to e2 do body

は, 順序型の変数 v を初期値 e1 から, 終値 e2 まで, 関数 succ を利用して一つずつ動かしながら文 body

を実行する. 特に, 上の制約を除き, 次の文と等価である.

begint1 := e1 ;t2 := e2 ;if t1 <= t2 thenbeginv := t1 ;repeatbody ;v := succ(v) ;

until v > t2end ;

また,

for v := e1 downto e2 do body

は, 順序型の変数 v を初期値 e1 から, 終値 e2 まで, 関数 pred を利用して一つずつ動かしながら文 body

を実行する.

Example 3.11.6 次のプログラムは, 1 から 10 までの和をとる文である.

program sum ;var i,j : integer ;

begini := 0 ;for j:=1 to 10 doi := i + j ;

end.

Example 3.11.7 次のプログラムは, 1 から 10 までの和をとる文である.

program sum ;var i,j : integer ;

begini := 0 ;for j:=10 downto 1 doi := i + j ;

end.

このように, for 文では, 制御変数を 1 刻みにしか動かせないので, それ以外の時には while 文, または

repeat 文を利用することとなる.

3.11.3.4 with 文

with 文に関しては, 後ほど述べる.

Id: P4.tex,v 1.2 2000/04/21 02:13:09 naito Exp

Page 26: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

50 理学部数理学科計算機

3.11.4 演習問題

ここの演習問題は, ここまでに学んだ繰り返し文や条件文を使って書くことができる.

はじめに演習問題をやるために必要な関数について注意しておく.

3.11.4.1 数値を入力する

標準入力から整数数値を入力するためには, readln を使う.

readln(v)

利用法は, 以下の通り.

Example 3.11.8 標準入力から整数を読んで, それを出力する.

var n : integer ;beginreadln(n) ;writeln(n)

end.

3.11.4.2 乱数の発生

random という(SPARCompiler に付属の)関数は real 値の乱数を発生させる. 通常, 次のようにして

使う.

Example 3.11.9 乱数を2つ発生させる.

var n : integer ;r, s : real ;

beginn := seed(wallclock) ;r := random(n) ;s := random(n) ;

end.

(SPARCompiler に付属の)関数 seed の部分は, 乱数を初期化する部分で, 現在の時刻から決まる数を

使って初期化をしている. また, random の引数 n は特に意味はないが, 文法上必要なものである. ここで,

発生する乱数は 0 から 1 の間の数が出てくる.

Exercise 3.11.1 repeat 文, while 文, for 文を利用して, 2 から N 迄の偶数の和を計算して出力するプロ

グラムを書け.

Exercise 3.11.2 摂氏と華氏の温度対応は, ◦C = (5/9)(◦F − 32) である. 華氏の温度(整数)を入力し

て, 摂氏の温度を印字するプログラムを書け. その際, 摂氏の温度として, 小数点以下切捨て, 小数点以下四

捨五入, 小数点以下第2桁めを四捨五入の3種類を書け.

Exercise 3.11.3 非負の integer 型の数値を入力して, それを2進数で表示するプログラムを書け.

Exercise 3.11.4 0 から 1 までの乱数を十分沢山発生させ, その値が 0.5 未満の確率を表示するプログラ

ムを書け.

Exercise 3.11.5 浮動小数点数に対しては, 1 + ε = 1 となるような数が存在する. このような ε の上限を

求めるプログラムを書け.

Id: P4.tex,v 1.2 2000/04/21 02:13:09 naito Exp

Page 27: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 51

Exercise 3.11.6 for 文

for v := e1 downto e2 do body

と等価な repeat 文を作れ.

3.12 構造つきの型

構造つきの型は, 構造型, レコード型, 集合型, ファイル型に分類される.

〈構造型 〉 ::= 〈書き下し構造型 〉 | 〈構造型名 〉

〈構造型名 〉 ::= 〈型名 〉

〈書き下し構造型 〉 ::= { packed } 〈詰めなし構造型 〉

〈詰めなし構造型 〉 ::= 〈配列型 〉 | 〈レコード型 〉 | 〈集合型 〉 | 〈ファイル型 〉

書き下し構造型に packed がある場合には, その型は「詰めあり」と呼ばれる. 構造型に対する詰めあ

りの指定は, 値のデータ領域を節約するように処理系に指示する働きがあり, その型の変数に対する演算な

どが高速に行なわれる可能性がある10 .

3.12.1 配列型

配列 (array) 型は, 添字型で示される値から個々の成分への写像としての構造を持つ. 各成分は配列型の

成分型の型表記で示される型を持つ.

〈配列型 〉 ::= array [ 〈添字型 〉 { , 〈添字型 〉 } ] of 〈成分型 〉

〈添字型 〉 ::= 〈順序型 〉

〈成分型 〉 ::= 〈型 〉

Example 3.12.1 例えば, integer 型の添字 0 から 9 までを持つ配列型の変数 digit は次のように定義

される.

var digit : array [0..9] of integer ;

この時, 添字型 0..9 は整数型の部分範囲型として決めている.

digit[0] digit[1] digit[2] digit[3] digit[4] digit[5] digit[6] digit[7] digit[8] digit[9]

その他にも, 次のようなものも定義できる.

array [Boolean] of color

ここで, 型名 color は, 正当に定義された型であるとしている.

二つ以上の「添字型」の列を指定する配列型は, 次のような配列型の省略記法である.

• 「添字型」はもとの配列型の最初の「添字型」である.

• 「成分型」はもとの指定の2番め以降の「添字型」の列を持ち, もとの指定と同じ「成分型」を持つ

配列型である. この「成分型」は, もとの配列型が詰めありの時に限り, 詰めありとなる.

次の2つの例は, それぞれ同じ配列型の異なる表現法を表す.

10 SPARCompiler では, packed には何も効果がない.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 28: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

52 理学部数理学科計算機

Example 3.12.2  

array [Boolean] of array [1..10] of array [size] of realarray [Boolean] of array [1..10,size] of realarray [Boolean,1..10] of array [size] of realarray [Boolean,1..10,size] of real

Example 3.12.3  

packed array [1..10,1..8] of Boolean ;packed array [1..10] of packed array [1..8] of Boolean ;

Example 3.12.4  

var str : array [0..1][0..9] of integer ;

str[i] は, 10 個の要素を持つ配列となる.

str[0] [0] str[0] [1] str[0] [2] str[0] [3] str[0] [4] str[0] [5] str[0] [6] str[0] [7]

str[1] [0] str[1] [1] str[1] [2] str[1] [3] str[1] [4] str[1] [5] str[1] [6] str[1] [7]

str[0] [8] str[0] [9]

str[1] [8] str[1] [9]

配列型の変数の値は次のようにして定義される. 配列型の添字型の値の最小値を m, 最大値を n とした時,

k = ord(n)−ord(m)+1 とおき, 配列型の値は, 成分型の値の k 個の組である. それを, v = (v1, · · · , vk)

と書いた時, 配列型の変数 v の値は v であり, v[i] は vord(i)−ord(m)+1 を表す. このような, 配列型の

成分を表す変数を添字つき変数と呼ぶ.

〈成分変数 〉 ::= 〈添字つき変数 〉 | 〈フィールド表記 〉

〈添字つき変数 〉 ::= 〈配列変数 〉 [ 〈添字式 〉 { , 〈添字式 〉 } ]

〈添字式 〉 ::= 〈式 〉

〈配列変数 〉 ::= 〈変数 〉

配列型の変数の値は, その成分が全て定義されている時に限り, 決まっている.

これらの配列の定義は, コンパイル時に配列の大きさが決定できることが必要であり, 実行時に配列の大

きさを変更したりすることはできない.

2つ以上の添字を持つ配列(多次元配列)の添字の評価順序は処理系依存である.

3.12.1.1 配列型の例

ここでは, real 型の配列をベクトルと思い, その和を計算してみよう.

program sum_of_vector ;vara,b,c : array[1..3] of real ;i : integer ;

begina[1] := 1.0 ; a[2] := 1.0 ; a[3] := 2.0 ;b[1] := 2.0 ; b[2] := 0.0 ; b[3] := 3.0 ;for i:=1 to 3 doc[i] := a[i] + b[i] ;

end.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 29: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 53

3.12.2 文字列型

文字列型とは, 次のような詰めありの配列型である.

• 「添字型」は最小値が 1 で, 最大値が 1 より大きいような部分範囲型.

• 「成分型」は文字型.

文字列型は, その値をテキストファイルに書くことができる, 関係演算子が利用できるという意味で, 通

常の配列型とは異なった性格を持つ.

3.12.2.1 文字列の例

ここでは, 文字列型の変数に文字を代入して, 出力をしてみる.

program output_of_string (output) ;vars : packed array [1..30] of char ;i : integer ;

beginfor i := 1 to 30 dos[i] := chr(ord(’A’) + (i-1)) ;

writeln(s) ;end.

この例で, 30 まで値を与えなかった時, SPARCompiler は値が与えられた範囲のみを出力する. また,

SPARCompiler では, 次のような特別な型が用意されている.

型名 内容

alfa 長さ 10 の文字列型

string 長さ 80 の文字列型

varying 可変長の文字列型,

varying[u] と定義した時, 長さ u の文字列型を表す.

u は 0 から 65535 まで.

ただし, これらの型で指定した文字列を writeln で出力する時には, それぞれの型で結果が異なることが

あるので注意すること.

varname1 : packed array [1..25] of char ;name2 : packed array [76..100] of char ;name3 : alfa ;name4 : string ;name5 : varying [25] of char ;name6 : varying [25] of char ;

beginname1 := ’a’ ;name2 := ’a’ ;name3 := ’a’ ;name4 := ’a’ ;name5 := ’a’ ;name6 := ’a’ ;writeln(name1, ’ and ’, name2) ;writeln(name3, ’ and ’, name4) ;writeln(name4, ’ and ’, name6)

end.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 30: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

54 理学部数理学科計算機

3.12.2.2 配列と文字列の初期化

SPRACompiler では, 配列, 文字列を宣言と同時に初期化できる.

varint : array [1..10] of integer = [maxint,1,-375,5,20] ;ch : packed array [1..10] of char = ’ABCDEF’ ;int2 : array [1..*] of integer = [maxint,1,-375,5,20] ;ch2 : packed array [1..*] of char = ’ABCDEF’ ;

ここで, * が利用されている例では, 初期化が同時に行なわれているので, 必要最小限の量の配列が自動的

に確保される.

varint : array [1..100] of integer = [50 of 1,50 of 2] ;

この例では, 最初の 50 個に 1 が, 次の 50 個に 2 が入る.

varint : array [1..100] of integer = [* of 1] ;int2 : array [1..10, 1..10] of integer = [[* of 1], [3 of 8], [10 of 88],] ;

二つめの例では, 第1列の全てに 1 が, 第2列の最初の3つに 8 が, 第3列の全てに 88 が入る.

このように, SPARCompiler では, 配列を宣言と同時に初期化する場合には, 配列の大きさをわざわざ書

かなくても済むのだが, やはりコンパイル時に配列の大きさが決定されていることに注意. 決して, 実行時

に配列の大きさを変更できているわけではない.

3.12.3 集合型

集合型は, ある基底の型のベキ集合としての構造を持つ. 集合型の各々の値は, 基底型の値を元とする集

合である.

〈集合型 〉 ::= set of 〈基底型 〉

〈基底型 〉 ::= 〈順序型 〉

次は, 集合型の例である.

set of char ;set of (club, diamond, heart, spade) ;

各順序型 S に対して, 正規 T 集合型と呼ばれる集合型が存在する. もし, S が部分範囲型であれば, T は

その親の型であり, そうでなければ, T は S である. 正規 T 集合型とは,

A : set of 1..5 ;B : set of 2..9 ;

に対して, A and B が定義できるようにした仮想的な型のことである.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 31: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 55

3.12.3.1 集合型の例

program set_operation ;typedays = (mon,tue,wed,thr,fri,sat,sun) ;week = set of days ;

varwk,work,free : week ;d : days ;

beginwork := [] ;free := [] ;wk := [mon..sun] ;d := sat ;free := [d] + free + [sun]

end.

この例では, 曜日の列挙型 days と, その集合型 week を定義している. さらに, week 型の変数 wk, work,

free を定め, 最終的に, free は要素 sat と sun を持つ集合型となっている.

3.12.3.2 集合型の内部表現

集合型の変数は, 内部では次のように表現されている. 例えば,

T : set of T0

となっているとしよう. この時, T0 が N(T0) 個の要素を持つとすると, T の型の変数のメモリ領域は,

少なくとも N (T0) ビット必要である. 実際には, 中途半端なビット数のメモリ領域は利用できないので,

SPARCompiler では, 少なくとも16ビット, さらに, 16ビットの倍数のメモリ領域が利用され, その最

大は256ビットである.

3.12.4 レコード型

レコード型とは一つの型の中に必ずしも同一の型ではない決まった数の成分を持つような型のことであ

る. それぞれの成分をフィールド (field) と呼ぶ.

〈レコード型 〉 ::= record 〈フィールド並び 〉 end

〈フィールド並び 〉 ::= { 〈固定部 〉 { ; 〈可変部 〉 }| 〈可変部 〉 }{ ; }

〈固定部 〉 ::= 〈レコード要素 〉 { ; 〈レコード要素 〉 }

〈レコード要素 〉 ::= 〈名称並び 〉 : 〈型表記 〉

〈可変部 〉 ::= case 〈可変要素選択子 〉 of 〈可変要素 〉 { ; 〈可変要素 〉 }

〈可変要素選択子 〉 ::= { 〈タグフィールド 〉 : } 〈タグ型 〉

〈タグフィールド 〉 ::= 〈名称 〉

〈可変要素 〉 ::= 〈選択定数並び 〉 : ( 〈フィールド並び 〉 )

〈タグ型 〉 ::= 〈順序型名 〉

〈選択定数並び 〉 ::= 〈選択定数 〉 { , 〈選択定数 〉 }

〈選択定数 〉 ::= 〈定数 〉

固定部も可変部も持たないフィールド並びは, 成分を持たず, 値は空値ただ1種類を持つ. このような

フィールド並びは空であるという.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 32: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

56 理学部数理学科計算機

Example 3.12.5 例えば, 固定部のみからなるレコード型は次のようなものである.

recordyear : 0..3000 ;month : 1..12 ;day : 1..31

end

これは, フィールドとして, year, month, day を持ち, それぞれが integer 型の部分範囲型として定義さ

れている.

m 個の成分を持つ空でないフィールド並びの値は, 次の m 組である. ただし, Vi はそのフィールド並び

の i 番めの成分である.

(V1, · · · , Vm)

可変部を直接に含むフィールド並びは, その可変部に対応した一つの成分を持つ. この成分の値と構造は,

その可変部によって定義される.

Example 3.12.6 可変部を含むレコード型は次のようなものである.

typemonth_type = 1..12 ;days_type = record

year : 0..3000 ;case days : month_type of

1,3,5,7,8,10,12 : (days_1 : 1..31) ;4,6,9,11 : (days_2 : 1..30) ;2 : (days_3 : 1..28)

end

可変部の値は, 可変部の選択子の値 k と可変部の有効な可変要素のフィールド並びの値 Xk によって決ま

る (k,Xk) である.

Example 3.12.7 固定部と可変部を持つレコード型の例は次のようなものである.

recordx, y : real ;area : real ;case shape ofrectangle : (side1, side2 : real ; skew : angle) ;circle : (diamiter : real)

end

この例では,「可変要素選択子」で「タグフィールド」を利用していない. この時, x をこの型の変数と

すると, x.side1 を利用すると, それは 可変部が rectangle であるとみなされる. 可変部が rectangle

の時, diamiter は有効ではない.

レコード型の変数の各フィールドの値は, そのフィールド名を変数名のあとに . を使ってつなぐことによ

り得ることができる.

〈フィールド表記 〉 ::= 〈レコード変数 〉 . 〈フィールド指定部 〉 | 〈フィールド表記名 〉

〈レコード変数 〉 ::= 〈変数 〉

〈フィールド指定部 〉 ::= 〈フィールド名 〉

〈フィールド名 〉 ::= 〈名称 〉

ここで, 可変部の選択子が不定であれば, 可変部のどの可変要素も有効ではない. また, フィールド名は

変数名とは別の名前空間に属するので, 次のような名前の与え方は間違いではない.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 33: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 57

a : recorda : real ;b : real ;

end ;b : integer ;

Example 3.12.8 この例は, 固定部と可変部を持つレコード型を定義し, そのフィールドに値を代入して

いる.

program record_test ;typeb_year = 1..4 ;m_year = (m1,m2) ;d_year = (d1,d2,d3) ;b_or_m_or_d = (bachler,master,doctor) ;person = record

name : recordfirst, family : string ;

end ;id : string ;case kind : b_or_m_or_d ofbachler : (gakunen_b : b_year) ;master : (gakunen_m : m_year ;

boss_m : string) ;doctor : (gakunen_d : d_year ;

boss_d : string)end ;

varp : array [1..100] of person ;

beginp[1].name.first := ’Masashi’ ;p[1].name.family := ’Kubo’ ;p[1].id := ’9400001’ ;p[1].kind := doctor ;p[1].gakunen_d := d3 ;p[1].boss_d := ’Prof. Ihara’

end.

また, 可変部の指定で, 次のようなものは誤りである.

recordcase digit : integer of1 : (S1 : array[1..1] of char) ;10 : (S2 : array[1..2] of char) ;100 : (S3 : array[1..3] of char)

end

これは, タグフィールドがとびとびの値しかとっていない.

3.12.4.1 レコード型の変数の内部表現

レコード型の変数はメモリ内で, 可変部がどのような状態であっても, それを格納するために十分なメモ

リ領域が使用される. しかしながら, メモリ内でフィールド並びの順にならんでいるとは限らない.

3.12.4.2 with 文

with 文は次のような構文を持つ.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 34: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

58 理学部数理学科計算機

〈with 文 〉 ::= with 〈レコード変数 〉 { , 〈レコード変数 〉 } do 〈文 〉

これは, 指定したレコード変数に対して, そのフィールド名を指定するだけで, 各レコード変数のフィー

ルドをアクセスするための構文である.

Example 3.12.9 次の代入は Example 3.12.8 の例の代入と等価である.

with p[1],name dobeginfirst := ’Masashi’ ;family := ’Kubo’ ;id := ’9400001’ ;kind := doctor ;gakunen_d := d3 ;boss_d := ’Prof. Ihara’

end

with 文中において, レコード変数を変更してはならない.

3.12.5 ファイル型

ファイル型は, 指定された成分型の列を, 列中の現在の位置, 及び, 列が検査中か生成中かを示すモードも

含めて表現するものである.

〈ファイル型 〉 ::= file of 〈成分型 〉

ただし, 成分型として次のようなものは許されない.

• ファイル型.

• 成分の型表記の中にファイル型の成分型として許されないものがある構造型.

Example 3.12.10 次のようなものはファイル型の例となる.

file of realfile of vector

要素が文字であるファイルをテキストファイルといい, そのために標準の型 text を

type text = file of char ;

と定義する.

3.12.6 ポインタ型

ポインタ型とは, nil 値, もしくは指示値の値を持つ変数である. 指示値とは, ポインタ型の被指示型の

変数を指示する. nil は指示値ではない.

〈ポインタ型 〉 ::= 〈書き下しポインタ型 〉 | 〈ポインタ型名 〉

〈書き下しポインタ型 〉 ::= ^ 〈被指示型 〉

〈被指示型 〉 ::= 〈型名 〉

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 35: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 59

3.12.6.1 被指示変数

被指示変数は, そのポインタ変数の値が指示する変数を表す.

〈被指示変数 〉 ::= 〈ポインタ変数 〉 ^

〈ポインタ変数 〉 ::= 〈変数 〉

3.12.6.2 バッファ変数

ファイル変数はファイル型の変数であり, バッファ変数はファイル変数が表す変数と結合された変数であ

る. テキストファイルのバッファ変数は文字型である. それ以外の場合には, ファイル変数の持つ成分型で

ある.

〈バッファ変数 〉 ::= 〈ファイル変数 〉 ^

〈ファイル変数 〉 ::= 〈変数 〉

3.12.7 配列型・レコード型変数の代入

配列型, レコード型変数は, それらの間に代入可能性があれば, 次のようにして代入をすることができる.

program a_test (output) ;type

ax = array [1..10] of integer ;bx = record

a : integer ;b : real ;

end ;

vara0,a1 : ax ;b0,b1 : bx ;i : integer ;

beginfor i:=1 to 10 dobegin

a0[i] := i ;end;b0.a := 100 ;b0.b := 0.125 ;a1 := a0 ;b1 := b0

end.

3.12.8 演習問題

Exercise 3.12.1 integer 型の数値を入力して, それを次のような平衡3進展開を行なうプログラムを書

け. ここで, 整数 n の平衡3進展開とは, n =∑tk3k, tk = −1, 0, 1 と展開することで,プログラムの出力

には, −1 を n, 0 を z, 1 を p と表せ. 例えば, 5 = 9− 3− 1 であるので, pnn と表すことができる.

Exercise 3.12.2 2× 2 行列の和と積を計算するプログラムを書け.

Id: P5.tex,v 1.2 2000/04/21 02:14:33 naito Exp

Page 36: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

60 理学部数理学科計算機

Exercise 3.12.3 集合 A = {1, 2, 3}, B = {2, 3, 4} の和集合 A∪B, 積集合 A∩B, 差集合 A−B, B−A,

対称差 (A−B) ∪ (B −A) を求めるプログラムを書け.

Exercise 3.12.4 複素数を表すレコード型の変数を定義し, その和, 差, 積を計算するプログラムを書け.

3.13 関数と手続き

プログラムは一連の計算のステップによって記述されるが, それらの中では, いくつかの部分的な仕事に

分割し, それぞれをプログラム部分として定義することが可能である.

このようなプログラムの部分的な仕事を手続きもしくは関数としてはっきりとした部分として定義する

ことができる.

3.13.1 手続き

手続き宣言はプログラムの一部分を定義するものであり, 手続き呼びだし文によって, それらを実行する

ことができる.

この宣言は,プログラムと同一の形式であり,プログラムの頭書きの変わりに手続きの頭書きを利用する.

〈手続き宣言 〉 ::= 〈手続き見出し 〉 ; 〈指令 〉 | 〈手続き表示 〉 ; 〈手続きブロック 〉

| 〈手続き見出し 〉 ; 〈手続きブロック 〉

〈手続き見出し 〉 ::= procedure 〈名前 〉 ( { 〈仮パラメタ節 〉 { ; 〈仮パラメタ節 〉 }} )

〈手続き表示 〉 ::= procedure 〈手続き名 〉

〈手続き名 〉 ::= 〈名前 〉

〈手続きブロック 〉 ::= 〈ブロック 〉

〈指令 〉 ::= 〈英字 〉 { 〈英字 〉 | 〈数字 〉 }

〈仮パラメタ節 〉 ::= 〈パラメタ群 〉 | var 〈パラメタ群 〉 | 〈関数引数仕様 〉 | 〈手続き引数仕様 〉

〈パラメタ群 〉 ::= 〈名前 〉 { , 〈名前 〉 } : 〈型名 〉

〈手続き引数仕様 〉 ::= 〈手続き見出し 〉

〈関数引数仕様 〉 ::= 〈関数見出し 〉

手続きを呼び出す場合には, その手続きは呼び出す以前に宣言されていなければならない. 従って, 2つ

の手続きもしくは関数をお互いに呼びあう場合などには問題が生じる. その場合に利用されるのが, 指令

forward である. 指令 forward のついた手続き宣言は, その手続きブロックが後方にあってもよいが,

どこかに手続きブロックが存在しなければならない.

3.13.1.1 手続きブロックでの宣言

手続きブロック内で宣言されたラベル, 定数, 型, 変数は, そのブロック内でのみ有効であり, そのブロッ

ク外からは参照できない. このようなものを, 局所的に定義されているという. 例えば, 局所的に定義され

た変数は局所変数と呼ぶ. また, 外のブロックと同じ名前で宣言されたものがある場合には, より内部で定

義されたものが有効となる. これを(変数の)隠蔽と呼ぶ.

局所変数はプログラムの実行中には, その局所変数を定義するブロックを駆動中の時のみメモリ内に存

在する. それ以外の時には, その局所変数はメモリ内には存在しない.

ただし, SPARCompiler の static をつけて宣言された局所変数は, そのブロックの駆動中以外でもメ

モリ内には存在しているが, 外部のブロックからは見ることができない. このような, その変数がどこのブ

Id: P6.tex,v 1.1 2000/04/20 12:28:08 naito Exp

Page 37: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 61

ロックから参照可能かの概念を, 変数のスコープと呼ぶ. また, どのような時に変数がメモリ内にあるかの

概念を変数の寿命と呼ぶ.

3.13.1.2 手続きの仮パラメタ節と呼びだし

手続きの仮パラメタ節中で定義された変数は, 局所変数と同様に扱うことができる. 実際に, 手続き呼び

だし文において書かれた変数を実引数と呼ぶ.

〈手続き呼びだし文 〉 ::= 〈手続き名 〉 〈実引数並び 〉

〈実引数並び 〉 ::= ( 〈実引数 〉 { , 〈実引数 〉 } )

〈実引数 〉 ::= 〈式 〉 | 〈変数 〉 | 〈手続き名 〉 | 〈関数名 〉

ただし, 手続き read, readln, write, writeln の場合には, 少々定義が異なる.

仮パラメタとしては, 単に変数が書かれた時(値引数), var が指定されている時(変数引数), 手続

き名が指定されている時(手続き引数), 関数名が指定されている時(関数引数)によって, 呼び出しの方

法が異なる.

3.13.1.2.1 値引数 値引数の場合には, 仮パラメタ節に記述された型と同値な型を持つ値であることが

必要である. この場合, 手続きにはその値のみが渡される. これを値呼びだし (call by value) と呼ぶ.

3.13.1.2.2 変数引数 変数引数の場合には, 仮パラメタ節に記述された型と同値な型を持つ変数である

ことが必要である. この場合, 手続き中ではその変数が参照されている. (具体的には, 変数のアドレスが

渡される.)これを参照呼びだし (call by address) と呼ぶ.

3.13.1.2.3 手続き引数 この場合には, 実引数の手続きは手続きを呼び出したブロックで定義されてい

なければならない. 手続き中では, その実引数を表している.

3.13.1.2.4 関数引数 この場合には, 実引数の関数は手続きを呼び出したブロックで定義されていなけ

ればならない. 手続き中では, その実引数を表している.

3.13.1.3 手続きの副作用

参照呼び出しで渡した変数は, 手続き内ではもとの変数を参照しているので, 手続き内で変更をした場合

にも, もとの変数が変更されている. これを手続きの副作用と呼ぶ.

3.13.2 関数

関数は式の評価で利用するために, 単一のスカラ値, もしくはポインタ値を計算するプログラムの一部分

である. 関数宣言は関数を定義するものであり, 関数呼びだし文によって, それらを実行することができる.

この宣言は,プログラムと同一の形式であり,プログラムの頭書きの変わりに関数の頭書きを利用する.

Id: P6.tex,v 1.1 2000/04/20 12:28:08 naito Exp

Page 38: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

62 理学部数理学科計算機

〈関数宣言 〉 ::=

〈関数見出し 〉 ; 〈指令 〉 | 〈関数表示 〉 ; 〈関数ブロック 〉 | 〈関数見出し 〉 ; 〈関数ブロック 〉

〈関数見出し 〉 ::= function 〈名前 〉 ( { 〈仮パラメタ節 〉 { ; 〈仮パラメタ節 〉 }} )

〈関数表示 〉 ::= function 〈関数名 〉

〈関数名 〉 ::= 〈名前 〉 : 〈結果型 〉

〈関数ブロック 〉 ::= 〈ブロック 〉

〈結果型 〉 ::= 〈単純型名 〉 | 〈ポインタ型名 〉

この定義を見ればわかるように, ほとんど手続きと同じであるが, その値を返すことだけが異なる.

結果の型としては, 単純型及びポインタ型以外を返すことはできない.

関数に関することは, 値を返すこと以外は全て手続きと同じである.

〈関数呼びだし文 〉 ::= 〈関数名 〉 〈実引数並び 〉

3.13.3 手続きと関数の例

Example 3.13.1 以下の手続きと, それを呼び出しているプログラムは, 与えられた2つの integer 型の

変数のうち小さくない方を表示するものである.

program print_max (output) ;varx,y : integer ;

procedure print_max(x,y : integer) ;varz : integer ;

beginif (x < y) thenwriteln(y)

elsewriteln(x) ;

end ;

beginx := 1 ;y := 2 ;print_max(x,y)

end.

Example 3.13.2 この例では, 2つの integer 型の変数の和を返す関数を記述している.

Id: P6.tex,v 1.1 2000/04/20 12:28:08 naito Exp

Page 39: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 63

program print_sum (output) ;varx,y : integer ;

function return_max(x,y : integer) : integer ;beginreturn_max := x + y ;

end ;

beginx := 1 ;y := 2 ;writeln(return_max(x,y))

end.

Example 3.13.3 この例は, 配列をベクトルと思い, それの長さを返し, さらに, それに直交するベクトル

を一つ求めている11 .

program vector (output) ;typevector = array [1..2] of real ;

varx,y : vector ;r : real ;

function get_norm_and_normal (a : vector ; var b : vector) : real ;beginb[1] := a[2] ;b[2] := (-1)*a[1] ;get_norm_and_normal := sqrt(a[1]*a[1] + a[2]*a[2]) ;

end ;

beginx[1] := 1.0 ;x[2] := 0.0 ;r := get_norm_and_normal(x,y) ;writeln(’length of (’,a[1],’,’,a[2],’) = ’,r) ;writeln(’normal of (’,a[1],’,’,a[2],’) = (’,b[1],’,’,b[2],’)’) ;

end.

このように, 関数の結果型とはなり得ないものを求めるには, 関数もしくは手続きの副作用を利用するこ

とができる.

Example 3.13.4 この例は, 異なった関数に対して, f(x) + g(y/2) の値を求める関数である.

11 本当はちょっと問題のある計算である.

Id: P6.tex,v 1.1 2000/04/20 12:28:08 naito Exp

Page 40: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

64 理学部数理学科計算機

program sum_of_function_values (output) ;varx,y : real ;

function sin_ft(a : real) : real ;begin

sin_ft := sin(a) ;end ;

function cos_ft(a : real) : real ;begin

cos_ft := cos(a) ;end ;

procedure ch(var a : real) ;begin

a := a/2.0 ;end;

function sum_of_function_values (a,b : real;procedure ch (var a : real) ;function f(a : real) : real ;function g(a : real) : real ) : real ;begin

ch(b) ;sum_of_function_values := (f(a) + g(b)) ;

end ;

beginx := 0.0 ;y := 1.0 ;writeln(x,y,sum_of_function_values(x,y,ch,sin_ft,cos_ft)) ;

end.

Example 3.13.5 この例は, 上の例と同じ結果をもたらすが, forward を利用している.

Id: P6.tex,v 1.1 2000/04/20 12:28:08 naito Exp

Page 41: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 65

program sum_of_function_values (output) ;varx,y : real ;

procedure ch(var a : real) ; forward ;

function sin_ft(a : real) : real ;begin

sin_ft := sin(a) ;end ;

function cos_ft(a : real) : real ;begin

cos_ft := cos(a) ;end ;

function sum_of_function_values (a,b : real;

function f(a : real) : real ;function g(a : real) : real ) : real ;begin

ch(b) ;sum_of_function_values := (f(a) + g(b)) ;

end ;

procedure ch ;begin

a := a/2.0 ;end;

beginx := 0.0 ;y := 1.0 ;writeln(x,y,sum_of_function_values(x,y,sin_ft,cos_ft)) ;

end.

3.14 再帰的関数呼びだし

前の section で解説した関数, 手続きは, それ自身をその内部で呼び出すことができる. これを再帰的関

数呼び出し (recursive function call) と呼ぶ.

再帰的関数呼び出しを利用すると, 帰納的に定義されたものを計算することが容易になる. 数学的には,

再帰で計算できるものは必ず再帰を利用しなくても計算できることが証明されているが, 再帰で計算する

とプログラムが簡潔になるという利点がある. 一方, 関数, 手続き等を呼び出す際には, 多くの処理系にお

いて呼び出しの手順として時間がかかることが多い. したがって, 再帰には時間がかかることが多い.

Example 3.14.1 次は, 帰納的に定義された数列 an+1 = an + 2, a1 = 1 の an を求める関数である.

function recursive_function(n : integer) : integer ;beginif (n = 1) thenrecursive_function := 1

elserecursive_function := recursive_function(n-1) + 2 ;

end ;

Id: P6.tex,v 1.1 2000/04/20 12:28:08 naito Exp

Page 42: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

66 理学部数理学科計算機

3.14.1 演習問題

Exercise 3.14.1 二つの複素数を与えた時, その和, 差, 積等を計算するプログラムを手続きもしくは関数

を利用して書け.

Exercise 3.14.2 Fibonacci 数列を計算するプログラムを書け.

Exercise 3.14.3 与えられた整数係数 n× n 行列( n はプログラム中で指定して良い)の行列式を計算

するプログラムを書け.

3.15 ファイル入出力

ファイルへの入出力を行なうには, ファイル型変数と, read, write 手続きを利用する.

ファイル変数を宣言すると, その要素の型を持ったバッファ変数が自動的に定義される. それをファイル

変数 f に対して f^ と表す. バッファ変数は, ファイルに対して既存の要素を読みだしたり, 書き出したり

することができる窓であると理解する. この窓は, ファイル演算によって自動的に移動する.

3.15.1 ファイル処理の関数と演算子

バッファ変数 f^ がファイル f の終りを通過すれば, 標準の論理関数 eof (f) は true を返し, そうでな

ければ false となる.

ファイル演算子には標準的には次のものがある.

reset(f,filename) 読み込みを開始するために, バッファ変数を初期化する. すなわち, f の最初の要素

に f^ をセットする. f が空でなければ eof(f) は false となる. f が空であれば f^ は不定となり,

eof(f) は true となる.

rewrite(f,filename) ファイル f の書換えをするには, reset(f) の代わりにこれを用いる. このとき,

eof(f) は true となる.

get(f) バッファ変数を次の要素に進める. すなわち, 次の要素の値をバッファ変数に代入する. そのよう

な要素がなければ, バッファ変数の値は不定となり, eof(f) は true となる.

put(f) ファイルにバッファ変数の値を付け加える. これは, 実行の直前で eof(f) が true の時に限り定

義される. その結果は eof(f) が true となり, バッファ変数の値は不定となる.

実際には, get(f), put(f) の代わりに手続き read, write を用いる. それぞれは, 次と等価である.

read(f,x): x := f^ ; get(f)

write(f,x): f^ := x ; put(f)

Example 3.15.1 この例は, integer からなるファイルを作成し, そこからデータを読み出している.

Id: P7.tex,v 1.2 2000/04/21 02:15:10 naito Exp

Page 43: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 67

varf : file of integer ;i, n : integer ;

beginrewrite(f,’integer_file’) ;for i:=1 to 10 dowrite(f,i) ;

close(f) ;reset(f,’integer_file’) ;while (not(eof(f))) dobeginread(f,i) ;writeln(i) ;

end ;close(f)

end.

利用したファイルは利用後にその利用が終ったことを OSに対して知らせることが必要になることがおお

い. そのために利用するのが close(f) という手続きで, この手続き自身は SPARCompiler で定義されて

るものだが, 多くの処理系で対応するものが存在する. また, open 手続きというのもあり, reset, rewrite

よりも細かいファイルの制御が可能になる.

PASCAL は OS との関係については, その仕様には全く含まれないので, このような OS に関係する部

分に関しては, 処理系定義となることが多い.

3.15.2 テキストファイル

テキストファイルに対しては, writeln, readln, eoln が利用できる.

eoln(f) テキストファイル f が現在の行の終りに達したかどうかを判定する. true ならば, バッファ変数

は行末に位置している.

writeln(f,x) テキストファイル f に対して, x を出力し, 現在の行を終了する. すなわち, 行末文字を印

字する.

readln(f,x) テキストファイル f に対して, x を読み, 次の行の先頭まで読みとばす. バッファ変数は次

の行の最初の文字となる.

ここで, ファイル変数が省略された場合には, writeln は標準出力に対して, readln は標準入力に対して

行なわれる. また, SPARCompiler では標準エラー出力は errout と書かれる.

3.15.2.1 read, readln

手続き read, readln は,

read(file,v1,v2,v3)

といった書き方ができる. この場合, ファイルから, v1, v2, v3 を一度に読むことを指示している.

3.15.2.2 write, writeln

手続き write, writeln は,

write(file,v1,v2,v3)

といった書き方ができる. この場合, ファイルに v1, v2, v3 を書き出すことを指示している.

また, これをテキストファイルに適用する場合には, その引数として,

Id: P7.tex,v 1.2 2000/04/21 02:15:10 naito Exp

Page 44: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

68 理学部数理学科計算機

e:A:B

といった型をとれる. ここで, A, B は書き出す長さを指定する部分であり, その default の値は処理系定義

である.

e はファイルに書き出す値を表した式であり, その型は, 整数型, 実数型, 文字型, 論理型, 文字列型でな

くてはならない.

3.15.2.2.1 文字型の時 文字型の時,

e:A

という型をとり, ファイルに書き出される表現は

• (A− 1) 個の空白,

• e の文字値

である.

3.15.2.2.2 文字列型の時 文字列型の時,

e:A

という型をとり, e のあらわす文字列を, つぎのようにして書く. ここで, L をその文字列の長さとする.

1. A > L の時.

• (A− L)個の空白.

• e を順に並べたもの.

2. A ≤ L の時.

• e を順に A 番めまで並べたもの.

3.15.2.2.3 論理型の時 論理型の時,

e:A

という型をとり, e の値を文字列 true もしくは false を利用して書かれる. その文字列は, A を利用して

書かれる. この時, 文字列が大文字になるか, 小文字になるかは処理系定義である.

3.15.2.2.4 整数型の時 整数型の時,

e:A

という型をとり, e の10進表現がファイルに書かれ, A に関しては, 次のようになる.

1. A ≥ IntDigit +1 の時.

• (A− IntDigit− 1) 個の空白,

• e が負の時, 符号 -, それ以外の時空白

• IntDigit 桁の abs(e) の10進表現

2. A < IntDigit +1 の時.

• e が負の時, 符号 -, それ以外の時空白

• IntDigit 桁の abs(e) の10進表現

ここで, IntDigit は, その絶対値を10進表現するために必要な最小の桁数.

Id: P7.tex,v 1.2 2000/04/21 02:15:10 naito Exp

Page 45: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 69

3.15.2.2.5 実数型の時 実数型の時には, 浮動小数点表現と固定小数点表現がある.

3.15.2.2.5.1 浮動小数点表現

e:A

という型をとり, e の浮動小数点表現がファイルに書かれ, A に関しては, 次のようになる.

• 符号. e <0 かつ, eWritten > 0 の時 -, それ以外の時空白,

• eWritten の10進表現の第1桁めの数字,

• 文字 .,

• eWritten の10進表現の第2桁め以降の DecPlaces 個の数字,

• 処理系定義の指数部表現 e または E,

• ExpValue の符号, ExpValue < 0 の -, それ以外の時 +,

• ExpValue の ExpDigit 桁の10進表現. (必要なら先頭に文字 0 が並ぶ).

ここで, ExpDigit は処理系定義の値. eWritten, DecPlace, ExpValue は, 次のように定義されている.

• 整数 X に対して, TenPower(X) を 10 の X 乗の値 (実数).

• 実数 X に対して, RealSize(X) を, 次のような整数 Z: TenPower(Z-1) ≤ abs(X) < TenPower(z).

• 実数 X, 整数 Y に対して, Truncate(X,Y) を X の小数点以下 Y 桁より下を切捨てた実数の値.

とする. この時, ActWidth を

if A >= ExpDigit + 6 then ActWidth := Aelse ActWidth := ExpDigit + 6 ;

で定義する. これで, eWritten, DecPlace, ExpValue は,

DecPlace := ActWidth - ExpDigit - 5 ;if e = 0.0 thenbegineWritten := 0.0 ; Expvalue = 0

endelsebegineWritten := abs(e) ;ExpValue := RealSize(eWritten) - 1 ;eWritten := eWritten / TenPower(ExpValue) ;eWritten := eWritten + 0.5 * TenPower(-DecPlace) ;if eWritten >= 10.0 thenbegineWritten := eWritten / 10.0 ;ExpValue := ExpValue + 1 ;

end ;eWritten := Truncate(eWritten,DecPlace) ;

end.

Example 3.15.2 例えば, 10.255 という値を writeln(x:9) で表示すると, 1.03e+10 となる. ExpDigit

= 2 とすると, ActWidth = 9, DecPlace = 2, eWritten = 1.0300, ExpValue = 1 となる. 9 は全部の

出力する文字数を表し, 符号(1桁), 小数点の記号(1桁), e(1桁), 指数部(符号を含む)(3桁)の

桁数を引いた残りの桁 9-1-1-1-3 = 3 桁の仮数部を出力する. その際に, 仮数部の 3 + 1 = 4 桁めを四

捨五入している.

Id: P7.tex,v 1.2 2000/04/21 02:15:10 naito Exp

Page 46: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

70 理学部数理学科計算機

3.15.2.2.5.2 固定小数点表現

e:A:B

という型をとり, e の固定小数点表現がファイルに書かれ, A に関しては, 次のようになる.

• A ≥ MinNumChar なら (A− MinNumChar) 個の空白,

• 符号. e <0 かつ, eWritten > 0 の時 -,

• eWritten の10進表現の最初の IntDigit 個の数字,

• 文字 .,

• eWritten の10進表現のその次の B 個の数字.

ここで, ExpDigit は処理系定義の値. eWritten は, 次のように定義されている. TenPower, RealSize,

Truncate は前と同じ. これで, eWritten は,

if e = 0.0 thenbegineWritten := 0.0

endelsebegineWritten := abs(e) ;eWritten := eWritten + 0.5 * TenPower(-B) ;eWritten := Truncate(eWritten,B) ;

end.

であり, IntDigit は,

if RealSize(eWritten) < 1 thenIntDigit = 1

elseIntDigit = RealSize(eWritten) ;

MinNumChar は,

MinNumChar := IntDigit + B + 1 ;if (e < 0.0) and (eWritten > 0) thenMinNumChar := MinNumChar + 1 ;

Example 3.15.3 例えば, 10.255という値を writeln(x:3:1)で表示すると, 10.3となる. ここの x:3:1

の最初の 3 は, 全部の桁数を表し, 後ろの 1 は小数点以下の桁数を表している. ExpDigit = 2 とすれば,

eWritten = 10.3, IntDigit = 2, MinNumChr = 4 となる. おおよそ, 上から 3+1=4 桁めを四捨五入して

いる. 実際には, writeln(10.25:3:1) は 10.2 を出力し, writeln(10.250000000000001:3:1) は 10.3

を出力する.

Remark 3.15.1 SPARCompilerでは, writeln 手続きの桁指定子に関してはもっと多くの自由度がある.

詳しくは SPARCompiler のマニュアルを参照.

3.15.3 演習問題

Exercise 3.15.1 標準入力から入力されたファイルの行数を印字するプログラムを書け.

Exercise 3.15.2 標準入力から入力されたファイルの行数, 単語の数,文字数を印字するプログラムを書け.

Exercise 3.15.3 標準入力から入力された1文字が英字でなければ, そのまま印字し, 大文字の英字なら

小文字に, 小文字の英字なら大文字を印字するプログラムを書け. ただし, 改行だけが入力された場合には,

終了するようにしなさい. また, 入力された文字は ASCII コードで表現されていることに注意せよ.

Id: P8.tex,v 1.2 2000/04/21 02:17:03 naito Exp

Page 47: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 71

3.16 いくつかのデータ構造

レコード型を利用すると, アルゴリズムの実現に役立つリスト (list), ツリー (tree) といったデータ構造

を実現することができる.

これらのデータ構造は, そのデータ量があらかじめわかっているならば, ポインタを利用せずに実現でき

るが,データ量がアプリオリにはわからない時にはポインタを使わざるをえない. ここでは, これらのデー

タ構造が, どのようなものかを見ていこう.

3.16.1 リスト

リストとは,データが一列につながったものである. 各データは次のデータへのポインタを持ち, 最後の

データが持つ次のデータへのポインタは何も指し示していないという形で実現できる. リストになったデー

タを操作するには, ポインタを動かせば良い.

具体的には, 次のような形式になっている.

3.16.1.1 ツリー

ツリーとは, 各データが1つ以上の他のデータへのポインタを持ったものである. 各データは他のデータ

へのポインタを持ち, 最後のデータが持つ他のデータへのポインタは何も指し示していないという形で実

現できる.

具体的には, 次のような形式になっている.

3.16.1.2 自己参照

レコード型は, それ自身を参照することができる. これを利用して, リストやツリーといったデータ構造

を実現することができる.

例えば, リストを実現するには, 次のような方法を利用する.

Example 3.16.1 整数と, 次のデータへのポインタを持った構造体は以下のように定義できる.

Id: P8.tex,v 1.2 2000/04/21 02:17:03 naito Exp

Page 48: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

72 理学部数理学科計算機

typelink = ^data ;data = record

str : integer ;next : link ;

end ;

このように定義したレコード型を利用して, リストを実現することができる.

Example 3.16.2 Example 3.16.1 で定義した構造体を初期化する. 即ち, 一番始めのデータには何も入れ

ない. はじめに, このようにして定義した自己参照レコード型の変数を確保するために, 手続き new を行な

う. 次に必要なことは, 一番最後のデータ(最初は一番はじめのデータと同じ)にデータを入力したら, も

う一つデータを持ってきて, それを初期化することである.

program list (output) ;type

link = ^data ;data = record

str : integer ;next : link ;

end ;

varfirst, p, q : link ;i : integer ;

beginnew(first) ;first^.next := nil ;for i:= 1 to 10 dobegin

new(p) ;p^.next := first ;p^.str := i ;first := p ;

end ;q := p ;while(q^.next <> nil) dobegin

writeln(q^.str) ;q := q^.next ;

end;end.

このようにして作ったリスト形式のデータを一番最初のデータから順にアクセスするためには, 最初のデー

タを指し示すポインタを作成して, next が次のデータを指ししていることを利用して, ループを使ってア

クセスすれば良い.

Example 3.16.3 ここでは, リストの途中にデータを挿入するための手順を示している.

Id: P8.tex,v 1.2 2000/04/21 02:17:03 naito Exp

Page 49: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 73

program list (output) ;type

link = ^data ;data = record

str : integer ;next : link ;

end ;

varfirst, p, q, r : link ;i : integer ;

beginnew(first) ;first^.next := nil ;for i:= 1 to 10 dobegin

new(p) ;p^.next := first ;p^.str := i ;first := p ;

end ;q := p ;while(q^.next <> nil) dobegin

writeln(q^.str) ;q := q^.next ;

end;writeln ;new(r) ;r^.str := 11 ;q := p ;q := p^.next ;r^.next := q^.next^.next ;q^.next := r ;q := p ;while(q^.next <> nil) dobegin

writeln(q^.str) ;q := q^.next ;

end;end.

この例では, 前から2番めに新しいデータを挿入している.

p

p

p^.next

r^.next

r

ここで確保したメモリ領域は, 必要がなくなったら, dispose 手続きで領域を開放する.

Example 3.16.4 各データが2つのポインタを持ったツリーを実現するには, 次のようなデータ形式を利

用すれば良い.

Id: P8.tex,v 1.2 2000/04/21 02:17:03 naito Exp

Page 50: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

74 理学部数理学科計算機

typelink = ^data ;data = record

str : integer ;lnext : link ;rnext : link ;

end;

3.16.2 演習問題

Exercise 3.16.1 標準入力から, 空白で区切られた学籍番号, ID, 氏名の組を読み込み, それらをレコード

型の配列として格納し, 標準出力に以下のフォーマット (format)(書式)で出力するプログラムを書け.

学籍番号: xxxxxID : xxxxx氏名 : xxxxx

この際, 入力するデータの数は 100 以下と仮定して良い.

Exercise 3.16.2 Exercise 3.16.1 の問題をリスト形式で書け. この時は, 入力するデータの数はアプリオ

リにはわからない.

3.17 標準関数

ここでは, 今までに述べなかった PASCAL の標準関数を書いておく.

3.17.1 ファイル処理

page(f) テキストファイル f の次の行を新しいページの先頭から印刷するように, 印刷装置に指示する.

3.17.2 算術関数

abs(x) x の絶対値を計算する. x は整数型か実数型. 結果の型は x と同じ.

sqr(x) x の2乗を計算する. x は整数型か実数型. 結果の型は x と同じ.

sqrt(x) x の平方根を計算する. x は整数型か実数型. 結果の型は実数型.

sin(x) sin(x) を計算する. x は整数型か実数型. 結果の型は実数型.

cos(x) cos(x) を計算する. x は整数型か実数型. 結果の型は実数型.

arctan(x) arctan(x) を計算する. x は整数型か実数型. 結果の型は実数型.

exp(x) exp(x) を計算する. x は整数型か実数型. 結果の型は実数型.

ln(x) loge(x) を計算する. x は整数型か実数型. 結果の型は実数型.

3.17.3 論理関数

odd(x) x は整数型. x が奇数ならば結果は真. そうでなければ偽.

Id: P-etc.tex,v 1.2 2000/04/21 02:17:25 naito Exp

Page 51: 3 PASCAL 入門 - Welcome - Grad. Sch. of Math., Nagoya … 第3章 PASCAL 入門 3.1 ここでの目的 ここではPASCALの文法を中心に解説をするが,単にPASCALを用いてプログラムが書けるようにな

理学部数理学科計算機 75

3.18 その他の注意

3.18.1 日本語の文字列について

SPARCompiler 他の処理系において, JIS コードからなる日本語を含む文字列を利用しようとすると, コ

ンパイラが通らない時がある. これは, 次のような事情による. Pascal においては, ’ が, C においては "

が文字列の始まりと終りを表している. 一方,「是」という文字は JIS コードでは 0x4027 と書けているの

で, 文字列 ’是’ は, 完全に日本語化されていない Pacal コンパイラでは @’ と解釈されエラーとなる. 同

様に C でも, そのコードに 0x22 を含む漢字はエラーとなることがある.

これを避けるには, コンパイラに通すプログラムコードを EUC 漢字コードに直すと良い. UNIX におい

て EUC 漢字コードに変換するには, プログラム nkf を利用する. nkf は引数として与えられたファイル

を, オプションとして与えられた漢字コードに変換して標準出力に出力する. したがって, 次のようにすれ

ば良いことがわかる.

% nkf -e filename > eucfile

ここで, オプション -e は EUC 漢字コードに変換することを指示している.

3.18.2 ランタイム・エラーを起こした時

ここでは, 実行時のエラーを起こした時の対処法を述べておく. SPARCompiler PASCAL では, 実行時

にエラーを検出すると, 自動的に dbx と呼ばれるデバッカが起動する.

Example 3.18.1 次のようなプログラムを実行してみる.

program test (input,output) ;vari : integer ;

beginread(i) ;

end.

このプログラムで, integer 型以外の入力を行なうと, 次のような出力が行なわれ,プログラムの実行が

停止する.

standard input : Bad data found on integer read

*** ./a.out terminated by signal 5: trace/breakpoint trap*** Traceback being written to a.out.trace

これは, a.out というプログラムを実行した時に, 予期しないデータ・フォーマットの入力が行なわれた

ので, 実行時エラーを検出して, 自動的にデバッガが起動されている.

もし, この状態で止まってしまったら, quit と入力すればよい. その後, dbx のトレース・ファイル(実

行したプログラム名に .trace をつけた名前のファイル)を消去する必要がある.

Id: P-etc.tex,v 1.2 2000/04/21 02:17:25 naito Exp