What is this? #
RPCL is a minimalistic configuration and control language, initially designed to act as a CLI for daemon-like background processes. RPCL is an acronym for Reverse Polish Configuration (and Control) Language.
It is working stack-oriented in reverse polish notation and therefore borrows some control words from FORTH.
RPCL offers some control structures and has the ability to define compound words - however, the scope and purpose of RPCL remains to configure and control something (and not to program).
Overview #
The Datatypes #
C-compatible String #
RPCL is built around a basic datatype, a classical char
array with a maximum length
of RPCLWORDLEN
. Pushes and pops and all other operations are always ‘by value’. A RPCLWORD
is always 0-terminated internally.
This is how it is declared:
typedef uint8_t RPCLWORD[RPCLWORDLEN];
Binary Data with a length #
A second interpretation of a RPCLWORD
is binary data with a length. When interpreted as
a C-compatible string by a function that does not expect it, it just appears as a zero-length
string ""
. The available “payload” maximum buffer length is RCPLWORDLEN-4
to have 4 bytes
space to distinguish it internally.
Built-in RPCL words converting to another datatype internally need to verify that an RPCLWORD converts successfully and that the converted result is within its expected range. On failure, the built-in word is required to raise an error (return RPCL_FAILURE).
The Dictionary #
The RPCL dictionary is implemented as a skip list, where each entry holds a key, a value and an optional function pointer. Key and value are of size RPCLWORDLEN and always guaranteed to be 0 terminated.
UTF-8 / Unicode within the value field is supported, variable names are restricted to ASCII printable only, without double quotes, backslash and any whitespace. The variable name is resticted to a maximum length of 32 characters. The variable names are case sensitive.
An key-value entry in an RPCL dictionary belongs to one of these 3 classes:
- ordinary variables: A normal key-value pair held in the RPCL dictionary, accessible with
!
(store),@
fetch and removable withdelete
. - built-in words: A built-in word is additionally associated with a function pointer, the
value contains a brief description as specified with
RPCLRegister()
. A built-in word is immutable and therefore cannot be redefined or deleted from the RPCL command line. - compound words: A compound word holds the RPCL line as its value, wich is executed when the compound word is called. Compound words can be redefined and deleted.
The Stacks #
The Data Stack #
struct rpcl_stack {
char stack[RPCLSTACKDEPTH][RPCLWORDLEN];
int sp;
};
The Execution Stack #
The execution stack is represented by the underlying CPU stack, the interpreter keeps track of nested calls and signals an error when a threshold overflows.
The Stack Frame Delimiter #
A special object, the stack frame delimiter (SFD) allows to implement
- built-in functions which accept an arbitrary number of arguments
- and built-in functions, which return multiple results.
Comments #
Comments within a RPCL line are started with a #
.
Example:
$ rpclsh
ok 1 2 + . # just adding 1 and 2
3
ok "# This is not a comment" string ! # but this is
ok .d
string # This is not a comment
ok ▂
Double Quotes #
RPCL accepts strings enclosed in ASCII double quotes (0x22), nested double quotes can be specified with a preceeding backslash. Note that the Unicode-UTF-8 double quotes (0xe2 0x80 0x9d) are not recognized and do not work as it might be expected.
Example:
$ rpclsh
ok "This is a string containing also \\ and \"" .
This is a string containing also \ and "
ok "#" "#" strcat .
##
ok ▂
Forcing built-in/compound availability #
With an preceeding &
the remaining part of a token is forced to be available
as a built-in or compound word. This might be helpful to deal with misspellings,
which would be put on the stack as a value otherwise.
Another use case is to ensure the availability of a specific extension functionality registered by another component.
Example:
$ rpclsh
ok "3 +" addthree !!
ok 3 addthree .
6
ok 3 addthreee .
addthreee
ok 3 &addthreee .
unknown word "addthreee"
ERROR detected
ok ▂
True and False #
False is defined to be the empty string ""
, everything else is treated as logical
true.
Error Handling #
In case of an error (or when an error is raised) the execution stack is unwound
and the error message shown. When this happens during load
or load-if-present
,
the affected line number is additionally shown.
Loop Detection #
Endless loops are detected by an internal evaluation (or instruction) counter,
an “Evaluation threshold exceeded
” error
is signalled when a quite resonable threshold is exceeded.
Predefined Variables #
With RPCL itself, there are a few variables predefined. Other layers which embed RPCL are able to add their own set of predefined variables and compound words as desired.
Example:
$ rpclsh
ok .d
platform Debian12-amd64
version.rpcl 1.75
ok ▂