Adaのお勉強日記

Ada(エイダ)は Ada - WikipediaAdaとは 【エイダ】 - 意味・解説 : IT用語辞典 e-Words、 にあるような言語。

私はプログラミングスキルも英語力もありません。だから人に教えることはできません。 Lovelace - Master Outline of Lessons の内容をのーんびりお勉強し、ここにまとめていくだけです。もちろん翻訳はExcite翻訳を使います。 私のごときアホでないみなさんは、↑のサイトでお勉強するなり、本を買ってくださいね。

こんな調子ですので、間違いがあってもそのまま進んでしまうケースや、あとになって気づくケースもあると思います。

Adaをインストール

私は環境がWindowsXPなので、 ここからMinGWをインストールします。

MinGW-5.1.2.exeをデスクトップに落としました。んで、ダブルクリック。 ダイアログを適当に進めていくと、インストールするものを選べと。 最小で41.4MB、Adaを入れると73.9MBか。さすがAdaはでかいな。 んで、C:\MinGWにインストール。 なんか、デスクトップiniファイルとかに***.tzr.gzってのがうようよ沸いている。 インストールが終わったので、インストーラーもろともデスクトップをお掃除。

さっそくMinGWフォルダをあさる。 gnat.exeがAdaのコンパイラらしい。 gccも入ってる。しかもincludeフォルダにCのヘッダが!!! ご丁寧にwindows.hもあるじゃん。

pathを通してgnetを実行。

GNAT 3.4.2 (mingw-special) Copyright 1996-2004 Free Software Foundation, Inc.

List of available commands

GNAT BIND               gnatbind
GNAT CHOP               gnatchop
GNAT CLEAN              gnatclean
GNAT COMPILE            gnatmake -f -u -c
GNAT ELIM               gnatelim
GNAT FIND               gnatfind
GNAT KRUNCH             gnatkr
GNAT LINK               gnatlink
GNAT LIST               gnatls
GNAT MAKE               gnatmake
GNAT NAME               gnatname
GNAT PREPROCESS         gnatprep
GNAT PRETTY             gnatpp
GNAT STUB               gnatstub
GNAT XREF               gnatxref

Commands FIND, LIST, PRETTY, STUB and XREF accept project file switches -vPx, -
prj and -Xnam=val

よくわからん。まあ、gccとか使ったこと無いからしょうがない。そのうちわかるだろう。

Hello, World!!

さっそく例の勉強サイトにいく。当然Lesson 1から。 当然、Section 1.1 - What is Ada? の長文につまづく。 早速、Excite翻訳の出番だ。

とりあえず、ここにはAdaの紹介がしてあるようだ。Adaが米国国防総省(DoD)に設計されました。とか。 で、もうちょっと下に1から8までAdaの機能がまとめてある。

  1. 関連するタイプのパッケージ(モジュール)、オブジェクト、オペレーションを定義できる。 (←なんだこれ?)
  2. パッケージとタイプは再利用可能なコンポーネントを作成するのを助けるために一般可(テンプレートを通してパラメータ可される)される。
  3. 例外処理できる。いろんな良いことがある。
  4. タスク(並列スレッドコントロール)を作ったり通信できる。(←言語でマルチスレッドが使えるってことかな?)
  5. データ表現は正確。
  6. 標準ライブラリのサポート。
  7. オブジェクト指向プログラミングはサポート。(Ada95から)
  8. 他の言語へのインターフェースがある。

こんなことらしい。C++と何が違うんだろう...。まあいいや。 Section 1.2 - Simple Programにすすむ。

-- Print a simple message to demonstrate a trivial Ada program.
with Ada.Text_IO;
procedure Hello is
begin
 Ada.Text_IO.Put_Line("Hello, world!");
end Hello;

これがAdaのコードかぁ。
コメントは--で行末まで。(C++の//と同じ。)
withで必要なライブラリを宣言するみたい。--#pragma comment(lib, "")と脳内変換することにした。
3行目がプロシージャの名前 --たしかJavaってこんなことしてたよな。つかったことないけど。
4行目がプロシージャ開始。 --デルピーとおんなじだな。つかったことないけど。
5行目が文字表示。 --.net並に長いな。メソッドが。
6行目がend。 --おしまい。

こいつをエディタでtest.adaで保存。gnat.exeと同じフォルダにね。 GNAT COMPILEとだけ打つとオプションが入れるとえらいことに。gnatmakeを使えばいけそうだ。 つーわけで

C:\MinGW\bin>gnatmake test.ada
gcc -c -x ada test.ada
test.ada:3:11: warning: file name does not match unit name, should be "hello.adb"
gnatbind -x test.ali
gnatlink test.ali

ワーニングが出るな。hello.adbにしなきゃいけないんだな。 ファイル名とプロシージャ名をあわせないといけないようだ。 しかも拡張子はadbなのか。 で、ファイル名をhello.adbにリネーム。 test.exeとかが出来てたので削除。 もういちどトライ。おお、今度はコンパイルが通ったぜ。hello.exeも生成されている。

C:\MinGW\bin>hello.exe
Hello, world!

C:\MinGW\bin>

おっしゃ、これで私もAda使いじゃ。えへへ。 しかし983KBってでかすぎるな。デバッグ情報入ってるんかね。 それにしてもでかいけど。

Section 1.3 - Use Clausesにいく。 なんかいっぱい書いてあるけど、useを使うと、ライブラリの名前を省略できるようだ。 C++に似たようなusing namespaceてのがあったなあ。全然違うか。

変数とか例外

Section 1.4 はやっと変数だ。しかしプログラムが急に長くなった。 自分なりに注釈しとく。あくまで引用だからな。

-- Demonstrate a trivial procedure, with another nested inside.
with Ada.Text_IO, Ada.Integer_Text_IO; --左の2つのライブラリを使う。
use Ada.Text_IO, Ada.Integer_Text_IO; --長ーい名前を嫌う。
 
procedure Compute is --ここからComputeプロシージャ
 
 --Double関数。(Cとかのdouble型と間違えそうだな。)
 --カッコのItemが引数。in outは受け取りと変更が出来る。
 procedure Double(Item : in out Integer) is
 begin -- procedure Double.
   Item := Item * 2;
 end Double;

 X : Integer := 1;   -- Local variable X of type Integer.

begin -- procedure Compute
 loop
  Put(X); --Xを表示
  New_Line; --改行
  Double(X); --上の自作関数
 end loop; 
end Compute;

これをcompute.adbでコンパイルすると、compute.exeが出来上がる。

C:\MinGW\bin>gnatmake compute.adb
gcc -c compute.adb
gnatbind -x compute.ali
gnatlink compute.ali

こうなる。 実行すると

C:\MinGW\bin>compute
          1
          2
          4
          8
         16
         32
         64
        128
        256
        512
       1024
       2048
       4096
       8192
      16384
      32768
      65536
     131072
     262144
     524288
    1048576
    2097152
    4194304
    8388608
   16777216
   33554432
   67108864
  134217728
  268435456
  536870912
 1073741824
-2147483648
          0
(以下0が無限に続く.)

となる。 よく読むと-gnatoオプションが必要らしい。

C:\MinGW\bin>gnatmake compute.adb -gnato
gcc -c -gnato compute.adb
gnatbind -x compute.ali
gnatlink compute.ali

これでいいはずだ。

C:\MinGW\bin>compute.exe
          1
          2
          4
          8
         16
         32
         64
        128
        256
        512
       1024
       2048
       4096
       8192
      16384
      32768
      65536
     131072
     262144
     524288
    1048576
    2097152
    4194304
    8388608
   16777216
   33554432
   67108864
  134217728
  268435456
  536870912
 1073741824

raised CONSTRAINT_ERROR : compute.adb:11 overflow check failed

よし、例外処理が働いたぜ。でもexeで1MB越えはいかがなものかと。upxでつぶしても300MB超えてるし。

ここまでやっといてなんだけど、 Intellectual Ammunition - C-C++ to Ada Help and Discussion に、C/C++との対応が分かりやすく書いてあるので、こっちに浮気することに。

-- 素数を求める
with Ada.Text_IO, Ada.Integer_Text_IO;

procedure Sosuu is

  -- iが素数なら1 でないなら0を返す。
  function issosuu(i : in Integer) return Integer is
  j : Integer := 2; --初期化しないとなぜかワーニングが出る。
  begin
    for j in 2 .. i-1 loop
      if i mod j = 0 then
        return 0;
      end if;
    end loop;
    return 1;
  end issosuu;
  
i : Integer := 2;
begin
  for i in 2 .. 100 loop
    if issosuu(i) = 1 then
      Ada.Integer_Text_IO.Put(i);
      Ada.Text_IO.New_Line;
    end if;
  end loop;
end Sosuu;

プログラムは実際に作らないことには理解できたとはいえないので、作ってみた。 無駄の多すぎる素数を求めるプログラムね。

void型関数はprocedure、戻り値があるならfunction。引数はreturnを使う。

if文は以下のように書く。こりゃ完全にBASICだな。

if 条件式1 then 
  条件式1が真のとき;
elsif 条件式2 then
   条件式2が真のとき;
else
   条件式2が偽のとき;
end if;

forループは以下のように書く。BASICとは違うな。

for 変数 in 初期値 .. 最大値 loop
  計算;
end loop;

逆にデクリメントするなら、

for 変数 in reverse  最小値 .. 初期値 loop
  計算;
end loop;

Ada@WCIMH Adaに関する日本語のページを見つけたので参照しとく。

Adaのお勉強3日目

3日目だけど、今日はK&Rのやさしい入門の2つめの摂氏華氏対応表でもやってみようと思う。

with  Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;

procedure kr2 is
  fahr, celsius : Integer;
  lower, upper, step : Integer;
begin
  lower := 0;
  upper := 300;
  step := 20;
  
  fahr := lower;
  while fahr <= upper loop
    celsius := 5 * (fahr-32) / 9;
    Put_Line(Integer'Image(fahr) & "  " & Integer'Image(celsius));
    fahr := fahr + step;
  end loop;
end kr2;

Adaは可変引数がないのでprintfは使えないそうだ。 そろそろAda 95 Reference Manualを読まないといけないようだな。 その前にpascalのお勉強をしておいたほうがいいのかもしれない。