Well, that depends a lot on how you implement your execution engine. If you follow Rudiโs proposal to implement a execution mechanism with functions that recursively call each other to pass AST, then to implement break or return you need to return through several levels of the C call stack. You can do this with setjmp / longjmp. For example, your code might look something like this:
struct ExecEnviron { jmp_buf *break_context; jmp_buf *return_context; }; void ExecWhile(ExecEnviron *e, AstElement *a) { jmp_buf local, *old = e->break_context; e->break_context = &local; if (setjmp(&local) != 1) while (dispatchExpression(a->whileStmt.cond)) dispatchStatement(a->whileStmt.body); e->break_context = old; } void ExecBreak((ExecEnviron *e, AstElement *a) { longjmp(e->break_context, 1); } void ExecContinue((ExecEnviron *e, AstElement *a) { longjmp(e->break_context, 2); }
Setjmp / longjmp works well enough to split OUT the nested context, but will not work for general processing of / goto tags (since they allow you to jump INTO in the middle of the loop). If you want to deal with this, you will have to use a completely different execution mechanism and convert the AST to something more linear, like a bytecode or a threaded code.
source share