Added upstream from http://ftp.icm.edu.pl/pub/loglan/
[loglan.git] / utils / lotek / loglan.txt
1 \r
2 \r
3 \r
4  \r
5  \r
6  \r
7  \r
8  \r
9  \r
10  \r
11  \r
12  \r
13  \r
14  \r
15  \r
16  \r
17  \r
18  \r
19  \r
20                            A micro-manual\r
21  \r
22                                  of                 \r
23  \r
24                        the programming language\r
25  \r
26  \r
27                            L O G L A N - 82\r
28                            ================\r
29  \r
30  \r
31  \r
32                     Basic constructs and facilities\r
33  \r
34  \r
35                         Author: Antoni Kreczmar\r
36               Institute of Informatics, Warsaw University\r
37                             September 1982  \r
38 \r
39 \r
40   LOGLAN-82  is  a  universal  programming  language designed  at  the\r
41 Institute  of  Informatics,  University  of  Warsaw.  Its   syntax  is\r
42 patterned  upon Pascal's.  Its  rich semantics includes  the classical\r
43 constructs and  facilities offered  by  the  Algol-family  programming\r
44 languages as well as more modern facilities, such as  concurrency  and\r
45 exception handling.\r
46   The basic  constructs and  facilities of  the LOGLAN-82  programming\r
47 language include:\r
48  \r
49 1) A convenient set of structured statements,\r
50  \r
51 2) Modularity (with the possibility of module nesting and extending),\r
52  \r
53 3) Procedures and functions (fully recursive; procedures and functions\r
54    can be used also as formal parameters),\r
55  \r
56 4) Classes (as a  generalization of records)  which  enable to  define\r
57    complex structured types, data structures, packages, etc.,\r
58  \r
59 5) Adjustable arrays whose bounds are determined at run-time in such a\r
60    way that  multidimensional arrays may be  of  various  shapes, e.g.\r
61    triangular, k-diagonal, streaked, etc.,\r
62  \r
63 6) Coroutines and semi-coroutines,\r
64  \r
65 7) Prefixing  - the  facility borrowed  from Simula-67,  substantially\r
66    generalized in LOGLAN-82 - which enables to build up hierarchies of\r
67    types and data structures, problem-oriented languages, etc.,\r
68  \r
69 8) Formal types treated as a method of module parametrization,\r
70  \r
71 9) Module protection and encapsulation techniques,\r
72  \r
73 10) Programmed deallocator -  a  tool for efficient and secure garbage\r
74     collection,  which  allows  the  user  to  implement  the  optimal\r
75     strategy of storage management,\r
76  \r
77 11) Exception  handling  which  provides facilities  for  dealing with\r
78     run-time  errors and  other  exceptional situations raised  by the\r
79     user,\r
80  \r
81 12) Separate compilation techniques,\r
82  \r
83 13) Concurrency  easily adaptable to  any operating  system kernel and\r
84     allowing parallel programming in a natural and efficient way.\r
85  \r
86   The   language  covers  system  programming,  data  processing,  and\r
87 numerical computations. Its constructs represent the state-of-art  and\r
88 are  efficiently  implementable.  Large  systems  consisting  of  many\r
89 cooperating modules  are easily  decomposed  and assembled, due to the\r
90 class concept and prefixing.\r
91   LOGLAN-82  constructs  and  facilities  have  appeared  and  evolved\r
92 simultaneously with  the  experiments  on  the  first  pilot  compiler\r
93 (implemented  on  Mera-400  Polish  minicomputer).   The  research  on\r
94 LOGLAN-82  implementation engendered with  new algorithms  for  static\r
95 semantics,  context analysis,  code generation,  data  structures  for\r
96 storage management etc.\r
97   The LOGLAN-82  compiler provides  a  keen  analysis of syntactic and\r
98 semantic errors at compilation as well as at run time. The object code\r
99 is  very efficient with respect to time and space. The completeness of\r
100 error checking guarantees full security and ease of program debugging.\r
101 \r
102 1. Compound statements\r
103 ######################\r
104 \r
105   Compound statements in LOGLAN-82 are built up from simple statements\r
106 (like assignment  statement  e.g. x:=y+0.5,  call statement e.g.  callP(7,x+5) e\r
107   The syntax of conditional statement is as follows:\r
108  \r
109    if boolean expression\r
110    then    \r
111      sequence of statements\r
112    else   \r
113      sequence of statements\r
114    fi   \r
115  \r
116 where "else part" may be omitted:\r
117  \r
118    if boolean expression  \r
119    then   \r
120      sequence of statements\r
121    fi  \r
122  \r
123   The semantics  of conditional statement  is standard. The keyword fi  \r
124 allows to  nest conditional statements without appearence of "dangling\r
125 else" ambiguity.\r
126  \r
127 Example:\r
128 --------\r
129  \r
130   if delta>0   if  \r
131   then   \r
132     x2:=sqrt(delta)/a/2;\r
133     if b=0   \r
134     then  \r
135       x1:=x2\r
136     else  \r
137       x1:=-b/a/2+x2; x2:=x1-2*x2\r
138     fi  \r
139   else  \r
140     if delta=0   \r
141     then  \r
142       x1:=-b/a/2; x2:=x1\r
143     else  \r
144       write(" no real roots")\r
145     fi  \r
146   fi   \r
147  \r
148   The  statements in  a  sequence of  statements  are  separated  with\r
149 semicolons  (semicolon  may end  a  sequence  ,  and  then,  the  last\r
150 statement in the sequence is the empty statement).\r
151 \r
152   The short  circuit  control  forms are realized  in LOGLAN-82 by the\r
153 conditional  statements  with  orif  (or  andif) list.  A  conditional   \r
154 statement with orif list has the form:                orif \r
155  \r
156   if wb1 orif wb2 ... orif wbk   \r
157   then  \r
158     sequence of statements\r
159   else\r
160     sequence of statements\r
161   fi  \r
162  \r
163 and corresponds somehow to a conditional statement:\r
164  \r
165   if wb1 or wb2 ... or wbk   \r
166   then   \r
167     sequence of statements\r
168   else   \r
169     sequence of statements\r
170   fi   \r
171  \r
172   The  above  conditional statement (without  orif  list) selects  for   \r
173 execution  one of two sequences of statements, depending on  the truth\r
174 value of the boolean expression:\r
175  \r
176   wb1 or wb2 or ... wbk    \r
177  \r
178 which is  always  evaluated till  the end.  For  the execution of  the\r
179 conditional  statement   with  orif  list  the   specified   conditons  \r
180 wb1,...,wbk are evaluated in succession, until the first one evaluates\r
181 to true. Then the rest of  the sequence wb1,...,wbk  is abandoned  and\r
182 "then  part"  is  executed.  If  none  of  the conditions  wb1,...,wbk\r
183 evaluates to true "else part" is executed (if any).\r
184   Conditional statements with  orif  list facilitate to  program those  \r
185 conditions, which evaluation to the end may raise a run-time error.\r
186  \r
187 Example:\r
188 --------\r
189   The execution of the statement:\r
190  \r
191   if i>n or A(i)=0 then i:=i-1 else A(i):=1 fi  \r
192  \r
193 where the value of i  is greater than  n, and A is an array with upper\r
194 bound n, will raise the run-time error. Then the user can write:\r
195  \r
196   if i>n orif A(i)=0 then i:=i-1 else A(i):=1 fi\r
197  \r
198 what  allows to avoid this run-time error and probably agrees with his\r
199 intension.  \r
200 \r
201   Conditional statement with andif list has the form:\r
202  \r
203   if wb1 andif wb2 ...  andif wbk\r
204   then   \r
205     sequence of statements\r
206   else   \r
207     sequence of statements\r
208   fi   \r
209  \r
210   For  the  execution  of this  kind  of  statements,  the  conditions\r
211 wb1,...,wbk are evaluated in succession, until the first one evaluates\r
212 to false; then "else part" (if any) is executed. Otherwise "then part"\r
213 is executed.\r
214  \r
215   Iteration statement in LOGLAN-82 has the form:\r
216  \r
217  do sequence of statements od\r
218   An iteration statement specifies repeated execution of  the sequence\r
219 of  statements  and  terminates  with  the  execution  of  the  simple\r
220 statement exit\r
221  \r
222 Example:\r
223 --------\r
224  \r
225   s:=1; t:=1; i:=1;\r
226   do   \r
227     i:=i+1; t:=t*x/i;\r
228     if abs(t) < 1.0E-10 then exit fi; \r
229     s:=s+t\r
230   od;   \r
231  \r
232   If two  iteration statements are  nested,  then double  exit  in the   \r
233 inner one terminates both of them.\r
234  \r
235 Example:\r
236 --------\r
237  \r
238   r,x:=0;\r
239   do   \r
240     s,t:=1; i:=1; x:=x+0.2;\r
241     do     \r
242       i:=i+1; t:=t*x/i;\r
243       if i > n then exit exit fi; (* termination of both loops *)   \r
244       if t < 1 then exit fi;      (* termination of the inner loop *)   \r
245       s:=s+t\r
246     od     \r
247   od   \r
248  \r
249   In  the  example  above   simultaneous  assignment  statements  are\r
250 illustrated  (e.g.  r,x:=0) and  comments,  which  begin with  a  left\r
251 parenthesis  immediately followed  by  an  asterisk  and end  with  an\r
252 asterisk immediately followed by a right parenthesis.\r
253  \r
254   Triple exit terminates  three nested iteration statements, four exit          \r
255 terminates four nested iteration statements etc.\r
256 \r
257   The iteration statement with while condition:                                w\r
258  \r
259   while boolean expression \r
260   do   \r
261     sequence of statements\r
262   od   \r
263  \r
264 is equivalent to:\r
265  \r
266   do   \r
267     if not boolean expression then  exit  fi; \r
268     sequence of statements\r
269   od   \r
270  \r
271   The iteration  statements with controlled variables (for statements)   \r
272 have the forms:\r
273  \r
274   for j:=wa1 step wa2 to wa3   \r
275   do   \r
276     sequence of statements\r
277   od   \r
278  \r
279 or\r
280  \r
281   for j:=wa1 step wa2 downto wa3 \r
282   do   \r
283     sequence of statements\r
284   od   \r
285  \r
286   The type of the controlled variable j must be discrete. The value of\r
287 this variable  in the case  of the for statement with to is increased, \r
288 and  in  the  case  of the for statement with downto is decreased. The   \r
289 discrete  range begins with the value of wa1 and changes with the step\r
290 equal to  the value of wa2. The execution of the for statement with to\r
291 terminates when the value of j for the first time becomes greater than\r
292 the value of wa3 (with downto when the value  of j  for the first time  \r
293 becomes  less  than  the  value  of  wa3).  After  the  for  statement  \r
294 termination  the value of its  controlled variable  is determined  and\r
295 equal  to the first  value exceeding the specified discrete range. The\r
296 values of expressions wa1,  wa2 and wa3 are evaluated once, upon entry\r
297 to the iteration statement. Default value of  wa2 is equal 1 (when the\r
298 keyword step and expression wa2 are omitted).\r
299   for or while statements may be combined with exit statement. \r
300  \r
301 Example:\r
302 --------\r
303  \r
304   for j:=1 to n\r
305   do  \r
306      if x=A(j) then exit fi; \r
307   od   \r
308  \r
309   The above  iteration statement terminates either  for  the  least j,\r
310 1<=j<=n, such that x=A(j) or for j=n+1 when x=/=A(j), j=1,...,n.\r
311 \r
312   To  enhance the  user's comfort,  the  simple  statement  repeat  is\r
313 provided.  It may  appear  in an iteration  statement  and  causes the\r
314 current iteration  to be finished  and the  next one  to  be continued\r
315 (something like jump to CONTINUE in Fortran's DO statements).\r
316  \r
317 Example:\r
318 --------\r
319  \r
320   i:=0;  s:=0;\r
321   do   \r
322     i:=i+1;\r
323     if A(i) < 0 then repeat fi; (* jump to od, iterations are continued *)\r
324     if i > m then exit fi;      (* iteration statement is terminated *) \r
325     s:=s+sqrt(A(i));\r
326   od;   \r
327  \r
328   Just as exit, repeat may appear in for statement or while statement. \r
329 Then the next  iteration  begins with  either  the evaluation of a new\r
330 value  of  the  controlled  variable  (for  statement)  or   with  the   \r
331 evaluation of the condition (while statement). \r
332  \r
333   Case statement in LOGLAN-82 has the form:\r
334  \r
335   case WA   \r
336     when L1 : I1     \r
337     when L2 : I2     \r
338        ...\r
339     when Lk : Ik     \r
340     otherwise  I     \r
341   esac   \r
342  \r
343 where WA  is an expression , L1,...,Lk are constants and I1,...,  Ik,I\r
344 are sequences of statements.\r
345   A case statement selects for execution a sequence of statements  Ij,\r
346 1<=j<=k, where the value of WA equals Lj.  The choice otherwise covers    \r
347 all values  (possibly none)  not  given in  the previous choices.  The\r
348 execution of a  case statement chooses  one and  only  one alternative\r
349 (since the choices are to be exhaustive and mutually exclusive).\r
350 \r
351 2. Modularity\r
352 #############\r
353  \r
354   Modular structure of the  language is gained due to the large set of\r
355 means for module nesting  and extending.  Program modules  (units) are\r
356 blocks,  procedures,  functions,  classes,  coroutines  and processes.\r
357 Block is the simplest kind of unit. Its syntax is the following:\r
358  \r
359   block   \r
360     lists of declarations\r
361   begin   \r
362     sequence of statements\r
363   end   \r
364  \r
365   The  sequence of statements commences with the keyword begin (it may   \r
366 be omitted  when  this  sequence is empty). The lists  of declarations\r
367 define the syntactic  entities (variables,  constants,  other  units),\r
368 whose scope  is  that block.  The syntactic entities are identified in\r
369 the sequence of statements by means of names (identifiers).\r
370  \r
371 Example:\r
372 --------\r
373  \r
374   block   \r
375     const n=250;     \r
376     var x,y:real, i,j,k: integer, b: boolean;   \r
377     const m=n+1;     \r
378   begin   \r
379     read(i,j);            (* read two integers *)\r
380     x,y:=n/(i+j);         (* simultaneous assignment *)\r
381     read(c) ;             (* read a character *)\r
382     b:= c = 'a';          (* 'a'  a character *)\r
383     for k:= 1 to m   \r
384     do     \r
385       write(x+y/k:10:4);  (* print the value of x+y/k\r
386                      in the field of 10 characters, 4 digits after the point *)\r
387     od     \r
388   end   \r
389  \r
390   In the  lists of declarations semicolons terminate the whole  lists,\r
391 not  the lists  elements.  Any declaration  list  must begin with  the\r
392 pertinent keyword (var for variables, const  for  constants etc.). The   \r
393 value  of  an expression  defining  a  constant must  be  determinable\r
394 statically (at compilation time).\r
395   Program in LOGLAN-82 may be  a block or alternatively may  be of the\r
396 following form:\r
397  \r
398    program name;    \r
399      lists of declarations\r
400    begin    \r
401      sequence of statements\r
402    end    \r
403  \r
404 Then  the whole program can be identified by that name  (the source as\r
405 well as the object code).\r
406 \r
407   A block can appear in the sequence of statements (of any unit), thus\r
408 it is a  statement. (Main block is assumed to appear as a statement of\r
409 the given job control language.)\r
410   For  the  execution  of a  block  statement  the object of  block is\r
411 created in a computer memory, and  then, the sequence of statements is\r
412 performed.  The syntactic entities declared in the block are allocated\r
413 in its object. After a block's termination its object is automatically\r
414 deallocated (and the corresponding space may be immediately reused).\r
415   The modular structure of the language works "in full steam" when not\r
416 only blocks, but the other kinds of units  are also used. They will be\r
417 described closer in the following points.\r
418   Unit nesting allows to build up  hierarchies  of units and  supports\r
419 security of programming. It follows from the general visibility rules;\r
420 namely, a syntactic entity declared  in an outer unit is visible in an\r
421 inner one (unless hidden by an inner declaration). On the other  hand,\r
422 a syntactic entity declared  in an  inner unit is  not visible from an\r
423 outer one.\r
424  \r
425 Example:\r
426 --------\r
427  \r
428   program test;   \r
429     var a,b,c:real, i,j,k:integer;  \r
430   begin   \r
431     read(a,b,c,i);\r
432     block     \r
433       var j,k:real;  \r
434     begin     \r
435       j:=a; k:=j+b; write(" this is the inner block ",j,k)\r
436     end;     \r
437     write(" this is the outer block ",i,a:20)\r
438   end;   \r
439  \r
440   In this program, first  the  main block statement is  executed (with\r
441 variables  a,b,c,i,j,k). Next, after  the  read  statement, the  inner\r
442 block statement is  executed (with variables j,k).  In the inner block\r
443 the global variables j,k are hidden by the local ones.\r
444  \r
445 \r
446 3. Procedures and functions\r
447 ###########################\r
448  \r
449   Procedures and functions are well-known kinds of units. Their syntax\r
450 is  modelled  on Pascal's,  though  with  some  slight  modifications.\r
451 Procedure (function) declaration  consists of a specification part and\r
452 a body.\r
453  \r
454  Example:\r
455  --------\r
456     unit Euclid: function(i,j:integer):integer;   \r
457     var k:integer;\r
458     begin     \r
459       do       \r
460         if j=0 then exit fi;  \r
461         k:=i mod j; i:=j; j:=k   \r
462       od;       \r
463       result:=i\r
464     end;     \r
465  \r
466   Procedure  or  function  specification  begins  with its  identifier\r
467 preceded  by the keyword  unit. (The same  syntax  concerns any  other  module \r
468 named  unit.) Then follows its kind declaration, its formal parameters\r
469 (if  any), and the type of the  returned value (only for functions). A\r
470 body consists of declaration lists for local  entities and a  sequence\r
471 of statements. The  keyword begin commences the sequence of statements   \r
472 , and  is omitted , if this sequence is empty. The value returned by a\r
473 function  equals to the most  recent  value of the  standard  variable\r
474 "result",  implicitly declared in any function.  This variable  can be\r
475 used as a local auxiliary variable as well.\r
476  \r
477  Example:\r
478  --------\r
479     unit Newton: function(n,m:integer):integer;    \r
480     var i:integer; \r
481     begin     \r
482       if m > n then return fi;   \r
483       result:=n;\r
484       for i:=2 to m do result:=result*(n-i+1) div i od  \r
485     end Newton;\r
486   The  optional  identifier  at  the end of  a  unit  must repeat  the\r
487 identifier  of a unit. It is  suggested  that the compilers  check the\r
488 order of unit  nesting, so  these  optional occurrences of identifiers\r
489 would facilitate program debugging.\r
490   All  the local variables of a unit are initialized  (real with  0.0,\r
491 integer with  0,  boolean with  false etc.). Thus , for instance,  the\r
492 value  of  function  Newton  is  0  for m>n, since  "result"  is  also\r
493 initialized, as any other local variable.\r
494  \r
495   The return statement (return) completes the execution of a procedure \r
496 (function) body,i.e. return is made to the caller. If return does  not  \r
497 appear explicitly, return is made with the  execution of the final end  \r
498 of a unit. Upon  return to the  caller the procedure (function) object\r
499 is deallocated.\r
500   Functions are invoked in expressions with the  corresponding list of\r
501 actual parameters. Procedures are invoked by call statement (also with\r
502 the corresponding list of actual parameters).\r
503 \r
504  Example:\r
505  --------\r
506     i:=i*Euclid(k,105)-Newton(n,m+1);\r
507     call P(x,y+3);   \r
508  \r
509   Formal  parameters  are of  four  categories:  variable  parameters,\r
510 procedure  parameters,  function parameters and  type  parameters  (cf\r
511 p.8). Variable  parameters are considered local variables to the unit.\r
512 A  variable  parameter has  one  of  three transmission modes:  input,\r
513 output or  inout. If  no mode  is explicitly given the  input mode  is\r
514 assumed. For instance in the unit declaration:\r
515  \r
516  unit P: procedure(x,y:real,b:boolean;output c:char,i:integer;inout j:integer);\r
517  \r
518 x,y,b  are input  parameters ,  c,i  are output parameters ,  and j is\r
519 inout parameter.\r
520  \r
521   Input parameter acts as a local variable whose  value is initialized\r
522 by  the value of the corresponding actual parameter.  Output parameter\r
523 acts as a local variable initialized in the standard manner (real with\r
524 0.0, integer  with 0, boolean with  false etc.). Upon return its value\r
525 is  assigned to the  corresponding  actual parameter, in which case it\r
526 must be a variable. However the address of such an actual parameter is\r
527 determined  upon entry to the body. Inout  parameter acts as  an input\r
528 parameter and output parameter together.\r
529  \r
530  Example:\r
531  --------\r
532   unit squareeq: procedure(a,b,c:real;output xr,xi,yr,yi:real);  \r
533    (* given a,b,c the procedure solves  square equation : ax*x+bx+c=0.\r
534      xr,xi- real and imaginary part of the first root\r
535      yr,yi- real and imaginary part of the second root *)\r
536   var delta: real;   \r
537   begin     (*a=/=0*)   \r
538     a:=2*a; c:=2*c; delta:=b*b-a*c;\r
539     if delta <= 0     \r
540     then     \r
541       xr,yr:=-b/a;\r
542       if delta=0 then  return fi;     (*xi=yi=0 by default*)   \r
543       delta:=sqrt(-delta);\r
544       xi:=delta/a; yi:=-xi;\r
545       return       \r
546     fi;     \r
547     delta:=sqrt(delta);\r
548     if b=0    \r
549     then     \r
550       xr:=delta/a; yr:=-xr;\r
551       return       \r
552     fi;     \r
553     if b>0 then b:=b+delta else b:=b-delta fi;\r
554     xr:=-b/a; yr:=-c/b;\r
555   end squareeq;\r
556 \r
557   A procedure call to the above unit may be the following:\r
558  \r
559   call squareeq(3.75*H,b+7,3.14,g,gi,h,hi); \r
560 where g,h,gi,hi are real variables.\r
561  \r
562  \r
563   No  restriction   is  imposed  on  the  order  of  declarations.  In\r
564 particular, recursive procedures and functions can be declared without\r
565 additional announcements (in contrast to Pascal).\r
566  \r
567  Example:\r
568  --------\r
569  \r
570   For two recursive sequences defined as:\r
571  \r
572   a(n)=b(n-1)+n+2         n>0\r
573   b(n)=a(n-1)+(n-1)*n     n>0\r
574   a(0)=b(0)=0\r
575  \r
576 one can declare two functions:\r
577  \r
578   unit a: function(n:integer):integer;\r
579   begin   \r
580     if n>0 then result:=b(n-1)+n+2 fi\r
581   end a;   \r
582   unit b: function(n:integer):integer; \r
583   begin   \r
584     if n>0 then result:=a(n-1)+(n-1)*n fi  \r
585   end b;   \r
586  \r
587 and invoke them:\r
588  \r
589   k:=a(100)*b(50)+a(15);\r
590  \r
591   Functions and procedures can be formal parameters as well.\r
592  \r
593  Example:\r
594  --------\r
595  \r
596 unit Bisec: procedure(a,b,eps:real;output x:real;function f(x:real):real);\r
597 (*this procedures searches for zero of continous function f in segment (a,b) *)\r
598 var h:real,s:integer;\r
599 begin\r
600   s:=sign(f(a));\r
601   if sign(f(b))=s then return fi;   (* wrong segment *)   \r
602   h:=b-a;\r
603   do   \r
604     h:=h/2; x:=a+h;\r
605     if h < eps then  return fi;\r
606     if sign(f(x))=s then a:=x else b:=x fi\r
607   od   \r
608 end Bisec;\r
609 \r
610   In  the  above  declaration,  after  the  input  variable parameters\r
611 a,b,eps and the output variable  parameter x, a  function parameter  f\r
612 appears. Note that its specification part  is complete. Thus the check\r
613 of  actual-formal parameter  compatibility is  possible at compilation\r
614 time. Making  use of  this  syntactic  facility  is  not  possible  in\r
615 general, if a formal procedure  (function) is again a formal parameter\r
616 of  a  formal  procedure  (function).  The  second  degree  of  formal\r
617 procedures  (functions) nesting is rather scarce, but LOGLAN-82 admits\r
618 such  a   construct.  Then   formal   procedure  (function)   has   no\r
619 specification part  and  the  full  check of  actual-formal  parameter\r
620 compatibility is left to be done at run time.\r
621  \r
622  Example:\r
623  --------\r
624  \r
625   unit P: procedure(j:integer;procedure G(i:integer;procedure H));\r
626     ...\r
627   begin   \r
628     ...\r
629     call G(j,P);\r
630   end P;   \r
631  \r
632   Procedure G  is  a first degree parameter, therefore it occurs  with\r
633 complete specification part. Procedure H is a  second degree parameter\r
634 and has no specification part. In this case  a procedure  call can  be\r
635 strongly recursive:\r
636  \r
637     call P(i+10,P);  \r
638 \r
639 4. Classes\r
640 ##########\r
641  \r
642   Class  is  a facility which  covers  such programming  constructs as\r
643 structured type, package, access type, data  structure etc.  To  begin\r
644 with the presentation of this construct, let us consider  a structured\r
645 type assembled from primitive ones:\r
646  \r
647   unit bill: class;\r
648   var     dollars           :real, \r
649           not_paid          :boolean,\r
650           year,month,day    :integer;\r
651   end bill;   \r
652  \r
653   The  above class  declaration has  the attributes  : dollars (real),\r
654 not_paid (boolean), and year,month,day (integer). Wherever  class bill\r
655 is visibile one can declare variables of type bill:\r
656  \r
657     var x,y,z:bill;\r
658  \r
659   The values of  variables  x, y, z can be the addresses of objects of\r
660 class  bill. These  variables are  called  reference  variables.  With\r
661 reference variable one can create and operate the objects of reference\r
662 variable type.\r
663  \r
664   An object of a  class is  created by the class generation  statement\r
665 (new),  and  thereafter,  its  attributes  are  accessed  through  dot   \r
666 notation.\r
667  \r
668     x:=new bill;       (* a new object of class bill is created *)    \r
669     x.dollars:=500.5;  (* define amount *)\r
670     x.year:=1982;      (* define year *)\r
671     x.month:=3;        (* define month *)\r
672     x.day:=8;          (* define day *)\r
673     y:=new bill;       (* create a new object *)   \r
674     y.not_paid:=true;  (* bill not_paid *)\r
675     z:=y;              (* variable z points the same object as variable y *)\r
676  \r
677   If  an  object of  class  bill has been created (new bill)  and  its   \r
678 address has  been  assigned to  variable  x (x:=new  bill),  then  the  \r
679 attributes of that object are accessible through  dot notation (remote\r
680 access).  The expression x.dollars  gives , for  instance, the  remote\r
681 access to attribute dollars of the object referenced by x.\r
682   All attributes  of class objects are  initialized  as usual. For the\r
683 above example  the object referenced by x,  after the execution of the\r
684 specified sequence of statements, has the following structure:\r
685  \r
686       ---------------\r
687       |    500.5    |     dollars\r
688       ---------------\r
689       |    false    |     not_paid\r
690       ---------------\r
691       |    1982     |     year\r
692       ---------------\r
693       |      3      |     month\r
694       ---------------\r
695       |      8      |     day\r
696       ---------------\r
697  \r
698   The object referenced by y and z has the following structure:\r
699  \r
700       ---------------\r
701       |      0      |     dollars\r
702       ---------------\r
703       |    true     |     not_paid\r
704       ---------------\r
705       |      0      |     year\r
706       ---------------\r
707       |      0      |     month\r
708       ---------------\r
709       |      0      |     day\r
710       ---------------\r
711  \r
712   The  value  none  is  the  default initial  value  of any  reference  \r
713 variable  and denotes no object. A remote access to  an  attribute  of\r
714 none raises a run time error. \r
715   Class may have also formal parameters (as procedures and functions).\r
716 Kinds and  transmission modes of  formal parameters are the same as in\r
717 the case of procedures.\r
718  \r
719  Example:\r
720  --------\r
721  \r
722    unit node: class (a:integer);\r
723      var left,right:node;   \r
724    end node; \r
725  \r
726   Let , for instance, variables z1, z2,  z3 be of type  node. Then the\r
727 sequence of statements:\r
728  \r
729      z1:=new node(5);\r
730      z2:=new node(3);   \r
731      z3:=new node(7);  \r
732      z1.left:=z2; z1.right:=z3;\r
733  \r
734   creates the structure:\r
735  \r
736                    -----------\r
737            z1----> |    5    |\r
738                    -----------\r
739             <----  |   left  |\r
740             |      -----------\r
741             |      |   right | ------->\r
742             |      -----------        |\r
743             |                         |\r
744        ------------             ------------\r
745 z2---->|    3     |             |     7    | <----z3\r
746        ------------             ------------\r
747        |   none   |             |    none  | \r
748        ------------             ------------\r
749        |   none   |             |    none  | \r
750        ------------             ------------\r
751 \r
752  \r
753 where arrows denote the values of the reference variables.\r
754  \r
755   Class may also have a  sequence of  statements  (as any other unit).\r
756 That sequence can initialize the attributes of the class objects.\r
757  \r
758  Example:\r
759  --------\r
760  \r
761   unit complex:class(re,im:real);   \r
762   var module:real;  \r
763   begin   \r
764     module:=sqrt(re*re+im*im)\r
765   end complex;   \r
766  \r
767   Attribute module is  evaluated  for any object generation  of  class\r
768 complex:\r
769  \r
770   z1:=new complex(0,1); (* z1.module equals 1 *) \r
771   z2:=new complex(2,0); (* z2.module equals 2 *)   \r
772  \r
773   For  the  execution of  a class generator,  first a class  object is\r
774 created,  then the input parameters are transmitted , and finally, the\r
775 sequence of statements (if any) is  performed. Return is made with the\r
776 execution of return statement  or the final end of a unit. Upon return\r
777 the output parameters are transmitted.\r
778   Procedure object is automatically deallocated when return is made to\r
779 the caller. Class  object  is  not  deallocated  ,  its address can be\r
780 assigned to a reference variable, and its attributes can be thereafter\r
781 accessed via this variable.\r
782  \r
783   The  classes  presented  so  far had only  variable  attributes.  In\r
784 general, class attributes may  be also  other syntactic entities, such\r
785 as   constants,  procedures,  functions,  classes  etc.  Classes  with\r
786 procedure and  function attributes  provide a good facility  to define\r
787 data structures.\r
788  \r
789  Example:\r
790  --------\r
791  \r
792   A push_down memory of  integers may be implemented  in the following\r
793 way:\r
794  \r
795   unit push_down :class;   \r
796     unit elem:class(value:integer,next:elem);\r
797      (* elem - stack element *)\r
798     end elem;     \r
799     var top:elem;     \r
800     unit pop: function :integer;   \r
801     begin     \r
802       if top=/= none  \r
803       then       \r
804         result:=top.value; top:=top.next\r
805       fi;       \r
806     end pop;     \r
807     unit push:procedure(x:integer);    (* x - pushed integer *) \r
808 \r
809     begin     \r
810       top:=new elem(x,top);\r
811     end push;     \r
812   end push_down;\r
813 \r
814   Assume  that  somewhere in  a program  reference  variables  of type\r
815 push_down  are  declared  (of  course,  in  place where  push_down  is\r
816 visibile):\r
817  \r
818   var s,t,z:push_down;   \r
819  \r
820   Three different push_down memories may be now generated:\r
821  \r
822   s:=new push_down(100); t:=new push_down(911); z:=new push_down(5);   \r
823  \r
824   One can use these push_down memories as follows:\r
825  \r
826   call s.push(7); (* push  7 to s *)   \r
827   call t.push(1); (* push  1 to t *)    \r
828   i:=z.pop;       (* pop an element from z *)\r
829   etc.\r
830 \r
831 5. Adjustable arrays\r
832 ####################\r
833  \r
834   In LOGLAN-82 arrays are adjustable at  run time. They may be treated\r
835 as objects of specified standard type with index instead of identifier\r
836 selecting  an  attribute.  An  adjustable  array   should  be  declare\r
837 somewhere among the lists of declarations and then may be generated in\r
838 the sequence of statements.\r
839  \r
840  Example:\r
841  --------\r
842  \r
843   block   \r
844     var n,j:integer;     \r
845     var A:arrayof integer;   (* here is the declaration of A *)  \r
846   begin   \r
847     read(n);\r
848     new_array A dim (1:n);       (* here is the generation of A *)   \r
849     for i:=1 to n   \r
850     do     \r
851       read(A(i));\r
852     od;     \r
853     (* etc.*)\r
854   end   \r
855  \r
856   A variable A is an array variable. Its value should be the reference\r
857 to  an integer array, i.e.  a composite object  consisting  of integer\r
858 components each  one  defined by  an integer index.  Array  generation\r
859 statement:\r
860  \r
861   new_array A dim (1:n);    \r
862  \r
863 allocates a one-dimensional integer array with  the index bounds 1,n ,\r
864 and assigns  its  address  to variable A. The figure below illustrates\r
865 this situation:\r
866  \r
867         ----------              -----------\r
868         |        |              |   A(1)  |\r
869         |        |              -----------\r
870         |   ...  |              |   A(2)  |\r
871         ----------              -----------\r
872         |    n   |              |         |\r
873         ----------                  ...\r
874         |    j   |              |         |\r
875         ----------              -----------\r
876         |    A   | --------->   |   A(n)  |\r
877         ----------              -----------\r
878        Block object             Array object\r
879  \r
880   A general case of array generation statement has the form:\r
881  \r
882     new_array A dim (lower:upper)   \r
883  \r
884 where  lower and upper  are  arithmetic expressions  which  define the\r
885 range of the array index.\r
886 \r
887  Example:\r
888  --------\r
889  \r
890   Two-dimensional array declaration :\r
891  \r
892    var A: arrayof arrayof integer;   \r
893  \r
894 and generation:\r
895  \r
896     new_array A dim (1:n) \r
897     for i:=1 to n do new_array A(i) dim (1:m) od;   \r
898  \r
899 create the structure:\r
900  \r
901                                     ----------\r
902                                     | A(1,1) |\r
903                                     ----------\r
904                                     |        |\r
905                                         ...\r
906                                     |        |\r
907          ------------               ----------\r
908          |   A(1)   | --------->    | A(1,m) |\r
909          ------------               ----------\r
910          |          |\r
911               ...\r
912          |          |\r
913          ------------               ----------\r
914          |   A(n)   | --------->    | A(n,1) |\r
915          ------------               ----------\r
916                                     |        |\r
917                                         ...\r
918                                     |        |\r
919                                     ----------\r
920                                     | A(n,m) |\r
921                                     ----------\r
922  \r
923  Example:\r
924  --------\r
925  \r
926   block   \r
927     var i,j:integer, A,B: arrayof arrayof real, n:integer; \r
928   begin   \r
929     read(n);\r
930     new_array A dim (1:n);  \r
931     for i:=1 to n do new_array A(i) dim (1:n) od;   \r
932      (* A is square array *)\r
933     new_array B dim (1:n);   \r
934     for i:=1 to n do new_array B(i) dim(1:i) od; \r
935      (* B is lower triangular array *)\r
936     A(n,n):=B(n,n);\r
937     B(1):=A(1);\r
938     B(1):=copy(A(1)); \r
939   end   \r
940 \r
941   Array  A is the  square  array n  by n. Each  element A(i) , 1<=i<=n\r
942 contains  the  address  of  row   A(i,j),  1<=j<=n.  Array  B  is  the\r
943 lower-triangular  array.  Each  element B(i),  1<=i<=n,  contains  the\r
944 address  of  row   B(i,j),  1<=j<=i.  Thus  an   assignment  statement\r
945 A(n,n):=B(n,n)  transmits  real value B(n,n)  to real variable A(n,n).\r
946 Assignment  B(1):=A(1) transmits the address of the first row of A  to\r
947 variable B(1). Finally assignment B(1):=copy  (A(1)) creates a copy of  \r
948 the first row of A and assigns its address to B(1).\r
949  \r
950   Upper and lower bounds of an adjustable  array  A are determined  by\r
951 standard operators lower(A) and upper(A).\r
952  \r
953  Example:\r
954  --------\r
955  \r
956   unit sort: procedure(A:arrayof integer);   (*  insertion sort *) \r
957     var n,i,j:integer; var x:integer; \r
958   begin   \r
959     n:=upper(A);                             (* assume lower bound is 1 *)\r
960     for i:=2 to n     \r
961     do     \r
962       x:=A(i); j:=i-1;\r
963       do       \r
964         if x >= A(j) then exit fi;   \r
965         A(j+1):=A(j);  j:=j-1;\r
966         if j=0 then exit fi;\r
967       od;       \r
968       A(j+1):=x\r
969     od;     \r
970   end sort;   \r
971  \r
972   If an array variable A refers to no array  its  value is equal  none  \r
973 (the standard default  value of  any array  variable).  An attempt  to\r
974 access an array element (e.g. A(i)) or a  bound (e.g. lower(A)), where\r
975 A is none, raises a run time error.                       - 24 -                \r
976 \r
977 \r
978 6. Coroutines and semicoroutines\r
979 ################################\r
980  \r
981   Coroutine is  a generalization of class.  A coroutine object  is  an\r
982 object such  that the execution of its sequence of  statements can  be\r
983 suspended and reactivated in  a  programmed  manner. Consider first  a\r
984 simple class with a sequence of statements such that after return some  \r
985 non-executed   statements  remain.  The  generation  of   its   object\r
986 terminates with the execution of return statement, although the object\r
987 can be later reactivated. If such a  class is declared as a coroutine,\r
988 then its objects  may be reactivated. This  can be  realized by attach  \r
989 statement:\r
990  \r
991   attach(X)   \r
992  \r
993 where  X is a  reference variable designating the activating coroutine\r
994 object.\r
995   In general, since the  moment of  generation a  coroutine  object is\r
996 either active or suspended. Any reactivation  of a suspended coroutine\r
997 object X  (by  attach(X))  causes the  active  coroutine  object to be   \r
998 suspended  and  continues  the  execution  of  X  from  the  statement\r
999 following the last executed one.\r
1000   Main  program  is  also  a coroutine.  It  is  accessed  through the\r
1001 standard  variable main and may be reactivated  (if suspended) by  the    \r
1002 statement attach(main).  \r
1003  \r
1004  Example:\r
1005  --------\r
1006  \r
1007   In the example below the cooperation of two coroutines is presented.\r
1008 One reads the real values from  an input device, another prints  these\r
1009 values in columns  on a line-printer, n  numbers in  a line. The input\r
1010 stream ends with 0.\r
1011  \r
1012 program prodcons;\r
1013   var prod:producer,cons:consumer,n:integer,mag:real,last:bool;  \r
1014   unit producer: coroutine; \r
1015   begin   \r
1016     return;     \r
1017     do     \r
1018       read(mag);       (* mag- nonlocal variable, common store *)\r
1019       if mag=0       \r
1020       then             (* end of data *)  \r
1021         last:=true;\r
1022         exit         \r
1023       fi;       \r
1024       attach(cons);       \r
1025     od;     \r
1026     attach(cons)     \r
1027   end producer;  \r
1028 \r
1029   unit consumer: coroutine(n:integer); \r
1030   var Buf:arrayof real; \r
1031   var i,j:integer;   \r
1032   begin   \r
1033     new_array Buf dim(1:n); \r
1034     return;     \r
1035     do     \r
1036       for i:=1 to n       \r
1037       do       \r
1038         Buf(i):=mag;\r
1039         attach(prod);         \r
1040         if last then exit exit fi; \r
1041       od;       \r
1042       for i:=1 to n  \r
1043       do     (* print Buf *)   \r
1044         write(' ',Buf(i):10:2)\r
1045       od;       \r
1046       writeln;\r
1047     od;     \r
1048     (* print the rest of Buf *)\r
1049     for j:=1 to i do write(' ',Buf(j):10:2) od;   \r
1050     writeln;\r
1051     attach(main);     \r
1052   end consumer;   \r
1053  \r
1054  begin  \r
1055     prod:=new producer;           \r
1056     read(n);\r
1057     cons:=new consumer(n);    \r
1058     attach(prod);     \r
1059     writeln;\r
1060  end prodcons;  \r
1061  \r
1062   The above task  could  be programmed without coroutines at  all. The\r
1063 presented  solution  is,  however,  strictly modular,  i.e.  one  unit\r
1064 realizes  the input process, another realizes the output process,  and\r
1065 both are ready to cooperate with each other.\r
1066  \r
1067   LOGLAN-82   provides  also   a  facility  for   the   semi-coroutine\r
1068 operations. This is gained by the simple statement detach. If X is the \r
1069 active coroutine object, then detach reactivates that coroutine object  \r
1070 at  where the last  attach(X)  was executed. This statement meets  the  \r
1071 need for the  asymetric coroutine cooperations. (by  so it  is  called\r
1072 semi-coroutine  operation). Operation  attach  requires  a reactivated \r
1073 coroutine to be defined explicitly by the user as an actual parameter.\r
1074 Operation detach corresponds in  some manner to return in  procedures.\r
1075 It gives the  control  back  to a  coroutine  object  where  the  last\r
1076 attach(X)  was executed, and  that coroutine  object need not be known\r
1077 explicitly  in  X. This  mechanism is, however, not so  secure as  the\r
1078 normal control transfers during procedure calls and returns.\r
1079  \r
1080   In fact, the user is able to loop two coroutines traces by :\r
1081  \r
1082    attach(Y) in X    \r
1083    attach(X) in Y    \r
1084 \r
1085 \r
1086 Then detach in X reactivates Y, detach in Y reactivates X. \r
1087  \r
1088   In  the  example  below  the  application  of  detach  statement  is\r
1089 illustrated.\r
1090  \r
1091  Example:\r
1092  --------\r
1093  \r
1094  program reader_writers; \r
1095    (* In this example a single input stream consisting of blocks of\r
1096    numbers,  each  ending  with 0,  is  printed on two  printers of\r
1097    different  width. The choice of the printer is determined by the\r
1098    block  header  which  indicates  the  desired  number  of  print\r
1099    columns. The input stream ends with  a double 0.  m1 - the width\r
1100    of printer_1, m2 - the width of printer_2 *)\r
1101  const m1=10,m2=20;               \r
1102  var reader:reading,printer_1,printer_2:writing;                                \r
1103  var n:integer,new_sequence:boolean,mag:real;                                   \r
1104  \r
1105    unit writing:coroutine(n:integer);    \r
1106    var Buf: arrayof real, i,j:integer;   \r
1107    begin   \r
1108      new_array Buf dim (1:n);      (* array  generation *)       \r
1109      return;           (* return terminates coroutine initialization *)     \r
1110      do  \r
1111        attach(reader);         (* reactivates coroutine reader *)        \r
1112        if new_sequence        \r
1113        then  (* a new sequence causes buffer Buf to be cleared up *)        \r
1114          for j:=1 to i do write(' ',Buf(j):10:2) od;  writeln;          \r
1115          i:=0; new_sequence:=false;  attach(main)   \r
1116        else  \r
1117          i:=i+1;   Buf(i):=mag;\r
1118          if i=n  \r
1119          then  \r
1120            for j:=1 to n do write(' ',Buf(j):10:2) od;   writeln;\r
1121            i:=0;\r
1122          fi  \r
1123        fi  \r
1124      od  \r
1125    end writing;  \r
1126  \r
1127    unit reading: coroutine;  \r
1128    begin  \r
1129      return;  \r
1130      do  \r
1131        read(mag);\r
1132        if mag=0  then  new_sequence:=true;   fi;  \r
1133        detach;           (* detach returns control to printer_1 or  \r
1134      od  \r
1135    end reading;  \r
1136  \r
1137 \r
1138    begin  \r
1139      reader:=new reading;  \r
1140      printer_1:=new writing(m1); printer_2:=new writing(m2);\r
1141      do  \r
1142        read(n);\r
1143        case n  \r
1144          when 0:  exit  \r
1145          when m1: attach(printer_1)   \r
1146          when m2: attach(printer_2)   \r
1147          otherwise  write(" wrong data"); exit  \r
1148        esac  \r
1149      od    \r
1150    end;    \r
1151  \r
1152   Coroutines play the substantial  role in  process simulation.  Class\r
1153 Simulation provided in  Simula-67  makes  use  of  coroutines  at most\r
1154 degree. LOGLAN-82 provides for easy simulation  as well. The LOGLAN-82\r
1155 class Simulation is implemented  on a  heap what gives lg(n) time cost\r
1156 (in contrast with O(n) cost of the original implementation). It covers\r
1157 also  various  simulation   problems  of  large  size  and  degree  of\r
1158 complexity.\r
1159 \r
1160 \r
1161 7. Prefixing\r
1162 ############\r
1163  \r
1164   Classes and prefixing are ingenius inventions of Simula-67 (cf [1]).\r
1165 Unfortunately they are hardly ever known and,  perhaps,  by  this have\r
1166 not  been  introduced into  any other programming  language. Moreover,\r
1167 implementation  constraints of Simula-67 bind  prefixing  and  classes\r
1168 workableness to  such a degree that both  facilities cannot be used in\r
1169 all respects. We hope that LOGLAN-82,  adopting merits  and rooting up\r
1170 deficiencies  of these  constructs, will  smooth their  variations and\r
1171 vivify theirs usefulness.\r
1172   What is prefixing ? First of all  it is a method for unit extending.\r
1173 Consider the simplest example:\r
1174  \r
1175   unit bill: class;  \r
1176   var       dollars           :real,\r
1177            not_paid          :boolean,\r
1178            year,month,day    :integer;\r
1179   end bill;  \r
1180  \r
1181 Assume  the  user desires  to extend  this class with  new attributes.\r
1182 Instead of writing a completely new class, he may enlarge the existing\r
1183 one:\r
1184  \r
1185   unit gas_bill:bill class;  \r
1186     var cube_meters: real;  \r
1187   end gas_bill;  \r
1188  \r
1189   Class gas_bill is prefixed by  class bill. This new  declaration may\r
1190 appear anywhere within  the scope  of  declaration of class  bill. (In\r
1191 Simula-67  such  a  prefixing is  forbidden in  nested  units.)  Class\r
1192 gas_bill has all the attributes of class bill and additionally its own\r
1193 attributes (in this case  the  only one: cube_meters).  The generation\r
1194 statement of this class has the form:\r
1195  \r
1196    z:=new gas_bill;  \r
1197 where z is a reference variable of type gas_bill. Remote access to the\r
1198 attributes of prefixed class is standard:\r
1199  \r
1200    z.dollars:=500.5; z.year:=1982; z.month:=3; z.day:=8;\r
1201    z.cube_meters:=100000;\r
1202  \r
1203   Consider now the example of a class with parameters.\r
1204  \r
1205   Assume that in a program a class:\r
1206  \r
1207    unit id_card: class(name:string,age:integer);  \r
1208    end id_card;  \r
1209  \r
1210 and its extension:\r
1211  \r
1212    unit idf_card:id card class(first name:string);  \r
1213    end idf_card;  \r
1214  \r
1215 \r
1216 \r
1217 are declared.\r
1218 \r
1219 \r
1220   Then for  variable z of type id_card and variable t of type idf_card\r
1221 the corresponding generation statement may be the following:\r
1222  \r
1223    z:=new id_card("kreczmar",37);  \r
1224    t:=new idf_card("Kreczmar",37,"Qntoni");  \r
1225  \r
1226 Thus the formal parameters of a class are concatenated with the formal\r
1227 parameters of its prefix.\r
1228   One can still extend class idf_card. For instance:\r
1229  \r
1230   unit idr_card:idf_card class;  \r
1231     var children_number:integer;  \r
1232     var birth_place:string;  \r
1233   end idr_card;  \r
1234  \r
1235   Prefixing  allows  to  build  up hierarchies of  classes.  Each  one\r
1236 hierarchy  has a  tree structure. A  root  of  such a tree is  a class\r
1237 without  prefix. One class  is a  successor of  another class iff  the\r
1238 first is prefixed by the latter one.\r
1239  \r
1240   Consider the prefix structure:\r
1241  \r
1242                    A\r
1243                  . . .\r
1244                 .  .  .\r
1245                .   .   .\r
1246              B.    .C   .D\r
1247                .\r
1248                 .\r
1249                  .E\r
1250                   .\r
1251                    .\r
1252                     .F\r
1253                    . .\r
1254                   .   .\r
1255                 G.     .H\r
1256  \r
1257   Class H has  a  prefix sequence A, B, E, F,  H. Let  a,  b,  ... , h\r
1258 denote the corresponding unique attributes of classes  A, B, ... ,  H,\r
1259 respectively. The objects of these classes have the following forms:\r
1260  \r
1261       ------------  ------------  ------------  ------------\r
1262       |     a    |  |     a    |  |     a    |  |     a    |\r
1263       ------------  ------------  ------------  ------------\r
1264        object A     |     b    |  |     c    |  |     d    |\r
1265                     ------------  ------------  ------------\r
1266                       object B      object C      object D\r
1267 \r
1268 \r
1269 \r
1270       ------------  ------------  ------------  ------------\r
1271       |     a    |  |     a    |  |     a    |  |     a    |\r
1272       ------------  ------------  ------------  ------------\r
1273       |     b    |  |     b    |  |     b    |  |     b    |\r
1274       ------------  ------------  ------------  ------------\r
1275       |     e    |  |     e    |  |     e    |  |     e    |\r
1276       ------------  ------------  ------------  ------------\r
1277        object E     |     f    |  |     f    |  |     f    |\r
1278                     ------------  ------------  ------------\r
1279                       object F    |     g    |  |     h    |\r
1280                                   ------------  ------------\r
1281                                    object G       object H\r
1282  \r
1283   Let Ra, Rb,..., Rh  denote reference variables of types A, B,..., H,\r
1284 respectively. Then the following expressions are correct:\r
1285  \r
1286   Ra.a,  Rb.b, Rb.a,  Rg.g, Rg.f, Rh.h, Rh.f, Rh.e, Rh.b, Rh.a  etc.\r
1287  \r
1288   Variable Ra may  designate the object of class B (or C,..., H), i.e.\r
1289 the statement:\r
1290  \r
1291    Ra:=new B     \r
1292  \r
1293 is  legal.  But then attribute b is not accessible through dot via Ra,\r
1294 i.e. Ra.b is incorrect. This follows from insecurity  of such a remote\r
1295 access. In fact, variable Ra may point  any object of a class prefixed\r
1296 by A, in particular, Ra may point the object of A itself, which has no\r
1297 attribute  b.  If  Ra.b  had been  correct,  a  compiler  should  have\r
1298 distiguish the cases Ra points to the object of A or not. But this, of\r
1299 course, is undistinguishable at compilation time.\r
1300   To allow, however, the user's access to attribute b (after instruc tion Ra:= n\r
1301  \r
1302    Ra qua B  \r
1303 \r
1304   The correctness of  this expression  is checked at run  time. If  Ra\r
1305 designates an object of B or prefixed ba B, the type of the expression\r
1306 is  B. Otherwise the expression is erroneous. Thus, for instance,  the\r
1307 expressions:\r
1308  \r
1309    Ra qua G.b,    Ra qua G.e    etc.  \r
1310 enable remote access to the attributes b, c, ... via Ra.\r
1311  \r
1312   So far the question of attribute concatenation was merely discussed.\r
1313 However the sequences of statements can be also concatenated.\r
1314   Consider  class  B  prefixed  with  class  A.  In  the  sequence  of\r
1315 statements of  class A the keyword inner may occur anywhere, but  only\r
1316 once. The sequence of  statements of class B  consists of the sequence\r
1317 of  statements of  class A with  inner  replaced  by  the sequence  of  \r
1318 statements of class B.\r
1319  \r
1320     unit A :class                    unit B:A class  \r
1321         ...                                   ...\r
1322     begin                               begin   \r
1323        ...                             |---...\r
1324                                        |                                        \r
1325                                        |\r
1326        ...                             |---...\r
1327     end A;                              end B;                                  \r
1328 \r
1329 \r
1330   In this case inner in class B  is equivalent to the empty statement.  \r
1331 If class B prefixes  another class, say C, then inner in B is replaced  \r
1332 by the sequence of statements of class C, and so on.\r
1333   If inner  does not occur explicitly, an implicit occurrence of inner  \r
1334 before the final end of a class is assumed.  \r
1335  \r
1336  Example\r
1337  -------\r
1338  \r
1339   Let class complex be declared as usual:\r
1340  \r
1341   unit complex: class(re,im:real);   \r
1342   end complex;  \r
1343  \r
1344 and assume one desires to declare a class mcomplex with the additional\r
1345 attribute module. In order the generation of class mcomplex define the\r
1346 value of attribute module, one can declare a class:\r
1347  \r
1348   unit mcomplex:complex class;  \r
1349   var module:real;  \r
1350   begin  \r
1351     module:=sqrt(re*re+im*im)\r
1352   end mcomplex;  \r
1353  \r
1354   Class mcomplex may be still extended:\r
1355  \r
1356   unit pcomplex:mcomplex class;  \r
1357   var alfa:real;  \r
1358   begin  \r
1359     alfa:=arccos(re/module)\r
1360   end pcomplex;  \r
1361  \r
1362   For these declarations each generation of class mcomplex defines the\r
1363 value of  attribute module, each generation of class pcomplex  defines\r
1364 the values of attributes module and alfa.\r
1365   For reference  variables  z1, z2 z3 of  type complex, the  following\r
1366 sequence of statements illustrates the presented constructs:\r
1367  \r
1368   z1:=new complex(0,1);       \r
1369   z2:=new mcomplex(4,7);  \r
1370   z3:=new pcomplex(-10,12);  \r
1371   if z2 qua mcomplex.module > 1                   \r
1372   then  \r
1373       z1:=z2;\r
1374   fi;  \r
1375   if z3 qua pcomplex.alfa < 3.14   \r
1376   then   \r
1377      z3.re:=-z3.re;  z3.alfa:=z3.alfa+3.14;\r
1378   fi;  \r
1379   z1 qua mcomplex.module:= 0;   \r
1380   z1.re,z1.im:=0;                                \r
1381 \r
1382 \r
1383  Example:\r
1384  --------\r
1385   Binary search tree (Bst) is a binary tree where for  each node x the\r
1386 nodes in  the left subtree are  less than  x, the  nodes  in the right\r
1387 subtree are greater than  x.  It is the well-known exercise to program\r
1388 the algorithms for the following operations on Bst:\r
1389    member(x) = true iff x belongs to Bst\r
1390    insert(x),  enlarge Bst with x, if x does not yet belong to Bst\r
1391  \r
1392   We define both these operations in a class:\r
1393  \r
1394   unit Bst: class;  \r
1395     unit node: class(value:integer);  (*  tree node  *)   \r
1396       var left,right:node;  \r
1397     end node;  \r
1398     var root:node;  \r
1399     unit help: class(x:integer);      (* auxiliary class *)  \r
1400     var p,q:node;  \r
1401     begin   \r
1402        q:=root;\r
1403        while q=/= none  \r
1404        do  \r
1405          if x < q.value     \r
1406          then  \r
1407            p:=q; q:=q.left;\r
1408            repeat  (* jump to the beginning of a loop *)    \r
1409          fi;  \r
1410          if q.value < x  \r
1411          then  \r
1412            p:=q; q:=q.right;  repeat  \r
1413          fi;  \r
1414          exit  \r
1415        od;  \r
1416        inner                       (* virtual instruction to be  \r
1417     end help;  \r
1418     unit member:help function:boolean;  \r
1419       (* x is a formal parameter derived from the prefix help *)\r
1420     begin  \r
1421        result:=q=/=none  \r
1422     end member;  \r
1423     unit insert:help procedure;  \r
1424       (* x is a formal parameter derived from the prefix help *)\r
1425     begin    \r
1426        if q=/=none then return fi;   \r
1427        q:=new node(x);  \r
1428        if p=none then root:=q; return fi;  \r
1429        if p.value < x then p.right:=q else p.left:=q fi;  \r
1430     end insert;  \r
1431   begin  \r
1432     inner;  \r
1433   end Bst;  \r
1434  \r
1435   In  the  example  the  common  actions  of  member  and  insert  are\r
1436 programmed in class  help. Then  it  suffices to use  class  help as a\r
1437 prefix of function member and  procedure insert, instead  of redundant\r
1438 occurrences of the corresponding sequence of statements in both units. \r
1439 \r
1440 \r
1441   Class Bst may be applied as follows:\r
1442  \r
1443   var X,Y:Bst;  \r
1444   begin  \r
1445        X:=new Bst;  Y:=new Bst;  \r
1446        call X.insert(5);  \r
1447        if Y.member(-17) then ....  \r
1448   end  \r
1449  \r
1450   As shown in  the declaration of Bst, class may prefix not only other\r
1451 classes but also procedures and functions.  Class may prefix blocks as\r
1452 well.\r
1453  \r
1454  Example:\r
1455  --------\r
1456   Let class push_down (p. 5) prefix a block:\r
1457  \r
1458    pref push_down(1000) block  \r
1459    var ...   \r
1460    begin  \r
1461       ...\r
1462       call push(50); ...   \r
1463       i:=pop;\r
1464       ...\r
1465    end   \r
1466  \r
1467   In the above block prefixed with class push_down one can use pop and\r
1468 push as local attributes. (They are  local since the block is embedded\r
1469 in the prefix push down.)\r
1470  \r
1471  Example:\r
1472  --------\r
1473    pref push down(1000) block  \r
1474    begin  \r
1475       ...\r
1476       pref Bst block  \r
1477       begin  \r
1478       (* in this block both structures push down and Bst are visible *)\r
1479         call push(50);  \r
1480         call insert(13);  \r
1481         if member(10) then ...  \r
1482         i:=pop;\r
1483         ...\r
1484       end  \r
1485    end    \r
1486  \r
1487   In place  where  classes push_down  and Bst are visible  together  a\r
1488 block  prefixed with  Bst may  be  nested  in  a  block  prefixed with\r
1489 push_down (or vice versa). In the inner block both data structures are\r
1490 directly accessible. Note that this construct is illegal in Simula 67. \r
1491 \r
1492 \r
1493 8. Formal types\r
1494 ###############\r
1495  \r
1496   Formal types  serve  for  unit parametrization with  respect  to any\r
1497 non-primitive type.\r
1498  \r
1499  Example:\r
1500  --------\r
1501  \r
1502   unit Gsort:procedure(type T; A:arrayof T; function less(x,y:T):boolean);      \r
1503   var n,i,j:integer; var x:T;  \r
1504   begin   \r
1505     n:=upper(A);\r
1506     for i:=2 to n  \r
1507     do    \r
1508       x:=A(i); j:=i-1;\r
1509       do  \r
1510         if less(A(j),x) then exit fi;   exit fi \r
1511         A(j+1):=A(j); j:=j-1;\r
1512         if j=0 then exit fi;\r
1513       od;  \r
1514       A(j+1):=x;\r
1515     od  \r
1516   end Gsort;  \r
1517  \r
1518   Procedure Gsort  (the generalization of procedure sort from p.4) has\r
1519 type parameter T. A corresponding actual parameter may be an arbitrary\r
1520 non-primitive  type.  An actual parameter corresponding to A should be\r
1521 an array of elements of the actual type T. Function less should define\r
1522 the linear ordering on the domain T.\r
1523   For instance, the  array A of type bill (cf p.7) may  be sorted with\r
1524 respect to attribute dollars , if the function:\r
1525  \r
1526   unit less: function(t,u:bill):boolean;  \r
1527   begin  \r
1528     result:=t.dollars <= u.dollars\r
1529   end less;  \r
1530  \r
1531 is used as an actual parameter:\r
1532  \r
1533   call Gsort(bill,A,less);  \r
1534  \r
1535   If the user desires to sort A with respect to date, it is sufficient\r
1536 to declare :\r
1537  \r
1538   unit earlier:function(t,u:bill):boolean;  \r
1539   begin  \r
1540     if t.year < u.year then result:= true; return  fi;  \r
1541     if t.year=u.year   \r
1542     then  \r
1543       if t.month < u.month then result:=true; return fi;  \r
1544       if t.month=u.month then result:=t.day<=u.day  fi  \r
1545     fi;  \r
1546    end earlier;  \r
1547  \r
1548 and to call: call Gsort(bill,A,earlier);  \r
1549 \r
1550 \r
1551 9. Protection techniques\r
1552 ########################\r
1553  \r
1554   Protection techniques  ease  secure  programming. If  a  program  is\r
1555 large,  uses some system classes, is designed by a team etc., this  is\r
1556 important  (and non-trivial) to impose some  restrictions on access to\r
1557 non-local attributes.\r
1558   Let  us consider a  data structure declared as  a class. Some of its\r
1559 attributes should  be accessible for  the class  users  ,  the  others\r
1560 should not. For instance, in class Bst (p.7) the attributes member and\r
1561 insert  are to be  accessible. On  the other hand the attributes root,\r
1562 node and help should not be accessible, even for a meddlesome user. An\r
1563 improper use of them may jeopardize the data structure invariants.\r
1564   To forbid  the access to some  class attributes  the three following\r
1565 protection mechanisms are provided:\r
1566  \r
1567   close, hidden, and taken.  \r
1568  \r
1569   The protection close defined in a class forbids remote access to the  \r
1570 specified attributes. For example, consider the class declaration:\r
1571  \r
1572   unit A: class;  \r
1573     close x,y,z;  \r
1574     var  x: integer, y,z:real;  \r
1575     ....\r
1576   end  \r
1577  \r
1578   Remote  access  to  the  attributes  x,y,z  from  outside  of  A  is\r
1579 forbidden.\r
1580  \r
1581   The protection  hidden (with akin syntax) does not allow  to use the  \r
1582 specified  attributes  form outside of A  neither by the remote access\r
1583 nor in the units prefixed by A. The only way to use a hidden attribute\r
1584 is to use it within the body of class A.\r
1585   Protection taken defines these attributes derived from prefix, which  \r
1586 the  user wishes  to  use in  the  prefixed unit. Consider  a  unit  B\r
1587 prefixed by a class A. In unit B one may specify the  attributes  of A\r
1588 which are used in B. This protects the user against an unconscious use\r
1589 of an attribute of class A in unit B (because of identifier conflict).\r
1590 When  taken  list does not occur  ,  then by  default,  all non-hidden\r
1591 attributes of class A are accessible in unit B. \r
1592 \r
1593 \r
1594 10. Programmed deallocation\r
1595 ###########################\r
1596  \r
1597     The classical methods  implemented to deallocate class objects are\r
1598 based on reference counters or garbage collection. Sometimes  the both\r
1599 methods may  be  combined.  A reference counter is a  system attribute\r
1600 holding  the number of references pointing to  the given object. Hence\r
1601 any change of  the value of  a reference variable  X is followed by  a\r
1602 corresponding  increase  or  decrease  of  the  value of its reference\r
1603 counter. When the  reference counter becomes equals 0,  the object can\r
1604 be deallocated.\r
1605   The deallocation of class objects may  also occur during the process\r
1606 of garbage  collection. During this  process  all unreferenced objects\r
1607 are found and removed (while memory may be  compactified). In order to\r
1608 keep the garbage collector able to collect all the  garbage,  the user\r
1609 should clear all reference  variables  ,  i.e.  set to None,  whenever\r
1610 possible.  This  system has  many  disadvantages.  First  of all,  the\r
1611 programmer is  forced  to clear  all  reference variables, even  those\r
1612 which are of auxiliary character.  Moreover,  garbage  collector is  a\r
1613 very expensive  mechanism and  thus it can  be used  only in emergency\r
1614 cases.\r
1615   In  LOGLAN a dual operation  to the  object generator, the so-called\r
1616 object deallocator is provided. Its syntactic form is as follows:\r
1617  \r
1618            kill(X)   \r
1619  \r
1620 where  X  is  a reference expression.  If the value of X points to  no\r
1621 object (none) then kill(X) is equivalent to an empty statement. If the  \r
1622 value of X points to an object O, then after the execution of kill(X),  \r
1623 the object O is  deallocated. Moreover all  reference variables  which\r
1624 pointed to O are set to none. This deallocator provides full security,  \r
1625 i.e. the  attempt to  access the  deallocated  object O is checked and\r
1626 results in a run-time error.\r
1627   For example:\r
1628  \r
1629       Y:=X;  kill(X);   Y.W:=Z;  \r
1630  \r
1631 causes the same run-time error as:\r
1632  \r
1633       X:=none;  X.W:=Z;  \r
1634  \r
1635   The system of  storage management is arranged in such a way that the\r
1636 frames  of  killed  objects  may be  immediately  reused  without  the\r
1637 necessity of calling  the garbage collector, i.e.  the  relocation  is\r
1638 performed automatically. There is nothing for it but to  remember  not\r
1639 to use remote access to  a  killed object. (Note that the same problem\r
1640 appears when remote access X.W is used and X=none).     \r
1641 \r
1642  Example:\r
1643  --------\r
1644  \r
1645   Below  a  practical   example  of  the  programmed  deallocation  is\r
1646 presented.  Consider  class Bst (p.7). Let us define a  procedure that\r
1647 deallocates the  whole tree  and is called with the termination of the\r
1648 class Bst.\r
1649  \r
1650   unit Bst:class;  \r
1651     (* standard declarations list of  Bst *)\r
1652    unit kill_all:procedure(p:node);  \r
1653    (* procedure kill_all deallocates a tree with root p *)\r
1654    begin  \r
1655      if p= none then return fi;  \r
1656      call kill_all(p.left);  \r
1657      call kill_all(p.right);   \r
1658      kill(p)  \r
1659    end kill_all;  \r
1660    begin  \r
1661      inner;  \r
1662      call kill_all(root)   \r
1663   end Bst;       \r
1664  \r
1665   Bst may be applied as a prefix:\r
1666  \r
1667   pref Bst block  \r
1668     ...\r
1669   end  \r
1670  \r
1671 and automatically will cause the deallocation  of the whole tree after\r
1672 return to call kill_all(root) from the prefixed block.  \r
1673  \r
1674   To use  properly this  structure by  remote accessing one must  call\r
1675 kill_all by himself:\r
1676  \r
1677   unit var X,Y:Bst;  \r
1678     ...\r
1679   begin  \r
1680      X:=new Bst;  Y:=new Bst;  \r
1681         ...\r
1682      (* after the structures' application *)\r
1683      call X.kill_all(X.root);   \r
1684      kill(X);  \r
1685      call Y.kill_all(Y.root);  \r
1686      kill(Y);  \r
1687      ...\r
1688   end  \r
1689  \r
1690   Finally note that  deallocator  kill enables  deallocation of  array  \r
1691 objects, and suspended coroutines and processes as well (cf p.13). \r
1692 \r
1693 \r
1694 11.  Exception handling\r
1695 #######################\r
1696  \r
1697   Exceptions are  events that  cause  interruption of  normal  program\r
1698 execution.  One  kind  of exceptions  are those  which are raised as a\r
1699 result of some run time errors. For  instance, when an attempt is made\r
1700 to access  a  killed object, when the result of numeric operation does\r
1701 not  lie within  the  range,  when the dynamic storage allocated to  a\r
1702 program is exceeded etc.\r
1703   Another kind of exceptions  are those which are raised explicitly by\r
1704 a user (with the execution of the raise statement).\r
1705   The response to  exceptions (one or more) is defined by an exception\r
1706 handler. A handler may appear at the end of declarations  of any unit.\r
1707 The  corresponding  actions  are  defined as sequences  of  statements\r
1708 preceded by keyword when and an exception identifier.  \r
1709  \r
1710  Example:\r
1711  --------\r
1712  \r
1713   In procedure squareeq (p.3) we wish to include the case when a=0. It\r
1714 may be treated as an exception (division by zero).\r
1715  \r
1716   unit squareeq(a,b,c:real;output xr,xi,yr,yi:real);  \r
1717   var delta:real;  \r
1718   handlers  \r
1719     when division_by_zero:  \r
1720        if b =/= 0      \r
1721        then   \r
1722          xi,yr,yi:=0; xr:=-c/b; terminate  \r
1723        else   \r
1724          raise Wrong_data(" no roots")  \r
1725        fi; \r
1726   end  \r
1727   begin  \r
1728     ...\r
1729   end squareeq;  \r
1730  \r
1731   The  handler  declared  in  that  procedure  handles  the  only  one\r
1732 exception (division_by_zero).\r
1733   When an exception is raised,  the corresponding handler  is searched\r
1734 for, starting from the active  object and going through return traces.\r
1735 If there is no object  containing the declaration of the handler, then\r
1736 the program (or the  corresponding  process) is  terminated. Otherwise\r
1737 the control is transferred to the first found handler. \r
1738 \r
1739 \r
1740 \r
1741   In  our example  the handler is declared within the  unit itself, so\r
1742 control is passed to a sequence:\r
1743  \r
1744   if b=/=0   \r
1745   ...\r
1746  \r
1747   Therefore, when  b=/=0, the  unique root of square equation  will be\r
1748 determined and the procedure will be normally terminated (terminate).   \r
1749   In general,  terminate causes that  all  the objects are terminated,  \r
1750 starting from  that one where the exception was  raised and ending  on\r
1751 that  one  where  the  handler  was found.  Then  the  computation  is\r
1752 continued in a normal way.\r
1753   In our example, when b=0, a new exception is raised by the user. For\r
1754 this  kind of  exceptions , the  exception itself  should  be declared\r
1755 (because it is not  predefined as a  run time error). Its  declaration\r
1756 may have parameters which are  transmitted to a handler. The exception\r
1757 declaration need not  be visible by the exception handler. However the\r
1758 way the handler is searched for does not differ from the standard one.\r
1759   Consider an example:\r
1760  \r
1761   block\r
1762    signal Wrong_data(t:string);                        \r
1763    unit squareeq: \r
1764         ...\r
1765    end squareeq;\r
1766    ...\r
1767   begin  \r
1768       ...\r
1769   end  \r
1770  \r
1771   Exception Wrong_data may be raised wherever its declaration  (signal  \r
1772 Wrong_data)  is visible.  When  its  handler is  found  the  specified\r
1773 sequence  of  actions is performed.  In  the  example  above different\r
1774 handlers may  be  defined  in  inner  units to  the  main block  where\r
1775 squereeq is called.\r
1776   The case a=0 could be included , of course, in a normal way, i.e. by\r
1777 a corresponding conditional statement occurring in the procedure body.\r
1778 But the  case a=0  was assumed  to be exceptional (happens  scarcely).\r
1779 Thus the evaluation  of condition a=0 would be mostly  unnecessary. As\r
1780 can be noticed thanks to  exceptions  the above problem can be  solved\r
1781 with the minimal waste of run time. \r
1782  \r
1783 \r
1784 \r
1785 12. Separate compilation  (this section does not apply to PC version)\r
1786 ########################\r
1787  \r
1788 \r
1789 \r
1790 13. Processes\r
1791 #############\r
1792  \r
1793   The implementation of processes is different (May 1988) c.f. user's manual. \r
1794 \r
1795   Process in LOGLAN-82  is  a natural generalization  of coroutine (cf\r
1796 p.6).   Coroutines  are  units   which  once  generated  may   operate\r
1797 independently, each one treated as a separate process. For coroutines,\r
1798 however,  an essential  assumption is  established; namely,  when  one\r
1799 coroutine  object  is  reactivated,  the active one must  be suspended\r
1800 (i.e.  there which  is onle  one control is switched between coroutine\r
1801 objects). When processes are  used,  the  activation of a new  process\r
1802 does  not require the active one to be suspended. So many  objects may\r
1803 be simultaneously active.\r
1804   The statement  that  reactivates  a  suspended  process  X  (without\r
1805 suspention of the active one) has the form:\r
1806  \r
1807                                resume(X)                                \r
1808  \r
1809   The  main   problem   of   parallel   programming   is,  of  course,\r
1810 synchronization.  Elementary synchronization  in LOGLAN-82 is achieved\r
1811 by  two-valued  semaphores  and   some  number  of  simple  statements\r
1812 operating on them.\r
1813   A semaphore variable controls the entry to a critical region, i.e. a\r
1814 sequence of statements that  may be executed  by the one process only.\r
1815 When  a semaphore is  open, the corresponding critical region is free.\r
1816 When a semaphore is closed, it means the corresponding critical region\r
1817 is just executed by a certain process.\r
1818  \r
1819   These  are  the  simple  indivisible  statements  that   operate  on\r
1820 semaphores:\r
1821  \r
1822    lock(S)  -   If semaphore S is open,  the given  process  enters   \r
1823                 the   critical   region   guarded   by   S   ,  and\r
1824                 simultaneously,  semaphore  S  becomes  closed.  If\r
1825                 semaphore S  is already  closed,  the given process\r
1826                 waits until the critical region is open (by another\r
1827                 process).\r
1828    unlock(S)-   If semaphore S  is  closed, then  it  becomes open.   \r
1829                 Otherwise the statement is empty.\r
1830    stop(S)  -   The statement causes  semaphore S to  be open,  and   \r
1831                 simultaneously,  it   stops   the   given   process\r
1832                 execution.  The  statement  may be  used  without a\r
1833                 parameter,  and  then, it stops the  given  process\r
1834                 execution.\r
1835   Moreover, only those three above statements may change the values of\r
1836 semaphore variables.\r
1837   In general,  several processes may  wait  for  an entry  to the same\r
1838 critical region. When the process executing this critical region opens\r
1839 the semaphore  (by  unlock or stop),  one  of the waiting processes is  \r
1840 reactivated and enters the region. The way such a process  is selected\r
1841 is  not  defined  by  the  language. The  user  must assume  that this\r
1842 selection is performed arbitrarily. \r
1843 \r
1844 \r
1845 \r
1846  Example:\r
1847  --------\r
1848  \r
1849   In  the example  an input stream  of  real numbers  is  copied.  The\r
1850 copying process is  parallelized in such a  way that when  process get\r
1851 reads  the  next number, the  process  put writes  simultaneously  the\r
1852 number read in the preceding step. The input stream ends with 0.\r
1853  \r
1854   block   \r
1855     var in_buf,out_buf:real, completed:boolean, sem:semaphore;  \r
1856     var counter:integer,get:get_type,put:put_type;  \r
1857     unit cobegin:procedure;  (* called by the main program *)   \r
1858     begin   \r
1859       lock(sem);     (* critical region *)  \r
1860       resume(get);   (* activate reading *)  \r
1861       resume(put);   (* activate writing *)  \r
1862       stop(sem);     (* exit from critical region *)  \r
1863     end  cobegin;   \r
1864     unit coend: procedure;  \r
1865     begin            (* called by get and put *)  \r
1866       lock(sem);     (* entry to critical region *)   \r
1867       if counter=0     \r
1868       then           (* one process entered *)  \r
1869         counter:=1\r
1870       else           (* two processes entered *)                                \r
1871         counter:=0;\r
1872         resume(main) (* reactivate main program *)  \r
1873       fi;\r
1874       stop(sem)      (* exit from critical region *)   \r
1875     end coend;\r
1876  \r
1877     unit get_type:process;  \r
1878     begin   \r
1879        return;\r
1880        do   \r
1881          read(in_buf);\r
1882          if in_buf=0   \r
1883          then        (* end of data *)  \r
1884             completed:=true\r
1885          fi;  \r
1886          call coend    \r
1887        od      \r
1888     end get_type;\r
1889  \r
1890     unit put_type:process;  \r
1891     begin\r
1892        return;  \r
1893        do  \r
1894          write(out_buf);\r
1895          call coend;  \r
1896        od   \r
1897     end put_type;   \r
1898 \r
1899     begin            (* main process *)     \r
1900       read(in_buf);\r
1901       get:=new get_type;  \r
1902       put:=new put_type;  \r
1903       do   \r
1904         out_buf:=in_buf;\r
1905         call cobegin;     \r
1906         if completed then exit fi;  \r
1907       od; \r
1908       kill(get);  \r
1909       kill(put);  \r
1910     end;   \r
1911  \r
1912   Two  procedures cobegin and  coend synchronize the  execution of the\r
1913 main loop. Procedure cobegin implements fork operator, procedure coend\r
1914 called from processes put and get implements the end of fork operator.\r
1915 Variable count defines the  number of processes that called  procedure\r
1916 coend. By an  easy modification one can generalize these procedures in\r
1917 order to  implement the general k-fork and end of k-fork operators (if\r
1918 count can assume the values 0,1,...,k-1).\r
1919  \r
1920   Finally, let us present an example of a class that realizes  Hoare's\r
1921 monitors  (cf. [2]).  Monitor  is  a  structure  that synchronizes the\r
1922 access to a  common pool of data. The number and  kinds  of these data\r
1923 are defined by  the user.  Monitor task is  only to  give non-conflict\r
1924 access to  it. The access to a  monitor is  realized  by the so-called\r
1925 entry procedures. Entry procedure has a prefix entry which  guarantees\r
1926 that only one such a procedure may enter the monitor.\r
1927   In order to  allow scheduling of processes that entered the monitor,\r
1928 two specialized procedures operating on the inner  monitor queues  are\r
1929 provided.\r
1930  \r
1931    delay(Q)    - stops  the  execution of the  process and puts  it\r
1932                 into a queue Q, the entry to the monitor is free,\r
1933    continue(Q) - resumes the execution of the first  process from a\r
1934                 queue  Q (if Q is non-empty, otherwise the entry to\r
1935                 the monitor is free).\r
1936  \r
1937   As can  be  easily seen, the  correct use  of  these  constructs  is\r
1938 achieved when continue is called as the  last  statement  of  an entry\r
1939 procedure.\r
1940  \r
1941   The declaration of the class Monitor is as follows:  \r
1942 \r
1943 \r
1944 unit Monitor : queue class;  \r
1945   hidden sem,queue;      (* hidden protects attributes sem and queue *)   \r
1946   var sem:semaphore; (* sem is the  semaphore guarding the monitor entry *)   \r
1947  \r
1948   unit entry: class;    (* all entry procedures must have prefix entry  \r
1949                        which realized non-conflict access to Monitor *)\r
1950     var busy:boolean;     (* busy is true iff  continue(Q) was executed   \r
1951     hidden busy;  \r
1952     unit delay: procedure(Q:queue);  \r
1953     begin   \r
1954       call Q.into(this process);\r
1955         (* put the active process into queue Q *)  \r
1956       stop(sem) \r
1957         (* free the monitor access, halt the active process  *)       \r
1958     end delay;  \r
1959     unit continue:procedure(Q:queue);  \r
1960      (* continue can be called as the last statement of an entry procedure *)\r
1961     begin  \r
1962       if not Q.empty   \r
1963       then  \r
1964          busy:=true\r
1965          resume(Q.out);     (* resume the next process from queue Q *)  \r
1966       fi;  \r
1967     end continue;\r
1968   begin                                 (* beginning of the prefix entry *)  \r
1969     lock(sem);                           (* entry to the critical region *)  \r
1970     inner;                     (* the virtual body of an entry procedure *)  \r
1971     if not busy   \r
1972     then  \r
1973       unlock(sem)     (* free the monitor access, unless continue  \r
1974     fi;  \r
1975   end entry;  \r
1976 end Monitor;                                \r
1977 \r
1978 \r
1979   The mail-box structure which receives and sends the items  of type T\r
1980 may be implemented as the following class prefixed by Monitor:\r
1981  \r
1982   unit Buffering:Monitor class(type T;size:integer);  \r
1983     var Pool:arrayof T,count,in_index,out_index:integer;  \r
1984     var  readers_queue,writers_queue:queue;  \r
1985     unit writer:entry procedure(r:T);  \r
1986     begin\r
1987       if count=size then call delay(writers_queue) fi;                  in_index\r
1988       Pool(in_index):=r; call continue(readers_queue);  \r
1989     end writer;     \r
1990     unit reader:entry procedure(output r:T);  \r
1991     begin\r
1992       if count=0 then call  delay(readers_queue) fi;  \r
1993       out_index:=out_index mod size +1; count:=count-1;  \r
1994       r:=Pool(out_index); call continue(writers_queue);  \r
1995     end reader;       \r
1996   begin\r
1997     new_array Pool dim (1:size);  \r
1998     readers_queue:=new queue; writers_queue:=new queue;                    \r
1999   end Buffering;    \r
2000 \r
2001 \r
2002 References.\r
2003 ###########\r
2004  \r
2005   [1]  Dahl O-J.,Myhrhaug B,Nygaard K.:  Common  Base  Language  . NCC\r
2006 S-22, October 1970\r
2007   [2] Hoare C.A.R.: Monitors, an operating system structuring concept.\r
2008 CACM,vol.17,N.10,October 1974,pp.549-57\r
2009   [3] LOGLAN-82 Report ,  Warsaw, 1982\r
2010 \1a