@@@ man wip
[mLib] / utils / control.3
1 .\" -*-nroff-*-
2 .de VS
3 .sp 1
4 .RS
5 .nf
6 .ft B
7 ..
8 .de VE
9 .ft R
10 .fi
11 .RE
12 .sp 1
13 ..
14 .TH control 3 "23 April 2023" "Straylight/Edgeware" "mLib utilities library"
15 .
16 .SH NAME
17 control \- control structure metaprogramming
18 .\" @MC_BEFORE
19 .\" @MC_AFTER
20 .\" @MC_WRAP
21 .\" @MC_FINALLY
22 .\" @MC_DOWHILE
23 .\" @MC_DECL
24 .\" @MC_LOOPELSE
25 .\" @MC_LOOPBETWEEN
26 .\" @MC_ALLOWELSE
27 .\" @MC_GOELSE
28 .\" @MC_TARGET
29 .\" @MC_GOTARGET
30 .\" @MC_ACT
31 .\" @MC_LABEL
32 .\" @MC_GOTO
33 .
34 .SH SYNOPSIS
35 .nf
36 .B "#include <mLib/control.h>"
37
38 .BI MC_BEFORE( tag ", " stmts ") " body
39 .BI MC_AFTER( tag ", " stmts ") " body
40 .BI MC_WRAP( tag ", " before_stmt ", " onend_stmt ", " onbreak_stmt ") " body
41 .BI MC_FINALLY( tag ", " cleanup ") " body
42 .BI MC_DOWHILE( tag ", " cond ") " body
43 .BI MC_DECL( tag ", " decl ") " body
44 .BI MC_LOOPELSE( tag ", " head ") " loop_body " \fR[\fBelse " else_body \fR]
45 .BI MC_LOOPBETWEEN( tag ", " setup ", " cond ", " step ") " loop_body " \fR[\fBelse " else_body \fR]
46
47 .BI MC_TARGET( tag ", " stmt ") " body
48 .BI MC_GOTARGET( tag );
49 .BI MC_ALLOWELSE( tag ") " main_body " \fR[\fBelse " else_body \fR]
50 .BI MC_GOELSE( tag );
51
52 .BI MC_ACT( stmt )
53 .BI MC_LABEL( tag )
54 .BI MC_GOTO( tag )
55 .fi
56 .
57 .SH DESCRIPTION
58 The header file
59 .B <mLib/control.h>
60 defines a number of macros which are useful
61 when defining new control structures for C.
62 They are inspired by Simon Tatham's article
63 .IR "Metaprogramming custom control structures in C",
64 though these macros differ from Tatham's in a few respects.
65 .
66 .SS "Common features"
67 Each of these macros takes a
68 .I tag
69 argument.
70 A
71 .I tag
72 is lexically like an identifier,
73 except that it may begin with a digit,
74 so, for example, plain integers are acceptable tags.
75 Each use of an action macro by a user-level macro
76 must have a distinct
77 .IR tag .
78 If you're writing a new prefix action macro
79 written in terms of these existing actions,
80 your macro should receive a
81 .I tag
82 from its caller,
83 and pass this tag,
84 along with a distinctive component of its own,
85 down to any prefix actions that it calls;
86 the
87 .IR tag s
88 from each layer should be separated by a pair of underscores.
89 .PP
90 Some of these macros work by wrapping a loop around the
91 .I body
92 statement.
93 This interferes with the way that `free'
94 .B break
95 and
96 .B continue
97 statements within the
98 .I body
99 behave:
100 we say that these statements are
101 .I captured
102 by the macro.
103 A
104 .B break
105 or
106 .B continue
107 statement is
108 .I free
109 if it doesn't appear lexically within a loop or
110 (for
111 .B break)
112 .B switch
113 statement that is part of the
114 .IR body .
115 So
116 .VS
117 if (!x) break;
118 .VE
119 contains a free
120 .B break
121 statement,
122 while
123 .VS
124 .ta 2n
125 for (i = 0; i < n; i++)
126 if (interestingp(i)) break;
127 .VE
128 does not.
129 .PP
130 Some of these macros take special care
131 to give you control over what happens when a captured
132 .B break
133 is executed.
134 Alas, proper handling of
135 .B continue
136 doesn't seem possible.
137 Free
138 .B break
139 and
140 .B continue
141 statements
142 .I within
143 arguments to these macros are never captured.
144 .
145 .SS "Prefix action macros"
146 .B MC_BEFORE
147 macro is the simplest to understand. Executing
148 .IP
149 .BI MC_BEFORE( tag ", " stmt ") " body
150 .PP
151 has the same effect as executing
152 .I stmt
153 followed by
154 .IR body ,
155 except that the whole thing is syntactically a single statement,
156 so, for example, it doesn't need to be enclosed in braces
157 to be the body of a
158 .B for
159 loop.
160 .B MC_BEFORE
161 does not capture free
162 .B break
163 or
164 .B continue
165 statements.
166 .PP
167 Executing
168 .IP
169 .BI MC_AFTER( tag ", " stmt ") " body
170 .PP
171 has
172 .I nearly
173 the same effect as executing
174 .I stmt
175 followed by
176 .IR body .
177 Again, the whole thing is syntactically a single statement.
178 However,
179 .B MC_AFTER
180 captures free
181 .B break
182 and
183 .B continue
184 statements within the
185 .IR body .
186 A free
187 .B break
188 or
189 .B continue
190 abruptly ends execution of the
191 .IR body ,
192 immediately transferring control to the
193 .IR stmt .
194 .PP
195 Executing
196 .IP
197 .BI MC_WRAP( tag ", " before ", " onend ", " onbreak ") " body
198 .PP
199 has
200 .I nearly
201 the same effect as executing
202 .IR before ,
203 .IR body ,
204 and then
205 .IR onend .
206 If the
207 .I body
208 executes a free
209 .B break
210 statement, then control abruptly continues with the
211 .I onbreak
212 statement, and
213 .I onend
214 is not executed.
215 Currently, if the
216 .I body
217 executes a free
218 .B continue
219 statement,
220 then control abruptly continues with the
221 .I onend
222 statement,
223 but this behaviour is a bug and may be fixed in the future.
224 .PP
225 Executing
226 .IP
227 .BI MC_FINALLY( tag ", " cleanup ") " body
228 .PP
229 has the same effect as executing
230 .I body
231 followed by
232 .IR cleanup ,
233 except that a free
234 .B break
235 statement within
236 .I body
237 will execute
238 .I cleanup
239 before propagating the
240 .B break
241 to the enclosing context.
242 A free
243 .B continue
244 statement currently causes control to continue abruptly with
245 .I cleanup
246 but this behaviour is a bug and may be fixed in the future.
247 The
248 .I cleanup
249 code is textually duplicated,
250 so there'll be some code bloat if this is very complex.
251 If it arranges to have private long-term state
252 then the two copies will not share this state,
253 so probably don't do this.
254 .PP
255 Executing
256 .IP
257 .BI MC_DOWHILE( tag ", " cond ") " body
258 .PP
259 has exactly the same effect as
260 .BI "do " body " while (" cond ); \fR,
261 the only difference being that the
262 .I body
263 appears in tail position rather than sandwiched in the middle.
264 .PP
265 Executing
266 .BI MC_DECL( tag ", " decl ") " body
267 has the same effect as
268 .BI "{ " decl "; " body " }" \fR,
269 except that free
270 .B break
271 and
272 .B continue
273 statements are captured.
274 Currently, a free
275 .B continue
276 statement will simply abruptly terminate execution of the
277 .IR body ,
278 while a free
279 .B break
280 statement abruptly
281 .I restarts
282 executing the
283 .I body
284 without leaving the scope of the
285 .IR decl ;
286 but these behaviours are bugs and may be fixed in the future.
287 .PP
288 The
289 .B MC_DECL
290 macro makes use of the fact that a
291 .B for
292 statement can introduce a declaration
293 into its body's scope in C99 and C++;
294 the macro is not available in C89.
295 .PP
296 Executing
297 .IP
298 .nf
299 .ta 2n
300 .BI MC_LOOPELSE( head ", " tag ") "
301 .I " loop_body"
302 .RB [ else
303 .IR " else_body" ]
304 .fi
305 .PP
306 results in Python-like loop behaviour.
307 The
308 .I head
309 must be a valid loop head with one of the forms
310 .IP
311 .nf
312 .BI "while (" cond ")"
313 .BI "for (" decl "; " cond "; " next_expr ")"
314 .BI "MC_DOWHILE(" tag ", " cond ")"
315 .fi
316 .PP
317 The resulting loop executes the same as
318 .IP
319 .nf
320 .ta 2n
321 .I head
322 .I " loop_body"
323 .fi
324 .PP
325 If the loop ends abruptly, as a result of
326 .BR break ,
327 then control is passed to the statement following the loop
328 in the usual way.
329 However, if the loop completes naturally,
330 and the optional
331 .B else
332 clause is present,
333 then the
334 .I else_body
335 is executed.
336 A free
337 .B continue
338 statement within the
339 .I loop_body
340 behaves normally.
341 Free
342 .B break
343 and
344 .B continue
345 statements within the
346 .I else_body
347 are not captured.
348 .PP
349 Executing
350 .IP
351 .nf
352 .ta 2n
353 .BI MC_LOOPBETWEEN( tag ", " setup ", " cond ", " step ") "
354 .I " loop-body"
355 .RB [ else
356 .IR " else-body" ]
357 .fi
358 .PP
359 is similar to executing the
360 .B for
361 loop
362 .IP
363 .ta 2n
364 .nf
365 .BI "for (" setup "; " cond "; " step ") "
366 .I " loop-body"
367 .fi
368 .PP
369 except that, once the
370 .I loop_body
371 has finished,
372 the
373 .I step
374 expression evaluated,
375 and the
376 .I cond
377 evaluated and determined to be nonzero,
378 the
379 .I else_body
380 (if any) is executed before re-entering the
381 .IR loop_body .
382 This makes it a useful place to insert
383 any kind of interstitial material,
384 e.g., printing commas between list items.
385 Note that by the time the
386 .I else_body
387 is executed,
388 the decision has already been made
389 that another iteration will be performed,
390 and, in particular, the
391 .I step
392 has occurred. The
393 .I else_body
394 is therefore looking at the next item to be processed,
395 not the item that has just finished being processed.
396 The
397 .I cond
398 is textually duplicated,
399 so there'll be some code bloat if this is very complex.
400 If it somehow manages to have private long-term state
401 (e.g., as a result of declaring static variables
402 inside GCC statement expressions)
403 then the two copies will not share this state,
404 so probably don't do this.
405 .
406 .SS "Lower-level machinery"
407 Executing
408 .IP
409 .BI MC_TARGET( tag ", " stmt ") " body
410 .PP
411 has exactly the same effect as simply executing
412 .IR body .
413 Executing
414 .B MC_GOTARGET
415 immediately transfers control to
416 .IR stmt ,
417 with control continuing with the following statement,
418 skipping the
419 .IR body .
420 Free
421 .B break
422 or
423 .B continue
424 statements in
425 .I body
426 are not captured.
427 .PP
428 This is most commonly useful in loops
429 in order to arrange the correct behaviour of a free
430 .B break
431 within the loop body.
432 See the example below,
433 which shows the definition
434 of
435 .BR MC_LOOPELSE .
436 .PP
437 Executing
438 .IP
439 .nf
440 .ta 2n
441 .BI MC_ALLOWELSE( tag ") "
442 .I " main_body"
443 .RB [ else
444 .IR " else_body" ]
445 .fi
446 .PP
447 has exactly the same effect as just
448 .IR main_body .
449 Executing
450 .IP
451 .BI MC_GOELSE( tag );
452 .PP
453 transfers control immediately to
454 .I else_body
455 (if present);
456 control then naturally transfers to the following statement as usual.
457 Free
458 .B break
459 or
460 .B continue
461 statements in either of
462 .I main_body
463 or
464 .I else_body
465 are not captured.
466 .PP
467 Note that
468 .B MC_ALLOWELSE
469 works by secretly inserting an
470 .B if
471 statement head before the
472 .IR main_body ,
473 so things will likely to wrong if
474 .I main_body
475 is itself an
476 .B if
477 statement:
478 if
479 .I main_body
480 lacks an
481 .B else
482 clause,
483 then an
484 .B else
485 intended to match
486 .B MC_ALLOWELSE
487 will be mis-associated;
488 and even if
489 .I main_body
490 .I does
491 have an
492 .B else
493 clause,
494 the resulting program text is likely to provoke a compiler warning
495 about `dangling
496 .BR else '.
497 .PP
498 Using these tools,
499 it's relatively straightforward to define a macro like
500 .BR MC_LOOPELSE ,
501 described above:
502 .VS
503 .ta 4n 4n+\w'\fBMC_WRAP(tag##__body, 'u \n(.lu-\n(.iu-4n
504 #define MC_LOOPELSE(tag, head) \e
505 MC_TARGET(tag##__exit, { ; }) \e
506 MC_ALLOWELSE(tag##__else) \e
507 MC_AFTER(tag##__after, { MC_GOELSE(tag##__else); }) \e
508 head \e
509 MC_WRAP(tag##__body, { ; }, { ; }, \e
510 { MC_GOTARGET(tag##__exit); })
511 .VE
512 The main `trick' for these control-flow macros is
513 .BR MC_ACT ,
514 which wraps up a statement as an
515 .IR action .
516 An action is a valid
517 .IR "statement head" ,
518 like
519 .B if
520 or
521 .BR while :
522 i.e., it must be completed by following it with a
523 .I body
524 statement.
525 Executing
526 .IP
527 .BI MC_ACT( stmt ") " body
528 .PP
529 has the same effect as simply executing
530 .IR stmt ;
531 the
532 .I body
533 is usually ignored.
534 Note that
535 .B ;
536 is a valid statement which does nothing,
537 so
538 .BI MC_ACT( stmt );
539 is also a valid statement with the same effect as
540 .IR stmt .
541 The only way to cause
542 .I body
543 to be executed is to attach a label to it and transfer control using
544 .BR goto .
545 .PP
546 Executing
547 .IP
548 .BI MC_LABEL( tag ") " body
549 .PP
550 has the same effect as
551 .IR body .
552 Executing
553 .IP
554 .BI MC_GOTO( tag )
555 .PP
556 immediately transfers control to the
557 .IR body .
558 Note that
559 .B MC_GOTO
560 is syntactically an action,
561 i.e., it's wrapped in
562 .BR MC_ACT .
563 The
564 .IR tag s
565 here are scoped to the top-level source line,
566 like all
567 .IR tag s
568 in this macro package.
569 .PP
570 All of the control-flow macros in this package are mainly constructed from
571 .BR MC_ACT ,
572 .BR MC_LABEL ,
573 and
574 .BR MC_GOTO ,
575 sometimes with one or two other statement heads thrown into the mix.
576 For example,
577 .B MC_AFTER
578 is defined as
579 .VS
580 .ta 4n 28n 30n \n(.lu-\n(.iu-4n
581 #define MC_AFTER(tag, stmt) \e
582 MC_GOTO(tag##__body) \e
583 MC_LABEL(tag##__end) \e
584 MC_ACT(stmt) \e
585 for (;;) \e
586 MC_GOTO(tag##__end) \e
587 MC_LABEL(tag##__body)
588 .VE
589 (The unusual layout is conventional,
590 to make the overall structure of the code clear
591 despite visual interference from the labels.)
592 The
593 .I body
594 appears at the end,
595 labelled as
596 .IB tag __body \fR.
597 Control enters at the start,
598 and is immediately transferred to the
599 .I body ;
600 but the
601 .I body
602 is enclosed in a
603 .B for
604 loop, so when the
605 .I body
606 completes, the loop restarts,
607 transferring control to
608 .IB tag __end
609 and the
610 .IR stmt .
611 Since it is enclosed in
612 .BR MC_ACT ,
613 once
614 .I stmt
615 completes,
616 control transfers to the following statement.
617 .
618 .SH "BUGS"
619 Some macros cause free
620 .B break
621 and/or
622 .B continue
623 statements to behave in unexpected ways.
624 .PP
625 It's rather hard to use
626 .B MC_ALLOWELSE
627 in practice without provoking
628 .RB `dangling- else '
629 warnings.
630 .PP
631 The need for tagging is ugly,
632 and the restriction on having two
633 user-facing control-flow macros on the same line is objectionable.
634 The latter could be avoided
635 by using nonstandard features such as GCC's
636 .B __COUNTER__
637 macro,
638 but adopting that would do programmers a disservice
639 by introducing a hazard for those
640 trying to port code to other compilers which lack any such feature.
641 .
642 .SH "SEE ALSO"
643 .BR mLib (3),
644 .BR macros (3).
645 .PP
646 Simon Tatham,
647 .IR "Metaprogramming custom control structures in C",
648 .BR "https://www.chiark.greenend.org.uk/~sgtatham/mp/" .
649 .
650 .SH "AUTHOR"
651 Mark Wooding, <mdw@distorted.org.uk>