diff options
author | Alexis Lockwood | 2021-06-27 12:22:12 -0400 |
---|---|---|
committer | Alexis Lockwood | 2021-06-27 12:22:12 -0400 |
commit | 4a043e4c9980fd5180be3fe22144978742e7c3d0 (patch) | |
tree | 5f06bc68b496275f0899996e8ea123e7f1efb864 | |
parent | 6fb9b630ce5256ddc8d937dc6b2bd9a556936e59 (diff) |
Fix ls_run catching fire on string labels
-rw-r--r-- | func.bas | 6 | ||||
-rw-r--r-- | ls_run.c | 14 | ||||
-rw-r--r-- | src/ls.c | 29 | ||||
-rw-r--r-- | src/ls.h | 3 | ||||
-rw-r--r-- | src/ls_internal.c | 43 | ||||
-rw-r--r-- | src/ls_internal.h | 6 | ||||
-rw-r--r-- | src/ls_lex.c | 33 | ||||
-rw-r--r-- | src/ls_types.h | 8 |
8 files changed, 111 insertions, 31 deletions
diff --git a/func.bas b/func.bas new file mode 100644 index 0000000..20f96fb --- /dev/null +++ b/func.bas @@ -0,0 +1,6 @@ +gosub hello +end + +hello: +print "Hello, world!" +return @@ -125,16 +125,16 @@ int main(int argc, char ** argv) ls_ctx.fetcher_ctx = &fctx; ls_ctx.line_trace_hook = tron ? _line_trace_hook : NULL; - ls_value_t pool[1000]; - if (action == ACT_TOKENIZE) { ls_ctx.pc = 0; ls_ctx.line = 1; + ls_ctx.labels = NULL; _tokenize(&ls_ctx); exit(EXIT_SUCCESS); } + ls_value_t pool[1000]; ls_error_t e = ls_run(&ls_ctx, pool, 1000); if (e != 0) @@ -246,7 +246,15 @@ static void _usage(char const * argv0, bool short_text) static void _tokenize(ls_context_t * ctx) { - // TODO: errors will crash here, the jmpbuf isn't set up + ls_value_t pool[100]; // for labels + ls_init_ctx(ctx, pool, sizeof pool / sizeof pool[0]); + + if (setjmp(ctx->error_jmp_buf)) + { + fprintf(stderr, "error %d at line %"PRIu16"\n", + (int) ctx->error, ctx->line); + exit(EXIT_FAILURE); + } ls_token_t tok; @@ -32,34 +32,7 @@ ls_error_t ls_run(ls_context_t * ctx, ls_value_t * pool, size_t szpool) return ctx->error; } - ctx->error = LS_OK; - - ctx->pool = pool; - ctx->pool[szpool - 1].next = NULL; - ctx->pool[szpool - 1].prev = NULL; - ctx->pool[szpool - 1].ty = LS_TY_PRISTINE; - for (size_t i = 0; i < (szpool - 1); i++) - { - ctx->pool[i].ty = LS_TY_PRISTINE; - ctx->pool[i].next = &ctx->pool[i + 1]; - ctx->pool[i].prev = NULL; - } - - ctx->callstack = ls_alloc(ctx); - ctx->callstack->ty = LS_TY_SCTX_CALL; - ctx->callstack->prev = NULL; - ctx->callstack->next = NULL; - ctx->callstack->body.sctx_call.pc = LS_ADDR_NULL; - ctx->callstack->body.sctx_call.readptr = LS_ADDR_NULL; - - ctx->userstack = NULL; - ctx->funcs = NULL; - ctx->pc = 0; - ctx->line = 1; - - for (size_t i = 0; i < LS_LABEL_CACHE_SIZE; i++) - ctx->label_cache[i].pc = LS_ADDR_NULL; - ctx->label_cache_i = 0; + ls_init_ctx(ctx, pool, szpool); while (ls_exec_line(ctx)); @@ -50,6 +50,9 @@ typedef struct ls_context_s { /// User functions defined by DEF FN. ls_value_t * funcs; + /// Named labels + ls_value_t * labels; + /// Data pool. All runtime values are allocated from here. ls_value_t * pool; diff --git a/src/ls_internal.c b/src/ls_internal.c index 1bd065d..3027a14 100644 --- a/src/ls_internal.c +++ b/src/ls_internal.c @@ -37,6 +37,49 @@ // --- PRIVATE VARIABLES ------------------------------------------------------- // --- PUBLIC FUNCTIONS -------------------------------------------------------- +void ls_init_ctx(ls_context_t * ctx, ls_value_t * pool, size_t szpool) +{ + ctx->error = LS_OK; + + ctx->pool = pool; + + if (pool) + { + ctx->pool[szpool - 1].ty = LS_TY_PRISTINE; + ctx->pool[szpool - 1].next = NULL; + ctx->pool[szpool - 1].prev = NULL; + + for (size_t i = 0; i < szpool - 1; i++) + { + ctx->pool[i].ty = LS_TY_PRISTINE; + ctx->pool[i].next = &ctx->pool[i + 1]; + ctx->pool[i].prev = NULL; + } + + ctx->callstack = ctx->pool; + ctx->pool = ctx->pool->next; + *ctx->callstack = (ls_value_t) { + .ty = LS_TY_SCTX_CALL, + .prev = NULL, + .next = NULL, + .body.sctx_call = { + .pc = LS_ADDR_NULL, + .readptr = LS_ADDR_NULL, + }, + }; + } + + ctx->userstack = NULL; + ctx->funcs = NULL; + ctx->labels = NULL; + ctx->pc = 0; + ctx->line = 1; + + for (size_t i = 0; i < LS_LABEL_CACHE_SIZE; i++) + ctx->label_cache[i].pc = LS_ADDR_NULL; + ctx->label_cache_i = 0; +} + ls_kw_t ls_convert_kw(char const * word) { uint8_t hash = LS_KW_HASH_DEFAULT; diff --git a/src/ls_internal.h b/src/ls_internal.h index bf0e2d4..e5b38da 100644 --- a/src/ls_internal.h +++ b/src/ls_internal.h @@ -99,6 +99,12 @@ extern const LS_PROGMEM ls_kwdef_t ls_kwmap[]; // --- PUBLIC VARIABLES -------------------------------------------------------- // --- PUBLIC FUNCTIONS -------------------------------------------------------- +/// Initialize a context as if to run, but do not execute. +/// +/// @param pool - pool to load (can be null, but then pool and callstack will +/// not get initialized) +void ls_init_ctx(ls_context_t * ctx, ls_value_t * pool, size_t szpool); + /// Identify what type the next token is, but do not consume it. /// /// Can throw on internal errors, but returns LS_TOK_INVALID on a syntax error. diff --git a/src/ls_lex.c b/src/ls_lex.c index a5dd382..2441858 100644 --- a/src/ls_lex.c +++ b/src/ls_lex.c @@ -366,9 +366,42 @@ static void _lex_word(ls_context_t * ctx, ls_token_t * tok, ls_uchar ch[2]) { if (tok->ty == LS_TOK_STR_LABEL) ls_throw_err(ctx, LS_SYNTAX_ERROR); + tok->ty = LS_TOK_KEYWORD; tok->body.keyword_val = kw; } + else if (tok->ty == LS_TOK_STR_LABEL) + { + // The label might already exist. If it does, we're either + // seeing it again or shadowing it. + + ls_value_t * label = NULL; + for (ls_value_t * i = ctx->labels; i; i = i->next) + { + if (!strncmp(tok->body.word_val, i->body.label.ident, + LS_IDENT_LEN)) + { + label = i; + break; + } + } + + if (label) + { + if (label->body.label.pc != ctx->pc) + ls_throw_err(ctx, LS_DUPLICATE_DEFINITION); + } + else + { + label = ls_alloc(ctx); + label->next = ctx->labels; + label->prev = NULL; + strncpy(label->body.label.ident, tok->body.word_val, + LS_IDENT_LEN); + label->body.label.pc = ctx->pc; + ctx->labels = label; + } + } } static void _lex_str(ls_context_t * ctx, ls_token_t * tok, ls_uchar ch[2]) diff --git a/src/ls_types.h b/src/ls_types.h index 7894864..1b3f111 100644 --- a/src/ls_types.h +++ b/src/ls_types.h @@ -127,6 +127,12 @@ typedef struct { struct ls_value_s * value; } ls_ty_var_t; +/// Label. This points to the PC of the start of the line just after the label. +typedef struct { + char ident[LS_IDENT_LEN]; + ls_addr_t pc; +} ls_ty_label_t; + /// Function context stackframe. Used in function calls, and one is also used /// as the global context. NEXT pointer should point into a linked list of /// variables. @@ -181,6 +187,7 @@ typedef enum { LS_TY_INT_VAR = LS_TY_INTERNAL_START, LS_TY_VAR, + LS_TY_LABEL, LS_TY_SCTX_CALL, LS_TY_SCTX_FOR, LS_TY_SCTX_WHILE, @@ -210,6 +217,7 @@ typedef struct ls_value_s { ls_ty_int_var_t int_var; ls_ty_var_t var; + ls_ty_label_t label; ls_ty_sctx_call_t sctx_call; ls_ty_sctx_for_t sctx_for; ls_ty_sctx_while_t sctx_while; |