Pascal. Unidirectional list. Loop - pascal

Here is an example program from a book. I can't stop the "while not eof" loop. I tried to insert in program "Uses crt;", "const CheckEof: boolean=true" and to press "ctrl+Z" while running, it doesn't work.
Program P123;
uses
crt; {My insertion}
type
Adresacelula = ^Celula;
Celula = record
Info: string;
Urm: AdresaCelula;
end;
var
P, Q, R: AdresaCelula;
s: string;
i: integer;
const
CheckEOF: boolean = true; {My insertion}
Procedure Create;
begin
p := nil;
write ('s='); readln (s);
new (r); r^.Info := s; r^.Urm := nil;
p := r; q := r;
write ('s=');
while not eof do {Here is the loop i need to stop}
begin
readln (s); write ('s=');
new (r); r^.Info := s; r^.Urm := nil;
q^.Urm := r; q := r;
end;
end;
Procedure Display;
begin
r := p;
while r<>nil do
begin
writeln (r^.Info);
r := r^.Urm;
end;
readln;
end;
begin
Create;
Display;
end.

To make the example work, remove the line
const CheckEOF: boolean=true; {My insertion}
and insert CheckEOF:=true; before the Create; call in the main program. Then the program terminates when you press Ctrl-Z.
Your code declares a new variable CheckEOF while you probably want to change CheckEOF of the crt unit.

Related

AVL-tree in Pascal: rotation results in Error 202--stack overflow; why?

The following code for implementing AVL-tree insertion & deletion gives error #202 (stack overflow).
Source code looks like this:
program Avl_generator; uses Crt;
type p_Avl = ^Avl_node;
Avl_node = record
key: integer;
l, r, par: p_Avl; {pointers to left child, right child, parent}
bal, h: integer {balance factor, height}
end;
procedure init(var root: p_Avl); begin new(root); root:=nil end;
function get_height(var n: p_Avl): integer;
begin
if(n=nil) then get_height:=-1 else get_height:=n^.h;
end;
procedure reheight(var n: p_Avl); {refresh the height variable}
begin
if(n<>nil) then
begin
if(get_height(n^.r)>get_height(n^.l)) then n^.h:=1+get_height(n^.r)
else n^.h:=1+get_height(n^.l);
end;
end;
procedure set_balance(var n: p_Avl); begin reheight(n); n^.bal:=get_height(n^.r)-get_height(n^.l); end; {refresh the balance factor}
function rotate_l(var a: p_Avl): p_Avl; {left rotation, a is pivot}
var b: p_Avl;
begin
b := a^.r;
b^.par := a^.par;
a^.r := b^.l;
if(a^.r<>nil) then a^.r^.par := a;
b^.l := a;
a^.par := b;
if(b^.par<>nil) then
if(b^.par^.r=a) then b^.par^.r := b
else b^.par^.l := b;
set_balance(a); set_balance(b);
rotate_l := b;
end;
function rotate_r(var a: p_Avl): p_Avl; {right rotation, a is pivot}
var b: p_Avl;
begin
b := a^.l;
b^.par := a^.par;
a^.l := b^.r;
if(a^.l<>nil) then a^.l^.par := a;
b^.r := a;
a^.par := b;
if(b^.par<>nil) then
if(b^.par^.r=a) then b^.par^.r := b
else b^.par^.l := b;
set_balance(a); set_balance(b);
rotate_r := b;
end;
function rotate_l_r(var a: p_Avl): p_Avl; {left & right rotation, a is pivot}
begin
a^.l := rotate_l(a^.l);
rotate_l_r := rotate_r(a);
end;
function rotate_r_l(var a: p_Avl): p_Avl; {right & left rotation, a is pivot}
begin
a^.r := rotate_r(a^.r);
rotate_r_l := rotate_l(a);
end;
procedure rebalance(var root: p_Avl; var n: p_Avl); {refresh balance factors and see if sub-trees need rotating}
begin
set_balance(n);
if(n^.bal=-2) then
begin
if(get_height(n^.l^.l)>=get_height(n^.l^.r)) then n:=rotate_r(n)
else n:=rotate_l_r(n);
end
else if(n^.bal=2) then
begin
if(get_height(n^.r^.r)>=get_height(n^.r^.l)) then n:=rotate_l(n)
else n:=rotate_r_l(n);
end;
if(n^.par<>nil) then rebalance(root, n^.par) else root:=n; {recursion here}
end;
procedure insert(var root: p_Avl; what: integer);
var found: boolean;
pre_tmp, tmp: p_Avl;
begin
found:=false; tmp:=root; pre_tmp:= nil;
while(tmp<>nil) and not found do
if(tmp^.key=what) then found:=true
else if(tmp^.key>what) then begin pre_tmp:=tmp; tmp:=tmp^.l end
else begin pre_tmp:=tmp; tmp:=tmp^.r end;
if not found then
begin
new(tmp); tmp^.key:=what;
tmp^.l:=nil; tmp^.r:=nil; tmp^.par:=pre_tmp; tmp^.h:=0; tmp^.bal:=0;
if(pre_tmp=nil) then root:=tmp
else
begin
if(pre_tmp^.key>what) then pre_tmp^.l:=tmp else pre_tmp^.r:=tmp;
rebalance(root, pre_tmp);
end;
end;
end;
procedure delete(var root: p_Avl; what: integer);
var found: boolean;
tmp, pre_tmp, act, pre_act: p_Avl;
begin
found:=false; tmp:=root; pre_tmp:=nil;
while(tmp<>nil) and not found do
begin
if(tmp^.key=what) then found:=true
else if(tmp^.key>what) then
begin pre_tmp:=tmp; tmp:=tmp^.l end
else
begin pre_tmp:=tmp; tmp:=tmp^.r end;
if found then
if(tmp^.l=nil) then
begin
if(pre_tmp=nil) then root:=tmp^.r
else if(pre_tmp^.key>what) then pre_tmp^.l:=tmp^.r
else pre_tmp^.r:=tmp^.r;
dispose(tmp); rebalance(root,pre_tmp);
end else if(tmp^.r=nil) then
begin
if(pre_tmp=nil) then root:=tmp^.l
else if(pre_tmp^.key>what) then pre_tmp^.l:=tmp^.l
else begin pre_tmp^.r:=tmp^.l end;
dispose(tmp); rebalance(root,pre_tmp);
end else
begin
act:=tmp^.l; pre_act:=nil;
while(act^.r<>nil) do begin pre_act:=act; act:=act^.r end;
tmp^.key:=act^.key;
if(pre_act=nil) then begin tmp^.l:=act^.l; dispose(act); rebalance(root,tmp) end
else begin pre_act^.r:=act^.l; dispose(act); rebalance(root,pre_act) end;
end;
end;
end;
var Avl_tree: p_Avl;
begin
init(Avl_tree);
insert(Avl_tree,1);
insert(Avl_tree,2);
insert(Avl_tree,3);
insert(Avl_tree,4);
insert(Avl_tree,5);
writeln(get_path(Avl_tree, 5));
repeat until KeyPressed;
end.
This compiles fine (Turbo Pascal 7.0). When I run the code, though, the error occurs in the rotate_l procedure which is called after the third insertion (whereupon balance factor of the root node =2.
I checked some Java & C++ implementations and the rotation methods there seemed quite similar to mine, therefore I don't know where the problem is..?
Ok, it's been 14 years since I touched Pascal last time :)
So the problem is indeed with rotate_l function.
You are passing a parameter by-reference as indicated by var keyword.
rotate_l(var a: p_Avl)
That causes a to become nil when you overwrite b.par,
Because a references the address of b.par in that particular function invocation and you set b.par to nil.
So a now is referencing memory location that contains nil.
You need to change function signature to pass a parameter by value. This is done by removing var keyword.
rotate_l(a: p_Avl)
Stack overflow is caused by the same issue in rebalance procedure:
Change
procedure rebalance(var root: p_Avl; var n: p_Avl);
to
procedure rebalance(var root: p_Avl; n: p_Avl);
See Free Pascal language reference for parameters
http://wiki.lazarus.freepascal.org/Parameters

Pascal : fatal syntax error

Trying to execute catalan numbers in Pascal but getting fatal syntax error.
Error is :
Fatal: Syntax error, ";" expected but "identifier B" found
Error: /usr/bin/ppcx64 returned an error exitcode
Here is ref code
program main;
var
i,buf: integer;
function catalan(num: integer): integer;
var
sample, returnval : integer;
function bincoeff(n: integer): integer;
var
a,b,retval,numr,denom1,denom2: integer;
bc : integer;
function fact(x: integer): integer;
begin
// fact exec
if x=0 then
fact :=1
else
fact := x* fact(x-1);
end;
begin
//bincoeff exec
a := 2*n
b := n
if a==b then
retval :=1
else if b>a
retval :=0
else
numr := fact(a)
denom1 := fact(b)
denom2 := fact(a-b)
bc := numr /(denom1*denom2)
retval := bc
end;
begin
// catalan exec
sample :=bincoeff(num)
returnval := (sample/(num+1))
end;
begin
for i :=0 to 9 do
begin
buf := catalan(i)
writeln(buf)
end;
end.
Starting with
a := 2*n
till the end of the program you systematically don't use ';'. A fact that, by the way, is signaled pretty clearly by the compiler.
In this context it might be interesting to visit the FreePascal wiki on the topic of the semicolon which points out an important difference between C and Pascal's usage of the semicolon (separator vs terminator). A must-read.

Validation in Delphi

I'm a student and stuck on Delphi Validation. Here is my code:
begin
valid := true;
for I:=1 to Length(edtvalue.Text) do
if not (edtvalue.Text[I] in ['0'..'9','.'] )then
valid:= false;
if not valid then
begin
showmessage ('This item is not within the range');
DataItem1 := 0;
end
else
dataitem1 := strtofloat(edtvalue.Text);
This code reads in a value that the user inputs and checks whether it actually is an integer and detects when a user inputs letters.
However when the user inputs something else (e.g. + or #) the code doesn't work and breaks the system. Is there a way I can fix this please?
Thanks in advance
Use TryStrToFloat :
var
F: Double;
begin
if not TryStrToFloat(edtvalue.Text, F) then
showmessage ('This item is not within the range');
else
dataitem1 := F;
end;
Or if you want to set DataItem1 to 0 when error :
var
F: Double;
begin
if not TryStrToFloat(edtvalue.Text, F) then
begin
showmessage ('This item is not within the range');
DataItem1 := 0;
end
else
dataitem1 := F;
end;
Also you can create a Function to do that , like :
function IsFloat(Str: string): Boolean;
var
I: Double;
C: Integer;
begin
Val(Str, I, C);
Result := C = 0;
end;
I changed to use TryStrToFloat as recommended by David in the comments, you just need to declare that val variable:
var
val: Extended;
begin
val := 0;
if not TryStrToFloat(edtvalue.Text, val) then
showmessage ('This item is not within the range');
dataitem1 := val;
end;

Inno Setup - How to display notifying message while installing if application is already installed on the machine?

I am new to Inno Setup. I am creating an installer for my C# application using Inno Setup compiler-5.1.6.
Using my script an installer is created, and it works fine. It installs the application and can be uninstalled from control panel as well.
But my problem is that, if my application is already installed on my machine and I try to install it again it get installed without any message. It replaces the older installation.
So my requirement is that , if application is already installed , it should show me a message that "App already installed {existing version}. Do you want to replace existing installation." with 'Yes' and 'No' buttons. If user clicks 'Yes' button installer should proceed normally otherwise it should exit installation wizard without new installation.
AppVersion: it is changeable as version increases.
AppId: it will remain same for all version.
So, please can someone help me to achieve above..
Thanks in advance . .
Plz refer my question how to terminate installer if unstallation of legacy version of software is cancelled before executing it? , You can use same trick of checking registry for your app to check whether it is installed or not.
and to check version of app you can use following code that i got from https://blog.lextudio.com/2007/08/inno-setup-script-sample-for-version-comparison-2/:
[Code]
function GetNumber(var temp: String): Integer;
var
part: String;
pos1: Integer;
begin
if Length(temp) = 0 then
begin
Result := -1;
Exit;
end;
pos1 := Pos('.', temp);
if (pos1 = 0) then
begin
Result := StrToInt(temp);
temp := '';
end
else
begin
part := Copy(temp, 1, pos1 - 1);
temp := Copy(temp, pos1 + 1, Length(temp));
Result := StrToInt(part);
end;
end;
function CompareInner(var temp1, temp2: String): Integer;
var
num1, num2: Integer;
begin
num1 := GetNumber(temp1);
num2 := GetNumber(temp2);
if (num1 = -1) or (num2 = -1) then
begin
Result := 0;
Exit;
end;
if (num1 > num2) then
begin
Result := 1;
end
else if (num1 < num2) then
begin
Result := -1;
end
else
begin
Result := CompareInner(temp1, temp2);
end;
end;
function CompareVersion(str1, str2: String): Integer;
var
temp1, temp2: String;
begin
temp1 := str1;
temp2 := str2;
Result := CompareInner(temp1, temp2);
end;
function InitializeSetup(): Boolean;
var
oldVersion: String;
uninstaller: String;
ErrorCode: Integer;
begin
if RegKeyExists(HKEY_LOCAL_MACHINE,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F768F6BA-F164-4599-BC26-DCCFC2F76855}_is1') then
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F768F6BA-F164-4599-BC26-DCCFC2F76855}_is1','DisplayVersion', oldVersion);
if (CompareVersion(oldVersion, '6.0.0.1004') < 0) then
begin
if MsgBox('Version ' + oldVersion + ' of Code Beautifier Collection is already installed. Continue to use this old version?',mbConfirmation, MB_YESNO) = IDYES then
begin
Result := False;
end
else
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F768F6BA-F164-4599-BC26-DCCFC2F76855}_is1','UninstallString', uninstaller);
ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
Result := True;
end;
end
else
begin
MsgBox('Version ' + oldVersion + ' of Code Beautifier Collection is already installed. This installer will exit.',mbInformation, MB_OK);
Result := False;
end;
end
else
begin
Result := True;
end;
end;
GetNumber function returns only 'major' release.
To apply full Version comparison, you must concatenate Major and Minor release parts.
function GetNumber(var temp: String): Integer;
var
part: String;
pos1: Integer;
begin
if Length(temp) = 0 then
begin
Result := -1;
Exit;
end;
pos1 := Pos('.', temp);
if (pos1 = 0) then
begin
Result := StrToInt(temp);
temp := '';
end
else
begin
part := Copy(temp, 1, pos1 - 1);
temp := Copy(temp, pos1 + 1, Length(temp));
insert(temp, part, pos1);
Result := StrToInt(part);
end;
end;

ClientDataSet TBCDField rounding

I'm using Delphi 5 + BDE + Oracle. I have the following function:
class function TClientDataSetFactory.GetClientDataSet(
const qryGen: TDataSet): TClientDataSet;
var
dspDados: TDataSetProvider;
begin
Result := nil;
try
try
Result := TClientDataSet.Create(nil);
dspDados := TDataSetProvider.Create(Result);
dspDados.DataSet := qryGen;
qryGen.Active := True;
qryGen.First;
Result.Data := dspDados.Data;
Result.First;
except
on E: Exception do
begin
raise;
end;
end;
finally
end;
end;
so, when a run this:
var
qryGen: TQuery;
cdsGen: TClientDataSet;
begin
qryGen := nil;
try
try
qryGen := CriaQuery();
qryGen.SQL.Text :=
'SELECT SUM(TOTAL) AS TOTAL FROM MYTABLE';
cdsGen := TClientDataSetFactory.GetClientDataSet(qryGen);
ShowMessageFmt('Total: %f', [cdsGen.FieldByName('TOTAL').AsFloat]);
except
on E: Exception do
begin
raise;
end;
end;
finally
if Assigned(qryGen) then FreeAndNil(qryGen);
end;
end;
i got "159,00" but, if i run this:
ShowMessageFmt('Total: %f', [qryGen.FieldByName('TOTAL').AsFloat]);
i got "159,25".
can someone help me?
I solved the problem with another solution.
type
TInternalQuery = class(TQuery)
protected
procedure InternalInitFieldDefs; override;
public
constructor Create(AOwner: TComponent; const qryGen: TQuery); reintroduce;
end;
constructor TInternalQuery.Create(AOwner: TComponent; const qryGen: TQuery);
var
intCont: Integer;
begin
inherited Create(AOwner);
Self.DatabaseName := qryGen.DatabaseName;
Self.UpdateObject := qryGen.UpdateObject;
Self.SQL.Text := qryGen.SQL.Text;
for intCont := 0 to Self.ParamCount - 1 do
begin
Self.Params[intCont].Value := qryGen.Params[intCont].Value;
end;
end;
procedure TInternalQuery.InternalInitFieldDefs;
var
intCont: Integer;
begin
inherited InternalInitFieldDefs;
for intCont := 0 to FieldDefs.Count - 1 do
begin
if (FieldDefs[intCont].Size = 0) and (FieldDefs[intCont].DataType = ftBCD) then
begin
FieldDefs[intCont].Precision := 64;
FieldDefs[intCont].Size := 32;
end;
end;
end;
the problem is ((FieldDefs[intCont].Size = 0) and (FieldDefs[intCont].DataType = ftBCD)). when ClientDataSet is created, the field is truncated, because when oracle has a function like "SUM(TOTAL)" the result field is created with size 0, so the clientdataset handle the field as Integer field.
Try with
ShowMessageFmt('Total: %n', [cdsGen.FieldByName('TOTAL').AsFloat])
or this
cdsGen := TClientDataSetFactory.GetClientDataSet(qryGen);
**(cdsGen.FieldByName('Total') as TFloatField).DisplayFormat := '0.00';**
ShowMessageFmt('Total: %f', [cdsGen.FieldByName('TOTAL').AsFloat])

Resources