Hello loeric18,
I will first summarize what I found and then list the current version
of the source code at the end of this answer.As requested in your
first clarification, the code right now compiles error and warning
free with
gnatmake -gnaty main
If you have additional parameters for the command line, let me know
those as well. Based on your feedback to this answer, I can make some
more changes and make this answer complete in a clarification. Please
don't rate the answer until you are satisifed with the clarification.
General fixes:
- the instructions indicated to use -gnaty for style. The code below
compiles w/o error or warning using -gnaty. Lots of little spacing and
spelling fixes as a result. [all files]
- added begin and/or null; statements in a couple places to fix
compilation errors. [both bodies]
- started to add comments - expect to need more before we are done.
Note -gnaty requires "-- " as the prefix for each comment.
List package changes:
- removed with/use to Ada.Strings.Unbounded; with the other changes,
this package should not be referred to directly. Use Element_Type
instead.
- removed the array and index types (and variables using them). The
instructions said to use a "linked list" and the access to Node type
(Node_Access) takes the place of such an index. This also eliminates a
parameter to the generic package. Affects several function / procedure
declarations as well as types of data.
- swapped the order of Next and Info in the declaration. This is was
not necessary but makes it easier to review / debug the code. The
generated code is often more efficient as well this way because the
link is always first with the (arbitrary length) data following.
- use "null" instead of our_null for the comparisons for an empty
list (or end of list).
- added Draw_Graph to the specification
- removed the declaration of Node from the body; this conflicted with
the data type in the specification. Removed most references to Node in
the code; they also caused compile errors.
- made the code easier to read and print by adding line breaks -
mostly in procedure declarations
- Initialized Free to null. Assuming the global variable is
initialized is not recommended.
- If the free list (Free) is null, use "new" to create a new node
instead of raising Program_Error.
- I added FIXME to a few places where code must still be fixed. See
next section for questions / suggestions
- There are several places where to code does not check for null. I
did't fix them all but will do so in the next version. Especially
affects both Empty and Count.
- Insert needs more review once Find is fixed; I didn't work it out
by hand yet. Note the notation used to pass the parameter to New_Node.
- Retrieve needs more review once Find is fixed. I suggest setting
Element to null if the item is not found.
- Neither Count nor Empty assume the data at "List" is part of the
list. Since Node_Acc is an access to Node (or pointer), you can refer
to Node_Acc.Info. Suggest a slight revision to consider "Node_Acc" as
part of the list. Let me know if you want that change, it is an easy
fix.
- Remove deletes a node (puts it on the free list). It does not
remove it from a list and any subsequent nodes are on the free list as
well. Is that what you want or do you need both "Remove" and "Delete"?
- A thought, the nodes in the lower level list should be "Removed" as
well. Hmm. The example I referred to at
http://www.cs.fiu.edu/~weiss/ada.html
uses a finalization routine to "make it so". Do you want the same here
or can you require the main program to clean up the lower level list
before removing the upper level list? Since you may not understand
finalization - I won't add it unless you ask.
FIXME code:
- Find does not appear to have the right parameters nor does it do a
comparison to "find" the value you are looking for. Suggested changes
include:
o Add a value parameter to the call. Something like
Value : in Element_Type;
o Add a comparison in the loop. Something like
if (Element_Type."="(Value, Current.Info))
would work, but requires you to define an "=" function in List.
I think I know what you want here, but I wanted some feedback before
coding it up.
- Draw_Graph can be quite simple, but may require an additional
function added to the generic declaration. Something like
"Draw_Me(Value: in Element_Type)" that either returns a string or
prints a string using Text_IO. The recursive nature of this makes it a
little tricky to get the output to look "right". A simple suggestion
is to use => to show links and () to show groupings [or a lower level
list]. Would you like an example of this included as well?
I am thinking perhaps one or two more iterations will do once I get
your clarification request. Also, check that other reference - if
there are functions there you need, let me know.
--Maniac
main.adb
with List; -- with our generic pavkage
with Ada.Command_Line, Ada.Strings.Unbounded, Ada.Integer_Text_IO,
Text_IO;
use Ada.Command_Line, Ada.Strings.Unbounded, Ada.Integer_Text_IO,
Text_IO;
procedure main is
-- initialize first link list
package List1 is new List (Unbounded_String);
-- use List1;
-- now initialize link list off first linked list
package List2 is new List (List1.Node);
-- use List2;
begin
if Argument_Count = 0 then
Put_Line (Current_Error, "Files don't exist");
Set_Exit_Status (Failure);
else
for Arg in 1 .. Argument_Count loop
null;
-- Draw_Graph(possibly pass file as string argument);
end loop;
end if;
end main;
list.ads
generic
-- Element_Type is the data to be stored into the linked list
type Element_Type is private;
package List is
type Node; -- is private;
type Node_Acc is access Node;
-- Node is a simple linked list element with two parts
-- X.Next is the link to the next element of the list
-- X.Info is the data to be stored
type Node is
record
Next : Node_Acc;
Info : Element_Type;
end record;
-- Create (or reuse) a new node with initial value as provided
function New_Node (Initial_Value : in Node) return Node_Acc;
-- Find an element in the list
procedure Find (List : in Node_Acc;
Found : out Boolean;
Pred_Loc : out Node_Acc;
Location : out Node_Acc);
-- Draw a graph of the current list
procedure Draw_Graph (Fname : String);
-- Insert an element into the list
procedure Insert (List : in out Node_Acc;
Item : in Element_Type);
-- Retrieve an element from the list that matches the value
provided
procedure Retrieve (List : in Node_Acc;
Element : out Element_Type);
-- Return true if the list is empty
function Empty (List : Node_Acc) return Boolean;
-- Return the length of the list
function Length (List : in Node_Acc) return Natural;
-- Delete an element from the list
-- Deleted element retained in the free list for reuse
procedure Delete (X : in out Node_Acc);
end List;
list.adb
with Text_IO;
use Text_IO;
package body List is
-- Free list, initially empty
Free : Node_Acc := null;
-- Pull an item from the free list or create a new one
-- if none are available
function New_Node (Initial_Value : in Node) return Node_Acc is
Result : Node_Acc;
begin
if Free = null then
Result := new Node;
else
Result := Free;
Free := Free.Next;
end if;
Result.all := Initial_Value;
return Result;
end New_Node;
-- FIXME: Find an element in the list
procedure Find (List : in Node_Acc;
Found : out Boolean;
Pred_Loc : out Node_Acc;
Location : out Node_Acc) is
Current : Node_Acc;
Previous : Node_Acc;
begin
Current := List.Next;
Previous := null;
loop
exit when Current = null;
Previous := Current;
Current := Current.Next;
end loop;
Location := Current;
Pred_Loc := Previous;
Found := Current /= null;
end Find;
-- FIXME: Draw a graph of the list
-- program stub. Haven't implimented Draw_Graph yet.
-- still trying to get the other errors out.
procedure Draw_Graph (Fname : String) is
begin
null;
end Draw_Graph;
-- Insert an element into the list
procedure Insert (List : in out Node_Acc;
Item : in Element_Type) is
Have_Duplicate : Boolean;
Pred_Loc : Node_Acc;
Location : Node_Acc;
begin
Find (List => List,
Found => Have_Duplicate,
Pred_Loc => Pred_Loc,
Location => Location);
if Have_Duplicate then
raise Program_Error;
elsif Pred_Loc = null then
List.Next := New_Node (Node'(Info => Item, Next =>
List.Next));
else
Pred_Loc.Next := New_Node (Node'(Info => Item, Next =>
Location));
end if;
end Insert;
-- Retrieve an element from the list
procedure Retrieve (List : in Node_Acc;
Element : out Element_Type) is
Found : Boolean;
Pred_Loc : Node_Acc;
Location : Node_Acc;
begin
Find (List => List,
Found => Found,
Pred_Loc => Pred_Loc,
Location => Location);
if not Found then
Put_Line ("Cannot be found");
else
Element := Location.Info;
end if;
end Retrieve;
-- this function checks if the list is empty
function Empty (List : Node_Acc) return Boolean is
begin
return List.Next = null;
end Empty;
-- this function checks the length of the list
function Length (List : in Node_Acc) return Natural is
Location : Node_Acc;
Count : Natural;
begin
Count := 0;
Location := List.Next;
loop
exit when Location = null;
Count := Count + 1;
Location := Location.Next;
end loop;
return Count;
end Length;
-- FIXME: this procedure removes a node
procedure Delete (X : in out Node_Acc) is
begin
X.Next := Free;
Free := X;
X := null;
end Delete;
end List; |
Request for Answer Clarification by
loeric18-ga
on
20 Dec 2002 09:36 PST
Hi, Maniac
thank you for your rapid work. It is very helpful for me so far. But I
tried to compile it, it showed " main.adb 2:50 : warning: no entities
of "integer_text_io" are referenced " ..so can I remove it?
|
Clarification of Answer by
maniac-ga
on
20 Dec 2002 09:45 PST
Hello loeric18,
Re: Integer_Text_IO
Yes. I have found the warnings from GNAT to be quite helpful in
eliminating a lot of odd code. As a suggestion to clean up all that
kind of code is to use
-gnatWaH
which enables all warnings except for "hiding" warnings (the same name
used in more than one package).
I made a change to Find to add the Value parameter, but as I mentioned
before, I want feedback before sending you an update. In particular,
Is it your intent to "Insert" at the beginning if the entry is "not
found"?
Do you want to store data at the head of the list?
Answers to the other questions would help as well.
--Maniac
|
Request for Answer Clarification by
loeric18-ga
on
20 Dec 2002 10:05 PST
HI, Maniac
Actually, I am ashamed to say I don't even know very much about
how to answer your question to help me...so my feedback is "you could
decide yourself to finish the work", but please choose the easy simple
way which look like made by a rookie. And also please follow the
instruction of the project to finish the code...sorry, that's only
feedback I could give you....Could I just learned Ada 2 weeks..... :(
BTW, after I compiled the version you gave me, can it run for an
output? or just can be compiled?...
|
Request for Answer Clarification by
loeric18-ga
on
20 Dec 2002 12:18 PST
Hi,Maniac
I just finished the meeting with my instructor. He postponeed the
deadline to Jan 6th. So we can do this without rush.
About the input and output, please apply the example "
http://www.cs.fit.edu/~ryan/ada/programs/io/copy-adb.html " to the
main.adb program. you can decide which way to make the whole project
run correct according to the instruction of the project. Please help
me make the program done.
Eric
|
Clarification of Answer by
maniac-ga
on
20 Dec 2002 14:45 PST
Hello loeric18,
Glad for the extension, but I am not sure what is meant by the last
clarification. Is the output supposed to be line numbered or is this
supposed to be an example of how to input the data from the file? The
input method I used is a similar (use Get_Line) and use the length so
you may be OK already. You should probably read up on Find_Token in
the Ada Reference Manual - it is part of Ada.Strings so you can answer
questions about it. It is a handy tool.
Let me provide a copy of what I have right now. It appears to work
with the sample data posted on the web site and matches the format as
specified. The list stuff works OK - I am not sure how much polish you
want applied. The next few paragraphs describe what is done and how it
is done.
Main program:
The two lists are now called "South_Of" and "List_Of_Cities". The
first is just the name of a city, the second has an addition
"Is_South_Of" field that points to the list of cities south of this
one. An equals function is defined for both, Unbounded_String."=" for
the first and the one shown for the A_City type to compare just the
names of the city (and not the links).
The procedure Search_South_Of is recursive - it calls itself whenver
it finds a city and the name does not match the one it is looking for.
This is how the "transitive search" is done (e.g. A->B, and B->C, then
A->C). It runs pretty fast on my machine, no noticeable delay from
entry of the question to printing the answer. If there was one thing
you might want to change is to add functions to "go to next list item"
in the List package and use it here to replace the
South_Head := South_Head.Next;
statement.
The variables in the main program include
Big_Line - a string array long enough to fit the sample input.
Max_Big_Line, Last_Character, First, Last - indexes into Big_Line
Alpha_Set - a "set of characters"; the letters "A" through "Z" and
"a" through "z". This is used to recognize the city names.
Head - the head of the "List_Of_Cities" list
Pred_Loc - a dummy value, set but never read
Found - a boolean for a function return
The first loop loads the list of cities and the nested south of lists.
Read a line, use "Find_Token" to get the first word, insert into the
city list, use "Find_Token" again for the second word, insert that
into the city list, and then add the south of list item to the first
city. Repeats until a line w/ a single character is read.
The second loop does the same with reading the line and building the
two city names. It has five nested if cases
- first name not present, print the "unknown" message
- second name not present, ditto
- 2 is south of 1 according to Search_South_Of, say 2 is south of 1
- 1 is south of 2 according to Search_South_Of, say 2 is north of 1
- print the unknown message
and that's it for the main program.
List specification
Added the equals function to the generic declaration, otherwise pretty
much the same.
List body
Added the Value parameter to Find and made appropriate fixes. Works
really good.
Draw_Graph is still a stub, I used gvd to figure out the structures
for debugging so never needed it. You might just remove it.
Insert is modified to return "Where" the item was inserted and will
return "Location" if you attempt to insert the same value more than
once into a list.
I don't think I ever ran Retrieve, Empty, Length, nor Delete. I did
fix the null access type stuff so it should work OK, but otherwise
they are what you provided.
Give it a good beating and let me know how it works for you. If
something still is not clear, don't hesitate to ask more as a
clarification. I probably can't code up more until Monday but a
general question will be answered promptly.
Good luck.
--Maniac
---- source code follows ----
Main program
with List; -- with our generic pavkage
with Ada.Strings;
use Ada.Strings;
with Ada.Strings.Unbounded;
use Ada.Strings.Unbounded;
with Ada.Strings.Fixed;
use Ada.Strings.Fixed;
with Ada.Strings.Maps; -- for character set type
use Ada.Strings.Maps;
with Text_IO;
use Text_IO;
procedure main is
-- South of relationship
package South_Of is new List (Unbounded_String,
"=");
type A_City is record
Name : Unbounded_String;
Is_South_Of : South_Of.Node_Acc;
end record;
-- Equivalence function used to compare if two
-- cities in "A_City" match (ignore the link)
function "=" (Left, Right : A_City) return Boolean;
function "=" (Left, Right : A_City) return Boolean is
begin
return Left.Name = Right.Name;
end "=";
-- The list of cities (list of lists)
package List_Of_Cities is new List (A_City, "=");
-- Recursive function to do the transitive
-- search for a city "south of" another
procedure Search_South_Of (City1 : in List_Of_Cities.Node_Acc;
City2_Name : in Unbounded_String;
Found : out Boolean);
City1_Name, City2_Name : Unbounded_String;
City1, City2 : List_Of_Cities.Node_Acc;
Max_Big_Line : constant Natural := 500;
Big_Line : String (1 .. Max_Big_Line);
Last_Character : Natural; -- Last character of Big_Line
First, Last : Natural; -- Indicies into Big_Line
Alpha_Set : constant Character_Set :=
To_Set (Character_Ranges'((Low => 'A', High => 'Z'),
(Low => 'a', High => 'z')));
Head : List_Of_Cities.Node_Acc := null;
City_South : South_Of.Node_Acc;
Pred_Loc : List_Of_Cities.Node_Acc; -- dummy value for find
Found : Boolean; -- did we find the city
procedure Search_South_Of (City1 : in List_Of_Cities.Node_Acc;
City2_Name : in Unbounded_String;
Found : out Boolean) is
use type South_Of.Node_Acc;
South_Head : South_Of.Node_Acc := City1.Info.Is_South_Of;
Cityx : List_Of_Cities.Node_Acc;
Xfound : Boolean;
Xpred : List_Of_Cities.Node_Acc;
begin
Found := False;
loop
exit when South_Head = null;
if South_Head.Info = City2_Name then
Found := True;
exit;
else
List_Of_Cities.Find (Head, A_City'(South_Head.Info, null),
Xfound,
Xpred, Cityx);
Search_South_Of (Cityx, City2_Name, Xfound);
if Xfound then
Found := True;
exit;
else
South_Head := South_Head.Next;
end if;
end if;
end loop;
end Search_South_Of;
begin
loop -- build the lists
Text_IO.Get_Line (Big_Line, Last_Character);
exit when Last_Character = 1;
-- Extract the first city name (assume correct input)
Find_Token (Big_Line (1 .. Last_Character), Alpha_Set,
Inside, First, Last);
City1_Name := To_Unbounded_String (Big_Line (First .. Last));
List_Of_Cities.Insert (Head, A_City'(City1_Name, null), City1);
-- Repeat with the second city name
Find_Token (Big_Line (Last + 1 .. Last_Character), Alpha_Set,
Inside, First, Last);
City2_Name := To_Unbounded_String (Big_Line (First .. Last));
List_Of_Cities.Insert (Head, A_City'(City2_Name, null), City2);
-- Both cities now in the "list of cities, create a "south of"
-- relationship between them
South_Of.Insert (City1.Info.Is_South_Of, City2_Name,
City_South);
end loop;
-- at this point, we have our "list of lists"
-- Head points to a list of cities
-- Some of the Cities have "Is_South_Of" lists which point
-- to cities that are know to be north of them
null; -- debug point
loop
-- get the next pair of names
Text_IO.Get_Line (Big_Line, Last_Character);
exit when Last_Character = 1;
-- Extract the first city name (assume correct input)
Find_Token (Big_Line (1 .. Last_Character), Alpha_Set,
Inside, First, Last);
City1_Name := To_Unbounded_String (Big_Line (First .. Last));
-- Repeat with the second city name
Find_Token (Big_Line (Last + 1 .. Last_Character), Alpha_Set,
Inside, First, Last);
City2_Name := To_Unbounded_String (Big_Line (First .. Last));
List_Of_Cities.Find (Head, A_City'(City1_Name, null), Found,
Pred_Loc, City1);
-- first case, first name not found - can't say
-- anything about where it is
if (not Found) then
Text_IO.Put_Line ("The relative position of " &
To_String (City1_Name) & " and " &
To_String (City2_Name) & " is unknown.");
else
-- second case, same situation, same message
List_Of_Cities.Find (Head, A_City'(City2_Name, null), Found,
Pred_Loc, City2);
if (not Found) then
Text_IO.Put_Line ("The relative position of " &
To_String (City1_Name) & " and " &
To_String (City2_Name) & " is
unknown.");
else
-- third case, 2 is south of 1
Search_South_Of (City1, City2_Name, Found);
if (Found) then
Text_IO.Put_Line (To_String (City2_Name) &
" is north of " &
To_String (City1_Name) & ".");
else
-- fourth case, 2 is north of 1
Search_South_Of (City2, City1_Name, Found);
if (Found) then
Text_IO.Put_Line (To_String (City2_Name) &
" is south of " &
To_String (City1_Name) & ".");
else
-- last case, still can't tell
Text_IO.Put_Line ("The relative position of " &
To_String (City1_Name) & " and " &
To_String (City2_Name) & " is
unknown.");
end if;
end if;
end if;
end if;
end loop;
end main;
list.ads
generic
-- Element_Type is the data to be stored into the linked list
type Element_Type is private;
with function "=" (Left, Right : Element_Type) return Boolean;
package List is
type Node; -- is private;
type Node_Acc is access Node;
-- Node is a simple linked list element with two parts
-- X.Next is the link to the next element of the list
-- X.Info is the data to be stored
type Node is
record
Next : Node_Acc;
Info : Element_Type;
end record;
-- Create (or reuse) a new node with initial value as provided
function New_Node (Initial_Value : in Node) return Node_Acc;
-- Find an element in the list
procedure Find (List : in Node_Acc;
Value : in Element_Type;
Found : out Boolean;
Pred_Loc : out Node_Acc;
Location : out Node_Acc);
-- Draw a graph of the current list
procedure Draw_Graph (Fname : String);
-- Insert an element into the list
procedure Insert (List : in out Node_Acc;
Item : in Element_Type;
Where : out Node_Acc);
-- Retrieve an element from the list that matches the value
provided
procedure Retrieve (List : in Node_Acc;
Element : out Element_Type);
-- Return true if the list is empty
function Empty (List : Node_Acc) return Boolean;
-- Return the length of the list
function Length (List : in Node_Acc) return Natural;
-- Delete an element from the list
-- Deleted element retained in the free list for reuse
procedure Delete (X : in out Node_Acc);
end List;
list.adb
package body List is
use type Element_Type;
-- Free list, initially empty
Free : Node_Acc := null;
-- Pull an item from the free list or create a new one
-- if none are available
function New_Node (Initial_Value : in Node) return Node_Acc is
Result : Node_Acc;
begin
if Free = null then
Result := new Node;
else
Result := Free;
Free := Free.Next;
end if;
Result.all := Initial_Value;
return Result;
end New_Node;
-- Find an element in the list
procedure Find (List : in Node_Acc;
Value : in Element_Type;
Found : out Boolean;
Pred_Loc : out Node_Acc;
Location : out Node_Acc) is
Current : Node_Acc;
Previous : Node_Acc := null;
begin
Current := List;
loop
exit when Current = null;
exit when Value = Current.Info;
Previous := Current;
Current := Current.Next;
end loop;
Location := Current;
Pred_Loc := Previous;
Found := Current /= null;
end Find;
-- FIXME: Draw a graph of the list
-- program stub. Haven't implimented Draw_Graph yet.
-- still trying to get the other errors out.
procedure Draw_Graph (Fname : String) is
begin
null;
end Draw_Graph;
-- Insert an element into the list
procedure Insert (List : in out Node_Acc;
Item : in Element_Type;
Where : out Node_Acc) is
Have_Duplicate : Boolean;
Pred_Loc : Node_Acc;
Location : Node_Acc;
begin
Find (List => List,
Value => Item,
Found => Have_Duplicate,
Pred_Loc => Pred_Loc,
Location => Location);
if Have_Duplicate then
Where := Location;
elsif Pred_Loc = null then
List := New_Node (Node'(Info => Item, Next => List));
Where := List;
else
Pred_Loc.Next := New_Node (Node'(Info => Item, Next =>
Location));
Where := Pred_Loc.Next;
end if;
end Insert;
-- Retrieve an element from the list
procedure Retrieve (List : in Node_Acc;
Element : out Element_Type) is
Found : Boolean;
Pred_Loc : Node_Acc;
Location : Node_Acc;
begin
Find (List => List,
Value => Element,
Found => Found,
Pred_Loc => Pred_Loc,
Location => Location);
if not Found then
null;
else
Element := Location.Info;
end if;
end Retrieve;
-- this function checks if the list is empty
function Empty (List : Node_Acc) return Boolean is
begin
return List = null;
end Empty;
-- this function checks the length of the list
function Length (List : in Node_Acc) return Natural is
Location : Node_Acc;
Count : Natural;
begin
Count := 0;
Location := List;
loop
exit when Location = null;
Count := Count + 1;
Location := Location.Next;
end loop;
return Count;
end Length;
-- FIXME: this procedure removes a node
procedure Delete (X : in out Node_Acc) is
begin
X.Next := Free;
Free := X;
X := null;
end Delete;
end List;
|
Request for Answer Clarification by
loeric18-ga
on
21 Dec 2002 09:23 PST
Hi, Maniac
First of all, I have to appreciate to your awsome job. But I am
going to San Francisco for about one week, so after I come back I'll
test the program you gave me, and rate the answer. I think I am sure I
will pay some more for your excellemnt work. About the example
copy.adb is supposed to be an example of how to input the data from
the file asked by my instructor. Later
Eric
|
Clarification of Answer by
maniac-ga
on
21 Dec 2002 09:27 PST
Hello Loeric18,
OK. Have a good trip and hear from you again later.
--Maniac
|
Request for Answer Clarification by
loeric18-ga
on
05 Jan 2003 18:39 PST
Hi, Maniac
I jsut tried to compile those file. Compilation is ok, but I can't
find the list.exe to execute and run the file, is there anything
wrong?? thx
Eric
|
Request for Answer Clarification by
loeric18-ga
on
05 Jan 2003 18:58 PST
WOW.......I tried again, and it said "main.exe" missing, but I checked
the folder, these was a main.exe there, so I just ran it ,and it
worked perfect!!!!!! Thank you very much!!
Eric
|
Request for Answer Clarification by
loeric18-ga
on
05 Jan 2003 19:15 PST
Hi, Maniac
Could you modify little bit to make the program read all the
relations of the cities first, and then a "#", after "#" are all the
questions, then a "#" again, then all the answers. for example:
Melbourne DaytonaBeach
DaytonaBeach Jacksonville
Orlando Jacksonville
#
Melbourne Jacksonville
Tampa Melbourne
Jacksonville Orlando
Orlando DaytonaBeach
#
the output should be
Melbourne is south of Jacksonville.
The relative position of Tampa and Melbourne is unknown.
Jacksonville is north of Orlando.
The relative position of Orlando and DaytonaBeach is unknown.
thx!!! I think it would be the last request!!plz
Eric
|
Clarification of Answer by
maniac-ga
on
06 Jan 2003 14:04 PST
Hello loeric18,
Thank you for the kind comments (and tip!).
About the clarification request - that is a straightforward change.
In list.adb, lines 150-152 should read...
Text_Io.Put_Line(To_String(City1_Name) &
" is sorth of " &
To_String(City2_Name) & ".");
[third case - change the order of City1_Name and City2_Name, replace
"north" with "south"]
and similarly on lines 157-159, make the same kind of change (to
reverse City1_Name and City2_Name, and replace "south" with "north").
The line numbers may be off by a little in your copy - adjust if
needed. Check the comments for case 3 and 4 as well (I noticed they
were identical - oops :-() and fix them to match the code.
I tested with your input and get the "correct" output.
--Maniac
|