第三章 控制结构
第一节 语句级控制结构
?控制结构,程序员用来规定程序各个成分
的执行流程的控制部分 。
?语句级控制结构,语言用来构造各种语句
执行顺序的机制 。
?传统语言的三种语句级控制结构,顺序,
选择, 重复 。
一, 顺序
?顺序运算符;
?语句括号 begin,,, end
?复合语句
二, 选择
1,if语句
① ALGOL 60的选择结构引起二义性
if x>0 then if x<10 then x:=0 else x:=1000
② PL/1和 Pascal的“最近匹配原则”
③ ALGOL 68中 if语句的结束符号 fi
④ ALGOL 68和 Ada对 else if 进行缩写
2,多重选择
① PL/1的 select结构
SELECT,
WHEN(A)S1;
WHEN(B)S2;
WHEN(C)S3;
OTHERWISE S4;
END
② 多种语言的 case语句
var operator:char;
operand1,operand2,result:boolean;
……
case operator of
‘.’:result:=operand1 and operand2;
‘+’:result:=operand1 or operand2;
‘=’:result:=operand1 = operand2;
end
③ Dijkestra选择结构的非确定性
if B1→S 1
? B2 →S 2
? B3 →S 3
…,.,
? BN →SN
其中, Bi是布尔表达式, 称为卫哨 。 若有
多个卫哨为真时执行任一 Si。
三, 重复
1,计数器制导
当预先知道重复次数时,在循环计数器值的有
限集合上重复 。
① FORTRAN的 DO循环中,用标号控制循环体
DO 7 I=1,10
A( I) =0
B( I) =0
7 CONTINUE
② Pascal的 for 语句
?计数重复的值可在任何有序集上
? for,,, to
? for,,, downto
?在循环外循环控制变量的值无定义
2,条件制导
① while 循环:描述 0或任意多次的重复
② repeat until循环:至少一次以上的重复
③ ALGOL 68循环的一般形式,
for i from j by k to m while b do...od
④ Ada 的循环结构
loop /*可以在 loop前加重复说明 */
循环体 (语句序列 )
end loop;
?重复说明可以是,
while <条件 >
或 for <计数变量 > in <离散范围 >
或 for <计数变量 > in reverse <离散范围 >
?可由 exit或 exit when<条件 >终止循环
⑤ Dijkstra的卫哨命令表示法
do B1→S 1
? B2→S 2
,,,,,,
? BN→SN
od
四, 语句级控制结构讨论
?顺序, 选择, 重复是一定意义的抽象
?关于 goto语句的讨论
?控制结构的选择
五, 用户定义控制结构
如,Pascal的计数控制变量可以是枚举
类型
第二节 单元级控制结构
?单元级控制结构,规定程序单元之间控制
流程的机制
?四种单元级控制结构,显式调用,异常处
理,协同程序,并发单元
一, 显式调用从属单元
1.调用方式
由调用语句使用被调用单元的名字来
进行调用
2,参数的两种绑定方式
位臵绑定
关键字绑定
subprogram S(F1,F2,…,FN);
……
end
?位置绑定, call S(A1,A2,…,AN)
call S(A1,,A3,,,,,A8,,A10)
?关键字绑定,
call S(A1=>F1,A3=>F3,A8=>F8,A10=>F10)
3,副作用
? 对非局部环境的修改
① 副作用降低了程序的可读性
② 副作用限制了数学运算律的使用
如,w:=x+f(x,y)+z
③ 副作用影响目标代码的优化
如,u:=x+z+f(x,y)+f(x,y)+x+z
x,y为变参
z为全局变量
4.别名
? 在单元激活期间,两个变量表示 (共享 )同一
数据对象
① FORTRAN的 EQUIVALENCE语句
② Pascal的变参使得形参和实参共享同一数
据对象
procedure swap(var x,y:integer);
begin
x:=x+y;
y:=x-y;
x:=x-y;
end;
调用
swap(a,a);
swap(b[i],b[j]); 若 i=j
swap(p?,q?); 若 p,q指向同一数据对象
③ 变参和全局变量表示同一数据对象时,也
会引起别名
procedure swap(var x:integer); /*a是全局变量 */
begin
x:=x+a;
a:=x-a;
x:=x-a;
end;
调用
swap(a); 将产生不正确的结果
④ 别名也影响编译器生成优化的代码
a:=(x-y*z)+w
b:=(x-y*z)+u
⑤ 别名的消除
,废除可能引起别名的结构
,限制使用指针、变参、全局变量、数组等
二, 隐式调用单元 ? 异常处理
异常是指导致程序正常执行中止的事件,
要靠发信号来引发,用异常条件来表示。
有关异常处理的主要问题,
( 1)异常如何 说明,它的作用域是什么?
( 2)异常如何 发生 (或如何发信号)?
( 3)发出异常信号时,如何规定要执行的单元
(异常 处理 程序)?
( 4)发出异常时,如何 绑定 相应的异常处理程
序?
( 5)处理异常之后,控制 流程 转向何处?
1,PL/1异常处理
① 异常的说明
ON <条件 > <异常处理程序 >
② 异常的引发
SIGNAL<条件 >
③ 语言预定义了一些异常,
如 ZERODIVIDE
④ 异常名可多次说明,以最新一个为准
ON ZERODIVIDE BEGIN
……
END
⑤ 可用, NO <异常名 >”限定异常的范围
(NO ZERODIVIDE),BEGIN
……
END
2,CLU的异常处理
① 处理方法
,当过程 P引发一个异常时,只能将其信号
传送给调用 P的过程 。 这样做的目的使程
序有良好的结构, 但在表达力方面要弱一
些 。
,发信号的过程被终止,而不再恢复 。
② 过程内可以发信号的那些异常必须在过
程头加以说明
coca_cola=proc(a:int,s:string) returns(int)
signals (zero(int),overflow,had_format(string))
③ 异常处理程序静态绑定于调用者
<语句 > except<处理程序表 >end
其中, <处理程序表 >的形式是
when <异常表 1>,<语句 1>
……
when<异常表 n>,<语句 n>
3,Ada的异常处理
① 异常的说明类似于变量的类型说明
PECULIAR,BUFFER_FULL,ERROR:exception;
② 程序单元可以显式引发异常
raise <异常名 >;
③ 异常处理程序紧跟在子程序、程序包或
分程序之后
begin …;
exception when HELP=>…;
when DESPERATE=>…;
end;
④ 若引发异常的单元为异常提供处理程序,
控制将直接转移到那个处理程序,一旦处理程
序执行完后,引发异常的单元也终止
⑤ 若当前执行的单元 U并未提供相应的异常
处理程序,异常将被 传播, 若 U是一个分程序,那
么终止 U的执行,并在包围 U的单元内隐式引发
这个异常 ; 若 U是一个程序包体,那么异常 传播
给包含这个程序包说明的单元