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';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.
ldl_make_string(ch, ret_string); ldl_make_int(pos, state->position); state->position++; status = LDL_SUCCESS; } else status = LDL_FAIL return(status); }
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.