diff options
author | Gavin Howard <gavin@yzena.com> | 2021-07-20 23:47:47 -0600 |
---|---|---|
committer | Gavin Howard <gavin@yzena.com> | 2021-07-20 23:49:27 -0600 |
commit | f4e36d5707c0857f1761b85b4187c1c2d85c1771 (patch) | |
tree | bfefa0458ac4052fac21a5df35a4a50ab3d61a97 /src | |
parent | e9f2581d6c5021d9bc5136e2053cab0171174501 (diff) | |
download | platform_external_bc-f4e36d5707c0857f1761b85b4187c1c2d85c1771.tar.gz platform_external_bc-f4e36d5707c0857f1761b85b4187c1c2d85c1771.tar.bz2 platform_external_bc-f4e36d5707c0857f1761b85b4187c1c2d85c1771.zip |
Change the keyword redefinition infrastructure
This changes it to use a command-line option. This is best because if a
user encounters a problem; they *know* they are using my bc and can add
the command-line option.
This is also better because it allows the keyword to be used as variable
and array names as well as function names, without editing the script.
This has the double advantage that I can undo the change to the parser,
though I need to keep the one line change to the lexer.
The option is `-r` and `--redefine`, and they take an argument, which is
the keyword to redefine.
All docs and tests have been updated.
Signed-off-by: Gavin Howard <gavin@yzena.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/args.c | 36 | ||||
-rw-r--r-- | src/bc_lex.c | 5 | ||||
-rw-r--r-- | src/bc_parse.c | 42 | ||||
-rw-r--r-- | src/data.c | 1 | ||||
-rw-r--r-- | src/opt.c | 15 | ||||
-rw-r--r-- | src/vm.c | 5 |
6 files changed, 54 insertions, 50 deletions
@@ -80,6 +80,36 @@ static void bc_args_file(const char *file) { free(buf); } +#if BC_ENABLED + +/** + * Redefines a keyword, if it exists and is not a POSIX keyword. Otherwise, it + * throws a fatal error. + * @param keyword The keyword to redefine. + */ +static void bc_args_redefine(const char *keyword) { + + size_t i; + + for (i = 0; i < bc_lex_kws_len; ++i) { + + const BcLexKeyword *kw = bc_lex_kws + i; + + if (!strcmp(keyword, kw->name)) { + + if (BC_LEX_KW_POSIX(kw)) break; + + vm.redefined_kws[i] = true; + + return; + } + } + + bc_error(BC_ERR_FATAL_OPTION, 0, keyword); +} + +#endif // BC_ENABLED + void bc_args(int argc, char *argv[], bool exit_exprs) { int c; @@ -175,6 +205,12 @@ void bc_args(int argc, char *argv[], bool exit_exprs) { break; } + case 'r': + { + bc_args_redefine(opts.optarg); + break; + } + case 's': { assert(BC_IS_BC); diff --git a/src/bc_lex.c b/src/bc_lex.c index 717e7f04..c33052de 100644 --- a/src/bc_lex.c +++ b/src/bc_lex.c @@ -64,14 +64,13 @@ static void bc_lex_identifier(BcLex *l) { // If the keyword has been redefined, break out of the loop and use // it as a name. This depends on the parser ensuring that only // non-POSIX keywords get redefined. - if (BC_REDEFINE && vm.redefined_kws[i]) break; + if (vm.redefined_kws[i]) break; l->t = BC_LEX_KW_AUTO + (BcLexType) i; // Warn or error, as appropriate for the mode, if the keyword is not // in the POSIX standard. - if (!BC_LEX_KW_POSIX(kw)) - bc_lex_verr(l, BC_ERR_POSIX_KW, kw->name); + if (!BC_LEX_KW_POSIX(kw)) bc_lex_verr(l, BC_ERR_POSIX_KW, kw->name); // We minus 1 because the index has already been incremented. l->i += n - 1; diff --git a/src/bc_parse.c b/src/bc_parse.c index 70d982f5..30946ad5 100644 --- a/src/bc_parse.c +++ b/src/bc_parse.c @@ -1144,41 +1144,6 @@ static void bc_parse_loopExit(BcParse *p, BcLexType type) { } /** - * Redefines a keyword, if necessary. - * @param p The parser. - */ -static void bc_parse_redefineKeyword(BcParse *p) { - - // Must have a name, or a keyword that is going to be redefined. - if (BC_ERR(p->l.t != BC_LEX_NAME)) { - - if (BC_REDEFINE && BC_PARSE_IS_KEYWORD(p->l.t)) { - - size_t idx = p->l.t - BC_LEX_KW_AUTO; - const BcLexKeyword *kw = bc_lex_kws + idx; - - // If this is true, the keyword can be redefined. We don't allow - // redefining POSIX keywords because that would be a disaster. - if (!vm.redefined_kws[idx] && !BC_LEX_KW_POSIX(kw)) { - - vm.redefined_kws[idx] = true; - - // Set the token to BC_LEX_NAME because bc_parse_func() is - // expecting that. - p->l.t = BC_LEX_NAME; - - // Set the lexer's string to the name of the keyword to be used - // later in bc_parse_func(). I mean, the function *has* to have - // a name... - bc_vec_string(&p->l.str, BC_LEX_KW_LEN(kw), kw->name); - } - else bc_parse_err(p, BC_ERR_PARSE_FUNC); - } - else bc_parse_err(p, BC_ERR_PARSE_FUNC); - } -} - -/** * Parse a function (header). * @param p The parser. */ @@ -1190,8 +1155,8 @@ static void bc_parse_func(BcParse *p) { bc_lex_next(&p->l); - // Check for keyword redefinition. - bc_parse_redefineKeyword(p); + // Must have a name. + if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC); // If the name is "void", and POSIX is not on, mark as void. voidfn = (!BC_IS_POSIX && p->l.t == BC_LEX_NAME && @@ -1201,9 +1166,6 @@ static void bc_parse_func(BcParse *p) { // function name. bc_lex_next(&p->l); - // Check for keyword redefinition. - if (voidfn && p->l.t != BC_LEX_LPAREN) bc_parse_redefineKeyword(p); - // If we *don't* have another name, then void is the name of the function. voidfn = (voidfn && p->l.t == BC_LEX_NAME); @@ -145,6 +145,7 @@ const BcOptLong bc_args_lopt[] = { { "global-stacks", BC_OPT_BC_ONLY, 'g' }, { "mathlib", BC_OPT_BC_ONLY, 'l' }, { "quiet", BC_OPT_BC_ONLY, 'q' }, + { "redefine", BC_OPT_REQUIRED_BC_ONLY, 'r' }, { "standard", BC_OPT_BC_ONLY, 's' }, { "warn", BC_OPT_BC_ONLY, 'w' }, #endif // BC_ENABLED @@ -184,6 +184,15 @@ static int bc_opt_parseShort(BcOpt *o, const BcOptLong *longopts) { break; } + case BC_OPT_REQUIRED_BC_ONLY: + { + if (BC_IS_DC) + bc_opt_error(BC_ERR_FATAL_OPTION, option[0], + bc_opt_longopt(longopts, option[0]), true); + } + // Fallthrough + BC_FALLTHROUGH + case BC_OPT_REQUIRED: { // Always go to the next argument. @@ -303,6 +312,7 @@ int bc_opt_parse(BcOpt *o, const BcOptLong *longopts) { // Error if the option is invalid.. if ((longopts[i].type == BC_OPT_BC_ONLY && BC_IS_DC) || + (longopts[i].type == BC_OPT_REQUIRED_BC_ONLY && BC_IS_DC) || (longopts[i].type == BC_OPT_DC_ONLY && BC_IS_BC)) { bc_opt_error(BC_ERR_FATAL_OPTION, o->optopt, name, false); @@ -317,8 +327,9 @@ int bc_opt_parse(BcOpt *o, const BcOptLong *longopts) { // Set the argument, or check the next argument if we don't have // one. if (arg != NULL) o->optarg = arg; - else if (longopts[i].type == BC_OPT_REQUIRED) { - + else if (longopts[i].type == BC_OPT_REQUIRED || + longopts[i].type == BC_OPT_REQUIRED_BC_ONLY) + { // Get the next argument. o->optarg = o->argv[o->optind]; @@ -1376,13 +1376,8 @@ void bc_vm_boot(int argc, char *argv[]) { } #if BC_ENABLED - // Disable global stacks in POSIX mode. if (BC_IS_POSIX) vm.flags &= ~(BC_FLAG_G); - - bc_vm_setenvFlag("BC_REDEFINE_KEYWORDS", BC_DEFAULT_REDEFINE_KEYWORDS, - BC_FLAG_REDEFINE_KWS); - #endif // BC_ENABLED #if BC_ENABLED |