From 69e725cf694e3b5a06196feead70c7cfea1caf3a Mon Sep 17 00:00:00 2001 From: Evgeny Stepanischev Date: Thu, 17 Jul 2025 22:32:33 +0300 Subject: [PATCH] Added stack directive and global_pop function --- include/bc.h | 4 ++-- include/lang.h | 6 +++++ include/lex.h | 3 +++ include/parse.h | 3 +++ include/program.h | 4 +++- include/status.h | 3 +++ src/bc_parse.c | 56 +++++++++++++++++++++++++++++++---------------- src/data.c | 1 + src/lang.c | 1 + src/program.c | 35 ++++++++++++++++++++++++----- 10 files changed, 89 insertions(+), 27 deletions(-) diff --git a/include/bc.h b/include/bc.h index 670e9732..416877e9 100644 --- a/include/bc.h +++ b/include/bc.h @@ -96,13 +96,13 @@ typedef struct BcLexKeyword /// A macro for the number of keywords bc has. This has to be updated if any are /// added. This is for the redefined_kws field of the BcVm struct. -#define BC_LEX_NKWS (37) +#define BC_LEX_NKWS (38) #else // BC_ENABLE_EXTRA_MATH /// A macro for the number of keywords bc has. This has to be updated if any are /// added. This is for the redefined_kws field of the BcVm struct. -#define BC_LEX_NKWS (33) +#define BC_LEX_NKWS (34) #endif // BC_ENABLE_EXTRA_MATH diff --git a/include/lang.h b/include/lang.h index d0582a7d..c9ca088b 100644 --- a/include/lang.h +++ b/include/lang.h @@ -328,6 +328,9 @@ typedef enum BcInst #endif // DC_ENABLED + /// Pop the global stacks. + BC_INST_GLOBAL_POP, + /// Invalid instruction. BC_INST_INVALID, @@ -409,6 +412,9 @@ typedef struct BcFunc #if BC_ENABLED /// True if the function is a void function. bool voidfn; + + /// True if the function is a stack function (uses global stacks). + bool stackfn; #endif // BC_ENABLED } BcFunc; diff --git a/include/lex.h b/include/lex.h index 5f97a473..48282e31 100644 --- a/include/lex.h +++ b/include/lex.h @@ -407,6 +407,9 @@ typedef enum BcLexType /// bc else keyword. BC_LEX_KW_ELSE, + /// bc GLOBAL_POP keyword. + BC_LEX_KW_GLOBAL_POP, + #if DC_ENABLED /// dc extended registers keyword. diff --git a/include/parse.h b/include/parse.h index e39ea09a..d332489a 100644 --- a/include/parse.h +++ b/include/parse.h @@ -201,6 +201,9 @@ typedef struct BcParse /// True if the bc parser just entered a function and an auto statement /// would be valid. bool auto_part; + + /// True if the bc parser is in a stack function. + bool stackfn; #endif // BC_ENABLED } BcParse; diff --git a/include/program.h b/include/program.h index 17454057..00aa0aa7 100644 --- a/include/program.h +++ b/include/program.h @@ -631,6 +631,7 @@ extern const char bc_program_esc_seqs[]; &&lbl_BC_INST_QUIT, \ &&lbl_BC_INST_NQUIT, \ &&lbl_BC_INST_EXEC_STACK_LEN, \ + &&lbl_BC_INST_GLOBAL_POP, \ &&lbl_BC_INST_INVALID, \ } @@ -822,6 +823,7 @@ extern const char bc_program_esc_seqs[]; &&lbl_BC_INST_MODEXP, \ &&lbl_BC_INST_DIVMOD, \ &&lbl_BC_INST_PRINT_STREAM, \ + &&lbl_BC_INST_GLOBAL_POP, \ &&lbl_BC_INST_INVALID, \ } @@ -949,7 +951,7 @@ extern const char bc_program_esc_seqs[]; &&lbl_BC_INST_LOAD, &&lbl_BC_INST_PUSH_VAR, \ &&lbl_BC_INST_PUSH_TO_VAR, &&lbl_BC_INST_QUIT, \ &&lbl_BC_INST_NQUIT, &&lbl_BC_INST_EXEC_STACK_LEN, \ - &&lbl_BC_INST_INVALID, \ + &&lbl_BC_INST_GLOBAL_POP, &&lbl_BC_INST_INVALID, \ } #else // BC_ENABLE_EXTRA_MATH diff --git a/include/status.h b/include/status.h index 8e3ab9ed..84ee193b 100644 --- a/include/status.h +++ b/include/status.h @@ -595,6 +595,9 @@ typedef enum BcErr /// Non-POSIX void error. BC_ERR_POSIX_VOID, + /// Non-POSIX stack error. + BC_ERR_POSIX_STACK, + /// Non-POSIX brace position used error. BC_ERR_POSIX_BRACE, diff --git a/src/bc_parse.c b/src/bc_parse.c index f66e392a..3c3da4b7 100644 --- a/src/bc_parse.c +++ b/src/bc_parse.c @@ -1369,36 +1369,40 @@ bc_parse_loopExit(BcParse* p, BcLexType type) static void bc_parse_func(BcParse* p) { - bool comma = false, voidfn; + bool comma = false, voidfn, stackfn; uint16_t flags; size_t idx; bc_lex_next(&p->l); - // Must have a name. - if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC); + voidfn = stackfn = false; + + while (p->l.t == BC_LEX_NAME) + { + if (!strcmp(p->l.str.v, "void")) + { + if (BC_IS_POSIX) bc_parse_err(p, BC_ERR_POSIX_VOID); + if (BC_ERR(voidfn)) bc_parse_err(p, BC_ERR_PARSE_FUNC); // Duplicate void + voidfn = true; + bc_lex_next(&p->l); + } + else if (!strcmp(p->l.str.v, "stack")) + { + if (BC_IS_POSIX) bc_parse_err(p, BC_ERR_POSIX_STACK); + if (BC_ERR(stackfn)) bc_parse_err(p, BC_ERR_PARSE_FUNC); // Duplicate stack + stackfn = true; + bc_lex_next(&p->l); + } + else break; // Not a function type keyword, must be function name + } - // If the name is "void", and POSIX is not on, mark as void. - voidfn = (!BC_IS_POSIX && p->l.t == BC_LEX_NAME && - !strcmp(p->l.str.v, "void")); + // Must have a function name. + if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC); // We can safely do this because the expected token should not overwrite the // function name. bc_lex_next(&p->l); - // If we *don't* have another name, then void is the name of the function. - voidfn = (voidfn && p->l.t == BC_LEX_NAME); - - // With a void function, allow POSIX to complain and get a new token. - if (voidfn) - { - bc_parse_err(p, BC_ERR_POSIX_VOID); - - // We can safely do this because the expected token should not overwrite - // the function name. - bc_lex_next(&p->l); - } - // Must have a left paren. if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_FUNC); @@ -1414,6 +1418,7 @@ bc_parse_func(BcParse* p) // Update the function pointer and stuff in the parser and set its void. bc_parse_updateFunc(p, idx); p->func->voidfn = voidfn; + p->func->stackfn = stackfn; bc_lex_next(&p->l); @@ -1821,6 +1826,17 @@ bc_parse_stmt(BcParse* p) break; } + case BC_LEX_KW_GLOBAL_POP: + { + bc_lex_next(&p->l); + if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); + bc_lex_next(&p->l); + if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); + bc_lex_next(&p->l); + bc_parse_push(p, BC_INST_GLOBAL_POP); + break; + } + case BC_LEX_KW_QUIT: { // Quit is a compile-time command. We don't exit directly, so the vm @@ -2393,6 +2409,8 @@ bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next) break; } + + case BC_LEX_KW_SCALE: { // This is a leaf and cannot come right after a leaf. diff --git a/src/data.c b/src/data.c index 15a114c2..5537803a 100644 --- a/src/data.c +++ b/src/data.c @@ -895,6 +895,7 @@ const BcLexKeyword bc_lex_kws[] = { BC_LEX_KW_ENTRY("leading_zero", 12, false), BC_LEX_KW_ENTRY("stream", 6, false), BC_LEX_KW_ENTRY("else", 4, false), + BC_LEX_KW_ENTRY("global_pop", 11, false), }; /// The length of the list of bc keywords. diff --git a/src/lang.c b/src/lang.c index 2a62509c..7c2115e8 100644 --- a/src/lang.c +++ b/src/lang.c @@ -110,6 +110,7 @@ bc_func_init(BcFunc* f, const char* name) f->nparams = 0; f->voidfn = false; + f->stackfn = BC_G; } #endif // BC_ENABLED diff --git a/src/program.c b/src/program.c index af032c5f..a6b1c529 100644 --- a/src/program.c +++ b/src/program.c @@ -809,7 +809,7 @@ bc_program_read(BcProgram* p) #if BC_ENABLED // Push on the globals stack if necessary. - if (BC_G) bc_program_prepGlobals(p); + if (f->stackfn) bc_program_prepGlobals(p); #endif // BC_ENABLED // Set up a new BcInstPtr. @@ -1814,7 +1814,7 @@ bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn) assert(BC_PROG_STACK(&p->results, nargs)); // Prepare the globals' stacks. - if (BC_G) bc_program_prepGlobals(p); + if (f->stackfn) bc_program_prepGlobals(p); // Push the arguments onto the stacks of their respective parameters. for (i = 0; i < nargs; ++i) @@ -1949,7 +1949,7 @@ bc_program_return(BcProgram* p, uchar inst) bc_program_retire(p, nresults); // Pop the globals, if necessary. - if (BC_G) bc_program_popGlobals(p, false); + if (f->stackfn) bc_program_popGlobals(p, false); // Pop the stack. This is what causes the function to actually "return." bc_vec_pop(&p->stack); @@ -2731,7 +2731,15 @@ bc_program_globalSetting(BcProgram* p, uchar inst) #if BC_ENABLED else if (inst == BC_INST_GLOBAL_STACKS) { - val = (BC_G != 0); + if (p->stack.len > 0) + { + BcInstPtr* ip = bc_vec_top(&p->stack); + val = ((BcFunc*) bc_vec_item(&p->fns, ip->func))->stackfn || (BC_G != 0); + } + else + { + val = (BC_G != 0); + } } #endif // BC_ENABLED #if DC_ENABLED @@ -3028,7 +3036,7 @@ bc_program_reset(BcProgram* p) #if BC_ENABLED // Clear the globals' stacks. - if (BC_G) bc_program_popGlobals(p, true); + if (f->stackfn) bc_program_popGlobals(p, true); #endif // BC_ENABLED // Clear the bytecode vector of the main function. @@ -3507,6 +3515,23 @@ bc_program_exec(BcProgram* p) BC_PROG_JUMP(inst, code, ip); } + BC_PROG_LBL(BC_INST_GLOBAL_POP): + // clang-format on + { + if (p->stack.len > 0) + { + BcInstPtr* ip = bc_vec_top(&p->stack); + BcFunc* f = bc_vec_item(&p->fns, ip->func); + + if (f->stackfn) + { + bc_program_popGlobals(p, false); + bc_program_prepGlobals(p); + } + } + BC_PROG_JUMP(inst, code, ip); + } + // clang-format off BC_PROG_LBL(BC_INST_POP): // clang-format on