Ada チュートリアル (1): Ada の基本 - ワードカウント プログラム

Ada で一般的に使用されるライブラリとメソッド

Ada.Text_IO:このライブラリは、数値を操作する関数を含む、標準入出力用の一連の関数を提供します。たとえば、Get および Put を使用して、整数または浮動小数点数を読み取って出力できます。
Ada.Integer_Text_IO:このライブラリは、整数を操作するためのより具体的な入出力関数を提供します。
Ada.Float_Text_IO:このライブラリは、浮動小数点数を操作するためのより具体的な入出力関数を提供します。
Ada.Numerics:このライブラリには、平方根、指数関数、対数などのいくつかの数学関数を含む、数値計算のための一連の関数とプロシージャが含まれています。
Ada.Numerics.Float_Random:このライブラリは、浮動小数点数の乱数を生成できる擬似乱数ジェネレーターを提供します。

Ada.Characters.Handling

ここに画像の説明を挿入

文字型関数

文字分類機能:

Is_Control(Item : in Character) return Boolean:指定された文字が制御文字であるかどうかを判断します。制御文字の位置は、0 ~ 31 または 127 ~ 159 の範囲です。
Is_Graphic(Item : in Character) return Boolean:指定された文字がグラフィック文字であるかどうかを判断します。グラフィック文字の位置は 32 ~ 126 または 160 ~ 255 の範囲にあります。
Is_Letter(Item : in Character) return Boolean:指定された文字が文字であるかどうかを判断します。'A'...'Z' または 'a'...'z' の範囲、または 192...214、216...246、または 248...255 の範囲内のアルファベット文字の位置。
Is_Lower(Item : in Character) return Boolean:指定された文字が小文字かどうかを判断します。「a」...「z」の範囲、または 223...246 または 248...255 の範囲内の英小文字。
Is_Upper(Item : in Character) return Boolean:指定された文字が大文字かどうかを判断します。「A」~「Z」の範囲、または 192~214 または 216~222 の範囲の大文字の英字。
Is_Basic(Item : in Character) return Boolean:指定された文字が基本文字であるかどうかを判断します。「A」…「Z」および「a」…「z」の範囲の基本的なアルファベット文字、または特殊文字「Æ」、「æ」、「Ð」、「ð」、「Þ」、「þ」、または「ß」のいずれか。
Is_Digit(Item : in Character) return Boolean:指定された文字が 10 進数であるかどうかを判断します。「0」~「9」の範囲の 10 進数文字。
Is_Decimal_Digit(Item : in Character) return Boolean:この関数は Is_Digit のエイリアスです。
Is_Hexadecimal_Digit(Item : in Character) return Boolean:指定された文字が 16 進数かどうかを判断します。'0'...'9'、'A'...'F'、または 'a'...'f' の範囲の 16 進数文字。
Is_Alphanumeric(Item : in Character) return Boolean:指定された文字が文字であるか数字であるかを判断します。
Is_Special(Item : in Character) return Boolean:指定された文字が特殊なグラフィック文字であるかどうかを判断します。特殊グラフィック文字は、文字や数字ではないグラフィック文字です。

  • Is_space(Item: Character)スペースかどうかを判断する

変換関数

To_Lower(Item : in Character) return CharacterおよびTo_Lower(Item : in String) return String:指定された文字または文字列を小文字に変換します。
To_Upper(Item : in Character) return CharacterおよびTo_Upper(Item : in String) return String:指定された文字または文字列を大文字に変換します。文字列内の指定された文字がアクセント付き文字である場合は、アクセントなしの文字に変換します
To_Basic(Item : in Character) return CharacterTo_Basic(Item : in String) return String:

Ada の基本構文の概要

データタイプとサブタイプ

Ada では、タイプ (Type) とサブタイプ (Subtype) がその型システムの中核概念です。

タイプ

Ada では、型は値のセットとそれらの値に対するいくつかの操作を定義します。組み込み型には、整数型 Integer、実数型 Float、文字型 Character、ブール型 Boolean などがありますさらに、独自のタイプを定義することもできます。型定義は、スカラー (数値や列挙値など) または複合型 (配列やレコードなど) にすることができます。

たとえば、タイプ定義のサンプルをいくつか示します。

type My_Integer is range 1 .. 100;  -- 一个自定义的整数类型,值域是 1100
type Day is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);  -- 一个枚举类型
type Matrix is array (1 .. 10, 1 .. 10) of Float;  -- 一个二维数组类型

サブタイプ (サブタイプ)

サブタイプは、制約によって定義できるタイプのサブセットです。制約には、範囲制約または判別制約 (一部の高度なタイプの場合) を使用できます。各タイプには、追加の制約のない、対応する匿名サブタイプがあります。

**サブタイプの重要な使用法は、存在すべきではない値がプログラムに表示されるのを防ぐための追加の制約を提供することです。**例えば:

subtype Positive is Integer range 1 .. Integer'Last;  -- 一个表示正整数的子类型

この例では、は のサブタイプでPositiveあり、との間のInteger値を持つ必要がありますに負の値またはゼロを代入しようとすると、コンパイラはエラーを生成します。1Integer'LastPositive

サブタイプ化により追加の制約が提供されますが、それは新しいタイプではないこと に注意してください。つまり、明示的な型変換を行わずに、元の型の演算を直接使用できます。

タイプとサブタイプの違い

最も重要な違いは、タイプは新しいデータを定義するのに対し、サブタイプは元のタイプの一部にすぎないことです。新しい型を定義する場合、Ada はデフォルトの演算 (代入や比較など) を提供しますが、元の型の演算を直接使用することはできません。一方、サブタイプは元のタイプのすべての演算を直接使用できますが、許容可能な値を制限する追加の制約が提供されます。

一般的な型変換メソッド

Ada では、型変換は通常、「明示的な型変換」または「型関連関数」を通じて実現されますAda の型システムは厳密に型指定されていることに注意してください。これは、通常、コンパイラーがある型の値を別の型に自動的に変換せず、明示的に変換する必要があることを意味します。

一般的な型変換メソッドをいくつか示します。

表示タイプの変換

类型名(表达式)

例えば:

declare
   A : Integer := 42;
   B : Float;
begin
   B := Float(A);
end;

型依存関数

一部の型は、型変換を実行する関数を提供します。たとえば、Integer'Valueこの関数を使用して文字列を整数に変換できます。

declare
   S : String := "42";
   I : Integer;
begin
   I := Integer'Value(S);
end;

同様に、Float'Value、 、Boolean'Valueおよびその他の関数を使用して、文字列を他の型に変換できます。

これは型変換の基本的な方法です。より複雑な型変換には、サブルーチンや演算子のオーバーロードなど、他の手法の使用が必要になる場合があります。

ループ文

Ada プログラミング言語には、いくつかの種類のループ ステートメントがあります。以下に、それぞれを Markdown 形式でリストして説明します。

無条件ループ(ループ)

無条件ループは、明示的な終了条件が満たされるまでループ本体を繰り返し実行します。これは通常、exit ステートメントで実行されます。

loop
   -- 循环体
   exit when 条件;
end loop;

for ループ

for ループは、値の範囲またはイテレータのすべての要素を反復するために使用されます。Ada では、for ループのループ変数は不変です。つまり、ループ本体内でその値を変更することはできません。

-- 数值范围
for I in 1 .. 10 loop
   -- 循环体
end loop;

-- 迭代器
for Element of Some_Array loop
   -- 循环体
end loop;

while ループ

while ループは、特定の条件が満たされている間、ループの本体を実行します。そもそも条件が満たされていない場合、ループ本体が一度も実行されない可能性があります。

while 条件 loop
   -- 循环体
end loop;

ループ内のその他の制御構造

Ada は、他のループ制御構造も提供します。

exit:現在のループを終了するために使用されます。
exit when:特定の条件が満たされると、現在のループを終了します。
next:現在のループの反復をスキップして、次の反復に進みます。
next when:特定の条件が満たされた場合、現在のループ反復をスキップして次の反復に進みます。
return:現在のループを含むプロシージャまたは関数から戻ります。

分岐ステートメント

もしも

if 条件 then
   -- 条件为真时执行的语句
end if;

if ステートメントには 1 つ以上の elsif 部分を含めることができ、また else 部分を含めることもできます。

if 条件1 then
   -- 条件1为真时执行的语句
elsif 条件2 then
   -- 条件1为假,但是条件2为真时执行的语句
else
   -- 所有条件都为假时执行的语句
end if;

場合

case 表达式 is
   when1 =>
      -- 表达式的值为值1时执行的语句
   when2 =>
      -- 表达式的值为值2时执行的语句
   when others =>
      -- 表达式的值不是任何给定值时执行的语句
end case;
  • caseステートメントが処理できる値は离散的、たとえば、整数型または列挙型である必要があります。
  • when others部分はオプションですが、それがないと、case ステートメントは式のすべての可能な値を処理できる必要があります。ステートメント
    では、ある部分の値を繰り返すことはできません。つまり、同じ値を扱う部分が 2 つ存在することはできません。casewhen

配列

Ada では、配列は同じ型のデータ項目を格納するために使用される複合データ型です配列は元素と で構成されます索引要素は配列内のデータ項目であり、各要素には要素を一意に識別するインデックスが関連付けられています。

配列定義

Ada では、次の構文を使用して配列型を定義できます。

type Array_Type is array (Index_Type range <>) of Element_Type;
  • より具体的には: たとえば、次のコードは、インデックス タイプが である整数配列を定義しますInteger
-- 括号中的 Integer 的意思是索引类型, of Integer 代表数据类型是 integer
type Integer_Array is array (Integer range <>) of Integer;

多次元配列も定義できます。たとえば、次のコードは整数の 2 次元配列を定義します。

type Matrix is array (Integer range <>, Integer range <>) of Integer;

配列変数を宣言する

配列型を定義したら、配列変数を宣言できます。例えば:

declare
   A : Integer_Array(1 .. 10);
   M : Matrix(1 .. 10, 1 .. 10);
begin
   -- 这里可以使用数组 A 和 M
end;

この例では、A は10要素を含む 1 次元配列、M は100要素を含む 2 次元配列です。

配列要素にアクセスする

配列の要素にはインデックスによってアクセスできます。例えば:

declare
   A : Integer_Array(1 .. 10);
begin
   A(1) := 42;  -- 设置数组的第一个元素
   Put(A(1));  -- 输出数组的第一个元素
end;

多次元配列の場合は、複数のインデックスを指定する必要があります。例えば:

declare
   M : Matrix(1 .. 10, 1 .. 10);
begin
   M(1, 1) := 42;  -- 设置数组的第一个元素
   Put(M(1, 1));  -- 输出数组的第一个元素
end;

配列のその他のプロパティ

Ada は、配列のスライス、配列の割り当て、配列の比較など、他の配列機能も提供します。ここではいくつかの例を示します。

  • 配列スライス: 配列スライスを使用して、配列の一部にアクセスできます。たとえば、A(1 .. 5)は配列 A の最初の 5 つの要素です。
  • 配列の割り当て: 配列全体に一度に割り当てることができます。例:A := B配列 B のすべての要素を A に割り当てます。A と B は同じタイプでなければならないことに注意してください。
  • 配列の比較: =and/=演算子を使用して、2 つの配列が等しいかどうかを比較できます。例: A = B の場合、A と B のすべての要素が等しいことを意味します。

記録

レコード定義

Ada プログラミング言語において、record異なる型のデータ要素を単一のデータ構造に結合できる複合データ型。これは、C または C++ の構造体、または Python のクラスに似ています。
Recordタイプは一連のフィールドによって定義され、各フィールドには名前とタイプがあります。Record型定義の構文は次のとおりです。

type Record_Type is record
   Field1 : Type1;
   Field2 : Type2;
   -- 更多的字段...
end record;

たとえば、次のコードは、と のPerson3 つのフィールドを持つ名前のレコード タイプを定義しますName、AgeIs_Employed

type Person is record
   Name        : String;
   Age         : Integer;
   Is_Employed : Boolean;
end record;

レコード変数の作成と使用

レコード タイプを定義したら、このタイプの変数を作成し、.演算子を使用してそのフィールドにアクセスできます。例えば:

declare
   P : Person;
begin
   P.Name := "Alice";
   P.Age := 30;
   P.Is_Employed := True;
   
   Put("Name: " & P.Name);
   Put("Age: " & Integer'Image(P.Age));
   Put("Is employed: " & Boolean'Image(P.Is_Employed));
end;

Personこの例では、 type の変数を作成しP、そのフィールドの値を設定します。

レコードのその他の特徴

variant recordRecord には、や などの他の機能もありますnested record

バリアントレコード

バリアント レコードを使用すると、レコード内の一部のフィールドにさまざまな状況で異なる型と数値を設定できますこれは、C または C++ の共用体に似ています。

ネストされたレコード

ネストされたレコード: レコードには、ネストされたレコードと呼ばれる別のレコードを含めることができます。これにより、より複雑なデータ構造を構築できるようになります。

サブルーチン

処理手順

プロシージャは、何らかのアクションを実行するために使用されるサブルーチンですが、値を返しません。プロシージャを定義するための構文は次のとおりです。

procedure Procedure_Name (Parameter_List) is
begin
   -- 过程体
end Procedure_Name;

その中には、Procedure_Nameはプロシージャの名前、Parameter_Listはプロシージャのパラメータ リスト、-- 过程体および は実行されるコードを含むプロシージャの本体です。

たとえば、次のコードは、メッセージを出力する Print_Hello という名前のプロシージャを定義します。

procedure Print_Hello is
begin
   Put_Line("Hello, world!");
end Print_Hello;

関数

関数は、何らかのアクションを実行して値を返すサブルーチンです。関数定義の構文は次のとおりです。

function Function_Name (Parameter_List) return Return_Type is
begin
   -- 函数体
   return Result;
end Function_Name;

その中で、Function_Nameは関数の名前、Parameter_Listは関数のパラメータリスト、Return_Typeは関数の戻り値の型、 -- 関数本体は関数の本体であり、実行されるコードが含まれ、返される結果ですResult

たとえば、次のコードは、Add2 つの整数引数を受け取り、その合計を返す という名前の関数を定義します。

function Add (X, Y : Integer) return Integer is
begin
   return X + Y;
end Add;

パラメータの受け渡し

パラメータの受け渡しAda は、と の
3 種類のパラメータの受け渡しをサポートしていますin、outin out

  • In: これはデフォルトのパラメータ タイプで、パラメータがサブルーチン内でのみ読み取り可能で、変更できないことを示します。

  • Out: このタイプのパラメータは、サブルーチンを呼び出す前に初期化する必要はありません。パラメータはサブルーチン内で割り当てられ、サブルーチンの終了後に呼び出し元に返されます。

  • In Out: このタイプのパラメータは、サブルーチンで読み取りまたは変更できます。サブルーチンが終了すると、変更された値が呼び出し元に返されます。

以上が Ada のサブルーチンの基礎知識です。Ada のサブルーチンには、デフォルト パラメータ、サブルーチンのオーバーロード、サブルーチン ポインタなど、ここでは取り上げていない他の多くの機能や詳細があります。

チュートリアル 1

题目:概要 WordCount プログラムは、標準入力から文字列を受け取り、入力文字列内の単語数を返します。
以下は要件のリストです。

  1. プログラムは標準入力の文字列を受け入れ、入力内の単語数をカウントする必要があります
  2. 入力は「#」文字で終了します。
  3. 単語は空白で区切られます。作業を簡略化するために、空白がスペース文字であると仮定します (つまり、タブと改行文字は無視します)。
  4. このワークショップでは、空白文字ではない文字を使用します。
  5. 出力は単語数を示す単一の整数です。
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Characters.Handling; use Ada.Characters.Handling;

procedure Word_Count is
   Input   : Character;
   Word_Cnt: Integer := 0;
   In_Word : Boolean := False;
   
begin
   loop
      Get(Item => Input);
      exit when Input = '#';

      if Is_Space(Input) then
         if In_Word then
            Word_Cnt := Word_Cnt + 1;
         end if;
         In_Word := False;
      else
         In_Word := True;
      end if;
   end loop;


   if In_Word then
      Word_Cnt := Word_Cnt + 1;
   end if;

   Put_Line("Word count: " & Integer'Image(Word_Cnt));
end Word_Count;

要目:「仕様」セクションで指定された単語カウント プログラムを実装し、いくつかのテストを実行して、プログラムがほとんどの入力で動作することを確認します。
ヒント: もちろん、プログラムを段階的に実装することは良い考えです。まず、指定されたプログラムを拡張する小さなプログラムを作成して実行します。
提供されているスケルトンの次の点に注意してください。ProtectedStack は、以下を追加することでインポートされます。ここに画像の説明を挿入

  • この質問は、次の操作を含む教師によって与えられた答えです。
    • ProtectedStack package(adb ファイルと ads ファイルを含む)を定義します
    • solutionメインロジックを組み込みました
  • genericこのトピックには、使用前にインスタンス化する必要があるタイプのデータの使用が含まれます。is new
  • 実際、StringStackインスタンス化した関数はpackage前の関数と同じ関数を持っていますProtectedStackが、それは単なるインスタンスです。
-- protectedStack.adb

package body ProtectedStack is
   
   protected body Stack is 
      
      entry Push(I: in Item)
      when True is
      begin
	 if Stk.Size < Max_Size then
	    Stk.Size := Stk.Size + 1;
	    Stk.Data(Stk.Size) := I;
	 else
	    raise Stack_Overflow;
	 end if;
      end Push;

      entry Pop(I: out Item) 
      when True is
      begin
	 if Stk.Size > 0 then
	    I := Stk.Data(Stk.Size);
	    Stk.Size := Stk.Size - 1;
	 else
	    raise Stack_Underflow;
	 end if;
      end Pop;

      entry Top(I: out Item)
      when True is
      begin
	 if Stk.Size > 0 then
	    I := Stk.Data(Stk.Size);
	 else
	    raise Stack_Underflow;
	 end if;
      end Top;

      entry Empty(EmptyStack: out Boolean) 
      when True is
      begin
	 EmptyStack := (Stk.Size = 0);
      end Empty;

      entry Full(FullStack: out Boolean) 
      when True is
      begin
	 FullStack := (Stk.Size = Max_Size);
      end Full;

      entry Clean
      when True is
      begin
	 Stk.Size := 0;
      end Clean;
      
   end Stack;
   
end ProtectedStack;
--protectedstack.ads

generic
   Max_Size: Positive;          -- The maximum size of the stack.
   type Item is private;        -- The type of items in the stack. The type must
                                -- be definite, and the private means that this
                                -- package may not examine its internals.
package ProtectedStack is
   
   type StackType is private;

   -- Exceptions.
   Stack_Underflow, Stack_Overflow: exception;
   
   -- The public interface to the stack consists of the following
   --  operations. The stack is "protected" which means that the tasks
   --  have muitually exclusive access to the stack operations. They
   --  are declared just like the "entry" points in a task type
   --  declaration and are implemented using "entry" keywords as
   --  well. Entry calls are the main means of communication between
   --  concurrent tasks in Ada so this is effectively an Abstract Data
   --  Type that protects the Stack by enforcing mutually exlcusive
   --  access.
   
   protected type Stack is
      entry Push(I: in Item); 
      entry Pop(I: out Item);
      entry Top(I: out Item); 
      entry Empty(EmptyStack: out Boolean); 
      entry Full(FullStack: out Boolean);
      entry Clean; 
   private 
      Stk : StackType;
   end Stack;
   
private
   
   type StackData is array(1.. Max_Size) of Item;
   type StackType is record
      Size: Integer range 0 .. Max_Size := 0;
      Data: StackData;
   end record;
      
end ProtectedStack;

-- solution
with Ada.Text_IO; 
use  Ada.Text_IO;

with Ada.Integer_Text_IO;
use  Ada.Integer_Text_IO;

with ProtectedStack;
with Ada.Strings.Unbounded;

with Ada.Characters.Latin_1;

-- The WordCount program counts the number of characters and words in
--  a string received from standard input. A word is any alphanum
--  character separated by a space or tab
procedure WordCount is
   
   package ASU renames Ada.Strings.Unbounded;
   use ASU;   
   package StringStack is new ProtectedStack(100, ASU.Unbounded_String);
   
   Ch        : Character;            -- the current character
   Word      : ASU.Unbounded_String; -- the current word
   
   -- The number of characters and words
   NumChars : Integer := 0;
   NumWords : Integer := 0;
   
   -- a stack for putting words into
   St : StringStack.Stack;
   
   -- for testing is the stack is empty
   IsEmpty : Boolean;
   
begin
   
   Get(Ch);
   
   Word := ASU.To_Unbounded_String("");
   
   while (Ch /= '#') loop
      
      NumChars := NumChars + 1;
      
      -- if a space or tab, we encounter a new word
      if Ch = ' ' or Ch = Ada.Characters.Latin_1.HT then	 
	 
	 -- consume remaining spaces and tabs
	 while Ch = ' ' or Ch = Ada.Characters.Latin_1.HT loop
	    Get(Ch);
	 end loop;
	 
	 NumWords := NumWords + 1;
	 St.Push(Word);
	 Word := ASU.To_Unbounded_String("");
	 
      else
	 Word := Word & Ch;
	 Get(Ch);
      end if;
      
   end loop;
   
   -- push the terminating word
   NumWords := NumWords + 1;
   St.Push(Word);

   Put(NumWords); New_Line;
   Put(NumChars); New_Line;
   
   -- print the words on the stack
   St.Empty(IsEmpty);
   while not IsEmpty loop
      St.Pop(Word);
      Put(ASU.To_String(Word) & " ");
      St.Empty(IsEmpty);
   end loop;
end WordCount;

  • 予防:
    ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_42902997/article/details/131160770