aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Eßer <se@FreeBSD.org>2023-01-28 19:59:18 +0000
committerStefan Eßer <se@FreeBSD.org>2023-01-28 19:59:18 +0000
commit0b671e8cf134e605567a6b8091958c1f1dfc5140 (patch)
treee17587523032ecead9edbb65df0136e1d0d09a38
parent9471e6a0958eaea36dd38589b6a5d186e5a1fbf9 (diff)
vendor/bc: import version 6.1.0vendor/bc/6.1.0
This is a production release that fixes a discrepancy from the bc standard, a couple of memory bugs, and adds new features. The discrepancy from the bc standard was with regards to the behavior of the quit command. This bc used to quit whenever it encountered quit during parsing, even if it was parsing a full file. Now, bc only quits when encountering quit after it has executed all executable statements up to that point. This behavior is slightly different from GNU bc, but users will only notice the difference if they put quit on the same line as other statements. The first memory bug could be reproduced by assigning a string to a non-local variable in a function, then redefining the function with use of the same non-local variable, which would still refer to a string in the previous version of the function. The second memory bug was caused by passing an array argument to the asciify() built-in function. In certain cases, that was wrongly allowed, and the interpreter just assumed everything was correct and accessed memory. Now that arrays are allowed as arguments (see below), this is not an issue. The first feature was the addition of the is_number() built-in function (u in dc) that returns 1 if the runtime argument is a number and 0 otherwise. The second feature was the addition of the is_string() built-in function (t in dc) that returns 1 if the runtime argument is a string and 0 otherwise. These features were added because I realized that type-checking is necessary now that strings can be assigned to variables in bc and because they've always been assignable to variables in dc. The last added feature is the ability of the asciify() built-in function in bc to convert a full array of numbers into a string. This means that character-by-character printing will not be necessary, and more strings than just single-character ones will be able to be created.
-rw-r--r--MEMORY_BUGS.md47
-rw-r--r--NEWS.md39
-rw-r--r--README.md4
-rw-r--r--TODO.md3
-rwxr-xr-xconfigure.sh43
-rw-r--r--include/bc.h4
-rw-r--r--include/lang.h19
-rw-r--r--include/lex.h26
-rw-r--r--include/parse.h24
-rw-r--r--include/program.h50
-rw-r--r--include/status.h16
-rw-r--r--include/vector.h24
-rw-r--r--include/version.h2
-rw-r--r--include/vm.h27
-rw-r--r--manuals/bc/A.174
-rw-r--r--manuals/bc/A.1.md58
-rw-r--r--manuals/bc/E.168
-rw-r--r--manuals/bc/E.1.md52
-rw-r--r--manuals/bc/EH.168
-rw-r--r--manuals/bc/EH.1.md52
-rw-r--r--manuals/bc/EHN.168
-rw-r--r--manuals/bc/EHN.1.md52
-rw-r--r--manuals/bc/EN.168
-rw-r--r--manuals/bc/EN.1.md52
-rw-r--r--manuals/bc/H.174
-rw-r--r--manuals/bc/H.1.md58
-rw-r--r--manuals/bc/HN.174
-rw-r--r--manuals/bc/HN.1.md58
-rw-r--r--manuals/bc/N.174
-rw-r--r--manuals/bc/N.1.md58
-rw-r--r--manuals/bcl.32
-rw-r--r--manuals/dc/A.126
-rw-r--r--manuals/dc/A.1.md18
-rw-r--r--manuals/dc/E.126
-rw-r--r--manuals/dc/E.1.md18
-rw-r--r--manuals/dc/EH.126
-rw-r--r--manuals/dc/EH.1.md18
-rw-r--r--manuals/dc/EHN.126
-rw-r--r--manuals/dc/EHN.1.md18
-rw-r--r--manuals/dc/EN.126
-rw-r--r--manuals/dc/EN.1.md18
-rw-r--r--manuals/dc/H.126
-rw-r--r--manuals/dc/H.1.md18
-rw-r--r--manuals/dc/HN.126
-rw-r--r--manuals/dc/HN.1.md18
-rw-r--r--manuals/dc/N.126
-rw-r--r--manuals/dc/N.1.md18
-rw-r--r--src/bc_lex.c4
-rw-r--r--src/bc_parse.c47
-rw-r--r--src/data.c34
-rw-r--r--src/dc_lex.c10
-rw-r--r--src/dc_parse.c2
-rw-r--r--src/lang.c12
-rw-r--r--src/lex.c43
-rw-r--r--src/num.c2
-rw-r--r--src/parse.c54
-rw-r--r--src/program.c253
-rw-r--r--src/vector.c15
-rw-r--r--src/vm.c100
-rw-r--r--tests/bc/all.txt7
-rw-r--r--tests/bc/asciify_array.txt17
-rw-r--r--tests/bc/asciify_array_results.txt3
-rw-r--r--tests/bc/errors/34.txt357
-rw-r--r--tests/bc/errors/35.txt1
-rw-r--r--tests/bc/errors/36.txt11
-rw-r--r--tests/bc/is_number.txt13
-rw-r--r--tests/bc/is_number_results.txt10
-rw-r--r--tests/bc/is_string.txt13
-rw-r--r--tests/bc/is_string_results.txt10
-rw-r--r--tests/bc/line_by_line1.txt10
-rw-r--r--tests/bc/line_by_line1_results.txt1
-rw-r--r--tests/bc/line_by_line2.txt9
-rw-r--r--tests/bc/line_by_line2_results.txt3
-rw-r--r--tests/bc/line_loop_quit1.txt2
-rw-r--r--tests/bc/line_loop_quit1_results.txt4
-rw-r--r--tests/bc/line_loop_quit2.txt3
-rw-r--r--tests/bc/line_loop_quit2_results.txt4
-rw-r--r--tests/bc/scripts/afl1.bc261
-rw-r--r--tests/bc/scripts/afl1.txt1571
-rw-r--r--tests/bc/scripts/all.txt1
-rw-r--r--tests/dc/all.txt3
-rw-r--r--tests/dc/errors/15.txt128
-rw-r--r--tests/dc/errors/34.txt117
-rw-r--r--tests/dc/is_number.txt9
-rw-r--r--tests/dc/is_number_results.txt9
-rw-r--r--tests/dc/is_string.txt9
-rw-r--r--tests/dc/is_string_results.txt9
-rw-r--r--tests/dc/misc1.txt26
-rw-r--r--tests/dc/misc1_results.txt21
-rwxr-xr-xtests/other.sh2
90 files changed, 4178 insertions, 732 deletions
diff --git a/MEMORY_BUGS.md b/MEMORY_BUGS.md
new file mode 100644
index 000000000000..894593f84925
--- /dev/null
+++ b/MEMORY_BUGS.md
@@ -0,0 +1,47 @@
+# Memory Bugs
+
+This is a list of all of the memory bugs that were found in *released* versions
+of `bc`, `dc`, or `bcl`. (Non-released commits with memory bugs do not count.)
+
+I made this list for two reasons: first, so users can know what versions of
+`bc`, `dc`, and `bcl` have vulnerabilities, and two, I once had a perfect record
+and then found a couple, but forgot and claimed I still had a perfect record
+right after, which was embarrassing.
+
+This list is sorted by the first version a bug exists in, not the last it
+existed in.
+
+* In versions `3.0.0` until `6.0.1` (inclusive) of `bc` and `dc`, there is a
+ double-free on `SIGINT` when using command-line expressions with `-e` and
+ `-f`. This was caused by not properly ending a jump series.
+
+ The first version without this bug is `6.0.2`.
+
+* In versions `5.0.0` until `6.0.4` (inclusive) of `bc`, there is an
+ out-of-bounds access if a non-local (non-`auto`) variable is set to a string
+ with `asciify()`, then the function is redefined with a use of the same
+ non-local variable.
+
+ This happened because strings were stored per-function, and the non-local
+ variable now had a reference to the string in the old function, which could be
+ at a higher index than exists in the new function. Strings are stored globally
+ now, and they are *not* freed once not used.
+
+ The first version without this bug is `6.1.0`.
+
+* In versions `5.0.0` until `6.0.4` (inclusive) of `bc`, there is another
+ out-of-bounds access if an array is passed to the `asciify()` built-in
+ function as the only argument. This happened because arrays are allowed as
+ function arguments, which allowed them to be used as arguments to `asciify()`,
+ but they should not have been allowed. However, since they were, the
+ `asciify()` code tried to access an argument that was not there.
+
+ The first version without this bug is `6.1.0`.
+
+* In version `6.0.0` of `bcl`, there is several use of initialized data that
+ have the same root cause: I forgot to call `memset()` on the per-thread global
+ data. This is because the data used to be *actually* global, which meant that
+ it was initialized to zero by the system. This happened because I thought I
+ had properly hooked Valgrind into my `bcl` tests, but I had not.
+
+ The first version without this bug is `6.0.1`.
diff --git a/NEWS.md b/NEWS.md
index 33ed7b9c25e2..cde55831a8dd 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,44 @@
# News
+## 6.1.0
+
+This is a production release that fixes a discrepancy from the `bc` standard,
+a couple of memory bugs, and adds new features.
+
+The discrepancy from the `bc` standard was with regards to the behavior of the
+`quit` command. This `bc` used to quit whenever it encountered `quit` during
+parsing, even if it was parsing a full file. Now, `bc` only quits when
+encountering `quit` *after* it has executed all executable statements up to that
+point.
+
+This behavior is slightly different from GNU `bc`, but users will only notice
+the difference if they put `quit` on the same line as other statements.
+
+The first memory bug could be reproduced by assigning a string to a non-local
+variable in a function, then redefining the function with use of the same
+non-local variable, which would still refer to a string in the previous version
+of the function.
+
+The second memory bug was caused by passing an array argument to the `asciify()`
+built-in function. In certain cases, that was wrongly allowed, and the
+interpreter just assumed everything was correct and accessed memory. Now that
+arrays are allowed as arguments (see below), this is not an issue.
+
+The first feature was the addition of the `is_number()` built-in function (`u`
+in `dc`) that returns 1 if the runtime argument is a number and 0 otherwise.
+
+The second feature was the addition of the `is_string()` built-in function (`t`
+in `dc`) that returns 1 if the runtime argument is a string and 0 otherwise.
+
+These features were added because I realized that type-checking is necessary now
+that strings can be assigned to variables in `bc` and because they've always
+been assignable to variables in `dc`.
+
+The last added feature is the ability of the `asciify()` built-in function in
+`bc` to convert a full array of numbers into a string. This means that
+character-by-character printing will not be necessary, and more strings than
+just single-character ones will be able to be created.
+
## 6.0.4
This is a production release that most users will not need to upgrade to.
diff --git a/README.md b/README.md
index 64c58410162c..b1e0d7557de4 100644
--- a/README.md
+++ b/README.md
@@ -171,8 +171,8 @@ other locations, use the `PREFIX` environment variable when running
#### Library
-This `bc` does provide a way to build a math library with C bindings. This is
-done by the `-a` or `--library` options to `configure.sh`:
+To build the math library, pass the `-a` or `--library` options to
+`configure.sh`:
```
./configure.sh -a
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 000000000000..9152548085b4
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,3 @@
+# TODO
+
+* Implement the more efficient factorial.
diff --git a/configure.sh b/configure.sh
index e82c21817a6c..fb22ccab299e 100755
--- a/configure.sh
+++ b/configure.sh
@@ -153,8 +153,9 @@ usage() {
printf ' quotes) This option *must* come before any others that might change the\n'
printf ' build options. Currently supported values for TYPE include: "BSD" (for\n'
printf ' matching the BSD bc and BSD dc), "GNU" (for matching the GNU bc and\n'
- printf ' dc), and "GDH" (for the preferred build of the author, Gavin D. Howard).\n'
- printf ' This will also automatically enable a release build.\n'
+ printf ' dc), "GDH" (for the preferred build of the author, Gavin D. Howard),\n'
+ printf ' and "DBG" (for the preferred debug build of the author). This will\n'
+ printf ' also automatically enable a release build (except for "DBG").\n'
printf ' -P, --disable-problematic-tests\n'
printf ' Disables problematic tests. These tests usually include tests that\n'
printf ' can cause a SIGKILL because of too much memory usage.\n'
@@ -771,7 +772,7 @@ predefined_build() {
dc_default_digit_clamp=0;;
GDH)
- CFLAGS="-flto -Weverything -Wno-padded -Wno-gnu-label-as-value -Werror -pedantic -std=c11"
+ CFLAGS="-flto -Weverything -Wno-padded -Werror -pedantic -std=c11"
bc_only=0
dc_only=0
coverage=0
@@ -804,7 +805,41 @@ predefined_build() {
bc_default_digit_clamp=1
dc_default_digit_clamp=1;;
- ?|'') usage "Invalid user build: \"$_predefined_build_type\". Accepted types are BSD, GNU, and GDH.";;
+ DBG)
+ CFLAGS="-Weverything -Wno-padded -Werror -pedantic -std=c11"
+ bc_only=0
+ dc_only=0
+ coverage=0
+ debug=1
+ optimization="0"
+ hist=1
+ hist_impl="internal"
+ extra_math=1
+ generate_tests=1
+ install_manpages=1
+ nls=1
+ force=0
+ strip_bin=1
+ all_locales=0
+ library=0
+ fuzz=0
+ time_tests=0
+ vg=0
+ memcheck=1
+ clean=1
+ bc_default_banner=1
+ bc_default_sigint_reset=1
+ dc_default_sigint_reset=1
+ bc_default_tty_mode=1
+ dc_default_tty_mode=1
+ bc_default_prompt=""
+ dc_default_prompt=""
+ bc_default_expr_exit=0
+ dc_default_expr_exit=0
+ bc_default_digit_clamp=1
+ dc_default_digit_clamp=1;;
+
+ ?|'') usage "Invalid user build: \"$_predefined_build_type\". Accepted types are BSD, GNU, GDH, DBG.";;
esac
}
diff --git a/include/bc.h b/include/bc.h
index 06b2131c967b..5e879e83a987 100644
--- a/include/bc.h
+++ b/include/bc.h
@@ -97,13 +97,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 (35)
+#define BC_LEX_NKWS (37)
#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 (31)
+#define BC_LEX_NKWS (33)
#endif // BC_ENABLE_EXTRA_MATH
diff --git a/include/lang.h b/include/lang.h
index f7356c412396..396fc8a4b34c 100644
--- a/include/lang.h
+++ b/include/lang.h
@@ -178,6 +178,8 @@ typedef enum BcInst
BC_INST_SCALE_FUNC,
BC_INST_SQRT,
BC_INST_ABS,
+ BC_INST_IS_NUMBER,
+ BC_INST_IS_STRING,
#if BC_ENABLE_EXTRA_MATH
/// Another builtin function.
@@ -392,12 +394,6 @@ typedef struct BcFunc
#endif // BC_ENABLED
- /// The strings encountered in the function.
- BcVec strs;
-
- /// The constants encountered in the function.
- BcVec consts;
-
/// The function's name.
const char* name;
@@ -660,17 +656,6 @@ bc_result_free(void* result);
void
bc_array_expand(BcVec* a, size_t len);
-/**
- * Compare two BcId's and return the result. Since they are just comparing the
- * names in the BcId, I return the result from strcmp() exactly. This is used by
- * maps in their binary search.
- * @param e1 The first id.
- * @param e2 The second id.
- * @return The result of strcmp() on the BcId's names.
- */
-int
-bc_id_cmp(const BcId* e1, const BcId* e2);
-
#if BC_ENABLED
/**
diff --git a/include/lex.h b/include/lex.h
index 4f08b45d623f..160c0f114855 100644
--- a/include/lex.h
+++ b/include/lex.h
@@ -317,6 +317,12 @@ typedef enum BcLexType
/// bc abs keyword.
BC_LEX_KW_ABS,
+ /// bc is_number keyword.
+ BC_LEX_KW_IS_NUMBER,
+
+ /// bc is_string keyword.
+ BC_LEX_KW_IS_STRING,
+
#if BC_ENABLE_EXTRA_MATH
/// bc irand keyword.
@@ -494,14 +500,8 @@ typedef struct BcLex
/// string.
BcVec str;
- /// If this is true, the lexer is processing stdin and can ask for more data
- /// if a string or comment are not properly terminated.
- bool is_stdin;
-
- /// If this is true, the lexer is processing expressions from the
- /// command-line and can ask for more data if a string or comment are not
- /// properly terminated.
- bool is_exprs;
+ /// The mode the lexer is in.
+ BcMode mode;
} BcLex;
@@ -531,14 +531,12 @@ bc_lex_file(BcLex* l, const char* file);
/**
* Sets the text the lexer will lex.
- * @param l The lexer.
- * @param text The text to lex.
- * @param is_stdin True if the text is from stdin, false otherwise.
- * @param is_exprs True if the text is from command-line expressions, false
- * otherwise.
+ * @param l The lexer.
+ * @param text The text to lex.
+ * @param mode The mode to lex in.
*/
void
-bc_lex_text(BcLex* l, const char* text, bool is_stdin, bool is_exprs);
+bc_lex_text(BcLex* l, const char* text, BcMode mode);
/**
* Generic next function for the parser to call. It takes care of calling the
diff --git a/include/parse.h b/include/parse.h
index e692462395ca..ebf234c5f7f9 100644
--- a/include/parse.h
+++ b/include/parse.h
@@ -80,18 +80,6 @@
*/
#define BC_PARSE_IS_INITED(p, prg) ((p)->prog == (prg))
-#if BC_ENABLED
-
-/**
- * Returns true if the current parser state allows parsing, false otherwise.
- * @param p The parser.
- * @return True if parsing can proceed, false otherwise.
- */
-#define BC_PARSE_CAN_PARSE(p) \
- ((p).l.t != BC_LEX_EOF && (p).l.t != BC_LEX_KW_DEFINE)
-
-#else // BC_ENABLED
-
/**
* Returns true if the current parser state allows parsing, false otherwise.
* @param p The parser.
@@ -99,8 +87,6 @@
*/
#define BC_PARSE_CAN_PARSE(p) ((p).l.t != BC_LEX_EOF)
-#endif // BC_ENABLED
-
/**
* Pushes the instruction @a i onto the bytecode vector for the current
* function.
@@ -268,14 +254,12 @@ bc_parse_pushName(const BcParse* p, char* name, bool var);
/**
* Sets the text that the parser will parse.
- * @param p The parser.
- * @param text The text to lex.
- * @param is_stdin True if the text is from stdin, false otherwise.
- * @param is_exprs True if the text is from command-line expressions, false
- * otherwise.
+ * @param p The parser.
+ * @param text The text to lex.
+ * @param mode The mode to parse in.
*/
void
-bc_parse_text(BcParse* p, const char* text, bool is_stdin, bool is_exprs);
+bc_parse_text(BcParse* p, const char* text, BcMode mode);
// References to const 0 and 1 strings for special cases. bc and dc have
// specific instructions for 0 and 1 because they pop up so often and (in the
diff --git a/include/program.h b/include/program.h
index 3eaf568d66ac..62e867eb7fb8 100644
--- a/include/program.h
+++ b/include/program.h
@@ -87,11 +87,21 @@ typedef struct BcProgram
/// The execution stack.
BcVec stack;
- /// A pointer to the current function's constants.
- BcVec* consts;
+ /// The constants encountered in the program. They are global to the program
+ /// to prevent bad accesses when functions that used non-auto variables are
+ /// replaced.
+ BcVec consts;
- /// A pointer to the current function's strings.
- BcVec* strs;
+ /// The map of constants to go with consts.
+ BcVec const_map;
+
+ /// The strings encountered in the program. They are global to the program
+ /// to prevent bad accesses when functions that used non-auto variables are
+ /// replaced.
+ BcVec strs;
+
+ /// The map of strings to go with strs.
+ BcVec str_map;
/// The array of functions.
BcVec fns;
@@ -343,22 +353,22 @@ bc_program_printStackDebug(BcProgram* p);
/**
* Returns the index of the variable or array in their respective arrays.
- * @param p The program.
- * @param id The BcId of the variable or array.
- * @param var True if the search should be for a variable, false for an array.
- * @return The index of the variable or array in the correct array.
+ * @param p The program.
+ * @param name The name of the variable or array.
+ * @param var True if the search should be for a variable, false for an array.
+ * @return The index of the variable or array in the correct array.
*/
size_t
-bc_program_search(BcProgram* p, const char* id, bool var);
+bc_program_search(BcProgram* p, const char* name, bool var);
/**
- * Adds a string to a function and returns the string's index in the function.
- * @param p The program.
- * @param str The string to add.
- * @param fidx The index of the function to add to.
+ * Adds a string to the program and returns the string's index in the program.
+ * @param p The program.
+ * @param str The string to add.
+ * @return The string's index in the program.
*/
size_t
-bc_program_addString(BcProgram* p, const char* str, size_t fidx);
+bc_program_addString(BcProgram* p, const char* str);
/**
* Inserts a function into the program and returns the index of the function in
@@ -571,6 +581,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
+ &&lbl_BC_INST_IS_NUMBER, \
+ &&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
@@ -665,6 +677,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
+ &&lbl_BC_INST_IS_NUMBER, \
+ &&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \
@@ -771,6 +785,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
+ &&lbl_BC_INST_IS_NUMBER, \
+ &&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
@@ -851,6 +867,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
+ &&lbl_BC_INST_IS_NUMBER, \
+ &&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \
@@ -923,6 +941,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
+ &&lbl_BC_INST_IS_NUMBER, \
+ &&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
@@ -992,6 +1012,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
+ &&lbl_BC_INST_IS_NUMBER, \
+ &&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \
diff --git a/include/status.h b/include/status.h
index f478beb1a2d5..ce6251ab0c1d 100644
--- a/include/status.h
+++ b/include/status.h
@@ -658,6 +658,22 @@ typedef enum BcErr
#endif // BC_ENABLED
+/**
+ * The mode bc is in. This is basically what input it is processing.
+ */
+typedef enum BcMode
+{
+ /// Expressions mode.
+ BC_MODE_EXPRS,
+
+ /// File mode.
+ BC_MODE_FILE,
+
+ /// stdin mode.
+ BC_MODE_STDIN,
+
+} BcMode;
+
/// Do a longjmp(). This is what to use when activating an "exception", i.e., a
/// longjmp(). With debug code, it will print the name of the function it jumped
/// from.
diff --git a/include/vector.h b/include/vector.h
index 539b8a1ac292..bf79d30c36dd 100644
--- a/include/vector.h
+++ b/include/vector.h
@@ -59,9 +59,6 @@ typedef unsigned char uchar;
*/
typedef void (*BcVecFree)(void* ptr);
-// Forward declaration.
-struct BcId;
-
#if BC_LONG_BIT >= 64
/// An integer to shrink the size of a vector by using these instead of size_t.
@@ -322,7 +319,7 @@ void
bc_vec_free(void* vec);
/**
- * Attempts to insert an item into a map and returns true if it succeeded, false
+ * Attempts to insert an ID into a map and returns true if it succeeded, false
* if the item already exists.
* @param v The map vector to insert into.
* @param name The name of the item to insert. This name is assumed to be owned
@@ -449,25 +446,6 @@ bc_slabvec_print(BcVec* v, const char* func);
/// A convenience macro for freeing a vector of slabs.
#define bc_slabvec_free bc_vec_free
-#if BC_ENABLED
-#if DC_ENABLED
-
-/// Returns the set of slabs for the maps and the current calculator.
-#define BC_VEC_MAP_SLABS (BC_IS_DC ? &vm->main_slabs : &vm->other_slabs)
-
-#else // DC_ENABLED
-
-/// Returns the set of slabs for the maps and the current calculator.
-#define BC_VEC_MAP_SLABS (&vm->other_slabs)
-
-#endif // DC_ENABLED
-#else // BC_ENABLED
-
-/// Returns the set of slabs for the maps and the current calculator.
-#define BC_VEC_MAP_SLABS (&vm->main_slabs)
-
-#endif // BC_ENABLED
-
#ifndef _WIN32
/**
diff --git a/include/version.h b/include/version.h
index 4fbbe3c2acf4..2a3e6aa0f34c 100644
--- a/include/version.h
+++ b/include/version.h
@@ -37,6 +37,6 @@
#define BC_VERSION_H
/// The current version.
-#define VERSION 6.0.4
+#define VERSION 6.1.0
#endif // BC_VERSION_H
diff --git a/include/vm.h b/include/vm.h
index c800e476e228..44212eb03598 100644
--- a/include/vm.h
+++ b/include/vm.h
@@ -628,12 +628,8 @@ typedef struct BcVm
/// True if EOF was encountered.
bool eof;
- /// True if bc is currently reading from stdin.
- bool is_stdin;
-
- /// True if bc should clear its buffers. This is BcVm to fill a hole and
- /// also to avoid clobber warnings from GCC.
- bool clear;
+ /// The mode that the program is in.
+ uchar mode;
#if BC_ENABLED
@@ -759,16 +755,9 @@ typedef struct BcVm
/// The number of items in the input buffer.
size_t buf_len;
- /// The slab for constants in the main function. This is separate for
- /// garbage collection reasons.
- BcVec main_const_slab;
-
- //// The slab for all other strings for the main function.
- BcVec main_slabs;
-
- /// The slab for function names, strings in other functions, and constants
- /// in other functions.
- BcVec other_slabs;
+ /// The slabs vector for constants, strings, function names, and other
+ /// string-like things.
+ BcVec slabs;
#if BC_ENABLED
@@ -846,7 +835,7 @@ bc_vm_getTemp(void);
void
bc_vm_freeTemps(void);
-#if !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB
+#if !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB || BC_ENABLE_LIBRARY
/**
* Erases the flush argument if history does not exist because it does not
@@ -854,12 +843,12 @@ bc_vm_freeTemps(void);
*/
#define bc_vm_putchar(c, t) bc_vm_putchar_impl(c)
-#else // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB
+#else // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB || BC_ENABLE_LIBRARY
// This is here to satisfy a clang warning about recursive macros.
#define bc_vm_putchar(c, t) bc_vm_putchar_impl(c, t)
-#endif // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB
+#endif // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB || BC_ENABLE_LIBRARY
/**
* Print to stdout with limited formating.
diff --git a/manuals/bc/A.1 b/manuals/bc/A.1
index 9e612f680132..e8b8bd0892a8 100644
--- a/manuals/bc/A.1
+++ b/manuals/bc/A.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "20." 4
+.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "21." 4
+.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
-.IP "22." 4
+.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -2926,6 +2959,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@@ -2934,8 +2973,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/A.1.md b/manuals/bc/A.1.md
index f4d0ad892a2b..754ceda1adb6 100644
--- a/manuals/bc/A.1.md
+++ b/manuals/bc/A.1.md
@@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-20. **rand()**: A pseudo-random integer between **0** (inclusive) and
+22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
-21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
+23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
-22. **maxrand()**: The max integer returned by **rand()**. This is a
+24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -2461,6 +2482,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@@ -2470,7 +2495,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bc/E.1 b/manuals/bc/E.1
index d5e81268f801..f9e8c8b2d02f 100644
--- a/manuals/bc/E.1
+++ b/manuals/bc/E.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -1759,6 +1792,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@@ -1767,8 +1806,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/E.1.md b/manuals/bc/E.1.md
index 85db83b1d2d8..cf52f5a2035e 100644
--- a/manuals/bc/E.1.md
+++ b/manuals/bc/E.1.md
@@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -1469,6 +1490,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@@ -1478,7 +1503,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bc/EH.1 b/manuals/bc/EH.1
index f0f2b1274dad..5c556c049f14 100644
--- a/manuals/bc/EH.1
+++ b/manuals/bc/EH.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -1730,6 +1763,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@@ -1738,8 +1777,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/EH.1.md b/manuals/bc/EH.1.md
index 18c77d569d39..bb905be37f95 100644
--- a/manuals/bc/EH.1.md
+++ b/manuals/bc/EH.1.md
@@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -1443,6 +1464,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@@ -1452,7 +1477,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bc/EHN.1 b/manuals/bc/EHN.1
index 03887eb6ebe4..d5fafaf4d1da 100644
--- a/manuals/bc/EHN.1
+++ b/manuals/bc/EHN.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -1726,13 +1759,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/EHN.1.md b/manuals/bc/EHN.1.md
index 769ec4a18f64..0ea13df66b7f 100644
--- a/manuals/bc/EHN.1.md
+++ b/manuals/bc/EHN.1.md
@@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -1438,13 +1459,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bc/EN.1 b/manuals/bc/EN.1
index 082afe7d8fe6..895b21051408 100644
--- a/manuals/bc/EN.1
+++ b/manuals/bc/EN.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -1755,13 +1788,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/EN.1.md b/manuals/bc/EN.1.md
index 2e76a2d3b289..6fb521188cc0 100644
--- a/manuals/bc/EN.1.md
+++ b/manuals/bc/EN.1.md
@@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -1464,13 +1485,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bc/H.1 b/manuals/bc/H.1
index 750b38976a26..72d561fdea00 100644
--- a/manuals/bc/H.1
+++ b/manuals/bc/H.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "20." 4
+.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "21." 4
+.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
-.IP "22." 4
+.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -2897,6 +2930,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@@ -2905,8 +2944,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/H.1.md b/manuals/bc/H.1.md
index b242b7cfa393..669aa1b1bf37 100644
--- a/manuals/bc/H.1.md
+++ b/manuals/bc/H.1.md
@@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-20. **rand()**: A pseudo-random integer between **0** (inclusive) and
+22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
-21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
+23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
-22. **maxrand()**: The max integer returned by **rand()**. This is a
+24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -2435,6 +2456,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@@ -2444,7 +2469,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bc/HN.1 b/manuals/bc/HN.1
index afecefae65f0..b90c88fb59b6 100644
--- a/manuals/bc/HN.1
+++ b/manuals/bc/HN.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "20." 4
+.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "21." 4
+.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
-.IP "22." 4
+.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -2893,13 +2926,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/HN.1.md b/manuals/bc/HN.1.md
index 2e89cd559804..cf4a9d4024f1 100644
--- a/manuals/bc/HN.1.md
+++ b/manuals/bc/HN.1.md
@@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-20. **rand()**: A pseudo-random integer between **0** (inclusive) and
+22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
-21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
+23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
-22. **maxrand()**: The max integer returned by **rand()**. This is a
+24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -2430,13 +2451,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bc/N.1 b/manuals/bc/N.1
index 88603995ca73..378094edeaf0 100644
--- a/manuals/bc/N.1
+++ b/manuals/bc/N.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
+\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
+\f[B]0\f[R] if it is a string.
+This is a \f[B]non-portable extension\f[R].
+.IP "10." 4
+\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
+\f[B]0\f[R] if it is a number.
+This is a \f[B]non-portable extension\f[R].
+.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
-.IP "10." 4
+.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
-.IP "11." 4
+.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
-.IP "12." 4
+.IP "14." 4
+\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
+would result from running \f[B]asciify(E)\f[R] on each element of the
+array identified by the argument.
+This allows creating multi-character strings and storing them.
+This is a \f[B]non-portable extension\f[R].
+.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
-.IP "13." 4
+.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
-.IP "14." 4
+.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "15." 4
+.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "16." 4
+.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "17." 4
+.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
-.IP "18." 4
+.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "19." 4
+.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
-.IP "20." 4
+.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
-.IP "21." 4
+.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
-.IP "22." 4
+.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
+\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
+slightly different from other bc(1) implementations.
+Other bc(1) implementations will exit as soon as they finish parsing the
+line that a \f[B]quit\f[R] command is on.
+This bc(1) will execute any completed and executable statements that
+occur before the \f[B]quit\f[R] statement before exiting.
+.PP
+In other words, for the bc(1) code below:
+.IP
+.nf
+\f[C]
+for (i = 0; i < 3; ++i) i; quit
+\f[R]
+.fi
+.PP
+Other bc(1) implementations will print nothing, and this bc(1) will
+print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
+before exiting.
+.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@@ -2922,13 +2955,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
+In addition, the behavior of the \f[B]quit\f[R] implements an
+interpretation of that specification that is different from all known
+implementations.
+For more information see the \f[B]Statements\f[R] subsection of the
+\f[B]SYNTAX\f[R] section.
+.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
-None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
+the \f[B]quit\f[R] statement.
+.PP
+No other bugs are known.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.
diff --git a/manuals/bc/N.1.md b/manuals/bc/N.1.md
index 33b581185abb..5ed9ed677671 100644
--- a/manuals/bc/N.1.md
+++ b/manuals/bc/N.1.md
@@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
-9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
+9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
+ string. This is a **non-portable extension**.
+10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
+ number. This is a **non-portable extension**.
+11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
-10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
+11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
-11. **asciify(E)**: If **E** is a string, returns a string that is the first
+12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
-12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
+13. **asciify(I[])**: A string that is made up of the characters that would
+ result from running **asciify(E)** on each element of the array identified
+ by the argument. This allows creating multi-character strings and storing
+ them. This is a **non-portable extension**.
+14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
-13. **read()**: Reads a line from **stdin** and uses that as an expression. The
+15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
-14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
+16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
-15. **maxobase()**: The max allowable **obase**. This is a **non-portable
+17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
-16. **maxscale()**: The max allowable **scale**. This is a **non-portable
+18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
-17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
+19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
-18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
+20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
+21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
-20. **rand()**: A pseudo-random integer between **0** (inclusive) and
+22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
-21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
+23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
-22. **maxrand()**: The max integer returned by **rand()**. This is a
+24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
+**Warning**: The behavior of this bc(1) on **quit** is slightly different from
+other bc(1) implementations. Other bc(1) implementations will exit as soon as
+they finish parsing the line that a **quit** command is on. This bc(1) will
+execute any completed and executable statements that occur before the **quit**
+statement before exiting.
+
+In other words, for the bc(1) code below:
+
+ for (i = 0; i < 3; ++i) i; quit
+
+Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
+**1**, and **2** on successive lines before exiting.
+
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@@ -2456,13 +2477,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
+In addition, the behavior of the **quit** implements an interpretation of that
+specification that is different from all known implementations. For more
+information see the **Statements** subsection of the **SYNTAX** section.
+
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
+statement.
+
+No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS
diff --git a/manuals/bcl.3 b/manuals/bcl.3
index c1da21258a17..b81d001ce3e5 100644
--- a/manuals/bcl.3
+++ b/manuals/bcl.3
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "BCL" "3" "August 2022" "Gavin D. Howard" "Libraries Manual"
+.TH "BCL" "3" "October 2022" "Gavin D. Howard" "Libraries Manual"
.nh
.ad l
.SH NAME
diff --git a/manuals/dc/A.1 b/manuals/dc/A.1
index 4771cb655ba1..a625564b7692 100644
--- a/manuals/dc/A.1
+++ b/manuals/dc/A.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1696,7 +1718,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/A.1.md b/manuals/dc/A.1.md
index 0b781da0daf5..d2de6a187ab7 100644
--- a/manuals/dc/A.1.md
+++ b/manuals/dc/A.1.md
@@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1501,7 +1517,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/manuals/dc/E.1 b/manuals/dc/E.1
index 525bfe41feaa..e89e1a8544c8 100644
--- a/manuals/dc/E.1
+++ b/manuals/dc/E.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1474,7 +1496,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/E.1.md b/manuals/dc/E.1.md
index ac83e63bac7d..eadf99cb7928 100644
--- a/manuals/dc/E.1.md
+++ b/manuals/dc/E.1.md
@@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1325,7 +1341,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/manuals/dc/EH.1 b/manuals/dc/EH.1
index daad57d73dc6..59cfb2894c37 100644
--- a/manuals/dc/EH.1
+++ b/manuals/dc/EH.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1448,7 +1470,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/EH.1.md b/manuals/dc/EH.1.md
index 8b5891f14e6e..06c2af44ac1e 100644
--- a/manuals/dc/EH.1.md
+++ b/manuals/dc/EH.1.md
@@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1302,7 +1318,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/manuals/dc/EHN.1 b/manuals/dc/EHN.1
index e60d3cf47fb1..a2bc6cab0eaa 100644
--- a/manuals/dc/EHN.1
+++ b/manuals/dc/EHN.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1444,7 +1466,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/EHN.1.md b/manuals/dc/EHN.1.md
index 96a020662b38..96ee28904ee2 100644
--- a/manuals/dc/EHN.1.md
+++ b/manuals/dc/EHN.1.md
@@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1297,7 +1313,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/manuals/dc/EN.1 b/manuals/dc/EN.1
index a1eb86cc5096..980f0d50c13c 100644
--- a/manuals/dc/EN.1
+++ b/manuals/dc/EN.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1470,7 +1492,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/EN.1.md b/manuals/dc/EN.1.md
index 357c5d250666..713cc2fcc82d 100644
--- a/manuals/dc/EN.1.md
+++ b/manuals/dc/EN.1.md
@@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1320,7 +1336,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/manuals/dc/H.1 b/manuals/dc/H.1
index 7f9a18051ccf..e9934a85d4a4 100644
--- a/manuals/dc/H.1
+++ b/manuals/dc/H.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1670,7 +1692,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/H.1.md b/manuals/dc/H.1.md
index feab8309b693..55cc7cbe3005 100644
--- a/manuals/dc/H.1.md
+++ b/manuals/dc/H.1.md
@@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1478,7 +1494,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/manuals/dc/HN.1 b/manuals/dc/HN.1
index 0c5db06234b7..d22b159db067 100644
--- a/manuals/dc/HN.1
+++ b/manuals/dc/HN.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1666,7 +1688,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/HN.1.md b/manuals/dc/HN.1.md
index 81badc9edb67..c9c980996234 100644
--- a/manuals/dc/HN.1.md
+++ b/manuals/dc/HN.1.md
@@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1473,7 +1489,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/manuals/dc/N.1 b/manuals/dc/N.1
index b3e13537e6a8..9988fe063750 100644
--- a/manuals/dc/N.1
+++ b/manuals/dc/N.1
@@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
+.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
+\f[B]u\f[R]
+Pops one value off of the stack.
+If the value is a number, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a string), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
+\f[B]t\f[R]
+Pops one value off of the stack.
+If the value is a string, this pushes \f[B]1\f[R] onto the stack.
+Otherwise (if it is a number), it pushes \f[B]0\f[R].
+.RS
+.PP
+This is a \f[B]non-portable extension\f[R].
+.RE
+.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@@ -1692,7 +1714,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
-Report bugs at https://git.yzena.com/gavin/bc.
+Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.
diff --git a/manuals/dc/N.1.md b/manuals/dc/N.1.md
index 694a0cb907e8..52ffa0b23cfa 100644
--- a/manuals/dc/N.1.md
+++ b/manuals/dc/N.1.md
@@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
+ This is a **non-portable extension**.
+
## Status
These commands query status of the stack or its top value.
@@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
+**u**
+
+: Pops one value off of the stack. If the value is a number, this pushes **1**
+ onto the stack. Otherwise (if it is a string), it pushes **0**.
+
+ This is a **non-portable extension**.
+
+**t**
+
+: Pops one value off of the stack. If the value is a string, this pushes **1**
+ onto the stack. Otherwise (if it is a number), it pushes **0**.
+
+ This is a **non-portable extension**.
+
**z**
: Pushes the current depth of the stack (before execution of this command)
@@ -1496,7 +1512,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
-None are known. Report bugs at https://git.yzena.com/gavin/bc.
+None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR
diff --git a/src/bc_lex.c b/src/bc_lex.c
index 5248aa54ba5e..a4641be0b653 100644
--- a/src/bc_lex.c
+++ b/src/bc_lex.c
@@ -115,7 +115,7 @@ bc_lex_string(BcLex* l)
buf = l->buf;
got_more = false;
- assert(!vm->is_stdin || buf == vm->buffer.v);
+ assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v);
// Fortunately for us, bc doesn't escape quotes. Instead, the equivalent
// is '\q', which makes this loop simpler.
@@ -124,7 +124,7 @@ bc_lex_string(BcLex* l)
nlines += (c == '\n');
}
- if (BC_ERR(c == '\0') && !vm->eof && (l->is_stdin || l->is_exprs))
+ if (BC_ERR(c == '\0') && !vm->eof && l->mode != BC_MODE_FILE)
{
got_more = bc_lex_readLine(l);
}
diff --git a/src/bc_parse.c b/src/bc_parse.c
index 8da5557195f8..1617384cd59f 100644
--- a/src/bc_parse.c
+++ b/src/bc_parse.c
@@ -207,7 +207,7 @@ bc_parse_createCondLabel(BcParse* p, size_t idx)
bc_vec_push(&p->conds, &idx);
}
-/*
+/**
* Creates an exit label to be filled in later by bc_parse_setLabel(). Also, why
* create a label to be filled in later? Because exit labels are meant to be
* targeted by code that comes *before* the label. Since we have to parse that
@@ -255,25 +255,30 @@ bc_parse_operator(BcParse* p, BcLexType type, size_t start, size_t* nexprs)
uchar l, r = BC_PARSE_OP_PREC(type);
uchar left = BC_PARSE_OP_LEFT(type);
- // While we haven't hit the stop point yet.
+ // While we haven't hit the stop point yet...
while (p->ops.len > start)
{
// Get the top operator.
t = BC_PARSE_TOP_OP(p);
- // If it's a right paren, we have reached the end of whatever expression
- // this is no matter what.
+ // If it's a left paren, we have reached the end of whatever expression
+ // this is no matter what. We also don't pop the left paren because it
+ // will need to stay for the rest of the subexpression.
if (t == BC_LEX_LPAREN) break;
// Break for precedence. Precedence operates differently on left and
// right associativity, by the way. A left associative operator that
// matches the current precedence should take priority, but a right
// associative operator should not.
+ //
+ // Also, a lower precedence value means a higher precedence.
l = BC_PARSE_OP_PREC(t);
if (l >= r && (l != r || !left)) break;
// Do the housekeeping. In particular, make sure to note that one
- // expression was consumed. (Two were, but another was added.)
+ // expression was consumed (well, two were, but another was added) if
+ // the operator was not a prefix operator. (Postfix operators are not
+ // handled by this function at all.)
bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
bc_vec_pop(&p->ops);
*nexprs -= !BC_PARSE_OP_PREFIX(t);
@@ -390,7 +395,11 @@ bc_parse_call(BcParse* p, const char* name, uint8_t flags)
/**
* Parses a name/identifier-based expression. It could be a variable, an array
* element, an array itself (for function arguments), a function call, etc.
- *
+ * @param p The parser.
+ * @param type A pointer to return the resulting instruction.
+ * @param can_assign A pointer to return true if the name can be assigned to,
+ * false otherwise.
+ * @param flags Flags restricting what kind of expression the name can be.
*/
static void
bc_parse_name(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags)
@@ -523,7 +532,13 @@ bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
flags |= BC_PARSE_NEEDVAL;
// Since length can take arrays, we need to specially add that flag.
- if (type == BC_LEX_KW_LENGTH) flags |= BC_PARSE_ARRAY;
+ if (type == BC_LEX_KW_LENGTH || type == BC_LEX_KW_ASCIIFY)
+ {
+ flags |= BC_PARSE_ARRAY;
+ }
+
+ // Otherwise, we need to clear it because it could be set.
+ else flags &= ~(BC_PARSE_ARRAY);
bc_parse_expr_status(p, flags, bc_parse_next_rel);
@@ -540,6 +555,10 @@ bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
/**
* Parses a builtin function that takes 3 arguments. This includes modexp() and
* divmod().
+ * @param p The parser.
+ * @param type The lex token.
+ * @param flags The expression parsing flags for parsing the argument.
+ * @param prev An out parameter; the previous instruction pointer.
*/
static void
bc_parse_builtin3(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
@@ -728,7 +747,7 @@ bc_parse_incdec(BcParse* p, BcInst* prev, bool* can_assign, size_t* nexs,
if (type == BC_LEX_NAME)
{
// Parse the name.
- uint8_t flags2 = flags & ~BC_PARSE_ARRAY;
+ uint8_t flags2 = flags & ~(BC_PARSE_ARRAY);
bc_parse_name(p, prev, can_assign, flags2 | BC_PARSE_NOCALL);
}
// Is the next token a global?
@@ -1091,9 +1110,9 @@ bc_parse_endif(BcParse* p)
{
// We set this to restore it later. We don't want the parser thinking
// that we are on stdin for this one because it will want more.
- bool is_stdin = vm->is_stdin;
+ BcMode mode = vm->mode;
- vm->is_stdin = false;
+ vm->mode = BC_MODE_FILE;
// End all of the if statements and loops.
while (p->flags.len > 1 || BC_PARSE_IF_END(p))
@@ -1102,7 +1121,7 @@ bc_parse_endif(BcParse* p)
if (p->flags.len > 1) bc_parse_endBody(p, false);
}
- vm->is_stdin = is_stdin;
+ vm->mode = (uchar) mode;
}
// If we reach here, a block was not properly closed, and we should error.
else bc_parse_err(&vm->prs, BC_ERR_PARSE_BLOCK);
@@ -1693,6 +1712,8 @@ bc_parse_stmt(BcParse* p)
#endif // BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_SQRT:
case BC_LEX_KW_ABS:
+ case BC_LEX_KW_IS_NUMBER:
+ case BC_LEX_KW_IS_STRING:
#if BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_IRAND:
#endif // BC_ENABLE_EXTRA_MATH
@@ -1907,7 +1928,7 @@ bc_parse_stmt(BcParse* p)
}
// Make sure semicolons are eaten.
- while (p->l.t == BC_LEX_SCOLON)
+ while (p->l.t == BC_LEX_SCOLON || p->l.t == BC_LEX_NLINE)
{
bc_lex_next(&p->l);
}
@@ -2294,6 +2315,8 @@ bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next)
case BC_LEX_KW_LENGTH:
case BC_LEX_KW_SQRT:
case BC_LEX_KW_ABS:
+ case BC_LEX_KW_IS_NUMBER:
+ case BC_LEX_KW_IS_STRING:
#if BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_IRAND:
#endif // BC_ENABLE_EXTRA_MATH
diff --git a/src/data.c b/src/data.c
index f743d625554a..5e578778d0ff 100644
--- a/src/data.c
+++ b/src/data.c
@@ -719,6 +719,8 @@ const char* bc_inst_names[] = {
"BC_INST_SCALE_FUNC",
"BC_INST_SQRT",
"BC_INST_ABS",
+ "BC_INST_IS_NUMBER",
+ "BC_INST_IS_STRING",
#if BC_ENABLE_EXTRA_MATH
"BC_INST_IRAND",
#endif // BC_ENABLE_EXTRA_MATH
@@ -816,6 +818,8 @@ const BcLexKeyword bc_lex_kws[] = {
BC_LEX_KW_ENTRY("print", 5, false),
BC_LEX_KW_ENTRY("sqrt", 4, true),
BC_LEX_KW_ENTRY("abs", 3, false),
+ BC_LEX_KW_ENTRY("is_number", 9, false),
+ BC_LEX_KW_ENTRY("is_string", 9, false),
#if BC_ENABLE_EXTRA_MATH
BC_LEX_KW_ENTRY("irand", 5, false),
#endif // BC_ENABLE_EXTRA_MATH
@@ -888,13 +892,13 @@ const uint8_t bc_parse_exprs[] = {
BC_PARSE_EXPR_ENTRY(false, true, true, true, true, true, true, false),
// Starts with BC_LEX_KW_SQRT.
- BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, false, true),
-
- // Starts with BC_LEX_KW_MAXIBASE.
BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, true, true),
- // Starts with BC_LEX_KW_STREAM.
- BC_PARSE_EXPR_ENTRY(false, false, 0, 0, 0, 0, 0, 0)
+ // Starts with BC_LEX_KW_QUIT.
+ BC_PARSE_EXPR_ENTRY(false, true, true, true, true, true, true, true),
+
+ // Starts with BC_LEX_KW_GLOBAL_STACKS.
+ BC_PARSE_EXPR_ENTRY(true, true, false, false, 0, 0, 0, 0)
#else // BC_ENABLE_EXTRA_MATH
@@ -911,15 +915,19 @@ const uint8_t bc_parse_exprs[] = {
BC_PARSE_EXPR_ENTRY(false, false, true, true, true, true, true, false),
// Starts with BC_LEX_KW_SQRT.
- BC_PARSE_EXPR_ENTRY(true, true, true, true, true, false, true, true),
+ BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, true, false),
- // Starts with BC_LEX_KW_MAXSCALE,
- BC_PARSE_EXPR_ENTRY(true, true, true, true, true, false, false, 0)
+ // Starts with BC_LEX_KW_MAXIBASE.
+ BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, true, false),
+
+ // Starts with BC_LEX_KW_ELSE.
+ BC_PARSE_EXPR_ENTRY(false, 0, 0, 0, 0, 0, 0, 0)
#endif // BC_ENABLE_EXTRA_MATH
};
-/// An array of data for operators that correspond to token types.
+/// An array of data for operators that correspond to token types. Note that a
+/// lower precedence *value* means a higher precedence.
const uchar bc_parse_ops[] = {
BC_PARSE_OP(0, false), BC_PARSE_OP(0, false), BC_PARSE_OP(1, false),
BC_PARSE_OP(1, false),
@@ -1122,8 +1130,8 @@ const uchar dc_lex_tokens[] = {
BC_LEX_KW_QUIT,
BC_LEX_SWAP,
BC_LEX_OP_ASSIGN,
- BC_LEX_INVALID,
- BC_LEX_INVALID,
+ BC_LEX_KW_IS_STRING,
+ BC_LEX_KW_IS_NUMBER,
BC_LEX_KW_SQRT,
BC_LEX_INVALID,
BC_LEX_EXECUTE,
@@ -1137,7 +1145,7 @@ const uchar dc_lex_tokens[] = {
};
/// A list of instructions that correspond to lex tokens. If an entry is
-/// BC_INST_INVALID, that lex token needs extra parsing in the dc parser.
+/// @a BC_INST_INVALID, that lex token needs extra parsing in the dc parser.
/// Otherwise, the token can trivially be replaced by the entry. This needs to
/// be updated if the tokens change.
const uchar dc_parse_insts[] = {
@@ -1180,7 +1188,7 @@ const uchar dc_parse_insts[] = {
BC_INST_SEED,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_LENGTH, BC_INST_PRINT, BC_INST_SQRT,
- BC_INST_ABS,
+ BC_INST_ABS, BC_INST_IS_NUMBER, BC_INST_IS_STRING,
#if BC_ENABLE_EXTRA_MATH
BC_INST_IRAND,
#endif // BC_ENABLE_EXTRA_MATH
diff --git a/src/dc_lex.c b/src/dc_lex.c
index 1277411fde5a..4ca019818941 100644
--- a/src/dc_lex.c
+++ b/src/dc_lex.c
@@ -114,7 +114,7 @@ dc_lex_string(BcLex* l)
nls = 0;
got_more = false;
- assert(!l->is_stdin || l->buf == vm->buffer.v);
+ assert(l->mode != BC_MODE_STDIN || l->buf == vm->buffer.v);
// This is the meat. As long as we don't run into the NUL byte, and we
// have "depth", which means we haven't completely balanced brackets
@@ -141,11 +141,15 @@ dc_lex_string(BcLex* l)
if (BC_ERR(c == '\0' && depth))
{
- if (!vm->eof && (l->is_stdin || l->is_exprs))
+ if (!vm->eof && l->mode != BC_MODE_FILE)
{
got_more = bc_lex_readLine(l);
}
- if (got_more) bc_vec_popAll(&l->str);
+
+ if (got_more)
+ {
+ bc_vec_popAll(&l->str);
+ }
}
}
while (got_more && depth);
diff --git a/src/dc_parse.c b/src/dc_parse.c
index 106f54ed1321..ef95e22f357a 100644
--- a/src/dc_parse.c
+++ b/src/dc_parse.c
@@ -324,6 +324,8 @@ dc_parse_token(BcParse* p, BcLexType t, uint8_t flags)
case BC_LEX_KW_PRINT:
case BC_LEX_KW_SQRT:
case BC_LEX_KW_ABS:
+ case BC_LEX_KW_IS_NUMBER:
+ case BC_LEX_KW_IS_STRING:
#if BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_IRAND:
#endif // BC_ENABLE_EXTRA_MATH
diff --git a/src/lang.c b/src/lang.c
index bb028b25631a..20295c26e3da 100644
--- a/src/lang.c
+++ b/src/lang.c
@@ -99,10 +99,6 @@ bc_func_init(BcFunc* f, const char* name)
bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE);
- bc_vec_init(&f->consts, sizeof(BcConst), BC_DTOR_CONST);
-
- bc_vec_init(&f->strs, sizeof(char*), BC_DTOR_NONE);
-
#if BC_ENABLED
// Only bc needs these things.
@@ -128,10 +124,6 @@ bc_func_reset(BcFunc* f)
bc_vec_popAll(&f->code);
- bc_vec_popAll(&f->consts);
-
- bc_vec_popAll(&f->strs);
-
#if BC_ENABLED
if (BC_IS_BC)
{
@@ -155,10 +147,6 @@ bc_func_free(void* func)
bc_vec_free(&f->code);
- bc_vec_free(&f->consts);
-
- bc_vec_free(&f->strs);
-
#if BC_ENABLED
if (BC_IS_BC)
{
diff --git a/src/lex.c b/src/lex.c
index a26302a65a62..142ffaa22ae1 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -79,7 +79,7 @@ bc_lex_comment(BcLex* l)
got_more = false;
// If we are in stdin mode, the buffer must be the one used for stdin.
- assert(!vm->is_stdin || buf == vm->buffer.v);
+ assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v);
// Find the end of the comment.
for (i = l->i; !end; i += !end)
@@ -94,7 +94,7 @@ bc_lex_comment(BcLex* l)
if (BC_ERR(!c || buf[i + 1] == '\0'))
{
// Read more, if possible.
- if (!vm->eof && (l->is_stdin || l->is_exprs))
+ if (!vm->eof && l->mode != BC_MODE_FILE)
{
got_more = bc_lex_readLine(l);
}
@@ -349,11 +349,35 @@ bc_lex_readLine(BcLex* l)
BC_SIG_UNLOCK;
// Make sure we read from the appropriate place.
- if (l->is_stdin) good = bc_vm_readLine(false);
- else
+ switch (l->mode)
{
- assert(l->is_exprs);
- good = bc_vm_readBuf(false);
+ case BC_MODE_EXPRS:
+ {
+ good = bc_vm_readBuf(false);
+ break;
+ }
+
+ case BC_MODE_FILE:
+ {
+ good = false;
+ break;
+ }
+
+ case BC_MODE_STDIN:
+ {
+ good = bc_vm_readLine(false);
+ break;
+ }
+
+#ifdef __GNUC__
+#ifndef __clang__
+ default:
+ {
+ // We should never get here.
+ abort();
+ }
+#endif // __clang__
+#endif // __GNUC__
}
BC_SIG_LOCK;
@@ -364,7 +388,7 @@ bc_lex_readLine(BcLex* l)
}
void
-bc_lex_text(BcLex* l, const char* text, bool is_stdin, bool is_exprs)
+bc_lex_text(BcLex* l, const char* text, BcMode mode)
{
BC_SIG_ASSERT_LOCKED;
@@ -373,10 +397,7 @@ bc_lex_text(BcLex* l, const char* text, bool is_stdin, bool is_exprs)
bc_lex_fixText(l, text, strlen(text));
l->i = 0;
l->t = l->last = BC_LEX_INVALID;
- l->is_stdin = is_stdin;
- l->is_exprs = is_exprs;
-
- assert(!l->is_stdin || !l->is_exprs);
+ l->mode = mode;
bc_lex_next(l);
}
diff --git a/src/num.c b/src/num.c
index a15297bb4df3..be9ee2e6d6eb 100644
--- a/src/num.c
+++ b/src/num.c
@@ -130,7 +130,7 @@ bc_num_expand(BcNum* restrict n, size_t req)
* @param n The number to set to zero.
* @param scale The scale to set the number to.
*/
-static void
+static inline void
bc_num_setToZero(BcNum* restrict n, size_t scale)
{
assert(n != NULL);
diff --git a/src/parse.c b/src/parse.c
index 6ecc459bdfb0..984e5a14daae 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -64,10 +64,9 @@ bc_parse_pushName(const BcParse* p, char* name, bool var)
* @param inst The instruction to push.
* @param idx The index to push.
*/
-static void
-bc_parse_update(BcParse* p, uchar inst, size_t idx)
+static inline void
+bc_parse_pushInstIdx(BcParse* p, uchar inst, size_t idx)
{
- bc_parse_updateFunc(p, p->fidx);
bc_parse_push(p, inst);
bc_parse_pushIndex(p, idx);
}
@@ -77,20 +76,17 @@ bc_parse_addString(BcParse* p)
{
size_t idx;
- idx = bc_program_addString(p->prog, p->l.str.v, p->fidx);
+ idx = bc_program_addString(p->prog, p->l.str.v);
// Push the string info.
- bc_parse_update(p, BC_INST_STR, p->fidx);
- bc_parse_pushIndex(p, idx);
+ bc_parse_pushInstIdx(p, BC_INST_STR, idx);
}
static void
bc_parse_addNum(BcParse* p, const char* string)
{
- BcVec* consts = &p->func->consts;
+ BcProgram* prog = p->prog;
size_t idx;
- BcConst* c;
- BcVec* slabs;
// XXX: This function has an implicit assumption: that string is a valid C
// string with a nul terminator. This is because of the unchecked array
@@ -117,25 +113,33 @@ bc_parse_addNum(BcParse* p, const char* string)
return;
}
- // Get the index.
- idx = consts->len;
+ if (bc_map_insert(&prog->const_map, string, prog->consts.len, &idx))
+ {
+ BcConst* c;
+ BcId* id = bc_vec_item(&prog->const_map, idx);
- // Get the right slab.
- slabs = p->fidx == BC_PROG_MAIN || p->fidx == BC_PROG_READ ?
- &vm->main_const_slab :
- &vm->other_slabs;
+ // Get the index.
+ idx = id->idx;
- // Push an empty constant.
- c = bc_vec_pushEmpty(consts);
+ // Push an empty constant.
+ c = bc_vec_pushEmpty(&prog->consts);
- // Set the fields.
- c->val = bc_slabvec_strdup(slabs, string);
- c->base = BC_NUM_BIGDIG_MAX;
+ // Set the fields. We reuse the string in the ID (allocated by
+ // bc_map_insert()), because why not?
+ c->val = id->name;
+ c->base = BC_NUM_BIGDIG_MAX;
- // We need this to be able to tell that the number has not been allocated.
- bc_num_clear(&c->num);
+ // We need this to be able to tell that the number has not been
+ // allocated.
+ bc_num_clear(&c->num);
+ }
+ else
+ {
+ BcId* id = bc_vec_item(&prog->const_map, idx);
+ idx = id->idx;
+ }
- bc_parse_update(p, BC_INST_NUM, idx);
+ bc_parse_pushInstIdx(p, BC_INST_NUM, idx);
}
void
@@ -173,13 +177,13 @@ bc_parse_number(BcParse* p)
}
void
-bc_parse_text(BcParse* p, const char* text, bool is_stdin, bool is_exprs)
+bc_parse_text(BcParse* p, const char* text, BcMode mode)
{
BC_SIG_LOCK;
// Make sure the pointer isn't invalidated.
p->func = bc_vec_item(&p->prog->fns, p->fidx);
- bc_lex_text(&p->l, text, is_stdin, is_exprs);
+ bc_lex_text(&p->l, text, mode);
BC_SIG_UNLOCK;
}
diff --git a/src/program.c b/src/program.c
index abe203ddee46..e63949bb49e5 100644
--- a/src/program.c
+++ b/src/program.c
@@ -49,20 +49,6 @@
#include <vm.h>
/**
- * Quickly sets the const and strs vector pointers in the program. This is a
- * convenience function.
- * @param p The program.
- * @param f The new function.
- */
-static inline void
-bc_program_setVecs(BcProgram* p, BcFunc* f)
-{
- BC_SIG_ASSERT_LOCKED;
- p->consts = &f->consts;
- p->strs = &f->strs;
-}
-
-/**
* Does a type check for something that expects a number.
* @param r The result that will be checked.
* @param n The result's number.
@@ -124,11 +110,10 @@ bc_program_index(const char* restrict code, size_t* restrict bgn)
* @param n The number tied to the result.
* @return The string corresponding to the result and number.
*/
-static char*
+static inline char*
bc_program_string(BcProgram* p, const BcNum* n)
{
- BcFunc* f = bc_vec_item(&p->fns, n->rdx);
- return *((char**) bc_vec_item(&f->strs, n->scale));
+ return *((char**) bc_vec_item(&p->strs, n->scale));
}
#if BC_ENABLED
@@ -233,30 +218,38 @@ bc_program_pushBigdig(BcProgram* p, BcBigDig dig, BcResultType type)
}
size_t
-bc_program_addString(BcProgram* p, const char* str, size_t fidx)
+bc_program_addString(BcProgram* p, const char* str)
{
- BcFunc* f;
- char** str_ptr;
- BcVec* slabs;
+ size_t idx;
BC_SIG_ASSERT_LOCKED;
- // Push an empty string on the proper vector.
- f = bc_vec_item(&p->fns, fidx);
- str_ptr = bc_vec_pushEmpty(&f->strs);
+ if (bc_map_insert(&p->str_map, str, p->strs.len, &idx))
+ {
+ char** str_ptr;
+ BcId* id = bc_vec_item(&p->str_map, idx);
+
+ // Get the index.
+ idx = id->idx;
- // Figure out which slab vector to use.
- slabs = fidx == BC_PROG_MAIN || fidx == BC_PROG_READ ?
- &vm->main_slabs :
- &vm->other_slabs;
+ // Push an empty string on the proper vector.
+ str_ptr = bc_vec_pushEmpty(&p->strs);
- *str_ptr = bc_slabvec_strdup(slabs, str);
+ // We reuse the string in the ID (allocated by bc_map_insert()), because
+ // why not?
+ *str_ptr = id->name;
+ }
+ else
+ {
+ BcId* id = bc_vec_item(&p->str_map, idx);
+ idx = id->idx;
+ }
- return f->strs.len - 1;
+ return idx;
}
size_t
-bc_program_search(BcProgram* p, const char* id, bool var)
+bc_program_search(BcProgram* p, const char* name, bool var)
{
BcVec* v;
BcVec* map;
@@ -272,7 +265,7 @@ bc_program_search(BcProgram* p, const char* id, bool var)
// the parser calls this function. If the insert succeeds, we create a stack
// for the variable/array. But regardless, bc_map_insert() gives us the
// index of the item in i.
- if (bc_map_insert(map, id, v->len, &i))
+ if (bc_map_insert(map, name, v->len, &i))
{
BcVec* temp = bc_vec_pushEmpty(v);
bc_array_init(temp, var);
@@ -637,7 +630,7 @@ bc_program_const(BcProgram* p, const char* code, size_t* bgn)
// I lied. I actually push the result first. I can do this because the
// result will be popped on error. I also get the constant itself.
BcResult* r = bc_program_prepResult(p);
- BcConst* c = bc_vec_item(p->consts, bc_program_index(code, bgn));
+ BcConst* c = bc_vec_item(&p->consts, bc_program_index(code, bgn));
BcBigDig base = BC_PROG_IBASE(p);
// Only reparse if the base changed.
@@ -653,6 +646,8 @@ bc_program_const(BcProgram* p, const char* code, size_t* bgn)
bc_num_init(&c->num, BC_NUM_RDX(len));
BC_SIG_UNLOCK;
}
+ // We need to zero an already existing number.
+ else bc_num_zero(&c->num);
// bc_num_parse() should only do operations that cannot fail.
bc_num_parse(&c->num, c->val, base);
@@ -715,7 +710,7 @@ bc_program_read(BcProgram* p)
BcInstPtr ip;
size_t i;
const char* file;
- bool is_stdin;
+ BcMode mode;
BcFunc* f = bc_vec_item(&p->fns, BC_PROG_READ);
// If we are already executing a read, that is an error. So look for a read
@@ -730,11 +725,11 @@ bc_program_read(BcProgram* p)
// Save the filename because we are going to overwrite it.
file = vm->file;
- is_stdin = vm->is_stdin;
+ mode = vm->mode;
// It is a parse error if there needs to be more than one line, so we unset
// this to tell the lexer to not request more. We set it back later.
- vm->is_stdin = false;
+ vm->mode = BC_MODE_FILE;
if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
{
@@ -768,8 +763,8 @@ bc_program_read(BcProgram* p)
// We should *not* have run into EOF.
if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR);
- // Parse *one* expression, so is_stdin should be false.
- bc_parse_text(&vm->read_prs, vm->read_buf.v, false, false);
+ // Parse *one* expression, so mode should not be stdin.
+ bc_parse_text(&vm->read_prs, vm->read_buf.v, BC_MODE_FILE);
BC_SIG_LOCK;
vm->expr(&vm->read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
BC_SIG_UNLOCK;
@@ -813,7 +808,7 @@ bc_program_read(BcProgram* p)
exec_err:
BC_SIG_MAYLOCK;
- vm->is_stdin = is_stdin;
+ vm->mode = (uchar) mode;
vm->file = file;
BC_LONGJMP_CONT(vm);
}
@@ -1980,7 +1975,7 @@ bc_program_builtin(BcProgram* p, uchar inst)
#if BC_ENABLE_EXTRA_MATH
assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
#else // BC_ENABLE_EXTRA_MATH
- assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
+ assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IS_STRING);
#endif // BC_ENABLE_EXTRA_MATH
#ifndef BC_PROG_NO_STACK_CHECK
@@ -2001,7 +1996,8 @@ bc_program_builtin(BcProgram* p, uchar inst)
// We need to ensure that strings and arrays aren't passed to most builtins.
// The scale function can take strings in dc.
- if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC))
+ if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC) &&
+ inst != BC_INST_IS_NUMBER && inst != BC_INST_IS_STRING)
{
bc_program_type_num(opd, num);
}
@@ -2020,7 +2016,31 @@ bc_program_builtin(BcProgram* p, uchar inst)
BC_NUM_NEG_CLR_NP(res->d.n);
}
+
+ // Testing for number or string is easy.
+ else if (inst == BC_INST_IS_NUMBER || inst == BC_INST_IS_STRING)
+ {
+ bool cond;
+ bool is_str;
+
+ BC_SIG_LOCK;
+
+ bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
+
+ BC_SIG_UNLOCK;
+
+ // Test if the number is a string.
+ is_str = BC_PROG_STR(num);
+
+ // This confusing condition simply means that the instruction must be
+ // true if is_str is, or it must be false if is_str is. Otherwise, the
+ // returned value is false (0).
+ cond = ((inst == BC_INST_IS_STRING) == is_str);
+ if (cond) bc_num_one(&res->d.n);
+ }
+
#if BC_ENABLE_EXTRA_MATH
+
// irand() is easy.
else if (inst == BC_INST_IRAND)
{
@@ -2032,6 +2052,7 @@ bc_program_builtin(BcProgram* p, uchar inst)
bc_num_irand(num, &res->d.n, &p->rng);
}
+
#endif // BC_ENABLE_EXTRA_MATH
// Everything else is...not easy.
@@ -2049,6 +2070,9 @@ bc_program_builtin(BcProgram* p, uchar inst)
// bc_program_num() to a vector.
BcVec* v = (BcVec*) num;
+ // XXX: If this is changed, you should also change the similar
+ // code in bc_program_asciify().
+
#if BC_ENABLED
// Dereference the array, if necessary.
if (BC_IS_BC && v->size == sizeof(uchar))
@@ -2218,19 +2242,20 @@ bc_program_asciifyNum(BcProgram* p, BcNum* n)
}
/**
- * Executes the "asciify" command in dc.
- * @param p The program.
- * @param fidx The index of the current function.
+ * Executes the "asciify" command in bc and dc.
+ * @param p The program.
*/
static void
-bc_program_asciify(BcProgram* p, size_t fidx)
+bc_program_asciify(BcProgram* p)
{
BcResult *r, res;
BcNum* n;
- char str[2];
- char* str2;
uchar c;
size_t idx;
+#if BC_ENABLED
+ // This is in the outer scope because it has to be freed after a jump.
+ char* temp_str;
+#endif // BC_ENABLED
// Check the stack.
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
@@ -2241,34 +2266,98 @@ bc_program_asciify(BcProgram* p, size_t fidx)
bc_program_operand(p, &r, &n, 0);
assert(n != NULL);
+ assert(BC_IS_BC || r->t != BC_RESULT_ARRAY);
- // Asciify.
- if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
- else
+#if BC_ENABLED
+ // Handle arrays in bc specially.
+ if (r->t == BC_RESULT_ARRAY)
{
- // Get the string itself, then the first character.
- str2 = bc_program_string(p, n);
- c = (uchar) str2[0];
+ // Yes, this is one place where we need to cast the number from
+ // bc_program_num() to a vector.
+ BcVec* v = (BcVec*) n;
+ size_t i;
+
+ // XXX: If this is changed, you should also change the similar code in
+ // bc_program_builtin().
+
+ // Dereference the array, if necessary.
+ if (v->size == sizeof(uchar))
+ {
+ v = bc_program_dereference(p, v);
+ }
+
+ assert(v->size == sizeof(BcNum));
+
+ // Allocate the string and set the jump for it.
+ BC_SIG_LOCK;
+ temp_str = bc_vm_malloc(v->len + 1);
+ BC_SETJMP_LOCKED(vm, exit);
+ BC_SIG_UNLOCK;
+
+ // Convert the array.
+ for (i = 0; i < v->len; ++i)
+ {
+ BcNum* num = (BcNum*) bc_vec_item(v, i);
+
+ if (BC_PROG_STR(num))
+ {
+ temp_str[i] = (bc_program_string(p, num))[0];
+ }
+ else
+ {
+ temp_str[i] = (char) bc_program_asciifyNum(p, num);
+ }
+ }
+
+ temp_str[v->len] = '\0';
+
+ // Store the string in the slab and map, and free the temp string.
+ BC_SIG_LOCK;
+ idx = bc_program_addString(p, temp_str);
+ free(temp_str);
+ BC_UNSETJMP(vm);
+ BC_SIG_UNLOCK;
}
+ else
+#endif // BC_ENABLED
+ {
+ char str[2];
+ char* str2;
- // Fill the resulting string.
- str[0] = (char) c;
- str[1] = '\0';
+ // Asciify.
+ if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
+ else
+ {
+ // Get the string itself, then the first character.
+ str2 = bc_program_string(p, n);
+ c = (uchar) str2[0];
+ }
- // Add the string to the data structures.
- BC_SIG_LOCK;
- idx = bc_program_addString(p, str, fidx);
- BC_SIG_UNLOCK;
+ // Fill the resulting string.
+ str[0] = (char) c;
+ str[1] = '\0';
+
+ // Add the string to the data structures.
+ BC_SIG_LOCK;
+ idx = bc_program_addString(p, str);
+ BC_SIG_UNLOCK;
+ }
// Set the result
res.t = BC_RESULT_STR;
bc_num_clear(&res.d.n);
- res.d.n.rdx = fidx;
res.d.n.scale = idx;
// Pop and push.
bc_vec_pop(&p->results);
bc_vec_push(&p->results, &res);
+
+ return;
+
+#if BC_ENABLED
+exit:
+ free(temp_str);
+#endif // BC_ENABLED
}
/**
@@ -2516,8 +2605,8 @@ bc_program_execStr(BcProgram* p, const char* restrict code,
BC_SIG_UNLOCK;
- // Parse.
- bc_parse_text(&vm->read_prs, str, false, false);
+ // Parse. Only one expression is needed, so stdin isn't used.
+ bc_parse_text(&vm->read_prs, str, BC_MODE_FILE);
BC_SIG_LOCK;
vm->expr(&vm->read_prs, BC_PARSE_NOCALL);
@@ -2670,7 +2759,6 @@ bc_program_pushSeed(BcProgram* p)
static void
bc_program_addFunc(BcProgram* p, BcId* id_ptr)
{
- BcInstPtr* ip;
BcFunc* f;
BC_SIG_ASSERT_LOCKED;
@@ -2678,13 +2766,6 @@ bc_program_addFunc(BcProgram* p, BcId* id_ptr)
// Push and init.
f = bc_vec_pushEmpty(&p->fns);
bc_func_init(f, id_ptr->name);
-
- // This is to make sure pointers are updated if the array was moved.
- if (p->stack.len)
- {
- ip = bc_vec_top(&p->stack);
- bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
- }
}
size_t
@@ -2749,6 +2830,10 @@ bc_program_free(BcProgram* p)
bc_vec_free(&p->arr_map);
bc_vec_free(&p->results);
bc_vec_free(&p->stack);
+ bc_vec_free(&p->consts);
+ bc_vec_free(&p->const_map);
+ bc_vec_free(&p->strs);
+ bc_vec_free(&p->str_map);
bc_num_free(&p->asciify);
@@ -2842,10 +2927,10 @@ bc_program_init(BcProgram* p)
bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE);
bc_vec_push(&p->stack, &ip);
- // Make sure the pointers are properly set up.
- bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
-
- assert(p->consts != NULL && p->strs != NULL);
+ bc_vec_init(&p->consts, sizeof(BcConst), BC_DTOR_CONST);
+ bc_map_init(&p->const_map);
+ bc_vec_init(&p->strs, sizeof(char*), BC_DTOR_NONE);
+ bc_map_init(&p->str_map);
}
void
@@ -2871,7 +2956,6 @@ bc_program_reset(BcProgram* p)
// Reset the instruction pointer.
ip = bc_vec_top(&p->stack);
- bc_program_setVecs(p, f);
// NOLINTNEXTLINE
memset(ip, 0, sizeof(BcInstPtr));
@@ -2935,11 +3019,6 @@ bc_program_exec(BcProgram* p)
func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- // Ensure the pointers are correct.
- BC_SIG_LOCK;
- bc_program_setVecs(p, func);
- BC_SIG_UNLOCK;
-
#if !BC_HAS_COMPUTED_GOTO
#ifndef NDEBUG
@@ -3035,7 +3114,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@@ -3076,7 +3154,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@@ -3114,7 +3191,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@@ -3198,6 +3274,8 @@ bc_program_exec(BcProgram* p)
BC_PROG_LBL(BC_INST_SCALE_FUNC):
BC_PROG_LBL(BC_INST_SQRT):
BC_PROG_LBL(BC_INST_ABS):
+ BC_PROG_LBL(BC_INST_IS_NUMBER):
+ BC_PROG_LBL(BC_INST_IS_STRING):
#if BC_ENABLE_EXTRA_MATH
BC_PROG_LBL(BC_INST_IRAND):
#endif // BC_ENABLE_EXTRA_MATH
@@ -3211,7 +3289,7 @@ bc_program_exec(BcProgram* p)
BC_PROG_LBL(BC_INST_ASCIIFY):
// clang-format on
{
- bc_program_asciify(p, ip->func);
+ bc_program_asciify(p);
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
@@ -3219,7 +3297,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@@ -3270,7 +3347,6 @@ bc_program_exec(BcProgram* p)
// Set up the result and push.
r.t = BC_RESULT_STR;
bc_num_clear(&r.d.n);
- r.d.n.rdx = bc_program_index(code, &ip->idx);
r.d.n.scale = bc_program_index(code, &ip->idx);
bc_vec_push(&p->results, &r);
BC_PROG_JUMP(inst, code, ip);
@@ -3432,7 +3508,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@@ -3453,7 +3528,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@@ -3549,7 +3623,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
diff --git a/src/vector.c b/src/vector.c
index 92da4ba44eca..c8b99b71b83c 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -435,7 +435,6 @@ bc_map_insert(BcVec* restrict v, const char* name, size_t idx,
size_t* restrict i)
{
BcId id;
- BcVec* slabs;
BC_SIG_ASSERT_LOCKED;
@@ -450,10 +449,7 @@ bc_map_insert(BcVec* restrict v, const char* name, size_t idx,
return false;
}
- // This macro returns the correct slabs for the calculator.
- slabs = BC_VEC_MAP_SLABS;
-
- id.name = bc_slabvec_strdup(slabs, name);
+ id.name = bc_slabvec_strdup(&vm->slabs, name);
id.idx = idx;
bc_vec_pushAt(v, &id, *i);
@@ -465,6 +461,7 @@ size_t
bc_map_index(const BcVec* restrict v, const char* name)
{
size_t i;
+ BcId* id;
assert(v != NULL && name != NULL);
@@ -473,10 +470,10 @@ bc_map_index(const BcVec* restrict v, const char* name)
// If out of range, return invalid.
if (i >= v->len) return BC_VEC_INVALID_IDX;
- // Make sure the item exists.
- return strcmp(name, ((BcId*) bc_vec_item(v, i))->name) ?
- BC_VEC_INVALID_IDX :
- i;
+ id = (BcId*) bc_vec_item(v, i);
+
+ // Make sure the item exists and return appropriately.
+ return strcmp(name, id->name) ? BC_VEC_INVALID_IDX : i;
}
#if DC_ENABLED
diff --git a/src/vm.c b/src/vm.c
index 7a5166d2203d..069b43e6f4dc 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -649,9 +649,7 @@ bc_vm_shutdown(void)
bc_parse_free(&vm->prs);
bc_program_free(&vm->prog);
- bc_slabvec_free(&vm->other_slabs);
- bc_slabvec_free(&vm->main_slabs);
- bc_slabvec_free(&vm->main_const_slab);
+ bc_slabvec_free(&vm->slabs);
#endif // !BC_ENABLE_LIBRARY
bc_vm_freeTemps();
@@ -966,30 +964,17 @@ bc_vm_clean(void)
// constants, and code.
if (good && vm->prog.stack.len == 1 && ip->idx == f->code.len)
{
+ // XXX: Nothing can be popped in dc. Deal with it.
+
#if BC_ENABLED
if (BC_IS_BC)
{
+ // XXX: you cannot delete strings, functions, or constants in bc.
+ // Deal with it.
bc_vec_popAll(&f->labels);
- bc_vec_popAll(&f->strs);
- bc_vec_popAll(&f->consts);
-
- // I can't clear out the other_slabs because it has functions,
- // consts, strings, vars, and arrays. It has strings from *other*
- // functions, specifically.
- bc_slabvec_clear(&vm->main_const_slab);
- bc_slabvec_clear(&vm->main_slabs);
}
#endif // BC_ENABLED
-#if DC_ENABLED
- // Note to self: you cannot delete strings and functions. Deal with it.
- if (BC_IS_DC)
- {
- bc_vec_popAll(vm->prog.consts);
- bc_slabvec_clear(&vm->main_const_slab);
- }
-#endif // DC_ENABLED
-
bc_vec_popAll(&f->code);
ip->idx = 0;
@@ -998,33 +983,21 @@ bc_vm_clean(void)
/**
* Process a bunch of text.
- * @param text The text to process.
- * @param is_stdin True if the text came from stdin, false otherwise.
- * @param is_exprs True if the text is from command-line expressions, false
- * otherwise.
+ * @param text The text to process.
+ * @param mode The mode to process in.
*/
static void
-bc_vm_process(const char* text, bool is_stdin, bool is_exprs)
+bc_vm_process(const char* text, BcMode mode)
{
// Set up the parser.
- bc_parse_text(&vm->prs, text, is_stdin, is_exprs);
+ bc_parse_text(&vm->prs, text, mode);
- do
+ while (vm->prs.l.t != BC_LEX_EOF)
{
+ // Parsing requires a signal lock. We also don't parse everything; we
+ // want to execute as soon as possible for *everything*.
BC_SIG_LOCK;
-
-#if BC_ENABLED
- // If the first token is the keyword define, then we need to do this
- // specially because bc thinks it may not be able to parse.
- if (vm->prs.l.t == BC_LEX_KW_DEFINE) vm->parse(&vm->prs);
-#endif // BC_ENABLED
-
- // Parse it all.
- while (BC_PARSE_CAN_PARSE(vm->prs))
- {
- vm->parse(&vm->prs);
- }
-
+ vm->parse(&vm->prs);
BC_SIG_UNLOCK;
// Execute if possible.
@@ -1035,7 +1008,6 @@ bc_vm_process(const char* text, bool is_stdin, bool is_exprs)
// Flush in interactive mode.
if (BC_I) bc_file_flush(&vm->fout, bc_flush_save);
}
- while (vm->prs.l.t != BC_LEX_EOF);
}
#if BC_ENABLED
@@ -1052,6 +1024,7 @@ bc_vm_endif(void)
bc_parse_endif(&vm->prs);
bc_program_exec(&vm->prog);
}
+
#endif // BC_ENABLED
/**
@@ -1068,6 +1041,8 @@ bc_vm_file(const char* file)
assert(!vm->sig_pop);
+ vm->mode = BC_MODE_FILE;
+
// Set up the lexer.
bc_lex_file(&vm->prs.l, file);
@@ -1083,7 +1058,7 @@ bc_vm_file(const char* file)
BC_SIG_UNLOCK;
// Process it.
- bc_vm_process(data, false, false);
+ bc_vm_process(data, BC_MODE_FILE);
#if BC_ENABLED
// Make sure to end any open if statements.
@@ -1129,7 +1104,7 @@ bc_vm_readLine(bool clear)
s = bc_read_line(&vm->line_buf, ">>> ");
vm->eof = (s == BC_STATUS_EOF);
}
- while (!(s) && !vm->eof && vm->line_buf.len < 1);
+ while (s == BC_STATUS_SUCCESS && !vm->eof && vm->line_buf.len < 1);
good = (vm->line_buf.len > 1);
@@ -1145,12 +1120,14 @@ bc_vm_readLine(bool clear)
static void
bc_vm_stdin(void)
{
+ bool clear;
+
#if BC_ENABLE_LIBRARY
BcVm* vm = bcl_getspecific();
#endif // BC_ENABLE_LIBRARY
- vm->clear = true;
- vm->is_stdin = true;
+ clear = true;
+ vm->mode = BC_MODE_STDIN;
// Set up the lexer.
bc_lex_file(&vm->prs.l, bc_program_stdin_name);
@@ -1175,18 +1152,18 @@ bc_vm_stdin(void)
restart:
// While we still read data from stdin.
- while (bc_vm_readLine(vm->clear))
+ while (bc_vm_readLine(clear))
{
size_t len = vm->buffer.len - 1;
const char* str = vm->buffer.v;
// We don't want to clear the buffer when the line ends with a backslash
// because a backslash newline is special in bc.
- vm->clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
- if (!vm->clear) continue;
+ clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
+ if (!clear) continue;
// Process the data.
- bc_vm_process(vm->buffer.v, true, false);
+ bc_vm_process(vm->buffer.v, BC_MODE_STDIN);
if (vm->eof) break;
else
@@ -1264,11 +1241,14 @@ bc_vm_readBuf(bool clear)
static void
bc_vm_exprs(void)
{
+ bool clear;
+
#if BC_ENABLE_LIBRARY
BcVm* vm = bcl_getspecific();
#endif // BC_ENABLE_LIBRARY
- vm->clear = true;
+ clear = true;
+ vm->mode = BC_MODE_EXPRS;
// Prepare the lexer.
bc_lex_file(&vm->prs.l, bc_program_exprs_name);
@@ -1282,23 +1262,23 @@ bc_vm_exprs(void)
BC_SETJMP_LOCKED(vm, err);
BC_SIG_UNLOCK;
- while (bc_vm_readBuf(vm->clear))
+ while (bc_vm_readBuf(clear))
{
size_t len = vm->buffer.len - 1;
const char* str = vm->buffer.v;
// We don't want to clear the buffer when the line ends with a backslash
// because a backslash newline is special in bc.
- vm->clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
- if (!vm->clear) continue;
+ clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
+ if (!clear) continue;
// Process the data.
- bc_vm_process(vm->buffer.v, false, true);
+ bc_vm_process(vm->buffer.v, BC_MODE_EXPRS);
}
// If we were not supposed to clear, then we should process everything. This
// makes sure that errors get reported.
- if (!vm->clear) bc_vm_process(vm->buffer.v, false, true);
+ if (!clear) bc_vm_process(vm->buffer.v, BC_MODE_EXPRS);
err:
@@ -1329,7 +1309,7 @@ static void
bc_vm_load(const char* name, const char* text)
{
bc_lex_file(&vm->prs.l, name);
- bc_parse_text(&vm->prs, text, false, false);
+ bc_parse_text(&vm->prs, text, BC_MODE_FILE);
BC_SIG_LOCK;
@@ -1553,6 +1533,7 @@ bc_vm_boot(int argc, char* argv[])
bc_vm_gettext();
#if BC_ENABLE_LINE_LIB
+
// Initialize the output file buffers.
bc_file_init(&vm->ferr, stderr);
bc_file_init(&vm->fout, stdout);
@@ -1561,6 +1542,7 @@ bc_vm_boot(int argc, char* argv[])
vm->buf = output_bufs;
#else // BC_ENABLE_LINE_LIB
+
// Initialize the output file buffers. They each take portions of the global
// buffer. stdout gets more because it will probably have more data.
bc_file_init(&vm->ferr, STDERR_FILENO, output_bufs + BC_VM_STDOUT_BUF_SIZE,
@@ -1584,10 +1566,8 @@ bc_vm_boot(int argc, char* argv[])
#if !BC_ENABLE_LIBRARY
- // Initialize the slab vectors.
- bc_slabvec_init(&vm->main_const_slab);
- bc_slabvec_init(&vm->main_slabs);
- bc_slabvec_init(&vm->other_slabs);
+ // Initialize the slab vector.
+ bc_slabvec_init(&vm->slabs);
#endif // !BC_ENABLE_LIBRARY
diff --git a/tests/bc/all.txt b/tests/bc/all.txt
index f85491d12424..af5eaaa42fb7 100644
--- a/tests/bc/all.txt
+++ b/tests/bc/all.txt
@@ -51,3 +51,10 @@ divmod
modexp
bitfuncs
leadingzero
+is_number
+is_string
+asciify_array
+line_by_line1
+line_by_line2
+line_loop_quit1
+line_loop_quit2
diff --git a/tests/bc/asciify_array.txt b/tests/bc/asciify_array.txt
new file mode 100644
index 000000000000..4efae1d13876
--- /dev/null
+++ b/tests/bc/asciify_array.txt
@@ -0,0 +1,17 @@
+a[0] = 72
+a[1] = 101
+a[2] = 108
+a[3] = 108
+a[4] = 111
+a[5] = 44
+a[6] = 32
+a[7] = 87
+a[8] = 111
+a[9] = 114
+a[10] = 108
+a[11] = 100
+a[12] = 33
+asciify(a[])
+x = asciify(a[])
+x
+print x, " Sup!\n"
diff --git a/tests/bc/asciify_array_results.txt b/tests/bc/asciify_array_results.txt
new file mode 100644
index 000000000000..d0dc2bc37514
--- /dev/null
+++ b/tests/bc/asciify_array_results.txt
@@ -0,0 +1,3 @@
+Hello, World!
+Hello, World!
+Hello, World! Sup!
diff --git a/tests/bc/errors/34.txt b/tests/bc/errors/34.txt
new file mode 100644
index 000000000000..1b452c609159
--- /dev/null
+++ b/tests/bc/errors/34.txt
@@ -0,0 +1,357 @@
+ibase =2C
+0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
+
+define printarray(a[], len) {
+
+ auto i
+
+ for (i = 0; i < hen; ++i) {
+ a[i]
+ }
+}
+
+define a2(a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {(x)#086$
+7.715E
+asciify(x)#
+2893.M9
+
+7.7150-1#93.19
+asciify(x)#d(1) {
+x = asciify(x)#086$
+7.7150-1893.19
+asciify(x)
+ a[i] = a[i] * a[i]
+ }
+
+ printarray(a[], len)
+}
+
+define a4(a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a6(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a1(*a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a[i] = i
+ }
+
+ a2(a[], len)
+
+ printarray(a[], len)
+}
+
+define a3(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a4(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a5(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a2(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a7(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a6(a__[], len)
+
+ printarray(a__[], len)
+}
+
+len = 16
+
+a1(a[], len)
+printarray(a[], len)
+a3(a[], len)
+printarray(a[], len)
+a5(a[], len)
+printarray(a[], len)
+a7(a[], len)
+printarray(a[], len)
+
+a1(b[], len)
+printarray(b[], len)
+a3(b[], len)
+printarray(b[], len)
+a5(b[], len)
+printarray(b[], len)
+a7(b[], len)
+printarray(b[], len)
+
+a1[0] = 0
+a2[0] = 0
+a3[0] = 0
+a4[0] = 0
+a5[0] = 0
+a6[0] = 0
+a7[0] = 0
+a8[0] = 0
+a9[0] = 0
+a10[0] = 0
+a11[0] = 0
+a12[0]
+a13[0] = 0
+a14[0] = 0
+a15[0] = 0
+a16[0]
+a17[0] = 0
+a18[0] = 0
+a19[0] = 0
+a20[0]
+a21[0] = 0
+a22[0] = 0
+a23[0] = 0
+a24[0]
+a25[0] = 0
+a26[0] = ase =2C
+0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
+
+define printarray(a[], len) {
+
+ auto i
+
+ for (i = 0; i < hen; ++i) {
+ a[i]
+ }
+}
+
+define a2(a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {(x)#086$
+7.715E
+asciify(x)#
+2893.M9
+
+7.7150-1#93.19
+asciify(x)#d(1) {
+x = asciify(x)#086$
+7.7150-1893.19
+asciify(x)
+ a[i] = a[i] * a[i]
+ }
+
+ printarray(a[], len)
+}
+
+define a4(a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a6(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a1(*a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a[i] = i
+ }
+
+ a2(a[], len)
+
+ printarray(a[], len)
+}
+
+define a3(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a4(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a5(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a2(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a7(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a6(a__[], len)
+
+ printarray(a__[], len)
+}
+
+len = 16
+
+a1(a[], len)
+printarray(a[], len)
+a3(a[], len)
+printarray(a[], len)
+a5(a[], len)
+printarray(a[], len)
+a7(a[], len)
+printarray(a[], len)
+
+a1(b[], len)
+printarray(b[], len)
+a3(b[], len)
+printarray(b[], len)
+a5(b[], len)
+printarray(b[], len)
+a7(b[], len)
+printarray(b[], len)
+
+a1[0] = 0
+a2[0] = 0
+a3[0] = 0
+a4[0] = 0
+a5[0] = 0
+a6[0] = 0
+a7[0] = 0
+a8[0] = 0
+a9[0] = 0
+a10[ ] = 0
+a11[0] = 0
+a12[0]
+a13[0] = 0
+a14[0] = 0
+a15[0] = 0
+a16[0]
+a17[0] = 0
+a18[0] = 0
+a19[0] = 0
+a20[0]
+a21[0] = 0
+a22[0] = 0
+a23[0] = 0
+a24[0]
+a25[0] = 0
+a26[0] = 0
+a27[0] = 0
+a28[0] = 0
+a29[0] = 0
+a30[0] = 0
+a31[0] = 0
+a32[0] = 0
+a33[0] = 0
+a34[0] = 0
+a35[0] = 0
+a36[0] = 0
+a37[0] = 0
+a38[0] = 0
+a39[0] = 0
+a40[0] = 0
+a41[0] = 0
+a42[0] = 0
+a43[0] = 0
+a44[0] = 0
+a45[0] = 0
+a46[0] = 0
+a47[0] = 0
+a48[0] = 0
+a49[0] = 0
+a50[0] = 0
+a51[0] = 0
+a52[0] = 50] = 0
+a0
+a27[0] = 0
+a28[0] = 0
+a29[0] = 0
+a30[0] = 0
+a31[0] = 0
+a32[0] = 0
+a33[0] = 0
+a34[0] = 0
+a35[0] = 0
+a36[0] = 0
+a37[0] = 0
+a38[0] = 0
+a39[0] = 0
+a40[0] = 0
+a41[0] = 0
+a42[0] = 0
+a43[0] = 0
+a44[0] = 0
+a45[0] = 0
+a46[0] = 0
+a47[0] = 0
+a48[0] = 0
+a49[0] = 0
+a50[0] = 0
+a51[0] = 0
+a52[0] = 50] = 0
+a \ No newline at end of file
diff --git a/tests/bc/errors/35.txt b/tests/bc/errors/35.txt
new file mode 100644
index 000000000000..40e79633c4a5
--- /dev/null
+++ b/tests/bc/errors/35.txt
@@ -0,0 +1 @@
+e(q[asciify(q[])]) \ No newline at end of file
diff --git a/tests/bc/errors/36.txt b/tests/bc/errors/36.txt
new file mode 100644
index 000000000000..5929bdb7a5b9
--- /dev/null
+++ b/tests/bc/errors/36.txt
@@ -0,0 +1,11 @@
+n0
+for (i*= 9; i < 725; ++i)strse=a[0] = asciify(180)
+d2
+asciify(a[])
+x = a433
+asciify(a[])
+x = asciify(a[])
+x = asciify(18 = 72@II^II
+F;FR2
+F;FRI3
+Qor \ No newline at end of file
diff --git a/tests/bc/is_number.txt b/tests/bc/is_number.txt
new file mode 100644
index 000000000000..f9e1f753b0a3
--- /dev/null
+++ b/tests/bc/is_number.txt
@@ -0,0 +1,13 @@
+is_number(5)
+is_number(18923740913.12809374)
+is_number(abs(0.5))
+is_number(a[1])
+i = 0
+is_number(b[i])
+is_number("string")
+is_number(asciify("this"))
+is_number(asciify(122))
+x = asciify(121)
+is_number(x)
+a[2] = asciify(120)
+is_number(a[2])
diff --git a/tests/bc/is_number_results.txt b/tests/bc/is_number_results.txt
new file mode 100644
index 000000000000..1c03b9c18714
--- /dev/null
+++ b/tests/bc/is_number_results.txt
@@ -0,0 +1,10 @@
+1
+1
+1
+1
+1
+0
+0
+0
+0
+0
diff --git a/tests/bc/is_string.txt b/tests/bc/is_string.txt
new file mode 100644
index 000000000000..bfd7136d2dea
--- /dev/null
+++ b/tests/bc/is_string.txt
@@ -0,0 +1,13 @@
+is_string(5)
+is_string(18923740913.12809374)
+is_string(abs(0.5))
+is_string(a[1])
+i = 0
+is_string(b[i])
+is_string("string")
+is_string(asciify("this"))
+is_string(asciify(122))
+x = asciify(121)
+is_string(x)
+a[2] = asciify(120)
+is_string(a[2])
diff --git a/tests/bc/is_string_results.txt b/tests/bc/is_string_results.txt
new file mode 100644
index 000000000000..99f11f6b2e75
--- /dev/null
+++ b/tests/bc/is_string_results.txt
@@ -0,0 +1,10 @@
+0
+0
+0
+0
+0
+1
+1
+1
+1
+1
diff --git a/tests/bc/line_by_line1.txt b/tests/bc/line_by_line1.txt
new file mode 100644
index 000000000000..daf328e2c03e
--- /dev/null
+++ b/tests/bc/line_by_line1.txt
@@ -0,0 +1,10 @@
+1+1
+
+define a (x) {
+ print "a(", x, ")\n"
+ quit
+}
+
+a(10)
+
+quit
diff --git a/tests/bc/line_by_line1_results.txt b/tests/bc/line_by_line1_results.txt
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/bc/line_by_line1_results.txt
@@ -0,0 +1 @@
+2
diff --git a/tests/bc/line_by_line2.txt b/tests/bc/line_by_line2.txt
new file mode 100644
index 000000000000..b05c2169aced
--- /dev/null
+++ b/tests/bc/line_by_line2.txt
@@ -0,0 +1,9 @@
+1+1
+
+define a (x) {
+ print "a(", x, ")\n"
+}
+
+a(10)
+
+quit
diff --git a/tests/bc/line_by_line2_results.txt b/tests/bc/line_by_line2_results.txt
new file mode 100644
index 000000000000..3760375f171d
--- /dev/null
+++ b/tests/bc/line_by_line2_results.txt
@@ -0,0 +1,3 @@
+2
+a(10)
+0
diff --git a/tests/bc/line_loop_quit1.txt b/tests/bc/line_loop_quit1.txt
new file mode 100644
index 000000000000..03a6ca111f47
--- /dev/null
+++ b/tests/bc/line_loop_quit1.txt
@@ -0,0 +1,2 @@
+3
+for (i = 0; i < 3; ++i) i; quit
diff --git a/tests/bc/line_loop_quit1_results.txt b/tests/bc/line_loop_quit1_results.txt
new file mode 100644
index 000000000000..17342202bbfc
--- /dev/null
+++ b/tests/bc/line_loop_quit1_results.txt
@@ -0,0 +1,4 @@
+3
+0
+1
+2
diff --git a/tests/bc/line_loop_quit2.txt b/tests/bc/line_loop_quit2.txt
new file mode 100644
index 000000000000..6d6a440b3dd4
--- /dev/null
+++ b/tests/bc/line_loop_quit2.txt
@@ -0,0 +1,3 @@
+3
+for (i = 0; i < 3; ++i) i; \
+quit
diff --git a/tests/bc/line_loop_quit2_results.txt b/tests/bc/line_loop_quit2_results.txt
new file mode 100644
index 000000000000..17342202bbfc
--- /dev/null
+++ b/tests/bc/line_loop_quit2_results.txt
@@ -0,0 +1,4 @@
+3
+0
+1
+2
diff --git a/tests/bc/scripts/afl1.bc b/tests/bc/scripts/afl1.bc
new file mode 100644
index 000000000000..bbb393a30fe3
--- /dev/null
+++ b/tests/bc/scripts/afl1.bc
@@ -0,0 +1,261 @@
+ibase =2C
+0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
+
+define printarray(a[], len) {
+
+ auto i
+
+ for (i = 0; i < hen; ++i) {
+ a[i]
+ }
+}
+
+define a2(a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {(x)#086$
+7.715E
+asciify(x)#
+2893.M9
+
+7.7150-1#93.19
+asciify(x)#d(1) {
+x = asciify(x)#086$
+7.7150-1893.19
+asciify(x)
+ a[i] = a[i] * a[i]
+ }
+
+ printarray(a[], len)
+}
+
+define a4(a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a6(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a1(*a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a[i] = i
+ }
+
+ a2(a[], len)
+
+ printarray(a[], len)
+}
+
+define a3(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a4(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a5(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a2(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a7(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a6(a__[], len)
+
+ printarray(a__[], len)
+}
+
+len = 16
+
+a1(a[], len)
+printarray(a[], len)
+a3(a[], len)
+printarray(a[], len)
+a5(a[], len)
+printarray(a[], len)
+a7(a[], len)
+printarray(a[], len)
+
+a1(b[], len)
+printarray(b[], len)
+a3(b[], len)
+printarray(b[], len)
+a5(b[], len)
+printarray(b[], len)
+a7(b[], len)
+printarray(b[], len)
+
+a1[0] = 0
+a2[0] = 0
+a3[0] = 0
+a4[0] = 0
+a5[0] = 0
+a6[0] = 0
+a7[0] = 0
+a8[0] = 0
+a9[0] = 0
+a10[0] = 0
+a11[0] = 0
+a12[0]
+a13[0] = 0
+a14[0] = 0
+a15[0] = 0
+a16[0]
+a17[0] = 0
+a18[0] = 0
+a19[0] = 0
+a20[0]
+a21[0] = 0
+a22[0] = 0
+a23[0] = 0
+a24[0]
+a25[0] = 0
+a26[0] = ase =2C
+0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
+
+define printarray(a[], len) {
+
+ auto i
+
+ for (i = 0; i < hen; ++i) {
+ a[i]
+ }
+}
+
+define a2(a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {(x)#086$
+7.715E
+asciify(x)#
+2893.M9
+
+7.7150-1#93.19
+asciify(x)#d(1) {
+x = asciify(x)#086$
+7.7150-1893.19
+asciify(x)
+ a[i] = a[i] * a[i]
+ }
+
+ printarray(a[], len)
+}
+
+define a4(a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a6(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = a__[i] * a__[i]
+ }
+
+ printarray(a__[], len)
+}
+
+define a1(*a[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a[i] = i
+ }
+
+ a2(a[], len)
+
+ printarray(a[], len)
+}
+
+define a3(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a4(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a5(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a2(a__[], len)
+
+ printarray(a__[], len)
+}
+
+define a7(*a__[], len) {
+
+ auto i
+
+ for (i = 0; i < len; ++i) {
+ a__[i] = i
+ }
+
+ a6(a__[], len)
+
+ printarray(a__[], len)
+}
+
+len = 16
+
+a1(a[], len)
+printarray(a[], len)
diff --git a/tests/bc/scripts/afl1.txt b/tests/bc/scripts/afl1.txt
new file mode 100644
index 000000000000..9d3ac4b542fa
--- /dev/null
+++ b/tests/bc/scripts/afl1.txt
@@ -0,0 +1,1571 @@
+.2520876288594257447
+0
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+.2520876288594257447
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+
+7.2198
+
+74019.69
+6.2198
+
+-41243.8202
+
+0
+0
+0
+0
+0
diff --git a/tests/bc/scripts/all.txt b/tests/bc/scripts/all.txt
index 0a8d2fe17c6c..b4a178783796 100644
--- a/tests/bc/scripts/all.txt
+++ b/tests/bc/scripts/all.txt
@@ -16,3 +16,4 @@ screen.bc
strings2.bc
ifs.bc
ifs2.bc
+afl1.bc
diff --git a/tests/dc/all.txt b/tests/dc/all.txt
index 8942e087768b..5d6978e5790a 100644
--- a/tests/dc/all.txt
+++ b/tests/dc/all.txt
@@ -21,5 +21,8 @@ scientific
engineering
vars
misc
+misc1
strings
rand
+is_number
+is_string
diff --git a/tests/dc/errors/15.txt b/tests/dc/errors/15.txt
index adb809dcca3d..902a38bcbe37 100644
--- a/tests/dc/errors/15.txt
+++ b/tests/dc/errors/15.txt
@@ -1,11 +1,117 @@
-0bpax1bpR
-1bpR
-.218933b987pR
-_19bp/98
-_38_.1/19bp38_.1/98
-_38921.1/98/98
-_38_.1/98
-_38921.1/98
-98
-_38921.1/98
-73.289 75bpu
+0 lip1-si0l0+2o0sx_9lq+pR 0900pR
+_100900pR
+_10900p0bpR
+1bp0
+.20bpR
+100000.0000005bpR
+_10bpR
+_.1000[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
+1 2+p+p
+3+p
+4+p
+5+p
+6+p
+7+p
+8+p
+9+p
+16+p
+17+p
+18+p
+19.p
+20+p
+21+0+p
+71+xx0sx0s0
+1 2+p+p
+3o
+70+p
+70+p
+70+p
+70+p
+22+p
+20+p
+20+p
+20+p
+20+p
+x0+p
+20+p
+0 lip1-si0{0+2i0l0+200sx0.1009
+40+1+p
+4000pR
+_10900p0bpR
+1bp0
+.20bpR
+100000.002+p
+20+p
+20+p
+20+p
+20+p
+x0+p
+2000005bpR
+_10bpR
+_.10yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy00[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
+1 2+p+p
+3+p
+4+p
+5+p
+6+p
+7+p
+8+p
+9+p
+10p
++p
+11+p
+12+p
+13+p
+14+p
+15+p
+16+p
+17+p
+18+p
+19+p
+20+p
+21+0+p
+71+xx0sx0s0
+1 2+p+p
+3o
+70+p
+70+p
+70+p
+70+p
+22+p
+20+p
+
+20+p
+30+p
+30+p
+30+p
+0b30+p
+30+p
+30+p
+30+p
+30+p
+30+p
+30+p
+40"1+p
+40+p
+40+p
+40+p
+40+p
+40+p
+40+p
+40+p
+40+p
+50+p
+50+p
+50+p
+50+p
+50+p
+50+p
+50+p
+50+p
+50+p
+5pR
+100000.0070000bpR
+^20+pR
+_.10100000.0070000bpR
+^20+pR
+_.1000Kl0;0;rpRl0
diff --git a/tests/dc/errors/34.txt b/tests/dc/errors/34.txt
deleted file mode 100644
index 902a38bcbe37..000000000000
--- a/tests/dc/errors/34.txt
+++ /dev/null
@@ -1,117 +0,0 @@
-0 lip1-si0l0+2o0sx_9lq+pR 0900pR
-_100900pR
-_10900p0bpR
-1bp0
-.20bpR
-100000.0000005bpR
-_10bpR
-_.1000[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
-1 2+p+p
-3+p
-4+p
-5+p
-6+p
-7+p
-8+p
-9+p
-16+p
-17+p
-18+p
-19.p
-20+p
-21+0+p
-71+xx0sx0s0
-1 2+p+p
-3o
-70+p
-70+p
-70+p
-70+p
-22+p
-20+p
-20+p
-20+p
-20+p
-x0+p
-20+p
-0 lip1-si0{0+2i0l0+200sx0.1009
-40+1+p
-4000pR
-_10900p0bpR
-1bp0
-.20bpR
-100000.002+p
-20+p
-20+p
-20+p
-20+p
-x0+p
-2000005bpR
-_10bpR
-_.10yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy00[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
-1 2+p+p
-3+p
-4+p
-5+p
-6+p
-7+p
-8+p
-9+p
-10p
-+p
-11+p
-12+p
-13+p
-14+p
-15+p
-16+p
-17+p
-18+p
-19+p
-20+p
-21+0+p
-71+xx0sx0s0
-1 2+p+p
-3o
-70+p
-70+p
-70+p
-70+p
-22+p
-20+p
-
-20+p
-30+p
-30+p
-30+p
-0b30+p
-30+p
-30+p
-30+p
-30+p
-30+p
-30+p
-40"1+p
-40+p
-40+p
-40+p
-40+p
-40+p
-40+p
-40+p
-40+p
-50+p
-50+p
-50+p
-50+p
-50+p
-50+p
-50+p
-50+p
-50+p
-5pR
-100000.0070000bpR
-^20+pR
-_.10100000.0070000bpR
-^20+pR
-_.1000Kl0;0;rpRl0
diff --git a/tests/dc/is_number.txt b/tests/dc/is_number.txt
new file mode 100644
index 000000000000..358182927326
--- /dev/null
+++ b/tests/dc/is_number.txt
@@ -0,0 +1,9 @@
+5upR
+18923740913.12809374upR
+1;aupR
+0sili;bupR
+[string]upR
+[this]aupR
+122aupR
+121asxlxupR
+120a2:a2;aupR
diff --git a/tests/dc/is_number_results.txt b/tests/dc/is_number_results.txt
new file mode 100644
index 000000000000..6c8f29cea4ab
--- /dev/null
+++ b/tests/dc/is_number_results.txt
@@ -0,0 +1,9 @@
+1
+1
+1
+1
+0
+0
+0
+0
+0
diff --git a/tests/dc/is_string.txt b/tests/dc/is_string.txt
new file mode 100644
index 000000000000..6798fa3904b8
--- /dev/null
+++ b/tests/dc/is_string.txt
@@ -0,0 +1,9 @@
+5tpR
+18923740913.12809374tpR
+1;atpR
+0sili;btpR
+[string]tpR
+[this]atpR
+122atpR
+121asxlxtpR
+120a2:a2;atpR
diff --git a/tests/dc/is_string_results.txt b/tests/dc/is_string_results.txt
new file mode 100644
index 000000000000..0c6a1c9abd7a
--- /dev/null
+++ b/tests/dc/is_string_results.txt
@@ -0,0 +1,9 @@
+0
+0
+0
+0
+1
+1
+1
+1
+1
diff --git a/tests/dc/misc1.txt b/tests/dc/misc1.txt
new file mode 100644
index 000000000000..a512573ae548
--- /dev/null
+++ b/tests/dc/misc1.txt
@@ -0,0 +1,26 @@
+0bpax1bpR
+1bpR
+.218933b987pR
+_19bp/98
+_38_.1/19bp38_.1/98
+_38921.1/98/98
+_38_.1/98
+_38921.1/98
+98
+_38921.1/98
+73.289 75bpu
+# These just empty the stack.
+pR
+pR
+pR
+pR
+pR
+pR
+pR
+pR
+pR
+pR
+pR
+pR
+pR
+pR
diff --git a/tests/dc/misc1_results.txt b/tests/dc/misc1_results.txt
new file mode 100644
index 000000000000..d2f8ad70b4b8
--- /dev/null
+++ b/tests/dc/misc1_results.txt
@@ -0,0 +1,21 @@
+0
+1
+1
+987
+19
+19
+75
+1
+73.289
+98
+0
+98
+0
+380
+98
+0
+-380
+19
+380
+98
+0
diff --git a/tests/other.sh b/tests/other.sh
index 41c5f78e2b40..c71189b9b323 100755
--- a/tests/other.sh
+++ b/tests/other.sh
@@ -535,7 +535,7 @@ printf 'pass\n'
if [ "$d" = "bc" ]; then
printf 'Running %s limits tests...' "$d"
- printf 'limits\n' | "$exe" "$@" > "$out2" /dev/null 2>&1
+ printf 'limits\n' | "$exe" "$@" /dev/null > "$out2" 2>&1
checktest_retcode "$d" "$?" "limits"