1.8 练习
Exercises
1.1 计算机程序里的错误可以按照下面情况进行分类:什么时候检查它们;还有,如果一些错误是在编译中检查的,那么是编译程序的哪个部分检查它们。请针对你最喜爱的命令式程序设计语言,给出下面的例子:
(a) 一个词法错误,由扫描器检查;
(b) 一个语法错误,由语法分析器检查;
(c) 一个静态语义错误,由语义分析器检查;
(d) 一个动态语义错误,由编译器生成的代码检查;
(e) 一个这样的错误,编译器既不能捕捉到,也很难生成代码去捕捉(这种问题应该是违反了语言的定义,并不是一个简单的程序错)。
1.2 类Algol语言通常都是编译的,而类Lisp语言由于其中有许多问题在运行之前无法确定,通常都是解释的。难道解释简单的就是在编译无力去做的时候“不得不做”的事情吗?还是即使有编译器可以使用,去解释一个语言也存在一些实际的优势?
1.3 例1.17的gcd程序也可以写成下面的样子:

这个程序能计算出同样的结果吗?如果不能,你能把它改好吗?在什么环境中,你可以预期其中的某一个比另一个速度更快?
1.4 在你所用的C语言实现里,整数的大小限制是什么?如果出现算术溢出会发生什么事情?在把程序移植到另一机器/平台时,这种大小限制会造成什么影响?在Java里对这些问题的回答有什么不同吗?对于Ada呢?对于Pascal呢?对于Scheme呢?(你可能需要去查阅它们的手册。)
1.5 Unix的make功能使程序员可以清楚地描述一个程序的各个分别编译的片段之间的依赖关系。如果文件A依赖于文件B,而文件B修改了,make就会推断出A必须重新编译,因为B的任何改变都可能影响到A生成出的代码。这种依赖性管理的精确度如何?在什么情景中它会导致一些不必要的工作?在什么情景中它可能没有去重新编译某些应该重新编译的东西?
1.6 为什么确定一个程序是否正确是非常困难的事情?当需要找出代码里的错误时,你是怎样去做的?测试能够发现的是哪类程序错误?哪类程序错误无法发现?(有关程序正确性的更形式化的记法,见第4章最后有关参考文献的介绍。)






