[examples] setup an examples base layer; sketch parser example
parent
69b419b086
commit
b755026ba6
|
|
@ -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
|
||||
|
||||
|
|
@ -5,8 +5,10 @@
|
|||
#define SY__MAIN 1
|
||||
#include "symbol_set.h"
|
||||
|
||||
#include "examples.base.h"
|
||||
#include "example1.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "examples.base.c"
|
||||
|
||||
COMMAND_SCRIPT(foo, "Generates foo and increments the foo counter"){
|
||||
printf("foo, ");
|
||||
|
|
|
|||
|
|
@ -1,30 +1,6 @@
|
|||
#ifndef EXAMPLE1_H
|
||||
#define EXAMPLE1_H
|
||||
|
||||
////////////////////////////////
|
||||
// Little Base Layer
|
||||
|
||||
#include <stdint.h>
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef EXAMPLES_BASE_H
|
||||
#define EXAMPLES_BASE_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
////////////////////////////////
|
||||
// Typical Base Stuff
|
||||
|
||||
#include <stdint.h>
|
||||
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
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
@ -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
|
||||
|
|
@ -6,73 +6,10 @@
|
|||
#include "symbol_set.h"
|
||||
#include "symbol_set.init.h"
|
||||
|
||||
#include "examples.base.h"
|
||||
#include "hooks.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
////////////////////////////////
|
||||
// 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"
|
||||
|
|
|
|||
|
|
@ -1,57 +1,6 @@
|
|||
#ifndef HOOKS_H
|
||||
#define HOOKS_H
|
||||
|
||||
////////////////////////////////
|
||||
// Little Base Layer
|
||||
|
||||
#include <stdint.h>
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -6,45 +6,10 @@
|
|||
#include "symbol_set.h"
|
||||
#include "symbol_set.init.h"
|
||||
|
||||
#include "examples.base.h"
|
||||
#include "stack_machine.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
////////////////////////////////
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -1,104 +1,6 @@
|
|||
#ifndef STACK_MACHINE_H
|
||||
#define STACK_MACHINE_H
|
||||
|
||||
////////////////////////////////
|
||||
// Little Base Layer
|
||||
|
||||
#include <stdint.h>
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue