summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile15
-rw-r--r--spec/elf.fspec8
-rw-r--r--src/bin/fspec/dump.c (renamed from src/dump.c)33
-rw-r--r--src/fspec/bcode.c14
-rw-r--r--src/fspec/bcode.h110
-rw-r--r--src/fspec/lexer.h12
-rw-r--r--src/fspec/lexer.rl616
-rw-r--r--src/fspec/private/bcode-types.h (renamed from src/fspec/bcode-internal.h)0
-rw-r--r--src/fspec/ragel/lexer-expr.h20
-rw-r--r--src/fspec/ragel/lexer-expr.rl122
-rw-r--r--src/fspec/ragel/lexer-stack.h42
-rw-r--r--src/fspec/ragel/lexer-stack.rl153
-rw-r--r--src/fspec/ragel/lexer.rl180
-rw-r--r--src/fspec/ragel/validator.rl96
-rw-r--r--src/fspec/validator.h2
-rw-r--r--src/fspec/validator.rl236
-rw-r--r--src/util/membuf.c31
-rw-r--r--src/util/membuf.h14
-rw-r--r--src/util/ragel/ragel.h (renamed from src/ragel/ragel.h)0
-rw-r--r--src/util/ragel/ragel.rl (renamed from src/ragel/ragel.rl)1
-rw-r--r--vim/filespec.vim2
21 files changed, 796 insertions, 911 deletions
diff --git a/Makefile b/Makefile
index c360598..0848407 100644
--- a/Makefile
+++ b/Makefile
@@ -23,14 +23,17 @@ all: $(bins)
$(bins): %:
$(LINK.c) $(filter %.c %.a,$^) $(LDLIBS) -o $@
-fspec-ragel.a: src/ragel/ragel.h src/ragel/ragel.c
-fspec-bcode.a: src/fspec/memory.h src/fspec/bcode.h src/fspec/bcode.c
-fspec-lexer.a: src/ragel/ragel.h src/fspec/lexer.h src/fspec/lexer.c
-fspec-validator.a: src/ragel/ragel.h src/fspec/validator.h src/fspec/validator.c
+fspec-membuf.a: src/util/membuf.h src/util/membuf.c
+fspec-ragel.a: src/util/ragel/ragel.h src/util/ragel/ragel.c
+fspec-lexer-stack.a: src/fspec/ragel/lexer-stack.h src/fspec/ragel/lexer-stack.c
+fspec-lexer-expr.a: src/fspec/ragel/lexer-expr.h src/fspec/ragel/lexer-expr.c
+fspec-bcode.a: src/fspec/memory.h src/fspec/private/bcode-types.h src/fspec/bcode.h src/fspec/bcode.c fspec-ragel.a
+fspec-lexer.a: src/fspec/lexer.h src/fspec/ragel/lexer.c fspec-lexer-stack.a fspec-lexer-expr.a fspec-bcode.a
+fspec-validator.a: src/fspec/validator.h src/fspec/ragel/validator.c fspec-ragel.a
fspec-dump: private CPPFLAGS += $(shell pkg-config --cflags-only-I squash-0.8)
fspec-dump: private LDLIBS += $(shell pkg-config --libs-only-l squash-0.8)
-fspec-dump: src/dump.c fspec-ragel.a fspec-bcode.a fspec-lexer.a fspec-validator.a
+fspec-dump: src/bin/fspec/dump.c fspec-ragel.a fspec-membuf.a fspec-bcode.a fspec-lexer-stack.a fspec-lexer-expr.a fspec-lexer.a fspec-validator.a
dec2bin: src/bin/misc/dec2bin.c
@@ -48,7 +51,7 @@ install-bin: $(bins)
install: install-bin
clean:
- $(RM) src/ragel/ragel.c src/fspec/lexer.c src/fspec/validator.c
+ $(RM) src/util/ragel/*.c src/fspec/ragel/*.c
$(RM) $(bins) *.a
.PHONY: all clean install
diff --git a/spec/elf.fspec b/spec/elf.fspec
index e9f3f3b..2ad5f78 100644
--- a/spec/elf.fspec
+++ b/spec/elf.fspec
@@ -1,3 +1,11 @@
+enum foo {
+ foo: 0x1;
+ bar: 0x2;
+ eaf: 0x3;
+ eaf: 0xDEADBEEF;
+ bar;
+};
+
struct elf64 {
e_entry: u64 hex;
e_phoff: u64;
diff --git a/src/dump.c b/src/bin/fspec/dump.c
index 8af7119..07a6757 100644
--- a/src/dump.c
+++ b/src/bin/fspec/dump.c
@@ -14,9 +14,12 @@
#include <fspec/bcode.h>
#include <fspec/lexer.h>
#include <fspec/validator.h>
+#include "util/membuf.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#if 0
+
static size_t
to_hex(const uint8_t *buf, const size_t buf_sz, char *out, const size_t out_sz, const bool reverse)
{
@@ -737,6 +740,7 @@ execute(const struct fspec_mem *mem)
free(context.decl);
}
+#endif
static FILE*
fopen_or_die(const char *path, const char *mode)
@@ -754,17 +758,28 @@ fopen_or_die(const char *path, const char *mode)
struct lexer {
struct fspec_lexer lexer;
+ struct membuf output;
FILE *file;
};
static size_t
-fspec_lexer_read(struct fspec_lexer *lexer, void *ptr, const size_t size, const size_t nmemb)
+fspec_lexer_write(struct fspec_lexer *lexer, const enum fspec_lexer_section section, const void *output, const size_t size, const size_t nmemb)
+{
+ assert(lexer && output);
+ // struct lexer *l = container_of(lexer, struct lexer, lexer);
+ (void)lexer, (void)section, (void)size, (void)nmemb;
+ return nmemb;
+}
+
+static size_t
+fspec_lexer_read(struct fspec_lexer *lexer, void *input, const size_t size, const size_t nmemb)
{
- assert(lexer && ptr);
+ assert(lexer && input);
struct lexer *l = container_of(lexer, struct lexer, lexer);
- return fread(ptr, size, nmemb, l->file);
+ return fread(input, size, nmemb, l->file);
}
+#if 0
static size_t
fspec_validator_read(struct fspec_validator *validator, void *ptr, const size_t size, const size_t nmemb)
{
@@ -776,6 +791,7 @@ fspec_validator_read(struct fspec_validator *validator, void *ptr, const size_t
assert(validator->mem.input.len == 0);
return read;
}
+#endif
int
main(int argc, const char *argv[])
@@ -784,26 +800,28 @@ main(int argc, const char *argv[])
errx(EXIT_FAILURE, "usage: %s file.spec < data", argv[0]);
char output[4096];
- struct fspec_mem bcode = {0};
{
char input[4096];
struct lexer l = {
.lexer = {
.ops.read = fspec_lexer_read,
- .mem.input = { .data = input, sizeof(input) },
- .mem.output = { .data = output, sizeof(output) },
+ .ops.write = fspec_lexer_write,
+ .mem.input = { .data = input, .len = sizeof(input) },
},
.file = fopen_or_die(argv[1], "rb"),
+ .output.mem = { .data = output, .len = sizeof(output) },
};
if (!fspec_lexer_parse(&l.lexer, argv[1]))
exit(EXIT_FAILURE);
fclose(l.file);
- bcode = l.lexer.mem.output;
+ // bcode = l.lexer.mem.output;
}
+#if 0
+
{
struct fspec_validator validator = {
.ops.read = fspec_validator_read,
@@ -815,5 +833,6 @@ main(int argc, const char *argv[])
}
execute(&bcode);
+#endif
return EXIT_SUCCESS;
}
diff --git a/src/fspec/bcode.c b/src/fspec/bcode.c
index 0d0d3fd..70e4b08 100644
--- a/src/fspec/bcode.c
+++ b/src/fspec/bcode.c
@@ -1,5 +1,6 @@
#include <fspec/bcode.h>
-#include "bcode-internal.h"
+#include <fspec/memory.h>
+#include "private/bcode-types.h"
#include <stdlib.h>
#include <string.h>
@@ -8,7 +9,15 @@
static_assert(sizeof(fspec_off) <= sizeof(((struct fspec_mem*)0)->len), "fspec_off should not be larger than what fspec_mem can represent");
static_assert(sizeof(enum fspec_op) == sizeof(uint8_t), "enum fspec_op is expected to have size of uint8_t");
-static_assert(sizeof(enum fspec_arg) == sizeof(uint8_t), "enum fspec_arg is expected to have size of uint8_t");
+static_assert(sizeof(struct fspec_bcode) == sizeof(enum fspec_op), "struct fspec_bcode is expected to have size of enum fspec_op");
+static_assert(sizeof(FSPEC_OP_LAST) <= 8, "op codes need more than 3 bits to be represented");
+
+#if 0
+uint8_t
+fspec_op_get_num_args(const struct fspec_op_code *code)
+{
+ return code->op >> 2;
+}
static fspec_off
arg_data_len(const enum fspec_arg *arg)
@@ -187,3 +196,4 @@ fspec_op_next(const enum fspec_op *start, const void *end, const bool skip_args)
return NULL;
}
+#endif
diff --git a/src/fspec/bcode.h b/src/fspec/bcode.h
index d84060e..3d216af 100644
--- a/src/fspec/bcode.h
+++ b/src/fspec/bcode.h
@@ -1,7 +1,5 @@
#pragma once
-#include <fspec/memory.h>
-
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
@@ -10,34 +8,6 @@
#define PRI_FSPEC_NUM PRIu64
typedef uint64_t fspec_num;
-enum fspec_arg {
- FSPEC_ARG_DAT,
- FSPEC_ARG_OFF,
- FSPEC_ARG_NUM,
- FSPEC_ARG_VAR,
- FSPEC_ARG_STR,
- FSPEC_ARG_EOF,
- FSPEC_ARG_LAST,
-} __attribute__((packed));
-
-void
-fspec_arg_get_mem(const enum fspec_arg *arg, const void *data, struct fspec_mem *out_mem);
-
-fspec_num
-fspec_arg_get_num(const enum fspec_arg *arg);
-
-const char*
-fspec_arg_get_cstr(const enum fspec_arg *arg, const void *data);
-
-const enum fspec_arg*
-fspec_arg_next(const enum fspec_arg *arg, const void *end, const uint8_t nth, const uint32_t expect);
-
-enum fspec_declaration {
- FSPEC_DECLARATION_STRUCT,
- FSPEC_DECLARATION_MEMBER,
- FSPEC_DECLARATION_LAST,
-} __attribute__((packed));
-
enum fspec_visual {
FSPEC_VISUAL_NUL,
FSPEC_VISUAL_DEC,
@@ -46,19 +16,77 @@ enum fspec_visual {
FSPEC_VISUAL_LAST,
} __attribute__((packed));
+enum fspec_type {
+ FSPEC_TYPE_CODE,
+ FSPEC_TYPE_CALL,
+ FSPEC_TYPE_U8,
+ FSPEC_TYPE_S8,
+ FSPEC_TYPE_U16,
+ FSPEC_TYPE_S16,
+ FSPEC_TYPE_U32,
+ FSPEC_TYPE_S32,
+ FSPEC_TYPE_U64,
+ FSPEC_TYPE_S64,
+ FSPEC_TYPE_LAST,
+} __attribute__((packed));
+
+enum fspec_storage {
+ FSPEC_STORAGE_DATA,
+ FSPEC_STORAGE_LOCAL,
+ FSPEC_STORAGE_LAST,
+} __attribute__((packed));
+
+enum fspec_builtin {
+ FSPEC_BUILTIN_ADD,
+ FSPEC_BUILTIN_SUB,
+ FSPEC_BUILTIN_MUL,
+ FSPEC_BUILTIN_DIV,
+ FSPEC_BUILTIN_MOD,
+ FSPEC_BUILTIN_BIT_AND,
+ FSPEC_BUILTIN_BIT_OR,
+ FSPEC_BUILTIN_BIT_XOR,
+ FSPEC_BUILTIN_BIT_LEFT,
+ FSPEC_BUILTIN_BIT_RIGHT,
+ FSPEC_BUILTIN_DECLARE,
+ FSPEC_BUILTIN_READ,
+ FSPEC_BUILTIN_FILTER,
+ FSPEC_BUILTIN_VISUAL,
+ FSPEC_BUILTIN_LAST,
+} __attribute__((packed));
+
enum fspec_op {
- FSPEC_OP_ARG,
- FSPEC_OP_HEADER,
- FSPEC_OP_DECLARATION,
- FSPEC_OP_READ,
- FSPEC_OP_GOTO,
- FSPEC_OP_FILTER,
- FSPEC_OP_VISUAL,
+ FSPEC_OP_BUILTIN,
+ FSPEC_OP_PUSH,
+ FSPEC_OP_POP,
+ FSPEC_OP_VAR,
FSPEC_OP_LAST,
} __attribute__((packed));
-const enum fspec_op*
-fspec_op_next(const enum fspec_op *op, const void *end, const bool skip_args);
+struct fspec_bcode {
+ char op, data[];
+} __attribute__((packed));
+
+#if 0
+('fspc')(version)
+OP_BUILTIN (declare) OP_PUSH OP_VAR8 (storage) OP_VAR8 (type) OP_VAR [name] OP_POP
+OP_BUILTIN (filter)
+OP_FUN FUN_ASSIGN VAR0 VAR [data]
+OP_FUN FUN_READ
+#endif
-const enum fspec_arg*
-fspec_op_get_arg(const enum fspec_op *op, const void *end, const uint8_t nth, const uint32_t expect);
+#if 0
+uint8_t
+fspec_op_get_num_args(const struct fspec_bcode *code);
+
+const struct fspec_bcode*
+fspec_op_next(const struct fspec_bcode *code, const void *end, const bool skip_args);
+
+const struct fspec_bcode*
+fspec_op_get_arg(const struct fspec_bcode *code, const void *end, const uint8_t nth, const uint32_t expect);
+
+const struct fspec_arg*
+fspec_arg_next(const struct fspec_bcode *code, const void *end, const uint8_t nth, const uint32_t expect);
+
+fspec_num
+fspec_ref_get_num(const struct fspec_bcode *code);
+#endif
diff --git a/src/fspec/lexer.h b/src/fspec/lexer.h
index 7b60e6b..ef6e059 100644
--- a/src/fspec/lexer.h
+++ b/src/fspec/lexer.h
@@ -2,14 +2,22 @@
#include <fspec/memory.h>
+#include <stdbool.h>
+
+enum fspec_lexer_section {
+ FSPEC_SECTION_DATA,
+ FSPEC_SECTION_CODE,
+};
+
struct fspec_lexer;
struct fspec_lexer {
struct {
- size_t (*read)(struct fspec_lexer *lexer, void *ptr, const size_t size, const size_t nmemb);
+ size_t (*read)(struct fspec_lexer *lexer, void *input, const size_t size, const size_t nmemb);
+ size_t (*write)(struct fspec_lexer *lexer, const enum fspec_lexer_section section, const void *output, const size_t size, const size_t nmemb);
} ops;
struct {
- struct fspec_mem input, output;
+ struct fspec_mem input;
} mem;
};
diff --git a/src/fspec/lexer.rl b/src/fspec/lexer.rl
deleted file mode 100644
index 51d1a54..0000000
--- a/src/fspec/lexer.rl
+++ /dev/null
@@ -1,616 +0,0 @@
-#include "ragel/ragel.h"
-#include <fspec/bcode.h>
-#include <fspec/lexer.h>
-#include "bcode-internal.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <err.h>
-
-#define PLACEHOLDER 0xDEADBEEF
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-
-typedef uint8_t fspec_strsz;
-
-struct membuf {
- struct fspec_mem mem;
- fspec_off written;
-};
-
-static void
-membuf_bounds_check(const struct membuf *buf, const fspec_off nmemb)
-{
- assert(buf);
-
- if (buf->mem.len < nmemb || buf->written > buf->mem.len - nmemb)
- errx(EXIT_FAILURE, "%s: %" PRI_FSPEC_OFF " bytes exceeds the maximum storage size of %zu bytes", __func__, buf->written + nmemb, buf->mem.len);
-}
-
-static void
-membuf_terminate(struct membuf *buf, const void *data, const fspec_off data_sz)
-{
- membuf_bounds_check(buf, data_sz);
- memcpy((char*)buf->mem.data + buf->written, data, data_sz);
-}
-
-static void
-membuf_replace(struct membuf *buf, const fspec_off off, const void *data, const fspec_off data_sz)
-{
- assert(buf->mem.len >= data_sz && off <= buf->mem.len - data_sz);
- memcpy((char*)buf->mem.data + off, data, data_sz);
-}
-
-static void
-membuf_append_at(struct membuf *buf, const fspec_off off, const void *data, const fspec_off data_sz)
-{
- assert(off <= buf->written);
- membuf_bounds_check(buf, data_sz);
- const size_t rest = buf->written - off;
- memmove((char*)buf->mem.data + off + data_sz, (char*)buf->mem.data + off, rest);
- membuf_replace(buf, off, data, data_sz);
- buf->written += data_sz;
- assert(buf->written <= buf->mem.len);
-}
-
-static void
-membuf_append(struct membuf *buf, const void *data, const fspec_off data_sz)
-{
- membuf_append_at(buf, buf->written, data, data_sz);
-}
-
-struct varbuf {
- struct membuf buf;
- fspec_off offset;
-};
-
-static inline void
-varbuf_begin(struct varbuf *var)
-{
- assert(var);
- var->offset = var->buf.written;
- assert(var->offset <= var->buf.mem.len);
-}
-
-static void
-varbuf_reset(struct varbuf *var)
-{
- assert(var);
- var->offset = var->buf.written = 0;
-}
-
-static inline void
-varbuf_remove_last(struct varbuf *var)
-{
- assert(var);
- assert(var->buf.written >= var->offset);
- const fspec_off size = var->buf.written - var->offset;
- assert(var->buf.written >= size);
- var->buf.written -= size;
- assert(var->buf.written <= var->buf.mem.len);
-}
-
-enum section {
- SECTION_DATA,
- SECTION_CODE,
- SECTION_LAST,
-};
-
-struct codebuf {
- struct membuf buf;
- const void *decl[FSPEC_DECLARATION_LAST], *end[SECTION_LAST], *strings;
- fspec_var declarations;
-};
-
-static void
-codebuf_append(struct codebuf *code, const enum section section, const void *data, const fspec_off data_sz)
-{
- assert(code->end[section]);
- const fspec_off off = (char*)code->end[section] - (char*)code->buf.mem.data;
- membuf_append_at(&code->buf, off, data, data_sz);
-
- for (enum section s = section; s < ARRAY_SIZE(code->end); ++s) {
- code->end[s] = (char*)code->end[s] + data_sz;
- assert((char*)code->end[s] <= (char*)code->buf.mem.data + code->buf.mem.len);
- }
-
- if (section == SECTION_DATA) {
- for (enum fspec_declaration d = 0; d < ARRAY_SIZE(code->decl); ++d) {
- code->decl[d] = (code->decl[d] ? (char*)code->decl[d] + data_sz : NULL);
- assert((char*)code->decl[d] <= (char*)code->buf.mem.data + code->buf.mem.len);
- }
- }
-
- assert(code->end[SECTION_DATA] <= code->end[SECTION_CODE]);
- assert((char*)code->end[SECTION_CODE] == (char*)code->buf.mem.data + code->buf.written);
-}
-
-static void
-codebuf_append_op(struct codebuf *code, const enum fspec_op op)
-{
- codebuf_append(code, SECTION_CODE, &op, sizeof(op));
-}
-
-static uint8_t
-arg_sizeof(const enum fspec_arg type)
-{
- switch (type) {
- case FSPEC_ARG_DAT:
- case FSPEC_ARG_OFF:
- case FSPEC_ARG_STR:
- return sizeof(fspec_off);
-
- case FSPEC_ARG_NUM:
- return sizeof(fspec_num);
-
- case FSPEC_ARG_VAR:
- return sizeof(fspec_var);
-
- case FSPEC_ARG_EOF:
- break;
-
- case FSPEC_ARG_LAST:
- errx(EXIT_FAILURE, "%s: unexpected argument type %u", __func__, type);
- }
-
- return 0;
-}
-
-static void
-codebuf_append_arg(struct codebuf *code, const enum fspec_arg type, const void *v)
-{
- assert(code);
- codebuf_append_op(code, FSPEC_OP_ARG);
- codebuf_append(code, SECTION_CODE, &type, sizeof(type));
- codebuf_append(code, SECTION_CODE, v, arg_sizeof(type));
-}
-
-static void
-codebuf_replace_arg(struct codebuf *code, const enum fspec_arg *arg, const enum fspec_arg type, const void *v)
-{
- assert(code && arg);
- assert(*arg == type);
- const fspec_off off = ((char*)arg + 1) - (char*)code->buf.mem.data;
- membuf_replace(&code->buf, off, v, arg_sizeof(type));
-}
-
-static bool
-get_string_offset(const void *start, const void *end, const void *str, const fspec_strsz str_sz, void const **out_off)
-{
- assert(out_off);
-
- while (start < end) {
- fspec_strsz len;
- memcpy(&len, start, sizeof(len));
- if (len == str_sz && !memcmp((char*)start + sizeof(len), str, len)) {
- *out_off = start;
- return true;
- }
- start = (char*)start + sizeof(len) + len + 1;
- }
-
- return false;
-}
-
-static void
-codebuf_append_arg_cstr(struct codebuf *code, const void *str, const fspec_strsz str_sz)
-{
- const void *ptr;
- if (!get_string_offset(code->strings, code->end[SECTION_DATA], str, str_sz, &ptr)) {
- ptr = code->end[SECTION_DATA];
- codebuf_append(code, SECTION_DATA, &str_sz, sizeof(str_sz));
- codebuf_append(code, SECTION_DATA, str, str_sz);
- codebuf_append(code, SECTION_DATA, (char[]){ 0 }, 1);
- }
-
- const fspec_off off = (char*)ptr - (char*)code->buf.mem.data;
- codebuf_append_arg(code, FSPEC_ARG_STR, &off);
-}
-
-static const enum fspec_op*
-get_named_op(const enum fspec_op *start, const void *end, const void *data, const enum fspec_op op, const uint8_t nth, const void *name, const fspec_strsz name_sz, fspec_var *out_id)
-{
- fspec_var id = 0;
- if ((void*)start < end && *start == FSPEC_OP_DECLARATION)
- id = fspec_arg_get_num(fspec_op_get_arg(start, end, 2, 1<<FSPEC_ARG_NUM));
-
- for (const enum fspec_op *p = start; p; p = fspec_op_next(p, end, true)) {
- const enum fspec_arg *arg;
- if (*p != op || !(arg = fspec_op_get_arg(p, end, nth, 1<<FSPEC_ARG_STR)))
- continue;
-
- struct fspec_mem str;
- fspec_arg_get_mem(arg, data, &str);
- if (str.len == name_sz && !memcmp(name, str.data, name_sz)) {
- if (out_id)
- *out_id = id;
-
- return p;
- }
-
- ++id;
- }
-
- return NULL;
-}
-
-static const enum fspec_op*
-get_declaration(struct codebuf *code, const bool member, const struct fspec_mem *str, fspec_var *out_id)
-{
- const void *start = (member ? code->decl[FSPEC_DECLARATION_STRUCT] : code->end[SECTION_DATA]);
- return get_named_op(start, code->end[SECTION_CODE], code->buf.mem.data, FSPEC_OP_DECLARATION, 4, str->data, str->len, out_id);
-}
-
-static bool
-codebuf_append_arg_var(struct codebuf *code, const bool member, const struct fspec_mem *var)
-{
- fspec_var id = -1;
- if (!get_declaration(code, member, var, &id))
- return false;
-
- codebuf_append_arg(code, FSPEC_ARG_VAR, &id);
- return true;
-}
-
-static void
-codebuf_append_declaration(struct codebuf *code, const enum fspec_declaration decl)
-{
- code->decl[decl] = code->end[SECTION_CODE];
- codebuf_append_op(code, FSPEC_OP_DECLARATION);
- codebuf_append_arg(code, FSPEC_ARG_NUM, (fspec_num[]){ decl });
- codebuf_append_arg(code, FSPEC_ARG_NUM, (fspec_num[]){ code->declarations++ });
- codebuf_append_arg(code, FSPEC_ARG_OFF, (fspec_off[]){ PLACEHOLDER });
-}
-
-enum stack_type {
- STACK_STR,
- STACK_NUM,
-};
-
-struct stack {
- union {
- struct fspec_mem str;
- uint64_t num;
- };
- enum stack_type type;
-};
-
-static const char*
-stack_type_to_str(const enum stack_type type)
-{
- switch (type) {
- case STACK_STR: return "str";
- case STACK_NUM: return "num";
- };
- return "unknown";
-}
-
-static void
-stack_check_type(const struct stack *stack, const enum stack_type type)
-{
- assert(stack);
-
- if (stack->type != type)
- errx(EXIT_FAILURE, "tried to get '%s' from stack, but the last pushed type was '%s'", stack_type_to_str(type), stack_type_to_str(stack->type));
-}
-
-static const struct fspec_mem*
-stack_get_str(const struct stack *stack)
-{
- stack_check_type(stack, STACK_STR);
- return &stack->str;
-}
-
-static uint64_t
-stack_get_num(const struct stack *stack)
-{
- stack_check_type(stack, STACK_NUM);
- return stack->num;
-}
-
-struct state {
- struct ragel ragel;
- struct stack stack;
- struct codebuf out;
- struct varbuf var;
-};
-
-static void
-state_stack_num(struct state *state, const uint8_t base)
-{
- assert(state);
- membuf_terminate(&state->var.buf, (char[]){ 0 }, 1);
- const char *str = (char*)state->var.buf.mem.data + state->var.offset;
- state->stack.type = STACK_NUM;
- state->stack.num = strtoll(str + (base == 16 && *str == 'x'), NULL, base);
- varbuf_remove_last(&state->var);
-}
-
-static void
-state_append_arg_var(struct state *state, const bool member, const struct fspec_mem *str)
-{
- assert(state && str);
-
- if (!codebuf_append_arg_var(&state->out, member, str))
- ragel_throw_error(&state->ragel, "'%s' undeclared", (char*)str->data);
-}
-
-static void
-state_append_declaration(struct state *state, const enum fspec_declaration decl, const struct fspec_mem *str)
-{
- assert(state && str);
-
- if (get_declaration(&state->out, (decl == FSPEC_DECLARATION_MEMBER), str, NULL))
- ragel_throw_error(&state->ragel, "'%s' redeclared", (char*)str->data);
-
- codebuf_append_declaration(&state->out, decl);
- codebuf_append_arg_cstr(&state->out, str->data, str->len);
-}
-
-static void
-state_finish_declaration(struct state *state, const enum fspec_declaration decl)
-{
- assert(state && state->out.decl[decl]);
- const char *end = state->out.end[SECTION_CODE];
- const fspec_off off = end - (char*)state->out.decl[decl];
- codebuf_replace_arg(&state->out, fspec_op_get_arg(state->out.decl[decl], end, 3, 1<<FSPEC_ARG_OFF), FSPEC_ARG_OFF, &off);
- state->out.decl[decl] = NULL;
-}
-
-%%{
- machine fspec_lexer;
- variable p state.ragel.p;
- variable pe state.ragel.pe;
- variable eof state.ragel.eof;
- write data noerror nofinal;
-
- action arg_eof {
- codebuf_append_arg(&state.out, FSPEC_ARG_EOF, NULL);
- }
-
- action arg_num {
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ stack_get_num(&state.stack) });
- }
-
- action arg_str {
- const struct fspec_mem *str = stack_get_str(&state.stack);
- codebuf_append_arg_cstr(&state.out, str->data, str->len);
- }
-
- action arg_var {
- state_append_arg_var(&state, true, stack_get_str(&state.stack));
- }
-
- action filter {
- codebuf_append_op(&state.out, FSPEC_OP_FILTER);
- }
-
- action goto {
- codebuf_append_op(&state.out, FSPEC_OP_GOTO);
- state_append_arg_var(&state, false, stack_get_str(&state.stack));
- }
-
- action vnul {
- codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_NUL });
- }
-
- action vdec {
- codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_DEC });
- }
-
- action vhex {
- codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_HEX });
- }
-
- action vstr {
- codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_STR });
- }
-
- action r8 {
- codebuf_append_op(&state.out, FSPEC_OP_READ);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 8 });
- }
-
- action r16 {
- codebuf_append_op(&state.out, FSPEC_OP_READ);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 16 });
- }
-
- action r32 {
- codebuf_append_op(&state.out, FSPEC_OP_READ);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 32 });
- }
-
- action r64 {
- codebuf_append_op(&state.out, FSPEC_OP_READ);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 64 });
- }
-
- action member_end {
- state_finish_declaration(&state, FSPEC_DECLARATION_MEMBER);
- }
-
- action member_start {
- state_append_declaration(&state, FSPEC_DECLARATION_MEMBER, stack_get_str(&state.stack));
- }
-
- action struct_end {
- state_finish_declaration(&state, FSPEC_DECLARATION_STRUCT);
- }
-
- action struct_start {
- state_append_declaration(&state, FSPEC_DECLARATION_STRUCT, stack_get_str(&state.stack));
- }
-
- action stack_oct {
- state_stack_num(&state, 8);
- }
-
- action stack_hex {
- state_stack_num(&state, 16);
- }
-
- action stack_dec {
- state_stack_num(&state, 10);
- }
-
- action stack_str {
- membuf_terminate(&state.var.buf, (char[]){ 0 }, 1);
- state.stack.type = STACK_STR;
- state.stack.str = state.var.buf.mem;
- state.stack.str.len = state.var.buf.written;
- }
-
- action store_esc_num {
- const fspec_num v = stack_get_num(&state.stack);
- assert(v <= 255);
- const uint8_t u8 = v;
- membuf_append(&state.var.buf, &u8, sizeof(u8));
- }
-
- action store_esc {
- const struct { const char e, v; } 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 = 0x1B },
- };
-
- for (size_t i = 0; i < ARRAY_SIZE(map); ++i) {
- if (*state.ragel.p != map[i].e)
- continue;
-
- membuf_append(&state.var.buf, &map[i].v, sizeof(map[i].v));
- break;
- }
- }
-
- action store {
- membuf_append(&state.var.buf, state.ragel.p, 1);
- }
-
- action begin_num {
- varbuf_begin(&state.var);
- }
-
- action begin_str {
- varbuf_reset(&state.var);
- }
-
- action type_err {
- ragel_throw_error(&state.ragel, "unknown type name");
- }
-
- action visual_err {
- ragel_throw_error(&state.ragel, "unknown visualization");
- }
-
- action syntax_err {
- ragel_throw_error(&state.ragel, "malformed input (machine failed here or in next expression)");
- }
-
- action line {
- ragel_advance_line(&state.ragel);
- }
-
- # Semantic
- quote = ['"];
- newline = '\n';
- esc = [abfnrtv\\'"e];
- esc_chr = '\\';
- esc_hex = 'x' <: xdigit{2};
- hex = '0x' <: xdigit{1,};
- oct = [0-7]{1,3};
- dec = [\-+]? <: (([1-9] <: digit*) | '0');
- valid = ^cntrl;
- comment = '//' <: valid* :>> newline;
- type = ('u8' | 's8') %r8 | ('u16' | 's16') %r16 | ('u32' | 's32') %r32 | ('u64' | 's64') %r64;
- visual = 'nul' %vnul | 'dec' %vdec | 'hex' %vhex | 'str' %vstr;
- reserved = 'struct' | type | visual;
- name = ((alpha | '_') <: (alnum | '_')*) - reserved;
-
- # Stack
- stack_name = name >begin_str $store %stack_str;
- stack_hex = hex >begin_num $store %stack_hex;
- stack_dec = dec >begin_num $store %stack_dec;
- stack_oct = oct >begin_num $store %stack_oct;
- stack_esc_hex = esc_hex >begin_num $store %stack_hex;
- stack_esc = esc_chr <: ((stack_esc_hex | stack_oct) %store_esc_num | esc %~store_esc);
- stack_str = quote <: ((stack_esc? <: print? $store) - zlen)* >begin_str %stack_str :>> quote;
- stack_num = stack_dec | stack_hex;
-
- # Catchers
- catch_struct = 'struct ' <: stack_name;
- catch_type = (catch_struct %goto | type) $!type_err;
- catch_args = stack_num %arg_num | stack_str %arg_str | stack_name %arg_var;
- catch_array = '[' <: (catch_args | '$' %arg_eof) :>> ']';
- catch_filter = ' | ' %filter <: stack_name %arg_str :>> ('(' <: catch_args? <: (', ' <: catch_args)* :>> ')')?;
- catch_visual = ' ' <: visual $!visual_err;
-
- # Abstract
- member = stack_name %member_start :> ': ' <: (catch_type <: catch_array* catch_filter* catch_visual?) :>> ';' %member_end;
- struct = catch_struct %struct_start :>> ' {' <: (space | comment | member)* :>> '};' %struct_end;
- line = valid* :>> newline %line;
- main := ((space | comment | struct)* & line*) $!syntax_err;
-}%%
-
-bool
-fspec_lexer_parse(struct fspec_lexer *lexer, const char *name)
-{
- int cs;
- %% write init;
-
- (void)fspec_lexer_en_main;
- assert(lexer);
- assert(lexer->ops.read);
- assert(lexer->mem.input.data && lexer->mem.input.len);
- assert(lexer->mem.output.data && lexer->mem.output.len);
- assert(lexer->mem.input.len <= (size_t)~0 && "input storage size exceeds size_t range");
- assert(lexer->mem.output.len <= (fspec_off)~0 && "output storage size exceeds fspec_off range");
-
- char var[256];
- struct state state = {
- .ragel.name = name,
- .ragel.lineno = 1,
- .var.buf.mem = { .data = var, .len = sizeof(var) },
- .out.buf.mem = lexer->mem.output,
- };
-
- static const fspec_num version = 0;
- state.out.end[SECTION_CODE] = state.out.end[SECTION_DATA] = state.out.buf.mem.data;
- codebuf_append_op(&state.out, FSPEC_OP_HEADER);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, &version);
- codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ PLACEHOLDER });
- codebuf_append_arg(&state.out, FSPEC_ARG_DAT, (fspec_off[]){ PLACEHOLDER });
- state.out.end[SECTION_DATA] = state.out.end[SECTION_CODE];
- state.out.strings = state.out.end[SECTION_DATA];
-
- struct fspec_mem input = lexer->mem.input;
- for (bool eof = false; !state.ragel.error && !eof;) {
- const size_t bytes = lexer->ops.read(lexer, input.data, 1, input.len);
- const struct ragel_mem rl = { .data = input.data, .end = (char*)input.data + bytes };
- ragel_feed_input(&state.ragel, (eof = (bytes < input.len)), &rl);
- %% write exec;
- }
-
- {
- const void *end = state.out.end[SECTION_CODE];
- codebuf_replace_arg(&state.out, fspec_op_get_arg(state.out.buf.mem.data, end, 2, 1<<FSPEC_ARG_NUM), FSPEC_ARG_NUM, (fspec_num[]){ state.out.declarations });
- const fspec_off off = (char*)state.out.end[SECTION_DATA] - (char*)state.out.strings;
- codebuf_replace_arg(&state.out, fspec_op_get_arg(state.out.buf.mem.data, end, 3, 1<<FSPEC_ARG_DAT), FSPEC_ARG_DAT, &off);
- }
-
- lexer->mem.output.len = state.out.buf.written;
- return !state.ragel.error;
-}
diff --git a/src/fspec/bcode-internal.h b/src/fspec/private/bcode-types.h
index 8c9ce74..8c9ce74 100644
--- a/src/fspec/bcode-internal.h
+++ b/src/fspec/private/bcode-types.h
diff --git a/src/fspec/ragel/lexer-expr.h b/src/fspec/ragel/lexer-expr.h
new file mode 100644
index 0000000..904736d
--- /dev/null
+++ b/src/fspec/ragel/lexer-expr.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <fspec/memory.h>
+
+#include <stdbool.h>
+
+struct fspec_expr;
+struct fspec_expr {
+ struct {
+ size_t (*read)(struct fspec_expr *lexer, void *input, const size_t size, const size_t nmemb);
+ size_t (*write)(struct fspec_expr *lexer, const void *output, const size_t size, const size_t nmemb);
+ } ops;
+
+ struct {
+ struct fspec_mem input;
+ } mem;
+};
+
+bool
+fspec_expr_parse(struct fspec_expr *lexer, const char *name);
diff --git a/src/fspec/ragel/lexer-expr.rl b/src/fspec/ragel/lexer-expr.rl
new file mode 100644
index 0000000..2975043
--- /dev/null
+++ b/src/fspec/ragel/lexer-expr.rl
@@ -0,0 +1,122 @@
+#include "lexer-expr.h"
+#include "lexer-stack.h"
+#include "util/ragel/ragel.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <err.h>
+
+static uint8_t
+precedence(char op)
+{
+ switch (op) {
+ case '^': return 4;
+ case '*': return 3;
+ case '/': return 3;
+ case '+': return 2;
+ case '-': return 2;
+ }
+ errx(EXIT_FAILURE, "unknown operator %c for precedence", op);
+ return 0;
+}
+
+static size_t
+pop(char cur, char *mstack, size_t open)
+{
+ static char cvar = 'a';
+
+ // 1 + 2 + 4 + 3 * 2 / 2 * 2 * 2 - 2 * 2 + 5;
+ while (open >= 3) {
+ const char last_op = mstack[open - 2];
+ const uint8_t last_prio = precedence(last_op);
+ const uint8_t new_prio = precedence(cur);
+
+ if (last_prio <= new_prio)
+ break;
+
+ printf("%c = ", cvar);
+ for (size_t i = open - 3; i < open; ++i)
+ printf("%c ", mstack[i]);
+ puts(";");
+ open -= 3;
+
+ mstack[open++] = cvar;
+ ++cvar;
+ }
+
+ return open;
+}
+
+%%{
+ machine fspec_expr;
+ include fspec_stack "lexer-stack.rl";
+ variable p ragel.p;
+ variable pe ragel.pe;
+ variable eof ragel.eof;
+ write data noerror nofinal;
+
+ action op {
+ open = pop(fc, mstack, open);
+ mstack[open++] = fc;
+ }
+
+ logical_operators = '&&' | '||' | '==' | '<' | '>' | '<=' | '>=';
+ calc_operators = '-' | '+' | '/' | '*' | '%';
+ bitwise_operators = '&' | '|' | '^' | '<<' | '>>';
+
+ main := |*
+ '+' => op;
+ '/' => op;
+ '*' => op;
+ '-' => op;
+ '^' => op;
+ stack_num => { mstack[open++] = fc;};
+ '(' => { };
+ ')' => { };
+ ' ';
+ ';' => {
+ printf("v = ");
+ for (size_t i = 0; i < open; ++i)
+ printf("%c ", mstack[i]);
+ puts(";");
+ };
+ *|;
+}%%
+
+
+bool
+fspec_expr_parse(struct fspec_expr *expr, const char *name)
+{
+ int cs, act;
+ const char *ts, *te;
+ (void)ts;
+
+ size_t open = 0;
+ char mstack[25];
+
+ %% write init;
+
+ (void)fspec_expr_en_main;
+ assert(expr);
+ assert(expr->ops.read);
+ assert(expr->ops.write);
+ assert(expr->mem.input.data && expr->mem.input.len);
+ assert(expr->mem.input.len <= (size_t)~0 && "input storage size exceeds size_t range");
+
+ char var[256];
+ struct stack stack = { .var.buf.mem = { .data = var, .len = sizeof(var) } };
+ struct ragel ragel = { .name = name, .lineno = 1 };
+
+ // static const fspec_num version = 0;
+
+ struct fspec_mem input = expr->mem.input;
+ for (bool eof = false; !ragel.error && !eof;) {
+ const size_t bytes = expr->ops.read(expr, input.data, 1, input.len);
+ const struct ragel_mem rl = { .data = input.data, .end = (char*)input.data + bytes };
+ ragel_feed_input(&ragel, (eof = (bytes < input.len)), &rl);
+ %% write exec;
+ }
+
+ return !ragel.error;
+}
diff --git a/src/fspec/ragel/lexer-stack.h b/src/fspec/ragel/lexer-stack.h
new file mode 100644
index 0000000..eebf055
--- /dev/null
+++ b/src/fspec/ragel/lexer-stack.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "util/membuf.h"
+
+#include <stdint.h>
+
+struct varbuf {
+ struct membuf buf;
+ size_t offset;
+};
+
+void
+varbuf_begin(struct varbuf *var);
+
+void
+varbuf_reset(struct varbuf *var);
+
+void
+varbuf_remove_last(struct varbuf *var);
+
+struct stack {
+ struct varbuf var;
+
+ union {
+ struct fspec_mem str;
+ uint64_t num;
+ };
+
+ enum stack_type {
+ STACK_STR,
+ STACK_NUM,
+ } type;
+};
+
+void
+stack_num(struct stack *stack, const uint8_t base);
+
+const struct fspec_mem*
+stack_get_str(const struct stack *stack);
+
+uint64_t
+stack_get_num(const struct stack *stack);
diff --git a/src/fspec/ragel/lexer-stack.rl b/src/fspec/ragel/lexer-stack.rl
new file mode 100644
index 0000000..940f820
--- /dev/null
+++ b/src/fspec/ragel/lexer-stack.rl
@@ -0,0 +1,153 @@
+#include "lexer-stack.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+
+void
+varbuf_begin(struct varbuf *var)
+{
+ assert(var);
+ var->offset = var->buf.written;
+ assert(var->offset <= var->buf.mem.len);
+}
+
+void
+varbuf_reset(struct varbuf *var)
+{
+ assert(var);
+ var->offset = var->buf.written = 0;
+}
+
+void
+varbuf_remove_last(struct varbuf *var)
+{
+ assert(var);
+ assert(var->buf.written >= var->offset);
+ const size_t size = var->buf.written - var->offset;
+ assert(var->buf.written >= size);
+ var->buf.written -= size;
+ assert(var->buf.written <= var->buf.mem.len);
+}
+
+static void
+stack_check_type(const struct stack *stack, const enum stack_type type)
+{
+ assert(stack);
+
+ if (stack->type == type)
+ return;
+
+ const char *got = (type == STACK_STR ? "str" : "num"), *expected = (stack->type == STACK_STR ? "str" : "num");
+ errx(EXIT_FAILURE, "tried to get '%s' from stack, but the last pushed type was '%s'", got, expected);
+}
+
+void
+stack_num(struct stack *stack, const uint8_t base)
+{
+ assert(stack);
+ membuf_terminate(&stack->var.buf, (char[]){ 0 }, 1);
+ const char *str = (char*)stack->var.buf.mem.data + stack->var.offset;
+ stack->type = STACK_NUM;
+ stack->num = strtoll(str, NULL, base);
+ varbuf_remove_last(&stack->var);
+}
+
+const struct fspec_mem*
+stack_get_str(const struct stack *stack)
+{
+ stack_check_type(stack, STACK_STR);
+ return &stack->str;
+}
+
+uint64_t
+stack_get_num(const struct stack *stack)
+{
+ stack_check_type(stack, STACK_NUM);
+ return stack->num;
+}
+
+%%{
+ machine fspec_stack;
+
+ action stack_oct {
+ stack_num(&stack, 8);
+ }
+
+ action stack_hex {
+ stack_num(&stack, 16);
+ }
+
+ action stack_dec {
+ stack_num(&stack, 10);
+ }
+
+ action stack_str {
+ membuf_terminate(&stack.var.buf, (char[]){ 0 }, 1);
+ stack.type = STACK_STR;
+ stack.str = stack.var.buf.mem;
+ stack.str.len = stack.var.buf.written;
+ }
+
+ action store_esc_num {
+ const fspec_num v = stack_get_num(&stack);
+ assert(v <= 255);
+ membuf_append(&stack.var.buf, (uint8_t[]){ v }, sizeof(uint8_t));
+ }
+
+ action store_esc {
+ const struct { const char e, v; } 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 = 0x1B },
+ };
+
+ for (size_t i = 0; i < sizeof(map) / sizeof(map[0]); ++i) {
+ if (fc != map[i].e)
+ continue;
+
+ membuf_append(&stack.var.buf, &map[i].v, sizeof(map[i].v));
+ break;
+ }
+ }
+
+ action store {
+ membuf_append(&stack.var.buf, fpc, 1);
+ }
+
+ action begin_num {
+ varbuf_begin(&stack.var);
+ }
+
+ action begin_str {
+ varbuf_reset(&stack.var);
+ }
+
+ # Semantic
+ quote = ['"];
+ esc = [abfnrtv\\'"e];
+ esc_chr = '\\';
+ esc_hex = 'x' <: xdigit{2};
+ hex = '0x' <: xdigit{1,};
+ oct = [0-7]{1,3};
+ dec = [\-+]? <: (([1-9] <: digit*) | '0');
+ name = ((alpha | '_') <: (alnum | '_')*);
+
+ # Stack
+ stack_name = name >begin_str $store %stack_str;
+ stack_hex = hex >begin_num $store %stack_hex;
+ stack_dec = dec >begin_num $store %stack_dec;
+ stack_oct = oct >begin_num $store %stack_oct;
+ stack_esc_hex = esc_hex >begin_num <>*store %stack_hex;
+ stack_esc = esc_chr <: ((stack_esc_hex | stack_oct) %store_esc_num | esc %~store_esc);
+ stack_str = quote <: ((stack_esc? <: print? $store) - zlen)* >begin_str %stack_str :>> quote;
+ stack_num = stack_dec | stack_hex;
+}%%
diff --git a/src/fspec/ragel/lexer.rl b/src/fspec/ragel/lexer.rl
new file mode 100644
index 0000000..b4a21dc
--- /dev/null
+++ b/src/fspec/ragel/lexer.rl
@@ -0,0 +1,180 @@
+#include <fspec/lexer.h>
+#include <fspec/bcode.h>
+#include "lexer-stack.h"
+#include "util/ragel/ragel.h"
+#include "fspec/private/bcode-types.h"
+
+#include <assert.h>
+
+%%{
+ machine fspec_lexer;
+ include fspec_stack "lexer-stack.rl";
+ variable p ragel.p;
+ variable pe ragel.pe;
+ variable eof ragel.eof;
+ write data noerror nofinal;
+
+ action arg_eof {
+ // codebuf_append_arg(&state.out, FSPEC_ARG_EOF, NULL);
+ }
+
+ action arg_num {
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ stack_get_num(&state.stack) });
+ }
+
+ action arg_str {
+ // const struct fspec_mem *str = stack_get_str(&state.stack);
+ // codebuf_append_arg_cstr(&state.out, str->data, str->len);
+ }
+
+ action arg_var {
+ // state_append_arg_var(&state, true, stack_get_str(&state.stack));
+ }
+
+ action filter {
+ // codebuf_append_op(&state.out, FSPEC_OP_FILTER);
+ }
+
+ action goto {
+ // codebuf_append_op(&state.out, FSPEC_OP_GOTO);
+ // state_append_arg_var(&state, false, stack_get_str(&state.stack));
+ }
+
+ action vnul {
+ // codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_NUL });
+ }
+
+ action vdec {
+ // codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_DEC });
+ }
+
+ action vhex {
+ // codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_HEX });
+ }
+
+ action vstr {
+ // codebuf_append_op(&state.out, FSPEC_OP_VISUAL);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ FSPEC_VISUAL_STR });
+ }
+
+ action r8 {
+ // codebuf_append_op(&state.out, FSPEC_OP_READ);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 8 });
+ }
+
+ action r16 {
+ // codebuf_append_op(&state.out, FSPEC_OP_READ);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 16 });
+ }
+
+ action r32 {
+ // codebuf_append_op(&state.out, FSPEC_OP_READ);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 32 });
+ }
+
+ action r64 {
+ // codebuf_append_op(&state.out, FSPEC_OP_READ);
+ // codebuf_append_arg(&state.out, FSPEC_ARG_NUM, (fspec_num[]){ 64 });
+ }
+
+ action enum_member_end {
+ }
+
+ action enum_member_start {
+ }
+
+ action enum_end {
+ }
+
+ action enum_start {
+ }
+
+ action struct_member_end {
+ // state_finish_declaration(&state, FSPEC_DECLARATION_MEMBER);
+ }
+
+ action struct_member_start {
+ // state_append_declaration(&state, FSPEC_DECLARATION_MEMBER, stack_get_str(&state.stack));
+ }
+
+ action struct_end {
+ // state_finish_declaration(&state, FSPEC_DECLARATION_STRUCT);
+ }
+
+ action struct_start {
+ // state_append_declaration(&state, FSPEC_DECLARATION_STRUCT, stack_get_str(&state.stack));
+ }
+
+ action type_err {
+ ragel_throw_error(&ragel, "unknown type name");
+ }
+
+ action visual_err {
+ ragel_throw_error(&ragel, "unknown visualization");
+ }
+
+ action syntax_err {
+ ragel_throw_error(&ragel, "malformed input (machine failed here or in next expression)");
+ }
+
+ action line {
+ ragel_advance_line(&ragel);
+ }
+
+ # Semantic
+ newline = '\n';
+ valid = ^cntrl;
+ comment = '//' <: valid* :>> newline;
+ type = ('u8' | 's8') %r8 | ('u16' | 's16') %r16 | ('u32' | 's32') %r32 | ('u64' | 's32') %r64;
+ visual = 'nul' %vnul | 'dec' %vdec | 'hex' %vhex | 'str' %vstr;
+
+ # Catchers
+ catch_const_expr = stack_num %arg_num;
+ catch_struct = 'struct ' <: stack_name;
+ catch_enum = 'enum ' <: stack_name;
+ catch_type = (catch_struct %goto | type) $!type_err;
+ catch_args = stack_num %arg_num | stack_str %arg_str | stack_name %arg_var;
+ catch_array = '[' <: (catch_args | '$' %arg_eof) :>> ']';
+ catch_filter = ' | ' %filter <: stack_name %arg_str :>> ('(' <: catch_args? <: (', ' <: catch_args)* :>> ')')?;
+ catch_visual = ' ' <: visual $!visual_err;
+
+ # Abstract
+ struct_member = stack_name %struct_member_start :>> ': ' <: (catch_type <: catch_array* catch_filter* catch_visual?) :>> ';' %struct_member_end;
+ struct = catch_struct %struct_start :>> ' {' <: (space | comment | struct_member)* :>> '};' %struct_end;
+ enum_member = stack_name %enum_member_start :>> (': ' <: catch_const_expr)? :>> ';' %enum_member_end;
+ enum = catch_enum %enum_start :>> ' {' <: (space | comment | enum_member)* :>> '};' %enum_end;
+ line = valid* :>> newline %line;
+ main := ((space | comment | enum | struct)* & line*) $!syntax_err;
+}%%
+
+bool
+fspec_lexer_parse(struct fspec_lexer *lexer, const char *name)
+{
+ int cs;
+ %% write init;
+
+ (void)fspec_lexer_en_main;
+ assert(lexer);
+ assert(lexer->ops.read);
+ assert(lexer->mem.input.data && lexer->mem.input.len);
+ assert(lexer->mem.input.len <= (size_t)~0 && "input storage size exceeds size_t range");
+
+ char var[256];
+ struct stack stack = { .var.buf.mem = { .data = var, .len = sizeof(var) } };
+ struct ragel ragel = { .name = name, .lineno = 1 };
+
+ // static const fspec_num version = 0;
+
+ struct fspec_mem input = lexer->mem.input;
+ for (bool eof = false; !ragel.error && !eof;) {
+ const size_t bytes = lexer->ops.read(lexer, input.data, 1, input.len);
+ const struct ragel_mem rl = { .data = input.data, .end = (char*)input.data + bytes };
+ ragel_feed_input(&ragel, (eof = (bytes < input.len)), &rl);
+ %% write exec;
+ }
+
+ return !ragel.error;
+}
diff --git a/src/fspec/ragel/validator.rl b/src/fspec/ragel/validator.rl
new file mode 100644
index 0000000..90ead21
--- /dev/null
+++ b/src/fspec/ragel/validator.rl
@@ -0,0 +1,96 @@
+#include <fspec/bcode.h>
+#include <fspec/validator.h>
+#include "util/ragel/ragel.h"
+#include "fspec/private/bcode-types.h"
+
+#include <assert.h>
+
+struct stack {
+ union {
+ fspec_num num;
+ fspec_off off;
+ fspec_var var;
+ fspec_strsz strsz;
+ unsigned char b[sizeof(fspec_num)];
+ } u;
+ uint8_t i; // writing index for u.b
+};
+
+struct state {
+ struct ragel ragel;
+ struct stack stack;
+};
+
+%%{
+ machine fspec_validator;
+ variable p state.ragel.p;
+ variable pe state.ragel.pe;
+ variable eof state.ragel.eof;
+ write data noerror nofinal;
+
+# BLT_HEADER = 0;
+# BLT_ADD = 1;
+# BLT_SUB = 2;
+# BLT_MUL = 3;
+# BLT_DIV = 4;
+# BLT_MOD = 5;
+# BLT_BIT_AND = 6;
+# BLT_BIT_OR = 7;
+# BLT_BIT_XOR = 8;
+# BLT_BIT_LEFT = 9;
+# BLT_BIT_RIGHT = 10;
+# BLT_DECLARE = 11;
+# BLT_READ = 12;
+# BLT_GOTO = 13;
+# BLT_FILTER = 14;
+# BLT_VISUAL = 15;
+#
+# builtins = BLT_HEADER |
+# BLT_ADD | BLT_SUB | BLT_MUL | BLT_DIV | BLT_MOD |
+# BLT_BIT_AND | BLT_BIT_OR | BLT_BIT_XOR | BLT_BIT_LEFT | BLT_BIT_RIGHT
+# BLT_DECLARE | BLT_READ | BLT_GOTO | BLT_FILTER | BLT_VISUAL;
+#
+# OP_ARG = 0;
+# OP_REF = 1;
+# OP_BLT = 2 OP_ARG builtins;
+# OP_FUN = 3;
+#
+# arg_ops = OP_REF | OP_FUN | OP_BUILTIN OP_FUN
+#
+# BLT_DECLARE = OP_BUILTIN 10 OP_ARG 2 OP_REF OP_REF;
+# BLT_READ = OP_BUILTIN 11 OP_ARG 1..255 OP_REF (arg_ops)*;
+#
+# pattern = ((BLT_READ | BLT_GOTO) BLT_FILTER* BLT_VISUAL?)* $!pattern_error;
+# main := (BLT_HEADER <: BLT_DECLARE* <: pattern) %check_decls $advance $!syntax_error;
+ main := any*;
+}%%
+
+bool
+fspec_validator_parse(struct fspec_validator *validator, const char *name)
+{
+ int cs;
+ %% write init;
+
+ (void)fspec_validator_en_main;
+ assert(validator);
+ assert(validator->ops.read);
+ assert(validator->mem.input.data && validator->mem.input.len);
+ assert(validator->mem.input.len <= (size_t)~0 && "input storage size exceeds size_t range");
+
+ struct state state = {
+ .ragel.name = name,
+ .ragel.lineno = 1,
+ };
+
+ static_assert(sizeof(state.stack.u) == sizeof(state.stack.u.b), "bytes doesn't represent the largest member in union");
+
+ struct fspec_mem input = validator->mem.input;
+ for (bool eof = false; !state.ragel.error && !eof;) {
+ const size_t bytes = validator->ops.read(validator, input.data, 1, input.len);
+ const struct ragel_mem rl = { .data = input.data, .end = (char*)input.data + bytes, .binary = true };
+ ragel_feed_input(&state.ragel, (eof = (bytes < input.len)), &rl);
+ %% write exec;
+ }
+
+ return !state.ragel.error;
+}
diff --git a/src/fspec/validator.h b/src/fspec/validator.h
index c4705b2..a20e98a 100644
--- a/src/fspec/validator.h
+++ b/src/fspec/validator.h
@@ -2,6 +2,8 @@
#include <fspec/memory.h>
+#include <stdbool.h>
+
struct fspec_validator;
struct fspec_validator {
struct {
diff --git a/src/fspec/validator.rl b/src/fspec/validator.rl
deleted file mode 100644
index b00a827..0000000
--- a/src/fspec/validator.rl
+++ /dev/null
@@ -1,236 +0,0 @@
-#include "ragel/ragel.h"
-#include <fspec/bcode.h>
-#include <fspec/validator.h>
-#include "bcode-internal.h"
-
-#include <assert.h>
-
-struct stack {
- union {
- fspec_num num;
- fspec_off off;
- fspec_var var;
- fspec_strsz strsz;
- unsigned char b[sizeof(fspec_num)];
- } u;
- uint8_t i; // writing index for u.b
-};
-
-struct range {
- fspec_off start, end;
-};
-
-struct context {
- struct range data;
- fspec_var declarations, expected_declarations;
- fspec_off str_end, decl_start, decl_end[FSPEC_DECLARATION_LAST], offset;
- enum fspec_declaration last_decl_type;
-};
-
-struct state {
- struct ragel ragel;
- struct context context;
- struct stack stack;
-};
-
-%%{
- machine fspec_validator;
- variable p state.ragel.p;
- variable pe state.ragel.pe;
- variable eof state.ragel.eof;
- write data noerror nofinal;
-
- action store_decls {
- if (state.stack.u.num > (fspec_var)~0)
- ragel_throw_error(&state.ragel, "expected declarations overflows");
-
- state.context.expected_declarations = state.stack.u.num;
- }
-
- action check_decls {
- if (state.context.declarations != state.context.expected_declarations)
- ragel_throw_error(&state.ragel, "expected declarations did not match with the content: expected: %" PRI_FSPEC_VAR " got: %" PRI_FSPEC_VAR, state.context.expected_declarations, state.context.declarations);
- }
-
- action mark_dat {
- // we can replace this logic with fspec generated code in future
- // struct str { len: u32; str: u8[len]['\0']; }
- // struct dat { len: u32; strings: struct str[$::len]; }
- if (state.context.offset > (fspec_off)~0 - state.stack.u.off)
- ragel_throw_error(&state.ragel, "dat section length overflows");
-
- state.context.data = (struct range){ .start = state.context.offset, .end = state.stack.u.off };
- }
-
- action test_inside_dat {
- state.context.offset < (state.context.data.start + state.context.data.end)
- }
-
- action mark_str {
- if (state.context.offset >= (fspec_off)~0 - state.stack.u.strsz) // >= for null byte
- ragel_throw_error(&state.ragel, "str length overflows");
-
- state.context.str_end = state.context.offset + state.stack.u.strsz;
- }
-
- action test_inside_str {
- state.context.offset < state.context.str_end
- }
-
- action check_var {
- if (state.context.declarations <= state.stack.u.var)
- ragel_throw_error(&state.ragel, "refenced undeclared variable");
- }
-
- action check_str {
- if (state.stack.u.off < state.context.data.start) {
- ragel_throw_error(&state.ragel, "str before data section range: %" PRI_FSPEC_OFF " <= %" PRI_FSPEC_OFF, state.stack.u.off, state.context.data.start + state.context.data.end);
- } else if (state.context.data.start + state.context.data.end <= state.stack.u.off) {
- ragel_throw_error(&state.ragel, "str after data section range: %" PRI_FSPEC_OFF " <= %" PRI_FSPEC_OFF, state.context.data.start + state.context.data.end, state.stack.u.off);
- }
- }
-
- action check_decl_type {
- if (state.stack.u.num >= FSPEC_DECLARATION_LAST)
- ragel_throw_error(&state.ragel, "invalid declaration type: %" PRI_FSPEC_NUM, state.stack.u.num);
-
- state.context.last_decl_type = state.stack.u.num;
- }
-
- action check_decl_num {
- if (state.context.declarations >= (fspec_var)~0)
- ragel_throw_error(&state.ragel, "declarations overflows");
-
- if (state.context.declarations != state.stack.u.num)
- ragel_throw_error(&state.ragel, "invalid declaration number: %" PRI_FSPEC_NUM " expected: %" PRI_FSPEC_VAR, state.stack.u.num, state.context.declarations);
-
- ++state.context.declarations;
- }
-
- action start_decl {
- state.context.decl_start = state.context.offset;
- }
-
- action mark_decl {
- const fspec_off sz = (state.context.offset - state.context.decl_start);
- assert(sz <= state.stack.u.off);
-
- if (state.context.offset > (fspec_off)~0 - state.stack.u.off - sz)
- ragel_throw_error(&state.ragel, "declaration length overflows");
-
- state.context.decl_end[state.context.last_decl_type] = state.context.offset + state.stack.u.off - sz;
- }
-
- action check_struct {
- if (state.context.last_decl_type != FSPEC_DECLARATION_STRUCT)
- ragel_throw_error(&state.ragel, "expected struct declaration");
- }
-
- action check_member {
- if (state.context.last_decl_type != FSPEC_DECLARATION_MEMBER)
- ragel_throw_error(&state.ragel, "expected member declaration");
- }
-
- action check_member_end {
- if (state.context.decl_end[FSPEC_DECLARATION_MEMBER] != state.context.offset)
- ragel_throw_error(&state.ragel, "invalid member end: %" PRI_FSPEC_OFF " expected: %" PRI_FSPEC_OFF, state.context.decl_end[FSPEC_DECLARATION_MEMBER], state.context.offset);
- }
-
- action check_struct_end {
- if (state.context.decl_end[FSPEC_DECLARATION_STRUCT] != state.context.offset)
- ragel_throw_error(&state.ragel, "invalid struct end: %" PRI_FSPEC_OFF " expected: %" PRI_FSPEC_OFF, state.context.decl_end[FSPEC_DECLARATION_STRUCT], state.context.offset);
- }
-
- action check_visual_type {
- if (state.stack.u.num >= FSPEC_VISUAL_LAST)
- ragel_throw_error(&state.ragel, "invalid visual type: %" PRI_FSPEC_NUM, state.stack.u.num);
- }
-
- action arg_error {
- ragel_throw_error(&state.ragel, "malformed argument");
- }
-
- action op_error {
- ragel_throw_error(&state.ragel, "unexpected argument");
- }
-
- action pattern_error {
- ragel_throw_error(&state.ragel, "unexpected pattern");
- }
-
- action syntax_error {
- ragel_throw_error(&state.ragel, "unexpected byte");
- }
-
- action store {
- if (state.stack.i < sizeof(state.stack.u.b))
- state.stack.u.b[state.stack.i++] = fc;
- }
-
- action flush {
- state.stack.i = 0;
- }
-
- action advance {
- ++state.context.offset;
- }
-
- stack1 = any{1} >flush $store;
- stack2 = any{2} >flush $store;
- stack4 = any{4} >flush $store;
- stack8 = any{8} >flush $store;
-
- ARG_DAT = 0 stack4 %*mark_dat ((stack1 %*mark_str (any when test_inside_str)* 0) when test_inside_dat)*;
- ARG_OFF = 1 stack4;
- ARG_NUM = 2 stack8;
- ARG_VAR = 3 stack2 %check_var;
- ARG_STR = 4 stack4 %check_str;
- ARG_EOF = 5;
-
- OP_ARG_DAT = 0 ARG_DAT $!arg_error;
- OP_ARG_OFF = 0 ARG_OFF $!arg_error;
- OP_ARG_NUM = 0 ARG_NUM $!arg_error;
- OP_ARG_VAR = 0 ARG_VAR $!arg_error;
- OP_ARG_STR = 0 ARG_STR $!arg_error;
- OP_ARG_EOF = 0 ARG_EOF $!arg_error;
-
- OP_HEADER = 1 (OP_ARG_NUM OP_ARG_NUM %store_decls OP_ARG_DAT) $!op_error;
- OP_DECLARATION = 2 >start_decl (OP_ARG_NUM %check_decl_type OP_ARG_NUM %check_decl_num OP_ARG_OFF %mark_decl OP_ARG_STR) $!op_error;
- OP_READ = 3 (OP_ARG_NUM (OP_ARG_NUM | OP_ARG_VAR | OP_ARG_STR | OP_ARG_EOF)*) $!op_error;
- OP_GOTO = 4 (OP_ARG_VAR (OP_ARG_NUM | OP_ARG_VAR | OP_ARG_STR | OP_ARG_EOF)*) $!op_error;
- OP_FILTER = 5 (OP_ARG_STR (OP_ARG_NUM | OP_ARG_VAR | OP_ARG_STR)*) $!op_error;
- OP_VISUAL = 6 (OP_ARG_NUM %check_visual_type) $!op_error;
-
- pattern = (OP_DECLARATION %check_struct <: (OP_DECLARATION %check_member (OP_READ | OP_GOTO) OP_FILTER* OP_VISUAL? %check_member_end)*)* %check_struct_end $!pattern_error;
- main := (OP_HEADER <: pattern) %check_decls $advance $!syntax_error;
-}%%
-
-bool
-fspec_validator_parse(struct fspec_validator *validator, const char *name)
-{
- int cs;
- %% write init;
-
- (void)fspec_validator_en_main;
- assert(validator);
- assert(validator->ops.read);
- assert(validator->mem.input.data && validator->mem.input.len);
- assert(validator->mem.input.len <= (size_t)~0 && "input storage size exceeds size_t range");
-
- struct state state = {
- .ragel.name = name,
- .ragel.lineno = 1,
- };
-
- static_assert(sizeof(state.stack.u) == sizeof(state.stack.u.b), "bytes doesn't represent the largest member in union");
-
- struct fspec_mem input = validator->mem.input;
- for (bool eof = false; !state.ragel.error && !eof;) {
- const size_t bytes = validator->ops.read(validator, input.data, 1, input.len);
- const struct ragel_mem rl = { .data = input.data, .end = (char*)input.data + bytes, .binary = true };
- ragel_feed_input(&state.ragel, (eof = (bytes < input.len)), &rl);
- %% write exec;
- }
-
- return !state.ragel.error;
-}
diff --git a/src/util/membuf.c b/src/util/membuf.c
new file mode 100644
index 0000000..0602679
--- /dev/null
+++ b/src/util/membuf.c
@@ -0,0 +1,31 @@
+#include "membuf.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <memory.h>
+#include <err.h>
+
+static void
+membuf_bounds_check(const struct membuf *buf, const size_t nmemb)
+{
+ assert(buf);
+
+ if (buf->mem.len < nmemb || buf->written > buf->mem.len - nmemb)
+ errx(EXIT_FAILURE, "%s: %zu bytes exceeds the maximum storage size of %zu bytes", __func__, buf->written + nmemb, buf->mem.len);
+}
+
+void
+membuf_terminate(struct membuf *buf, const void *data, const size_t data_sz)
+{
+ assert(data || !data_sz);
+ membuf_bounds_check(buf, data_sz);
+ memcpy((char*)buf->mem.data + buf->written, data, data_sz);
+}
+
+void
+membuf_append(struct membuf *buf, const void *data, const size_t data_sz)
+{
+ membuf_terminate(buf, data, data_sz);
+ buf->written += data_sz;
+ assert(buf->written <= buf->mem.len);
+}
diff --git a/src/util/membuf.h b/src/util/membuf.h
new file mode 100644
index 0000000..86d8dde
--- /dev/null
+++ b/src/util/membuf.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <fspec/memory.h>
+
+struct membuf {
+ struct fspec_mem mem;
+ size_t written;
+};
+
+void
+membuf_terminate(struct membuf *buf, const void *data, const size_t data_sz);
+
+void
+membuf_append(struct membuf *buf, const void *data, const size_t data_sz);
diff --git a/src/ragel/ragel.h b/src/util/ragel/ragel.h
index b2c7572..b2c7572 100644
--- a/src/ragel/ragel.h
+++ b/src/util/ragel/ragel.h
diff --git a/src/ragel/ragel.rl b/src/util/ragel/ragel.rl
index 7e51030..c52f27b 100644
--- a/src/ragel/ragel.rl
+++ b/src/util/ragel/ragel.rl
@@ -1,4 +1,5 @@
#include "ragel.h"
+
#include <inttypes.h>
#include <stdio.h>
#include <stdarg.h>
diff --git a/vim/filespec.vim b/vim/filespec.vim
index 077f41c..19c9945 100644
--- a/vim/filespec.vim
+++ b/vim/filespec.vim
@@ -9,7 +9,7 @@ syn keyword fsTodo contained TODO FIXME XXX
syn cluster fsCommentGroup contains=fsTodo,fsBadContinuation
syn region fsComment start="//" skip="\\$" end="$" keepend contains=@fsCommentGroup,@Spell
-syn keyword fsStructure struct union
+syn keyword fsStructure enum struct union
syn keyword fsType s8 s16 s32 s64
syn keyword fsType u8 u16 u32 u64
syn keyword fsConstant nul dec hex str