Added upstream from http://ftp.icm.edu.pl/pub/loglan/
[loglan.git] / doc / loglanmi.txt
1 \r
2 \r
3 \r
4 \r
5 \r
6 \r
7 A micro-manual\r
8 \r
9 of\r
10 \r
11 the programming language\r\r
12 \r
13 \r
14 \r
15 \r
16 L O G L A N - 82\r\r
17 \r
18 Basic constructs and facilities\r\r
19 \r
20 \r
21 \r
22 \r
23 \r
24 \r
25 \r
26 \r
27 \r
28 Author: Antoni Kreczmar\r
29 \r
30 \r
31 \r
32 \r
33 \r
34 \r
35 \r
36 \r
37 \r
38 \r
39 \r
40 \r\r
41 Institute of Informatics, Warsaw University\r
42 March 1990\r\r\r
43 edited by A.Salwicki LITA Pau  November 1990\r
44
45 Table of contents\r
46 \r
47 \r
48 {TOC \o|1. Compound statements    4\r
49 2. Modularity     8\r
50 3. Procedures and functions     10\r
51 4. Classes      13\r
52 5. Adjustable arrays    16\r
53 6. Coroutines and semicoroutines        19\r
54 7. Prefixing    22\r
55 8. Formal types 28\r
56 9. Protection techniques        29\r
57 10. Programmed deallocation     30\r
58 11.  Exception handling 32\r
59 12. Concurrent processes.       33\r
60 References.     40\r
61 }\r
62 LOGLAN-82 is a universal programming language designed at the Institute of Informatics, University of Warsaw. Its syntax is patterned upon Pascal's. Its rich semantics includes the classical constructs and facilities offered by the Algol-family programming languages as well as more modern facilities, such as concurrency and exception handling.\r\r
63 The basic constructs and facilities of the LOGLAN-82 programming language include:\r\r
64 1)  A convenient set of structured statements,\r\r
65 2)  Modularity (with the possibility of module nesting and extending),\r\r
66 4) Classes (as a generalization of records) which enable to define  complex structured types, data structures, packages, etc.,\r\r
67 5) Adjustable arrays whose bounds are determined at run-time in such a  way that multidimensional arrays may be of various shapes, e.g.  triangular, k-diagonal, streaked, etc.,\r\r
68 6)  Coroutines and semi-coroutines,\r\r
69 7) Prefixing - the facility borrowed from Simula-67, substantially  generalized in LOGLAN-82 - which enables to build up hierarchies of  types and data structures, problem-oriented languages, etc.,\r\r
70 8)  Formal types treated as a method of module parametrization,\r\r
71 9)  Module protection and encapsulation techniques,\r\r
72 10) Programmed deallocator - a tool for efficient and secure garbage collection, which allows the user to implement the optimal strategy of storage management,\r\r
73 11) Exception handling which provides facilities for dealing with   run-time errors and other exceptional situations raised by the   user,\r\r
74 12) Concurrency easily adaptable to any operating system kernel and allowing parallel programming in a natural and efficient way.\r\r
75  The language covers system programming, data processing, and numerical computations. Its constructs represent the state-of-art and are efficiently implementable. Large systems consisting of many cooperating modules are easily decomposed and assembled, due to the class concept and prefixing.\r\r
76  LOGLAN-82 constructs and facilities have appeared and evolved simultaneously with the experiments on the first pilot compiler (implemented on Mera-400 Polish minicomputer).  The research on LOGLAN-82 implementation engendered with new algorithms for static semantics, context analysis, code generation, data structures for storage management etc.\r\r
77 The LOGLAN-82 compiler provides a keen analysis of syntactic and semantic errors at compilation as well as at run time. The object code is very efficient with respect to time and space. The completeness of error checking guarantees full security and ease of program debugging.\r\r
78 1. Compound statements\r\r
79  Compound statements in LOGLAN-82 are built up from simple statements (like assignment statement e.g. x:=y+0.5, call statement e.g. call P(7,x+5) etc.) by means of conditional, iteration and case statements.\r\r
80   The syntax of conditional statement is as follows:\r\r
81    if boolean expression\r
82    then\r   \r
83      sequence of statements\r
84    else\r  \r
85      sequence of statements\r
86    fi\r  \r\r
87 where "else part" may be omitted:\r\r
88    if boolean expression\r \r
89    then\r  \r
90      sequence of statements\r
91    fi\r \r\r
92  The semantics of conditional statement is standard. The keyword fi\r allows to nest conditional statements without appearence of "dangling else" ambiguity.\r\r\r
93
94 Example:\r\r
95   if delta>0\r    \r
96   then\r  \r
97     x2:=sqrt(delta)/a/2;\r
98     if b=0\r  \r
99     then\r \r
100       x1:=x2\r
101     else\r \r
102       x1:=-b/a/2+x2; x2:=x1-2*x2\r
103     fi\r \r
104   else\r \r
105     if delta=0\r  \r
106     then\r \r
107       x1:=-b/a/2; x2:=x1\r
108     else\r \r
109       write(" no real roots")\r
110     fi\r \r
111   fi\r  \r\r
112  The statements in a sequence of statements are separated with semicolons (semicolon may end a sequence , and then, the last statement in the sequence is the empty statement).\r\r
113  The short circuit control forms are realized in LOGLAN-82 by the conditional statements with orif (or andif) list. A conditional\r  statement with orif list has the form:\r        orif \r\r
114   if wb1 orif wb2 ... orif wbk\r  \r
115   then\r \r
116     sequence of statements\r
117   else\r
118     sequence of statements\r
119   fi\r \r\r
120 and corresponds somehow to a conditional statement:\r\r
121   if wb1 or wb2 ... or wbk\r  \r
122   then\r  \r
123     sequence of statements\r
124   else\r  \r
125     sequence of statements\r
126   fi\r  \r\r
127  The above conditional statement (without orif list) selects for\r  execution one of two sequences of statements, depending on the truth value of the boolean expression:\r\r
128 wb1 or wb2 or ... wbk\r   \r\r
129 which is always evaluated till the end. For the execution of the conditional statement with orif list the specified conditons\r wb1,...,wbk are evaluated in succession, until the first one evaluates to true. Then the rest of the sequence wb1,...,wbk is abandoned and "then part" is executed. If none of the conditions wb1,...,wbk evaluates to true "else part" is executed (if any).\r\r
130   Conditional statements with orif list facilitate to program those con_ditions, which evaluation to the end may raise a run-time error.\r\r
131 Example:\r\r
132   The execution of the statement:\r\r
133 if i>n or A(i)=0 then i:=i-1 else A(i):=1 fi\r \r\r
134 where the value of i  is greater than  n, and A is an array with upper bound n, will raise the run-time error. Then the user can write:\r\r
135 if i>n orif A(i)=0 then i:=i-1 else A(i):=1 fi\r\r
136 what  allows to avoid this run-time error and probably agrees with his intension.  \r\r
137   Conditional statement with andif list has the form:\r\r
138   if wb1 andif wb2 ...  andif wbk\r
139   then\r  \r
140     sequence of statements\r
141   else\r  \r
142     sequence of statements\r
143   fi\r  \r\r
144  For the execution of this kind of statements, the conditions wb1,...,wbk are evaluated in succession, until the first one evaluates to false; then "else part" (if any) is executed. Otherwise "then part" is executed.\r\r
145 Iteration statement in LOGLAN-82 has the form:\r\r
146 do sequence of statements od\r\r
147 An iteration statement specifies repeated execution of the sequence of statements and terminates with the execution of the simple statement exit\r\r
148 \r
149 Example:\r\r
150   s:=1; t:=1; i:=1;\r
151   do\r  \r
152     i:=i+1; t:=t*x/i;\r
153     if abs(t) < 1.0E-10 then exit fi; \r
154     s:=s+t\r
155   od;\r  \r\r
156  If two iteration statements are nested, then double exit in the\r  inner one terminates both of them.\r\r
157 Example:\r\r
158 r,x:=0;\r
159 do\r  \r
160   s,t:=1; i:=1; x:=x+0.2;\r
161   do\r    \r
162     i:=i+1; t:=t*x/i;\r
163     if i > n then exit exit fi; (* termination of both loops *)\r  \r
164     if t < 1 then exit fi;      (* termination of the inner loop *)\r
165     s:=s+t\r
166   od\r    \r
167 od\r  \r\r
168  In the example above simultaneous assignment statements are illustrated (e.g. r,x:=0) and comments, which begin with a left parenthesis immediately followed by an asterisk and end with an asterisk immediately followed by a right parenthesis.\r\r
169  Triple exit terminates three nested iteration statements, four exit terminates four nested iteration statements etc.\r\r
170 The iteration statement with while condition:\r  while  \r\r
171   while boolean expression \r
172   do\r  \r
173     sequence of statements\r
174   od\r  \r\r
175 is equivalent to:\r\r
176   do\r  \r
177     if not boolean expression then  exit  fi; \r
178     sequence of statements\r
179   od\r  \r\r
180  The iteration statements with controlled variables (for statements)\r  have the forms:\r\r
181   for j:=wa1 step wa2 to wa3\r  \r
182   do\r  \r
183     sequence of statements\r
184   od\r  \r\r
185 or\r\r
186   for j:=wa1 step wa2 downto wa3 \r
187   do\r  \r
188     sequence of statements\r
189   od\r  \r\r
190  The type of the controlled variable j must be discrete. The value of this variable in the case of the for statement with to is increased, and in the case of the for statement with downto is decreased. The\r  discrete range begins with the value of wa1 and changes with the step equal to the value of wa2. The execution of the for statement with to terminates when the value of j for the first time becomes greater than the value of wa3 (with downto when the value of j for the first time\r becomes less than the value of wa3). After the for statement\r termination the value of its controlled variable is determined and equal to the first value exceeding the specified discrete range. The values of expressions wa1, wa2 and wa3 are evaluated once, upon entry to the iteration statement. Default value of wa2 is equal 1 (when the keyword step and expression wa2 are omitted).\r\r
191   For or while statements may be combined with exit statement. \r\r
192 \r
193 Example:\r\r
194   for j:=1 to n\r
195   do\r \r
196      if x=A(j) then exit fi; \r
197   od\r  \r\r
198  The above iteration statement terminates either for the least j, 1<=j<=n, such that x=A(j) or for j=n+1 when x=/=A(j), j=1,...,n.\r\r
199  To enhance the user's comfort, the simple statement repeat is provided. It may appear in an iteration statement and causes the current iteration to be finished and the next one to be continued (something like jump to CONTINUE in Fortran's DO statements).\r\r
200 Example:\r\r
201   i:=0;  s:=0;\r
202   do\r  \r
203     i:=i+1;\r
204     if A(i)<0 then repeat fi; (* jump to od,iterations are contd.*)\r
205     if i > m then exit fi;    (* iteration statement is terminated*) \r
206     s:=s+sqrt(A(i));\r
207   od;\r  \r\r
208  Just as exit, repeat may appear in for statement or while statement. Then the next iteration begins with either the evaluation of a new value of the controlled variable (for statement) or  with the\r  evaluation of the condition (while statement). \r\r
209   Case statement in LOGLAN-82 has the form:\r\r
210   case WA\r  \r
211     when L1 : I1\r    \r
212     when L2 : I2\r    \r
213        ...\r
214     when Lk : Ik\r    \r
215     otherwise  I\r    \r
216   esac\r  \r\r
217 where WA is an expression , L1,...,Lk are constants and I1,..., Ik,I are sequences of statements.\r\r
218  A case statement selects for execution a sequence of statements Ij, 1{SYMBOL 163 \f "Symbol"}j{SYMBOL 163 \f "Symbol"}k, where the value of WA equals Lj. The choice otherwise covers\r  all values (possibly none) not given in the previous choices. The execution of a case statement chooses one and only one alternative (since the choices are to be exhaustive and mutually exclusive).\r
219 2. Modularity\r\r
220  Modular structure of the language is gained due to the large set of means for module nesting and extending. Program modules (units) are blocks, procedures, functions, classes, coroutines and processes. Block is the simplest kind of unit. Its syntax is the following:\r\r
221   block\r  \r
222     lists of declarations\r
223   begin\r  \r
224     sequence of statements\r
225   end\r  \r\r
226  The sequence of statements commences with the keyword begin (it may\r  be omitted when this sequence is empty). The lists of declarations define the syntactic entities (variables, constants, other units), whose scope is that block. The syntactic entities are identified in the sequence of statements by means of names (identifiers).\r\r
227 \r
228 Example:\r\r
229   block\r  \r
230     const n=250;\r    \r
231     var x,y:real, i,j,k: integer, b: boolean;\r  \r
232     const m=n+1;\r    \r
233   begin\r  \r
234     read(i,j);            (* read two integers *)\r
235     x,y:=n/(i+j);         (* simultaneous assignment *)\r
236     read(c) ;             (* read a character *)\r
237     b:= c = 'a';          (* 'a'  a character *)\r
238     for k:= 1 to m\r  \r
239     do\r
240       write(x+y/k:10:4);  (* print the value of x+y/k in the\r
241         field of  10 characters, 4 digits after the point *)\r
242     od\r
243   end\r  \r\r
244  In the lists of declarations semicolons terminate the whole lists, not the lists elements. Any declaration list must begin with the pertinent keyword (var for variables, const for constants etc.). The\r  value of an expression defining a constant must be determinable statically (at compilation time).\r\r
245   Program in LOGLAN-82 may be  a block or alternatively may  be of the following form:\r\r
246    program name;\r   \r
247      lists of declarations\r
248    begin\r   \r
249      sequence of statements\r
250    end\r   \r\r
251  Then the whole program can be identified by that name (the source as well as the object code).\r\r
252  A block can appear in the sequence of statements (of any unit), thus it is a statement. (Main block is assumed to appear as a statement of the given job control language.)\r\r
253  For the execution of a block statement the object of block is created in a computer memory, and then, the sequence of statements is performed. The syntactic entities declared in the block are allocated in its object. After a block's termination its object is automatically deallocated (and the corresponding space may be immediately reused).\r\r
254  The modular structure of the language works "in full steam" when not only blocks, but the other kinds of units are also used. They will be described closer in the following points.\r\r
255  Unit nesting allows to build up hierarchies of units and supports security of programming. It follows from the general visibility rules; namely, a syntactic entity declared in an outer unit is visible in an inner one (unless hidden by an inner declaration). On the other hand, a syntactic entity declared in an inner unit is not visible from an outer one.\r\r\r
256
257 Example:\r\r
258   program test;\r  \r
259     var a,b,c:real, i,j,k:integer;\r \r
260   begin\r  \r
261     read(a,b,c,i);\r
262     block\r    \r
263       var j,k:real;\r \r
264     begin\r    \r
265       j:=a; k:=j+b; write(" this is the inner block ",j,k)\r
266     end;\r    \r
267     write(" this is the outer block ",i,a:20)\r
268   end;\r  \r\r
269  In this program, first the main block statement is executed (with variables a,b,c,i,j,k). Next, after the read statement, the inner block statement is executed (with variables j,k). In the inner block the global variables j,k are hidden by the local ones.\r\r
270 3. Procedures and functions\r\r
271  Procedures and functions are well-known kinds of units. Their syntax is modelled on Pascal's, though with some slight modifications. Procedure (function) declaration consists of a specification part and a body.\r\r   \r
272
273 Example:\r\r
274     unit Euclid: function(i,j:integer):integer;\r  \r
275     var k:integer;\r
276     begin\r    \r
277       do\r      \r
278         if j=0 then exit fi;\r \r
279         k:=i mod j; i:=j; j:=k\r  \r
280       od;\r      \r
281       result:=i\r
282     end;\r    \r\r
283  Procedure or function specification begins with its identifier preceded by the keyword unit. (The same syntax concerns any other\r module named unit.) Then follows its kind declaration, its formal parameters (if any), and the type of the returned value (only for functions). A body consists of declaration lists for local entities and a sequence of statements. The keyword begin commences the sequence of statements, and is omitted, if this sequence is empty. The value returned by a function equals to the most recent value of the standard variable "result", implicitly declared in any function. This variable can be used as a local auxiliary variable as well.\r\r
284 \r
285 Example:\r\r
286     unit Newton: function(n,m:integer):integer;\r   \r
287                 var i:integer; \r
288     begin\r    \r
289       if m > n then return fi;\r  \r
290       result:=n;\r
291       for i:=2 to m do result:=result*(n-i+1) div i od\r \r
292     end Newton;\r\r
293  The optional identifier at the end of a unit must repeat the identifier of a unit. It is suggested that the compilers check the order of unit nesting, so these optional occurrences of identifiers would facilitate program debugging.\r\r
294  All the local variables of a unit are initialized (real with 0.0, integer with 0, boolean with false etc.). Thus , for instance, the value of function Newton is 0 for m>n, since "result" is also initialized, as any other local variable.\r\r
295   The return statement (return) completes the execution of a procedure (function) body,i.e. return is made to the caller. If return does not\r appear explicitly, return is made with the execution of the final end\r of a unit. Upon return to the caller the procedure (function) object is deallocated.\r\r
296  Functions are invoked in expressions with the corresponding list of actual parameters. Procedures are invoked by call statement (also with the corresponding list of actual parameters).\r\r
297 \r
298 Example:\r\r
299     i:=i*Euclid(k,105)-Newton(n,m+1);\r
300     call P(x,y+3);\r  \r\r
301  Formal parameters are of four categories: variable parameters, procedure parameters, function parameters and type parameters (cf p.8). Variable parameters are considered local variables to the unit. A variable parameter has one of three transmission modes: input, output or inout. If no mode is explicitly given the input mode is assumed. For instance in the unit declaration:\r\r
302  unit P: procedure(x,y:real,b:boolean;\r
303             output c:char,i:integer;inout :integer);\r\r
304 x,y,b are input parameters , c,i are output parameters , and j is inout parameter.\r\r
305  Input parameter acts as a local variable whose value is initialized by the value of the corresponding actual parameter. Output parameter acts as a local variable initialized in the standard manner (real with 0.0, integer with 0, boolean with false etc.). Upon return its value is assigned to the corresponding actual parameter, in which case it must be a variable. However the address of such an actual parameter is determined upon entry to the body. Inout parameter acts as an input parameter and output parameter together.\r\r
306 \r
307 Example:\r\r
308   unit squareeq: procedure(a,b,c:real;output xr,xi,yr,yi:real);\r \r
309    (* given a,b,c the procedure solves  square equation :\r
310       ax*x+bx+c=0.\r
311        xr,xi- real and imaginary part of the first root\r
312        yr,yi- real and imaginary part of the second root *)\r
313   var delta: real;\r  \r
314   begin     (*a=/=0*)\r  \r
315     a:=2*a; c:=2*c; delta:=b*b-a*c;\r
316     if delta <= 0\r    \r
317     then\r    \r
318       xr,yr:=-b/a;\r
319       if delta=0 then  return fi;     (*xi=yi=0 by default*)\r  \r
320       delta:=sqrt(-delta);\r
321       xi:=delta/a; yi:=-xi;\r
322       return\r      \r
323     fi;\r    \r
324     delta:=sqrt(delta);\r
325     if b=0\r   \r
326     then\r    \r
327       xr:=delta/a; yr:=-xr;\r
328       return\r      \r
329     fi;\r    \r
330     if b>0 then b:=b+delta else b:=b-delta fi;\r
331     xr:=-b/a; yr:=-c/b;\r
332   end squareeq;\r\r
333   A procedure call to the above unit may be the following:\r\r
334   call squareeq(3.75*H,b+7,3.14,g,gi,h,hi); \r\r
335 where g,h,gi,hi are real variables.\r\r
336  No restriction  is imposed on the order of declarations. In particular, recursive procedures and functions can be declared without additional announcements (in contrast to Pascal).\r\r
337 Example:\r\r
338   For two recursive sequences defined as:\r\r
339         a(n)=b(n-1)+n+2         n>0\r
340   b(n)=a(n-1)+(n-1)*n     n>0\r
341   a(0)=b(0)=0\r\r
342 one can declare two functions:\r\r
343   unit a: function(n:integer):integer;\r
344   begin\r  \r
345     if n>0 then result:=b(n-1)+n+2 fi\r
346   end a;\r  \r
347   unit b: function(n:integer):integer; \r
348   begin\r  \r
349     if n>0 then result:=a(n-1)+(n-1)*n fi\r \r
350   end b;\r  \r\r
351 and invoke them:\r\r
352   k:=a(100)*b(50)+a(15);\r\r
353   Functions and procedures can be formal parameters as well.\r\r
354 \r
355 Example:\r\r
356 unit Bisec: procedure(a,b,eps:real;output x:real;function                                                                                                       f(x:real):real);\r
357 (*this procedures searches for zero of the continous function f in                                                                                              the segment (a,b) *)\r
358 var h:real,s:integer;\r
359 begin\r
360   s:=sign(f(a));\r
361   if sign(f(b))=s then return fi;   (* wrong segment *)\r  \r
362   h:=b-a;\r
363   do\r  \r
364     h:=h/2; x:=a+h;\r
365     if h < eps then  return fi;\r
366     if sign(f(x))=s then a:=x else b:=x fi\r
367   od\r  \r
368 end Bisec;\r\r
369 In the above declaration, after the input variable parameters a,b,eps and the output variable parameter x, a function parameter f appears. Note that its specification part is complete. Thus the check of actual-formal parameter compatibility is possible at compilation time. Making use of this syntactic facility is not possible in general, if a formal procedure (function) is again a formal parameter of a formal procedure (function). The second degree of formal procedures (functions) nesting is rather scarce, but LOGLAN-82 admits such a  construct. Then  formal  procedure (function)  has no specification part and the full check of actual-formal parameter compatibility is left to be done at run time.\r\r
370 \r
371 Example:\r\r
372   unit P: procedure(j:integer; procedure G (i:integer;\r
373                                          procedure H));\r
374     ...\r
375   begin\r  \r
376     ...\r
377     call G(j,P);\r
378   end P;\r   \r\r
379  Procedure G is a first degree parameter, therefore it occurs with complete specification part. Procedure H is a second degree parameter and has no specification part. In this case a procedure call can be strongly recursive:\r\r
380      call P(i+10,P);\r \r\r
381 4. Classes\r\r
382  Class is a facility which covers such programming constructs as structured type, package, access type, data structure etc. To begin with the presentation of this construct, let us consider a structured type assembled from primitive ones:\r\r
383   unit bill: class;\r
384      var  dollars           :real, \r
385           not_paid          :boolean,\r
386           year,month,day    :integer;\r
387   end bill;\r  \r\r
388  The above class declaration has the attributes : dollars (real), not_paid (boolean), and year,month,day (integer). Wherever class bill is visibile one can declare variables of type bill:\r\r
389     var x,y,z: bill;\r\r
390  The values of variables x, y, z can be the addresses of objects of class bill. These variables are called reference variables. With reference variable one can create and operate the objects of reference variable type.\r\r
391  An object of a class is created by the class generation statement (new), and thereafter, its attributes are accessed through dot\r notation.\r\r
392     x:=new bill; (* a new object of class bill is created *)\r
393     x.dollars:=500.5;  (* define amount *)\r
394     x.year:=1982;      (* define year *)\r
395     x.month:=3;        (* define month *)\r
396     x.day:=8;          (* define day *)\r
397     y:=new bill;       (* create a new object *)\r  \r
398     y.not_paid:=true;  (* bill not_paid *)\r
399     z:=y;       (* variable z points the same object as y *)\r\r
400  If an object of class bill has been created (new bill) and its\r address has been assigned to variable x (x:=new bill), then the\r attributes of that object are accessible through dot notation (remote access). The expression x.dollars gives , for instance, the remote access to attribute dollars of the object referenced by x. All attributes of class objects are initialized as usual. For the above example the object referenced by x, after the execution of the specified sequence of statements, has the following structure:\r\r
401 \r
402       ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
403       ³    500.5    ³     dollars\r
404       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
405       ³    false    ³     not_paid\r
406       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
407       ³    1982     ³     year\r
408       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
409       ³      3      ³     month\r
410       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
411       ³      8      ³     day\r
412       ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r\r
413 \r
414  The object referenced by y and z has the following structure:\r\r
415 \r
416       ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
417       ³      0      ³     dollars\r
418       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
419       ³    true     ³     not_paid\r
420       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
421       ³      0      ³     year\r
422       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
423       ³      0      ³     month\r
424       ÃÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
425       ³      0      ³     day\r
426       ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r\r
427   The value none is the default initial value of any reference\r variable and denotes no object. A remote access to an attribute of none raises a run time error. \r\r
428  Class may have also formal parameters (as procedures and functions). Kinds and transmission modes of formal parameters are the same as in the case of procedures.\r\r
429 \r
430 \r
431 \r
432 Example:\r\r
433     unit node: class (a:integer);\r
434      var left,right:node;\r  \r
435     end node; \r\r
436  Let, for instance, variables z1, z2, z3 be of type node. Then the sequence of statements:\r\r
437      z1:=new node(5);\r
438      z2:=new node(3);\r  \r
439      z3:=new node(7);\r \r
440      z1.left:=z2; z1.right:=z3;\r\r
441  creates the structure:\r\r
442 \r
443                    ÚÄÄÄÄÄÄÄÄÄ¿\r
444            z1ÄÄÄÄÄÄ´    5    ³\r
445                    ÃÄÄÄÄÄÄÄÄÄ´\r
446             ÚÄÄÄÄÄÄ´   left  ³\r
447             ³      ÃÄÄÄÄÄÄÄÄÄ´\r
448             ³      ³   right ÃÄÄÄÄÄÄÄÄ¿\r
449             ³      ÀÄÄÄÄÄÄÄÄÄÙ        ³\r
450             ³                         ³\r
451        ÚÄÄÄÄÁÄÄÄÄÄ¿             ÚÄÄÄÄÄÁÄÄÄÄ¿\r
452 z2ÄÄÄÄÄ´    3     ³             ³     7    ÃÄÄÄÄÄÄz3\r
453        ÃÄÄÄÄÄÄÄÄÄÄ´             ÃÄÄÄÄÄÄÄÄÄÄ´\r
454        ³   none   ³             ³    none  ³ \r
455        ÃÄÄÄÄÄÄÄÄÄÄ´             ÃÄÄÄÄÄÄÄÄÄÄ´\r
456        ³   none   ³             ³    none  ³ \r
457        ÀÄÄÄÄÄÄÄÄÄÄÙ             ÀÄÄÄÄÄÄÄÄÄÄÙ\r\r
458 \r
459 where arrows denote the values of the reference variables.\r\r
460  Class may also have a sequence of statements (as any other unit). That sequence can initialize the attributes of the class objects.\r\r
461 \r
462 Example:\r\r
463   unit complex:class(re,im:real);\r  \r
464   var module:real;\r \r
465   begin\r  \r
466     module:=sqrt(re*re+im*im)\r
467   end complex;\r  \r\r
468  Attribute module is evaluated for any object generation of class complex:\r\r
469   z1:=new complex(0,1); (* z1.module equals 1 *) \r
470   z2:=new complex(2,0); (* z2.module equals 2 *)\r  \r\r
471  For the execution of a class generator, first a class object is created, then the input parameters are transmitted , and finally, the sequence of statements (if any) is performed. Return is made with the execution of return statement or the final end of a unit. Upon return the output parameters are transmitted.\r\r
472  Procedure object is automatically deallocated when return is made to the caller. Class object is not deallocated , its address can be assigned to a reference variable, and its attributes can be thereafter accessed via this variable. \r\r
473  The classes presented so far had only variable attributes. In general, class attributes may be also other syntactic entities, such as  constants, procedures, functions, classes etc. Classes with procedure and function attributes provide a good facility to define data structures.\r\r
474 \r
475 Example:\r\r
476 A push_down memory of integers may be implemented in the following way:\r\r
477   unit push_down :class;\r  \r
478     unit elem:class(value:integer,next:elem);\r
479      (* elem - stack element *)\r
480     end elem;\r    \r
481     var top:elem;\r    \r
482     unit pop: function :integer;\r  \r
483     begin\r    \r
484       if top=/= none\r \r
485       then\r      \r
486         result:=top.value; top:=top.next\r
487       fi;\r      \r
488     end pop;\r    \r
489     unit push:procedure(x:integer); (* x - pushed integer *)\r
490     begin\r    \r
491       top:=new elem(x,top);\r
492     end push;\r    \r
493   end push_down;\r\r
494  Assume that somewhere in a program reference variables of type push_down are declared (of course, in place where push_down is visibile):\r\r
495   var s,t,z:push_down;\r  \r\r
496  Three different push_down memories may be now generated:\r\r
497   s:=new push_down(100); t:=new push_down(911); z:=new push_down(5);\r  \r\r
498  One can use these push_down memories as follows:\r\r
499   call s.push(7); (* push  7 to s *)\r  \r
500   call t.push(1); (* push  1 to t *)\r   \r
501   i:=z.pop;       (* pop an element from z *)\r
502   etc.\r\r
503 5. Adjustable arrays\r\r
504  In LOGLAN-82 arrays are adjustable at run time. They may be treated as objects of specified standard type with index instead of identifier selecting an attribute. An adjustable array should be declare somewhere among the lists of declarations and then may be generated in the sequence of statements.\r\r
505 \r
506 Example:\r\r
507  block\r \r
508   var n,j:integer;\r  \r
509   var A:arrayof integer;  (* here is the declaration of A *) \r
510  begin\r \r
511   read(n);\r
512   array A dim (1:n);   (* here is the generation of A *)\r \r
513   for i:=1 to n\r \r
514   do\r  \r
515    read(A(i));\r
516   od;\r  \r
517   (* etc.*)\r
518  end\r \r\r
519  A variable A is an array variable. Its value should be the reference to an integer array, i.e. a composite object consisting of integer components each one defined by an integer index.       \r
520 Array generation statement:\r\r
521          array A dim (1:n);\r  \r\r
522 allocates a one-dimensional integer array with the index bounds 1,n , and assigns its address to variable A.    \r
523 The figure below illustrates this situation:\r\r
524 \r
525         ÚÄÄÄÄÄÄÄÄ¿              ÚÄÄÄÄÄÄÄÄÄ¿\r
526         ³        ³              ³  A(1)   ³\r
527         ³        ³              ÃÄÄÄÄÄÄÄÄÄ´\r
528         ³   ...  ³              ³  A(2)   ³\r
529         ÃÄÄÄÄÄÄÄÄ´              ÃÄÄÄÄÄÄÄÄÄ´\r
530         ³    n   ³              ³         ³\r
531         ÃÄÄÄÄÄÄÄÄ´              ³   ...   ³\r
532         ³    j   ³              ³         ³\r
533         ÃÄÄÄÄÄÄÄÄ´              ÃÄÄÄÄÄÄÄÄÄ´\r
534         ³    A   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´   A(n)  ³\r
535         ÀÄÄÄÄÄÄÄÄÙ              ÀÄÄÄÄÄÄÄÄÄÙ\r
536           Block object             Array object\r\r
537 \r
538 A general case of array generation statement has the form:\r
539     array A dim (lower:upper)\r  \r\r
540 where lower and upper are arithmetic expressions which define the range of the array index.\r\r
541 Example:\r\r
542  Two-dimensional array declaration :\r\r
543    var A: arrayof arrayof integer;\r  \r\r
544 and generation:\r\r
545     array A dim (1:n)\r
546     for i:=1 to n do array A(i) dim (1:m) od;\r  \r\r
547 create the structure:\r
548                                     ÚÄÄÄÄÄÄÄÄ¿\r
549                                     ³ A(1,1) ³\r
550                                     ÃÄÄÄÄÄÄÄÄ´\r
551                                     ³        ³\r
552                                     ³   ...  ³\r
553                                     ³        ³\r
554          ÚÄÄÄÄÄÄÄÄÄÄ¿               ÃÄÄÄÄÄÄÄij\r
555          ³   A(1)   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ A(1,m) ³\r
556          ³ÄÄÄÄÄÄÄÄÄÄ´               ÀÄÄÄÄÄÄÄÄÙ\r
557          ³          ³\r
558          ³    ...   ³\r
559          ³          ³\r
560          ÃÄÄÄÄÄÄÄÄÄÄ´               ÚÄÄÄÄÄÄÄÄ¿\r
561          ³   A(n)   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ A(n,1) ³\r
562          ÀÄÄÄÄÄÄÄÄÄÄÙ               ÃÄÄÄÄÄÄÄÄ´\r
563                                     ³        ³\r
564                                     ³   ...  ³\r
565                                     ³        ³\r
566                                     ÃÄÄÄÄÄÄÄÄ´\r
567                                     ³ A(n,m) ³\r
568                                     ÀÄÄÄÄÄÄÄÄÙ\r\r
569 \r
570   block\r  \r
571     var i,j:integer, A,B: arrayof arrayof real, n:integer; \r
572   begin\r  \r
573     read(n);\r
574     array A dim (1:n);  \r
575     for i:=1 to n do array A(i) dim (1:n) od;\r  \r
576      (* A is square array *)\r
577     array B dim (1:n);\r  \r
578     for i:=1 to n do array B(i) dim(1:i) od; \r
579      (* B is lower triangular array *)\r
580     A(n,n):=B(n,n);\r
581     B(1):=A(1);\r
582     B(1):=copy(A(1)); \r
583   end\r  \r\r
584  Array A is the square array n by n. Each element A(i) , 1{SYMBOL 163 \f "Symbol"}i{SYMBOL 163 \f "Symbol"}n contains the address of row A(i,j), 1{SYMBOL 163 \f "Symbol"}j{SYMBOL 163 \f "Symbol"}n. Array B is the lower-triangular array. Each element B(i), 1{SYMBOL 163 \f "Symbol"}i{SYMBOL 163 \f "Symbol"}n, contains the address of row B(i,j), 1{SYMBOL 163 \f "Symbol"}j{SYMBOL 163 \f "Symbol"}i. Thus an assignment statement A(n,n):=B(n,n) transmits real value B(n,n) to real variable A(n,n). Assignment B(1):=A(1) transmits the address of the first row of A to variable B(1). Finally assignment B(1):=copy (A(1)) creates a copy of\r the first row of A and assigns its address to B(1).\r\r
585  Upper and lower bounds of an adjustable array A are determined by standard operators lower(A) and upper(A).\r\r
586 \r
587 Example:\r\r
588   unit sort: procedure(A:arrayof integer);\r
589    (*  insertion sort *) \r
590     var n,i,j:integer; var x:integer; \r
591   begin\r  \r
592     n:=upper(A);              (* assume lower bound is 1 *)\r
593     for i:=2 to n\r    \r
594     do\r    \r
595       x:=A(i); j:=i-1;\r
596       do\r      \r
597         if x >= A(j) then exit fi;\r  \r
598         A(j+1):=A(j);  j:=j-1;\r
599         if j=0 then exit fi;\r
600       od;\r      \r
601       A(j+1):=x\r
602     od;\r    \r
603   end sort;\r  \r\r
604   If an array variable A refers to no array its value is equal none\r (the standard default value of any array variable). An attempt to access an array element (e.g. A(i)) or a bound (e.g. lower(A)), where A is none, raises a run time error.\r\r
605 6. Coroutines and semicoroutines\r\r
606  Coroutine is a generalization of class. A coroutine object is an object such that the execution of its sequence of statements can be suspended and reactivated in a programmed manner. Consider first a simple class with a sequence of statements such that after return some\r non-executed  statements remain. The generation of  its  object terminates with the execution of return statement, although the object can be later reactivated. If such a class is declared as a coroutine, then its objects may be reactivated. This can be realized by attach\r statement:\r\r
607   attach(X)\r  \r\r
608 where X is a reference variable designating the activating coroutine object.\r\r
609  In general, since the moment of generation a coroutine object is either active or suspended. Any reactivation of a suspended coroutine object X (by attach(X)) causes the active coroutine object to be\r  suspended and continues the execution of X from the statement following the last executed one.\r\r
610 Main program is also a coroutine. It is accessed through the standard variable main and may be reactivated (if suspended) by the\r statement     attach(main).\r \r\r
611 \r
612 Example:\r\r
613 In the example below the cooperation of two coroutines is presented. One reads the real values from an input device, another prints these values in columns on a line-printer, n numbers in a line. The input stream ends with 0.\r\r
614 program prodcons;\r
615   var prod:producer,cons:consumer,n:integer,mag:real,last:bool;  \r
616   unit producer: coroutine; \r
617   begin\r  \r
618     return;\r    \r
619     do\r    \r
620       read(mag);  (* mag- nonlocal variable, common store *)\r
621       if mag=0\r      \r
622       then             (* end of data *)  \r
623         last:=true;\r
624         exit\r        \r
625       fi;\r      \r
626       attach(cons);\r      \r
627     od;\r    \r
628     attach(cons)\r    \r
629   end producer;\r \r\r
630   unit consumer: coroutine(n:integer); \r
631   var Buf:arrayof real; \r
632   var i,j:integer;\r  \r
633   begin\r  \r
634     array Buf dim(1:n); \r
635     return;\r    \r
636     do\r    \r
637       for i:=1 to n\r      \r
638       do\r      \r
639         Buf(i):=mag;\r
640         attach(prod);\r        \r
641         if last then exit exit fi; \r
642       od;\r      \r
643       for i:=1 to n\r \r
644       do     (* print Buf *)\r  \r
645         write(' ',Buf(i):10:2)\r
646       od;\r      \r
647       writeln;\r
648     od;\r    \r
649     (* print the rest of Buf *)\r
650     for j:=1 to i do write(' ',Buf(j):10:2) od;\r  \r
651     writeln;\r
652     attach(main);\r    \r
653   end consumer;\r  \r\r
654  begin\r \r
655     prod:=new producer;\r          \r
656     read(n);\r
657     cons:=new consumer(n);\r   \r
658     attach(prod);\r    \r
659     writeln;\r
660  end prodcons;\r \r\r
661  The above task could be programmed without coroutines at all. The presented solution is, however, strictly modular, i.e. one unit realizes the input process, another realizes the output process, and both are ready to cooperate with each other.\r\r
662  LOGLAN-82  provides also  a facility for  the  semi-coroutine operations. This is gained by the simple statement detach. If X is the active coroutine object, then detach reactivates that coroutine object\r at where the last attach(X) was executed. This statement meets the\r need for the asymetric coroutine cooperations. (by so it is called semi-coroutine operation). Operation attach requires a reactivated coroutine to be defined explicitly by the user as an actual parameter. Operation detach corresponds in some manner to return in procedures. It gives the control back to a coroutine object where the last attach(X) was executed, and that coroutine object need not be known explicitly in X. This mechanism is, however, not so secure as the normal control transfers during procedure calls and returns.\r\r
663  In fact, the user is able to loop two coroutines traces by :\r\r
664    attach(Y) in X\r       attach(X) in Y\r   \r\r
665 Then detach in X reactivates Y, detach in Y reactivates X. \r\r
666  In the example below the application of detach statement is illustrated.\r\r
667 Example:\r\r
668 program reader_writers; \r
669 (* In this example a single input stream consisting of blocks of numbers, each ending with 0, is printed on two printers of different width. The choice of the printer is determined by the block header which indicates the desired number of print columns. The input stream ends with a double 0. m1 - the width of printer_1, m2 - the width of printer_2 *)\r
670  const m1=10,m2=20;\r              \r
671  var reader:reading,printer_1,printer_2:writing;\r                                             \r
672  var n:integer,new_sequence:boolean,mag:real;\r                                         \r
673  \r
674    unit writing:coroutine(n:integer);\r   \r
675       var Buf: arrayof real, i,j:integer;\r  \r
676    begin\r  \r
677      array Buf dim (1:n);      (* array  generation *)\r      \r
678      return;(* return terminates coroutine initialization *)\r    \r
679      do\r \r
680        attach(reader);   (* reactivates coroutine reader *)\r
681        if new_sequence\r       \r
682        then \r
683      (* a new sequence causes buffer Buf to be cleared up *)\r
684          for j:=1 to i do write(' ',Buf(j):10:2) od;\r
685          writeln;\r
686          i:=0; new_sequence:=false;  attach(main)\r  \r
687        else\r \r
688          i:=i+1;   Buf(i):=mag;\r
689          if i=n\r \r
690          then\r \r
691            for j:=1 to n do write(' ',Buf(j):10:2) od;\r
692            writeln;\r
693            i:=0;\r
694          fi\r \r
695        fi\r \r
696      od\r \r
697    end writing;\r \r\r
698    unit reading: coroutine;\r \r
699    begin\r \r
700      return;\r \r
701      do\r \r
702        read(mag);\r
703        if mag=0  then  new_sequence:=true;   fi;\r \r
704        detach;\r
705          (* detach returns control to printer_1 or printer_2                                                     depending which one reactivated the reader *)\r
706      od\r \r
707    end reading;\r \r\r
708    begin\r \r
709      reader:=new reading;\r \r
710      printer_1:=new writing(m1); printer_2:=new writing(m2);\r
711      do\r \r
712        read(n);\r
713        case n\r \r
714          when 0:  exit\r \r
715          when m1: attach(printer_1)\r  \r
716          when m2: attach(printer_2)\r  \r
717          otherwise  write(" wrong data"); exit\r \r
718        esac\r \r
719      od\r   \r
720    end;\r   \r\r
721 \r\r
722  Coroutines play the substantial role in process simulation. Class Simulation provided in Simula-67 makes use of coroutines at most degree. LOGLAN-82 provides for easy simulation as well. The LOGLAN-82 class Simulation is implemented on a heap what gives lg(n) time cost (in contrast with O(n) cost of the original implementation). It covers also various simulation  problems of large size and degree of complexity.\r\r
723 7. Prefixing\r\r
724  Classes and prefixing are ingenius inventions of Simula-67(cf [1]). Unfortunately they were hardly ever known and, perhaps, by this have not been introduced into many programming language that gained certain popularity. Moreover, implementation constraints of Simula-67 bind prefixing and classes workableness to such a degree that both facilities cannot be used in all respects. We hope that LOGLAN-82, adopting merits and rooting up deficiencies of these constructs, will smooth their variations and vivify theirs usefulness.\r\r
725  What is prefixing ? First of all it is a method for unit extending. Consider the simplest example:\r\r
726   unit bill: class;\r \r
727      var\r   dollars           :real,\r
728            not_paid          :boolean,\r
729            year,month,day    :integer;\r
730   end bill;\r \r\r
731 Assume the user desires to extend this class with new attributes. Instead of writing a completely new class, he may enlarge the existing one:\r\r
732   unit gas_bill:bill class;\r \r
733     var cube_meters: real;\r \r
734   end gas_bill;\r \r\r
735  Class gas_bill is prefixed by class bill. This new declaration may appear anywhere within the scope of declaration of class bill. (In Simula-67 such a prefixing is forbidden in nested units.) Class gas_bill has all the attributes of class bill and additionally its own attributes (in this case the only one: cube_meters). The generation statement of this class has the form:\r\r
736 z:=new gas_bill;\r \r\r
737 where z is a reference variable of type gas_bill. Remote access to the attributes of prefixed class is standard:\r\r
738 z.dollars:=500.5; z.year:=1982; z.month:=3; z.day:=8;\r
739 z.cube_meters:=100000;\r\r
740 \r
741 Consider now the example of a class with parameters.\r\r
742 Assume that in a program a class:\r\r
743 unit id_card: class(name:string,age:integer);\r \r
744 end id_card;\r \r\r
745 and its extension:\r\r
746 unit idf_card:id card class(first name:string);\r \r
747 end idf_card;\r \r\r
748 are declared.\r\r
749  Then for variable z of type id_card and variable t of type idf_card the corresponding generation statement may be the following:\r\r
750    z:=new id_card("kreczmar",37);\r \r
751    t:=new idf_card("Kreczmar",37,"Antoni");\r \r\r
752 Thus the formal parameters of a class are concatenated with the formal parameters of its prefix.\r\r
753 One can still extend class idf_card. For instance:\r\r
754   unit idr_card:idf_card class;\r \r
755     var children_number:integer;\r \r
756     var birth_place:string;\r \r
757   end idr_card;\r \r\r
758  Prefixing allows to build up hierarchies of classes. Each one hierarchy has a tree structure. A root of such a tree is a class without prefix. One class is a successor of another class iff the first is prefixed by the latter one.\r\r
759 \r
760  Consider the prefix structure:\r\r
761                    A\r
762                  . . .\r
763                 .  .  .\r
764                .   .   .\r
765              B.    .C   .D\r
766                .\r
767                 .\r
768                  .E\r
769                   .\r
770                    .\r
771                     .F\r
772                    . .\r
773                   .   .\r
774                 G.     .H\r\r
775  Class H has a prefix sequence A, B, E, F, H. Let a, b, ... , h denote the corresponding unique attributes of classes A, B, ... , H, respectively. The objects of these classes have the following forms: \r\r
776 \r\r
777       ÚÄÄÄÄÄÄÄÄÄÄ¿  ÚÄÄÄÄÄÄÄÄÄÄ¿  ÚÄÄÄÄÄÄÄÄÄÄ¿  ÚÄÄÄÄÄÄÄÄÄÄ¿\r
778       ³     a    ³  ³     a    ³  ³     a    ³  ³     a    ³\r
779       ÀÄÄÄÄÄÄÄÄÄÄÙ  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´\r
780        object A     ³     b    ³  ³     c    ³  ³     d    ³\r
781                     ÀÄÄÄÄÄÄÄÄÄÄÙ  ÀÄÄÄÄÄÄÄÄÄÄÙ  ÀÄÄÄÄÄÄÄÄÄÄÙ\r
782                       object B      object C      object D\r\r
783       ÚÄÄÄÄÄÄÄÄÄÄ¿  ÚÄÄÄÄÄÄÄÄÄÄ¿  ÚÄÄÄÄÄÄÄÄÄÄ¿  ÚÄÄÄÄÄÄÄÄÄÄ¿\r
784       ³     a    ³  ³     a    ³  ³     a    ³  ³     a    ³\r
785       ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´\r
786       ³     b    ³  ³     b    ³  ³     b    ³  ³     b    ³\r
787       ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´\r
788       ³     e    ³  ³     e    ³  ³     e    ³  ³     e    ³\r
789       ÀÄÄÄÄÄÄÄÄÄÄÙ  ³ÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´\r
790        object E     ³     f    ³  ³     f    ³  ³     f    ³\r
791                     ÀÄÄÄÄÄÄÄÄÄÄÙ  ÃÄÄÄÄÄÄÄÄÄÄ´  ÃÄÄÄÄÄÄÄÄÄÄ´\r
792                       object F    ³     g    ³  ³     h    ³\r
793                                   ÀÄÄÄÄÄÄÄÄÄÄÙ  ÀÄÄÄÄÄÄÄÄÄÄÙ\r
794                                                                 object G      object H\r\r
795 \r
796 Let Ra, Rb,..., Rh denote reference variables of types A, B,..., H, respectively. Then the following expressions are correct:\r\r
797   Ra.a,  Rb.b, Rb.a,  Rg.g, Rg.f, Rh.h, Rh.f, Rh.e, Rh.b, Rh.a  etc.\r\r
798 Variable Ra may designate the object of class B (or C,..., H), i.e. the statement:\r\r
799    Ra:=new B\r    \r\r
800 is legal. But then attribute b is not accessible through dot via Ra, i.e. Ra.b is incorrect. This follows from insecurity of such a remote access. In fact, variable Ra may point any object of a class prefixed by A, in particular, Ra may point the object of A itself, which has no attribute b. If Ra.b had been correct, a compiler should have distiguish the cases Ra points to the object of A or not. But this, of course, is undistinguishable at compilation time.\r\r
801  To allow, however, the user's access to attribute b (after instruction Ra:=new B), the instantaneous type modification is provided within the language:\r\r
802    Ra qua B\r \r\r
803  The correctness of this expression is checked at run time. If Ra designates an object of B or prefixed ba B, the type of the expression is B. Otherwise the expression is erroneous. Thus, for instance, the expressions:\r\r
804    Ra qua G.b,    Ra qua G.e    etc.\r \r\r
805 enable remote access to the attributes b, c, ... via Ra.\r\r
806  So far the question of attribute concatenation was merely discussed. However the sequences of statements can be also concatenated.\r\r
807  Consider class B prefixed with class A. In the sequence of statements of class A the keyword inner may occur anywhere, but only once. The sequence of statements of class B consists of the sequence of statements of class A with inner replaced by the sequence of\r statements of class B.\r\r
808 \r
809     unit A :class                    unit B:A class\r \r
810         ...                                   ...\r
811     begin                               begin\r  \r
812        ...                             ÚÄÄÄ...\r
813                                        ³                                 inner   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ inner\r \r
814                                        ³\r
815        ...                             ÀÄÄÄ...\r
816     end A;                              end B;\r    \r\r\r
817    \r\r
818
819  In this case inner in class B is equivalent to the empty statement.\r If class B prefixes another class, say C, then inner in B is replaced\r by the sequence of statements of class C, and so on.  If inner does not occur explicitly, an implicit occurrence of inner\r before the final end of a class is assumed.\r \r\r
820 \r
821 Example\r\r
822  Let class complex be declared as usual:\r\r
823   unit complex: class(re,im:real);\r  \r
824   end complex;\r \r\r
825 and assume one desires to declare a class mcomplex with the additional attribute module. In order the generation of class mcomplex define the value of attribute module, one can declare a class:\r\r
826   unit mcomplex:complex class;\r \r
827   var module:real;\r \r
828   begin\r \r
829     module:=sqrt(re*re+im*im)\r
830   end mcomplex;\r \r\r
831  Class mcomplex may be still extended:\r\r
832   unit pcomplex:mcomplex class;\r \r
833     var alfa:real;\r \r
834   begin\r \r
835     alfa:=arccos(re/module)\r
836   end pcomplex;\r \r\r
837  For these declarations each generation of class mcomplex defines the value of attribute module, each generation of class pcomplex defines the values of attributes module and alfa.\r\r
838  For reference variables z1, z2 z3 of type complex, the following sequence of statements illustrates the presented constructs:\r\r
839   z1:=new complex(0,1);\r      \r
840   z2:=new mcomplex(4,7);\r \r
841   z3:=new pcomplex(-10,12);\r \r
842   if z2 qua mcomplex.module > 1\r                  \r
843   then\r \r
844       z1:=z2;\r
845   fi;\r \r
846   if z3 qua pcomplex.alfa < 3.14\r  \r
847   then\r  \r
848      z3.re:=-z3.re;  z3.alfa:=z3.alfa+3.14;\r
849   fi;\r \r
850   z1 qua mcomplex.module:= 0;\r  \r
851   z1.re,z1.im:=0;                                \r\r
852 Example:\r\r
853  Binary search tree (Bst) is a binary tree where for each node x the nodes in the left subtree are less than x, the nodes in the right subtree are greater than x. It is the well-known exercise to program the algorithms for the following operations on Bst:         \r
854         member(x) = true iff x belongs to Bst\r
855         insert(x),  enlarge Bst with x, if x does not yet belong to Bst\r\r
856 We define both these operations in a class:\r\r
857   unit Bst: class;\r \r
858     unit node: class(value:integer);  (*  tree node  *)\r  \r
859       var left,right:node;\r \r
860     end node;\r \r
861     var root:node;\r \r
862     unit help: class(x:integer);      (* auxiliary class *)\r \r
863       var p,q:node;\r \r
864     begin\r  \r
865        q:=root;\r
866        while q=/= none\r \r
867        do\r \r
868          if x < q.value\r    \r
869          then\r \r
870            p:=q; q:=q.left;\r
871            repeat  (* jump to the beginning of a loop *)\r   \r
872          fi;\r \r
873          if q.value < x\r \r
874          then\r \r
875            p:=q; q:=q.right;  repeat\r \r
876          fi;\r \r
877          exit\r \r
878        od;\r \r
879        inner\r
880        (* virtual instruction to beÿreplaced\r by the body of\r
881          a module prefixed by help  *)\r
882     end help;\r \r
883     unit member:help function:boolean;\r \r
884   (* x is a formal parameter derived from the prefix help *)\r
885     begin\r \r
886        result:=q=/=none\r \r
887     end member;\r \r
888     unit insert:help procedure;\r \r
889   (* x is a formal parameter derived from the prefix help *)\r
890     begin\r   \r
891        if q=/=none then return fi;\r  \r
892        q:=new node(x);\r \r
893        if p=none then root:=q; return fi;\r \r
894        if p.value < x then p.right:=q else p.left:=q fi;\r \r
895     end insert;\r \r
896   begin\r \r
897     inner;\r \r
898   end Bst;\r \r\r
899  In the example the common actions of member and insert are programmed in class help. Then it suffices to use class help as a prefix of function member and procedure insert, instead of redundant occurrences of the corresponding sequence of statements in both units. \r\r
900 Class Bst may be applied as follows:\r\r
901   var X,Y:Bst;\r \r
902   begin\r \r
903        X:=new Bst;  Y:=new Bst;\r \r
904        call X.insert(5);\r \r
905        if Y.member(-17) then ....\r \r
906   end\r \r\r
907  As shown in the declaration of Bst, class may prefix not only other classes but also procedures and functions. Class may prefix blocks as well.\r\r
908 \r
909 Example:\r\r
910  Let class push_down (p. 5) prefix a block:\r\r
911    pref push_down(1000) block\r \r
912    var ...\r  \r
913    begin\r \r
914       ...\r
915       call push(50); ...\r  \r
916       i:=pop;\r
917       ...\r
918    end\r  \r\r
919  In the above block prefixed with class push_down one can use pop and push as local attributes. (They are local since the block is embedded in the prefix push down.)\r\r
920 \r
921 Example:\r\r
922    pref push down(1000) block\r \r
923    begin\r \r
924       ...\r
925       pref Bst block\r \r
926       begin\r \r
927       (* in this block both structures\r
928             push down and Bst are visible *)\r
929         call push(50);\r \r
930         call insert(13);\r \r
931         if member(10) then ...\r \r
932         i:=pop;\r
933         ...\r
934       end\r \r
935    end\r   \r\r
936  In place where classes push_down and Bst are visible together a block prefixed with Bst may be nested in a block prefixed with push_down (or vice versa). In the inner block both data structures are directly accessible. Note that this construct is illegal in Simula 67. \r\r
937 8. Formal types\r\r
938 Formal types serve for unit parametrization with respect to any non-primitive type.\r\r
939 Example:\r\r
940   unit Gsort:procedure(type T; A:arrayof T; function less\r
941                                                          (x, y: T): boolean);\r
942   var n,i,j:integer; var x:T;\r \r
943   begin\r  \r
944     n:=upper(A);\r
945     for i:=2 to n\r \r
946     do\r   \r
947       x:=A(i); j:=i-1;\r
948       do\r \r
949         if less(A(j),x) then exit fi;\r   \r
950         A(j+1):=A(j); j:=j-1;\r
951         if j=0 then exit fi;\r
952       od;\r \r
953       A(j+1):=x;\r
954     od\r \r
955   end Gsort;\r \r\r
956 Procedure Gsort (the generalization of procedure sort from p.4) has type parameter T. A corresponding actual parameter may be an arbitrary non-primitive type. An actual parameter corresponding to A should be an array of elements of the actual type T. Function less should define the linear ordering on the domain T.\r\r
957  For instance, the array A of type bill (cf p.7) may be sorted with respect to attribute dollars , if the function:\r\r
958   unit less: function(t,u:bill):boolean;\r \r
959   begin\r \r
960     result:=t.dollars <= u.dollars\r
961   end less;\r
962 is used as an actual parameter:\r\r
963   call Gsort(bill,A,less);\r \r\r
964 If the user desires to sort A with respect to date, it is sufficient to declare :\r\r
965   unit earlier:function(t,u:bill):boolean;\r \r
966   begin\r \r
967     if t.year < u.year then result:= true; return  fi;\r \r
968     if t.year=u.year\r  \r
969     then\r \r
970       if t.month < u.month then result:=true; return fi;\r \r
971       if t.month=u.month then result:=t.day<=u.day  fi\r \r
972     fi;\r \r
973    end earlier;\r \r\r
974 and to call: call Gsort(bill,A,earlier);\r \r\r
975 9. Protection techniques\r\r
976  Protection techniques ease secure programming. If a program is large, uses some system classes, is designed by a team etc., this is important (and non-trivial) to impose some restrictions on access to non-local attributes.\r\r
977  Let us consider a data structure declared as a class. Some of its attributes should be accessible for the class users, the others should not. For instance, in class Bst (p.7) the attributes member and insert are to be accessible. On the other hand the attributes root, node and help should not be accessible, even for a meddlesome user. An improper use of them may jeopardize the data structure invariants.\r\r
978  To forbid the access to some class attributes the three following protection mechanisms are provided:\r\r
979   close, hidden, and taken.\r \r\r
980  The protection close defined in a class forbids remote access to the\r specified attributes. For example, consider the class declaration:\r\r
981   unit A: class;\r \r
982     close x,y,z;\r \r
983     var  x: integer, y,z:real;\r \r
984     ....\r
985   end A\r \r\r
986 Remote access to the attributes x,y,z from outside of A is forbidden.\r\r
987 The protection hidden (with akin syntax) does not allow to use the\r specified attributes form outside of A neither by the remote access nor in the units prefixed by A. The only way to use a hidden attribute is to use it within the body of class A.\rProtection taken defines these attributes derived from prefix, which\r the user wishes to use in the prefixed unit. Consider a unit B prefixed by a class A. In unit B one may specify the attributes of A which are used in B. This protects the user against an unconscious use of an attribute of class A in unit B (because of identifier conflict). When taken list does not occur, then by default, all non-hidden attributes of class A are accessible in unit B. \r\r
988 10. Programmed deallocation\r\r
989   The classical methods implemented to deallocate class objects are based on reference counters or garbage collection. Sometimes the both methods may be combined. A reference counter is a system attribute holding the number of references pointing to the given object. Hence any change of the value of a reference variable X is followed by a corresponding increase or decrease of the value of its reference counter. When the reference counter becomes equal 0, the object can be deallocated.\r\r
990  The deallocation of class objects may also occur during the process of garbage collection. During this process all unreferenced objects are found and removed (while memory may be compactified). In order to keep the garbage collector able to collect all the garbage, the user should clear all reference variables , i.e. set to None, whenever possible. This system has many disadvantages. First of all, the programmer is forced to clear all reference variables, even those which are of auxiliary character. Moreover, garbage collector is a very expensive mechanism and thus it can be used only in emergency cases.\r\r
991  In LOGLAN a dual operation to the object generator, the so-called object deallocator is provided. Its syntactic form is as follows:\r\r
992            kill(X)\r  \r\r
993 where X is a reference expression. If the value of X points to no object (none) then kill(X) is equivalent to an empty statement. If the\r value of X points to an object O, then after the execution of kill(X),\r the object O is deallocated. Moreover all reference variables which pointed to O are set to none. This deallocator provides full security,\r i.e. the attempt to access the deallocated object O is checked and results in a run-time error.\r\r
994   For example:\r\r
995       Y:=X;  kill(X);   Y.W:=Z;\r \r\r
996 causes the same run-time error as:\r\r
997       X:=none;  X.W:=Z;\r \r\r
998  The system of storage management is arranged in such a way that the frames of killed objects may be immediately reused without the necessity of calling the garbage collector, i.e. the relocation is performed automatically. There is nothing for it but to remember not to use remote access to a killed object. (Note that the same problem appears when remote access X.W is used and X=none).\r  \r\r
999 \r
1000 \r
1001 \r
1002 Example:\r\r
1003  Below a practical  example of the programmed deallocation is presented. Consider class Bst (p.7). Let us define a procedure that deallocates the whole tree and is called with the termination of the class Bst.\r\r
1004   unit Bst:class;\r \r
1005     (* standard declarations list of  Bst *)\r
1006    unit kill_all:procedure(p:node);\r \r
1007    (* procedure kill_all deallocates a tree with root p *)\r
1008    begin\r \r
1009      if p= none then return fi;\r \r
1010      call kill_all(p.left);\r \r
1011      call kill_all(p.right);\r  \r
1012      kill(p)\r \r
1013    end kill_all;\r \r
1014    begin\r \r
1015      inner;\r \r
1016      call kill_all(root)\r  \r
1017   end Bst;\r      \r\r
1018 Bst may be applied as a prefix:\r\r
1019   pref Bst block\r \r
1020     ...\r
1021   end\r \r\r
1022 and automatically will cause the deallocation of the whole tree after return to call kill_all(root) from the prefixed block.\r \r\r
1023  To use properly this structure by remote accessing one must call kill_all by himself:\r\r
1024   unit var X,Y:Bst;\r \r
1025     ...\r
1026   begin\r \r
1027      X:=new Bst;  Y:=new Bst;\r \r
1028         ...\r
1029      (* after the structures' application *)\r
1030      call X.kill_all(X.root);\r  \r
1031      kill(X);\r \r
1032      call Y.kill_all(Y.root);\r \r
1033      kill(Y);\r \r
1034      ...\r
1035   end\r \r\r
1036  Finally note that deallocator kill enables deallocation of array\r objects, and suspended coroutines and processes as well (cf p.13). \r\r
1037 11.  Exception handling\r\r
1038  Exceptions are events that cause interruption of normal program execution. One kind of exceptions are those which are raised as a result of some run time errors. For instance, when an attempt is made to access a killed object, when the result of numeric operation does not lie within the range, when the dynamic storage allocated to a program is exceeded etc.\r\r
1039  Another kind of exceptions are those which are raised explicitly by a user (with the execution of the raise statement).\r\r
1040  The response to exceptions (one or more) is defined by an exception handler. A handler may appear at the end of declarations of any unit. The corresponding actions are defined as sequences of statements preceded by keyword when and an exception identifier.\r \r\r
1041 Example:\r\r
1042  In procedure squareeq (p.3) we wish to include the case when a=0. It may be treated as an exception (division by zero).\r\r
1043   unit squareeq(a,b,c:real;output xr,xi,yr,yi:real);\r \r
1044      var delta:real;\r \r
1045      handlers\r \r
1046        when division_by_zero:\r \r
1047        if b =/= 0\r     \r
1048        then\r  \r
1049          xi,yr,yi:=0; xr:=-c/b; terminate\r \r
1050        else\r  \r
1051          raise Wrong_data(" no roots")\r \r
1052        fi; \r
1053   end\r \r
1054   begin\r \r
1055     ...\r
1056   end squareeq;\r \r\r
1057  The handler declared in that procedure handles the only one exception (division_by_zero).\r\r
1058  When an exception is raised, the corresponding handler is searched for, starting from the active object and going through return traces. If there is no object containing the declaration of the handler, then the program (or the corresponding process) is terminated. Otherwise the control is transferred to the first found handler. \r\r
1059  In our example the handler is declared within the unit itself, so control is passed to a sequence:\r\r
1060   if b=/=0\r    ...\r\r
1061  Therefore, when b=/=0, the unique root of square equation will be determined and the procedure will be normally terminated (terminate).\r   In general, terminate causes that all the objects are terminated,\r starting from that one where the exception was raised and ending on that one where the handler was found. Then the computation is continued in a normal way.\r\r
1062  In our example, when b=0, a new exception is raised by the user. For this kind of exceptions , the exception itself should be declared (because it is not predefined as a run time error). Its declaration may have parameters which are transmitted to a handler. The exception declaration need not be visible by the exception handler. However the way the handler is searched for does not differ from the standard one.  Consider an example:\r\r
1063   block\r
1064    signal Wrong_data(t:string);\r                       \r
1065    unit squareeq: \r
1066         ...\r
1067    end squareeq;\r
1068    ...\r
1069   begin\r \r
1070       ...\r
1071   end\r \r\r
1072  Exception Wrong_data may be raised wherever its declaration (signal\r Wrong_data) is visible. When its handler is found the specified sequence of actions is performed. In the example above different handlers may be defined in inner units to the main block where squereeq is called.\r\r
1073  The case a=0 could be included , of course, in a normal way, i.e. by a corresponding conditional statement occurring in the procedure body. But the case a=0 was assumed to be exceptional (happens scarcely). Thus the evaluation of condition a=0 would be mostly unnecessary. As can be noticed thanks to exceptions the above problem can be solved with the minimal waste of run time. \r\r
1074 12. Concurrent processes.\r\r
1075    Loglan allows to create and execute objects-processes. They can operate simultaneously on different computers linked into a LAN network or a few processes can share one processor (its time-slices).\r\r
1076    Process modules are different from the classes and coroutines for, they use the keyword process. The syntax of process modules is otherwise the same. In a process one can use a few more instructions: resume (resume a process which is passive), stop - make the current process passive, etc.  \r\r
1077  All processes (even those executed on the same computer) are implemented as distributed, i.e. without any shared memory. This fact implies some restrictions on how processes may be used. Not all restrictions are enforced by the present compiler, so it is the programmer's responsibility to respect them. For the details see the User's Manual.\r\r
1078   Semantics of the generator new is slightly modified when applied to the processes. The first parameter of the first process unit in the prefix sequence must be of type INTEGER. This parameter denotes the node number of the computer on which this process will be created. For a single computer operation this parameter must be equal to 0.\r\r
1079 \r
1080 Example:\r\r
1081 unit A:class(msg:string);\r
1082 ...\r
1083 end A;\r
1084 unit P:A process(node:integer, pi:real);\r
1085 ...\r
1086 end P;\r
1087 ...\r
1088 var x:P;\r
1089 ...\r
1090 begin\r
1091 ...\r
1092  (* Create process on node  4.  The  first  parameter  is  the  *) \r
1093  (*string required by the prefix A, the second is the node number *)\r
1094  x := new P("Hello", 4, 3.141592653);\r
1095 ...\r
1096 end\r\r
1097 \r
1098 \r
1099 \r
1100   COMMUNICATION MECHANISM\r
1101 \r\r
1102 Processes may communicate and synchronize by a mechanism based on rendez-vous. It will be referred to as "alien call" in the following description.\r\r
1103         An alien call is either:        \r
1104   - a procedure  call performed by a remote access to a process object, or      \r
1105   - a call of a procedure which is a formal parameter of a process,  or \r
1106   - a call of a procedure which is a formal parameter of an alien-called procedure (this is a recursive definition).\r\r
1107 Every process object has an enable mask. It is defined as a subset of all procedures declared directly inside a process unit or any unit from its prefix sequence (i.e. subset of all procedures that may be alien-called).\r\r
1108 A procedure is enabled in a process if it belongs to that process' enable mask. A procedure is disabled if it does not belong to the enable mask. \r\r
1109 Immediately after generation of a process object its enable mask is empty (all procedures are disabled).\r\r
1110 Semantics of the alien call is different from the remote call described in the report. Both the calling process and the process in which the procedure is declared (i.e. the called process) are involved in the alien call. This way the alien call may be used as a synchronization mechanism.\r\r
1111 The calling process passes the input parameters and waits for the call to be completed.\r\r
1112 The alien-called procedure is executed by the called process. Execution of the procedure will not begin before certain conditions are satisfied. First, the called process must not be suspended in any way. The only exception is that it may be waiting during the ACCEPT statement (see below). Second, the procedure must be enabled in the called process.\r\r
1113 When the above two conditions are met the called process is interrupted and forced to execute the alien-called procedure (with parameters passed by the calling process).\r\r
1114 Upon entry to the alien-called procedure all procedures become disabled in the called process.\r\r
1115   Upon exit the enable mask of the called process is restored to that from before the call (regardless of how it has been changed during the execution of the procedure). The called process is resumed at the point of the interruption. The execution of the ACCEPT statement is ended if the called process was waiting during the ACCEPT (see below). At last the calling process reads back the output parameters and resumes its execution after the call statement.\r\r
1116   The process executing an alien-called procedure can easily be interrupted by another alien call if the enable mask is changed.\r\r
1117   There are some new language constructs associated with the alien call mechanism. The following statements change the enable mask of a process:        \r
1118         ENABLE p1, ..., pn      \r
1119 enables the procedures with identifiers p1, ..., pn. If there are any processes waiting for an alien call of one of these procedures, one of them is chosen and its request is processed. The scheduling is done on a FIFO basis, so it is strongly fair. The statement:        \r
1120     DISABLE p1, ..., pn         \r
1121 disables the procedures with identifiers p1, ..., pn.\r\r
1122   In addition a special form of the RETURN statement:   \r
1123     RETURN ENABLE p1, ..., pn DISABLE q1, ..., qn       \r
1124 allows to enable the procedures p1, ..., pn and disable the procedures q1,...,qn after the enable mask is restored on exit from the alien-called procedure. It is legal only in  the  alien-called procedures (the legality is not enforced by the compiler).\r\r
1125  A called process may avoid busy waiting for an alien call by means of the ACCEPT statement:    \r
1126         ACCEPT p1, ..., pn      \r
1127 adds the procedures p1, ..., pn to the current mask, and waits for an alien call of one of the currently enabled procedures. After the procedure return the enable mask is restored to that from before the ACCEPT statement.\r\r
1128  Note that the ACCEPT statement alone (i.e. without any ENABLE/DISABLE statements or options) provides a sufficient communication mechanism. In this case the called process may execute the alien-called procedure only during the ACCEPT statement (because otherwise all procedures are disabled). It means that the enable mask may be forgotten altogether and the alien call may be used as a pure totally synchronous rendez-vous. Other constructs are introduced to make partially asynchronous communication patterns possible.\r\r
1129 \r
1130 Below find a complete listing of a simple example - monitors.\r\r
1131 \r
1132 program monitors;\r
1133  \r
1134 (* this an example showing 5 processes: two of them are in fact monitors, one controls the screen=ekran *)\r
1135 \r
1136   unit ANSI: class;  \r
1137   (* CHECK whether config.sys contains a line\r
1138        device=ansi.sys\r
1139      the class ANSI enables operations on cursor,\r
1140                        and bold, blink, underscore etc. *) \r
1141                                \r
1142   unit Bold : procedure;\r
1143   begin\r
1144     write( chr(27), "[1m")\r
1145   end Bold;\r
1146     \r
1147   unit Blink : procedure;\r
1148   begin\r
1149     write( chr(27), "[5m")\r
1150   end Blink;\r
1151   \r
1152   unit Reverse : procedure;\r
1153   begin\r
1154     write( chr(27), "[7m")\r
1155   end Reverse;\r
1156 \r
1157   unit Normal : procedure;\r
1158   begin\r
1159     write( chr(27), "[0m")\r
1160   end Normal;\r
1161   \r
1162   unit Underscore : procedure;\r
1163   begin\r
1164     write( chr(27), "[4m")\r
1165   end Underscore;\r
1166 \r
1167   unit inchar : IIUWgraph function : integer;\r
1168     (*podaj nr znaku przeslanego z klawiatury *)\r
1169     var i : integer;\r
1170   begin\r
1171     do\r
1172       i := inkey;\r
1173       if i <> 0 then exit fi;\r
1174     od;\r
1175     result := i;\r
1176   end inchar;\r
1177   \r
1178   unit NewPage : procedure;\r
1179   begin\r
1180     write( chr(27), "[2J")\r
1181   end NewPage;\r
1182   \r
1183   unit  SetCursor : procedure(row, column : integer);\r
1184     var c,d,e,f  : char,\r
1185         i,j : integer;\r
1186   begin\r
1187     i := row div 10;\r
1188     j := row mod 10;\r
1189     c := chr(48+i);\r
1190     d := chr(48+j);\r
1191     i := column div 10;\r
1192     j := column mod 10;\r
1193     e := chr(48+i);\r
1194     f := chr(48+j);\r
1195     write( chr(27), "[", c, d, ";", e, f, "H")\r
1196   end SetCursor;        \r
1197 end ANSI;\r
1198 \r
1199   \r
1200     unit monitor:  process(node:integer, size:integer,e: ekran);\r
1201 \r
1202        var buf: arrayof integer,\r
1203            nr,i,j,k1,k2,n1,n2: integer;\r
1204 \r
1205         \r
1206     unit lire: procedure(output k: integer);\r
1207     begin\r
1208       call e.druk(13,2+nr*30+k1,0,k2);\r
1209       call e.druk(13,2+nr*30+(i-1)*6,1,buf(i));\r
1210       k1:=(i-1)*6;\r
1211       k:=buf(i);\r
1212       k2:=k;\r
1213       i:= (i mod size)+1;\r
1214       if i=j\r
1215       then\r
1216         call e.printtext("i equal j")\r
1217       fi; \r
1218     end lire;\r
1219     \r
1220     unit ecrire: procedure(n:integer);\r
1221     begin\r
1222       call e.druk(13,2+nr*30+n1,0,n2);\r
1223       call e.druk(13,2+nr*30+(j-1)*6,2,n);\r
1224       n1:=(j-1)*6;\r
1225       buf(j) := n;\r
1226       n2:=buf(j);\r
1227       j := (j mod size)+1;\r
1228       if i=j\r
1229       then\r
1230         call e.printtext("j equal i")\r
1231       fi; \r
1232     end ecrire;\r
1233   begin\r
1234     array buf dim(1:size);\r
1235     nr := size - 4;\r
1236     for i := 1 to size\r
1237     do\r
1238       buf(i) :=  i+nr*4;\r
1239       call e.druk(13,2+nr*30+(i-1)*6,0,buf(i));\r
1240     od;\r
1241     i:=1;  \r
1242     j := size;\r
1243     k1:=0;\r
1244     k2:=buf(1);\r
1245     n1:=(size-1)*6;\r
1246     n2:=buf(size);\r
1247     (* end initialize buffer *)\r
1248     return;\r
1249     \r
1250     do\r
1251       accept lire, ecrire\r
1252     od\r
1253   end monitor;\r
1254   \r
1255   unit prcs:  process(node,nr:integer, mleft,mright:\r
1256                                                          monitor, e: ekran);\r
1257     var l,o: integer;\r
1258 \r
1259   begin\r
1260     call e.SetCursor(8+(nr-1)*10,29);\r
1261     if nr = 1\r
1262     then\r
1263       call e.printtext("<-- p1 <--");\r
1264     else\r
1265       call e.printtext("--> p2 -->");\r
1266     fi;    \r
1267     return;\r
1268     do\r
1269       call mleft.lire(l) ;\r
1270       call e.druk(11+(nr-1)*4,31-(nr-1)*8,1,l);\r
1271       l:= l+1;\r
1272       call mright.ecrire(l) ; \r
1273       call e.druk(10+(nr-1)*6,23+(nr-1)*8,2,l);\r
1274       if l mod 15 = 0 \r
1275       then\r
1276         o:= e.inchar;\r
1277               if o = -79 then call endrun fi;\r
1278       fi;       \r
1279     od;\r
1280   end prcs;\r
1281   \r
1282 unit ekran : ANSI process(nrprocesora: integer);\r
1283     unit printtext: procedure(s:string);\r
1284     begin\r
1285       write(s);\r
1286       call Normal;\r
1287     end printtext;\r
1288 \r
1289     unit  druk: procedure(gdzieW,gdzieK,jak,co:integer);\r
1290     begin\r
1291       call SetCursor(gdzieW,gdzieK);\r
1292       write("   ");\r
1293       if jak=0 then call Normal else\r
1294         if jak=1 then call Reverse else\r
1295           if jak=2 then call Bold \r
1296           fi\r
1297         fi\r
1298       fi;\r
1299       write(co:3);\r
1300       call Normal;\r
1301     end druk;\r
1302 \r
1303     unit print: procedure (i:integer);\r
1304     begin\r
1305       write(i:4)\r
1306     end print;\r
1307   begin\r
1308     return;\r
1309     \r
1310     do accept inchar, \r
1311               Normal,NewPage, SetCursor, Bold, Underscore,\r
1312               Reverse, Blink, print, printtext, druk\r
1313     od\r
1314   end ekran;\r
1315   \r
1316 var m1,m2:monitor,\r
1317     e:ekran,\r
1318     p1,p2:prcs;\r
1319      \r
1320 begin     (* ----- HERE IS THE MAIN PROGRAM ----- *)\r
1321   (* create a  configuration *)\r
1322   e:= new ekran(0);\r
1323   resume(e);\r
1324   call e.Normal;\r
1325   call e.NewPage;\r
1326   m1 := new monitor(0,4,e);\r
1327   m2 := new monitor(0,5,e);\r
1328   \r
1329   p1 := new prcs(0,1,m2,m1,e);\r
1330   p2 := new prcs(0,2,m1,m2,e);\r
1331     \r
1332   resume(m1);\r
1333   resume(m2);\r
1334   resume(p1);\r
1335   resume(p2);\r
1336 end monitors;\r
1337 \r
1338 References.\r\r
1339 \r
1340 Bartol,W.M., et al.\r
1341 Report on the Loglan 82 programming Language,\r
1342 Warszawa-Lodz, PWN, 1984\r
1343 \r
1344 O.-J. Dahl, B. Myhrhaug, K. Nygaard, \r
1345 Simula 67 Common Base Language, \r
1346 Norwegian Computing Center, Oslo, 1970           the mother of object languages!!\r
1347 \r
1348 Hoare C.A.R.\r
1349  Monitors, an operating system structuring concept.\r
1350 CACM,vol.17,N.10,October 1974,pp.549-57\r
1351 \r
1352 Loglan'82 \r
1353 User's guide\r
1354 Institute of Informatics, University of Warsaw 1983, 1988\r
1355 LITA, Université de Pau, 1993\r
1356 (distributed together with this package)\r
1357 \r
1358 A.Kreczmar, A.Salwicki, M. Warpechowski, \r
1359 Loglan'88 - Report on the Programming Language,\r
1360 Lecture Notes on Computer Science vol. 414, Springer Vlg, 1990,\r
1361 ISBN 3-540-52325-1\r
1362 \r
1363 /* if you can read polish, there is a good manual of Loglan   */\r
1364 A.Szalas, J.Warpechowska,\r
1365 LOGLAN,   \r
1366 Wydawnictwa Naukowo-Techniczne, Warszawa, 1991 ISBN 82-204-1295-1 \r
1367      \r
1368 see also the Readings file of this distribution.\r
1369 \r
1370 {PAGE|34}       A.Kreczmar      Nov.1990\r
1371 \r
1372         Loglan'82       {PAGE|33}\r
1373 \r
1374 \r