another portable, embeddable Lisp/Scheme implementation based on a register-oriented bytecode vm
C++
11
119 commits
updated Sep 30, 2026
A portable, embeddable Scheme implementation based on a register-oriented bytecode vm
I have many years of work experiences in game programming, especially backend. Lua is so pupular in the game industry, and also in many other areas. I like SICP very much, and have read the article The Roots Of Lisp and the book "Hackers and Painters". Lisp is highly praised.
I want to have a scheme implementation that's like lua, a vm register and bytecode-based with line level debug info
It could be easily embed to many host programs, only need to copy some .h/.cpp files to compile together, and write stubs
call/cc)
multi-short, unlimited, use the method copy-on-write of the callframes.
delimited continuation will be supported in the near future toosyntax-rules hygienic macros
custom ellipsis is also supported-1. to test scheme code, please refer to r4rstest.scm, r5rs-tests.scm, aftertest.scm in the project
#include "vm.h"
using namespace Scheme;
use default malloc/free
VM vm;
or use custom malloc/free
static void * myalloc(void *ptr, size_t nsize) {
if (nsize == 0) {
myfree(ptr);
return NULL;
}
else
return myrealloc(ptr, nsize);
}
VM vm(myalloc);
vm.loadfile("filename.scm");
// (lambda (a b) xxx)
static ValueT scm_stub_my_add(VM* vm, ValueT* a, ValueT* b)
{
return scm_make_int(vm, scm_get_int(vm, a) + scm_get_int(vm, b));
}
// (lambda rest xxx)
static ValueT scm_stub_my_sum(VM* vm, ValueT* rest)
{
scm_int t = 0;
ValueT* p = rest;
while (!scm_is_null(vm, p))
{
t += scm_get_int(vm, scm_car(vm, p));
p = scm_cdr(vm, p);
}
return scm_make_int(vm, t);
}
const RegCProc myext[] = {
RegCProc("my-add", scm_stub_my_add), // (lambda (a) xxx)
RegCProc("my-sum", scm_stub_my_sum, true), // (lambda (a . rest) xxx)
RegCProc(NULL, -1)
};
regcfunc(vm, myext);
(my-add 2 3)
(my-sum 1 2 3 4)
ValueT val = vm->evalstr("(+ 1 2)")
int iv = scm_get_int(vm, &val);
// iv = 3
ValueT* argv[] = {xxx};
ValueT val = vm->call("f", argv, n)
Optimization and features are endless
MIT
C++
80.8%
Scheme
16.6%
Tree-sitter Query
2.4%
another portable, embeddable Lisp/Scheme implementation based on a register-oriented bytecode vm
C++
11
119 commits
updated Sep 30, 2026
A portable, embeddable Scheme implementation based on a register-oriented bytecode vm
I have many years of work experiences in game programming, especially backend. Lua is so pupular in the game industry, and also in many other areas. I like SICP very much, and have read the article The Roots Of Lisp and the book "Hackers and Painters". Lisp is highly praised.
I want to have a scheme implementation that's like lua, a vm register and bytecode-based with line level debug info
It could be easily embed to many host programs, only need to copy some .h/.cpp files to compile together, and write stubs
call/cc)
multi-short, unlimited, use the method copy-on-write of the callframes.
delimited continuation will be supported in the near future toosyntax-rules hygienic macros
custom ellipsis is also supported-1. to test scheme code, please refer to r4rstest.scm, r5rs-tests.scm, aftertest.scm in the project
#include "vm.h"
using namespace Scheme;
use default malloc/free
VM vm;
or use custom malloc/free
static void * myalloc(void *ptr, size_t nsize) {
if (nsize == 0) {
myfree(ptr);
return NULL;
}
else
return myrealloc(ptr, nsize);
}
VM vm(myalloc);
vm.loadfile("filename.scm");
// (lambda (a b) xxx)
static ValueT scm_stub_my_add(VM* vm, ValueT* a, ValueT* b)
{
return scm_make_int(vm, scm_get_int(vm, a) + scm_get_int(vm, b));
}
// (lambda rest xxx)
static ValueT scm_stub_my_sum(VM* vm, ValueT* rest)
{
scm_int t = 0;
ValueT* p = rest;
while (!scm_is_null(vm, p))
{
t += scm_get_int(vm, scm_car(vm, p));
p = scm_cdr(vm, p);
}
return scm_make_int(vm, t);
}
const RegCProc myext[] = {
RegCProc("my-add", scm_stub_my_add), // (lambda (a) xxx)
RegCProc("my-sum", scm_stub_my_sum, true), // (lambda (a . rest) xxx)
RegCProc(NULL, -1)
};
regcfunc(vm, myext);
(my-add 2 3)
(my-sum 1 2 3 4)
ValueT val = vm->evalstr("(+ 1 2)")
int iv = scm_get_int(vm, &val);
// iv = 3
ValueT* argv[] = {xxx};
ValueT val = vm->call("f", argv, n)
Optimization and features are endless
MIT
C++
80.8%
Scheme
16.6%
Tree-sitter Query
2.4%