Writing C++ Extensions

Extensions can create variables and functions that are accessible from LDPL through the CALL EXTERNAL statement and EXTERNAL data type keyword. Typically all you need is a single .cpp file that you give the ldpl compiler when building your program, but you can also use .o files, .a files, or any combination of them all.

Extensions interact with LDPL in two main way: defining functions and declaring variables.

Functions

To create a function in C++ that can be called from an LDPL program, you must follow two rules:

  1. The function's type must be void(void), ex: void MY_FUNC();

  2. The function's name must conform to LDPL's Extension Naming Convention.

Because LDPL functions don't accept arguments or return values, to be callable from LDPL your C++ functions musn't either.

And because LDPL doesn't "know" the names of your functions and instead allows the programmer to call them using the EXTERNAL syntax, all C++ variable and subprocedure names must contain only A-Z, 0-9, and the _ character. Everything else on the LDPL side will get converted to an underscore (_) when referencing the C++ side.

Example

For example, this function:

void PROMPT_ADD()
{
int a, b, sum;
cout << "1st number: ";
cin >> a;
cout << "2nd number: ";
cin >> b;
cout << "sum: " << sum << end;
}

Once defined and built into LDPL, can be called using:

CALL EXTERNAL prompt-add

Variables

To create or reference a variable in a C++ extension that is shared with an LDPL program, you must follow two rules:

  1. The variable's name must conform to LDPL's Extension Naming Convention.

  2. The C++ type of the variable must match LDPL's internal type usage.

The first rule should be familiar from the functions section: all C++ variable and subprocedure names must contain only A-Z, 0-9, and the _ character. Everything else on the LDPL side will get converted to an underscore (_).

For the second, here's the mapping between types:

LDPL Data Type

C++ Type

TEXT

std::string

NUMBER

ldpl_number

TEXT MAP

ldpl_vector<std::string>

NUMBER MAP

ldpl_vector<ldpl_number>

TEXT LIST

ldpl_list<std::string>

NUMBER LIST

ldpl_list<ldpl_number>

The definitions for these data types can be found in the LDPL C++ Types section.

Example

Declaring TEXTand NUMBER variables is easy on the C++ side:

std::string NAME;
ldpl_number AGE;
std::string STREET_ADDRESS;

These will be available to an LDPL program to declare in its DATA: section:

DATA:
name IS EXTERNAL TEXT
age IS EXTERNAL NUMBER
street-address IS EXTERNAL TEXT

Accessing Variables in Functions

Since LDPL and C++ are using the same variable when you use the EXTERNAL keyword, any changes you make to the variable's content are shared. Just use them like you would use regular C++ variables.

ldpl_number A, B, SUM;
void ADD()
{
SUM = A + B;
}
DATA:
A IS EXTERNAL NUMBER
B IS EXTERNAL NUMBER
SUM IS EXTERNAL NUMBER
PROCEDURE:
STORE 100 IN A
STORE 250 IN B
CALL EXTERNAL add
DISPLAY SUM CRLF

Building and running this program will print 350.

LDPL MAPs

The MAP types are a bit trickier - they are defined as ldpl_vector<T>, so you'll want to declare this prototype in your .cpp or .h file to use it in your extension:

#ifndef ldpl_vector
template<typename T>
struct ldpl_vector {
T& operator [] (const std::string& i);
T& operator [] (double i);
};
#endif

Now you can use MAPs in LDPL:

DATA:
Names IS EXTERNAL TEXT MAP

And in C++:

ldpl_vector<std::string> NAMES;
// later...
NAMES[0] = "Pauline"
NAMES[1] = "just Paul"

The internal datatype for LDPL MAPs is called ldpl_vector because in LDPL releases prior to LDPL 3.1.0 Diligent Dreadnoughtus, MAPs where called VECTORs.