How to change a name of a function which is already defined? fe. writeNap to write (Pascal) - pascal

in our last class we defined a couple of functions and procedures in our unit file.
procedure WriteNap(const elo: string; const n: TNap; const uto: string);
begin
Write(elo, Nap2Str(n), uto);
end;
function PredNap(const n: TNap): TNap;
begin
case n of
hetfo: PredNap := vasarnap;
NemNap: PredNap := n;
else
PredNap := Pred(n)
end;
end;
function SuccNap(const n: TNap): TNap;
begin
case n of
NemNap: SuccNap := n;
else
SuccNap := Succ(n)
end;
end;
I have to get rid of the word 'Nap' so that i can just use Pred, Write, Succ in the main program instead of PredNap etc... i tried to create another unit file which uses this unit and contains functions like Succ Pred... didnt really work out..
thanks in advance :)

Declare in somewhere in your file:
var Pred = Function (Const n:TNap):TNap;
And before you do anything in the body of your program, write:
Pred := #PredNap;
What this code does is, it creates a new function pointer with the same signature as your PredNap() and then assign the address of PredNap() to this pointer. So, whenever you call Pred() the actual function that gets called is PredNap(). Hope this helps.

Related

How to set a procedure (function) to an event in delphi 7?

I am writing which component will run through the array like ['form1.Button1', 'form1.memo1', 'form1'] - like
And put the showms2 handler on it (form1.Button1.onclick: = showms2)
var
comp: array of Tcomponent;
met: Tmethod;
start off
setlength (comp, Lines.Count);
for i: = 0 to Lines.Count-1 do
start off
comp [i]: = (FindComponent (Lines.Names [i]) as TControl);
met: = GetMethodProp (comp [i], 'OnClick');
meth.Code: = form1.MethodAddress ('showms2');
met.Data: = 0;
// When splitting into elements, nothing happens, is there an alternative?
FindComponent() does not work the way you are using it. You need to specify only the name of a component that is directly owned by the component being searched, you can't specify a chain of components, ie Form1.FindComponent('Form1.Button1') won't ever work, but Form1.FindComponent('Button1') will work, if Form1 owns Button1.
Also, if you are going to set both TMethod.Code and TMethod.Data then calling GetMethodProp() is completely redundant and should be removed.
Also, you need to use SetMethodProp() to actually assign the TMethod to the target event.
Try this instead:
var
comp: TComponent;
met: TMethod;
i: Integer;
begin
for i := 0 to Lines.Count-1 do
begin
comp := FindComponent(Lines.Names[i]);
if comp <> nil then
begin
if IsPublishedProp(comp, 'OnClick') then
begin
meth.Code := Form1.MethodAddress('showms2');
meth.Data := Form1;
SetMethodProp(comp, 'OnClick', met);
end;
end;
end;
end;

Assigning procedures to variables and calling them in Pascal

I have a small terminal program which displays a menu. I want to have a function which takes the user's input and an array of procedure names and be able to call the procedure the user chose. I know that I could do that using if or case statements in the main program, but I want to make a unit with the above procedure and a couple of other menu functions, and if this was possible, I could make it call arbitrary procedures. Here's more or less how I would like it to work (I know it's wrong, but so you get a general idea).
program menu;
uses crt;
type procs = array [0..1] of procedure;
procedure call_procs(inp: int; procsy: procs);
begin
writeln(procsy[ord(inp)]); {And call it here.}
end;
var procsx : procs;
begin
procsx[0] := readkey; {I would like to somehow store the procedure here.}
procsx[1] := clrscr;
call_procs(0, procsx);
end.
Is there any way to do something like this? Thank you in advance.
There are a few things wrong with your original code which are not cited in your answer.
You have an array of procedure but you are calling writeln with these procedure calls as arguments as if they were function, which they are not.
readkey is a function, not a procedure, so its type doesn't match the element type of your array
Your assignment of the procedures to the array need to use # to reference the procedure pointer and not actually call the procedure
Not sure what compiler or options you're using, but int isn't the standard Pascal integer type, rather integer is.
As a niggle, since you're already using the integer index of the array, you don't need to use ord.
So the minimal changes to your code to make it basically work would be:
program menu;
uses crt;
type procs = array [0..1] of procedure;
procedure call_procs(inp: integer; procsy: procs);
begin
procsy[inp]; { call the procedure here - removed 'ord' since it's superfluous }
end;
var procsx : procs;
begin
{ procsx[0] := readkey; {- 'readkey' is a function and won't work here }
procsx[1] := #clrscr;
call_procs(1, procsx);
end.
You can create an array of functions that return char which matches the type for readkey:
program menu;
uses crt;
type procs = array [0..1] of function: char;
procedure call_procs(inp: integer; procsy: procs);
begin
writeln(procsy[inp]); { call the function; write out the returned char }
end;
function foo: char;
begin
foo := 'X';
end;
var procsx : procs;
begin
procsx[0] := #readkey;
procsx[1] := #foo;
call_procs(0, procsx);
call_procs(1, procsx);
end.
I figured out how to do this. One can use pointers to a procedure, then create an array of those pointers, and pass them to the procedure I wanted to use. Also, for some reason, it doesn't seem to work with the functions that come with Pascal (such as readkey or clrscr). For this example, one could do this:
program menu;
type
Tprocptr = procedure; {This creates a pointer to procedures.}
Tprocarray = array of Tprocptr;
procedure writeHi;
begin
writeln('Hi!');
end;
procedure writeHello;
begin
writeln('Hello!');
end;
procedure call_proc(inp: integer; procsy: Tprocarray);
{This now calls functions like one would expect.}
begin
procsy[ord(inp)];
end;
var
proclist : Tprocarray;
begin
setlength(proclist, 2);
proclist[0] := #writeHi; {The '#' creates a pointer to those procedures.}
proclist[1] := #writeHello;
call_proc(0, proclist);
end.
This works as expected, calling (in this case) the procedure writeHi, so if you run this program it will output Hi! to the terminal. If you change call_proc(0,proclist) to call_proc(1, proclist), it will call writeHello instead.

Lazarus error "External: SIGSEGV" on variable increment?

I got a problem in my Lazarus project: everytime I want to use a function it throws the above error (External: SIGSEGV). I don't know what that means, but some debugging showed me, that this is the code, causing the error:
class function TUtils.AsStringArray(const Strs:TStrings): TStringArray;
var
s:string;
i:integer;
begin
SetLength(Result, Strs.Count);
i := 1;
for s in Strs do
begin
Result[i] := s;
i := i + 1;
end;
end;
And the definitions
TStringArray = array of string;
TUtils = class
public
[...]
class function AsStringArray(const Strs:TStrings): TStringArray; static;
end;
The exception occurs after i := i + 1;. I would be really thankful if you could help me!
Dynamic arrays such as TStringArray = array of string; are zero-based; your code uses it as 1-based and raises access violation.
You should replace i := 1; by i := 0;
To the second Problem, it is because you are accesing to the index i, wich at the start it is 1 that is why you have the problem, the range of the array is determined by "length - 1", so if your length is 1, then your range is 0. So to solve the problem in your for loop you have to put Result[i-1] := s; like this you acces the index you really want.
More of this on http://wiki.freepascal.org/Dynamic_array

Reading record from a text file into array in Pascal

1.this is my code i want to read a record from a text file into array in pascal my program is about making a hotel helper and i already have a text file with the data of the hotel then i should read it from the text file and store it in array .. but i am facing error 103 exit code (file not open).... any help Please . :)
program Hotel1(input,output);
const max =10; MaxFloor =10;
type
Date = record
day :1..31;
month:1..12;
year:integer;
end;
Booking = record
Guest:string[20];
S_Date:date;
E_date:date;
end;
Booking_Mat= array[1..max] of Booking;
History_Booking = record
B_num:integer;
B_Mat:Booking_Mat;
end;
Room = record
Num:integer;
Bed_num:integer;
Price:integer;
Status:Boolean;
H:History_Booking;
end;
Data = record
Ro:Room;
m:integer;
end;
Data_mat= array [1..max] of Data;
Procedure Read_Data(filename:string; var table:Data_mat);
var df:text; i,j :integer;
n,m,num,GN:integer;
Bed_num,Price:integer;
f:text;
s,e:Date;
Gname:string[20];
ok:boolean;
a:Data_mat;
c:char;
Begin
writeln('Reading ',filename,' records into array.... ');
assign(df,filename);
reset(df);
i:=0;
while (not eof) do
begin
i:=i+1;
Read (f,num);
a[i].Ro.num:=num;
Read (f,Bed_num);
a[i].Ro.Bed_num:=Bed_num;
Read (f,Price);
a[i].Ro.Price:=Price;
Read(f,c);
if (c ='Y') then
a[i].Ro.status:= true
else
a[i].Ro.status:= false;
readln;
End; {while eof}
close(df);
End; {Read_Data}
You've declared two variables of type Text, (df and f) in your var block.
You open df with these lines:
assign(df,filename);
reset(df);
You then read from f (which is not the file you opened above) in several lines, such as this one:
Read (f, num);
It's interesting to note that you actually manage to close the file you really opened, even though you never use it in your loop:
close(df);
The solution to all of these issues is to delete the declaration of either f or df, and then fix the compiler errors you get by correcting the code to use the remaining text variable. (Two important lessons here are
Only declare the variables you actually need.
Use the variables you declare.
Your loop is also invalid, because you're using while not eof with no file provided for which to test the end. Your loop should read while not Eof(df) do instead.
It's also much better to follow the typical naming convention of prefixing types with a T. It makes it clear that it's a type and not a variable, and allows you to read the code more easily. For instance, I'd change your definition of Data to TRoomData, and change the other type declarations accordingly. Here's an example - note that TRoomData now has a field (member) named Room of type TRoom:
TRoomData = record
Room: TRoom;
m: Integer;
end;
TRoom is defined as
TRoom = record
Num: Integer;
Bed_num: Integer;
Price: Integer;
Status: Boolean;
H: THistory_Booking;
end;
And so forth. This allows you to write code more clearly:
var
RoomData: TRoomData;
begin
RoomData.Room.Num := 1;
RoomData.Room.Price := 50;
// etc.
end;
With all that being said, your file does not contain text, and therefore you're using the wrong file type by using df: Text in the first place. You should use a File of TRoomData, allowing you to read and write entire records at a time. Here's an example of doing so:
var
DF: File of TRoomData;
RoomData: TRoomData;
i: Integer;
const
DataFileName = 'D:\TempFiles\RoomData.dat';
Writing it:
// Put some data into the record
RoomData.Room.Num := 1;
RoomData.Room.Bed_num := 1;
RoomData.Room.Price := 40;
RoomData.Room.Status := True;
RoomData.Room.H.B_num := 1;
for i := 1 to Max do
begin
RoomData.Room.H.B_Mat[1].Guest := Format('Guest %d', [i]);
RoomData.Room.H.B_Mat[1].S_Date.Year := 2014;
RoomData.Ro.H.B_Mat[1].S_Date.Month := i;
RoomData.Ro.H.B_Mat[1].S_Date.Day := i;
end;
// Write it out to the file
AssignFile(DF, DataFileName);
try
Rewrite(DF);
Write(DF, RoomData);
finally
CloseFile(DF);
end;
Reading it back in:
AssignFile(DF, DataFileName);
try
Reset(DF);
Read(DF, RoomData);
finally
CloseFile(DF);
end;
(Or, better yet: If the version of Pascal you're using supports it, move away from the old file I/O routines and start using TFileStream instead.)
Last but not least, learn to properly format your code. It makes it much easier to debug and maintain, and it's much easier to read when you can follow the execution path clearly.

Returning a value in Pascal

For a function to return a value in Pascal the assignment FunctionName := SomeVal; is used. I assume it doesn't stop the function execution in that exact place as return in C does. Is there something similar to C return in Pascal? (I'm using FreePascal compiler)
You can use the Exit procedure.
function Foo (Value : integer) : Integer;
begin
Exit(Value*2);
DoSomethingElse(); // This will never execute
end;
The return code of the end of every program is stored in the EAX register. So you can use Assembly inline on Pascal to return wherever you want to end the program running using!
asm
mov eax,%ERROLEVEL%
end;
I think you can use either the function name itself, "result", or Exit(), but I've only used the result identifier, so don't know if the others will work for you:
function Foo(a, b: Integer): Integer;
begin
result := a + b;
end;
Hope that helps ^^
In canonical pascal (without keyword Exit) you can emulate return via goto:
function Foo (Value : integer) : boolean;
label return;
begin
if Value < 0 then
begin
Foo := false;
goto return;
end;
Calc();
Foo := true;
return:
end;

Resources