Monday 31 July 2023

More on attachable scopes

I previously called these braceless scopes, and ended up writing more in discussion with Jens that I did on my blog - but now I come to needed it, and further back in time than I expected I find this gem carbuncle below.

(By attachable-scope I mean a braced-scope that get's attached to the expansion of previous macro, perhaps as the body of a function definition, or a for loop, or even an else clause).

Hah! Your example there was the clue to propagating breaks.

Thanks to your tip on the gcc equivalence using BREAKOUT and BREAKIN I can contrive a bunch of macros that expand to this:

1
2
3
4
5
6
7
8
9
main() {
  int a;
  for (a=1; a<=2; a++) {
    printf("Main context a=%d\n", a);
 
    if (0) { break_line_6: break ; } else for (int o = 0; o >=0; ) if (o == 1) { printf("Detected break\n"); goto break_line_6; } else
      for (int i=0; !o && (o=1), i==0; o=-1, i=-1 ) { printf("Inner context\n"); break; }
  }
}

it does not require gcc-isms – sadly the C style is lacking but it functions as desired

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define GENSYM_CONCAT(name, salt) name ## salt
#define GENSYM2(name, salt) GENSYM_CONCAT(name, salt)
#define GENSYM(name) GENSYM2(name, __LINE__)
 
#define _BRACELESS_SCOPE(__label__, _declaration_) \
    if (0) { __label__: break ; } else for (int _o = 0; _o >=0; ) if (_o == 1) goto __label__; else \
      for (_declaration_; !_o && (_o=1); _o=-1) \
 
#define BRACELESS_SCOPE(_declaration_) _BRACELESS_SCOPE(GENSYM(break_line_) , _declaration_)
 
main() {
  int a;
  for (a=1; a<=2; a++) {
    printf("Main context a=%d\n", a);
 
    BRACELESS_SCOPE(char* message="hello") { printf("Inner context: %s\n", message); break; }
  }
}

The main deficiency is that a single macro cannot cannot ultimately expand to more than one of these constructs, nor can it be used twice on the same line, or the generated labels will conflict. __COUNTER__ where supported could be passed instead of __LINE__. I guess this is something you already addressed in P99 if I look again…

It's just what I needed as I convert a narrating block logger (that annotates progress through a block scope) from gcc-isms to clang-isms.


It originally expanded to a nested function forward definition, a setup block, a nested function invocation, a clean-up block, followed by a the first half of a nested function definition which sticks onto a following scope that becomes the body.


clang won't take nested functions (even without arguments) and clang's objective-C style blocks is no help as it can't access the variables in the calling scope as gcc does.


Knowing that I've passed this way before I look at this and this, before finally recovering the carbuncle above which is to be pressed into service.

No comments:

Post a Comment