diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/ls_kw_impl.c | 216 | ||||
-rw-r--r-- | src/ls_kw_impl_LOOPS.c | 221 | ||||
-rw-r--r-- | src/ls_lex.c | 12 | ||||
-rw-r--r-- | src/ls_lex.h | 3 |
5 files changed, 239 insertions, 215 deletions
@@ -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) |