Features
This page is a catalog of Lambda C's capabilities and APIs. For internal design — the 4-byte instruction format, FFI linking mechanism, three-stack model, hot-reload, and design rationale — see Architecture.
Language Features
Supported
- C-like syntax (subset)
- Integers, floats, pointers
- Arithmetic, logical, bitwise operators
- Control flow:
if,while,for,switch,goto - Functions (parameter count bounded only by the stack, no fixed limit)
- Function pointers - callbacks, state transition tables, etc.
- Global/local variables
- Arrays, including multi-dimensional (up to 6 dimensions), and structs
- Type casts between integers, floating point, and pointers
- enum - both explicit values and auto-increment supported
- union - memory-efficient variant types
- typedef - type aliases
- Qualifiers - const, static, etc.
- Forward declarations (FFI)
- Standard library:
printf,sqrt,sin,cos, etc.
Supported (Preprocessor)
#include- External file inclusion#define- Macro definitions#ifdef/#ifndef/#endif- Conditional compilation
Not Supported
- Nested functions
- User-defined variadic functions (
...) —printfetc. are built-in intrinsics - Variable-length arrays (sizes must be compile-time constants)
- Bit-fields, compound literals, designated initializers
- C99 types:
long long,_Bool(useint, or atypedeffor fixed-width)
FFI System
Function Registration
// Basic registration (returns negative ID starting from -1000)
int lcvm_register_function(const char *name, lcvm_ffi_func_t func, int arg_count);
// Registration with type signature (type checking in DEBUG builds)
int lcvm_register_function_ex(const char *name, lcvm_ffi_func_t func,
int arg_count, const char *signature);
// Find function by name (for manual linking)
int lcvm_ffi_find_by_name(const char *name, int *arg_count);
// Automatic linking (called after bytecode load)
int lcvm_link_program(compact_program_t *prog);Type Signatures
Signature characters for lcvm_register_function_ex():
| Character | Type |
|---|---|
i | int |
d | double |
f | float |
p | pointer |
s | string |
// Example: function taking int and double
lcvm_register_function_ex("add", ffi_add, 2, "id");
// Example: function taking two pointers
lcvm_register_function_ex("memcpy", ffi_memcpy, 2, "pp");
Type mismatch log output example:
FFI add: arg 0 type mismatch (expected i, got pointer)FFI Function Signature
typedef void (*lcvm_ffi_func_t)(LcvmState *vm);
// Push return value to stack
void lcvm_push_int(LcvmState *vm, int32_t value);
void lcvm_push_double(LcvmState *vm, double value);
// Pop arguments from stack (in reverse order)
int32_t lcvm_pop_int(LcvmState *vm);
double lcvm_pop_double(LcvmState *vm);Example: Multi-argument FFI
// Script: result = add(10, 20.5);
static void ffi_add(LcvmState *vm) {
double b = lcvm_pop_double(vm); // 20.5
int32_t a = lcvm_pop_int(vm); // 10
lcvm_push_double(vm, a + b); // 30.5
}
lcvm_register_function_ex("add", ffi_add, 2, "id");Memory Management
Memory Layout
Flash/ROM (Read-only)
- VM code (compact_vm.o, intprt.o)
- FFI handlers (host_ffi.o)
- Standard library (liblcvm.a)
RAM (Writable)
- Bytecode (loaded from file/network)
- Global variables (garea)
- Stack (locals, temps)
- Heap (dynamic allocation)
Heap Watermark API
Ideal for temporary bulk memory allocation and batch release patterns:
// Record current heap position
size_t mark = lcvm_heap_mark();
// Allocate temporary memory
char *buf = lcvm_malloc(64 * 1024);
// ... processing ...
// Batch release to mark position (O(1), no fragmentation)
lcvm_heap_release(mark);
Also available from scripts:
int mark = heap_mark();
// ... temporary processing ...
heap_release(mark);Recommended Settings
Cortex-M0+ (32KB RAM)
#define VM_STACK_SIZE (8 * 1024) /* 8KB */
#define VM_GAREA_SIZE (8 * 1024) /* 8KB */
#define VM_HEAP_SIZE (12 * 1024) /* 12KB */Cortex-M4 with FPU (64KB RAM)
#define VM_STACK_SIZE (16 * 1024) /* 16KB */
#define VM_GAREA_SIZE (16 * 1024) /* 16KB */
#define VM_HEAP_SIZE (24 * 1024) /* 24KB */
Hardware FPU (FPv4-SP) support enables fast floating-point operations.
RISC-V RV32 (RV32IMC)
#define VM_STACK_SIZE (8 * 1024) /* 8KB */
#define VM_GAREA_SIZE (8 * 1024) /* 8KB */
#define VM_HEAP_SIZE (12 * 1024) /* 12KB */
Open ISA. Supports Integer, Multiply, and Compressed instruction sets.
ESP32 (320KB RAM)
#define VM_STACK_SIZE (32 * 1024) /* 32KB */
#define VM_GAREA_SIZE (32 * 1024) /* 32KB */
#define VM_HEAP_SIZE (128 * 1024) /* 128KB */Static Type Mode
Compile with -Os to omit stack-side type tracking. Achieves ~2x speedup for integer-heavy programs.
lcvmc -Os -oc output.lcbc source.c
Limitations:
- Optimized for integer operations (normal mode recommended for floating-point)
- printf/sprintf supported; configure
LCVM_PRINTF_BUFSIZEfor embedded (default: 1024 bytes)
For benchmarks and the technical background, see Architecture.
Debug Support Features
Watchpoint Feature
Automatic detection of global variable modifications:
Watch range is specified by an offset and size into garea (size must be 1, 2, 4, or 8).
// Enable: build with LCVM_WATCH_ENABLED=1
// Add watch targets (up to 8)
lcvm_watch_add(&vm, hp_offset, sizeof(int), "player_hp");
lcvm_watch_add(&vm, state_offset, sizeof(int), "game_state");
// Clear watches
lcvm_watch_clear(&vm);
Writes that overlap a watched range are automatically logged.
GDB Pretty Printer
Load tools/gdb_lcvm.py to display VM state in human-readable format within GDB:
(gdb) source tools/gdb_lcvm.py
(gdb) p vm
$1 = LcvmState { pc=42, sp=8, error=NONE, ... }
Shows call stack, registers, and opcode details on error.
Postmortem Tool
Ideal for crash analysis in embedded environments:
Writes the dump into a buffer and returns the byte count (minimum 24 bytes). The caller forwards the buffer to storage or transport.
// Output binary dump on host side
unsigned char buf[256];
int len = lcvm_dump_diagnostic_binary(&vm, buf, sizeof(buf));
// e.g. forward buf to Flash / serial / file# Analyze on PC
python tools/lcvm_postmortem.py crash.binSimulator SDK
Framework for rapidly building domain-specific simulators.
Minimal Configuration
Implement a simulator with just 2 callback functions:
void on_init(LcvmState *vm, void *user) {
// Register FFI functions (with type signature)
lcvm_register_function_ex("set_motor", ffi_set_motor, 2, "ii");
lcvm_register_function_ex("get_sensor", ffi_get_sensor, 1, "i");
}
void on_frame(LcvmState *vm, float dt, void *user) {
// Physics simulation
update_physics(dt);
// Rendering
render_scene();
}Implementation Example
demos/raylib_drone/ — RayLib-integrated drone delivery simulator. See Drone Demo for the full walkthrough.
Safety Features
Watchdog Timer
- Time-based: Terminate execution after N milliseconds
- Instruction-based: Terminate after N instructions
- Configurable:
lcvm_set_watchdog_ms(),lcvm_set_watchdog_ic()
Sandbox Mode
- On by default: Pointer access is range-checked unless explicitly disabled
- Memory isolation: Scripts can only access VM stack, garea, and heap
- Hardware protection: Peripheral access only via FFI functions
- Disable:
lcvm_set_sandbox_mode(0)orLCVM_SANDBOX=0
Error Handling
- Graceful recovery:
setjmp/longjmpbased error handling - Detailed diagnostics: Error code, message, PC, line number
- API:
lcvm_has_error(),lcvm_get_error_code(),lcvm_get_error_message()