好吧,这在很大程度上取决于您如何实现执行引擎。如果你按照 Rudi 的建议,用递归调用对方遍历 AST 的函数来实现执行引擎,那么要实现一个break
or return
,你需要通过几级 C 调用堆栈返回。您可以使用 setjmp/longjmp 执行此操作。例如,您的代码可能类似于:
struct ExecEnviron {
/* other contents of ExecEnviron, we're just adding a bit */
jmp_buf *break_context; /* where a 'break' or 'continue' should jump to */
jmp_buf *return_context; /* where a 'return' should jump to */
};
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 可以很好地打破嵌套上下文,但不适用于一般的标签/goto 处理(因为它们允许跳转到循环的中间)。如果你想处理这个问题,你将不得不使用一个完全不同的执行引擎,并将 AST 转换成更线性的东西,比如字节码或线程代码。