-
Notifications
You must be signed in to change notification settings - Fork 22
libiuab developer guide
Welcome to the developer guide for libiuab, the official "I use Arch btw" library for C/C++.
libiuab allows you to embed the "I use Arch btw" programming language into your C/C++ programs. More precisely, it mainly provides an "I use Arch btw" compiler, as well as a bytecode virtual machine to run compiled "I use Arch btw" programs. Although the library supports C++, it is written in C and therefore does not make use of namespaces or any other feature exclusive to C++.
This guide aims to get C/C++ developers started with libiuab.
An example C++ program that uses libiuab can be found here.
The following is true for any struct type TYPE
defined in a libiuab header:
If there is a function named TYPE_init
, structs of type TYPE
must be
initialized using a call to that function.
If there is a function named TYPE_fini
, structs of type TYPE
must be
deinitialized using a call to that function once they are no longer used in your
code. Structs that were dynamically allocated must be deinitialized before being
deallocated, as TYPE_fini
functions free the resources that were dynamically
allocated by TYPE_init
functions.
Some functions defined by libiuab may fail. These functions return a value of
the iuab_error
enum type, which is defined in
iuab/errors.h
. In order to check
if a call to one of those functions was successful, you should check if the
returned value equals to IUAB_ERROR_SUCCESS
.
The iuab/errors.h
header also defines the following function, which takes a
libiuab error code and returns a string describing the error:
char *iuab_strerror(enum iuab_error error);
The iuab/compiler.h
header
provides a bytecode compiler for "I use Arch btw" source code. The bytecode
generated by the compiler is not fully portable as multi-byte bytecode elements
are written in the host machine's byte order.
The compiler reads source code from files. fmemopen()
should be used if
available on the target platform in order to compile a string of source code.
Here is an example usage in C: a function that takes a file containing "I use Arch btw" source code, compiles the source code it contains, and returns a pointer to the first byte of the bytecode generated by the compiler:
uint8_t *compile(FILE *src) {
struct iuab_compiler *comp = malloc(sizeof(struct iuab_compiler));
if (!comp) {
fputs("memory allocation failure", stderr);
return NULL;
}
/* Initialize the compiler for compilation of src */
enum iuab_error result = iuab_compiler_init(comp, src);
if (result != IUAB_ERROR_SUCCESS) {
fprintf(stderr, "compiler init failure: %s\n", iuab_strerror(result));
iuab_compiler_fini(comp);
free(comp);
return NULL;
}
/* The compiler will make this point to the generated bytecode */
uint8_t *code;
/* Run the compiler, compile src into code */
result = iuab_compiler_run(comp, &code);
if (result != IUAB_ERROR_SUCCESS) {
fprintf(stderr, "error: %s at line %zu, col %zu\n",
iuab_strerror(result), comp->token.line, comp->token.col);
iuab_compiler_fini(comp);
free(comp);
return NULL;
}
iuab_compiler_fini(comp);
free(comp);
/* code must be free()'d once it is no longer used. */
return code;
}
The iuab/vm.h
header provides a
bytecode virtual machine for running compiled "I use Arch btw" bytecode
programs. Its specification is available here.
Here is an example function written in C that takes a pointer to a block of "I use Arch btw" bytecode and executes it using the virtual machine:
void execute(const uint8_t *code) {
struct iuab_vm *vm = malloc(sizeof(struct iuab_vm));
if (vm == NULL) {
fputs("memory allocation failure", stderr);
return;
}
/* Initialize the VM for execution of code */
iuab_vm_init(vm, code, stdin, stdout);
/* Index of the last opcode processed by the VM in the bytecode */
size_t last_op_pos;
/* Run the VM, execute code */
enum iuab_error result = iuab_vm_run(vm, &last_op_pos);
if (result != IUAB_ERROR_SUCCESS) {
fprintf(stderr, "error at 0x%zX: %s\n", last_op_pos,
iuab_strerror(result));
}
free(vm);
}