A parser’s escape route
A recursive parser checks for unmatched braces, excessive nesting, output failure, and interruption. Its outer function declares a jmp_buf and switches on setjmp(jmpTarget). Case 0 calls descend. If descend detects an exceptional condition, it calls longjmp(jmpTarget, condition); control reaches the switch again, now selecting the corresponding warning or error. A failed newline write, for example, calls longjmp(jmpTarget, eofOut) rather than continuing to parse. section 17.5
setjmp establishes a target; longjmp transfers control back to it across nested function calls. The target is an opaque jmp_buf whose contents must still be valid when used. Unlike a goto label, the target can be used from another function. setjmp returns zero when first reached and a nonzero result after the jump, allowing one switch to distinguish normal execution from exceptional outcomes. section 17.5
Compare an ordinary function return with the jump back to the position marked by setjmp. section 17.5
Two details matter when following this control flow:
- longjmp never returns to its caller. Once an error branch calls it, statements later in that call do not execute; the compiler can use that fact when analyzing the remaining branches. section 17.5
- A jump can bypass ordinary cleanup on the way out of recursive calls. A depth value that would normally be restored before return may therefore remain changed. This interaction with optimization is why some variables need volatile qualification. section 17.4 section 17.7
TAKEAWAY: setjmp/longjmp provides one destination for exceptional conditions detected deep in a call chain, but the jump is not a sequence of normal returns. Check both the target’s validity and any state that ordinary returns would have restored. section 17.5 section 17.4


