stucking logical operator in WHILE statement - loops

as you can see my picture above, i have problem with logical operators, so i need a looping program for searching data, my parameter can be filled with game_code or game_title, but there are some problem in the looping sequence.
so how to solve this problem, i tried this but not work
begin
write(#32'Enter Game Title or Code: '); readln(param);
i:=1;
while((data[i].game_title<>param) or (data[i].game_code<>param)) and (i<totaldata) do
i:=i+1;
if (data[i].game_title=param) or (data[i].game_code=param) then

You seem to be missing a parenthesis. try this and let me know:
while(((data[i].game_title=param) or (data[i].game_code=param)) and (i<totaldata)) do
begin
i:=i+1;
end;

You should go with and:
while (i < totaldata) and (data[i].game_title <> param) and (data[i].game_code <> param) do
i:=i+1;
The or expression (data[i].game_title <> param) or (data[i].game_code <> param) will always be true until game_title = game_data = param.
Note that i < totaldata check must be done first to avoid access to memory out of array bounds.

Related

Ada - try to call entry of element of array of protected type, if busy - try next element

I'm working on a multithreading project and i have one array of tasks, let's call it A and one array of protected, let's call it B.
Now every element of A at some point will want to access entry from one of the elements of B. Is there a way to iterate quickly through B's and find accesible one?
I was browsing some resources avalaible online and found only
select
call entry;
or
delay;
which won't do the job.
Is there a way to do that that i'm not aware of?
Thanks in advance!
EDIT
So i got really excited about that select else statements and tried it out, unfortunately it still doesnt work, if I try it this way - using Mr. Simon Wright's code sample to simulate effect i need, the
else
part of code never gets executed, they (the taskArray elements) all think they can acces Call_Me and get stuck in the queue.
How can i solve this issue? I also tried using 'Count thing, but it somehow always ended up being 0.
with Ada.Text_IO; use Ada.Text_IO;
procedure Array_Of_POs is
protected type PO is
entry Call_Me;
private
Callable : Boolean := True; --changed
end PO;
protected body PO is
entry Call_Me when Callable is
begin
Callable := False; --added
Put_Line("Doin stuff");
delay 1.0;
Callable := True;
end Call_Me;
end PO;
POs : array (1 .. 3) of PO;
Success : Boolean := False;
task type Test; --added
task body Test is
begin
for J in POs'Range loop -- '
select
POs (J).Call_Me;
Success := True;
else
Put_Line("I never get displayed!"); --added
end select;
end loop;
Put_Line ((if Success
then "succeeded, oh dear"
else "didn't succeed, good"));
end Test;
testArray : array (1..3) of Test;
end Array_Of_POs;
You could try finding an entry E whose Count attribute (E’Count, ARM 9.9(5)) is zero; but this is going to result in race conditions, since another task could sneak in between your checking the count and your making the call. And see the note at (7), ibid.
You need a conditional entry call, as in ARM 9.7.3.
It would look something like
with Ada.Text_IO; use Ada.Text_IO;
procedure Array_Of_POs is
protected type PO is
entry Call_Me;
private
Callable : Boolean := False;
end PO;
protected body PO is
entry Call_Me when Callable is
begin
null;
end Call_Me;
end PO;
POs : array (1 .. 3) of PO;
Success : Boolean := False;
begin
for J in POs'Range loop -- '
select
POs (J).Call_Me;
Success := True;
else
null;
end select;
end loop;
Put_Line ((if Success
then "succeeded, oh dear"
else "didn't succeed, good"));
end Array_Of_POs;
In your case, I suspect this construct would be in an outer loop, so you’d need to do something to avoid busy-waiting (on the lines of putting in a delay if not Success, perhaps).
EDIT
This is a response to your edited question.
ARM 9.5.1(8) states that your PO.Call_Me contains a bounded error. In the next paragraph,
If the bounded error is detected, Program_Error is raised. If not detected, the bounded error might result in deadlock or a (nested) protected action on the same target object.
At least GNAT hasn’t done either of those.
The issue is that the body of the entry is executed in the context (thread) of the caller. So what happens is
Test calls POs(1).Call_Me
The call is accepted
Callable is set False
Put_Line and delay are called (still in the context of Test)
Callable is set True
POs(1).Call_Me returns to Test
...
The approach you’ve adopted might work if instead of using an array of POs you used an array of tasks.

IF ELSE syntax error

My IF..ELSE block fails at BEGIN. I can understand how my expression is not boolean in nature, but what is causing this failure?
IF (SUBSTRING(#PARIDIN,1,1) = 'P'
BEGIN
SET #PARIDTEMP = SUBSTRING(LTRIM(RTRIM(#PARIDIN)),2,6))
END
BEGIN
ELSE SET #PARIDTEMP = #PARIDIN
END
You have an extra set of parentheses in a weird place.:
IF SUBSTRING(#PARIDIN,1,1) = 'P' -- one at the beginning of this line.
BEGIN
SET #PARIDTEMP = SUBSTRING(LTRIM(RTRIM(#PARIDIN)),2,6) -- one at the end of this line.
END
ELSE
BEGIN
SET #PARIDTEMP = #PARIDIN
END
You are not closing the expression being evaluated.
Change
IF (SUBSTRING(#PARIDIN,1,1) = 'P'
To
IF (SUBSTRING(#PARIDIN,1,1) = 'P')
Taking everybody else's suggestion of fixing the condition I am surprised nobody mentioned the very strange BEGIN END blocks. They don't make sense and not sure they would even work. Since you have only a single statement for each it makes more sense to remove them.
IF (SUBSTRING(#PARIDIN,1,1) = 'P')
SET #PARIDTEMP = SUBSTRING(LTRIM(RTRIM(#PARIDIN)),2,6))
ELSE
SET #PARIDTEMP = #PARIDIN

pascal illegal qualifier error when calling function from a procedure

function classes(o:integer): String;
var allclasses : array[1..7] of String;
begin
allclasses[1]:= 'class1';
allclasses[2]:= 'class2';
allclasses[3]:= 'class3';
allclasses[4]:= 'class4';
allclasses[5]:= 'class5';
allclasses[6]:= 'class6';
allclasses[7]:= 'class7';
classes := allclasses[o];
end;
Above you can see a function, which should receive an integer and give a result of string that was stored in array.
procedure loadthis(chosen : string);
var f: text;
i : integer;
begin
Assign(f, 'files\'+chosen+'.txt');
Reset(f);
ReadLn(f, i);
MyChar.clas := classes[i];
end;
When this procedure is called, it calls a "classes" function. Pleae note that Mychar ir a global variable.
begin
loadthis(FileName);
ReadLn;
Readln
end.
Ant this is the main program, which calls "loadthis" procedure.
I Have no idea whats wrong, but I am getting these errors:
Wrong amount of parameters specified
Illegal qualifier
Both errors come from this line:
MyChar.clas := classes[i];. I have really no idea what is wrong, maybe I can not call a function from a procedure ? Please help.
You're trying to access it as an array index, but it needs to be a function call:
MyChar.clas := classes(i); { note () instead of [] }
You should probably add some range checking, too. What happens if someone puts 20 in the text file? Your array only has items at indexes 1 through 7, so you'll get a runtime error when you call classes(20) with the out of range value.
(You could probably use a constant array for allclasses to lessen your code as well, but your instructor probably haven't gotten that far yet.)
Given your comment about not having an instructor, here's a suggestion about a better way to handle the function:
function classes(o:integer): String;
const
allclasses: array[1..7] of string = ('class1',
'class2',
'class3',
'class4',
'class5',
'class6',
'class7');
begin
{
Low() returns the lowest index of the array, and
High() returns the highest. The if statement makes sure
that o is between them. It is the range check I mentioned.
}
if (o >= Low(allclasses)) and (o <= High(allclasses)) then
classes := allclasses[o]
else
classes := '';
end;

To have conditional ANDing inside WHERE clause

Can we add null check over one of the parameter of procedure inside WHERE clause and avoid block of code getting repeated like
select aa=t1.aa,bb=t2.bb ,cc=t3.cc
from t1,t2,t3,t4,t5
where t1.p1=t2.p1
and t2.p2=t3.p2
IF(procParameter IS NOT NULL)
and t3.p2=procParameter
and t4.p2=t5.p2
and t5.p3=t1.p2
Look I want one of the AND to get executed conditionally and otherwise it should NOT GET EXECUTED AT ALL..!!!!
How should I go for this optimisation??
I dont want code repeatation like
IF(procParameter IS NOT NULL)
begin
select aa=t1.aa,bb=t2.bb ,cc=t3.cc
from t1,t2,t3,t4,t5
where t1.p1=t2.p1
and t2.p2=t3.p2
and t3.p2=procParameter
and t4.p2=t5.p2
and t5.p3=t1.p2
end
Else
begin
select aa=t1.aa,bb=t2.bb ,cc=t3.cc
from t1,t2,t3,t4,t5
where t1.p1=t2.p1
and t2.p2=t3.p2
and t4.p2=t5.p2
and t5.p3=t1.p2
end
Thanks,
This is one approach:
AND (procParameter IS NULL OR t3.p2=procParameter)

Problems with writing to a MS Access Database (Delphi)

I'm trying to write bits of code to a Microsoft access database from Delphi. I'm getting data from a TStringGrid. The first column has the ItemID, and the 2nd column has the Quantity. I'd like it to loop through the TStringGrid and save each row as a reperate row in my database and also save the Order ID with it on every column (The order ID stays the same for each order so that doesn't need to change) .
I'm getting an error when running which says
"Project Heatmat.exe raised an exception class EVarientInvalidArgError with message 'Invalid Argument'. Process Stopped."
I can't figure out why it's giving me this error, and as you can probably see i'm not very good at coding yet. Any help would be appreciated!
Thank you.
procedure TCreateNewOrder.btnSaveClick(Sender: TObject);
var
intNumber, count : integer;
begin
Count:= 0;
if messagedlg ('Are you sure?', mtWarning, [mbyes, mbno], 0) = mryes then
begin
with HeatmatConnection.HeatmatDatabase do
begin
intNumber:= TBLOrder.RecordCount;
TBLOrder.Append;
TBLOrder['CustomerID']:= CompanyName.ItemIndex+1;
TBLOrder['OrderID']:= intNumber +1;
for count:= 1 to StringGrid1.RowCount-1 do
begin
TBLOrderedItem.Append;
TBLOrderedItem['OrderID']:= intNumber+1;
TBLOrderedItem['ItemID']:= StringGrid1.Cells[1, count];
TBLOrderedItem['Quantity']:= StringGrid1.Cells[2, count];
TBLOrderedItem.Post;
end;
end;
end;
end;
TStringGrid cells are strings. trying to assign a string directly to a numeric field will raise an Exception.
So a good practice is to assign values to database fields via AsString, AsInteger, AsBoolean etc... this will make the correct conversion.
In your code use:
TBLOrderedItem.FieldByName('ItemID').AsString := StringGrid1.Cells[1, count];
The same is true for Quantity.
To assign an Integer value use:
TBLOrderedItem.FieldByName('OrderID').AsInteger := intNumber + 1;
BTW, you are forgetting TBLOrder.Post i.e:
....
TBLOrder.Append;
TBLOrder.FieldByName('CustomerID').AsInteger := CompanyName.ItemIndex + 1;
TBLOrder.FieldByName('OrderID').AsInteger := intNumber + 1;
TBLOrder.Post;
...
Finally, I would also suggest to rename TBLOrder to tblOrder so that it's name wont imply that it is a Type.

Resources