Pascal (程式語言)

历史

Pascal基于ALGOL编程语言，为纪念法国数学家和哲学家布莱兹·帕斯卡而命名。维尔特后来开发了类似Pascal的Modula-2和Oberon。在开发Pascal之前，维尔特开发了语言Euler，然后开发了Algol-W。
最初，Pascal在很大程度上但不是完全地为了教授学生结构化编程。很多代学生已使用Pascal作为本科课程的入门语言。Pascal的变种也逐渐地用于从研究项目到PC游戏和嵌入式系统的所有领域。更新的Pascal编译器存在于广泛使用它的领域。
GCC，Gnu C编译器，最初是用Pascal的一种方言Pastel编写的（见GCC#概观）。Pascal是Apple Lisa和早期Mac开发使用的高级语言；最初Macintosh操作系统的部分是从Pascal源代码手工翻译成Motorola 68000汇编语言的。流行的排版系统TeX是由高德纳使用基于DEC PDP-10 Pascal的最初文学编程系统WEB编写的，而像Total Commander的应用是使用Delphi（即Object Pascal）编写的。
Object Pascal仍然广泛用于开发像Skype这样的Windows应用。

简要描述

维尔特的意图是，基于结构化编程，创建一个高效（无论是编译速度还是生成代码）的运行速度。Pascal植根于Algol 60语言，但是也引进了一些概念和机制，使程序员（在Algol的标量和数组之上）能定义他们自己的复杂（结构化）数据类型，也使创建诸如lists、trees和graphs这样的动态和递归数据结构更容易。这些重要的特性包括记录、枚举、子范围、使用关联指针去动态分配变量和集合。为了使这些有可能和有意义，Pascal在所有对象上有一个强类型，意味着如果不使用显式转换，一种数据类型不能转换或解释成另外一种。类似的机制是今天许多编程语言的标准。影响Pascal开发的其它语言是COBOL、Simula 67和维尔特自己的Algol-W。
Pascal，像今天的许多编程语言一样（但是不像C家族的绝大多数语言），允许任意层次的嵌套过程定义，也允许过程和函数内部的绝大多数种类的定义和声明。这使得一个非常简单和一致的语法，能让一个完整的program与一个单独的procedure或function语法上近似相同（当然除了关键字本身外）。

实现

第一个Pascal编译器是在Zurich为CDC 6000系列大型计算机家族设计的。维尔特报道，在1969年第一次使用Fortran实现的尝试没有成功，由于Fortran不足以表达复杂的数据结构。第二次尝试以Pascal语言本身来制定，并在1970年代中期实施。由于许多Pascal编译器已类似地自托管，即编译器本身是以Pascal编写的，因此在新特性加入语言或编译器移植到一个新环境时编译器通常能重编译其本身。用C编写的GNU Pascal编译器是一个显著的例外。
1972年，Welsh和Quinn在贝尔法斯特女王大学，第一次将CDC Pascal编译器成功地移植到另外一个主机。目标主机是ICL1900系列。这个编译器反过来说是ICS Multum微计算机Pascal编译器的父母。以一个使用Pascal作为系统编程语言的视角，Glasgow University计算机科学系的Findlay，Cupples，Cavouras和Davis开发了Multum接口。完成于1973年夏季的Multum Pascal被认为是第一个16位实现。
一个全新的编译器由QUB的Welsh et al.在1977年完成。它提供了一个由Glasgow University的Findlay和Watt实现的源语言诊断特性（结合分析，跟踪和类型识别格式化事后转储）。该实现在1980年由南安普敦大学和Glasgow University的一个小组移植到ICL 2900系列。标准Pascal模式实现也基于该编译器，曼彻斯特大学的Welsh和Hay在1984年已将其改编，以严格检查与BSI 6192/ISO 7185标准的一致性，以及为可移植抽象机生成代码。
在北美洲为PDP-11编写的第一个Pascal编译器在Donald B. Gillies的伊利诺伊大学厄巴纳-香槟分校构造，并生成了本地机器代码。Pascal在整个1970年代和1980年代大受欢迎。
为了迅速地传播该语言，一个编译器“移植工具包”在Zurich产生，包括一个为“虚拟”堆栈机（即引导本身合理有效解释的代码）生成代码的编译器，一个解释这些代码的解释器——Pascal-P系统。虽然SC（堆栈计算机）代码的主要意图是在至少一个系统上编译成真实的机器代码，著名的UCSD实现使用它创建了解释性UCSD p-System。P-系统编译器被称作P1-P4，P1是来自于Zurich的第一个版本，P4是最后一个。
P4编译器/解释器仍然可以在兼容最初Pascal的系统上运行和编译。然而，它本身只是Pascal语言的一个子集。接受全部Pascal语言和包含ISO 7185兼容性的一个P4版本创建了，称作P5编译器，它在源形式上可用。
一个为IBM System/370大型计算机产生本地二机制代码的P4编译器版本由澳大利亚原子能委员会发布；缩写该委员会的名称后，它被称作“AAEC Pascal编译器”。从1975年6月起，一个包含编译器源代码和二机制代码，以及PDP-10主机运行时库文件的P4版本可以从这里下载。
在1980年代早期，也是为IBM System 370开发的Watcom Pascal开发了。
IP Pascal是一个使用Micropolis DOS的Pascal编程语言的实现，但是被迅速地移植到运行于Z80上的CP/M。在1994年它被移植动80386类型机器上，今天作为Windows/XP和Linux实现存在。在2008年，该系统达到一个新层次，该结果语言称作“Pascaline”（Pascal的计算器之后）。它包括对象，名字空间控制，动态数组和许多其它扩展，以及与C有相同功能和类型保护的通用特性。它仅是也兼容最初Pascal实现（作为ISO 7185的标准）的这样一个实现。
在1980年代早期，UCSD Pascal移植到Apple II和Apple III计算机，以提供一个随着机器而来的BASIC解释器的结构化替代品。
Apple Computer在1982年为Lisa Workshop创建了自己的Lisa Pascal，在1985年将该编译器移植到Apple Macintosh和MPW。在1985年，经咨询维尔特，Larry Tesler定义了Object Pascal，这些扩展合并进Lisa Pascal和Mac Pascal编译器。
在1980年代，Anders Hejlsberg为Nascom-2编写了Blue Label Pascal编译器。为IBM PC编写的该编译器的重实现在Borland收购之前以Compas Pascal和PolyPascal的名称销售。重命名为Turbo Pascal后，它变得广受欢迎，一方面由于一个积极的定价策略，一方面由于是第一个全屏集成开发环境之一，以及快速的周转时间（只需要数秒编译，链接和运行）。另外，它用汇编语言编写，并整体高度优化，使它比许多竞争对手更小和更快。1986年Anders将Turbo Pascal移植到Macintosh，并将Apple的Object Pascal扩展合并进Turbo Pascal。这些扩展然后加回到Turbo Pascal v5.5的PC版本中。与此同时Microsoft也实现了Object Pascal编译器。 Turbo Pascal 5.5给在1980年代后期开始主要关注于IBM PC的Pascal社区带来巨大影响力。许多研究BASIC结构化替代品的PC爱好者使用该产品。它也开始被专业开发人员接受。几乎同时，为了让Pascal程序员直接使用Microsoft Windows的基于C的API，许多概念从C语言引入。这些扩展包括空终止字符串，指针算术运算，函数指针，address-of运算符和非安全类型转换。
然而，Borland后来决定需要更多精细的面向对象特性，并在Delphi里使用Apple提议的Object Pascal草图标准作为基础重新开始。（该Apple草图仍然不是一个正式的标准。）Delphi编程语言的第一版相应地命名为Object Pascal。与老的OOP扩展相比较，主要的增加是基于参考对象模型，虚拟构建器和析构器，以及属性。几个其它编译器也实现了该方言。
Turbo Pascal，和其它有单元或模块概念的派生物是模块化语言。然而，它不提供一个嵌套模块概念或合格的导入和导出指定符号。
Super Pascal是一个增加了非数字标签，作为类型名称的返回语句和表达式的变异。
Zurich、Karlsruhe和Wuppertal大学已开发了一个EXtension for Scientific Computing（Pascal XSC），为有控制精度的数字计算编程提供了一个自由的解决方案。

语言结构

最初形式的Pascal是一个纯粹的过程化语言，包括有诸如if，then，else，while，for等等保留字的类Algol控制结构的传统数组。然而，Pascal也有许多最初Algol60不包括的数据结构工具和其它抽象概念，像类型定义、记录、指针、枚举和集合。这些结构部分从Simula67、Algol68、尼克劳斯·维尔特自己的Algol-W和C. A. R. Hoare的建议继承或获得灵感。

Hello world

Pascal程序开始于外部文件描述符作为参数的program关键字；然后跟着begin和end关键字封装的主要块。分号分割语句，句点终结整个程序（或单元）。Pascal源代码不区分大小写。
这里是一个非常简单的“Hello world”程序示例的源代码：
（注：在实际编程中，通常可以省略第一行的output甚至program行）
Program HelloWorld(output);begin
  writeln('Hello, world!')
 {程序块的最后一条语句后不需要";" -    如果添加一个";"会在程序中增加一个“空语句”}end.

标量类型

Pascal的标量类型是real、integer、character、boolean和引进Pascal的新类型枚举：
var
  r: Real;
  i: Integer;
  c: Char;
  b: Boolean;
  e: (apple, pear, banana, orange, lemon);

子范围类型

可以构造任意有序类型（除了real的简单类型）的子范围：
var
  x: 1..10;
  y: 'a'..'z';
  z: pear..orange;

集合类型

与该时代的其它编程语言相反，Pascal支持集合类型：
var
  set1: set of 1..10;
  set2: set of 'a'..'z';
  set3: set of pear..orange;
集合是现代数学的基础概念，可能在很多算法中使用。这样一个特性是非常有用的，可能比不支持集合的语言的同等结构更快。例如，对于许多Pascal编译器：
if i in [5..10] then...
比下面代码执行更快：
if (i>4) and (i<11) then...
从性能和可读性来说，非连续值的集合可能特别有用：
if i in [0..3, 7, 9, 12..15] then...
对于像这些涉及小域上集合的例子，性能的提高通常是编译器将集合变量看作位掩码实现的。集合操作符然后可以作为按位机器码运算有效实现。
然而，对于值范围显著大于本地字长的例子，集合表达式比使用关系运算符的同等表达式可能导致更糟的性能和更多的内存使用。

类型声明

使用类型声明，可以从其它类型定义新类型：
type
  x = Integer;
  y = x;...
更进一步，复杂的类型可以从简单的类型构建：
type
  a = Array [1..10] of Integer;
  b = record
        x: Integer;
        y: Char
      end;
  c = File of a;

File类型

正如上面的例子所示，Pascal的文件是组件序列。每个文件有一个用f^表示的缓冲变量。过程get（读）和put（写）移动到缓冲变量的下一个元素。引进了读，使得read(f, x)与x:=f^; get(f);相同。引进了写，使得write(f, x)与f^ := x; put(f);相同。打印的文字作为字符文件预定义了。当缓冲变量能用于检查下一个字符可用（读一个整数前检查一个数字）时，这个概念导致了早期实现的交互程序的严重问题，但是后来用“lazy I/O”概念解决了。
在Jensen & Wirth的Pascal里，字符串用封装的字符数组表示；因此有固定长度和通常是空间填充。有些方言有一个自定义字符串类型。

指针类型

Pascal支持指针的使用：
type
  a = ^b;
  b = record
        a: Integer;
        b: Char;
        c: a
      end;var
  pointertob: a;
这里变量pointertob是数据类型记录b的一个指针。指针在声明之前可用。这是前向声明，一个使用之前必须声明的规则的例外。创建一个新记录，将值10和字符A分配给记录的域a和b，将指针c初始化为nil，命令是这样的：
new(pointertob);
pointertob^.a := 10;pointertob^.b := 'A';pointertob^.c := nil;...
也可以如下面这样使用with语句来做：
new(pointertob);with pointertob^ dobegin
  a := 10;
  b := 'A';
  c := nilend;...
在with语句范围内，a和b指记录指针pointertob的子域，而不是记录b或指针类型a。
通过在记录里包含一个指针类型域（c，参见nil和null），可以创建链表、栈和队列。
与许多以指针为特性的语言不同，Pascal只允许指针引用匿名的动态创建的变量，不允许引用标准的静态或本地变量。另外，指针是类型绑定的，即字符指针与整数指针是类型不兼容的。该净效果是Pascal指针是“安全的”，远离其它指针实现固有的类型安全问题。

控制结构

Pascal是结构化编程语言，意味着控制流被结构化成标准语句，理想地没有“go to”命令。
while a <> b do writeln('Waiting');if a > b then writeln('Condition met')else writeln('Condition not met');for i := 1 to 10 do writeln('Iteration: ', i:1);repeat
  a := a + 1until a = 10;case i of
  0: write('zero');
  1: write('one');
  2: write('two')end;

过程和函数

Pascal将程序结构化成过程和函数。
program mine(output);var i : integer;procedure print(var j: integer);

  function next(k: integer): integer;
  begin
    next := k + 1
  end;begin
  writeln('The total is: ', j);
  j := next(j)end;begin
  i := 1;
  while i <= 10 do print(i)end.
过程和函数可以嵌套任意深度，“program”构造是逻辑上最外层的块。
每个过程或函数可以有自己的正确顺序的goto标签、常量、类型、变量和其它过程和函数声明。
此顺序要求最初的本意是允许高效的单通编译。然而，在一些方言里声明节严格的顺序要求是不必要的。

分号作为语句分割符

Pascal从ALGOL语言里吸纳了许多语言语法特性，包括使用分号作为语句分割符。这与其它诸如PL/I、C等的语言是不同的。它们使用分号作为语句终止符。正如上述例子演示的，记录类型声明、块或case语句的end关键字之前，repeat语句的until关键字之前，if语句的else关键字之前，不需要分号。
在Pascal的早期版本里，不允许存在额外的分号。然而，1973年的修订报告，后来成为ISO 7185:1983里的额外的类ALGOL空语句现在允许这些情况的绝大多数可选地使用分号。例外是仍然不允许分号立即出现在if语句的else关键字之前。
在一些情况下，真正需要空语句：
(* skip blanks *)while GetChar() = ' ' do ;
然而，滥用可能会产生问题。虽然下面语句是语法正确的，但是结果不大可能是想要的：
if alarm then;begin;
  SendMayday;
  EjectPilot;end;

标准

1983年，该语言标准化为国际标准IEC/ISO 7185，以及一些当地国家的具体标准，包括美国ANSI/IEEE770X3.97-1983和ISO 7185:1983。这2个标准的区别仅在于ISO标准包含一个conformant数组的“级别1”扩展，而ANSI不允许对原始（维尔特版本）语言扩展。1989年，对ISO 7185进行了修正（ISO 7185:1990），纠正了原始文档中找到的各种错误和模糊。
1990年，一个扩展的Pascal标准作为ISO/IEC 10206创建。1993年，ANSI组织用ISO 7185:1990标准代替了ANSI标准，有效地终结了作为一个不同标准的状态。
ISO 7185被说成是对《用户手册和报告（Jensen和维尔特）》详述的维尔特的1974年语言的澄清，但是引人注意的是增加了作为标准级别1的“Conformant Array Parameters”，级别0是没有Conformant Array的数组。该增加是在C. A. R. Hoare的请求下，得到了维尔特赞同。该变动的原因是Hoare想创建数学算法库（NAG）的一个Pascal版本，该库最初用FORTRAN编写，发现如果没有允许变长数组参数的扩展就无法实现该库。出于同样的考虑，ISO 7185包含了指定过程和函数参数的参数类型的工具。
注意维尔特自己将1974年的语言当作“标准”，以将其与CDC 6000编译器的机器特定特征相区别。该语言记录在“Pascal用户手册和报告”的第二部分报告”。
在Pascal起源的大型机（主机和微计算机）上，这些标准普遍遵循。在IBM-PC上，这些标准不被遵循。在IBM-PC上，Borland标准Turbo Pascal和Delphi有最大量的用户。因此，了解一个特别的实现匹配原始Pascal语言还是Borland方言非常重要。
该语言的IBM-PC版本开始区别于UCSD Pascal，以对该语言的几个扩展以及几个遗漏和变化为特性的解释型实现。许多UCSD语言特性今天仍然存在，包含于Borland的方言。

Divisions

Pascal的维尔特的Zurich版本在ETH之外以2个基本形式发布，CDC 6000编译器源和一个称作Pascal-P系统的移植工具。Pascal-P编译器遗漏了完全语言的几个特性。例如，作为参数使用的过程和函数，无区别变体记录，包装，处理，过程间的goto方法和完全编译器的其它特性被忽略。
Kenneth Bowles教授的UCSD Pascal是基于Pascal-P2包的，因此有几个共同的Pascal-P语言限制。UCSD Pascal后来作为Apple Pascal被接纳了，并持续有几个版本。虽然UCSD Pascal实际上扩展了Pascal-P2包的Pascal子集，通过添加回标准Pascal结构，它仍然不是一个完整的Pascal标准安装。
Borland的Turbo Pascal由Anders Hejlsberg用汇编语言独立于UCSD或Zurich编译器编写。然而，它与UCSD编译器一样接纳了许多相同子集和扩展。这可能是因为UCSD系统是适于在当时可用的资源限制的微处理器上开发应用的最常见Pascal系统。

评论

Pascal在计算社区产生了广泛的响应，包括批评和赞美。

批评

尽管非常流行（尤其在八十到九十年代），依据维尔特的对这种语言的定义来构建Pascal，使它不适合非教学的使用，这遭到了广泛的批评。 推广了C语言的布莱恩·柯林汉（Brian Kernighan）早在1981年就在他的论文Why Pascal Is Not My Favorite Programming Language对Pascal提出了严厉的抨击。