跳轉到內容

來自華夏公益教科書

本檔案最初託管在 ETHZ。它仍然在 ETH 許可證 下,並且在 WayBack 存檔 中。

Oberon 語言報告
修訂版 1. 10. 90, N. Wirth
儘可能簡單,但不要更簡單。
A. 愛因斯坦


 
  1. 介紹
  2. 語法
  3. 詞彙和表示
  4. 宣告和作用域規則
  5. 常量宣告
  6. 型別宣告
  7. 變數宣告
  8. 表示式
  9. 語句
  10. 過程宣告
  11. 模組
  12. SYSTEM 模組
 

1. 簡介

Oberon 是一種通用程式語言,它從 Modula-2 發展而來。它的主要新特性是型別擴充套件的概念。它允許基於現有型別構建新的資料型別,並在它們之間建立關係。

 

本報告並非旨在作為程式設計師教程。它有意保持簡潔。它的作用是作為程式設計師、實現者和手冊作者的參考。未言明的事物大多是出於有意,要麼是因為它可以從語言的既定規則中推斷出來,要麼是因為它需要在普遍承諾顯得不明智時做出具體承諾。

2. 語法

語言是句子的無限集合,即根據其語法形成的句子。在 Oberon 中,這些句子被稱為編譯單元。每個單元都是來自有限詞彙的有限符號序列。Oberon 的詞彙表包含識別符號、數字、字串、運算子、分隔符和註釋。它們被稱為詞法符號,由字元序列組成。(注意符號和字元之間的區別。)

 

為了描述語法,使用了稱為 EBNF 的擴充套件巴克斯-諾爾正規化。方括號 [ 和 ] 表示所包含的句法形式的可選性,而花括號 { 和 } 表示其重複(可能為 0 次)。句法實體(非終結符)由表達其直觀含義的英文單詞表示。語言詞彙表中的符號(終結符)由包含在引號中的字串或以大寫字母書寫的單詞表示,即所謂的保留字。句法規則(產生式)在行左側標記為 $ 符號。

3. 詞彙和表示

使用 ASCII 集定義符號的字元表示。符號是識別符號、數字、字串、運算子、分隔符和註釋。必須遵守以下詞法規則。空格和換行符不能出現在符號內(除了註釋中,以及字串中空格的情況)。它們被忽略,除非它們是分隔兩個連續符號所必需的。大寫和小寫字母被認為是不同的。

1. 識別符號是字母和數字的序列。第一個字元必須是字母。
$  ident  =  letter {letter | digit}.

示例

  x   scan   Oberon   GetSymbol   firstLetter
2. 數字是(無符號)整數或實數。整數是數字序列,後面可以跟一個字尾字母。型別是最小的包含該數字的型別(參見第 6.1 節)。如果沒有指定字尾,則表示為十進位制。字尾H表示十六進位制表示。

實數始終包含小數點。可選地,它也可以包含小數比例因子。字母E(或D)讀作“乘以十的次方”。實數的型別為 REAL,除非其比例因子包含字母D,在這種情況下其型別為 LONGREAL。

$  number  =  integer | real.
$  integer  =  digit {digit} | digit {hexDigit} "H" .
$  real  =  digit {digit} "." {digit} [ScaleFactor].
$  ScaleFactor  =  ("E" | "D") ["+" | "-"] digit {digit}.
$  hexDigit  =  digit | "A" | "B" | "C" | "D" | "E" | "F".
$  digit  =  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".

示例

  1987
  100H          = 256
  12.3
  4.567E8       = 456700000
  0.57712566D-6 = 0.00000057712566
3. 字元常量要麼由包含在引號中的單個字元表示,要麼由字元在十六進位制表示中的序數後跟字母X表示。

$ CharConstant = """ character """ | digit {hexDigit} "X".

4. 字串是包含在引號(")中的字元序列。字串不能包含引號。字串中的字元數稱為字串的長度。字串可以分配給字元陣列並與之進行比較(參見第 9.1 節和第 8.2.4 節)。

$ string = """ {character} """ .

示例

  "OBERON"   "Don't worry!"

5. 運算子和分隔符是下面列出的特殊字元、字元對或保留字。這些保留字僅由大寫字母組成,不能用作識別符號。
  +   :=   ARRAY    IS       TO
  -   ^    BEGIN    LOOP     TYPE
  *   =    CASE     MOD      UNTIL
  /   #    CONST    MODULE   VAR
  ~   <    DIV      NIL      WHILE
  &   >    DO       OF       WITH
  .   <=   ELSE     OR
  ,   >=   ELSIF    POINTER
  ;   ..   END      PROCEDURE
  |   :    EXIT     RECORD
  (   )    IF       REPEAT
  [   ]    IMPORT   RETURN
  {   }    IN       THEN
6. 註釋可以插入程式中任何兩個符號之間。它們是透過括號 (* 開頭並以 *) 結尾的任意字元序列。註釋不會影響程式的含義。
4. 宣告和作用域規則

程式中出現的每個識別符號都必須透過宣告引入,除非它是預定義的識別符號。宣告還用於指定物件的某些永久屬性,例如它是否是常量、型別、變數或過程。

然後使用識別符號引用關聯的物件。這隻能在程式中處於宣告作用域內的部分進行。在給定作用域內,任何識別符號都不能表示多個物件。作用域在文字上從宣告點延伸到其所屬的塊(過程或模組)的末尾,因此物件是區域性的。作用域規則有以下修正

1. 如果型別T被定義為 POINTER TO T1(參見第 6.4 節),則識別符號T1可以在文字上宣告為T的宣告之後,但必須位於相同的範圍之內。
2. 記錄宣告的欄位識別符號(參見第 6.3 節)僅在欄位指示符中有效。

在宣告中,全域性範圍內的識別符號後面可以跟一個匯出標記 (*),以指示它要從其宣告模組匯出。在這種情況下,識別符號可以在其他模組中使用,如果它們匯入宣告模組。然後,識別符號將以指定其模組的識別符號為字首(參見第 11 節)。字首和識別符號由句點分隔,合在一起稱為限定識別符號

$  qualident = [ident "."] ident.
$  identdef = ident ["*"].

以下識別符號是預定義的;它們在指示的節中定義了含義

  ABS       (10.2)   LEN       (10.2)
  ASH       (10.2)   LONG      (10.2)
  BOOLEAN   (6.1)    LONGINT   (6.1)
  CAP       (10.2)   LONGREAL  (6.1)
  CHAR      (6.1)    MAX       (10.2)
  CHR       (10.2)   MIN       (10.2)
  COPY      (10.2)   NEW       (6.4)
  DEC       (10.2)   ODD       (10.2)
  ENTIER    (10.2)   ORD       (10.2)
  EXCL      (10.2)   REAL      (6.1)
  FALSE     (6.1)    SET       (6.1)
  HALT      (10.2)   SHORT     (10.2)
  INC       (10.2)   SHORTINT  (6.1)
  INCL      (10.2)   SIZE      (10.2)
  INTEGER   (6.1)    TRUE      (6.1)
5. 常量宣告

常量宣告將識別符號與常數值關聯起來。

$  ConstantDeclaration  =  identdef "=" ConstExpression.
$  ConstExpression  =  expression.

常量表達式可以透過簡單的文字掃描進行計算,而無需實際執行程式。它的運算元是常量(參見第 8 節)。

示例

  N      =  100
  limit  =  2*N -1
  all    =  {0 .. WordSize-1}
6. 型別宣告

資料型別確定該型別變數可以假設的值集,以及適用的運算子。型別宣告用於將識別符號與型別關聯起來。這種關聯可以是與非結構化(基本)型別,也可以是與結構化型別,在這種情況下,它定義了此型別變數的結構,並隱含地定義了適用於元件的運算子。有兩種不同的結構,即陣列和記錄,它們具有不同的元件選擇器。

$  TypeDeclaration  =  identdef "=" type.
$  type  =  qualident | ArrayType | RecordType | PointerType | ProcedureType.

示例

  Table       =  ARRAY N OF REAL
  Tree        =  POINTER TO Node
  Node        =  RECORD key: INTEGER;
                   left, right: Tree
                 END

  CenterNode  =  RECORD (Node)
                   name: ARRAY 32 OF CHAR;
                   subnode: Tree
                 END

  Function*   =  PROCEDURE (x: INTEGER): INTEGER
6.1. 基本型別

以下基本型別由預定義的識別符號表示。關聯的運算子在第 8.2 節中定義,預定義的函式過程在第 10.2 節中定義。給定基本型別的值如下

  1. BOOLEAN 真值 TRUE 和 FALSE。
  2. CHAR 擴充套件 ASCII 集中的字元(0X ... 0FFX)。
  3. SHORTINT MIN(SHORTINT) 和 MAX(SHORTINT) 之間的整數。
  4. INTEGER MIN(INTEGER) 和 MAX(INTEGER) 之間的整數。
  5. LONGINT MIN(LONGINT) 和 MAX(LONGINT) 之間的整數。
  6. REAL MIN(REAL) 和 MAX(REAL) 之間的實數。
  7. LONGREAL MIN(LONGREAL) 和 MAX(LONGREAL) 之間的實數。
  8. SET 0 和 MAX(SET) 之間的整數集合。

型別 3 到 5 是整數型別,6 和 7 是實數型別,它們合稱為數值型別。它們形成一個層次結構;較大的型別包含(較小的型別的)值

LONGREAL >= REAL >= LONGINT >= INTEGER >= SHORTINT

注意:>= 在這裡表示“是超集或等於”。

6.2. 陣列型別

陣列是由固定數量的元素組成的結構,這些元素都是相同型別,稱為元素型別。陣列的元素數量稱為其長度。陣列的元素由索引指定,索引是 0 到長度減 1 之間的整數。

$  ArrayType  =  ARRAY length {"," length} OF type.
$  length  =  ConstExpression.

以下形式的宣告:ARRAY N0, N1, ... , Nk OF T
被理解為以下宣告的縮寫

ARRAY N0 OF
  ARRAY N1 OF
    ...
      ARRAY Nk OF T

示例

ARRAY N OF INTEGER
ARRAY 10, 20 OF REAL
6.3. 記錄型別

記錄型別是由固定數量的元素組成的結構,這些元素可能是不同型別。記錄型別宣告為每個元素(稱為欄位)指定其型別和識別符號,該識別符號表示該欄位。這些欄位識別符號的作用域是記錄定義本身,但它們也在引用記錄變數的元素的欄位指示符中可見(參見第 8.1 節)。

$  RecordType  =  RECORD ["(" BaseType ")"] FieldListSequence END.
$  BaseType  =  qualident.
$  FieldListSequence  =  FieldList {";" FieldList}.
$  FieldList  =  [IdentList ":" type].
$  IdentList  =  identdef {"," identdef}.

如果匯出記錄型別,則在宣告模組之外可見的欄位識別符號必須被標記。它們被稱為公共欄位;未標記的欄位被稱為私有欄位

記錄型別是可擴充套件的,也就是說,可以將記錄型別定義為另一個記錄型別的擴充套件。在上面的示例中,CenterNode(直接)擴充套件Node,它是 CenterNode 的(直接)基型別。更具體地說,CenterNode透過namesubnode欄位擴充套件了Node

定義:型別T0擴充套件型別T,如果它等於T,或者如果它直接擴充套件了T的擴充套件。相反,型別TT0基型別,如果它等於T0,或者如果它是T0基型別的直接基型別。

示例

  RECORD day, month, year: INTEGER
  END

  RECORD
    name, firstname: ARRAY 32 OF CHAR;
    age: INTEGER;
    salary: REAL
  END
6.4. 指標型別

指標型別 P 的變數假設指向某種型別 T 的變數的指標作為值。指標型別 P 被稱為繫結到 T,而 T 是 P 的指標基型別。T 必須是記錄型別或陣列型別。指標型別繼承了其基型別的擴充套件關係。如果型別 T0 是 T 的擴充套件,而 P0 是繫結到 T0 的指標型別,則 P0 也是 P 的擴充套件。

$  PointerType  =  POINTER TO type.

如果 p 是型別 P = POINTER TO T 的變數,則呼叫預定義過程 NEW(p) 會產生以下效果(參見 10.2):在空閒儲存中分配一個型別為 T 的變數,並將其指標分配給 p。這個指標 p 是型別為 P;被引用的變數 p^ 是型別為 T。分配失敗會導致 p 獲得值 NIL。任何指標變數都可以分配值 NIL,它不指向任何變數。

6.5. 過程型別

過程型別 T 的變數具有過程(或 NIL)作為值。如果過程 P 被分配給型別為 T 的過程變數,則 P 的形式引數(型別)必須與 T 的形式引數中指示的相同。在函式過程的情況下,結果型別也是如此(參見 10.1)。P 不能被宣告為另一個過程的區域性過程,也不能是預定義的過程。

$  ProcedureType = PROCEDURE [FormalParameters].
7. 變數宣告

變數宣告用於引入變數並將它們與在給定作用域內必須唯一的識別符號關聯起來。它們還用於將固定資料型別與變數關聯起來。

$  VariableDeclaration  =  IdentList ":" type.

識別符號出現在同一列表中的變數都具有相同的型別。

變數宣告示例(參見第 6 節中的示例)

  i, j, k:  INTEGER
  x, y:     REAL
  p, q:     BOOLEAN
  s:        SET
  f:        Function
  a:        ARRAY 100 OF REAL
  w:        ARRAY 16 OF
              RECORD ch: CHAR;
                count: INTEGER
              END
  t:        Tree

指標型別T0的變數和記錄型別T0的 VAR 引數可以假設其型別T1是其宣告型別T0的擴充套件的值。

8. 表示式

表示式是表示計算規則的結構,透過該規則將常量和變數的當前值結合起來,透過應用運算子和函式過程來推匯出其他值。表示式由運算元和運算子組成。可以使用括號來表達運算子和運算元的特定關聯。

8.1. 運算元

除了集合和字面常量(例如數字和字元字串)之外,運算元由識別符號表示。識別符號由一個識別符號組成,該識別符號引用要指定的常量、變數或過程。此識別符號可能由模組識別符號限定(參見第 4 節和第 11 節),如果指定的物件是結構的元素,則後面可以跟選擇器。

如果 A 表示一個數組,則 A[E] 表示 A 中索引為表示式 E 的當前值的元素。E 的型別必須是整數型別。形式為 A[E1, E2, ... , En] 的識別符號代表 A[E1][E2] ... [En]。如果 p 表示一個指標變數,則 p^ 表示 p 所引用的變數。如果 r 表示一個記錄,則 r.f 表示 r 的欄位 f。如果 p 表示一個指標,則 p.f 表示記錄 p^ 的欄位 f,即點表示解引用,p.f 代表 p^.f,而 p[E] 表示 p^ 中索引為 E 的元素。

型別保護 v(T0) 斷言v 的型別為T0,即如果v 的型別不為T0,則它會中止程式執行。如果滿足以下條件,則該保護可應用:

1. T0v 的宣告型別T 的擴充套件,並且如果
2. v 是記錄型別形式變數引數或v 是指標。
$  designator  =  qualident {"." ident | "[" ExpList "]" | "(" qualident ")" | "^" }.
$  ExpList  =  expression {"," expression}.

如果指定的物件是變數,則識別符號引用變數的當前值。如果該物件是過程,則不帶引數列表的識別符號引用該過程。如果後面跟著(可能為空)的引數列表,則識別符號表示過程的啟用,並表示其執行結果的值。(實際引數的)型別必須與過程宣告中指定的形式引數相對應(參見第 10 節)。

識別符號示例(參見第 7 節中的示例)

  i                      (INTEGER)
  a[i]                   (REAL)
  w[3].ch                (CHAR)
  t.key                  (INTEGER)
  t.left.right           (Tree)
  t(CenterNode).subnode  (Tree)
8.2. 運算子

表示式的語法區分了四類具有不同優先順序(繫結強度)的運算子。運算子 ~ 具有最高優先順序,其次是乘法運算子、加法運算子和關係運算符。具有相同優先順序的運算子從左到右結合。例如,x-y-z 代表 (x-y)-z。

$  expression  =  SimpleExpression [relation SimpleExpression].
$  relation  =  "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
$  SimpleExpression  =  ["+"|"-"] term {AddOperator term}.
$  AddOperator  =  "+" | "-" | OR .
$  term  =  factor {MulOperator factor}.
$  MulOperator  =  "*" | "/" | DIV | MOD | "&" .
$  factor  =  number | CharConstant | string | NIL | set |
$    designator [ActualParameters] | "(" expression ")" | "~" factor.
$  set  =  "{" [element {"," element}] "}".
$  element  =  expression [".." expression].
$  ActualParameters  =  "(" [ExpList] ")" .

可用的運算子列在下面的表格中。在某些情況下,同一個運算子符號可能表示幾種不同的運算。在這些情況下,實際運算由運算元的型別確定。

8.2.1 邏輯運算子

symbol    result
 OR       logical disjunction
  &       logical conjunction
  ~       negation

這些運算子適用於 BOOLEAN 運算元併產生 BOOLEAN 結果。

p OR q  stands for   "if p then TRUE, else q"
p & q   stands for   "if p then q, else FALSE"
~ p     stands for   "not p"

8.2.2. 算術運算子

symbol  result
  +     sum
  -     difference
  *     product
  /     quotient
 DIV    integer quotient
 MOD    modulus

運算子 +、-、* 和 / 適用於數字型別運算元。結果的型別是包含另一個運算元型別的運算元型別,除了除法 (/),其中結果是包含兩個運算元型別的實數型別。當用作具有單個運算元的運算子時,- 表示符號反轉,+ 表示恆等運算。

運算子 DIV 和 MOD 僅適用於整數運算元。它們由以下公式定義,適用於任何被除數 x 和正除數 y

    x  =  (x DIV y) * y  +  (x MOD y)
    0  <= (x MOD y) < y

8.2.3. 集合運算子

symbol  result
   +  union
   -  difference
   *  intersection
   /  symmetric set difference

一元減號表示 x 的補集,即 -x 表示 0 到 MAX(SET) 之間的整數集,這些整數不是 x 的元素。

x - y  =  x * (-y)
x / y  =  (x-y) + (y-x)

8.2.4. 關係

symbol  relation
  =      equal
  #      unequal
  <      less
  <=     less or equal
  >      greater
  >=     greater or equal
  IN     set membership
  IS     type test

關係是布林值。排序關係 <、<=、> 和 >= 適用於數字型別、CHAR 和字元陣列(字串)。關係 = 和 # 也適用於型別 BOOLEAN 以及集合、指標和過程型別。x IN s 表示“x 是 s 的元素”。x 必須是整數型別,而 s 必須是 SET 型別。v IS T 表示“v 的型別為 T”,稱為型別測試。如果滿足以下條件,則該測試適用:

  1. T 是 v 的宣告型別 T0 的擴充套件,並且如果
  2. v 是記錄型別變數引數或 v 是指標。

例如,假設 T 是 T0 的擴充套件,並且 v 是宣告為型別 T0 的識別符號,則測試“v IS T”確定實際指定的變數是否為(不僅是 T0,而且也是)T。NIL IS T 的值是未定義的。

表示式示例(參見第 7 節中的示例)

  1987               (INTEGER)
  i DIV 3            (INTEGER)
  ~p OR q            (BOOLEAN)
  (i+j) * (i-j)      (INTEGER)
  s - {8, 9, 13}     (SET)
  i + x              (REAL)
  a[i+j] * a[i-j]    (REAL)
  (0<=i) & (i<100)   (BOOLEAN)
  t.key = 0          (BOOLEAN)
  k IN {i .. j-1}    (BOOLEAN)
  t IS CenterNode    (BOOLEAN)
9. 語句

語句表示動作。有基本語句和結構化語句。基本語句不包含任何本身是語句的部分。它們是賦值、過程呼叫以及返回和退出語句。結構化語句由本身是語句的部分組成。它們用於表達順序執行以及條件執行、選擇執行和重複執行。語句也可能是空的,在這種情況下,它表示不執行任何操作。空語句的引入是為了放鬆語句序列中的標點規則。

$  statement  =  [assignment | ProcedureCall |
$    IfStatement | CaseStatement | WhileStatement | RepeatStatement |
$    LoopStatement | WithStatement | EXIT | RETURN [expression] ].
9.1 賦值

賦值用於用表示式指定的新的值替換變數的當前值。賦值運算子寫為 ":=",讀作變成。

$  assignment  =  designator ":=" expression.

表示式的型別必須被變數的型別包含,或者它必須擴充套件變數的型別。以下例外情況成立:

  1. 常量 NIL 可以分配給任何指標或過程型別的變數。
  2. 字串可以分配給任何型別為字元陣列的變數,前提是字串的長度小於陣列的長度。如果長度為 n 的字串 s 分配給陣列 a,則結果為 a[i] = si,其中 i = 0 ... n-1,而 a[n] = 0X。

賦值示例(參見第 7 節中的示例)

  i := 0
  p := i = j
  x := i + 1
  k := log2(i+j)
  F := log2
  s := {2, 3, 5, 7, 11, 13}
  a[i] := (x+y) * (x-y)
  t.key := i
  w[i+1].ch := "A"
9.2 過程呼叫

過程呼叫用於啟用過程。過程呼叫可能包含實際引數列表,這些引數將替換過程宣告中定義的相應形式引數(參見第 10 節)。對應關係由引數在實際引數列表和形式引數列表中的位置分別建立。引數有兩種型別:變數引數和值引數。

在變數引數的情況下,實際引數必須是表示變數的識別符號。如果它指定了結構化變數的元素,則選擇器在形式引數/實際引數替換髮生時(即在過程執行之前)進行計算。如果引數是值引數,則相應的實際引數必須是表示式。該表示式在過程啟用之前進行計算,所得的值被分配給形式引數,該形式引數現在構成了區域性變數(另見 10.1)。

$  ProcedureCall  =  designator [ActualParameters].

過程呼叫的示例

  ReadInt(i) (see Section 10)
  WriteInt(j*2+1, 6)
  INC(w[k].count)
9.3. 語句序列

語句序列表示由元件語句指定的動作序列,這些元件語句由分號分隔。

$  StatementSequence  =  statement {";" statement}.
9.4. if 語句
$  IfStatement  =  IF expression THEN StatementSequence
$    {ELSIF expression THEN StatementSequence}
$    [ELSE StatementSequence]
$  END.

if 語句指定受保護語句的條件執行。語句之前的布林表示式稱為其保護條件。保護條件按出現順序進行計算,直到其中一個計算結果為 TRUE,然後執行其關聯的語句序列。如果沒有任何保護條件滿足,則執行 ELSE 符號後的語句序列(如果有)。

示例

  IF (ch >= "A") & (ch <= "Z") THEN ReadIdentifier
    ELSIF (ch >= "0") & (ch <= "9") THEN ReadNumber
    ELSIF ch = 22X THEN ReadString
  END
9.5. case 語句

case 語句指定根據表示式的值選擇和執行語句序列。首先計算 case 表示式,然後執行其 case 標籤列表包含所得值的語句序列。case 表示式和所有標籤必須具有相同的型別,該型別必須是整數型別或 CHAR。case 標籤是常量,任何值不得出現多次。如果表示式的值在任何 case 的標籤中都沒有出現,則選擇 ELSE 符號後的語句序列(如果有)。否則,它被視為錯誤。

$  CaseStatement  =  CASE expression OF case {"|" case}
$                    [ELSE StatementSequence] END.
$  case  =  [CaseLabelList ":" StatementSequence].
$  CaseLabelList  =  CaseLabels {"," CaseLabels}.
$  CaseLabels  =  ConstExpression [".." ConstExpression].

示例

  CASE ch OF
      "A" .. "Z": ReadIdentifier
    | "0" .. "9": ReadNumber
    | 22X : ReadString
  ELSE SpecialCharacter
  END
9.6. while 語句

while 語句指定重複執行。如果布林表示式(保護條件)結果為 TRUE,則執行語句序列。表示式計算和語句執行重複進行,直到布林表示式結果為 TRUE。

$  WhileStatement  =  WHILE expression DO StatementSequence END.

示例

  WHILE j > 0 DO
    j := j DIV 2; i := i+1
  END

  WHILE (t # NIL) & (t.key # i) DO
    t := t.left
  END
9.7. repeat 語句

repeat 語句指定語句序列的重複執行,直到滿足條件為止。語句序列至少執行一次。

$  RepeatStatement  =  REPEAT StatementSequence UNTIL expression.
9.8. loop 語句

loop 語句指定語句序列的重複執行。它由該序列中任何退出語句的執行終止(參見 9.9)。

$  LoopStatement  =  LOOP StatementSequence END.

示例

  LOOP
    IF t1 = NIL THEN EXIT END ;
    IF k < t1.key THEN t2 := t1.left; p := TRUE
    ELSIF k > t1.key THEN t2 := t1.right; p := FALSE
    ELSE EXIT
    END ;
    t1 := t2
  END

雖然 while 和 repeat 語句可以透過包含單個退出語句的 loop 語句來表達,但在大多數情況下,建議使用 while 和 repeat 語句,在這種情況下,終止依賴於在重複語句序列的開頭或結尾確定的單個條件。loop 語句用於表達具有多個終止條件和點的案例。

9.9. 返回和退出語句

返回語句由符號 RETURN 組成,後面可能跟著一個表示式。它表示過程的終止,表示式指定函式過程的結果。它的型別必須與過程標題中指定的返回型別相同(參見第 10 節)。

函式過程需要一個返回語句,表示結果值。可能有多個,但只有一個會被執行。在正確過程中,返回語句由過程體末尾隱式提供。因此,顯式返回語句作為附加的(可能是例外情況的)終止點出現。

退出語句由符號 EXIT 組成。它指定退出封閉的 loop 語句,並繼續執行該 loop 語句後的語句。退出語句與包含它們的 loop 語句在語義上相關聯,儘管在語法上沒有關聯。

9.10. with 語句

如果指標變數或帶有記錄結構的變數引數的型別為 T0,則它可以在 with 子句的標題中與型別 T 一起指定,該型別 T 是 T0 的擴充套件。然後,該變數在 with 語句中被保護,就好像它已宣告為型別 T 一樣。with 語句承擔類似於型別保護的角色,將保護條件擴充套件到整個語句序列。它可以被視為區域型別保護。

$  WithStatement  =  WITH qualident ":" qualident DO StatementSequence END .

示例

  WITH t: CenterNode DO name := t.name; L := t.subnode END
10. 過程宣告

過程宣告由過程標題過程體組成。標題指定過程識別符號、形式引數和返回型別(如果有)。主體包含宣告和語句。過程識別符號在過程宣告末尾重複。

過程有兩種型別:正確過程函式過程。後者由表示式中的函式識別符號啟用,併產生一個表示式中的運算元結果。正確過程由過程呼叫啟用。函式過程在宣告中透過在引數列表之後指示其結果的型別來區分。它的主體必須包含一個定義函式過程結果的 RETURN 語句。

在過程體內宣告的所有常量、變數、型別和過程都對該過程是區域性的。在進入過程時,區域性變數的值未定義。由於過程也可以宣告為區域性物件,因此過程宣告可以巢狀。

除了其形式引數和區域性宣告的物件外,在過程環境中宣告的物件在過程中也是可見的(那些與區域性宣告的物件同名的物件除外)。

在過程宣告中呼叫時使用過程識別符號表示過程的遞迴啟用。

$  ProcedureDeclaration  =  ProcedureHeading ";" ProcedureBody ident.
$  ProcedureHeading  =  PROCEDURE ["*"] identdef [FormalParameters].
$  ProcedureBody  =  DeclarationSequence [BEGIN StatementSequence] END.
$  ForwardDeclaration  =  PROCEDURE "^" identdef [FormalParameters].
$  DeclarationSequence  =  {CONST {ConstantDeclaration ";"} |
$    TYPE {TypeDeclaration ";"} | VAR {VariableDeclaration ";"}}
$    {ProcedureDeclaration ";" | ForwardDeclaration ";"}.

前向宣告用於允許對文字中後面出現的過程進行前向引用。實際宣告 - 指定主體 - 必須指示與前向宣告相同的引數和返回型別(如果有),並且必須在同一個範圍內。

在符號 PROCEDURE 後面的星號是編譯器的提示,指定該過程可用作引數並可分配給變數。(根據實現方式,提示可能是可選的或必需的。)

10.1. 形式引數

形式引數是識別符號,表示在過程呼叫中指定的實際引數。當呼叫過程時,建立形式引數和實際引數之間的對應關係。引數有兩種,即*值*引數和*變數引數*。引數的型別在形式引數列表中指示。值引數代表區域性變數,將對應實際引數的求值結果作為初始值賦予該區域性變數。變數引數對應於實際引數,實際引數是變數,並且變數引數代表這些變數。變數引數用符號 VAR 表示,值引數用 VAR 符號的缺失表示。沒有引數的函式過程必須有一個空引數列表。它必須透過一個實際引數列表也是空的函式設計器來呼叫。

形式引數對過程是區域性的,即它們的範圍是構成過程宣告的程式文字。

$  FormalParameters  =  "(" [FPSection {";" FPSection}] ")" [":" qualident].
$  FPSection  =  [VAR] ident  {"," ident} ":" FormalType.
$  FormalType  =  {ARRAY OF} qualident | ProcedureType.

每個形式引數的型別在引數列表中指定。對於變數引數,它必須與相應實際引數的型別相同,除了記錄的情況,它必須是相應實際引數型別的基本型別。對於值引數,賦值規則適用(參見 9.1)。如果形式引數的型別指定為 ARRAY OF T,則該引數被稱為*開放陣列引數*,並且相應的實際引數可以是任何元素型別為 *T* 的陣列。

如果形式引數指定了過程型別,則相應的實際引數必須是全域性宣告的過程,或者該過程型別的變數(或引數)。它不能是預定義的過程。過程的結果型別既不能是記錄也不能是陣列。

過程宣告的示例

PROCEDURE ReadInt(VAR x: INTEGER);
   VAR i : INTEGER; ch: CHAR;
BEGIN i := 0; Read(ch);
   WHILE ("0" <= ch) & (ch <= "9") DO
       i := 10*i + (ORD(ch)-ORD("0")); Read(ch)
   END ;
   x := i
END ReadInt

PROCEDURE WriteInt(x: INTEGER);  (* 0 <= x < 10.0E5 *)
   VAR i: INTEGER;
       buf: ARRAY 5 OF INTEGER;
BEGIN i := 0;
   REPEAT buf[i] := x MOD 10;  x := x DIV 10;  INC(i) UNTIL x = 0;
   REPEAT DEC(i); Write(CHR(buf[i] + ORD("0"))) UNTIL i = 0
END WriteInt

PROCEDURE log2(x: INTEGER): INTEGER;
   VAR y: INTEGER;  (*assume x > 0*)
BEGIN y := 0;
   WHILE x > 1 DO x := x DIV 2; INC(y) END ;
   RETURN y
END log2
10.2. 預定義過程

下表列出了預定義的過程。一些是*泛型*過程,即它們適用於幾種型別的運算元。v 代表變數,x 和 n 代表表示式,T 代表型別。

函式過程

名稱 引數型別 結果型別 函式
ABS(x) 數字型別 x 的型別 絕對值
ODD(x) 整數型別 BOOLEAN x MOD 2 = 1
CAP(x) CHAR CHAR 相應的大寫字母
ASH(x, n) x, n: 整數型別 LONGINT x * 2n,算術移位
LEN(v, n) v: 陣列
n: 整數型別
LONGINT v 在維度 n 中的長度
LEN(v) 陣列型別 LONGINT LEN(v, 0)
MAX(T) T = 基本型別
T = SET
T
INTEGER
型別 T 的最大值
集合的最大元素
MIN(T) T = 基本型別
T = SET
T
INTEGER
型別 T 的最小值
0
SIZE(T) T = 任何型別 整數型別 T 需要的位元組數

型別轉換過程

名稱 引數型別 結果型別 函式
ORD(x) CHAR INTEGER x 的序數
CHR(x) 整數型別 CHAR 序數為 x 的字元
SHORT(x) LONGINT
INTEGER
LONGREAL
INTEGER
SHORTINT
REAL
身份(可能截斷)
LONG(x) SHORTINT
INTEGER
REAL
INTEGER
LONGINT
LONGREAL
身份
ENTIER(x) 實數型別 LONGINT 不超過 x 的最大整數。
注意 ENTIER(i/j) = i DIV j

適當的過程

名稱 引數型別 函式
INC(v) 整數型別 v := v+1
INC(v, x) 整數型別 v := v+x
DEC(v) 整數型別 v := v-1
DEC(v, x) 整數型別 v := v-x
INCL(v, x) v: SET
x: 整數型別
v := v + {x}
EXCL(v, x) v: SET
x: 整數型別
v := v - {x}
COPY(x, v) x: 字元陣列,字串
v: 字元陣列
v := x
NEW(v) 指標型別 分配 v^
HALT(x) 整數常量 終止程式執行

在 HALT(x) 中,x 是一個引數,其解釋留給底層系統實現。

11. 模組

模組是常量、型別、變數和過程宣告的集合,以及用於為變數分配初始值的語句序列。模組通常構成一個可作為單元編譯的文字。

$ module  =  MODULE ident ";"  [ImportList] DeclarationSequence
$     [BEGIN StatementSequence] END ident "." .
$ ImportList  =  IMPORT import {"," import} ";" .
$ import  =  ident [":=" ident].

匯入列表指定了模組是其客戶端的模組。如果識別符號 x 從模組 M 匯出,並且 M 列在模組的匯入列表中,則 x 被稱為 M.x。如果在匯入列表中使用形式“M := M1”,則在 M1 中宣告的物件將被引用為 M.x 。

在客戶端模組中可見的識別符號,即在宣告模組之外可見的識別符號,必須在其宣告中用匯出標記標記。

在符號 BEGIN 之後的語句序列是在將模組新增到系統(載入)時執行的。此後,可以從系統中啟用各個(無引數)過程,這些過程用作*命令*。

示例

MODULE Out;
  (*exported procedures:  Write, WriteInt, WriteLn*)
  IMPORT Texts, Oberon;
  VAR W: Texts.Writer;
  PROCEDURE Write*(ch: CHAR);
  BEGIN Texts.Write(W, ch)
  END ;
  PROCEDURE WriteInt*(x, n: LONGINT);
    VAR i: INTEGER; a: ARRAY 16 OF CHAR;
  BEGIN i := 0;
    IF x < 0 THEN Texts.Write(W, "-"); x := -x END ;
    REPEAT a[i] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(i) UNTIL x = 0;
    REPEAT Texts.Write(W, " "); DEC(n) UNTIL n <= i;
    REPEAT DEC(i); Texts.Write(W, a[i]) UNTIL i = 0
  END WriteInt;
  PROCEDURE WriteLn*;
  BEGIN Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  END WriteLn;
BEGIN Texts.OpenWriter(W)
END Out.
12. 模組 SYSTEM

模組 SYSTEM 包含定義,這些定義對於直接引用特定計算機和/或實現的資源的*低階*操作的程式設計是必需的。這些包括例如訪問由計算機控制的裝置的工具,以及打破語言定義中其他施加的資料型別相容性規則的工具。建議將它們的使用限制在特定的*低階*模組中。此類模組本質上不可移植,但由於它們的匯入列表中出現了識別符號 SYSTEM 而易於識別。隨後的定義適用於大多數現代計算機;但是,各個實現可能在此模組中包含特定於特定底層計算機的定義。

模組 SYSTEM 匯出資料型別 BYTE。沒有指定值的表示。相反,給出了與其他型別的某些相容性規則

  1. 型別 BYTE 與 CHAR 和 SHORTINT 相容。
  2. 如果形式引數的型別為 ARRAY OF BYTE,則相應的實際引數可以是任何型別。

模組 SYSTEM 中包含的過程列在下表中。它們對應於作為內聯程式碼編譯的單個指令。有關詳細資訊,請參閱處理器手冊。v 代表變數,x、y、a 和 n 代表表示式,T 代表型別。

函式過程

名稱 引數型別 結果型別 函式
ADR(v) 任何 LONGINT 變數 v 的地址
BIT(a, n) a: LONGINT
n: 整數型別
BOOLEAN Mem[a] 的位 n
CC(n) 整數常量 BOOLEAN 條件 n (0 <= n < 16)
LSH(x, n) x: 整數型別或 SET
n: 整數型別
x 的型別 邏輯移位
ROT(x, n) x: 整數型別或 SET
n: 整數型別
x 的型別 旋轉
VAL(T, x) T, x: 任何型別 T x 被解釋為型別 T

適當的過程

名稱 引數型別 函式
GET(a, v) a: LONGINT
v: 任何基本型別
v := Mem[a]
PUT(a, x) a: LONGINT
x: 任何基本型別
Mem[a] := x
MOVE(s, d, n) s, d: LONGINT
n: 整數型別
Mem[d] ... Mem[d+n-1]
:= Mem[s] ... Mem[s+n-1]
NEW(v, n) v: 任何指標型別
n: 整數型別
分配大小為 n 位元組的儲存塊
將它的地址分配給 v

HTML 翻譯:A. Fischer 和 J. Gutknecht/ 1999 年 10 月

2002 年 7 月 13 日 - 版權所有 © 2002 ETH Zürich。保留所有權利。
電子郵件:oberon at lists.inf.ethz.ch
主頁:http://www.ethoberon.ethz.ch/

華夏公益教科書