AlanS2000
AlanS2000

Reputation: 47

How to use Ada doubly linked lists

I am working on a school project with the Ada programming language. The professor wants us to use a language that we are not familiar with to write. I need to use Ada doubly linked list to write a text editor program. The program will take a single optional command-line argument when called that will specify the default file name. If that file already exists, its contents should be loaded into the text buffer. Upon saving the file, the contents of the buffer will be dumped into a file with the specified name, overwriting any existing file.

for example, if I enter

a -- command for appended

hello

world

.

the file will have

hello

world

appended to the end of the document

if I type

3 a

hello

world

.

then the same line gets appended after line 3 of the document.

Here is the code I wrote so far, but I can't figure out how to use string as my case statement's condition too.

Can someone help me with this project?

with Ada.Containers.Doubly_Linked_Lists;
with Ada.Text_Io; use Ada.Text_Io;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;


procedure main is
   package String_List is new Ada.Containers.Doubly_Linked_Lists(Unbounded_String);
   use String_List;
   --Userinput : String(1 .. 10) := (others => ' '); --This string length is 10
   Last: Integer; --This is use to count input string length
   currentAddress: Integer := 0;
   text : List; -- List is from Doubly_Linked_Lists
   type Userinput is (a, c, p, e);
   --size: Integer; --This is use to count input string length


   procedure Print(Position : Cursor) is -- this subprogram print all string from list
   begin
      Put_Line(To_String(Element(Position)));
      --Put_Line("K");
   end Print;



begin
   loop

      Put( Integer'Image (currentAddress) & " >> " );

      Get_Line(Userinput);

      case Userinput is

         when a =>
            Put( Integer'Image (currentAddress) & " >> " );
            Get_Line(Userinput);  
            text.Append(To_Unbounded_String(Userinput)); -- if letter is a add it to the doubly link list        

         when c =>      
            --text.Insert(Before => text.Find(To_Unbounded_String(Userinput)), New_Item => To_Unbounded_String( ? ));

         when p =>      
            text.Iterate(Print'access);
         when e =>      
            Put_Line("Program Exit");                     
            exit;
         when others =>
            Put_Line ("No command found ");   

      end case;

   end loop;

end main;

Upvotes: 2

Views: 889

Answers (2)

Simon Wright
Simon Wright

Reputation: 25491

You can’t use a String as the "selecting expression" of a case statement (ARM 5.4(4)), because it’s not a discrete type (any more than a real number, or a record, is).

You might try using an enumeration as in the example below (which leaves open the question of how to deal with input like your example 3 a):

with Ada.Text_IO;
with Ada.IO_Exceptions;
procedure Alan is
   type Command is (A, C, P, E);
   package Command_IO is new Ada.Text_IO.Enumeration_IO (Command);
begin
   loop
      declare
         Cmd : Command;
      begin
         Command_IO.Get (Cmd);
         Ada.Text_IO.Skip_Line;
         Ada.Text_IO.Put_Line ("read " & Cmd'Image);                -- ' to sort out the not-fully-Ada-aware syntax highlighting
         case Cmd is
            when A => ...
            ...
            when E => exit;
         end case;
      exception
         when Ada.IO_Exceptions.Data_Error =>
            Ada.Text_IO.Put_Line ("unrecognised command");
      end;
   end loop;
end Alan;

Normally I’d use Ada.Text_IO;; not here, for clarity.

Upvotes: 3

DeeDee
DeeDee

Reputation: 5941

The trick of implementing an application is to decompose it into functional components and implement each of them in a separate (family of) package(s). You could, for example, start as follows:

  • Split the parsing of the command from where it acts on the text buffer. Define and implement (as an example) a package with the following specification:

parser.ads

package Parser is

   Parse_Error : exception;   

   type Command_Kind is (Insert, Delete, Clear);

   subtype Line_Number is Natural;   
   No_Line_Number : constant Line_Number := 0;

   type Command is record
      Kind : Command_Kind;
      Line : Line_Number;
   end record;      

   function Parse (Str : String) return Command;
   --  Parses the given string and returns a command data object on success.

end Parser;
  • Implement an abstract text buffer. You might want to use Indefinite_Vectors instead of a Doubly_Linked_List as the container of your choice as you will deal with line numbers extensively (vectors can be indexed more easily compared to doubly linked lists). Define and implement (as an example) a package with the following specification:

text_buffers.ads

with Ada.Containers.Indefinite_Vectors;

package Text_Buffers is

   type Text_Buffer is private;

   subtype Line_Number is Positive;   --  Different from Parsers.Line_Number!

   procedure Load 
     (Buffer   : in out Text_Buffer; 
      Filename : String);
   --  Loads a text file into the text buffer.

   procedure Save 
     (Buffer   : in out Text_Buffer;
      Filename : String);
   --  Saves a text buffer into a text file.

   function Line_Count 
     (Buffer : Text_Buffer) return Natural;
   --  Gets the number of lines in the buffer.

   function Get_Line
     (Buffer : Text_Buffer;
      Line   : Line_Number) return String;
   --  Gets the text of the given line.

   procedure Clear 
     (Buffer : in out Text_Buffer);
   --  Clears the text buffer.

   procedure Insert
     (Buffer : in out Text_Buffer; 
      Text   : String; 
      After  : Line_Number);
   --  Inserts line of text to the text buffer.

   procedure Delete
     (Buffer : in out Text_Buffer; 
      Line   : Line_Number);
   --  Deletes a line of text from the text buffer.

   --  ... other actions.   

private

   package Vector_String is 
     new Ada.Containers.Indefinite_Vectors (Line_Number, String);  
   use Vector_String;

   type Text_Buffer is new Vector with null record;

end Text_Buffers;
  • Use the packages Parser and Text_Buffers to build your final text editor application. I would advise to put the application logic (initialization and main loop) also into a separate package and call Run from Main (see below):

editor.ads

package Editor is

   procedure Run (Filename : String);
   --  Runs the editor application.

end Editor;

editor.adb

with Parser;
with Text_Buffers;

package body Editor is

   ---------
   -- Run --
   ---------

   procedure Run (Filename : String) is
   begin      
      -- Initialization & Program loop.
      null;
   end Run;      

end Editor;

main.adb

with Ada.Command_Line;
with Editor;

procedure Main is
  Filename : String;
begin
   --  Process command line options, set Filename.
   Editor.Run (Filename);
end Main;

Upvotes: 2

Related Questions