| 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> |