From b755026ba67b35b84fe267a11e47ba10ff489921 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Wed, 15 Jul 2026 14:13:29 -0700 Subject: [PATCH] [examples] setup an examples base layer; sketch parser example --- build_all_examples.sh | 29 +++ examples/example1.c | 4 +- examples/example1.h | 24 --- examples/examples.base.c | 121 ++++++++++++ examples/examples.base.h | 127 +++++++++++++ examples/expression_parser.c | 345 +++++++++++++++++++++++++++++++++++ examples/expression_parser.h | 160 ++++++++++++++++ examples/hooks.c | 67 +------ examples/hooks.h | 51 ------ examples/stack_machine.c | 39 +--- examples/stack_machine.h | 98 ---------- project.4coder | 11 +- 12 files changed, 798 insertions(+), 278 deletions(-) create mode 100755 build_all_examples.sh create mode 100644 examples/examples.base.c create mode 100644 examples/examples.base.h create mode 100644 examples/expression_parser.c create mode 100644 examples/expression_parser.h diff --git a/build_all_examples.sh b/build_all_examples.sh new file mode 100755 index 0000000..700b75d --- /dev/null +++ b/build_all_examples.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +code=$PWD +opts="-g -Wno-switch" +inc="-I$code/symbol_set" + +mkdir -p build +cd build + +echo example1 +clang -c $code/examples/example1.c $opts $inc +./symbol_set.ld_meta example1.o +clang -o example1 $code/examples/example1.c $opts $inc -T sy.ld + +echo stack_machine +clang -c $code/examples/stack_machine.c $opts $inc +./symbol_set.ld_meta stack_machine.o +clang -o stack_machine $code/examples/stack_machine.c $opts $inc -T sy.ld + +echo hooks +clang -c $code/examples/hooks.c $opts $inc +./symbol_set.ld_meta hooks.o +clang -o hooks $code/examples/hooks.c $opts $inc -T sy.ld + +echo expression_parser +clang -c $code/examples/expression_parser.c $opts $inc +./symbol_set.ld_meta expression_parser.o +clang -o expression_parser $code/examples/expression_parser.c $opts $inc -T sy.ld + diff --git a/examples/example1.c b/examples/example1.c index bc363aa..44cea98 100644 --- a/examples/example1.c +++ b/examples/example1.c @@ -5,8 +5,10 @@ #define SY__MAIN 1 #include "symbol_set.h" +#include "examples.base.h" #include "example1.h" -#include + +#include "examples.base.c" COMMAND_SCRIPT(foo, "Generates foo and increments the foo counter"){ printf("foo, "); diff --git a/examples/example1.h b/examples/example1.h index 34af4fb..a441491 100644 --- a/examples/example1.h +++ b/examples/example1.h @@ -1,30 +1,6 @@ #ifndef EXAMPLE1_H #define EXAMPLE1_H -//////////////////////////////// -// Little Base Layer - -#include -typedef int8_t S8; -typedef int16_t S16; -typedef int32_t S32; -typedef int64_t S64; -typedef uint8_t U8; -typedef uint16_t U16; -typedef uint32_t U32; -typedef uint64_t U64; -typedef S8 B8; -typedef S16 B16; -typedef S32 B32; -typedef S64 B64; -typedef float F32; -typedef double F64; - -typedef struct String8{ - U8 *str; - U64 size; -} String8; - //////////////////////////////// // Example Specifics diff --git a/examples/examples.base.c b/examples/examples.base.c new file mode 100644 index 0000000..b1c5826 --- /dev/null +++ b/examples/examples.base.c @@ -0,0 +1,121 @@ +//////////////////////////////// +// Typical Base Stuff + +static B32 +str8_match(String8 a, String8 b){ + B32 result = 0; + if (a.size == b.size){ + result = 1; + for (U64 i = 0; i < a.size; i += 1){ + if (a.str[i] != b.str[i]){ + result = 0; + break; + } + } + } + return(result); +} + +static Arena +arena_alloc(U64 cap){ + Arena arena = {0}; + arena.memory = malloc(cap); + arena.cap = cap; + return(arena); +} + +static void* +arena_push(Arena *arena, U64 size){ + void *result = 0; + if (arena->pos + size <= arena->cap){ + result = (U8*)arena->memory + arena->pos; + arena->pos += size; + arena->pos = (arena->pos + 7)&~7; // "round up to multiple of 8" + memset(result, 0, size); + } + return(result); +} + +static void +arena_pop_to(Arena *arena, U64 pos){ + if (pos < arena->pos){ + arena->pos = (pos + 7)&~7; // "round up to multiple of 8" + } +} + +static void +arena_pop_amount(Arena *arena, U64 amount){ + U64 pos = arena->pos; + U64 new_pos = 0; + if (pos > amount){ + new_pos = pos - amount; + } + arena_pop_to(arena, new_pos); +} + +static U64 +arena_pos(Arena *arena){ + return(arena->pos); +} + +static String8 +str8_pushfv(Arena *arena, char *fmt, va_list args){ + // in case we need to try a second time + va_list args2; + va_copy(args2, args); + + // try to build the string in 1024 bytes + U64 buffer_size = 1024; + U8 *buffer = push_array(arena, U8, buffer_size); + U64 actual_size = vsnprintf((char*)buffer, buffer_size, fmt, args); + + String8 result = {0}; + if (actual_size < buffer_size){ + // if first try worked, put back what we didn't use and finish + arena_pop_amount(arena, buffer_size - actual_size - 1); + result = (String8){buffer, actual_size}; + } + else{ + // if first try failed, reset and try again with correct size + arena_pop_amount(arena, buffer_size); + U8 *fixed_buffer = push_array(arena, U8, actual_size + 1); + U64 final_size = vsnprintf((char*)fixed_buffer, actual_size + 1, fmt, args2); + result = (String8){fixed_buffer, final_size}; + } + + // end args2 + va_end(args2); + + return(result); +} + +//////////////////////////////// +// Symbol-Set Specific Upgrades + +static void* +copy_strided(void *dst, U32 dst_stride, + void *src, U32 src_stride, + U32 count){ + void *base_src = src; + void *base_dst = dst; + if (dst_stride != src_stride){ + U32 size = Min(dst_stride, src_stride); + for (U32 i = 0; i < count; i += 1){ + memcpy(dst, src, size); + dst = (U8*)dst + dst_stride; + src = (U8*)src + src_stride; + } + } + else{ + memcpy(dst, src, dst_stride*count); + } + return(base_dst); +} + +static void* +arena_push_symbol_set__raw(Arena *arena, + U32 size, void *src, U32 src_stride, U32 count){ + void *dst = push_array(arena, U8, size*(count + 1)); + copy_strided((U8*)dst + size, size, src, src_stride, count); + return(dst); +} diff --git a/examples/examples.base.h b/examples/examples.base.h new file mode 100644 index 0000000..18596d7 --- /dev/null +++ b/examples/examples.base.h @@ -0,0 +1,127 @@ +#ifndef EXAMPLES_BASE_H +#define EXAMPLES_BASE_H + +#include +#include +#include +#include + +//////////////////////////////// +// Typical Base Stuff + +#include +typedef int8_t S8; +typedef int16_t S16; +typedef int32_t S32; +typedef int64_t S64; +typedef uint8_t U8; +typedef uint16_t U16; +typedef uint32_t U32; +typedef uint64_t U64; +typedef S8 B8; +typedef S16 B16; +typedef S32 B32; +typedef S64 B64; +typedef float F32; +typedef double F64; + +typedef struct String8{ + U8 *str; + U64 size; +} String8; + +#define str8_const(S) {(U8*)(S), (U64)(sizeof(S) - 1)} +#define str8(s,z) (String8){(s), (z)} + +static B32 str8_match(String8 a, String8 b); + +typedef struct Arena{ + void *memory; + U64 pos; + U64 cap; +} Arena; + +static Arena arena_alloc(U64 cap); +static void* arena_push(Arena *arena, U64 size); +static void arena_pop_to(Arena *arena, U64 pos); +static void arena_pop_amount(Arena *arena, U64 amount); +static U64 arena_pos(Arena *arena); + +#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) + +#define Min(a,b) ((a)<(b))?(a):(b) + +// Macros: Linked Lists + +#define DLLPushBack_NPZ(f,l,n,next,prev,nil)\ +(((f) == (nil))?\ +((f)=(l)=(n),(n)->next=(n)->prev=(nil)):\ +((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=(nil))) + +#define DLLPushBack(f,l,n) DLLPushBack_NPZ(f,l,n,next,prev,0) +#define DLLPushFront(f,l,n) DLLPushBack_NPZ(l,f,n,prev,next,0) + +#define DLLInsert_NPZ(f,l,p,n,next,prev,nil) \ +(((p) != (l))?\ +((n)->next = (p)->next,\ +(n)->prev = (p),\ +(p)->next->prev = (n),\ +(p)->next = (n))\ +:((n)->next = (nil),\ +(n)->prev = (l),\ +(l)->next = (n),\ +(l) = (n))) + +#define DLLInsert(f,l,p,n) DLLInsert_NPZ(f,l,p,n,next,prev,0) + +#define DLLRemove_NPZ(f,l,n,next,prev,nil)\ +((f)==(n)?\ +((f)==(l)?\ +((f)=(l)=(nil)):\ +((f)=(f)->next,(f)->prev=(nil))):\ +(l)==(n)?\ +((l)=(l)->prev,(l)->next=(nil)):\ +((n)->next->prev=(n)->prev,\ +(n)->prev->next=(n)->next)) + +#define DLLRemove(f,l,n) DLLRemove_NPZ(f,l,n,next,prev,0) + +#define SLLQueuePush_NZ(f,l,n,next,nil) (((f)==(nil)?\ +(f)=(l)=(n):\ +((l)->next=(n),(l)=(n))),\ +(n)->next=(nil)) +#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(f,l,n,next,0) + +#define SLLQueuePushFront_NZ(f,l,n,next,nil) ((f)==(nil)?\ +((f)=(l)=(n),(n)->next=(nil)):\ +((n)->next=(f),(f)=(n))) +#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(f,l,n,next,0) + +#define SLLQueuePop_NZ(f,l,next,nil) ((f)==(l)?\ +(f)=(l)=(nil):\ +((f)=(f)->next)) +#define SLLQueuePop(f,l) SLLQueuePop_NZ(f,l,next,0) + +#define SLLStackPush_N(f,n,next) ((n)->next=(f),(f)=(n)) +#define SLLStackPush(f,n) SLLStackPush_N(f,n,next) + +#define SLLStackPop_NZ(f,next,nil) ((f)==(nil)?(nil):\ +((f)=(f)->next)) +#define SLLStackPop(f) SLLStackPop_NZ(f,next,0) + + +//////////////////////////////// +// Symbol-Set Specific Upgrades + +static void*copy_strided(void *dst, U32 dst_stride, + void *src, U32 src_stride, + U32 count); + +static void*arena_push_symbol_set__raw(Arena *arena, + U32 size, void *src, U32 src_stride, U32 count); + +#define arena_push_symbol_set(ar,S) (SyType(S)*) \ +arena_push_symbol_set__raw((ar), sizeof(SyType(S)), SyFirst(S), SyStride(S), SyCount(S)) + + +#endif //EXAMPLES_BASE_H diff --git a/examples/expression_parser.c b/examples/expression_parser.c new file mode 100644 index 0000000..65c550a --- /dev/null +++ b/examples/expression_parser.c @@ -0,0 +1,345 @@ +/* +** C Scripting - Expression Parser +*/ + +#define SY__MAIN 1 +#include "symbol_set.h" +#include "symbol_set.init.h" + +#include "examples.base.h" +#include "expression_parser.h" + +#include "examples.base.c" + +//////////////////////////////// +// Operator Functions + +static U32 +exp_operator_id_from_string(String8 string){ + // TODO(allen): bake accelerator ahead of time for this path + U32 operator_id = 0; + for (SyEachID(EXP_OPERATOR, id)){ + EXP_Operator *op = SyAddressFromID(EXP_OPERATOR, id); + if (str8_match(op->token_str, string)){ + operator_id = id; + break; + } + } + return(operator_id); +} + +//////////////////////////////// +// Lexer Functions + +static EXP_TokenArray +exp_lex(Arena *arena, String8 text){ + // Static Map of char -> TokenKind + static U8 token_kind_table[127] = {0}; + static B8 token_kinds_initialized = 0; + if (!token_kinds_initialized){ + token_kind_table[' '] = token_kind_table['\n'] = + token_kind_table['\t'] = token_kind_table['\r'] = + token_kind_table['\f'] = token_kind_table['\v'] = EXP_TokenKind_Whitespace; + + token_kind_table['`'] = token_kind_table['~'] = + token_kind_table['!'] = token_kind_table['@'] = + token_kind_table['#'] = token_kind_table['$'] = + token_kind_table['%'] = token_kind_table['^'] = + token_kind_table['&'] = token_kind_table['*'] = + token_kind_table['='] = token_kind_table['-'] = + token_kind_table['+'] = token_kind_table['\\'] = + token_kind_table['|'] = token_kind_table[':'] = + token_kind_table[','] = token_kind_table['<'] = + token_kind_table['.'] = token_kind_table['>'] = + token_kind_table['/'] = token_kind_table['?'] = EXP_TokenKind_Operator; + + for (U32 i = 'a'; i <= 'z'; i += 1){ + token_kind_table[i] = EXP_TokenKind_IDNum; + } + for (U32 i = 'A'; i <= 'Z'; i += 1){ + token_kind_table[i] = EXP_TokenKind_IDNum; + } + for (U32 i = '0'; i <= '9'; i += 1){ + token_kind_table[i] = EXP_TokenKind_IDNum; + } + + token_kind_table['('] = EXP_TokenKind_OpenParen|(1 << 7); + token_kind_table[')'] = EXP_TokenKind_CloseParen|(1 << 7); + token_kind_table['['] = EXP_TokenKind_OpenBracket|(1 << 7); + token_kind_table[']'] = EXP_TokenKind_CloseBracket|(1 << 7); + token_kind_table['{'] = EXP_TokenKind_OpenBrace|(1 << 7); + token_kind_table['}'] = EXP_TokenKind_CloseBrace|(1 << 7); + } + + // over-allocate tokens + U32 token_cap = text.size + 1; + EXP_Token *tokens = push_array(arena, EXP_Token, token_cap); + + // fill tokens array + EXP_Token *tp = tokens; + U8 *ptr = text.str; + U8 *opl = text.str + text.size; + for (;ptr < opl;){ + U32 kind = EXP_TokenKind_IDNum; + if (*ptr < 127){ + kind = token_kind_table[*ptr]; + } + + tp->pos = (U32)(ptr - text.str); + tp->kind = kind&~(1 << 7); + + if (kind&(1 << 7)){ + ptr += 1; + } + else{ + for (ptr += 1; + ptr < opl && token_kind_table[*ptr] == kind; + ptr += 1); + } + + tp += 1; + } + + tp->pos = (U32)text.size; + tp->kind = EXP_TokenKind_EndOfFile; + tp += 1; + + // put back extra memory + U32 token_count = (U32)(tp - tokens); + arena_pop_amount(arena, sizeof(*tokens)*(token_cap - token_count)); + + // arrange as result + EXP_TokenArray result = {0}; + result.tokens = tokens; + result.count = token_count - 1; + return(result); +} + +//////////////////////////////// +// Parser Functions + +EXP_PRECEDENCE(1, Multiplicative); +EXP_PRECEDENCE(2, Additive); +EXP_PRECEDENCE(3, Assignment, .right_to_left = 1); + +EXP_OPERATOR(Multiply, "*", Multiplicative); +EXP_OPERATOR(Divide, "/", Multiplicative); +EXP_OPERATOR(Modulo, "%", Multiplicative); +EXP_OPERATOR(Add, "+", Additive); +EXP_OPERATOR(Subtract, "-", Additive); +EXP_OPERATOR(Assign, "=", Assignment); +EXP_OPERATOR(MulAssign, "*=", Assignment); +EXP_OPERATOR(DivAssign, "/=", Assignment); +EXP_OPERATOR(AddAssign, "+=", Assignment); +EXP_OPERATOR(SubAssign, "-=", Assignment); + +static EXP_ParseNode* +exp_parse(Arena *arena, String8 text, EXP_TokenArray tokens){ + EXP_ParseCtx ctx = {0}; + ctx.text = text; + ctx.tokens = tokens; + ctx.token = tokens.tokens; + + EXP_ParseNode *result = exp__parse_op(arena, &ctx); + return(result); +} + +static EXP_ParseNode* +exp__parse_op_rec(Arena *arena, EXP_ParseCtx *ctx, + EXP_ParseNode *left, U32 max_precedence_level){ + // read first operator + exp__parse_skip_whitespace(ctx); + EXP_OperatorRead peak_op = exp__parse_read_operator(ctx); + + for (;;){ + EXP_OperatorRead left_op = peak_op; + + // end loop when precedence level increases (or no operator next) + if (left_op.operator_id == 0 || + left_op.precedence_level > max_precedence_level){ + break; + } + + // consume left op + ctx->token += 1; + + // read right leaf + exp__parse_skip_whitespace(ctx); + EXP_ParseNode *right = exp__parse_leaf(arena, ctx); + + // apply stickier right hand operators + for (;;){ + + // read right operator + exp__parse_skip_whitespace(ctx); + peak_op = exp__parse_read_operator(ctx); + + // check precedence + if (peak_op.operator_id == 0 || + peak_op.precedence_level > left_op.precedence_level || + (peak_op.precedence_level == left_op.precedence_level && !peak_op.right_to_left)){ + break; + } + + // recursively fold onto right + right = exp__parse_op_rec(arena, ctx, right, peak_op.precedence_level); + } + + // combine left & right with operator + { + EXP_ParseNode *node = push_array(arena, EXP_ParseNode, 1); + node->kind = EXP_ParseNodeKind_Operator; + node->op.operator_id = left_op.operator_id; + node->op.child[0] = left; + node->op.child[1] = right; + left = node; + } + } + + done:; + return(left); +} + +static EXP_ParseNode* +exp__parse_op(Arena *arena, EXP_ParseCtx *ctx){ + EXP_ParseNode *left = exp__parse_leaf(arena, ctx); + EXP_ParseNode *result = exp__parse_op_rec(arena, ctx, left, 3); + return(result); +} + +static EXP_ParseNode* +exp__parse_leaf(Arena *arena, EXP_ParseCtx *ctx){ + EXP_ParseNode *result = 0; + + exp__parse_skip_whitespace(ctx); + + // check next token + switch (ctx->token->kind){ + case EXP_TokenKind_OpenParen: { + ctx->token += 1; + result = exp__parse_op(arena, ctx); + if (ctx->error) goto done; + if (ctx->token->kind == EXP_TokenKind_CloseParen){ + ctx->token += 1; + } + else{ + exp__parse_errorf(arena, ctx, "Expected ')'"); + goto done; + } + }break; + + case EXP_TokenKind_IDNum: { + result = push_array(arena, EXP_ParseNode, 1); + result->kind = EXP_ParseNodeKind_Leaf; + result->leaf.token_idx = (U32)(ctx->token - ctx->tokens.tokens); + ctx->token += 1; + }break; + } + + done:; + return(result); +} + +static void +exp__parse_errorf(Arena *arena, EXP_ParseCtx *ctx, char *fmt, ...){ + if (ctx->error == 0){ + va_list args; + va_start(args, fmt); + String8 string = str8_pushfv(arena, fmt, args); + va_end(args); + ctx->error = 1; + ctx->error_token_idx = (U32)(ctx->token - ctx->tokens.tokens); + ctx->error_message = string; + } +} + +static void +exp__parse_skip_whitespace(EXP_ParseCtx *ctx){ + if (ctx->token->kind == EXP_TokenKind_Whitespace){ + ctx->token += 1; + } +} + +static EXP_OperatorRead +exp__parse_read_operator(EXP_ParseCtx *ctx){ + EXP_OperatorRead result = {0}; + if (ctx->token->kind == EXP_TokenKind_Operator){ + String8 operator_text = str8(ctx->text.str + ctx->token->pos, + (ctx->token + 1)->pos - ctx->token->pos); + result.operator_id = exp_operator_id_from_string(operator_text); + + if (result.operator_id != 0){ + // TODO(allen): [operator] -> precedence_level accelerator + EXP_Operator *op = SyAddressFromID(EXP_OPERATOR, result.operator_id); + EXP_Precedence *precedence = SyAddressFromID(EXP_PRECEDENCE, op->precedence_id); + result.precedence_level = precedence->order; + result.right_to_left = precedence->right_to_left; + } + } + return(result); +} + +static void +exp_parse_node_print(String8 text, EXP_TokenArray tokens, + EXP_ParseNode *node, S32 indent){ + printf("%.*s", indent, " "); + switch (node->kind){ + case EXP_ParseNodeKind_Operator: { + EXP_Operator *op = SyAddressFromID(EXP_OPERATOR, node->op.operator_id); + printf("%.*s\n", (U32)op->token_str.size, op->token_str.str); + exp_parse_node_print(text, tokens, node->op.child[0], indent + 1); + exp_parse_node_print(text, tokens, node->op.child[1], indent + 1); + }break; + + case EXP_ParseNodeKind_Leaf: { + EXP_Token *token = &tokens.tokens[node->leaf.token_idx]; + String8 string = str8(text.str + token->pos, (token + 1)->pos - token->pos); + printf("%.*s\n", (U32)string.size, string.str); + }break; + } +} + +//////////////////////////////// +// Entrpy Point + +int main(void){ + sy__run_init(); + + Arena arena = arena_alloc((10 << 20)); + +#if 0 + String8 text = str8_const("((FooBar + 100 ** 3 ^;;\r\n\t\t 17){{[[?/:::~`]]}})"); + EXP_TokenArray tokens = exp_lex(&arena, text); + + for (U32 i = 0; i < tokens.count; i += 1){ + EXP_Token *token = &tokens.tokens[i]; + char *token_kind_str = 0; + switch (token->kind){ +#define X(N) case EXP_TokenKind_##N: token_kind_str = #N; break; + EXP_TokenKindXList(X) +#undef X + } + U32 token_size = (token + 1)->pos - token->pos; + printf("TOKEN %s: '%.*s'\n", token_kind_str, token_size, text.str + token->pos); + } +#endif + + String8 text = str8_const("1 + 2 = a - b + c /= a + b * c = (a + b) / (x += c) = d"); + EXP_TokenArray tokens = exp_lex(&arena, text); + EXP_ParseNode *root = exp_parse(&arena, text, tokens); + + exp_parse_node_print(text, tokens, root, 0); + + return(0); +} + + +/* TODO + ** C-Scripted Interpretations +** +** C-Scripted Prefix Postfix Operators +** +** C-Scripted Bracket Operators +** +** C-Scripted Structure Builder +*/ diff --git a/examples/expression_parser.h b/examples/expression_parser.h new file mode 100644 index 0000000..a37d1db --- /dev/null +++ b/examples/expression_parser.h @@ -0,0 +1,160 @@ +#ifndef EXPRESSION_PARSER_H +#define EXPRESSION_PARSER_H + +//////////////////////////////// +// Operators + +//// PRECEDENCE //// + +typedef struct EXP_Precedence{ + String8 name; + U32 order; + B32 right_to_left; +} EXP_Precedence; + +#define SYMBOL_SET_DEFINE EXP_PRECEDENCE +#define EXP_PRECEDENCE_Type EXP_Precedence +#define EXP_PRECEDENCE_elf_section ".sy.precedence" +#define EXP_PRECEDENCE_coff_a_section ".sy$precedence_a" +#define EXP_PRECEDENCE_coff_m_section ".sy$precedence_m" +#define EXP_PRECEDENCE_coff_z_section ".sy$precedence_z" +#define EXP_PRECEDENCE_marker precedence +#include "symbol_set.define.h" + +#define EXP_PRECEDENCE(ord,N,...) \ +SyDefine(EXP_PRECEDENCE, N) = { .order = (ord), .name = str8_const(#N), __VA_ARGS__ } + +//// OPERATOR //// + +typedef struct EXP_Operator{ + String8 name; + String8 token_str; + SY__UAddr precedence_id; +} EXP_Operator; + +#define SYMBOL_SET_DEFINE EXP_OPERATOR +#define EXP_OPERATOR_Type EXP_Operator +#define EXP_OPERATOR_elf_section ".sy.operator" +#define EXP_OPERATOR_coff_a_section ".sy$operator_a" +#define EXP_OPERATOR_coff_m_section ".sy$operator_m" +#define EXP_OPERATOR_coff_z_section ".sy$operator_z" +#define EXP_OPERATOR_marker operator +#include "symbol_set.define.h" + +#define EXP_OPERATOR(N,str,P) \ +SyDefine(EXP_OPERATOR, N) = { .name = str8_const(#N), \ +.token_str = str8_const(str), \ +.precedence_id = SyRaw(EXP_PRECEDENCE, P) } + +#if SY__MAIN +SY_INIT(EXP_OPERATOR){ + for (SyEach(EXP_OPERATOR, op)){ + op->precedence_id = SyIDFromRaw(EXP_PRECEDENCE, op->precedence_id); + } +} +#endif + +//////////////////////////////// +// Operator Functions + +static U32 exp_operator_id_from_string(String8 string); + +//////////////////////////////// +// Lexer Types + +#define EXP_TokenKindXList(X) \ +X(Error)\ +X(EndOfFile)\ +X(Whitespace)\ +X(IDNum)\ +X(Operator)\ +X(OpenParen)\ +X(CloseParen)\ +X(OpenBracket)\ +X(CloseBracket)\ +X(OpenBrace)\ +X(CloseBrace) + +typedef enum EXP_TokenKind{ +#define X(N) EXP_TokenKind_##N, + EXP_TokenKindXList(X) +#undef X + EXP_TokenKind_COUNT +} EXP_TokenKind; + +typedef struct EXP_Token{ + EXP_TokenKind kind; + U32 pos; +} EXP_Token; + +typedef struct EXP_TokenArray{ + EXP_Token *tokens; + U64 count; +} EXP_TokenArray; + +//////////////////////////////// +// Lexer Functions + +static EXP_TokenArray exp_lex(Arena *arena, String8 text); + +//////////////////////////////// +// Parser Types + +#define EXP_ParseNodeKindXList(X)\ +X(NULL)\ +X(Operator)\ +X(Leaf) + +typedef enum EXP_ParseNodeKind{ +#define X(N) EXP_ParseNodeKind_##N, + EXP_ParseNodeKindXList(X) +#undef X + EXP_ParseNodeKind_COUNT +} EXP_ParseNodeKind; + +typedef struct EXP_ParseNode{ + EXP_ParseNodeKind kind; + union{ + struct{ + U32 operator_id; + struct EXP_ParseNode *child[2]; + } op; + struct{ + U32 token_idx; + } leaf; + }; +} EXP_ParseNode; + +typedef struct EXP_ParseCtx{ + String8 text; + EXP_TokenArray tokens; + EXP_Token *token; + B32 error; + U32 error_token_idx; + String8 error_message; +} EXP_ParseCtx; + +typedef struct EXP_OperatorRead{ + U32 operator_id; + U32 precedence_level; + B32 right_to_left; +} EXP_OperatorRead; + +//////////////////////////////// +// Parser Functions + +static EXP_ParseNode* exp_parse(Arena *arena, String8 text, EXP_TokenArray tokens); + +static EXP_ParseNode* exp__parse_op_rec(Arena *arena, EXP_ParseCtx *ctx, + EXP_ParseNode *left, U32 precedence_level); +static EXP_ParseNode* exp__parse_op(Arena *arena, EXP_ParseCtx *ctx); +static EXP_ParseNode* exp__parse_leaf(Arena *arena, EXP_ParseCtx *ctx); + +static void exp__parse_errorf(Arena *arena, EXP_ParseCtx *ctx, char *fmt, ...); +static void exp__parse_skip_whitespace(EXP_ParseCtx *ctx); +static EXP_OperatorRead exp__parse_read_operator(EXP_ParseCtx *ctx); + +static void exp_parse_node_print(String8 text, EXP_TokenArray tokens, + EXP_ParseNode *node, S32 indent); + +#endif //EXPRESSION_PARSER_H diff --git a/examples/hooks.c b/examples/hooks.c index 2ffded9..2058348 100644 --- a/examples/hooks.c +++ b/examples/hooks.c @@ -6,73 +6,10 @@ #include "symbol_set.h" #include "symbol_set.init.h" +#include "examples.base.h" #include "hooks.h" -#include -#include -#include -//////////////////////////////// -// Little Base Layer - -static Arena -arena_alloc(U64 cap){ - Arena arena = {0}; - arena.memory = malloc(cap); - arena.cap = cap; - return(arena); -} - -static void* -arena_push(Arena *arena, U64 size){ - void *result = 0; - if (arena->pos + size <= arena->cap){ - result = (U8*)arena->memory + arena->pos; - arena->pos += size; - arena->pos = (arena->pos + 7)&~7; // "round up to multiple of 8" - memset(result, 0, size); - } - return(result); -} - -static void -arena_pop_to(Arena *arena, U64 pos){ - if (pos < arena->pos){ - arena->pos = (pos + 7)&~7; // "round up to multiple of 8" - } -} - -static U64 -arena_pos(Arena *arena){ - return(arena->pos); -} - -static void* -copy_strided(void *dst, U32 dst_stride, - void *src, U32 src_stride, - U32 count){ - void *base_src = src; - void *base_dst = dst; - if (dst_stride != src_stride){ - U32 size = Min(dst_stride, src_stride); - for (U32 i = 0; i < count; i += 1){ - memcpy(dst, src, size); - dst = (U8*)dst + dst_stride; - src = (U8*)src + src_stride; - } - } - else{ - memcpy(dst, src, dst_stride*count); - } - return(base_dst); -} - -static void* -arena_push_symbol_set__raw(Arena *arena, - U32 size, void *src, U32 src_stride, U32 count){ - void *dst = push_array(arena, U8, size*(count + 1)); - copy_strided((U8*)dst + size, size, src, src_stride, count); - return(dst); -} +#include "examples.base.c" //////////////////////////////// // Pretend "Core API" diff --git a/examples/hooks.h b/examples/hooks.h index 7a0bea9..11b4047 100644 --- a/examples/hooks.h +++ b/examples/hooks.h @@ -1,57 +1,6 @@ #ifndef HOOKS_H #define HOOKS_H -//////////////////////////////// -// Little Base Layer - -#include -typedef int8_t S8; -typedef int16_t S16; -typedef int32_t S32; -typedef int64_t S64; -typedef uint8_t U8; -typedef uint16_t U16; -typedef uint32_t U32; -typedef uint64_t U64; -typedef S8 B8; -typedef S16 B16; -typedef S32 B32; -typedef S64 B64; -typedef float F32; -typedef double F64; - -typedef struct String8{ - U8 *str; - U64 size; -} String8; - -#define str8_const(S) {(U8*)(S), (U64)(sizeof(S) - 1)} - -typedef struct Arena{ - void *memory; - U64 pos; - U64 cap; -} Arena; - -static Arena arena_alloc(U64 cap); -static void* arena_push(Arena *arena, U64 size); -static void arena_pop_to(Arena *arena, U64 pos); -static U64 arena_pos(Arena *arena); - -#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) - -static void*copy_strided(void *dst, U32 dst_stride, - void *src, U32 src_stride, - U32 count); - -static void*arena_push_symbol_set__raw(Arena *arena, - U32 size, void *src, U32 src_stride, U32 count); - -#define arena_push_symbol_set(ar,S) (SyType(S)*) \ -arena_push_symbol_set__raw((ar), sizeof(SyType(S)), SyFirst(S), SyStride(S), SyCount(S)) - -#define Min(a,b) ((a)<(b))?(a):(b) - //////////////////////////////// // Hooks diff --git a/examples/stack_machine.c b/examples/stack_machine.c index bdbec39..7da4d09 100644 --- a/examples/stack_machine.c +++ b/examples/stack_machine.c @@ -6,45 +6,10 @@ #include "symbol_set.h" #include "symbol_set.init.h" +#include "examples.base.h" #include "stack_machine.h" -#include -#include -#include -//////////////////////////////// -// Little Base Layer - -static Arena -arena_alloc(U64 cap){ - Arena arena = {0}; - arena.memory = malloc(cap); - arena.cap = cap; - return(arena); -} - -static void* -arena_push(Arena *arena, U64 size){ - void *result = 0; - if (arena->pos + size <= arena->cap){ - result = (U8*)arena->memory + arena->pos; - arena->pos += size; - arena->pos = (arena->pos + 7)&~7; // "round up to multiple of 8" - memset(result, 0, size); - } - return(result); -} - -static void -arena_pop_to(Arena *arena, U64 pos){ - if (pos < arena->pos){ - arena->pos = (pos + 7)&~7; // "round up to multiple of 8" - } -} - -static U64 -arena_pos(Arena *arena){ - return(arena->pos); -} +#include "examples.base.c" //////////////////////////////// // Stack Machine diff --git a/examples/stack_machine.h b/examples/stack_machine.h index f9403c0..fb9a8c5 100644 --- a/examples/stack_machine.h +++ b/examples/stack_machine.h @@ -1,104 +1,6 @@ #ifndef STACK_MACHINE_H #define STACK_MACHINE_H -//////////////////////////////// -// Little Base Layer - -#include -typedef int8_t S8; -typedef int16_t S16; -typedef int32_t S32; -typedef int64_t S64; -typedef uint8_t U8; -typedef uint16_t U16; -typedef uint32_t U32; -typedef uint64_t U64; -typedef S8 B8; -typedef S16 B16; -typedef S32 B32; -typedef S64 B64; -typedef float F32; -typedef double F64; - -typedef struct String8{ - U8 *str; - U64 size; -} String8; - -#define str8_const(S) {(U8*)(S), (U64)(sizeof(S) - 1)} - -typedef struct Arena{ - void *memory; - U64 pos; - U64 cap; -} Arena; - -static Arena arena_alloc(U64 cap); -static void* arena_push(Arena *arena, U64 size); -static void arena_pop_to(Arena *arena, U64 pos); -static U64 arena_pos(Arena *arena); - -#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) - -//////////////////////////////// -// Macros: Linked Lists - -#define DLLPushBack_NPZ(f,l,n,next,prev,nil)\ -(((f) == (nil))?\ -((f)=(l)=(n),(n)->next=(n)->prev=(nil)):\ -((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=(nil))) - -#define DLLPushBack(f,l,n) DLLPushBack_NPZ(f,l,n,next,prev,0) -#define DLLPushFront(f,l,n) DLLPushBack_NPZ(l,f,n,prev,next,0) - -#define DLLInsert_NPZ(f,l,p,n,next,prev,nil) \ -(((p) != (l))?\ -((n)->next = (p)->next,\ -(n)->prev = (p),\ -(p)->next->prev = (n),\ -(p)->next = (n))\ -:((n)->next = (nil),\ -(n)->prev = (l),\ -(l)->next = (n),\ -(l) = (n))) - -#define DLLInsert(f,l,p,n) DLLInsert_NPZ(f,l,p,n,next,prev,0) - -#define DLLRemove_NPZ(f,l,n,next,prev,nil)\ -((f)==(n)?\ -((f)==(l)?\ -((f)=(l)=(nil)):\ -((f)=(f)->next,(f)->prev=(nil))):\ -(l)==(n)?\ -((l)=(l)->prev,(l)->next=(nil)):\ -((n)->next->prev=(n)->prev,\ -(n)->prev->next=(n)->next)) - -#define DLLRemove(f,l,n) DLLRemove_NPZ(f,l,n,next,prev,0) - -#define SLLQueuePush_NZ(f,l,n,next,nil) (((f)==(nil)?\ -(f)=(l)=(n):\ -((l)->next=(n),(l)=(n))),\ -(n)->next=(nil)) -#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(f,l,n,next,0) - -#define SLLQueuePushFront_NZ(f,l,n,next,nil) ((f)==(nil)?\ -((f)=(l)=(n),(n)->next=(nil)):\ -((n)->next=(f),(f)=(n))) -#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(f,l,n,next,0) - -#define SLLQueuePop_NZ(f,l,next,nil) ((f)==(l)?\ -(f)=(l)=(nil):\ -((f)=(f)->next)) -#define SLLQueuePop(f,l) SLLQueuePop_NZ(f,l,next,0) - -#define SLLStackPush_N(f,n,next) ((n)->next=(f),(f)=(n)) -#define SLLStackPush(f,n) SLLStackPush_N(f,n,next) - -#define SLLStackPop_NZ(f,next,nil) ((f)==(nil)?(nil):\ -((f)=(f)->next)) -#define SLLStackPop(f) SLLStackPop_NZ(f,next,0) - //////////////////////////////// // Stack Machine diff --git a/project.4coder b/project.4coder index a35e895..dc9933f 100644 --- a/project.4coder +++ b/project.4coder @@ -23,15 +23,22 @@ commands = { .footer_panel = true, .save_dirty_files = true, .linux = "./build_ld_meta.sh", .mac = "./build_ld_meta.sh" }, + .build_all_examples = { .out = "*compilation*", + .footer_panel = true, .save_dirty_files = true, + .linux = "./build_all_examples.sh", .mac = "./build_all_examples.sh" + }, .run_example1 = { .out = "*run*", .footer_panel = false, .save_dirty_files = false, .win = "build\\example1", .linux = "build/example1", .mac = "build/example1" }, .run_hooks = { .out = "*run*", .footer_panel = false, .save_dirty_files = false, .win = "build\\hooks", .linux = "build/hooks", .mac = "build/hooks" }, + .run_expression_parser = { .out = "*run*", .footer_panel = false, .save_dirty_files = false, + .win = "build\\expression_parser", .linux = "build/expression_parser", .mac = "build/expression_parser" + }, }; fkey_command = { - .F1 = "build_with_clang", - .F2 = "run_hooks", + .F1 = "build_all_examples", + .F2 = "run_expression_parser", };