chiark / gitweb /
@@@ all the mess ever
[mLib] / utils / control.3
1 .\" -*-nroff-*-
2 .TH control 3 "23 April 2023" "Straylight/Edgeware" "mLib utilities library"
3 .SH NAME
4 control \- control structure metaprogramming
5 .\" @MC_BEFORE
6 .\" @MC_AFTER
7 .\" @MC_WRAP
8 .\" @MC_FINALLY
9 .\" @MC_DOWHILE
10 .\" @MC_DECL
11 .\" @MC_LOOPELSE
12 .\" @MC_LOOPBETWEEN
13 .\" @MC_ALLOWELSE
14 .\" @MC_GOELSE
15 .\" @MC_TARGET
16 .\" @MC_GOTARGET
17 .\" @MC_ACT
18 .\" @MC_LABEL
19 .\" @MC_GOTO
20 .SH SYNOPSIS
21 .nf
22 .B "#include <mLib/control.h>"
23
24 .BI MC_BEFORE( tag ", " stmts ") " body
25 .BI MC_AFTER( tag ", " stmts ") " body
26 .BI MC_WRAP( tag ", " before_stmt ", " onend_stmt ", " onbreak_stmt ") " body
27 .BI MC_DOWHILE( tag ", " cond ") " body
28 .BI MC_DECL( tag ", " decl ") " body
29 .BI MC_LOOPELSE( tag ", " head ") " loop_body " \fR[\fBelse " else_body \fR]
30
31 .BI MC_TARGET( tag ", " stmt ") " body
32 .BI MC_GOTARGET( tag );
33 .BI MC_ALLOWELSE( tag ") " main_body " \fR[\fBelse " else_body \fR]
34 .BI MC_GOELSE( tag );
35
36 .BI MC_ACT( stmt )
37 .BI MC_LABEL( tag )
38 .BI MC_GOTO( tag )
39 .fi
40 .SH DESCRIPTION
41 The header file
42 .B <mLib/control.h>
43 defines a number of macros which are useful when defining new
44 control structures for C.  They are inspired by Simon Tatham's article
45 .IR "Metaprogramming custom control structures in C",
46 though these macros differ from Tatham's in a few respects.
47 .SS "Common features"
48 Each of these macros takes a
49 .I tag
50 argument.  A
51 .I tag
52 is lexically like an identifier, except that it may begin with a digit,
53 so, for example, plain integers are acceptable tags.  Each use of an
54 action macro by a user-level macro must have a distinct
55 .IR tag .
56 If you're writing a new prefix action macro written in terms of these
57 existing actions, your macro should receive a
58 .I tag
59 from its caller, and pass this tag, along with a distinctive component
60 of its own, down to any prefix actions that it calls; the
61 .IR tag s
62 from each layer should be separated by a pair of underscores.
63 .PP
64 Some of these macros work by wrapping a loop around the
65 .I body
66 statement.  This interferes with the way that `free'
67 .B break
68 and
69 .B continue
70 statements within the
71 .I body
72 behave: we say that these statements are
73 .I captured
74 by the macro.
75 A
76 .B break
77 or
78 .B continue
79 statement is `free' if it doesn't appear lexically within a loop or
80 (for
81 .B break)
82 .B switch
83 statement that is part of the
84 .IR body .
85 So
86 .IP
87 .B "if (!x) break;"
88 .PP
89 contains a free
90 .B break
91 statement, while
92 .IP
93 .nf
94 .ft B
95 for (i = 0; i < n; i++)
96 \h'4n'if (interestingp(i)) break;
97 .ft
98 .fi
99 .PP
100 does not.
101 .PP
102 Some of these macros take special care to give you control over what
103 happens when a captured
104 .B break
105 is executed.  Alas, proper handling of
106 .B continue
107 doesn't seem possible.  Free
108 .B break
109 and
110 .B continue
111 statements
112 .I within
113 arguments to these macros are never captured.
114 .SS "Prefix action macros"
115 .B MC_BEFORE
116 macro is the simplest to understand.  Executing
117 .IP
118 .BI MC_BEFORE( tag ", " stmt ") " body
119 .PP
120 has the same effect as executing
121 .I stmt
122 followed by
123 .IR body ,
124 except that the whole thing is syntactically a single statement, so, for
125 example, it doesn't need to be enclosed in braces to be the body of a
126 .B for
127 loop.
128 .B MC_BEFORE
129 does not capture free
130 .B break
131 or
132 .B continue
133 statements.
134 .PP
135 Executing
136 .IP
137 .BI MC_AFTER( tag ", " stmt ") " body
138 .PP
139 has
140 .I nearly
141 the same effect as executing
142 .I stmt
143 followed by
144 .IR body .
145 Again, the whole thing is syntactically a single statement.  However,
146 .B MC_AFTER
147 captures free
148 .B break
149 and
150 .B continue
151 statements within the
152 .IR body .
153 A free
154 .B break
155 or
156 .B continue
157 abruptly ends execution of the
158 .IR body ,
159 immediately transferring control to the
160 .IR stmt .
161 .PP
162 Executing
163 .IP
164 .BI MC_WRAP( tag ", " before ", " onend ", " onbreak ") " body
165 .PP
166 has
167 .I nearly
168 the same effect as executing
169 .IR before ,
170 .IR body ,
171 and then
172 .IR onend .
173 If the
174 .I body
175 executes a free
176 .B break
177 statement, then control abruptly continues with the
178 .I onbreak
179 statement, and
180 .I onend
181 is not executed.  Currently, if the
182 .I body
183 executes a free
184 .B continue
185 statement, then control abruptly continues with the
186 .I onend
187 statement, but this behaviour is a bug and may be fixed in the future.
188 .PP
189 .\" @@@ mc_finally
190 .PP
191 Executing
192 .IP
193 .BI MC_DOWHILE( tag ", " cond ") " body
194 .PP
195 has exactly the same effect as
196 .BI "do " body " while (" cond ); \fR,
197 the only difference being that the
198 .I body
199 appears in tail position rather than sandwiched in the middle.
200 .PP
201 Executing
202 .BI MC_DECL( tag ", " decl ") " body
203 has the same effect as
204 .BI "{ " decl "; " body " }" \fR,
205 except that free
206 .B break
207 and
208 .B continue
209 statements are captured.  Currently, a free
210 .B continue
211 statement will simply abruptly terminate execution of the
212 .IR body ,
213 while a free
214 .B break
215 statement abruptly
216 .I restarts
217 executing the
218 .I body
219 without leaving the scope of the
220 .IR decl ;
221 but these behaviours are bugs and may be fixed in the future.
222 .PP
223 The
224 .B MC_DECL
225 macro makes use of the fact that a
226 .B for
227 statement can introduce a declaration into its body's scope in C99 and
228 C++; the macro is not available in C89.
229 .PP
230 Executing
231 .IP
232 .nf
233 .BI MC_LOOPELSE( head ", " tag ") "
234 .RI \h'4n' loop_body
235 .RB [ else
236 .RI \h'4n' else_body ]
237 .fi
238 .PP
239 results in Python-like loop behaviour.  The
240 .I head
241 must be a valid loop head with one of the forms
242 .IP
243 .BI "while (" cond ")"
244 .br
245 .BI "for (" decl "; " cond "; " next_expr ")"
246 .br
247 .BI "MC_DOWHILE(" tag ", " cond ")"
248 .PP
249 The resulting loop executes the same as
250 .IP
251 .nf
252 .I head
253 .RI \h'4n' loop_body
254 .fi
255 .PP
256 If the loop ends abruptly, as a result of
257 .BR break ,
258 then control is passed to the statement following the loop in the usual
259 way.  However, if the loop completes naturally, and the optional
260 .B else
261 clause is present, then the
262 .I else_body
263 is executed.  A free
264 .B continue
265 statement within the
266 .I loop_body
267 behaves normally.  Free
268 .B break
269 and
270 .B continue
271 statements within the
272 .I else_body
273 are not captured.
274 .PP
275 .\" @@@ loopbetween
276 .SS "Lower-level machinery"
277 Executing
278 .IP
279 .BI MC_TARGET( tag ", " stmt ") " body
280 .PP
281 has exactly the same effect as simply executing
282 .IR body .
283 Executing
284 .B MC_GOTARGET
285 immediately transfers control to
286 .IR stmt ,
287 with control continuing with the following statement, skipping the
288 .IR body .
289 Free
290 .B break
291 or
292 .B continue
293 statements in
294 .I body
295 are not captured.
296 .PP
297 This is most commonly useful in loops in order to arrange the correct
298 behaviour of a free
299 .B break
300 within the loop body.  See the example below, which shows the definition
301 of
302 .BR MC_LOOPELSE .
303 .PP
304 Executing
305 .IP
306 .BI MC_ALLOWELSE( tag ") " main_body " \fR[\fBelse " else_body \fR]
307 .PP
308 has exactly the same effect as just
309 .IR main_body .
310 Executing
311 .IP
312 .BI MC_GOELSE( tag );
313 .PP
314 transfers control immediately to
315 .I else_body
316 (if present); control then naturally transfers to the following
317 statement as usual.  Free
318 .B break
319 or
320 .B continue
321 statements in either of
322 .I main_body
323 or
324 .I else_body
325 are not captured.
326 .PP
327 Note that
328 .B MC_ALLOWELSE
329 works by secretly inserting an
330 .B if
331 statement head before the
332 .IR main_body ,
333 so things will likely to wrong if
334 .I main_body
335 is itself an
336 .B if
337 statement: if
338 .I main_body
339 lacks an
340 .B else
341 clause, then an
342 .B else
343 intended to match
344 .B MC_ALLOWELSE
345 will be mis-associated; and even if
346 .I main_body
347 .I does
348 have an
349 .B else
350 clause, the resulting program text is likely to provoke a compiler
351 warning about `dangling
352 .BR else '.
353 .PP
354 Using these tools, it's relatively straightforward to define a macro
355 like
356 .BR MC_LOOPELSE ,
357 described above:
358 .IP
359 .nf
360 .ft B
361 #define MC_LOOPELSE(tag, head) \e
362 \h'4n'MC_TARGET(tag##__exit, { ; }) \e
363 \h'4n'MC_ALLOWELSE(tag##__else) \e
364 \h'4n'MC_AFTER(tag##__after, { MC_GOELSE(tag##__else); }) \e
365 \h'4n'head \e
366 \h'8n'MC_WRAP(tag##__body, { ; }, { ; }, \e
367 \h'8n+\w'MC_WRAP(tag##__body, ''{ MC_GOTARGET(tag##__exit); })
368 .ft R
369 .fi
370 .PP
371 The main `trick' for these control-flow macros is
372 .BR MC_ACT ,
373 which wraps up a statement as an
374 .IR action .
375 An action is a valid
376 .IR  "statement head" ,
377 like
378 .B if
379 or
380 .BR while :
381 i.e., it must be completed by following it with a
382 .I body
383 statement.  Executing
384 .IP
385 .BI MC_ACT( stmt ") " body
386 .PP
387 has the same effect as simply executing
388 .IR stmt ;
389 the
390 .I body
391 is usually ignored.  Note that
392 .B ;
393 is a valid statement which does nothing, so
394 .BI MC_ACT( stmt );
395 is also a valid statement with the same effect as
396 .IR stmt .
397 The only way to cause
398 .I body
399 to be executed is to attach a label to it and transfer control using
400 .BR goto .
401 .PP
402 Executing
403 .IP
404 .BI MC_LABEL( tag ") " body
405 .PP
406 has the same effect as
407 .IR body .
408 Executing
409 .IP
410 .BI MC_GOTO( tag )
411 .PP
412 immediately transfers control to the
413 .IR body .
414 Note that
415 .B MC_GOTO
416 is syntactically an action
417 (i.e., it's wrapped in
418 .BR MC_ACT ).
419 The
420 .IR tag s
421 here are scoped to the top-level source line, like all
422 .IR tag s
423 in this macro package.
424 .PP
425 All of the control-flow macros in this package are mainly constructed from
426 .BR MC_ACT ,
427 .BR MC_LABEL ,
428 and
429 .BR MC_GOTO ,
430 sometimes with one or two other statement heads thrown into the mix.
431 For example,
432 .B MC_AFTER
433 is defined as
434 .IP
435 .nf
436 .ft B
437 #define MC_AFTER(tag, stmt) \e
438 \h'28n'MC_GOTO(tag##__body) \e
439 \h'4n'MC_LABEL(tag##__end) \e
440 \h'28n'MC_ACT(stmt) \e
441 \h'28n'for (;;) \e
442 \h'32n'MC_GOTO(tag##__end) \e
443 \h'4n'MC_LABEL(tag##__body)
444 .ft R
445 .fi
446 .PP
447 (The unusual layout is conventional, to make the overall structure of
448 the code clear despite visual interference from the labels.)
449 The
450 .I body
451 appears at the end, labelled as
452 .IB tag __body \fR.
453 Control enters at the start, and is immediately transferred to the
454 .I body ;
455 but the
456 .I body
457 is enclosed in a
458 .B for
459 loop, so when the
460 .I body
461 completes, the loop restarts, transferring control to
462 .IB tag __end
463 and the
464 .IR stmt .
465 Since it is enclosed in
466 .BR MC_ACT ,
467 once
468 .I stmt
469 completes, control transfers to the following statement.
470 .SH BUGS
471 Some macros cause free
472 .B break
473 and/or
474 .B continue
475 statements to behave in unexpected ways.
476 .PP
477 The need for tagging is ugly, and the restriction on having two
478 user-facing control-flow macros on the same line is objectionable.  The
479 latter could be avoided by using nonstandard features such as GCC's
480 .B __COUNTER__
481 macro, but adopting that would do programmers a disservice by
482 introducing a hazard for those trying to port code to other compilers
483 which lack any such feature.
484 .SH "SEE ALSO"
485 .BR mLib (3),
486 .BR macros (3).
487 .PP
488 Simon Tatham,
489 .IR "Metaprogramming custom control structures in C",
490 .BR "https://www.chiark.greenend.org.uk/~sgtatham/mp/" .
491 .SH "AUTHOR"
492 Mark Wooding, <mdw@distorted.org.uk>