|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 147584 (0x24080) Types: TextFile Names: »D169«
└─⟦4b76feb82⟧ Bits:30008865 Diskette med tekster der formodes at være 31-D-163…174 └─⟦this⟧ »D169«
\f i T_A_B_L_E_ _O_F_ _C_O_N_T_E_N_T_S_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _P_A_G_E_ _ 1. INTRODUCTION .......................................... 1 2. BASIC DEFINITIONS ..................................... 3 2.1 Vocabulary ....................................... 3 2.2 Syntax Diagrams .................................. 3 2.2.1 Comments .................................. 4 2.2.2 Identifiers ............................... 5 2.2.3 Numbers ................................... 5 2.2.4 Separators ................................ 6 2.2.5 Strings of Characters ..................... 6 2.3 Fundamental Concepts ............................. 7 3. THE PASCAL80 LANGUAGE ................................. 10 3.1 The Process Structure ............................ 10 3.2 The Process Heading .............................. 12 3.3 The Declaration Part ............................. 13 3.3.1 Label Declaration Part .................... 14 3.3.2 Constants Definition Part ................. 15 3.3.3 Variable Declaration Part ................. 17 3.3.4 Type Definition Part ...................... 18 3.3.4.1 Types ............................ 18 3.3.4.2 Type Compatibility ............... 31 3.3.5 Routine Declaration Part .................. 34 3.3.5.1 Scope Rules ...................... 37 3.3.5.2 Routine Blocks ................... 38 3.3.5.3 Functions ........................ 38 3.3.6 Export Part ............................... 39 3.4 The Statement Part ............................... 40 3.4.1 Statements ................................ 40 3.4.2 Assignment Statement ...................... 41 3.4.3 Exchange Statement ........................ 44 3.4.4 Repetitive Statements ..................... 44 3.4.5 Conditional Statements .................... 46 2.4.6 Procedure Call ............................ 48 3.4.7 With Statement ............................ 50 3.4.8 Lock Statement ............................ 50 3.4.9 Channel Statement ......................... 51 \f ii T_A_B_L_E_ _O_F_ _C_O_N_T_E_N_T_S_ _(_c_o_n_t_i_n_u_e_d_)_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _P_A_G_E_ _ 3.4.10 Goto Statement ........................... 52 3.4.11 Standard Routines abs, succ, pred, chr, ord ...................................... 52 4. PROCESS COMMUNICATION ................................. 54 4.1 General Process Communication .................... 54 4.2 The Predefined Communication Routines ............ 68 5. PROCESS CONTROL ....................................... 75 5.1 The Predefined Routines for Process Control ...... 75 6. UTILITY PROGRAMS ...................................... 78 6.1 Indent ........................................... 78 6.2 Cross Reference Program .......................... 79 A_P_P_E_N_D_I_X_: A. REFERENCES ............................................ 81 \f F_ 1_._ _ _ _ _ _ _ _ _I_N_T_R_O_D_U_C_T_I_O_N_ 1. This first edition of the PASCAL80 User>s Guide is mainly based on extracts from earlier PASCAL80 papers such as the Report 1, and some preliminary introductions, and information published in Danish under the common little "PASCAL80 NYT". This manual is directed to those who have previously acquired some familiarity with computer programming, and now wish to get acquainted with the programming language PASCAL80. The style of the manual is that of a tutorial, i.e. a demonstration of the language features by means of examples. For a concise ultimate of the language definition the PASCAL80 REPORT 1 may be used and the actual implementations are des- cribed in xx-PASCAL80-REFERENCE manuals, by now xx is RC3502 and RC850. Since PASCAL80 is based directly on Wirth>s Standard Pascal 2 familiarity with that language means that the parts concerning sequential programs, i.e. most of the declarations and control statements, may be well known. PASCAL80 can be characterized as Standard Pascal without files but extended with communication primitives to be used to connect concurrent process incarnations. For programmers acquainted with ALGOL, or FORTRAN it may prove helpful to glance at PASCAL80 in terms of these other languages. For this purpose we list the following characteristics of PASCAL80. 1. Declaration of variables is mandatory. 2. Certain key words (e.g. PROCESS, BEGIN) are "reserved" and cannot be used as identifiers. In this manual they are writ- ten with capital letters. 3. The semicolon (;) is considered as a statement separator, not a statement terminator. 4. The standard data types are those of whole numbers, the logi- cal values, the characters, semaphores, shadows, references, and pools. The basic data structuring facilities include the array, the record (corresponding to COBOL>s "structure"),\f the pool, and the set. These structures can be combined and nested. 5. The facilities of the ALGOL switch and the computed go to of FORTRAN are represented by the case statement. 6. The for statement corresponding to the DO loop of FORTRAN, may only have steps of 1 (TO) or -1 (DOWNTO) and is executed only as long as the value of the control variable lies within the limits. Consequently, the controlled statement may not be executed at all. 7. There are no conditional expressions and no multiple assign- ments. 8. Procedures and functions may be called recursively. 9. There is no "own" attribute for variables (as in ALGOL). Parameters are called either by value or by reference; there is no call by name. 10. The "block structure" differs from that of ALGOL insofar as there are no anonymous blocks, i.e. each block is given a name, and thereby is made into a routine. 11. PASCAL80 is equipped with semaphores as a synchronizing tool and message buffers as a communication tool. 12. Concurrent process incarnations are synchronized by means of signal-wait primitives. \f F_ 2_._ _ _ _ _ _ _ _ _B_A_S_I_C_ _D_E_F_I_N_I_T_I_O_N_S_ 2. 2_._1_ _ _ _ _ _ _ _V_o_c_a_b_u_l_a_r_y_ 2.1 The basic vocabulary consists of language symbols and user defined symbols. The language symbols are reserved words (key words) and punctuation marks: AND ELSE LABEL PROCESS ARRAY END LOCK RECORD AS EXPORT MOD REPEAT BEGIN EXTERNAL NOT SET BEGINBODY FOR OF THEN CASE FORWARD OR TO CHANNEL FUNCTION OTHERWISE TYPE CONST GOTO PACKED UNTIL DIV IF POOL VAR DO IN PREFIX WHILE DOWNTO INCLUDE PROCEDURE WITH + - * / " > < ' <' <= '= ( ) (. .) = := :=: . , : ; .. *** (* *) ! ? <* *' # The user may not use the reserved words in a context other than that explicit stated in the definition of PASCAL80; in particu- lar, these words may not be used as identifiers. 2_._2_ _ _ _ _ _ _ _S_y_n_t_a_x_ _D_i_a_g_r_a_m_s_ 2.2 The syntax of PASCAL80 is defined graphically by syntax diagrams. A syntax diagram consists of arrows, language symbols, and names of syntax diagrams. A PASCAL80 program is syntactically correct if it can be obtained by traversing the syntax diagrams. A trav- ersal must follow the arrows. The name of a syntax diagram indi- cates a traversal of the corresponding diagram. The result of a traversal is the sequence of language symbols encountered in the traversal. \f The following is an example of a syntax diagram. while statement: 'WHILE 'expression 'DO 'statement ' The syntax diagram defines the name (while statement) and syntax of language construct. The name is used when the construct is referred to elsewhere in the text or in other syntax diagrams. Language symbols are either names in capital letters (e.g. WHILE) or punctuation marks (e.g. :=). Constructs defined by other syntax diagrams are given by their names in small letters (e.g. expression). To be able to distin- quish between several occurrences of a construct, its name my be subscripted. 2_._2_._1_ _ _ _ _ _C_o_m_m_e_n_t_s_ 2.2.1 Comment: ' '(* ' ' '*) ' ' < character< < non-printing symbol< '<* ' ' '*' ' < character< < non-printing symbol< Comments may be inserted between any two identifiers, numbers or special symbols. A comment does not affect the execution of the program. \f 2_._2_._2_ _ _ _ _ _I_d_e_n_t_i_f_i_e_r_s_ 2.2.2 Names denoting labels, constants, types, variables, processes, and routines are called identifiers. They must begin with a letter or an underscore which may be followed by any combination and number of letters, digits, and underscores. Contrary to Standard PASCAL all the characters of an identifier are recog- nized as significant. Small and big letters are handled as being the same in identifiers. identifier: 'letter ' ' ' ' ' _ ' < letter< < digit< < _< letter is A,B,...,Å,a,b,c,...,å digit is 0,1,2,...,9 Examples of legal identifiers: step use _count Local _Message _ _ _ _ _very _ _ _special _ _ _defined _ _ _identifier Note: "Local _Message" is identical to "local message", "LOCAL _MESSAGE", and any other combination of small and big letters. 2_._2_._3_ _ _ _ _ _N_u_m_b_e_r_s_2.2.3 At label can be either an identifier or a numeric value in PASCAL80, this is in contrast to Standard Pascal where label is demanded to be an unsigned integer. \f numeric value: ' 'digit ' ' ' < '#b ' 'binary digit ' ' '#o ' 'octal digit ' ' '#h ' 'hexa digit ' ' binary digits are 0..1 octal digits are 0..7 hexa digits are 0..9 and a..f Example of legal numbers: 7913 0033 #b101 #hff00 #o7654 2_._2_._4_ _ _ _ _ _S_e_p_a_r_a_t_o_r_s_ 2.2.4 Blanks, nl>s, ff>s and comments are considered as separators. Separators can appear between any two consecutive language symbols. No separator may occur within an identifier, number, numeric value, or language symbol. At least one separator must appear between any pair of consecutive identifiers, character strings, numbers, numeric values, or language symbols. 2_._2_._5_ _ _ _ _ _S_t_r_i_n_g_s_ _o_f_ _C_h_a_r_a_c_t_e_r_s_ 2.2.5 A character string is a sequence of characters enclosed by quote marks, both single and double guote marks are legal but the end mark must match the start mark. \f Character string: ' '" '-'string character ' '" ' ' < '> ' 'string character ' '> ' < String characters are the printable subset of the alphabet, excluding newline (nl) and form feed (ff), i.e. > >, >!>, ...,> > Examples of legal strings: "abcd", " > > is a strange character", >"> Note: If a string surrounded by single quote marks is to contain a quote mark or a string surrounded by double quote marks is to contain the surrounding quote mark, then this quote mark is to be written twice, for example """" is equivalent to >">, and >>>> is equivalent to ">". 2_._3_ _ _ _ _ _ _ _F_u_n_d_a_m_e_n_t_a_l_ _C_o_n_c_e_p_t_s_ 2.3 This section gives a brief explanation of a few concepts and the context in which they are used. The complete description of all PASCAL80 concepts is given in the following sections. A p_r_o_g_r_a_m_ consists of a number of processes. Each p_r_o_c_e_s_s_ is a description of some actions and a description of a data struc- ture. An i_n_c_a_r_n_a_t_i_o_n_ of a process is the execution of the actions on a private data structure. Many incarnations can be executed concurrently. Actions are described by s_t_a_t_e_m_e_n_t_s_. The actions of one incarna- tion are executed one at a time in the order defined by the statements. The actions manipulate the data structure, which is described by a number of v_a_r_i_a_b_l_e_s_. A v_a_r_i_a_b_l_e_ has a name and a type. The t_y_p_e_ describes the set of values the variable can hold when the program is executed. There is a number of p_r_e_d_e_f_i_n_e_d_ t_y_p_e_s_ (integer, char, boolean, reference, semaphore, and shadow). \f New types are defined either by listing their values or by com- bining several types into a s_t_r_u_c_t_u_r_e_d_ _t_y_p_e_. A number of statements and declarations can be combined into a r_o_u_t_i_n_e_ _d_e_c_l_a_r_a_t_i_o_n_. Activation of a routine is described by r_o_u_t_i_n_e_ _c_a_l_l_s_ (statement). Process incarnations communicate by exchanging m_e_s_s_a_g_e_s_. A mes- sage can be accessed by one incarnation at a time. place data M await access in M A to M B T_i_m_e_ _T_: A has exclusive access to the message M. M read data A in M B T_i_m_e_ _T_ _+_ _1_: B has exclusive access to M. Variables of the two predefined types reference and semaphore are used for accessing and exchanging access to messages. The value of a reference variable is either a reference to a mes- sage or nil (representing "no reference"). A message can be accessed through at most one reference variable at a time. Since process incarnations access messages through reference variables only, mutually exclusive access to messages is secured. Incarnations exchange access to messages by means of q_u_e_u_e_ _s_e_m_a_p_- h_o_r_e_s_. An incarnation places a message in a semaphore from which another incarnation can get access to it. Variables of type se- maphore can be declared in any process. A semaphore variable may be accessible by many incarnations simultaneously. \f Processes can be nested and a process which is declared within another process is a sub-process (of the surrounding process). An arbitrary number of incarnations of sub-processes (children) can be created, they are all controlled by the parent. Incarnations are created and removed dynamically. A process can have f_o_r_m_a_l_ _p_a_r_a_m_e_t_e_r_s_. When an incarnation of the process is created a number of a_c_t_u_a_l_ _p_a_r_a_m_e_t_e_r_s_ is given. Incar- nations communicate through common semaphore variables only. In this way a process determines the communication paths of sub-pro- cesses. Note, however, that the controlling process incarnation need not participate in the comminication. \f F_3_._ _ _ _ _ _ _ _ _T_H_E_ _P_A_S_C_A_L_8_0_ _L_A_N_G_U_A_G_E_ 3. This chapter consists of descriptions of the different compo- nents of a PASCAL80 process. First an example which shows the structure of a complete process definition, and after the example is given a more precise description of the syntactical defini- tion, of the different parts of the process definition. 3_._1_ _ _ _ _ _ _ _T_h_e_ _P_r_o_c_e_s_s_ _S_t_r_u_c_t_u_r_e_ 3.1 A PASCAL80 process consists of d_e_c_l_a_r_a_t_i_o_n_s_ of constants, types, variables, routines, labels, and some s_t_a_t_e_m_e_n_t_s_ that operate on the declared objects. This is an outline of a PASCAL80 process: PROCESS catalog; CONST idlength = 10; catalogsize = 256; TYPE identifier = ARRAY (1 .. idlength) OF char; M_m_m_ . . P_p_p_ . VAR name: identifier; found: boolean; index: integer; FUNCTION hash (id: identifier): integer; VAR key, next: integer; ch: char; \f BEGIN (* body of function hash *) key:= 1; next:= 0; REPEAT next:= next + 1; ch:= id (next); IF ch <' sp THEN key:= key * ord (ch) MOD catalogsize + 1; UNTIL (ch = sp) OR (next '= idlength); hash:= key; END; (* of hash *) M_m_m_ . . P_p_p_ . BEGIN (* main program *) M_m_m_ . . P_p_p_ . index:= hash (name); REPEAT M_m_m_ . . P_p_p_ . found:= --- M_m_m_ . . P_p_p_ . UNTIL found; M_m_m_ . . P_p_p_ . END. The process contains a declaration of - two contants: idlength with the value 10 and catalogsize with the value 256 - a type: identifier which is an array of characters \f - three variables: name which can hold a value of type identi- fier, found which can hold a value of type boolean, and index which can hold an integer. - a function hash which maps an identifier to an integer. The function has a formal parameter id and three local variables key, next, and ch. The assignment statement: index:= hash (name) contains a call of the function; the result of the function is assigned to the variable index. All declared objects have names: catalog, idlength, catalogsize, identifier, name, found, index, hash, id, key, next, and ch. These names are defined by declarations before they are used in statements. 3_._2_ _ _ _ _ _ _ _T_h_e_ _P_r_o_c_e_s_s_ _H_e_a_d_i_n_g_ 3.2 The process heading consists of an identification of the process to be declared and a parameter description. The process in the example of section 3.1 has no parameter, the identification is "catalog". process heading: 'PROCESS 'process name 'formal parameter ' (formal parameters are described in subsection 3.3.5). Declarations common to more processes may be defined in a context, and it may be specified in the call of the compiler which context(s) to include. The syntax is: context: 'context name '; 'context declarations '. ' \f context declarations: ' ' ' < ; 'constant declaration ' 'type declaration ' 'external routine declaration ' external routine declaration: ' 'procedure heading ' '; external ' 'function heading 3_._3_ _ _ _ _ _ _ _T_h_e_ _D_e_c_l_a_r_a_t_i_o_n_ _P_a_r_t_ 3.3 The declarations of a program serves as a description of the data which are manipulated by the actions performed by the program. declarations: ' ' ' ' < < 'contstant declaration ' '; 'type declaration ' 'variable declaration ' 'label declaration ' 'routine declaration ' 'prefixed process declaration ' 'export export part ' The order of declarations is only restricted of the demand for definition before use. \f 3_._3_._1_ _ _ _ _ _L_a_b_e_l_ _D_e_c_l_a_r_a_t_i_o_n_ _P_a_r_t_ 3.3.1 A l_a_b_e_l_ is an identification of a statement, it can be either a number or an identifier. Every label must be declared. label declaration: 'LABEL ' label ' ' ,< label: ' 'number ' ' 'identifier Example: LABEL 7913, even _action; A label is denoted by the identifier or the integer value of the number. (GOTO statement 3.4.10) A l_a_b_e_l_ _i_s_ _d_e_f_i_n_e_d_ by a labelled statement. labelled statement: 'label ': 'statement ' Labels must be defined and used in the scope (not block) where they are declared. A label may only be defined once in a scope. Scope is defined in subsection 3.3.5. example: error _action: exception (error _code); \f 3_._3_._2_ _ _ _ _ _C_o_n_s_t_a_n_t_s_ _D_e_f_i_n_i_t_i_o_n_ _P_a_r_t_ 3.3.2 If a value is used serveral times in a program, it is useful to declare a constant with this value. In the program the constant is used to denote the value. constant declaration: CONST ' 'constant name '= 'constant expression ' ' ;< The constant expression is an expression the value of which may be computed at compile time, i.e. each operand must be a constant or a symbolic value. A very convenient feature of PASCAL80 is the so-called structured value which may be used for defining constants and for initialization of structured variables. structured value: ' 'character string ' ' 'set ' 'type name '( 'value list ') ' value list: ' ' 'unit ' ' ' 'repetition '*** 'unit ,< Units of a value list are given one at a time (separated by ,) or by repeating a unit. The value of repetition specifies how many times the unit is repeated. \f A structured value is built as follows: - type name denotes a record type: There must be a unit for each field and the first field gets the value of the first unit, the second field the value of the second unit etc. The repetition cannot be used. - type name denotes an array type: There must be a unit for each element and the first element gets the value of the first unit, the second element the value of the second unit etc. repetition: 'constant expression ' unit: ' 'constant expression ' ' '? The unit "?" specifies n_o_ _v_a_l_u_e_, i.e. the component is skipped, its type is compatible with any type. This element is necessary to specify values of components which have no symbolic represen- tation, e.g. values of shielded types. The no value element can only be used in value lists. Example: CONST catalogsize = 256; test = true; nul = 0; If these values are changed, only the constant declaration needs to be changed. \f 3_._3_._3_ _ _ _ _ _V_a_r_i_a_b_l_e_ _D_e_c_l_a_r_a_t_i_o_n_ _P_a_r_t_ 3.3.3 A declaration of a variable must specify the name and type of the variable. variable declaration: 'VAR ' 'variable name list ': 'type ' 'initialization ' ' ' ' ;< variable declaration ' 'variable name ' ' ,< initialization: ':= 'constant expression ' The type of the expression must be compatible with the type of the variable. The value specified by the constant expression becomes the ini- tial value of all variables in the variable name list. Example: VAR found: boolean:= false; index: 1 .. catalogsize; name: identifier:= identifier (idlength***sp); \f The type defines which values a variable can hold. The variable found can hold the boolean values false and true, the initial value is false. The variable index can hold an integer in the range 1 to 256 (catalogsize = 256) the value of index is unde- fined until first assignment. The value of a variable is changed by an assignment: found:= true; index:= index MOD catalogsize + 1; 3_._3_._4_ _ _ _ _ _T_y_p_e_ _D_e_f_i_n_i_t_i_o_n_ _P_a_r_t_ 3.3.4 All data which is manipulated by a PASCAL80 program has a type. All operands (variables, constants, values etc.) have a fixed type and for each operator and statement there are strict rules defining which types of operands it accepts. 3_._3_._4_._1_ _ _ _T_y_p_e_s_ 3.3.4.1 A_ _t_y_p_e_ _i_s_ _a_ _s_e_t_ _o_f_ _v_a_l_u_e_s_ _a_n_d_ _a_ _m_e_t_h_o_d_ _o_f_ _a_c_c_e_s_s_i_n_g_ _t_h_e_s_e_ _v_a_l_u_e_s_. There is a number of predefined types: integer, char, boolean, semaphore, reference, and shadow. New types are named and defined by type declarations. type declaration: 'TYPE ' 'type name '=type ' ' ;< \f type: ' 'enumeration type ' ' 'shielded type ' 'pointer type ' 'structured type ' 'named type ' 'frozen type Type declarations may not be recursive, except in a type declara- tion: TYPE name = t; where t may contain the pointer type name as an element or field type; E_n_u_m_e_r_a_t_i_o_n_ _T_y_p_e_s_ An e_n_u_m_e_r_a_t_i_o_n_ _t_y_p_e_ consists of a finite, totally ordered set of values. Furthermore, there is a mapping from the set of values to the integers. enumeration type: ' 'char ' ' 'boolean ' 'integer ' 'scalar type ' 'subrange type ' The three predefined types char, boolean, and integer are described below. S_c_a_l_a_r_ _T_y_p_e_s_ A s_c_a_l_a_r_ _t_y_p_e_ is a sequence of values (scalar constants). A scalar type is declared by listing its values in increasing order. scalar type: '( ' 'scalar constant ' ') ' ,< \f scalar constant: 'identifier ' A s_c_a_l_a_r_ _c_o_n_s_t_a_n_t_ is an identifier appearing in the declaration of a scalar type T. The type of the scalar constant is T. Con- M_M_m_ sider the following scalar type (e , e , ... e , e , ... e ), P_P_p_ 0 1 n n+1 N M_M_m_ then e is the p_r_e_d_e_c_e_s_s_o_r_ of e and e is the s_u_c_c_e_s_s_o_r_ of e P_P_p_ n-1 n n+1 n M_M_m_ the o_r_d_i_n_a_l_ _v_a_l_u_e_ of e is n. The predecessor of e and the P_P_p_ n 0 M_M_m_ successor of e are undefined. P_P_p_ N Example: TYPE device = (drum, tape, disk); The type device has the values drum, tape, and disk. T_h_e_ _T_y_p_e_ _C_h_a_r_ The type c_h_a_r_ is a predefined enumeration type. Its values are the (Danish) ISO characters. _ _ _ _ _ _0_ _ _ _ _1_ _ _ _ _2_ _ _ _ _3_ _ _ _ _4_ _ _ _ _5_ _ _ _ _6_ _ _ _ _7_ _ _ _ _8_ _ _ _ _9_ _ _ _ _ _ 0 nul soh stx etx eot enq ack bel bs ht 10 nl vt ff cr so si dle dc1 dc2 dc3 20 dc4 nak syn etb can em sub esc fs gs 30 rs us sp ! " % & > 40 ( ) * + , - . / 0 1 50 2 3 4 5 6 7 8 9 : ; 60 < = ' ? @ A B C D E 70 F G H I J K L M N O 80 P Q R S T U V W X Y 90 Z Æ Ø Å _ a b c 100 d e f g h i j k l m 110 n o p q r s t u v w 120 x y z æ ø å del \f The characters are numbered and the ordinal number of a character is the sum of its row and column number in the above table. The ordinal values define the ordering of the characters. > > (sp), >!> >">, ... > > are printing characters. T_h_e_ _T_y_p_e_ _B_o_o_l_e_a_n_ The type b_o_o_l_e_a_n_ is a predefined scalar type, defined as: TYPE boolean = (false, true); S_u_b_r_a_n_g_e_ _T_y_p_e_s_ A type can also be declared as a_ _s_u_b_r_a_n_g_e_ of an already defined type. A subrange type is a sub-sequence of an enumeration type. subrange type: 'min bound '.. 'max bound ' min bound, max bound: 'expression ' The min and max bounds must be of the same enumeration type. example: TYPE index = 1 .. catalogsize; small _letters = "a" .. "å"; byte = 0 .. 255; These declarations restrict the set of values of the type to the specified range. \f S_t_r_u_c_t_u_r_e_d_ _T_y_p_e_s_ A structured type is a composition of other types. There are three kinds of structured types: array, record, and set. structured type: ' ' ' 'array type ' ' 'PACKED 'record type ' 'set type ' A structured type has a number of c_o_m_p_o_n_e_n_t_ _t_y_p_e_s_. A_r_r_a_y_ _T_y_p_e_s_ An a_r_r_a_y_ consists of a number of elements of the same type. The number of elements is specified by an index type. array type: 'ARRAY '( ' 'index type ' ') 'OF 'element type ' ,< index type, element type: 'type ' The index type must be an enumeration type or the name of an enumeration type. Example: TYPE identifier = ARRAY (1 .. idlength) OF char; count = ARRAY (letters) OF integer; VAR id: identifier; \f The elements of the array "id" have indices from 1 to 10 (idlength). The value of an element can be changed: id (5):= "x"; An array value (whole array) can also be constructed and manipulated: CONST blank = " "; . . . IF id <' blank THEN ... Then array type M_M_m_ ARRAY (t ,t ) OF t P_P_p_ 1 2 3 is a shorthand for the type M_M_m_ ARRAY (t ) OF ARRAY (t ) OF t . P_P_p_ 1 2 3 This is a m_u_l_t_i_-_d_i_m_e_n_s_i_o_n_a_l_ array. The number of index types is the d_i_m_e_n_s_i_o_n_ of the array. The name of an array variable denotes the whole array. An element is accessed by the array variable followed by an index enclosed in parentheses. An index consists of a number of index expres- sions. The number of index expressions must be less than or equal to the dimension of the array. If the element type itself is structured, the c_o_m_p_o_n_e_n_t_ _t_y_p_e_s_ _o_f_ t_h_e_ _a_r_r_a_y_ _t_y_p_e_ are the component types of the element type. \f array variable: 'variable ' ' ' 'indec selector index selector: '( ' 'index expression ' ') ' ,< index expression: 'expression ' The type of each index expression must be compatible with the corresponding index type. R_e_c_o_r_d_ _T_y_p_e_s_ A r_e_c_o_r_d_ consists of a number of fields. Each f_i_e_l_d_ has a name and a type. record type: 'RECORD 'field list 'END ' field list: ' 'field name list ': 'field type ' ' '; ' ' ;< ' field name list: ' 'field name ' ' ,< \f Example: TYPE catalogentry = RECORD id: identifier; hashkey: integer; medium: device; addr: range; END; VAR element: catalogentry; The record of type catalogentry has four fields: id, hashkey, medium, and addr. These fields are of the type identifier, integer, device, and range respectively. The value of a field can be changed or read: element.medium:= drum; IF element.id (1) <_ "a" THEN ... Values of record type are structured values (see subsection 3.4.1): element:= catalogentry (blank, 0, drum, 16712); S_e_t_ _T_y_p_e_s_ The values of a s_e_t_ _t_y_p_e_ are the subset of some enumeration type. set type: 'SET 'OF 'element type ' element type: 'type ' The element type must be an enumeration type or the name of an enumeration type. \f A s_e_t_ _e_l_e_m_e_n_t_ is a value of the element type. The component type of a set is the element type. Values of set type are written as a list of set elements. set: '(. ' ' 'element list ' ' '.) ' ,< ' element list: ' 'element ' ' M_M_m_ 'element '.. 'element P_P_p_ 1 2 element: 'expression ' All elements in a set must be of the same type and these must all be compatible with the element type. The empty set is denoted (..). The type of (..) is compatible with any set type. A variable of type set can be given a value: digits:= (. "0" .. "9".); The operators on set operands are + (union), * (intersection), - (difference), and IN (membership). \f Example: TYPE characters = SET OF char; VAR digits, letters: characters; FUNCTION nextid: identifier; VAR i: 1 .. idlength; ch: char; BEGIN (* body of nextid *) i:= 1; nextid:= blank; ch:= getchar; IF ch IN letters THEN WHILE (ch IN (letters + digits)) AND (i <= idlength) DO BEGIN nextid (i):= ch; i:= i + 1; ch:= getchar; END; END; (* of nextid *) (Note, getchar is not a PASCAL80 primitive). As the above examples show, a type (predefined or programmer defined) can be used for constructing values of the type, defining constants, and declaring variables. P_o_i_n_t_e_r_ _T_y_p_e_s_ The values of pointer type are pointers to variables or nil (no pointer). pointer type: ' 'type ' \f The value nil belongs to every pointer type; it does not point to any variable. Assignments can be made to variables of pointer types. The variable pointed to by a pointer (value) is denoted by a variable of pointer type followed by an arrow ( ). For the use of pointer variables and pointer types see the example in section 4.2 (under "ref"). F_r_o_z_e_n_ _T_y_p_e_s_ In PASCAL80 the programmer has the possibility of declaring vari- ables and parameters as "read only" i.e. the variable/parameters cannot be changed inside the process/routine with the read-only declaration. frozen type: '! 'base type ' base type: 'type ' A variable of a frozen type must not be used as the lefthand side of an assignment, in an exchange statement, or as a variable parameter, unless the formal parameter is of the same frozen type! A frozen type is compatible with its base type. The component types of a frozen type are the component types of the base type. S_h_i_e_l_d_e_d_ _T_y_p_e_s_ Variables of s_h_i_e_l_d_e_d_ _t_y_p_e_s_ enable a process incarnation to communicate with and control other incarnations. \f shielded type: ' 'reference ' ' 'semaphore ' 'shadow ' 'pool type ' The values of shielded types cannot be accessed directly. They are protected against malicious or accidental misuse. Therefore, the assignment statement cannot be applied to variables of shielded types. The exhange statement is provided instead (see subsection 3.4.3). T_h_e_ _T_y_p_e_ _R_e_f_e_r_e_n_c_e_ The values of type r_e_f_e_r_e_n_c_e_ are references to messages or nil (no reference). A message is always accessible through exactly one reference variable. The syntax used to denote the accessible fields of a message header is derived from considering the type reference as a predefined pointer type (see section 5.3): TYPE reference = message; The type of the message header is: TYPE message = RECORD (*message header*) size, messagekind: !integer; u1, u2, u3, u4: 0..255; (*owner, answer: semaphore; data: message data; other implementation dependent fields*) END; \f The interpretation of s_i_z_e_ and m_e_s_s_a_g_e_k_i_n_d_ is i_m_p_l_e_m_e_n_t_a_t_i_o_n_ d_e_p_e_n_d_e_n_t_. The owner, answer, and data fields cannot be used directly. M_e_s_s_a_g_e_s_ Process incarnations communicate by exchanging access to messages which hold data. When a process has access to a message it can place data in or read data from the message. A message can be accessed by one incarnation at a time (see section 2.3) A message consists of a m_e_s_s_a_g_e_ _h_e_a_d_e_r_ and m_e_s_s_a_g_e_ _d_a_t_a_ (possibly empty). A h_e_a_d_e_r_ _m_e_s_s_a_g_e_ is a message with no message data. T_h_e_ _T_y_p_e_ _S_e_m_a_p_h_o_r_e_ A q_u_e_u_e_ _s_e_m_a_p_h_o_r_e_ consists of a sequence (fifo) of messages and a set of waiting process incarnations. One of these is always empty. The values of type semaphore are queue semaphores. The semaphore is o_p_e_n_ when the set of waiting incarnations is empty and the sequence of messages in non-empty. When the sequence is empty and the set of waiting incarnations is none- empty, the semaphore is l_o_c_k_e_d_. If both are empty, the semaphore is p_a_s_s_i_v_e_. These concepts are described in details in the sections concern- ing process communication (chapter 4). Variables of type semaphore (or variables with semaphore compo- nents) are restricted only to be declared in the declarations of a process and not in the declarations of a routine. T_h_e_ _T_y_p_e_ _S_h_a_d_o_w_ The values of type s_h_a_d_o_w_ are references to process incarnations or nil (no reference). Initially, a shadow variable is nil. \f A shadow variable is given a value by creating a new incarnation. The incarnation is controlled through the shadow variable. The predefined routines for controlling incarnations are des- cribed in the sections concerning process control (chapter 5). P_o_o_l_ _T_y_p_e_s_ A p_o_o_l_ consists of a number of messages. pool type: 'POOL 'cardinality ' 'OF 'type ' ' ' cardinality: 'expression ' Initially a pool consists of a number of messages. The number is the value of cardinality (expression) which must be a positive integer. Each of the messages can hold a value from type. If no type is specified, the messages have headers only. With each variable of type pool an anonymous semaphore is asso- ciated. This is the owner semaphore of all messages in the pool. A message is allocated from the pool by the predefined procedure alloc (see chapter 4). 3_._3_._4_._2_ _ _ _T_y_p_e_ _C_o_m_p_a_t_i_b_i_l_i_t_y_ 3.3.4.2 In PASCAL80 any operand has a fixed type which can be determined statically. The type of constants, variables, and formal parame- ters is specified in their declaration. \f CONST length = 16; TYPE word = ARRAY (0 .. length - 1) OF boolean; CONST nul = word (length *** false); VAR status: word; The constant length is of type integer. The construct "word (length *** false)" is a value of type word where all elements are false. The constant nul and the variable status are both of type word. The type of an expression is determined by the types of its operands and the way they are combined by operators. The addition of two integers, i.e. length + 1, gives a result of type integer, comparison of two integers, i.e. j <= length, gives a result of type boolean, conjunction of two booleans gives a boolean result, i.e. found AND (j <= length) etc. The operator AND can only be applied to boolean operands, the operator / can only be applied to integer operands etc. Similar restrictions are put on the operands used in all other constructs. In a while statement, for example, an expression of type boolean must be given: WHILE found AND (j <= length) DO ... A value of some type T can be assigned to a variable of the same type. status:= nul; T_h_e_ _t_y_p_e_s_ _o_f_ _t_w_o_ _o_p_e_r_a_n_d_s_ _a_r_e_ _t_h_e_ _s_a_m_e_ _o_n_l_y_ _i_f_ _t_h_e_i_r_ _t_y_p_e_ _n_a_m_e_s_ (_i_d_e_n_t_i_f_i_e_r_s_)_ _a_r_e_ _t_h_e_ _s_a_m_e_,_ _o_r_ _t_h_e_ _t_w_o_ _o_p_e_r_a_n_d_s_ _a_r_e_ _d_e_c_l_a_r_e_d_ _i_n_ t_h_e_ _s_a_m_e_ _l_i_s_t_. \f VAR status: word; mask : word; result: ARRAY (0 .. length - 1) OF boolean; trap : ARRAY (0 .. length - 1) OF boolean; rec1, rec2: record ... end; The types of status and mask are the same, but none of them are the same as the type of result. Consequently: status:= mask; is a valid assignment, but status:= result; is not a valid assignment. Furthermore, the type of trap is neither the same as the type of result nor the same as the type of status and mask. And the operands rec1 and rec2 are of the same type. M_M_m_ The type t is c_o_m_p_a_t_i_b_l_e_ with the type t if: P_P_p_ 1 2 M_M_m_ - t and t are the same named type P_P_p_ 1 2 M_M_m_ - t is a subrange or t or t is a subrange of t P_P_p_ 1 2 2 1 M_M_m_ - t is SET OF b and t is SET OF b and P_P_p_ 1 1 2 2 M_M_m_ b is compatible with b P_P_p_ 1 2 M_M_m_ - t is ! t P_P_p_ 1 2 M_M_m_ - t is t and t is t where t is a type name P_P_p_ 1 2 M_M_m_ - t and t are of pool type P_P_p_ 1 2 Note, that the relation compatible is not symmetric. If the type M_M_m_ t is compatible with the type t , a value of type t can be P_P_p_ 1 2 1 M_M_m_ assigned to a variable of type t . P_P_p_ 2 \f 3_._3_._5_ _ _ _ _ _R_o_u_t_i_n_e_ _D_e_c_l_a_r_a_t_i_o_n_ _P_a_r_t_ 3.3.5 A number of statements and declarations can be combined into a routine. When the routine is called, the data structure defined by the declarations is allocated and the statements are executed. A routine is either a procedure or a function. routine declaration: ' 'procedure heading ' '; 'block ' 'function heading procedure heading: 'PROCEDURE 'procedure name 'formal parameters ' function heading: 'FUNCTION 'function name 'formal parameters ':type ' The type of a function cannot be a shielded type. F_o_r_m_a_l_ _P_a_r_a_m_e_t_e_r_s_ The f_o_r_m_a_l_ _p_a_r_a_m_e_t_e_r_s_ specify the interface between a block and the surrounding. For each formal parameter is given its kind, formal name, and type. formal parameters: ' ' ' '( ' 'parameter description ' ') ;< parameter description: ' ' 'formal name list ': 'type ' ' 'VAR \f formal name list: ' 'formal name ' ' ,< If VAR is specified the parameter is of kind variable: a v_a_r_ p_a_r_a_m_e_t_e_r_; otherwise the parameter is of kind value: a v_a_l_u_e_ p_a_r_a_m_e_t_e_r_. A formal parameter is used as a declared variable of the speci- fied name and type. Parameters with components of shielded type must be of kind vari- able. Example: TYPE parity = (even, odd); frame = 0 .. 31; FUNCTION frame _parity (arg: frame): parity; CONST table = (. 0,3,5,6,9,10,12,15, 17,18,20,23,24,27,29,30 .); (* The set table contains all values of type frame with even parity *) BEGIN IF arg IN table THEN frame _parity:= even ELSE frame _parity:= odd; END; A routine can have local declarations as in this case the con- stant table. A function returns a result, this result is the value assigned to the funcion name, e.g. frame _parity:= even. The function has a parameter with the name arg and the type frame. The type of the result is parity. \f Routine declarations can be nested: TYPE parity = (even, odd); byte = 0 .. 255; FUNCTION byte _parity (arg: byte) : parity; TYPE frame = 0 .. 31; FUNCTION frame _parity (arg: frame) : parity; CONST table = (. 0,3,5,6,9,10,12,15, 17,18,20,23,24,27,30 .); BEGIN (* frame parity *) IF arg IN table THEN frame _parity:= even ELSE frame _parity:= odd; END; BEGIN (* byte parity *) IF frame _parity (arg MOD 32) = frame _parity (arg DIV 32) THEN byte _parity:= even ELSE byte _parity:= odd; END; The declaration of a name in a routine is only valid inside the routine. Outside the routine it is invisible. The constant table can therefore only be applied in the function frame _parity where it is declared. But it cannot be applied in the function byte _parity. Similarly, the type frame is not known outside byte _parity. It can, however, be applied in inner routines such as the function frame _parity. The exact rules about valid con- texts for a variable are called the scope rules (see the next subsection). \f The scope rules require that a process or routine is declared before it is used. A declaration where the block is a forward block is an announcement of a routine or process declaration which is given textually later, this is a f_o_r_w_a_r_d_ _d_e_c_l_a_r_a_t_i_o_n_. The heading of the declaration must be the same as the heading given in the forward declaration. That is the name, type, and order of the formal parameters must be the same. 3_._3_._5_._1_ _ _ _S_c_o_p_e_ _R_u_l_e_s_ 3.3.5.1 A scope is one of the following: - a field list excluding inner scopes, - a process or routine heading excluding inner scopes, - a block excluding inner scopes, - a prefix excluding inner scopes, - a local declaration (in a lock statement) excluding inner scopes. A name can be declared once in each scope only. All names must be declared before they are used. If a name is declared both in a scope and in an inner scope, it is always the inner declaration which is effective in the inner scope. Generally the declaration of a name is effective in the rest of the block where it is declared. Further details for each kind of name is given below. c_o_n_s_t_a_n_t_ _n_a_m_e_, t_y_p_e_ _n_a_m_e_, v_a_r_i_a_b_l_e_ _n_a_m_e_, and r_o_u_t_i_n_e_ _n_a_m_e_: The declaration of these names is effective in the rest of the block excluding inner process blocks. f_i_e_l_d_ _n_a_m_e_: The declaration of a field name is effective in the rest of the block excluding inner process blocks. But the field name can be used in record variables and with-statements only. \f s_c_a_l_a_r_ _c_o_n_s_t_a_n_t_: The declaration of a scalar constant name is effective in the rest of the block excluding inner process blocks. But used in a type definition of a fieldname the constant name can be used in with-statements only. l_a_b_e_l_: The declaration of a label is effective in the scope where it is declared. r_o_u_t_i_n_e_ _p_a_r_a_m_e_t_e_r_ _n_a_m_e_ (implicit and explicit): The declaration of a routine parameter name is effective in the routine block. Note that the declaration is not effective in the routine heading. p_r_o_c_e_s_s_ _n_a_m_e_: The declaration of a process name is effective in the rest of the block where it is declared excluding inner pro- cess blocks. 3_._3_._5_._2_ _ _ _R_o_u_t_i_n_e_ _B_l_o_c_k_s_ 3.3.5.2 Within the block of a routine a recursive call of the routine can be made. Processes, exception routines, and variables with semaphore or pool components cannot be declared in a routine block. 3_._3_._5_._3_ _ _ _F_u_n_c_t_i_o_n_s_ 3.3.5.3 A function name may appear as a variable on the left head side of an assignment. The type in the function heading is the f_u_n_c_t_i_o_n_ t_y_p_e_, it specifies the range of the function. The value of a function is the dynamically last value assigned to the function variable. \f function variable: 'function name ' 3_._3_._6_ _ _ _ _ _E_x_p_o_r_t_ _P_a_r_t_ 3.3.6 Export part is an implementation dependent feature which may open for special linkage editor facilities (see chapter 4). export part: 'EXPORT ' 'export name '= 'exp.kind 'simple variable' ' ;< exp.kind: ' 'VALUE ' ' 'DISP ' 'SIZE ' N_o_t_e_: 'ADDRESS ' The five words for exp.kind 'OFFSET ' are not reserved words! VALUE is for constants only DISP is for fields only and means displacement relative to record start SIZE is for constants, entire variables, and fields. SIZE means size (in bytes) of the type which is associated to the "simple variable" ADDRESS indicates absolute address OFFSET indicates relative offset in current stack frame \f simple variable: 'simple var name ' ' ' field name< .< simple var name can be either a constant name or a variable name. 3_._4_ _ _ _ _ _ _ _T_h_e_ _S_t_a_t_e_m_e_n_t_ _P_a_r_t_ 3.4 This section contains subsections describing the syntax and the use of the different statements which are included in the language. Most of the statements are also found in Standard PASCAL and may be well known language elements. 3_._4_._1_ _ _ _ _ _S_t_a_t_e_m_e_n_t_s_ 3.4.1 The statements of a process describe the actions which are exe- cuted by a process incarnation. These statements are collected in a compound statement. compound statement: 'BEGIN ' 'statement ' 'END ' ;< The statements are executed one at a time in the specified order. Below, all statement forms are given together with references to their precise description: \f statement: section ' ' ' 'compound statement ' 3.4.1 'procedure call ' 3.4.6 'assignment statement ' 3.4.2 'exchange statement ' 3.4.3 'case statement ' 3.4.5 'for statement ' 3.4.4 'if statement ' 3.4.5 'repeat statement ' 3.4.4 'while statement ' 3.4.4 'with statement ' 3.4.7 'goto statement ' 3.4.10 'labelled statement ' 3.4.10 'lock statement ' 3.4.8 'channel statement ' 3.4.9 3_._4_._2_ _ _ _ _ _A_s_s_i_g_n_m_e_n_t_ _S_t_a_t_e_m_e_n_t_ 3.4.2 assignment statement: 'variable ':= 'expression ' The type of the variable must be compatible with the type of the expression. Assignments can be made to a variable of: - a simple type, - a pointer type, - a structured type where all components are of a simple type or a pointer type. The assignment statement replaces the current value of the vari- able by the value of the expression. \f E_x_p_r_e_s_s_i_o_n_s_ describe how values are computed. Expressions are evaluated from left to right using the following precedence rules: NOT has the highest precedence followed by *, /, DIV, MOD, AND followed by + , - , OR followed by =, <', <, <=, ', '=, IN expression: 'simple expression ' ' ' '=---'--'simple expression ' <' ' ' < ' ' <= ' ' ' ' ' '= ' ' IN ' simple expression ' ' ' 'term ' ' ' + ' < + < ' - ' < - < < OR < term: ' 'factor ' ' < *< < /< < DIV< < MOD< < AND< \f N_o_t_e_: All factors in an expression are evaluated. Factor: ' 'operand ' ' ' '( 'expression ) ' 'NOT 'factor ' operand: ' 'variable ' ' 'value V_a_r_i_a_b_l_e_s_ The term variable includes declared variables, formal parameters, and function variables. All variables are denoted by their name and possibly a selector. variable: ' 'variable name ' ' 'function variable ' 'formal name ' 'array variable ' 'record variable ' 'pointed variable ' array record variables are described in subsection 3.3.4 pointed function variables are described in subsection 3.3.5.3 \f Variables of shielded and pointer types are implicitly given the following initial values: semaphore: passive shadow: nil reference: nil pool: a number of messages, determined by the cardinality expression; the contents of these messages are unde- fined pointer: nil 3_._4_._3_ _ _ _ _ _E_x_c_h_a_n_g_e_ _S_t_a_t_e_m_e_n_t_ 3.4.3 exchange statement: 'variable ':=: 'variable ' The two variables must either both be of type reference or both be of type shadow. The exchange statement exchanges the values of the two variables. 3_._4_._4_ _ _ _ _ _R_e_p_e_t_i_t_i_v_e_ _S_t_a_t_e_m_e_n_t_s_ 3.4.4 R_e_p_e_a_t_ _S_t_a_t_e_m_e_n_t_ repeat statement: 'REPEAT ' 'statement ' 'UNTIL 'expression ' ;< The result of the expression must be of type boolean. The statement sequence is executed one or more times. Every time the sequence has been executed, the expression is evaluated, when the result is true the repeat statement is completed. \f W_h_i_l_e_ _S_t_a_t_e_m_e_n_t_ while statement: 'WHILE 'expression 'DO 'statement ' The result of the expression must be of type boolean. The statement is executed a number of times (possibly zero). The expression is evaluated before each execution, when the result is false, the while statement is completed. F_o_r_ _S_t_a_t_e_m_e_n_t_ for statement: 'FOR 'variable ':= 'for list 'DO 'statement ' for list: 'TO ' M_M_m_ 'expression ' 'expression ' P_P_p_ 1 2 U_U_u_ --'DOWNTO-' The two expressions must be of the same enumeration type and the type of the variable must be compatible with this. The selection of the variable cannot be changed in the statement. Hence, if the variable has array indices or pointers, changes to these (in the statement) will not affect the selection. The statement is executed with consecutive values of the variable The ordinal value of the variable can either be incremented (in M_M_m_ steps of 1 (succ)) from expression TO expression , or descrem- P_P_p_ 1 2 M_M_m_ ted (in steps 1 (pred)) from expression DOWNTO expression . The P_P_p_ 1 2 two expressions are evaluated once, before the repetition. If the M_M_m_ value of expression is greater than the value of expression and P_P_p_ 1 2 TO is specified, the statement is not executed. \f M_M_m_ Similarly, if the value of expression is less than the value of P_P_p_ 1 M_M_m_ expression and DOWNTO is specified, the statement is not execu- P_P_p_ 2 ted. The value of the variable is dependent of the expressions after the for statement. 3_._4_._5_ _ _ _ _ _C_o_n_d_i_t_i_o_n_a_l_ _S_t_a_t_e_m_e_n_t_s_ 3.4.5 C_a_s_e_ _ _S_t_a_t_e_m_e_n_t_ case statement: 'CASE 'switch OF ' 'case list element 'end part ' ;< end part: ' ' 'END ' 'OTHERWISE ' 'statement ' ;< case list element: ' ' ' 'constant expression ' ' ': statement ' ' 'constant expression '.. 'constant expression ,< ' switch: 'expression ' \f The values of the constant expressions in case list elements are called c_a_s_e_ _l_a_b_e_l_s_. All case labels and the switch must be of the same enumeration type and all case labels must be distinct. The switch is evaluated and the statement labelled by the value of the switch is executed. If no such label is present, the state- ment following OTHERWISE is executed; if OTHERWISE is not speci- fied, an exception occurs. I_f_ _S_t_a_t_e_m_e_n_t_ if statement: M_M_m_ 'IF 'expression 'THEN 'statement ' 'ELSE 'statement ' ' P_P_p_ 1 2 U_U_u_ ' The result of the expression must be of type boolean. M_M_m_ Statement is executed if the value of the expression is true. If P_P_p_ 1 M_M_m_ it is false, statement (if specified) is executed. P_P_p_ 2 The statement: M_M_m_ IF e THEN IF e THEN s ELSE s P_P_p_ 1 2 1 2 is equivalent to: M_M_m_ IF e P_P_p_ 1 THEN BEGIN M_M_m_ IF e P_P_p_ 2 M_M_m_ THEN s P_P_p_ 1 M_M_m_ ELSE s P_P_p_ 2 U_U_u_ END \f 3_._4_._6_ _ _ _ _ _P_r_o_c_e_d_u_r_e_ _C_a_l_l_ 3.4.6 routine call: 'routine name 'actual parameters ' A r_o_u_t_i_n_e_ _c_a_l_l_ binds actual parameters to formal parameters, allocates local variables, and executes the compound statement of the block. When the compound statement is completed, local vari- ables are deallocated and execution is resumed immediately after the routine call. All local reference and shadow variables must be nil when the compound statement is completed, otherwise an exception occurs. The variables of a routine are associated with a specific call; they exist from the routine call until the compound statement (of the block) is completed. When a routine is called recursively, several versions of the variables exist simultaneously, one for each uncompleted call. The difference between a procedure and a function is that a pro- cedure call is a statement and a function call a factor (function variable) in an expression. A f_u_n_c_t_i_o_n_ _c_a_l_l_ is an operand in an expression. function call: 'function name 'actual parameters ' A_c_t_u_a_l_ _P_a_r_a_m_e_t_e_r_s_ When a process incarnation is created or a routine is called a_c_t_u_a_l_ _p_a_r_a_m_e_t_e_r_s_ are bound to formal parameters. actual parameters: ' ' ' '( ' 'actual parameter ' ') ,< \f actual parameter: 'expression ' There must be an actual parameter for each explicit formal para- meter. The binding of an actual parameter to a formal parameter depends on the parameter kind: value: The type of the actual parameter must be compatible with the type of the formal parameter. The value of the actual parameter is evaluated and this value becomes the initial value of the formal parameter. Assignments to the formal parameter within the block does not affect the actual parameter (call by value). variable: The type of the actual and formal parameter must be the same. The actual parameter must be a variable, the value of this variable becomes the initial value of the formal parameter. Changes to the value of the formal parameter within the block affects the actual parameter directly. The actual parameter selects a variable, this selection cannot be changed in the block. Hence, if the variable has array indices or pointers, changes to these do not affect the selection (c_a_l_l_ _b_y_ _r_e_f_e_r_e_n_c_e_). An element or a field of a packed variable cannot be an actual var parameter. The w_h_o_l_e_ packed variable can, however, be an actual var parameter. \f 3_._4_._7_ _ _ _ _ _W_i_t_h_ _S_t_a_t_e_m_e_n_t_ 3.4.7 with statement: 'WITH ' 'record variable ' 'DO 'statement ' ,< Within the statement fields can be accessed by giving their field names only. The with statement WITH v1, v2, ..., vn DO s; is a shorthand for the nested with statement shown below. WITH v1 DO WITH v2 DO . . . WITH vn DO s; The record variable selects a record, this selection cannot be changed in the statement. Hence, if the record variable has array indices or pointers, changes to these (in the statement) will not affect the selection. 3_._4_._8_ _ _ _ _ _L_o_c_k_ _S_t_a_t_e_m_e_n_t_ 3.4.8 lock statement: 'LOCK 'reference variable 'AS 'local declaration 'DO 'statement ' local declaration: 'local name ': 'type ' \f reference variable: 'variable ' local name: 'identifier ' The component types of the type must be simple. The reference variable must refer to a message (must not be nil), otherwise an exception occurs. If the message is too small to represent the specified type an exception occurs. In the statement local name is a declared variable with the specified type. In the statement the reference variable must not be used as part of an exchange statement or as a parameter to signal, return, release, pop, or push. The data part of a message is manipulated as a declared variable with the local name. It is always the top in the message stack which is manipulated. 3_._4_._9_ _ _ _ _ _C_h_a_n_n_e_l_ _S_t_a_t_e_m_e_n_t_ 3.4.9 channel statement: 'CHANNEL 'reference variable 'DO 'statement ' The reference variable must refer to a message (must not be nil). Any implementation may place restrictions on this message. If the message is not of this restricted form an exception occurs. In the statement the reference variable must not be used as part of an exchange statement or as a parameter to, signal, return, release, pop, or push. \f The channel statement controls the handling of peripherals in an implementation dependent way. 3_._4_._1_0_ _ _ _ _G_o_t_o_ _S_t_a_t_e_m_e_n_t_ 3.4.10 goto statement: 'GOTO 'label ' The goto statement, the declaration of the label, and the definition of the label must be in the same scope. Execution continues at the statement labelled by the label (labelled statement). Jumps out of a channel or lock statement and jumps out of a routine are not allowed. labelled statement: 'label ': 'statement ' 3_._4_._1_1_ _ _ _ _S_t_a_n_d_a_r_d_ _R_o_u_t_i_n_e_s_ _a_b_s_,_ _s_u_c_c_,_ _p_r_e_d_,_ _c_h_r_,_ _o_r_d_ 3.4.11 The absolute value of an integer variable is given as the result of: FUNCTION abs (int: integer) : integer; The successor and predecessor of a variable of scalar type is given as the result of: FUNCTION succ (s: s _type): s _type FUNCTION pred (s: s _type): s _type s _type may be any scalar type. succ taken on the last element and pred taken on the first ele- ment of a scalar type results in an exception. \f The character with the ordinal value n is the result of a call chr(n) where chr is defined as: FUNCTION chr (n: 0 .. 127): char; The ordinal value of a scalar element is retrieved by the func- tion ord: FUNCTION ord (s: s _type): integer; where s _type may be any scalar type. \f F_ 4_._ _ _ _ _ _ _ _ _P_R_O_C_E_S_S_ _C_O_M_M_U_N_I_C_A_T_I_O_N_ 4. This chapter contains a general description of communication between incarnations, i.e. a description of the language concepts and the tables available for the programmer. After that is a more detailed description of the predefined routines intended for syn- chronization of the communication between process incarnations. 4.1 4_._1_ _ _ _ _ _ _ _G_e_n_e_r_a_l_ _P_r_o_c_e_s_s_ _C_o_m_m_u_n_i_c_a_t_i_o_n_ A process consists of a number of statements and declarations. An incarnation of a process is the execution of the actions on a private data structure. Many incarnations can be executed concur- rently. Process incarnations communicate by exchanging m_e_s_s_a_g_e_s_. A mes- sage can be accessed by at most one incarnation at a time. M_m_m_ place data await access M P_p_p_ in M to M A B T_i_m_e_ _T_: A has exclusive access to the message M. read data M in M A B T_i_m_e_ _T_ _+_ _1_: B has exclusive access to M. The two predefined types reference and semaphore are used for re- ferencing and exchanging access to messages. \f The value of a reference variable is either a reference to a message or nil (representing "no reference"). At most one variable references a message. Since process incarnations access messages through reference variables only, mutually exclusive access to messages is secured. Q_u_e_u_e_ _s_e_m_a_p_h_o_r_e_s_ are used for exchanging access to messages. A queue semaphore consists of a sequence (fifo) of messages and a set of waiting process incarnations. One of these is always empty. A queue semaphore s can be in one of three states: o_p_e_n_ 1 2 The sequence of messages is n_o_t_ _e_m_p_t_y_. M_m_m_ s . The set of incarnations is e_m_p_t_y_. . P_p_p_ . N sequence of messages l_o_c_k_e_d_ The sequence of messages is e_m_p_t_y_. The set of incarnations is n_o_t_ _e_m_p_t_y_. s waiting incarnations p_a_s_s_i_v_e_ s The sequence of messages is e_m_p_t_y_. The set of incarnations is e_m_p_t_y_. \f Any process may contain declarations of variables of type sema- phore, and it may receive semaphore variables as parameters when it is created. All declared semephore variables are initially in the passive state. In constrast to variables of any other type a semaphore variable can be accessible by many process incarnations simultaneously. example: PROCESS converter (input, output: semaphore); VAR myown: ARRAY (1 .. 2) OF semaphore; The process converter has access to four semaphores: input, output, myown(1), and myown(2). The predefined routines signal and wait are used for exchanging access to messages. PROCEDURE signal (VAR r: reference; VAR s: semaphore); The reference r must reference a message. If the semaphore s is open or passive, the message referenced by r is entered in the sequence of messages belonging to s. o_p_e_n_ _o_r_ _p_a_s_s_i_v_e_ incarnation executing signal 1 r s 2 M_m_m_ . message . P_p_p_ . N sequence of messages p_r_i_o_r_ _t_o_ _s_i_g_n_a_l_ _(_r_,_ _s_)_ \f incarnation executing signal s 1 r 2 M_m_m_ nil . . P_p_p_ . N N + 1 sequence of messages a_f_t_e_r_ _s_i_g_n_a_l_ _(_r_,_ _s_)_ If s is locked one incarnation is removed from the set of waiting incarnations and reactivated. That is, it will be allowed to com- plete the call of wait which caused it to wait. l_o_c_k_e_d_ incarnation executing signal incarnation executing wait s r message waiting incarnations p_r_i_o_r_ _t_o_ _s_i_g_n_a_l_ _(_r_,_ _s_)_ incarnation executing signal incarnation executing wait r nil message s waiting incarnations a_f_t_e_r_ _s_i_g_n_a_l_ _(_r_,_ _s_)_ \f PROCEDURE wait (VAR r: reference; VAR s: semaphore); The reference r must be nil. If the semaphore is open the first message in the sequence is removed and r becomes a reference to this message. o_p_e_n_ 1 incarnation executing wait 2 message r M_m_m_ s . nil . P_p_p_ . N sequence of messages p_r_i_o_r_ _t_o_ _w_a_i_t_ _(_r_,_ _s_)_ 2 M_m_m_ s . message incarnation executing wait . r P_p_p_ . N sequence of messages a_f_t_e_r_ _w_a_i_t_ _(_r_,_ _s_)_ If the state is locked or passive the incarnation is temporarily stopped and entered in the set of waiting incarnations. l_o_c_k_e_d_ _o_r_ _p_a_s_s_i_v_e_ incarnation executing wait r s nil waiting incarnations p_r_i_o_r_ _t_o_ _w_a_i_t_ _(_r_,_ _s_)_ \f incarnation executing wait r s nil waiting incarnations Incarnation has been stopped during wait (r, s) It is implementation dependent which one of several waiting in- carnations is selected for activation during execution of signal. However, the selection algorithm must be fair: no incarnation may remain waiting indefinitely on a semaphore, provided some other incarnations continue to signal messages to that semaphore. Execution of wait and of signal is performed indivisibly: e.g. from the moment an incarnation starts execution of a signal on a given semaphore and until the execution is completed, any other incarnation trying to operate on that semaphore variable is delayed. A process may only inspect or alter the contents of a message in a so-called lock statement. Let r be a reference variable which references a message: LOCK r AS b: t DO s; In the statement s the message referenced by r is manipulated as if it were a variable with the name b of type t. In the following example there are two processes, one which pro- duces data (e.g. input data) and one which consumes data (e.g. uses the input data in a computation). \f PROCESS producer (full, PROCESS consumer (full, void: semaphore); void: semaphore); TYPE TYPE buffertype = ...; buffertype = ...; VAR VAR r: reference; r: reference; BEGIN BEGIN REPEAT REPEAT wait (r, void); wait (r, full); LOCK r AS b: buffertype DO LOCK r AS b: buffertype DO BEGIN BEGIN (*...produce data...*) (*...consume data...*) END; END; signal (r, full); signal (r, void); UNTIL...; UNTIL...; END; END; The allocation of messages is specified by declaring a variable of pool type. VAR m: POOL cardinality OF type; Initially, the variable m contains cardinality messages. These messages can hold a value from type. The predefined procedure alloc removes a message from a pool variable: alloc (r, m, s); The reference r must be nil. If the pool of messages is not emp- ty, one of the messages is removed and r references this message. If the pool is empty the process incarnation waits until a mes- sage is released (by another incarnation calling the predefined procedure release). \f Each message contains information about its origin. The third parameter to alloc must be a semaphore and it becomes the a_n_s_w_e_r_ s_e_m_a_p_h_o_r_e_ of the message. This is the equivalent of a return address on an envelope of a letter. The answer semaphore is used in the predefined procedure return: PROCEDURE return (VAR r: reference); A call of return is equivalent to a call of signal: signal (r, "answer semaphore") But the answer semaphore is only implicitly available through return. The following is a revised version of the producer comsumer example given above. PROCESS proceducer (stream: PROCESS comsumer (stream: semaphore); semaphore); TYPE TYPE buffertype = ...; buffertype = ...; VAR VAR r: reference; r: reference; m: POOL 1 OF buffertype; a: semaphore; BEGIN BEGIN alloc (r, m, a); REPEAT REPEAT wait (r, stream); LOCK r AS b: buffertype DO LOCK r AS b: buffertype DO BEGIN BEGIN (*...produce buffer...*) (*...comsume buffer...*) END; END; signal (r, stream); return (r); wait (r, a); UNTIL...; UNTIL...; END; END; \f The following communication flow is possible by means of SIGNAL/RETURN: A reference variable may point to none or a stack of messages. This is a generalization of the concept of reference variables as described earlier. In general terms a reference variable points to a stack of messages. When the value of the reference variable is nil, the stack is empty. A well-defined reference variable points to a stack of reference variables. The message header of the stack elements contains a field, which chains the messages together. This field is called the s_t_a_c_k_ _c_h_a_i_n_. This pointer is nil in the last element of the chain. Two procedures: PUSH(<reference variable',<reference variable') POP (<reference variable',<reference variable') are used to manipulate reference variables when interpreted as stack reference variables. \f example: VAR element: REFERENCE; stack: REFERENCE; M_m_m_ . . P_p_p_ . PUSH (element, stack); M_m_m_ . . P_p_p_ . POP (element, stack); P_U_S_H_ _(_r_e_f_1_,_ _r_e_f_2_)_ B_e_f_o_r_e_ _c_a_l_l_ ref1 - well-defined reference to element. The stack chain field in the element m_u_s_t_ be NIL. ref2 - well-defined stackop element or nil if stack is empty: A_f_t_e_r_ _c_a_l_l_ ref1 - nil ref2 - ref2:= old ref1 If the old ref1 has no associated message data, the message data associated the old ref2, if any, are assigned the old ref1, together with the pushing. If the old ref1 has associated message data the old ref1 is just pushed. \f E_x_a_m_p_l_e_ 1) Before call After call ref1 ref2 ref1 ref2 2) ref1 ref2 ref1 ref2 P_O_P_ _(_r_e_f_1_,_ _r_e_f_2_)_ B_e_f_o_r_e_ _c_a_l_l_ ref1 - nil ref2 - well-defined stacktop element \f A_f_t_e_r_ _c_a_l_l_ ref1 - ref1:= old ref2 ref2 - new stacktopelement. Note: ref2:= nil if the stack became empty during call. If the old stackop element has associated message data, and the new stackop element points to the same message data, the message data pointer in the popped element is set to nil. This is not done if the new stackop element points either to another message data or points to nil. \f E_x_a_m_p_l_e_s_ 1) Before call After call ref1 ref2 ref1 ref2 2) ref1 ref2 ref1 ref2 3) ref1 ref2 ref1 ref2 \f The PUSH and POP procedures are especially suited to the following situations: - to associate a new messageheader to received message data by the PUSH procedure in order to avoid copying of data, and to signal the message on to the next incarnation in the flow. The general answer mechanism will be to reestablish the original message header by a call of POP and return the message to the sender by calling RETURN. SIGNAL SIGNAL SIGNAL SIGNAL M_M_m_ P P P P P_P_p_ 1 2 n-1 n RETURN RETURN RETURN RETURN - to pile together a number of messages and pass the whole batch to an incarnation by one call of SIGNAL. S_e_m_a_p_h_o_r_e_ _P_o_i_n_t_e_r_s_ A semaphore pointer variable is a variable of type: semaphore A semaphore pointer variable is a variable, whose value refer- ences a semaphore variable. If the value is not a reference to a semaphore variable, the value is nil. The only legal operations on semaphore pointer variables are: nil, and := (assignment) If p is a semaphore pointer variable, p denotes the semaphore pointed to by p. \f 4_._2_ _ _ _ _ _ _ _T_h_e_ _P_r_e_d_e_f_i_n_e_d_ _C_o_m_m_u_n_i_c_a_t_i_o_n_ _R_o_u_t_i_n_e_s_ 4.2 s_i_g_n_a_l_,_ _w_a_i_t_,_ _r_e_t_u_r_n_,_ _a_n_d_ _r_e_l_e_a_s_e_. There are four predefined communication routines, signal, return, wait, and release. PROCEDURE signal (VAR r: reference; VAR s: semaphore); The reference parameter must refer to a message (must not be nil), otherwise an exception occurs. The reference variable is nil after a call of signal. If the semaphore is passive or open, the message referred to by r becomes the last element of the semaphore>s sequence of messages. If the semaphore is locked, one of the incarnations waiting on the semaphore completes its wait call. When several process incarnations are waiting, it is implementa- tion dependent which one is resumed by a signal call. No process must, however, be waiting indefinitely if other incarnations con- tinue to signal messages to the semaphore. PROCEDURE return (VAR r: reference); The parameter must refer to a message (must not be nil), other- wise an exception occurs. The call: return (r); has the same effect as the call: signal (r, r .answer ); The latter is, however, not a valid call because the answer semaphore is not explicitly available. \f PROCEDURE release (VAR r: reference); The parameter must refer to a message (must not be nil), other- wise an exception occurs. The call: release (r); has the same effect as the call: signal (r, r .owner ); The latter is, however, not a valid call because the owner sama- phore is not explicitly avaiable. PROCEDURE wait (VAR r: reference; VAR s: semaphore); The reference parameter must be nil, otherwise an exception occurs. After a call of wait it refers to a message. If the semaphore is open, the first message is removed from the semaphore>s sequence of messages. If the semaphore is passive or locked, the incarnation waits and enters the set of incarnations waiting on the semaphore. It can be resumed by another incarnation calling signal or return. O_p_e_n_,_ _L_o_c_k_e_d_,_ _P_a_s_s_i_v_e_,_ _a_n_d_ _S_e_n_s_e_s_e_m_ There are three predefined boolean functions to detect the state of a semaphore variable: FUNCTION open (s: semaphore): boolean FUNCTION locked (s: semaphore): boolean FUNCTION passive (s: semaphore): boolean \f The three states may be depicted as: o_p_e_n_ 1 2 The sequence of messages is n_o_t_ _e_m_p_t_y_. M_m_m_ . The set of incarnations is e_m_p_t_y_. . P_p_p_ . N sequence of messages l_o_c_k_e_d_ The sequence of messages is e_m_p_t_y_. The set of incarnations is n_o_t_ _e_m_p_t_y_. s waiting incarnations p_a_s_s_i_v_e_ s The sequence of messages is e_m_p_t_y_. The set of incarnations is e_m_p_t_y_. S_e_n_s_e_s_e_m_ PROCEDURE sensesem (VAR r: reference; VAR s: semaphore); The body of sensesem is equivalent to: IF open (s) THEN wait (r, s); i.e. take a message from s if there is any, otherwise r remains nil. \f R_e_f_ Semaphore pointers may be assigned to denote a semaphore by means of the predefined routine ref: FUNCTION ref (s: semaphore): semaphore; Semaphore pointers are initially set to nil by the system, this may be used to define a nilpointer which may be useful if semaphore pointers are used. example: var nil _pointer:! semaphore; (* nil _pointer cannot be changed since it is frozen*) sem _arr: array (low .. high) of semaphore; . . sem _arr (index):= ref (sem); . . sem _arr (index):= nil _pointer; P_u_s_h_,_ _p_o_p_,_ _a_n_d_ _e_m_p_t_y_ A message may consist of a stack of headers and data areas. The stack of message headers is the m_e_s_s_a_g_e_ _h_e_a_d_e_r_ _s_t_a_c_k_, and the stack of the data areas, the m_e_s_s_a_g_e_ _d_a_t_a_ _s_t_a_c_k_. \f message: M_M_m_ header header ... header message header stack P_P_p_ 1 2 n M_M_m_ data ... data message data stack P_P_p_ 1 m A header may or may not point to a data area (m <_ n). The t_o_p_ M_M_m_ h_e_a_d_e_r_ of the message is header . The t_o_p_ _d_a_t_a_ of a message is P_P_p_ 1 M_M_m_ data . P_P_p_ 1 The message is organized as a stack which is manipulated by the two predefined procedures push and pop. PROCEDURE push (VAR r1, r2: reference); The parameter r1 must refer to a message (must not be nil), and this message must have exactly one header, otherwise an exception occurs. The message accessible through r2 (possibly nil) is called the stack. The header referred to by r1 becomes the new top header of the stack. After the call, r2 refers to the new stack. If the new top message is a header message, the top data of r2 remains the same. After the call r1 is nil. PROCEDRUE pop (VAR r1, r2: reference); Reference variable r1 must be nil and r2 must refer to a message (must not be nil), otherwise an exception occurs. The top header is removed from the message (accessed through r2) and after the call r2 refers to the remaining part, while r1 refers to the removed message. \f It may be detected if a reference variable refers to a message with one header only by means of the predefined boolean function: FUNCTION empty (r: reference): boolean The body of empty may be: pop (local ref, r), empty:= nil (r) where nil is another standard function: N_i_l_ FUNCTION nil (p: pointer _type): boolean pointer _type may be any pointed type, for example reference which is defined like TYPE reference = message; A_l_l_o_c_ _a_n_d_ _O_p_e_n_p_o_o_l_ With each variable of type pool an anonymous semaphore is asso- ciated. This is the owner semaphore of all messages in the pool. A message is allocated from the pool by the predefined procedure alloc. PROCEDURE alloc (VAR r: reference, VAR p: pool 1; VAR s: semaphore); The pool variable can be of any pool type. The reference variable must be nil, otherwise an exception occurs. After the call it refers to a message. If the pool of message is not empty, one of the messages is removed. If the pool is empty the incarnation waits until a message is released to the pool by another process incarnation calling release. The answer semaphore of the removed message becomes s. Variables of type pool (or variables with pool components) can only be declared in the declaration of a process and not in the declarations of a routine. \f It may be detected if a pool is open (i.e. not empty) by means of FUNCTION openpool (VAR p: pool 1): boolean; the function result becomes true if the pool is not empty (cf. function open for semaphore). \f F_ 5_._ _ _ _ _ _ _ _ _P_R_O_C_E_S_S_ _C_O_N_T_R_O_L_ 5. Processes can be nested and a process declared within another process is a s_u_b_-_p_r_o_c_e_s_s_ (of the surrounding process). An arbitrary number of incarnations of sub-processes (children) can be created, they are all controlled by the parent. Incar- nations are created and removed dynamically. A process can have f_o_r_m_a_l_ _p_a_r_a_m_e_t_e_r_s_. When an incarnation of the process is created a number of a_c_t_u_a_l_ _p_a_r_a_m_e_t_e_r_s_ is given. Incar- nations communicate through common semaphore variables only. In this way a parent determines the communication paths of children. Note, however, that the controlling process incarnation need not participate in the communication. Variables of the predefined type shadow are used to discern dif- ferent incarnations of sub-processes. A shadow variable is the controlling process> link to an incarnation of a child. There is a number of predefined routines for exercising this control (start, stop, etc.). 5_._1_ _ _ _ _ _ _ _T_h_e_ _P_r_e_d_e_f_i_n_e_d_ _R_o_u_t_i_n_e_s_ _f_o_r_ _P_r_o_c_e_s_s_ _C_o_n_t_r_o_l_ 5.1 L_i_n_k_ FUNCTION link (external _name: alfa; process name): integer; There must not be a process linked to process name, process name must be the name of a process. The process identified by the external _name is linked to process name. The external identifica- tion of processes is implementation dependent. Result 0 means success, other values are implementation dependent error codes. \f FUNCTION create (incarnation _name: alfa; process name (actual parameters); VAR sh: shadow; storage: integer): integer; The shadow variable must be nil and process name must be linked to a process. Result 0 means success, other values are implemen- tation dependent error codes. A new i_n_c_a_r_n_a_t_i_o_n_ of the process linked to process name is crea- ted. The storage parameter specifies the amount of storage for holding the runtime stack. The store is initialized with the actual parameters and various administrative informations but the incarnation is stopped. The created incarnation is a c_h_i_l_d_ of the creating incarnation, the p_a_r_e_n_t_. After the call the shadow variable refers to the child. R_e_m_o_v_e_ PROCEDURE remove (VAR sh: shadow); The shadow variable must refer to a process incarnation (child), otherwise an exception occurs. Remove terminates execution of the child and deallocates all its resources. Execution of that incarnation cannot be resumed. Remove also removes all incarnations controlled by the child, their children ect. After the call the shadow variable is nil. S_t_a_r_t_,_ _S_t_o_p_,_ _a_n_d_ _B_r_e_a_k_ The following predefined procedures are used for controlling children between calls of create and remove. PROCEDURE start (VAR sh: shadow; priority: integer); \f Start initiates or resumes execution of a child which is stopped. The meaning of priority is implementation dependent. PRODURE stop (VAR sh: shadow); The shadow variable must refer to a process incarnation (child). The child is stopped. PROCEDURE break (VAR sh: shadow; exception _code: integer); The shadow variable must refer to a process incarnation (child). The call forces an exception upon the child. The meaning of the exception _code is implementation dependent. U_n_l_i_n_k_ FUNCTION unlink (process name): integer; At process must be linked to process name and no incarnations of the process may exist. After the call the link is deleted. Result 0 means success, other values are implementation dependent error codes. \f F_6_._ _ _ _ _ _ _ _ _U_T_I_L_I_T_Y_ _P_R_O_G_R_A_M_S_ 6. 6_._1_ _ _ _ _ _ _ _I_n_d_e_n_t_ 6.1 T_e_x_t_ _f_o_r_m_a_t_t_i_n_g_ _p_r_o_g_r_a_m_ The program performs indention of source programs depending on the options specified in the call and on the keyswords (reserved words) of PASCAL/PASCAL80. c_a_l_l_: M_m_m_ 1 <outputfile'= indent <input file' <option' P_p_p_ 0 0 <option'::= lines line numbers are added mark the blockstructure is made clear by means of ! between matching begin-end>s list the same as: lines mark noind the output will be left justified myind the output indention is the same as the input indention lc lists keywords in capital letters and identifiers in small (lower case) letters uc both key words and indentifiers are listed in upper case letters help produces a list of legal options Storage requirements: The core store required for indent is 16000 hW (size 16000). E_r_r_o_r_ _m_e_s_s_a_g_e_s_: ??? illegal input-filename input file must be specified \f call: "indent help", for help an error is detected in the program call, a new call "indent help" will produce a list of the valid options. ** warning, end(s) missing an error in the begin-end structure has been detected. ** premature end of file comment or string not terminated. 6_._2_ _ _ _ _ _ _ _C_r_o_s_s_ _R_e_f_e_r_e_n_c_e_ _P_r_o_g_r_a_m_ 6.2 Produces a cross reference listing of the identifiers and numbers and a use count of the PASCAL/PASCAL80 key words used in the input text. The cross reference list is made with no regard to the block structure of the program. The list is sorted according to the ISO-alphabet, i.e. numbers before letters, but with no difference between upper and lower case letters. The occurrence list for an identifier consists of a sequence of PASCAL/PASCAL80 line numbers. The occurrence kind is specified by means of the character following the line number: * meaning the identifier or number is found in a declaration part. = meaning the identifier is assigned to in the line specified. : meaning the identifier or number occurred as a label. blank all other uses <<<<<<<<<<<<<<in the list is a warning denoting that the name consists of more than 12 characters, which is the number of significant characters for PASCAL-identifiers. \f C_a_l_l_: M_m_m_ 1 <output file' = cross <input file' <option' P_p_p_ 0 <option'::= bossline. <yes or no' <yes or no'::= yes bossline>s are added to the listing. (default). no only PASCAL/PASCAL80 line numbers are generated. S_t_o_r_a_g_e_ _r_e_q_u_i_r_e_m_e_n_t_s_: The core store required for cross is at least 40000 hW (size 40000), but the requirement depends on the size of the input text. E_r_r_o_r_m_e_s_s_: ??? illegal output-filename left hand side of the call must be a name. ??? illegal input-filename input file must be specified ??? yes or no expected option >bossline> must be >bossline.yes> or >bossline.no> ??? error in bracket structure, detected at line: xx missing ")" (>s) ??? error in blockstructure, detected at line: xx unmatched end ***** warning: hash table overflow at line: xx the name table ran full at line xx, the cross referencing continues for the names met until line xx, new names in the following lines are ignored. \f F_ A_._ _ _ _ _ _ _ _ _R_E_F_E_R_E_N_C_E_S_A. 1 Staunstrup, J.: PASCAL80 Report RCSL No 52-AA964 A/S Regnecentralen af 1979 2 Jensen, K. and Wirth, N.: PASCAL User Manual and Report Springer - Verlag Berlin 1974 \f \f i T_A_B_L_E_ _O_F_ _C_O_N_T_E_N_T_S_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _P_A_G_E_ _ 1. INTRODUCTION .......................................... 1 2. FUNCTIONS SUPPORTED BY THE DRIVER ..................... 3 3. DRIVER INTERFACE ...................................... 4 3.1 Read Character ROM ............................... 4 3.2 Read Character RAM ............................... 4 3.3 Write Character RAM .............................. 4 3.4 Write Shadow RAM ................................. 5 3.5 Write Attribute RAM .............................. 5 4. DRIVER DECLARATION .................................... 6 5. BASIC DISPLAY ROUTINES ................................ 7 A_P_P_E_N_D_I_X_: A. REFERENCES ............................................ 11 \f ii \f 1_._ _ _ _ _ _ _ _ _I_N_T_R_O_D_U_C_T_I_O_N_ 1. The RC850 display driver is used to control the screen display function of an RC850 terminal. The driver runs on the PI-1 Machine 1 implemented on a Z80-microprocessor as part of the RC850. The functions provided by the driver may be characterized as rudimentary. Most of the functions are transparent transfer functions between CPU-memory and the various memories of the display module. The display module is described in detail in chapter 2 of 2. Its components are summarized below: R_e_f_r_e_s_h_ _R_A_M_ The memory holds the picture shown on the display, 2000 char- acters. 16 bits per. display position: 9 bits character value and 7 bits attributes. C_h_a_r_a_c_t_e_r_ _R_O_M_ The memory holds up to 128 standard character patterns, addressed by character values 0-127. C_h_a_r_a_c_t_e_r_ _R_A_M_ This memory can hold up to 256 extra character patterns, addressed by character values 256-511. S_h_a_d_o_w_ _R_A_M_ This memory can hold 4 shadow patterns which can be shown together with the addressed character. It is addressed by 2 attribute bits. A_t_t_r_i_b_u_t_e_ _R_A_M_ This memory can perform a conversion of 5 of the attribute bits to a number of different light effects on the display. C_R_T_ _c_o_n_t_r_o_l_l_e_r_ Contains the physical display parameters. These parameters are initialized by the driver, and can only be changed in the driver code. \f Under normal use only the refresh RAM is updated dynamically. In fact when the driver is not performing a specifically requested transfer function it will continously transfer the contents of a buffer in CPU RAM, the r_e_f_r_e_s_h_ _R_A_M_ _o_r_i_g_i_n_a_l_ to the display refresh RAM by means of DMA. With this strategy process incarnations on the PI-1 machine may update the display picture simply be writing into the refresh RAM original. Normally, an RC850 application will issue very few request to the display driver, because only those functions which require syn- chronization by means of interrupts have been implemented as parts of the actual driver. A number of more commonly used func- tions are provided by the basic display routines described in chapter 5. The implementation of these functions in the form of routines eliminates a significant amount of costly process inter- communication. \f 2_._ _ _ _ _ _ _ _ _F_U_N_C_T_I_O_N_S_ _S_U_P_P_O_R_T_E_D_ _B_Y_ _T_H_E_ _D_R_I_V_E_R_ 2. The CTR controller will be initialized to physical characteris- tics as described in 2. The contents of all RAM memories will be undefined, and the dis- play will be blocked. Proper initialization from the application should include writing of all RAM memories and unblocking the display. The following data transfer functions are executed by the driver on request: - read character ROM to CPU RAM, - read/write character RAM, - write shadow RAM, - write attribute RAM. Note that all display memories are accessed in blocks of bytes from byte 0 onwards. The following basic functions on the display module are not performed by the driver, but by a collection of basic display routines described in chapter 5: - set/read cursor position, - block/unblock the display, - set cursor mode. \f 3_._ _ _ _ _ _ _ _ _D_R_I_V_E_R_ _I_N_T_E_R_F_A_C_E_ 3. The following description is based on the driver interface conventions 3. Each request supported by the driver is described in one section. 3_._1_ _ _ _ _ _ _ _R_e_a_d_ _C_h_a_r_a_c_t_e_r_ _R_O_M_ 3.1 Transfers contents of the character ROM to the data buffer. function code 5 (read + 1 * 4) Possible results: 0 processed succesfully 4 illegal function. 3_._2_ _ _ _ _ _ _ _R_e_a_d_ _C_h_a_r_a_c_t_e_r_ _R_A_M_ 3.2 Transfers contents of the character RAM to the data buffer. function code 9 (read + 2 * 4) Possible results: 0 processed succesfully 4 illegal function. 3_._3_ _ _ _ _ _ _ _W_r_i_t_e_ _C_h_a_r_a_c_t_e_r_ _R_A_M_ 3.3 Transfers contents of the data buffer to the character RAM. function code 10 (write + 2 * 4) Possible results: 0 processed successfully 4 illegal function. \f 3_._4_ _ _ _ _ _ _ _W_r_i_t_e_ _S_h_a_d_o_w_ _R_A_M_ 3.4 Transfers contents of data buffer to shadow RAM. function code 14 (write + 3 * 4) Possible results: 0 processed succesfully 4 illegal function. 3_._5_ _ _ _ _ _ _ _W_r_i_t_e_ _A_t_t_r_i_b_u_t_e_ _R_A_M_ 3.5 Transfers contents of data buffer to attribute RAM. function code 18 (write + 4 * 4) Possible results: 0 processed succesfully 4 illegal function. \f 4_._ _ _ _ _ _ _ _ _D_R_I_V_E_R_ _D_E_C_L_A_R_A_T_I_O_N_ 4. The display driver is always placed in an RC850 bootstrap image along with the PI-1 basic software. The parent of the display driver is the Eve process (see 1). The PASCAL80 process heading of the display driver is as follows: PROCESS Display _driver (VAR display _sem: semaphore; int _vector: channel _number); where display _sem is the driver>s request semaphore, and int _vector is the interrupt vector programmed in channel 2 of the CTC (used for interrupt on termination of DMA transfer). The basic system variables used for performing display functions which are defined in the next chapter are also declared in the Eve process. \f 5_._ _ _ _ _ _ _ _ _B_A_S_I_C_ _D_I_S_P_L_A_Y_ _R_O_U_T_I_N_E_S_ The routines described in the following are included in the boot- strap image of any RC850 terminal along with the display driver and included in the RC850 context used when compiling PASCAL80 program for an RC850 terminal. The routines access three basic system variables: - the refresh RAM orginal, cf. chapter 1, - the current cursor position (row, column), - the current attribute byte (this is stored together with each character written). PROCEDURE WriteDisplay (a: integer; b: byte); The byte is written in the refresh RAM original at address a. FUNCTION ReadDisplay (a: integer): byte; The function returns the value stored at address a in the refresh RAM original. PROCEDURE SetCursorPosition (r,c: byte); The cursor is placed at location (r,c) on the display, and the current cursor position variable is updated to this value. The caller is responsible for ensuring that 0 <_ r <_ 24 and 0 <_ c <_ 79. PROCEDURE ReadCursorPosition (VAR r,c: byte); The value of the current cursor position variable is copied into r and c. PROCEDURE BlockDisplay; Display of the contents of the refresh RAM on the screen is inhibited, i.e. the screen goes black. PROCEDURE UnblockDisplay; Display of the contents of the refresh RAM is enabled. PROCEDURE SetCursorMode (mode: cursor _mode); The type cursor _mode is defined as \f cursor _mode = PACKED RECORD dummy1: bit; blink: boolean; blinkrate: bit; dummy2: bit; startc: 0..13; dummy3: 0..15; endc: 0..13 END; A call of SetCursorMode will set the blink rate, size, and position of the cursor as specified by the fields of mode. blink: If TRUE, the cursor will blink. blinkrate: If 0 the blink rate is 1/32 of the field rate (50 Hz), otherwise 1/16. startc and endc: First and last scanline of the cursor block. PROCEDURE WriteChar (b: char); The character is written on the display at the current cursor position which is then updated. Updating the cursor position (r,c) yields (r,c+1), except if c = 79 in which case a newline is output (see WriteNL). The cursor is set at the updated position. The attribute byte of the character is set to current attribute. PROCEDURE WriteNL; The cursor and current cursor position are both moved to the begin- ning of the next line. If the cursor was already in the last line (24) before the call, the screen image is rolled one line before the new line function is performed. Spaces are written in all char- acter positions of the new bottom line, with zero attribyte bytes. PROCEDURE SetAttribute (att: byte); The current attribute byte is set to the value of att. Subsequent characters written using WriteChar will have this byte as attri- bute byte. \f PROCEDURE ClearScreen; The procedure will clear the screen (setting all positions to blank with zero attribute), set current cursor position to (0,0) and set current attribute to 0. \f \f A_._ _ _ _ _ _ _ _ _R_E_F_E_R_E_N_C_E_S_ A. 1 RCSL No 31-D615: The P1-1 Machine, Reference Manual. 2 RCSL No 31-D594: RC850 Controllers, Reference Manual. 3 RCSL No 31-D617: PASCAL80 Driver Conventions. \f «eof»