Skip to content

C++ Extensions

About C++ Extensions

C++ extensions are packages of code written in C++ that can interface with LDPL code and be added to your LDPL projects.

Because LDPL programs compile down to C++, there is no need for a translation layer or bridge: extensions can be included directly into LDPL programs and manipulate, share, and access subprocedures and variables natively. All that's needed is a few naming conventions on the C++ side and the use of the external syntax for variables and subprocedures on the LDPL side. External variable and sub-procedure naming conventions are explained in detail in the Naming Schemes section of this documentation.

Extensions contain sub-procedures and variables that are considered to be external. This means that they are not part of an LDPL source code and thus must be accessed and called in a different way to what you might be used to. External sub-procedures should be called using the call external statement. While it is explained in greater detail in the Control Flow Statements section of this documentation, the statement works just like the normal call statement with the exception that it doesn't accept parameters.

1
2
3
4
// In C++
void CPPFUNCTION(){
    //...
}
1
2
# In LDPL
call external cppFunction

External variables (declared in a C++ file) should be re-declared again in your LDPL data section with the same type they have in the C++ file, appending to their type the extenal keyword. This allows programmers to extend LDPL with new features or to wrap 3rd party libraries and re-use their functionality.

1
2
// In C++
ldpl_number MYNUMBER = 9;
1
2
3
# In LDPL
data:
myNumber is external number

This will be explained in greater detail in the following sections.

Writing C++ Extensions

If LDPL lacks some feature that C++ might offer, for example graphics or networking, you might find yourself in the need of writing a C++ extension (provided an extension for what you are looking for has not been already written, of course).

Extensions can create variables and functions that are accessible from LDPL through the call external and external data type keyword, as explained in the previous section. Typically, all you need is a single .cpp file that you include from your LDPL source using the extension keyword (explained in the Code Structure section of this documentation), but you may also include .o files, .a files, or any combination of them all.

Functions

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

  1. The function type must be void(void), ex: void MY_FUNC();
  2. The function name must conform to LDPL's external identifier naming conventions explained in the Naming Schemes section of this documentation.
  3. The function must not take any parameters.
  4. The function must not return any values.

Because LDPL does not know the name of any variables or functions declared in non-LDPL files, it allows the programmer to call any function or variable, existing or not, by using the external syntax. If the variable or function you are trying to access does not exist, the C++ linker will throw a nasty error. Also, all C++ variable and function names must contain only A-Z, 0-9, and the _ character. Every character on the LDPL side will be converted to upper case, and non alpha-numeric characters will be converted to an underscore (_) when referencing the C++ side (again, as stated in the Naming Schemes section of this documentation).

Example:

For example, this function in a file called add.cpp

1
2
3
4
5
6
7
8
9
void PROMPT_ADD() 
{
  int a, b, sum;
  cout << "1st number: ";
  cin >> a;
  cout << "2nd number: ";
  cin >> b;
  cout << "sum: " << sum << end; 
}

can be accessed from LDPL in the following way

1
2
3
4
external "add.cpp"

procedure:
    call external prompt_add

Variables

To create a variable in a C++ extension that can be accessed from LDPL code, you must follow two rules:

  1. The variable's name must conform to the LDPL external identifier naming convention stated in the Naming Schemes section of this documentation.
  2. The C++ type of the variable must match the type used by LDPL for the data type represented by that variable.

The first rule should be familiar from the previous section: all C++ variable and function 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 rule, the LDPL compiler provides the data types ldpl_number, ldpl_text, ldpl_list<T> and ldpl_map<T>. These will be explained in greater detail in the next section.

Example:

Declaring variables is easy on the C++ side:

1
2
3
ldpl_text NAME;
ldpl_number AGE;
ldpl_text STREET_ADDRESS;

These will be available to an LDPL program when declared as external in its data: section:

1
2
3
4
data:
    name is external text
    age is external number
    street_address is external text

The LDPL Data Types

The LDPL compiler provides the data types ldpl_number, ldpl_text, ldpl_list<T> and ldpl_map<T>. To use them, just use them as if they were declared and the LDPL compiler will add the declarations and definitions for you once the extension is compiled.

  • The ldpl_number data type is just a rename for double.
  • The ldpl_text data type is a special UTF-8 string class used just like the regular C++ std::string class, with the exception that if you want to get an std::string from an ldpl_text you can call the ldpl_text method ldpl_text::str_rep() to get the std::string representation of an ldpl_text. Just like you would use std::string::c_str() to get the C char* representation of an std::string.
  • The ldpl_list<T> data type represents an std::vector with a special [] operator overload.
  • The ldpl_map<T> data type represents an std::unordered_map with special [] operator overloadings.

You can read the definition of these data types on the ldpl_lib.cpp file of the LDPL source repository.

Accessing Variables in C++ Functions

Since LDPL and C++ are using the same variable when you use the external keyword (say, for example, MY_VAR in C++ and external my-var in LDPL), any changes you make to the content of said variables are shared. Use them just like you would use any regular variable, both in C++ and LDPL.

1
2
3
4
5
ldpl_number A, B, SUM;
void ADD() 
{
    SUM = A + B;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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 lf

Building and running this program will print 350.

Building C++ Extensions

Extensions are easy to build: when compiling your LDPL program, use the extension keyword (explained in detail in the Code Structure section of this documentation) to add .cpp files, .o files, or .a files to your LDPL project. They will be included in your program and become available using the external statements.

If your C++ extension files require extra flags to be passed to the C++ compiler in order to compile (for example, -lSDL when working with SDL) you can use the flag statement (explained in detail in the Code Structure section of this documentation) to pass flags to the C++ compiler.

1
2
3
4
5
6
7
external "otherFile.cpp"
flag "-fpermisive"
flag "-lSDL2"
data:
    #...
procedure:
    #...

"Hello World" C++ Example

File simple.cpp:

1
2
3
4
#include <iostream>
void SIMPLE(){
        std::cout << "Very simple!" << std::endl;
}

File simple.ldpl:

1
2
3
4
extension "simple.cpp"

procedure:
call external simple

Console:

1
2
3
4
5
6
$ ldpl simple.ldpl
LDPL: Compiling...
* File(s) compiled successfully.
* Saved as simple-bin
$ ./simple-bin
Very simple!

External Sub-procedures

Sometimes when writing C++ Extensions you'll find yourself in the need of declaring a function in C++ but coding it in LDPL. This is the opposite of writing C++ functions and calling them from LDPL, it's writing LDPL sub-procedures and calling them from C++.

These C++ callable sub-procedures are called external sub-procedures, as they can be called from an external medium.

In order to declare an external sub-procedure, you must first forward-declare it in your C++ source code. Say, for example, that you want to declare a sub-procedure called helloWorld. In your C++ you should write the following line:

1
void HELLOWORLD();

Note that external sub-procedures cannot receive any kind of parameters and must be declared as void. You may then call the external sub-procedure from C++ code like this:

1
2
3
4
int myCPPFunction(){
  HELLOWORLD();
  return 1;
}

Once that's taken care of, you can declare your external sub-procedure as any other sub-procedure in LDPL by prepending the identifier external to the sub-procedure declaration:

1
2
3
external sub-procedure myExternalSub
    #...
end sub-procedure

or just

1
2
3
external sub myExternalSub
    #...
end sub

These sub-procedures can be called from LDPL like you would call any other sub-procedure, but their names must follow the external identifier naming scheme detailed in the Naming Schemes section of this documentation as any other C++ interfacing identifier.

External Variables

Variables defined in extensions can be accessed by prefacing their data type declaration with the external keyword. This must occur in the data section of your LDPL code. Once an external variable is declared, it can be used just like any other LDPL variable.

Syntax:

1
<variable> is external <data type>

Example:

1
2
3
data:
    rl-prompt is external text
    window.size is external number