vendor/bc: import version 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.
This commit is contained in:
parent
9471e6a095
commit
0b671e8cf1
47
MEMORY_BUGS.md
Normal file
47
MEMORY_BUGS.md
Normal file
@ -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`.
|
39
NEWS.md
39
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.
|
||||
|
@ -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
|
||||
|
43
configure.sh
43
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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, \
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
27
include/vm.h
27
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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
34
src/data.c
34
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
|
||||
|
10
src/dc_lex.c
10
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);
|
||||
|
@ -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
|
||||
|
12
src/lang.c
12
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)
|
||||
{
|
||||
|
43
src/lex.c
43
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
54
src/parse.c
54
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;
|
||||
}
|
||||
|
253
src/program.c
253
src/program.c
@ -48,20 +48,6 @@
|
||||
#include <program.h>
|
||||
#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.
|
||||
@ -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);
|
||||
|
||||
// Figure out which slab vector to use.
|
||||
slabs = fidx == BC_PROG_MAIN || fidx == BC_PROG_READ ?
|
||||
&vm->main_slabs :
|
||||
&vm->other_slabs;
|
||||
// Get the index.
|
||||
idx = id->idx;
|
||||
|
||||
*str_ptr = bc_slabvec_strdup(slabs, str);
|
||||
// Push an empty string on the proper vector.
|
||||
str_ptr = bc_vec_pushEmpty(&p->strs);
|
||||
|
||||
return f->strs.len - 1;
|
||||
// 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 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);
|
||||
|
15
src/vector.c
15
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
|
||||
|
100
src/vm.c
100
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
|
||||
|
||||
|
@ -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
|
||||
|
17
tests/bc/asciify_array.txt
Normal file
17
tests/bc/asciify_array.txt
Normal file
@ -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"
|
3
tests/bc/asciify_array_results.txt
Normal file
3
tests/bc/asciify_array_results.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Hello, World!
|
||||
Hello, World!
|
||||
Hello, World! Sup!
|
357
tests/bc/errors/34.txt
Normal file
357
tests/bc/errors/34.txt
Normal file
@ -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
|
1
tests/bc/errors/35.txt
Normal file
1
tests/bc/errors/35.txt
Normal file
@ -0,0 +1 @@
|
||||
e(q[asciify(q[])])
|
11
tests/bc/errors/36.txt
Normal file
11
tests/bc/errors/36.txt
Normal file
@ -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
|
13
tests/bc/is_number.txt
Normal file
13
tests/bc/is_number.txt
Normal file
@ -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])
|
10
tests/bc/is_number_results.txt
Normal file
10
tests/bc/is_number_results.txt
Normal file
@ -0,0 +1,10 @@
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
13
tests/bc/is_string.txt
Normal file
13
tests/bc/is_string.txt
Normal file
@ -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])
|
10
tests/bc/is_string_results.txt
Normal file
10
tests/bc/is_string_results.txt
Normal file
@ -0,0 +1,10 @@
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
10
tests/bc/line_by_line1.txt
Normal file
10
tests/bc/line_by_line1.txt
Normal file
@ -0,0 +1,10 @@
|
||||
1+1
|
||||
|
||||
define a (x) {
|
||||
print "a(", x, ")\n"
|
||||
quit
|
||||
}
|
||||
|
||||
a(10)
|
||||
|
||||
quit
|
1
tests/bc/line_by_line1_results.txt
Normal file
1
tests/bc/line_by_line1_results.txt
Normal file
@ -0,0 +1 @@
|
||||
2
|
9
tests/bc/line_by_line2.txt
Normal file
9
tests/bc/line_by_line2.txt
Normal file
@ -0,0 +1,9 @@
|
||||
1+1
|
||||
|
||||
define a (x) {
|
||||
print "a(", x, ")\n"
|
||||
}
|
||||
|
||||
a(10)
|
||||
|
||||
quit
|
3
tests/bc/line_by_line2_results.txt
Normal file
3
tests/bc/line_by_line2_results.txt
Normal file
@ -0,0 +1,3 @@
|
||||
2
|
||||
a(10)
|
||||
0
|
2
tests/bc/line_loop_quit1.txt
Normal file
2
tests/bc/line_loop_quit1.txt
Normal file
@ -0,0 +1,2 @@
|
||||
3
|
||||
for (i = 0; i < 3; ++i) i; quit
|
4
tests/bc/line_loop_quit1_results.txt
Normal file
4
tests/bc/line_loop_quit1_results.txt
Normal file
@ -0,0 +1,4 @@
|
||||
3
|
||||
0
|
||||
1
|
||||
2
|
3
tests/bc/line_loop_quit2.txt
Normal file
3
tests/bc/line_loop_quit2.txt
Normal file
@ -0,0 +1,3 @@
|
||||
3
|
||||
for (i = 0; i < 3; ++i) i; \
|
||||
quit
|
4
tests/bc/line_loop_quit2_results.txt
Normal file
4
tests/bc/line_loop_quit2_results.txt
Normal file
@ -0,0 +1,4 @@
|
||||
3
|
||||
0
|
||||
1
|
||||
2
|
261
tests/bc/scripts/afl1.bc
Normal file
261
tests/bc/scripts/afl1.bc
Normal file
@ -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)
|
1571
tests/bc/scripts/afl1.txt
Normal file
1571
tests/bc/scripts/afl1.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,3 +16,4 @@ screen.bc
|
||||
strings2.bc
|
||||
ifs.bc
|
||||
ifs2.bc
|
||||
afl1.bc
|
||||
|
@ -21,5 +21,8 @@ scientific
|
||||
engineering
|
||||
vars
|
||||
misc
|
||||
misc1
|
||||
strings
|
||||
rand
|
||||
is_number
|
||||
is_string
|
||||
|
@ -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
|
||||
|
@ -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
|
9
tests/dc/is_number.txt
Normal file
9
tests/dc/is_number.txt
Normal file
@ -0,0 +1,9 @@
|
||||
5upR
|
||||
18923740913.12809374upR
|
||||
1;aupR
|
||||
0sili;bupR
|
||||
[string]upR
|
||||
[this]aupR
|
||||
122aupR
|
||||
121asxlxupR
|
||||
120a2:a2;aupR
|
9
tests/dc/is_number_results.txt
Normal file
9
tests/dc/is_number_results.txt
Normal file
@ -0,0 +1,9 @@
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
9
tests/dc/is_string.txt
Normal file
9
tests/dc/is_string.txt
Normal file
@ -0,0 +1,9 @@
|
||||
5tpR
|
||||
18923740913.12809374tpR
|
||||
1;atpR
|
||||
0sili;btpR
|
||||
[string]tpR
|
||||
[this]atpR
|
||||
122atpR
|
||||
121asxlxtpR
|
||||
120a2:a2;atpR
|
9
tests/dc/is_string_results.txt
Normal file
9
tests/dc/is_string_results.txt
Normal file
@ -0,0 +1,9 @@
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
26
tests/dc/misc1.txt
Normal file
26
tests/dc/misc1.txt
Normal file
@ -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
|
21
tests/dc/misc1_results.txt
Normal file
21
tests/dc/misc1_results.txt
Normal file
@ -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
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user