diff options
Diffstat (limited to 'src/fspec/ragel')
-rw-r--r-- | src/fspec/ragel/lexer-expr.h | 20 | ||||
-rw-r--r-- | src/fspec/ragel/lexer-expr.rl | 122 | ||||
-rw-r--r-- | src/fspec/ragel/lexer-stack.h | 42 | ||||
-rw-r--r-- | src/fspec/ragel/lexer-stack.rl | 153 | ||||
-rw-r--r-- | src/fspec/ragel/lexer.rl | 180 | ||||
-rw-r--r-- | src/fspec/ragel/validator.rl | 96 |
6 files changed, 613 insertions, 0 deletions
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; +} |