aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/ls_kw_impl.c216
-rw-r--r--src/ls_kw_impl_LOOPS.c221
-rw-r--r--src/ls_lex.c12
-rw-r--r--src/ls_lex.h3
5 files changed, 239 insertions, 215 deletions
diff --git a/Makefile b/Makefile
index 524e25b..070d261 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ LS_INCLUDE := src
LS_SOURCES := src/ls_internal.c src/ls_kws.c src/ls_expr.c src/ls.c \
src/ls_lex.c src/ls_goto.c \
src/ls_kw_impl.c src/ls_kw_impl_PRINT.c src/ls_kw_impl_GOTO.c \
- src/ls_kw_impl_GOSUB_RETURN.c
+ src/ls_kw_impl_GOSUB_RETURN.c src/ls_kw_impl_LOOPS.c
LS_ARGS := -I${LS_INCLUDE} -Lsrc -lls
TEST_ARGS := -Imunit -Lmunit -lmunit test/tsupport.c
diff --git a/src/ls_kw_impl.c b/src/ls_kw_impl.c
index 9070ab7..6330be0 100644
--- a/src/ls_kw_impl.c
+++ b/src/ls_kw_impl.c
@@ -24,8 +24,6 @@
/// Call for keywords without implementations.
static void _no_impl(ls_t * self);
-static void _consume_to_eol(ls_t * self);
-
void ls_kw_fun_GOTO(ls_t * self);
// --- PUBLIC VARIABLES --------------------------------------------------------
@@ -47,85 +45,12 @@ void ls_kw_fun_COUNT(ls_t * self) { _no_impl(self); }
void ls_kw_fun_DATA(ls_t * self) { _no_impl(self); }
void ls_kw_fun_DEC(ls_t * self) { _no_impl(self); }
void ls_kw_fun_DEF(ls_t * self) { _no_impl(self); }
-
void ls_kw_fun_END(ls_t * self) { ls_throw_err(self, LS_STOPPED); }
-
void ls_kw_fun_EQV(ls_t * self) { _no_impl(self); }
void ls_kw_fun_ERASE(ls_t * self) { _no_impl(self); }
void ls_kw_fun_ERROR(ls_t * self) { _no_impl(self); }
void ls_kw_fun_FN(ls_t * self) { _no_impl(self); }
-
-void ls_kw_fun_FOR(ls_t * self)
-{
- // FOR ident = a TO b [STEP c]
- ls_value_t * ctx = ls_alloc(self);
- *ctx = (ls_value_t) {
- .ty = LS_TY_SCTX_FOR,
- .body.sctx_for = {
- .term = 0,
- .step = 1,
- .for_pc = LS_ADDR_NULL,
- },
- .prev = self->_callstack,
- .next = NULL,
- };
- self->_callstack = ctx;
-
- ls_value_t * iterator = ls_alloc(self);
- *iterator = (ls_value_t) {
- .ty = LS_TY_INT_VAR,
- .body.int_var = {{0}},
- };
-
- ctx->next = iterator;
-
- // FOR ident = a TO b [STEP c]
- if (ls_lex(self) != LS_TOK_WORD)
- ls_throw_err(self, LS_SYNTAX_ERROR);
-
- strncpy(iterator->body.int_var.ident, self->_token.word, LS_IDENT_LEN);
-
- if (ls_lex(self) != LS_OP_EQ)
- ls_throw_err(self, LS_SYNTAX_ERROR);
-
- ls_value_t val;
- ls_eval_expr(self, &val, LS_TOK_NONE);
- if (val.ty != LS_TY_INT)
- ls_throw_err(self, LS_SYNTAX_ERROR);
- iterator->body.int_var.value = val.body.integer.value;
-
- if (ls_lex(self) != LS_KW_TO)
- ls_throw_err(self, LS_SYNTAX_ERROR);
-
- ls_eval_expr(self, &val, LS_TOK_NONE);
- if (val.ty != LS_TY_INT)
- ls_throw_err(self, LS_SYNTAX_ERROR);
- ctx->body.sctx_for.term = val.body.integer.value;
-
- ls_token_t tok = ls_lex(self);
-
- if (tok == LS_KW_STEP)
- {
- ls_eval_expr(self, &val, LS_TOK_NONE);
- if (val.ty != LS_TY_INT)
- ls_throw_err(self, LS_SYNTAX_ERROR);
-
- if (val.body.integer.value > INT16_MAX ||
- val.body.integer.value < INT16_MIN)
- ls_throw_err(self, LS_FOR_STEP_TOO_LARGE);
-
- ctx->body.sctx_for.step = (int16_t) val.body.integer.value;
- tok = ls_lex(self);
- }
-
- if (tok == LS_TOK_STATEMENT_SEP)
- ctx->body.sctx_for.for_pc = self->_pc;
- else
- ls_throw_err(self, LS_SYNTAX_ERROR);
-}
-
void ls_kw_fun_HEX(ls_t * self) { _no_impl(self); }
-
void ls_kw_fun_IF(ls_t * self)
{
// TODO how to support ELSE - the current parsing method doesn't
@@ -138,7 +63,7 @@ void ls_kw_fun_IF(ls_t * self)
if (cond.body.integer.value == 0)
{
- _consume_to_eol(self);
+ ls_consume_to_eol(self);
return;
}
else
@@ -162,45 +87,6 @@ void ls_kw_fun_LEFT(ls_t * self) { _no_impl(self); }
void ls_kw_fun_LET(ls_t * self) { _no_impl(self); }
void ls_kw_fun_LOG(ls_t * self) { _no_impl(self); }
void ls_kw_fun_MID(ls_t * self) { _no_impl(self); }
-
-void ls_kw_fun_NEXT(ls_t * self)
-{
- if (self->_callstack->ty != LS_TY_SCTX_FOR)
- ls_throw_err(self, LS_FOR_NEXT_MISMATCH);
-
- ls_value_t * ctx = self->_callstack;
- ls_value_t * iterator = ctx->next;
- ls_int_t itval = iterator->body.int_var.value;
- ls_int_t term = ctx->body.sctx_for.term;
- ls_int_t step = (ls_int_t) ctx->body.sctx_for.step;
-
- bool done = false;
-
- if (step < 0)
- {
- if (itval <= term || (itval + step < term))
- done = true;
- }
- else
- {
- if (itval >= term || (itval + step > term))
- done = true;
- }
-
- if (done)
- {
- self->_callstack = ctx->prev;
- ls_free_val(self, ctx);
- _consume_to_eol(self);
- }
- else
- {
- self->_pc = ctx->body.sctx_for.for_pc;
- itval += step;
- iterator->body.int_var.value = itval;
- }
-}
-
void ls_kw_fun_NOT(ls_t * self) { _no_impl(self); }
void ls_kw_fun_OCT(ls_t * self) { _no_impl(self); }
void ls_kw_fun_ON(ls_t * self) { _no_impl(self); }
@@ -212,7 +98,7 @@ void ls_kw_fun_READ(ls_t * self) { _no_impl(self); }
void ls_kw_fun_REM(ls_t * self)
{
- _consume_to_eol(self);
+ ls_consume_to_eol(self);
}
void ls_kw_fun_RESTORE(ls_t * self) { _no_impl(self); }
@@ -228,93 +114,6 @@ void ls_kw_fun_TO(ls_t * self) { _no_impl(self); }
void ls_kw_fun_UNPACK(ls_t * self) { _no_impl(self); }
void ls_kw_fun_UNTIL(ls_t * self) { _no_impl(self); }
void ls_kw_fun_VAL(ls_t * self) { _no_impl(self); }
-
-void ls_kw_fun_WEND(ls_t * self)
-{
- if (self->_callstack->ty != LS_TY_SCTX_WHILE)
- ls_throw_err(self, LS_WHILE_WEND_MISMATCH);
-
- ls_addr_t pc_wend = self->_pc;
- self->_pc = self->_callstack->body.sctx_while.while_pc;
-
- ls_value_t cond;
- ls_eval_expr(self, &cond, LS_TOK_NONE);
-
- if (cond.ty != LS_TY_INT)
- ls_throw_err(self, LS_SYNTAX_ERROR);
-
- if (cond.body.integer.value == 0)
- {
- ls_value_t * ctx = self->_callstack;
- self->_callstack = ctx->prev;
- ls_free_val(self, ctx);
- self->_pc = pc_wend;
- }
-}
-
-void ls_kw_fun_WHILE(ls_t * self)
-{
- ls_addr_t pc_cond = self->_pc;
-
- ls_value_t cond;
- ls_eval_expr(self, &cond, LS_TOK_NONE);
-
- if (cond.ty != LS_TY_INT)
- ls_throw_err(self, LS_SYNTAX_ERROR);
-
- if (cond.body.integer.value != 0)
- {
- ls_value_t * ctx = ls_alloc(self);
- *ctx = (ls_value_t) {
- .ty = LS_TY_SCTX_WHILE,
- .body.sctx_while = {
- .while_pc = pc_cond,
- },
- .prev = self->_callstack,
- .next = NULL,
- };
- self->_callstack = ctx;
- }
- else
- {
- bool keyword_allowed = false;
- ls_token_t tok = LS_TOK_NUMBER;
- int8_t nest = 0;
-
- while (tok != LS_TOK_NONE)
- {
- tok = ls_lex(self);
-
- if (keyword_allowed)
- {
- if (tok == LS_KW_WHILE)
- nest++;
- else if (tok == LS_KW_WEND)
- if (nest)
- nest--;
- else
- break;
- else if (tok == LS_KW_REM)
- {
- _consume_to_eol(self);
- continue; // keep keyword true
- }
- }
-
- keyword_allowed =
- tok == LS_TOK_STR_LABEL ||
- tok == LS_TOK_NUM_LABEL ||
- tok == LS_TOK_STATEMENT_SEP;
- }
-
- if (tok == LS_TOK_NONE)
- {
- self->_pc = pc_cond;
- ls_throw_err(self, LS_WHILE_WEND_MISMATCH);
- }
- }
-}
-
void ls_kw_fun_WRITE(ls_t * self) { _no_impl(self); }
void ls_kw_fun_XOR(ls_t * self) { _no_impl(self); }
@@ -325,14 +124,3 @@ static void _no_impl(ls_t * self)
ls_throw_err(self, LS_BAD_KEYWORD);
}
-static void _consume_to_eol(ls_t * self)
-{
- for (;;) {
- ls_uchar uch = ls_fetch_rel(self, 0);
-
- if (uch == 0 || uch == '\n')
- return;
-
- self->_pc++;
- }
-}
diff --git a/src/ls_kw_impl_LOOPS.c b/src/ls_kw_impl_LOOPS.c
new file mode 100644
index 0000000..48aa560
--- /dev/null
+++ b/src/ls_kw_impl_LOOPS.c
@@ -0,0 +1,221 @@
+// This software disclaims copyright. Do what you want with it. Be gay, do
+// crime. Originally written by Alexis Lockwood in 2021. Ⓐ
+
+// --- DEPENDENCIES ------------------------------------------------------------
+
+// This module
+
+// Supporting modules
+#include "ls_internal.h"
+#include "ls_kws.h"
+#include "ls_expr.h"
+#include "ls_lex.h"
+
+// Standard headers
+#include <stdbool.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+
+// --- PRIVATE MACROS ----------------------------------------------------------
+// --- PRIVATE DATATYPES -------------------------------------------------------
+// --- PRIVATE CONSTANTS -------------------------------------------------------
+// --- PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+// --- PUBLIC VARIABLES --------------------------------------------------------
+// --- PRIVATE VARIABLES -------------------------------------------------------
+// --- PUBLIC FUNCTIONS --------------------------------------------------------
+
+void ls_kw_fun_FOR(ls_t * self)
+{
+ // FOR ident = a TO b [STEP c]
+ ls_value_t * ctx = ls_alloc(self);
+ *ctx = (ls_value_t) {
+ .ty = LS_TY_SCTX_FOR,
+ .body.sctx_for = {
+ .term = 0,
+ .step = 1,
+ .for_pc = LS_ADDR_NULL,
+ },
+ .prev = self->_callstack,
+ .next = NULL,
+ };
+ self->_callstack = ctx;
+
+ ls_value_t * iterator = ls_alloc(self);
+ *iterator = (ls_value_t) {
+ .ty = LS_TY_INT_VAR,
+ .body.int_var = {{0}},
+ };
+
+ ctx->next = iterator;
+
+ // FOR ident = a TO b [STEP c]
+ if (ls_lex(self) != LS_TOK_WORD)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+
+ strncpy(iterator->body.int_var.ident, self->_token.word, LS_IDENT_LEN);
+
+ if (ls_lex(self) != LS_OP_EQ)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+
+ ls_value_t val;
+ ls_eval_expr(self, &val, LS_TOK_NONE);
+ if (val.ty != LS_TY_INT)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+ iterator->body.int_var.value = val.body.integer.value;
+
+ if (ls_lex(self) != LS_KW_TO)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+
+ ls_eval_expr(self, &val, LS_TOK_NONE);
+ if (val.ty != LS_TY_INT)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+ ctx->body.sctx_for.term = val.body.integer.value;
+
+ ls_token_t tok = ls_lex(self);
+
+ if (tok == LS_KW_STEP)
+ {
+ ls_eval_expr(self, &val, LS_TOK_NONE);
+ if (val.ty != LS_TY_INT)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+
+ if (val.body.integer.value > INT16_MAX ||
+ val.body.integer.value < INT16_MIN)
+ ls_throw_err(self, LS_FOR_STEP_TOO_LARGE);
+
+ ctx->body.sctx_for.step = (int16_t) val.body.integer.value;
+ tok = ls_lex(self);
+ }
+
+ if (tok == LS_TOK_STATEMENT_SEP)
+ ctx->body.sctx_for.for_pc = self->_pc;
+ else
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+}
+
+void ls_kw_fun_NEXT(ls_t * self)
+{
+ if (self->_callstack->ty != LS_TY_SCTX_FOR)
+ ls_throw_err(self, LS_FOR_NEXT_MISMATCH);
+
+ ls_value_t * ctx = self->_callstack;
+ ls_value_t * iterator = ctx->next;
+ ls_int_t itval = iterator->body.int_var.value;
+ ls_int_t term = ctx->body.sctx_for.term;
+ ls_int_t step = (ls_int_t) ctx->body.sctx_for.step;
+
+ bool done = false;
+
+ if (step < 0)
+ {
+ if (itval <= term || (itval + step < term))
+ done = true;
+ }
+ else
+ {
+ if (itval >= term || (itval + step > term))
+ done = true;
+ }
+
+ if (done)
+ {
+ self->_callstack = ctx->prev;
+ ls_free_val(self, ctx);
+ ls_consume_to_eol(self);
+ }
+ else
+ {
+ self->_pc = ctx->body.sctx_for.for_pc;
+ itval += step;
+ iterator->body.int_var.value = itval;
+ }
+}
+
+void ls_kw_fun_WHILE(ls_t * self)
+{
+ ls_addr_t pc_cond = self->_pc;
+
+ ls_value_t cond;
+ ls_eval_expr(self, &cond, LS_TOK_NONE);
+
+ if (cond.ty != LS_TY_INT)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+
+ if (cond.body.integer.value != 0)
+ {
+ ls_value_t * ctx = ls_alloc(self);
+ *ctx = (ls_value_t) {
+ .ty = LS_TY_SCTX_WHILE,
+ .body.sctx_while = {
+ .while_pc = pc_cond,
+ },
+ .prev = self->_callstack,
+ .next = NULL,
+ };
+ self->_callstack = ctx;
+ }
+ else
+ {
+ bool keyword_allowed = false;
+ ls_token_t tok = LS_TOK_NUMBER;
+ int8_t nest = 0;
+
+ while (tok != LS_TOK_NONE)
+ {
+ tok = ls_lex(self);
+
+ if (keyword_allowed)
+ {
+ if (tok == LS_KW_WHILE)
+ nest++;
+ else if (tok == LS_KW_WEND)
+ if (nest)
+ nest--;
+ else
+ break;
+ else if (tok == LS_KW_REM)
+ {
+ ls_consume_to_eol(self);
+ continue; // keep keyword true
+ }
+ }
+
+ keyword_allowed =
+ tok == LS_TOK_STR_LABEL ||
+ tok == LS_TOK_NUM_LABEL ||
+ tok == LS_TOK_STATEMENT_SEP;
+ }
+
+ if (tok == LS_TOK_NONE)
+ {
+ self->_pc = pc_cond;
+ ls_throw_err(self, LS_WHILE_WEND_MISMATCH);
+ }
+ }
+}
+
+void ls_kw_fun_WEND(ls_t * self)
+{
+ if (self->_callstack->ty != LS_TY_SCTX_WHILE)
+ ls_throw_err(self, LS_WHILE_WEND_MISMATCH);
+
+ ls_addr_t pc_wend = self->_pc;
+ self->_pc = self->_callstack->body.sctx_while.while_pc;
+
+ ls_value_t cond;
+ ls_eval_expr(self, &cond, LS_TOK_NONE);
+
+ if (cond.ty != LS_TY_INT)
+ ls_throw_err(self, LS_SYNTAX_ERROR);
+
+ if (cond.body.integer.value == 0)
+ {
+ ls_value_t * ctx = self->_callstack;
+ self->_callstack = ctx->prev;
+ ls_free_val(self, ctx);
+ self->_pc = pc_wend;
+ }
+}
+
+// --- PRIVATE FUNCTION DEFINITIONS --------------------------------------------
diff --git a/src/ls_lex.c b/src/ls_lex.c
index e685f37..634bd0d 100644
--- a/src/ls_lex.c
+++ b/src/ls_lex.c
@@ -125,6 +125,18 @@ ls_token_t ls_lex(ls_t * self)
}
}
+void ls_consume_to_eol(ls_t * self)
+{
+ for (;;) {
+ ls_uchar uch = ls_fetch_rel(self, 0);
+
+ if (uch == 0 || uch == '\n')
+ return;
+
+ self->_pc++;
+ }
+}
+
// --- PRIVATE FUNCTION DEFINITIONS --------------------------------------------
static ch_kind_t _ident_ch_kind(unsigned char ch)
diff --git a/src/ls_lex.h b/src/ls_lex.h
index 0605986..9aa7b63 100644
--- a/src/ls_lex.h
+++ b/src/ls_lex.h
@@ -26,4 +26,7 @@
/// self->_token.
ls_token_t ls_lex(ls_t * self);
+/// Consume everything until the end of like (or end of stream)
+void ls_consume_to_eol(ls_t * self);
+
#endif // !defined(LS_LEX_H)