1 发展历史

1.1 起源背景(1950年代后期)

1950年代后期,计算机科学尚处于萌芽阶段,编程语言种类稀少且高度依赖特定机器。当时的主流语言如FORTRAN和COBOL分别面向科学与商业领域,但缺乏一种通用的、数学上严谨的算法描述语言。1958年,国际信息处理联合会(IFIP)的前身——一群来自欧美学术界与工业界的计算机科学家,在瑞士苏黎世召开会议,决定设计一种跨平台、与机器无关的算法语言。这一倡议源于对FORTRAN过早标准化和缺乏结构化的不满,以及学术界对更精确表达算法逻辑的需求。

1.2 ALGOL 58:首次尝试

1.2.1 主要设计目标

ALGOL 58(最初称为IAL,International Algebraic Language)的目标包括:提供一种与具体计算机无关的算法表示法、支持数学符号的自然书写(如使用:=作赋值)、允许高级控制结构(布尔表达式、条件语句),并强调语言的简洁性与可读性。委员会希望它能成为国际学术交流的标准工具。

1.2.2 未被广泛实现的原因

ALGOL 58虽在纸面上极具吸引力,但实际实现寥寥无几。原因包括:其语法定义仍不够精确,导致不同实现之间的兼容性问题;缺乏输入输出标准规定,每种实现都自行定义I/O机制;此外,当时主流厂商(如IBM)更倾向于推广自己的FORTRAN,对ALGOL的商业价值持怀疑态度。最终,ALGOL 58更像一份蓝图,而非可落地的语言。

1.3 ALGOL 60:革命性版本

1.3.1 报告与修订

1960年1月,ALGOL委员会在巴黎发布了《ALGOL 60报告》,该报告被誉为编程语言发展史上的里程碑。报告由彼得·诺尔(Peter Naur)、约翰·麦卡锡John McCarthy)等多位先驱共同编写,并先后经历1962年、1963年等数次修订,修正歧义并补充了标准函数

1.3.2 BNF文法的引入

ALGOL 60首次采用巴科斯-诺尔范式(Backus-Naur Form, BNF)来精确描述语法。BNF由约翰·巴科斯与彼得·诺尔首创,将语言规则形式化为产生式集合,使语法定义无歧义。这一创新直接催生了后来编译器领域的语法分析理论(如LL和LR分析),也成为几乎所有编程语言语法描述的标杆。

1.3.3 块结构与作用域规则

ALGOL 60引入了块结构(block structure):程序由嵌套的beginend块组成,每个块可以声明局部变量,且变量作用域严格以词法嵌套为准。这一设计首次实现了词法作用域(lexical scoping),使得变量可见性清晰可控,并允许程序员精确管理内存分配(动态与静态存储)。块结构也支持在任意嵌套层定义过程,为递归与局部过程奠定了基础。

1.4 ALGOL 68:争议与激进

1.4.1 正交性与复杂语法

ALGOL 68于1968年发布,是ALGOL家族的一次激进革新。设计团队采取了“正交性”(orthogonality)原则:语言特性相互独立且可自由组合,例如数组、结构体、指针等类型可以用于任意上下文。这赋予了语言极高的表达能力,但也导致语法极度复杂:引入了模式(mode)取代简单类型、新的赋值运算符(如:==)、以及“三重赋值”等令人费解的特性。报告长达数百页,被戏称为“航空母舰级别的语言”。

1.4.2 “我宁愿不实现它”运动

ALGOL 68的复杂性引发了强烈反弹。许多编译器实现者抱怨其规范过于模糊和庞大,甚至出现了名为“我宁愿不实现它”(I'd rather not implement it)的非正式运动。最终,只有少数完整的ALGOL 68编译器面世(如RRE和FLACC),且几乎未获商业成功。这场风波也让编程语言社区重新思考“语言设计应该追求华丽还是务实”。

1.5 ALGOL 后代与分支

1.5.1 ALGOL W与Pascal

ALGOL W是IBM的托尼·霍尔(C. A. R. Hoare)在1966年基于ALGOL 60设计的简化语言,加入了记录类型、子程序参数化等特性,并用作教学工具。其后继者Pascal由尼古拉斯·沃斯(Niklaus Wirth)于1970年发布,继承了ALGOL的块结构与BNF语法,但大幅简化,成为20世纪70-80年代最流行的编程入门语言之一。

1.5.2 Simula与面向对象萌芽

Simula I(1962)和Simula 67由挪威的奥利-约翰·达尔(Ole-Johan Dahl)与克利斯登·奈加特(Kristen Nygaard)开发,本质上是ALGOL 60的扩展。它首次引入了类、对象、继承、虚函数等概念,被公认为面向对象编程的鼻祖。ALGOL的块结构在此处被自然转化为类的封装结构,从而催生了整个OOP范式。

2 语言特征

2.1 语法风格

2.1.1 关键字与标点符号

ALGOL使用英文关键字(如beginendifthenelse)并采用分号作为语句分隔符。与FORTRAN的固定格式不同,ALGOL是自由格式语言,允许程序员缩进排版。标点符号包括.用于子过程筛选、,用于参数列表、:=用于赋值(灵感来自数学中的“定义为”符号)。这些约定后来被Pascal、Modula-2等语言继承。

2.1.2 条件与循环结构(if…then…else、for…step…until)

ALGOL 60定义了经典的条件语句:if 条件 then 语句 else 语句,且支持嵌套。循环语句为for 变量 := 初值 step 步长 until 终值 do 语句,也可使用whileuntil变体(需通过条件表达式实现)。这些结构将逻辑流程与数学记号紧密结合,提升了算法表述的直观性。

2.2 数据类型与声明

2.2.1 基本类型(整数、实数、布尔、数组)

ALGOL 60提供了integerrealboolean三种基本类型,以及由它们构成的数组(array)。数组的索引可以灵活指定(如array a[1:10, -5:5]),且上下界可在运行时确定。此外,string类型在ALGOL 60中未原生支持,但可通过字符数组模拟。

2.2.2 用户自定义类型与枚举

ALGOL 60本身不提供显式的用户自定义类型,但ALGOL 68引入了“模式”(mode)系统,允许程序员通过mode关键字定义结构体、联合体、指针等复杂类型。枚举类型(如mode color = (red, green, blue))也在ALGOL 68中出现,为Pascal和C的枚举提供原型。

2.3 过程与参数传递

2.3.1 按值调用与按名调用(call by name)

ALGOL 60开创性地支持两种参数传递方式:按值调用(call by value)和按名调用(call by name)。按值调用将实参的副本传递给形参;按名调用则每次引用形参时重新求值实参表达式(类似宏替换)。按名调用强大的副作用引发了许多诡异行为(如著名的“Jensen's device”——通过按名调用实现类高阶函数机制),但也带来了性能和分析困难。后续语言大多舍弃了按名调用,仅保留按值、按引用和按结果等模式。

2.3.2 递归与局部过程

ALGOL 60允许过程直接或间接调用自身,支持函数与过程的递归定义。其块结构还支持在过程内部嵌套定义其他过程(局部过程),且外部过程的活动记录必须保存内部过程的环境。这一设计在Algol 60的实现中推动了栈式动态存储管理的成熟,也为后来的寄存器分配和闭包理论铺平道路。

2.4 块结构与存储类别

2.4.1 词法作用域与内嵌块

ALGOL 60通过嵌套的beginend块实现词法作用域。每个块可以声明变量,且变量可见性完全由文本嵌套深度决定:内层块可以访问外层同名变量的固定实例。这种规则保证了静态可分析性,并在编译器设计中被系统地实现为符号表和活动记录栈。

2.4.2 动态与静态变量

ALGOL 60默认变量是动态分配的(基于栈的生命周期),但支持通过own关键字声明“自己的”变量(类似于静态局部变量,只初始化一次且跨调用持久保留)。这一设计允许程序员在块内维护状态,而不必将数据提升到全局范围,后来被Pascal和C的“static”变量概念继承。

3 影响与遗产

3.1 对现代编程语言的影响

3.1.1 C语言家族中的ALGOL痕迹

C语言虽直接继承自BCPL,但其语法风格深受ALGOL影响:块结构(花括号起源于ALGOL的begin/end的简写)、if-elsefor循环、赋值运算符=与比较运算符==的区分(ALGOL用:==,C作了符号简化)、函数参数传递默认按值调用等方式均可溯源至ALGOL 60。此外,C指针的声明语法(如int *p)与ALGOL 68的引用模式有深层次关联

3.1.2 Pascal与教学语言

Pascal作为ALGOL最直接的简化后代,长期被用作计算机科学入门教育的标准语言,直到被Java和Python取代。Pascal特别强调ALGOL式的结构化和强类型,并完整保留了BNF语法定义习惯。许多大学课程以Pascal作为教授算法和编程基础的载体。

3.1.3 算法描述中的伪代码标准

ALGOL的语法风格(尤其是自然语言关键字和数学记号)被广泛用于算法教科书中的伪代码描述。例如,Knuth的《计算机程序设计艺术》大量使用类似ALGOL的记号算法,而ACM和IEEE的许多论文也以ALGOL 60的伪代码形式呈现算法逻辑。这种“算法描述方言”至今仍在学术写作中流行。

3.2 编译器技术的推动

3.2.1 自展与编译系统

ALGOL 60编译器是自展(bootstrapping)技术的早期实践者。研究者利用ALGOL本身编写编译器的部分组件,再通过机器码翻译实现完整系统。荷兰数学家范·维恩(Adriaan van Wijngaarden)等人提出的“维恩加顿文法”(W-grammar)为ALGOL 68的自定义语法分析提供了理论框架。

3.2.2 语法分析与语义分析先驱

ALGOL的BNF描述直接催生了语法分析算法的研究(如递归下降、LL分析、算符优先分析)。同时,ALGOL 60的块结构作用域规则促使编译器开发者设计符号表管理、活动记录栈以及静态链-动态链等运行时结构。这些技术在后来的Pascal、C、Java等编译器中继续演化和完善。

3.3 学术与工业界的“未竟之梦”

3.3.1 ALGOL在苏联与欧洲的特殊地位

由于美国主导的FORTRAN占据商业市场,ALGOL在东欧和苏联反而获得较大学术应用。苏联工程师开发了较为完整的ALGOL实现(如МИР系列计算机上的ALGOL编译器),并将它用于物理计算教学。西方的一些欧洲国家如挪威、荷兰的计算机界对ALGOL的拥护也远超美国,直接孕育了Simula与后来Eiffel等语言。

3.3.2 “ALGOL烈酒”梗与程序员玩笑

在编程文化中,ALGOL常被戏称为“程序员界的拉丁文”——高贵但濒死。网络流传的“ALGOL烈酒”梗指一种想象中的鸡尾酒,配方包括“纯正的正交性、一份递归、一丝非主流语法,不加任何妥协”。这种调侃体现了程序员对ALGOL设计哲学既尊敬又调侃的态度。

4 主要实现与变体

4.1 B5000上的Burroughs ALGOL

Burroughs B5000大型主机(1961年)上配备的Burroughs ALGOL是最早、最完整的ALGOL 60实现之一。它针对栈式硬件架构优化,直接支持过程调用与递归,并集成了操作系统级安全保护。Burroughs还将ALGOL作为系统程序设计语言(ESPOL),开创了用高级语言编写操作系统的先河。

4.2 IBM 7090上的ALGOL

IBM 7090上的ALGOL编译器由SHARE用户组创建,作为FORTRAN的替代选择。虽然商业表现不佳,但该实现附带了详尽的调试器和库函数,成为ALGOL 60研究者的重要参考平台。

4.3 挪威的Norsk Data实现

挪威Norsk Data公司在20世纪70年代至80年代为其Nord系列计算机开发了ALGOL 60编译器,并集成到多任务交互操作系统中。该实现被广泛用于挪威大学的教学与科研,支持动态数组、递归多线程等特性,是北欧ALGOL传统的历史见证。

4.4 小众但有趣的实现:ALGOL 60 for Zuse Z22

Zuse Z22(1958年)是德国康拉德·楚泽设计的早期真空管计算机。针对该机器实现的ALGOL 60子集非常精简,仅有整数类型和基础控制流,但将ALGOL 60的理念成功移植到资源极度有限的硬件上。如今,通过模拟器可以重温这一趣味实现,感受早期编译约束下的算法之美。

5 相关文化

5.1 “ALGOL是纯血统,FORTRAN是泥腿子”的传说

在计算机语言早期的“贵族与平民”对立中,ALGOL支持者常揶揄FORTRAN为“泥腿子”(意指它妥协于硬件实现、不讲究形式化正确性,且对数值计算以外特性支持差)。而FORTRAN拥护者则回击ALGOL“只会纸上谈兵”。这种对立最终随Pascal和C的出现而消解,但成为技术文化史中的一段趣谈。

5.2 算法竞赛中的ALGOL代码考古

现代算法竞赛(如ACM/ICPC)底层参考伪代码往往采用类ALGOL风格。有些极客怀念ALGOL的简洁,尝试编译古董ALGOL代码来解题,甚至专门制作模拟器运行1960年代编译器。这种“代码考古”活动(例如在在线古董机模拟器上运行ALGOL 60求素数)成为编程文化的一部分。

5.3 现代模拟器与怀旧复刻

近年来,多个ALGOL 60和ALGOL 68的模拟器项目在GitHub上复活(如“algol60-compiler”、“algol68-simulation”)。爱好者通过JavaScript或Python重新实现核心理法的解释器,允许现代程序员体验编写begin integer i; for i:=1 step 1 until 10 do print(i) end的古老快感。这些项目与复古计算网站一起,保留了ALGOL这份稀有遗产的鲜活记忆。