Overview

 

RPCL 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, which directly allows typical C referencing as a string.

This is how it is declared:

typedef uint8_t RPCLWORD[RPCLWORDLEN];

Data with a length #

A second interpretation of a RPCLWORD is 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.

With this data type RPCL is able to handle and compose raw networking packets and all other raw binary data as long as the data fits into an area of RPCLWORDLEN-4.

Data Subtypes #

Data may be generic or may carry a specific subtype, all corresponding C types are implicitly in host byte order as stored on the host system. This extension has been added to interface C functions properly handling endianess.

In the stack notation of an RPCL word the data subtype appears as in the second column without the leading D.

When printing a data subtype with ., the conversion if known is indicated by underscoring the output. If it’s not known or generic_t, then a “hexdump” type of output is displayed (as with .x).

//                         bytes
#define Dgeneric_t  0   //   *   unspecified data
#define Dint8_t     1   //   1   int8_t
#define Duint8_t    2   //   1   uint8_t
#define Dint16_t    3   //   2   int16_t
#define Duint16_t   4   //   2   uint16_t
#define Dint32_t    5   //   4   int32_t
#define Duint32_t   6   //   4   uint32_t
#define Dint64_t    7   //   8   int64_t
#define Duint64_t   8   //   8   uint64_t
#define Dip_t       9   //  16   IP address
#define Dip4_t      10  //   4   IPv4 address
#define Diprange_t  11  //  32   IP address "from"-"to"
#define Dmac_t      12  //   6   MAC address
#define Dmacrange_t 13  //  12   MAC address "from"-"to"
Built-in RPCL words converting from a string to data with a subtype 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 skiplist, 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, the value can also hold arbitrary data with a length being a 0-terminated string of strlen 0 at the same time.

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 with delete.
  • 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 
rpcl.platform                    Debian12-amd64
rpcl.version                     1.137
ok

Changing the Prompt #

rpcl.prompt #

The variable rpcl.prompt allows to change the prompt from ok to something else.

This may be useful to be included in a machine specific configuration file of a RPCL controlled application, for example.

Example:

$ rpclsh
ok application@testmachine rpcl.prompt ! 
application@testmachine .d 
rpcl.platform                    Debian12-amd64
rpcl.prompt                      application@testmachine
rpcl.version                     1.139
application@testmachine

rpcl.prompt.color #

The variable rpcl.prompt.color allows to set the color of the prompt. Possible values are:

  • red
  • green
  • blue
  • yellow
  • anything else: the terminal default color

If rpcl.prompt.color is not set (undefined), the prompt color defaults to green.

Example:

$ rpclsh
ok bngx@test rpcl.prompt ! 
bngx@test red rpcl.prompt.color ! 
bngx@test .d 
rpcl.platform                    Debian12-amd64
rpcl.prompt                      bng@test
rpcl.prompt.color                red
rpcl.version                     1.139
bngx@test default rpcl.prompt.color ! 
bngx@test rpcl.prompt.color delete 
bngx@test .d 
rpcl.platform                    Debian12-amd64
rpcl.prompt                      bng@test
rpcl.version                     1.139
bngx@test rpcl.prompt delete 
ok