问题
Im stuck in Ada. I'm supposed to create a package with a specific Flag_Type that can be written to and read in order to print a simple flag. Id like to think Ive managed to make the package ads and the package body adb right but I struggle with the commands for the main program.
First is first, the output is supposed to look like this:
Enter the flag name: Italys flag
Enter the flag height: 2
Enter the stripes width: 3
Enter the flags colors: GWR
Italys flag
+---------+
|GGGWWWRRR|
|GGGWWWRRR|
+---------+
now, my package ADS looks like this:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
package Flagdrawer is
type Flag_Type is private;
procedure Get(Item: out Flag_Type);
procedure Put(Item: in Flag_Type);
private
type Flag_Type is
record
Flag_Name: String(1..20);
L : Integer;
Flag_Height : Integer;
Flag_Width : Integer;
Flag_Colors : String(1..3);
end record;
end Flagdrawer;
My package body looks like this:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Flagdrawer; use Flagdrawer;
package body Flagdrawer is
procedure Get(Item: out Flag_Type) is
begin
Get_Line(Item.Flag_Name, Item.L);
Get(Item.Flag_Height);
Get(Item.Flag_Width);
Get(Item.Flag_Colors);
end Get;
procedure Put(Item: in Flag_Type) is
Real_Width : Integer;
begin
Real_Width := Item.Flag_Width *3;
Put(Item.Flag_Name(1..Item.L));
New_Line;
Put("+");
for I in 1..Real_Width loop
Put("-");
end loop;
Put_Line("+");
for J in 1..Item.Flag_Height loop
Put("!");
for K in 1..Item.Flag_Width loop
Put(Item.Flag_Colors(1));
end loop;
for L in 1..Item.Flag_Width loop
Put(Item.Flag_Colors(2));
end loop;
for M in 1..Item.Flag_Width loop
Put(Item.Flag_Colors(3));
end loop;
Put_Line("!");
end loop;
Put("+");
for I in 1..Real_Width loop
Put("-");
end loop;
Put_Line("+");
end Put;
end Flagdrawer;
and then my sorely lacking main program looks like this:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Flagdrawer; use Flagdrawer;
procedure Tenta_Flagdrawah is
F: Flag_Type;
begin
Put_line("Enter the flags name (1): ");
Put_Line("Enter the flags height (2): ");
Put_Line("Enter the stripes' width (3): ");
Put_Line("Enter the RGB for the flag's colors (4): ");
Get(F);
New_Line;
Put(F);
end Tenta_Flagdrawah;
Im only used to assignments that have one specific input, lets say Get(F) where F is Flag_Type, now its spread out over multiple variables and I dont know how to consolidate them.
I've been getting good responses from here in the past, is there any chance anyone could give me some tips as to where Im at fault? I know my main program is severely lacking but I dont know how to code it.
Thanks in advance for any help!
EDIT
I found a solution that works (sort of) which is commented out of this main program I direct to Simon Wright as I didnt quite get what you meant with your declarations. I put them in my MP and I keep getting "actual for item must be a variable". I tried using Item.Name instead but it claims its an invalid prefix. Where did I go wrong you think?
main program .adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Flagdrawer; use Flagdrawer;
procedure Tenta_Flagdrawah is
F: Flag_Type;
subtype Color_String is String (1 .. 3);
procedure Get (Item : out Flag_Type;
Name : in String;
Height : in Natural;
Stripe_Width : in Natural;
Colors : in Color_String) is
begin
Put("Enter the flag's name: ");
Get(Name);
Put("Enter the flag's height: ");
Get(Height);
end Get;
begin
-- Put_line("Enter the flags name (1): ");
-- Put_Line("Enter the flags height (2): ");
-- Put_Line("Enter the stripes' width (3): ");
-- Put_Line("Enter the RGB for the flag's colors (4): ");
-- Get(F);
New_Line;
Put(F);
end Tenta_Flagdrawah;
回答1:
A lot of your trouble is the Get
procedure; it implements all the text input for the various fields without reference to whatever the main program’s doing.
In general, it isn’t good practice to do I/O within an abstract data type like Flag
; much better to do it in the calling program. (I can see that’d be awkward for Put
).
You could read the parameters in the main program and supply them to Get
,
subtype Color_String is String (1 .. 3);
procedure Get (Item : out Flag_Type;
Name : in String;
Height : in Natural;
Stripe_Width : in Natural;
Colors : in Color_String);
This would mean making the package spec (sorry, I couldn’t resist some tidying)
package Flagdrawer is
type Flag_Type is private;
subtype Color_String is String (1 .. 3);
procedure Get (Item : out Flag_Type;
Name : in String;
Height : in Positive;
Stripe_Width : in Positive;
Colors : in Color_String);
procedure Put(Item: in Flag_Type);
private
type Flag_Type is
record
Name : String (1 .. 20);
Name_Len : Natural;
Height : Positive;
Stripe_Width : Positive;
Colors : Color_String;
end record;
end Flagdrawer;
and implementing Get
in the package body as
procedure Get (Item : out Flag_Type;
Name : in String;
Height : in Positive;
Stripe_Width : in Positive;
Colors : in Color_String) is
begin
-- Don’t exceed the 20-character limit on the stored Name
Item.Name_Len := Natural'Min (Item.Name'Length, Name'Length);
Item.Name (1 .. Item.Name_Len) := Name (Name'First .. Item.Name_Len);
Item.Height := Height;
Item.Stripe_Width := Stripe_Width;
Item.Colors := Colors;
end Get;
and the main program would be
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Flagdrawer; use Flagdrawer;
procedure Tenta_Flagdrawah is
F: Flag_Type;
begin
Put("Enter the flags name: ");
-- Need a declare block so that Name
-- is as long as the user input
declare
Name : constant String := Get_Line;
Height : Positive;
Stripe_Width : Positive;
Colors : Flagdrawer.Color_String;
begin
Put("Enter the flag's height: ");
Get (Height);
Put("Enter the stripes' width: ");
Get (Stripe_Width);
Put("Enter the RGB for the flag's colors: ");
Get (Colors);
Get(F,
Name => Name,
Height => Height,
Stripe_Width => Stripe_Width,
Colors => Colors);
end;
New_Line;
Put(F);
end Tenta_Flagdrawah;
回答2:
Same method as in the previous post (see here), just add the user input logic:
main.adb
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
Stripes : constant array (Natural range <>) of Character := "GWR";
Stripe_Width : constant Positive := 3;
Width : constant Natural := 2 + Stripes'Length * Stripe_Width;
Height : constant Natural := 2 + 2;
type Screen_X is new Natural range 0 .. Width - 1;
type Screen_Y is new Natural range 0 .. Height - 1;
-------------
-- Pattern --
-------------
function Pattern (X : Screen_X; Y : Screen_Y) return Character is
Is_Border_LR : constant Boolean :=
X = Screen_X'First or else X = Screen_X'Last;
Is_Border_TB : constant Boolean :=
Y = Screen_Y'First or else Y = Screen_Y'Last;
begin
if Is_Border_LR and Is_Border_TB then
return '+';
elsif Is_Border_LR then
return '|';
elsif Is_Border_TB then
return '-';
else
return Stripes (Integer (X - Screen_X'First - 1) / Stripe_Width);
end if;
end Pattern;
begin
-- The Render loop.
for Y in Screen_Y loop
for X in Screen_X loop
Put (Pattern (X, Y));
end loop;
New_Line;
end loop;
end Main;
output
$ ./main
+---------+
|GGGWWWRRR|
|GGGWWWRRR|
+---------+
来源:https://stackoverflow.com/questions/61974481/package-bodies-and-main-programs-simple-assignment-ada