ALGOL 68(源自英语:ALGOrithmic Language 1968的缩写),一种指令式程式语言,为ALGOL家族的成员,是官方上的ALGOL 60后继者。它设计的目标,是提供更广泛的应用,以及更严格的语法定义。
编程范型 | 多范式:指令式,过程式,结构化,并发 |
---|---|
设计者 | 阿德里安·范·韦恩加登, B.J. Mailloux, J.E.L. Peck, C.H.A. Koster等人 |
发行时间 | 最终报告: 1968年 |
型态系统 | 静态、强类型、安全、结构式 |
网站 | Revised Report on the Algorithmic Language ALGOL 68 |
主要实作产品 | |
ALGOL 68C, ALGOL 68 Genie(新近[1]), ALGOL 68-R, ALGOL 68RS, ALGOL 68S, FLACC, 列宁格勒ALGOL 68, Odra ALGOL 68 | |
衍生副语言 | |
ALGOL 68r0 (最终报告:1968年), ALGOL 68r1 (修订报告:1973年) | |
启发语言 | |
ALGOL 60, ALGOL Y | |
影响语言 | |
C[2]、C++[3]、Bourne shell、KornShell、Bash、Steelman、Ada、Python[4]、Seed7、Mary、S3 |
ALGOL 68的特征包括基于表达式的语法,用户声明的类型和结构/加标记的联合,变量和引用参数的引用模型,字符串、数组和矩阵的分片,以及并发。
概论
ALGOL 68由IFIP工作组2.1负责设计。1968年12月20日,IFIP工作组2.1通过了这个语法规范,并提交IFIP大会通过且出版。
ALGOL 68的定义使用了阿德里安·范·韦恩加登发明的一种数学形式主义的两级形式文法。Van Wijngaarden文法使用分别称为“超文法”和“元文法”的两组上下文无关文法规则,生成形成一个无限集合的一些产生式,它们将识别特定的ALGOL 68程序;值得注意的是,它们能够表达在很多其他编程语言的技术标准中被标记为“语义”的那种要求,其他语言的语义必须用易致歧义的自然语言叙述来表达,并接着在编译器中实现为附加到形式语言解析器的“特设”代码。
ALGOL 68设计的主要目标和原则为:
ALGOL 68曾受到批评,最突出的是来自其设计委员会的一些成员比如C. A. R. Hoare[7],还有ALGOL 60编译器作者比如Edsger Dijkstra[8],它抛弃了ALGOL 60的简单性,成为了复杂或过于笼统的想法的载体,不能使编译器作者的任务变得更轻易些,与刻意保持简单的同时代(竞争)者如C、S-algol和Pascal形成了鲜明对比。
在1970年,ALGOL 68-R成为了第一个投入工作的ALGOL 68编译器。
在1973年9月确定的修订版本中,省略了特定特征比如过程化、gomma[9]和形式边界[5]。
Stephen R. Bourne是ALGOL 68修订委员会成员,他选取了它的一些想法到他的Bourne shell之中。
ALGOL 68的语言定义出版后的文本长达两百多页并充斥着非标准术语,这种复杂性使得编译器实现变得困难,故而它曾被称为“没有实现也没有用户”。这么说只是部份真实的,ALGOL 68曾应用于一些小众市场,特别是流行于英国的国际计算机有限公司(ICL)的机器之上,还有在教学角色之上。在这些领域之外,其使用相对有限。
尽管如此,ALGOL 68对计算机科学领域的贡献是深刻、广泛而持久的,虽然这些贡献大多只是在它们于后来开发的编程语言中重现之时才被公开认可。很多语言是为了应对这门语言的复杂性而专门开发的,其中最著名的是Niklaus Wirth的Pascal[10],或者是针对特定角色而重新实现的,比如有些人认为Ada可以看作ALGOL 68的后继者[11]。
1970年代的很多语言可以追溯其设计至ALGOL 68,选取一些特征,并放弃被认为太复杂或超出给定角色范围的其他特征。其中就有C语言,它受到ALGOL 68的直接影响,特别是它的强类型和结构。多数现代语言都至少可以追溯其部份语法至要么C语言要么Pascal,因而很多语言可直接或间接的经由C语言而追溯至ALGOL 68。
规定和实现时间线
名称 | 年 | 用途 | 国家 | 描述 | 目标CPU | 属主/许可证 | 实现语言 |
---|---|---|---|---|---|---|---|
广义ALGOL | 1962 | 科学 | 荷兰 | 广义文法的ALGOL[12] | |||
ALGOL 68DR | 1968 | 草案 | IFIP WG 2.1草案报告[13] | ||||
ALGOL 68r0 | 1968 | 标准 | IFIP WG 2.1最终报告[14] | ||||
ALGOL 68-R | 1970 | 军用 | 英国 | 在GEORGE 3下的ALGOL 68 | ICL 1900 | 皇家雷达研究所 | ALGOL 60 |
DTSS ALGOL 68 | 1970 | 美国 | 达特茅斯分时系统的ALGOL 68[15] | GE-635 | 达特茅斯学院 | ||
Mini ALGOL 68 | 1973 | 研究 | 荷兰 | 针对简单Algol 68程序的解释器[16] | 可移植解释器 | 荷兰数学中心 | ALGOL 60 |
OREGANO | 1973 | 研究 | 美国 | “实现模型的重要性。”[17] | 加州大学洛杉矶分校 | ||
ALGOL 68C | 1975 | 科学 | 英国 | 剑桥Algol 68 | ICL, IBM System/360, PDP-10 和 Unix, Telefunken, Tesla & Z80 (1980)[18] | 剑桥大学 | ALGOL 68C |
ALGOL 68r1 | 1975 | 标准 | IFIP WG 2.1修订报告[19] | ||||
Algol H | 1975 | 实验等 | 英国 | 对Algol 68的模态系统提议了扩展[20] | ALGOL W | ||
CDC ALGOL 68 | 1975 | 科学 | 美国 | 完全实现的ALGOL 68[21] | CDC 6000系列, CDC Cyber | 控制数据公司 | |
Odra Algol 68 | 1976 | 实用 | 苏联/ 波兰 | Odra 1204/IL | ALGOL 60 | ||
俄克拉何马ALGOL 68 | 1976 | 编程指导 | 美国 | 俄克拉何马州立大学实现[22] | IBM 1130和System/370 Model 158 | 俄克拉何马州立大学 | ANSI Fortran 66 |
柏林ALGOL 68 | 1977 | 研究 | 德国 | 柏林ALGOL 68实现[23] | 抽象ALGOL 68机器 – 机器无关编译器 | 柏林工业大学 | CDL 2 |
FLACC | 1977 | 多用途 | 加拿大 | 具有调试特征的修订报告完整实现 | System/370 | 租用, Chion公司 | 汇编 |
ALGOL 68RS | 1977 | 军用 | 英国 | 可移植编译器 | ICL 2900系列, Multics, VMS 和 C生成器 (1993) | 皇家信号与雷达研究所 | ALGOL 68RS |
ALGOL 68-RT | 1979 | 科学 | 英国 | 并行ALGOL 68-R | |||
ALGOL 68+ | 1980 | 科学 | 荷兰 | 提议的ALGOL 68的超语言[24] | |||
M-220 ALGOL 68 | 苏联 | M-220 | EPSILON | ||||
列宁格勒ALGOL 68 | 1980 | 电信 | 苏联 | 完全语言 + 模块 | IBM, DEC, CAMCOH, PS 1001 和 PC | ||
交互式ALGOL 68 | 1983 | 英国 | 增量编译 | PC | 非商业共享软件 | ||
ALGOL 68S | 1985 | 科学 | 英国 | ALGOL 68的子集语言[25] | Sun-3, Sun SPARC (在SunOS 4.1和Solaris 2之下), Atari ST (在GEMDOS之下), Acorn Archimedes (在RISC OS之下), VAX-11在Ultrix-32之下 | 曼彻斯特维多利亚大学 | BLISS |
Algol68toC[26] | 1985 | 电子 | 英国 | 基于源自ELLA ALGOL 68RS的ctrans | 可移植C生成器 | 开源软件 1995 | ALGOL 68RS |
MK2 交互式ALGOL 68 | 1992 | 英国 | 增量编译 | PC | 非商业共享软件[27] | ||
Algol 68 Genie | 2001 | 完全语言 | 荷兰 | 包括标准的并立子句 | 可移植解释器 | GNU GPL | C |
Algol 68 Genie版本2 | 2010 | 完全语言 | 荷兰 | 可移植解释器;可选的选定单元的编译 | GNU GPL | C |
样例代码
下面的样例代码实现了埃拉托斯特尼筛法来找到小于等于100的所有素数。ALGOL 68中NIL
类似于其他语言中的空指针,x OF y
表示访问STRUCT y
的成员x
。
BEGIN # ALGOL68的素数筛法,基于链表实现 #
MODE
LIST = REF NODE,
NODE = STRUCT (INT h, LIST t);
OP CONS = (INT n, LIST l) LIST: HEAP NODE := (n, LIST: l);
PRIO CONS = 9;
PROC
one to = (INT n) LIST:
(PROC f = (INT m) LIST: (m > n | NIL | m CONS f(m+1));
f(1)),
error = (STRING s) VOID:
(print((newline, " error: ", s, newline)); GOTO stop),
hd = (LIST l) INT: (l IS NIL | error("hd NIL"); SKIP | h OF l),
tl = (LIST l) LIST: (l IS NIL | error("tl NIL"); SKIP | t OF l),
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:
IF l IS NIL THEN NIL
ELIF p(hd(l)) THEN hd(l) CONS filter(p, tl(l))
ELSE filter(p, tl(l))
FI;
PROC sieve = (LIST l) LIST:
IF l IS NIL THEN NIL
ELSE
PROC not multiple = (INT n) BOOL: n MOD hd(l) NE 0;
hd(l) CONS sieve(filter(not multiple, 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, BITS,BOOL,BYTES,CHAR,COMPL,INT,REAL,SEMA,STRING,VOID, CHANNEL,FILE,FORMAT,STRUCT,UNION, AT @,EITHERr0,IS :=:,ISNT IS NOTr0 :/=: :≠:,OF →r0,TRUE,FALSE,EMPTY,NIL ○,SKIP ~, CO COMMENT ¢,PR PRAGMAT, CASE ~ IN ~ OUSE ~ IN ~ OUT ~ ESAC ( ~ | ~ |: ~ | ~ | ~ ), FOR ~ FROM ~ TO ~ BY ~ WHILE ~ DO ~ OD, IF ~ THEN ~ ELIF ~ THEN ~ ELSE ~ FI ( ~ | ~ |: ~ | ~ | ~ ), PAR,BEGIN ~ END ( ~ ),GO TO GOTO,EXIT □r0。
基本语言构造是“单元”(unit)。单元可以是“公式”、“闭合子句”、“例程正文”和某个技术上需要的那些构造(赋值、跳转、跳跃、空无)。技术术语“闭合子句”(enclosed clause)统一了某些固有的加括号的构造,在其他当代语言种被称为“块”、“do语句”、“switch语句”。在使用关键字的时候,通常使用介入关键字的反转字符序列来终结这个闭包(enclosure),比如( IF ~ THEN ~ ELSE ~ FI, CASE ~ IN ~ OUT ~ ESAC, FOR ~ WHILE ~ DO ~ OD )
。这种守卫命令语法被Stephen Bourne重新使用在常用的Unix Bourne shell之中。一个表达式还可以产生“多个值”,它是通过“并立子句”(collateral clause)从其他一些值构造出来的。这种构造看起来就像过程调用的参数包(pack)。
基本数据类型在ALGOL 68用语中叫做“模态”(mode),包括:REAL
、INT
、COMPL
(复数)、BOOL
、CHAR
、BITS
和BYTES
。例如:
INT n = 2; CO n被固定为常量2 CO INT m := 3; CO m是新建的局部变量,它的值被初始化为3 CO CO 这是REF INT m = LOC INT := 3;的简写 CO REAL avogadro = 6.0221415⏨23; CO 阿伏伽德罗常数 CO LONG LONG REAL long long pi = 3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510; COMPL square root of minus one = 0 ⊥ 1;
然而,声明REAL x;
只是REF REAL x = LOC REAL;
的语法糖。就是说,x
实际上是“常量标识符”,它“引用到”一个新创建的局部REAL变量。
进一步的,不再定义float
和double
,或者long
和short
等,ALGOL 68提供了修饰符(modifier),以目前常见的double
为例,它们将写为LONG REAL
或LONG LONG REAL
。提供了预置常量(prelude constant)max real
和min long int
来将程序适配到不同实现之中。
所有变量都必须被声明,但是声明不必须先于第一次使用。
原始声明符:INT、REAL、COMPL、COMPLEXG、BOOL、CHAR、STRING、BITS、BYTES、FORMAT、FILE、PIPEG、CHANNEL、SEMA。
- BITS – BOOL值的包装向量(packed vector)。
- BYTES – CHAR值的包装向量。
- STRING – CHAR值的FLEX(灵活)数组。
- SEMA – 可以通过OP LEVEL初始化的信号量。
复杂类型可以使用各种类型构造子创建自更简单的类型:
- REF
mode
– 到类型mode
的值的引用,类似于C/C++中和Pascal中的指针。 - STRUCT – 用来建造结构,类似于C/C++中的
struct
和Pascal中的recode
。 - UNION – 用来建造联合,类似于C/C++和Pascal中的
union
。 - PROC – 用来指定过程,类似于C/C++中的函数和Pascal中的过程/函数。
具体例子可参见ALGOL 68与C++的比较。
其他声明符号包括:FLEX、HEAP、LOC、REF、LONG、SHORT、EVENTS。
- FLEX – 声明这个数组是灵活的,就是说它的长度可以按需要增长。
- HEAP – 为变量从全局堆中分配一些空闲空间。
- LOC – 为变量分配这个局部栈的一些空闲空间。
- LONG – 声明INT、REAL或COMPL的大小为LONG。
- SHORT – 声明INT、REAL或COMPL的大小为SHORT。
声明模态(类型)的名字可以使用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 );
这类似于如下C语言代码:
const int max=99;
typedef struct {
double a, b, c; short i, j, k; float *r;
} newmode[9+1][max+1];
对于ALGOL 68,只有模态指示符NEWMODE
出现在等号的左侧,最值得注意的是,构造的制造和读取,是从左至右而不顾及优先级的。还有ALGOL 68数组的下界(lower bound)缺省的是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
强制(coercion)依据三个要件,从被强制者(coercend)产生已强制者(coercee):在应用任何强制之前作为被强制者的一个先验模态,在这些强制之后作为已经强制者的一个后验模态,已强制者的的语法位置(position)或类属(sort)。强制是可以级联的(cascaded)。
有六种可能的强制,其术语为解过程化(deproceduring),解引用(dereferencing), 单元化(uniting),扩大化(widening)、成行化(rowing)和成空化(voiding)。除了单位化之外,每种强制都在所关联的值之上规制一个相应的动态效果。因此,很多原始行动可以使用强制来编程。
上下文强度 – 允许的强制:
- 软(soft)– 解过程化。
- 弱(weak) – 解引用或解过程化,产生一个名字。
- 柔(meek)– 解引用或解过程化。
- 硬(firm)– 柔强制,随后单元化。
- 强(strong)– 硬强制,随后扩大化、成行化或成空化。
ALGOL 68有着上下文层级,它确定在程序中特定点之上可获得的强制的种类。这种上下文是为:
上下文 | 上下文位置 | 可获得的强制 | 在此上下文中强制例子 | ||||
---|---|---|---|---|---|---|---|
软 | 弱 | 柔 | 硬 | 强 | |||
强 | 如下情况中的右手侧:
还有:
|
解过程化 | 都软强制再解引用或解过程化产生一个名字 | 都弱强制再解引用或解过程化 | 都柔强制再单元化 | 都硬强制再扩大或成行或成空 |
扩大化出现在没有精度损失的情况下。例如:
变量可以成行化为长度为1的数组。例如:
|
硬 |
|
例子:
| |||||
柔 |
|
例子:
| |||||
弱 |
|
例子:
| |||||
软 | 赋值的左手侧,如~ 之于~ := ...
|
例子:
|
关于一级符号(primary)、二级符号(secondary)、三级符号(tertiary)和四级符号(quaternary)可参见运算符优先级。
指示(pragmat)在程序中的编译指导,典型的提示给编译器;在新近的语言中叫做“pragma”。例如:
PRAGMAT heap=32 PRAGMAT PR heap=32 PR
注释可以按各种方式插入:
¢ 最初方式是在程序中增加两个美分符号 ¢ COMMENT "粗体"注释 COMMENT CO 风格i注释 CO # 风格ii注释 # £ 针对英国键盘的横杠/英镑注释 £
一般而言,注释在ALGOL 68中不能嵌套。这个限制可以使用不同的注释分界符来绕过,比如只对临时代码删除使用井号。
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)
注意,作为整数表达式,前面的代码块可以用在“整数值可以使用的任何上下”之中。代码块返回它被求值的最后一个表达式的值;这个概念也出现在LISP以及其他一些语言之上。
复合语句都终止于独特的闭括号:
- IF选择子句:
IF 条件 THEN 诸语句 [ ELSE 诸语句 ] FI “简短”形式: ( 条件 | 诸语句 | 诸语句 )
IF 条件1 THEN 诸语句 ELIF 条件2 THEN 诸语句 [ ELSE 诸语句 ] FI “简短”形式: ( 条件1 | 诸语句 |: 条件2 | 诸语句 | 诸语句 )
这种方案不仅避免了悬摆else问题,还避免了必须对嵌入的语句序列使用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: (month| 31, (year÷×4=0 ∧ year÷×100≠0 ∨ year÷×400=0 | 29 | 28 ), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
采用“粗体”符号的选择子句的例子:
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: CASE month IN ¢一月¢ 31, ¢二月¢ ( year MOD 4 = 0 AND year MOD 100 ≠ 0 OR year MOD 400 = 0 | 29 | 28 ), ¢三月¢ 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ¢ 直到十二月 ¢ ESAC;
Algol68允许开关具有类型要么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
后续的对标准Algol68的扩展允许TO语法元素被替代为UPTO和DOWNTO来达成小优化。这些编译器还结合了:
- UNTIL(C) – 用于更晚的循环终止。
- FOREACH(S) – 用于并行的运算于数组之上。
进一步的例子可以在下面的代码例子中找到。
ALGOL 68支持据于任意数目维度的数组,并且允许整体或部份横行或纵列的切片。
MODE VECTOR = [1:3] REAL; # vector MODE声明 (即类型定义) # MODE MATRIX = [1:3,1:3]REAL; # matrix 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 ⌊a TO ⌈a DO out[i] := a[i]+b[i] OD; out); MATRIX m := (v1, v2, v1+v2); print ((m[,2:])); # 第二和第三纵列的切片 #
矩阵可以用任何一种方式定义,例如:
REF VECTOR row = m[2,]; # 定义一个REF(类似指针)到第二横行 # REF VECTOR col = m[,2]; # 定义一个REF(类似指针)到第二纵列 #
ALGOL 68支持多字段结构STRUCT和标签联合UNION。引用变量可以指向任何MODE,包括数组切片和结构字段。
作为递归模态的例子,下面是传统的链表的声明:
MODE NODE = UNION (VOID, REAL, INT, COMPL, STRING), LIST = STRUCT (NODE val, REF LIST next);
对上述NODE
的UNION使用CASE的例子:
Algol68r0遵循1968年最终报告 | Algol68r1遵循1973年修订报告 |
---|---|
NODE n := "1234"; REAL r; INT i; COMPL c; STRING s CASE r,i,c,s::=n IN print(("real:", r)), print(("int:", i)), print(("compl:", c)), print(("string:", s)) OUT print(("?:", n)) ESAC |
NODE n := "1234"; # 或者 n := EMPTY; # CASE n 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(("?:", n)) ESAC |
过程PROC声明对参数和结果二者要求类型指定,如果无结果则为VOID:
PROC max of real = (REAL a, b) REAL: IF a > b THEN a ELSE b FI;
或者使用条件语句的“简短”形式:
PROC max of real = (REAL a, b) REAL: (a>b | a | b);
PROC
的返回值是在过程中求值的最后一个的表达式的值 。到过程的引用REF PROC也是允许的。提供了传引用调用参数来在形式参数列表中指定引用,比如REF REAL
。下列例子定义一个过程,它将(作为参数而指定的)一个函数应用于一个数组的每个元素:
PROC apply = (REF [] REAL a, PROC (REAL) REAL f): FOR i FROM LWB a TO UPB a DO a[i] := f(a[i]) OD
这种代码的简单性是在ALGOL 68的前身ALGOL 60中不能达成的。
编程者可以定义新的运算符,并且这些自定义的和预定义的运算符二者都可以重载,并且它们的优先级可以由编码者变更。下列例子定义的运算符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)
这些符号在技术上不是运算符,它们转而被“当作关联着名字的单元”[28]。
PRIO (三级符号) |
Algol68“杰出字符”r0&r1 | +Algol68r0&r1 | +Algol68r0 |
---|---|---|---|
9 | +*,I | +×,⊥ | ! |
8 | SHL,SHR,**,UP,DOWN,LWB,UPB | ↑,↓,⌊,⌈ | ××,^, 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,DIV,OVERB,MODB,÷::=,PRUS |
特殊细节:
- 三级符号包括名字NIL和
○
。 - LWS:在ALGOL 68r0中,运算符LWS和
⎩
,在一个数组的这个维度的“下界状态”为固定的(fixed)的情况下, 二者都返回TRUE。 - UPS和
⎧
运算符针对“上界状态”。 - LWB和UPB运算符自动的可获得在一个数组的不同阶次(和MODE)的UNION之上,例如:
UNION([]INT, [,]REAL, FLEX[,,,]CHAR)
的UPB。
这些符号在技术上不是运算符,它们转而被“当作关联着名字的单元”[28]。
注意:四级符号包括名字SKIP和~
。
IS(可替代为:=:
)测试两个引用是否相等;ISNT(可替代为:/=:
)测试两个引用是否不相等。
多数ALGOL的“特殊”字符(⊂, ≡, ␣, ×, ÷, ≤, ≥, ≠, ¬, ⊃, ≡, ∨, ∧, →, ↓, ↑, ⌊, ⌈, ⎩, ⎧, ⊥, ⏨, ¢, ○, □
),可以在具有APL符号的IBM 2741键盘上找到;故而这些字符在1960年代中期起草ALGOL 68的时候就能获得到。这些字符也是Unicode标准的一部份并且在一些流行字体中可获得到。
传输(transput)是ALGOL 68用来称谓输入和输出设施的术语。它包括针对非格式化、格式化和二进制传输的预定义的过程。文件和其他传输设备以机器无关的方式来处理。下面的例子打印出一些非格式化的输出到“标准输出”设备:
print ((newpage, "Title", newline, "Value of i is ", i, "and x[i] is ", x[i], newline))
注意预定义的过程newpage
和newline
作为实际参数而传送。
在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!",new line))), speak = VOID: ( words-:=1; print(("Yak...",new line))); 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);
其中的b
只有在a
为真的情况下才求值。
在修订之前,编程者可以通过使用叫做“gomma”的分号替代逗号,从而决定一个过程的参数串行而非并立的求值。例如:
PROC test = (REAL a; REAL b) :... ... test (x PLUS 1, x);
这里保证第一个实际参数求值在第二个实际参数之前,但是在平常情况:
PROC test = (REAL a, b) :... ... test (x PLUS 1, x);
这时编译器可以按它喜好的次序来求值实际参数。
参见
- ALGOL 60
- ALGOL Y
- ALGOL N
- ALGOL 68C
- C
- C++
- ALGOL 68与C++的比较
- Bourne shell
- Bash (Unix shell)
注释
外部链接
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.