ALGOL 68

ALGOL 68（源自的縮寫），是一種指令式程式語言，作為ALGOL家族的成員，它是官方上的ALGOL 60後繼者。ALGOL 68的設計目標，是提供更廣泛的應用，以及更嚴格的語法定義。

ALGOL 68的特征包括的语法，用户声明的类型和结构与标签联合类型，变量与引用参数的引用模型，可变长数组和字符串、数组与矩阵的，用户定义的运算符和运算符重载，高阶函数与匿名函数，以及并发。

概論
在1964年3月达成一致，要制定ALGOL 60的两个后续语言标准：ALGOL X，它是具有增补的强类型和中的树或列表的ALGOL语言重新定义，和，它具有LISP的同像性风格修改自身程序能力。经过多次会议研讨针对ALGOL X的提案之后，1968年12月20日，正式通过了ALGOL 68最终报告，并在1969年1月将其提交给了大会，在1969年3月，IFIP大会经过邮件投票授权出版此报告。

ALGOL 68的定义使用了阿德里安·范·韦恩加登发明的一种数学形式主义的两级形式文法。使用分别称为“元产生式规则”和“超规则”的两组上下文无关文法规则，生成形成一个可能无限的集合，而这些常规的产生式将识别特定的ALGOL 68程序；值得注意的是，它们能够表达在很多其他编程语言的技术标准中被标记为“语义”的那种要求，其他语言的语义必须用易致歧义的自然语言叙述来表达，并接着在编译器中实现为附加到形式语言解析器的“特设”代码。

ALGOL 68设计的主要目标和原则为：
描述的完备性和清晰性；
设计的正交性；
安全性；
高效性：
 静态的模态（即类型）检查，
 模态无关的解析，
 分立编译，
 循环优化，
 表示于极小化和更大的字符集。

在1970年，成为了第一个投入工作的ALGOL 68编译器。在1973年9月确定并于1975年出版的修订报告中，省略了特定特征比如过程化、gomma和形式边界。Stephen R. Bourne是ALGOL 68修订委员会成员，他选取了它的一些想法到他的Bourne shell之中。

ALGOL 68曾受到激烈的批评，最突出的是来自其设计委员会的一些成员比如C. A. R. Hoare，还有ALGOL 60编译器作者比如Edsger Dijkstra，它获评为抛弃了ALGOL 60的简单性，成为了复杂或过于笼统的想法的载体。ALGOL 68与刻意保持简单的同时代（竞争）者如C、和Pascal形成了鲜明对比。

ALGOL 68的语言定义出版后的文本长达两百多页并充斥着非既有标准的术语，这种复杂性使得编译器实现任务变得困难，故而它曾被称为“没有实现也没有用户”。这么说只是部份真实的，ALGOL 68曾应用于一些小众市场，特别是流行于英国的（ICL）的机器之上，还有在教学角色之上。在这些领域之外，其使用相对有限。

尽管如此，ALGOL 68对计算机科学领域的贡献是深刻、广泛而持久的，虽然这些贡献大多只是在它们于后来开发的编程语言中重现之时才被公开认可。很多语言是为了应对设计这门语言时所采用的形式化方法导致的复杂性而专门开发的，其中最著名的是Niklaus Wirth的采用的ALGOL W和作为其后继者的采用扩展巴科斯-瑙尔范式（EBNF）的Pascal；或者是针对特定角色而重新实现的，比如有些人认为Ada可以看作ALGOL 68的后继者。

1970年代的很多语言可以追溯其设计至ALGOL 68，选取一些特征，并放弃被认为太复杂或超出给定角色范围的其他特征。其中就有C语言，它受到ALGOL 68的直接影响，特别是它的强类型和结构。多数现代语言都至少可以追溯其部份语法至要么C语言要么Pascal，因而很多语言可直接或间接的经由C语言而追溯至ALGOL 68。

ALGOL 68项目的完整历史可参见的《A History of ALGOL 68》。ALGOL 68语言的长篇阐述可参见Dr. Sian Mountbatten的《Programming ALGOL 68 Made Easy》，或者Marcel van der Veer的《Learning ALGOL 68 Genie》。

规定和实现时间线
 名称  年 国家  描述  目标CPU/平台  属主/许可证  实现语言 Generalized ALGOL  1962     广义ALGOL   荷兰数学中心 ALGOL XDP 1966    ALGOL X草拟提案A. van Wijngaarden and B. J. Mailloux. A Draft Proposal for the Algorithmic Language ALGOL X. IFIP WG 2.1 Working Paper 47 (Warsaw 2), October 1966.    ALGOL 68DR  1968     ALGOL 68草案报告    ALGOL 68r0  1968     ALGOL 68最终报告      1970     之下的ALGOL 68      ALGOL 60 DTSS ALGOL 68  1970    的ALGOL 68   达特茅斯学院  Mini ALGOL 68  1973    针对简单ALGOL 68程序的解释器 可移植解释器  荷兰数学中心  ALGOL 60OREGANO  1973     实践“实现模型的重要性。”   加州大学洛杉矶分校  M-220 ALGOL 68  1974     使用在上实现ALGOL 68"Application of the Machine-Oriented Language Epsilon to Software Development", I.V. Pottosin et al., in Machine Oriented Higher Level Languages, W. van der Poel, N-H 1974, pp. 417–434      1975    剑桥大学ALGOL 68实现 ，IBM System/360，PDP-10和Unix，Telefunken TR440/TR445， 200和Z80（1980年） 剑桥大学  ALGOL 68CALGOL 68r1  1975    ALGOL 68修订报告    ALGOL 68 H  1975     ALGOL 68编译器   阿尔伯塔大学，荷兰数学中心   ALGOL W CDC ALGOL 68 1975    完全实现的ALGOL 68 ，CDC Cyber  控制数据公司  Odra ALGOL 68  1976        1204/IL    ALGOL 60Oklahoma ALGOL 68  1976    俄克拉何马州立大学ALGOL 68实现 IBM 1130和  俄克拉何马州立大学  ANSI Fortran 66 Berlin ALGOL 68  1977    柏林工业大学ALGOL 68实现"The Berlin ALGOL 68 implementation" An abstract ALGOL 68 machine and its application in a machine independent compiler – Springer. Springerlink.com. Retrieved on 2013-07-21. 基于抽象ALGOL 68机器的机器无关编译器  柏林工业大学    1977    具有调试特征的修订报告完整实现  System/370  租用，Chion公司  汇编  1977    可移植编译器  ，Multics，VMS和    ALGOL 68RSALGOL 68 MR  1978    ALGOL 68的模块和分立编译规定      1979    并行ALGOL 68-R     Leningrad ALGOL 68  1980    列宁格勒国立大学开发的完全语言加上模块系统  IBM，DEC，CAMCOH，PS 1001和PC      1983    增量编译，1992年再版MK2 PC 非商业共享软件   1985     ALGOL 68的子集语言 ，Sun SPARC（在SunOS 4.1和Solaris 2下），Atari ST（在GEMDOS下），（在RISC OS下），（在下）  利物浦大学，卡内基·梅隆大学，曼彻斯特大学  ，PascalRutgers ALGOL 68  1990     Mini ALGOL 68解释器后续版本 可移植解释器  写于罗格斯大学的非商业开源软件  C Algol68toC  1993    基于源自1985年的ctrans 可移植C生成器  的皇冠版权开源软件  ALGOL 68RSALGOL 68 Genie  2001     完全语言包括标准的并立子句 可移植解释器；2010年版本2之后，具有可选的选定单元的编译  CAlgol68FrontEnd in GCC 2025   GCC中的ALGOL 68前端 跨平台     C/C++

样例代码
下面是采用了的程序结构的Hello World样例代码，严格的说只有在BEGIN与END之间的诸行是ALGOL 68程序，第一行、第二行和最后一行都特定于a68toc编译器。
PROGRAM helloworld CONTEXT VOID
USE standard
BEGIN
    print(("hello, world!", newline))
END
FINISH
第一行给出这个程序的标识为helloworld而且这个名字的文件包含了这个程序；CONTEXT VOID短语指定这个程序独立而非嵌入到其他部份之中。第二行的USE加载了标准预置（prelude），print()就在其中。将上述代码保存入文本文件helloworld.a68中，然后使用ALGOL 68RS编译器a68toc编译并接着执行它：
$ ca -u ASDFGHJ helloworld.a68
$ ./helloworld
hello, world!

下面是采用GCC的ALGOL 68前端ga68程序结构的Hello World样例代码：
PROGRAM
BEGIN
    puts ("Hello world\n");
    0
END
这里的puts()包含在POSIX标准预置之中，这里的0是POSIX退出代码。将上述代码保存入文本文件helloworld.a68中，然后使用ga68编译器来编译并接着执行它：
$ ga68-15 -shared-libga68 -o helloworld helloworld.a68
$ ./helloworld
Hello world

下面的样例代码实现了埃拉托斯特尼筛法来找到小于等于100的所有素数。ALGOL 68中NIL类似于其他语言中的空指针，x OF y表示访问STRUCT y的成员x。
BEGIN # ALGOL68的素数筛法，基于链表实现 #
    MODE
        NODE = STRUCT (INT h, REF NODE t),
        LIST = REF NODE;
    OP CONS = (INT n, LIST l) LIST: HEAP NODE := NODE (n, l);
    PRIO CONS = 9;
    PROC one to = (INT n) LIST:
        (PROC fn = (INT m) LIST: (m > n | NIL | m CONS fn(m + 1));
         fn(1));
    PROC error = (STRING s) VOID:
        (print((newline, " error: ", s, newline)); stop);
    PROC hd = (LIST l) INT:
        (l IS NIL | error("hd NIL"); SKIP | h OF l);
    PROC tl = (LIST l) LIST:
        (l IS NIL | error("tl NIL"); SKIP | t OF l);
    PROC show = (LIST l) VOID:
        (l ISNT NIL | print((" ", whole(hd(l), 0))); show(tl(l)) 
         | print(newline));
    PROC filter = (PROC (INT) BOOL p, LIST l) LIST:
    BEGIN
        PROC fn = (LIST m) LIST:
            IF m IS NIL THEN NIL
            ELIF p(hd(m)) THEN hd(m) CONS fn(tl(m))
            ELSE fn(tl(m))
            FI;
        fn(l)
    END;
    PROC sieve = (LIST l) LIST:
        IF l IS NIL THEN NIL
        ELSE hd(l) CONS sieve(filter(
                (INT n) BOOL: n MOD hd(l) NE 0, tl(l)))
        FI;
    PROC primes = (INT n) LIST: sieve(tl(one to(n)));
    show(primes(100))
END
将上述代码保存入文本文件primes.a68中，然后使用ALGOL 68 Genie解释器执行它：
$ a68g primes.a68
 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

显著的语言元素

保留字及其等价符号
标准语言包含六十一个保留字，典型的用粗体字打印，并且其中一些还具有“简短”符号等价者：
{|
|-
|MODE，OP，PRIO，PROC，FLEX，HEAP，LOC，LONG，REF，SHORT，STRUCT，UNION，VOID，
|-
|BITS，BOOL，BYTES，CHAR，COMPL，INT，REAL，SEMA，STRING，CHANNEL，FILE，FORMAT，
|- 
|AT @，IS :=:， ISNT :/=:，OF，TRUE，FALSE，EMPTY，NIL ○，SKIP ~，
|-
|COMMENT  CO # ¢，PRAGMAT  PR，BEGIN ~ END ( ~ )，
|-
|IF ~ THEN ~ ELIF ~ THEN ~ ELSE ~ FI ( ~ | ~ |: ~ | ~ | ~ )，
|- 
|CASE ~ IN ~ OUSE ~ IN ~ OUT ~ ESAC ( ~ | ~ |: ~ | ~ | ~ )，
|- 
|FOR ~ FROM ~ TO ~ BY ~ WHILE ~ DO ~ OD，PAR，GO TO  GOTO，EXIT。
|}
GO TO被当作两个保留字。在未修订报告的语言中，OF有等价符号 →，EXIT有等价符号□，还有保留字EITHER和IS NOT结合。

字符表示
“值当字符”（worthy character）是1977年出版的ALGOL 68标准硬件表示报告出于可移植性而推荐的字符集中的字符:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9   " # $ % ' ( ) * + , - . / : ; < = > @ [ ] _ |
这反映了当年一些硬件不支持在ANSI的ASCII或IBM的EBCDIC之外其他字符的事实。

传输表示采用“值当字符”时，“加上乘以”符号⊥替代为I，“乘以的幂”符号⏨和\替代为E。

500px|thumb|配备APL打字球与键帽后的终端的键盘，它不再支持小写字母。
ALGOL的“特殊”字符：
× ÷ ≤ ≥ ≠ ≡ ¬ ∧ ∨ ⊃ ↑ ⏨ ␣ ↓ → ⊥ ○ □ ⌊ ⌈ ⎩ ⎧ ¢
多数都可以在1965年出现的配备APL打字球与键帽后的终端的键盘上找到。这些字符也是Unicode标准的一部份，并且在一些流行的字体中可获得到。

单元
基本语言构造是“单元”（unit）。单元可以是“公式”、“封闭子句”、“例程正文”这样的构造，也可以是某个技术上需要的构造诸如赋值、跳转、越过和空无。

技术术语“封闭子句”（enclosed clause）统一了某些固有的加括号的构造，它们在其他当代语言中被称为“块”、“do语句”、“”等等。在使用关键字的时候，通常使用介入关键字的反转字符序列来终结这个包围，比如：IF ~ THEN ~ ELSE ~ FI、CASE ~ IN ~ OUT ~ ESAC和FOR ~ WHILE ~ DO ~ OD。这种守卫命令语法被Stephen Bourne重新使用在常用的Unix Bourne shell之中。

一个表达式还可以产生多元值（multiple value）即有多个元素的一个值，它是通过“并立子句”（collateral clause）从其他一些值构造出来的。这种构造看起来就像过程调用的参数包（pack）。

模态
数据类型在ALGOL 68用语中叫做“模态”（mode），其原始模态的声明符为：INT、REAL、COMPL（复数）、BOOL、CHAR、BITS、BYTES和STRING。ALGOL 68不再定义long、short和double这样的类型，而是提供了修饰符（modifier）LONG和SHORT。
 BITS – BOOL值的压缩向量（packed vector）。
 BYTES – CHAR值的固定大小的紧致多元组（即数组）。
 STRING – CHAR值的FLEX [1 : 0]（声明时无元素）的灵活多元组（即数组）。
 LONG – 声明INT、REAL或COMPL的大小为LONG。
 SHORT – 声明INT、REAL或COMPL的大小为SHORT。
ALGOL 68提供了预置常量（prelude constant）如max real和long max real等来将程序适配到不同实现之中。

复杂模态可以使用模态构造子REF、STRUCT、UNION和PROC来创建自更简单的模态：
 REF mode – 到模态mode的值的引用，类似于C/C++中和Pascal中的指针。
 STRUCT – 用来建造结构，类似于C/C++中的struct和Pascal中的recode。
 UNION – 用来建造联合，类似于C/C++和Pascal中的union。
 PROC – 用来指定过程，类似于C/C++中的函数和Pascal中的过程/函数。

在一个代码块中，诸声明不必须都先于诸语句，但所有名字都必须在使用前声明。ALGOL 68提供了恒等声明来将标识符绑定到常量值之上。在声明给名字的标识符之时，这个名字可以被初始化为立即引用一个值；还可以将名字声明为等同于以前声明的名字而使得二者互为别名。例如：
 INT n = 2;  # n是新建的常量，它被固定为2 #
 INT m := 3;  # m是新建的局部变量的名字，这个变量的值被初始化为3 #
 INT p = m;  # p是新建的常量，它被固定为同于m当前的值 #
 INT q := m;  # q是新建的局部变量的名字，这个变量的值被初始化为同于m当前的值 #
 REF INT r = m;  # r是新建的变量名字，它与m引用的是同一个变量 #
 REAL avogadro = 6.02214076E23;  # 阿伏伽德罗常数 #
 LONG REAL long pi = 3.14159 26535 89793 23846 26433 832795;
 COMPL imaginary unit = 0 I 1;  # 虚数单位i即复数0 + 1i #

其他声明符号包括：FLEX、HEAP和LOC。
 FLEX – 所声明的名字是灵活的，就是说它可以引用任何数量元素的多元组（即数组）。
 HEAP – 为变量从全局堆中分配一些空闲空间。
 LOC – 为变量分配这个局部栈的一些空闲空间。

声明REAL x只是REF REAL x = LOC REAL的语法糖，LOC REAL是生成REF REAL模态的名字的单元。在REF REAL x = LOC REAL := 0中，赋值LOC REAL := 0导致整数0在被赋值给这个生成器产生的名字之前就被扩充（widen）为实数0.0，声明的名字x与生成器产生的名字二者所引用的是同一个变量。

原始声明符还包括：FORMAT、FILE、CHANNEL、SEMA、COMPLEXG和PIPEG。
 SEMA – 可以通过运算符LEVEL初始化的信号量。

ALGOL 68使用MODE声明来给模态声明名字，它类似于C/C+中的typedef和Pascal中的type：
 INT max = 99;
 MODE NEWMODE = [0:9][0:max]STRUCT (
     LONG REAL a, b, c, SHORT INT i, j, k, REF REAL r);

这类似于如下C99代码： 
const int max = 99;
typedef struct {
    double a, b, c; short i, j, k; float *r;
} newmode[9+1][max+1];

对于ALGOL 68，只有模态标示（indicant）NEWMODE出现在等号的左侧，最值得注意的是，构造的制造和读取，是从左至右而不顾及优先级的。还有ALGOL 68多元组（数组）的下界缺省的是1，但也可以是从-max int到max int的任何整数。

模态声明允许递归模态，就是说模态可直接或间接的依据自身来进行定义。这要服从一些限制，例如下列声明是非法的：
 MODE A = REF A;
 MODE A = STRUCT (A a, B b);
 MODE A = PROC (A a) A;

而下列声明是有效的：
 MODE A = STRUCT (REF A a, B b);
 MODE A = PROC (REF A a) REF A;

注释和编译指导
注释可以按各种方式插入：

 ¢ 最初方式是在程序中增加两个美分符号 ¢
 COMMENT "粗体"注释 COMMENT
 CO 风格i注释 CO
 # 风格ii注释 #
 £ 针对英国键盘的横杠/英镑注释 £

一般而言，注释在ALGOL 68中不能嵌套。这个限制可以使用不同的注释分界符来绕过。

语用指定（pragmat）是在程序中的编译指导，典型的提示给编译器；在新近的语言中叫做“pragma”。例如：

 PRAGMAT heap=32 PRAGMAT
 PR heap=32 PR

表达式和复合语句
ALGOL 68成为了，赋值语句所返回的值是到目的地的引用。因此下列代码在ALGOL 68中是有效的：

 REAL half pi, one pi; one pi := 2*(half pi := 2*arc tan(1))

这种表示法也出现在C语言和Perl以及其他一些语言之中。注意在早期语言比如ALGOL 60和FORTRAN中，在标识符中的空格是允许的，所以half pi是一个单一的标识符，因而无需采用蛇形命名法或驼峰式大小写。

另一个例子，要表达数学中f(i)从i=1到n的总和，下列ALGOL 68整数表达式就可充任：

 (INT sum := 0; FOR i TO n DO sum +:= f(i) OD; sum)

注意，作为整数表达式，上述的代码块可以用在“整数值可以使用的任何上下”之中。代码块在ALGOL 68称为“系列子句”（serial clause），它返回其中被求值的最后一个表达式的值；这个概念也出现在LISP以及其他一些语言之上。系列子句加上封闭它的一对圆括号或BEGIN与END叫做闭合子句（closed-clause）。

复合语句都终止于独特的闭括号：

IF选择子句
 IF 条件 THEN 诸语句 [ ELSE 诸语句 ] FI
 简短形式：( 条件 | 诸语句 | 诸语句 )

 IF 条件1 THEN 诸语句 ELIF 条件2 THEN 诸语句 [ ELSE 诸语句 ] FI
 简短形式：( 条件1 | 诸语句 |: 条件2 | 诸语句 | 诸语句 )

这种方案不仅避免了问题，还避免了必须对嵌入的语句序列使用BEGIN和END。

CASE选择子句
 CASE 接转 IN 诸语句, 诸语句, ... [ OUT 诸语句 ] ESAC
 简短形式：( 接转 | 诸语句, 诸语句, ... | 诸语句 )

 CASE 接转1 IN 诸语句, 诸语句, ... OUSE 接转2 IN 诸语句, 诸语句, ... [ OUT 诸语句 ] ESAC
 简短形式：( 接转1 | 诸语句, 诸语句, ... |: 接转2 | 诸语句, 诸语句, ... | 诸语句 )

采用粗体符号的选择子句的例子：

 PROC days in month = (INT year, month) INT:
     CASE month IN
     #一月# 31,
     #二月# IF year MOD 4 EQ 0 AND year MOD 100 NE 0 OR year MOD 400 EQ 0 THEN 29 ELSE 28 FI,
           31, 30, 31, 30, 31, 31, 30, 31, 30, 31 # 直到十二月 #
     ESAC;

采用简短符号的选择子句的例子：

 PROC days in month = (INT year, month) INT:
     (month|
      31,
      (year%*4 = 0 AND year%*100 /= 0 OR year%*400 = 0 | 29 | 28),
      31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

粗体和简短符号的选择子句可以混合使用。

ALGOL 68允许接转（switch）具有的类型，要么是INT要么是（独有的）UNION。后者允许在UNION变量上施加强类型，参见后面的联合例子。

DO循环子句
 [ FOR 索引 ] [ FROM 第一个 ] [ BY 增量 ] [ TO 最后一个 ] [ WHILE 条件  ] DO 诸语句 OD

循环语句的极小化形式是：DO 诸语句 OD。

下面是这种“通用”循循的完整例子：

 FOR i FROM 1 BY -22 TO -333 WHILE i*i /= 4444 DO ~ OD

这个构造有一些不寻常的方面：
 只有DO ~ OD部份是强制性的，在这种情况下循环将无限迭代。
 因此子句TO 100 DO ~ OD，将只迭代100次。
 WHILE“语法元素”允许编程者更早的从FOR循环中破出，例如：
 INT sum sq := 0;
 FOR i
 WHILE
     print(("So far:", i, newline));
     sum sq /= 70**2
 DO
     sum sq +:= i**2
 OD

后续的对标准ALGOL 68的扩展，允许TO语法元素被替代为UPTO和DOWNTO来达成小优化。这些编译器还结合了：

 UNTILC – 用于更晚的循环终止。
 FOREACHS – 用于并行的运算于多元组（数组）之上。

结构与联合
ALGOL 68支持多字段结构STRUCT和标签联合UNION。REF可以前导于任何MODE，包括多元组分片和结构字段。

作为递归模态的例子，下面是传统的链表的声明：

 MODE
     VALUE = UNION (VOID, REAL, INT, COMPL, STRING),
     NODE = STRUCT (VALUE val, REF NODE next),
     LIST = REF NODE;

对上述VALUE的UNION使用共形子句（conformity clause）的CASE的例子：

 VALUE v := "1234";  # 或者 v := EMPTY; #
 CASE v IN
     (VOID):     print(("void:", "EMPTY")),
     (REAL r):   print(("real:", r)),
     (INT i):    print(("int:", i)),
     (COMPL c):  print(("compl:", c)),
     (STRING s): print(("string:", s))
     OUT         print("undefined value")
 ESAC

在未修订报告的语言中共形子句的功能通过在CASE子句中采用共形关系CTAB来实现。

多元组

在ALGOL 68中，不再采用术语数组或阵列（array），转而基于数学中的元组（-tuple）定义了多元值（multiple value）亦简称多元组（multiple）。多元组由一定数量的元素组成，每个元素都有相同的模态，有时称之为基础模态。多元组的模态由前导着一对方括号的针对每个元素的模态标示组成，它被读作“的模态”（row of mode），它不同于函数式编程语言如ML中的对应于代数数据类型里的“元组”（tuple）。

ALGOL 68多元组的属性之一是它的维度数目。可以声明任何数目维度的多元组，整数的二维多元组拥有模态[,]INT，它被读作“行套行的整数”（row-row-of-int），而实数的三维多元组拥有模态[,,]REAL。

 MODE VECTOR = [1:3]REAL;  # 向量MODE声明 #
 MODE MATRIX = [1:3,1:3]REAL;  # 矩阵MODE声明 #
 VECTOR v1 := (1,2,3);  # 向量变量初始化为 (1,2,3) #
 []REAL v2 = (4,5,6);  # 常量元组，类型等价于VECTOR，边界是隐含的 #
 OP + = (VECTOR a, b) VECTOR:  # 二元OP即运算符定义 #
     (VECTOR out; FOR i FROM LWB a TO UPB a DO out[i] := a[i]+b[i] OD; out);
 MATRIX m := (v1, v2, v1+v2);

这里的冒号分隔构造：第一个元素的下标 : 最后一个元素的下标，被称为裁剪器（trimmer）。

ALGOL 68的，在概念上涵盖了向多元组的各个维度加（subscript）从而访问其中特定元素的常规情况，但这个术语更常用的保留给至少一个维度不加下标的情况，比如从矩阵中切分出部份横行（row）或纵列（column）。例如：

 REF VECTOR row = m[2,];  # 定义一个REF至矩阵的第二个横行 #
 REF VECTOR col = m[,2];  # 定义一个REF至矩阵的第二个纵列 #
 print ((m[,2:]));  # 打印矩阵的从第二个至最后一个的纵列 #

省略了裁剪器中第一个下标则假定其为此维度的下界，而省略了第二个下标则将假定其为对应的上界，两个下标都省略则产生下界为1的全部分片。

过程
过程（procedure）的PROC声明对参数和结果值二者要求类型指定，如果没有参数则省略参数列表，如果没有结果值则指定结果模态为VOID：

 PROC max of real = (REAL a, b) REAL: (a > b | a | b);

过程的返回值是在过程中求值的最后一个的表达式的值。当进行如下过程调用之时：
 a := max of real(x, y)
得到等价于进行了如下变换后的结果：
 a := REAL (REAL a = x, b = y; (a > b | a | b))

在这个过程之内对变量a和b的赋值是非法的。针对需要变更形式参数所提及的值的情况，ALGOL 68提供了传引用调用参数，用来在形式参数列表中指定引用，比如REF REAL。到过程的引用REF PROC也是允许的。下列例子定义一个过程，它将作为参数而指定的一个函数应用于一个数组的每个元素：

 PROC apply = (REF []REAL a, PROC (REAL) REAL f) VOID:
     FOR i FROM LWB a TO UPB a DO a[i] := f(a[i]) OD;

这种代码的简单性是在ALGOL 68的前身ALGOL 60中不能达成的。

运算符与关联名字的单元
过程和运算符（operator）合称例程（routine），编程者可以定义新的运算符，并且这些自定义的和预定义的运算符二者都可以重载，并且它们的优先级可以由编码者变更。下列例子定义的运算符MAX具有二元和一元形式二者，一元形式在一个数组的元素之上进行扫描。

 PRIO MAX = 9;
 OP MAX = (INT a, b) INT: (a > b | a | b);
 OP MAX = (REAL a, b) REAL: (a > b | a | b);
 OP MAX = (COMPL a, b) COMPL: (ABS a > ABS b | a | b);
 OP MAX = ([]REAL a) REAL:
     (REAL out := a[LWB a];
      FOR i FROM LWB a + 1 TO UPB a DO (a[i] > out | out := a[i]) OD;
      out);

初等和二等单元
初等单元（primary）涵盖封闭子句，此类属自身包括：所应用的标识符、调用、铸型、除了例程指示之外的指示和分片。

所应用的标识符（applied-identifier）意味着标识符在一个上下文之中被使用，并非处在其定义之中。

指示（denotation）是其所产生与任何行动都无关的构造，比如实数指示3.14或字符串指示"abc"，模态VOID只有一个值，其指示是EMPTY。在其他语言中，指示有时叫做“”（literal）或“常值”（constant）。

铸型（cast）构成自一个模态标示（indicant）和随后的通常为闭合子句的封闭子句。铸型可被用来提供强位置，在强上下文中能获得所有的强制。例如在REF REAL (xx) := 1中的REF REAL (xx)。

调用（call）引起（invoke）一个过程，调用在ALGOL 68 Genie中可以被部份参数化（partial parameterisation）：就是说增加实际参数到一个过程的语境（locale）中，当这个语境完全之时调用这个过程，否则发生柯里化。

 优先级 ALGOL68r1“值当字符” ALGOL68G 相当于12  加下标[~]，分片[~,~]，裁剪[~:~]，AT @ DIAG，TRNSP，ROW，COL

二等单元（secondary）包括生成器（generator）和选取（selection）。

 优先级 ALGOL68r1“值当字符” ALGOL68r0−r1 ALGOL68G 相当于11  OF，LOC，HEAP
  →
  NEW

有关的符号在技术上不是运算符，它们转而被当作“关联名字的单元”。

三等单元
三等单元（tertiary）包括公式和NIL（可替代为○）。公式构成自运算符和运算元。

在ALGOL 68中对于名字只有一个指示，那就是含义为不引用任何值的NIL。NIL的模态依赖于上下文，例如：REF INT k = NIL，这里的NIL拥有模态REF INT。尽管NIL是一个名字却不可以对它赋值。

一元运算符
 优先级 ALGOL68r1“值当字符” ALGOL68r1替代符号 ALGOL68C,G ALGOL68r0-r1 相当于10  NOT，-，UP，DOWN，LWB，UPB，ABS，ARG，BIN，ENTIER，LENG，LEVEL，ODD，REPR，ROUND，SHORTEN ¬ ~，↑，↓，⌊，⌈ NORM，TRACE，T，DET，INV LWS ⎩，UPS ⎧，BTB，CTB

二元运算符及其关联的优先级
 优先级 ALGOL68r1“值当字符” ALGOL68r1替代符号 ALGOL68r0−r19  I +*  ⊥ +× !8  UP **，DOWN，LWB，UPB，SHL，SHR  ↑，↓，⌊，⌈  ^ ××，LWS ⎩，UPS ⎧7  *，/，OVER %，MOD %*，ELEM  ×，÷，÷× ÷* %×，□  ÷:6  -，+   5  LT <，LE <=，GE >=，GT >  ≤，≥ 4  EQ =，NE /=  ≠ ¬= ~= 3  AND  ∧ & /\ 2  OR  ∨  \/1  MINUSAB -:=，PLUSAB +:=，TIMESAB *:=，DIVAB /:=，OVERAB %:=，MODAB %*:=，PLUSTO +=:
  ×:=，÷:=，÷×:= ÷*:= %×:= MINUS，PLUS，TIMES，DIV，OVERB，MODB ÷::=，PRUS
LWB（可替代为⌊）和UPB（可替代为⌈），这两个运算符所运算的多元组运算元的模态是ROW，它是指称任何的模态。在未修订报告的语言中，LWS（可替代为⎩）和UPS（可替代为⎧），分别是在一个多元组（数组）的这个维度的“下界状态”和“上界状态”为固定的（fixed）的情况下返回TRUE。

四等单元
四等单元（quaternary）包括：赋值、同一关系、例程指示（也称作例程正文）和SKIP（可替代为~）。四等单元并非语言报告中的术语，它是给从单元这个类属中除去封闭子句、初等单元、二等单元和三等单元所余下的只称为“单元”的类属的别名。

SKIP产生任何模态的未定义的值，并且只能出现在强上下文中。
 优先级 ALGOL68r1“值当字符” ALGOL68r1替代符号 ALGOL68C,R ALGOL68r0−r1 相当于0  :=，IS :=:，ISNT :/=:  :≠: :¬=: :~=: :=:=C，=:=R  ..= .=，IS NOT，CT ::，CTAB ::=

在ALGOL 68中除了恒等声明之外的所有构造都有一个值，它允许链式赋值，例如a := b := c，这些赋值是从右至左执行的。

同一关系包括：IS（可替代为:=:）测试两个引用是否相等；ISNT（可替代为:/=:）测试两个引用是否不相等。同一关系的一侧是可以在强制时解引用来匹配另一侧的强侧，而另一侧则为软侧，不允许两侧都解引用。

强制
强制（coercion）依据三个要件，从被强制者（coercend）产生已强制者（coercee）：在应用任何强制之前作为要被强制者的一个先验模态，在这些强制之后作为已被强制者的一个后验模态，已强制者的的语法位置（position）或类属（sort）。强制是可以级联的（cascaded）。

有7种可能的强制，其术语为解过程化（deproceduring），解引用（dereferencing）和弱解引用（weakly-dereferencing），联合化（uniting），扩充（widening）、入行（rowing）和弃置（voiding）。除了联合化之外，每种强制都在所关联的值之上，规制（prescribe）一个相应的动态效果。因此，可以使用强制来编程很多原始行动。

允许特定强制的境况（circumstance）叫做上下文（context）。下面列出每种上下文所固有的强度及其允许的强制：

 软（soft）– 解过程化。
 弱（weak) – 软强制，随后弱解引用而产生一个名字。
 柔（meek）– 软强制，随后解引用。
 硬（firm）– 柔强制，随后联合化。
 强（strong）– 硬强制，随后扩充、入行或弃置。

在任何上下文中，都有拥有或产生某种模态的值的一个单元，并且在这个上下文中亦有所需的一个模态。如果两个模态不同而现有模态的值能够强制成所需模态的值，则这种强制是合法的。

平衡是将IF、CASE和共形子句中的交替者（alternative）即可供选择者，和同一关系的两侧，都强制成共同（common）的模态的手段，这使得所涉及构造的上下文会被提升（promote）从而获得这种强制。

 强制层级及例子 
ALGOL 68有着上下文层级，它确定在程序中特定点之上可获得的强制的种类。这种上下文分为五个层次：
 上下文 上下文位置  可获得的强制 在此上下文中强制例子软弱柔硬强强 
 恒等（identity）声明的右手侧，如~之于REAL …… = ~
 初始化的名字声明的右手侧，如~之于REAL …… := ~
 赋值的右手侧，如~之于 …… := ~
 调用的实际参数，如~之于 ……(~)
 铸型（cast）的封闭子句，如~之于REAL(~)
 例程指示的单元
 产生VOID的单元
 平衡（balanced）子句的除第一部份之外的所有部份
 同一关系的一侧，它可能需要解引用来适配于另一侧，如xx之于xx := x; xx IS x 解过程化 只在弱上下文时软强制再弱解引用 软强制再解引用 柔强制再联合化 硬强制再扩充或入行或弃置扩充出现在没有精度损失的情况下。例如：
 LONG INTINT 
 REALINT
 LONG REALREAL
 COMPLREAL
 []BOOLBITS 
 STRINGBYTES 
变量可以入行为长度为1的多元组。例如:
 [1]INTINT 
 [1]REALREAL硬公式的运算元，如~之于~ + ~
传输调用的实际参数 例子：
UNION(INT, REAL) var := 1柔剪标（trimscript）：裁剪器、下标和边界，产生INT
 质询（enquiry）子句，如~之于IF ~ THEN …… FI和 FROM ~ BY ~ TO ~ WHILE ~ DO …… OD
 调用的初等单元（被调用者），如~之于~(……)例子：
 BOOLREF REF BOOL 
 INTREF REF REF INT弱 分片的初等单元（被分片者），如~之于~[……]
 选取的二等单元（被选取者），如~之于…… OF ~例子：
 REF INTREF REF INT 
 REF REALREF REF REF REAL
 REF STRUCTREF REF REF REF STRUCT软 赋值的左手侧，如~之于~ := ……
 同一关系的另一侧，它被其中一侧可能需要解引用来匹配，如x之于xx := x; xx IS x 例子：
 PROC REAL rnd := random的解过程化：rnd

正交性
ALGOL 68文法的表达依据了一些原始概念：值、模态、上下文、强制和短语（phrase）。短语是声明和单元二者之一。共有5种上下文、7种强制、22种不同的单元，和潜在无穷数量的值和模态。在每种上下文中都有可获得的强制。

正交性所称谓的是基本概念可以被没有副作用的组合。原始概念：值、模态、上下文、强制和短语，是相互独立的，它们的组合给予了ALGOL 68少有编程语言拥有的灵活性。举个例子，如果需要模态INT的一个值，比如在多元组的声明的裁剪器或边界中，那么在这个上下文中任何会产生一个整数的单元都可充任。其结果是ALGOL 68程序可以用宽广多样的风格来书写。例如打印从键盘读取的两个数的总和，用常规风格可以写为：

 INT a, b;
 read((a, b));
 print((a + b, newline))

也可以等价的写为：

 print(((INT a, b;
     read((a, b));
     a + b), newline))

只要所书写的是合法的ALGOL 68代码，可以采用编程者喜好的任何方式。这种独立性的另一个结果是语言的规则极少有例外。

传输
传输（transput）是ALGOL 68用来称谓输入和输出设施的术语。它包括针对非格式化、格式化和二进制传输的预定义的过程。文件和其他传输设备以机器无关的方式来处理。下面的例子打印出一些非格式化的输出到“标准输出”设备：

 print ((newpage, "Title", newline, "Value of i is ",
     i, "and x[i] is ", x[i], newline))

注意预定义的过程newpage和newline作为实际参数而传送。

print和read接受可能具有各种所需模态的实际参数，这些例程的形式参数具有成行的联合模态：
 PROC print = ([]SIMPLOUT items) VOID: …… ;
 MODE SIMPLOUT = UNION (
     INT, REAL, BOOL, CHAR,
     []INT, []REAL, []BOOL, []CHAR,
     [,]INT, [,]REAL, [,]BOOL, [,]CHAR,
     …… );
 PROC read = ([]SIMPLIN items) VOID: …… ;
 MODE SIMPLIN = UNION (
     REF INT, REF REAL, REF BOOL, REF CHAR,
     REF []INT, REF []REAL, REF []BOOL, REF []CHAR,
     REF [,]INT, REF [,]REAL, REF [,]BOOL, REF [,]CHAR,
     …… );

read使用的模态SIMPLIN是来自各种名字的模态的联合。print使用共形子句来从参数行中每个元素提取出实际的值。

在ALGOL 68中“格式化传输”拥有自己的语法和模式（函数），具有嵌入在两个$字符之间的FORMAT。例如：

 printf (($2l"The sum is:"x, g(0)$, m + n)); # 其打印相同于下列： #
 print (new line, new line, "The sum is:", space, whole(m + n, 0))

并行处理
ALGOL 68支持并行处理编程。使用关键字PAR，可以将“并立子句”转换成“并行子句”，这里的行动的同步使用信号量来控制。并行行动在ALOGL 68 Genie中被映射到线程上，如果它们在宿主操作系统上能获得到的话。例如：

 PROC
     eat = VOID: (muffins -:= 1; print(("Yum!", newline))),
     speak = VOID: (words -:= 1; print(("Yak...", newline)));
 INT muffins := 4, words := 8;
 SEMA mouth = LEVEL 1;
 PAR BEGIN
     WHILE muffins > 0 DO
         DOWN mouth;
         eat;
         UP mouth
     OD,
     WHILE words > 0 DO
         DOWN mouth;
         speak;
         UP mouth
     OD
 END

未修订报告的语言
原本依据1968年最终报告的语言在模态铸型的语法上有所不同，并且它拥有过程化（proceduring）这个特征，就是说，将一个项目的值强制成求值这个项目的一个过程。过程化意图进行惰性求值。最有用的应用是实现布尔运算符的短路求值：

 OP ANDF = (BOOL a, PROC BOOL b) BOOL: (a | b | FALSE);
 OP ORF = (BOOL a, PROC BOOL b) BOOL: (a | TRUE | b);

在ANDF中，b只在a为TRUE的情况下才求值。预期下面例子中的print不会被执行：

 IF FALSE ANDF (print("Should not be executed"); TRUE) THEN …… FI

语言修订之后，已经不再允许这种从模态BOOL到模态PROC BOOL的强制和铸型。ALGOL 68 Genie将ANDF和ORF作为扩展而实现为伪运算符。

在语言修订之前，编程者可以通过使用叫做“gomma”的分号替代逗号（comma），从而决定一个过程的参数串行而非并立的求值。例如：

 PROC test = (REAL a; REAL b): …… ;
 test (x +:= 1, x);

这里保证第一个实际参数求值在第二个实际参数之前，但是在平常情况：

 PROC test = (REAL a, b): …… ;
 test (x +:= 1, x);

这时编译器可以按它喜好的次序来求值实际参数。

参见

 ALGOL 60


 C
 C++

 Bourne shell
 Bash（Unix shell）

註釋

参考文献









外部链接
 Revised Report on the Algorithmic Language ALGOL 68 The official reference for users and implementors of the language (large pdf file, scanned from Algol Bulletin)
 Revised Report on the Algorithmic Language ALGOL 68 Hyperlinked HTML version of the Revised Report
 A Tutorial on Algol 68, by Andrew S. Tanenbaum, in Computing Surveys, Vol. 8, No. 2, June 1976, with Corrigenda (Vol. 9, No. 3, September 1977)
 Algol 68 Genie – a GNU GPL Algol 68 compiler-interpreter
 Open source Algol 68 implementations, on SourceForge
 Algol68 Standard Hardware representation
 Из истории создания компилятора с Алгол 68
 Algol 68 – 25 Years in the USSR
 McJones, Paul, "Algol 68 implementations and dialects", Software Preservation Group, Computer History Museum, 2011-07-05

Category:学术的编程语言
Category:ALGOL程式語言家族
Category:1968年建立的程式語言