aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Lockwood2021-06-27 12:22:12 -0400
committerAlexis Lockwood2021-06-27 12:22:12 -0400
commit4a043e4c9980fd5180be3fe22144978742e7c3d0 (patch)
tree5f06bc68b496275f0899996e8ea123e7f1efb864
parent6fb9b630ce5256ddc8d937dc6b2bd9a556936e59 (diff)
Fix ls_run catching fire on string labels
-rw-r--r--func.bas6
-rw-r--r--ls_run.c14
-rw-r--r--src/ls.c29
-rw-r--r--src/ls.h3
-rw-r--r--src/ls_internal.c43
-rw-r--r--src/ls_internal.h6
-rw-r--r--src/ls_lex.c33
-rw-r--r--src/ls_types.h8
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
diff --git a/ls_run.c b/ls_run.c
index c565bba..7468a32 100644
--- a/ls_run.c
+++ b/ls_run.c
@@ -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;
diff --git a/src/ls.c b/src/ls.c
index 615a39a..e265ac4 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -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));
diff --git a/src/ls.h b/src/ls.h
index adb40c2..9b1971b 100644
--- a/src/ls.h
+++ b/src/ls.h
@@ -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;