《程序设计语言——实践之路》前言

来源:互联网 发布:福建水利概预算软件 编辑:程序博客网 时间:2024/04/19 15:05
关于计算机程序设计的课程给了普通学生有关计算机领域的第一个印象。大多数学生在这样的课程之前对于计算机已经有了一些接触,例如以计算机游戏或者其他个人应用的形式,在他们还没有写出自己的程序之前,就已经开始意识到这些应用的工作方式了。在获得了作为程序员的一定能力之后(假定已经学过很好的有关数据结构和算法的课程),很自然的下一步就是想知道程序设计语言是如何工作的。本书将对此提供一个解释。
  在常规的有关“系统”的教学计划里,数据结构(或者再加上计算机组织)之后的内容被分门别类归入属于一些子领域的一批课程,如程序设计语言、编译、计算机体系结构、操作系统、数据库管理系统,可能还有软件工程、图形学或者用户界面系统。这种安排方式存在一个缺点:有关计算机科学的最有趣的东西,许多都处于这些子领域的边界上。例如,RISC革命推动了计算机体系结构和编译器构造之间的结盟,微内核的出现使得操作系统和语言运行库之间的界限变得模糊起来,基于Java的系统以类似形式模糊了编译器和运行库之间的分野。超级计算机里功能强大的存储器系统正在重新定义操作系统、编译器和硬件之间的相对作用。而程序设计语言的设计也始终受到实现问题的重要影响。越来越多的教育工作者和研究者逐渐认识到关注这些相互关系的重要性。
  分门别类的教学计划的另一个问题是提供的课程太多,本科学生没有足够时间去学完它们。如果一个学生希望在理论、人工智能、数值方法或者其他独立领域里打下坚实的基础,那么就可能没时间去上5门系统方面的高级课程。我的认识是,与给予学生对两个或者三个子领域的深入讨论相比,集中提供一些横跨这些子领域的最基本材料可能更有意义。
  《程序设计语言——实践之路》一书的核心,就是讨论程序设计语言如何工作的问题。从某种角度看,它是程序设计语言和编译的传统教科书的混合,再加上一些有关汇编层体系结构的材料,以满足那些没有学过计算机组织的学生的需要。它不是综述性的语言教科书,其中没有列举许多不同语言的细节,而是集中关注学生们可能遇到的作为所有语言之基础的一批概念,并通过各种语言的例子阐释这些概念。它也不是一本有关编译器构造的教科书,其中没有去解释如何构造一个编译器(那只是很少数的程序员最终需要整个参与的一种工作,虽然许多其他工具也会使用其前端技术),而是解释编译器如何工作,它对源程序做了什么事情,以及为什么要那样做。语言的设计和实现在这里被放在一起考察,其中特别强调它们之间相互作用的各种方式。在讨论迭代的时候(6.5.1节),我们可以看到语义问题(什么是指标变量的作用域?如果循环的体要修改循环指标或者界的时候会出现什么问题?)与实际的问题(循环的每次迭代中必须执行多少条分支指令?更新指标时如何避免算术溢出)相互作用,造就了循环结构的演化和发展。在讨论面向对象的程序设计时,我们可以看到在语义优雅与实现速度之间的紧张关系,看到它怎样影响着如Smalltalk、Eiffel、C++和Java等语言的设计。
  在典型的本科生教学计划里,我们希望将本书用于程序设计语言课程。与其他教科书相比,这本书中稍微少了一点综述风格的细节,但也覆盖了同样广泛的语言和概念,并包含了更多有关实现问题的信息。对于那些在语言设计方面有强烈兴趣的学生,可以鼓励他们去进一步学习形式语义、类型理论或者面向对象的设计方面的课程。对那些在语言实现方面有着强烈兴趣的学生,应该鼓励他们去学习编译器构造方面的进一步课程。有了这本书作基础,有关编译器的课程就可以把更多的时间用在代码生成和优化方面,这些问题也是今天的大部分有趣工作之所在。
  在Rochster大学里,本书的材料已经被使用了十多年,用于教授一门名为“软件系统”的课程。这一课程吸引着中高年级的本科生和一年级的研究生。本书对于专业程序员和其他实际工作者也同样很有价值,如果他们希望对自己所喜爱的程序设计语言“背后”的情况有一个更好的理解。通过把有关语法、语义和实际(实现)方面的问题集中到一起讨论,本书企图对语言的设计问题提供一个比其他教科书更完整和平衡的处理,希望能帮助学生理解为什么各种语言特征被设计成现在的样子,使程序员能针对具体应用选择合适的语言,更容易学好新的语言,更清晰高效地使用任何语言。
  在多数章的最后作为总结的一节里,我们都回到了有关设计与实现的问题,其中特别强调两者在前面各节里所表现出的相互作用。此外,附录B列出了一个表,总结了这些相互作用,其中还包括了讨论它们的章节索引。这些相互作用被分为几类,包括今天的大多数语言设计师认为是错误的语言特征,至少部分原因是实现很困难;一些可能有用的特征在有些语言里没有,主要是考虑它们的实现可能很困难或者很慢;某些语言特征被引入,至少部分地是由于它们能高效而优美地实现等等。
  有些章(第2、4、5、9和13章)比其他的章更着重强调实现问题。这些章与其他更多关注语言设计的章之间的顺序可以在一定限度内调整,但一定要保证第5章或者与之相当的内容出现在第6、7、8章之前。许多读者可能已经熟悉了第5章的大部分或者全部材料,多半是来自一个有关计算机组织的课程。在这种情况下就可以简单地跳过这一章。请注意,后面各章都假定了对于新型(即RISC)微处理器的汇编层体系结构的理解。有些读者可能已经熟悉了第2章的一些材料,可能是来自一门有关自动机的课程。在这种情况下,该章的内容可以很快读过去,只是可能要在某些实际问题上(例如从语法错误中恢复)多停留一下。
  作为自学,或者作为一个整整一年的课程,我建议从头到尾使用这本书。在Rochster作为一学期的课程时,我们也覆盖了本书的大部分内容。课程里集中讨论教师们从下面章节里选出的材料:第1章,1.2节到2.2.3节,第3、4、6、7、8章,9.1到9.3节,第10到第12章。同时要求学生阅读本书里所有材料,除了标星号的各节。还要求他们跳过第5章,主要是因为已经学过有关计算机组织的课程。
如果作为更传统的程序设计语言课程,那么可以排除2.2节和第4、5、9章,减少对其他章节里与实现有关的材料的重视程度,把更多时间用到仔细考察语义问题和不同的程序设计范型(例如,第11章里的一些理论基础材料)。对那些采用4学期制的学校,一种明显选择方案是开一学期的导引性课程和两个随后的选修课程。导引性课程可以覆盖下面章节:第1章,2.1节到2.2.3节,第3、6、7章,8.1节到8.4节。后一学期的面向语言的课程可以覆盖8.5节到8.6节,第10到12章,以及另外的有关形式语义学、类型系统或其他相关论题的补充材料。后一学期面向编译器的课程可以包含2.2.4节到2.3节,第4、5(如果需要)、9和13章,以及某些有关自动代码生成、更富进取性的代码优化、程序设计工具等等方面的材料。对这种安排的反对意见可能是认为它没有把有关面向对象、函数式和逻辑式程序设计的内容包括在导引部分。另一种选择就是从更广更具针对性的基于设计的观点出发,把1.4节到1.6节和2.2.1节到2.2.3节移到面向编译器的课程中,减少第6章到第8章里与实现有关的材料,加入10.1节到10.4节和10.6节,以及第11章里理论基础之外的部分。
  我假定典型的读者已经对至少一种高级命令式程序设计语言有了相当的经验。具体是哪种语言并没有关系。书中例子取自各种不同的语言,但总是带有足够的说明和其他讨论,使不熟悉该语言的读者也能比较容易地理解它们。在需要时,算法都是采用自明的非形式的伪代码给出。真正的程序设计语言代码用的字体是this font(Computer Modern),伪代码用的字体是this font(UniversLight)。
  每章最后都有一些复习题和一些更具挑战性的练习。这些练习的特别价值在于引导学生理解各种语言或者技术,其中许多都是他们不大会在其他地方遇到的,或者不会很快遇到的。我建议程序设计作业用C++或者Java;Scheme、ML或者Haskell;以及Prolog。布置一个有关异常处理的题目也是非常好的想法,它可以用Ada、C++、Java、ML或者Modula-3写。如果课程里包含了并行性,作业应该在SR、Java、Ada或者Modula-3里给,可以根据本地的条件选择。在附录A里给出了各种语言实现的资源信息。
  除了这种小型课题之外(或者在那些希望的地方),教师还可能希望学生做一些语言实现方面的工作。由于从空白开始做一个小编译器也是一个学期的工作,Rochester采用的方式是给学生提供能工作的编译器的代码,要求他们做些修改。对于其中的许多人,这是他们第一次阅读、理解和修改一个大的实在的程序——就其本身而言也是非常有价值的练习。Rochester的PL/0编译器把一个归功于Wirth[Wir76,307-347页] 的小语言翻译到MIPS I汇编语言,这一汇编语言被广泛认为是商品的RISC指令集中“最友好的”。威斯康星大学计算机系提供了一个非常好的MIPS解释器(“SPIM”,www.cs.wisc.edu/~larus.spim.html)。编译器本身可以从Rochester得到(ftp://ftp.cs.rochester.edu/pub/packages/plzero/)。它是用C++写的,仔细划分了各个编译阶段,并有很详尽的文档。