ADA 95教程 示例程序2

动态字符串包

Example program ------> e_c16_p3.ada

                                       -- Chapter 16 - Program 3
-- This is a dynamic string package which can be used as an aid
-- in writing string intensive programs.  Ada only has a static
-- string capability, so this package was written as an example of
-- how the Ada programming language can be expanded.  The basis
-- for this package is the dynamic string available with the
-- Borland International implementation of Pascal, TURBO Pascal.

-- A dynamic string is defined as an array of characters of maximum
-- length of 255.  The dynamic length of the dynamic string is
-- stored in the string location with index = 0, so the dynamic
-- string must be defined with a lower limit of 0 and an upper
-- limit of whatever the desired maximum length of the string is
-- to be.  The subtype STRING_SIZE below limits the string length
-- when it is defined.

-- Put      Outputs a dynamic string to the monitor
-- ConCat   Concatenates two dynamic strings and puts the result
--           into a third dynamic string
-- Copy     Copies a dynamic string to another dynamic string
-- Copy     Copies a static string to a dynamic string
-- Delete   Deletes a group of characters from a dynamic string
-- Insert   Inserts a group of characters into a dynamic string
-- Length   Returns the dynamic length of a dynamic string
-- Size_Of  Returns the static length of a dynamic string
-- Pos      Returns the first location of a dynamic string within
--           another dynamic string

with Ada.Text_IO; use Ada.Text_IO;
package DynStrng is

   subtype STRING_SIZE is INTEGER range 0..255;
   type DYNAMIC_STRING is array(STRING_SIZE range <>) of CHARACTER;

-- Put : Display a dynamic string on the monitor.
procedure Put(Input_String : in     DYNAMIC_STRING);


-- ConCat : Concatenation - The First_String is copied into the
--             Result_String, then the Second_String is copied
--             into the Result_String following the First_String.
--             If all characters fit, Result is set to TRUE.
--             If Result_String will not hold all characters,
--             only as many as will fit are copied and Result
--             is set to FALSE.
--             Result = TRUE, complete copy done.
--             Result = FALSE, some or all not copied
procedure ConCat(First_String  : in     DYNAMIC_STRING;
                 Second_String : in     DYNAMIC_STRING;
                 Result_String : in out DYNAMIC_STRING;
                 Result        :    out BOOLEAN);


-- Copy : The String contained in Input_String is copied into
--             the string Output_String.  This procedure is
--             overloaded to include copying from either dynamic
--             strings or static strings.
--             Result = TRUE, complete copy done
--             Result = FALSE, some or all not copied
procedure Copy(Input_String  : in     DYNAMIC_STRING;
               Output_String : in out DYNAMIC_STRING;
               Result        :    out BOOLEAN);
procedure Copy(Input_String  : in     STRING;
               Output_String :    out DYNAMIC_STRING;
               Result        :    out BOOLEAN);


-- Delete : Beginning at First_Position, as many characters as are
--             indicated by Number_Of_Characters are deleted from
--             String_To_Modify.  If there are not that many, only
--             as many as are left are deleted.
--             Result = TRUE, deletion was complete
--             Result = FALSE, only a partial deletion was done
procedure Delete(String_To_Modify     : in out DYNAMIC_STRING;
                 First_Position       : in     STRING_SIZE;
                 Number_Of_Characters : in     STRING_SIZE;
                 Result               :    out BOOLEAN);


-- Insert : The string String_To_Insert is inserted into the string
--             String_To_Modify begining at location Place_To_Insert
--             if there is enough room.
--             Result = TRUE, insert completed in full
--             Result = FALSE, not enough room for full insert
procedure Insert(String_To_Modify : in out DYNAMIC_STRING;
                 String_To_Insert : in     DYNAMIC_STRING;
                 Place_To_Insert  : in     STRING_SIZE;
                 Result           :    out BOOLEAN);


-- Length : Returns the dynamic length of the string defined by
--             String_To_Measure.
function Length(String_To_Measure : in DYNAMIC_STRING)
                 return STRING_SIZE;


-- Size_Of : Returns the static length of the string, the actual
--             upper limit of the string definition.
function Size_Of(String_To_Measure : in DYNAMIC_STRING)
                 return STRING_SIZE;


-- Pos : Position of substring - The string String_To_Search is
--             searched for the string Required_String beginning
--             at Place_To_Start.
--             Result = TRUE, a search was possible
--             Result = FALSE, no search could be made
--             Location_Found = 0, no string found
--             Location_Found = N, start of matching string
procedure Pos(String_To_Search : in     DYNAMIC_STRING;
              Required_String  : in     DYNAMIC_STRING;
              Place_To_Start   : in     STRING_SIZE;
              Location_Found   :    out STRING_SIZE;
              Result           :    out BOOLEAN);

end DynStrng;







package body DynStrng is

               -- The display procedure overloads the existing
               -- Put procedures to output a dynamic string. Note
               -- that the existing Put is used in this new Put.
procedure Put(Input_String : in     DYNAMIC_STRING) is
begin
   for Index in 1..CHARACTER'POS(Input_String(0)) loop
      Put(Input_String(Index));
   end loop;
end Put;




procedure ConCat(First_String  : in     DYNAMIC_STRING;
                 Second_String : in     DYNAMIC_STRING;
                 Result_String : in out DYNAMIC_STRING;
                 Result        :    out BOOLEAN) is
Intermediate_Result : BOOLEAN;
Character_Count     : STRING_SIZE;
Room_Left           : STRING_SIZE;
begin
                       -- Copy the first into the result string
   Copy(First_String,Result_String,Intermediate_Result);
   if Intermediate_Result then
      Character_Count := CHARACTER'POS(Second_String(0));
      Room_Left := Result_String'LAST
                                - CHARACTER'POS(Result_String(0));
      Result := TRUE;
      if Character_Count > Room_Left then
         Character_Count := Room_Left;
         Result := FALSE;
      end if;
      for Index in 1..Character_Count loop
         Result_String(Index + CHARACTER'POS(Result_String(0))) :=
                                          Second_String(Index);
      end loop;
      Result_String(0) :=
             CHARACTER'VAL(CHARACTER'POS(Result_String(0))
                                                 + Character_Count);
   else
      Result := FALSE;
   end if;
end ConCat;




               -- This procedure overloads the name Copy to
               -- copy from one dynamic string to another.
procedure Copy(Input_String  : in     DYNAMIC_STRING;
               Output_String : in out DYNAMIC_STRING;
               Result        :    out BOOLEAN) is
Character_Count : STRING_SIZE;
begin
                       -- First pick the smallest string size
   Character_Count := CHARACTER'POS(Input_String(0));
   if Character_Count > Output_String'LAST then
      Character_Count := Output_String'LAST;
      Result := FALSE; -- The entire string didn't fit
   else
      Result := TRUE;  -- The entire string fit
   end if;

   for Index in 0..Character_Count loop
      Output_String(Index) := Input_String(Index);
   end loop;
   Output_String(0) := CHARACTER'VAL(Character_Count);
end Copy;




               -- This routine overloads the copy procedure name
               -- to copy a static string into a dynamic string.
procedure Copy(Input_String  : in     STRING;
               Output_String :    out DYNAMIC_STRING;
               Result        :    out BOOLEAN) is
Character_Count : STRING_SIZE;
begin
                       -- First pick the smallest string size
   Character_Count := Input_String'LAST;
   if Character_Count > Output_String'LAST then
      Character_Count := Output_String'LAST;
      Result := FALSE; -- The entire string didn't fit
   else
      Result := TRUE;  -- The entire string fit
   end if;

   for Index in 1..Character_Count loop
      Output_String(Index) := Input_String(Index);
   end loop;
   Output_String(0) := CHARACTER'VAL(Character_Count);
end Copy;




procedure Delete(String_To_Modify     : in out DYNAMIC_STRING;
                 First_Position       : in     STRING_SIZE;
                 Number_Of_Characters : in     STRING_SIZE;
                 Result               :    out BOOLEAN) is
Number_To_Delete       : STRING_SIZE;
Number_To_Move         : STRING_SIZE;
Last_Dynamic_Character : STRING_SIZE :=
                                CHARACTER'POS(String_To_Modify(0));
begin
                         -- can we delete any at all?
   if First_Position > Last_Dynamic_Character then
      Result := FALSE;
      return;
   end if;
                         -- Decide how many to delete
   if (First_Position + Number_Of_Characters)
                                   > Last_Dynamic_Character then
      Number_To_Delete := Last_Dynamic_Character
                                             - First_Position + 1;
      Result := FALSE;
   else
      Number_To_Delete := Number_Of_Characters;
      Result := TRUE;
   end if;

                  -- find out how many to move back
   if (Last_Dynamic_Character - (First_Position + Number_To_Delete))
                                                           >= 0 then
      Number_To_Move := 1 + Last_Dynamic_Character
                           - (First_Position + Number_To_Delete);
   else
      Number_To_Move := 0;
   end if;

                  -- now delete the characters by moving them back
   for Index in First_Position..
                          (First_Position + Number_To_Move - 1) loop
      String_To_Modify(Index) := String_To_Modify(Index
                                                + Number_To_Delete);
   end loop;
   String_To_Modify(0) :=
            CHARACTER'VAL(CHARACTER'POS(String_To_Modify(0))
                                               - Number_To_Delete);
end Delete;




procedure Insert(String_To_Modify : in out DYNAMIC_STRING;
                 String_To_Insert : in     DYNAMIC_STRING;
                 Place_To_Insert  : in     STRING_SIZE;
                 Result           :    out BOOLEAN) is
Number_To_Add  : STRING_SIZE;
Number_To_Move : STRING_SIZE;
Room_Left      : STRING_SIZE;
begin
                        -- Can we add any at all?
   if (Place_To_Insert > String_To_Modify'LAST) or
     (Place_To_Insert > CHARACTER'POS(String_To_Modify(0)) + 1) then
      Result := FALSE;
      return;
   end if;
   Result := TRUE;

                        -- How many can we add?
   Number_To_Add := String_To_Modify'LAST - Place_To_Insert + 1;
   if Number_To_Add > CHARACTER'POS(String_To_Insert(0)) then
      Number_To_Add := CHARACTER'POS(String_To_Insert(0));
   end if;

                        -- Find how many to move forward
   Number_To_Move := CHARACTER'POS(String_To_Modify(0))
                                             - Place_To_Insert + 1;
   Room_Left := String_To_Modify'LAST - Place_To_Insert + 1;
   if Room_Left < Number_To_Move then
      Number_To_Move := Room_Left;
   end if;

                        -- Move them forward
   for Index in reverse Place_To_Insert..Place_To_Insert
                                         + Number_To_Move - 1 loop
      String_To_Modify(Index + Number_To_Add) :=
                                           String_To_Modify(Index);
   end loop;
   for Index in 1..Number_To_Add loop
      String_To_Modify(Index + Place_To_Insert - 1) :=
                                           String_To_Insert(Index);
   end loop;

                        -- Increase the length of the string
   String_To_Modify(0) := CHARACTER'VAL(
             CHARACTER'POS(String_To_Modify(0)) + Number_To_Add);
   if CHARACTER'POS(String_To_Modify(0)) > String_To_Modify'LAST
                                                               then
      String_To_Modify(0) := CHARACTER'VAL(String_To_Modify'LAST);
   end if;

end Insert;




               -- This returns the dynamic length of a string
function Length(String_To_Measure : in DYNAMIC_STRING)
                 return STRING_SIZE is
begin
   return CHARACTER'POS(String_To_Measure(0));
end Length;




               -- This returns the static length of a string
function Size_Of(String_To_Measure : in DYNAMIC_STRING)
                 return STRING_SIZE is
begin
   return String_To_Measure'LAST;
end Size_Of;




procedure Pos(String_To_Search : in     DYNAMIC_STRING;
              Required_String  : in     DYNAMIC_STRING;
              Place_To_Start   : in     STRING_SIZE;
              Location_Found   :    out STRING_SIZE;
              Result           :    out BOOLEAN) is
End_Search             : STRING_SIZE;
Characters_All_Compare : BOOLEAN;
begin
   Location_Found := 0;
                          -- can we search the string at all?
   if (Place_To_Start < CHARACTER'POS(String_To_Search(0))) and
                     (Place_To_Start < String_To_Search'LAST) then
      Result := TRUE;
   else
      Result := FALSE;
      return;
   end if;

                          -- search the loop for the string now
   End_Search := CHARACTER'POS(String_To_Search(0)) -
                         CHARACTER'POS(Required_String(0)) + 1;

   for Index in Place_To_Start..End_Search loop      -- search loop
      Characters_All_Compare := TRUE;
      for Count in 1..CHARACTER'POS(Required_String(0)) loop
         if Required_String(Count) /=
                           String_To_Search(Count + Index - 1) then
            Characters_All_Compare := FALSE;
            exit;         -- exit loop, a character did not match
         end if;
      end loop;
      if Characters_All_Compare then
         Location_Found := Index;
         return;             -- string match found, return location
      end if;
   end loop;  -- end search loop

end Pos;

end DynStrng;

 

下一个示例程序名为e_c16_p3.ada,它实现了我们在研究字符串时所做的承诺。当时,我们提到ada83没有动态字符串功能,但是ada95有几个包,这些包在ARM中定义为Ada环境的一部分。学习如何在生产程序中使用这些提供的包对您是有利的。就目前而言,花点时间研究e_c16_p3.ada 中包含的动态字符串包将是有益的,因为它说明了如何使用我们在本教程中研究的许多构造

动态字符串包虽然实现了动态字符串包的完整版本,但并不是作为字符串包中的最后一个字提交的。事实上,它有一个问题,我们将在本章后面描述。即使我们解决了这个问题,还有一个更好的字符串包,我们可以在所有的生产程序中使用。这一点也将在本章后面讨论。

我们在本教程中还没有研究过一个结构,尽管我们在上一章中顺便提到过它。第33行包含一个无约束数组类型声明。在名为e_c16_p4.ada的程序的第9行和第10行中说明了它的用法。本教程的第2部分将研究无约束数组。除了这个构造,e_c16_p3.ada没有使用我们在本教程中尚未研究过的ada部分,因此它没有利用ada的高级构造。它只是一个教学辅助工具,但您可以在制作程序中使用它,欢迎您作为Coronado Enterprises教程的用户使用它。您有权将所包含的任何软件用于您认为必要的任何目的,但教程本身的商业化除外。您可能需要为自己的目的稍微修改一个程序,并且您有权这样做。

这里定义的动态字符串最大长度为255个字符,动态长度存储在下标为零的字符串的第一个元素中。因此,必须将字符串声明为下界为0的字符串,上界表示该字符串将被要求存储的最大长度。这个定义来自于borlandinternational对Pascal的实现,他们将其称为turbopascal。

 

DYNSTRNG规范

DynStrng的规范包在该文件的第29行到第116行中进行了定义,该文件有很好的注释,给出了该包的完整定义,并描述了如何使用它。正文在第124行到第384行中给出,并给出了实际的实现。请注意,有些软件开发人员只提供包的规范部分,而这正是您真正需要使用它的部分,并对您隐藏正文。如果它们提供了编译后的主体和规范源代码,那么您就可以将包与特定编译器一起使用。你的编译器附带了这个包Ada.Text_IO文件,一个标准包,而您的编译器作者几乎肯定没有向您提供源代码的正文。这个Ada.Text_IO文件如ARM中所定义的,包只是包的规范部分Ada.Text_IO文件. 可在ARM的附录A.10.1中找到。

您应该注意这样一个事实:我们正在重载这个包的第36行上的名称,这样我们就可以使用它向监视器输出一个动态字符串。系统根据实际使用的参数类型知道我们希望使用哪一个。细心的观察者会注意到我们使用Ada.Text_IO文件版本的Put在第132行的程序中用来重载名称Put。继续讨论重载,您将看到我们在第60行和第63行中定义了两个同名的过程,再次根据类型为每个调用选择适当的过程。

研究DynStrng包,直到你觉得你能很好地理解它,然后编译这个文件为下一个程序做准备。

 

 

 

---------------------------------------------------------------------------------------------------------------------------

原英文版出处:https://perso.telecom-paristech.fr/pautet/Ada95/a95list.htm

翻译(百度):博客园  一个默默的 *** 的人

 

posted @ 2021-04-08 21:17  yangjianfeng  阅读(67)  评论(0编辑  收藏  举报