ということで、Javaに続いてまた何となく Delphiを始めてみました(何となくというのもおかしいのですが、実際のところDelphiの知識が特に必要とされているわけでもないですし、ちょっと興味がある程度、趣味の範囲でDelphiを始めたという意味では「何となく」になるでしょうか)。
今回使用したコンパイラ・開発環境はBorland社の「Delphi 6 Personal」です。 これは使用者登録等の簡単な手続きが必要になりますが、フリーでダウンロードできます。 ここではインストールの説明などは特にしません。
Javaに関してはC系の言語であるので、言語仕様自体の習得はそれほど難しいものではなかったのですが、Delphiは今まで使ったことのない Pascal系の言語(Object Pascal)であるので最初からかなり手こずりました。 他の言語と比較しつつ基本的なところから勉強していくことにします。
最初はHello, world!
何はなくとも、最初のプログラムは「Hello, world!」と決まっているので、コンソールアプリでこれを表示してみます。 「新規作成」メニューの「その他」をクリックし、表示されたダイアログから「コンソール」をクリックして、コンソールアプリケーション用のプロジェクトを生成します。 DelphiはよくVisual Basicと比較されますが、Delphiにはコンソールアプリを作れないと思いこんでいたので驚きです。 VBでもコンソールアプリが作れれば良かったのですが・・・
このプログラムの大半はテンプレートとして提供されたものです。 実際に追加したのは11,12行目だけです。 プログラムの詳細はこの次で説明するとして、ひとまず「Hello, world!」が無事表示されたことを喜ぶことにします。
Object Pascal のプログラム構造
といっても、「Hello, world!」が表示されただけではどうしようもないので、Object Pascalにおけるプログラムの構造はどのようなものなのかを見てみます。
Object Pascalではこのようなプログラム構造になっています。 これはVBと言うよりはC/C++の構造に似ていると言えます。 続いて、部分毎に説明していきます。
まず、プログラムヘッダでプログラムの名前を決めます。 この名前とファイル名は一致している必要があります。 また、コンパイル命令などもここに記述します。 これはprogram文の前にあっても問題ないようです。
続いて、プログラムブロックですが、これはさらに細かいブロックに分かれます。 最初に来るuses文では使用するユニットを記述します。 ユニットとはヘッダーのようなもので、ヘッダーのインクルードや名前空間のインポートなどと似たようなことを行います。 続く変数宣言部ではvar文により変数を宣言します。 宣言すべき変数がない場合は省略できます。
最後にプログラム本体を記述します。 begin から end で囲まれる部分が Main関数 に相当する部分です。 Main関数以外の関数・手続き(プロシージャ)を記述するにはこの部分より上に記述する必要があります。
Object Pascal の文法
構造がわかったところで文法について見てみます。
まず、コメントとなる部分は緑色に変えておきました。 コメントは様々な種類があります。 VB、C++と同じ感覚で使えるコメントが「//(ダブルスラッシュ)」です。 コメント文でコンパイル命令を記述することができます。 プログラムの一番はじめに記述した部分がコンパイル命令です。
Object Pascalでは大文字と小文字は区別されません。 つまり、「Integer」も「integer」も「INTEGER」も、そしてもちろん「iNtEgEr」なども同じと見なされます。 VBでは大文字小文字の区別はされなくとも自動的に単一の表記になるように調整されました。 しかし、 Delphiでは調整されることはありません。
文の終わりにはC/C++同様「;(セミコロン)」を付けます。 また、代入は「=」ではなく「:=」で行います。 VB, C/C++での代入は「=」で、C/C++で等価を表す「==」はObject Pascalでは「=」になります。 ここが注意すべきことだと思います。
また、 'と' の間が文字列リテラルになります。 文字列リテラル中にこのクォーテーションを含めたい場合はVBと同じように「''」と二つ続けることで一つのクォーテーションとして扱われます。 さらに、関数・プロシージャ呼び出しで渡すべき引数がないときは「Readln()」のように括弧を残してはならず、「Readln」としなければなりません。
最後に、変数の宣言なのですが、変数の宣言は必ずvar文で行わなければなりません。 それ以外の部分でローカル変数を宣言したりすることはできません。 ただし、プロシージャ・関数レベルで変数を宣言することはできます。
標準入出力
簡単な文字列型変数を使って標準入出力で入出力をしてみます。
Write, Writelnは.NET FrameworkのConsole.Write, Console.WriteLineに相当するプロシージャです。 ReadlnもReadLineに相当するものです。 しかし、入力された文字列は戻り値ではなく引数に渡されます。 文字列を連結する際にはVBのように & ではなく + を用いることができます。
ちなみに、一番最後にあるReadlnは何らかの入力があるまで終了させないためのものです。 これを省くと名前を入力した瞬間に目にもとまらぬ速さでコンソールが閉じてしまいます。
算術演算
算術演算は基本的には他の言語とは大差ありません。
/ 演算子は除算を行いますが、オペランドが整数でもその結果は実数型になります。 FloatToStr関数はその名の通り、浮動小数点の数値を文字列に変換します。 ただし、指数表記ではなく読みやすい表記に変えてくれます。 Trunc関数は小数部を切り捨て、Round関数は小数部を丸めて整数に変換します。 div及びmodは商と剰余を求める演算子です。 VBの\とModに相当するものといえます。 Odd関数はその整数が奇数であるかを Boolean値で返します。
その他の算術演算
平方根、べき乗、対数などの算術演算も他の言語とあまり変わりません。 ただし、これらの関数を利用する場合はMathユニットをuses文に含める必要があります。
注意すべきことは、Sqrが平方を求め、Sqrtが平方根を求める関数であるということです。 双方非常に似た名前なので注意が必要です。 また、特殊なプロシージャにSinCosがあります。 これはあるラジアン値の正弦と余弦を同時に求めるというものです。 ヘルプによるとSinとCosを一度ずつ呼び出すよりは高速に動作するそうです。 ちなみに、Extended型は拡張精度実数型と呼ばれるもので、これらの関数の戻り値はExtended型になっています。
for文
for文の動作自体は他の言語とほとんど変わりありません。 ただ、カウンタ変数の増分は±1に固定されています。 Stepを利用したりすることができないので、それ以外の値は指定できません。 表記自体はVBのFor文と非常に似ています。
カウンタをインクリメントする場合はtoを用い、ディクリメントする場合はdowntoを用います。 繰り返す文をdoに続けて記述します。 繰り返す文が一行の場合はdoの後にそのまま記述し、複数行の場合はbeginとendの間に記述します。 この記述方法はC/C++に似ていると言えます。 また、二重ループなどをすることもできます。
while文, repeat文
while文は他の言語同様、前置条件判断の無限ループ、repeat文は後置条件判断の無限ループです。 for文で1以外の増分を指定したいときはwhile/repeatを使うことができます。
while文はfor文同様beginからendまでのブロックを、条件式の値が真の間繰り返します。 逆に、repeat文は条件式が真になるまで(式が偽の間)繰り返します。 repeat文ではブロック構造を成さず、repeatからuntilまでを繰り返します。 これもまたfor文同様に入れ個にして二重ループを形成することもできます。
if文
例によってif文も他の言語と大差ありません。 ただ、前述の通り、等価を表す演算子にはVB同様 = 演算子を用います。 また、一つだけ注意として、「elseはそれ単体では文になり得ない」ということからelseの前には ;(セミコロン) をつけません。 つけてしまうと構文エラーになります。
まずはじめにif文意外の注意点として、SetLengthは配列要素の長さを指定するものですが、この例のように文字列に対しても有効です。 つまり、文字列の長さを設定することができます。 この例では3バイト(Object Pascalの文字列はAsciiとして扱われるため。ちなみにVBはUnicode。)に設定して書式を併せています。
if文ではVBのEnd Ifに相当するものはありません。 形式的にはC/C++に似たものと言えます。 ただし、条件式を()でくくる必要はありません。 また、for文同様に、実行する文が一行だけの場合はbegin-endブロックを作る必要がありません。 else ifはこの次の例で使用します。
break, continue
Object Pascalではbreakとcontinueが採用されています。 その用法はC/C++と同じです。
この例を見てわかるとおり else if の前であっても ;(セミコロン) をつけてはいけません。 continueとbreakがC/C++と同じ動作であることは実行結果を見れば納得がいくと思います。
case文
case文はswitch文やSelect Caseステートメントと同じような働きを持つ構文です。 caseは値の分類には用いられません。
この例では二つの表記方法を使っていますが、どちらでも問題ないと言うことだけを示している以外は特に意味はありません。 case文は「case 値 of」というように用います。 また、breakなどを用いなくても下の文に流れていくことがないので、動作はVBのSelect Caseステートメントに似ていると言えます。 case文の終わりにはend;をつけます。
さらに、複数の連続した値や、いずれの値にも当てはまらない場合などを記述することもできます。
配列(静的配列)
配列という要素はほとんどの言語に存在しますが、Object Pascalにおける配列の動作はVBに近く、表記方法などはC++に似ています。
宣言方法は見ての通りです。 「arrはinteger型の配列(添え字0〜4)」のように読むことができます。 Low関数とHigh関数は配列の下限と上限を取得するものです。 VBにおけるLBound関数とUBound関数に相当するものといえます。 また、配列の長さを求めるLength関数というものも存在します。
配列への値の代入と参照は特に問題ないのですが、興味深いことに、配列の添え字の範囲外の部分を参照しようとしてもエラーにはなりませんでした。 ただ、その値は必ずしも初期化されていない意味不明な数値です。
配列(動的配列)
Object Pascalには動的に長さを変えられる動的配列も存在します。
宣言直後には長さがなく、値が割り当てられていないので、SetLengthによって配列に長さを設定します。 また、長さを変えるときもSetLenghtを用います。