解释执行含有goto语句的语法树是相当麻烦的。
当遇到goto节点时,要抛出goto的目标节点。然后逐级向语法树上游回溯,每回溯一层,又要向下扫描这一层除抛出goto的节点以外的语句。如果找到目标节点,则清除这个label,从这个点恢复执行语法树。否则继续抛出goto。这里还有两种情况,因为下层的语句有可能已经执行过了,然而在执行过程中又抛出了goto。所以还需判断返回的goto是否和传入的goto相同。如果不同,那么前面被排除的抛出goto的分支再排除已经是不对的了,要重新加回去扫描。
在搜寻goto 目标时,所有的语句都“不执行”。不管是条件语句,循环语句,还是复合语句,都被同样的对待。这时,条件控制逻辑不起作用。直到回溯返回值告知goto已经被解除时,才从当前层下一条语句恢复解释执行。当然这是恢复语法树的下一条语句,而不是解释程序的下一条语句。
如此,解释程序的这部分代码是非常复杂的。里面充满了平时难以得见的奇怪的goto语句,如果想用结构化语句来表达会很难很难,对绝大多数程序员来说,这基本上是妄想。所以简单的说一句“我不用goto语句”,真的很无知,只能说明“我”从来没有做过复杂一点的东西。
相应的代码看起来是这样的:
struct node *execute_e_ls(struct node *s, struct node *label, int *exception)
{
int i;
struct node *res;
struct node *disable;
struct exprval val;
if (!s) return NULL;
disable = NULL;
if (s == label) {
label = NULL;
}
if (label) goto locate_label;
switch(s->node_type) {
case NT_EMPTYS:
return NULL;
case NT_AS:
e_eval(s->left,exception); EXCEPTION_CHK;
return NULL;
case NT_PS:
do_e_print_op(s->left, exception); EXCEPTION_CHK;
printf("\n");
return NULL;
case NT_IFS:
restart_ifs:
val = e_eval(s->left,exception); EXCEPTION_CHK;
if (val.u.value) {
res = execute_e_ls(s->medium, 0,exception);
EXCEPTION_CHK;
if (res==&throw_goto && throw_goto.medium==s) {
goto restart_ifs;
}
return res;
}
return NULL;
case NT_IFSES:
restart_ifses:
val = e_eval(s->left,exception); EXCEPTION_CHK;
if (val.u.value) {
res = execute_e_ls(s->medium, 0,exception);
EXCEPTION_CHK;
if (res==&throw_goto) {
if (throw_goto.medium==s) {
goto restart_ifses;
}
label = throw_goto.medium;
disable = s->medium;
goto locate_ifses2;
}
}
else {
res = execute_e_ls(s->right, 0,exception);
EXCEPTION_CHK;
if (res==&throw_goto) {
if (throw_goto.medium==s) {
goto restart_ifses;
}
label = throw_goto.medium;
disable = s->right;
goto locate_ifses1;
}
}
return res;
case NT_WS:
restart_ws:
val = e_eval(s->left,exception); EXCEPTION_CHK;
while (val.u.value) {
res = execute_e_ls(s->medium, 0,exception);
EXCEPTION_CHK;
enable_ws:
if (res == &node_return) {
return res;
}
if (res == &node_break) {
break;
}
if (res == &throw_goto) {
if (throw_goto.medium==s) {
goto restart_ws;
}
return res;
}
val = e_eval(s->left,exception); EXCEPTION_CHK;
}
return NULL;
case NT_FS:
restart_fs:
if(s->left->left) {
e_eval(s->left->left,exception); EXCEPTION_CHK;
}
val = e_eval(s->left->medium,exception); EXCEPTION_CHK;
while (val.u.value!=0) {
res = execute_e_ls(s->medium, 0,exception);
EXCEPTION_CHK;
enable_fs:
if (res == &node_return) {
return res;
}
if (res == &node_break) {
break;
}
if (res == &throw_goto) {
if (throw_goto.medium==s) {
goto restart_fs;
}
return res;
}
if(s->left->right) {
e_eval(s->left->right,exception); EXCEPTION_CHK;
}
val = e_eval(s->left->medium,exception); EXCEPTION_CHK;
}
return NULL;
case NT_CSS:
restart_css:
if (s->left) {
res = execute_e_ls(s->left, 0,exception);
EXCEPTION_CHK;
if (res == &throw_goto) {
if (throw_goto.medium==s) {
goto restart_css;
}
label= throw_goto.medium;
disable = s->left;
goto locate_css2;
}
if (res !=NULL) {
return res;
}
}
enable_css:
res = execute_e_ls(s->medium, 0,exception);
EXCEPTION_CHK;
if (res == &throw_goto) {
if (throw_goto.medium==s) {
goto restart_css;
}
label= throw_goto.medium;
disable = s->medium;
goto locate_css1;
}
return res;
case NT_BS_BRK:
return &node_break;
case NT_BS_CONT:
return &node_continue;
case NT_BS_RET:
val = e_eval(s->left,exception); EXCEPTION_CHK;
stk->e[top].ret = val;
return &node_return;
case NT_INITVS:
i = (int) s->left;
e_initv(i, s->right, exception); EXCEPTION_CHK;
return NULL;
case NT_GOTO:
i = (int) s->left;
throw_goto.medium = stk->e[top].func->labeltab[i];
if (throw_goto.medium== s) {
printf("dead loop\n");
*exception=1; goto exception_out;
}
return &throw_goto;
}
locate_label:
switch (s->node_type) {
case NT_IFS:
res = execute_e_ls(s->medium, label,exception);
EXCEPTION_CHK;
if (res == &throw_goto &&throw_goto.medium==s) {
label = NULL;
goto restart_ifs;
}
return res;
case NT_IFSES:
locate_ifses1:
res = execute_e_ls(s->medium, label,exception);
EXCEPTION_CHK;
if (res == &throw_goto &&throw_goto.medium==s) {
label = NULL;
goto restart_ifses;
}
locate_ifses2:
if (res == &throw_goto && throw_goto.medium != label) {
label = throw_goto.medium;
disable = s->medium;
}
if (res == &throw_goto &&s->right!=disable) {
res = execute_e_ls(s->right, label,exception);
EXCEPTION_CHK;
if (res == &throw_goto) {
if (throw_goto.medium==s) {
label = NULL;
goto restart_ifses;
}
if (throw_goto.medium != label) {
label = throw_goto.medium;
disable = s->right;
goto locate_ifses1;
}
}
}
return res;
case NT_WS:
res = execute_e_ls(s->medium, label,exception);
EXCEPTION_CHK;
if (res!= &throw_goto) {
label == NULL;
goto enable_ws;
}
else if (throw_goto.medium==s) {
label == NULL;
goto restart_ws;
}
return res;
case NT_FS:
res = execute_e_ls(s->medium, label,exception);
EXCEPTION_CHK;
if (res!= &throw_goto) {
label == NULL;
goto enable_fs;
}
else if (throw_goto.medium==s) {
label == NULL;
goto restart_fs;
}
return res;
case NT_CSS:
locate_css1:
if (s->left) {
res = execute_e_ls(s->left, label,exception);
EXCEPTION_CHK;
if (res == &throw_goto) {
if (throw_goto.medium==s) {
label == NULL;
goto restart_css;
}
if (throw_goto.medium != label) {
label = throw_goto.medium;
disable = s->left;
}
}
else if (res==NULL) {
label = NULL;
goto enable_css;
}
else return res;
}
locate_css2:
if (s->medium != disable) {
res = execute_e_ls(s->medium, label,exception);
EXCEPTION_CHK;
if (res == &throw_goto) {
if (throw_goto.medium==s) {
label == NULL;
goto restart_css;
}
if (throw_goto.medium != label) {
label = throw_goto.medium;
disable = s->medium;
goto locate_css1;
}
}
}
return res;
default:
return &throw_goto;
}
exception_out:
return NULL;
}