The return values for the foreign function
have to be passed in as arguments of type LdlObject. Inside
the funtion, the user accesses for reading only the input
arguments. Similarly, all the output arguments are assigned
or set in the function. The return value of the function is of
type LdlStatus which signifes wither a logical success
of a failure.
Since we might have more than one value being returned
after a call to a foreign function, this function should be prepared
to handle multiple calls. This feature requires the function to
have some sort of a state associated with it to distinguish between
several calls in the same session (a session here implies the
duration from the instant the first result is generated until
the last result is generated).
We also need to distinguish between the first time
a function is called, with a new set (possibly null) of values,
and subsequent calls. This is done typically to create the state
structure, initialize any state variables etc., the first time
the function is called. To find out if this was the first time
the function was being called, we provide a convenience function
ldl_entry_p0. This function returns a non-zero value if
indeed the function was called the first time with a new set of
values--it returns a zero otherwise. Various other functions are
provided to extract data from LDL++ objects and to create LDL++
objects. Upon a successful execution of the function the user
is expected to return the value LDL_SUCCESS, otherwise
the user is expected to return the value LDL_FAIL.
The user is expected to compile this external function
file and create a binary file. This binary file has to be specified
as part of the import declaration in the LDL++ program. This basically
tells the LDL++ system where to pick up the definition for the
externally defined predicate.
Consider now the
example all_letters.
This function essentially takes
a string as an input parameter and assigns each letter
of the string and its position in the string to the two output
parameters. It returns a value of LDL_SUCCESS as long as
it can find such a pair, or it returns a value of LDL_FAIL.
Let us examine each part of this code.
#include <ldl_extern.h> #include <string.h>Here we are including two files. The first file contains all the declaration of the LDL++ accessory functions. It also contains definitions of some LDL++ objects. The second file, string.h, is the standard C include file containing declarations for string manipulation functions.
extern "C"
{
LdlStatus all_letters
(LdlObject str, LdlObject ch, LdlObject pos);
}
Here we enclose the function declaration in an extern
statement in order to suppress the name mangling performed by
most C++ compilers. The function is declared to accept three arguments
of type LdlObject and is expected to return a value of
type LdlStatus.
typedef struct
{
int position; // Current position
int length; // Length of string
} State;
This is the definition of the state structure we
intend to use for this function. It contains two state variables,
one to store the current position within the string and the other
to store the length of the entire string.
LdlStatus all_letters (LdlObject str, LdlObject
ch, LdlObject pos)
{
State* state;
LdlStatus status;
char ret_string [2];
char* c_string;
if (ldl_entry_p())
{
// This is the first time around
// Create the state structure
state = (State*)ldl_create_state(sizeof(State))
// Initialize the position
state->position = 0;
if (c_string = ldl_get_string(str))
state->length = strlen(c_string);
else
state->lenth = 0
}
In this section of the code, we examine if this was
the first time this function was invoked. If that were the case,
we created the state structure by using a LDL++ system function,
ldl_create_state. We pass to this function the size in
bytes of the state structure we are intercede in creating. Once
we have the state, we initialize the state variable position.
To initialize the other variable, length, we first need
to extract the C string from the input parameter, str and compute
its length. This length is now assigned to the state variable
length. This ends the initialization process. Now we are ready
to perform the actual processing.
// Recover the state from the LDL++ system
state = (State *)ldl_get_state();
if ((c_string = ldl_get_string(str))
&&
(state->position < state->length))
{
ret_string[0] = c_string[state->position];
ret_string[1] = '\0';
ldl_make_string(ch,
ret_string);
ldl_make_int(pos,
state->position);
state->position++;
status = LDL_SUCCESS;
}
else
status = LDL_FAIL
return(status);
}
This section of the code is executed every time this
function is called. We first recover the state using the LDL++
system function ldl_get_state. We then examine if our current
position is less than the length of the string. If true, this
implies that we have some more values to return. We extract the
"C" string from the input parameter and create a string
of one character picked up from the current position. We use the
system function, ldl_make_string, to create a string and
assign it to the output parameter.ch. Similarly, using ldl_make_int,
we create a integer denoting the corresponding position of the
character and assign it to the other output parameter, pos.
Then we increment the state variable, position, to look
at the next character (if any) during the next call of this function.
Finally we return a value of LDL_SUCCESS. Once all the
characters have been processed, we return a value of LDL_FAIL.
This link shows a complete LDL++ program using the external C++ function described above.
In general, to import an external C/C++ function as a predicate,
you need to declare it as follows:
import foreign PredicateName( Argl: Type, Arg2: Type, ... ) from 'file1.o', 'file2.o', ...., 'lib1.o', 'lib2.o', ... , 'libn.o'.For our example, the declaration would be:
import foreign all_letters( $Word: string, Letter:string, Position: integer_ from '/usr/local/ldl++/demo/all_letters.o' '/usr/lib/libc.a'.The C++ file is assumed to be located at '/usr/local/ldl++/demo/all_letters.o'. Once we have this declaration, all_letters can be treated as an LDL++ predicate.
Carlo Zaniolo, 1997