Added upstream from http://ftp.icm.edu.pl/pub/loglan/
[loglan.git] / HTML / signals.htm
1 <!doctype html public "-//IETF//DTD HTML//EN">\r
2 <HTML>\r
3 \r
4 <HEAD>\r
5 \r
6 <TITLE>Signals</TITLE>\r
7 \r
8 <META NAME="GENERATOR" CONTENT="Internet Assistant for Word 1.0Z">\r
9 <META NAME="AUTHOR" CONTENT="NOM">\r
10 </HEAD>\r
11 \r
12 <BODY>\r
13 \r
14 <H4>Loglan'82 Programming Language<BR>\r
15 ______________________________</H4>\r
16 \r
17 <H1>Signallling Exceptional Situations &amp; Treatment of Exceptions\r
18 <BR>\r
19 </H1>\r
20 \r
21 <H2>1. MOTIVATIONS</H2>\r
22 \r
23 <P>\r
24 Programs which we are constructing should be <I>robust</I>, i.e.\r
25 they should not fail even if the values of parameters(data) for\r
26 a procedure, function etc.are out of the domain of a procedure\r
27 in question. The minimal requirement would be: if the data do\r
28 not belong to the assumed domain of program then this information\r
29 should be displayed. However, in many cases the programmer is\r
30 able to react at errors which appear during the execution of a\r
31 program.<BR>\r
32 Sometimes she(he) is able to use the mechanisms build for the\r
33 use in unusual situations in a non-standard, elegant way (see\r
34 the example MAZE below). However we are not suggesting this to\r
35 turn into your style or &quot;maniere&quot; of writing programs.\r
36 <P>\r
37 Another keyword applicable here is security. If we wish to construct\r
38 a secure program then we need appropriate tools to assure this\r
39 property.<BR>\r
40 What will be called an exceptional situation?<BR>\r
41 <B>Example 1<BR>\r
42 </B>Let us consider the data structure STACKS with operations\r
43 <BR>\r
44 \r
45 <UL>\r
46 <LI>pop(s)\r
47 <LI>push(e,s)\r
48 <LI>top(s)\r
49 <LI>empty(s)\r
50 </UL>\r
51 \r
52 <P>\r
53 It will be an exceptional situation, if one will call pop for\r
54 an empty stack or will call push for a full stack. Obviously we\r
55 can require that the user never calls pop(s) when s in an empty\r
56 stack, but our program can be more flexible i.e. clever and we\r
57 can foresee eventual unproper usage of the partial operations\r
58 from our module. <BR>\r
59 \r
60 <P>\r
61 Another example of exceptional situation arrive when one thinks\r
62 of getting an element of an array in such a way that the index\r
63 of the element is outside the limits of the array. Obviously we\r
64 can advise to replace any occurrency of a subscripted variable\r
65 A[i] by a guarded command like the following one\r
66 <PRE>\r
67    if lower(A)-1 &lt; i and i &lt; upper(A)+1 \r
68    then \r
69        y := A[i]\r
70    else\r
71       (* put here your reaction for the array index error *)\r
72    fi <BR>\r
73 \r
74 </PRE>\r
75 \r
76 <P>\r
77 which replaces the instruction\r
78 <PRE>\r
79    y := A[i]\r
80 </PRE>\r
81 \r
82 <P>\r
83 .<BR>\r
84 The advice consequently applied throughout a program would make\r
85 it unreadable, thus opening the doors for numerous errors. A solution\r
86 lies in signalling an error or exception and propagating such\r
87 a signal to the nearest object or dynamic instance of a procedure\r
88 which contain a recipe (a handler) how to react. Some exceptional\r
89 situations are detected automatically by the Loglan system (see\r
90 the list of run-time errors) . Some exceptions may be signalled\r
91 trough the <B>raise</B> instruction.<BR>\r
92 \r
93 <H2>2. SYNTAX</H2>\r
94 \r
95 <P>\r
96 Treatment of signals in Loglan is distributed onto different fragments\r
97 of a program.\r
98 <UL>\r
99 <LI>(a) declaration of signal\r
100 <LI>(b) handlers of exceptions\r
101 <LI>(c) <B>raise</B> instruction\r
102 <LI>(d) <B>return</B>, <B>terminated</B>, <B>wind</B>: the ways\r
103 to terminate handlers\r
104 <LI>(e) <B>lastwill</B> \r
105 </UL>\r
106 \r
107 <P>\r
108 In order to do with signals and exceptional situations one must:\r
109 <BR>\r
110 \r
111 <OL>\r
112 <LI>declare a signal,<BR>\r
113 \r
114 <LI>propagate the signal toward a handler,<BR>\r
115 \r
116 <LI>write one or more modules which will handle the signal,<BR>\r
117 \r
118 <LI>exit from a handler,<BR>\r
119 \r
120 <LI>the latter action may necessitate the execution of the lastwill\r
121 instructions for the instances of modules that may be killed by\r
122 such an exit.<BR>\r
123 \r
124 </OL>\r
125 \r
126 <H2>3. SEMANTICS</H2>\r
127 \r
128 <H3>(a) Signal declaration <BR>\r
129 </H3>\r
130 \r
131 <P>\r
132 A signal declaration consists of keyword <B>signal</B> and the\r
133 list of names of signals we are going to use together with eventual\r
134 lists of formal parameters (the parameters of signals are not\r
135 obligatory however ), e.g. <BR>\r
136 \r
137 <PRE>\r
138 <B>signal</B> empty_stack(s:stack),\r
139         no_record(r:key),\r
140         stackoverflow; \r
141 </PRE>\r
142 \r
143 <P>\r
144 Declaration of signal(s)may appear anywhere in the declaration\r
145 part of a module. <BR>\r
146 \r
147 <H3>(b) Modules handling signals <BR>\r
148 </H3>\r
149 \r
150 <P>\r
151 Let <I>Ni</I> be a name of a signal and <I>Si</I> a sequence of\r
152 instructions. We assume that names of signals are visible (declared).\r
153 Then we can write ( as the end part of the declaration part of\r
154 a module) the following definition of handling signals:<BR>\r
155 \r
156 <PRE>\r
157 handlers\r
158    when <I>N1</I>: <I>S1</I>;\r
159 <B>when</B> <I>N2</I>: <I>S2</I>;\r
160    ..............\r
161 <B>others </B><I>Sn\r
162 </I><B>end handlers</B>\r
163 </PRE>\r
164 \r
165 <P>\r
166 The sequence of instructions Si is called a handler for the signal\r
167 Ni. The sequence Sn appearing after the clause <B>others</B> is\r
168 a universal handler for any signal which can be propagated into\r
169 an object of this module and which is not listed above. Si - can\r
170 contain any legal instructions and moreover instructions <B>return,\r
171 wind, terminate</B> which determine the way in which this handler\r
172 will be finished, and the place where the execution of program\r
173 will be continued. <BR>\r
174 \r
175 <H3>(c) Raising a signal <BR>\r
176 </H3>\r
177 \r
178 <P>\r
179 An instruction raising a signal contains the keyword <B>raise</B>\r
180 and the name of a signal which we would like to be handled, the\r
181 list of actual parameters can be given if the signal was declared\r
182 with a list of formal parameters. <BR>\r
183 <B>Example 2<BR>\r
184 <B> raise </B></B>found;<BR>\r
185 <B>if </B>x&gt; size <B> then raise </B>too_much <B>fi;<BR>\r
186 raise</B> empty_stack(s)<BR>\r
187 <BR>\r
188 Meaning:<BR>\r
189 A signal can be raised during an execution of a program either\r
190 by run-time system (e.g. MEMERROR) or by program (cf. <B>raise</B>\r
191 instruction above) Suppose that a signal f has been raised in\r
192 an object M. For brevity, we shall use the name object also for\r
193 dynamic instances of blocks, functions, procedures. If M contains\r
194 a handler for f then this handler is executed. More precisely:\r
195 an instance H of this handler is created, the static father of\r
196 H is M, the dynamic father of H is the module in which the signal\r
197 was raised, in this case it is again M. Otherwise the search of\r
198 a handler for a signal is continued in the dynamic father of the\r
199 object M. One can also say that the signal has been propagated\r
200 to the dynamic father of the object. There are three modifications\r
201 to this scheme: 1. if M is an exception handler then signal is\r
202 propagated to the object in which M is declared 2. if M is a coroutine\r
203 or the whole program then the whole program is terminated' 3.\r
204 If M is a process then the process is terminated. When an object\r
205 containing a handler for the signal was found, the object of handler\r
206 is created. Its dynamic father is the object in which the signal\r
207 was raised, its static father is the object in which a declaration\r
208 of the handler was found. <BR>\r
209 <B>Example 3</B> <BR>\r
210 \r
211 <PRE>\r
212 <B>program</B> three;\r
213 <B>unit </B>record : class;\r
214 <B>var </B>key : T;\r
215 <B>  end</B> record;\r
216 \r
217 <B>  signal</B> no_record(k:T);\r
218 <B>unit </B>search : <B> function</B>(k:T): record;\r
219 <B>var </B>r:record;\r
220 <B>handlers\r
221         when </B>eof_error: <B>raise </B>no_record(k);\r
222 <B>end handlers</B>;\r
223 <B>   begin\r
224       do</B>         get(f,r);\r
225 <B>  if</B> equal(r.key,k)<B> then </B> result:=r; exit <B>fi</B>;\r
226 <B>od\r
227    end</B> search;\r
228 <B>handlers\r
229       when</B> no_record : ...\r
230 <B>end handlers</B>;\r
231 <B>begin</B>    ...\r
232     r:=search(k);\r
233     ...\r
234 <B>end </B>three<BR>\r
235 \r
236 </PRE>\r
237 \r
238 <P>\r
239 In this example the signal no-record is raised when the system\r
240 raises the signal eof. Thus we reinterpret the eof signal and\r
241 adapt it to our aims. <BR>\r
242 \r
243 <P>\r
244 <B>Example 4</B> <BR>\r
245 \r
246 <PRE>\r
247 <B>program</B> exercise4;\r
248    <B>signal</B> f;\r
249    <B>unit</B> A: <B>procedure</B>;\r
250    <B>begin</B>...\r
251       <B>raise</B> f;\r
252        ...\r
253    <B>end</B> A;\r
254 \r
255    <B>unit</B> B : <B>procedure</B>;\r
256      <B>handlers\r
257 </B>         <B>when</B> f : ...\r
258      <B>end</B> handlers;\r
259    <B>begin\r
260 </B>     <B>call</B> A; \r
261       ...\r
262      <B>raise</B> f;\r
263    <B>end</B> B;\r
264    <B>handlers\r
265 </B>       <B>when</B> f :...\r
266    <B>end</B> handlers;\r
267 <B>begin</B>        (*main program *)\r
268     ...\r
269    <B>raise</B> f;\r
270     ...\r
271    <B>call</B> B;\r
272     ...\r
273    <B>call </B>A\r
274 <B>end </B>exercise4.<BR>\r
275 \r
276 </PRE>\r
277 \r
278 <P>\r
279 In this example one signal has two handlers. The signal f raised\r
280 in the main program or in procedure A will be served by the handler\r
281 declared in the main program module. The signal f raised in procedure\r
282 B either directly: by <B>raise</B>, or indirectly by <B>raise</B>\r
283 in the procedure A called from B will be served by the handler\r
284 declared in procedure B.<BR>\r
285 .<BR>\r
286 <I> <BR>\r
287 </I>\r
288 <H3><I>(d) How to end a service (handling) of a signal? <BR>\r
289 </I></H3>\r
290 \r
291 <P>\r
292 When the handler finishes the service of a signal, the execution\r
293 continues in a module determined by the appropriate instruction\r
294 which should be:\r
295 <UL>\r
296 <LI><B>return</B> - then the execution is resumed in an object\r
297 where the instruction <B>raise</B> was executed,\r
298 <LI><B>wind</B> - then all objects we were searching for a handler\r
299 will be terminated (see <B>lastwill</B>) and the program continues\r
300 in the object containing the handler from the dynamic instance\r
301 in which it generated an object that later led to the signal raising,\r
302 <LI><B>terminate</B> - then all objects we were searching will\r
303 be terminated including also the object containing the handler,\r
304 the execution is continued in the dynamic father of the object\r
305 containing handler,\r
306 <LI><B>call</B> endrun - in order to halt the entire program.\r
307 <BR>\r
308 \r
309 </UL>\r
310 \r
311 <H3>(e) Lastwill <BR>\r
312 </H3>\r
313 \r
314 <P>\r
315 When an object (or a dynamic instance of a block, procedure, function)\r
316 is terminated abnormally through the execution of <B>wind</B>\r
317 or <B>terminate</B> instructions, then the lastwill - a sequence\r
318 of instructions will be executed before such an object will be\r
319 terminated. The sequence of <B>lastwill</B> instructions must\r
320 be located at the <B>end</B> of a module and is announced by a\r
321 label <B>lastwill:</B>. A normal termination of an object will\r
322 never cause the execution of lastwill. Termination of a dynamic\r
323 instance of block, function, procedure causes its deallocation.\r
324 In the following example we shall demonstrate the usage of the\r
325 <B>wind</B> instruction in a handler. When executed it causes\r
326 that all objects - instances beginning from the module in which\r
327 a signal was raised and ending in the module containing the handler\r
328 are closed and terminated. The execution will be continued in\r
329 the object containing the handler from the point which caused\r
330 creation. In order to assure the smooth continuation the language\r
331 offers a possibility to define a lastwill instruction(s). <BR>\r
332 \r
333 <P>\r
334 <B>Example 5</B> <BR>\r
335 \r
336 <PRE>\r
337 <B>program</B> MAZE;\r
338  <B>var  </B>A : <B>arrayof arrayof boolean</B>,\r
339       i,n : <B>integer</B>,\r
340       there_is_a_path : <B>boolean</B>;\r
341  <B>signal </B>Found;\r
342  \r
343  <B>unit </B>PATH : <B> procedure </B>(i,j : <B>integer</B>);\r
344       (* the procedure makes one move from(i,j) *)\r
345  <B>begin\r
346 </B>   <B>if </B>A(i,j)\r
347    <B>then</B>  (* we can go through (i,j) field *)\r
348       <B>if</B> i=n <B>and </B>j=n <B> then raise </B>Found <B>fi</B>;\r
349       <B>if</B> i&lt; n <B>then call</B> PATH(i+1,j) <B>fi</B>;\r
350       <B>if </B>j&lt; n <B>then call </B>PATH(i,j+1) <B>fi;\r
351    fi</B>;\r
352  <B>last_will </B>: write(i,j);\r
353        (* the path will be printed in the reverse order *)\r
354  <B>end </B>PATH;\r
355 \r
356  <B>handlers\r
357         when</B> Found : there _is_a_path :=<B>true</B>; <B>wind\r
358  end handlers</B>;\r
359 <B>begin</B> (**  main program **)\r
360      .... (* create a maze A etc. *)\r
361    <B>call </B>PATH(1,1);\r
362    <B>if </B>there_is_a_path <B> then </B>...\r
363      ...\r
364 <B>end MAZE.</B><BR>\r
365 \r
366 </PRE>\r
367 \r
368 <P>\r
369 In this example we can observe how the programmer turned unusual\r
370 situation of a raised signal into the desired one: through lastwills\r
371 she got a simple program to print the path through the maze. \r
372 <BR>\r
373 \r
374 <H3>(f) Inheritance vs. signalling <BR>\r
375 </H3>\r
376 \r
377 <P>\r
378 Handlers (modules handling signals) behave similarly to virtual\r
379 procedures, i.e. the new handler from the prefixed module replaces\r
380 the module from the prefixing module. <BR>\r
381 <B>Example 6<BR>\r
382 </B>\r
383 <PRE>\r
384 <B>unit</B> STACKS:  <B>class</B> (type :telem);\r
385   <B>signal</B> empty_stack(s:stack), stack_overflow(s:stack);\r
386   <B>unit</B> stack : <B>class</B> (size:integer);\r
387     <B>hidden</B> place, top;\r
388     <B>var</B> place : <B>arrayof</B> taken,\r
389         top: integer;\r
390     <B>unit</B> pop: <B>function</B>:telem;\r
391       <B>handlers\r
392 </B>       <B>when</B> conerror: <B>raise</B> empty_stack(<B>this</B> stack)\r
393       <B>end</B> <B>handlers</B>;\r
394     <B>begin\r
395 </B>     <B>result</B> :=place(top);\r
396       (** here con_error signal can be raised by run_time_system **)\r
397       top:=top-1\r
398     <B>end</B> pop;\r
399 \r
400     <B>unit</B> push : <B>procedure</B> (e:telem);\r
401     <B>begin\r
402 </B>      <B>if</B> top&gt; size \r
403       <B>then\r
404 </B>        <B>raise</B> stack_overflow(<B>this</B> stack)\r
405       <B>fi</B>;\r
406       top:=top+1;\r
407       place(top):=e\r
408     <B>end</B> push;\r
409 \r
410     <B>unit</B> empty: <B>function</B> : boolean;\r
411     <B>begin\r
412 </B>      <B>result</B>:=top&lt; 1\r
413     <B>end</B> empty;\r
414 \r
415     <B>unit</B> increase : <B>procedure</B> (addition: integer);\r
416       <B>var</B> i : integer,\r
417           x : <B>arrayof</B> telem;\r
418     <B>begin\r
419 </B>      <B>array</B> X <B>dim</B> (size+addition);\r
420       size:=size+addition;\r
421       <B>for</B> i:=1 <B>to</B> upper(place)\r
422       <B>do\r
423 </B>        x(i):=place(i)\r
424       <B>od</B>;\r
425       <B>kill</B>(place);\r
426       place:=X\r
427     <B>end</B> increase.\r
428 \r
429   <B>begin\r
430 </B>    <B>array</B> place <B>dim</B>(1:size);\r
431   <B>end</B> stack;\r
432   <B>handlers\r
433 </B>    <B>when</B> empty_stack: write(&quot;empty stack&quot;); <B>terminate</B>;\r
434     <B>when</B> stack_overflow: write(&quot;stack overflow&quot;); <B>terminate</B>;  \r
435     <B>when</B> conerror : write(&quot;error in stack increasing&quot;);\r
436          <B>call</B> endrun;\r
437   <B>end</B> <B>handlers</B>;\r
438 \r
439 <B>end</B> STACKS; <BR>\r
440 \r
441 </PRE>\r
442 \r
443 <P>\r
444 Applications<BR>\r
445 <B> Example 7<BR>\r
446 </B>\r
447 <PRE>\r
448 <B>program</B> APPLICATION_1;\r
449   <B>unit</B> STACKS: ...\r
450   <B>unit</B> element: ...\r
451    ...\r
452   <B>pref</B> STACKS(element) <B>block\r
453 </B>    <B>var</B> s1,s2 : stack\r
454        ...\r
455     <B>handlers\r
456 </B>      <B>when</B> stack_overflow : ...\r
457       <B>call</B> s.increase(70);\r
458       <B>return</B>;\r
459     <B>end</B> <B>handler</B>;\r
460 <B>  begin</B> (***  block ***)\r
461        ...\r
462        s1:= <B>new</B> stack(c1);\r
463        s2:= <B>new</B> stack(c2);\r
464        ...\r
465        <B>call</B> s1.push(e);\r
466        ...\r
467        y:=s2.pop;\r
468        ...\r
469   <B>end</B> (*block*);\r
470 \r
471 <B>end</B> APPLICATION_1<BR>\r
472 \r
473 </PRE>\r
474 \r
475 <P>\r
476 In this example the handler for stack_overflow from the prefixed\r
477 block overrides the handler given in the class STACKS.<BR>\r
478 <BR>\r
479 <B>Example 8</B> <BR>\r
480 \r
481 <PRE>\r
482 <B>program</B> ReversePolishNotation;   (* Application 2 *)\r
483   <B>unit</B> STACKS: <B>class</B>; ... <B>end</B> STACKS;\r
484         ...\r
485   <B>unit</B> element : <B>class</B>(sign:char);\r
486   <B>end</B> element;\r
487     ...\r
488   <B>pref</B> STACKS(element) <B>block</B>;\r
489       ...\r
490     <B>handlers\r
491 </B>       <B>when</B> empty_stack: write(&quot;\r
492             error in expression_to many ( closing brackets &quot;);\r
493        <B>terminate</B>;\r
494     <B>end</B> <B>handlers</B>;\r
495 \r
496   <B>begin</B> (*block *)\r
497     <B>while</B> not eof\r
498     <B>do\r
499 </B>      read(x);\r
500       <B>if</B> x= ')' <B>then</B> \r
501          (* take operators from stack until ( is met *)\r
502       <B>else\r
503 </B>          ....\r
504       <B>fi\r
505 </B>    <B>od\r
506 </B>  <B>end</B> (*block*)\r
507 <B>end</B> ReversePolishNotation;<BR>\r
508 \r
509 </PRE>\r
510 \r
511 <P>\r
512 This example shows that there are situations in which the user\r
513 of a class STACKS knows how to handle the signal empty_stack and\r
514 solves the problem gracefully since in this case empty_stack means\r
515 that the data were not a well formed expression.<HR>\r
516 \r
517 <ADDRESS>\r
518 <A HREF = "http://www.univ-pau.fr/~salwicki/GMyAS.html">GMyAS</A>\r
519 </ADDRESS>\r
520 \r
521 <P>\r
522 Last update Wed 3 May 1995 \r
523 </BODY>\r
524 \r
525 </HTML>\r