Reputation: 47
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
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
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:
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;
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;
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