多层返回的概念假定了被调用方知道调用方期的是什么,并且能返回一个适当的值。还存在一种情况,其中深层嵌套的子程序中发生了一些情况,导致无法继续执行下去,而且因为没有足够的环境信息,甚至无法合适的结束自己的工作,这种情况下,唯一能做的就是”退回去“,一直回退到能够恢复执行的地方,这种要求程序退回去的条件通常称为叫做”异常“。常见的结构化的异常处理和多层返回有很大的相似性,两者都需要从某一个内层上下文回退到外层的上下文。具体的差异则是多层返回是内层的上下文正常的完成计算然后根据需要返回正确的值,然后转移到外层上下文,并不需要后续处理。而异常中的内层上下文已经是无法进行正常的计算,必须以一种非正常的退出一直回卷,然后触发某个特殊的处理流程直到catch到它。
继续
如果进一步推广上一小节中造成栈回卷的非局部goto概念,则可以定义一种称为继续(Continuations)的概念。从底层来看,一个继续是由一个代码地址与其关联的一个引用环境组成的,如果跳转到这个地址,就该恢复这个引用环境。从抽象层面看,它描述一个可能由此继续下去的执行上下文。在Scheme和Ruby中,继续是基本的一等公民,我们可以利用这种机制有效的扩充流程控制结构集合。
Scheme中支持继续由一个通常称为call-with-current-continuation的函数实现,有时简称"call/cc"。该函数有一个参数f,f也是一个函数;"call/cc"调用函数f,把一个记录着当前程序计数器和引用环境的“继续(暂时称为是c)c”传递给f,这种"继续c"由一个闭包来表示(通过参数传递的子程序的表示的闭包并无不同)。在将来任何时候,f都可以调用c,然后可以用c来重新建立其保存的上下文。一般的应用情况是我们把这个c赋值给一个变量,则可重复的调用它,甚至我们可以在f中返回它,即使f已经执行完毕,仍然可以调用c。
顺序执行 选择现在大部分命令式语言中采用的选择语句,都是从Algol 60引进过的 if...then...else 的某种演进变形:
if condition then statement else if condition then statement else if condition then statement ... else statement 短路条件虽然 if...then...else 语句的条件是一个布尔表达式,但是通常没有必要求出这个表达式的值放入寄存器。大部分机器都提供了条件分支指令(如上面提到的IL指令brtrue.s),因为这个表达式求值的目的并不是为了值,而是为了跳转到合适的位置。这种看法使得可以对短路求值的表达式生成高效的代码(称为跳转码)。跳转码不但可以用于选择语句,也可用在“逻辑控制的循环”中。如下面代码:
if((A>B)&&(C<D)||(E!=F)){ then_clause } else{ else_clause }在不使用短路求值的Pascal中,生成的代码大致如下(它会计算每个表达式的结果并放入寄存器r1...,然后再决定跳转):
r1=A r2=B r1=r1>r2 r2=C r3=D r2=r2>r3 r1=r1&r2 r2=E r3=F r2=r2!=r3 r1=r1|r2 if r1=0 goto L2 L1: then_clause goto L3 L2: else_clause L3:跳转码的情况于此不同,它不会把表达式的值存入寄存器,而是直接跳转(只用到了r1和r2两个寄存器,明显也不会针对整个表达式进行求值,比上面的要高效一些):
r1=A r2=B if r1<=r2 goto L4 r1=C r2=D if r1>r2 goto L1 L4: r1=E r2=F if r1=r2 goto L2 L1: then_clause goto L3 L2: else_clause L3: case/switch语句对于if else结构来说,如果嵌套的层数过多、或者是用于判断的条件表达式是基于一些有限的简单值(或编译时常量),那么出现了一种更为优雅的语法结构“case语句”,有很多ifelse都可以很轻松的改写成case/switch语句
对于case/switch的优势还不只是语法上的优雅,有时还可以生成更高效的代码
T: &L1 &L2 &L3 &L4 &L5 &L6 L1: clause_A goto L7 L2: clause_B goto L7 L3: clause_C goto L7 L4: clause_D goto L7 L5: clause_E goto L7 L6: clause_F goto L7 L7:这样其实T就是一个地址跳转表
迭代