Topic : The GFA-Basic Compendium
Author : GFA Systemtechnik GmbH
Version : GFABasic.HYP v2.98 (12/31/2023)
Subject : Documentation/Programming
Nodes : 899
Index Size : 28056
HCP-Version : 3
Compiled on : Atari
@charset : atarist
@lang :
@default : Document not found
@help : Help
@options : +g -i -s +z
@width : 75
@hostname : STRNGSRV
@hostname : CAB
@hostname : HIGHWIRE
@hostname : THING
View Ref-FileThe basic method will now be demonstrated with the aid of an example. The
routine to be included is to fill the elements of a two-byte array with numbers
from 0 to n, passing the address and the size of the array. The parameter
passed for the array size will only be a two-byte variable so that the size of
the array is limited to 32267 elements. The function carrying out this task
will work without the use of library functions.
The program is to be written in such a way that it can also be run by
the interpreter. In the interpreter, of course, the C routine cannot be
included through the linker. Therefore it is made executable within the
interpreter by a routine taking over the task of the C routine to be
linked.
The program looks like this:
DlM x&(32000),y&(32000)
'
t1%=TIMER
f_gfa(32000)
t2%=TIMER
PRINT "In :"'(t2%-t1%)/200
FOR i&=0 TO 39
PRINT x&(i&),
NEXT i&
'
t1%=TIMER
f_c(V:y&(0),32000)
t2%=TIMER
PRINT "In Turbo C:"'(t2%-t1%)/200
FOR i&=0 TO 39
PRINT y&(i&),
NEXT i&
'
PROCEDURE f_gfa(n&)
FOR i&=0 TO n&
x&(i&)=i&
NEXT i&
RETURN
'
PROCEDURE f_c(adr%,n&)
$X fill
i&=0
a%=adr%
WHILE i&<=n&
WORD{a%}=i&
INC i&
ADD a%,2
WEND
RETURN
First, two arrays are dimensioned. Then two timings are taken: the first calls
the f_gfa routine which assigns values of 0 to 32000 to the elements of the
array x&(). For display purposes, the first 40 elements of the array are then
displayed on screen.
The second of the timings calls the routine f_c. This routine, too, is to
assign values of 0 to 32000 to an array, but this task is to be performed in
the compiled and linked program by a C routine. Therefore this routine is
supplied with the field address and the number of values to be written.
In the first line of the procedure f_c you will find an instruction which tells
the linker to include the C function "fill". The name of the function can be
found after the $X option. This line must always be the first line of the
procedure.
The linker replaces the contents of the procedure with the C routine named
after $X. In the interpreter, this line is ignored and the command lines
following $X c_routine are executed. There are three of these in the given
example, which perform the same function as the C routine and also work in the
same way as the C routine by carrying out value assignments through a pointer.
Now to the structure of the C program carrying out the assignment. It was
written in Turbo C and reads:
void cdecl fill(n,adr)
int n;
int *adr;
{
int i; int *a;
a = adr;
for( i=0 ; i<=n ; *a++ = i++ );
}
The first line contains the name of the function which appears after $X in the
GFA-Baisc listing. This function has no return value and has therefore been
declared as void.
Before the function name there is the instruction cdecl. It tells Turbo C to
receive the parameters via the stack. Some other C compilers, such as C, do
this automatically. In the GFA BASIC listing the parameters are passed in the
order adr%, n&.
C takes the parameters from the stack in the reverse order, i.e. first the
two-byte value n and then the address of a four-byte variable adr. The
following lines then carry out the assignment of values to the field elements.
This completes the description of the structure of the and the C
listings. It only remains to explain how you can get the linker to insert the C
function in the position of $X fill. To do this, you only need to specify the
name of the object file generated by the C compiler.
This file name can simply be entered in the command line if a DOS shell is
used. In the shell supplied the variable G3OBJ can be amended.
The execution time of the loop is around 0.51 seconds, while the
Turbo C loop only requires about 0.115 seconds. This shows how assignments
using pointer operations can be effectively optimized in Turbo C.
Thus the following steps have to be followed:
1. You write a procedure in the GFA BASlC program, the first line of which
contains the $X option followed by a C function name.
2. You write a C program containing this function. This must take the
parameters and place them on the stack. There the parameters are placed in
the reverse of the order that they have when passed by the
program.
3. When linking, the object file of the C listing with the routine to be linked
must be specified.
If the C compiler is used, one point to be noted is that this compiler
prefixes C function names with the underscore character. Hence, instead of $X
fill, $X _fill would have to be entered.
In our example, the C function had no return value and was therefore declared
as void. However, a C function can be employed not only in place of a
procedure, but also in place of a function.
The appropriate listing could be, for example:
value%=100
PRINT @doub(value%)
'
FUNCTION doub(a%)
$X double
ALERT 1,"Place marker for|a C function.",1,"Return",a&
RETURN 0
ENDFUNC
In this example, the function does not perform the task of the C
routine to be linked in. The simple C programs follows:
long cdecl double(x)
long x;
{
return x+x;
}
The return value of such an external function is always an integer value.
You can, of course, also link assembler routines. These must take their
parameters from the stack and must not change the stack pointer SP or the
registers A3, A4, A5 and A6.