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