Skip to content

Instantly share code, notes, and snippets.

@barrucadu
Last active February 24, 2020 16:39
Show Gist options
  • Save barrucadu/af9eea657c13de811f1843a6a0e8813a to your computer and use it in GitHub Desktop.
Save barrucadu/af9eea657c13de811f1843a6a0e8813a to your computer and use it in GitHub Desktop.
clang jmp-cflow.c -Weverything -Wno-shadow -Wno-unused-variable -Wno-missing-noreturn -Wno-reserved-id-macro -Wno-unused-macros -Werror
#include <setjmp.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define BEGIN_BLOCK \
{ \
volatile uint8_t orig_exc_i = exc_i; \
volatile uint8_t exc_i = orig_exc_i + 1; \
switch(setjmp(exc[exc_i].catcher)) { \
case 0: \
case 1:
#define __E_CATCHER(off) exc[exc_i-off].catcher
#define __E_RESUMER(off) exc[exc_i-off].resumer
#define __E_THROW(n) if(setjmp(__E_RESUMER(0)) == 0) { longjmp(__E_CATCHER(0), n); }
#define __E_THROW_UP(n) if(setjmp(__E_RESUMER(1)) == 0) { longjmp(__E_CATCHER(1), n); }
#define __E_CATCH(n) break; case (n):
#define END_BLOCK \
break; \
default: \
fprintf(stderr, "missing CATCH for THROW - did you mean to use THROW_UP? aborting...\n"); \
abort(); \
} \
}
#define THROW(n) __E_THROW((n)+2)
#define CATCH(n) __E_CATCH((n)+2)
#define RESTART longjmp(__E_CATCHER(0), 1)
#define RESUME longjmp(__E_RESUMER(0), 1)
#define THROW_UP(n) __E_THROW_UP((n)+2)
#define RESTART_UP longjmp(__E_CATCHER(1), 1)
#define RESUME_UP longjmp(__E_RESUMER(1), 1)
#define BEGIN_E_FUNC(ty, name, ...) \
__attribute__((always_inline)) \
__attribute__((noreturn)) \
static inline ty name(uint8_t exc_i, __VA_ARGS__) {
#define END_E_FUNC \
fprintf(stderr, "control has reached end of E_FUNC. aborting...\n"); \
abort(); \
}
#define CALL_E_FUNC(name, ...) name(exc_i, __VA_ARGS__)
static struct {
jmp_buf catcher;
jmp_buf resumer;
} exc[255];
/* THROWs true or false */
BEGIN_E_FUNC(void, check_numbers, int a, int b)
THROW(a == b);
printf("\nTry again, but enter two equal numbers this time!\n\n");
RESTART;
END_E_FUNC
BEGIN_E_FUNC(void, e_main, int *ret)
volatile int a, b;
BEGIN_BLOCK
printf("Enter a number:\n");
scanf("%d", &a);
printf("Enter a second number:\n");
scanf("%d", &b);
CALL_E_FUNC(check_numbers, a, b);
CATCH(true)
printf("%d == %d\n", a, b);
THROW_UP(256);
printf("yay!\n");
*ret = 0;
THROW_UP(42);
CATCH(false)
printf("%d != %d\n", a, b);
RESUME;
END_BLOCK
END_E_FUNC
int main(void) {
uint8_t exc_i = 0;
int ret = 1;
switch(setjmp(__E_CATCHER(0))) {
case 0:
case 1:
e_main(exc_i, &ret);
case 42:
printf("returning\n");
break;
default:
fprintf(stderr, "uncaught exception!\n");
longjmp(__E_RESUMER(0), 1);
}
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment