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

Quick Facts 編程範型, 設計者 ...
ALGOL 68
編程範型多范型指令式過程式結構化並發
設計者阿德里安·范·韋恩加登, B.J. Mailloux英語Barry J. Mailloux, J.E.L. Peck英語John E. L. Peck, C.H.A. Koster英語Cornelis H.A. Koster等人
面市時間最終報告: 1968年,​56年前​(1968
修訂報告: 1973年,​51年前​(1973
型態系統靜態強類型安全結構式英語Structural type system
網站Revised Report on the Algorithmic Language ALGOL 68
主要實作產品
Algol68toC[1], ALGOL 68 Genie[2], ALGOL 68-R英語ALGOL 68-R, ALGOL 68C英語ALGOL 68C, ALGOL 68RS英語ALGOL 68RS, ALGOL 68S英語ALGOL 68S, FLACC英語FLACC
衍生副語言
ALGOL 68r0 (最終報告:1968年),
ALGOL 68r1 (修訂報告:1973年)
啟發語言
ALGOL 60, ALGOL X英語ALGOL X, ALGOL Y英語ALGOL Y
影響語言
C[3]C++[4]Bourne shellKornShellBashSteelman英語Steelman language requirementsAdaPython[5]Seed7英語Seed7Mary英語Mary (programming language)S3英語S3 (programming language)
Close

ALGOL 68的特徵包括基於表達式英語Expression-oriented programming language的語法,用戶聲明的類型結構標籤聯合類型,變量和引用參數的引用模型可變長數組,字符串、數組和矩陣的分片英語array slicing,用戶定義的運算符運算符重載高階函數匿名函數,以及並發

概論

ALGOL 68由IFIP工作組2.1英語IFIP Working Group 2.1負責設計。1968年12月20日,IFIP工作組2.1通過了這個語法規範,並提交IFIP大會通過且出版。

ALGOL 68的定義使用了阿德里安·范·韋恩加登發明的一種數學形式主義的兩級形式文法Van Wijngaarden文法英語Van Wijngaarden grammar使用分別稱為「超規則」和「元產生式規則」的兩組上下文無關文法規則,生成形成一個可能無限的產生式集合,而這些常規的產生式將識別特定的ALGOL 68程序;值得注意的是,它們能夠表達在很多其他編程語言的技術標準中被標記為「語義」的那種要求,其他語言的語義必須用易致歧義的自然語言敘述來表達,並接着在編譯器中實現為附加到形式語言解析器的「特設」代碼。

ALGOL 68設計的主要目標和原則為:

  1. 描述的完備性和清晰性[6]
  2. 設計的正交性[7]
  3. 安全性[6]
  4. 高效性[6]

在1970年,ALGOL 68-R英語ALGOL 68-R成為了第一個投入工作的ALGOL 68編譯器。在1973年9月確定的修訂版本中,省略了特定特徵比如過程化、gomma和形式邊界[6]Stephen R. Bourne是ALGOL 68修訂委員會成員,他選取了它的一些想法到他的Bourne shell之中。

ALGOL 68曾受到嚴厲批評[8],最突出的是來自其設計委員會的一些成員比如C. A. R. Hoare[9],還有ALGOL 60編譯器作者比如Edsger Dijkstra[10],它獲評為拋棄了ALGOL 60的簡單性,成為了複雜或過於籠統的想法的載體,與刻意保持簡單的同時代(競爭)者如CS-algol英語S-algolPascal形成了鮮明對比。

ALGOL 68的語言定義出版後的文本長達兩百多頁並充斥着非標準術語,這種複雜性使得編譯器實現任務變得困難,故而它曾被稱為「沒有實現也沒有用戶」。這麼說只是部份真實的,ALGOL 68曾應用於一些小眾市場,特別是流行於英國國際計算機有限公司英語International Computers Limited(ICL)的機器之上,還有在教學角色之上。在這些領域之外,其使用相對有限。

儘管如此,ALGOL 68對計算機科學領域的貢獻是深刻、廣泛而持久的,雖然這些貢獻大多只是在它們於後來開發的編程語言中重現之時才被公開認可。很多語言是為了應對設計這門語言時所採用的形式化方法導致的複雜性而專門開發的,其中最著名的是Niklaus WirthALGOL W及其後繼者Pascal[11],或者是針對特定角色而重新實現的,比如有些人認為Ada可以看作ALGOL 68的後繼者[12]

1970年代的很多語言可以追溯其設計至ALGOL 68,選取一些特徵,並放棄被認為太複雜或超出給定角色範圍的其他特徵。其中就有C語言,它受到ALGOL 68的直接影響,特別是它的強類型結構。多數現代語言都至少可以追溯其部份語法至要麼C語言要麼Pascal,因而很多語言可直接或間接的經由C語言而追溯至ALGOL 68。

規定和實現時間線

More information 名稱, 年 ...
名稱 國家 描述 目標CPU/平台 屬主/許可證 實現語言
廣義ALGOL 1962  荷蘭 廣義文法的ALGOL[13]
ALGOL 68DR 1968 Does not appear IFIP WG 2.1草案報告[14] Does not appear
ALGOL 68r0 1968 Does not appear IFIP WG 2.1最終報告[15] Does not appear
ALGOL 68-R英語ALGOL 68-R 1970  英國 GEORGE 3英語GEORGE (operating system)之下的ALGOL 68 ICL 1900英語ICT 1900 series 皇家雷達研究所英語Royal Radar Establishment ALGOL 60
DTSS ALGOL 68 1970  美國 Dartmouth分時系統英語Dartmouth Time Sharing System的ALGOL 68[16] GE-635英語GE-600 series 達特茅斯學院
Mini ALGOL 68 1973  荷蘭 針對簡單ALGOL 68程序的解釋器[17] 可移植解釋器 荷蘭數學中心 ALGOL 60
OREGANO 1973  美國 實踐「實現模型的重要性。」[18] 加州大學洛杉磯分校
M-220 ALGOL 68 1974  蘇聯 使用EPSILON英語EPSILON (programming language)M-220英語M series (computer)上實現ALGOL 68[19] M-220英語M series (computer) EPSILON英語EPSILON (programming language)
ALGOL 68C英語ALGOL 68C 1975  英國 劍橋大學ALGOL 68實現[20] ICL英語International Computers LimitedIBM System/360PDP-10UnixTelefunken TR440/TR445,Tesla英語Tesla a.s. 200和Z80(1980年)[21] 劍橋大學 ALGOL 68C
ALGOL 68r1 1975 Does not appear IFIP WG 2.1修訂報告[22] Does not appear
ALGOL 68 H 1975  荷蘭 加拿大 ALGOL 68編譯器[23] 阿爾伯塔大學荷蘭數學中心 ALGOL W
CDC ALGOL 68 1975  美國 完全實現的ALGOL 68[24] CDC 6000系列英語CDC 6000 seriesCDC Cyber 控制數據公司
Odra ALGOL 68 1976  蘇聯 波蘭 Odra英語Odra (computer) 1204/IL ALGOL 60
Oklahoma ALGOL 68 1976  美國 俄克拉何馬州立大學ALGOL 68實現[25] IBM 1130System/370 Model 158英語IBM System/370 俄克拉何馬州立大學 ANSI Fortran 66
Berlin ALGOL 68 1977  德國 柏林工業大學ALGOL 68實現[26] 基於抽象ALGOL 68機器的機器無關編譯器 柏林工業大學 CDL 2英語Compiler Description Language
FLACC英語FLACC 1977  加拿大 具有調試特徵的修訂報告完整實現 System/370 租用,Chion公司 匯編
ALGOL 68RS英語ALGOL 68RS 1977  英國 可移植編譯器 ICL 2900系列英語ICL 2900 SeriesMulticsVMSC生成器(1993年) 皇家信號與雷達研究所英語Royal Signals and Radar Establishment ALGOL 68RS
ALGOL 68-RT英語ALGOL 68-RT 1979  英國 並行ALGOL 68-R
ALGOL 68+ 1980  荷蘭 提議的ALGOL 68的超語言[27]
Leningrad ALGOL 68 1980  蘇聯 列寧格勒國立大學開發的完全語言加上模塊系統 IBM,DEC,CAMCOH,PS 1001和PC
交互式ALGOL 68英語Interactive ALGOL 68 1983  英國 增量編譯,1992年再版MK2[28] PC 非商業共享軟件
ALGOL 68S英語ALGOL 68S 1985  英國 美國 ALGOL 68的子集語言[29][30] Sun-3英語Sun-3,Sun SPARC(在SunOS 4.1和Solaris 2下),Atari ST(在GEMDOS下),Acorn Archimedes英語Acorn Archimedes(在RISC OS下),VAX-11英語VAX-11(在Ultrix-32英語Ultrix下) 利物浦大學卡內基·梅隆大學曼徹斯特大學 BLISS英語BLISSPascal
Rutgers ALGOL 68 1990  美國 匈牙利 Mini ALGOL 68解釋器後續版本[31] 可移植解釋器 寫於羅格斯大學的非商業開源軟件 C
Algol68toC 1993  英國 基於源自1985年ELLA英語ELLA (programming language) ALGOL 68RS英語ALGOL 68RS的ctrans[32][1] 可移植C生成器 國防研究局英語Defence Research Agency皇冠版權開源軟件 ALGOL 68RS
ALGOL 68 Genie 2001  荷蘭 完全語言包括標準的並立子句[2] 可移植解釋器;2010年版本2之後,具有可選的選定單元的編譯 GNU GPL C
Close

樣例代碼

下面是Hello World樣例代碼,採用了ALGOL 68RS英語ALGOL 68RS的程序結構,嚴格的說只有在BEGINEND之間的諸行是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!

下面的樣例代碼實現了埃拉托斯特尼篩法來找到小於等於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 f = (INT m) LIST: (m > n | NIL | m CONS f(m + 1));
         f(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:
        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 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

顯著的語言元素

符號和保留字

標準語言包含六十一個保留字,典型的用粗體字打印,並且其中一些還具有「簡短」符號等價者:

MODEOPPRIOPROCFLEXHEAPLOCLONGREFSHORTBITSBOOLBYTESCHARCOMPLINTREALSEMASTRINGVOIDCHANNELFILEFORMATSTRUCTUNIONAT @,IS :=:, ISNT :/=:,OFr0TRUEFALSEEMPTYNIL ○,SKIP ~,
COMMENT  CO # ¢,PRAGMAT  PRCASE ~ IN ~ OUSE ~ IN ~ OUT ~ ESAC ( ~ | ~ |: ~ | ~ | ~ ),
FOR ~ FROM ~ TO ~ BY ~ WHILE ~ DO ~ ODIF ~ THEN ~ ELIF ~ THEN ~ ELSE ~ FI ( ~ | ~ |: ~ | ~ | ~ ),
PARBEGIN ~ END ( ~ ),GO TO  GOTOEXITr0

GO TO被當作兩個保留字,未修訂報告的語言還有保留字EITHERIS NOT結合。

符號表示

Thumb
1963年版的ASCII,在後來版本中,被替代為^被替代為_

「臻選字符」(worthy character)是1977年出版的ALGOL 68標準硬件表示報告出於可移植性而推薦的字符集中的字符[33]:

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   " # $ % ' ( ) * + , - . / : ; < = > @ [ ] _ |

這反映了當年一些硬件不支持在ANSIASCIIIBMEBCDIC之外其他字符的事實。

傳輸表示採用「臻選字符」時,「加上乘以」符號替代為I,「乘以的冪」符號\替代為E

Thumb
配備APL打字球與鍵帽後的IBM 2741英語IBM 2741終端的鍵盤,它不再支持小寫字母。

ALGOL的「特殊」字符:

× ÷ ≤ ≥ ≠ ≡ ¬ ∧ ∨ ⊃ ↑ ⏨ ␣ ↓ → ⊥ ○ □ ⌊ ⌈ ⎩ ⎧ ¢

多數都可以在1965年出現的配備APL打字球與鍵帽後的IBM 2741英語IBM 2741終端的鍵盤上找到。這些字符也是Unicode標準的一部份,並且在一些流行的字體中可獲得到。

單元

基本語言構造是「單元」(unit)。單元可以是「公式」、「封閉子句」、「例程正文」這樣的構造,也可以是某個技術上需要的構造諸如賦值、跳轉、越過和空無。

技術術語「封閉子句」(enclosed clause)統一了某些固有的加括號的構造,在其他當代語言中被稱為「」、「do語句」、「switch語句英語Switch statement」。在使用關鍵字的時候,通常使用介入關鍵字的反轉字符序列來終結這個包圍,比如:IF ~ THEN ~ ELSE ~ FICASE ~ IN ~ OUT ~ ESACFOR ~ WHILE ~ DO ~ OD。這種守衛命令語法被Stephen Bourne重新使用在常用的Unix Bourne shell之中。

一個表達式還可以產生多元值(multiple value)即有多個元素的一個值,它是通過「並立子句」(collateral clause)從其他一些值構造出來的。這種構造看起來就像過程調用的參數包(pack)。

模態

基本數據類型在ALGOL 68用語中叫做「模態」(mode),其原始聲明符為:INTREALCOMPL複數)、BOOLCHARBITSBYTES。ALGOL 68不再定義longshortdouble這樣的類型,而是提供了修飾符(modifier)LONGSHORT

  • BITSBOOL值的包裝向量(packed vector)。
  • BYTESCHAR值的包裝向量。
  • LONG – 聲明INTREALCOMPL的大小為LONG
  • SHORT – 聲明INTREALCOMPL的大小為SHORT

ALGOL 68提供了預置常量(prelude constant)如max reallong max real等來將程序適配到不同實現之中。

所有變量都必須被聲明,但是聲明不必須先於第一次使用。例如:

INT n = 2;  # n被固定为常量2 #
INT m := 3; # m是新建的局部变量,它的值被初始化为3 #
# 这是REF INT m = LOC INT := 3;的简写 #
REAL avogadro = 6.02214076E23; # 阿伏伽德罗常数 #
LONG LONG REAL long long pi = 3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510;
COMPL square root of minus one = 0 I 1; # 复数0 + 1i #

原始聲明符還包括:COMPLEXGSTRINGFORMATFILEPIPEGCHANNELSEMA

  • STRINGCHAR值的FLEX(靈活)元組。
  • SEMA – 可以通過OP LEVEL初始化的信號量

複雜類型可以使用類型構造子REFSTRUCTUNIONPROC來創建自更簡單的類型:

  • REF mode – 到類型mode的值的引用,類似於C/C++中和Pascal中的指針
  • STRUCT – 用來建造結構,類似於C/C++中的struct和Pascal中的recode
  • UNION – 用來建造聯合,類似於C/C++和Pascal中的union
  • PROC – 用來指定過程,類似於C/C++中的函數和Pascal中的過程/函數。

其他聲明符號包括:FLEXHEAPLOCEVENTS

  • FLEX – 所聲明的名字是靈活的,就是說它可以引用任何數量元素的元組。
  • HEAP – 為變量從全局堆中分配一些空閒空間。
  • LOC – 為變量分配這個局部棧的一些空閒空間。

聲明REAL x;只是REF REAL x = LOC REAL;語法糖。就是說,x實際上是「常量標識符」,它「引用到」一個新創建的局部REAL變量。

聲明模態(類型)的名字可以使用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數組的下界(lower bound)缺省的是1,但也可以是從-max intmax 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成為了面向表達式編程語言英語Expression-oriented programming language賦值語句所返回的值是到目的地的引用。因此下列代碼在ALGOL 68中是有效的:

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

這種表示法也出現在C語言和Perl以及其他一些語言之中。注意在早期語言比如ALGOL 60FORTRAN中,在標識符中的空格是允許的,所以half pi是一個單一的標識符,因而無需採用蛇形命名法駝峰式大小寫

另一個例子,要表達數學中f(i)i=1n的總和,下列ALGOL 68整數表達式就可充任:

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

注意,作為整數表達式,上述的代碼塊可以用在「整數值可以使用的任何上下」之中。代碼塊在ALGOL 68稱為「系列子句」(serial clause),它返回其中被求值的最後一個表達式的值;這個概念也出現在LISP以及其他一些語言之上。系列子句加上封閉它的一對圓括號或BEGINEND叫做閉合子句(closed-clause)。

複合語句都終止於獨特的閉括號:

IF選擇子句

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

這種方案不僅避免了懸擺else英語dangling else問題,還避免了必須對嵌入的語句序列使用BEGINEND

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 AND year%*100 /= 0 OR 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;

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語法元素被替代為UPTODOWNTO來達成小優化。這些編譯器還結合了:

  • UNTILC – 用於更晚的循環終止。
  • FOREACHS – 用於並行的運算於數組之上。

結構與聯合

ALGOL 68支持多字段結構STRUCT標籤聯合UNION。引用變量可以指向任何MODE,包括數組切片和結構字段。

作為遞歸模態的例子,下面是傳統的鍊表的聲明:

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

對上述VALUEUNION使用共形子句(conformity clause)的CASE的例子:

More information ALGOL68r0遵循1968年最終報告, ALGOL68r1遵循1973年修訂報告 ...
ALGOL68r0遵循1968年最終報告 ALGOL68r1遵循1973年修訂報告
 VALUE v := "1234";
 REAL r; INT i; COMPL c; STRING s
 CASE r,i,c,s CTAB v IN
     print(("real:", r)),
     print(("int:", i)),
     print(("compl:", c)),
     print(("string:", s))
 OUT print(("?:", v))
 ESAC
 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
Close

多元組

在ALGOL 68中,不再採用術語數組陣列(array),轉而基於數學中的元組-tuple)定義了多元值(multiple value)亦簡稱多元組(multiple)。多元組由一定數量的元素組成,每個元素都有相同的模態,有時稱之為基礎模態。多元組的模態由前導着一對方括號的針對每個元素的模態標示組成,它被讀作「成行英語Row- and column-major order的模態」(row of mode),它不同於函數式編程語言ML中的對應於代數數據類型積類型英語Product type的「元組」(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的分片英語array slicing,在概念上涵蓋了向多元組的各個維度加下標英語Subscript and superscript(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:
    IF a > b THEN a ELSE b FI;

或者使用條件語句的簡短形式:

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

過程的返回值是在過程中求值的最後一個的表達式的值 。到過程的引用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中不能達成的。

運算符與關聯名字的單元

過程和運算符(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",是其所產生與任何行動都無關的構造,在其他語言中,它們有時叫做「文字英語Literal (computer programming)」(literal)或「常值」(constant)。

鑄型(cast)構成自一個模態標示(indicant)和隨後的通常為閉合子句的封閉子句。鑄型可被用來提供強位置,在強上下文中能獲得所有的強制。例如在REF REAL (xx) := 1中的REF REAL (xx)

調用(call)引起(invoke)一個過程,調用在ALGOL 68 Genie中可以被部份參數化英語Partial application(partial parameterisation):就是說增加實際參數到一個過程的語境(locale)中,當這個語境完全之時調用這個過程,否則發生柯里化

More information PRIO, ALGOL68r1「臻選字符」 ...
PRIO ALGOL68r1「臻選字符」 ALGOL68G
相當於12 加下標[~],分片[~,~],裁剪[~:~]AT @ DIAGTRNSPROWCOL
Close

二等單元(secondary)包括生成器(generator)和選取(selection)。

More information PRIO, ALGOL68r1「臻選字符」 ...
PRIO ALGOL68r1「臻選字符」 ALGOL68r0−r1 ALGOL68G
相當於11 OFLOCHEAP NEW
Close

有關的符號在技術上不是運算符,它們轉而被當作「關聯名字的單元」[34]

三等單元

三等單元(tertiary)包括公式和NIL(可替代為)。公式構成自運算符運算元

一元運算符
More information PRIO, ALGOL68r1「臻選字符」 ...
PRIO ALGOL68r1「臻選字符」 ALGOL68r1替代符號 ALGOL68C,G ALGOL68r0-r1
相當於10 NOT,-,UPDOWNLWBUPBABSARGBINENTIERLENGLEVELODDREPRROUNDSHORTEN ¬ ~,↑,↓,⌊,⌈ NORMTRACETDETINV LWS ⎩,UPS ⎧,BTBCTB
Close
二元運算符及其關聯的優先級
More information PRIO, ALGOL68r1「臻選字符」 ...
PRIO ALGOL68r1「臻選字符」 ALGOL68r1替代符號 ALGOL68r0−r1
9 I +* ⊥ +× !
8 UP **,DOWNLWBUPBSHLSHR ↑,↓,⌊,⌈ ^ ××,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 +=: ×:=,÷:=,÷×:=,÷*:=,%×:= MINUSPLUSTIMESDIVOVERBMODB ÷::=,PRUS
Close

特殊細節:

  • LWS:在ALGOL 68r0中,運算符LWS(可替代為),在一個多元組(數組)的這個維度的「下界狀態」為固定的(fixed)的情況下返回TRUE
  • UPS(可替代為)運算符針對「上界狀態」。
  • LWBUPB運算符自動的可獲得在一個多元組(數組)的不同階次(和MODE)的UNION之上,例如:UNION([]INT, [,]REAL, FLEX[,,,]CHAR)UPB

四等單元

四等單元(quaternary)包括:賦值、恆等(identity)關係、例程指示(也稱作例程正文)和SKIP(可替代為~)。四等單元並非語言報告中的術語,它是給從單元這個類屬中除去封閉子句、初等單元、二等單元和三等單元所餘下的只稱為「單元」的類屬的別名。

More information PRIO, ALGOL68r1「臻選字符」 ...
PRIO ALGOL68r1「臻選字符」 ALGOL68r1替代符號 ALGOL68C,R ALGOL68r0−r1
相當於0 :=,IS :=:,ISNT :/=: :≠: :¬=: :~=: :=:=C,=:=R ..= .=,IS NOTCT ::,CTAB ::=
Close

在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)– 硬強制,隨後擴大、入行或棄置。

在任何上下文中,都有擁有或產生某種模態的值的一個單元,並且在這個上下文中亦有所需的一個模態。如果兩個模態不同而現有模態的值能夠強制成所需模態的值,則這種強制是合法的。

平衡是將條件、case和共形子句中的交替者(alternative)即可供選擇者,和恆等關係的兩側,都強制成共同(common)的模態的手段,這使得所涉及構造的上下文會被提升(promote)從而獲得這種強制。

強制層級及例子

ALGOL 68有着上下文層級,它確定在程序中特定點之上可獲得的強制的種類。這種上下文分為五個層次:

More information 上下文, 上下文位置 ...
上下文 上下文位置 可獲得的強制 在此上下文中強制例子
  • 恆等(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 …… FIFROM ~ 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;
Close

正交性

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))

注意預定義的過程newpagenewline作為實際參數而傳送。

printread接受可能具有各種所需模態的實際參數,這些例程的形式參數具有成行的聯合模態:

PROC print = ([]SIMPLOUT) VOID: …… ;
MODE SIMPLOUT = UNION (
    INT, REAL, BOOL, CHAR,
    []INT, []REAL, []BOOL, []CHAR,
    [,]INT, [,]REAL, [,]BOOL, [,]CHAR,
    …… );
PROC read = ([]SIMPLIN) 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!", 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);

ANDF中,b只在aTRUE的情況下才求值。例如:

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

與編程者的預期相反,打印仍會執行,需要增加模態鑄型PROC BOOL:使打印不執行:

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

語言修訂之後,已經不允許如此定義ANDFORF,ALGOL 68 Genie將二者作為擴展而實現為偽運算符。

在語言修訂之前,編程者可以通過使用叫做「gomma」的分號替代逗號(comma),從而決定一個過程的參數串行而非並立的求值。例如:

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

這裡保證第一個實際參數求值在第二個實際參數之前,但是在平常情況:

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

這時編譯器可以按它喜好的次序來求值實際參數。

參見

註釋

參考文獻

外部連結

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.