This is from the hip and probably dragon-infested, but it looks legal:
int thread[] = {
1, 2, 3, n, 0
}; /* thread of instructions */
int *ip = thread; /* initialize instruction pointer */
jmp_buf buf[0xff]; /* 0x00..0xff bytecode operations */
jmp_buf top; /* top-level interpreter */
if (setjmp(buf[0x00])) {
/* example uses op 0x00 as terminator, so this should never be executed */
longjmp(top, 1); /* optionally, use second parameter to raise exceptions */
}
if (setjmp(buf[0x01])) {
/* do op 0x01, manipulate ip (also the stack) as needed */
longjmp(top, 1); /* optionally, use second parameter to raise exceptions */
}
if (setjmp(buf[0x02])) {
/* do op 0x02, manipulate ip (also the stack) as needed */
longjmp(top, 1); /* optionally, use second parameter to raise exceptions */
}
if (setjmp(buf[n])) {
/* do op n, manipulate ip (also the stack) as needed */
longjmp(top, 1); /* optionally, use second parameter to raise exceptions */
}
while (*ip) {
if (!setjmp(top)) {
longjmp(buf[*ip++], 1);
}
else {
/* process exception */
}
}
The overhead of setjmp/longjmp is system specific but probably less than a function call.