From 76b8c9e03c97b16d9ff97f3b79c0ecbff0f5e7f2 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 30 Mar 2017 17:31:44 +0300 Subject: Initial commit --- src/ragel/ragel.h | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 src/ragel/ragel.h (limited to 'src/ragel/ragel.h') diff --git a/src/ragel/ragel.h b/src/ragel/ragel.h new file mode 100644 index 0000000..af06f4a --- /dev/null +++ b/src/ragel/ragel.h @@ -0,0 +1,236 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ragel { + struct { + uint8_t *data; // data\0another_data\0 + const uint8_t *cur; // data\0another_data\0cursor + size_t written, size; // amount of data written / size of data + } mem; + + char buf[4096]; // block of input data + const char *p, *pe, *eof; // see ragel doc + size_t lineno; // current line +}; + +static inline void +ragel_get_current_line(const struct ragel *ragel, size_t *out_lineno, size_t *out_ls, size_t *out_le, size_t *out_ws, size_t *out_we) +{ + assert(out_ls && out_le && out_ws && out_we); + assert(ragel->p >= ragel->buf && ragel->pe >= ragel->p); + + size_t ls, le, ws, we; + size_t off = ragel->p - ragel->buf; + size_t lineno = ragel->lineno; + const size_t end = ragel->pe - ragel->buf; + + // rewind to first non-space + for (; off > 0 && (isspace(ragel->buf[off]) || !ragel->buf[off]); --off) { + if (lineno > 0 && ragel->buf[off] == '\n') + --lineno; + } + + for (ls = off; ls > 0 && ragel->buf[ls] != '\n'; --ls); // beginning of line + for (le = off; le < end && ragel->buf[le] != '\n'; ++le); // end of line + for (; ls < le && isspace(ragel->buf[ls]); ++ls); // strip leading whitespace + for (ws = off; ws > ls && isspace(ragel->buf[ws]); --ws); // rewind to first non-space + for (; ws > 0 && ws > ls && !isspace(ragel->buf[ws - 1]); --ws); // find word start + for (we = ws; we < le && !isspace(ragel->buf[we]); ++we); // find word ending + + assert(we >= ws && ws >= ls && le >= ls && le >= we); + *out_lineno = lineno; + *out_ls = ls; + *out_le = le; + *out_ws = ws; + *out_we = we; +} + +__attribute__((format(printf, 2, 3))) +static inline void +ragel_throw_error(const struct ragel *ragel, const char *fmt, ...) +{ + assert(ragel && fmt); + + size_t lineno, ls, le, ws, we; + ragel_get_current_line(ragel, &lineno, &ls, &le, &ws, &we); + assert(le - ls <= INT_MAX && ws - ls <= INT_MAX); + + char msg[255]; + va_list args; + va_start(args, fmt); + vsnprintf(msg, sizeof(msg), fmt, args); + va_end(args); + + const int indent = 8; + const size_t mark = (we - ws ? we - ws : 1), cur = (ragel->p - ragel->buf) - ws; + warnx("\x1b[37m%zu: \x1b[31merror: \x1b[0m%s\n%*s%.*s", lineno, msg, indent, "", (int)(le - ls), ragel->buf + ls); + fprintf(stderr, "%*s%*s\x1b[31m", indent, "", (int)(ws - ls), ""); + for (size_t i = 0; i < mark; ++i) fputs((i == cur ? "^" : "~"), stderr); + fputs("\x1b[0m\n", stderr); + + exit(EXIT_FAILURE); +} + +static inline void +ragel_bounds_check_data(const struct ragel *ragel, const size_t nmemb) +{ + assert(ragel); + + if (ragel->mem.size < nmemb || ragel->mem.written >= ragel->mem.size - nmemb) + ragel_throw_error(ragel, "data storage limit exceeded: %zu bytes exceeds the maximum store size of %zu bytes", ragel->mem.written, ragel->mem.size); +} + +static inline void +ragel_replace_data(struct ragel *ragel, const size_t nmemb, char replacement) +{ + assert(ragel); + + if (ragel->mem.written < nmemb) + ragel_throw_error(ragel, "parse error: received escape conversion with mem.written of %zu, expected >= %zu", ragel->mem.written, nmemb); + + ragel->mem.data[(ragel->mem.written -= nmemb)] = replacement; + ragel->mem.data[++ragel->mem.written] = 0; +} + +static inline void +ragel_convert_escape(struct ragel *ragel) +{ + assert(ragel); + + if (ragel->mem.written < 2) + ragel_throw_error(ragel, "parse error: received escape conversion with mem.written of %zu, expected >= 2", ragel->mem.written); + + const struct { + const char *e; + const char v, b; + } map[] = { + { .e = "\\a", .v = '\a' }, + { .e = "\\b", .v = '\b' }, + { .e = "\\f", .v = '\f' }, + { .e = "\\n", .v = '\n' }, + { .e = "\\r", .v = '\r' }, + { .e = "\\t", .v = '\t' }, + { .e = "\\v", .v = '\v' }, + { .e = "\\\\", .v = '\\' }, + { .e = "\\'", .v = '\'' }, + { .e = "\\\"", .v = '"' }, + { .e = "\\e", .v = '\e' }, + { .e = "\\x", .b = 16 }, + { .e = "\\", .b = 8 }, + }; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + const char *cur = (char*)ragel->mem.cur; + const size_t cur_sz = strlen(cur); + for (size_t i = 0; i < ARRAY_SIZE(map); ++i) { + if (!strncmp(cur, map[i].e, strlen(map[i].e))) { + const char v = (!map[i].b ? map[i].v : strtol(cur + strlen(map[i].e), NULL, map[i].b)); + assert((map[i].b == 8 && cur_sz >= 2) || (map[i].b == 16 && cur_sz >= 2) || (map[i].b == 0 && cur_sz == 2)); + assert(map[i].b != 8 || isdigit(cur[1])); + ragel_replace_data(ragel, cur_sz, v); + return; + } + } +#undef ARRAY_SIZE + + ragel_throw_error(ragel, "parse error: received unknown escape conversion"); +} + +static inline void +ragel_dump_data(struct ragel *ragel, const size_t offset) +{ + const uint8_t *end = ragel->mem.data + ragel->mem.written; + for (const uint8_t *p = ragel->mem.data + offset; p && p < end; p = (uint8_t*)memchr(p, 0, end - p), p += !!p) + printf("%s\n", p); +} + +static inline const uint8_t* +ragel_search_data(const struct ragel *ragel, const size_t offset, const uint8_t *data, const size_t size) +{ + assert(ragel && data); + + const uint8_t *end = ragel->mem.data + ragel->mem.written; + for (const uint8_t *p = ragel->mem.data + offset; p && p < end && (size_t)(end - p) >= size; p = (uint8_t*)memchr(p, 0, end - p), p += !!p) { + if (!memcmp(data, p, size)) + return p; + } + + return NULL; +} + +static inline const uint8_t* +ragel_search_str(const struct ragel *ragel, const size_t offset, const char *str) +{ + return ragel_search_data(ragel, offset, (const uint8_t*)str, strlen(str) + 1); +} + +static inline void +ragel_remove_last_data(struct ragel *ragel) +{ + assert(ragel); + const uint8_t *end = ragel->mem.data + ragel->mem.written; + const size_t size = end - ragel->mem.cur + 1; + assert(ragel->mem.written >= size); + ragel->mem.written -= size; + ragel->mem.data[ragel->mem.written] = 0; +} + +static inline void +ragel_finish_data(struct ragel *ragel) +{ + assert(ragel); + + const uint8_t *end = ragel->mem.data + ragel->mem.written, *p; + if ((p = ragel_search_data(ragel, 0, ragel->mem.cur, end - ragel->mem.cur + 1))) { + ragel_remove_last_data(ragel); + ragel->mem.cur = p; + } +} + +static inline void +ragel_store_data(struct ragel *ragel) +{ + ragel_bounds_check_data(ragel, 1); + ragel->mem.data[ragel->mem.written++] = *ragel->p; + ragel->mem.data[ragel->mem.written] = 0; +} + +static inline void +ragel_begin_data(struct ragel *ragel) +{ + ragel_bounds_check_data(ragel, 1); + ragel->mem.written += (ragel->mem.written > 0); + ragel->mem.cur = ragel->mem.data + ragel->mem.written; +} + +static inline void +ragel_advance_line(struct ragel *ragel) +{ + assert(ragel); + ++ragel->lineno; +} + +static inline bool +ragel_confirm_input(struct ragel *ragel, const size_t bytes) +{ + assert(ragel); + + if (bytes > sizeof(ragel->buf)) + errx(EXIT_FAILURE, "%s: gave larger buffer than %zu", __func__, sizeof(ragel->buf)); + + const bool in_eof = (bytes < sizeof(ragel->buf)); + ragel->p = ragel->buf; + ragel->pe = ragel->p + bytes; + ragel->eof = (in_eof ? ragel->pe : NULL); + return !in_eof; +} -- cgit v1.2.3