Ada get Character input and check if it is a valid input - character

with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Characters.Handling;
with Ada.Exceptions; use Ada.Exceptions;
USE Ada, Ada.Text_Io;
WITH connectfour;
PROCEDURE Main IS
PACKAGE board is new connectfour;
USE board;
col : Character;
function checkInput (input : Character) RETURN BOOLEAN is
ins : Character := input;
begin
ins := Ada.Characters.Handling.To_Lower(ins);
if ins = 'a' or ins = 'b' or ins = 'c' or ins = 'd' or
ins = 'e' or ins = 'f' or ins = 'g' or ins = 'h' then
return true;
end if;
return false;
end checkInput;
begin
board.initialize;
board.print;
while (not board.isFull) loop
loop
PUT("Player"&Integer'Image(board.turn)&": ");
Ada.Text_IO.Get(col);
exit when checkInput(col);
end loop;
exit when col = '0';
Text_IO.New_Line;
Text_IO.Put ("");
board.play(col);
end loop;
end Main;
So when I run my program I get:
Player 1: a --> (I entered the character 'a' and clicked enter)
Then I keep getting this error right after, at the line "Ada.Text_IO.Get(col);"
raised ADA.IO_EXCEPTIONS.DATA_ERROR : a-tiinio.adb:86 instantiated at a-inteio.ads:18
What I want to do, is get a single character input from the user and check if it is within the range A .. H, if yes, then exit the loop, otherwise keep asking...
I cannot find out what my issue is...
I allow the user to enter lowercase or uppercase characters, and I convert uppercase to lowercase and perform a check.
Please help...
I am not sure how to read in a single Character....

Okay the exception message could be clearer (and there are ways to get stack traces when one happens but let's work with what we've got...)
locate a-tiinio.adb
/usr/lib/gcc/x86_64-linux-gnu/4.9/rts-native/adainclude/a-tiinio.adb
which is
package body Ada.Text_IO.Integer_IO
and line 86 is an exception raised in
procedure Get
(Item : out Num;
Width : Field := 0)
Details don't matter (yet) but I cannot see any calls to Ada.Text_IO.Integer_IO.Get.
So my suspicion is that the code shown is working
(as well as can be expected : NOTE HOWEVER there is no way to get to exit when col = '0'; with col outside a .. h) and there is another call to Get (this time Integer_IO.Get) buried in board.play. It would be easy to test this by printing col= before calling board.play.
Minor style comment:
function checkInput (input : Character) RETURN BOOLEAN is
ins : Character := input;
begin
ins := Ada.Characters.Handling.To_Lower(ins);
can be simplified
function checkInput (input : Character) RETURN BOOLEAN is
ins : Character := Ada.Characters.Handling.To_Lower(input);
begin

Related

How to make Boolean write True or False in Ada

I'm very new to programming and have just gotten started with Records and boolean in Ada.
I'm trying to make it so that whenever I write 'T' it will say "True" and whenever I write 'F' it will say False, but I´m not sure how to do that. In this assignment I'm not allowed to change T: Boolean:= False; this has to be in the code, but I´m not sure what I have to do to get what I want. I guess I have to do some sort of if statement like
But i´m not sure how to do that.
My code looks like the following:
type Sub_J is
record
Y: Character:= '9';
Q: Character:= 'p';
end record;
type Sub_B is
record
Y: Character:= 'J';
Q: Character:= 'o';
end record;
type Sub_O is
record
T: Boolean:= False;
L: Character:= '5';
end record;
type DS3 is
record
J: Sub_J;
B: Sub_B;
O: Sub_O;
end record;
procedure Get_3(DSThree: out DS3) is
Space: Character;
begin
Put("Mata in datamängd: ");
Get(DSThree.J.Y);
Get(Space);
Get(DSThree.J.Q);
Get(Space);
Get(DSThree.B.Y);
Get(Space);
Get(DSThree.B.Q);
Get(Space);
Get(DSThree.O.T);
Get(Space);
Get(DSThree.O.L);
end Get_3;
procedure Put_3(DSThree: in DS3) is
begin
Put("Inmatad datamängd: ");
Put(DSThree.J.Y);
Put(" ");
Put(DSThree.J.Q);
Put(" ");
Put(DSThree.B.Y);
Put(" ");
Put(DSThree.B.Q);
Put(" ");
Put(DSThree.O.T);
Put(" ");
Put(DSThree.O.L);
end Put_3;
I assume that you’re using Ada.Text_IO.Put (or Put_Line): what you have to do is to print the image of the variable.
In the case of a Character or String, the image is the thing itself. In the case of other simple types, you can apply the attribute Image:
Ada.Text_IO.Put (T’Image);
This will result in TRUE or FALSE.
Your question is unfortunately not very clear. You show a program, but the program is incomplete and not compilable, and you do not say explicitly which part of the program your question concerns -- is it about an input operation (Get), an output operation (Put), or something else?
You say your goal is "whenever I write 'T' it will say "True"", and likewise F for False. But do you mean that you write 'T' into the program's source code, or in response to an input operation (Get) when you run the program? And is it an output operation that you want to "say "True""? Or do you want to make 'T' and 'F' be abbreviations for True and False in the Ada source code?
If you want to be able to enter 'T' in response to a Get operation for a Boolean variable, for example B : Boolean, and have 'T' mean True, one way is to Get a Character value, for example Get(C) where C is a Character variable, and then make a case selection:
case C is
when 'T' => B := True;
when 'F' => B := False;
when others =>
-- Erroneous input.
-- Perhaps tell the user and ask for new input.
...
end case;
Note, however, that Get for a Character really does give the next character, and does not skip blank characters in the way Get for other types does. However it does skip line terminators (and page terminators).
Giving you a good answer would be much easier if you could show a compilable program and explain what you want it do.
I figured it out
procedure Get_3(DSThree: out DS3) is
Space: Character;
True_Or_False: Character;
begin
Put("Mata in datamängd: ");
Get(DSThree.J.Y);
Get(Space);
Get(DSThree.J.Q);
Get(Space);
Get(DSThree.B.Y);
Get(Space);
Get(DSThree.B.Q);
Get(Space);
Get(True_Or_False);
if True_Or_False = 'T' then
DSThree.O.T:= True;
elsif True_Or_False = 'F' then
DSThree.O.T:= False;
end if;
Get(Space);
Get(DSThree.O.L);
end Get_3;
procedure Put_3(DSThree: in DS3) is
begin
Put("Inmatad datamängd: ");
Put(DSThree.J.Y);
Put(" ");
Put(DSThree.J.Q);
Put(" ");
Put(DSThree.B.Y);
Put(" ");
Put(DSThree.B.Q);
Put(" ");
if DSThree.O.T = True then
Put("True");
elsif DSThree.O.T = False then
Put("False");
end if;
Put(" ");
Put(DSThree.O.L);
end Put_3;

Ada - Commando- line reader and processer

A program that loads and processes command-line arguments should be created.
Here comes a few examples on how it should look when you run it (bold text is the text that the user will type):
Terminal prompt % **./my_program**
No arguments given.
Terminal prompt % **./my_program 123**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 10 XYZ 999 Greetings!**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 3 HELLO**
Message: HELLOHELLOHELLO
The program "./my program" is ending.
Terminal prompt % **./my_program 0 Bye**
Message:
The program "./my program" is ending.
This is my code so far:
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
type String is array (Positive) of Character;
N : Integer;
Text : String;
begin
N := Argument_Count;
if N = 0 then
Put_Line("No arguments given.");
elsif N /= 2 then
Put_Line("Wrong number of arguments given.");
elsif N = 2 then
Put("Message: ");
for I in 1 .. N loop
Put(Text);
New_Line;
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
end my_program;
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says
Missing argument for parameter "Item" in call to "Put"
I don't know if I declared my string right because I don't want a string of a specific length. Can anyone come up with something that could help me solve case 4 and 5? It would be nice and highly appreciated
This seems to be a homework or exam question, so I would usually not provide a full answer. But Chris already gave that (with some defects), so here is my suggestion. Compared to Chris's solution, I try to avoid using unnecessary variables, and I favour case statements over if-then-else cascades, and I try to reduce the scope of exception handlers. I prefer to put use clauses in the subprogram so that the context-clause section contains only with clauses. I use the string-multiplying "*" operator from Ada.Strings.Fixed, but that is perhaps an unnecessary refinement.
with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure My_Program
is
use Ada.Strings.Fixed;
use Ada.Text_IO;
begin
case Ada.Command_Line.Argument_Count is
when 0 =>
Put_Line ("No arguments given.");
when 2 =>
begin
Put_Line (
Natural'Value (Ada.Command_Line.Argument(1))
* Ada.Command_Line.Argument(2));
exception
when Constraint_Error =>
Put_Line ("Invalid input for argument 1.");
end;
when others =>
Put_Line ("Wrong amount of arguments given.");
end case;
Put_Line (
"The program """
& Ada.Command_Line.Command_Name
& """ is ending.");
end My_Program;
Note that my version:
Rejects negative first arguments (like "-3").
Outputs the repeated strings on a single line, as was required by the examples given.
Includes the name of the program in the final message, as was also required.
Given the clarification in comments as to the purpose of the program, to print a message n times where n is the first argument, and the message is the second argument, you need to parse the first argument as an integer. This can be done with Integer'Value.
Now, that raises the prospect of the user not running the program with an integer. So we have to handle the possible Constraint_Error exception.
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
argc : Integer;
N : Integer;
begin
argc := Argument_Count;
if argc = 0 then
Put_Line("No arguments given.");
elsif argc /= 2 then
Put_Line("Wrong number of arguments given.");
else
n := Integer'Value(Argument(1));
Put("Message: ");
for I in 1 .. N loop
Put_Line(Argument(2));
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
exception
when Constraint_Error =>
Put_Line("Invalid input for argument 1.");
end my_program;
As an aside, when we've checked in our conditional if argc is zero, and that it doesn't equal two, we don't have to use elsif. The only other possibility is that it is 2.
You say
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says "Missing argument for parameter "Item" in call to "Put". "
which doesn't make sense, because your program as shown doesn't compile. I guess what you mean is "when I try to add the code to handle cases 4 and 5, it doesn't compile".
The reason why it doesn’t compile is hidden in the actual error messages:
leun.adb:24:10: no candidate interpretations match the actuals:
leun.adb:24:10: missing argument for parameter "Item" in call to "put" declared at a-tiinio.ads:97, instance at a-inteio.ads:18
...
leun.adb:24:14: expected type "Standard.Integer"
leun.adb:24:14: found type "String" defined at line 7
leun.adb:24:14: ==> in call to "Put" at a-tiinio.ads:80, instance at a-inteio.
You have at line 7
type String is array (Positive) of Character;
which is both misleading and not what you meant.
It’s ’not what you meant’ because array (Positive) means an array of fixed length from 1 to Positive’Last, which will not fit into your computer’s memory. What you meant is array (Positive range <>).
Even with this correction, it's 'misleading' because although it would be textually the same as the declaration of the standard String in ARM 3.6.3(4), in Ada two different type declarations declare two different types. So, when you write Put(Text); the Put that you meant to call (the second in ARM A.10.7(16)) doesn’t match because it’s expecting a parameter of type Standard.String but Text is of type my_program.String.
Cure for this problem: don’t declare your own String type.

Why is implicit conversion between anonymous access objects disallowed in Ada?

I am working my way through Barnes' book 'Programming in Ada 2012'. This is a code sample implementing a stack from section 12.5.
src/stacks.adb: (the main relevant file)
package body Stacks is
procedure Push(S: in out Stack; X: in Integer) is
begin
S := new Cell'(S,X);
end Push;
procedure Pop(S: in out Stack; X: in out Integer) is
begin
X := S.Value;
S := Stack(S.Next);
end Pop;
function "="(S, T: Stack) return Boolean is
SS: access Cell := S;
TT: access Cell := T;
begin
while SS /= null and TT /= null loop
if SS.Value /= TT.Value then
return false;
end if;
SS := SS.Next;
TT := TT.Next;
end loop;
return SS = TT; -- error: implicit conversion of stand-alone anonymous access object not allowed
end "=";
end Stacks;
I have added a comment containing the error that gnat gives me. Why am I not allowed to convert from one anonymous access Cell to another?
I can solve the problem by inverting the condition:
return not (SS /= TT);
It mystifies me as John Barnes states earlier that if you define a "=" operator returning a boolean, then the inverse "/=" is generated automatically for you, meaning the opposite.
Similarly, the loop condition can be inverted, in which case it fails to compile with the same message.
Finally, a side-note: the expected behaviour of the program, which it gives after changing to return not (SS /= TT) is to recurse infinitely and raise a storage_error due to stack overflow. The reason for that is better seen in this other SO question, and is not the subject of this question.
Why is the conversion disallowed by the compiler when I write "="?
Why is it different when I write "/=", which I thought would always be the inverse?
The other files needed in order to compile the example for yourself:
src/stacks.ads:
package Stacks is
type Stack is limited private;
procedure Push(S: in out Stack; X: in Integer);
procedure Pop(S: in out Stack; X: in out Integer);
function "="(S, T: Stack) return Boolean;
private
type Cell is
record
Next: access Cell;
Value: Integer;
end record;
type Stack is access all Cell;
end;
src/main.adb:
with Ada.Text_IO; use Ada.Text_IO;
with Stacks; use Stacks;
procedure Main is
A : Stack;
B : Stack;
begin
Push(A, 1);
Push(B, 1);
Push(A, 2);
Push(B, 2);
Push(A, 1);
Push(B, 1);
Push(A, 8);
Push(B, 8);
declare
Same : Boolean := A = B;
Text : String := (if Same then "They are the same" else "They are not the same");
begin
Put_Line(Text);
end;
end Main;
stacks.gpr:
project stacks is
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Main use ("main.adb");
end stacks;
Makefile:
all:
gprbuild -d -p -g
clean:
rm -rf obj *.o *.ali
Or compile with gcc:
gcc -c src/*.adb
gnatbind main
gnatlink main
It gives the same results.

ERROR at line 8: PL/SQL: Statement ignored

ERROR at line 8: PL/SQL: Statement ignored
CREATE OR REPLACE PROCEDURE POS(A IN NUMBER,M IN NUMBER,TOTAL OUT NUMBER)
AS
BEGIN
TOTAL:=0;
WHILE A>0 LOOP
M:=MOD(A,10);
TOTAL:=TOTAL+M;
A:=(A/10);//statement ignored error
END LOOP;
DBMS_OUTPUT.PUT_LINE(TOTAL);
END;
DECLARE
X NUMBER;
Y NUMBER:=5;
Z NUMBER;
BEGIN
POA(X,Y,Z);
END;
OK, I've had a look at your procedure and tried to resolve the issues you are having with it.
You haven't explained much (or indeed anything) about what you are trying to achieve which makes it really difficult to get you an answer.
People on here really want to help but you have to at least give us the tools with witch to provide that help.
Anyhow, with a host of assumptions, here is my version of your procedure with the following assumptions:
Your procedure is names POS (you name it POS in the procedure definition but then try to execute it as POA).
Your main issue was trying to assign a new value to input parameter "a" within the loop. As it is an input parameter it is immutable and you cannot assign new values to it. I have got round this by declaring a local variable "v_iter" and assigning that the value of "a" and then using it to control the loop.
I have added an "exception" section to handle any unexpected errors and output that error via DBMS_OUTPUT. You might want to make this more robust.
You do not test to check if the input parameter "a" is null or a valid number (i.e. not negative), you might want to do this to make your procedure more robust.
Here is the changed code:
CREATE OR REPLACE
PROCEDURE POS (
a IN NUMBER,
m IN NUMBER,
total OUT NUMBER
)
AS
— Declare variables
v_iter NUMBER := a;
BEGIN
— Initialise total
total := 0;
— Loop through “v_iter”
WHILE v_iter > 0
LOOP
m := MOD(v_iter,10);
total := total + m;
v_iter := (v_iter/10);
END LOOP;
DBMS_OUTPUT.put_line(total);
EXCEPTION
WHEN others
THEN
— Output and raise an error;
DBMS_OUTPUT.put_line(sqlerrm);
RAISE;
END POS;
/
To call it:
DECLARE
X NUMBER;
Y NUMBER:=5;
Z NUMBER;
BEGIN
POS(X,Y,Z);
END;
/
Hope it helps.

Finding the error in this code

I keep receiving error,';' unexpected in this piece of maple code. I have looked and looked and just can't seem to find where I'm going wrong. Can anyone spot it?
QSFactorization := proc (n::(And(posint, odd)), mult::nonnegint := 0, { mindeps::posint := 5, c := 1.5 })
local mfb, m, x, fb, nfb, r, M, d;
if isprime(n) then
return "(n)"
elif issqr(n) then
return "(isqrt(n))"*"(isqrt(n))"
elif n < 1000000 then
return ifactor(n)
end if;
if mult = 0 then
mfb := MultSelect(n, ':-c' = c)
else mfb := [mult, FactorBase(mult*n, c)]
end if;
m := mfb[1];
if 1 < m then
print('Using*multiplier; -1');
print(m)
end if;
x := m*n*print('Using*smoothness*bound; -1');
print(ceil(evalf(c*sqrt(exp(sqrt(ln(n)*ln(ln(n))))))));
fb := Array(mfb[2], datatype = integer[4]);
nfb := ArrayNumElems(fb);
print('Size*of*factor*base; -1');
print(nfb);
r := Relations(x, fb, ':-mindeps' = mindeps);
M := r[3]; print('Smooth*values*found; -1');
print(nfb+mindeps);
print('Solving*a*matrix*of*size; -1');
print(LinearAlgebra:-Dimension(M));
d := Dependencies(M);
print('Number*of*linear*dependencies*found; -1');
print(nops(d));
print('Factors; -1');
FindFactors(n, r, d)
end proc
I'd really appreciate any insight.
You basic problem is that you are using the wrong quotes inside your print statements. This is invalid,
print('Using*multiplier; -1');
You are using single right-quotes (tick), which in Maple is used for unevaluation. In this case the semicolons inside your print statements are syntax errors.
Use either double-quotes or single left-quotes instead. The former delimits a string, and the latter delimits a name. Eg,
print("Using*multiplier; -1");
print(`Using*multiplier; -1`);
If you choose to go with name-quotes then the print command will prettyprint the output in the Maple GUI with the name in an italic font by default, but you won't see the quotes in the output.
If you choose to go with string-quotes then the print command will show the quotes in the output, but will use an upright roman font by default.
Some other comments/answers (since deleted) on your post suggest that you are missing statement terminators (colon or semicolon) for these two statements,
print(m)
FindFactors(n, r, d)
That is not true. Those statements appear right before end if and end proc respectively, and as such statement terminators are optional for them. Personally I dislike coding Maple with such optional terminator instances left out, as it can lead to confusion when you add intermediate lines or pass the code to someone else, etc.