Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Last active October 23, 2022 11:02
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pervognsen/a199b91ace24554b7fc6f26b693df11b to your computer and use it in GitHub Desktop.
Save pervognsen/a199b91ace24554b7fc6f26b693df11b to your computer and use it in GitHub Desktop.
// The stack is 8-byte aligned.
#define ALIGN(p) ((uint64_t *)(((uintptr_t)(p) + 7) & ~7))
#define STACK(stack, size) uint64_t *_stack = ALIGN(stack), *_stack_end = (uint64_t *)((char *)(stack) + size)
#define PUSH(x) do { memcpy(_stack, &x, sizeof(x)); _stack += (sizeof(x) + 7) / 8; } while (0)
#define POP(x) do { _stack -= (sizeof(x) + 7) / 8; memcpy(&x, _stack, sizeof(x)); } while (0)
#if __GNUC__
// Use computed gotos on GCC-compatible compilers (including Clang).
#define JOIN(x, y) x##y
#define LABEL(name) JOIN(label, name)
#define BEGIN(name) CALL(name); goto _end;
#define END RETURN; _end: ;
#define FUNCTION(name) RETURN; name:
#define CALL(name) do { *_stack++ = (uint64_t)&&LABEL(__LINE__); goto name; LABEL(__LINE__): ; } while (0)
#define RETURN goto *(void *)*--_stack
#else
// Use Duff's Device as a fallback on other compilers.
#define BEGIN(name) uint32_t _case = 0; *_stack++ = 0; goto name; _dispatch: switch(_case) { case 0: goto _end;
#define END RETURN; _end: ; }
#define FUNCTION(name) RETURN; name:
#define CALL(name) do { *_stack++ = __LINE__; goto name; case __LINE__: ; } while (0)
#define RETURN do { _case = *--_stack; goto _dispatch; } while (0)
#endif
void parse(char *input, char *input_end) {
char ch;
uintptr_t nesting;
char stack[1024];
STACK(stack, sizeof(stack));
BEGIN(parse_root)
FUNCTION(parse_root)
while (input != input_end) {
if (*input++ == '@')
CALL(parse_tag);
}
FUNCTION(parse_tag)
while (input != input_end && !word_terminator[*input])
input++;
if (input != input_end) {
ch = *input;
if (ch == '{') {
input++;
nesting = 0;
while (input != input_end) {
ch = *input++;
if (ch == '@') {
PUSH(nesting);
CALL(parse_tag);
POP(nesting);
} else if (ch == '{') {
nesting++;
} else if (ch == '}') {
if (nesting == 0)
break;
nesting--;
}
}
} else if (ch == '=') {
input++;
while (input != input_end && !word_terminator[*input])
input++;
} else if (ch == ':') {
input++;
while (input != input_end && *input != '\n' && *input != '\r') {
ch = *input++;
if (ch == '@')
CALL(parse_tag);
}
}
}
END
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment