aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGavin Howard <gavin@yzena.com>2021-07-20 23:47:47 -0600
committerGavin Howard <gavin@yzena.com>2021-07-20 23:49:27 -0600
commitf4e36d5707c0857f1761b85b4187c1c2d85c1771 (patch)
treebfefa0458ac4052fac21a5df35a4a50ab3d61a97 /src
parente9f2581d6c5021d9bc5136e2053cab0171174501 (diff)
downloadplatform_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.c36
-rw-r--r--src/bc_lex.c5
-rw-r--r--src/bc_parse.c42
-rw-r--r--src/data.c1
-rw-r--r--src/opt.c15
-rw-r--r--src/vm.c5
6 files changed, 54 insertions, 50 deletions
diff --git a/src/args.c b/src/args.c
index f07c5be6..eb12688f 100644
--- a/src/args.c
+++ b/src/args.c
@@ -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);
diff --git a/src/data.c b/src/data.c
index ab980b13..e2461b13 100644
--- a/src/data.c
+++ b/src/data.c
@@ -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
diff --git a/src/opt.c b/src/opt.c
index 6fb61574..ddc78362 100644
--- a/src/opt.c
+++ b/src/opt.c
@@ -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];
diff --git a/src/vm.c b/src/vm.c
index ea5e4f25..695306d8 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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