ALGOL 60

ALGOL 60（源自 ALGOrithmic Language 1960 的縮寫），是在 1960 年建立的稱為 “演算法語言” 的一種程式語言。它是以後來稱為 ALGOL 58 的 “國際代數語言” 為基礎，其官方後繼者是 ALGOL 68，它們一起並稱為 ALGOL 語言家族。Algol 60 引進了許多新的概念如：塊、詞法作用域、遞迴、巴科斯 - 諾爾正規化（BNF），它在程式語言設計和發展演化中有著巨大的影響力。

歷史

1960 年，在巴黎舉行的討論會上，來自歐洲的諾爾、、、、範・韋恩加登、、，與來自美國的佩利、巴科斯、麥卡錫、、和 J. Green，共同發表了《演算法語言 ALGOL 60 報告》。戴克斯特拉實現了 ALGOL 60 語言的第一個編譯器。在 1962 年羅馬會議上，ALGOL 60 報告得到了修訂，並於 1963 年出版。

ALGOL 60 是程式設計語言發展史上的一個里程碑，影響到其後的 Simula、CPL、ALGOL W、ISWIM、BCPL、B、Pascal、C、Scheme 等。它標誌著程式設計語言成為一門獨立的科學學科，併為後來軟體自動化及軟體可靠性的發展奠定了基礎。

1.1 標準

ALGOL 60 以及 COBOL，是最初的企圖示準化的程式語言。ALGOL60 曾經提出兩項 ISO 標準：

ISO 1538: 1984 年，程式語言 ALGOL 60，它已穩固化。
ISO 1672: 1977 年，ALGOL 基本符號的 ISO 7 位編碼字元集硬體表示，它已撤消。

1.2 實現時間線

ALGOL 60 在語言報告中沒有 I/O 設施；諸多實現以少有相互相容的方式定義了自己的設施。迄今 ALGOL 60 已經有了至少 70 個擴充、擴充套件、派生和子語言。

詞法

2.1 簡單符號

除了字母和數字之外，ALGOL 定義了運算子：

和:

在 ISO 1672 標準中，用:= 表示≔（U+2254），用 表示 ×；用 % 表示 ÷，用 * 或 ^ 表示↑，用 @表示科學記數法中指數運算的底數 10 所用符號⏨（U+23E8），用 {表示‘，並且用} 表示’，用空格 表示在字串中的空白字元␣（U+2423）。

2.2 關鍵字

ALGOL 60 有 24 個關鍵字：

還包括標準函式名字作為限制識別符號：

關鍵字寫法依賴於實現，常見的是一種叫做（stropping）的方法，即將關鍵字大寫幷包圍在兩個 ' 之間，例如將 go to 寫為 'GOTO'。在 ISO 1672 標準中關鍵字還包括對特定符號的某種文字轉寫：

語義

3.1 塊與作用域

在 ALGOL 60 中，“複合語句” 被定義為：包圍在語句括號 begin 和 end 之間的成序列的語句，形成一個複合語句。塊被定義為：成序列的宣告，跟隨著成序列的語句，並被包圍在 begin 和 end 之間，形成一個塊；所有宣告以這種方式出現在一個塊中，並只在這個塊中有效。

一個程式是特定的一個塊或複合語句，它不包含在另一個語句之中，並且不使用不包含在它之中的其他語句。在 1976 年的修改版語言報告中，程式只能包含在叫做 “環境塊” 的假定總是存在的一個虛構塊之中，除了可以使用在環境塊中宣告的過程識別符號和函式指定符之外，不使用不包含在它之中的其他語句。

量（quantity）被區分出如下種類：簡單變數、陣列、標籤、switch（switch 列表由標籤組成

dead-url=no}}“25.4.3.

Here, by virtue of switch wernik, the computation follows one of four possible branches of the program depending on the current value of k. Afterwards the common course of the calculation (i.e. the statements which would follow «end») is taken up again.”）和過程。宣告負擔定義在程式中用到的量的特定屬性，並給它們關聯上識別符號。宣告包括：型別宣告、陣列宣告、switch 宣告和過程宣告。量的作用域是語句和表示式的集合，在其中關聯於這個量的識別符號的宣告是有效的。所有的塊，自動地介入（nomenclature）的一個新的層級：

在這個塊內出現的識別符號，可以透過合適的宣告，而被指定為區域性於所論及的這個塊。這個識別符號在這個塊裡面的所表示的實體，不存在於它的外面。這個識別符號在這個塊外面的所表示的任何實體，在這個塊裡面是不可見的。
除了表示標籤的識別符號之外，一個識別符號，如果出現在一個塊中，而且並非聲明於這個塊中，則它於這個塊

42.5.2. Hidden operands. A block may have hidden operands: Indeed, if a procedure P is operand of block B, …… the global parameters of P are also involved in the execution of B, hence operands of B. We call these hidden operands of B because they cannot be found by inspection of block B but only by inspection of the declaration for procedure P, which is given somewhere outside B. ……

42.5.3. The operands of a block B fall into the following four categories:

⒜ Arguments …… ⒝ Results …… ⒞ Transients: …… which have properties of both arguments and results …… ⒟ Exits: Labels referring to destinations located outside B and switches which are declared outside B. ……

52.3.1. Considering a mathematical expression, e.g. an integralit is seen that the variables x and y serve entirely different purposes: y is a variable upon which the value of I depends; in mathematical logic this is called a free variable (of the expression). This latter term indicates that one is free to substitute a value, e.g. 2.75, for y, where-upon one obtains the resultThe variable x, on the other hand, is only an auxiliary object for describing the operation to be performed by the expression. It is called a bound variable since it is not accessible from outside the expression. ……

52.3.2. Comparing these examples with an ALGOL procedure and the terminology used ……, it becomes obvious that the free variables correspond to what are called the operands of a procedure, while the bound variables correspond to the internal quantities.”，就是說它在這個塊裡面和在緊鄰其外的層級中所表示的是同一個實體。

因為塊中的語句自身可以是一個塊，區域性和非區域性於一個塊的概念，必須遞迴地去理解，就是說非區域性於一個塊 A 的一個識別符號，可是亦可否地，非區域性於 A 是其中語句的塊 B。

這動態的蘊涵了：在透過 begin 進入一個塊的時候，所有為這個塊宣告的識別符號，假定了這個給定宣告的所蘊涵的（significance）；如果這些識別符號已經被外面的其他宣告所定義，這時它們被給予新的意義；在另一方面，並非為這個塊宣告的識別符號，保持它們舊有的含義。在透過 end 或 go to 語句退出一個塊的時候，為這個塊宣告的識別符號失去它們的區域性意義。宣告可以標記上額外的宣告符 own，其效果為：在重新進入一個塊的時候，自有的這些量的值將不變更而仍是上次退出時的值，然而宣告的沒有標記上 own 的變數的值是未定義的。

3.2 表示式和語句

在描述演算法處理的程式中，主要構成者是算術表示式、布林表示式，和得到語句標籤的指定（designational）表示式。除了特定的分界符之外，表示式的構成者包括：邏輯值、數值、變數、函式指定式，和基本的算術、關係、邏輯運算子（operator）及順序運算子。用以形成語句的關鍵字，在 ALGOL 60 中被歸入順序運算子和分隔符之中。

變數是對一個單一值的指名。下標（subscripted）變數指定（designate）多維陣列的元素的值，這裡將陣列元素稱為 “組成元件”（component）

lk ≤ ik ≤ uk(k = 1, 2, ……, p),

whose boundaries (i.e. the array bounds l1, l2 ……, lp, u1, u2, ……, up) are given in the corresponding array declaration ……. ……

14.3.2. A subscripted variable «IE1, E2, ……, Ep», if encountered in an expression, represents also a single value defined as follows: Evaluate the subscript expressions E1, E2, ……, Ep; if their values are i1, i2, ……, ip, then the subscripted variable represents the value that has most recently been assigned to the i1, i2, ……, ip-component of the array I.”。函式指定式（designator）定義單一的數量值或邏輯值，它們是將給定的由過程宣告定義的規則集合，應用於固定的實際引數集合的結果。

現在通常將變數定義為抽象的儲存位置，它含有了被稱為一個值的某種已知或未知的資訊量，並且配對了關聯的名字。在 ALGOL 60 中，某些語法單位，比如表示式及其構成者和陣列識別符號，被稱為擁有值。各種 “型別” 即 integer、real 和 Boolean，指稱（denote）值的基本的屬性。

在左圓括號和匹配的右圓括號之間的表示式（parenthesized expression）自行求值，而這個值被用於後續的計算之中；因此透過適當的圓括號放置，總是可以在表示式之內安排出想要的運算次序。

ALGOL 60 將語句分為三類：無條件語句、條件語句和 for 語句。賦值語句擔負將表示式的值，指派（assign）到一個或多個變數，或者在定義函式指定式的值的過程主體中指派到過程識別符號；在作為指派目標的下標變數中出現的任何下標表達式，先於得出所指派之值的表示式，而按從左至右順序求值。空無的虛設（dummy）語句不執行任何運算。過程語句負擔實施呼叫一個過程主體的執行。

控制流程語句包括：go to 跳轉語句、條件語句、for 迴圈語句。go to 語句結合了無條件 go to 和計算 go to 二者，goto 語句不能從塊外跳轉到塊內的標籤，但可以跳轉進入複合語句。條件語句包括 if 語句（即 if 布林表示式 > then 無條件語句 >），和 if 語句經由關鍵字 else 與隨後的語句聯合在一起的形式（即 if 語句 > else 語句 >）。ALGOL 60 在 if 語句和 for 語句中介入了子句概念，算術表示式、布林表示式和指定表示式，可以是條件表示式（即 if ~ then ~ else ~）19.7.1. «x + (if t> t1 then 1 else -1) /x».We recall that a conditional arithmetic expression cannot be used directly as a primary in a larger expression, but must for this purpose be enclosed in parentheses (the sequence «+ if» is always illegal).

19.7.2. Selection of a component of an array with safeguards against exceeding the array bounds:«aif k > n then n else if k ».

19.7.3. Where conditional expressions are intended as comparands of a relation or as alternatives of a conditional expression, they must again be enclosed in parentheses:«if (if u then x else y) > 0 then (if z = 0 then x + y else x - y) else x × y».”。

由於變數和函式指定式二者的語法定義都包含表示式，表示式及其構成者的定義必須是遞迴的。由於成序列的語句，可以被組織成複合語句和塊，語句的定義必需是遞迴的。ALGOL 60 採用了左遞迴的巴科斯正規化（BNF）。

3.3 過程

在 ALGOL 60 中，過程宣告擔負定義過程識別符號所關聯的過程，其主要構成者是過程主體，它是一個語句或一段程式碼。過程主體總是表現得如同一個塊，不管它是否有著塊的形式；故而標記了在過程主體內語句或者主體自身的標籤的作用域，永遠不能延伸超出這個過程主體«begin real æ; S end»1, 2.……1 The declaration of the fictitious variable æ serves solely to make this piece of program a block.2 In case S is already an unlabelled block, this artificial construction is unneeded and we could take S instead. ……”。

過程主體關聯著一個頭部，它規定了出現在過程主體內的代表形式引數的特定識別符號。過程的引數傳遞有兩種求值策略：傳名呼叫和傳值呼叫。在過程宣告中，透過對形式引數名字前導 value 來指定傳值呼叫，預設為傳名呼叫。在過程主體是用 ALGOL 語言寫的語句的情況下，過程語句執行它的效果，等價於在程式上進行下列操作的效果：

宣告為傳值呼叫的形式引數，都要被賦值即指派上對應的實際引數的值，這些指派被認為是在進入過程主體之前顯式進行的。其效果如同建立了包圍著這個過程主體的一個額外的塊，在其中所做的這些指派針對的是區域性於這個虛構塊的變數，它們具有在相應規定中給出的型別。作為結論，傳值呼叫的變數，被認為於過程主體，但是區域性於這個虛構塊。
宣告為傳名呼叫的形式引數，在整個過程主體內，要被替代為對應的實際引數，並且只要語法上可能就對這些實際引數包圍上圓括號。在透過這個名字替代處理而插入的識別符號，和已經存在於過程主體之內的其他識別符號，二者之間的可能衝突，將憑藉對涉及到的（這個過程主體的）形式識別符號或區域性識別符號的適合的系統性變更來避免

«begin real z; z := 2 × y; z := z /z end»,

which certainly was not the intention of the designer of the procedure. With the above amendment, however, the internal z is changed into zæ, after which we obtain the equivalence block correctly as

«begin real zæ; zæ := 2 × z; z := z /zæ end».”。

最終經過上述修改後的過程主體，被插入到過程語句的位置上並被執行。如果呼叫這個過程的位置，處在這個過程主體的任何非區域性量⒜ Those operands of the fictitious block whose identifiers are not quoted in the formal parameter part are called global operands of the procedure. …… ⒝…… formal operands ……⒞…… hidden operands ……

44.3.1. A global parameter - that is, the identifier of a global operand - represents the same quantity inside the procedure body as outside in the environment of the procedure declaration. A global operand is therefore simply the extension of a quantity which exists outside the procedure. As a consequence we have

44.3.2. The environment rule for global parameters:If the identifier I is global parameter of a procedure, then a (true or formal) quantity Q with that identifier must exist in the environment of the procedure declaration, and it is this Q which in a call of the procedure is meant by the identifier I.

According to this rule, a global parameter acts like a thread which links the procedure declaration permanently to its environment; indeed, a procedure which has global parameters is only fully defined if it is embedded into an ALGOL program in which the global operands are properly declared.” 的作用域的外面，在透過這個過程主體替代處理而插入的識別符號，和在這個過程語句或函式指定式所在位置上其宣告有效的識別符號，二者之間的可能衝突，將透過（在發起呼叫的這個層級上）對後者識別符號的適合的系統性變更來避免

«begin real æ; t := tæ end».

Accordingly, this call accomplishes something which would seem impossible, namely changing the value of a suppressed variable.

45.2.5. ……Consequently no name changes apply where the identifier of a global operand not suppressed at the location of a procedure call coincides with the identifier of an actual operand.”。

對於定義函式指定式的值的過程宣告，在其過程主體中，必須出現具有過程識別符號在其左側部份中的一個或多個賦值語句，其中至少有一個必須被執行；並且這個過程識別符號所關聯的型別，必須透過以型別宣告符作為其過程宣告的最先符號的樣貌來宣告。最後那個這樣指派的值，被用來繼續此函式指定式在其中出現的表示式的求值。在這個過程主體中，這個過程識別符號的不在賦值語句左側部份中的任何出現，指示了這個過程的啟用（activation）。

兩個傳名呼叫形式引數，其對應的實際引數之間可能存在依賴關係，比如第一個是整數變數 i，而第二個是下標變數 Ai，從而導致後者形式引數也依賴於前者形式引數，利用傳名呼叫和這種副作用可以實現；它典型的用於定義對應於的級數過程 Sum (k, l, u, ak)，它有兩個傳名呼叫的形式引數：索引變數 k 和通項（general）表示式 ak。

對於交換兩個引數的值的 swap (x, y) 過程，其過程主體定義為：t:=x; x:=y; y:=t，這種依賴性副作用會導致可能出現異常行為，由於名字替代機制相當於宏展開（expansion），過程語句 swap (i, Ai) 中下標變數 Ai 的下標 i 未經求值，對應的過程主體就轉換成為：t:=i; i:=Ai; Ai:=t。1964 年制定了《SUBSET ALGOL 60 報告》，在這個子集語言中對 “完全的名字概念”（full name-concept）增加了一項限制：在名字替代（傳名呼叫）中，實際引數只能是一個識別符號或字串。

在過程的引數列表 (… …) 中，有可選的 “) : (” 樣式的引數。眾所周知的傳名呼叫實現採用了。Donald Knuth 設計了 “男人抑或男孩測試”，來區分編譯器是否正確的實現了 “遞迴和非區域性引用”，這個測試用到了傳名呼叫。

例子

下面是語言報告中過程宣告的一個例子：

procedure Absmax (a) Size:(n, m) Re​sult:(y) Subscripts:(i, k);

value n, m; array a; integer n, m, i, k; real y;

comment 矩陣 a，其大小為 n 乘 m，其絕對值最大的

元素被傳送到 y，並且這個元素的下標是 i 和 k。 ;

begin

integer p, q;

y := 0; i := k := 1;

for p := 1 step 1 until n do

for q := 1 step 1 until m do

if abs (ap, q) > y then

begin

y := abs (ap, q);

i := p; k := q

end

end Absmax

在 1976 年修改版語言報告的環境塊中，定義了輸入輸出過程：inchar、outchar、length、outstring、outterminator、ininteger、outinteger、inreal 和 outreal，下面以其中的 outinteger 作為演示例子：

procedure outinteger (channel, int);

value channel, int;

integer channel, int;

comment 將表示 int 的值的那些字元，

加上尾隨的終結符傳遞到 channel。 ;

begin

procedure digits (int);

value int; integer int;

begin

integer j;

comment 使用遞迴從右至左求值數字，

但從左至右列印它們。 ;

j := int ÷ 10;

int := int - 10 × j;

if j ≠ 0 then

di​gits (j);

outchar (channel, ‘0123456789’, int + 1)

end digits;

if int

這裡呼叫到的 outchar (channel, str, int)，將在字串 str 中對應整數 int 的值的那個字元，傳遞到通道 channel；outterminator (channel)，用於輸出在數值之後的終結符（即空格、換行或分號）。此外，在 1964 年曾制定《ALGOL 60 輸入輸出過程報告》，其中定義了 insymbol、outsymbol、length、inreal、outreal、inarray 和 outarray，這裡的多維陣列採用了（Row major）次序

il = jl for l = 1, 2, ……, h - 1, but ih h.

Moreover, these procedures always transfer all components of the array appearing as the second actual operand.

As a consequence, a call «outarray (15, p)», where p is declared e.g. as «array p-4:5, 1:50, 0:20», is equivalent to。