home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / Misc / OB3.2D1.DMS / in.adf / Oberon2.txt < prev    next >
Encoding:
Text File  |  1992-11-03  |  66.3 KB  |  1,676 lines

  1. Differences between Oberon and Oberon-2
  2. H. Mössenböck, N. Wirth
  3. Institut für Computersysteme, ETH Zürich
  4.  
  5. Oberon-2 is a true extension of Oberon [1]. This paper summarizes the
  6. extensions and tries to shed some light on the motivations behind them. By
  7. that we hope to make it easier for the reader to classify Oberon-2. For
  8. details the reader is referred to the language report.
  9.  
  10. One important goal for Oberon-2 was to make object-oriented programming
  11. easier without sacrificing the conceptual simplicity of Oberon. After
  12. three years of using Oberon and its experimental offspring Object Oberon
  13. [2] we merged our experiences into a single refined version of Oberon.
  14.  
  15. The new features of Oberon-2 are type-bound procedures, read-only export
  16. of variables and record fields, open arrays as pointer base types, and a
  17. with statement with variants. The for statement is reintroduced after
  18. having been eliminated in the step from Modula-2 to Oberon.
  19.  
  20. Oberon-2 is the result of many discussions among all members of the
  21. Institute for Computer Systems at ETH. It is particularly influenced by
  22. the ideas of JŸrg Gutknecht and Josef Templ.
  23.  
  24.  
  25. Type-bound procedures
  26.  
  27. Procedures can be bound to a record (or a pointer) type. They are
  28. equivalent to methods in object-oriented terminology. The binding is
  29. expressed by a separate parameter (the operand to which the procedure is
  30. applicable, or the "receiver" as it is called in object-oriented
  31. terminology).
  32.  
  33.         TYPE
  34.                 Figure = POINTER TO FigureDesc;
  35.                 FigureDesc = RECORD
  36.                         x, y, w, h: INTEGER
  37.                 END;
  38.  
  39.         PROCEDURE (f: Figure) Draw; BEGIN ...  END Draw;
  40.         PROCEDURE (f: Figure) Move (dx, dy: INTEGER); BEGIN ...  END Move;
  41.  
  42. Draw and Move are bound to Figure which means that they are operations
  43. applicable to Figure objects. They are considered local to FigureDesc and
  44. can be referenced like record fields, e.g. f.Move(10, 10) if f is a
  45. variable of type Figure.
  46.  
  47. Any procedure bound to a type T is implicitly also bound to all extensions
  48. of T. It can be redefined (overridden) by a procedure with the same name
  49. and the same formal parameter list which is explicitly bound to an
  50. extension of T, such as in
  51.  
  52.         TYPE
  53.                 Circle = POINTER TO CircleDesc;
  54.                 CircleDesc = RECORD (FigureDesc)
  55.                         radius: INTEGER
  56.                 END;
  57.  
  58.         PROCEDURE (c: Circle) Move (dx, dy: INTEGER);
  59.         BEGIN ...
  60.         END Move;
  61.  
  62. Circle is an extension of Figure. A procedure Move is explicitly bound to
  63. Circle and redefines the Move that is "inherited" from Figure. Let f be a
  64. variable of type Figure and c a variable of type Circle; then the
  65. assignment f := c makes the dynamic type of f (its run time type) be
  66. Circle instead of Figure. In the call
  67.  
  68.         f.Move(10, 10)
  69.  
  70. the variable f serves two purposes: First it is passed as the receiver
  71. parameter to the procedure Move. Second, its dynamic type determines which
  72. variant of Move is called. Since after the assignment f := c the dynamic
  73. type of f is Circle, the Move that is bound to Circle is called and not
  74. the one that is bound to Figure. This mechanism is called dynamic binding,
  75. since the dynamic type of the receiver is used to bind the procedure name
  76. to the actual procedure.
  77.  
  78. Within a redefining procedure the redefined procedure can be invoked by
  79. calling it with the suffix ^, e.g. f.Move^ (dx, dy).
  80.  
  81. Motivation. We refrained from introducing the concept of a class but
  82. rather replaced it by the well-known concept of records. Classes are
  83. simply record types with procedures bound to them.
  84.  
  85. We also refrained from duplicating the headers of bound procedures in the
  86. record as it is done in other object-oriented languages like C++ or Object
  87. Pascal. This keeps record declarations short and avoids unpleasant
  88. redundancy (changes to a header would have to be made at two places in the
  89. program and the compiler would have to check the equality of the headers).
  90. If the programmer wants to see the record together with all procedures
  91. bound to it he uses a tool (a browser) to obtain the information on screen
  92. or on paper.
  93.  
  94. The procedures bound to a type may be declared in any order. They can even
  95. be mixed with procedures bound to a different type. In Object Oberon,
  96. where all methods have to be declared within their class declaration, it
  97. turned out that indirect recursion between methods of different classes
  98. make awkward forward declarations of whole classes necessary.
  99.  
  100. In languages like Object Pascal or C++, instance variables of the receiver
  101. object self can be accessed with or without qualification (i.e. one can
  102. write either x or self.x). In these languages it is sometimes difficult to
  103. see whether a name is an ordinary variable or an instance variable. It is
  104. even more confusing if the name denotes an instance variable that is
  105. inherited from a base class. We therefore decided that instance variables
  106. must always be qualified in Oberon-2. This avoids having a choice between
  107. two semantically equivalent constructs, which we consider undesirable in
  108. programming languages.
  109.  
  110. In Oberon-2, the receiver is an explicit parameter, so the programmer can
  111. choose a meaningful name for it, which is usually more expressive than the
  112. predeclared name self that is used in other object-oriented languages. The
  113. explicit declaration of the receiver makes clear that the object to which
  114. an operation is applied is passed as a parameter to that operation. This
  115. is usually not expressed in other object-oriented languages. It is in the
  116. spirit of Oberon to avoid hidden mechanisms.
  117.  
  118. In Object Oberon methods have the same syntax as ordinary procedures. In
  119. large classes where the class header is not visible near the method header
  120. it is impossible to see whether the procedure is an ordinary procedure or
  121. a method, and to which class the method belongs. In Oberon-2, the type of
  122. the receiver parameter of a bound procedure denotes the type to which the
  123. procedure is bound, so no confusion can arise.
  124.  
  125.  
  126. Read-only export
  127.  
  128. While in Oberon all exported variables and record fields can be modified
  129. by a client module, it is possible in Oberon-2 to restrict the use of an
  130. exported variable or record field to read-only access. This is expressed
  131. by marking its declaration with a "-" instead of a "*". The "-" suggests
  132. the restricted use of such a variable.
  133.  
  134.         TYPE
  135.                 Rec* = RECORD
  136.                         f0*: INTEGER;
  137.                         f1-: INTEGER;
  138.                         f2: INTEGER
  139.                 END;
  140.  
  141.         VAR
  142.                 a*: INTEGER;
  143.                 b-: Rec;
  144.                 c: INTEGER;
  145.  
  146. Client modules can read the variables a and b as well as the fields f0 and
  147. f1, since these objects are exported. However, they can modify only a and
  148. f0; the value of b and f1 can be read but not modified. Only the module
  149. which exports these objects can modify their values. (Even if clients
  150. declare a private variable of type Rec, its field f1 is read-only.) Since
  151. b is read-only, its components are read-only, too.
  152.  
  153. The motivation behind read-only export is to allow a finer grain of
  154. information hiding. Information hiding serves two purposes: First, it
  155. helps to keep off unnecessary details from clients. Second, it allows
  156. establishing the assertion that the values of hidden variables are only
  157. modified by access procedures of the module itself, which is important to
  158. guarantee invariants. Read-only export supports the second goal.
  159.  
  160.  
  161. Open arrays
  162.  
  163. Both in Modula-2 and in Oberon it is possible to have open arrays as
  164. parameters. The length of such an array is given by the length of the
  165. actual parameter.  In Oberon-2 open arrays may not only be declared as
  166. formal parameter types but also as pointer base types. In this case, the
  167. predeclared procedure NEW is used to allocate the open array with
  168. arbitrary length.
  169.  
  170.         VAR v: POINTER TO ARRAY OF INTEGER;
  171.         ... NEW (v, 100)
  172.  
  173. The array v ^ is allocated at run time with a length of 100 elements
  174. accessed as v[0] to v[99].
  175.  
  176.  
  177. With statements
  178.  
  179. In Oberon, a with statement is a regional type guard of the form
  180.  
  181.         WITH v: T DO S END
  182.  
  183. If the variable v is of dynamic type T, then the statement sequence S is
  184. executed where a type guard v(T) is applied to every occurrence of v, i.e.
  185. v is regarded as if it had the static type T. If the dynamic type of v is
  186. not T the program is aborted. In Oberon-2, the with statement can be
  187. written with variants, e.g:
  188.  
  189.         WITH v : T0 DO S0
  190.         |  v : T1 DO S1
  191.         ELSE S2
  192.         END
  193.  
  194.  
  195. If the dynamic type of v is T0, then S0 is executed and v is regarded as
  196. if it had the static type T0; if the dynamic type of v is T1, then S1 is
  197. executed and v is regarded as if it had the static type T1; else S2 is
  198. executed. If no variant can be executed and if an else clause is missing
  199. the program is aborted.
  200.  
  201.  
  202. For statements
  203.  
  204. Although for statements can always be expressed by while statements, they
  205. are sometimes more convenient because they are shorter and termination is
  206. inherent. This is the case if the number of iterations is fixed like in
  207. many applications dealing with arrays. The for statement is written as:
  208.  
  209.         FOR i := a TO b BY step DO statements END
  210.  
  211. The control variable i as well as the expressions a and b and the constant
  212. expression step must be of an integer type. The above for statement is
  213. equivalent to the statement sequence
  214.  
  215.         i := a; temp := b;
  216.         IF step > 0 THEN
  217.                 WHILE i <= temp DO statements; i := i + step END
  218.         ELSE
  219.                 WHILE i >= temp DO statements; i := i + step END
  220.         END
  221.  
  222.  
  223. References
  224.  
  225. [1]     N.Wirth: The Programming Language Oberon. Software Practice &
  226.         Experience, 18 (1988)
  227. [2]     H.Mössenböck, J. Templ: Object Oberon Ð A Modest Object-Oriented
  228.         Language. Structured Programming 10/4: 199-207, 1989
  229.  
  230.  
  231.  
  232. The Programming Language Oberon-2
  233.  
  234. H. Mössenböck, N. Wirth
  235. Institut für Computersysteme, ETH Zürich
  236.  
  237.  
  238.  
  239. 1. Introduction
  240.  
  241. Oberon-2 is a general-purpose language in the tradition of Oberon and
  242. Modula-2. Its most important features are block structure, modularity,
  243. separate compilation, static typing with strong type checking (also across
  244. module boundaries), and type extension with type-bound procedures.
  245.  
  246. Type extension makes Oberon-2 an object-oriented language. An object is a
  247. variable of an abstract data type consisting of private data (its state)
  248. and procedures that operate on this data. Abstract data types are declared
  249. as extensible records. Oberon-2 covers most terms of object-oriented
  250. languages by the established vocabulary of imperative languages in order
  251. to minimize the number of notions for similar concepts.
  252.  
  253. This report is not intended as a programmer's tutorial. It is
  254. intentionally kept concise. Its function is to serve as a reference for
  255. programmers, implementors, and manual writers. What remains unsaid is
  256. mostly left so intentionally, either because it can be derived from stated
  257. rules of the language, or because it would require to commit the
  258. definition when a general commitment appears as unwise.
  259.  
  260. Appendix A defines some terms that are used to express the type checking
  261. rules of Oberon-2. Where they appear in the text, they are written in
  262. italics to indicate their special meaning (e.g. the same type).
  263.  
  264.  
  265. 2. Syntax
  266.  
  267. An extended Backus-Naur Formalism (EBNF) is used to describe the syntax of
  268. Oberon-2: Brackets [ and ] denote optionality of the enclosed expression,
  269. and braces { and } denote its repetition (possibly 0 times). Non-terminal
  270. symbols start with an upper-case letter (e.g. Statement). Terminal symbols
  271. either start with a lower-case letter (e.g. ident), or are written all in
  272. upper-case letters (e.g. BEGIN), or are denoted by strings (e.g. ":=").
  273.  
  274.  
  275. 3. Vocabulary and Representation
  276.  
  277. The representation of (terminal) symbols in terms of characters is defined
  278. using the ASCII set. Symbols are identifiers, numbers, strings, operators,
  279. and delimiters. The following lexical rules must be observed: Blanks and
  280. line breaks must not occur within symbols (except in comments, and blanks
  281. in strings). They are ignored unless they are essential to separate two
  282. consecutive symbols. Capital and lower-case letters are considered as
  283. distinct.
  284.  
  285. 1. Identifiers are sequences of letters and digits. The first character
  286. must be a letter.
  287.  
  288. ident = letter {letter | digit}.
  289.  
  290. Examples:     x     Scan     Oberon2     GetSymbol     firstLetter
  291.  
  292. 2. Numbers are (unsigned) integer or real constants. Integers are
  293. sequences of digits and may be followed by a suffix letter. The type is
  294. the minimal type to which the number belongs (see 6.1). If no suffix is
  295. specified, the representation is decimal. The suffix H indicates
  296. hexadecimal representation.
  297.  
  298. A real number always contains a decimal point. Optionally it may also
  299. contain a decimal scale factor. The letter E (or D) means "times ten to
  300. the power of". A real number is of type REAL, unless it has a scale factor
  301. containing the letter D. In this case it is of type LONGREAL.
  302.  
  303. number  = integer | real.
  304. integer         = digit {digit} | digit {hexDigit} "H".
  305. real    = digit {digit} "." {digit} [ScaleFactor].
  306. ScaleFactor     = ("E" | "D") ["+" | "-"] digit {digit}.
  307. hexDigit        = digit | "A" | "B" | "C" | "D" | "E" | "F".
  308. digit   = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".
  309.  
  310. Examples:
  311.  
  312. 1991    INTEGER 1991
  313. 0DH     SHORTINT        13
  314. 12.3    REAL    12.3
  315. 4.567E8         REAL    456700000
  316. 0.57712566D-6   LONGREAL        0.00000057712566
  317.  
  318. 3. Character constants are either denoted by a single character enclosed
  319. in single (') or double (") quote marks or by the ordinal number of the
  320. character in hexadecimal notation followed by the letter X.
  321.  
  322. character = ' " ' char ' " ' | " ' " char " ' " | digit {hexDigit} "X".
  323.  
  324. 4. Strings are sequences of characters enclosed in single (') or
  325. double (") quote marks. The opening quote must be the same as the closing
  326. quote and must not occur within the string. The number of characters in a
  327. string is called its length.
  328.  
  329. string = ' " ' {char} ' " ' | " ' " {char} " ' ".
  330.  
  331. Examples:     "Oberon-2"     "Don't worry!"
  332.  
  333. 5. Operators and delimiters are the special characters, character pairs,
  334. or reserved words listed below. The reserved words consist exclusively of
  335. capital letters and cannot be used as identifiers.
  336.  
  337. +       :=      ARRAY   IMPORT  RETURN
  338. -       ^       BEGIN   IN      THEN
  339. *       =       BY      IS      TO
  340. /       #       CASE    LOOP    TYPE
  341. ~       <       CONST   MOD     UNTIL
  342. &       >       DIV     MODULE  VAR
  343. .       <=      DO      NIL     WHILE
  344. ,       >=      ELSE    OF      WITH
  345. ;       ..      ELSIF   OR
  346. |       :       END     POINTER
  347. (       )       EXIT    PROCEDURE
  348. [       ]       FOR     RECORD
  349. {       }       IF      REPEAT
  350.  
  351. 6. Comments may be inserted between any two symbols in a program. They are
  352. arbitrary character sequences opened by the bracket (* and closed by *).
  353. Comments may be nested. They do not affect the meaning of a program.
  354.  
  355. 4. Declarations and scope rules
  356.  
  357. Every identifier occurring in a program must be introduced by a
  358. declaration, unless it is a predeclared identifier. Declarations also
  359. specify certain permanent properties of an object, such as whether it is a
  360. constant, a type, a variable, or a procedure. The identifier is then used
  361. to refer to the associated object.
  362.  
  363. The scope of an object x extends textually from the point of its
  364. declaration to the end of the block (module, procedure, or record) to
  365. which the declaration belongs and hence to which the object is local. It
  366. excludes the scopes of equally named objects which are declared in nested
  367. blocks. The scope rules are:
  368.  
  369. 1. No identifier may denote more than one object within a given scope (i.
  370.    e. no identifier may be declared twice in a block);
  371. 2. An object may only be referenced within its scope;
  372. 3. A type T of the form POINTER TO T1 (see 6.4) can be declared before the
  373.    scope of T1. In this case, the declaration of T1 must follow in the
  374.    same block to which T is local;
  375. 4. Identifiers denoting record fields (see 6.3) or type-bound procedures (
  376.    see 10.2) are valid in record designators only.
  377.  
  378. An identifier declared in a module block may be followed by an export
  379. mark (" * " or " - ") in its declaration to indicate that it is exported.
  380. An identifier x exported by a module M may be used in other modules, if
  381. they import M (see Ch.11). The identifier is then denoted as M.x in these
  382. modules and is called a qualified identifier. Identifiers marked
  383. with " - " in their declaration are read-only in importing modules.
  384.  
  385. Qualident       = [ident "."] ident.
  386. IdentDef        = ident [" * " | " - "].
  387.  
  388. The following identifiers are predeclared; their meaning is defined in the
  389. indicated sections:
  390.  
  391. ABS     (10.3)  LEN     (10.3)
  392. ASH     (10.3)  LONG    (10.3)
  393. BOOLEAN (6.1)   LONGINT (6.1)
  394. CAP     (10.3)  LONGREAL        (6.1)
  395. CHAR    (6.1)   MAX     (10.3)
  396. CHR     (10.3)  MIN     (10.3)
  397. COPY    (10.3)  NEW     (10.3)
  398. DEC     (10.3)  ODD     (10.3)
  399. ENTIER  (10.3)  ORD     (10.3)
  400. EXCL    (10.3)  REAL    (6.1)
  401. FALSE   (6.1)   SET     (6.1)
  402. HALT    (10.3)  SHORT   (10.3)
  403. INC     (10.3)  SHORTINT        (6.1)
  404. INCL    (10.3)  SIZE    (10.3)
  405. INTEGER (6.1)   TRUE    (6.1)
  406.  
  407.  
  408. 5. Constant declarations
  409.  
  410. A constant declaration associates an identifier with a constant value.
  411.  
  412. ConstantDeclaration     = IdentDef "=" ConstExpression.
  413. ConstExpression         = Expression.
  414.  
  415. A constant expression is an expression that can be evaluated by a mere
  416. textual scan without actually executing the program. Its operands are
  417. constants (Ch.8) or predeclared functions (Ch.10.3) that can be evaluated
  418. at compile time. Examples of constant declarations are:
  419.  
  420.         N = 100
  421.         limit = 2*N - 1
  422.         fullSet = {MIN(SET) .. MAX(SET)}
  423.  
  424.  
  425. 6. Type declarations
  426.  
  427. A data type determines the set of values which variables of that type may
  428. assume, and the operators that are applicable. A type declaration
  429. associates an identifier with a type. In the case of structured types
  430. (arrays and records) it also defines the structure of variables of this
  431. type.
  432.  
  433. TypeDeclaration         = IdentDef "=" Type.
  434. Type    = Qualident | ArrayType | RecordType | PointerType | ProcedureType.
  435.  
  436. Examples:
  437.  
  438. Table = ARRAY N OF REAL
  439. Tree = POINTER TO Node
  440. Node =  RECORD
  441.         key : INTEGER;
  442.         left, right: Tree
  443. END
  444. CenterTree = POINTER TO CenterNode
  445. CenterNode = RECORD (Node)
  446.         width: INTEGER;
  447.         subnode: Tree
  448. END
  449. Function = PROCEDURE(x: INTEGER): INTEGER
  450.  
  451.  
  452. 6.1 Basic types
  453.  
  454. The basic types are denoted by predeclared identifiers. The associated
  455. operators are defined in 8.2 and the predeclared function procedures in 10.
  456. 3. The values of the given basic types are the following:
  457.  
  458. 1. BOOLEAN   the truth values TRUE and FALSE
  459. 2. CHAR      the characters of the extended ASCII set (0X .. 0FFX)
  460. 3. SHORTINT  the integers between MIN(SHORTINT) and MAX(SHORTINT)
  461. 4. INTEGER   the integers between MIN(INTEGER) and MAX(INTEGER)
  462. 5. LONGINT   the integers between MIN(LONGINT) and MAX(LONGINT)
  463. 6. REAL      the real numbers between MIN(REAL) and MAX(REAL)
  464. 7. LONGREAL  the real numbers between MIN(LONGREAL) and MAX(LONGREAL)
  465. 8. SET       the sets of integers between 0 and MAX(SET)
  466.  
  467. Types 3 to 5 are integer types, types 6 and 7 are real types, and together
  468. they are called numeric types. They form a hierarchy; the larger type
  469. includes (the values of) the smaller type:
  470.  
  471.         LONGREAL  <=  REAL  <=  LONGINT  <=  INTEGER  <=  SHORTINT
  472.  
  473. 6.2 Array types
  474.  
  475. An array is a structure consisting of a number of elements which are all
  476. of the same type, called the element type. The number of elements of an
  477. array is called its length. The elements of the array are designated by
  478. indices, which are integers between 0 and the length minus 1.
  479.  
  480. ArrayType       = ARRAY [Length {"," Length}] OF Type.
  481. Length  = ConstExpression.
  482.  
  483. A declaration of the form
  484.  
  485.         ARRAY L0, L1, ..., Ln OF T
  486.  
  487. is understood as an abbreviation of the declaration
  488.  
  489.         ARRAY L0 OF
  490.                 ARRAY L1 OF
  491.                 ...
  492.                         ARRAY Ln OF T
  493.  
  494. Arrays declared without length are called open arrays. They are restricted
  495. to pointer base types (see 6.4) and formal parameter types (see 10.1).
  496.  
  497. Examples:
  498.         ARRAY 10, N OF INTEGER
  499.         ARRAY OF CHAR
  500.  
  501.  
  502. 6.3 Record types
  503.  
  504. A record type is a structure consisting of a fixed number of elements,
  505. called fields, with possibly different types. The record type declaration
  506. specifies the name and type of each field. The scope of the field
  507. identifiers extends from the point of their declaration to the end of the
  508. record type, but they are also visible within designators referring to
  509. elements of record variables (see 8.1). If a record type is exported,
  510. field identifiers that are to be visible outside the declaring module must
  511. be marked. They are called public fields; unmarked elements are called
  512. private fields.
  513.  
  514. RecordType      = RECORD ["("BaseType")"] FieldList {";" FieldList} END.
  515. BaseType        = Qualident.
  516. FieldList       = [IdentList ":" Type ].
  517.  
  518. Record types are extensible, i.e. a record type can be declared as an
  519. extension of another record type. In the example
  520.  
  521.         T0 = RECORD x: INTEGER END
  522.         T1 = RECORD (T0) y: REAL END
  523.  
  524. T1 is a (direct) extension of T0 and T0 is the (direct) base type of T1
  525. (see App. A). An extended type T1 consists of the fields of its base type
  526. and of the fields which are declared in T1 (see Ch. 6).
  527.  
  528. Examples of record type declarations:
  529.  
  530. RECORD
  531.         day, month, year: INTEGER
  532. END
  533.  
  534. RECORD
  535.         name, firstname: ARRAY 32 OF CHAR;
  536.         age: INTEGER;
  537.         salary: REAL
  538. END
  539.  
  540.  
  541. 6.4 Pointer types
  542.  
  543. Variables of a pointer type P assume as values pointers to variables of
  544. some type T. T is called the pointer base type of P and must be a record
  545. or array type. Pointer types inherit the extension relation of their
  546. pointer base types: if a type T1 is an extension of T, and P1 is of type
  547. POINTER TO T1, then P1 is also an extension of P.
  548.  
  549. PointerType = POINTER TO Type.
  550.  
  551. If p is a variable of type P = POINTER TO T, a call of the predeclared
  552. procedure NEW (see 10.3) allocates a variable of type T in free storage.
  553. If T is a record type or an array type with fixed length, the allocation
  554. has to be done with NEW(p); if T is an n-dimensional open array type the
  555. allocation has to be done with NEW(p, e0, ..., en-1) where T is allocated
  556. with lengths given by the expressions e0, ..., en-1. In either case a
  557. pointer to the allocated variable is assigned to p. p is of type P. The
  558. referenced  variable p ^ is of type T.
  559.  
  560. Any pointer variable may assume the value NIL, which points to no variable
  561. at all. All pointer variables are initialized to NIL.
  562.  
  563.  
  564. 6.5 Procedure types
  565.  
  566. Variables of a procedure type T have a procedure (or NIL) as value. If a
  567. procedure P is assigned to a variable of type T, the formal parameter
  568. lists of P and T must match(see App. A). P must not be a predeclared or
  569. type-bound procedure nor may it be local to another procedure.
  570.  
  571. ProcedureType = PROCEDURE [FormalParameters].
  572.  
  573.  
  574. 7. Variable declarations
  575.  
  576. Variable declarations introduce variables by defining an identifier and a
  577. data type for them.
  578.  
  579. VariableDeclaration = IdentList ":" Type.
  580.  
  581. Record and pointer variables have both a static type (the type with which
  582. they are declared Ð simply called their type) and a dynamic type (the type
  583. they assume at run time). For pointers and variable parameters of record
  584. type the dynamic type may be an extension of their static type. The static
  585. type determines which fields of a record are accessible. The dynamic type
  586. is used to call type-bound procedures (see 10.2).
  587.  
  588. Examples of variable declarations (refer to examples in Ch. 6):
  589.  
  590. i, j, k: INTEGER
  591. x, y: REAL
  592. p, q: BOOLEAN
  593. s: SET
  594. F: Function
  595. a: ARRAY 100 OF REAL
  596. w: ARRAY 16 OF RECORD
  597.                 name: ARRAY 32 OF CHAR;
  598.                 count: INTEGER
  599.         END
  600. t, c: Tree
  601.  
  602.  
  603. 8. Expressions
  604.  
  605. Expressions are constructs denoting rules of computation whereby constants
  606. and current values of variables are combined to compute other values by
  607. the application of operators and function procedures. Expressions consist
  608. of operands and operators. Parentheses may be used to express specific
  609. associations of operators and operands.
  610.  
  611.  
  612. 8.1 Operands
  613.  
  614. With the exception of set constructors and literal constants (numbers,
  615. character constants, or strings), operands are denoted by designators. A
  616. designator consists of an identifier referring to a constant, variable, or
  617. procedure. This identifier may possibly be qualified by a module
  618. identifier (see Ch. 4 and 11) and may be followed by selectors if the
  619. designated object is an element of a structure.
  620.  
  621. Designator      = Qualident {"." ident | "[" ExpressionList "]" | "^" |
  622.                   "(" Qualident ")"}.
  623. ExpressionList  = Expression {"," Expression}.
  624.  
  625. If a designates an array, then a[e] denotes that element of a whose index
  626. is the current value of the expression e. The type of e must be an integer
  627. type. A designator of the form a[e0, e1, ..., en] stands for a[e0][e1]...[
  628. en]. If r designates a record, then r.f denotes the field f of r or the
  629. procedure f bound to the dynamic type of r (Ch. 10.2). If p designates a
  630. pointer, p^ denotes the variable which is referenced by p. The designators
  631. p^.f and p^[e] may be abbreviated as p.f and p[e], i.e. record and array
  632. selectors imply dereferencing. If a or r are read-only, then also a[e] and
  633. r.f are read-only.
  634.  
  635. A type guard v(T) asserts that the dynamic type of v is T (or an extension
  636. of T), i.e. program execution is aborted, if the dynamic type of v is not
  637. T (or an extension of T). Within the designator, v is then regarded as
  638. having the static type T. The guard is applicable, if
  639.  
  640. 1.      v is a variable parameter of record type or v is a pointer, and if
  641. 2.      T is an extension of the static type of v
  642.  
  643. If the designated object is a variable, then the designator refers to the
  644. variable's current value. If it is a procedure, the designator refers to
  645. that procedure unless it is followed by a (possibly empty) parameter list
  646. in which case it implies an activation of that procedure and stands for
  647. the value resulting from its execution. The actual parameters must
  648. correspond to the formal parameters as in proper procedure calls (see 10.1).
  649.  
  650.  
  651. Examples of designators (refer to examples in Ch.7):
  652.  
  653. i       (INTEGER)
  654. a[i]    (REAL)
  655. w[3].name[i]    (CHAR)
  656. t.left.right    (Tree)
  657. t(CenterNode).subnode   (Tree)
  658.  
  659.  
  660. 8.2 Operators
  661.  
  662. Four classes of operators with different precedences (binding strengths)
  663. are syntactically distinguished in expressions. The operator ~ has the
  664. highest precedence, followed by multiplication operators, addition
  665. operators, and relations. Operators of the same precedence associate from
  666. left to right. For example, x-y-z stands for (x-y)-z.
  667.  
  668. Expression      = SimpleExpression [Relation SimpleExpression].
  669. SimpleExpression        = ["+" | "-"] Term {AddOperator Term}.
  670. Term    = Factor {MulOperator Factor}.
  671. Factor  = Designator [ActualParameters] |
  672.             number | character | string | NIL | Set | "(" Expression ")" | "~" Factor.
  673. Set     = "{" [Element {"," Element}] "}".
  674. Element         = Expression [".." Expression].
  675. ActualParameters        = "(" [ExpressionList] ")".
  676. Relation        = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
  677. AddOperator     = "+" | "-" | OR.
  678. MulOperator     = "*" | "/" | DIV | MOD | "&".
  679.  
  680. The available operators are listed in the following tables. Some operators
  681. are applicable to operands of various types, denoting different
  682. operations. In these cases, the actual operation is identified by the type
  683. of the operands. The operands must be expression compatible with respect
  684. to the operator (see App.A).
  685.  
  686. 8.2.1 Logical operators
  687.  
  688. OR      logical disjunction     p OR q  º  "if p then TRUE, else q"
  689. &       logical conjunction     p & q   º  "if p then q, else FALSE"
  690. ~       negation        ~ p     º  "not p"
  691.  
  692.         These operators apply to BOOLEAN operands and yield a BOOLEAN result.
  693.  
  694. 8.2.2 Arithmetic operators
  695.  
  696. +       sum
  697. -       difference
  698. *       product
  699. /       real quotient
  700. DIV     integer quotient
  701. MOD     modulus
  702.  
  703. The operators +, -, *, and / apply to operands of numeric types. The type
  704. of the result is the type of that operand which includes the type of the
  705. other operand, except for division (/), where the result is the smallest
  706. real type which includes both operand types. When used as monadic
  707. operators, - denotes sign inversion and + denotes the identity operation.
  708. The operators DIV and MOD apply to integer operands only. They are related
  709. by the following formulas defined for any x and positive divisors y:
  710.  
  711.         x = (x DIV y) * y + (x MOD y)
  712.         0 ² (x MOD y) < y
  713.  
  714.         Examples:
  715.         x       y       x DIV y x MOD y
  716.         5       3       1       2
  717.         -5      3       -2      1
  718.  
  719. 8.2.3 Set Operators
  720.  
  721. +       union
  722. -       difference (x - y = x * (-y))
  723. *       intersection
  724. /       symmetric set difference (x / y = (x-y) + (y-x))
  725.  
  726. Set operators apply to operands of type SET and yield a result of type
  727. SET. The monadic minus sign denotes the complement of x, i.e. -x denotes
  728. the set of integers between 0 and MAX(SET) which are not elements of x.
  729.  
  730. A set constructor defines the value of a set by listing its elements
  731. between curly brackets. The elements must be integers in the range 0..MAX(
  732. SET). A range a..b denotes all integers in the interval [a, b].
  733.  
  734. 8.2.4 Relations
  735.  
  736. =       equal
  737. #       unequal
  738. <       less
  739. <=      less or equal
  740. >       greater
  741. >=      greater or equal
  742. IN      set membership
  743. IS      type test
  744.  
  745. Relations yield a BOOLEAN result. The ordering relations <, <=, >, and >=
  746. apply to the numeric types, CHAR, (open) character arrays, and strings.
  747. The relations = and # also apply to BOOLEAN and SET, as well as to pointer
  748. and procedure types (including the value NIL). x IN s stands for "x is an
  749. element of s". x must be of an integer type, and s of type SET. v IS T
  750. stands for "the dynamic type of v is T (or an extension of T)" and is
  751. called a type test. It is applicable if
  752.  
  753. 1.      v is a variable parameter of record type or v is a pointer, and if
  754. 2.      T is an extension of the static type of v
  755.  
  756. Examples of expressions (refer to examples in Ch.7):
  757.  
  758. 1991    INTEGER
  759. i DIV 3 INTEGER
  760. ~p OR q BOOLEAN
  761. (i+j) * (i-j)   INTEGER
  762. s - {8, 9, 13}  SET
  763. i + x   REAL
  764. a[i+j] * a[i-j] REAL
  765. (0<=i) & (i<100)        BOOLEAN
  766. t.key = 0       BOOLEAN
  767. k IN {i..j-1}   BOOLEAN
  768. w[i].name <= "John"     BOOLEAN
  769. t IS CenterNode BOOLEAN
  770.  
  771.  
  772. 9. Statements
  773.  
  774. Statements denote actions. There are elementary and structured statements.
  775. Elementary statements are not composed of any parts that are themselves
  776. statements. They are the assignment, the procedure call, the return, and
  777. the exit statement. Structured statements are composed of parts that are
  778. themselves statements. They are used to express sequencing and
  779. conditional, selective, and repetitive execution. A statement may also be
  780. empty, in which case it denotes no action. The empty statement is included
  781. in order to relax punctuation rules in statement sequences.
  782.  
  783. Statement =
  784.         [ Assignment | ProcedureCall | IfStatement | CaseStatement | WhileStatement | RepeatStatement |
  785.         ForStatement | LoopStatement | WithStatement | EXIT | RETURN [Expression] ].
  786.  
  787.  
  788. 9.1 Assignments
  789.  
  790. Assignments replace the current value of a variable by a new value
  791. specified by an expression. The expression must be assignment compatible
  792. with the variable (see App. A). The assignment operator is written as ":="
  793. and pronounced as becomes.
  794.  
  795. Assignment = Designator ":=" Expression.
  796.  
  797. If an expression e of type Te is assigned to a variable v of type Tv, the
  798. following happens:
  799.  
  800. 1. if Tv and Te are record types, only those fields of Te are assigned
  801.    which also belong to Tv (projection); the dynamic type of v  must be the
  802.    same as the static type of v and  is not changed by the assignment;
  803. 2. if Tv and Te are pointer types, the dynamic type of v becomes the
  804.    dynamic type of e;
  805. 3. if Tv is ARRAY n OF CHAR and e is a string of length m<n, v[i] becomes
  806.    ei for i = 0..m-1 and v[m] becomes 0X.
  807.  
  808. Examples of assignments (refer to examples in Ch.7):
  809.  
  810. i := 0
  811. p := i = j
  812. x := i + 1
  813. k := log2(i+j)
  814. F := log2       (* see 10.1 *)
  815. s := {2, 3, 5, 7, 11, 13}
  816. a[i] := (x+y) * (x-y)
  817. t.key := i
  818. w[i+1].name := "John"
  819. t := c
  820.  
  821. 9.2 Procedure calls
  822.  
  823. A procedure call activates a procedure. It may contain a list of actual
  824. parameters which replace the corresponding formal parameters defined in
  825. the procedure declaration (see Ch. 10). The correspondence is established
  826. by the positions of the parameters in the actual and formal parameter
  827. lists. There are two kinds of parameters: variable and value parameters.
  828.  
  829. If a formal parameter is a variable parameter, the corresponding actual
  830. parameter must be a designator denoting a variable. If it denotes an
  831. element of a structured variable, the component selectors are evaluated
  832. when the formal/actual parameter substitution takes place, i.e. before the
  833. execution of the procedure. If a formal parameter is a value parameter,
  834. the corresponding actual parameter must be an expression. This expression
  835. is evaluated before the procedure activation, and the resulting value is
  836. assigned to the formal parameter (see also 10.1).
  837.  
  838. ProcedureCall = Designator [ActualParameters].
  839.  
  840. Examples:
  841.  
  842. WriteInt(i*2+1) (* see 10.1 *)
  843. INC(w[k].count)
  844. t.Insert("John")        (* see 11 *)
  845.  
  846.  
  847. 9.3 Statement sequences
  848.  
  849. Statement sequences denote the sequence of actions specified by the
  850. component statements which are separated by semicolons.
  851.  
  852. StatementSequence = Statement {";" Statement}.
  853.  
  854.  
  855. 9.4 If statements
  856.  
  857. IfStatement =
  858.         IF Expression THEN StatementSequence
  859.         {ELSIF Expression THEN StatementSequence}
  860.         [ELSE StatementSequence]
  861.         END.
  862.  
  863. If statements specify the conditional execution of guarded statement
  864. sequences. The Boolean expression preceding a statement sequence is called
  865. its guard. The guards are evaluated in sequence of occurrence, until one
  866. evaluates to TRUE, whereafter its associated statement sequence is
  867. executed. If no guard is satisfied, the statement sequence following the
  868. symbol ELSE is executed, if there is one.
  869.  
  870. Example:
  871.  
  872. IF (ch >= "A") & (ch <= "Z") THEN ReadIdentifier
  873. ELSIF (ch >= "0") & (ch <= "9") THEN ReadNumber
  874. ELSIF (ch = " ' ") OR (ch = ' " ') THEN ReadString
  875. ELSE SpecialCharacter
  876. END
  877.  
  878.  
  879. 9.5 Case statements
  880.  
  881. Case statements specify the selection and execution of a statement
  882. sequence according to the value of an expression. First the case
  883. expression is evaluated, then that statement sequence is executed whose
  884. case label list contains the obtained value. The case expression and all
  885. labels must be of the same type, which must be an integer type or CHAR.
  886. Case labels are constants, and no value must occur more than once. If the
  887. value of the expression does not occur as a label of any case, the
  888. statement sequence following the symbol ELSE is selected, if there is one,
  889. otherwise the program is aborted.
  890.  
  891. CaseStatement   = CASE Expression OF Case {"|" Case} [ELSE StatementSequence] END.
  892. Case    = [CaseLabelList ":" StatementSequence].
  893. CaseLabelList   = CaseLabels {"," CaseLabels}.
  894. CaseLabels      = ConstExpression [".." ConstExpression].
  895.  
  896. Example:
  897.  
  898. CASE ch OF
  899.         "A" .. "Z": ReadIdentifier
  900. |       "0" .. "9": ReadNumber
  901. |       " ' ", ' " ': ReadString
  902. ELSE SpecialCharacter
  903. END
  904.  
  905.  
  906. 9.6 While statements
  907.  
  908. While statements specify the repeated execution of a statement sequence
  909. while the Boolean expression (its guard) yields TRUE. The guard is checked
  910. before every execution of the statement sequence.
  911.  
  912.         WhileStatement = WHILE Expression DO StatementSequence END.
  913.  
  914. Examples:
  915.  
  916. WHILE i > 0 DO i := i DIV 2; k := k + 1 END
  917. WHILE (t # NIL) & (t.key # i) DO t := t.left END
  918.  
  919.  
  920. 9.7 Repeat statements
  921.  
  922. A repeat statement specifies the repeated execution of a statement
  923. sequence until a condition specified by a Boolean expression is satisfied.
  924. The statement sequence is executed at least once.
  925.  
  926. RepeatStatement = REPEAT StatementSequence UNTIL Expression.
  927.  
  928.  
  929. 9.8 For statements
  930.  
  931. A for statement specifies the repeated execution of a statement sequence
  932. for a fixed number of times while a progression of values is assigned to
  933. an integer variable called the control variable of the for statement.
  934.  
  935. ForStatement =
  936.         FOR ident ":=" Expression TO Expression [BY ConstExpression] DO StatementSequence END.
  937.  
  938. The statement
  939.  
  940.         FOR v := low TO high BY step DO statements END
  941.  
  942. is equivalent to
  943.  
  944.         v := low; temp := high;
  945.         IF step > 0 THEN
  946.                 WHILE v <= temp DO statements; v := v + step END
  947.         ELSE
  948.                 WHILE v >= temp DO statements; v := v + step END
  949.         END
  950.  
  951. low must be assignment compatible with v (see App. A), high must be
  952. expression compatible (i.e. comparable) with v, and step must be a nonzero
  953. constant expression of an integer type. If step is not specified, it is
  954. assumed to be 1.
  955.  
  956. Examples:
  957.         FOR i := 0 TO 79 DO k := k + a[i] END
  958.         FOR i := 79 TO 1 BY -1 DO a[i] := a[i-1] END
  959.  
  960.  
  961. 9.9 Loop statements
  962.  
  963. A loop statement specifies the repeated execution of a statement sequence.
  964. It is terminated upon execution of an exit statement within that sequence (
  965. see 9.10).
  966.  
  967. LoopStatement = LOOP StatementSequence END.
  968.  
  969. Example:
  970. LOOP
  971.         ReadInt(i);
  972.         IF i < 0 THEN EXIT END;
  973.         WriteInt(i)
  974. END
  975.  
  976. Loop statements are useful to express repetitions with several exit points
  977. or cases where the exit condition is in the middle of the repeated
  978. statement sequence.
  979.  
  980.  
  981. 9.10 Return and exit statements
  982.  
  983. A return statement indicates the termination of a procedure. It is denoted
  984. by the symbol RETURN, followed by an expression if the procedure is a
  985. function procedure. The type of the expression must be assignment
  986. compatible (see App. A) with the result type specified in the procedure
  987. heading (see Ch.10).
  988.  
  989. Function procedures require the presence of a return statement indicating
  990. the result value. In proper procedures, a return statement is implied by
  991. the end of the procedure body. Any explicit return statement therefore
  992. appears as an additional (probably exceptional) termination point.
  993.  
  994. An exit statement is denoted by the symbol EXIT. It specifies termination
  995. of the enclosing loop statement and continuation with the statement
  996. following that loop statement. Exit statements are contextually, although
  997. not syntactically associated with the loop statement which contains them.
  998.  
  999.  
  1000. 9.11 With statements
  1001.  
  1002. With statements execute a statement sequence depending on the result of a
  1003. type test and apply a type guard to every occurrence of the tested
  1004. variable within this statement sequence.
  1005.  
  1006. WithStatement   =       WITH Guard DO StatementSequence {"|" Guard DO StatementSequence}
  1007.                 [ELSE StatementSequence] END.
  1008. Guard   =       Qualident ":" Qualident.
  1009.  
  1010. If v is a variable parameter of record type or a pointer variable, and if
  1011. it is of a static type T0, the statement
  1012.  
  1013.         WITH v: T1 DO S1 | v: T2 DO S2 ELSE S3 END
  1014.  
  1015. has the following meaning: if the dynamic type of v is T1, then the
  1016. statement sequence S1 is executed where v is regarded as if it had the
  1017. static type T1; else if the dynamic type of v is T2, then S2 is executed
  1018. where v is regarded as if it had the static type T2; else S3 is executed.
  1019. T1 and T2 must be extensions of T0. If no type test is satisfied and if an
  1020. else clause is missing the program is aborted.
  1021.  
  1022. Example:
  1023.  
  1024.         WITH t: CenterTree DO i := t.width; c := t.subnode END
  1025.  
  1026.  
  1027. 10. Procedure declarations
  1028.  
  1029. A procedure declaration consists of a procedure heading and a procedure
  1030. body. The heading specifies the procedure identifier and the formal
  1031. parameters. For type-bound procedures it also specifies the receiver
  1032. parameter. The body contains declarations and statements. The procedure
  1033. identifier is repeated at the end of the procedure declaration.
  1034.  
  1035. There are two kinds of procedures: proper procedures and function
  1036. procedures. The latter are activated by a function designator as a
  1037. constituent of an expression and yield a result that is an operand of the
  1038. expression. Proper procedures are activated by a procedure call. A
  1039. procedure is a function procedure if its formal parameters specify a
  1040. result type. The body of a function procedure must contain a return
  1041. statement which defines its result.
  1042.  
  1043. All constants, variables, types, and procedures declared within a
  1044. procedure body are local to the procedure. Since procedures may be
  1045. declared as local objects too, procedure declarations may be nested. The
  1046. call of a procedure within its declaration implies recursive activation.
  1047.  
  1048. In addition to its formal parameters and locally declared objects, the
  1049. objects declared in the environment of the procedure are also visible in
  1050. the procedure (with the exception of those objects that have the same name
  1051. as an object declared locally).
  1052.  
  1053. ProcedureDeclaration    = ProcedureHeading ";" ProcedureBody ident.
  1054. ProcedureHeading        = PROCEDURE [Receiver] IdentDef [FormalParameters].
  1055. ProcedureBody   = DeclarationSequence [BEGIN StatementSequence] END.
  1056. DeclarationSequence     =
  1057.         {CONST {ConstantDeclaration ";"} | TYPE {TypeDeclaration ";"} | VAR {VariableDeclaration ";"} }
  1058.         {ProcedureDeclaration ";" | ForwardDeclaration ";"}.
  1059. ForwardDeclaration      = PROCEDURE " ^ " [Receiver] IdentDef [FormalParameters].
  1060. If a procedure declaration specifies a receiver parameter, the procedure is considered to be bound to a type (see 10.2). A forward declaration serves to allow forward references to a procedure whose actual declaration appears later in the text. The formal parameter lists of the forward declaration and the actual declaration must match (see App. A).
  1061.  
  1062.  
  1063. 10.1 Formal parameters
  1064.  
  1065. Formal parameters are identifiers declared in the formal parameter list of
  1066. a procedure. They correspond to actual parameters specified in the
  1067. procedure call. The correspondence between formal and actual parameters is
  1068. established when the procedure is called. There are two kinds of
  1069. parameters, value and variable parameters, indicated in the formal
  1070. parameter list by the absence or presence of the keyword VAR. Value
  1071. parameters are local variables to which the value of the corresponding
  1072. actual parameter is assigned as an initial value. Variable parameters
  1073. correspond to actual parameters that are variables, and they stand for
  1074. these variables. The scope of a formal parameter extends from its
  1075. declaration to the end of the procedure block in which it is declared. A
  1076. function procedure without parameters must have an empty parameter list.
  1077. It must be called by a function designator whose actual parameter list is
  1078. empty too.
  1079.  
  1080. FormalParameters        = "(" [FPSection {";" FPSection}] ")" [":" Qualident].
  1081. FPSection       = [VAR] ident {"," ident} ":" Type.
  1082.  
  1083. Let Tf be the type of a formal parameter f and Ta the type of the
  1084. corresponding actual parameter a. For variable parameters, Ta must be the
  1085. same as Tf, or Tf must be a record type and Ta an extension of Tf. For
  1086. value parameters, a must be assignment compatible with f (see App. A). If
  1087. Tf is an open array , then a must be array compatible with f (see App. A).
  1088. The lengths of f are taken from a. The result type of a procedure can be
  1089. neither a record nor an array.
  1090.  
  1091. Examples of procedure declarations:
  1092.  
  1093. PROCEDURE ReadInt(VAR x: INTEGER);
  1094.         VAR i: INTEGER; ch: CHAR;
  1095. BEGIN i := 0; Read(ch);
  1096.         WHILE ("0" <= ch) & (ch <= "9") DO
  1097.                 i := 10*i + (ORD(ch)-ORD("0")); Read(ch)
  1098.         END;
  1099.         x := i
  1100. END ReadInt
  1101.  
  1102. PROCEDURE WriteInt(x: INTEGER); (*0 <= x <10^5*)
  1103.         VAR i: INTEGER; buf: ARRAY 5 OF INTEGER;
  1104. BEGIN i := 0;
  1105.         REPEAT buf[i] := x MOD 10; x := x DIV 10; INC(i) UNTIL x = 0;
  1106.         REPEAT DEC(i); Write(CHR(buf[i] + ORD("0"))) UNTIL i = 0
  1107. END WriteInt
  1108.  
  1109. PROCEDURE WriteString(s: ARRAY OF CHAR);
  1110.         VAR i: INTEGER;
  1111. BEGIN i := 0;
  1112.         WHILE (i < LEN(s)) & (s[i] # 0X) DO Write(s[i]); INC(i) END
  1113. END WriteString;
  1114.  
  1115.  
  1116. PROCEDURE log2(x: INTEGER): INTEGER;
  1117.         VAR y: INTEGER; (*assume x>0*)
  1118. BEGIN
  1119.         y := 0; WHILE x > 1 DO x := x DIV 2; INC(y) END;
  1120.         RETURN y
  1121. END log2
  1122.  
  1123.  
  1124. 10.2 Type-bound procedures
  1125.  
  1126. An abstract data type consists of a record type and a set of associated
  1127. procedures which are said to be bound to it. The binding is expressed by
  1128. the type of the receiver in the heading of a procedure declaration.  The
  1129. receiver may be either a variable parameter of record type or a value
  1130. parameter of type pointer to record. The procedure is bound to the type of
  1131. the receiver. If it is bound to a pointer type it is also bound to its
  1132. pointer base type. A procedure bound to a record type is considered local
  1133. to it.
  1134.  
  1135. ProcedureHeading        = PROCEDURE [Receiver] IdentDef [FormalParameters].
  1136. Receiver        = "(" [VAR] ident ":" ident ")".
  1137.  
  1138. If a procedure P is bound to a type T0, it is implicitly also bound to any
  1139. type T1 which is an extension of T0. However, a procedure P ' (with the
  1140. same name as P) may be explicitly bound to T1 in which case it overrides
  1141. the binding of P. P ' is considered as a redefinition of P for T1. The
  1142. formal parameters of P and P ' must match (see App. A).
  1143.  
  1144. If v is a designator and P is a type-bound procedure, then v.P denotes
  1145. that procedure P which is bound to the dynamic type of v (dynamic
  1146. binding). Note, that this may be a different procedure than the one bound
  1147. to the static type of v. v is passed to P's receiver according to the
  1148. parameter passing rules specified in Chapter 10.1.
  1149.  
  1150. If r is a receiver parameter declared with type T, r.P ^ denotes the
  1151. (redefined) procedure P bound to the base type of T.
  1152.  
  1153. In a forward declaration of a type-bound procedure the receiver parameter
  1154. must be of the same type as in the actual procedure declaration. The
  1155. formal parameter lists of both declarations must match (App.A).
  1156.  
  1157. Examples:
  1158.  
  1159. PROCEDURE (t: Tree) Insert (node: Tree);
  1160.         VAR p, father: Tree;
  1161. BEGIN p := t;
  1162.         REPEAT father := p;
  1163.                 IF node.key = p.key THEN RETURN END;
  1164.                 IF node.key < p.key THEN p := p.left ELSE p := p.right END
  1165.         UNTIL p = NIL;
  1166.         IF node.key < father.key THEN father.left := node ELSE father.right := node END;
  1167.         node.left := NIL; node.right := NIL
  1168. END Insert;
  1169.  
  1170. PROCEDURE (t: CenterTree) Insert (node: Tree);  (*redefinition*)
  1171. BEGIN
  1172.         WriteInt(node(CenterTree).width);
  1173.         t.Insert^ (node)  (* calls the Insert procedure bound to Tree *)
  1174. END Insert;
  1175.  
  1176.  
  1177. 10.3 Predeclared procedures
  1178.  
  1179. The following table lists the predeclared procedures. Some are generic
  1180. procedures, i.e. they apply to several types of operands. v stands for a
  1181. variable, x and n for expressions, and T for a type.
  1182.  
  1183. Function procedures
  1184.  
  1185. Name    Argument type   Result type     Function
  1186. ABS(x)  numeric type    type of x       absolute value
  1187. ASH(x, n)       x, n: integer type      LONGINT arithmetic shift (x * 2n)
  1188. CAP(x)  CHAR    CHAR    x is letter: corresponding capital letter
  1189. CHR(x)  integer type    CHAR    character with ordinal number x
  1190. ENTIER(x)       real type       LONGINT largest integer not greater than x
  1191. LEN(v, n)       v: array; n: integer const.     LONGINT length of v in dimension n
  1192. LEN(v)  v: array        LONGINT equivalent to LEN(v, 0)
  1193. LONG(x) SHORTINT        INTEGER identity
  1194.         INTEGER LONGINT
  1195.         REAL    LONGREAL
  1196. MAX(T)  T = basic type  T       maximum value of type T
  1197.         T = SET INTEGER maximum element of a set
  1198. MIN(T)  T = basic type  T       minimum value of type T
  1199.         T = SET INTEGER 0
  1200. ODD(x)  integer type    BOOLEAN x MOD 2 = 1
  1201. ORD(x)  CHAR    INTEGER ordinal number of x
  1202. SHORT(x)        LONGINT INTEGER identity
  1203.         INTEGER SHORTINT        identity
  1204.         LONGREAL        REAL    identity (truncation possible)
  1205. SIZE(T) any type        integer type    number of bytes required by T
  1206.  
  1207. Proper procedures
  1208.  
  1209. Name    Argument types          Function
  1210.  
  1211. COPY(x, v)      x: character array, string; v: character array  v := x
  1212. DEC(v)  integer type            v := v - 1
  1213. DEC(v, n)       v, n: integer type              v := v - n
  1214. EXCL(v, x)      v: SET; x: integer type v := v - {x}
  1215. HALT(x) integer constant                terminate program execution
  1216. INC(v)  integer type            v := v + 1
  1217. INC(v, n)       v, n: integer type              v := v + n
  1218. INCL(v, x)      v: SET; x: integer type v := v + {x}
  1219. NEW(v)  pointer to record or fixed array        allocate v ^
  1220. NEW(v, x0, ..., xn) v: pointer to open array; xi: integer type    allocate v ^ with lengths x0.. xn
  1221.  
  1222. COPY allows the assignment between (open) character arrays with different
  1223. types. If necessary, the source is shortened to the target length minus
  1224. one. The target is always terminated by the character 0X. In HALT(x), the
  1225. interpretation of x is left to the underlying system implementation.
  1226.  
  1227. 11. Modules
  1228.  
  1229. A module is a collection of declarations of constants, types, variables,
  1230. and procedures, together with a sequence of statements for the purpose of
  1231. assigning initial values to the variables. A module constitutes a text
  1232. that is compilable as a unit.
  1233.  
  1234. Module  = MODULE ident ";" [ImportList] DeclarationSequence
  1235.             [BEGIN StatementSequence] END ident ".".
  1236. ImportList      = IMPORT Import {"," Import} ";".
  1237. Import  = [ident ":="] ident.
  1238.  
  1239. The import list specifies the names of the imported modules. If a module A
  1240. is imported by a module M and A exports an identifier x, then x is
  1241. referred to as A.x within M. If A is imported as B := A, the object x is
  1242. referenced as B.x. This allows short alias names in qualified identifiers.
  1243. Identifiers that are to be exported (i.e. that are to be visible in client
  1244. modules) must be marked by an export mark in their declaration (see
  1245. Chapter 4).
  1246.  
  1247. The statement sequence following the symbol BEGIN is executed when the
  1248. module is added to a system (loaded), which is done after the imported
  1249. modules have been loaded. It follows that cyclic import of modules is
  1250. illegal. Individual (parameterless and exported) procedures can be
  1251. activated from the system, and these procedures serve as commands (see
  1252. Appendix D1).
  1253.  
  1254. MODULE Trees;   (* exports: Tree, Node, Insert, Search, Write, NewTree *)
  1255.         IMPORT Texts, Oberon;   (* exports read-only: Node.name *)
  1256.  
  1257.         TYPE
  1258.                 Tree* = POINTER TO Node;
  1259.                 Node* = RECORD
  1260.                         name-: POINTER TO ARRAY OF CHAR;
  1261.                         left, right: Tree
  1262.                 END;
  1263.  
  1264.         VAR w: Texts.Writer;
  1265.  
  1266.         PROCEDURE (t: Tree) Insert* (name: ARRAY OF CHAR);
  1267.                 VAR p, father: Tree;
  1268.         BEGIN p := t;
  1269.                 REPEAT father := p;
  1270.                         IF name = p.name^ THEN RETURN END;
  1271.                         IF name < p.name^ THEN p := p.left ELSE p := p.right END
  1272.                 UNTIL p = NIL;
  1273.                 NEW(p); p.left := NIL; p.right := NIL; NEW(p.name, LEN(name)+1); COPY(name, p.name^);
  1274.                 IF name < father.name^ THEN father.left := p ELSE father.right := p END
  1275.         END Insert;
  1276.  
  1277.         PROCEDURE (t: Tree) Search* (name: ARRAY OF CHAR): Tree;
  1278.                 VAR p: Tree;
  1279.         BEGIN p := t;
  1280.                 WHILE (p # NIL) & (name # p.name^) DO
  1281.                         IF name < p.name^ THEN p := p.left ELSE p := p.right END
  1282.                 END;
  1283.                 RETURN p
  1284.         END Search;
  1285.         PROCEDURE (t: Tree) Write*;
  1286.         BEGIN
  1287.                 IF t.left # NIL THEN t.left.Write END;
  1288.                 Texts.WriteString(w, t.name^); Texts.WriteLn(w); Texts.Append(Oberon.Log, w.buf);
  1289.                 IF t.right # NIL THEN t.right.Write END
  1290.         END Write;
  1291.  
  1292.         PROCEDURE NewTree* (): Tree;
  1293.                 VAR t: Tree;
  1294.         BEGIN NEW(t); NEW(t.name, 1); t.name[0] := 0X; t.left := NIL; t.right := NIL; RETURN t
  1295.         END NewTree;
  1296.  
  1297. BEGIN Texts.OpenWriter(w)
  1298. END Trees.
  1299. Appendix A: Definition of terms
  1300.  
  1301.  
  1302. Integer types   SHORTINT, INTEGER, LONGINT
  1303. Real types      REAL, LONGREAL
  1304. Numeric types   integer types, real types
  1305.  
  1306.  
  1307. Same types
  1308. Two variables a and b with types Ta and Tb are of the same type if
  1309. 1. Ta and Tb are both denoted by the same type identifier, or
  1310. 2. Ta is declared to equal Tb in a type declaration of the form Ta = Tb, or
  1311. 3. a and b appear in the same identifier list in a variable, record field,
  1312.    or formal parameter declaration.
  1313.  
  1314.  
  1315. Equal types
  1316. Two types Ta and Tb are equal if
  1317. 1. Ta and Tb are the same type,  or
  1318. 2. Ta and Tb are open array types with equal element types.
  1319.  
  1320.  
  1321. Type inclusion
  1322.  
  1323. Numeric types include (the values of) smaller numeric types according to
  1324. the following hierarchy:
  1325.  
  1326. LONGREAL <= REAL <= LONGINT <= INTEGER <= SHORTINT
  1327.  
  1328.  
  1329. Type extension (base type)
  1330.  
  1331. Given a type declaration Tb = RECORD (Ta) ... END, Tb is a direct
  1332. extension of Ta, and Ta is a direct base type of Tb. A type Tb is an
  1333. extension of a type Ta (Ta is a base type of Tb) if
  1334.  
  1335. 1. Ta and Tb are the same types, or
  1336. 2. Tb is a direct extension of an extension of Ta
  1337.  
  1338. If Pa = POINTER TO Ta and Pb = POINTER TO Tb, Pb is an extension of Pa (Pa
  1339. is a base type of Pb) if Tb is an extension of Ta.
  1340.  
  1341.  
  1342. Assignment compatible
  1343.  
  1344. An expression e of type Te is assignment compatible with a variable v of
  1345. type Tv if one of the following conditions hold:
  1346.  
  1347. 1. Te and Tv are the same type but are not open arrays;
  1348. 2. Te and Tv are numeric types and Tv includes Te;
  1349. 3. Te and Tv are record types and Te is an extension of Tv and the dynamic
  1350.    type of v is Tv ;
  1351. 4. Te and Tv are pointer types and Te is an extension of Tv;
  1352. 5. Tv is a pointer or a procedure type and e is NIL;
  1353. 6. Tv is ARRAY n OF CHAR, e is a string constant with m characters, and
  1354.    m < n;
  1355. 7. Tv is a procedure type and e is the name of a procedure whose formal
  1356.    parameters match those of Tv.
  1357.  
  1358.  
  1359.  
  1360. Array compatible
  1361.  
  1362. An actual parameter a of type Ta is array compatible with a formal
  1363. parameter f of type Tf if
  1364. 1. Tf and Ta are the same type, or
  1365. 2. Tf is an open array, Ta is any array, and their element types are array
  1366.    compatible.
  1367.  
  1368.  
  1369. Expression compatible
  1370.  
  1371. For a given operator, the types of its operands are expression compatible
  1372. if they conform to the following table (which shows also the result type
  1373. of the expression):
  1374.  
  1375. operator        valid operand types     result type
  1376. + - *   numeric largest numeric type of the operands
  1377. /       numeric smallest real type incl. both operands
  1378. + - * / SET     SET
  1379. DIV MOD integer largest integer type of the operands
  1380. OR & ~  BOOLEAN BOOLEAN
  1381. = # < <= > >=   numeric, CHAR, character arrays, strings        BOOLEAN
  1382. = #     BOOLEAN, SET, pointers (incl. NIL),
  1383.         procedure types (incl. NIL)     BOOLEAN
  1384. IN      1st: integer; 2nd: SET  BOOLEAN
  1385. IS      1st: pointer or record variable BOOLEAN
  1386.         2nd: pointer or record type
  1387.  
  1388.  
  1389. Matching formal parameter lists
  1390.  
  1391. Two formal parameter lists match if
  1392. 1. they have the same number of parameters, and
  1393. 2. they have either the same function result type or none, and
  1394. 3. parameters at corresponding positions have equal types, and
  1395. 4. parameters at corresponding positions are both either value or variable
  1396.    parameters.
  1397.  
  1398.  
  1399. Appendix B: Syntax of Oberon-2
  1400.  
  1401.  
  1402. Module  =       MODULE ident ";" [ImportList] DeclSeq  [BEGIN StatementSeq] END ident ".".
  1403. ImportList      =       IMPORT [ident ":="] ident {"," [ident ":="] ident} ";".
  1404. DeclSeq         =       { CONST {ConstDecl ";" } | TYPE {TypeDecl ";"} | VAR {VarDecl ";"}} {ProcDecl ";" | ForwardDecl ";"}.
  1405. ConstDecl       =       IdentDef "=" ConstExpr.
  1406. TypeDecl        =       IdentDef "=" Type.
  1407. VarDecl =       IdentList ":" Type.
  1408. ProcDecl        =       PROCEDURE [Receiver] IdentDef [FormalPars] ";" DeclSeq [BEGIN StatementSeq] END ident.
  1409. ForwardDecl     =       PROCEDURE "^" [Receiver] IdentDef [FormalPars].
  1410. FormalPars      =       "(" [FPSection {";" FPSection}] ")" [":" Qualident].
  1411. FPSection       =       [VAR] ident {"," ident} ":" Type.
  1412. Receiver        =       "(" [VAR] ident ":" ident ")".
  1413. Type    =               Qualident
  1414.                 |       ARRAY [ConstExpr {"," ConstExpr}] OF Type
  1415.                 |       RECORD ["("Qualident")"] FieldList {";" FieldList} END
  1416.                 |       POINTER TO Type
  1417.                 |       PROCEDURE [FormalPars].
  1418. FieldList       =       [IdentList ":" Type].
  1419. StatementSeq    =       Statement {";" Statement}.
  1420. Statement       =       [       Designator ":=" Expr
  1421.                 |       Designator ["(" [ExprList] ")"]
  1422.                 |       IF Expr THEN StatementSeq {ELSIF Expr THEN StatementSeq} [ELSE StatementSeq] END
  1423.                 |       CASE Expr OF Case {"|" Case} [ELSE StatementSeq] END
  1424.                 |       WHILE Expr DO StatementSeq END
  1425.                 |       REPEAT StatementSeq UNTIL Expr
  1426.                 |       FOR ident ":=" Expr TO Expr [BY ConstExpr] DO StatementSeq END
  1427.                 |       LOOP StatementSeq END
  1428.                 |       WITH Guard DO StatementSeq {"|" Guard DO StatementSeq} [ELSE StatementSeq] END
  1429.                 |       EXIT
  1430.                 |       RETURN [Expr]
  1431.                 ].
  1432. Case    =       [CaseLabels {"," CaseLabels} ":" StatementSeq].
  1433. CaseLabels      =       ConstExpr [".." ConstExpr].
  1434. Guard   =       Qualident ":" Qualident.
  1435. ConstExpr       =       Expr.
  1436. Expr    =       SimpleExpr [Relation SimpleExpr].
  1437. SimpleExpr      =       ["+" | "-"] Term {AddOp Term}.
  1438. Term    =       Factor {MulOp Factor}.
  1439. Factor  =       Designator ["(" [ExprList] ")"] | number | character | string | NIL | Set | "(" Expr ")" | " ~ " Factor.
  1440. Set     =       "{" [Element {"," Element}] "}".
  1441. Element         =       Expr [".." Expr].
  1442. Relation        =       "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
  1443. AddOp   =       "+" | "-" | OR.
  1444. MulOp   =       " * " | "/" | DIV | MOD | "&".
  1445. Designator      =       Qualident {"." ident | "[" ExprList "]" | " ^ " | "(" Qualident ")"}.
  1446. ExprList        =       Expr {"," Expr}.
  1447. IdentList       =       IdentDef {"," IdentDef}.
  1448. Qualident       =       [ident "."] ident.
  1449. IdentDef        =       ident [" * " | "-"].
  1450. Appendix C: The module SYSTEM
  1451.  
  1452. The module SYSTEM contains certain types and procedures that are necessary
  1453. to implement low-level operations particular to a given computer and/or
  1454. implementation. These include for example facilities for accessing devices
  1455. that are controlled by the computer, and facilities to break the type
  1456. compatibility rules otherwise imposed by the language definition. It is
  1457. strongly recommended to restrict their use to specific modules (called low-
  1458. level modules). Such modules are inherently non-portable, but easily
  1459. recognized due to the identifier SYSTEM appearing in their import list.
  1460. The following specifications hold for the implementation of Oberon-2 on
  1461. the Ceres computer.
  1462.  
  1463. Module SYSTEM exports a type BYTE with the following characteristics:
  1464. Variables of type CHAR or SHORTINT can be assigned to variables of type
  1465. BYTE. If a formal variable parameter is of type ARRAY OF BYTE then the
  1466. corresponding actual parameter may be of any type.
  1467.  
  1468. Another type exported by module SYSTEM is the type PTR. Variables of any
  1469. pointer type may be assigned to variables of type PTR. If a formal
  1470. variable parameter is of type PTR, the actual parameter may be of any
  1471. pointer type.
  1472.  
  1473. The procedures contained in module SYSTEM are listed in the following
  1474. tables. Most of them correspond to single instructions compiled as in-line
  1475. code. For details, the reader is referred to the processor manual. v
  1476. stands for a variable, x, y, a, and n for expressions, and T for a type.
  1477.  
  1478. Function procedures
  1479.  
  1480. Name    Argument types  Result type     Function
  1481.  
  1482. ADR(v)  any     LONGINT address of variable v
  1483. BIT(a, n)       a: LONGINT      BOOLEAN bit n of Mem[a]
  1484.         n: integer type
  1485. CC(n)   integer constant        BOOLEAN condition n (0 ² n ² 16)
  1486. LSH(x, n)       x, n: integer type      type of x       logical shift
  1487. ROT(x, n)       x, n: integer type      type of x       rotation
  1488. VAL(T, x)       T, x: any type  T       x interpreted as of type T
  1489.  
  1490. Proper procedures
  1491.  
  1492. Name    Argument types          Function
  1493.  
  1494. GET(a, v)       a: LONGINT; v: any basic type,  v := Mem[a]
  1495.         pointer type, procedure type
  1496. PUT(a, x)       a: LONGINT; x: any basic type,  Mem[a] := x
  1497.         pointer type, procedure type
  1498. GETREG(n, v)    n: integer constant; v: any basic type, v := Registern
  1499.         pointer type, procedure type
  1500. PUTREG(n, x)    n: integer constant; x: any basic type, Registern := v
  1501.         pointer type, procedure type
  1502. MOVE(a0, a1, n) a0, a1: LONGINT; n: integer type        Mem[a1.. a1+n-1] := Mem[a0.. a0+n-1]
  1503. NEW(v, n)       v: any pointer type; n: integer type    allocate storage block of n bytes
  1504.                         assign its address to v
  1505.  
  1506. Appendix D: The Oberon Environment
  1507.  
  1508. Oberon-2 programs usually run in an environment that provides command
  1509. activation, garbage collection, dynamic loading of modules, and certain
  1510. run time data structures. Although not part of the language, this
  1511. environment contributes to the power of Oberon-2 and is to some degree
  1512. implied by the language definition. Appendix D describes the essential
  1513. features of a typical Oberon environment and provides implementation
  1514. hints. More details can be found in [1], [2], and [3].
  1515.  
  1516.  
  1517. D1. Commands
  1518.  
  1519. A command is any parameterless procedure P that is exported from a module
  1520. M. It is denoted by M.P and can be activated under this name from the
  1521. shell of the operating system. In Oberon, a user invokes commands instead
  1522. of programs or modules. This gives him a finer grain of control and allows
  1523. modules with multiple entry points. When a command M.P is invoked, the
  1524. module M is dynamically loaded unless it is already in memory (see D2) and
  1525. the procedure P is executed. When P terminates, M remains loaded. All
  1526. global variables and data structures that can be reached from global
  1527. pointer variables in M retain their values. When P (or another command of
  1528. M) is invoked again, it may continue to use these values.
  1529.  
  1530. The following module demonstrates the use of commands. It implements an
  1531. abstract data structure Counter that encapsulates a counter variable and
  1532. provides commands to increment and print its value.
  1533.  
  1534. MODULE Counter;
  1535.         IMPORT Texts, Oberon;
  1536.  
  1537.         VAR
  1538.                 counter: LONGINT;
  1539.                 w: Texts.Writer;
  1540.  
  1541.         PROCEDURE Add*;   (* takes a numeric argument from the command line *)
  1542.                 VAR s: Texts.Scanner;
  1543.         BEGIN
  1544.                 Texts.OpenScanner(s, Oberon.Par.text, Oberon.Par.pos);
  1545.                 Texts.Scan(s);
  1546.                 IF s.class = Texts.Int THEN INC(counter, s.i) END
  1547.         END Add;
  1548.  
  1549.         PROCEDURE Write*;
  1550.         BEGIN
  1551.                 Texts.WriteInt(w, counter, 5); Texts.WriteLn(w);
  1552.                 Texts.Append(Oberon.Log, w.buf)
  1553.         END Write;
  1554.  
  1555. BEGIN counter := 0; Texts.OpenWriter(w)
  1556. END Counter.
  1557.  
  1558. The user may execute the following two commands:
  1559.  
  1560. Counter.Add   n         adds the value n to the variable counter
  1561. Counter.Write   writes the current value of counter to the screen
  1562.  
  1563. Since commands are parameterless they have to get their arguments from the
  1564. operating system. In general, commands are free to take arguments from
  1565. everywhere (e.g. from the text following the command, from the most recent
  1566. selection, or from a marked viewer). The command Add uses a scanner (a
  1567. data type provided by the Oberon system) to read the value that follows it
  1568. on the command line.
  1569.  
  1570. When Counter.Add is invoked for the first time, the module Counter is
  1571. loaded and its body is executed. Every call of Counter.Add n increments
  1572. the variable counter by n. Every call of Counter.Write writes the current
  1573. value of counter to the screen.
  1574.  
  1575. Since a module remains loaded after the execution of its commands, there
  1576. must be an explicit way to unload it (e.g. when the user wants to
  1577. substitute the loaded version by a recompiled version.) The Oberon system
  1578. provides a command to do that.
  1579.  
  1580.  
  1581. D2. Dynamic Loading of Modules
  1582.  
  1583. A loaded module may invoke a command of a still unloaded module by
  1584. specifying its name as a string. The specified module is then dynamically
  1585. loaded and the designated command is executed. Dynamic loading allows the
  1586. user to start a program as a small set of basic modules and to extend it
  1587. by adding further modules at run time as the need becomes evident.
  1588.  
  1589. A module M0 may cause the dynamic loading of a module M1 without importing
  1590. it. M1 may of course import and use M0, but M0 need not know about the
  1591. existence of M1. M1 can be a module that is designed and implemented long
  1592. after M0.
  1593.  
  1594.  
  1595. D3. Garbage Collection
  1596.  
  1597. In Oberon-2, the predeclared procedure NEW is used to allocate data blocks
  1598. in free memory. There is, however, no way to explicitly dispose an
  1599. allocated block. Rather, the Oberon environment uses a garbage collector
  1600. to find the blocks that are not used any more and to make them available
  1601. for allocation again. A block is in use as long as it can be reached from
  1602. a global pointer variable via a pointer chain. Cutting this chain (e.g.,
  1603. setting a pointer to NIL) makes the block collectable.
  1604.  
  1605. A garbage collector frees a programmer from the non-trivial task of
  1606. deallocating data structures correctly and thus helps to avoid errors.
  1607. However, it requires information about dynamic data at run time (see D5).
  1608.  
  1609.  
  1610. D4. Browser
  1611.  
  1612. The interface of a module (the declaration of the exported objects) is
  1613. extracted from the module by a so-called browser which is a separate tool
  1614. of the Oberon environment. For example, the browser produces the following
  1615. interface of the module Trees from Ch. 11.
  1616.  
  1617. DEFINITION Trees;
  1618.         TYPE
  1619.                 Tree = POINTER TO Node;
  1620.                 Node = RECORD
  1621.                         name: POINTER TO ARRAY OF CHAR;
  1622.                         PROCEDURE (t: Tree) Insert (name: ARRAY OF CHAR);
  1623.                         PROCEDURE (t: Tree) Search (name: ARRAY OF CHAR): Tree;
  1624.                         PROCEDURE (t: Tree) Write;
  1625.                 END;
  1626.         PROCEDURE NewTree (): Tree;
  1627. END Trees.
  1628.  
  1629. For a record type, the browser also collects all procedures bound to this
  1630. type and shows their declaration in the record type declaration.
  1631.  
  1632. D5. Run Time Data Structures
  1633.  
  1634. Certain information about records has to be available at run time: The
  1635. dynamic type of records is needed for type tests and type guards. A table
  1636. with the addresses of the procedures bound to a record is needed for
  1637. calling them using dynamic binding. Finally, the garbage collector needs
  1638. information about the location of pointers in dynamically allocated
  1639. records. All that information is stored in so-called type descriptors of
  1640. which there is one for every record type at run time. The following
  1641. paragraphs show a possible implementation of type descriptors.
  1642.  
  1643. The dynamic type of a record corresponds to the address of its type
  1644. descriptor. For dynamically allocated records this address is stored in a
  1645. so-called type tag which precedes the actual record data and which is
  1646. invisible for the programmer. If t is a variable of type CenterTree (see
  1647. example in Ch. 6) Figure D5.1 shows one possible implementation of the run
  1648. time data structures.
  1649.  
  1650.  
  1651. Fig. D5.1  A variable t of type CenterTree, the record t^ it points to,
  1652. and its type descriptor
  1653.  
  1654. Since both the table of procedure addresses and the table of pointer
  1655. offsets must have a fixed offset from the type descriptor address, and
  1656. since both may grow when the type is extended and further procedures and
  1657. pointers are added, the tables are located at the opposite ends of the
  1658. type descriptor and grow in different directions.
  1659.  
  1660. A type-bound procedure t.P is called as t^.tag^.ProcTab[IndexP]. The
  1661. procedure table index of every type-bound procedure is known at compile
  1662. time. A type test v IS T is translated into v^.tag^.BaseTypes[
  1663. ExtensionLevelT] = TypeDescrAdrT. Both the extension level of a record
  1664. type and the address of its type descriptor are known at compile time. For
  1665. example, the extension level of Node is 0 (it has no base type), and the
  1666. extension level of CenterNode is 1.
  1667.  
  1668.  
  1669. [1]     N.Wirth, J.Gutknecht: The Oberon System. Software Practice and
  1670.         Experience 19, 9, Sept. 1989
  1671. [2]     M.Reiser: The Oberon System. User Guide and Programming Manual.
  1672.         Addison-Wesley, 1991
  1673. [3]     C.Pfister, B.Heeb, J.Templ: Oberon Technical Notes. Report 156,
  1674.         ETH Zürich, March 1991
  1675.  
  1676.