How to output Integers using the Put_Line method? - ada

I can't get this program to compile because it doesn't seem to print integer variables along with strings in the Put_Line method. I've looked at source code online and it works when they do it so where am I going wrong. Thanks for your help.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure MultiplicationTable is
procedure Print_Multiplication_Table(Number :in Integer; Multiple :in Integer) is
Result : Integer;
begin
for Count in 1 ..Multiple
loop
Result := Number * Count;
Put_Line(Number & " x " & Count & " = " & Result);
end loop;
end Print_Multiplication_Table;
Number : Integer;
Multiple : Integer;
begin
Put("Display the multiplication of number: ");
Get(Number);
Put("Display Multiplication until number: ");
Get(Multiple);
Print_Multiplication_Table(Number,Multiple);
end MultiplicationTable;`

The problem is that you're using & with strings and integers.
Try one of the following:
Replace Number inside the parameter of put with Integer'Image(Number)
Or break up the Put_Line into the components that you want; ex:
-- Correction to Put_Line(Number & " x " & Count & " = " & Result);
Put( Number );
Put( " x " );
Put( Count );
Put( " = " );
Put( Result);
New_Line(1);

Try this:
Put_Line(Integer'Image(Number) & " x " & Integer'Image(Count) & " = " & Integer'Image(Result));

You're already have with and use clauses for Ada.Integer_Text_IO, but you're not actually using it.
Change this:
Put_Line(Number & " x " & Count & " = " & Result);
to this:
Put(Number); Put(" x "); Put(Count); Put(" = "); Put(Result); New_Line;
(I normally wouldn't put multiple statements on one line, but in this case it makes sense.)
Note that Integer'Image prepends non-negative integers with a space, something I've always found greatly annoying; Ada.Integer_Text_IO.Put doesn't do that (unless you ask it to).
You could define overloaded "&" functions, something like this:
function "&"(Left: String; Right: Integer) return String is
begin
return Left & Integer'Image(Right);
end "&";
function "&"(Left: Integer; Right: String) return String is
begin
return Integer'Image(Left) & Right;
end "&";
which would make your original Put_Line call valid, but the multiple Put calls are probably better style.

Building on the answer (and a comment in another question) from Keith Thompson, here is a full Ada program that can output strings and integers with &, using Put_Line, but without the spaces that Integer'Image would otherwise prepend:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
function lstrip(S: String) return String is
begin
if S(S'First) = ' ' then
return S(S'First+1 .. S'Last);
else
return S;
end if;
end;
function "&"(Left: String; Right: Integer) return String is
begin
return Left & lstrip(Integer'Image(Right));
end "&";
function "&"(Left: Integer; Right: String) return String is
begin
return lstrip(Integer'Image(Left)) & Right;
end "&";
begin
Put_Line("x=" & 42);
end Main;

Related

Using multidimensional array in Ada

In this code, I need help writing a multidimensional array with a range between 2020-01-01 to 2119-12-31.
My code works but as you see there are no arrays in it. How can I write this code with only arrays?
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
Procedure Date is
type date_type is record
Str : string (1..8);
Length : Natural := 0; end record;
A: date_type;
begin
loop
Put ("Enter a date between 2020-01-01 to 2119-12-31 : ");
Get_Line (A.Str, A.Length);
exit when A.Length = 8;
Put_Line ("Wrong input. Try again.");
end loop;
Put_Line (A.Str (1 .. 4) & "-" & A.Str (5 .. 6) & "-" & A.Str (7 .. 8));
end Date;
Perhaps, rather than a multi-dimensional array you should consider using a record such as
type Year_Number is range 1900..3000;
type Month_Number is range 1..12;
type Day_Number is range 1..31;
type Date_Rec is record
Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
end record;
subtype Year_String is string (1..4);
subtype Month_String is string (1..2);
subtype Day_String is string (1..2);
function To_Date (Yr : Year_String; Mnth : Month_String; Dy : Day_String)
return Date_Rec is
Result : Date_Rec;
begin
Result.Year := Year_Number'Value (Yr);
Result.Month := Month_Number'Value (Mnth);
Result.Day := Day_Number'Value (Dy);
return Result;
end To_Date;
You can now pass around instances of Date_
Rec doing whatever you want with the date.
If you go this far then you might want to consider using the Time type described in Ada Language Reference Manual sections 9.6 and 9.6.1.
You haven't asked a reasonable question here because "I want to use arrays" is not a good reason to use an array.
"This problem can be best solved with an array ... but how do I deal with ... ?" would be a reasonable question, but you haven't stated a problem,let alone one that needs an array.
This is important because "using an array" is thinking in the solution domain, like "using a chisel". It's not the way to think about programming in Ada, (or IMO in any language).
Try thinking in the problem domain first : instead of "I want to use a chisel", I think "I want to recess this hinge so the door fits precisely" and a chisel is the neatest way of doing the job.
Then "How can I best validate a date?" would be one reasonable question, or "how can I store events that happen on each day for 100 years?"
The answer to the first question is probably in the Ada.Calendar package. Possibly the Value function in Ada.Calendar.Formatting, with an exception handler to catch incomprehensible strings and make the user try again.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar;
with Ada.Calendar.Formatting;
procedure date is
Date : Ada.Calendar.Time;
Done : Boolean;
begin
loop
Put ("Enter a date between 2020-01-01 to 2119-12-31 : ");
Done := TRUE;
declare
A : String := Get_Line & " 12:00:00";
begin
Date := Ada.Calendar.Formatting.Value(A); -- validate it's a date
Done := Ada.Calendar.Year(Date) >= 2020
and Ada.Calendar.Year(Date) < 2120; -- validate correct range
exception
when Constraint_Error => Done := False; -- Formatting.Value failed
end;
exit when Done;
Put("Try Again : ");
end loop;
end date;
The answer to the second is probably a 1-dimensional array indexed by Day_Count from Ada.Calendar.Arithmetic but let's use the wrong tool : a 3D array indexed by your range of years, Month_Number and Day_Number from the Ada.Calendar base package.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Calendar.Formatting;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure date is
Date : Ada.Calendar.Time;
Done : Boolean := TRUE;
Event_Array : array(2020 .. 2119,
Ada.Calendar.Month_Number,
Ada.Calendar.Day_Number) of Unbounded_String;
begin
Event_Array := (others => (others => (others => Null_Unbounded_String)));
Event_Array(2020,11,3) := To_Unbounded_String("nothing much");
loop
Put ("Enter a date between 2020-01-01 to 2119-12-31 : ");
Done := TRUE;
declare
A : String := Get_Line & " 12:00:00";
begin
Date := Ada.Calendar.Formatting.Value(A);
Done := Ada.Calendar.Year(Date) >= 2020
and Ada.Calendar.Year(Date) < 2120;
exception
when Constraint_Error => Done := False;
end;
exit when Done;
Put("Try Again : ");
end loop;
Put_Line("Today " & Ada.Calendar.Formatting.Image(Date) & " : " &
To_String(Event_Array(Year(Date), Month(Date), Day(Date))) & " happened");
end date;
Test with the string 2020-11-03

Pascal Infinite while loop

I'm implementing a program in FreePascal in Win10(64-bit). The problem state:
'Given a string, replace all substring 'child' with 'childhood' '
or
'Replace all 'child' with 'childhood''
I try this program
uses crt;
var s, newS : string;
tmp, tmp2, tmp3 : int64;
tmpstr, tmpstr2 : string;
step, step2, step3 : longint;
position : longint;
begin
clrscr;
write('Nhap xau : '); readln(s);
//main mechanism
while pos('child',s) <> 0 do begin
position := pos('child', s);
delete(s, pos('child',1), 5);
insert('childhood',s,position);
inc(position, 9);
newS := '';
for step:=position to length(s) do begin
newS := newS + s[step];
end;
s := newS;
end;
writeln(s);
readkey;
end.
You can see that this part:
inc(position, 9);
newS := '';
for step:=position to length(s) do begin
newS := newS + s[step];
end;
s := newS;
was used to try to cut off the while loop, but it doesn't work. Any idea?
Thanks a lot and have a good day! Thanks for reading this question thread! =)
This is just one of the possibilities, not optimized but perhaps the easiest to understand:
oldstr := 'original child string';
newstr := '';
while oldstr<>'' do begin
// analyze the string from left to right
if copy(oldstr, 1 5)='child' then begin
// match found, perform substitution
newstr := newstr+'childhood';
delete(oldstr, 1, 5)
end else begin
// does not match, go ahead to the next possibility
newstr := newstr+oldstr[1];
delete(oldstr, 1, 1)
end
end
// now newstr is the desired result
The gotcha here was to not analyze again what was added in a previous step (child->childhood). The algorithm above (warning, I've not tested it) ensures that any single char from the original string is checked only once.

Why is my Ada program not outputting correctly?

Let me start by saying this is the first ada program I have ever created. I have no idea how it works, and my assignment is incredibly simple. However, the output is not working correctly. It works with the first variable, but not with the next two. It also prints the first variable weird. Here is my code:
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
Author, Title, Pages: String := " ";
begin
Put("Enter Author: ");
Get(Author);
Put("Enter Title: ");
Get(Title);
Put("Enter number of pages: ");
Get(Pages);
Put("Author: ");
Put(Author);
New_Line;
Put("Title: ");
Put(Title);
New_Line;
Put("Number of pages: ");
Put(Pages);
end Main;
The goal is simply to enter information about a book and the program reads it out to you. This is the output:
Enter Author: john
Enter Title: Enter number of pages: Author: j
Title: o
Number of pages: h
Side note, I couldn't get page numbers to work as an integer. The get and put methods just gave errors. That isn't important but if anyone can help make that an integer I would appreciate it.
Here's a possible solution:
with Ada.Text_IO;
procedure Text_Input is
type Page_Count is range 1 .. 10_000;
package Page_Count_Text_IO is new Ada.Text_IO.Integer_IO (Page_Count);
function Get_Line (Message : in String) return String;
function Get_Line (Message : in String) return Page_Count;
function Get_Line (Message : in String) return String is
begin
Ada.Text_IO.Put (Message);
return Ada.Text_IO.Get_Line;
end Get_Line;
function Get_Line (Message : in String) return Page_Count is
begin
return Result : Page_Count do
Ada.Text_IO.Put (Message);
Page_Count_Text_IO.Get (Result);
if Ada.Text_IO.Get_Line /= "" then
raise Constraint_Error
with "Page count followed by extra characters.";
end if;
end return;
end Get_Line;
Author : constant String := Get_Line ("Enter author: ");
Title : constant String := Get_Line ("Enter title: ");
Pages : constant Page_Count := Get_Line ("Enter number of pages: ");
begin
Ada.Text_IO.Put_Line ("Author: " & Author);
Ada.Text_IO.Put_Line ("Title: " & Title);
Ada.Text_IO.Put_Line ("Number of pages:" & Page_Count'Image (Pages));
end Text_Input;
Notice that I've made the Get_Line function for Page_Count check that you don't have any trailing garbage on the line, where you enter the number of pages.
I hope you don't disagree with my estimate that John will never write a single book of more than 10'000 pages. :-)

raised CONSTRAINT_ERROR : josephus.adb:50 index check failed

I'm trying to run this code, but something is going wrong with the line:
Soldiers (Number_Of_Soldiers) := Soldier_Type'(Name=>new String'(Line(1..Length)), Alive=>True);
Can someone help me, please?
Thank you so much!
--Josephus Problem
with Ada.Text_IO,Ada.Integer_Text_IO;
use Ada;
procedure Josephus is
type String_Pointer is access String;
type Soldier_Type is record
Name : String_Pointer;
Alive : Boolean;
end record;
Max_Number_Of_Soldiers: constant := 10;
Number_Of_Soldiers : Integer range 0..Max_Number_Of_Soldiers := 0;
-- start with 0 to facilitate modular arithmetic
Soldiers: array (0..Max_Number_Of_Soldiers-1) of Soldier_Type;
procedure Next (Index: in out Integer; Interval: Positive) is
begin
for I in 1..Interval loop
loop
Index := (Index + 1) mod Number_Of_Soldiers;
exit when Soldiers(Index).Alive;
end loop;
end loop;
end Next;
Interval : Integer;
Man : Integer := Soldiers'First;
begin
-- get interval from the standard input
Integer_Text_IO.Get (Interval);
Text_IO.Skip_Line;
Text_IO.Put ("Skip every ");
Integer_Text_IO.Put (Interval, Width=>1);
Text_IO.Put_Line (" soldiers.");
-- get names (one per line) from the standard input
declare
Line: String (1..10);
Length: Integer;
begin
while not (Text_IO.End_Of_File) loop
Text_IO.Get_Line (Line, Length);
Soldiers (Number_Of_Soldiers) := Soldier_Type'(Name=>new String'(Line(1..Length)), Alive=>True);
Number_Of_Soldiers := Number_Of_Soldiers + 1;
end loop;
end;
for I in 1..Number_Of_Soldiers-1 loop
Soldiers(Man).Alive := False;
Text_IO.Put (Soldiers(Man).Name.all);
Text_IO.Put_Line (" commits suicide.");
Next (Man, Interval);
end loop;
Text_IO.Put (Soldiers(Man).Name.all);
Text_IO.Put_Line (" is the last.");
end Josephus;
I think your problem is with the line
Max_Number_Of_Soldiers: constant := 10;
Obviously the number specified needs to be more than the maximum possible number of entries in your input!
The problem of unbounded input data sets is one reason to look at using Ada.Containers.Vectors instead of arrays.

Ada 95 Check if enter was pressed

I am new to Ada.
How can I check if enter was pressed?
The while loop should be able to check whether the input character is a white space or an enter key.
Furthermore, how can I check the user input type, like the type() or typeof() function in other languages?
FUNCTION ReadValue RETURN Unbounded_String IS
ValueChar : Character;
Result : Unbounded_String := To_Unbounded_String("NULL");
BEGIN
Get(ValueChar);
Skip_Line;
WHILE ValueChar /= ';'LOOP
Get(ValueChar);
IF IsValidNameInput(ValueChar) THEN
Result := Result & ValueChar;
ELSE
exit;
END IF;
END LOOP;
ValueIntegerFlag := CheckValue(Value);
RETURN Result;
END ReadValue;
Read the characters one-at-a-time without special ENTER handling using Get_Immediate instead of Get - ARM A.10.7(9).
You can do checks on the class of the character you’ve just read using Ada.Characters.Handling - ARM A.3.2 - something like
function Is_Valid_Name_Input (Ch : Character) return Boolean is
begin
return Ada.Characters.Handling.Is_Graphic (Ch)
and then not Ada.Characters.Handling.Is_Space (Ch);
end Is_Valid_Name_Input;
(probably not quite what you want, since it makes &*^$$^ a valid name!)
Ada.Characters.Handling.Is_Line_Terminator detects ENTER (on Unix; probably on Windows too).
You can check whether a string corresponds to an integer by trying the conversion and catching the exception when it fails:
function Check_Integer_Value (Str : Unbounded_String) return Boolean is
Dummy : Integer;
begin
Dummy := Integer'Value (To_String (Str));
return True;
exception
when Constraint_Error =>
return False;
end Check_Integer_Value;
With regard to ReadValue:
Don’t initialize Result - it starts off as the empty string (and you really don’t want to start with the string ”NULL”).
It skips the first character input.
What’s that Skip_Line for?
Try something like
function Read_Value return Unbounded_String is
Value_Char : Character;
Result : Unbounded_String;
begin
loop
Get_Immediate (Value_Char);
exit when Value_Char = ';';
if Is_Valid_Name_Input (Value_Char) then
Result := Result & Value_Char;
end if;
end loop;
return Result;
end Read_Value;

Resources