ImageVerifierCode 换一换
格式:DOCX , 页数:24 ,大小:76.38KB ,
资源ID:17364825      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/17364825.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(程序控制程序设计语言原理文档格式.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

程序控制程序设计语言原理文档格式.docx

1、 GOTO和语句标号把顺序的程序代码切分得七零八落。 编译时只能把它们分成很多可连续执行的程序小块(显然,GOTO语句的前后语句不能在一块)的语句组。这就是模块(Module)一词的来历。对于重复执行的块单给出关键字和截止处语句标号,并引出循环域和嵌套循环的概念。这是模块封闭性的开始:GOTO只能从循环域内转向域外,反之不行。但当时重点还在想出方便的GOTO表示上。单GOTO语句FORTRAN就有五种之多。流程图的发明使得编程思路清晰,而程序代码仅仅是实现流程图的表示工具,它本身的可读性未引起足够重视。随着程序尺寸的增长,脱离了流程图,程序正文越来越难读(见第2章图2-3示例)。即使不太大的程

2、序,几十个GOTO来回穿梭就成了戏称的“乱面条”程序。难读、难调、难修改。但当时人们醉心于精巧的设计。终于酿成60年代初的软件危机。 自从1965年E.Dijkstra提出“GOTO语句是有害的”以来,60年代中叶在西方软件界引起一场争论,因为它动摇了赖以构成巧妙计算转移的根基。既然它有害,那么,首先要回答,不用GOTO行不行?1966年Boehm和Jacopini回答了这个问题:任何流程图的计算逻辑都可以用顺序组、条件选择组、迭代组三种程序结构实现。这三种结构严格一个进口一个出口。也正因为如此可以随意嵌套(将某一对进出口置换成另一结构), 构成极为复杂的程序。用这三种构件块构造程序可完全不用

3、GOTO语句。这就是结构化程序设计的基本思想。程序控制在块一级,块相对封闭,即不许有控制从块的一部分处转移到另一块内。这样程序控制就成了组织顺序、选择、迭代的结构了。 理论探索完成后要回答的第二个问题是用结构化程序代替非结构化程序会有哪些问题? 是否一切都好?事实上,结构化程序结构确有不方便之处,至少是低效。例如,在一计数循环中查找一个数,头几次就找到了,余下空循环不做到底是不能出来的。保留GOTO一跳出来不是更好吗?此外,若想利用某块中的部分代码不能从需用处进入非得从头上进入,这势必要保证不用部分空执行(没有GOTO,就要增加很多不必要的代码)。这就是是否取消GOTO值得争论的原因。最后大家

4、接受了Knuth(1974)对GOTO使用的折衷意见:GOTO是有害的,但有时对改善效率带来好处。可以保留GOTO,但要加以限制使用。只能向前转移,不能向后。GOTO的迹线不能交叉,只能从块内转到块外,不得相反。问题基本解决,争论的双方依然坚持各自信念,所以70年代以后发展起来的语言有保留GOTO的,如Pascal,Ada,C,但不提倡使用。有完全取消GOTO的,如Modula,Adison等等。有的保留GOTO的积极作用限制GOTO的副效应,把它们改头换面变为比较安全的顺序控制器(sequencer),详见后文。 结构化程序除了顺序、条件选择、迭代三种最基本控制而外,子程序调用也是一种重要的

5、控制。虽然在子程序体中依然是三种基本控制结构的复合,子程序调用本身是显式地控制抽象。多次子程序调用和返回,构成程序的深层嵌套。对于非命令式语言,如纯函数式语言, 顺序控制并不十分重要。它控制计算更多的依靠嵌套。7.2 顺序控制 顺序控制在程序结构上是一组可顺序执行的简单语句,如果每一个顺序成分可用一顺序结构置换,顺序结构可形式地表示为: S1; S2 进一步扩展可为: S2; .Sn 其中Si为简单语句(命令)。一般过程语言有哪些简单语句呢?我们用最丰富的Ada简单语句作解释。 简单_语句:=空_语句 |赋值_语句 | 过程调用_语句 |goto_语句 | 入口调用_语句 |出口_语句 | 返

6、回_语句 |引发_语句 | 夭折_语句 |延迟_语句 | 代码_语句其中空_语句,赋值_语句,代码_语句不影响控制和转移,代码语句是某些信息要用机器(或汇编)码。延迟语句为控制同步,指定在原地停留的时间,但无控制转移。 连续的赋值是最基本的运算。goto语句已如前述,可以往前、往后跳过任意行代码。当然它和语句标号要配合。标号的表示法各语言不一,有用数字,有用字符串的。Ada用。 exit(出口)语句,raise(引发)语句,abort(夭折)语句,都是顺序控制符。 exit将程序控制跳到所在块的末端,或由它指明的外嵌套块的末端。C语言中与其相当的是break。 raise是引发异常。当程序执行

7、到此句(一般是程序员预感要出异常设在此处)时,跳到有exception关键字处执行异常处理段(一般在本程序块末尾),且不返回。异常引发规则比较复杂,详见本章7.5节。 abort是强行夭折即就地停止,有的语言是HALT命令。这类就地停止和暂停命令在FORTRAN早已有过。FORTRAN的STOP和END分工是一为执行停止,一为代码结束。由于它把程序正文表示和执行逻辑分开。任设STOP为多出口。与结构化宗旨有悖,在以后的版本中取消了。FORTRAN的PAUSE为暂停语句,它中止程序执行,以便程序员中途作些调整,调试程序,而且必须重按回车才能恢复运行。这些早期单机单用户,惜机时如金时代的便于调试的

8、语句,以后都取消了。完全可以设“断点”,追踪排错解决。恢复abort和HALT是新一轮并发程序和增加了异常处理后的要求。强行终止程序执行一般是信息不足,事先考虑的异常处理段不足以处理已发生的异常。而进一步运行又无意义,只好终止程序的执行。一般终止前应将当前信息尽可能收集、显示出来,以便调试员分析。 入口调用和子程序调用相似,前者是专用于并发程序的任务调用。也要作参数匹配。每当执行到此句,一个任务被激活,任务体开始执行。它对程序控制转移到另一程序单元作用是一样的。 同样,return是显式指明执行到此返回至调用点。因为返回是同一点,多个return一般都是允许的(违反一出口的规定吗?)。早期子程

9、序过程必有return,而现代语言则不一定(为什么)? 程序总是按程序正文自上至下,自左至右地(隐含)顺序执行的。表达式求值规则和顺序控制器是对这个隐含执行的“修正”,从而达到控制计算的目的。7.3 条件选择控制 计算机“聪明”最基本的基础是会根据条件选择它应执行的代码。所有的程序设计语言都离不开条件控制。7.3.1 结构式条件控制 简单的条件语句IF(e),根据逻辑表达式的真假值在程序中产生分枝。它本来就是想做if. then.else计算逻辑的。不过早期语言用的IF(e)是语句级的,这种程序语言编的程序不仅不宜于阅读,且T-部分和F-部分得不到保护,甚至它有多大都没有明确界线,其它地方的g

10、oto可随意进入,程序极易出错,Algol-60正式把它看作复合语句,那么,这两部分代码叫T-子句和F-子句。子句以语句结束符终止没有其它标记。 if语句的退化型是if_then,正规型是if_then_else,T-子句和F-子句可以是任何语句组。嵌套if一开始就发现了问题,在Algol60草案讨论中,就发现了悬挂else问题。例如, 当有if嵌套时,有: if E1 then if E2 then S1 else S2它可以解释为: (E1=true)(E2=false) 执行S2,else属于内部if,也可以解释为: (E1=false) 执行S2,else属于外部if即不管E1为真假S

11、2均可能执行。原因是可以画成多个语法树,它有二义性。 解决这个问题是很容易的,加上语句括号DO_END(PL/1),BEGIN_END(Pascal)就可以: if E1 then begin if E2 then S1 else S2 end if E1 then begin if E2 then S1 end else S2 它的简化形式(FORTRAN-77, Ada)是: if E1 then if E2 then S1 endif else S2 endif if E1 then if E2 then S1 else S2 endif endif 就近匹配语句括号既使语义清晰又可以封

12、闭块,所以,Pascal,C的程序员要指明块时(两个语句以上),都要用语句括号begin_end或 。 既然不要goto,早期的流程图也可以结构化。与此对应的选择结构有nassi_Schneiderman式流程图。每个语句和复合语句都是块连接,如图7-2所示。块中分成T-,F-子句分别画成T-域和F-域。可随意嵌套(将-S块又扩充为选择结构)。7.3.2 case和switch 在图7-2所示结构选择中是连续嵌套的选择结构对应的程序结构是: IF exp1 THEN IF exp1 THEN ST1 ST1 ELSEIF exp2 THEN ELSE ST2 IF exp2 THEN ELSE

13、IF exp. ST2 . ELSE IF exp . ELSE ELSE SF3 SF3 ENDIF ENDIF左右两表示法语义是一样的,但左边出了新关键字ELSEIF。这是在FORTRAN-IV到FORTRAN-77结构化改版时增加的,增加后显得自然方便,只是在“都不”满足条件时执行最后一个ELSE。 不用费心记对应是那一层。ELSEIF在Ada中更成为可区分的elsif,和else if是两种表示。嵌套IF结构的执行,永远是执行一组代码就跳到endif。对于不同条件, if_then_elseif.else结构方便,清晰。然而,对于同一条件表达式而多次判断其值的嵌套IF结构,这种表示显得

14、累赘,且多次错缩进编排,程序反倒歪斜。于是多数结构化语言提供case选择。两种语言的分情况语句的表示示例如下: case Exp is switch (exp) when v1= case v1: when v2= break; . case v2: when vm|vn=Sn; when others = St; default: end case; Ada 的case语句 C的switch语句这两种表示法略有差异,大体一致。Ada的Exp不限于真值表达式(只两种情况),可以是任何离散类型表达式(C限于整数)。根据取值Vi的情况跳到对应的case标号那个子句Si执行。Ada是执行完子句跳到e

15、nd case,而C若无break则不跳,接连执行下句.C语言设计者认为会对组合分枝带来方便,但这种过分灵活性,实际上是设计缺陷。others和default选择都是在取值超出了case标号的值域时执行。Pascal类似Ada,但无others选择。7.3.3 以条件表达式实现选择控制 函数式语言没有语句,只有表达式,选择控制只能由条件表达式完成。C语言是面向表达式语言,它有条件表达式,且编译处理最小单位也不限于语句。例如,C语言语句行中可以出现: +x; x+;这种无赋值号的表达式。它还有 ? : 双目运算符表示的表达式,例7-1示出条件表达式和条件语句差别。例7-1 将b,c中小值存入a

16、(C语言) a=bc ? b:c if (bnext) sum += current -value; /循环控制变量current就用表list 2 sum在循环内赋初值: for (current=list, sum=0; current != NULL; current =current - next) sum += current-value 3 循环控制变量可以在for以外赋初值,增量在体内赋值: current = list, sum=0; for ( ; )value, current = current-next; /用,号连接的两语句成为一个命令表达式 4 循环条件为空,用条件

17、表达式完成: current = list, sum = 0; for(; ; if (current = NULL) break; else sum += current-value, current- /不提倡此种风格 5 完全不用循环体,全部在循环条件中完成 for (current = List, sum = 0;(current = current-next)!value); /效率最高. 但list不能为NULL表 6 逻辑混乱,也能正确计算: for (; current = current-value) /最坏的风格,list也不能为NULL表 这个例子说明语言的语法规则的灵活

18、性,C语言的哲学是只要不给实现带来过多开销,尽量灵活,不管程序员如何写,说得过去就行,例如,4中的if的T-子句是语句,F-子句是表达式,整个既是命令表达式也是条件命令。这种过多的灵活性也带来排错调试的困难。7.4.1 显式迭代控制 控制迭代可以在一段循环代码开始处设条件,也可以在执行一次后设条件,决定是否重复。也可以规定次数,虽然都可以用最基本的while_do仿真。 但各有特点,语言选用也不完全一致。(1) 无限循环在顺序式命令语言中无限循环被认为是死循环,早期语言均没有,对于并发程序,为了随时接受另一进程发来的信息,它要处于活动的运行状态,就必须用无限循环。以下是Ada的无限循环及其对应

19、的结构图: 名字name是可选的,有的语言用关键字BEGIN_REPEAT(FORTH83)表示,C语言用空记数f(;)B;当然,进去出不来无限运行下去是不可接受的。这就要在循环体内设exit命令跳出(或调用另一子程序或任务,在另一程序块中终止)。(2) 有限循环 满足某个条件不再迭代,其迭代次数是有限的。 如果先测试条件再进入循环体叫当循环(while_do),形式如下(Ada),在无限循环体之上加while子句:条件表达式为真执行循环体。 如果先执行循环体再测试条件叫直到循环(do_until),形式如下(Pascal);在无限循环体之下加until子句:条件表达式为假再次执行循环体。这种

20、循环的缺点是条件不完全或条件已满足至少要执行一次。所以是条件比较清楚时用它。 两种循环中条件表达式的变量,或进入循环被加工数据的初始化可以在循环体或子句内完成,也可以在循环外完成。一般说来,这两种循环的次数难以预知,以满足条件为准。 这两种循环实质是一种,故有些语言只有while_do,没有do_until,每当需用do_until时,可用以下等价形式: REPEAT B; B: = while TEXP loop UNTIL Exp B; end loop; 通用有限循环(general loop) 如果循环控制条件可以设在循环的任意位置(即通用),它相当于while_do和do_until

21、的功能复合。结构化理论叫它do_while_do,其形式是(FORTH): 这种结构最方便,若B1,Exp2为空,即while_do。若Exp1为空,即do_until。多数结构化语言没有专门的通用循环,但提供的其它机制可以实现,如下例:例7-3 将屏幕上输入的数求和以便打印(Ada),约定当输入负数时停止。 function READ_ADD return Integer is N:Integer; SUM: Integer:=0; loop WRITE_PROMPT (Please enter a number and type a CR);=GET_NUMBER; exit when N

22、 =SUM+N; end loop; return SUM; end READ _ADD;(3) 计数循环 如果已知数据结构的长度,将while子句的条件表达式量化,即给循环控制变量以初值、终值、增量,当控制变量中的值达到终值即出循环。这种循环叫计数循环(counted loop)。它是效率最高的循环,也是程序设计语言最早采用的循环(FORTRAN): DO L I=EXP1, EXP2, EXP3其中I是事先声明的控制变量,整数类型,三个表达式是在此刻能求出值的整表达式。用EXP1赋初值后进入循环,执行完循环体检查是否超出EXP2。若未超出,则增量EXP3后执行,否则出循环。以后陆续研制的语

23、言与此大同小异,主要是在循环控制变量和表达式约定上不同。几十年来一直在演变。 循环控制变量,最初限于非负整数,相应表达式也是整数类型。FORTRAN曾经有过许可实数表达式,但未推广。Ada容许所有表达式均为离散类型(整、真值、字符、枚举)。 控制变量声明,早期是全局静态变量,如从循环中跳出,控制变量值仍可引用,但如果正常出口该值总要大于或等于终值。而终值本身在不同语言中也是可变的(PL/1,COBOL可在循环体内改变表达式EXP2的值,FORTRAN不可)。这样就难于控制了。所以,现代语言 即使是静态变量出了循环也不能引用,Pascal的循环控制变量规定了局部于子程序,并明文规定,循环内不得改

24、变终值和增量表达式的值。虽然出了循环该值仍存在(局部变量),但使用无效。Ada更进一步,循环控制变量仅限于该循环,事先不用声明,给变量定义的取值范围自动作了声明,也不能在循环体内改变取值范围大小,且出了循环无效(编译可查出)。 关于增量表达式,在仅限于正整数的语言中,缺省为+1,Alogl60和Pascal容许递减, 可以是负整数。Ada的增量随类型,它只有正序和逆(reverse)序,如:例7-4 Ada的for循环 for I in reverse 1. N loop -I自动为整型,=N , N-1 , . , 1 for TODAY in DAY range MON. FRI loop

25、 -TODAY 自动为DAY(枚举)类型并取子域MON.FRI, - 其增量按DAY中定义顺序一一枚举 for BACKDAY in reverse DAY RANGE loop -按枚举类型DAY的逆序,即SUN, SAT, FRI, . , MON -DAY RANGE是属性表达式, 意即DAY类型的值域 还有一个要说明的问题,是表达式EXP2在顶部求值还是在底部求值? EXP1在顶部或外部,EXP3在底部求值这都没有问题。早期FORTRAN的EXP2在底部求值,以后FORTRAN-77改为顶部,这样一开始条件不满足就不要进入循环。(4)迭代元素 1963年美国Galler和Fischer对FOR循环提出迭代元素(Iteration element)概念,以后C语言的发明人D.Rit

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1