diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/build.h | 2 | ||||
| -rw-r--r-- | src/core/interpret.c | 101 | ||||
| -rw-r--r-- | src/core/token.c | 4 | ||||
| -rw-r--r-- | src/core/token.h | 2 |
4 files changed, 108 insertions, 1 deletions
diff --git a/src/build.h b/src/build.h index c3808f5..edfddfd 100644 --- a/src/build.h +++ b/src/build.h @@ -36,7 +36,7 @@ #ifndef BUILD_H #define BUILD_H -#define BUILDNR 9672 +#define BUILDNR 9674 #define OS_LINUX #endif diff --git a/src/core/interpret.c b/src/core/interpret.c index 0667148..f19dec4 100644 --- a/src/core/interpret.c +++ b/src/core/interpret.c @@ -630,6 +630,107 @@ _control(Interpret *p_interpret) { return (1); } break; + case TT_LOOP: + { + List *p_list_block = list_new(); + _NEXT + _block_get(p_interpret, p_list_block); + Token *p_token_backup = p_interpret->p_token; + + /* Run forever; break is the only exit, next restarts the body */ + for (;;) { + scope_up(p_interpret->p_scope); + interpret_subprocess(p_interpret, p_list_block); + scope_down(p_interpret->p_scope); + + if (p_interpret->ct == CONTROL_BREAK) { + p_interpret->ct = CONTROL_NONE; + break; + } else if (p_interpret->ct == CONTROL_NEXT) { + p_interpret->ct = CONTROL_NONE; + /* skip the rest of the body; re-run from the top */ + } + } + + list_delete(p_list_block); + p_interpret->p_token = p_token_backup; + p_interpret->tt = token_get_tt(p_token_backup); + return (1); + } + break; + case TT_DO: + { + /* do { body } while expr; or do { body } until expr; + * The body always executes at least once; the condition is evaluated + * at the bottom of each iteration (post-condition loop). */ + List *p_list_block = list_new(); + List *p_list_expr = list_new(); + + _NEXT + _block_get(p_interpret, p_list_block); /* leaves at 'while'/'until' */ + + Token *p_token = p_interpret->p_token; + TokenType tt = p_interpret->tt; + if (tt != TT_WHILE && tt != TT_UNTIL) + _INTERPRET_ERROR( + "Expected 'while' or 'until' after 'do' block", p_token); + + _NEXT /* past 'while' or 'until' */ + + /* Collect condition tokens until ';' — mirrors _expression_get but + * stops at semicolon instead of '{' since there is no block here */ + while (p_interpret->tt != TT_SEMICOLON + && p_interpret->tt != TT_NONE) { + list_add_back(p_list_expr, p_interpret->p_token); + _NEXT + } + _NEXT /* past ';' */ + Token *p_token_backup = p_interpret->p_token; /* after ';' */ + + _Bool b_flag = true; + do { + scope_up(p_interpret->p_scope); + interpret_subprocess(p_interpret, p_list_block); + scope_down(p_interpret->p_scope); + + /* Handle break/next before re-evaluating the condition */ + if (p_interpret->ct == CONTROL_BREAK) { + p_interpret->ct = CONTROL_NONE; + b_flag = false; + continue; + } else if (p_interpret->ct == CONTROL_NEXT) { + p_interpret->ct = CONTROL_NONE; + /* fall through to condition check */ + } + + /* Re-evaluate condition using a temp stack/iterator over + * p_list_expr, exactly as the while/until loop does */ + Stack *p_stack_backup = p_interpret->p_stack; + p_interpret->p_stack = stack_new(); + ListIterator *p_iter_backup = p_interpret->p_iter; + p_interpret->p_iter = listiterator_new(p_list_expr); + _NEXT + + if (_expression_(p_interpret)) { + Token *p_token_top = stack_pop(p_interpret->p_stack); + int i_val = convert_to_integer_get(p_token_top); + b_flag = (tt == TT_WHILE) ? (i_val != 0) : (i_val == 0); + } + + listiterator_delete(p_interpret->p_iter); + p_interpret->p_iter = p_iter_backup; + stack_delete(p_interpret->p_stack); + p_interpret->p_stack = p_stack_backup; + + } while (b_flag); + + list_delete(p_list_block); + list_delete(p_list_expr); + p_interpret->p_token = p_token_backup; + p_interpret->tt = token_get_tt(p_token_backup); + return (1); + } + break; NO_DEFAULT; } diff --git a/src/core/token.c b/src/core/token.c index e8a6d9b..ea72a82 100644 --- a/src/core/token.c +++ b/src/core/token.c @@ -51,6 +51,8 @@ get_tt(char *c_token) { CHECK("until") TT_UNTIL; CHECK("int") TT_INT; CHECK("next") TT_NEXT; + CHECK("loop") TT_LOOP; + CHECK("do") TT_DO; CHECK("defined") TT_DEFINED; CHECK("undef") TT_UNDEF; CHECK("syms") TT_SYMS; @@ -130,6 +132,8 @@ tt_get_name(TokenType tt_cur) { CASE(TT_WHILE,"TT_WHILE") CASE(TT_UNTIL,"TT_UNTIL") CASE(TT_NEXT,"TT_NEXT") + CASE(TT_LOOP,"TT_LOOP") + CASE(TT_DO,"TT_DO") CASE(TT_DEFINED,"TT_DEFINED") CASE(TT_UNDEF,"TT_UNDEF") CASE(TT_SYMS,"TT_SYMS") diff --git a/src/core/token.h b/src/core/token.h index cb41335..1660e7b 100644 --- a/src/core/token.h +++ b/src/core/token.h @@ -109,6 +109,8 @@ typedef enum { TT_WHILE, TT_UNTIL, TT_NEXT, + TT_LOOP, + TT_DO, TT_INT, TT_DEFINED, TT_UNDEF, |
