mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-06 16:40:47 +00:00
vendor/bc: imoport release 5.0.0
This is a new major release with a number of changes and extensions: - Limited the number of temporary numbers and made the space for them static so that allocating more space for them cannot fail. - Allowed integers with non-zero scale to be used with power, places, and shift operators. - Added greatest common divisor and least common multiple to lib2.bc. - Made bc and dc UTF-8 capable. - Added the ability for users to have bc and dc quit on SIGINT. - Added the ability for users to disable prompt and TTY mode by environment variables. - Added the ability for users to redefine keywords. - Added dc's modular exponentiation and divmod to bc. - Added the ability to assign strings to variables and array elements and pass them to functions in bc. - Added dc's asciify command and stream printing to bc. - Added bitwise and, or, xor, left shift, right shift, reverse, left rotate, right rotate, and mod functions to lib2.bc. - Added the functions s2u(x) and s2un(x,n), to lib2.bc.
This commit is contained in:
parent
b46baf82c7
commit
2f57ecae4b
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -1,3 +1,3 @@
|
|||
*.vcxproj eol=crlf
|
||||
*.vcxproj.filters eol=crlf
|
||||
*.sln eol= crlf
|
||||
*.sln eol=crlf
|
||||
|
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -51,11 +51,17 @@ print_results.txt
|
|||
bessel.txt
|
||||
bessel_results.txt
|
||||
prime.txt
|
||||
stream.txt
|
||||
strings2.txt
|
||||
strings2_results.txt
|
||||
tests/bc/scripts/add.txt
|
||||
tests/bc/scripts/divide.txt
|
||||
tests/bc/scripts/multiply.txt
|
||||
tests/bc/scripts/subtract.txt
|
||||
tests/bc/scripts/strings2.txt
|
||||
benchmarks/bc/*.txt
|
||||
benchmarks/dc/*.txt
|
||||
scripts/ministat
|
||||
scripts/bitgen
|
||||
perf.data
|
||||
perf.data.old
|
||||
*.gcda
|
||||
|
|
14
LICENSE.md
14
LICENSE.md
|
@ -79,9 +79,9 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## `safe-install.sh`
|
||||
## `scripts/safe-install.sh`
|
||||
|
||||
The file `safe-install.sh` is under the following copyright and license:
|
||||
The file `scripts/safe-install.sh` is under the following copyright and license:
|
||||
|
||||
Copyright (c) 2021 Rich Felker
|
||||
|
||||
|
@ -101,3 +101,13 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## `scripts/ministat.c`
|
||||
|
||||
The file `scripts/ministat.c` is under the following license:
|
||||
|
||||
"THE BEER-WARE LICENSE" (Revision 42):
|
||||
|
||||
<phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
|
||||
can do whatever you want with this stuff. If we meet some day, and you think
|
||||
this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
|
|
217
Makefile.in
217
Makefile.in
|
@ -134,39 +134,64 @@ BC_ENABLE_HISTORY = %%HISTORY%%
|
|||
BC_ENABLE_EXTRA_MATH_NAME = BC_ENABLE_EXTRA_MATH
|
||||
BC_ENABLE_EXTRA_MATH = %%EXTRA_MATH%%
|
||||
BC_ENABLE_NLS = %%NLS%%
|
||||
BC_ENABLE_PROMPT = %%PROMPT%%
|
||||
BC_LONG_BIT = %%LONG_BIT%%
|
||||
|
||||
BC_ENABLE_AFL = %%FUZZ%%
|
||||
BC_ENABLE_MEMCHECK = %%MEMCHECK%%
|
||||
|
||||
BC_DEFAULT_BANNER = %%BC_DEFAULT_BANNER%%
|
||||
BC_DEFAULT_SIGINT_RESET = %%BC_DEFAULT_SIGINT_RESET%%
|
||||
DC_DEFAULT_SIGINT_RESET = %%DC_DEFAULT_SIGINT_RESET%%
|
||||
BC_DEFAULT_TTY_MODE = %%BC_DEFAULT_TTY_MODE%%
|
||||
DC_DEFAULT_TTY_MODE = %%DC_DEFAULT_TTY_MODE%%
|
||||
BC_DEFAULT_PROMPT = %%BC_DEFAULT_PROMPT%%
|
||||
DC_DEFAULT_PROMPT = %%DC_DEFAULT_PROMPT%%
|
||||
|
||||
RM = rm
|
||||
MKDIR = mkdir
|
||||
|
||||
INSTALL = ./exec-install.sh
|
||||
SAFE_INSTALL = ./safe-install.sh
|
||||
LINK = ./link.sh
|
||||
MANPAGE = ./manpage.sh
|
||||
KARATSUBA = ./karatsuba.py
|
||||
LOCALE_INSTALL = ./locale_install.sh
|
||||
LOCALE_UNINSTALL = ./locale_uninstall.sh
|
||||
SCRIPTS = ./scripts
|
||||
|
||||
MINISTAT = ministat
|
||||
MINISTAT_EXEC = $(SCRIPTS)/$(MINISTAT)
|
||||
|
||||
BITFUNCGEN = bitfuncgen
|
||||
BITFUNCGEN_EXEC = $(SCRIPTS)/$(BITFUNCGEN)
|
||||
|
||||
INSTALL = $(SCRIPTS)/exec-install.sh
|
||||
SAFE_INSTALL = $(SCRIPTS)/safe-install.sh
|
||||
LINK = $(SCRIPTS)/link.sh
|
||||
MANPAGE = $(SCRIPTS)/manpage.sh
|
||||
KARATSUBA = $(SCRIPTS)/karatsuba.py
|
||||
LOCALE_INSTALL = $(SCRIPTS)/locale_install.sh
|
||||
LOCALE_UNINSTALL = $(SCRIPTS)/locale_uninstall.sh
|
||||
|
||||
VALGRIND_ARGS = --error-exitcode=100 --leak-check=full --show-leak-kinds=all --errors-for-leak-kinds=all
|
||||
|
||||
TEST_STARS = "***********************************************************************"
|
||||
TEST_STARS = ***********************************************************************
|
||||
|
||||
BC_NUM_KARATSUBA_LEN = %%KARATSUBA_LEN%%
|
||||
|
||||
BC_DEFS0 = -DBC_DEFAULT_BANNER=$(BC_DEFAULT_BANNER)
|
||||
BC_DEFS1 = -DBC_DEFAULT_SIGINT_RESET=$(BC_DEFAULT_SIGINT_RESET)
|
||||
BC_DEFS2 = -DBC_DEFAULT_TTY_MODE=$(BC_DEFAULT_TTY_MODE)
|
||||
BC_DEFS3 = -DBC_DEFAULT_PROMPT=$(BC_DEFAULT_PROMPT)
|
||||
BC_DEFS = $(BC_DEFS0) $(BC_DEFS1) $(BC_DEFS2) $(BC_DEFS3)
|
||||
DC_DEFS1 = -DDC_DEFAULT_SIGINT_RESET=$(DC_DEFAULT_SIGINT_RESET)
|
||||
DC_DEFS2 = -DDC_DEFAULT_TTY_MODE=$(DC_DEFAULT_TTY_MODE)
|
||||
DC_DEFS3 = -DDC_DEFAULT_PROMPT=$(DC_DEFAULT_PROMPT)
|
||||
DC_DEFS = $(DC_DEFS1) $(DC_DEFS2) $(DC_DEFS3)
|
||||
|
||||
CPPFLAGS1 = -D$(BC_ENABLED_NAME)=$(BC_ENABLED) -D$(DC_ENABLED_NAME)=$(DC_ENABLED)
|
||||
CPPFLAGS2 = $(CPPFLAGS1) -I./include/ -DBUILD_TYPE=$(BC_BUILD_TYPE) %%LONG_BIT_DEFINE%%
|
||||
CPPFLAGS3 = $(CPPFLAGS2) -DEXECPREFIX=$(EXEC_PREFIX) -DMAINEXEC=$(MAIN_EXEC)
|
||||
CPPFLAGS4 = $(CPPFLAGS3) -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
|
||||
CPPFLAGS4 = $(CPPFLAGS3) -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 %%BSD%%
|
||||
CPPFLAGS5 = $(CPPFLAGS4) -DBC_NUM_KARATSUBA_LEN=$(BC_NUM_KARATSUBA_LEN)
|
||||
CPPFLAGS6 = $(CPPFLAGS5) -DBC_ENABLE_NLS=$(BC_ENABLE_NLS) -DBC_ENABLE_PROMPT=$(BC_ENABLE_PROMPT)
|
||||
CPPFLAGS6 = $(CPPFLAGS5) -DBC_ENABLE_NLS=$(BC_ENABLE_NLS)
|
||||
CPPFLAGS7 = $(CPPFLAGS6) -D$(BC_ENABLE_EXTRA_MATH_NAME)=$(BC_ENABLE_EXTRA_MATH)
|
||||
CPPFLAGS8 = $(CPPFLAGS7) -DBC_ENABLE_HISTORY=$(BC_ENABLE_HISTORY) -DBC_ENABLE_LIBRARY=$(BC_ENABLE_LIBRARY)
|
||||
CPPFLAGS = $(CPPFLAGS8) -DBC_ENABLE_MEMCHECK=$(BC_ENABLE_MEMCHECK) -DBC_ENABLE_AFL=$(BC_ENABLE_AFL)
|
||||
CFLAGS = $(CPPFLAGS) %%CPPFLAGS%% %%CFLAGS%%
|
||||
CFLAGS = $(CPPFLAGS) $(BC_DEFS) $(DC_DEFS) %%CPPFLAGS%% %%CFLAGS%%
|
||||
LDFLAGS = %%LDFLAGS%%
|
||||
|
||||
HOSTCFLAGS = %%HOSTCFLAGS%%
|
||||
|
@ -219,6 +244,12 @@ $(BIN):
|
|||
|
||||
headers: %%HEADERS%%
|
||||
|
||||
$(MINISTAT):
|
||||
$(HOSTCC) $(HOSTCFLAGS) -lm -o $(MINISTAT_EXEC) scripts/ministat.c
|
||||
|
||||
$(BITFUNCGEN):
|
||||
$(HOSTCC) $(HOSTCFLAGS) -lm -o $(BITFUNCGEN_EXEC) scripts/bitfuncgen.c
|
||||
|
||||
help:
|
||||
@printf 'available targets:\n'
|
||||
@printf '\n'
|
||||
|
@ -249,16 +280,25 @@ help:
|
|||
@printf ' valgrind_dc runs the dc test suite, if dc has been built,\n'
|
||||
@printf ' through valgrind\n'
|
||||
|
||||
run_all_tests:
|
||||
run_all_tests: bc_all_tests timeconst_all_tests dc_all_tests history_all_tests
|
||||
|
||||
bc_all_tests:
|
||||
%%BC_ALL_TESTS%%
|
||||
|
||||
timeconst_all_tests:
|
||||
%%TIMECONST_ALL_TESTS%%
|
||||
|
||||
dc_all_tests:
|
||||
%%DC_ALL_TESTS%%
|
||||
|
||||
history_all_tests:
|
||||
%%HISTORY_TESTS%%
|
||||
|
||||
check: test
|
||||
|
||||
test: %%TESTS%%
|
||||
|
||||
test_bc: test_bc_header test_bc_tests test_bc_scripts test_bc_stdin test_bc_read test_bc_errors test_bc_other
|
||||
test_bc: test_bc_header test_bc_tests test_bc_scripts test_bc_errors test_bc_stdin test_bc_read test_bc_other
|
||||
@printf '\nAll bc tests passed.\n\n$(TEST_STARS)\n'
|
||||
|
||||
test_bc_tests:%%BC_TESTS%%
|
||||
|
@ -275,12 +315,12 @@ test_bc_errors:
|
|||
@sh tests/errors.sh bc %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_other:
|
||||
@sh tests/other.sh bc %%BC_TEST_EXEC%%
|
||||
@sh tests/other.sh bc $(BC_ENABLE_EXTRA_MATH) %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_header:
|
||||
@printf '$(TEST_STARS)\n\nRunning bc tests...\n\n'
|
||||
|
||||
test_dc: test_dc_header test_dc_tests test_dc_scripts test_dc_stdin test_dc_read test_dc_errors test_dc_other
|
||||
test_dc: test_dc_header test_dc_tests test_dc_scripts test_dc_errors test_dc_stdin test_dc_read test_dc_other
|
||||
@printf '\nAll dc tests passed.\n\n$(TEST_STARS)\n'
|
||||
|
||||
test_dc_tests:%%DC_TESTS%%
|
||||
|
@ -297,7 +337,7 @@ test_dc_errors:
|
|||
@sh tests/errors.sh dc %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_other:
|
||||
@sh tests/other.sh dc %%DC_TEST_EXEC%%
|
||||
@sh tests/other.sh dc $(BC_ENABLE_EXTRA_MATH) %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_header:
|
||||
@printf '$(TEST_STARS)\n\nRunning dc tests...\n\n'
|
||||
|
@ -305,6 +345,122 @@ test_dc_header:
|
|||
timeconst:
|
||||
%%TIMECONST%%
|
||||
|
||||
test_history: test_history_header test_bc_history test_dc_history
|
||||
@printf '\nAll history tests passed.\n\n$(TEST_STARS)\n'
|
||||
|
||||
test_bc_history:%%BC_HISTORY_TEST_PREREQS%%
|
||||
|
||||
test_bc_history_all: test_bc_history0 test_bc_history1 test_bc_history2 test_bc_history3 test_bc_history4 test_bc_history5 test_bc_history6 test_bc_history7 test_bc_history8 test_bc_history9 test_bc_history10 test_bc_history11 test_bc_history12 test_bc_history13 test_bc_history14 test_bc_history15 test_bc_history16 test_bc_history17 test_bc_history18 test_bc_history19 test_bc_history20 test_bc_history21
|
||||
|
||||
test_bc_history_skip:
|
||||
@printf 'No bc history tests to run\n'
|
||||
|
||||
test_bc_history0:
|
||||
@sh tests/history.sh bc 0 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history1:
|
||||
@sh tests/history.sh bc 1 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history2:
|
||||
@sh tests/history.sh bc 2 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history3:
|
||||
@sh tests/history.sh bc 3 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history4:
|
||||
@sh tests/history.sh bc 4 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history5:
|
||||
@sh tests/history.sh bc 5 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history6:
|
||||
@sh tests/history.sh bc 6 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history7:
|
||||
@sh tests/history.sh bc 7 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history8:
|
||||
@sh tests/history.sh bc 8 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history9:
|
||||
@sh tests/history.sh bc 9 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history10:
|
||||
@sh tests/history.sh bc 10 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history11:
|
||||
@sh tests/history.sh bc 11 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history12:
|
||||
@sh tests/history.sh bc 12 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history13:
|
||||
@sh tests/history.sh bc 13 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history14:
|
||||
@sh tests/history.sh bc 14 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history15:
|
||||
@sh tests/history.sh bc 15 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history16:
|
||||
@sh tests/history.sh bc 16 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history17:
|
||||
@sh tests/history.sh bc 17 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history18:
|
||||
@sh tests/history.sh bc 18 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history19:
|
||||
@sh tests/history.sh bc 19 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history20:
|
||||
@sh tests/history.sh bc 20 %%BC_TEST_EXEC%%
|
||||
|
||||
test_bc_history21:
|
||||
@sh tests/history.sh bc 21 %%BC_TEST_EXEC%%
|
||||
|
||||
test_dc_history:%%DC_HISTORY_TEST_PREREQS%%
|
||||
|
||||
test_dc_history_all: test_dc_history0 test_dc_history1 test_dc_history2 test_dc_history3 test_dc_history4 test_dc_history5 test_dc_history6 test_dc_history7 test_dc_history8 test_dc_history9
|
||||
|
||||
test_dc_history_skip:
|
||||
@printf 'No dc history tests to run\n'
|
||||
|
||||
test_dc_history0:
|
||||
@sh tests/history.sh dc 0 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history1:
|
||||
@sh tests/history.sh dc 1 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history2:
|
||||
@sh tests/history.sh dc 2 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history3:
|
||||
@sh tests/history.sh dc 3 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history4:
|
||||
@sh tests/history.sh dc 4 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history5:
|
||||
@sh tests/history.sh dc 5 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history6:
|
||||
@sh tests/history.sh dc 6 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history7:
|
||||
@sh tests/history.sh dc 7 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history8:
|
||||
@sh tests/history.sh dc 8 %%DC_TEST_EXEC%%
|
||||
|
||||
test_dc_history9:
|
||||
@sh tests/history.sh dc 9 %%DC_TEST_EXEC%%
|
||||
|
||||
test_history_header:
|
||||
@printf '$(TEST_STARS)\n\nRunning history tests...\n\n'
|
||||
|
||||
library_test: $(LIBBC)
|
||||
$(CC) $(CFLAGS) $(BCL_TEST_C) $(LIBBC) -o $(BCL_TEST)
|
||||
|
||||
|
@ -322,12 +478,6 @@ coverage_output:
|
|||
|
||||
coverage:%%COVERAGE_PREREQS%%
|
||||
|
||||
libcname:
|
||||
@printf '%s' "$(BC_LIB_C)"
|
||||
|
||||
extra_math:
|
||||
@printf '%s' "$(BC_ENABLE_EXTRA_MATH)"
|
||||
|
||||
manpages:
|
||||
$(MANPAGE) bc
|
||||
$(MANPAGE) dc
|
||||
|
@ -348,15 +498,19 @@ clean:%%CLEAN_PREREQS%%
|
|||
@$(RM) -f $(BC_LIB2_C) $(BC_LIB2_O)
|
||||
@$(RM) -f $(BC_HELP_C) $(BC_HELP_O)
|
||||
@$(RM) -f $(DC_HELP_C) $(DC_HELP_O)
|
||||
@$(RM) -fr $(BC_TEST_OUTPUTS) $(DC_TEST_OUTPUTS)
|
||||
@$(RM) -fr $(BC_FUZZ_OUTPUTS) $(DC_FUZZ_OUTPUTS)
|
||||
@$(RM) -fr Debug/ Release/
|
||||
|
||||
clean_config: clean
|
||||
clean_benchmarks:
|
||||
@printf 'Cleaning benchmarks...\n'
|
||||
@$(RM) -f $(MINISTAT_EXEC)
|
||||
@$(RM) -f benchmarks/bc/*.txt
|
||||
@$(RM) -f benchmarks/dc/*.txt
|
||||
|
||||
clean_config: clean clean_benchmarks
|
||||
@printf 'Cleaning config...\n'
|
||||
@$(RM) -f Makefile
|
||||
@$(RM) -f $(BC_MD) $(DC_MD)
|
||||
@$(RM) -f $(BC_MANPAGE) $(DC_MANPAGE)
|
||||
@$(RM) -f $(BC_MD) $(BC_MANPAGE)
|
||||
@$(RM) -f $(DC_MD) $(DC_MANPAGE)
|
||||
|
||||
clean_coverage:
|
||||
@printf 'Cleaning coverage files...\n'
|
||||
|
@ -376,9 +530,12 @@ clean_coverage:
|
|||
|
||||
clean_tests: clean clean_config clean_coverage
|
||||
@printf 'Cleaning test files...\n'
|
||||
@$(RM) -fr $(BC_TEST_OUTPUTS) $(DC_TEST_OUTPUTS)
|
||||
@$(RM) -fr $(BC_FUZZ_OUTPUTS) $(DC_FUZZ_OUTPUTS)
|
||||
@$(RM) -f tests/bc/parse.txt tests/bc/parse_results.txt
|
||||
@$(RM) -f tests/bc/print.txt tests/bc/print_results.txt
|
||||
@$(RM) -f tests/bc/bessel.txt tests/bc/bessel_results.txt
|
||||
@$(RM) -f tests/bc/strings2.txt tests/bc/strings2_results.txt
|
||||
@$(RM) -f tests/bc/scripts/bessel.txt
|
||||
@$(RM) -f tests/bc/scripts/parse.txt
|
||||
@$(RM) -f tests/bc/scripts/print.txt
|
||||
|
@ -386,13 +543,15 @@ clean_tests: clean clean_config clean_coverage
|
|||
@$(RM) -f tests/bc/scripts/divide.txt
|
||||
@$(RM) -f tests/bc/scripts/multiply.txt
|
||||
@$(RM) -f tests/bc/scripts/subtract.txt
|
||||
@$(RM) -f tests/dc/scripts/prime.txt tests/dc/scripts/stream.txt
|
||||
@$(RM) -f tests/bc/scripts/strings2.txt
|
||||
@$(RM) -f tests/dc/scripts/prime.txt
|
||||
@$(RM) -f .log_*.txt
|
||||
@$(RM) -f .math.txt .results.txt .ops.txt
|
||||
@$(RM) -f .test.txt
|
||||
@$(RM) -f tags .gdbbreakpoints .gdb_history .gdbsetup
|
||||
@$(RM) -f cscope.*
|
||||
@$(RM) -f bc.old
|
||||
@$(RM) -f $(BITFUNCGEN_EXEC)
|
||||
|
||||
install_locales:
|
||||
%%INSTALL_LOCALES%%
|
||||
|
|
61
NEWS.md
61
NEWS.md
|
@ -1,5 +1,55 @@
|
|||
# News
|
||||
|
||||
## 5.0.0
|
||||
|
||||
This is a major production release with several changes:
|
||||
|
||||
* Added support for OpenBSD's `pledge()` and `unveil()`.
|
||||
* Fixed print bug where a backslash newline combo was printed even if only one
|
||||
digit was left, something I blindly copied from GNU `bc`, like a fool.
|
||||
* Fixed bugs in the manuals.
|
||||
* Fixed a possible multiplication overflow in power.
|
||||
* Temporary numbers are garbage collected if allocation fails, and the
|
||||
allocation is retried. This is to make `bc` and `dc` more resilient to running
|
||||
out of memory.
|
||||
* Limited the number of temporary numbers and made the space for them static so
|
||||
that allocating more space for them cannot fail.
|
||||
* Allowed integers with non-zero `scale` to be used with power, places, and
|
||||
shift operators.
|
||||
* Added greatest common divisor and least common multiple to `lib2.bc`.
|
||||
* Added `SIGQUIT` handling to history.
|
||||
* Added a command to `dc` (`y`) to get the length of register stacks.
|
||||
* Fixed multi-digit bugs in `lib2.bc`.
|
||||
* Removed the no prompt build option.
|
||||
* Created settings that builders can set defaults for and users can set their
|
||||
preferences for. This includes the `bc` banner, resetting on `SIGINT`, TTY
|
||||
mode, and prompt.
|
||||
* Added history support to Windows.
|
||||
* Fixed bugs with the handling of register names in `dc`.
|
||||
* Fixed bugs with multi-line comments and strings in both calculators.
|
||||
* Added a new error type and message for `dc` when register stacks don't have
|
||||
enough items.
|
||||
* Optimized string allocation.
|
||||
* Made `bc` and `dc` UTF-8 capable.
|
||||
* Fixed a bug with `void` functions.
|
||||
* Fixed a misspelled symbol in `bcl`. This is technically a breaking change,
|
||||
which requires this to be `5.0.0`.
|
||||
* Added the ability for users to get the copyright banner back.
|
||||
* Added the ability for users to have `bc` and `dc` quit on `SIGINT`.
|
||||
* Added the ability for users to disable prompt and TTY mode by environment
|
||||
variables.
|
||||
* Added the ability for users to redefine keywords. This is another reason this
|
||||
is `5.0.0`.
|
||||
* Added `dc`'s modular exponentiation and divmod to `bc`.
|
||||
* Added the ability to assign strings to variables and array elements and pass
|
||||
them to functions in `bc`.
|
||||
* Added `dc`'s asciify command and stream printing to `bc`.
|
||||
* Added a command to `dc` (`Y`) to get the length of an array.
|
||||
* Added a command to `dc` (`,`) to get the depth of the execution stack.
|
||||
* Added bitwise and, or, xor, left shift, right shift, reverse, left rotate,
|
||||
right rotate, and mod functions to `lib2.bc`.
|
||||
* Added the functions `s2u(x)` and `s2un(x,n)`, to `lib2.bc`.
|
||||
|
||||
## 4.0.2
|
||||
|
||||
This is a production release that fixes two bugs:
|
||||
|
@ -310,8 +360,8 @@ running tests during install. **If `bc` segfaults while running arg tests when
|
|||
updating, it is because the global locale files have not been replaced. Make
|
||||
sure to either prevent the test suite from running on update or remove the old
|
||||
locale files before updating.** (Removing the locale files can be done with
|
||||
`make uninstall` or by running the `locale_uninstall.sh` script.) Once this is
|
||||
done, `bc` should install without problems.*
|
||||
`make uninstall` or by running the [`locale_uninstall.sh`][22] script.) Once
|
||||
this is done, `bc` should install without problems.*
|
||||
|
||||
*Second, **the option to build without signal support has been removed**. See
|
||||
below for the reasons why.*
|
||||
|
@ -396,7 +446,7 @@ diameter of the universe in Planck lengths.
|
|||
|
||||
(For 32-bit, these numbers are either 32 integer digits or 12 integer digits and
|
||||
20 fractional digits. These are also quite big, and going much bigger on a
|
||||
32-bit system seems a little pointless since 12 digits in just under a trillion
|
||||
32-bit system seems a little pointless since 12 digits is just under a trillion
|
||||
and 20 fractional digits is still enough for about any use since `10^-20` light
|
||||
years is just under a millimeter.)
|
||||
|
||||
|
@ -1084,7 +1134,7 @@ not thoroughly tested.
|
|||
[1]: https://docs.microsoft.com/en-us/windows/wsl/install-win10
|
||||
[2]: https://pkg.musl.cc/bc/
|
||||
[3]: http://lcamtuf.coredump.cx/afl/
|
||||
[4]: ./karatsuba.py
|
||||
[4]: ./scripts/karatsuba.py
|
||||
[5]: ./README.md
|
||||
[6]: ./configure.sh
|
||||
[7]: https://github.com/rain-1/linenoise-mob
|
||||
|
@ -1092,7 +1142,7 @@ not thoroughly tested.
|
|||
[9]: ./manuals/bc/A.1.md
|
||||
[10]: ./manuals/dc/A.1.md
|
||||
[11]: https://scan.coverity.com/projects/gavinhoward-bc
|
||||
[12]: ./locale_install.sh
|
||||
[12]: ./scripts/locale_install.sh
|
||||
[13]: ./manuals/build.md
|
||||
[14]: https://github.com/stesser
|
||||
[15]: https://github.com/bugcrazy
|
||||
|
@ -1102,3 +1152,4 @@ not thoroughly tested.
|
|||
[19]: ./manuals/benchmarks.md
|
||||
[20]: https://github.com/apjanke/ronn-ng
|
||||
[21]: https://pandoc.org/
|
||||
[22]: ./scripts/locale_uninstall.sh
|
||||
|
|
50
README.md
50
README.md
|
@ -1,7 +1,5 @@
|
|||
# `bc`
|
||||
|
||||
[![Coverity Scan Build Status][17]][18]
|
||||
|
||||
***WARNING: This project has moved to [https://git.yzena.com/][20] for [these
|
||||
reasons][21], though GitHub will remain a mirror.***
|
||||
|
||||
|
@ -23,6 +21,8 @@ This `bc` also provides `bc`'s math as a library with C bindings, called `bcl`.
|
|||
|
||||
For more information, see the full manual for `bcl`.
|
||||
|
||||
## License
|
||||
|
||||
This `bc` is Free and Open Source Software (FOSS). It is offered under the BSD
|
||||
2-clause License. Full license text may be found in the [`LICENSE.md`][4] file.
|
||||
|
||||
|
@ -55,6 +55,12 @@ system.
|
|||
|
||||
## Build
|
||||
|
||||
This `bc` should build unmodified on any POSIX-compliant system or on Windows
|
||||
starting with Windows 10 (though earlier versions may work).
|
||||
|
||||
For more complex build requirements than the ones below, see the
|
||||
[build manual][5].
|
||||
|
||||
### Windows
|
||||
|
||||
There is no guarantee that this `bc` will work on any version of Windows earlier
|
||||
|
@ -96,12 +102,6 @@ where `<config>` is either one of `Debug` or `Release`.
|
|||
|
||||
### POSIX-Compatible Systems
|
||||
|
||||
This `bc` should build unmodified on any POSIX-compliant system or on Windows
|
||||
starting with Windows 10 (though earlier versions may work).
|
||||
|
||||
For more complex build requirements than the ones below, see the
|
||||
[build manual][5].
|
||||
|
||||
On POSIX-compatible systems, `bc` is built as `bin/bc` and `dc` is built as
|
||||
`bin/dc` by default. On Windows, they are built as `Release/bc/bc.exe` and
|
||||
`Release/bc/dc.exe`.
|
||||
|
@ -243,7 +243,7 @@ allowed.
|
|||
##### Karatsuba Number
|
||||
|
||||
Package and distro maintainers have one tool at their disposal to build this
|
||||
`bc` in the optimal configuration: `karatsuba.py`.
|
||||
`bc` in the optimal configuration: `scripts/karatsuba.py`.
|
||||
|
||||
This script is not a compile-time or runtime prerequisite; it is for package and
|
||||
distro maintainers to run once when a package is being created. It finds the
|
||||
|
@ -272,6 +272,21 @@ releases with additional features. However, it *is* actively maintained, so if
|
|||
any bugs are found, they will be fixed in new releases. Also, additional
|
||||
translations will also be added as they are provided.
|
||||
|
||||
### Development
|
||||
|
||||
If I (Gavin D. Howard) get [hit by a bus][27] and future programmers need to
|
||||
handle work themselves, the best place to start is the [Development manual][28].
|
||||
|
||||
## Vim Syntax
|
||||
|
||||
I have developed (using other people's code to start) [`vim` syntax files][17]
|
||||
for this `bc` and `dc`, including the extensions.
|
||||
|
||||
## `bc` Libs
|
||||
|
||||
I have gathered some excellent [`bc` and `dc` libraries][18]. These libraries
|
||||
may prove useful to any serious users.
|
||||
|
||||
## Comparison to GNU `bc`
|
||||
|
||||
This `bc` compares favorably to GNU `bc`.
|
||||
|
@ -366,20 +381,10 @@ Files:
|
|||
bcl.vcxproj.filters The Visual Studio filters file for bcl.
|
||||
configure A symlink to configure.sh to make packaging easier.
|
||||
configure.sh The configure script.
|
||||
functions.sh A script with functions used by other scripts.
|
||||
install.sh Install script.
|
||||
karatsuba.py Script to find the optimal Karatsuba number.
|
||||
LICENSE.md A Markdown form of the BSD 2-clause License.
|
||||
link.sh A script to link dc to bc.
|
||||
locale_install.sh A script to install locales, if desired.
|
||||
locale_uninstall.sh A script to uninstall locales.
|
||||
Makefile.in The Makefile template.
|
||||
manpage.sh Script to generate man pages from markdown files
|
||||
(maintainer use only).
|
||||
NOTICE.md List of contributors and copyright owners.
|
||||
RELEASE.md A checklist for making a release (maintainer use only).
|
||||
release.sh A script to test for release (maintainer use only).
|
||||
safe-install.sh Safe install script from musl libc.
|
||||
|
||||
Folders:
|
||||
|
||||
|
@ -388,6 +393,7 @@ Folders:
|
|||
locales Locale files, in .msg format. Patches welcome for translations.
|
||||
manuals Manuals for both programs.
|
||||
src All source code.
|
||||
scripts A bunch of shell scripts to help with development and building.
|
||||
tests All tests.
|
||||
|
||||
[1]: https://www.gnu.org/software/bc/
|
||||
|
@ -399,8 +405,8 @@ Folders:
|
|||
[10]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||
[11]: http://semver.org/
|
||||
[12]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html
|
||||
[17]: https://img.shields.io/coverity/scan/16609.svg
|
||||
[18]: https://scan.coverity.com/projects/gavinhoward-bc
|
||||
[17]: https://git.yzena.com/gavin/vim-bc
|
||||
[18]: https://git.yzena.com/gavin/bc_libs
|
||||
[19]: ./manuals/benchmarks.md
|
||||
[20]: https://git.yzena.com/gavin/bc
|
||||
[21]: https://gavinhoward.com/2020/04/i-am-moving-away-from-github/
|
||||
|
@ -409,3 +415,5 @@ Folders:
|
|||
[24]: https://bugs.freebsd.org/
|
||||
[25]: https://reviews.freebsd.org/
|
||||
[26]: ./manuals/bcl.3.md
|
||||
[27]: https://en.wikipedia.org/wiki/Bus_factor
|
||||
[28]: ./manuals/development.md
|
||||
|
|
54
RELEASE.md
54
RELEASE.md
|
@ -1,54 +0,0 @@
|
|||
# Release Checklist
|
||||
|
||||
This is the checklist for cutting a release.
|
||||
|
||||
1. Update the README.
|
||||
2. Update the manuals.
|
||||
3. Test history manually.
|
||||
4. Test with POSIX test suite.
|
||||
5. Run the randmath.py script an excessive amount and add failing tests to
|
||||
test suite.
|
||||
* debug
|
||||
* release
|
||||
* minrelease
|
||||
6. Fuzz with AFL.
|
||||
* reldebug
|
||||
7. Fix AFL crashes.
|
||||
8. Find ASan crashes on AFL test cases.
|
||||
9. Fix ASan crashes.
|
||||
10. Build with xstatic.
|
||||
11. Run and pass the `release.sh` script on my own machine.
|
||||
12. Run and pass the `release.sh` script, without generated tests and
|
||||
sanitizers, on FreeBSD.
|
||||
13. Run and pass the `release.sh` script, without generated tests, sanitizers,
|
||||
and 64-bit, on Thalheim's ARM server.
|
||||
14. Run and pass the release script, with no generated tests, no clang, no
|
||||
sanitizers, and no valgrind, on NetBSD.
|
||||
15. Run and pass the release script, with no generated tests, no clang, no
|
||||
sanitizers, and no valgrind, on OpenBSD.
|
||||
16. Run Coverity Scan and eliminate warnings, if possible (both only).
|
||||
* debug
|
||||
17. Run `scan-build make`.
|
||||
18. Repeat steps 3-14 again and repeat until nothing is found.
|
||||
19. Update the benchmarks.
|
||||
20. Change the version (remove "-dev") and commit.
|
||||
21. Run `make clean_tests`.
|
||||
22. Run the release script.
|
||||
23. Upload the custom tarball to GitHub.
|
||||
24. Add sha's to release notes.
|
||||
25. Edit release notes for the changelog.
|
||||
26. Increment to the next version (with "-dev").
|
||||
27. Notify the following:
|
||||
* FreeBSD
|
||||
* Adelie Linux
|
||||
* Ataraxia Linux
|
||||
* Sabotage
|
||||
* xstatic
|
||||
* OpenBSD
|
||||
* NetBSD
|
||||
28. Submit new packages for the following:
|
||||
* Alpine Linux
|
||||
* Void Linux
|
||||
* Gentoo Linux
|
||||
* Linux from Scratch
|
||||
* Arch Linux
|
80
bc.vcxproj
80
bc.vcxproj
|
@ -64,33 +64,33 @@
|
|||
<ItemGroup>
|
||||
<CustomBuild Include="gen\strgen.c">
|
||||
<Message>Building strgen</Message>
|
||||
<Command>CL /Fo:$(Configuration)\$(ProjectName)\ /Fe:$(Configuration)\$(ProjectName)\strgen.exe gen\strgen.c</Command>
|
||||
<Command>CL /Fo:$(Configuration)\$(Platform)\$(ProjectName)\ /Fe:$(Configuration)\$(Platform)\$(ProjectName)\strgen.exe gen\strgen.c</Command>
|
||||
<Inputs>gen\strgen.c</Inputs>
|
||||
<Outputs>$(Configuration)\$(ProjectName)\strgen.exe</Outputs>
|
||||
<Outputs>$(Configuration)\$(Platform)\$(ProjectName)\strgen.exe</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="gen\lib.bc">
|
||||
<Message>Generating $(Configuration)\$(ProjectName)/lib.c</Message>
|
||||
<Command>START $(Configuration)\$(ProjectName)/strgen gen\lib.bc $(Configuration)\$(ProjectName)/lib.c bc_lib bc_lib_name BC_ENABLED 1</Command>
|
||||
<Inputs>$(Configuration)\$(ProjectName)\strgen.exe;gen\lib.bc</Inputs>
|
||||
<Outputs>$(Configuration)\$(ProjectName)\lib.c</Outputs>
|
||||
<Message>Generating $(Configuration)\$(Platform)\$(ProjectName)/lib.c</Message>
|
||||
<Command>START $(Configuration)\$(Platform)\$(ProjectName)/strgen gen\lib.bc $(Configuration)\$(Platform)\$(ProjectName)/lib.c bc_lib bc_lib_name BC_ENABLED 1</Command>
|
||||
<Inputs>$(Configuration)\$(Platform)\$(ProjectName)\strgen.exe;gen\lib.bc</Inputs>
|
||||
<Outputs>$(Configuration)\$(Platform)\$(ProjectName)\lib.c</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="gen\lib2.bc">
|
||||
<Message>Generating $(Configuration)\$(ProjectName)/lib2.c</Message>
|
||||
<Command>START $(Configuration)\$(ProjectName)/strgen gen\lib2.bc $(Configuration)\$(ProjectName)/lib2.c bc_lib2 bc_lib2_name BC_ENABLED 1</Command>
|
||||
<Inputs>$(Configuration)\$(ProjectName)\strgen.exe;gen\lib2.bc</Inputs>
|
||||
<Outputs>$(Configuration)\$(ProjectName)\lib2.c</Outputs>
|
||||
<Message>Generating $(Configuration)\$(Platform)\$(ProjectName)/lib2.c</Message>
|
||||
<Command>START $(Configuration)\$(Platform)\$(ProjectName)/strgen gen\lib2.bc $(Configuration)\$(Platform)\$(ProjectName)/lib2.c bc_lib2 bc_lib2_name BC_ENABLED 1</Command>
|
||||
<Inputs>$(Configuration)\$(Platform)\$(ProjectName)\strgen.exe;gen\lib2.bc</Inputs>
|
||||
<Outputs>$(Configuration)\$(Platform)\$(ProjectName)\lib2.c</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="gen\bc_help.txt">
|
||||
<Message>Generating $(Configuration)\$(ProjectName)/bc_help.c</Message>
|
||||
<Command>START $(Configuration)\$(ProjectName)/strgen gen\bc_help.txt $(Configuration)\$(ProjectName)\bc_help.c bc_help "" BC_ENABLED</Command>
|
||||
<Inputs>$(Configuration)\$(ProjectName)\strgen.exe;gen\bc_help.txt</Inputs>
|
||||
<Outputs>$(Configuration)\$(ProjectName)\bc_help.c</Outputs>
|
||||
<Message>Generating $(Configuration)\$(Platform)\$(ProjectName)/bc_help.c</Message>
|
||||
<Command>START $(Configuration)\$(Platform)\$(ProjectName)/strgen gen\bc_help.txt $(Configuration)\$(Platform)\$(ProjectName)\bc_help.c bc_help "" BC_ENABLED</Command>
|
||||
<Inputs>$(Configuration)\$(Platform)\$(ProjectName)\strgen.exe;gen\bc_help.txt</Inputs>
|
||||
<Outputs>$(Configuration)\$(Platform)\$(ProjectName)\bc_help.c</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="gen\dc_help.txt">
|
||||
<Message>Generating $(Configuration)\$(ProjectName)/dc_help.c</Message>
|
||||
<Command>START $(Configuration)\$(ProjectName)/strgen gen\dc_help.txt $(Configuration)\$(ProjectName)\dc_help.c dc_help "" DC_ENABLED</Command>
|
||||
<Inputs>$(Configuration)\$(ProjectName)\strgen.exe;gen\dc_help.txt</Inputs>
|
||||
<Outputs>$(Configuration)\$(ProjectName)\dc_help.c</Outputs>
|
||||
<Message>Generating $(Configuration)\$(Platform)\$(ProjectName)/dc_help.c</Message>
|
||||
<Command>START $(Configuration)\$(Platform)\$(ProjectName)/strgen gen\dc_help.txt $(Configuration)\$(Platform)\$(ProjectName)\dc_help.c dc_help "" DC_ENABLED</Command>
|
||||
<Inputs>$(Configuration)\$(Platform)\$(ProjectName)\strgen.exe;gen\dc_help.txt</Inputs>
|
||||
<Outputs>$(Configuration)\$(Platform)\$(ProjectName)\dc_help.c</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
|
@ -99,27 +99,27 @@
|
|||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=1;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=HN</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=1;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=N;BC_DEFAULT_BANNER=1;BC_DEFAULT_SIGINT_RESET=0;DC_DEFAULT_SIGINT_RESET=0;BC_DEFAULT_TTY_MODE=1;DC_DEFAULT_TTY_MODE=1;BC_DEFAULT_PROMPT=1;DC_DEFAULT_PROMPT=1</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
|
@ -130,12 +130,12 @@
|
|||
</ClCompile>
|
||||
<Link>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>DebugFastLink</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;bcrypt.lib;ucrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(ProjectName)\dc.exe"</Command>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\dc.exe"</Command>
|
||||
</PostBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Message>Copying bc to dc...</Message>
|
||||
|
@ -143,7 +143,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=1;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=HN</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=1;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=N;BC_DEFAULT_BANNER=1;BC_DEFAULT_SIGINT_RESET=0;DC_DEFAULT_SIGINT_RESET=0;BC_DEFAULT_TTY_MODE=1;DC_DEFAULT_TTY_MODE=1;BC_DEFAULT_PROMPT=1;DC_DEFAULT_PROMPT=1</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
|
@ -161,7 +161,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(ProjectName)\dc.exe"</Command>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\dc.exe"</Command>
|
||||
</PostBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Message>Copying bc to dc...</Message>
|
||||
|
@ -169,7 +169,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=1;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=HN</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=1;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=N;BC_DEFAULT_BANNER=1;BC_DEFAULT_SIGINT_RESET=0;DC_DEFAULT_SIGINT_RESET=0;BC_DEFAULT_TTY_MODE=1;DC_DEFAULT_TTY_MODE=1;BC_DEFAULT_PROMPT=1;DC_DEFAULT_PROMPT=1</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
|
@ -185,7 +185,7 @@
|
|||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;bcrypt.lib;ucrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(ProjectName)\dc.exe"</Command>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\dc.exe"</Command>
|
||||
</PostBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Message>Copying bc to dc...</Message>
|
||||
|
@ -193,7 +193,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=1;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=HN</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=1;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=0;EXECSUFFIX=.exe;BUILD_TYPE=N;BC_DEFAULT_BANNER=1;BC_DEFAULT_SIGINT_RESET=0;DC_DEFAULT_SIGINT_RESET=0;BC_DEFAULT_TTY_MODE=1;DC_DEFAULT_TTY_MODE=1;BC_DEFAULT_PROMPT=1;DC_DEFAULT_PROMPT=1</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
|
@ -205,22 +205,22 @@
|
|||
</ClCompile>
|
||||
<Link>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>DebugFastLink</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;bcrypt.lib;ucrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(ProjectName)\dc.exe"</Command>
|
||||
<Command>copy /b "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\bc.exe" "$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\dc.exe"</Command>
|
||||
</PostBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Message>Copying bc to dc...</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(Configuration)\$(ProjectName)\lib.c" />
|
||||
<ClCompile Include="$(Configuration)\$(ProjectName)\lib2.c" />
|
||||
<ClCompile Include="$(Configuration)\$(ProjectName)\bc_help.c" />
|
||||
<ClCompile Include="$(Configuration)\$(ProjectName)\dc_help.c" />
|
||||
<ClCompile Include="$(Configuration)\$(Platform)\$(ProjectName)\lib.c" />
|
||||
<ClCompile Include="$(Configuration)\$(Platform)\$(ProjectName)\lib2.c" />
|
||||
<ClCompile Include="$(Configuration)\$(Platform)\$(ProjectName)\bc_help.c" />
|
||||
<ClCompile Include="$(Configuration)\$(Platform)\$(ProjectName)\dc_help.c" />
|
||||
<ClCompile Include="src\args.c" />
|
||||
<ClCompile Include="src\bc.c" />
|
||||
<ClCompile Include="src\bc_lex.c" />
|
||||
|
|
24
bcl.vcxproj
24
bcl.vcxproj
|
@ -65,27 +65,27 @@
|
|||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
|
@ -100,7 +100,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
|
@ -116,13 +116,13 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_ENABLE_PROMPT=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);BC_ENABLED=1;DC_ENABLED=1;BC_ENABLE_EXTRA_MATH=1;BC_ENABLE_HISTORY=0;BC_ENABLE_NLS=0;BC_DEBUG_CODE=0;BC_ENABLE_LIBRARY=1</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
383
configure.sh
383
configure.sh
|
@ -31,10 +31,12 @@ script="$0"
|
|||
scriptdir=$(dirname "$script")
|
||||
script=$(basename "$script")
|
||||
|
||||
. "$scriptdir/functions.sh"
|
||||
. "$scriptdir/scripts/functions.sh"
|
||||
|
||||
cd "$scriptdir"
|
||||
|
||||
# Simply prints the help message and quits based on the argument.
|
||||
# @param val The value to pass to exit. Must be an integer.
|
||||
usage() {
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
|
@ -52,16 +54,16 @@ usage() {
|
|||
printf ' %s --help\n' "$script"
|
||||
printf ' %s [-a|-bD|-dB|-c] [-CEfgGHlmMNPtTvz] [-O OPT_LEVEL] [-k KARATSUBA_LEN]\n' "$script"
|
||||
printf ' %s \\\n' "$script"
|
||||
printf ' [--library|--bc-only --disable-dc|--dc-only --disable-bc|--coverage]\\\n'
|
||||
printf ' [--force --debug --disable-extra-math --disable-generated-tests] \\\n'
|
||||
printf ' [--disable-history --disable-man-pages --disable-nls] \\\n'
|
||||
printf ' [--disable-prompt --disable-strip] [--install-all-locales] \\\n'
|
||||
printf ' [--opt=OPT_LEVEL] [--karatsuba-len=KARATSUBA_LEN] \\\n'
|
||||
printf ' [--prefix=PREFIX] [--bindir=BINDIR] [--datarootdir=DATAROOTDIR] \\\n'
|
||||
printf ' [--datadir=DATADIR] [--mandir=MANDIR] [--man1dir=MAN1DIR] \\\n'
|
||||
printf ' [--library|--bc-only --disable-dc|--dc-only --disable-bc|--coverage] \\\n'
|
||||
printf ' [--force --debug --disable-extra-math --disable-generated-tests] \\\n'
|
||||
printf ' [--disable-history --disable-man-pages --disable-nls --disable-strip] \\\n'
|
||||
printf ' [--install-all-locales] [--opt=OPT_LEVEL] \\\n'
|
||||
printf ' [--karatsuba-len=KARATSUBA_LEN] \\\n'
|
||||
printf ' [--prefix=PREFIX] [--bindir=BINDIR] [--datarootdir=DATAROOTDIR] \\\n'
|
||||
printf ' [--datadir=DATADIR] [--mandir=MANDIR] [--man1dir=MAN1DIR] \\\n'
|
||||
printf '\n'
|
||||
printf ' -a, --library\n'
|
||||
printf ' Build the libbc instead of the programs. This is meant to be used with\n'
|
||||
printf ' Build the libbcl instead of the programs. This is meant to be used with\n'
|
||||
printf ' Other software like programming languages that want to make use of the\n'
|
||||
printf ' parsing and math capabilities. This option will install headers using\n'
|
||||
printf ' `make install`.\n'
|
||||
|
@ -72,7 +74,7 @@ usage() {
|
|||
printf ' Disable bc. It is an error if "-b", "--bc-only", "-D", or "--disable-dc"\n'
|
||||
printf ' are specified too.\n'
|
||||
printf ' -c, --coverage\n'
|
||||
printf ' Generate test coverage code. Requires gcov and regcovr.\n'
|
||||
printf ' Generate test coverage code. Requires gcov and gcovr.\n'
|
||||
printf ' It is an error if either "-b" ("-D") or "-d" ("-B") is specified.\n'
|
||||
printf ' Requires a compiler that use gcc-compatible coverage options\n'
|
||||
printf ' -C, --disable-clean\n'
|
||||
|
@ -121,10 +123,14 @@ usage() {
|
|||
printf ' Set the optimization level. This can also be included in the CFLAGS,\n'
|
||||
printf ' but it is provided, so maintainers can build optimized debug builds.\n'
|
||||
printf ' This is passed through to the compiler, so it must be supported.\n'
|
||||
printf ' -P, --disable-prompt\n'
|
||||
printf ' Disables the prompt in the built bc. The prompt will never show up,\n'
|
||||
printf ' or in other words, it will be permanently disabled and cannot be\n'
|
||||
printf ' enabled.\n'
|
||||
printf ' -s SETTING, --set-default-on SETTING\n'
|
||||
printf ' Set the default named by SETTING to on. See below for possible values\n'
|
||||
printf ' for SETTING. For multiple instances of the -s or -S for the the same\n'
|
||||
printf ' setting, the last one is used.\n'
|
||||
printf ' -S SETTING, --set-default-off SETTING\n'
|
||||
printf ' Set the default named by SETTING to off. See below for possible values\n'
|
||||
printf ' for SETTING. For multiple instances of the -s or -S for the the same\n'
|
||||
printf ' setting, the last one is used.\n'
|
||||
printf ' -t, --enable-test-timing\n'
|
||||
printf ' Enable the timing of tests. This is for development only.\n'
|
||||
printf ' -T, --disable-strip\n'
|
||||
|
@ -239,10 +245,66 @@ usage() {
|
|||
printf '\n'
|
||||
printf 'WARNING: even though `configure.sh` supports both option types, short and\n'
|
||||
printf 'long, it does not support handling both at the same time. Use only one type.\n'
|
||||
printf '\n'
|
||||
printf 'Settings\n'
|
||||
printf '========\n'
|
||||
printf '\n'
|
||||
printf 'bc and dc have some settings that, while they cannot be removed by build time\n'
|
||||
printf 'options, can have their defaults changed at build time by packagers. Users are\n'
|
||||
printf 'also able to change each setting with environment variables.\n'
|
||||
printf '\n'
|
||||
printf 'The following is a table of settings, along with their default values and the\n'
|
||||
printf 'environment variables users can use to change them. (For the defaults, non-zero\n'
|
||||
printf 'means on, and zero means off.)\n'
|
||||
printf '\n'
|
||||
printf '| Setting | Description | Default | Env Variable |\n'
|
||||
printf '| =============== | ==================== | ============ | ==================== |\n'
|
||||
printf '| bc.banner | Whether to display | 0 | BC_BANNER |\n'
|
||||
printf '| | the bc version | | |\n'
|
||||
printf '| | banner when in | | |\n'
|
||||
printf '| | interactive mode. | | |\n'
|
||||
printf '| --------------- | -------------------- | ------------ | -------------------- |\n'
|
||||
printf '| bc.sigint_reset | Whether SIGINT will | 1 | BC_SIGINT_RESET |\n'
|
||||
printf '| | reset bc, instead of | | |\n'
|
||||
printf '| | exiting, when in | | |\n'
|
||||
printf '| | interactive mode. | | |\n'
|
||||
printf '| --------------- | -------------------- | ------------ | -------------------- |\n'
|
||||
printf '| dc.sigint_reset | Whether SIGINT will | 1 | DC_SIGINT_RESET |\n'
|
||||
printf '| | reset dc, instead of | | |\n'
|
||||
printf '| | exiting, when in | | |\n'
|
||||
printf '| | interactive mode. | | |\n'
|
||||
printf '| --------------- | -------------------- | ------------ | -------------------- |\n'
|
||||
printf '| bc.tty_mode | Whether TTY mode for | 1 | BC_TTY_MODE |\n'
|
||||
printf '| | bc should be on when | | |\n'
|
||||
printf '| | available. | | |\n'
|
||||
printf '| --------------- | -------------------- | ------------ | -------------------- |\n'
|
||||
printf '| dc.tty_mode | Whether TTY mode for | 0 | BC_TTY_MODE |\n'
|
||||
printf '| | dc should be on when | | |\n'
|
||||
printf '| | available. | | |\n'
|
||||
printf '| --------------- | -------------------- | ------------ | -------------------- |\n'
|
||||
printf '| bc.prompt | Whether the prompt | $BC_TTY_MODE | BC_PROMPT |\n'
|
||||
printf '| | for bc should be on | | |\n'
|
||||
printf '| | in tty mode. | | |\n'
|
||||
printf '| --------------- | -------------------- | ------------ | -------------------- |\n'
|
||||
printf '| dc.prompt | Whether the prompt | $DC_TTY_MODE | DC_PROMPT |\n'
|
||||
printf '| | for dc should be on | | |\n'
|
||||
printf '| | in tty mode. | | |\n'
|
||||
printf '| --------------- | -------------------- | ------------ | -------------------- |\n'
|
||||
printf '\n'
|
||||
printf 'These settings are not meant to be changed on a whim. They are meant to ensure\n'
|
||||
printf 'that this bc and dc will conform to the expectations of the user on each\n'
|
||||
printf 'platform.\n'
|
||||
|
||||
exit "$_usage_val"
|
||||
}
|
||||
|
||||
# Replaces a file extension in a filename. This is used mostly to turn filenames
|
||||
# like `src/num.c` into `src/num.o`. In other words, it helps to link targets to
|
||||
# the files they depend on.
|
||||
#
|
||||
# @param file The filename.
|
||||
# @param ext1 The extension to replace.
|
||||
# @param ext2 The new extension.
|
||||
replace_ext() {
|
||||
|
||||
if [ "$#" -ne 3 ]; then
|
||||
|
@ -258,6 +320,13 @@ replace_ext() {
|
|||
printf '%s\n' "$_replace_ext_result"
|
||||
}
|
||||
|
||||
# Replaces a file extension in every filename given in a list. The list is just
|
||||
# a space-separated list of words, so filenames are expected to *not* have
|
||||
# spaces in them. See the documentation for `replace_ext()`.
|
||||
#
|
||||
# @param files The list of space-separated filenames to replace extensions for.
|
||||
# @param ext1 The extension to replace.
|
||||
# @param ext2 The new extension.
|
||||
replace_exts() {
|
||||
|
||||
if [ "$#" -ne 3 ]; then
|
||||
|
@ -276,6 +345,17 @@ replace_exts() {
|
|||
printf '%s\n' "$_replace_exts_result"
|
||||
}
|
||||
|
||||
# Finds a placeholder in @a str and replaces it. This is the workhorse of
|
||||
# configure.sh. It's what replaces placeholders in Makefile.in with the data
|
||||
# needed for the chosen build. Below, you will see a lot of calls to this
|
||||
# function.
|
||||
#
|
||||
# Note that needle can never contain an exclamation point. For more information,
|
||||
# see substring_replace() in scripts/functions.sh.
|
||||
#
|
||||
# @param str The string to find and replace placeholders in.
|
||||
# @param needle The placeholder name.
|
||||
# @param replacement The string to use to replace the placeholder.
|
||||
replace() {
|
||||
|
||||
if [ "$#" -ne 3 ]; then
|
||||
|
@ -289,6 +369,9 @@ replace() {
|
|||
substring_replace "$_replace_str" "%%$_replace_needle%%" "$_replace_replacement"
|
||||
}
|
||||
|
||||
# This function finds all the source files that need to be built. If there is
|
||||
# only one argument and it is empty, then all source files are built. Otherwise,
|
||||
# the arguments are all assumed to be source files that should *not* be built.
|
||||
find_src_files() {
|
||||
|
||||
if [ "$#" -ge 1 ] && [ "$1" != "" ]; then
|
||||
|
@ -306,6 +389,11 @@ find_src_files() {
|
|||
printf '%s\n' $(find src/ -depth -name "*.c" $_find_src_files_args)
|
||||
}
|
||||
|
||||
# This function generates a list of files to go into the Makefile. It generates
|
||||
# the list of object files, as well as the list of test coverage files.
|
||||
#
|
||||
# @param contents The contents of the Makefile template to put the list of
|
||||
# files into.
|
||||
gen_file_list() {
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
|
@ -351,21 +439,25 @@ gen_file_list() {
|
|||
printf '%s\n' "$_gen_file_list_contents"
|
||||
}
|
||||
|
||||
# Generates the proper test targets for each test to have its own target. This
|
||||
# allows `make test` to run in parallel.
|
||||
#
|
||||
# @param name Which calculator to generate tests for.
|
||||
# @param extra_math An integer that, if non-zero, activates extra math tests.
|
||||
# @param time_tests An integer that, if non-zero, tells the test suite to time
|
||||
# the execution of each test.
|
||||
gen_tests() {
|
||||
|
||||
_gen_tests_name="$1"
|
||||
shift
|
||||
|
||||
_gen_tests_uname="$1"
|
||||
shift
|
||||
|
||||
_gen_tests_extra_math="$1"
|
||||
shift
|
||||
|
||||
_gen_tests_time_tests="$1"
|
||||
shift
|
||||
|
||||
_gen_tests_extra_required=$(cat tests/extra_required.txt)
|
||||
_gen_tests_extra_required=$(cat "$scriptdir/tests/extra_required.txt")
|
||||
|
||||
for _gen_tests_t in $(cat "$scriptdir/tests/$_gen_tests_name/all.txt"); do
|
||||
|
||||
|
@ -388,6 +480,10 @@ gen_tests() {
|
|||
done
|
||||
}
|
||||
|
||||
# Generates a list of test targets that will be used as prerequisites for other
|
||||
# targets.
|
||||
#
|
||||
# @param name The name of the calculator to generate test targets for.
|
||||
gen_test_targets() {
|
||||
|
||||
_gen_test_targets_name="$1"
|
||||
|
@ -402,6 +498,14 @@ gen_test_targets() {
|
|||
printf '\n'
|
||||
}
|
||||
|
||||
# Generates the proper script test targets for each script test to have its own
|
||||
# target. This allows `make test` to run in parallel.
|
||||
#
|
||||
# @param name Which calculator to generate tests for.
|
||||
# @param extra_math An integer that, if non-zero, activates extra math tests.
|
||||
# @param generate An integer that, if non-zero, activates generated tests.
|
||||
# @param time_tests An integer that, if non-zero, tells the test suite to time
|
||||
# the execution of each test.
|
||||
gen_script_tests() {
|
||||
|
||||
_gen_script_tests_name="$1"
|
||||
|
@ -429,6 +533,36 @@ gen_script_tests() {
|
|||
done
|
||||
}
|
||||
|
||||
set_default() {
|
||||
|
||||
_set_default_on="$1"
|
||||
shift
|
||||
|
||||
_set_default_name="$1"
|
||||
shift
|
||||
|
||||
# The reason that the variables that are being set do not have the same
|
||||
# non-collision avoidance that the other variables do is that we *do* want
|
||||
# the settings of these variables to leak out of the function. They adjust
|
||||
# the settings outside of the function.
|
||||
case "$_set_default_name" in
|
||||
|
||||
bc.banner) bc_default_banner="$_set_default_on" ;;
|
||||
bc.sigint_reset) bc_default_sigint_reset="$_set_default_on" ;;
|
||||
dc.sigint_reset) dc_default_sigint_reset="$_set_default_on" ;;
|
||||
bc.tty_mode) bc_default_tty_mode="$_set_default_on" ;;
|
||||
dc.tty_mode) dc_default_tty_mode="$_set_default_on" ;;
|
||||
bc.prompt) bc_default_prompt="$_set_default_on" ;;
|
||||
dc.prompt) dc_default_prompt="$_set_default_on" ;;
|
||||
?) usage "Invalid setting: $_set_default_name" ;;
|
||||
|
||||
esac
|
||||
}
|
||||
|
||||
# Generates a list of script test targets that will be used as prerequisites for
|
||||
# other targets.
|
||||
#
|
||||
# @param name The name of the calculator to generate script test targets for.
|
||||
gen_script_test_targets() {
|
||||
|
||||
_gen_script_test_targets_name="$1"
|
||||
|
@ -446,6 +580,12 @@ gen_script_test_targets() {
|
|||
printf '\n'
|
||||
}
|
||||
|
||||
# This is a list of defaults, but it is also the list of possible options for
|
||||
# users to change.
|
||||
#
|
||||
# The development options are: force (force options even if they fail), valgrind
|
||||
# (build in a way suitable for valgrind testing), memcheck (same as valgrind),
|
||||
# and fuzzing (build in a way suitable for fuzzing).
|
||||
bc_only=0
|
||||
dc_only=0
|
||||
coverage=0
|
||||
|
@ -457,7 +597,6 @@ optimization=""
|
|||
generate_tests=1
|
||||
install_manpages=1
|
||||
nls=1
|
||||
prompt=1
|
||||
force=0
|
||||
strip_bin=1
|
||||
all_locales=0
|
||||
|
@ -468,7 +607,20 @@ vg=0
|
|||
memcheck=0
|
||||
clean=1
|
||||
|
||||
while getopts "abBcdDEfgGhHk:lMmNO:PStTvz-" opt; do
|
||||
# The empty strings are because they depend on TTY mode. If they are directly
|
||||
# set, though, they will be integers. We test for empty strings later.
|
||||
bc_default_banner=0
|
||||
bc_default_sigint_reset=1
|
||||
dc_default_sigint_reset=1
|
||||
bc_default_tty_mode=1
|
||||
dc_default_tty_mode=0
|
||||
bc_default_prompt=""
|
||||
dc_default_prompt=""
|
||||
|
||||
# getopts is a POSIX utility, but it cannot handle long options. Thus, the
|
||||
# handling of long options is done by hand, and that's the reason that short and
|
||||
# long options cannot be mixed.
|
||||
while getopts "abBcdDEfgGhHk:lMmNO:S:s:tTvz-" opt; do
|
||||
|
||||
case "$opt" in
|
||||
a) library=1 ;;
|
||||
|
@ -490,7 +642,8 @@ while getopts "abBcdDEfgGhHk:lMmNO:PStTvz-" opt; do
|
|||
M) install_manpages=0 ;;
|
||||
N) nls=0 ;;
|
||||
O) optimization="$OPTARG" ;;
|
||||
P) prompt=0 ;;
|
||||
S) set_default 0 "$OPTARG" ;;
|
||||
s) set_default 1 "$OPTARG" ;;
|
||||
t) time_tests=1 ;;
|
||||
T) strip_bin=0 ;;
|
||||
v) vg=1 ;;
|
||||
|
@ -591,6 +744,20 @@ while getopts "abBcdDEfgGhHk:lMmNO:PStTvz-" opt; do
|
|||
fi
|
||||
optimization="$1"
|
||||
shift ;;
|
||||
set-default-on=?*) set_default 1 "$LONG_OPTARG" ;;
|
||||
set-default-on)
|
||||
if [ "$#" -lt 2 ]; then
|
||||
usage "No argument given for '--$arg' option"
|
||||
fi
|
||||
set_default 1 "$1"
|
||||
shift ;;
|
||||
set-default-off=?*) set_default 0 "$LONG_OPTARG" ;;
|
||||
set-default-off)
|
||||
if [ "$#" -lt 2 ]; then
|
||||
usage "No argument given for '--$arg' option"
|
||||
fi
|
||||
set_default 0 "$1"
|
||||
shift ;;
|
||||
disable-bc) dc_only=1 ;;
|
||||
disable-dc) bc_only=1 ;;
|
||||
disable-clean) clean=0 ;;
|
||||
|
@ -599,7 +766,6 @@ while getopts "abBcdDEfgGhHk:lMmNO:PStTvz-" opt; do
|
|||
disable-history) hist=0 ;;
|
||||
disable-man-pages) install_manpages=0 ;;
|
||||
disable-nls) nls=0 ;;
|
||||
disable-prompt) prompt=0 ;;
|
||||
disable-strip) strip_bin=0 ;;
|
||||
enable-test-timing) time_tests=1 ;;
|
||||
enable-valgrind) vg=1 ;;
|
||||
|
@ -625,27 +791,33 @@ while getopts "abBcdDEfgGhHk:lMmNO:PStTvz-" opt; do
|
|||
esac
|
||||
shift
|
||||
OPTIND=1 ;;
|
||||
?) usage "Invalid option $opt" ;;
|
||||
?) usage "Invalid option: $opt" ;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
# Sometimes, developers don't want configure.sh to do a config clean. But
|
||||
# sometimes they do.
|
||||
if [ "$clean" -ne 0 ]; then
|
||||
if [ -f ./Makefile ]; then
|
||||
make clean_config > /dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
# It is an error to say that bc only should be built and likewise for dc.
|
||||
if [ "$bc_only" -eq 1 ] && [ "$dc_only" -eq 1 ]; then
|
||||
usage "Can only specify one of -b(-D) or -d(-B)"
|
||||
fi
|
||||
|
||||
# The library is mutually exclusive to the calculators, so it's an error to
|
||||
# give an option for either of them.
|
||||
if [ "$library" -ne 0 ]; then
|
||||
if [ "$bc_only" -eq 1 ] || [ "$dc_only" -eq 1 ]; then
|
||||
usage "Must not specify -b(-D) or -d(-B) when building the library"
|
||||
fi
|
||||
fi
|
||||
|
||||
# KARATSUBA_LEN must be an integer and must be 16 or greater.
|
||||
case $karatsuba_len in
|
||||
(*[!0-9]*|'') usage "KARATSUBA_LEN is not a number" ;;
|
||||
(*) ;;
|
||||
|
@ -668,6 +840,11 @@ fi
|
|||
if [ -z "$CC" ]; then
|
||||
CC="c99"
|
||||
else
|
||||
|
||||
# I had users complain that, if they gave CFLAGS as part of CC, which
|
||||
# autotools allows in its braindead way, the build would fail with an error.
|
||||
# I don't like adjusting for autotools, but oh well. These lines puts the
|
||||
# stuff after the first space into CFLAGS.
|
||||
ccbase=$(basename "$CC")
|
||||
suffix=" *"
|
||||
prefix="* "
|
||||
|
@ -693,6 +870,8 @@ elif [ -z "$HOSTCC" ]; then
|
|||
fi
|
||||
|
||||
if [ "$HOSTCC" != "$CC" ]; then
|
||||
|
||||
# Like above, this splits HOSTCC and HOSTCFLAGS.
|
||||
ccbase=$(basename "$HOSTCC")
|
||||
suffix=" *"
|
||||
prefix="* "
|
||||
|
@ -717,14 +896,18 @@ elif [ -z "${HOSTCFLAGS+set}" ]; then
|
|||
HOSTCFLAGS="$HOST_CFLAGS"
|
||||
fi
|
||||
|
||||
# Store these for the cross compilation detection later.
|
||||
OLDCFLAGS="$CFLAGS"
|
||||
OLDHOSTCFLAGS="$HOSTCFLAGS"
|
||||
|
||||
link="@printf 'No link necessary\\\\n'"
|
||||
main_exec="BC"
|
||||
executable="BC_EXEC"
|
||||
|
||||
tests="test_bc timeconst test_dc"
|
||||
tests="test_bc timeconst test_dc test_history"
|
||||
|
||||
bc_test="@tests/all.sh bc $extra_math 1 $generate_tests 0 \$(BC_EXEC)"
|
||||
dc_test="@tests/all.sh dc $extra_math 1 $generate_tests 0 \$(DC_EXEC)"
|
||||
bc_test="@tests/all.sh bc $extra_math 1 $generate_tests $time_tests \$(BC_EXEC)"
|
||||
dc_test="@tests/all.sh dc $extra_math 1 $generate_tests $time_tests \$(DC_EXEC)"
|
||||
|
||||
timeconst="@tests/bc/timeconst.sh tests/bc/scripts/timeconst.bc \$(BC_EXEC)"
|
||||
|
||||
|
@ -739,6 +922,9 @@ else
|
|||
dc_test_exec='$(DC_EXEC)'
|
||||
fi
|
||||
|
||||
test_bc_history_prereqs="test_bc_history_all"
|
||||
test_dc_history_prereqs="test_dc_history_all"
|
||||
|
||||
karatsuba="@printf 'karatsuba cannot be run because one of bc or dc is not built\\\\n'"
|
||||
karatsuba_test="@printf 'karatsuba cannot be run because one of bc or dc is not built\\\\n'"
|
||||
|
||||
|
@ -754,12 +940,13 @@ second_target_prereqs=""
|
|||
second_target_cmd="$default_target_cmd"
|
||||
second_target="\$(BC_EXEC)"
|
||||
|
||||
# This if/else if chain is for setting the defaults that change based on whether
|
||||
# the library is being built, bc only, dc only, or both calculators.
|
||||
if [ "$library" -ne 0 ]; then
|
||||
|
||||
extra_math=1
|
||||
nls=0
|
||||
hist=0
|
||||
prompt=0
|
||||
bc=1
|
||||
dc=1
|
||||
|
||||
|
@ -767,6 +954,8 @@ if [ "$library" -ne 0 ]; then
|
|||
default_target_cmd="ar -r -cu \$(LIBBC) \$(OBJ)"
|
||||
default_target="\$(LIBBC)"
|
||||
tests="test_library"
|
||||
test_bc_history_prereqs=" test_bc_history_skip"
|
||||
test_dc_history_prereqs=" test_dc_history_skip"
|
||||
|
||||
elif [ "$bc_only" -eq 1 ]; then
|
||||
|
||||
|
@ -778,6 +967,7 @@ elif [ "$bc_only" -eq 1 ]; then
|
|||
executables="bc"
|
||||
|
||||
dc_test="@printf 'No dc tests to run\\\\n'"
|
||||
test_dc_history_prereqs=" test_dc_history_skip"
|
||||
|
||||
install_prereqs=" install_execs"
|
||||
install_man_prereqs=" install_bc_manpage"
|
||||
|
@ -786,7 +976,7 @@ elif [ "$bc_only" -eq 1 ]; then
|
|||
|
||||
default_target="\$(BC_EXEC)"
|
||||
second_target="\$(DC_EXEC)"
|
||||
tests="test_bc timeconst"
|
||||
tests="test_bc timeconst test_history"
|
||||
|
||||
elif [ "$dc_only" -eq 1 ]; then
|
||||
|
||||
|
@ -802,6 +992,7 @@ elif [ "$dc_only" -eq 1 ]; then
|
|||
executable="DC_EXEC"
|
||||
|
||||
bc_test="@printf 'No bc tests to run\\\\n'"
|
||||
test_bc_history_prereqs=" test_bc_history_skip"
|
||||
|
||||
timeconst="@printf 'timeconst cannot be run because bc is not built\\\\n'"
|
||||
|
||||
|
@ -810,7 +1001,7 @@ elif [ "$dc_only" -eq 1 ]; then
|
|||
uninstall_prereqs=" uninstall_dc"
|
||||
uninstall_man_prereqs=" uninstall_dc_manpage"
|
||||
|
||||
tests="test_dc"
|
||||
tests="test_dc test_history"
|
||||
|
||||
else
|
||||
|
||||
|
@ -841,14 +1032,15 @@ else
|
|||
|
||||
fi
|
||||
|
||||
# We need specific stuff for fuzzing.
|
||||
if [ "$fuzz" -ne 0 ]; then
|
||||
debug=1
|
||||
hist=0
|
||||
prompt=0
|
||||
nls=0
|
||||
optimization="3"
|
||||
fi
|
||||
|
||||
# This sets some necessary things for debug mode.
|
||||
if [ "$debug" -eq 1 ]; then
|
||||
|
||||
if [ -z "$CFLAGS" ] && [ -z "$optimization" ]; then
|
||||
|
@ -858,16 +1050,20 @@ if [ "$debug" -eq 1 ]; then
|
|||
CFLAGS="-g $CFLAGS"
|
||||
|
||||
else
|
||||
|
||||
CPPFLAGS="-DNDEBUG $CPPFLAGS"
|
||||
|
||||
if [ "$strip_bin" -ne 0 ]; then
|
||||
LDFLAGS="-s $LDFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set optimization CFLAGS.
|
||||
if [ -n "$optimization" ]; then
|
||||
CFLAGS="-O$optimization $CFLAGS"
|
||||
fi
|
||||
|
||||
# Set test coverage defaults.
|
||||
if [ "$coverage" -eq 1 ]; then
|
||||
|
||||
if [ "$bc_only" -eq 1 ] || [ "$dc_only" -eq 1 ]; then
|
||||
|
@ -879,7 +1075,7 @@ if [ "$coverage" -eq 1 ]; then
|
|||
|
||||
COVERAGE_OUTPUT="@gcov -pabcdf \$(GCDA) \$(BC_GCDA) \$(DC_GCDA) \$(HISTORY_GCDA) \$(RAND_GCDA)"
|
||||
COVERAGE_OUTPUT="$COVERAGE_OUTPUT;\$(RM) -f \$(GEN)*.gc*"
|
||||
COVERAGE_OUTPUT="$COVERAGE_OUTPUT;gcovr --html-details --output index.html"
|
||||
COVERAGE_OUTPUT="$COVERAGE_OUTPUT;gcovr --exclude-unreachable-branches --exclude-throw-branches --html-details --output index.html"
|
||||
COVERAGE_PREREQS=" test coverage_output"
|
||||
|
||||
else
|
||||
|
@ -887,6 +1083,8 @@ else
|
|||
COVERAGE_PREREQS=""
|
||||
fi
|
||||
|
||||
|
||||
# Set some defaults.
|
||||
if [ -z "${DESTDIR+set}" ]; then
|
||||
destdir=""
|
||||
else
|
||||
|
@ -909,12 +1107,16 @@ if [ -z "${LIBDIR+set}" ]; then
|
|||
LIBDIR="$PREFIX/lib"
|
||||
fi
|
||||
|
||||
# Set a default for the DATAROOTDIR. This is done if either manpages will be
|
||||
# installed, or locales are enabled because that's probably where NLS_PATH
|
||||
# points.
|
||||
if [ "$install_manpages" -ne 0 ] || [ "$nls" -ne 0 ]; then
|
||||
if [ -z "${DATAROOTDIR+set}" ]; then
|
||||
DATAROOTDIR="$PREFIX/share"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set defaults for manpage environment variables.
|
||||
if [ "$install_manpages" -ne 0 ]; then
|
||||
|
||||
if [ -z "${DATADIR+set}" ]; then
|
||||
|
@ -938,6 +1140,9 @@ else
|
|||
uninstall_man_prereqs=""
|
||||
fi
|
||||
|
||||
# Here is where we test NLS (the locale system). This is done by trying to
|
||||
# compile src/vm.c, which has the relevant code. If it fails, then it is
|
||||
# disabled.
|
||||
if [ "$nls" -ne 0 ]; then
|
||||
|
||||
set +e
|
||||
|
@ -945,7 +1150,7 @@ if [ "$nls" -ne 0 ]; then
|
|||
printf 'Testing NLS...\n'
|
||||
|
||||
flags="-DBC_ENABLE_NLS=1 -DBC_ENABLED=$bc -DDC_ENABLED=$dc"
|
||||
flags="$flags -DBC_ENABLE_HISTORY=$hist"
|
||||
flags="$flags -DBC_ENABLE_HISTORY=$hist -DBC_ENABLE_LIBRARY=0 -DBC_ENABLE_AFL=0"
|
||||
flags="$flags -DBC_ENABLE_EXTRA_MATH=$extra_math -I./include/"
|
||||
flags="$flags -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700"
|
||||
|
||||
|
@ -987,7 +1192,10 @@ if [ "$nls" -ne 0 ]; then
|
|||
|
||||
printf 'gencat works.\n\n'
|
||||
|
||||
if [ "$HOSTCC" != "$CC" ]; then
|
||||
# It turns out that POSIX locales are really terrible, and running
|
||||
# gencat on one machine is not guaranteed to make those cat files
|
||||
# portable to another machine, so we had better warn the user here.
|
||||
if [ "$HOSTCC" != "$CC" ] || [ "$OLDHOSTCFLAGS" != "$OLDCFLAGS" ]; then
|
||||
printf 'Cross-compile detected.\n\n'
|
||||
printf 'WARNING: Catalog files generated with gencat may not be portable\n'
|
||||
printf ' across different architectures.\n\n'
|
||||
|
@ -1018,6 +1226,7 @@ else
|
|||
install_locales="\$(LOCALE_INSTALL) \$(NLSPATH) \$(MAIN_EXEC) \$(DESTDIR)"
|
||||
fi
|
||||
|
||||
# Like the above tested locale support, this tests history.
|
||||
if [ "$hist" -eq 1 ]; then
|
||||
|
||||
set +e
|
||||
|
@ -1025,7 +1234,7 @@ if [ "$hist" -eq 1 ]; then
|
|||
printf 'Testing history...\n'
|
||||
|
||||
flags="-DBC_ENABLE_HISTORY=1 -DBC_ENABLED=$bc -DDC_ENABLED=$dc"
|
||||
flags="$flags -DBC_ENABLE_NLS=$nls -DBC_ENABLE_LIBRARY=0"
|
||||
flags="$flags -DBC_ENABLE_NLS=$nls -DBC_ENABLE_LIBRARY=0 -DBC_ENABLE_AFL=0"
|
||||
flags="$flags -DBC_ENABLE_EXTRA_MATH=$extra_math -I./include/"
|
||||
flags="$flags -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700"
|
||||
|
||||
|
@ -1053,6 +1262,39 @@ if [ "$hist" -eq 1 ]; then
|
|||
|
||||
fi
|
||||
|
||||
# We have to disable the history tests if it is disabled or valgrind is on.
|
||||
if [ "$hist" -eq 0 ] || [ "$vg" -ne 0 ]; then
|
||||
test_bc_history_prereqs=" test_bc_history_skip"
|
||||
test_dc_history_prereqs=" test_dc_history_skip"
|
||||
history_tests="@printf 'Skipping history tests...\\\\n'"
|
||||
else
|
||||
history_tests="@printf '\$(TEST_STARS)\\\\n\\\\nRunning history tests...\\\\n\\\\n' \&\& tests/history.sh bc -a \&\& tests/history.sh dc -a \&\& printf '\\\\nAll history tests passed.\\\\n\\\\n\$(TEST_STARS)\\\\n'"
|
||||
fi
|
||||
|
||||
# Test OpenBSD. This is not in an if statement because regardless of whatever
|
||||
# the user says, we need to know if we are on OpenBSD to activate _BSD_SOURCE.
|
||||
# No, I cannot `#define _BSD_SOURCE` in a header because OpenBSD's patched GCC
|
||||
# and Clang complain that that is only allowed for system headers. Sigh....So we
|
||||
# have to check at configure time and set it on the compiler command-line. And
|
||||
# we have to set it because we also set _POSIX_C_SOURCE, which OpenBSD headers
|
||||
# detect, and when they detect it, they turn off _BSD_SOURCE unless it is
|
||||
# specifically requested.
|
||||
set +e
|
||||
printf 'Testing for OpenBSD...\n'
|
||||
|
||||
flags="-DBC_TEST_OPENBSD -DBC_ENABLE_AFL=0"
|
||||
"$CC" $CPPFLAGS $CFLAGS $flags -I./include -E "include/status.h" > /dev/null 2>&1
|
||||
|
||||
err="$?"
|
||||
|
||||
if [ "$err" -ne 0 ]; then
|
||||
printf 'On OpenBSD. Using _BSD_SOURCE.\n\n'
|
||||
bsd="-D_BSD_SOURCE"
|
||||
else
|
||||
printf 'Not on OpenBSD.\n\n'
|
||||
bsd=""
|
||||
fi
|
||||
|
||||
if [ "$library" -eq 1 ]; then
|
||||
bc_lib=""
|
||||
fi
|
||||
|
@ -1063,9 +1305,11 @@ else
|
|||
BC_LIB2_O=""
|
||||
fi
|
||||
|
||||
# These lines set the appropriate targets based on whether `gen/strgen.c` or
|
||||
# `gen/strgen.sh` is used.
|
||||
GEN="strgen"
|
||||
GEN_EXEC_TARGET="\$(HOSTCC) \$(HOSTCFLAGS) -o \$(GEN_EXEC) \$(GEN_C)"
|
||||
CLEAN_PREREQS=" clean_gen"
|
||||
CLEAN_PREREQS=" clean_gen clean_coverage"
|
||||
|
||||
if [ -z "${GEN_HOST+set}" ]; then
|
||||
GEN_HOST=1
|
||||
|
@ -1073,7 +1317,7 @@ else
|
|||
if [ "$GEN_HOST" -eq 0 ]; then
|
||||
GEN="strgen.sh"
|
||||
GEN_EXEC_TARGET="@printf 'Do not need to build gen/strgen.c\\\\n'"
|
||||
CLEAN_PREREQS=""
|
||||
CLEAN_PREREQS=" clean_coverage"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -1081,6 +1325,7 @@ manpage_args=""
|
|||
unneeded=""
|
||||
headers="\$(HEADERS)"
|
||||
|
||||
# This series of if statements figure out what source files are *not* needed.
|
||||
if [ "$extra_math" -eq 0 ]; then
|
||||
manpage_args="E"
|
||||
unneeded="$unneeded rand.c"
|
||||
|
@ -1088,6 +1333,9 @@ else
|
|||
headers="$headers \$(EXTRA_MATH_HEADERS)"
|
||||
fi
|
||||
|
||||
# All of these next if statements set the build type and mark certain source
|
||||
# files as unneeded so that they won't have targets generated for them.
|
||||
|
||||
if [ "$hist" -eq 0 ]; then
|
||||
manpage_args="${manpage_args}H"
|
||||
unneeded="$unneeded history.c"
|
||||
|
@ -1099,10 +1347,6 @@ if [ "$nls" -eq 0 ]; then
|
|||
manpage_args="${manpage_args}N"
|
||||
fi
|
||||
|
||||
if [ "$prompt" -eq 0 ]; then
|
||||
manpage_args="${manpage_args}P"
|
||||
fi
|
||||
|
||||
if [ "$bc" -eq 0 ]; then
|
||||
unneeded="$unneeded bc.c bc_lex.c bc_parse.c"
|
||||
else
|
||||
|
@ -1125,6 +1369,12 @@ else
|
|||
unneeded="$unneeded library.c"
|
||||
fi
|
||||
|
||||
# library.c is not needed under normal circumstances.
|
||||
if [ "$unneeded" = "" ]; then
|
||||
unneeded="library.c"
|
||||
fi
|
||||
|
||||
# This sets the appropriate manpage for a full build.
|
||||
if [ "$manpage_args" = "" ]; then
|
||||
manpage_args="A"
|
||||
fi
|
||||
|
@ -1133,6 +1383,15 @@ if [ "$vg" -ne 0 ]; then
|
|||
memcheck=1
|
||||
fi
|
||||
|
||||
if [ "$bc_default_prompt" = "" ]; then
|
||||
bc_default_prompt="$bc_default_tty_mode"
|
||||
fi
|
||||
|
||||
if [ "$dc_default_prompt" = "" ]; then
|
||||
dc_default_prompt="$dc_default_tty_mode"
|
||||
fi
|
||||
|
||||
# Generate the test targets and prerequisites.
|
||||
bc_tests=$(gen_test_targets bc)
|
||||
bc_script_tests=$(gen_script_test_targets bc)
|
||||
dc_tests=$(gen_test_targets dc)
|
||||
|
@ -1154,7 +1413,6 @@ printf 'BC_ENABLE_LIBRARY=%s\n\n' "$library"
|
|||
printf 'BC_ENABLE_HISTORY=%s\n' "$hist"
|
||||
printf 'BC_ENABLE_EXTRA_MATH=%s\n' "$extra_math"
|
||||
printf 'BC_ENABLE_NLS=%s\n' "$nls"
|
||||
printf 'BC_ENABLE_PROMPT=%s\n' "$prompt"
|
||||
printf 'BC_ENABLE_AFL=%s\n' "$fuzz"
|
||||
printf '\n'
|
||||
printf 'BC_NUM_KARATSUBA_LEN=%s\n' "$karatsuba_len"
|
||||
|
@ -1181,6 +1439,19 @@ printf 'DESTDIR=%s\n' "$DESTDIR"
|
|||
printf 'LONG_BIT=%s\n' "$LONG_BIT"
|
||||
printf 'GEN_HOST=%s\n' "$GEN_HOST"
|
||||
printf 'GEN_EMU=%s\n' "$GEN_EMU"
|
||||
printf '\n'
|
||||
printf 'Setting Defaults\n'
|
||||
printf '================\n'
|
||||
printf 'bc.banner=%s\n' "$bc_default_banner"
|
||||
printf 'bc.sigint_reset=%s\n' "$bc_default_sigint_reset"
|
||||
printf 'dc.sigint_reset=%s\n' "$dc_default_sigint_reset"
|
||||
printf 'bc.tty_mode=%s\n' "$bc_default_tty_mode"
|
||||
printf 'dc.tty_mode=%s\n' "$dc_default_tty_mode"
|
||||
printf 'bc.prompt=%s\n' "$bc_default_prompt"
|
||||
printf 'dc.prompt=%s\n' "$dc_default_prompt"
|
||||
|
||||
# This is where the real work begins. This is the point at which the Makefile.in
|
||||
# template is edited and output to the Makefile.
|
||||
|
||||
contents=$(cat "$scriptdir/Makefile.in")
|
||||
|
||||
|
@ -1189,14 +1460,14 @@ replacement='*** WARNING: Autogenerated from Makefile.in. DO NOT MODIFY ***'
|
|||
|
||||
contents=$(replace "$contents" "$needle" "$replacement")
|
||||
|
||||
if [ "$unneeded" = "" ]; then
|
||||
unneeded="library.c"
|
||||
fi
|
||||
|
||||
# The contents are edited to have the list of files to build.
|
||||
contents=$(gen_file_list "$contents" $unneeded)
|
||||
|
||||
SRC_TARGETS=""
|
||||
|
||||
# This line and loop generates the individual targets for source files. I used
|
||||
# to just use an implicit target, but that was found to be inadequate when I
|
||||
# added the library.
|
||||
src_files=$(find_src_files $unneeded)
|
||||
|
||||
for f in $src_files; do
|
||||
|
@ -1205,6 +1476,7 @@ for f in $src_files; do
|
|||
"$SRC_TARGETS" "$o" "$headers" "$f" "$o" "$f")
|
||||
done
|
||||
|
||||
# Replace all the placeholders.
|
||||
contents=$(replace "$contents" "HEADERS" "$headers")
|
||||
|
||||
contents=$(replace "$contents" "BC_ENABLED" "$bc")
|
||||
|
@ -1227,7 +1499,6 @@ contents=$(replace "$contents" "LIBRARY" "$library")
|
|||
contents=$(replace "$contents" "HISTORY" "$hist")
|
||||
contents=$(replace "$contents" "EXTRA_MATH" "$extra_math")
|
||||
contents=$(replace "$contents" "NLS" "$nls")
|
||||
contents=$(replace "$contents" "PROMPT" "$prompt")
|
||||
contents=$(replace "$contents" "FUZZ" "$fuzz")
|
||||
contents=$(replace "$contents" "MEMCHECK" "$memcheck")
|
||||
|
||||
|
@ -1281,7 +1552,10 @@ contents=$(replace "$contents" "EXEC" "$executable")
|
|||
contents=$(replace "$contents" "TESTS" "$tests")
|
||||
|
||||
contents=$(replace "$contents" "BC_TEST" "$bc_test")
|
||||
contents=$(replace "$contents" "BC_HISTORY_TEST_PREREQS" "$test_bc_history_prereqs")
|
||||
contents=$(replace "$contents" "DC_TEST" "$dc_test")
|
||||
contents=$(replace "$contents" "DC_HISTORY_TEST_PREREQS" "$test_dc_history_prereqs")
|
||||
contents=$(replace "$contents" "HISTORY_TESTS" "$history_tests")
|
||||
|
||||
contents=$(replace "$contents" "VG_BC_TEST" "$vg_bc_test")
|
||||
contents=$(replace "$contents" "VG_DC_TEST" "$vg_dc_test")
|
||||
|
@ -1299,20 +1573,33 @@ contents=$(replace "$contents" "GEN_EXEC_TARGET" "$GEN_EXEC_TARGET")
|
|||
contents=$(replace "$contents" "CLEAN_PREREQS" "$CLEAN_PREREQS")
|
||||
contents=$(replace "$contents" "GEN_EMU" "$GEN_EMU")
|
||||
|
||||
contents=$(replace "$contents" "BSD" "$bsd")
|
||||
|
||||
contents=$(replace "$contents" "BC_DEFAULT_BANNER" "$bc_default_banner")
|
||||
contents=$(replace "$contents" "BC_DEFAULT_SIGINT_RESET" "$bc_default_sigint_reset")
|
||||
contents=$(replace "$contents" "DC_DEFAULT_SIGINT_RESET" "$dc_default_sigint_reset")
|
||||
contents=$(replace "$contents" "BC_DEFAULT_TTY_MODE" "$bc_default_tty_mode")
|
||||
contents=$(replace "$contents" "DC_DEFAULT_TTY_MODE" "$dc_default_tty_mode")
|
||||
contents=$(replace "$contents" "BC_DEFAULT_PROMPT" "$bc_default_prompt")
|
||||
contents=$(replace "$contents" "DC_DEFAULT_PROMPT" "$dc_default_prompt")
|
||||
|
||||
# Do the first print to the Makefile.
|
||||
printf '%s\n%s\n\n' "$contents" "$SRC_TARGETS" > "$scriptdir/Makefile"
|
||||
|
||||
# Generate the individual test targets.
|
||||
if [ "$bc" -ne 0 ]; then
|
||||
gen_tests bc BC "$extra_math" "$time_tests" $bc_test_exec
|
||||
gen_tests bc "$extra_math" "$time_tests" $bc_test_exec
|
||||
gen_script_tests bc "$extra_math" "$generate_tests" "$time_tests" $bc_test_exec
|
||||
fi
|
||||
|
||||
if [ "$dc" -ne 0 ]; then
|
||||
gen_tests dc DC "$extra_math" "$time_tests" $dc_test_exec
|
||||
gen_tests dc "$extra_math" "$time_tests" $dc_test_exec
|
||||
gen_script_tests dc "$extra_math" "$generate_tests" "$time_tests" $dc_test_exec
|
||||
fi
|
||||
|
||||
cd "$scriptdir"
|
||||
|
||||
# Copy the correct manuals to the expected places.
|
||||
cp -f manuals/bc/$manpage_args.1.md manuals/bc.1.md
|
||||
cp -f manuals/bc/$manpage_args.1 manuals/bc.1
|
||||
cp -f manuals/dc/$manpage_args.1.md manuals/dc.1.md
|
||||
|
|
|
@ -108,6 +108,17 @@ Options:
|
|||
|
||||
Disable the read prompt in interactive mode.
|
||||
|
||||
-r keyword --redefine=keyword
|
||||
|
||||
Redefines "keyword" and allows it to be used as a function, variable, and
|
||||
array name. This is useful when this bc gives parse errors on scripts
|
||||
meant for other bc implementations.
|
||||
|
||||
Only keywords that are not in the POSIX bc spec may be redefined.
|
||||
|
||||
It is a fatal error to attempt to redefine a keyword that cannot be
|
||||
redefined or does not exist.
|
||||
|
||||
-q --quiet
|
||||
|
||||
Don't print version and copyright.
|
||||
|
@ -123,3 +134,44 @@ Options:
|
|||
-v --version
|
||||
|
||||
Print version information and copyright and exit.
|
||||
|
||||
Environment variables:
|
||||
|
||||
POSIXLY_CORRECT
|
||||
|
||||
Error if any non-POSIX extensions are used.
|
||||
|
||||
BC_ENV_ARGS
|
||||
|
||||
Command-line arguments to use on every run.
|
||||
|
||||
BC_LINE_LENGTH
|
||||
|
||||
If an integer, the number of characters to print on a line before
|
||||
wrapping.
|
||||
|
||||
BC_BANNER
|
||||
|
||||
If an integer and non-zero, display the copyright banner in interactive
|
||||
mode.
|
||||
|
||||
Overrides the default, which is %s print the banner.
|
||||
|
||||
BC_SIGINT_RESET
|
||||
|
||||
If an integer and non-zero, reset on SIGINT, rather than exit, when in
|
||||
interactive mode.
|
||||
|
||||
Overrides the default, which is %s.
|
||||
|
||||
BC_TTY_MODE
|
||||
|
||||
If an integer and non-zero, enable TTY mode when it is available.
|
||||
|
||||
Overrides the default, which is TTY mode %s.
|
||||
|
||||
BC_PROMPT
|
||||
|
||||
If an integer and non-zero, enable prompt when TTY mode is possible.
|
||||
|
||||
Overrides the default, which is prompt %s.
|
||||
|
|
|
@ -104,3 +104,33 @@ Options:
|
|||
-x --extended-register
|
||||
|
||||
Enable extended register mode.
|
||||
|
||||
Environment variables:
|
||||
|
||||
DC_ENV_ARGS
|
||||
|
||||
Command-line arguments to use on every run.
|
||||
|
||||
DC_LINE_LENGTH
|
||||
|
||||
If an integer, the number of characters to print on a line before
|
||||
wrapping.
|
||||
|
||||
DC_SIGINT_RESET
|
||||
|
||||
If an integer and non-zero, reset on SIGINT, rather than exit, when in
|
||||
interactive mode.
|
||||
|
||||
Overrides the default, which is %s.
|
||||
|
||||
DC_TTY_MODE
|
||||
|
||||
If an integer and non-zero, enable TTY mode when it is available.
|
||||
|
||||
Overrides the default, which is TTY mode %s.
|
||||
|
||||
DC_PROMPT
|
||||
|
||||
If an integer and non-zero, enable prompt when TTY mode is possible.
|
||||
|
||||
Overrides the default, which is prompt %s.
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
scale=20
|
||||
scale=2*A
|
||||
define e(x){
|
||||
auto b,s,n,r,d,i,p,f,v
|
||||
b=ibase
|
||||
|
|
247
gen/lib2.bc
247
gen/lib2.bc
|
@ -119,7 +119,7 @@ define root(x,n){
|
|||
m=(x<0)
|
||||
x=abs(x)
|
||||
p=n-1
|
||||
q=10^ceil((length(x$)/n)$,0)
|
||||
q=A^ceil((length(x$)/n)$,0)
|
||||
while(r!=q){
|
||||
r=q
|
||||
q=(p*r+x/r^p)/n
|
||||
|
@ -129,6 +129,37 @@ define root(x,n){
|
|||
return r@s
|
||||
}
|
||||
define cbrt(x){return root(x,3)}
|
||||
define gcd(a,b){
|
||||
auto g,s
|
||||
if(!b)return a
|
||||
s=scale
|
||||
scale=0
|
||||
a=abs(a)$
|
||||
b=abs(b)$
|
||||
if(a<b){
|
||||
g=a
|
||||
a=b
|
||||
b=g
|
||||
}
|
||||
while(b){
|
||||
g=a%b
|
||||
a=b
|
||||
b=g
|
||||
}
|
||||
scale=s
|
||||
return a
|
||||
}
|
||||
define lcm(a,b){
|
||||
auto r,s
|
||||
if(!a&&!b)return 0
|
||||
s=scale
|
||||
scale=0
|
||||
a=abs(a)$
|
||||
b=abs(b)$
|
||||
r=a*b/gcd(a,b)
|
||||
scale=s
|
||||
return r
|
||||
}
|
||||
define pi(s){
|
||||
auto t,v
|
||||
if(s==0)return 3
|
||||
|
@ -140,12 +171,12 @@ define pi(s){
|
|||
return v@s
|
||||
}
|
||||
define t(x){
|
||||
auto s,c,l
|
||||
auto s,c
|
||||
l=scale
|
||||
scale+=2
|
||||
s=s(x)
|
||||
c=c(x)
|
||||
scale=l
|
||||
scale-=2
|
||||
return s/c
|
||||
}
|
||||
define a2(y,x){
|
||||
|
@ -192,7 +223,7 @@ define d2r(x){
|
|||
}
|
||||
define frand(p){
|
||||
p=abs(p)$
|
||||
return irand(10^p)>>p
|
||||
return irand(A^p)>>p
|
||||
}
|
||||
define ifrand(i,p){return irand(abs(i)$)+frand(p)}
|
||||
define srand(x){
|
||||
|
@ -210,28 +241,39 @@ define void output(x,b){
|
|||
define void hex(x){output(x,G)}
|
||||
define void binary(x){output(x,2)}
|
||||
define ubytes(x){
|
||||
auto p,b,i
|
||||
b=ibase
|
||||
ibase=A
|
||||
auto p,i
|
||||
x=abs(x)$
|
||||
i=2^8
|
||||
for(p=1;i-1<x;p*=2){i*=i}
|
||||
ibase=b
|
||||
return p
|
||||
}
|
||||
define sbytes(x){
|
||||
auto p,b,n,z
|
||||
auto p,n,z
|
||||
z=(x<0)
|
||||
x=abs(x)
|
||||
x=x$
|
||||
n=ubytes(x)
|
||||
b=ibase
|
||||
ibase=A
|
||||
p=2^(n*8-1)
|
||||
if(x>p||(!z&&x==p))n*=2
|
||||
ibase=b
|
||||
return n
|
||||
}
|
||||
define s2un(x,n){
|
||||
auto t,u,s
|
||||
x=x$
|
||||
if(x<0){
|
||||
x=abs(x)
|
||||
s=scale
|
||||
scale=0
|
||||
t=n*8
|
||||
u=2^(t-1)
|
||||
if(x==u)return x
|
||||
else if(x>u)x%=u
|
||||
scale=s
|
||||
return 2^(t)-x
|
||||
}
|
||||
return x
|
||||
}
|
||||
define s2u(x){return s2un(x,sbytes(x))}
|
||||
define void output_byte(x,i){
|
||||
auto j,p,y,b
|
||||
j=ibase
|
||||
|
@ -240,7 +282,7 @@ define void output_byte(x,i){
|
|||
scale=0
|
||||
x=abs(x)$
|
||||
b=x/(2^(i*8))
|
||||
b%=2^8
|
||||
b%=256
|
||||
y=log(256,obase)
|
||||
if(b>1)p=log(b,obase)+1
|
||||
else p=b
|
||||
|
@ -250,15 +292,12 @@ define void output_byte(x,i){
|
|||
ibase=j
|
||||
}
|
||||
define void output_uint(x,n){
|
||||
auto i,b
|
||||
b=ibase
|
||||
ibase=A
|
||||
auto i
|
||||
for(i=n-1;i>=0;--i){
|
||||
output_byte(x,i)
|
||||
if(i)print" "
|
||||
else print"\n"
|
||||
}
|
||||
ibase=b
|
||||
}
|
||||
define void hex_uint(x,n){
|
||||
auto o
|
||||
|
@ -301,7 +340,7 @@ define void intn(x,n){
|
|||
print "Error: ",x," cannot fit into ",n," signed byte(s).\n"
|
||||
return
|
||||
}
|
||||
if(x<0)x=2^(n*8)-(-x)
|
||||
x=s2un(x,n)
|
||||
binary_uint(x,n)
|
||||
hex_uint(x,n)
|
||||
}
|
||||
|
@ -315,3 +354,175 @@ define void uint64(x){uintn(x,8)}
|
|||
define void int64(x){intn(x,8)}
|
||||
define void uint(x){uintn(x,ubytes(x))}
|
||||
define void int(x){intn(x,sbytes(x))}
|
||||
define bunrev(t){
|
||||
auto a,s,m[]
|
||||
s=scale
|
||||
scale=0
|
||||
t=abs(t)$
|
||||
while(t!=1){
|
||||
t=divmod(t,2,m[])
|
||||
a*=2
|
||||
a+=m[0]
|
||||
}
|
||||
scale=s
|
||||
return a
|
||||
}
|
||||
define band(a,b){
|
||||
auto s,t,m[],n[]
|
||||
a=abs(a)$
|
||||
b=abs(b)$
|
||||
if(b>a){
|
||||
t=b
|
||||
b=a
|
||||
a=t
|
||||
}
|
||||
s=scale
|
||||
scale=0
|
||||
t=1
|
||||
while(b){
|
||||
a=divmod(a,2,m[])
|
||||
b=divmod(b,2,n[])
|
||||
t*=2
|
||||
t+=(m[0]&&n[0])
|
||||
}
|
||||
scale=s
|
||||
return bunrev(t)
|
||||
}
|
||||
define bor(a,b){
|
||||
auto s,t,m[],n[]
|
||||
a=abs(a)$
|
||||
b=abs(b)$
|
||||
if(b>a){
|
||||
t=b
|
||||
b=a
|
||||
a=t
|
||||
}
|
||||
s=scale
|
||||
scale=0
|
||||
t=1
|
||||
while(b){
|
||||
a=divmod(a,2,m[])
|
||||
b=divmod(b,2,n[])
|
||||
t*=2
|
||||
t+=(m[0]||n[0])
|
||||
}
|
||||
while(a){
|
||||
a=divmod(a,2,m[])
|
||||
t*=2
|
||||
t+=m[0]
|
||||
}
|
||||
scale=s
|
||||
return bunrev(t)
|
||||
}
|
||||
define bxor(a,b){
|
||||
auto s,t,m[],n[]
|
||||
a=abs(a)$
|
||||
b=abs(b)$
|
||||
if(b>a){
|
||||
t=b
|
||||
b=a
|
||||
a=t
|
||||
}
|
||||
s=scale
|
||||
scale=0
|
||||
t=1
|
||||
while(b){
|
||||
a=divmod(a,2,m[])
|
||||
b=divmod(b,2,n[])
|
||||
t*=2
|
||||
t+=(m[0]+n[0]==1)
|
||||
}
|
||||
while(a){
|
||||
a=divmod(a,2,m[])
|
||||
t*=2
|
||||
t+=m[0]
|
||||
}
|
||||
scale=s
|
||||
return bunrev(t)
|
||||
}
|
||||
define bshl(a,b){return abs(a)$*2^abs(b)$}
|
||||
define bshr(a,b){return (abs(a)$/2^abs(b)$)$}
|
||||
define bnotn(x,n){
|
||||
auto s,t,m[]
|
||||
s=scale
|
||||
scale=0
|
||||
t=2^(abs(n)$*8)
|
||||
x=abs(x)$%t+t
|
||||
t=1
|
||||
while(x!=1){
|
||||
x=divmod(x,2,m[])
|
||||
t*=2
|
||||
t+=!m[0]
|
||||
}
|
||||
scale=s
|
||||
return bunrev(t)
|
||||
}
|
||||
define bnot8(x){return bnotn(x,1)}
|
||||
define bnot16(x){return bnotn(x,2)}
|
||||
define bnot32(x){return bnotn(x,4)}
|
||||
define bnot64(x){return bnotn(x,8)}
|
||||
define bnot(x){return bnotn(x,ubytes(x))}
|
||||
define brevn(x,n){
|
||||
auto s,t,m[]
|
||||
s=scale
|
||||
scale=0
|
||||
t=2^(abs(n)$*8)
|
||||
x=abs(x)$%t+t
|
||||
scale=s
|
||||
return bunrev(x)
|
||||
}
|
||||
define brev8(x){return brevn(x,1)}
|
||||
define brev16(x){return brevn(x,2)}
|
||||
define brev32(x){return brevn(x,4)}
|
||||
define brev64(x){return brevn(x,8)}
|
||||
define brev(x){return brevn(x,ubytes(x))}
|
||||
define broln(x,p,n){
|
||||
auto s,t,m[]
|
||||
s=scale
|
||||
scale=0
|
||||
n=abs(n)$*8
|
||||
p=abs(p)$%n
|
||||
t=2^n
|
||||
x=abs(x)$%t
|
||||
if(!p)return x
|
||||
x=divmod(x,2^(n-p),m[])
|
||||
x+=m[0]*2^p%t
|
||||
scale=s
|
||||
return x
|
||||
}
|
||||
define brol8(x,p){return broln(x,p,1)}
|
||||
define brol16(x,p){return broln(x,p,2)}
|
||||
define brol32(x,p){return broln(x,p,4)}
|
||||
define brol64(x,p){return broln(x,p,8)}
|
||||
define brol(x,p){return broln(x,p,ubytes(x))}
|
||||
define brorn(x,p,n){
|
||||
auto s,t,m[]
|
||||
s=scale
|
||||
scale=0
|
||||
n=abs(n)$*8
|
||||
p=abs(p)$%n
|
||||
t=2^n
|
||||
x=abs(x)$%t
|
||||
if(!p)return x
|
||||
x=divmod(x,2^p,m[])
|
||||
x+=m[0]*2^(n-p)%t
|
||||
scale=s
|
||||
return x
|
||||
}
|
||||
define bror8(x,p){return brorn(x,p,1)}
|
||||
define bror16(x,p){return brorn(x,p,2)}
|
||||
define bror32(x,p){return brorn(x,p,4)}
|
||||
define bror64(x,p){return brorn(x,p,8)}
|
||||
define brol(x,p){return brorn(x,p,ubytes(x))}
|
||||
define bmodn(x,n){
|
||||
auto s
|
||||
s=scale
|
||||
scale=0
|
||||
x=abs(x)$%2^(abs(n)$*8)
|
||||
scale=s
|
||||
return x
|
||||
}
|
||||
define bmod8(x){return bmodn(x,1)}
|
||||
define bmod16(x){return bmodn(x,2)}
|
||||
define bmod32(x){return bmodn(x,4)}
|
||||
define bmod64(x){return bmodn(x,8)}
|
||||
|
|
112
gen/strgen.c
112
gen/strgen.c
|
@ -40,15 +40,19 @@
|
|||
|
||||
#include <errno.h>
|
||||
|
||||
// For some reason, Windows needs this header.
|
||||
#ifndef _WIN32
|
||||
#include <libgen.h>
|
||||
#endif // _WIN32
|
||||
|
||||
// This is exactly what it looks like. It just slaps a simple license header on
|
||||
// the generated C source file.
|
||||
static const char* const bc_gen_header =
|
||||
"// Copyright (c) 2018-2021 Gavin D. Howard and contributors.\n"
|
||||
"// Licensed under the 2-clause BSD license.\n"
|
||||
"// *** AUTOMATICALLY GENERATED FROM %s. DO NOT MODIFY. ***\n\n";
|
||||
|
||||
// These are just format strings used to generate the C source.
|
||||
static const char* const bc_gen_label = "const char *%s = \"%s\";\n\n";
|
||||
static const char* const bc_gen_label_extern = "extern const char *%s;\n\n";
|
||||
static const char* const bc_gen_ifdef = "#if %s\n";
|
||||
|
@ -56,43 +60,86 @@ static const char* const bc_gen_endif = "#endif // %s\n";
|
|||
static const char* const bc_gen_name = "const char %s[] = {\n";
|
||||
static const char* const bc_gen_name_extern = "extern const char %s[];\n\n";
|
||||
|
||||
// Error codes. We can't use 0 because these are used as exit statuses, and 0
|
||||
// as an exit status is not an error.
|
||||
#define IO_ERR (1)
|
||||
#define INVALID_INPUT_FILE (2)
|
||||
#define INVALID_PARAMS (3)
|
||||
|
||||
#define MAX_WIDTH (74)
|
||||
// This is the max width to print characters to the screen. This is to ensure
|
||||
// that lines don't go much over 80 characters.
|
||||
#define MAX_WIDTH (72)
|
||||
|
||||
/**
|
||||
* Open a file. This function is to smooth over differences between POSIX and
|
||||
* Windows.
|
||||
* @param f A pointer to the FILE pointer that will be initialized.
|
||||
* @param filename The name of the file.
|
||||
* @param mode The mode to open the file in.
|
||||
*/
|
||||
static void open_file(FILE** f, const char* filename, const char* mode) {
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
*f = fopen(filename, mode);
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
// We want the file pointer to be NULL on failure, but fopen_s() is not
|
||||
// guaranteed to set it.
|
||||
*f = NULL;
|
||||
fopen_s(f, filename, mode);
|
||||
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a label, which is a string literal that the code can use as a name
|
||||
* for the file that is being turned into a string. This is important for the
|
||||
* math libraries because the parse and lex code expects a filename. The label
|
||||
* becomes the filename for the purposes of lexing and parsing.
|
||||
*
|
||||
* The label is generated from bc_gen_label (above). It has the form:
|
||||
*
|
||||
* const char *<label_name> = <label>;
|
||||
*
|
||||
* This function is also needed to smooth out differences between POSIX and
|
||||
* Windows, specifically, the fact that Windows uses backslashes for filenames
|
||||
* and that backslashes have to be escaped in a string literal.
|
||||
*
|
||||
* @param out The file to output to.
|
||||
* @param label The label name.
|
||||
* @param name The actual label text, which is a filename.
|
||||
* @return Positive if no error, negative on error, just like *printf().
|
||||
*/
|
||||
static int output_label(FILE* out, const char* label, const char* name) {
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
return fprintf(out, bc_gen_label, label, name);
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
size_t i, count = 0, len = strlen(name);
|
||||
char* buf;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
count += (name[i] == '\\');
|
||||
}
|
||||
// This loop counts how many backslashes there are in the label.
|
||||
for (i = 0; i < len; ++i) count += (name[i] == '\\');
|
||||
|
||||
buf = (char*) malloc(len + 1 + count);
|
||||
if (buf == NULL) return -1;
|
||||
|
||||
count = 0;
|
||||
|
||||
// This loop is the meat of the Windows version. What it does is copy the
|
||||
// label byte-for-byte, unless it encounters a backslash, in which case, it
|
||||
// copies the backslash twice to have it escaped properly in the string
|
||||
// literal.
|
||||
for (i = 0; i < len; ++i) {
|
||||
|
||||
buf[i + count] = name[i];
|
||||
|
||||
if (name[i] == '\\') {
|
||||
count += 1;
|
||||
buf[i + count] = name[i];
|
||||
|
@ -110,6 +157,51 @@ static int output_label(FILE* out, const char* label, const char* name) {
|
|||
#endif // _WIN32
|
||||
}
|
||||
|
||||
/**
|
||||
* This program generates C strings (well, actually, C char arrays) from text
|
||||
* files. It generates 1 C source file. The resulting file has this structure:
|
||||
*
|
||||
* <Copyright Header>
|
||||
*
|
||||
* [<Label Extern>]
|
||||
*
|
||||
* <Char Array Extern>
|
||||
*
|
||||
* [<Preprocessor Guard Begin>]
|
||||
* [<Label Definition>]
|
||||
*
|
||||
* <Char Array Definition>
|
||||
* [<Preprocessor Guard End>]
|
||||
*
|
||||
* Anything surrounded by square brackets may not be in the final generated
|
||||
* source file.
|
||||
*
|
||||
* The required command-line parameters are:
|
||||
*
|
||||
* input Input filename.
|
||||
* output Output filename.
|
||||
* name The name of the char array.
|
||||
*
|
||||
* The optional parameters are:
|
||||
*
|
||||
* label If given, a label for the char array. See the comment for the
|
||||
* output_label() function. It is meant as a "filename" for the
|
||||
* text when processed by bc and dc. If label is given, then the
|
||||
* <Label Extern> and <Label Definition> will exist in the
|
||||
* generated source file.
|
||||
* define If given, a preprocessor macro that should be used as a guard
|
||||
* for the char array and its label. If define is given, then
|
||||
* <Preprocessor Guard Begin> will exist in the form
|
||||
* "#if <define>" as part of the generated source file, and
|
||||
* <Preprocessor Guard End> will exist in the form
|
||||
* "endif // <define>".
|
||||
* remove_tabs If this parameter exists, it must be an integer. If it is
|
||||
* non-zero, then tabs are removed from the input file text before
|
||||
* outputting to the output char array.
|
||||
*
|
||||
* All text files that are transformed have license comments. This program finds
|
||||
* the end of that comment and strips it out as well.
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
FILE *in, *out;
|
||||
|
@ -117,8 +209,9 @@ int main(int argc, char *argv[]) {
|
|||
int c, count, slashes, err = IO_ERR;
|
||||
bool has_label, has_define, remove_tabs;
|
||||
|
||||
if (argc < 5) {
|
||||
printf("usage: %s input output name header [label [define [remove_tabs]]]\n", argv[0]);
|
||||
if (argc < 4) {
|
||||
printf("usage: %s input output name [label [define [remove_tabs]]]\n",
|
||||
argv[0]);
|
||||
return INVALID_PARAMS;
|
||||
}
|
||||
|
||||
|
@ -147,18 +240,24 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
c = count = slashes = 0;
|
||||
|
||||
// This is where the end of the license comment is found.
|
||||
while (slashes < 2 && (c = fgetc(in)) >= 0) {
|
||||
slashes += (slashes == 1 && c == '/' && fgetc(in) == '\n');
|
||||
slashes += (!slashes && c == '/' && fgetc(in) == '*');
|
||||
}
|
||||
|
||||
// The file is invalid if the end of the license comment could not be found.
|
||||
if (c < 0) {
|
||||
err = INVALID_INPUT_FILE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Do not put extra newlines at the beginning of the char array.
|
||||
while ((c = fgetc(in)) == '\n');
|
||||
|
||||
// This loop is what generates the actual char array. It counts how many
|
||||
// chars it has printed per line in order to insert newlines at appropriate
|
||||
// places. It also skips tabs if they should be removed.
|
||||
while (c >= 0) {
|
||||
|
||||
int val;
|
||||
|
@ -181,6 +280,7 @@ int main(int argc, char *argv[]) {
|
|||
c = fgetc(in);
|
||||
}
|
||||
|
||||
// Make sure the end looks nice and insert the NUL byte at the end.
|
||||
if (!count && (fputc(' ', out) == EOF || fputc(' ', out) == EOF)) goto err;
|
||||
if (fprintf(out, "0\n};\n") < 0) goto err;
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@ export LC_CTYPE=C
|
|||
|
||||
progname=${0##*/}
|
||||
|
||||
# See strgen.c comment on main() for what these mean. Note, however, that this
|
||||
# script generates a string literal, not a char array. To understand the
|
||||
# consequences of that, see manuals/development.md#strgenc.
|
||||
if [ $# -lt 3 ]; then
|
||||
echo "usage: $progname input output name [label [define [remove_tabs]]]"
|
||||
exit 1
|
||||
|
|
|
@ -37,10 +37,19 @@
|
|||
#define BC_ARGS_H
|
||||
|
||||
#include <status.h>
|
||||
#include <opt.h>
|
||||
#include <vm.h>
|
||||
|
||||
/**
|
||||
* Processes command-line arguments.
|
||||
* @param argc How many arguments there are.
|
||||
* @param argv The array of arguments.
|
||||
* @param exit_exprs True if bc/dc should exit when there are expressions,
|
||||
* false otherwise.
|
||||
*/
|
||||
void bc_args(int argc, char *argv[], bool exit_exprs);
|
||||
|
||||
extern const char* const bc_args_env_name;
|
||||
// A reference to the list of long options.
|
||||
extern const BcOptLong bc_args_lopt[];
|
||||
|
||||
#endif // BC_ARGS_H
|
||||
|
|
302
include/bc.h
302
include/bc.h
|
@ -29,7 +29,7 @@
|
|||
*
|
||||
* *****************************************************************************
|
||||
*
|
||||
* Definitions for bc.
|
||||
* Definitions for bc only.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -45,108 +45,334 @@
|
|||
#include <lex.h>
|
||||
#include <parse.h>
|
||||
|
||||
void bc_main(int argc, char **argv);
|
||||
/**
|
||||
* The main function for bc. It just sets variables and passes its arguments
|
||||
* through to @a bc_vm_boot().
|
||||
*/
|
||||
void bc_main(int argc, char *argv[]);
|
||||
|
||||
// These are references to the help text, the library text, and the "filename"
|
||||
// for the library.
|
||||
extern const char bc_help[];
|
||||
extern const char bc_lib[];
|
||||
extern const char* bc_lib_name;
|
||||
|
||||
// These are references to the second math library and its "filename."
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
extern const char bc_lib2[];
|
||||
extern const char* bc_lib2_name;
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* A struct containing information about a bc keyword.
|
||||
*/
|
||||
typedef struct BcLexKeyword {
|
||||
|
||||
/// Holds the length of the keyword along with a bit that, if set, means the
|
||||
/// keyword is used in POSIX bc.
|
||||
uchar data;
|
||||
|
||||
/// The keyword text.
|
||||
const char name[9];
|
||||
} BcLexKeyword;
|
||||
|
||||
/// Sets the most significant bit. Used for setting the POSIX bit in
|
||||
/// BcLexKeyword's data field.
|
||||
#define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1))
|
||||
|
||||
/// Returns non-zero if the keyword is POSIX, zero otherwise.
|
||||
#define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1)))
|
||||
|
||||
/// Returns the length of the keyword.
|
||||
#define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1))))
|
||||
|
||||
/// A macro to easily build a keyword entry. See bc_lex_kws in src/data.c.
|
||||
#define BC_LEX_KW_ENTRY(a, b, c) \
|
||||
{ .data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c), .name = a }
|
||||
|
||||
#if 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 (32)
|
||||
|
||||
#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 (28)
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
// The array of keywords and its length.
|
||||
extern const BcLexKeyword bc_lex_kws[];
|
||||
extern const size_t bc_lex_kws_len;
|
||||
|
||||
/**
|
||||
* The @a BcLexNext function for bc. (See include/lex.h for a definition of
|
||||
* @a BcLexNext.)
|
||||
* @param l The lexer.
|
||||
*/
|
||||
void bc_lex_token(BcLex *l);
|
||||
|
||||
// The following section is for flags needed when parsing bc code. These flags
|
||||
// are complicated, but necessary. Why you ask? Because bc's standard is awful.
|
||||
//
|
||||
// If you don't believe me, go read the bc Parsing section of the Development
|
||||
// manual (manuals/development.md). Then come back.
|
||||
//
|
||||
// In other words, these flags are the sign declaring, "Here be dragons."
|
||||
|
||||
/**
|
||||
* This returns a pointer to the set of flags at the top of the flag stack.
|
||||
* @a p is expected to be a BcParse pointer.
|
||||
* @param p The parser.
|
||||
* @return A pointer to the top flag set.
|
||||
*/
|
||||
#define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags))
|
||||
|
||||
/**
|
||||
* This returns the flag set at the top of the flag stack. @a p is expected to
|
||||
* be a BcParse pointer.
|
||||
* @param p The parser.
|
||||
* @return The top flag set.
|
||||
*/
|
||||
#define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p)))
|
||||
|
||||
// After this point, all flag #defines are in sets of 2: one to define the flag,
|
||||
// and one to define a way to grab the flag from the flag set at the top of the
|
||||
// flag stack. All `p` arguments are pointers to a BcParse.
|
||||
|
||||
// This flag is set if the parser has seen a left brace.
|
||||
#define BC_PARSE_FLAG_BRACE (UINTMAX_C(1)<<0)
|
||||
#define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE)
|
||||
|
||||
// This flag is set if the parser is parsing inside of the braces of a function
|
||||
// body.
|
||||
#define BC_PARSE_FLAG_FUNC_INNER (UINTMAX_C(1)<<1)
|
||||
#define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER)
|
||||
|
||||
// This flag is set if the parser is parsing a function. It is different from
|
||||
// the one above because it is set if it is parsing a function body *or* header,
|
||||
// not just if it's parsing a function body.
|
||||
#define BC_PARSE_FLAG_FUNC (UINTMAX_C(1)<<2)
|
||||
#define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC)
|
||||
|
||||
// This flag is set if the parser is expecting to parse a body, whether of a
|
||||
// function, an if statement, or a loop.
|
||||
#define BC_PARSE_FLAG_BODY (UINTMAX_C(1)<<3)
|
||||
#define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY)
|
||||
|
||||
// This flag is set if bc is parsing a loop. This is important because the break
|
||||
// and continue keywords are only valid inside of a loop.
|
||||
#define BC_PARSE_FLAG_LOOP (UINTMAX_C(1)<<4)
|
||||
#define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP)
|
||||
|
||||
// This flag is set if bc is parsing the body of a loop. It is different from
|
||||
// the one above the same way @a BC_PARSE_FLAG_FUNC_INNER is different from
|
||||
// @a BC_PARSE_FLAG_FUNC.
|
||||
#define BC_PARSE_FLAG_LOOP_INNER (UINTMAX_C(1)<<5)
|
||||
#define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER)
|
||||
|
||||
// This flag is set if bc is parsing an if statement.
|
||||
#define BC_PARSE_FLAG_IF (UINTMAX_C(1)<<6)
|
||||
#define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF)
|
||||
|
||||
// This flag is set if bc is parsing an else statement. This is important
|
||||
// because of "else if" constructions, among other things.
|
||||
#define BC_PARSE_FLAG_ELSE (UINTMAX_C(1)<<7)
|
||||
#define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE)
|
||||
|
||||
// This flag is set if bc just finished parsing an if statement and its body.
|
||||
// It tells the parser that it can probably expect an else statement next. This
|
||||
// flag is, thus, one of the most subtle.
|
||||
#define BC_PARSE_FLAG_IF_END (UINTMAX_C(1)<<8)
|
||||
#define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END)
|
||||
|
||||
/**
|
||||
* This returns true if bc is in a state where it should not execute any code
|
||||
* at all.
|
||||
* @param p The parser.
|
||||
* @return True if execution cannot proceed, false otherwise.
|
||||
*/
|
||||
#define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0)
|
||||
|
||||
/**
|
||||
* This returns true if the token @a t is a statement delimiter, which is
|
||||
* either a newline or a semicolon.
|
||||
* @param t The token to check.
|
||||
* @return True if t is a statement delimiter token; false otherwise.
|
||||
*/
|
||||
#define BC_PARSE_DELIMITER(t) \
|
||||
((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF)
|
||||
|
||||
/**
|
||||
* This is poorly named, but it basically returns whether or not the current
|
||||
* state is valid for the end of an else statement.
|
||||
* @param f The flag set to be checked.
|
||||
* @return True if the state is valid for the end of an else statement.
|
||||
*/
|
||||
#define BC_PARSE_BLOCK_STMT(f) \
|
||||
((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER))
|
||||
|
||||
/**
|
||||
* This returns the value of the data for an operator with precedence @a p and
|
||||
* associativity @a l (true if left associative, false otherwise). This is used
|
||||
* to construct an array of operators, bc_parse_ops, in src/data.c.
|
||||
* @param p The precedence.
|
||||
* @param l True if the operator is left associative, false otherwise.
|
||||
* @return The data for the operator.
|
||||
*/
|
||||
#define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l)))
|
||||
|
||||
/**
|
||||
* Returns the operator data for the lex token @a t.
|
||||
* @param t The token to return operator data for.
|
||||
* @return The operator data for @a t.
|
||||
*/
|
||||
#define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) - BC_LEX_OP_INC)]
|
||||
|
||||
/**
|
||||
* Returns non-zero if operator @a op is left associative, zero otherwise.
|
||||
* @param op The operator to test for associativity.
|
||||
* @return Non-zero if the operator is left associative, zero otherwise.
|
||||
*/
|
||||
#define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1))
|
||||
|
||||
/**
|
||||
* Returns the precedence of operator @a op. Lower number means higher
|
||||
* precedence.
|
||||
* @param op The operator to return the precedence of.
|
||||
* @return The precedence of @a op.
|
||||
*/
|
||||
#define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1)))
|
||||
|
||||
/**
|
||||
* A macro to easily define a series of bits for whether a lex token is an
|
||||
* expression token or not. It takes 8 expression bits, corresponding to the 8
|
||||
* bits in a uint8_t. You can see this in use for bc_parse_exprs in src/data.c.
|
||||
* @param e1 The first bit.
|
||||
* @param e2 The second bit.
|
||||
* @param e3 The third bit.
|
||||
* @param e4 The fourth bit.
|
||||
* @param e5 The fifth bit.
|
||||
* @param e6 The sixth bit.
|
||||
* @param e7 The seventh bit.
|
||||
* @param e8 The eighth bit.
|
||||
* @return An expression entry for bc_parse_exprs[].
|
||||
*/
|
||||
#define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8) \
|
||||
((UINTMAX_C(e1) << 7) | (UINTMAX_C(e2) << 6) | (UINTMAX_C(e3) << 5) | \
|
||||
(UINTMAX_C(e4) << 4) | (UINTMAX_C(e5) << 3) | (UINTMAX_C(e6) << 2) | \
|
||||
(UINTMAX_C(e7) << 1) | (UINTMAX_C(e8) << 0))
|
||||
|
||||
/**
|
||||
* Returns true if token @a i is a token that belongs in an expression.
|
||||
* @param i The token to test.
|
||||
* @return True if i is an expression token, false otherwise.
|
||||
*/
|
||||
#define BC_PARSE_EXPR(i) \
|
||||
(bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07))))
|
||||
|
||||
/**
|
||||
* Returns the operator (by lex token) that is at the top of the operator
|
||||
* stack.
|
||||
* @param p The parser.
|
||||
* @return The operator that is at the top of the operator stack, as a lex
|
||||
* token.
|
||||
*/
|
||||
#define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops)))
|
||||
|
||||
/**
|
||||
* Returns true if bc has a "leaf" token. A "leaf" token is one that can stand
|
||||
* alone in an expression. For example, a number by itself can be an expression,
|
||||
* but a binary operator, while valid for an expression, cannot be alone in the
|
||||
* expression. It must have an expression to the left and right of itself. See
|
||||
* the documentation for @a bc_parse_expr_err() in src/bc_parse.c.
|
||||
* @param prev The previous token as an instruction.
|
||||
* @param bin_last True if that last operator was a binary operator, false
|
||||
* otherwise.
|
||||
* @param rparen True if the last operator was a right paren.
|
||||
* return True if the last token was a leaf token, false otherwise.
|
||||
*/
|
||||
#define BC_PARSE_LEAF(prev, bin_last, rparen) \
|
||||
(!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
/**
|
||||
* This returns true if the token @a t should be treated as though it's a
|
||||
* variable. This goes for actual variables, array elements, and globals.
|
||||
* @param t The token to test.
|
||||
* @return True if @a t should be treated as though it's a variable, false
|
||||
* otherwise.
|
||||
*/
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
#define BC_PARSE_INST_VAR(t) \
|
||||
((t) >= BC_INST_VAR && (t) <= BC_INST_SEED && (t) != BC_INST_ARRAY)
|
||||
#else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#else // BC_ENABLE_EXTRA_MATH
|
||||
#define BC_PARSE_INST_VAR(t) \
|
||||
((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY)
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#define BC_PARSE_PREV_PREFIX(p) \
|
||||
((p) >= BC_INST_NEG && (p) <= BC_INST_BOOL_NOT)
|
||||
/**
|
||||
* Returns true if the previous token @a p (in the form of a bytecode
|
||||
* instruction) is a prefix operator. The fact that it is for bytecode
|
||||
* instructions is what makes it different from @a BC_PARSE_OP_PREFIX below.
|
||||
* @param p The previous token.
|
||||
* @return True if @a p is a prefix operator.
|
||||
*/
|
||||
#define BC_PARSE_PREV_PREFIX(p) ((p) >= BC_INST_NEG && (p) <= BC_INST_BOOL_NOT)
|
||||
|
||||
/**
|
||||
* Returns true if token @a t is a prefix operator.
|
||||
* @param t The token to test.
|
||||
* @return True if @a t is a prefix operator, false otherwise.
|
||||
*/
|
||||
#define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG)
|
||||
|
||||
// We can calculate the conversion between tokens and exprs by subtracting the
|
||||
// position of the first operator in the lex enum and adding the position of
|
||||
// the first in the expr enum. Note: This only works for binary operators.
|
||||
/**
|
||||
* We can calculate the conversion between tokens and bytecode instructions by
|
||||
* subtracting the position of the first operator in the lex enum and adding the
|
||||
* position of the first in the instruction enum. Note: This only works for
|
||||
* binary operators.
|
||||
* @param t The token to turn into an instruction.
|
||||
* @return The token as an instruction.
|
||||
*/
|
||||
#define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) - BC_LEX_NEG + BC_INST_NEG))
|
||||
|
||||
/**
|
||||
* Returns true if the token is a bc keyword.
|
||||
* @param t The token to check.
|
||||
* @return True if @a t is a bc keyword, false otherwise.
|
||||
*/
|
||||
#define BC_PARSE_IS_KEYWORD(t) ((t) >= BC_LEX_KW_AUTO && (t) <= BC_LEX_KW_ELSE)
|
||||
|
||||
/// A struct that holds data about what tokens should be expected next. There
|
||||
/// are a few instances of these, all named because they are used in specific
|
||||
/// cases. Basically, in certain situations, it's useful to use the same code,
|
||||
/// but have a list of valid tokens.
|
||||
///
|
||||
/// Obviously, @a len is the number of tokens in the @a tokens array. If more
|
||||
/// than 4 is needed in the future, @a tokens will have to be changed.
|
||||
typedef struct BcParseNext {
|
||||
|
||||
/// The number of tokens in the tokens array.
|
||||
uchar len;
|
||||
|
||||
/// The tokens that can be expected next.
|
||||
uchar tokens[4];
|
||||
|
||||
} BcParseNext;
|
||||
|
||||
/// A macro to construct an array literal of tokens from a parameter list.
|
||||
#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
|
||||
|
||||
/// A macro to generate a BcParseNext literal from BcParseNext data. See
|
||||
/// src/data.c for examples.
|
||||
#define BC_PARSE_NEXT(a, ...) \
|
||||
{ .len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) }
|
||||
|
||||
/// A status returned by @a bc_parse_expr_err(). It can either return success or
|
||||
/// an error indicating an empty expression.
|
||||
typedef enum BcParseStatus {
|
||||
|
||||
BC_PARSE_STATUS_SUCCESS,
|
||||
|
@ -154,27 +380,77 @@ typedef enum BcParseStatus {
|
|||
|
||||
} BcParseStatus;
|
||||
|
||||
/**
|
||||
* The @a BcParseExpr function for bc. (See include/parse.h for a definition of
|
||||
* @a BcParseExpr.)
|
||||
* @param p The parser.
|
||||
* @param flags Flags that define the requirements that the parsed code must
|
||||
* meet or an error will result. See @a BcParseExpr for more info.
|
||||
*/
|
||||
void bc_parse_expr(BcParse *p, uint8_t flags);
|
||||
|
||||
/**
|
||||
* The @a BcParseParse function for bc. (See include/parse.h for a definition of
|
||||
* @a BcParseParse.)
|
||||
* @param p The parser.
|
||||
*/
|
||||
void bc_parse_parse(BcParse *p);
|
||||
void bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next);
|
||||
|
||||
/// References to the signal message and its length.
|
||||
extern const char bc_sig_msg[];
|
||||
extern const uchar bc_sig_msg_len;
|
||||
|
||||
extern const char* const bc_parse_const1;
|
||||
/// A reference to an array of bits that are set if the corresponding lex token
|
||||
/// is valid in an expression.
|
||||
extern const uint8_t bc_parse_exprs[];
|
||||
|
||||
/// A reference to an array of bc operators.
|
||||
extern const uchar bc_parse_ops[];
|
||||
|
||||
// References to the various instances of BcParseNext's.
|
||||
|
||||
/// A reference to what tokens are valid as next tokens when parsing normal
|
||||
/// expressions. More accurately. these are the tokens that are valid for
|
||||
/// *ending* the expression.
|
||||
extern const BcParseNext bc_parse_next_expr;
|
||||
extern const BcParseNext bc_parse_next_param;
|
||||
|
||||
/// A reference to what tokens are valid as next tokens when parsing function
|
||||
/// parameters (well, actually arguments).
|
||||
extern const BcParseNext bc_parse_next_arg;
|
||||
|
||||
/// A reference to what tokens are valid as next tokens when parsing a print
|
||||
/// statement.
|
||||
extern const BcParseNext bc_parse_next_print;
|
||||
|
||||
/// A reference to what tokens are valid as next tokens when parsing things like
|
||||
/// loop headers and builtin functions where the only thing expected is a right
|
||||
/// paren.
|
||||
///
|
||||
/// The name is an artifact of history, and is related to @a BC_PARSE_REL (see
|
||||
/// include/parse.h). It refers to how POSIX only allows some operators as part
|
||||
/// of the conditional of for loops, while loops, and if statements.
|
||||
extern const BcParseNext bc_parse_next_rel;
|
||||
|
||||
// What tokens are valid as next tokens when parsing an array element
|
||||
// expression.
|
||||
extern const BcParseNext bc_parse_next_elem;
|
||||
|
||||
/// A reference to what tokens are valid as next tokens when parsing the first
|
||||
/// two parts of a for loop header.
|
||||
extern const BcParseNext bc_parse_next_for;
|
||||
|
||||
/// A reference to what tokens are valid as next tokens when parsing a read
|
||||
/// expression.
|
||||
extern const BcParseNext bc_parse_next_read;
|
||||
|
||||
/// A reference to what tokens are valid as next tokens when parsing a builtin
|
||||
/// function with multiple arguments.
|
||||
extern const BcParseNext bc_parse_next_builtin;
|
||||
|
||||
#else // BC_ENABLED
|
||||
|
||||
// If bc is not enabled, execution is always possible because dc has strict
|
||||
// rules that ensure execution can always proceed safely.
|
||||
#define BC_PARSE_NO_EXEC(p) (0)
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
|
147
include/bcl.h
147
include/bcl.h
|
@ -49,99 +49,8 @@
|
|||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define BC_SEED_ULONGS (4)
|
||||
#define BC_SEED_SIZE (sizeof(long) * BC_SEED_ULONGS)
|
||||
|
||||
// For some reason, LONG_BIT is not defined in some versions of gcc.
|
||||
// I define it here to the minimum accepted value in the POSIX standard.
|
||||
#ifndef LONG_BIT
|
||||
#define LONG_BIT (32)
|
||||
#endif // LONG_BIT
|
||||
|
||||
#ifndef BC_LONG_BIT
|
||||
#define BC_LONG_BIT LONG_BIT
|
||||
#endif // BC_LONG_BIT
|
||||
|
||||
#if BC_LONG_BIT > LONG_BIT
|
||||
#error BC_LONG_BIT cannot be greater than LONG_BIT
|
||||
#endif // BC_LONG_BIT > LONG_BIT
|
||||
|
||||
#if BC_LONG_BIT >= 64
|
||||
|
||||
typedef uint64_t BclBigDig;
|
||||
typedef uint64_t BclRandInt;
|
||||
|
||||
#elif BC_LONG_BIT >= 32
|
||||
|
||||
typedef uint32_t BclBigDig;
|
||||
typedef uint32_t BclRandInt;
|
||||
|
||||
#else
|
||||
|
||||
#error BC_LONG_BIT must be at least 32
|
||||
|
||||
#endif // BC_LONG_BIT >= 64
|
||||
#define BC_UNUSED(e) ((void) (e))
|
||||
|
||||
#ifndef BC_LIKELY
|
||||
#define BC_LIKELY(e) (e)
|
||||
#endif // BC_LIKELY
|
||||
|
||||
#ifndef BC_UNLIKELY
|
||||
#define BC_UNLIKELY(e) (e)
|
||||
#endif // BC_UNLIKELY
|
||||
|
||||
#define BC_ERR(e) BC_UNLIKELY(e)
|
||||
#define BC_NO_ERR(s) BC_LIKELY(s)
|
||||
|
||||
#ifndef BC_DEBUG_CODE
|
||||
#define BC_DEBUG_CODE (0)
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
#if __STDC_VERSION__ >= 201100L
|
||||
#include <stdnoreturn.h>
|
||||
#define BC_NORETURN _Noreturn
|
||||
#else // __STDC_VERSION__
|
||||
#define BC_NORETURN
|
||||
#define BC_MUST_RETURN
|
||||
#endif // __STDC_VERSION__
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(fallthrough)
|
||||
#define BC_FALLTHROUGH __attribute__((fallthrough));
|
||||
#else // __has_attribute(fallthrough)
|
||||
#define BC_FALLTHROUGH
|
||||
#endif // __has_attribute(fallthrough)
|
||||
#else // defined(__has_attribute)
|
||||
#define BC_FALLTHROUGH
|
||||
#endif // defined(__has_attribute)
|
||||
#else // defined(__clang__) || defined(__GNUC__)
|
||||
#define BC_FALLTHROUGH
|
||||
#endif // defined(__clang__) || defined(__GNUC__)
|
||||
|
||||
// Workarounds for AIX's POSIX incompatibility.
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX __SIZE_MAX__
|
||||
#endif // SIZE_MAX
|
||||
#ifndef UINTMAX_C
|
||||
#define UINTMAX_C __UINTMAX_C
|
||||
#endif // UINTMAX_C
|
||||
#ifndef UINT32_C
|
||||
#define UINT32_C __UINT32_C
|
||||
#endif // UINT32_C
|
||||
#ifndef UINT_FAST32_MAX
|
||||
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
|
||||
#endif // UINT_FAST32_MAX
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX __UINT16_MAX__
|
||||
#endif // UINT16_MAX
|
||||
#ifndef SIG_ATOMIC_MAX
|
||||
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
|
||||
#endif // SIG_ATOMIC_MAX
|
||||
|
||||
// Windows has deprecated isatty() and the rest of these.
|
||||
// Or doesn't have them.
|
||||
// Windows has deprecated isatty() and the rest of these. Or doesn't have them.
|
||||
// So these are just fixes for Windows.
|
||||
#ifdef _WIN32
|
||||
|
||||
// This one is special. Windows did not like me defining an
|
||||
|
@ -159,9 +68,9 @@ typedef uint32_t BclRandInt;
|
|||
#define sigsetjmp(j, s) setjmp(j)
|
||||
#define siglongjmp longjmp
|
||||
#define isatty _isatty
|
||||
#define STDIN_FILENO (0)
|
||||
#define STDOUT_FILENO (1)
|
||||
#define STDERR_FILENO (2)
|
||||
#define STDIN_FILENO _fileno(stdin)
|
||||
#define STDOUT_FILENO _fileno(stdout)
|
||||
#define STDERR_FILENO _fileno(stderr)
|
||||
#define ssize_t SSIZE_T
|
||||
#define S_ISDIR(m) ((m) & _S_IFDIR)
|
||||
#define O_RDONLY _O_RDONLY
|
||||
|
@ -173,6 +82,50 @@ typedef uint32_t BclRandInt;
|
|||
#define BC_FILE_SEP '/'
|
||||
#endif // _WIN32
|
||||
|
||||
#define BCL_SEED_ULONGS (4)
|
||||
#define BCL_SEED_SIZE (sizeof(long) * BCL_SEED_ULONGS)
|
||||
|
||||
// For some reason, LONG_BIT is not defined in some versions of gcc.
|
||||
// I define it here to the minimum accepted value in the POSIX standard.
|
||||
#ifndef LONG_BIT
|
||||
#define LONG_BIT (32)
|
||||
#endif // LONG_BIT
|
||||
|
||||
#ifndef BC_LONG_BIT
|
||||
#define BC_LONG_BIT LONG_BIT
|
||||
#endif // BC_LONG_BIT
|
||||
|
||||
#if BC_LONG_BIT > LONG_BIT
|
||||
#error BC_LONG_BIT cannot be greater than LONG_BIT
|
||||
#endif // BC_LONG_BIT > LONG_BIT
|
||||
|
||||
// For more information about the items here, see the either the
|
||||
// manuals/bcl.3.md or manuals/bcl.3 manuals.
|
||||
|
||||
// BclBigDig is a fixed-size integer type that bcl can convert numbers to.
|
||||
//
|
||||
// BclRandInt is the type of fixed-size integer natively returned by the
|
||||
// pseudo-random number generator.
|
||||
#if BC_LONG_BIT >= 64
|
||||
|
||||
typedef uint64_t BclBigDig;
|
||||
typedef uint64_t BclRandInt;
|
||||
|
||||
#elif BC_LONG_BIT >= 32
|
||||
|
||||
typedef uint32_t BclBigDig;
|
||||
typedef uint32_t BclRandInt;
|
||||
|
||||
#else
|
||||
|
||||
#error BC_LONG_BIT must be at least 32
|
||||
|
||||
#endif // BC_LONG_BIT >= 64
|
||||
|
||||
#ifndef BC_ENABLE_LIBRARY
|
||||
#define BC_ENABLE_LIBRARY (1)
|
||||
#endif // BC_ENABLE_LIBRARY
|
||||
|
||||
#if BC_ENABLE_LIBRARY
|
||||
|
||||
typedef enum BclError {
|
||||
|
@ -275,7 +228,7 @@ BclNumber bcl_frand(size_t places);
|
|||
BclNumber bcl_ifrand(BclNumber a, size_t places);
|
||||
|
||||
BclError bcl_rand_seedWithNum(BclNumber n);
|
||||
BclError bcl_rand_seed(unsigned char seed[BC_SEED_SIZE]);
|
||||
BclError bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]);
|
||||
void bcl_rand_reseed(void);
|
||||
BclNumber bcl_rand_seed2num(void);
|
||||
BclRandInt bcl_rand_int(void);
|
||||
|
|
42
include/dc.h
42
include/dc.h
|
@ -29,7 +29,7 @@
|
|||
*
|
||||
* *****************************************************************************
|
||||
*
|
||||
* Definitions for bc.
|
||||
* Definitions for dc only.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -42,23 +42,61 @@
|
|||
#include <lex.h>
|
||||
#include <parse.h>
|
||||
|
||||
void dc_main(int argc, char **argv);
|
||||
/**
|
||||
* The main function for dc. It just sets variables and passes its arguments
|
||||
* through to @a bc_vm_boot().
|
||||
*/
|
||||
void dc_main(int argc, char *argv[]);
|
||||
|
||||
// A reference to the dc help text.
|
||||
extern const char dc_help[];
|
||||
|
||||
/**
|
||||
* The @a BcLexNext function for dc. (See include/lex.h for a definition of
|
||||
* @a BcLexNext.)
|
||||
* @param l The lexer.
|
||||
*/
|
||||
void dc_lex_token(BcLex *l);
|
||||
|
||||
/**
|
||||
* Returns true if the negative char `_` should be treated as a command or not.
|
||||
* dc considers negative a command if it does *not* immediately proceed a
|
||||
* number. Otherwise, it's just considered a negative.
|
||||
* @param l The lexer.
|
||||
* @return True if a negative should be treated as a command, false if it
|
||||
* should be treated as a negative sign on a number.
|
||||
*/
|
||||
bool dc_lex_negCommand(BcLex *l);
|
||||
|
||||
// References to the signal message and its length.
|
||||
extern const char dc_sig_msg[];
|
||||
extern const uchar dc_sig_msg_len;
|
||||
|
||||
// References to an array and its length. This array is an array of lex tokens
|
||||
// that, when encountered, should be treated as commands that take a register.
|
||||
extern const uint8_t dc_lex_regs[];
|
||||
extern const size_t dc_lex_regs_len;
|
||||
|
||||
// References to an array of tokens and its length. This array corresponds to
|
||||
// the ASCII table, starting at double quotes. This makes it easy to look up
|
||||
// tokens for characters.
|
||||
extern const uint8_t dc_lex_tokens[];
|
||||
extern const uint8_t dc_parse_insts[];
|
||||
|
||||
/**
|
||||
* The @a BcParseParse function for dc. (See include/parse.h for a definition of
|
||||
* @a BcParseParse.)
|
||||
* @param p The parser.
|
||||
*/
|
||||
void dc_parse_parse(BcParse *p);
|
||||
|
||||
/**
|
||||
* The @a BcParseExpr function for dc. (See include/parse.h for a definition of
|
||||
* @a BcParseExpr.)
|
||||
* @param p The parser.
|
||||
* @param flags Flags that define the requirements that the parsed code must
|
||||
* meet or an error will result. See @a BcParseExpr for more info.
|
||||
*/
|
||||
void dc_parse_expr(BcParse *p, uint8_t flags);
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
|
|
@ -42,48 +42,136 @@
|
|||
|
||||
#define BC_FILE_ULL_LENGTH (21)
|
||||
|
||||
/// The file struct.
|
||||
typedef struct BcFile {
|
||||
|
||||
// The actual file descriptor.
|
||||
int fd;
|
||||
|
||||
// The buffer for the file.
|
||||
char *buf;
|
||||
|
||||
// The length (number of actual chars) in the buffer.
|
||||
size_t len;
|
||||
|
||||
// The capacity (max number of chars) of the buffer.
|
||||
size_t cap;
|
||||
|
||||
} BcFile;
|
||||
|
||||
#if BC_ENABLE_HISTORY
|
||||
|
||||
/// Types of flushing. These are important because of history and printing
|
||||
/// strings without newlines, something that users could use as their own
|
||||
/// prompts.
|
||||
typedef enum BcFlushType {
|
||||
|
||||
/// Do not clear the stored partial line, but don't add to it.
|
||||
BC_FLUSH_NO_EXTRAS_NO_CLEAR,
|
||||
|
||||
/// Do not clear the stored partial line and add to it.
|
||||
BC_FLUSH_SAVE_EXTRAS_NO_CLEAR,
|
||||
|
||||
/// Clear the stored partial line and do not save the new stuff either.
|
||||
BC_FLUSH_NO_EXTRAS_CLEAR,
|
||||
|
||||
/// Clear the stored partial line, but save the new stuff.
|
||||
BC_FLUSH_SAVE_EXTRAS_CLEAR,
|
||||
|
||||
} BcFlushType;
|
||||
|
||||
#else // BC_ENABLE_HISTORY
|
||||
|
||||
// These make sure that the BcFlushType parameter disappears if history is not
|
||||
// used.
|
||||
|
||||
#define bc_file_putchar(f, t, c) bc_file_putchar(f, c)
|
||||
#define bc_file_flushErr(f, t) bc_file_flushErr(f)
|
||||
#define bc_file_flush(f, t) bc_file_flush(f)
|
||||
#define bc_file_write(f, t, b, n) bc_file_write(f, b, n)
|
||||
#define bc_file_puts(f, t, s) bc_file_puts(f, s)
|
||||
|
||||
#endif // BC_ENABLE_HISTORY
|
||||
|
||||
/**
|
||||
* Initialize a file.
|
||||
* @param f The file to initialize.
|
||||
* @param fd The file descriptor.
|
||||
* @param buf The buffer for the file.
|
||||
* @param cap The capacity of the buffer.
|
||||
*/
|
||||
void bc_file_init(BcFile *f, int fd, char *buf, size_t cap);
|
||||
|
||||
/**
|
||||
* Frees a file, including flushing it.
|
||||
* @param f The file to free.
|
||||
*/
|
||||
void bc_file_free(BcFile *f);
|
||||
|
||||
/**
|
||||
* Print a char into the file.
|
||||
* @param f The file to print to.
|
||||
* @param type The flush type.
|
||||
* @param c The character to write.
|
||||
*/
|
||||
void bc_file_putchar(BcFile *restrict f, BcFlushType type, uchar c);
|
||||
|
||||
/**
|
||||
* Flush and return an error if it failed. This is meant to be used when needing
|
||||
* to flush in error situations when an error is already in flight. It would be
|
||||
* a very bad deal to throw another error.
|
||||
* @param f The file to flush.
|
||||
* @param type The flush type.
|
||||
* @return A status indicating if an error occurred.
|
||||
*/
|
||||
BcStatus bc_file_flushErr(BcFile *restrict f, BcFlushType type);
|
||||
|
||||
/**
|
||||
* Flush and throw an error on failure.
|
||||
* @param f The file to flush.
|
||||
* @param type The flush type.
|
||||
*/
|
||||
void bc_file_flush(BcFile *restrict f, BcFlushType type);
|
||||
|
||||
/**
|
||||
* Write the contents of buf to the file.
|
||||
* @param f The file to flush.
|
||||
* @param type The flush type.
|
||||
* @param buf The buffer whose contents will be written to the file.
|
||||
* @param n The length of buf.
|
||||
*/
|
||||
void bc_file_write(BcFile *restrict f, BcFlushType type,
|
||||
const char *buf, size_t n);
|
||||
|
||||
/**
|
||||
* Write to the file like fprintf would. This is very rudimentary.
|
||||
* @param f The file to flush.
|
||||
* @param fmt The format string.
|
||||
*/
|
||||
void bc_file_printf(BcFile *restrict f, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* Write to the file like vfprintf would. This is very rudimentary.
|
||||
* @param f The file to flush.
|
||||
* @param fmt The format string.
|
||||
*/
|
||||
void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args);
|
||||
|
||||
/**
|
||||
* Write str to the file.
|
||||
* @param f The file to flush.
|
||||
* @param type The flush type.
|
||||
* @param str The string to write to the file.
|
||||
*/
|
||||
void bc_file_puts(BcFile *restrict f, BcFlushType type, const char *str);
|
||||
|
||||
#if BC_ENABLE_HISTORY
|
||||
|
||||
// Some constant flush types for ease of use.
|
||||
extern const BcFlushType bc_flush_none;
|
||||
extern const BcFlushType bc_flush_err;
|
||||
extern const BcFlushType bc_flush_save;
|
||||
|
||||
#endif // BC_ENABLE_HISTORY
|
||||
|
||||
#endif // BC_FILE_H
|
||||
|
|
|
@ -85,19 +85,30 @@
|
|||
|
||||
#if BC_ENABLE_HISTORY
|
||||
|
||||
#ifdef _WIN32
|
||||
#error History is not supported on Windows.
|
||||
#endif // _WIN32
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#else // _WIN32
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif // WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
#include <io.h>
|
||||
#include <conio.h>
|
||||
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#include <status.h>
|
||||
#include <vector.h>
|
||||
|
@ -107,19 +118,40 @@
|
|||
#include <file.h>
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
/// Default columns.
|
||||
#define BC_HIST_DEF_COLS (80)
|
||||
|
||||
/// Max number of history entries.
|
||||
#define BC_HIST_MAX_LEN (128)
|
||||
|
||||
/// Max length of a line.
|
||||
#define BC_HIST_MAX_LINE (4095)
|
||||
|
||||
/// Max size for cursor position buffer.
|
||||
#define BC_HIST_SEQ_SIZE (64)
|
||||
|
||||
/**
|
||||
* The number of entries in the history.
|
||||
* @param h The history data.
|
||||
*/
|
||||
#define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1)
|
||||
|
||||
/**
|
||||
* Read n characters into s and check the error.
|
||||
* @param s The buffer to read into.
|
||||
* @param n The number of bytes to read.
|
||||
* @return True if there was an error, false otherwise.
|
||||
*/
|
||||
#define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1)
|
||||
|
||||
/// Markers for direction when using arrow keys.
|
||||
#define BC_HIST_NEXT (false)
|
||||
#define BC_HIST_PREV (true)
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
|
||||
// These are just for debugging.
|
||||
|
||||
#define BC_HISTORY_DEBUG_BUF_SIZE (1024)
|
||||
|
||||
#define lndebug(...) \
|
||||
|
@ -142,12 +174,8 @@
|
|||
#define lndebug(fmt, ...)
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
#if !BC_ENABLE_PROMPT
|
||||
#define bc_history_line(h, vec, prompt) bc_history_line(h, vec)
|
||||
#define bc_history_raw(h, prompt) bc_history_raw(h)
|
||||
#define bc_history_edit(h, prompt) bc_history_edit(h)
|
||||
#endif // BC_ENABLE_PROMPT
|
||||
|
||||
/// An enum of useful actions. To understand what these mean, check terminal
|
||||
/// emulators for their shortcuts or the VT100 codes.
|
||||
typedef enum BcHistoryAction {
|
||||
|
||||
BC_ACTION_NULL = 0,
|
||||
|
@ -171,6 +199,7 @@ typedef enum BcHistoryAction {
|
|||
BC_ACTION_CTRL_W = 23,
|
||||
BC_ACTION_CTRL_Z = 26,
|
||||
BC_ACTION_ESC = 27,
|
||||
BC_ACTION_CTRL_BSLASH = 28,
|
||||
BC_ACTION_BACKSPACE = 127
|
||||
|
||||
} BcHistoryAction;
|
||||
|
@ -190,13 +219,11 @@ typedef struct BcHistory {
|
|||
/// Any material printed without a trailing newline.
|
||||
BcVec extras;
|
||||
|
||||
#if BC_ENABLE_PROMPT
|
||||
/// Prompt to display.
|
||||
const char *prompt;
|
||||
|
||||
/// Prompt length.
|
||||
size_t plen;
|
||||
#endif // BC_ENABLE_PROMPT
|
||||
|
||||
/// Prompt column length.
|
||||
size_t pcol;
|
||||
|
@ -213,13 +240,14 @@ typedef struct BcHistory {
|
|||
/// The history index we are currently editing.
|
||||
size_t idx;
|
||||
|
||||
#ifndef _WIN32
|
||||
/// The original terminal state.
|
||||
struct termios orig_termios;
|
||||
#else // _WIN32
|
||||
DWORD orig_console_mode;
|
||||
#endif // _WIN32
|
||||
|
||||
/// These next three are here because pahole found a 4 byte hole here.
|
||||
|
||||
/// This is to signal that there is more, so we don't process yet.
|
||||
bool stdin_has_data;
|
||||
/// These next two are here because pahole found a 4 byte hole here.
|
||||
|
||||
/// Whether we are in rawmode.
|
||||
bool rawMode;
|
||||
|
@ -227,6 +255,7 @@ typedef struct BcHistory {
|
|||
/// Whether the terminal is bad.
|
||||
bool badTerm;
|
||||
|
||||
#ifndef _WIN32
|
||||
/// This is to check if stdin has more data.
|
||||
fd_set rdset;
|
||||
|
||||
|
@ -235,26 +264,69 @@ typedef struct BcHistory {
|
|||
|
||||
/// This is to check if stdin has more data.
|
||||
sigset_t sigmask;
|
||||
#endif // _WIN32
|
||||
|
||||
} BcHistory;
|
||||
|
||||
/**
|
||||
* Get a line from stdin using history. This returns a status because I don't
|
||||
* want to throw errors while the terminal is in raw mode.
|
||||
* @param h The history data.
|
||||
* @param vec A vector to put the line into.
|
||||
* @param prompt The prompt to display, if desired.
|
||||
* @return A status indicating an error, if any. Returning a status here
|
||||
* is better because if we throw an error out of history, we
|
||||
* leave the terminal in raw mode or in some other half-baked
|
||||
* state.
|
||||
*/
|
||||
BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt);
|
||||
|
||||
/**
|
||||
* Initialize history data.
|
||||
* @param h The struct to initialize.
|
||||
*/
|
||||
void bc_history_init(BcHistory *h);
|
||||
|
||||
/**
|
||||
* Free history data (and recook the terminal).
|
||||
* @param h The struct to free.
|
||||
*/
|
||||
void bc_history_free(BcHistory *h);
|
||||
|
||||
/**
|
||||
* Frees strings used by history.
|
||||
* @param str The string to free.
|
||||
*/
|
||||
void bc_history_string_free(void *str);
|
||||
|
||||
// A list of terminals that don't work.
|
||||
extern const char *bc_history_bad_terms[];
|
||||
|
||||
// A tab in history and its length.
|
||||
extern const char bc_history_tab[];
|
||||
extern const size_t bc_history_tab_len;
|
||||
|
||||
// A ctrl+c string.
|
||||
extern const char bc_history_ctrlc[];
|
||||
|
||||
// UTF-8 data arrays.
|
||||
extern const uint32_t bc_history_wchars[][2];
|
||||
extern const size_t bc_history_wchars_len;
|
||||
extern const uint32_t bc_history_combo_chars[];
|
||||
extern const size_t bc_history_combo_chars_len;
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
|
||||
// Debug data.
|
||||
extern BcFile bc_history_debug_fp;
|
||||
extern char *bc_history_debug_buf;
|
||||
void bc_history_printKeyCodes(BcHistory* l);
|
||||
|
||||
/**
|
||||
* A function to print keycodes for debugging.
|
||||
* @param h The history data.
|
||||
*/
|
||||
void bc_history_printKeyCodes(BcHistory* h);
|
||||
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
#endif // BC_ENABLE_HISTORY
|
||||
|
|
464
include/lang.h
464
include/lang.h
|
@ -42,34 +42,28 @@
|
|||
#include <vector.h>
|
||||
#include <num.h>
|
||||
|
||||
#if BC_ENABLED
|
||||
#define BC_INST_IS_ASSIGN(i) \
|
||||
((i) == BC_INST_ASSIGN || (i) == BC_INST_ASSIGN_NO_VAL)
|
||||
#define BC_INST_USE_VAL(i) ((i) <= BC_INST_ASSIGN)
|
||||
#else // BC_ENABLED
|
||||
#define BC_INST_IS_ASSIGN(i) ((i) == BC_INST_ASSIGN_NO_VAL)
|
||||
#define BC_INST_USE_VAL(i) (false)
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define BC_ENABLE_FUNC_FREE (1)
|
||||
#else // NDEBUG
|
||||
#define BC_ENABLE_FUNC_FREE DC_ENABLED
|
||||
#endif // NDEBUG
|
||||
|
||||
/// The instructions for bytecode.
|
||||
typedef enum BcInst {
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// Postfix increment and decrement. Prefix are translated into
|
||||
/// BC_INST_ONE with either BC_INST_ASSIGN_PLUS or BC_INST_ASSIGN_MINUS.
|
||||
BC_INST_INC = 0,
|
||||
BC_INST_DEC,
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Unary negation.
|
||||
BC_INST_NEG,
|
||||
|
||||
/// Boolean not.
|
||||
BC_INST_BOOL_NOT,
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Truncation operator.
|
||||
BC_INST_TRUNC,
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// These should be self-explanatory.
|
||||
BC_INST_POWER,
|
||||
BC_INST_MULTIPLY,
|
||||
BC_INST_DIVIDE,
|
||||
|
@ -78,12 +72,16 @@ typedef enum BcInst {
|
|||
BC_INST_MINUS,
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Places operator.
|
||||
BC_INST_PLACES,
|
||||
|
||||
/// Shift operators.
|
||||
BC_INST_LSHIFT,
|
||||
BC_INST_RSHIFT,
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Comparison operators.
|
||||
BC_INST_REL_EQ,
|
||||
BC_INST_REL_LE,
|
||||
BC_INST_REL_GE,
|
||||
|
@ -91,10 +89,12 @@ typedef enum BcInst {
|
|||
BC_INST_REL_LT,
|
||||
BC_INST_REL_GT,
|
||||
|
||||
/// Boolean or and and.
|
||||
BC_INST_BOOL_OR,
|
||||
BC_INST_BOOL_AND,
|
||||
|
||||
#if BC_ENABLED
|
||||
/// Same as the normal operators, but assigment. So ^=, *=, /=, etc.
|
||||
BC_INST_ASSIGN_POWER,
|
||||
BC_INST_ASSIGN_MULTIPLY,
|
||||
BC_INST_ASSIGN_DIVIDE,
|
||||
|
@ -102,12 +102,20 @@ typedef enum BcInst {
|
|||
BC_INST_ASSIGN_PLUS,
|
||||
BC_INST_ASSIGN_MINUS,
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Places and shift assignment operators.
|
||||
BC_INST_ASSIGN_PLACES,
|
||||
BC_INST_ASSIGN_LSHIFT,
|
||||
BC_INST_ASSIGN_RSHIFT,
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Normal assignment.
|
||||
BC_INST_ASSIGN,
|
||||
|
||||
/// bc and dc detect when the value from an assignment is not necessary.
|
||||
/// For example, a plain assignment statement means the value is never used.
|
||||
/// In those cases, we can get lots of performance back by not even creating
|
||||
/// a copy at all. In fact, it saves a copy, a push onto the results stack,
|
||||
/// a pop from the results stack, and a free. Definitely worth it to detect.
|
||||
BC_INST_ASSIGN_POWER_NO_VAL,
|
||||
BC_INST_ASSIGN_MULTIPLY_NO_VAL,
|
||||
BC_INST_ASSIGN_DIVIDE_NO_VAL,
|
||||
|
@ -115,212 +123,564 @@ typedef enum BcInst {
|
|||
BC_INST_ASSIGN_PLUS_NO_VAL,
|
||||
BC_INST_ASSIGN_MINUS_NO_VAL,
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Same as above.
|
||||
BC_INST_ASSIGN_PLACES_NO_VAL,
|
||||
BC_INST_ASSIGN_LSHIFT_NO_VAL,
|
||||
BC_INST_ASSIGN_RSHIFT_NO_VAL,
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Normal assignment that pushes no value on the stack.
|
||||
BC_INST_ASSIGN_NO_VAL,
|
||||
|
||||
/// Push a constant onto the results stack.
|
||||
BC_INST_NUM,
|
||||
BC_INST_VAR,
|
||||
BC_INST_ARRAY_ELEM,
|
||||
#if BC_ENABLED
|
||||
BC_INST_ARRAY,
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Push a variable onto the results stack.
|
||||
BC_INST_VAR,
|
||||
|
||||
/// Push an array element onto the results stack.
|
||||
BC_INST_ARRAY_ELEM,
|
||||
|
||||
/// Push an array onto the results stack. This is different from pushing an
|
||||
/// array *element* onto the results stack; it pushes a reference to the
|
||||
/// whole array. This is needed in bc for function arguments that are
|
||||
/// arrays. It is also needed for returning the length of an array.
|
||||
BC_INST_ARRAY,
|
||||
|
||||
/// Push a zero or a one onto the stack. These are special cased because it
|
||||
/// does help performance, particularly for one since inc/dec operators
|
||||
/// use it.
|
||||
BC_INST_ZERO,
|
||||
BC_INST_ONE,
|
||||
|
||||
#if BC_ENABLED
|
||||
/// Push the last printed value onto the stack.
|
||||
BC_INST_LAST,
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Push the value of any of the globals onto the stack.
|
||||
BC_INST_IBASE,
|
||||
BC_INST_OBASE,
|
||||
BC_INST_SCALE,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Push the value of the seed global onto the stack.
|
||||
BC_INST_SEED,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// These are builtin functions.
|
||||
BC_INST_LENGTH,
|
||||
BC_INST_SCALE_FUNC,
|
||||
BC_INST_SQRT,
|
||||
BC_INST_ABS,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Another builtin function.
|
||||
BC_INST_IRAND,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Asciify.
|
||||
BC_INST_ASCIIFY,
|
||||
|
||||
/// Another builtin function.
|
||||
BC_INST_READ,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Another builtin function.
|
||||
BC_INST_RAND,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Return the max for the various globals.
|
||||
BC_INST_MAXIBASE,
|
||||
BC_INST_MAXOBASE,
|
||||
BC_INST_MAXSCALE,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Return the max value returned by rand().
|
||||
BC_INST_MAXRAND,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// This is slightly misnamed versus BC_INST_PRINT_POP. Well, it is in bc.
|
||||
/// dc uses this instruction to print, but not pop. That's valid in dc.
|
||||
/// However, in bc, it is *never* valid to print without popping. In bc,
|
||||
/// BC_INST_PRINT_POP is used to indicate when a string should be printed
|
||||
/// because of a print statement or whether it should be printed raw. The
|
||||
/// reason for this is because a print statement handles escaped characters.
|
||||
/// So BC_INST_PRINT_POP is for printing a string from a print statement,
|
||||
/// BC_INST_PRINT_STR is for printing a string by itself.
|
||||
///
|
||||
/// In dc, BC_INST_PRINT_POP prints and pops, and BC_INST_PRINT just prints.
|
||||
///
|
||||
/// Oh, and BC_INST_STR pushes a string onto the results stack.
|
||||
BC_INST_PRINT,
|
||||
BC_INST_PRINT_POP,
|
||||
BC_INST_STR,
|
||||
#if BC_ENABLED
|
||||
BC_INST_PRINT_STR,
|
||||
|
||||
#if BC_ENABLED
|
||||
/// Jumps unconditionally.
|
||||
BC_INST_JUMP,
|
||||
|
||||
/// Jumps if the top of the results stack is zero (condition failed). It
|
||||
/// turns out that we only want to jump when conditions fail to "skip" code.
|
||||
BC_INST_JUMP_ZERO,
|
||||
|
||||
/// Call a function.
|
||||
BC_INST_CALL,
|
||||
|
||||
/// Return the top of the stack to the caller.
|
||||
BC_INST_RET,
|
||||
|
||||
/// Return 0 to the caller.
|
||||
BC_INST_RET0,
|
||||
|
||||
/// Special return instruction for void functions.
|
||||
BC_INST_RET_VOID,
|
||||
|
||||
/// Special halt instruction.
|
||||
BC_INST_HALT,
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Pop an item off of the results stack.
|
||||
BC_INST_POP,
|
||||
|
||||
#if DC_ENABLED
|
||||
BC_INST_POP_EXEC,
|
||||
BC_INST_MODEXP,
|
||||
BC_INST_DIVMOD,
|
||||
|
||||
BC_INST_EXECUTE,
|
||||
BC_INST_EXEC_COND,
|
||||
|
||||
BC_INST_ASCIIFY,
|
||||
BC_INST_PRINT_STREAM,
|
||||
|
||||
BC_INST_PRINT_STACK,
|
||||
BC_INST_CLEAR_STACK,
|
||||
BC_INST_STACK_LEN,
|
||||
BC_INST_DUPLICATE,
|
||||
/// Swaps the top two items on the results stack.
|
||||
BC_INST_SWAP,
|
||||
|
||||
/// Modular exponentiation.
|
||||
BC_INST_MODEXP,
|
||||
|
||||
/// Do divide and modulus at the same time.
|
||||
BC_INST_DIVMOD,
|
||||
|
||||
/// Turns a number into a string and prints it.
|
||||
BC_INST_PRINT_STREAM,
|
||||
|
||||
#if DC_ENABLED
|
||||
|
||||
/// dc's return; it pops an executing string off of the stack.
|
||||
BC_INST_POP_EXEC,
|
||||
|
||||
/// Unconditionally execute a string.
|
||||
BC_INST_EXECUTE,
|
||||
|
||||
/// Conditionally execute a string.
|
||||
BC_INST_EXEC_COND,
|
||||
|
||||
/// Prints each item on the results stack, separated by newlines.
|
||||
BC_INST_PRINT_STACK,
|
||||
|
||||
/// Pops everything off of the results stack.
|
||||
BC_INST_CLEAR_STACK,
|
||||
|
||||
/// Pushes the current length of a register stack onto the results stack.
|
||||
BC_INST_REG_STACK_LEN,
|
||||
|
||||
/// Pushes the current length of the results stack onto the results stack.
|
||||
BC_INST_STACK_LEN,
|
||||
|
||||
/// Pushes a copy of the item on the top of the results stack onto the
|
||||
/// results stack.
|
||||
BC_INST_DUPLICATE,
|
||||
|
||||
/// Copies the value in a register and pushes the copy onto the results
|
||||
/// stack.
|
||||
BC_INST_LOAD,
|
||||
|
||||
/// Pops an item off of a register stack and pushes it onto the results
|
||||
/// stack.
|
||||
BC_INST_PUSH_VAR,
|
||||
|
||||
/// Pops an item off of the results stack and pushes it onto a register's
|
||||
/// stack.
|
||||
BC_INST_PUSH_TO_VAR,
|
||||
|
||||
/// Quit.
|
||||
BC_INST_QUIT,
|
||||
|
||||
/// Quit executing some number of strings.
|
||||
BC_INST_NQUIT,
|
||||
|
||||
/// Push the depth of the execution stack onto the stack.
|
||||
BC_INST_EXEC_STACK_LEN,
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
BC_INST_INVALID = UCHAR_MAX,
|
||||
/// Invalid instruction.
|
||||
BC_INST_INVALID,
|
||||
|
||||
} BcInst;
|
||||
|
||||
/// Used by maps to identify where items are in the array.
|
||||
typedef struct BcId {
|
||||
|
||||
/// The name of the item.
|
||||
char *name;
|
||||
|
||||
/// The index into the array where the item is.
|
||||
size_t idx;
|
||||
|
||||
} BcId;
|
||||
|
||||
/// The location of a var, array, or array element.
|
||||
typedef struct BcLoc {
|
||||
|
||||
/// The index of the var or array.
|
||||
size_t loc;
|
||||
|
||||
/// The index of the array element. Only used for array elements.
|
||||
size_t idx;
|
||||
|
||||
} BcLoc;
|
||||
|
||||
/// An entry for a constant.
|
||||
typedef struct BcConst {
|
||||
|
||||
/// The original string as parsed from the source code.
|
||||
char *val;
|
||||
|
||||
/// The last base that the constant was parsed in.
|
||||
BcBigDig base;
|
||||
|
||||
/// The parsed constant.
|
||||
BcNum num;
|
||||
|
||||
} BcConst;
|
||||
|
||||
/// A function. This is also used in dc, not just bc. The reason is that strings
|
||||
/// are executed in dc, and they are converted to functions in order to be
|
||||
/// executed.
|
||||
typedef struct BcFunc {
|
||||
|
||||
/// The bytecode instructions.
|
||||
BcVec code;
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// The labels. This is a vector of indices. The index is the index into
|
||||
/// the bytecode vector where the label is.
|
||||
BcVec labels;
|
||||
|
||||
/// The autos for the function. The first items are the parameters, and the
|
||||
/// arguments to the parameters must match the types in this vector.
|
||||
BcVec autos;
|
||||
|
||||
/// The number of parameters the function takes.
|
||||
size_t nparams;
|
||||
|
||||
#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;
|
||||
|
||||
#if BC_ENABLED
|
||||
/// True if the function is a void function.
|
||||
bool voidfn;
|
||||
#endif // BC_ENABLED
|
||||
|
||||
} BcFunc;
|
||||
|
||||
/// Types of results that can be pushed onto the results stack.
|
||||
typedef enum BcResultType {
|
||||
|
||||
/// Result is a variable.
|
||||
BC_RESULT_VAR,
|
||||
BC_RESULT_ARRAY_ELEM,
|
||||
#if BC_ENABLED
|
||||
BC_RESULT_ARRAY,
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Result is an array element.
|
||||
BC_RESULT_ARRAY_ELEM,
|
||||
|
||||
/// Result is an array. This is only allowed for function arguments or
|
||||
/// returning the length of the array.
|
||||
BC_RESULT_ARRAY,
|
||||
|
||||
/// Result is a string.
|
||||
BC_RESULT_STR,
|
||||
|
||||
/// Result is a temporary. This is used for the result of almost all
|
||||
/// expressions.
|
||||
BC_RESULT_TEMP,
|
||||
|
||||
/// Special casing the two below gave performance improvements.
|
||||
|
||||
/// Result is a 0.
|
||||
BC_RESULT_ZERO,
|
||||
|
||||
/// Result is a 1. Useful for inc/dec operators.
|
||||
BC_RESULT_ONE,
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// Result is the special "last" variable.
|
||||
BC_RESULT_LAST,
|
||||
|
||||
/// Result is the return value of a void function.
|
||||
BC_RESULT_VOID,
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Result is the value of ibase.
|
||||
BC_RESULT_IBASE,
|
||||
|
||||
/// Result is the value of obase.
|
||||
BC_RESULT_OBASE,
|
||||
|
||||
/// Result is the value of scale.
|
||||
BC_RESULT_SCALE,
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Result is the value of seed.
|
||||
BC_RESULT_SEED,
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
} BcResultType;
|
||||
|
||||
/// A union to store data for various result types.
|
||||
typedef union BcResultData {
|
||||
|
||||
/// A number. Strings are stored here too; they are numbers with
|
||||
/// cap == 0 && num == NULL. The string's index into the strings vector is
|
||||
/// stored in the scale field. But this is only used for strings stored in
|
||||
/// variables.
|
||||
BcNum n;
|
||||
|
||||
/// A vector.
|
||||
BcVec v;
|
||||
|
||||
/// A variable, array, or array element reference. This could also be a
|
||||
/// string if a string is not stored in a variable (dc only).
|
||||
BcLoc loc;
|
||||
|
||||
} BcResultData;
|
||||
|
||||
/// A tagged union for results.
|
||||
typedef struct BcResult {
|
||||
|
||||
/// The tag. The type of the result.
|
||||
BcResultType t;
|
||||
|
||||
/// The data. The data for the result.
|
||||
BcResultData d;
|
||||
|
||||
} BcResult;
|
||||
|
||||
/// An instruction pointer. This is how bc knows where in the bytecode vector,
|
||||
/// and which function, the current execution is.
|
||||
typedef struct BcInstPtr {
|
||||
|
||||
/// The index of the currently executing function in the fns vector.
|
||||
size_t func;
|
||||
|
||||
/// The index into the bytecode vector of the *next* instruction.
|
||||
size_t idx;
|
||||
|
||||
/// The length of the results vector when this function started executing.
|
||||
/// This is mostly used for bc where functions should not affect the results
|
||||
/// of their callers.
|
||||
size_t len;
|
||||
|
||||
} BcInstPtr;
|
||||
|
||||
/// Types of identifiers.
|
||||
typedef enum BcType {
|
||||
|
||||
/// Variable.
|
||||
BC_TYPE_VAR,
|
||||
|
||||
/// Array.
|
||||
BC_TYPE_ARRAY,
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// Array reference.
|
||||
BC_TYPE_REF,
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
} BcType;
|
||||
|
||||
#if BC_ENABLED
|
||||
/// An auto variable in bc.
|
||||
typedef struct BcAuto {
|
||||
|
||||
/// The index of the variable in the vars or arrs vectors.
|
||||
size_t idx;
|
||||
|
||||
/// The type of the variable.
|
||||
BcType type;
|
||||
|
||||
} BcAuto;
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Forward declaration.
|
||||
struct BcProgram;
|
||||
|
||||
/**
|
||||
* Initializes a function.
|
||||
* @param f The function to initialize.
|
||||
* @param name The name of the function. The string is assumed to be owned by
|
||||
* some other entity.
|
||||
*/
|
||||
void bc_func_init(BcFunc *f, const char* name);
|
||||
|
||||
/**
|
||||
* Inserts an auto into the function.
|
||||
* @param f The function to insert into.
|
||||
* @param p The program. This is to search for the variable or array name.
|
||||
* @param name The name of the auto to insert.
|
||||
* @param type The type of the auto.
|
||||
* @param line The line in the source code where the insert happened. This is
|
||||
* solely for error reporting.
|
||||
*/
|
||||
void bc_func_insert(BcFunc *f, struct BcProgram* p, char* name,
|
||||
BcType type, size_t line);
|
||||
void bc_func_reset(BcFunc *f);
|
||||
void bc_func_free(void *func);
|
||||
|
||||
/**
|
||||
* Resets a function in preparation for it to be reused. This can happen in bc
|
||||
* because it is a dynamic language and functions can be redefined.
|
||||
* @param f The functio to reset.
|
||||
*/
|
||||
void bc_func_reset(BcFunc *f);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* Frees a function. This is a destructor. This is only used in debug builds
|
||||
* because all functions are freed at exit. We free them in debug builds to
|
||||
* check for memory leaks.
|
||||
* @param func The function to free as a void pointer.
|
||||
*/
|
||||
void bc_func_free(void *func);
|
||||
#endif // NDEBUG
|
||||
|
||||
/**
|
||||
* Initializes an array, which is the array type in bc and dc source code. Since
|
||||
* variables and arrays are both arrays (see the development manual,
|
||||
* manuals/development.md#execution, for more information), the @a nums
|
||||
* parameter tells bc whether to initialize an array of numbers or an array of
|
||||
* arrays of numbers. If the latter, it does a recursive call with nums set to
|
||||
* true.
|
||||
* @param a The array to initialize.
|
||||
* @param nums True if the array should be for numbers, false if it should be
|
||||
* for vectors.
|
||||
*/
|
||||
void bc_array_init(BcVec *a, bool nums);
|
||||
|
||||
/**
|
||||
* Copies an array to another array. This is used to do pass arrays to functions
|
||||
* that do not take references to arrays. The arrays are passed entirely by
|
||||
* value, which means that they need to be copied.
|
||||
* @param d The destination array.
|
||||
* @param s The source array.
|
||||
*/
|
||||
void bc_array_copy(BcVec *d, const BcVec *s);
|
||||
|
||||
/**
|
||||
* Frees a string stored in a function. This is a destructor.
|
||||
* @param string The string to free as a void pointer.
|
||||
*/
|
||||
void bc_string_free(void *string);
|
||||
|
||||
/**
|
||||
* Frees a constant stored in a function. This is a destructor.
|
||||
* @param constant The constant to free as a void pointer.
|
||||
*/
|
||||
void bc_const_free(void *constant);
|
||||
void bc_id_free(void *id);
|
||||
|
||||
/**
|
||||
* Clears a result. It sets the type to BC_RESULT_TEMP and clears the union by
|
||||
* clearing the BcNum in the union. This is to ensure that bc does not use
|
||||
* uninitialized data.
|
||||
* @param r The result to clear.
|
||||
*/
|
||||
void bc_result_clear(BcResult *r);
|
||||
|
||||
/**
|
||||
* Copies a result into another. This is done for things like duplicating the
|
||||
* top of the results stack or copying the result of an assignment to put back
|
||||
* on the results stack.
|
||||
* @param d The destination result.
|
||||
* @param src The source result.
|
||||
*/
|
||||
void bc_result_copy(BcResult *d, BcResult *src);
|
||||
|
||||
/**
|
||||
* Frees a result. This is a destructor.
|
||||
* @param result The result to free as a void pointer.
|
||||
*/
|
||||
void bc_result_free(void *result);
|
||||
|
||||
/**
|
||||
* Expands an array to @a len. This can happen because in bc, you do not have to
|
||||
* explicitly initialize elements of an array. If you access an element that is
|
||||
* not initialized, the array is expanded to fit it, and all missing elements
|
||||
* are initialized to 0 if they are numbers, or arrays with one element of 0.
|
||||
* This function does that expansion.
|
||||
* @param a The array to expand.
|
||||
* @param len The length to expand to.
|
||||
*/
|
||||
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
|
||||
|
||||
/**
|
||||
* Returns non-zero if the bytecode instruction i is an assignment instruction.
|
||||
* @param i The instruction to test.
|
||||
* @return Non-zero if i is an assignment instruction, zero otherwise.
|
||||
*/
|
||||
#define BC_INST_IS_ASSIGN(i) \
|
||||
((i) == BC_INST_ASSIGN || (i) == BC_INST_ASSIGN_NO_VAL)
|
||||
|
||||
/**
|
||||
* Returns true if the bytecode instruction @a i requires the value to be
|
||||
* returned for use.
|
||||
* @param i The instruction to test.
|
||||
* @return True if @a i requires the value to be returned for use, false
|
||||
* otherwise.
|
||||
*/
|
||||
#define BC_INST_USE_VAL(i) ((i) <= BC_INST_ASSIGN)
|
||||
|
||||
#else // BC_ENABLED
|
||||
|
||||
/**
|
||||
* Returns non-zero if the bytecode instruction i is an assignment instruction.
|
||||
* @param i The instruction to test.
|
||||
* @return Non-zero if i is an assignment instruction, zero otherwise.
|
||||
*/
|
||||
#define BC_INST_IS_ASSIGN(i) ((i) == BC_INST_ASSIGN_NO_VAL)
|
||||
|
||||
/**
|
||||
* Returns true if the bytecode instruction @a i requires the value to be
|
||||
* returned for use.
|
||||
* @param i The instruction to test.
|
||||
* @return True if @a i requires the value to be returned for use, false
|
||||
* otherwise.
|
||||
*/
|
||||
#define BC_INST_USE_VAL(i) (false)
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
/// Reference to string names for all of the instructions. For debugging.
|
||||
extern const char* bc_inst_names[];
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
/// References to the names of the main and read functions.
|
||||
extern const char bc_func_main[];
|
||||
extern const char bc_func_read[];
|
||||
|
||||
|
|
364
include/lex.h
364
include/lex.h
|
@ -43,9 +43,17 @@
|
|||
#include <vector.h>
|
||||
#include <lang.h>
|
||||
|
||||
// Two convencience macros for throwing errors in lex code. They take care of
|
||||
// plumbing like passing in the current line the lexer is on.
|
||||
#define bc_lex_err(l, e) (bc_vm_handleError((e), (l)->line))
|
||||
#define bc_lex_verr(l, e, ...) (bc_vm_handleError((e), (l)->line, __VA_ARGS__))
|
||||
|
||||
// BC_LEX_NEG_CHAR returns the char that corresponds to negative for the
|
||||
// current calculator.
|
||||
//
|
||||
// BC_LEX_LAST_NUM_CHAR returns the char that corresponds to the last valid
|
||||
// char for numbers. In bc and dc, capital letters are part of numbers, to a
|
||||
// point. (dc only goes up to hex, so its last valid char is 'F'.)
|
||||
#if BC_ENABLED
|
||||
|
||||
#if DC_ENABLED
|
||||
|
@ -63,185 +71,503 @@
|
|||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#define BC_LEX_NUM_CHAR(c, pt, int_only) \
|
||||
(isdigit(c) || ((c) >= 'A' && (c) <= BC_LEX_LAST_NUM_CHAR) || \
|
||||
/**
|
||||
* Returns true if c is a valid number character.
|
||||
* @param c The char to check.
|
||||
* @param pt If a decimal point has already been seen.
|
||||
* @param int_only True if the number is expected to be an int only, false if
|
||||
* non-integers are allowed.
|
||||
* @return True if @a c is a valid number character.
|
||||
*/
|
||||
#define BC_LEX_NUM_CHAR(c, pt, int_only) \
|
||||
(isdigit(c) != 0 || ((c) >= 'A' && (c) <= BC_LEX_LAST_NUM_CHAR) || \
|
||||
((c) == '.' && !(pt) && !(int_only)))
|
||||
|
||||
// BC_LEX_NEG is not used in lexing; it is only for parsing.
|
||||
/// An enum of lex token types.
|
||||
typedef enum BcLexType {
|
||||
|
||||
/// End of file.
|
||||
BC_LEX_EOF,
|
||||
|
||||
/// Marker for invalid tokens, used by bc and dc for const data.
|
||||
BC_LEX_INVALID,
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// Increment operator.
|
||||
BC_LEX_OP_INC,
|
||||
|
||||
/// Decrement operator.
|
||||
BC_LEX_OP_DEC,
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// BC_LEX_NEG is not used in lexing; it is only for parsing. The lexer
|
||||
/// marks all '-' characters as BC_LEX_OP_MINUS, but the parser needs to be
|
||||
/// able to distinguish them.
|
||||
BC_LEX_NEG,
|
||||
|
||||
/// Boolean not.
|
||||
BC_LEX_OP_BOOL_NOT,
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Truncation operator.
|
||||
BC_LEX_OP_TRUNC,
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Power operator.
|
||||
BC_LEX_OP_POWER,
|
||||
|
||||
/// Multiplication operator.
|
||||
BC_LEX_OP_MULTIPLY,
|
||||
|
||||
/// Division operator.
|
||||
BC_LEX_OP_DIVIDE,
|
||||
|
||||
/// Modulus operator.
|
||||
BC_LEX_OP_MODULUS,
|
||||
|
||||
/// Addition operator.
|
||||
BC_LEX_OP_PLUS,
|
||||
|
||||
/// Subtraction operator.
|
||||
BC_LEX_OP_MINUS,
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Places (truncate or extend) operator.
|
||||
BC_LEX_OP_PLACES,
|
||||
|
||||
/// Left (decimal) shift operator.
|
||||
BC_LEX_OP_LSHIFT,
|
||||
|
||||
/// Right (decimal) shift operator.
|
||||
BC_LEX_OP_RSHIFT,
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Equal operator.
|
||||
BC_LEX_OP_REL_EQ,
|
||||
|
||||
/// Less than or equal operator.
|
||||
BC_LEX_OP_REL_LE,
|
||||
|
||||
/// Greater than or equal operator.
|
||||
BC_LEX_OP_REL_GE,
|
||||
|
||||
/// Not equal operator.
|
||||
BC_LEX_OP_REL_NE,
|
||||
|
||||
/// Less than operator.
|
||||
BC_LEX_OP_REL_LT,
|
||||
|
||||
/// Greater than operator.
|
||||
BC_LEX_OP_REL_GT,
|
||||
|
||||
/// Boolean or operator.
|
||||
BC_LEX_OP_BOOL_OR,
|
||||
|
||||
/// Boolean and operator.
|
||||
BC_LEX_OP_BOOL_AND,
|
||||
|
||||
#if BC_ENABLED
|
||||
/// Power assignment operator.
|
||||
BC_LEX_OP_ASSIGN_POWER,
|
||||
|
||||
/// Multiplication assignment operator.
|
||||
BC_LEX_OP_ASSIGN_MULTIPLY,
|
||||
|
||||
/// Division assignment operator.
|
||||
BC_LEX_OP_ASSIGN_DIVIDE,
|
||||
|
||||
/// Modulus assignment operator.
|
||||
BC_LEX_OP_ASSIGN_MODULUS,
|
||||
|
||||
/// Addition assignment operator.
|
||||
BC_LEX_OP_ASSIGN_PLUS,
|
||||
|
||||
/// Subtraction assignment operator.
|
||||
BC_LEX_OP_ASSIGN_MINUS,
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Places (truncate or extend) assignment operator.
|
||||
BC_LEX_OP_ASSIGN_PLACES,
|
||||
|
||||
/// Left (decimal) shift assignment operator.
|
||||
BC_LEX_OP_ASSIGN_LSHIFT,
|
||||
|
||||
/// Right (decimal) shift assignment operator.
|
||||
BC_LEX_OP_ASSIGN_RSHIFT,
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// Assignment operator.
|
||||
BC_LEX_OP_ASSIGN,
|
||||
|
||||
/// Newline.
|
||||
BC_LEX_NLINE,
|
||||
|
||||
/// Whitespace.
|
||||
BC_LEX_WHITESPACE,
|
||||
|
||||
/// Left parenthesis.
|
||||
BC_LEX_LPAREN,
|
||||
|
||||
/// Right parenthesis.
|
||||
BC_LEX_RPAREN,
|
||||
|
||||
/// Left bracket.
|
||||
BC_LEX_LBRACKET,
|
||||
|
||||
/// Comma.
|
||||
BC_LEX_COMMA,
|
||||
|
||||
/// Right bracket.
|
||||
BC_LEX_RBRACKET,
|
||||
|
||||
/// Left brace.
|
||||
BC_LEX_LBRACE,
|
||||
|
||||
/// Semicolon.
|
||||
BC_LEX_SCOLON,
|
||||
|
||||
/// Right brace.
|
||||
BC_LEX_RBRACE,
|
||||
|
||||
/// String.
|
||||
BC_LEX_STR,
|
||||
|
||||
/// Identifier/name.
|
||||
BC_LEX_NAME,
|
||||
|
||||
/// Constant number.
|
||||
BC_LEX_NUMBER,
|
||||
|
||||
// These keywords are in the order they are in for a reason. Don't change
|
||||
// the order unless you want a bunch of weird failures in the test suite.
|
||||
// In fact, almost all of these tokens are in a specific order for a reason.
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// bc auto keyword.
|
||||
BC_LEX_KW_AUTO,
|
||||
|
||||
/// bc break keyword.
|
||||
BC_LEX_KW_BREAK,
|
||||
|
||||
/// bc continue keyword.
|
||||
BC_LEX_KW_CONTINUE,
|
||||
|
||||
/// bc define keyword.
|
||||
BC_LEX_KW_DEFINE,
|
||||
|
||||
/// bc for keyword.
|
||||
BC_LEX_KW_FOR,
|
||||
|
||||
/// bc if keyword.
|
||||
BC_LEX_KW_IF,
|
||||
|
||||
/// bc limits keyword.
|
||||
BC_LEX_KW_LIMITS,
|
||||
|
||||
/// bc return keyword.
|
||||
BC_LEX_KW_RETURN,
|
||||
|
||||
/// bc while keyword.
|
||||
BC_LEX_KW_WHILE,
|
||||
|
||||
/// bc halt keyword.
|
||||
BC_LEX_KW_HALT,
|
||||
|
||||
/// bc last keyword.
|
||||
BC_LEX_KW_LAST,
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// bc ibase keyword.
|
||||
BC_LEX_KW_IBASE,
|
||||
|
||||
/// bc obase keyword.
|
||||
BC_LEX_KW_OBASE,
|
||||
|
||||
/// bc scale keyword.
|
||||
BC_LEX_KW_SCALE,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// bc seed keyword.
|
||||
BC_LEX_KW_SEED,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// bc length keyword.
|
||||
BC_LEX_KW_LENGTH,
|
||||
|
||||
/// bc print keyword.
|
||||
BC_LEX_KW_PRINT,
|
||||
|
||||
/// bc sqrt keyword.
|
||||
BC_LEX_KW_SQRT,
|
||||
|
||||
/// bc abs keyword.
|
||||
BC_LEX_KW_ABS,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// bc irand keyword.
|
||||
BC_LEX_KW_IRAND,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// bc asciffy keyword.
|
||||
BC_LEX_KW_ASCIIFY,
|
||||
|
||||
/// bc modexp keyword.
|
||||
BC_LEX_KW_MODEXP,
|
||||
|
||||
/// bc divmod keyword.
|
||||
BC_LEX_KW_DIVMOD,
|
||||
|
||||
/// bc quit keyword.
|
||||
BC_LEX_KW_QUIT,
|
||||
|
||||
/// bc read keyword.
|
||||
BC_LEX_KW_READ,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// bc rand keyword.
|
||||
BC_LEX_KW_RAND,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// bc maxibase keyword.
|
||||
BC_LEX_KW_MAXIBASE,
|
||||
|
||||
/// bc maxobase keyword.
|
||||
BC_LEX_KW_MAXOBASE,
|
||||
|
||||
/// bc maxscale keyword.
|
||||
BC_LEX_KW_MAXSCALE,
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// bc maxrand keyword.
|
||||
BC_LEX_KW_MAXRAND,
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// bc stream keyword.
|
||||
BC_LEX_KW_STREAM,
|
||||
|
||||
/// bc else keyword.
|
||||
BC_LEX_KW_ELSE,
|
||||
|
||||
#if DC_ENABLED
|
||||
BC_LEX_EQ_NO_REG,
|
||||
BC_LEX_OP_MODEXP,
|
||||
BC_LEX_OP_DIVMOD,
|
||||
|
||||
/// A special token for dc to calculate equal without a register.
|
||||
BC_LEX_EQ_NO_REG,
|
||||
|
||||
/// Colon (array) operator.
|
||||
BC_LEX_COLON,
|
||||
|
||||
/// Execute command.
|
||||
BC_LEX_EXECUTE,
|
||||
|
||||
/// Print stack command.
|
||||
BC_LEX_PRINT_STACK,
|
||||
|
||||
/// Clear stack command.
|
||||
BC_LEX_CLEAR_STACK,
|
||||
|
||||
/// Register stack level command.
|
||||
BC_LEX_REG_STACK_LEVEL,
|
||||
|
||||
/// Main stack level command.
|
||||
BC_LEX_STACK_LEVEL,
|
||||
|
||||
/// Duplicate command.
|
||||
BC_LEX_DUPLICATE,
|
||||
|
||||
/// Swap (reverse) command.
|
||||
BC_LEX_SWAP,
|
||||
|
||||
/// Pop (remove) command.
|
||||
BC_LEX_POP,
|
||||
|
||||
BC_LEX_ASCIIFY,
|
||||
BC_LEX_PRINT_STREAM,
|
||||
|
||||
/// Store ibase command.
|
||||
BC_LEX_STORE_IBASE,
|
||||
|
||||
/// Store obase command.
|
||||
BC_LEX_STORE_OBASE,
|
||||
|
||||
/// Store scale command.
|
||||
BC_LEX_STORE_SCALE,
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
/// Store seed command.
|
||||
BC_LEX_STORE_SEED,
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Load variable onto stack command.
|
||||
BC_LEX_LOAD,
|
||||
|
||||
/// Pop off of variable stack onto results stack command.
|
||||
BC_LEX_LOAD_POP,
|
||||
|
||||
/// Push onto variable stack command.
|
||||
BC_LEX_STORE_PUSH,
|
||||
|
||||
/// Print with pop command.
|
||||
BC_LEX_PRINT_POP,
|
||||
|
||||
/// Parameterized quit command.
|
||||
BC_LEX_NQUIT,
|
||||
|
||||
/// Execution stack depth command.
|
||||
BC_LEX_EXEC_STACK_LENGTH,
|
||||
|
||||
/// Scale of number command. This is needed specifically for dc because bc
|
||||
/// parses the scale function in parts.
|
||||
BC_LEX_SCALE_FACTOR,
|
||||
|
||||
/// Array length command. This is needed specifically for dc because bc
|
||||
/// just reuses its length keyword.
|
||||
BC_LEX_ARRAY_LENGTH,
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
} BcLexType;
|
||||
|
||||
struct BcLex;
|
||||
typedef void (*BcLexNext)(struct BcLex*);
|
||||
|
||||
/**
|
||||
* A function pointer to call when another token is needed. Mostly called by the
|
||||
* parser.
|
||||
* @param l The lexer.
|
||||
*/
|
||||
typedef void (*BcLexNext)(struct BcLex* l);
|
||||
|
||||
/// The lexer.
|
||||
typedef struct BcLex {
|
||||
|
||||
/// A pointer to the text to lex.
|
||||
const char *buf;
|
||||
|
||||
/// The current index into buf.
|
||||
size_t i;
|
||||
|
||||
/// The current line.
|
||||
size_t line;
|
||||
|
||||
/// The length of buf.
|
||||
size_t len;
|
||||
|
||||
/// The current token.
|
||||
BcLexType t;
|
||||
|
||||
/// The previous token.
|
||||
BcLexType last;
|
||||
|
||||
/// A string to store extra data for tokens. For example, the @a BC_LEX_STR
|
||||
/// token really needs to store the actual string, and numbers also need the
|
||||
/// 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;
|
||||
|
||||
} BcLex;
|
||||
|
||||
/**
|
||||
* Initializes a lexer.
|
||||
* @param l The lexer to initialize.
|
||||
*/
|
||||
void bc_lex_init(BcLex *l);
|
||||
|
||||
/**
|
||||
* Frees a lexer. This is not guarded by #ifndef NDEBUG because a separate
|
||||
* parser is created at runtime to parse read() expressions and dc strings, and
|
||||
* that parser needs a lexer.
|
||||
* @param l The lexer to free.
|
||||
*/
|
||||
void bc_lex_free(BcLex *l);
|
||||
|
||||
/**
|
||||
* Sets the filename that the lexer will be lexing.
|
||||
* @param l The lexer.
|
||||
* @param file The filename that the lexer will lex.
|
||||
*/
|
||||
void bc_lex_file(BcLex *l, const char *file);
|
||||
void bc_lex_text(BcLex *l, const char *text);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void bc_lex_text(BcLex *l, const char *text, bool is_stdin);
|
||||
|
||||
/**
|
||||
* Generic next function for the parser to call. It takes care of calling the
|
||||
* correct @a BcLexNext function and consuming whitespace.
|
||||
* @param l The lexer.
|
||||
*/
|
||||
void bc_lex_next(BcLex *l);
|
||||
|
||||
/**
|
||||
* Lexes a line comment (one beginning with '#' and going to a newline).
|
||||
* @param l The lexer.
|
||||
*/
|
||||
void bc_lex_lineComment(BcLex *l);
|
||||
|
||||
/**
|
||||
* Lexes a general comment (C-style comment).
|
||||
* @param l The lexer.
|
||||
*/
|
||||
void bc_lex_comment(BcLex *l);
|
||||
|
||||
/**
|
||||
* Lexes whitespace, finding as much as possible.
|
||||
* @param l The lexer.
|
||||
*/
|
||||
void bc_lex_whitespace(BcLex *l);
|
||||
|
||||
/**
|
||||
* Lexes a number that begins with char @a start. This takes care of parsing
|
||||
* numbers in scientific and engineering notations.
|
||||
* @param l The lexer.
|
||||
* @param start The starting char of the number. To detect a number and call
|
||||
* this function, the lexer had to eat the first char. It fixes
|
||||
* that by passing it in.
|
||||
*/
|
||||
void bc_lex_number(BcLex *l, char start);
|
||||
|
||||
/**
|
||||
* Lexes a name/identifier.
|
||||
* @param l The lexer.
|
||||
*/
|
||||
void bc_lex_name(BcLex *l);
|
||||
|
||||
/**
|
||||
* Lexes common whitespace characters.
|
||||
* @param l The lexer.
|
||||
* @param c The character to lex.
|
||||
*/
|
||||
void bc_lex_commonTokens(BcLex *l, char c);
|
||||
|
||||
/**
|
||||
* Throws a parse error because char @a c was invalid.
|
||||
* @param l The lexer.
|
||||
* @param c The problem character.
|
||||
*/
|
||||
void bc_lex_invalidChar(BcLex *l, char c);
|
||||
|
||||
/**
|
||||
* Reads a line from stdin and puts it into the lexer's buffer.
|
||||
* @param l The lexer.
|
||||
*/
|
||||
bool bc_lex_readLine(BcLex *l);
|
||||
|
||||
#endif // BC_LEX_H
|
||||
|
|
|
@ -40,6 +40,11 @@
|
|||
|
||||
#include <num.h>
|
||||
|
||||
/**
|
||||
* A header for functions that need to lock and setjmp(). It also sets the
|
||||
* variable that tells bcl that it is running.
|
||||
* @param l The label to jump to on error.
|
||||
*/
|
||||
#define BC_FUNC_HEADER_LOCK(l) \
|
||||
do { \
|
||||
BC_SIG_LOCK; \
|
||||
|
@ -48,6 +53,11 @@
|
|||
vm.running = 1; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A footer to unlock and stop the jumping if an error happened. It also sets
|
||||
* the variable that tells bcl that it is running.
|
||||
* @param e The error variable to set.
|
||||
*/
|
||||
#define BC_FUNC_FOOTER_UNLOCK(e) \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
|
@ -58,6 +68,10 @@
|
|||
vm.sig_lock = 0; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A header that sets a jump and sets running.
|
||||
* @param l The label to jump to on error.
|
||||
*/
|
||||
#define BC_FUNC_HEADER(l) \
|
||||
do { \
|
||||
BC_SETJMP(l); \
|
||||
|
@ -65,6 +79,11 @@
|
|||
vm.running = 1; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A header that assumes that signals are already locked. It sets a jump and
|
||||
* running.
|
||||
* @param l The label to jump to on error.
|
||||
*/
|
||||
#define BC_FUNC_HEADER_INIT(l) \
|
||||
do { \
|
||||
BC_SETJMP_LOCKED(l); \
|
||||
|
@ -72,6 +91,10 @@
|
|||
vm.running = 1; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A footer for functions that do not return an error code. It clears running
|
||||
* and unlocks the signals. It also stops the jumping.
|
||||
*/
|
||||
#define BC_FUNC_FOOTER_NO_ERR \
|
||||
do { \
|
||||
vm.running = 0; \
|
||||
|
@ -80,19 +103,25 @@
|
|||
vm.sig_lock = 0; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A footer for functions that *do* return an error code. It clears running and
|
||||
* unlocks the signals. It also stops the jumping.
|
||||
* @param e The error variable to set.
|
||||
*/
|
||||
#define BC_FUNC_FOOTER(e) \
|
||||
do { \
|
||||
e = vm.err; \
|
||||
BC_FUNC_FOOTER_NO_ERR; \
|
||||
} while (0)
|
||||
|
||||
#define BC_FUNC_RESETJMP(l) \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
BC_UNSETJMP; \
|
||||
BC_SETJMP_LOCKED(l); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A footer that sets up n based the value of e and sets up the return value in
|
||||
* idx.
|
||||
* @param c The context.
|
||||
* @param e The error.
|
||||
* @param n The number.
|
||||
* @param idx The idx to set as the return value.
|
||||
*/
|
||||
#define BC_MAYBE_SETUP(c, e, n, idx) \
|
||||
do { \
|
||||
if (BC_ERR((e) != BCL_ERROR_NONE)) { \
|
||||
|
@ -102,6 +131,11 @@
|
|||
else idx = bcl_num_insert(c, &(n)); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A header to check the context and return an error encoded in a number if it
|
||||
* is bad.
|
||||
* @param c The context.
|
||||
*/
|
||||
#define BC_CHECK_CTXT(c) \
|
||||
do { \
|
||||
c = bcl_context(); \
|
||||
|
@ -112,6 +146,11 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* A header to check the context and return an error directly if it is bad.
|
||||
* @param c The context.
|
||||
*/
|
||||
#define BC_CHECK_CTXT_ERR(c) \
|
||||
do { \
|
||||
c = bcl_context(); \
|
||||
|
@ -120,12 +159,22 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A header to check the context and abort if it is bad.
|
||||
* @param c The context.
|
||||
*/
|
||||
#define BC_CHECK_CTXT_ASSERT(c) \
|
||||
do { \
|
||||
c = bcl_context(); \
|
||||
assert(c != NULL); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A header to check the number in the context and return an error encoded as a
|
||||
* @param c The context.
|
||||
* number if it is bad.
|
||||
* @param n The BclNumber.
|
||||
*/
|
||||
#define BC_CHECK_NUM(c, n) \
|
||||
do { \
|
||||
if (BC_ERR((n).i >= (c)->nums.len)) { \
|
||||
|
@ -138,6 +187,12 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* A header to check the number in the context and return an error directly if
|
||||
* it is bad.
|
||||
* @param c The context.
|
||||
* @param n The BclNumber.
|
||||
*/
|
||||
#define BC_CHECK_NUM_ERR(c, n) \
|
||||
do { \
|
||||
if (BC_ERR((n).i >= (c)->nums.len)) { \
|
||||
|
@ -147,17 +202,36 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Turns a BclNumber into a BcNum.
|
||||
* @param c The context.
|
||||
* @param n The BclNumber.
|
||||
*/
|
||||
#define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i))
|
||||
|
||||
typedef size_t (*BcReqOp)(const BcNum*, const BcNum*, size_t);
|
||||
/**
|
||||
* Frees a BcNum for bcl. This is a destructor.
|
||||
* @param num The BcNum to free, as a void pointer.
|
||||
*/
|
||||
void bcl_num_destruct(void *num);
|
||||
|
||||
/// The actual context struct.
|
||||
typedef struct BclCtxt {
|
||||
|
||||
/// The context's scale.
|
||||
size_t scale;
|
||||
|
||||
/// The context's ibase.
|
||||
size_t ibase;
|
||||
|
||||
/// The context's obase.
|
||||
size_t obase;
|
||||
|
||||
/// A vector of BcNum numbers.
|
||||
BcVec nums;
|
||||
|
||||
/// A vector of BclNumbers. These are the indices in nums that are currently
|
||||
/// not used (because they were freed).
|
||||
BcVec free_nums;
|
||||
|
||||
} BclCtxt;
|
||||
|
|
652
include/num.h
652
include/num.h
|
@ -51,70 +51,117 @@
|
|||
#define BC_ENABLE_EXTRA_MATH (1)
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Everything in bc is base 10..
|
||||
#define BC_BASE (10)
|
||||
|
||||
/// Alias.
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/// This is here because BcBigDig came first, but when I created bcl, it's
|
||||
/// definition has to be defined first.
|
||||
typedef BclBigDig BcBigDig;
|
||||
|
||||
#if BC_LONG_BIT >= 64
|
||||
|
||||
/// The biggest number held by a BcBigDig.
|
||||
#define BC_NUM_BIGDIG_MAX ((BcBigDig) UINT64_MAX)
|
||||
|
||||
/// The number of decimal digits in one limb.
|
||||
#define BC_BASE_DIGS (9)
|
||||
|
||||
/// The max number + 1 that one limb can hold.
|
||||
#define BC_BASE_POW (1000000000)
|
||||
|
||||
/// An alias for portability.
|
||||
#define BC_NUM_BIGDIG_C UINT64_C
|
||||
|
||||
/// The actual limb type.
|
||||
typedef int_least32_t BcDig;
|
||||
|
||||
#elif BC_LONG_BIT >= 32
|
||||
|
||||
/// The biggest number held by a BcBigDig.
|
||||
#define BC_NUM_BIGDIG_MAX ((BcBigDig) UINT32_MAX)
|
||||
|
||||
/// The number of decimal digits in one limb.
|
||||
#define BC_BASE_DIGS (4)
|
||||
|
||||
/// The max number + 1 that one limb can hold.
|
||||
#define BC_BASE_POW (10000)
|
||||
|
||||
/// An alias for portability.
|
||||
#define BC_NUM_BIGDIG_C UINT32_C
|
||||
|
||||
/// The actual limb type.
|
||||
typedef int_least16_t BcDig;
|
||||
|
||||
#else
|
||||
|
||||
/// LONG_BIT must be at least 32 on POSIX. We depend on that.
|
||||
#error BC_LONG_BIT must be at least 32
|
||||
|
||||
#endif // BC_LONG_BIT >= 64
|
||||
|
||||
/// The default (and minimum) number of limbs when allocating a number.
|
||||
#define BC_NUM_DEF_SIZE (8)
|
||||
|
||||
/// The actual number struct. This is where the magic happens.
|
||||
typedef struct BcNum {
|
||||
|
||||
/// The limb array. It is restrict because *no* other item should own the
|
||||
/// array. For more information, see the development manual
|
||||
/// (manuals/development.md#numbers).
|
||||
BcDig *restrict num;
|
||||
|
||||
/// The number of limbs before the decimal (radix) point. This also stores
|
||||
/// the negative bit in the least significant bit since it uses at least two
|
||||
/// bits less than scale. It is also used less than scale. See the
|
||||
/// development manual (manuals/development.md#numbers) for more info.
|
||||
size_t rdx;
|
||||
|
||||
/// The actual scale of the number. This is different from rdx because there
|
||||
/// are multiple digits in one limb, and in the last limb, only some of the
|
||||
/// digits may be part of the scale. However, scale must always match rdx
|
||||
/// (except when the number is 0), or there is a bug. For more information,
|
||||
/// see the development manual (manuals/development.md#numbers).
|
||||
size_t scale;
|
||||
|
||||
/// The number of valid limbs in the array. If this is 0, then the number is
|
||||
/// 0 as well.
|
||||
size_t len;
|
||||
|
||||
/// The capacity of the limbs array. This is how many limbs the number could
|
||||
/// expand to without reallocation.
|
||||
size_t cap;
|
||||
|
||||
} BcNum;
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#ifndef BC_ENABLE_RAND
|
||||
#define BC_ENABLE_RAND (1)
|
||||
#endif // BC_ENABLE_RAND
|
||||
|
||||
#if BC_ENABLE_RAND
|
||||
// Forward declaration
|
||||
struct BcRNG;
|
||||
#endif // BC_ENABLE_RAND
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// The minimum obase.
|
||||
#define BC_NUM_MIN_BASE (BC_NUM_BIGDIG_C(2))
|
||||
|
||||
/// The maximum ibase allowed by POSIX.
|
||||
#define BC_NUM_MAX_POSIX_IBASE (BC_NUM_BIGDIG_C(16))
|
||||
|
||||
/// The actual ibase supported by this implementation.
|
||||
#define BC_NUM_MAX_IBASE (BC_NUM_BIGDIG_C(36))
|
||||
// This is the max base allowed by bc_num_parseChar().
|
||||
|
||||
/// The max base allowed by bc_num_parseChar().
|
||||
#define BC_NUM_MAX_LBASE (BC_NUM_BIGDIG_C('Z' + BC_BASE + 1))
|
||||
|
||||
/// The default number of characters to print before a backslash newline.
|
||||
#define BC_NUM_PRINT_WIDTH (BC_NUM_BIGDIG_C(69))
|
||||
|
||||
/// The base for printing streams from numbers.
|
||||
#define BC_NUM_STREAM_BASE (256)
|
||||
|
||||
// This sets a default for the Karatsuba length.
|
||||
#ifndef BC_NUM_KARATSUBA_LEN
|
||||
#define BC_NUM_KARATSUBA_LEN (BC_NUM_BIGDIG_C(32))
|
||||
#elif BC_NUM_KARATSUBA_LEN < 16
|
||||
|
@ -125,43 +172,183 @@ struct BcRNG;
|
|||
// the size required for ibase and obase BcNum's.
|
||||
#define BC_NUM_BIGDIG_LOG10 (BC_NUM_DEF_SIZE)
|
||||
|
||||
/**
|
||||
* Returns non-zero if the BcNum @a n is non-zero.
|
||||
* @param n The number to test.
|
||||
* @return Non-zero if @a n is non-zero, zero otherwise.
|
||||
*/
|
||||
#define BC_NUM_NONZERO(n) ((n)->len)
|
||||
|
||||
/**
|
||||
* Returns true if the BcNum @a n is zero.
|
||||
* @param n The number to test.
|
||||
* @return True if @a n is zero, false otherwise.
|
||||
*/
|
||||
#define BC_NUM_ZERO(n) (!BC_NUM_NONZERO(n))
|
||||
|
||||
/**
|
||||
* Returns true if the BcNum @a n is one with no scale.
|
||||
* @param n The number to test.
|
||||
* @return True if @a n equals 1 with no scale, false otherwise.
|
||||
*/
|
||||
#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
|
||||
|
||||
/**
|
||||
* Converts the letter @a c into a number.
|
||||
* @param c The letter to convert.
|
||||
* @return The number corresponding to the letter.
|
||||
*/
|
||||
#define BC_NUM_NUM_LETTER(c) ((c) - 'A' + BC_BASE)
|
||||
|
||||
/// The number of allocations done by bc_num_k(). If you change the number of
|
||||
/// allocations, you must change this. This is done in order to allocate them
|
||||
/// all as one allocation and just give them all pointers to different parts.
|
||||
/// Works pretty well, but you have to be careful.
|
||||
#define BC_NUM_KARATSUBA_ALLOCS (6)
|
||||
|
||||
/**
|
||||
* Rounds @a s (scale) up to the next power of BC_BASE_DIGS. This also check for
|
||||
* overflow and gives a fatal error if that happens because we just can't go
|
||||
* over the limits we have imposed.
|
||||
* @param s The scale to round up.
|
||||
* @return @a s rounded up to the next power of BC_BASE_DIGS.
|
||||
*/
|
||||
#define BC_NUM_ROUND_POW(s) (bc_vm_growSize((s), BC_BASE_DIGS - 1))
|
||||
|
||||
/**
|
||||
* Returns the equivalent rdx for the scale @a s.
|
||||
* @param s The scale to convert.
|
||||
* @return The rdx for @a s.
|
||||
*/
|
||||
#define BC_NUM_RDX(s) (BC_NUM_ROUND_POW(s) / BC_BASE_DIGS)
|
||||
|
||||
/**
|
||||
* Returns the actual rdx of @a n. (It removes the negative bit.)
|
||||
* @param n The number.
|
||||
* @return The real rdx of @a n.
|
||||
*/
|
||||
#define BC_NUM_RDX_VAL(n) ((n)->rdx >> 1)
|
||||
|
||||
/**
|
||||
* Returns the actual rdx of @a n, where @a n is not a pointer. (It removes the
|
||||
* negative bit.)
|
||||
* @param n The number.
|
||||
* @return The real rdx of @a n.
|
||||
*/
|
||||
#define BC_NUM_RDX_VAL_NP(n) ((n).rdx >> 1)
|
||||
|
||||
/**
|
||||
* Sets the rdx of @a n to @a v.
|
||||
* @param n The number.
|
||||
* @param v The value to set the rdx to.
|
||||
*/
|
||||
#define BC_NUM_RDX_SET(n, v) \
|
||||
((n)->rdx = (((v) << 1) | ((n)->rdx & (BcBigDig) 1)))
|
||||
|
||||
/**
|
||||
* Sets the rdx of @a n to @a v, where @a n is not a pointer.
|
||||
* @param n The number.
|
||||
* @param v The value to set the rdx to.
|
||||
*/
|
||||
#define BC_NUM_RDX_SET_NP(n, v) \
|
||||
((n).rdx = (((v) << 1) | ((n).rdx & (BcBigDig) 1)))
|
||||
|
||||
/**
|
||||
* Sets the rdx of @a n to @a v and the negative bit to @a neg.
|
||||
* @param n The number.
|
||||
* @param v The value to set the rdx to.
|
||||
* @param neg The value to set the negative bit to.
|
||||
*/
|
||||
#define BC_NUM_RDX_SET_NEG(n, v, neg) \
|
||||
((n)->rdx = (((v) << 1) | (neg)))
|
||||
|
||||
/**
|
||||
* Returns true if the rdx and scale for @a n match.
|
||||
* @param n The number to test.
|
||||
* @return True if the rdx and scale of @a n match, false otherwise.
|
||||
*/
|
||||
#define BC_NUM_RDX_VALID(n) \
|
||||
(BC_NUM_ZERO(n) || BC_NUM_RDX_VAL(n) * BC_BASE_DIGS >= (n)->scale)
|
||||
|
||||
/**
|
||||
* Returns true if the rdx and scale for @a n match, where @a n is not a
|
||||
* pointer.
|
||||
* @param n The number to test.
|
||||
* @return True if the rdx and scale of @a n match, false otherwise.
|
||||
*/
|
||||
#define BC_NUM_RDX_VALID_NP(n) \
|
||||
((!(n).len) || BC_NUM_RDX_VAL_NP(n) * BC_BASE_DIGS >= (n).scale)
|
||||
|
||||
/**
|
||||
* Returns true if @a n is negative, false otherwise.
|
||||
* @param n The number to test.
|
||||
* @return True if @a n is negative, false otherwise.
|
||||
*/
|
||||
#define BC_NUM_NEG(n) ((n)->rdx & ((BcBigDig) 1))
|
||||
|
||||
/**
|
||||
* Returns true if @a n is negative, false otherwise, where @a n is not a
|
||||
* pointer.
|
||||
* @param n The number to test.
|
||||
* @return True if @a n is negative, false otherwise.
|
||||
*/
|
||||
#define BC_NUM_NEG_NP(n) ((n).rdx & ((BcBigDig) 1))
|
||||
|
||||
/**
|
||||
* Clears the negative bit on @a n.
|
||||
* @param n The number.
|
||||
*/
|
||||
#define BC_NUM_NEG_CLR(n) ((n)->rdx &= ~((BcBigDig) 1))
|
||||
|
||||
/**
|
||||
* Clears the negative bit on @a n, where @a n is not a pointer.
|
||||
* @param n The number.
|
||||
*/
|
||||
#define BC_NUM_NEG_CLR_NP(n) ((n).rdx &= ~((BcBigDig) 1))
|
||||
|
||||
/**
|
||||
* Sets the negative bit on @a n.
|
||||
* @param n The number.
|
||||
*/
|
||||
#define BC_NUM_NEG_SET(n) ((n)->rdx |= ((BcBigDig) 1))
|
||||
|
||||
/**
|
||||
* Toggles the negative bit on @a n.
|
||||
* @param n The number.
|
||||
*/
|
||||
#define BC_NUM_NEG_TGL(n) ((n)->rdx ^= ((BcBigDig) 1))
|
||||
|
||||
/**
|
||||
* Toggles the negative bit on @a n, where @a n is not a pointer.
|
||||
* @param n The number.
|
||||
*/
|
||||
#define BC_NUM_NEG_TGL_NP(n) ((n).rdx ^= ((BcBigDig) 1))
|
||||
|
||||
/**
|
||||
* Returns the rdx val for @a n if the negative bit is set to @a v.
|
||||
* @param n The number.
|
||||
* @param v The value for the negative bit.
|
||||
* @return The value of the rdx of @a n if the negative bit were set to @a v.
|
||||
*/
|
||||
#define BC_NUM_NEG_VAL(n, v) (((n)->rdx & ~((BcBigDig) 1)) | (v))
|
||||
|
||||
/**
|
||||
* Returns the rdx val for @a n if the negative bit is set to @a v, where @a n
|
||||
* is not a pointer.
|
||||
* @param n The number.
|
||||
* @param v The value for the negative bit.
|
||||
* @return The value of the rdx of @a n if the negative bit were set to @a v.
|
||||
*/
|
||||
#define BC_NUM_NEG_VAL_NP(n, v) (((n).rdx & ~((BcBigDig) 1)) | (v))
|
||||
|
||||
/**
|
||||
* Returns the size, in bytes, of limb array with @a n limbs.
|
||||
* @param n The number.
|
||||
* @return The size, in bytes, of a limb array with @a n limbs.
|
||||
*/
|
||||
#define BC_NUM_SIZE(n) ((n) * sizeof(BcDig))
|
||||
|
||||
// These are for debugging only.
|
||||
#if BC_DEBUG_CODE
|
||||
#define BC_NUM_PRINT(x) fprintf(stderr, "%s = %lu\n", #x, (unsigned long)(x))
|
||||
#define DUMP_NUM bc_num_dump
|
||||
|
@ -171,94 +358,503 @@ struct BcRNG;
|
|||
#define BC_NUM_PRINT(x)
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
typedef void (*BcNumBinaryOp)(BcNum*, BcNum*, BcNum*, size_t);
|
||||
typedef void (*BcNumBinOp)(BcNum*, BcNum*, BcNum* restrict, size_t);
|
||||
typedef size_t (*BcNumBinaryOpReq)(const BcNum*, const BcNum*, size_t);
|
||||
typedef void (*BcNumDigitOp)(size_t, size_t, bool);
|
||||
typedef void (*BcNumShiftAddOp)(BcDig* restrict, const BcDig* restrict, size_t);
|
||||
/**
|
||||
* A function type for binary operators.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
typedef void (*BcNumBinaryOp)(BcNum* a, BcNum* b, BcNum* c, size_t scale);
|
||||
|
||||
/**
|
||||
* A function type for binary operators *after* @a c has been properly
|
||||
* allocated. At this point, *nothing* should be pointing to @a c (in any way
|
||||
* that matters, anyway).
|
||||
* @param a The first operand.
|
||||
* @param b The second operand.
|
||||
* @param c The return parameter.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
typedef void (*BcNumBinOp)(BcNum* a, BcNum* b, BcNum* restrict c, size_t scale);
|
||||
|
||||
/**
|
||||
* A function type for getting the allocation size needed for a binary operator.
|
||||
* Any function used for this *must* return enough space for *all* possible
|
||||
* invocations of the operator.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param scale The current scale.
|
||||
* @return The size of allocation needed for the result of the operator
|
||||
* with @a a, @a b, and @a scale.
|
||||
*/
|
||||
typedef size_t (*BcNumBinaryOpReq)(const BcNum* a, const BcNum* b,
|
||||
size_t scale);
|
||||
|
||||
/**
|
||||
* A function type for printing a "digit." Functions of this type will print one
|
||||
* digit in a number. Digits are printed differently based on the base, which is
|
||||
* why there is more than one implementation of this function type.
|
||||
* @param n The "digit" to print.
|
||||
* @param len The "length" of the digit, or number of characters that will
|
||||
* need to be printed for the digit.
|
||||
* @param rdx True if a decimal (radix) point should be printed.
|
||||
* @param bslash True if a backslash+newline should be printed if the character
|
||||
* limit for the line is reached, false otherwise.
|
||||
*/
|
||||
typedef void (*BcNumDigitOp)(size_t n, size_t len, bool rdx, bool bslash);
|
||||
|
||||
/**
|
||||
* A function type to run an operator on @a a and @a b and store the result in
|
||||
* @a a. This is used in karatsuba for faster adds and subtracts at the end.
|
||||
* @param a The first parameter and return value.
|
||||
* @param b The second parameter.
|
||||
* @param len The minimum length of both arrays.
|
||||
*/
|
||||
typedef void (*BcNumShiftAddOp)(BcDig* restrict a, const BcDig* restrict b,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* Initializes @a n with @a req limbs in its array.
|
||||
* @param n The number to initialize.
|
||||
* @param req The number of limbs @a n must have in its limb array.
|
||||
*/
|
||||
void bc_num_init(BcNum *restrict n, size_t req);
|
||||
|
||||
/**
|
||||
* Initializes (sets up) @a n with the preallocated limb array @a num that has
|
||||
* size @a cap. This is called by @a bc_num_init(), but it is also used by parts
|
||||
* of bc that use statically allocated limb arrays.
|
||||
* @param n The number to initialize.
|
||||
* @param num The preallocated limb array.
|
||||
* @param cap The capacity of @a num.
|
||||
*/
|
||||
void bc_num_setup(BcNum *restrict n, BcDig *restrict num, size_t cap);
|
||||
|
||||
/**
|
||||
* Copies @a s into @a d. This does a deep copy and requires that @a d is
|
||||
* already a valid and allocated BcNum.
|
||||
* @param d The destination BcNum.
|
||||
* @param s The source BcNum.
|
||||
*/
|
||||
void bc_num_copy(BcNum *d, const BcNum *s);
|
||||
|
||||
/**
|
||||
* Creates @a d and copies @a s into @a d. This does a deep copy and requires
|
||||
* that @a d is *not* a valid or allocated BcNum.
|
||||
* @param d The destination BcNum.
|
||||
* @param s The source BcNum.
|
||||
*/
|
||||
void bc_num_createCopy(BcNum *d, const BcNum *s);
|
||||
void bc_num_createFromBigdig(BcNum *n, BcBigDig val);
|
||||
|
||||
/**
|
||||
* Creates (initializes) @a n and sets its value to the equivalent of @a val.
|
||||
* @a n must *not* be a valid or preallocated BcNum.
|
||||
* @param n The number to initialize and set.
|
||||
* @param val The value to set @a n's value to.
|
||||
*/
|
||||
void bc_num_createFromBigdig(BcNum *restrict n, BcBigDig val);
|
||||
|
||||
/**
|
||||
* Makes @a n valid for holding strings. @a n must *not* be allocated; this
|
||||
* simply clears some fields, including setting the num field to NULL.
|
||||
* @param n The number to clear.
|
||||
*/
|
||||
void bc_num_clear(BcNum *restrict n);
|
||||
|
||||
/**
|
||||
* Frees @a num, which is a BcNum as a void pointer. This is a destructor.
|
||||
* @param num The BcNum to free as a void pointer.
|
||||
*/
|
||||
void bc_num_free(void *num);
|
||||
|
||||
/**
|
||||
* Returns the scale of @a n.
|
||||
* @param n The number.
|
||||
* @return The scale of @a n.
|
||||
*/
|
||||
size_t bc_num_scale(const BcNum *restrict n);
|
||||
|
||||
/**
|
||||
* Returns the length (in decimal digits) of @a n. This is complicated. First,
|
||||
* if the number is zero, we always return at least one, but we also return the
|
||||
* scale if it exists. Then, If it is not zero, it opens a whole other can of
|
||||
* worms. Read the comments in the definition.
|
||||
* @param n The number.
|
||||
* @return The length of @a n.
|
||||
*/
|
||||
size_t bc_num_len(const BcNum *restrict n);
|
||||
|
||||
void bc_num_bigdig(const BcNum *restrict n, BcBigDig *result);
|
||||
void bc_num_bigdig2(const BcNum *restrict n, BcBigDig *result);
|
||||
/**
|
||||
* Convert a number to a BcBigDig (hardware integer). This version does error
|
||||
* checking, and if it finds an error, throws it. Otherwise, it calls
|
||||
* bc_num_bigdig2().
|
||||
* @param n The number to convert.
|
||||
* @return The number as a hardware integer.
|
||||
*/
|
||||
BcBigDig bc_num_bigdig(const BcNum *restrict n);
|
||||
|
||||
/**
|
||||
* Convert a number to a BcBigDig (hardware integer). This version does no error
|
||||
* checking.
|
||||
* @param n The number to convert.
|
||||
* @return The number as a hardware integer.
|
||||
*/
|
||||
BcBigDig bc_num_bigdig2(const BcNum *restrict n);
|
||||
|
||||
/**
|
||||
* Sets @a n to the value of @a val. @a n is expected to be a valid and
|
||||
* allocated BcNum.
|
||||
* @param n The number to set.
|
||||
* @param val The value to set the number to.
|
||||
*/
|
||||
void bc_num_bigdig2num(BcNum *restrict n, BcBigDig val);
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
void bc_num_irand(const BcNum *restrict a, BcNum *restrict b,
|
||||
struct BcRNG *restrict rng);
|
||||
void bc_num_rng(const BcNum *restrict n, struct BcRNG *rng);
|
||||
void bc_num_createFromRNG(BcNum *restrict n, struct BcRNG *rng);
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* Generates a random arbitrary-size integer less than or equal to @a a and
|
||||
* returns it in @a b. This implements irand().
|
||||
* @param a The limit for the integer to generate.
|
||||
* @param b The return value.
|
||||
* @param rng The pseudo-random number generator.
|
||||
*/
|
||||
void bc_num_irand(BcNum *restrict a, BcNum *restrict b,
|
||||
struct BcRNG *restrict rng);
|
||||
|
||||
/**
|
||||
* Sets the seed for the PRNG @a rng from @a n.
|
||||
* @param n The new seed for the PRNG.
|
||||
* @param rng The PRNG to set the seed for.
|
||||
*/
|
||||
void bc_num_rng(const BcNum *restrict n, struct BcRNG *rng);
|
||||
|
||||
/**
|
||||
* Sets @a n to the value produced by the PRNG. This implements rand().
|
||||
* @param n The number to set.
|
||||
* @param rng The pseudo-random number generator.
|
||||
*/
|
||||
void bc_num_createFromRNG(BcNum *restrict n, struct BcRNG *rng);
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* The add function. This is a BcNumBinaryOp function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
/**
|
||||
* The subtract function. This is a BcNumBinaryOp function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
/**
|
||||
* The multiply function.
|
||||
* @param a The first parameter. This is a BcNumBinaryOp function.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
/**
|
||||
* The division function.
|
||||
* @param a The first parameter. This is a BcNumBinaryOp function.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
/**
|
||||
* The modulus function.
|
||||
* @param a The first parameter. This is a BcNumBinaryOp function.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
/**
|
||||
* The power function.
|
||||
* @param a The first parameter. This is a BcNumBinaryOp function.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* The places function (@ operator). This is a BcNumBinaryOp function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_places(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
/**
|
||||
* The left shift function (<< operator). This is a BcNumBinaryOp function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_lshift(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
/**
|
||||
* The right shift function (>> operator). This is a BcNumBinaryOp function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_rshift(BcNum *a, BcNum *b, BcNum *c, size_t scale);
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* Square root.
|
||||
* @param a The first parameter.
|
||||
* @param b The return value.
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_sqrt(BcNum *restrict a, BcNum *restrict b, size_t scale);
|
||||
void bc_num_sr(BcNum *restrict a, BcNum *restrict b, size_t scale);
|
||||
|
||||
/**
|
||||
* Divsion and modulus together. This is a dc extension.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The first return value (quotient).
|
||||
* @param d The second return value (modulus).
|
||||
* @param scale The current scale.
|
||||
*/
|
||||
void bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale);
|
||||
|
||||
/**
|
||||
* A function returning the required allocation size for an addition or a
|
||||
* subtraction. This is a BcNumBinaryOpReq function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param scale The current scale.
|
||||
* @return The size of allocation needed for the result of add or subtract
|
||||
* with @a a, @a b, and @a scale.
|
||||
*/
|
||||
size_t bc_num_addReq(const BcNum* a, const BcNum* b, size_t scale);
|
||||
|
||||
/**
|
||||
* A function returning the required allocation size for a multiplication. This
|
||||
* is a BcNumBinaryOpReq function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param scale The current scale.
|
||||
* @return The size of allocation needed for the result of multiplication
|
||||
* with @a a, @a b, and @a scale.
|
||||
*/
|
||||
size_t bc_num_mulReq(const BcNum *a, const BcNum *b, size_t scale);
|
||||
|
||||
/**
|
||||
* A function returning the required allocation size for a division or modulus.
|
||||
* This is a BcNumBinaryOpReq function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param scale The current scale.
|
||||
* @return The size of allocation needed for the result of division or
|
||||
* modulus with @a a, @a b, and @a scale.
|
||||
*/
|
||||
size_t bc_num_divReq(const BcNum *a, const BcNum *b, size_t scale);
|
||||
|
||||
/**
|
||||
* A function returning the required allocation size for an exponentiation. This
|
||||
* is a BcNumBinaryOpReq function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param scale The current scale.
|
||||
* @return The size of allocation needed for the result of exponentiation
|
||||
* with @a a, @a b, and @a scale.
|
||||
*/
|
||||
size_t bc_num_powReq(const BcNum *a, const BcNum *b, size_t scale);
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* A function returning the required allocation size for a places, left shift,
|
||||
* or right shift. This is a BcNumBinaryOpReq function.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param scale The current scale.
|
||||
* @return The size of allocation needed for the result of places, left
|
||||
* shift, or right shift with @a a, @a b, and @a scale.
|
||||
*/
|
||||
size_t bc_num_placesReq(const BcNum *a, const BcNum *b, size_t scale);
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* Truncate @a n *by* @a places decimal places. This only extends places *after*
|
||||
* the decimal point.
|
||||
* @param n The number to truncate.
|
||||
* @param places The number of places to truncate @a n by.
|
||||
*/
|
||||
void bc_num_truncate(BcNum *restrict n, size_t places);
|
||||
|
||||
/**
|
||||
* Extend @a n *by* @a places decimal places. This only extends places *after*
|
||||
* the decimal point.
|
||||
* @param n The number to truncate.
|
||||
* @param places The number of places to extend @a n by.
|
||||
*/
|
||||
void bc_num_extend(BcNum *restrict n, size_t places);
|
||||
|
||||
/**
|
||||
* Shifts @a n right by @a places decimal places. This is the workhorse of the
|
||||
* right shift operator, and would be static to src/num.c, except that
|
||||
* src/library.c uses it for efficiency when executing its frand.
|
||||
* @param n The number to shift right.
|
||||
* @param places The number of decimal places to shift @a n right by.
|
||||
*/
|
||||
void bc_num_shiftRight(BcNum *restrict n, size_t places);
|
||||
|
||||
/**
|
||||
* Compare a and b and return the result of their comparison as an ssize_t.
|
||||
* Returns >0 if @a a is greater than @a b, <0 if @a a is less than @a b, and =0
|
||||
* if a == b.
|
||||
* @param a The first number.
|
||||
* @param b The second number.
|
||||
* @return The result of the comparison.
|
||||
*/
|
||||
ssize_t bc_num_cmp(const BcNum *a, const BcNum *b);
|
||||
|
||||
#if DC_ENABLED
|
||||
/**
|
||||
* Modular exponentiation.
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The third parameter.
|
||||
* @param d The return value.
|
||||
*/
|
||||
void bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d);
|
||||
#endif // DC_ENABLED
|
||||
|
||||
/**
|
||||
* Sets @a n to zero with a scale of zero.
|
||||
* @param n The number to zero.
|
||||
*/
|
||||
void bc_num_zero(BcNum *restrict n);
|
||||
|
||||
/**
|
||||
* Sets @a n to one with a scale of zero.
|
||||
* @param n The number to set to one.
|
||||
*/
|
||||
void bc_num_one(BcNum *restrict n);
|
||||
|
||||
/**
|
||||
* An efficient function to compare @a n to zero.
|
||||
* @param n The number to compare to zero.
|
||||
* @return The result of the comparison.
|
||||
*/
|
||||
ssize_t bc_num_cmpZero(const BcNum *n);
|
||||
|
||||
#if !defined(NDEBUG) || BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Check a number string for validity and return true if it is, false otherwise.
|
||||
* The library needs this to check user-supplied strings, but in bc and dc, this
|
||||
* is only used for debug asserts because the parsers should get the numbers
|
||||
* parsed right, which should ensure they are always valid.
|
||||
* @param val The string to check.
|
||||
* @return True if the string is a valid number, false otherwise.
|
||||
*/
|
||||
bool bc_num_strValid(const char *restrict val);
|
||||
|
||||
#endif // !defined(NDEBUG) || BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Parses a number string into the number @a n according to @a base.
|
||||
* @param n The number to set to the parsed value.
|
||||
* @param val The number string to parse.
|
||||
* @param base The base to parse the number string by.
|
||||
*/
|
||||
void bc_num_parse(BcNum *restrict n, const char *restrict val, BcBigDig base);
|
||||
|
||||
/**
|
||||
* Prints the number @a n according to @a base.
|
||||
* @param n The number to print.
|
||||
* @param base The base to print the number by.
|
||||
* @param newline True if a newline should be inserted at the end, false
|
||||
* otherwise.
|
||||
*/
|
||||
void bc_num_print(BcNum *restrict n, BcBigDig base, bool newline);
|
||||
#if DC_ENABLED
|
||||
void bc_num_stream(BcNum *restrict n, BcBigDig base);
|
||||
#endif // DC_ENABLED
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Prints a number as a character stream.
|
||||
* @param n The number to print as a character stream.
|
||||
*/
|
||||
void bc_num_stream(BcNum *restrict n);
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
|
||||
/**
|
||||
* Print a number with a label. This is a debug-only function.
|
||||
* @param n The number to print.
|
||||
* @param name The label to print the number with.
|
||||
* @param emptyline True if there should be an empty line after the number.
|
||||
*/
|
||||
void bc_num_printDebug(const BcNum *n, const char *name, bool emptyline);
|
||||
|
||||
/**
|
||||
* Print the limbs of @a n. This is a debug-only function.
|
||||
* @param n The number to print.
|
||||
* @param len The length of the number.
|
||||
* @param emptyline True if there should be an empty line after the number.
|
||||
*/
|
||||
void bc_num_printDigs(const BcDig* n, size_t len, bool emptyline);
|
||||
|
||||
/**
|
||||
* Print debug info about @a n along with its limbs.
|
||||
* @param n The number to print.
|
||||
* @param name The label to print the number with.
|
||||
* @param emptyline True if there should be an empty line after the number.
|
||||
*/
|
||||
void bc_num_printWithDigs(const BcNum *n, const char *name, bool emptyline);
|
||||
|
||||
/**
|
||||
* Dump debug info about a BcNum variable.
|
||||
* @param varname The variable name.
|
||||
* @param n The number.
|
||||
*/
|
||||
void bc_num_dump(const char *varname, const BcNum *n);
|
||||
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
/// A reference to an array of hex digits for easy conversion for printing.
|
||||
extern const char bc_num_hex_digits[];
|
||||
|
||||
/// An array of powers of 10 for easy conversion from number of digits to
|
||||
//powers.
|
||||
extern const BcBigDig bc_num_pow10[BC_BASE_DIGS + 1];
|
||||
|
||||
/// A reference to a constant array that is the max of a BigDig.
|
||||
extern const BcDig bc_num_bigdigMax[];
|
||||
extern const BcDig bc_num_bigdigMax2[];
|
||||
|
||||
/// A reference to a constant size of the above array.
|
||||
extern const size_t bc_num_bigdigMax_size;
|
||||
|
||||
/// A reference to a constant array that is 2 times the max of a BigDig.
|
||||
extern const BcDig bc_num_bigdigMax2[];
|
||||
|
||||
/// A reference to a constant size of the above array.
|
||||
extern const size_t bc_num_bigdigMax2_size;
|
||||
|
||||
#endif // BC_NUM_H
|
||||
|
|
|
@ -41,38 +41,99 @@
|
|||
#define BC_OPT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/// The data required to parse command-line arguments.
|
||||
typedef struct BcOpt {
|
||||
|
||||
/// The array of arguments.
|
||||
char **argv;
|
||||
|
||||
/// The index of the current argument.
|
||||
size_t optind;
|
||||
|
||||
/// The actual parse option character.
|
||||
int optopt;
|
||||
|
||||
/// Where in the option we are for multi-character single-character options.
|
||||
int subopt;
|
||||
|
||||
/// The option argument.
|
||||
char *optarg;
|
||||
|
||||
} BcOpt;
|
||||
|
||||
/// The types of arguments. This is specially adapted for bc.
|
||||
typedef enum BcOptType {
|
||||
|
||||
/// No argument required.
|
||||
BC_OPT_NONE,
|
||||
|
||||
/// An argument required.
|
||||
BC_OPT_REQUIRED,
|
||||
|
||||
/// An option that is bc-only.
|
||||
BC_OPT_BC_ONLY,
|
||||
|
||||
/// An option that is bc-only that requires an argument.
|
||||
BC_OPT_REQUIRED_BC_ONLY,
|
||||
|
||||
/// An option that is dc-only.
|
||||
BC_OPT_DC_ONLY,
|
||||
|
||||
} BcOptType;
|
||||
|
||||
/// A struct to hold const data for long options.
|
||||
typedef struct BcOptLong {
|
||||
|
||||
/// The name of the option.
|
||||
const char *name;
|
||||
|
||||
/// The type of the option.
|
||||
BcOptType type;
|
||||
|
||||
/// The character to return if the long option was parsed.
|
||||
int val;
|
||||
|
||||
} BcOptLong;
|
||||
|
||||
/**
|
||||
* Initialize data for parsing options.
|
||||
* @param o The option data to initialize.
|
||||
* @param argv The array of arguments.
|
||||
*/
|
||||
void bc_opt_init(BcOpt *o, char **argv);
|
||||
|
||||
/**
|
||||
* Parse an option. This returns a value the same way getopt() and getopt_long()
|
||||
* do, so it returns a character for the parsed option or -1 if done.
|
||||
* @param o The option data.
|
||||
* @param longopts The long options.
|
||||
* @return A character for the parsed option, or -1 if done.
|
||||
*/
|
||||
int bc_opt_parse(BcOpt *o, const BcOptLong *longopts);
|
||||
|
||||
/**
|
||||
* Returns true if the option is `--` and not a long option.
|
||||
* @param a The argument to parse.
|
||||
* @return True if @a a is the `--` option, false otherwise.
|
||||
*/
|
||||
#define BC_OPT_ISDASHDASH(a) \
|
||||
((a) != NULL && (a)[0] == '-' && (a)[1] == '-' && (a)[2] == '\0')
|
||||
|
||||
/**
|
||||
* Returns true if the option is a short option.
|
||||
* @param a The argument to parse.
|
||||
* @return True if @a a is a short option, false otherwise.
|
||||
*/
|
||||
#define BC_OPT_ISSHORTOPT(a) \
|
||||
((a) != NULL && (a)[0] == '-' && (a)[1] != '-' && (a)[1] != '\0')
|
||||
|
||||
/**
|
||||
* Returns true if the option has `--` at the beginning, i.e., is a long option.
|
||||
* @param a The argument to parse.
|
||||
* @return True if @a a is a long option, false otherwise.
|
||||
*/
|
||||
#define BC_OPT_ISLONGOPT(a) \
|
||||
((a) != NULL && (a)[0] == '-' && (a)[1] == '-' && (a)[2] != '\0')
|
||||
|
||||
|
|
188
include/parse.h
188
include/parse.h
|
@ -45,72 +45,230 @@
|
|||
#include <lex.h>
|
||||
#include <lang.h>
|
||||
|
||||
// The following are flags that can be passed to @a BcParseExpr functions. They
|
||||
// define the requirements that the parsed expression must meet to not have an
|
||||
// error thrown.
|
||||
|
||||
/// A flag that requires that the expression is valid for conditionals in for
|
||||
/// loops, while loops, and if statements. This is because POSIX requires that
|
||||
/// certain operators are *only* used in those cases. It's whacked, but that's
|
||||
/// how it is.
|
||||
#define BC_PARSE_REL (UINTMAX_C(1)<<0)
|
||||
|
||||
/// A flag that requires that the expression is valid for a print statement.
|
||||
#define BC_PARSE_PRINT (UINTMAX_C(1)<<1)
|
||||
|
||||
/// A flag that requires that the expression does *not* have any function call.
|
||||
#define BC_PARSE_NOCALL (UINTMAX_C(1)<<2)
|
||||
|
||||
/// A flag that requires that the expression does *not* have a read() expression.
|
||||
#define BC_PARSE_NOREAD (UINTMAX_C(1)<<3)
|
||||
|
||||
/// A flag that *allows* (rather than requires) that an array appear in the
|
||||
/// expression. This is mostly used as parameters in bc.
|
||||
#define BC_PARSE_ARRAY (UINTMAX_C(1)<<4)
|
||||
|
||||
/// A flag that requires that the expression is not empty and returns a value.
|
||||
#define BC_PARSE_NEEDVAL (UINTMAX_C(1)<<5)
|
||||
|
||||
/**
|
||||
* Returns true if the parser has been initialized.
|
||||
* @param p The parser.
|
||||
* @param prg The program.
|
||||
* @return True if @a p has been initialized, false otherwise.
|
||||
*/
|
||||
#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.
|
||||
* @return True if parsing can proceed, false otherwise.
|
||||
*/
|
||||
#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.
|
||||
* @param p The parser.
|
||||
* @param i The instruction to push onto the bytecode vector.
|
||||
*/
|
||||
#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (uchar) (i)))
|
||||
|
||||
/**
|
||||
* Pushes an index onto the bytecode vector. For more information, see
|
||||
* @a bc_vec_pushIndex() in src/vector.c and @a bc_program_index() in
|
||||
* src/program.c.
|
||||
* @param p The parser.
|
||||
* @param idx The index to push onto the bytecode vector.
|
||||
*/
|
||||
#define bc_parse_pushIndex(p, idx) (bc_vec_pushIndex(&(p)->func->code, (idx)))
|
||||
|
||||
/**
|
||||
* A convenience macro for throwing errors in parse code. They take care of
|
||||
* plumbing like passing in the current line the lexer is on.
|
||||
* @param p The parser.
|
||||
* @param e The error.
|
||||
*/
|
||||
#define bc_parse_err(p, e) (bc_vm_handleError((e), (p)->l.line))
|
||||
|
||||
/**
|
||||
* A convenience macro for throwing errors in parse code. They take care of
|
||||
* plumbing like passing in the current line the lexer is on.
|
||||
* @param p The parser.
|
||||
* @param e The error.
|
||||
* @param ... The varags that are needed.
|
||||
*/
|
||||
#define bc_parse_verr(p, e, ...) \
|
||||
(bc_vm_handleError((e), (p)->l.line, __VA_ARGS__))
|
||||
|
||||
typedef struct BcParseNext {
|
||||
uchar len;
|
||||
uchar tokens[4];
|
||||
} BcParseNext;
|
||||
|
||||
#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
|
||||
#define BC_PARSE_NEXT(a, ...) \
|
||||
{ .len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) }
|
||||
|
||||
// Forward declarations.
|
||||
struct BcParse;
|
||||
struct BcProgram;
|
||||
|
||||
typedef void (*BcParseParse)(struct BcParse*);
|
||||
typedef void (*BcParseExpr)(struct BcParse*, uint8_t);
|
||||
/**
|
||||
* A function pointer to call when more parsing is needed.
|
||||
* @param p The parser.
|
||||
*/
|
||||
typedef void (*BcParseParse)(struct BcParse* p);
|
||||
|
||||
/**
|
||||
* A function pointer to call when an expression needs to be parsed. This can
|
||||
* happen for read() expressions or dc strings.
|
||||
* @param p The parser.
|
||||
* @param flags The flags for what is allowed or required. (See flags above.)
|
||||
*/
|
||||
typedef void (*BcParseExpr)(struct BcParse* p, uint8_t flags);
|
||||
|
||||
/// The parser struct.
|
||||
typedef struct BcParse {
|
||||
|
||||
/// The lexer.
|
||||
BcLex l;
|
||||
|
||||
#if BC_ENABLED
|
||||
/// The stack of flags for bc. (See comments in include/bc.h.) This stack is
|
||||
/// *required* to have one item at all times. Not maintaining that invariant
|
||||
/// will cause problems.
|
||||
BcVec flags;
|
||||
|
||||
/// The stack of exits. These are indices into the bytecode vector where
|
||||
/// blocks for loops and if statements end. Basically, these are the places
|
||||
/// to jump to when skipping code.
|
||||
BcVec exits;
|
||||
|
||||
/// The stack of conditionals. Unlike exits, which are indices to jump
|
||||
/// *forward* to, this is a vector of indices to jump *backward* to, usually
|
||||
/// to the conditional of a loop, hence the name.
|
||||
BcVec conds;
|
||||
|
||||
/// A stack of operators. When parsing expressions, the bc parser uses the
|
||||
/// Shunting-Yard algorithm, which requires a stack of operators. This can
|
||||
/// hold the stack for multiple expressions at once because the expressions
|
||||
/// stack as well. For more information, see the Expression Parsing section
|
||||
/// of the Development manual (manuals/development.md).
|
||||
BcVec ops;
|
||||
|
||||
/// A buffer to temporarily store a string in. This is because the lexer
|
||||
/// might generate a string as part of its work, and the parser needs that
|
||||
/// string, but it also needs the lexer to continue lexing, which might
|
||||
/// overwrite the string stored in the lexer. This buffer is for copying
|
||||
/// that string from the lexer to keep it safe.
|
||||
BcVec buf;
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// A reference to the program to grab the current function when necessary.
|
||||
struct BcProgram *prog;
|
||||
|
||||
/// A reference to the current function. The function is what holds the
|
||||
/// bytecode vector that the parser is filling.
|
||||
BcFunc *func;
|
||||
|
||||
/// The index of the function.
|
||||
size_t fidx;
|
||||
|
||||
#if BC_ENABLED
|
||||
/// True if the bc parser just entered a function and an auto statement
|
||||
/// would be valid.
|
||||
bool auto_part;
|
||||
#endif // BC_ENABLED
|
||||
|
||||
} BcParse;
|
||||
|
||||
/**
|
||||
* Initializes a parser.
|
||||
* @param p The parser to initialize.
|
||||
* @param prog A referenc to the program.
|
||||
* @param func The index of the current function.
|
||||
*/
|
||||
void bc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
|
||||
|
||||
/**
|
||||
* Frees a parser. This is not guarded by #ifndef NDEBUG because a separate
|
||||
* parser is created at runtime to parse read() expressions and dc strings.
|
||||
* @param p The parser to free.
|
||||
*/
|
||||
void bc_parse_free(BcParse *p);
|
||||
|
||||
/**
|
||||
* Resets the parser. Resetting means erasing all state to the point that the
|
||||
* parser would think it was just initialized.
|
||||
* @param p The parser to reset.
|
||||
*/
|
||||
void bc_parse_reset(BcParse *p);
|
||||
|
||||
/**
|
||||
* Adds a string. See @a BcProgram in include/program.h for more details.
|
||||
* @param p The parser that parsed the string.
|
||||
*/
|
||||
void bc_parse_addString(BcParse *p);
|
||||
void bc_parse_number(BcParse *p);
|
||||
void bc_parse_updateFunc(BcParse *p, size_t fidx);
|
||||
void bc_parse_pushName(const BcParse* p, char *name, bool var);
|
||||
void bc_parse_text(BcParse *p, const char *text);
|
||||
|
||||
/**
|
||||
* Adds a number. See @a BcProgram in include/program.h for more details.
|
||||
* @param p The parser that parsed the number.
|
||||
*/
|
||||
void bc_parse_number(BcParse *p);
|
||||
|
||||
/**
|
||||
* Update the current function in the parser.
|
||||
* @param p The parser.
|
||||
* @param fidx The index of the new function.
|
||||
*/
|
||||
void bc_parse_updateFunc(BcParse *p, size_t fidx);
|
||||
|
||||
/**
|
||||
* Adds a new variable or array. See @a BcProgram in include/program.h for more
|
||||
* details.
|
||||
* @param p The parser that parsed the variable or array name.
|
||||
* @param name The name of the variable or array to add.
|
||||
* @param var True if the name is for a variable, false if it's for an array.
|
||||
*/
|
||||
void 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.
|
||||
*/
|
||||
void bc_parse_text(BcParse *p, const char *text, bool is_stdin);
|
||||
|
||||
// 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
|
||||
// case of 1), increment/decrement operators.
|
||||
extern const char bc_parse_zero[2];
|
||||
extern const char bc_parse_one[2];
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#ifndef BC_PROGRAM_H
|
||||
#define BC_PROGRAM_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <status.h>
|
||||
|
@ -44,144 +45,911 @@
|
|||
#include <num.h>
|
||||
#include <rand.h>
|
||||
|
||||
/// The index of ibase in the globals array.
|
||||
#define BC_PROG_GLOBALS_IBASE (0)
|
||||
|
||||
/// The index of obase in the globals array.
|
||||
#define BC_PROG_GLOBALS_OBASE (1)
|
||||
|
||||
/// The index of scale in the globals array.
|
||||
#define BC_PROG_GLOBALS_SCALE (2)
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// The index of the rand max in the maxes array.
|
||||
#define BC_PROG_MAX_RAND (3)
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// The length of the globals array.
|
||||
#define BC_PROG_GLOBALS_LEN (3 + BC_ENABLE_EXTRA_MATH)
|
||||
|
||||
#define BC_PROG_ONE_CAP (1)
|
||||
|
||||
typedef struct BcProgram {
|
||||
|
||||
/// The array of globals values.
|
||||
BcBigDig globals[BC_PROG_GLOBALS_LEN];
|
||||
|
||||
/// The array of globals stacks.
|
||||
BcVec globals_v[BC_PROG_GLOBALS_LEN];
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
BcRNG rng;
|
||||
#endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// The pseudo-random number generator.
|
||||
BcRNG rng;
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// The results stack.
|
||||
BcVec results;
|
||||
|
||||
/// The execution stack.
|
||||
BcVec stack;
|
||||
|
||||
/// A pointer to the current function's constants.
|
||||
BcVec *consts;
|
||||
|
||||
/// A pointer to the current function's strings.
|
||||
BcVec *strs;
|
||||
|
||||
/// The array of functions.
|
||||
BcVec fns;
|
||||
|
||||
/// The map of functions to go with fns.
|
||||
BcVec fn_map;
|
||||
|
||||
/// The array of variables.
|
||||
BcVec vars;
|
||||
|
||||
/// The map of variables to go with vars.
|
||||
BcVec var_map;
|
||||
|
||||
/// The array of arrays.
|
||||
BcVec arrs;
|
||||
|
||||
/// The map of arrays to go with arrs.
|
||||
BcVec arr_map;
|
||||
|
||||
#if DC_ENABLED
|
||||
BcVec strs_v;
|
||||
|
||||
/// A vector of tail calls. These are just integers, which are the number of
|
||||
/// tail calls that have been executed for each function (string) on the
|
||||
/// stack for dc. This is to prevent dc from constantly growing memory use
|
||||
/// because of pushing more and more string executions on the stack.
|
||||
BcVec tail_calls;
|
||||
|
||||
BcBigDig strm;
|
||||
BcNum strmb;
|
||||
#endif // DC_ENABLED
|
||||
|
||||
BcNum zero;
|
||||
BcNum one;
|
||||
/// A BcNum that has the proper base for asciify.
|
||||
BcNum strmb;
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// The last printed value for bc.
|
||||
BcNum last;
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#if DC_ENABLED
|
||||
// This uses BC_NUM_LONG_LOG10 because it is used in bc_num_ulong2num(),
|
||||
// which attempts to realloc, unless it is big enough. This is big enough.
|
||||
// The BcDig array for strmb. This uses BC_NUM_LONG_LOG10 because it is used
|
||||
// in bc_num_ulong2num(), which attempts to realloc, unless it is big
|
||||
// enough. This is big enough.
|
||||
BcDig strmb_num[BC_NUM_BIGDIG_LOG10];
|
||||
#endif // DC_ENABLED
|
||||
|
||||
BcDig zero_num[BC_PROG_ONE_CAP];
|
||||
BcDig one_num[BC_PROG_ONE_CAP];
|
||||
|
||||
} BcProgram;
|
||||
|
||||
/**
|
||||
* Returns true if the stack @a s has at least @a n items, false otherwise.
|
||||
* @param s The stack to check.
|
||||
* @param n The number of items the stack must have.
|
||||
* @return True if @a s has at least @a n items, false otherwise.
|
||||
*/
|
||||
#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) (n)))
|
||||
|
||||
/**
|
||||
* Get a pointer to the top value in a global value stack.
|
||||
* @param v The global value stack.
|
||||
* @return A pointer to the top value in @a v.
|
||||
*/
|
||||
#define BC_PROG_GLOBAL_PTR(v) (bc_vec_top(v))
|
||||
|
||||
/**
|
||||
* Get the top value in a global value stack.
|
||||
* @param v The global value stack.
|
||||
* @return The top value in @a v.
|
||||
*/
|
||||
#define BC_PROG_GLOBAL(v) (*((BcBigDig*) BC_PROG_GLOBAL_PTR(v)))
|
||||
|
||||
/**
|
||||
* Returns the current value of ibase.
|
||||
* @param p The program.
|
||||
* @return The current ibase.
|
||||
*/
|
||||
#define BC_PROG_IBASE(p) ((p)->globals[BC_PROG_GLOBALS_IBASE])
|
||||
|
||||
/**
|
||||
* Returns the current value of obase.
|
||||
* @param p The program.
|
||||
* @return The current obase.
|
||||
*/
|
||||
#define BC_PROG_OBASE(p) ((p)->globals[BC_PROG_GLOBALS_OBASE])
|
||||
|
||||
/**
|
||||
* Returns the current value of scale.
|
||||
* @param p The program.
|
||||
* @return The current scale.
|
||||
*/
|
||||
#define BC_PROG_SCALE(p) ((p)->globals[BC_PROG_GLOBALS_SCALE])
|
||||
|
||||
/// The index for the main function in the functions array.//
|
||||
#define BC_PROG_MAIN (0)
|
||||
|
||||
/// The index for the read function in the functions array.
|
||||
#define BC_PROG_READ (1)
|
||||
|
||||
/**
|
||||
* Retires (completes the execution of) an instruction. Some instructions
|
||||
* require special retirement, but most can use this. This basically pops the
|
||||
* operands while preserving the result (which we assumed was pushed before the
|
||||
* actual operation).
|
||||
* @param p The program.
|
||||
* @param nres The number of results returned by the instruction.
|
||||
* @param nops The number of operands used by the instruction.
|
||||
*/
|
||||
#define bc_program_retire(p, nres, nops) \
|
||||
(bc_vec_npopAt(&(p)->results, (nops), (p)->results.len - (nres + nops)))
|
||||
|
||||
#if DC_ENABLED
|
||||
|
||||
/// A constant that tells how many functions are required in dc.
|
||||
#define BC_PROG_REQ_FUNCS (2)
|
||||
|
||||
#if !BC_ENABLED
|
||||
// For dc only, last is always true.
|
||||
|
||||
/// This define disappears the parameter last because for dc only, last is
|
||||
/// always true.
|
||||
#define bc_program_copyToVar(p, name, t, last) \
|
||||
bc_program_copyToVar(p, name, t)
|
||||
|
||||
#endif // !BC_ENABLED
|
||||
|
||||
#else // DC_ENABLED
|
||||
// For bc, 'pop' and 'copy' are always false.
|
||||
|
||||
/// This define disappears pop and copy because for bc, 'pop' and 'copy' are
|
||||
/// always false.
|
||||
#define bc_program_pushVar(p, code, bgn, pop, copy) \
|
||||
bc_program_pushVar(p, code, bgn)
|
||||
|
||||
// In debug mode, we want bc to check the stack, but otherwise, we don't because
|
||||
// the bc language implicitly mandates that the stack should always have enough
|
||||
// items.
|
||||
#ifdef NDEBUG
|
||||
#define BC_PROG_NO_STACK_CHECK
|
||||
#endif // NDEBUG
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
/**
|
||||
* Returns true if the BcNum @a n is acting as a string.
|
||||
* @param n The BcNum to test.
|
||||
* @return True if @a n is acting as a string, false otherwise.
|
||||
*/
|
||||
#define BC_PROG_STR(n) ((n)->num == NULL && !(n)->cap)
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/**
|
||||
* Returns true if the result @a r and @a n is a number.
|
||||
* @param r The result.
|
||||
* @param n The number corresponding to the result.
|
||||
* @return True if the result holds a number, false otherwise.
|
||||
*/
|
||||
#define BC_PROG_NUM(r, n) \
|
||||
((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
|
||||
|
||||
#else // BC_ENABLED
|
||||
|
||||
/**
|
||||
* Returns true if the result @a r and @a n is a number.
|
||||
* @param r The result.
|
||||
* @param n The number corresponding to the result.
|
||||
* @return True if the result holds a number, false otherwise.
|
||||
*/
|
||||
#define BC_PROG_NUM(r, n) ((r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
|
||||
// For dc, inst is always BC_INST_ARRAY_ELEM.
|
||||
#define bc_program_pushArray(p, code, bgn, inst) \
|
||||
bc_program_pushArray(p, code, bgn)
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
typedef void (*BcProgramUnary)(BcResult*, BcNum*);
|
||||
/**
|
||||
* This is a function type for unary operations. Currently, these include
|
||||
* boolean not, negation, and truncation with extra math.
|
||||
* @param r The BcResult to store the result into.
|
||||
* @param n The parameter to the unary operation.
|
||||
*/
|
||||
typedef void (*BcProgramUnary)(BcResult *r, BcNum *n);
|
||||
|
||||
/**
|
||||
* Initializes the BcProgram.
|
||||
* @param p The program to initialize.
|
||||
*/
|
||||
void bc_program_init(BcProgram *p);
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/**
|
||||
* Frees a BcProgram. This is only used in debug builds because a BcProgram is
|
||||
* only freed on program exit, and we don't care about freeing resources on
|
||||
* exit.
|
||||
* @param p The program to initialize.
|
||||
*/
|
||||
void bc_program_free(BcProgram *p);
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
#if BC_ENABLED && DC_ENABLED
|
||||
|
||||
/**
|
||||
* Prints the bytecode in a function. This is a debug-only function.
|
||||
* @param p The program.
|
||||
*/
|
||||
void bc_program_code(const BcProgram *p);
|
||||
|
||||
/**
|
||||
* Prints an instruction. This is a debug-only function.
|
||||
* @param p The program.
|
||||
* @param code The bytecode array.
|
||||
* @param bgn A pointer to the current index. It is also updated to the next
|
||||
* index.
|
||||
*/
|
||||
void bc_program_printInst(const BcProgram *p, const char *code,
|
||||
size_t *restrict bgn);
|
||||
|
||||
/**
|
||||
* Prints the stack. This is a debug-only function.
|
||||
* @param p The program.
|
||||
*/
|
||||
void bc_program_printStackDebug(BcProgram* p);
|
||||
|
||||
#endif // BC_ENABLED && DC_ENABLED
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
size_t bc_program_search(BcProgram *p, const char* id, 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.
|
||||
*/
|
||||
size_t bc_program_addString(BcProgram *p, const char *str, size_t fidx);
|
||||
|
||||
/**
|
||||
* Inserts a function into the program and returns the index of the function in
|
||||
* the fns array.
|
||||
* @param p The program.
|
||||
* @param name The name of the function.
|
||||
* @return The index of the function after insertion.
|
||||
*/
|
||||
size_t bc_program_insertFunc(BcProgram *p, const char *name);
|
||||
|
||||
/**
|
||||
* Resets a program, usually because of resetting after an error.
|
||||
* @param p The program to reset.
|
||||
*/
|
||||
void bc_program_reset(BcProgram *p);
|
||||
|
||||
/**
|
||||
* Executes bc or dc code in the BcProgram.
|
||||
* @param p The program.
|
||||
*/
|
||||
void bc_program_exec(BcProgram *p);
|
||||
|
||||
/**
|
||||
* Negates a copy of a BcNum. This is a BcProgramUnary function.
|
||||
* @param r The BcResult to store the result into.
|
||||
* @param n The parameter to the unary operation.
|
||||
*/
|
||||
void bc_program_negate(BcResult *r, BcNum *n);
|
||||
|
||||
/**
|
||||
* Returns a boolean not of a BcNum. This is a BcProgramUnary function.
|
||||
* @param r The BcResult to store the result into.
|
||||
* @param n The parameter to the unary operation.
|
||||
*/
|
||||
void bc_program_not(BcResult *r, BcNum *n);
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/**
|
||||
* Truncates a copy of a BcNum. This is a BcProgramUnary function.
|
||||
* @param r The BcResult to store the result into.
|
||||
* @param n The parameter to the unary operation.
|
||||
*/
|
||||
void bc_program_trunc(BcResult *r, BcNum *n);
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// A reference to an array of binary operator functions.
|
||||
extern const BcNumBinaryOp bc_program_ops[];
|
||||
|
||||
/// A reference to an array of binary operator allocation request functions.
|
||||
extern const BcNumBinaryOpReq bc_program_opReqs[];
|
||||
|
||||
/// A reference to an array of unary operator functions.
|
||||
extern const BcProgramUnary bc_program_unarys[];
|
||||
|
||||
/// A reference to a filename for command-line expressions.
|
||||
extern const char bc_program_exprs_name[];
|
||||
|
||||
/// A reference to a filename for stdin.
|
||||
extern const char bc_program_stdin_name[];
|
||||
|
||||
/// A reference to the ready message printed on SIGINT.
|
||||
extern const char bc_program_ready_msg[];
|
||||
|
||||
/// A reference to the length of the ready message.
|
||||
extern const size_t bc_program_ready_msg_len;
|
||||
|
||||
/// A reference to an array of escape characters for the print statement.
|
||||
extern const char bc_program_esc_chars[];
|
||||
|
||||
/// A reference to an array of the characters corresponding to the escape
|
||||
/// characters in bc_program_esc_chars.
|
||||
extern const char bc_program_esc_seqs[];
|
||||
|
||||
#if BC_HAS_COMPUTED_GOTO
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
|
||||
#define BC_PROG_JUMP(inst, code, ip) \
|
||||
do { \
|
||||
inst = (uchar) (code)[(ip)->idx++]; \
|
||||
bc_file_printf(&vm.ferr, "inst: %s\n", bc_inst_names[inst]); \
|
||||
bc_file_flush(&vm.ferr, bc_flush_none); \
|
||||
goto *bc_program_inst_lbls[inst]; \
|
||||
} while (0)
|
||||
|
||||
#else // BC_DEBUG_CODE
|
||||
|
||||
#define BC_PROG_JUMP(inst, code, ip) \
|
||||
do { \
|
||||
inst = (uchar) (code)[(ip)->idx++]; \
|
||||
goto *bc_program_inst_lbls[inst]; \
|
||||
} while (0)
|
||||
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
#define BC_PROG_DIRECT_JUMP(l) goto lbl_ ## l;
|
||||
#define BC_PROG_LBL(l) lbl_ ## l
|
||||
#define BC_PROG_FALLTHROUGH
|
||||
|
||||
#if BC_C11
|
||||
|
||||
#define BC_PROG_LBLS_SIZE (sizeof(bc_program_inst_lbls) / sizeof(void*))
|
||||
#define BC_PROG_LBLS_ASSERT \
|
||||
static_assert(BC_PROG_LBLS_SIZE == BC_INST_INVALID + 1,\
|
||||
"bc_program_inst_lbls[] mismatches the instructions")
|
||||
|
||||
#else // BC_C11
|
||||
|
||||
#define BC_PROG_LBLS_ASSERT
|
||||
|
||||
#endif // BC_C11
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
#if DC_ENABLED
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#define BC_PROG_LBLS static const void* const bc_program_inst_lbls[] = { \
|
||||
&&lbl_BC_INST_INC, \
|
||||
&&lbl_BC_INST_DEC, \
|
||||
&&lbl_BC_INST_NEG, \
|
||||
&&lbl_BC_INST_BOOL_NOT, \
|
||||
&&lbl_BC_INST_TRUNC, \
|
||||
&&lbl_BC_INST_POWER, \
|
||||
&&lbl_BC_INST_MULTIPLY, \
|
||||
&&lbl_BC_INST_DIVIDE, \
|
||||
&&lbl_BC_INST_MODULUS, \
|
||||
&&lbl_BC_INST_PLUS, \
|
||||
&&lbl_BC_INST_MINUS, \
|
||||
&&lbl_BC_INST_PLACES, \
|
||||
&&lbl_BC_INST_LSHIFT, \
|
||||
&&lbl_BC_INST_RSHIFT, \
|
||||
&&lbl_BC_INST_REL_EQ, \
|
||||
&&lbl_BC_INST_REL_LE, \
|
||||
&&lbl_BC_INST_REL_GE, \
|
||||
&&lbl_BC_INST_REL_NE, \
|
||||
&&lbl_BC_INST_REL_LT, \
|
||||
&&lbl_BC_INST_REL_GT, \
|
||||
&&lbl_BC_INST_BOOL_OR, \
|
||||
&&lbl_BC_INST_BOOL_AND, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS, \
|
||||
&&lbl_BC_INST_ASSIGN_PLACES, \
|
||||
&&lbl_BC_INST_ASSIGN_LSHIFT, \
|
||||
&&lbl_BC_INST_ASSIGN_RSHIFT, \
|
||||
&&lbl_BC_INST_ASSIGN, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_PLACES_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_LSHIFT_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_RSHIFT_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_NO_VAL, \
|
||||
&&lbl_BC_INST_NUM, \
|
||||
&&lbl_BC_INST_VAR, \
|
||||
&&lbl_BC_INST_ARRAY_ELEM, \
|
||||
&&lbl_BC_INST_ARRAY, \
|
||||
&&lbl_BC_INST_ZERO, \
|
||||
&&lbl_BC_INST_ONE, \
|
||||
&&lbl_BC_INST_LAST, \
|
||||
&&lbl_BC_INST_IBASE, \
|
||||
&&lbl_BC_INST_OBASE, \
|
||||
&&lbl_BC_INST_SCALE, \
|
||||
&&lbl_BC_INST_SEED, \
|
||||
&&lbl_BC_INST_LENGTH, \
|
||||
&&lbl_BC_INST_SCALE_FUNC, \
|
||||
&&lbl_BC_INST_SQRT, \
|
||||
&&lbl_BC_INST_ABS, \
|
||||
&&lbl_BC_INST_IRAND, \
|
||||
&&lbl_BC_INST_ASCIIFY, \
|
||||
&&lbl_BC_INST_READ, \
|
||||
&&lbl_BC_INST_RAND, \
|
||||
&&lbl_BC_INST_MAXIBASE, \
|
||||
&&lbl_BC_INST_MAXOBASE, \
|
||||
&&lbl_BC_INST_MAXSCALE, \
|
||||
&&lbl_BC_INST_MAXRAND, \
|
||||
&&lbl_BC_INST_PRINT, \
|
||||
&&lbl_BC_INST_PRINT_POP, \
|
||||
&&lbl_BC_INST_STR, \
|
||||
&&lbl_BC_INST_PRINT_STR, \
|
||||
&&lbl_BC_INST_JUMP, \
|
||||
&&lbl_BC_INST_JUMP_ZERO, \
|
||||
&&lbl_BC_INST_CALL, \
|
||||
&&lbl_BC_INST_RET, \
|
||||
&&lbl_BC_INST_RET0, \
|
||||
&&lbl_BC_INST_RET_VOID, \
|
||||
&&lbl_BC_INST_HALT, \
|
||||
&&lbl_BC_INST_POP, \
|
||||
&&lbl_BC_INST_SWAP, \
|
||||
&&lbl_BC_INST_MODEXP, \
|
||||
&&lbl_BC_INST_DIVMOD, \
|
||||
&&lbl_BC_INST_PRINT_STREAM, \
|
||||
&&lbl_BC_INST_POP_EXEC, \
|
||||
&&lbl_BC_INST_EXECUTE, \
|
||||
&&lbl_BC_INST_EXEC_COND, \
|
||||
&&lbl_BC_INST_PRINT_STACK, \
|
||||
&&lbl_BC_INST_CLEAR_STACK, \
|
||||
&&lbl_BC_INST_REG_STACK_LEN, \
|
||||
&&lbl_BC_INST_STACK_LEN, \
|
||||
&&lbl_BC_INST_DUPLICATE, \
|
||||
&&lbl_BC_INST_LOAD, \
|
||||
&&lbl_BC_INST_PUSH_VAR, \
|
||||
&&lbl_BC_INST_PUSH_TO_VAR, \
|
||||
&&lbl_BC_INST_QUIT, \
|
||||
&&lbl_BC_INST_NQUIT, \
|
||||
&&lbl_BC_INST_EXEC_STACK_LEN, \
|
||||
&&lbl_BC_INST_INVALID, \
|
||||
}
|
||||
|
||||
#else // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#define BC_PROG_LBLS static const void* const bc_program_inst_lbls[] = { \
|
||||
&&lbl_BC_INST_INC, \
|
||||
&&lbl_BC_INST_DEC, \
|
||||
&&lbl_BC_INST_NEG, \
|
||||
&&lbl_BC_INST_BOOL_NOT, \
|
||||
&&lbl_BC_INST_POWER, \
|
||||
&&lbl_BC_INST_MULTIPLY, \
|
||||
&&lbl_BC_INST_DIVIDE, \
|
||||
&&lbl_BC_INST_MODULUS, \
|
||||
&&lbl_BC_INST_PLUS, \
|
||||
&&lbl_BC_INST_MINUS, \
|
||||
&&lbl_BC_INST_REL_EQ, \
|
||||
&&lbl_BC_INST_REL_LE, \
|
||||
&&lbl_BC_INST_REL_GE, \
|
||||
&&lbl_BC_INST_REL_NE, \
|
||||
&&lbl_BC_INST_REL_LT, \
|
||||
&&lbl_BC_INST_REL_GT, \
|
||||
&&lbl_BC_INST_BOOL_OR, \
|
||||
&&lbl_BC_INST_BOOL_AND, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS, \
|
||||
&&lbl_BC_INST_ASSIGN, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_NO_VAL, \
|
||||
&&lbl_BC_INST_NUM, \
|
||||
&&lbl_BC_INST_VAR, \
|
||||
&&lbl_BC_INST_ARRAY_ELEM, \
|
||||
&&lbl_BC_INST_ARRAY, \
|
||||
&&lbl_BC_INST_ZERO, \
|
||||
&&lbl_BC_INST_ONE, \
|
||||
&&lbl_BC_INST_LAST, \
|
||||
&&lbl_BC_INST_IBASE, \
|
||||
&&lbl_BC_INST_OBASE, \
|
||||
&&lbl_BC_INST_SCALE, \
|
||||
&&lbl_BC_INST_LENGTH, \
|
||||
&&lbl_BC_INST_SCALE_FUNC, \
|
||||
&&lbl_BC_INST_SQRT, \
|
||||
&&lbl_BC_INST_ABS, \
|
||||
&&lbl_BC_INST_ASCIIFY, \
|
||||
&&lbl_BC_INST_READ, \
|
||||
&&lbl_BC_INST_MAXIBASE, \
|
||||
&&lbl_BC_INST_MAXOBASE, \
|
||||
&&lbl_BC_INST_MAXSCALE, \
|
||||
&&lbl_BC_INST_PRINT, \
|
||||
&&lbl_BC_INST_PRINT_POP, \
|
||||
&&lbl_BC_INST_STR, \
|
||||
&&lbl_BC_INST_PRINT_STR, \
|
||||
&&lbl_BC_INST_JUMP, \
|
||||
&&lbl_BC_INST_JUMP_ZERO, \
|
||||
&&lbl_BC_INST_CALL, \
|
||||
&&lbl_BC_INST_RET, \
|
||||
&&lbl_BC_INST_RET0, \
|
||||
&&lbl_BC_INST_RET_VOID, \
|
||||
&&lbl_BC_INST_HALT, \
|
||||
&&lbl_BC_INST_POP, \
|
||||
&&lbl_BC_INST_SWAP, \
|
||||
&&lbl_BC_INST_MODEXP, \
|
||||
&&lbl_BC_INST_DIVMOD, \
|
||||
&&lbl_BC_INST_PRINT_STREAM, \
|
||||
&&lbl_BC_INST_POP_EXEC, \
|
||||
&&lbl_BC_INST_EXECUTE, \
|
||||
&&lbl_BC_INST_EXEC_COND, \
|
||||
&&lbl_BC_INST_PRINT_STACK, \
|
||||
&&lbl_BC_INST_CLEAR_STACK, \
|
||||
&&lbl_BC_INST_REG_STACK_LEN, \
|
||||
&&lbl_BC_INST_STACK_LEN, \
|
||||
&&lbl_BC_INST_DUPLICATE, \
|
||||
&&lbl_BC_INST_LOAD, \
|
||||
&&lbl_BC_INST_PUSH_VAR, \
|
||||
&&lbl_BC_INST_PUSH_TO_VAR, \
|
||||
&&lbl_BC_INST_QUIT, \
|
||||
&&lbl_BC_INST_NQUIT, \
|
||||
&&lbl_BC_INST_EXEC_STACK_LEN, \
|
||||
&&lbl_BC_INST_INVALID, \
|
||||
}
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#else // DC_ENABLED
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#define BC_PROG_LBLS static const void* const bc_program_inst_lbls[] = { \
|
||||
&&lbl_BC_INST_INC, \
|
||||
&&lbl_BC_INST_DEC, \
|
||||
&&lbl_BC_INST_NEG, \
|
||||
&&lbl_BC_INST_BOOL_NOT, \
|
||||
&&lbl_BC_INST_TRUNC, \
|
||||
&&lbl_BC_INST_POWER, \
|
||||
&&lbl_BC_INST_MULTIPLY, \
|
||||
&&lbl_BC_INST_DIVIDE, \
|
||||
&&lbl_BC_INST_MODULUS, \
|
||||
&&lbl_BC_INST_PLUS, \
|
||||
&&lbl_BC_INST_MINUS, \
|
||||
&&lbl_BC_INST_PLACES, \
|
||||
&&lbl_BC_INST_LSHIFT, \
|
||||
&&lbl_BC_INST_RSHIFT, \
|
||||
&&lbl_BC_INST_REL_EQ, \
|
||||
&&lbl_BC_INST_REL_LE, \
|
||||
&&lbl_BC_INST_REL_GE, \
|
||||
&&lbl_BC_INST_REL_NE, \
|
||||
&&lbl_BC_INST_REL_LT, \
|
||||
&&lbl_BC_INST_REL_GT, \
|
||||
&&lbl_BC_INST_BOOL_OR, \
|
||||
&&lbl_BC_INST_BOOL_AND, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS, \
|
||||
&&lbl_BC_INST_ASSIGN_PLACES, \
|
||||
&&lbl_BC_INST_ASSIGN_LSHIFT, \
|
||||
&&lbl_BC_INST_ASSIGN_RSHIFT, \
|
||||
&&lbl_BC_INST_ASSIGN, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_PLACES_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_LSHIFT_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_RSHIFT_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_NO_VAL, \
|
||||
&&lbl_BC_INST_NUM, \
|
||||
&&lbl_BC_INST_VAR, \
|
||||
&&lbl_BC_INST_ARRAY_ELEM, \
|
||||
&&lbl_BC_INST_ARRAY, \
|
||||
&&lbl_BC_INST_ZERO, \
|
||||
&&lbl_BC_INST_ONE, \
|
||||
&&lbl_BC_INST_LAST, \
|
||||
&&lbl_BC_INST_IBASE, \
|
||||
&&lbl_BC_INST_OBASE, \
|
||||
&&lbl_BC_INST_SCALE, \
|
||||
&&lbl_BC_INST_SEED, \
|
||||
&&lbl_BC_INST_LENGTH, \
|
||||
&&lbl_BC_INST_SCALE_FUNC, \
|
||||
&&lbl_BC_INST_SQRT, \
|
||||
&&lbl_BC_INST_ABS, \
|
||||
&&lbl_BC_INST_IRAND, \
|
||||
&&lbl_BC_INST_ASCIIFY, \
|
||||
&&lbl_BC_INST_READ, \
|
||||
&&lbl_BC_INST_RAND, \
|
||||
&&lbl_BC_INST_MAXIBASE, \
|
||||
&&lbl_BC_INST_MAXOBASE, \
|
||||
&&lbl_BC_INST_MAXSCALE, \
|
||||
&&lbl_BC_INST_MAXRAND, \
|
||||
&&lbl_BC_INST_PRINT, \
|
||||
&&lbl_BC_INST_PRINT_POP, \
|
||||
&&lbl_BC_INST_STR, \
|
||||
&&lbl_BC_INST_PRINT_STR, \
|
||||
&&lbl_BC_INST_JUMP, \
|
||||
&&lbl_BC_INST_JUMP_ZERO, \
|
||||
&&lbl_BC_INST_CALL, \
|
||||
&&lbl_BC_INST_RET, \
|
||||
&&lbl_BC_INST_RET0, \
|
||||
&&lbl_BC_INST_RET_VOID, \
|
||||
&&lbl_BC_INST_HALT, \
|
||||
&&lbl_BC_INST_POP, \
|
||||
&&lbl_BC_INST_SWAP, \
|
||||
&&lbl_BC_INST_MODEXP, \
|
||||
&&lbl_BC_INST_DIVMOD, \
|
||||
&&lbl_BC_INST_PRINT_STREAM, \
|
||||
&&lbl_BC_INST_INVALID, \
|
||||
}
|
||||
|
||||
#else // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#define BC_PROG_LBLS static const void* const bc_program_inst_lbls[] = { \
|
||||
&&lbl_BC_INST_INC, \
|
||||
&&lbl_BC_INST_DEC, \
|
||||
&&lbl_BC_INST_NEG, \
|
||||
&&lbl_BC_INST_BOOL_NOT, \
|
||||
&&lbl_BC_INST_POWER, \
|
||||
&&lbl_BC_INST_MULTIPLY, \
|
||||
&&lbl_BC_INST_DIVIDE, \
|
||||
&&lbl_BC_INST_MODULUS, \
|
||||
&&lbl_BC_INST_PLUS, \
|
||||
&&lbl_BC_INST_MINUS, \
|
||||
&&lbl_BC_INST_REL_EQ, \
|
||||
&&lbl_BC_INST_REL_LE, \
|
||||
&&lbl_BC_INST_REL_GE, \
|
||||
&&lbl_BC_INST_REL_NE, \
|
||||
&&lbl_BC_INST_REL_LT, \
|
||||
&&lbl_BC_INST_REL_GT, \
|
||||
&&lbl_BC_INST_BOOL_OR, \
|
||||
&&lbl_BC_INST_BOOL_AND, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS, \
|
||||
&&lbl_BC_INST_ASSIGN, \
|
||||
&&lbl_BC_INST_ASSIGN_POWER_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MULTIPLY_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_DIVIDE_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MODULUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_PLUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_MINUS_NO_VAL, \
|
||||
&&lbl_BC_INST_ASSIGN_NO_VAL, \
|
||||
&&lbl_BC_INST_NUM, \
|
||||
&&lbl_BC_INST_VAR, \
|
||||
&&lbl_BC_INST_ARRAY_ELEM, \
|
||||
&&lbl_BC_INST_ARRAY, \
|
||||
&&lbl_BC_INST_ZERO, \
|
||||
&&lbl_BC_INST_ONE, \
|
||||
&&lbl_BC_INST_LAST, \
|
||||
&&lbl_BC_INST_IBASE, \
|
||||
&&lbl_BC_INST_OBASE, \
|
||||
&&lbl_BC_INST_SCALE, \
|
||||
&&lbl_BC_INST_LENGTH, \
|
||||
&&lbl_BC_INST_SCALE_FUNC, \
|
||||
&&lbl_BC_INST_SQRT, \
|
||||
&&lbl_BC_INST_ABS, \
|
||||
&&lbl_BC_INST_ASCIIFY, \
|
||||
&&lbl_BC_INST_READ, \
|
||||
&&lbl_BC_INST_MAXIBASE, \
|
||||
&&lbl_BC_INST_MAXOBASE, \
|
||||
&&lbl_BC_INST_MAXSCALE, \
|
||||
&&lbl_BC_INST_PRINT, \
|
||||
&&lbl_BC_INST_PRINT_POP, \
|
||||
&&lbl_BC_INST_STR, \
|
||||
&&lbl_BC_INST_PRINT_STR, \
|
||||
&&lbl_BC_INST_JUMP, \
|
||||
&&lbl_BC_INST_JUMP_ZERO, \
|
||||
&&lbl_BC_INST_CALL, \
|
||||
&&lbl_BC_INST_RET, \
|
||||
&&lbl_BC_INST_RET0, \
|
||||
&&lbl_BC_INST_RET_VOID, \
|
||||
&&lbl_BC_INST_HALT, \
|
||||
&&lbl_BC_INST_POP, \
|
||||
&&lbl_BC_INST_SWAP, \
|
||||
&&lbl_BC_INST_MODEXP, \
|
||||
&&lbl_BC_INST_DIVMOD, \
|
||||
&&lbl_BC_INST_PRINT_STREAM, \
|
||||
&&lbl_BC_INST_INVALID, \
|
||||
}
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
#else // BC_ENABLED
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#define BC_PROG_LBLS static const void* const bc_program_inst_lbls[] = { \
|
||||
&&lbl_BC_INST_NEG, \
|
||||
&&lbl_BC_INST_BOOL_NOT, \
|
||||
&&lbl_BC_INST_TRUNC, \
|
||||
&&lbl_BC_INST_POWER, \
|
||||
&&lbl_BC_INST_MULTIPLY, \
|
||||
&&lbl_BC_INST_DIVIDE, \
|
||||
&&lbl_BC_INST_MODULUS, \
|
||||
&&lbl_BC_INST_PLUS, \
|
||||
&&lbl_BC_INST_MINUS, \
|
||||
&&lbl_BC_INST_PLACES, \
|
||||
&&lbl_BC_INST_LSHIFT, \
|
||||
&&lbl_BC_INST_RSHIFT, \
|
||||
&&lbl_BC_INST_REL_EQ, \
|
||||
&&lbl_BC_INST_REL_LE, \
|
||||
&&lbl_BC_INST_REL_GE, \
|
||||
&&lbl_BC_INST_REL_NE, \
|
||||
&&lbl_BC_INST_REL_LT, \
|
||||
&&lbl_BC_INST_REL_GT, \
|
||||
&&lbl_BC_INST_BOOL_OR, \
|
||||
&&lbl_BC_INST_BOOL_AND, \
|
||||
&&lbl_BC_INST_ASSIGN_NO_VAL, \
|
||||
&&lbl_BC_INST_NUM, \
|
||||
&&lbl_BC_INST_VAR, \
|
||||
&&lbl_BC_INST_ARRAY_ELEM, \
|
||||
&&lbl_BC_INST_ARRAY, \
|
||||
&&lbl_BC_INST_ZERO, \
|
||||
&&lbl_BC_INST_ONE, \
|
||||
&&lbl_BC_INST_IBASE, \
|
||||
&&lbl_BC_INST_OBASE, \
|
||||
&&lbl_BC_INST_SCALE, \
|
||||
&&lbl_BC_INST_SEED, \
|
||||
&&lbl_BC_INST_LENGTH, \
|
||||
&&lbl_BC_INST_SCALE_FUNC, \
|
||||
&&lbl_BC_INST_SQRT, \
|
||||
&&lbl_BC_INST_ABS, \
|
||||
&&lbl_BC_INST_IRAND, \
|
||||
&&lbl_BC_INST_ASCIIFY, \
|
||||
&&lbl_BC_INST_READ, \
|
||||
&&lbl_BC_INST_RAND, \
|
||||
&&lbl_BC_INST_MAXIBASE, \
|
||||
&&lbl_BC_INST_MAXOBASE, \
|
||||
&&lbl_BC_INST_MAXSCALE, \
|
||||
&&lbl_BC_INST_MAXRAND, \
|
||||
&&lbl_BC_INST_PRINT, \
|
||||
&&lbl_BC_INST_PRINT_POP, \
|
||||
&&lbl_BC_INST_STR, \
|
||||
&&lbl_BC_INST_POP, \
|
||||
&&lbl_BC_INST_SWAP, \
|
||||
&&lbl_BC_INST_MODEXP, \
|
||||
&&lbl_BC_INST_DIVMOD, \
|
||||
&&lbl_BC_INST_PRINT_STREAM, \
|
||||
&&lbl_BC_INST_POP_EXEC, \
|
||||
&&lbl_BC_INST_EXECUTE, \
|
||||
&&lbl_BC_INST_EXEC_COND, \
|
||||
&&lbl_BC_INST_PRINT_STACK, \
|
||||
&&lbl_BC_INST_CLEAR_STACK, \
|
||||
&&lbl_BC_INST_REG_STACK_LEN, \
|
||||
&&lbl_BC_INST_STACK_LEN, \
|
||||
&&lbl_BC_INST_DUPLICATE, \
|
||||
&&lbl_BC_INST_LOAD, \
|
||||
&&lbl_BC_INST_PUSH_VAR, \
|
||||
&&lbl_BC_INST_PUSH_TO_VAR, \
|
||||
&&lbl_BC_INST_QUIT, \
|
||||
&&lbl_BC_INST_NQUIT, \
|
||||
&&lbl_BC_INST_EXEC_STACK_LEN, \
|
||||
&&lbl_BC_INST_INVALID, \
|
||||
}
|
||||
|
||||
#else // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#define BC_PROG_LBLS static const void* const bc_program_inst_lbls[] = { \
|
||||
&&lbl_BC_INST_NEG, \
|
||||
&&lbl_BC_INST_BOOL_NOT, \
|
||||
&&lbl_BC_INST_POWER, \
|
||||
&&lbl_BC_INST_MULTIPLY, \
|
||||
&&lbl_BC_INST_DIVIDE, \
|
||||
&&lbl_BC_INST_MODULUS, \
|
||||
&&lbl_BC_INST_PLUS, \
|
||||
&&lbl_BC_INST_MINUS, \
|
||||
&&lbl_BC_INST_REL_EQ, \
|
||||
&&lbl_BC_INST_REL_LE, \
|
||||
&&lbl_BC_INST_REL_GE, \
|
||||
&&lbl_BC_INST_REL_NE, \
|
||||
&&lbl_BC_INST_REL_LT, \
|
||||
&&lbl_BC_INST_REL_GT, \
|
||||
&&lbl_BC_INST_BOOL_OR, \
|
||||
&&lbl_BC_INST_BOOL_AND, \
|
||||
&&lbl_BC_INST_ASSIGN_NO_VAL, \
|
||||
&&lbl_BC_INST_NUM, \
|
||||
&&lbl_BC_INST_VAR, \
|
||||
&&lbl_BC_INST_ARRAY_ELEM, \
|
||||
&&lbl_BC_INST_ARRAY, \
|
||||
&&lbl_BC_INST_ZERO, \
|
||||
&&lbl_BC_INST_ONE, \
|
||||
&&lbl_BC_INST_IBASE, \
|
||||
&&lbl_BC_INST_OBASE, \
|
||||
&&lbl_BC_INST_SCALE, \
|
||||
&&lbl_BC_INST_LENGTH, \
|
||||
&&lbl_BC_INST_SCALE_FUNC, \
|
||||
&&lbl_BC_INST_SQRT, \
|
||||
&&lbl_BC_INST_ABS, \
|
||||
&&lbl_BC_INST_ASCIIFY, \
|
||||
&&lbl_BC_INST_READ, \
|
||||
&&lbl_BC_INST_MAXIBASE, \
|
||||
&&lbl_BC_INST_MAXOBASE, \
|
||||
&&lbl_BC_INST_MAXSCALE, \
|
||||
&&lbl_BC_INST_PRINT, \
|
||||
&&lbl_BC_INST_PRINT_POP, \
|
||||
&&lbl_BC_INST_STR, \
|
||||
&&lbl_BC_INST_POP, \
|
||||
&&lbl_BC_INST_SWAP, \
|
||||
&&lbl_BC_INST_MODEXP, \
|
||||
&&lbl_BC_INST_DIVMOD, \
|
||||
&&lbl_BC_INST_PRINT_STREAM, \
|
||||
&&lbl_BC_INST_POP_EXEC, \
|
||||
&&lbl_BC_INST_EXECUTE, \
|
||||
&&lbl_BC_INST_EXEC_COND, \
|
||||
&&lbl_BC_INST_PRINT_STACK, \
|
||||
&&lbl_BC_INST_CLEAR_STACK, \
|
||||
&&lbl_BC_INST_REG_STACK_LEN, \
|
||||
&&lbl_BC_INST_STACK_LEN, \
|
||||
&&lbl_BC_INST_DUPLICATE, \
|
||||
&&lbl_BC_INST_LOAD, \
|
||||
&&lbl_BC_INST_PUSH_VAR, \
|
||||
&&lbl_BC_INST_PUSH_TO_VAR, \
|
||||
&&lbl_BC_INST_QUIT, \
|
||||
&&lbl_BC_INST_NQUIT, \
|
||||
&&lbl_BC_INST_EXEC_STACK_LEN, \
|
||||
&&lbl_BC_INST_INVALID, \
|
||||
}
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#else // BC_HAS_COMPUTED_GOTO
|
||||
|
||||
#define BC_PROG_JUMP(inst, code, ip) break
|
||||
#define BC_PROG_DIRECT_JUMP(l)
|
||||
#define BC_PROG_LBL(l) case l
|
||||
#define BC_PROG_FALLTHROUGH BC_FALLTHROUGH
|
||||
|
||||
#define BC_PROG_LBLS
|
||||
|
||||
#endif // BC_HAS_COMPUTED_GOTO
|
||||
|
||||
#endif // BC_PROGRAM_H
|
||||
|
|
328
include/rand.h
328
include/rand.h
|
@ -50,12 +50,27 @@
|
|||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#if BC_ENABLE_RAND
|
||||
#if BC_ENABLE_LIBRARY
|
||||
#define BC_RAND_USE_FREE (1)
|
||||
#else // BC_ENABLE_LIBRARY
|
||||
#ifndef NDEBUG
|
||||
#define BC_RAND_USE_FREE (1)
|
||||
#else // NDEBUG
|
||||
#define BC_RAND_USE_FREE (0)
|
||||
#endif // NDEBUG
|
||||
#endif // BC_ENABLE_LIBRARY
|
||||
|
||||
typedef ulong (*BcRandUlong)(void*);
|
||||
/**
|
||||
* A function to return a random unsigned long.
|
||||
* @param ptr A void ptr to some data that will help generate the random ulong.
|
||||
* @return The random ulong.
|
||||
*/
|
||||
typedef ulong (*BcRandUlong)(void *ptr);
|
||||
|
||||
#if BC_LONG_BIT >= 64
|
||||
|
||||
// If longs are 64 bits, we have the option of 128-bit integers on some
|
||||
// compilers. These two sections test that.
|
||||
#ifdef BC_RAND_BUILTIN
|
||||
#if BC_RAND_BUILTIN
|
||||
#ifndef __SIZEOF_INT128__
|
||||
|
@ -73,135 +88,432 @@ typedef ulong (*BcRandUlong)(void*);
|
|||
#endif // __SIZEOF_INT128__
|
||||
#endif // BC_RAND_BUILTIN
|
||||
|
||||
/// The type for random integers.
|
||||
typedef uint64_t BcRand;
|
||||
|
||||
/// A constant defined by PCG.
|
||||
#define BC_RAND_ROTC (63)
|
||||
|
||||
#if BC_RAND_BUILTIN
|
||||
|
||||
/// A typedef for the PCG state.
|
||||
typedef __uint128_t BcRandState;
|
||||
|
||||
/**
|
||||
* Multiply two integers, worrying about overflow.
|
||||
* @param a The first integer.
|
||||
* @param b The second integer.
|
||||
* @return The product of the PCG states.
|
||||
*/
|
||||
#define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Add two integers, worrying about overflow.
|
||||
* @param a The first integer.
|
||||
* @param b The second integer.
|
||||
* @return The sum of the PCG states.
|
||||
*/
|
||||
#define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Multiply two PCG states.
|
||||
* @param a The first PCG state.
|
||||
* @param b The second PCG state.
|
||||
* @return The product of the PCG states.
|
||||
*/
|
||||
#define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Add two PCG states.
|
||||
* @param a The first PCG state.
|
||||
* @param b The second PCG state.
|
||||
* @return The sum of the PCG states.
|
||||
*/
|
||||
#define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Figure out if the PRNG has been modified. Since the increment of the PRNG has
|
||||
* to be odd, we use the extra bit to store whether it has been modified or not.
|
||||
* @param r The PRNG.
|
||||
* @return True if the PRNG has *not* been modified, false otherwise.
|
||||
*/
|
||||
#define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
|
||||
|
||||
/**
|
||||
* Return true if the PRNG has not been seeded yet.
|
||||
* @param r The PRNG.
|
||||
* @return True if the PRNG has not been seeded yet, false otherwise.
|
||||
*/
|
||||
#define BC_RAND_ZERO(r) (!(r)->state)
|
||||
|
||||
/**
|
||||
* Returns a constant built from @a h and @a l.
|
||||
* @param h The high 64 bits.
|
||||
* @param l The low 64 bits.
|
||||
* @return The constant built from @a h and @a l.
|
||||
*/
|
||||
#define BC_RAND_CONSTANT(h, l) ((((BcRandState) (h)) << 64) + (BcRandState) (l))
|
||||
|
||||
/**
|
||||
* Truncates a PCG state to the number of bits in a random integer.
|
||||
* @param s The state to truncate.
|
||||
* @return The truncated state.
|
||||
*/
|
||||
#define BC_RAND_TRUNC(s) ((uint64_t) (s))
|
||||
|
||||
/**
|
||||
* Chops a PCG state in half and returns the top bits.
|
||||
* @param s The state to chop.
|
||||
* @return The chopped state's top bits.
|
||||
*/
|
||||
#define BC_RAND_CHOP(s) ((uint64_t) ((s) >> 64UL))
|
||||
|
||||
/**
|
||||
* Rotates a PCG state.
|
||||
* @param s The state to rotate.
|
||||
* @return The rotated state.
|
||||
*/
|
||||
#define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 122UL))
|
||||
|
||||
#else // BC_RAND_BUILTIN
|
||||
|
||||
/// A typedef for the PCG state.
|
||||
typedef struct BcRandState {
|
||||
|
||||
/// The low bits.
|
||||
uint_fast64_t lo;
|
||||
|
||||
/// The high bits.
|
||||
uint_fast64_t hi;
|
||||
|
||||
} BcRandState;
|
||||
|
||||
/**
|
||||
* Multiply two integers, worrying about overflow.
|
||||
* @param a The first integer.
|
||||
* @param b The second integer.
|
||||
* @return The product of the PCG states.
|
||||
*/
|
||||
#define bc_rand_mul(a, b) (bc_rand_multiply((a), (b)))
|
||||
|
||||
/**
|
||||
* Add two integers, worrying about overflow.
|
||||
* @param a The first integer.
|
||||
* @param b The second integer.
|
||||
* @return The sum of the PCG states.
|
||||
*/
|
||||
#define bc_rand_add(a, b) (bc_rand_addition((a), (b)))
|
||||
|
||||
/**
|
||||
* Multiply two PCG states.
|
||||
* @param a The first PCG state.
|
||||
* @param b The second PCG state.
|
||||
* @return The product of the PCG states.
|
||||
*/
|
||||
#define bc_rand_mul2(a, b) (bc_rand_multiply2((a), (b)))
|
||||
|
||||
/**
|
||||
* Add two PCG states.
|
||||
* @param a The first PCG state.
|
||||
* @param b The second PCG state.
|
||||
* @return The sum of the PCG states.
|
||||
*/
|
||||
#define bc_rand_add2(a, b) (bc_rand_addition2((a), (b)))
|
||||
|
||||
/**
|
||||
* Figure out if the PRNG has been modified. Since the increment of the PRNG has
|
||||
* to be odd, we use the extra bit to store whether it has been modified or not.
|
||||
* @param r The PRNG.
|
||||
* @return True if the PRNG has *not* been modified, false otherwise.
|
||||
*/
|
||||
#define BC_RAND_NOTMODIFIED(r) (((r)->inc.lo & 1) == 0)
|
||||
|
||||
/**
|
||||
* Return true if the PRNG has not been seeded yet.
|
||||
* @param r The PRNG.
|
||||
* @return True if the PRNG has not been seeded yet, false otherwise.
|
||||
*/
|
||||
#define BC_RAND_ZERO(r) (!(r)->state.lo && !(r)->state.hi)
|
||||
|
||||
/**
|
||||
* Returns a constant built from @a h and @a l.
|
||||
* @param h The high 64 bits.
|
||||
* @param l The low 64 bits.
|
||||
* @return The constant built from @a h and @a l.
|
||||
*/
|
||||
#define BC_RAND_CONSTANT(h, l) { .lo = (l), .hi = (h) }
|
||||
|
||||
/**
|
||||
* Truncates a PCG state to the number of bits in a random integer.
|
||||
* @param s The state to truncate.
|
||||
* @return The truncated state.
|
||||
*/
|
||||
#define BC_RAND_TRUNC(s) ((s).lo)
|
||||
|
||||
/**
|
||||
* Chops a PCG state in half and returns the top bits.
|
||||
* @param s The state to chop.
|
||||
* @return The chopped state's top bits.
|
||||
*/
|
||||
#define BC_RAND_CHOP(s) ((s).hi)
|
||||
|
||||
/**
|
||||
* Returns the rotate amount for a PCG state.
|
||||
* @param s The state to rotate.
|
||||
* @return The semi-rotated state.
|
||||
*/
|
||||
#define BC_RAND_ROTAMT(s) ((unsigned int) ((s).hi >> 58UL))
|
||||
|
||||
/// A 64-bit integer with the bottom 32 bits set.
|
||||
#define BC_RAND_BOTTOM32 (((uint_fast64_t) 0xffffffffULL))
|
||||
|
||||
/**
|
||||
* Returns the 32-bit truncated value of @a n.
|
||||
* @param n The integer to truncate.
|
||||
* @return The bottom 32 bits of @a n.
|
||||
*/
|
||||
#define BC_RAND_TRUNC32(n) ((n) & BC_RAND_BOTTOM32)
|
||||
|
||||
/**
|
||||
* Returns the second 32 bits of @a n.
|
||||
* @param n The integer to truncate.
|
||||
* @return The second 32 bits of @a n.
|
||||
*/
|
||||
#define BC_RAND_CHOP32(n) ((n) >> 32)
|
||||
|
||||
#endif // BC_RAND_BUILTIN
|
||||
|
||||
/// A constant defined by PCG.
|
||||
#define BC_RAND_MULTIPLIER \
|
||||
BC_RAND_CONSTANT(2549297995355413924ULL, 4865540595714422341ULL)
|
||||
|
||||
/**
|
||||
* Returns the result of a PCG fold.
|
||||
* @param s The state to fold.
|
||||
* @return The folded state.
|
||||
*/
|
||||
#define BC_RAND_FOLD(s) ((BcRand) (BC_RAND_CHOP(s) ^ BC_RAND_TRUNC(s)))
|
||||
|
||||
#else // BC_LONG_BIT >= 64
|
||||
|
||||
// If we are using 32-bit longs, we need to set these so.
|
||||
#undef BC_RAND_BUILTIN
|
||||
#define BC_RAND_BUILTIN (1)
|
||||
|
||||
/// The type for random integers.
|
||||
typedef uint32_t BcRand;
|
||||
|
||||
/// A constant defined by PCG.
|
||||
#define BC_RAND_ROTC (31)
|
||||
|
||||
/// A typedef for the PCG state.
|
||||
typedef uint_fast64_t BcRandState;
|
||||
|
||||
/**
|
||||
* Multiply two integers, worrying about overflow.
|
||||
* @param a The first integer.
|
||||
* @param b The second integer.
|
||||
* @return The product of the PCG states.
|
||||
*/
|
||||
#define bc_rand_mul(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Add two integers, worrying about overflow.
|
||||
* @param a The first integer.
|
||||
* @param b The second integer.
|
||||
* @return The sum of the PCG states.
|
||||
*/
|
||||
#define bc_rand_add(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Multiply two PCG states.
|
||||
* @param a The first PCG state.
|
||||
* @param b The second PCG state.
|
||||
* @return The product of the PCG states.
|
||||
*/
|
||||
#define bc_rand_mul2(a, b) (((BcRandState) (a)) * ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Add two PCG states.
|
||||
* @param a The first PCG state.
|
||||
* @param b The second PCG state.
|
||||
* @return The sum of the PCG states.
|
||||
*/
|
||||
#define bc_rand_add2(a, b) (((BcRandState) (a)) + ((BcRandState) (b)))
|
||||
|
||||
/**
|
||||
* Figure out if the PRNG has been modified. Since the increment of the PRNG has
|
||||
* to be odd, we use the extra bit to store whether it has been modified or not.
|
||||
* @param r The PRNG.
|
||||
* @return True if the PRNG has *not* been modified, false otherwise.
|
||||
*/
|
||||
#define BC_RAND_NOTMODIFIED(r) (((r)->inc & 1UL) == 0)
|
||||
|
||||
/**
|
||||
* Return true if the PRNG has not been seeded yet.
|
||||
* @param r The PRNG.
|
||||
* @return True if the PRNG has not been seeded yet, false otherwise.
|
||||
*/
|
||||
#define BC_RAND_ZERO(r) (!(r)->state)
|
||||
|
||||
#define BC_RAND_CONSTANT UINT64_C
|
||||
/**
|
||||
* Returns a constant built from a number.
|
||||
* @param n The number.
|
||||
* @return The constant built from @a n.
|
||||
*/
|
||||
#define BC_RAND_CONSTANT(n) UINT64_C(n)
|
||||
|
||||
/// A constant defined by PCG.
|
||||
#define BC_RAND_MULTIPLIER BC_RAND_CONSTANT(6364136223846793005)
|
||||
|
||||
/**
|
||||
* Truncates a PCG state to the number of bits in a random integer.
|
||||
* @param s The state to truncate.
|
||||
* @return The truncated state.
|
||||
*/
|
||||
#define BC_RAND_TRUNC(s) ((uint32_t) (s))
|
||||
|
||||
/**
|
||||
* Chops a PCG state in half and returns the top bits.
|
||||
* @param s The state to chop.
|
||||
* @return The chopped state's top bits.
|
||||
*/
|
||||
#define BC_RAND_CHOP(s) ((uint32_t) ((s) >> 32UL))
|
||||
|
||||
/**
|
||||
* Returns the rotate amount for a PCG state.
|
||||
* @param s The state to rotate.
|
||||
* @return The semi-rotated state.
|
||||
*/
|
||||
#define BC_RAND_ROTAMT(s) ((unsigned int) ((s) >> 59UL))
|
||||
|
||||
/**
|
||||
* Returns the result of a PCG fold.
|
||||
* @param s The state to fold.
|
||||
* @return The folded state.
|
||||
*/
|
||||
#define BC_RAND_FOLD(s) ((BcRand) ((((s) >> 18U) ^ (s)) >> 27U))
|
||||
|
||||
#endif // BC_LONG_BIT >= 64
|
||||
|
||||
/**
|
||||
* Rotates @a v by @a r bits.
|
||||
* @param v The value to rotate.
|
||||
* @param r The amount to rotate by.
|
||||
* @return The rotated value.
|
||||
*/
|
||||
#define BC_RAND_ROT(v, r) \
|
||||
((BcRand) (((v) >> (r)) | ((v) << ((0 - (r)) & BC_RAND_ROTC))))
|
||||
|
||||
/// The number of bits in a random integer.
|
||||
#define BC_RAND_BITS (sizeof(BcRand) * CHAR_BIT)
|
||||
|
||||
/// The number of bits in a PCG state.
|
||||
#define BC_RAND_STATE_BITS (sizeof(BcRandState) * CHAR_BIT)
|
||||
|
||||
/// The size of a BcNum with the max random integer. This isn't exact; it's
|
||||
/// actually rather crude. But it's always enough.
|
||||
#define BC_RAND_NUM_SIZE (BC_NUM_BIGDIG_LOG10 * 2 + 2)
|
||||
|
||||
/// The mask for how many bits bc_rand_srand() can set per iteration.
|
||||
#define BC_RAND_SRAND_BITS ((1 << CHAR_BIT) - 1)
|
||||
|
||||
/// The actual RNG data. These are the actual PRNG's.
|
||||
typedef struct BcRNGData {
|
||||
|
||||
/// The state.
|
||||
BcRandState state;
|
||||
|
||||
/// The increment and the modified bit.
|
||||
BcRandState inc;
|
||||
|
||||
} BcRNGData;
|
||||
|
||||
/// The public PRNG. This is just a stack of PRNG's to maintain the globals
|
||||
/// stack illusion.
|
||||
typedef struct BcRNG {
|
||||
|
||||
/// The stack of PRNG's.
|
||||
BcVec v;
|
||||
|
||||
} BcRNG;
|
||||
|
||||
/**
|
||||
* Initializes a BcRNG.
|
||||
* @param r The BcRNG to initialize.
|
||||
*/
|
||||
void bc_rand_init(BcRNG *r);
|
||||
#ifndef NDEBUG
|
||||
void bc_rand_free(BcRNG *r);
|
||||
#endif // NDEBUG
|
||||
|
||||
#if BC_RAND_USE_FREE
|
||||
|
||||
/**
|
||||
* Frees a BcRNG. This is only in debug builds because it would only be freed on
|
||||
* exit.
|
||||
* @param r The BcRNG to free.
|
||||
*/
|
||||
void bc_rand_free(BcRNG *r);
|
||||
|
||||
#endif // BC_RAND_USE_FREE
|
||||
|
||||
/**
|
||||
* Returns a random integer from the PRNG.
|
||||
* @param r The PRNG.
|
||||
* @return A random integer.
|
||||
*/
|
||||
BcRand bc_rand_int(BcRNG *r);
|
||||
|
||||
/**
|
||||
* Returns a random integer from the PRNG bounded by @a bound. Bias is
|
||||
* eliminated.
|
||||
* @param r The PRNG.
|
||||
* @param bound The bound for the random integer.
|
||||
* @return A bounded random integer.
|
||||
*/
|
||||
BcRand bc_rand_bounded(BcRNG *r, BcRand bound);
|
||||
|
||||
/**
|
||||
* Seed the PRNG with the state in two parts and the increment in two parts.
|
||||
* @param r The PRNG.
|
||||
* @param state1 The first part of the state.
|
||||
* @param state2 The second part of the state.
|
||||
* @param inc1 The first part of the increment.
|
||||
* @param inc2 The second part of the increment.
|
||||
*/
|
||||
void bc_rand_seed(BcRNG *r, ulong state1, ulong state2, ulong inc1, ulong inc2);
|
||||
|
||||
/**
|
||||
* Pushes a new PRNG onto the PRNG stack.
|
||||
* @param r The PRNG.
|
||||
*/
|
||||
void bc_rand_push(BcRNG *r);
|
||||
|
||||
/**
|
||||
* Pops one or all but one items off of the PRNG stack.
|
||||
* @param r The PRNG.
|
||||
* @param reset True if all but one PRNG should be popped off the stack, false
|
||||
* if only one should be popped.
|
||||
*/
|
||||
void bc_rand_pop(BcRNG *r, bool reset);
|
||||
|
||||
/**
|
||||
* Returns, via pointers, the state of the PRNG in pieces.
|
||||
* @param r The PRNG.
|
||||
* @param s1 The return value for the first part of the state.
|
||||
* @param s2 The return value for the second part of the state.
|
||||
* @param i1 The return value for the first part of the increment.
|
||||
* @param i2 The return value for the second part of the increment.
|
||||
*/
|
||||
void bc_rand_getRands(BcRNG *r, BcRand *s1, BcRand *s2, BcRand *i1, BcRand *i2);
|
||||
|
||||
/**
|
||||
* Seed the PRNG with random data.
|
||||
* @param rng The PRNG.
|
||||
*/
|
||||
void bc_rand_srand(BcRNGData *rng);
|
||||
|
||||
/// A reference to a constant multiplier.
|
||||
extern const BcRandState bc_rand_multiplier;
|
||||
|
||||
#endif // BC_ENABLE_RAND
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
#endif // BC_RAND_H
|
||||
|
|
|
@ -41,20 +41,42 @@
|
|||
#include <status.h>
|
||||
#include <vector.h>
|
||||
|
||||
#ifndef BC_ENABLE_PROMPT
|
||||
#define BC_ENABLE_PROMPT (1)
|
||||
#endif // BC_ENABLE_PROMPT
|
||||
|
||||
#if !BC_ENABLE_PROMPT
|
||||
#define bc_read_line(vec, prompt) bc_read_line(vec)
|
||||
#define bc_read_chars(vec, prompt) bc_read_chars(vec)
|
||||
#endif // BC_ENABLE_PROMPT
|
||||
|
||||
#define BC_READ_BIN_CHAR(c) (((c) < ' ' && !isspace((c))) || ((uchar) c) > '~')
|
||||
/**
|
||||
* Returns true if @a c is a non-ASCII (invalid) char.
|
||||
* @param c The character to test.
|
||||
* @return True if @a c is an invalid char.
|
||||
*/
|
||||
#define BC_READ_BIN_CHAR(c) (!(c))
|
||||
|
||||
/**
|
||||
* Reads a line from stdin after printing prompt, if desired.
|
||||
* @param vec The vector to put the stdin data into.
|
||||
* @param prompt The prompt to print, if desired.
|
||||
*/
|
||||
BcStatus bc_read_line(BcVec *vec, const char *prompt);
|
||||
void bc_read_file(const char *path, char **buf);
|
||||
|
||||
/**
|
||||
* Read a file and return a buffer with the data. The buffer must be freed by
|
||||
* the caller.
|
||||
* @param path The path to the file to read.
|
||||
*/
|
||||
char* bc_read_file(const char *path);
|
||||
|
||||
/**
|
||||
* Helper function for reading characters from stdin. This takes care of a bunch
|
||||
* of complex error handling. Thus, it returns a status instead of throwing an
|
||||
* error, except for fatal errors.
|
||||
* @param vec The vec to put the stdin into.
|
||||
* @param prompt The prompt to print, if desired.
|
||||
*/
|
||||
BcStatus bc_read_chars(BcVec *vec, const char *prompt);
|
||||
|
||||
/**
|
||||
* Read a line from buf into vec.
|
||||
* @param vec The vector to read data into.
|
||||
* @param buf The buffer to read from.
|
||||
* @param buf_len The length of the buffer.
|
||||
*/
|
||||
bool bc_read_buf(BcVec *vec, char *buf, size_t *buf_len);
|
||||
|
||||
#endif // BC_READ_H
|
||||
|
|
642
include/status.h
642
include/status.h
|
@ -29,7 +29,7 @@
|
|||
*
|
||||
* *****************************************************************************
|
||||
*
|
||||
* All bc status codes.
|
||||
* All bc status codes and cross-platform portability.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -38,6 +38,13 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
// This is used by configure.sh to test for OpenBSD.
|
||||
#ifdef BC_TEST_OPENBSD
|
||||
#ifdef __OpenBSD__
|
||||
#error On OpenBSD without _BSD_SOURCE
|
||||
#endif // __OpenBSD__
|
||||
#endif // BC_TEST_OPENBSD
|
||||
|
||||
#ifndef BC_ENABLED
|
||||
#define BC_ENABLED (1)
|
||||
#endif // BC_ENABLED
|
||||
|
@ -46,9 +53,10 @@
|
|||
#define DC_ENABLED (1)
|
||||
#endif // DC_ENABLED
|
||||
|
||||
// This is error checking for fuzz builds.
|
||||
#if BC_ENABLE_AFL
|
||||
#ifndef __AFL_HAVE_MANUAL_CONTROL
|
||||
#error Must compile with afl-clang-fast for fuzzing
|
||||
#error Must compile with afl-clang-fast or afl-clang-lto for fuzzing
|
||||
#endif // __AFL_HAVE_MANUAL_CONTROL
|
||||
#endif // BC_ENABLE_AFL
|
||||
|
||||
|
@ -56,98 +64,726 @@
|
|||
#define BC_ENABLE_MEMCHECK (0)
|
||||
#endif // BC_ENABLE_MEMCHECK
|
||||
|
||||
/**
|
||||
* Mark a variable as unused.
|
||||
* @param e The variable to mark as unused.
|
||||
*/
|
||||
#define BC_UNUSED(e) ((void) (e))
|
||||
|
||||
// If users want, they can define this to something like __builtin_expect(e, 1).
|
||||
// It might give a performance improvement.
|
||||
#ifndef BC_LIKELY
|
||||
|
||||
/**
|
||||
* Mark a branch expression as likely.
|
||||
* @param e The expression to mark as likely.
|
||||
*/
|
||||
#define BC_LIKELY(e) (e)
|
||||
|
||||
#endif // BC_LIKELY
|
||||
|
||||
// If users want, they can define this to something like __builtin_expect(e, 0).
|
||||
// It might give a performance improvement.
|
||||
#ifndef BC_UNLIKELY
|
||||
|
||||
/**
|
||||
* Mark a branch expression as unlikely.
|
||||
* @param e The expression to mark as unlikely.
|
||||
*/
|
||||
#define BC_UNLIKELY(e) (e)
|
||||
|
||||
#endif // BC_UNLIKELY
|
||||
|
||||
/**
|
||||
* Mark a branch expression as an error, if true.
|
||||
* @param e The expression to mark as an error, if true.
|
||||
*/
|
||||
#define BC_ERR(e) BC_UNLIKELY(e)
|
||||
|
||||
/**
|
||||
* Mark a branch expression as not an error, if true.
|
||||
* @param e The expression to mark as not an error, if true.
|
||||
*/
|
||||
#define BC_NO_ERR(s) BC_LIKELY(s)
|
||||
|
||||
// Disable extra debug code by default.
|
||||
#ifndef BC_DEBUG_CODE
|
||||
#define BC_DEBUG_CODE (0)
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
// We want to be able to use _Noreturn on C11 compilers.
|
||||
#if __STDC_VERSION__ >= 201100L
|
||||
|
||||
#include <stdnoreturn.h>
|
||||
#define BC_NORETURN _Noreturn
|
||||
#define BC_C11 (1)
|
||||
|
||||
#else // __STDC_VERSION__
|
||||
|
||||
#define BC_NORETURN
|
||||
#define BC_MUST_RETURN
|
||||
#define BC_C11 (0)
|
||||
|
||||
#endif // __STDC_VERSION__
|
||||
|
||||
#define BC_HAS_UNREACHABLE (0)
|
||||
#define BC_HAS_COMPUTED_GOTO (0)
|
||||
|
||||
// GCC and Clang complain if fallthroughs are not marked with their special
|
||||
// attribute. Jerks. This creates a define for marking the fallthroughs that is
|
||||
// nothing on other compilers.
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
|
||||
#if defined(__has_attribute)
|
||||
|
||||
#if __has_attribute(fallthrough)
|
||||
#define BC_FALLTHROUGH __attribute__((fallthrough));
|
||||
#else // __has_attribute(fallthrough)
|
||||
#define BC_FALLTHROUGH
|
||||
#endif // __has_attribute(fallthrough)
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
#undef BC_HAS_UNREACHABLE
|
||||
#define BC_HAS_UNREACHABLE (1)
|
||||
#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
|
||||
#else // __GNUC__
|
||||
|
||||
#if __clang_major__ >= 4
|
||||
#undef BC_HAS_UNREACHABLE
|
||||
#define BC_HAS_UNREACHABLE (1)
|
||||
#endif // __clang_major__ >= 4
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
#else // defined(__has_attribute)
|
||||
#define BC_FALLTHROUGH
|
||||
#endif // defined(__has_attribute)
|
||||
#else // defined(__clang__) || defined(__GNUC__)
|
||||
#define BC_FALLTHROUGH
|
||||
#endif // defined(__clang__) || defined(__GNUC__)
|
||||
|
||||
#if BC_HAS_UNREACHABLE
|
||||
|
||||
#define BC_UNREACHABLE __builtin_unreachable();
|
||||
|
||||
#else // BC_HAS_UNREACHABLE
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define BC_UNREACHABLE __assume(0);
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
#define BC_UNREACHABLE
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // BC_HAS_UNREACHABLE
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
|
||||
#undef BC_HAS_COMPUTED_GOTO
|
||||
#define BC_HAS_COMPUTED_GOTO (1)
|
||||
|
||||
#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
#ifdef __clang__
|
||||
|
||||
#if __clang_major__ >= 4
|
||||
|
||||
#undef BC_HAS_COMPUTED_GOTO
|
||||
#define BC_HAS_COMPUTED_GOTO (1)
|
||||
|
||||
#endif // __clang_major__ >= 4
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
#ifdef BC_NO_COMPUTED_GOTO
|
||||
|
||||
#undef BC_HAS_COMPUTED_GOTO
|
||||
#define BC_HAS_COMPUTED_GOTO (0)
|
||||
|
||||
#endif // BC_NO_COMPUTED_GOTO
|
||||
|
||||
#ifdef __GNUC__
|
||||
#ifdef __OpenBSD__
|
||||
// The OpenBSD GCC doesn't like inline.
|
||||
#define inline
|
||||
#endif // __OpenBSD__
|
||||
#endif // __GNUC__
|
||||
|
||||
// Workarounds for AIX's POSIX incompatibility.
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX __SIZE_MAX__
|
||||
#endif // SIZE_MAX
|
||||
#ifndef UINTMAX_C
|
||||
#define UINTMAX_C __UINTMAX_C
|
||||
#endif // UINTMAX_C
|
||||
#ifndef UINT32_C
|
||||
#define UINT32_C __UINT32_C
|
||||
#endif // UINT32_C
|
||||
#ifndef UINT_FAST32_MAX
|
||||
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
|
||||
#endif // UINT_FAST32_MAX
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX __UINT16_MAX__
|
||||
#endif // UINT16_MAX
|
||||
#ifndef SIG_ATOMIC_MAX
|
||||
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
|
||||
#endif // SIG_ATOMIC_MAX
|
||||
|
||||
// Yes, this has to be here.
|
||||
#include <bcl.h>
|
||||
|
||||
// All of these set defaults for settings.
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
#ifndef BC_DEFAULT_BANNER
|
||||
#define BC_DEFAULT_BANNER (0)
|
||||
#endif // BC_DEFAULT_BANNER
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#ifndef BC_DEFAULT_SIGINT_RESET
|
||||
#define BC_DEFAULT_SIGINT_RESET (1)
|
||||
#endif // BC_DEFAULT_SIGINT_RESET
|
||||
|
||||
#ifndef BC_DEFAULT_TTY_MODE
|
||||
#define BC_DEFAULT_TTY_MODE (1)
|
||||
#endif // BC_DEFAULT_TTY_MODE
|
||||
|
||||
#ifndef BC_DEFAULT_PROMPT
|
||||
#define BC_DEFAULT_PROMPT BC_DEFAULT_TTY_MODE
|
||||
#endif // BC_DEFAULT_PROMPT
|
||||
|
||||
// All of these set defaults for settings.
|
||||
#ifndef DC_DEFAULT_SIGINT_RESET
|
||||
#define DC_DEFAULT_SIGINT_RESET (1)
|
||||
#endif // DC_DEFAULT_SIGINT_RESET
|
||||
|
||||
#ifndef DC_DEFAULT_TTY_MODE
|
||||
#define DC_DEFAULT_TTY_MODE (0)
|
||||
#endif // DC_DEFAULT_TTY_MODE
|
||||
|
||||
#ifndef DC_DEFAULT_HISTORY
|
||||
#define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE
|
||||
#endif // DC_DEFAULT_HISTORY
|
||||
|
||||
#ifndef DC_DEFAULT_PROMPT
|
||||
#define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE
|
||||
#endif // DC_DEFAULT_PROMPT
|
||||
|
||||
/// Statuses, which mark either which category of error happened, or some other
|
||||
/// status that matters.
|
||||
typedef enum BcStatus {
|
||||
|
||||
/// Normal status.
|
||||
BC_STATUS_SUCCESS = 0,
|
||||
|
||||
/// Math error.
|
||||
BC_STATUS_ERROR_MATH,
|
||||
|
||||
/// Parse (and lex) error.
|
||||
BC_STATUS_ERROR_PARSE,
|
||||
|
||||
/// Runtime error.
|
||||
BC_STATUS_ERROR_EXEC,
|
||||
|
||||
/// Fatal error.
|
||||
BC_STATUS_ERROR_FATAL,
|
||||
|
||||
/// EOF status.
|
||||
BC_STATUS_EOF,
|
||||
|
||||
/// Quit status. This means that bc/dc is in the process of quitting.
|
||||
BC_STATUS_QUIT,
|
||||
|
||||
} BcStatus;
|
||||
|
||||
/// Errors, which are more specific errors.
|
||||
typedef enum BcErr {
|
||||
|
||||
// Math errors.
|
||||
|
||||
/// Negative number used when not allowed.
|
||||
BC_ERR_MATH_NEGATIVE,
|
||||
|
||||
/// Non-integer used when not allowed.
|
||||
BC_ERR_MATH_NON_INTEGER,
|
||||
|
||||
/// Conversion to a hardware integer would overflow.
|
||||
BC_ERR_MATH_OVERFLOW,
|
||||
|
||||
/// Divide by zero.
|
||||
BC_ERR_MATH_DIVIDE_BY_ZERO,
|
||||
|
||||
// Fatal errors.
|
||||
|
||||
/// An allocation or reallocation failed.
|
||||
BC_ERR_FATAL_ALLOC_ERR,
|
||||
|
||||
/// I/O failure.
|
||||
BC_ERR_FATAL_IO_ERR,
|
||||
|
||||
/// File error, such as permissions or file does not exist.
|
||||
BC_ERR_FATAL_FILE_ERR,
|
||||
|
||||
/// File is binary, not text, error.
|
||||
BC_ERR_FATAL_BIN_FILE,
|
||||
|
||||
/// Attempted to read a directory as a file error.
|
||||
BC_ERR_FATAL_PATH_DIR,
|
||||
|
||||
/// Invalid option error.
|
||||
BC_ERR_FATAL_OPTION,
|
||||
|
||||
/// Option with required argument not given an argument.
|
||||
BC_ERR_FATAL_OPTION_NO_ARG,
|
||||
|
||||
/// Option with no argument given an argument.
|
||||
BC_ERR_FATAL_OPTION_ARG,
|
||||
|
||||
/// Option argument is invalid.
|
||||
BC_ERR_FATAL_ARG,
|
||||
|
||||
// Runtime errors.
|
||||
|
||||
/// Invalid ibase value.
|
||||
BC_ERR_EXEC_IBASE,
|
||||
|
||||
/// Invalid obase value.
|
||||
BC_ERR_EXEC_OBASE,
|
||||
|
||||
/// Invalid scale value.
|
||||
BC_ERR_EXEC_SCALE,
|
||||
|
||||
/// Invalid expression parsed by read().
|
||||
BC_ERR_EXEC_READ_EXPR,
|
||||
|
||||
/// read() used within an expression given to a read() call.
|
||||
BC_ERR_EXEC_REC_READ,
|
||||
|
||||
/// Type error.
|
||||
BC_ERR_EXEC_TYPE,
|
||||
|
||||
/// Stack has too few elements error.
|
||||
BC_ERR_EXEC_STACK,
|
||||
|
||||
/// Register stack has too few elements error.
|
||||
BC_ERR_EXEC_STACK_REGISTER,
|
||||
|
||||
/// Wrong number of arguments error.
|
||||
BC_ERR_EXEC_PARAMS,
|
||||
|
||||
/// Undefined function error.
|
||||
BC_ERR_EXEC_UNDEF_FUNC,
|
||||
|
||||
/// Void value used in an expression error.
|
||||
BC_ERR_EXEC_VOID_VAL,
|
||||
|
||||
// Parse (and lex errors).
|
||||
|
||||
/// EOF encountered when not expected error.
|
||||
BC_ERR_PARSE_EOF,
|
||||
|
||||
/// Invalid character error.
|
||||
BC_ERR_PARSE_CHAR,
|
||||
|
||||
/// Invalid string (no ending quote) error.
|
||||
BC_ERR_PARSE_STRING,
|
||||
|
||||
/// Invalid comment (no end found) error.
|
||||
BC_ERR_PARSE_COMMENT,
|
||||
|
||||
/// Invalid token encountered error.
|
||||
BC_ERR_PARSE_TOKEN,
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// Invalid expression error.
|
||||
BC_ERR_PARSE_EXPR,
|
||||
|
||||
/// Expression is empty error.
|
||||
BC_ERR_PARSE_EMPTY_EXPR,
|
||||
|
||||
/// Print statement is invalid error.
|
||||
BC_ERR_PARSE_PRINT,
|
||||
|
||||
/// Function definition is invalid error.
|
||||
BC_ERR_PARSE_FUNC,
|
||||
|
||||
/// Assignment is invalid error.
|
||||
BC_ERR_PARSE_ASSIGN,
|
||||
|
||||
/// No auto identifiers given for an auto statement error.
|
||||
BC_ERR_PARSE_NO_AUTO,
|
||||
|
||||
/// Duplicate local (parameter or auto) error.
|
||||
BC_ERR_PARSE_DUP_LOCAL,
|
||||
|
||||
/// Invalid block (within braces) error.
|
||||
BC_ERR_PARSE_BLOCK,
|
||||
|
||||
/// Invalid return statement for void functions.
|
||||
BC_ERR_PARSE_RET_VOID,
|
||||
|
||||
/// Reference attached to a variable, not an array, error.
|
||||
BC_ERR_PARSE_REF_VAR,
|
||||
|
||||
// POSIX-only errors.
|
||||
|
||||
/// Name length greater than 1 error.
|
||||
BC_ERR_POSIX_NAME_LEN,
|
||||
|
||||
/// Non-POSIX comment used error.
|
||||
BC_ERR_POSIX_COMMENT,
|
||||
|
||||
/// Non-POSIX keyword error.
|
||||
BC_ERR_POSIX_KW,
|
||||
|
||||
/// Non-POSIX . (last) error.
|
||||
BC_ERR_POSIX_DOT,
|
||||
|
||||
/// Non-POSIX return error.
|
||||
BC_ERR_POSIX_RET,
|
||||
|
||||
/// Non-POSIX boolean operator used error.
|
||||
BC_ERR_POSIX_BOOL,
|
||||
|
||||
/// POSIX relation operator used outside if, while, or for statements error.
|
||||
BC_ERR_POSIX_REL_POS,
|
||||
|
||||
/// Multiple POSIX relation operators used in an if, while, or for statement
|
||||
/// error.
|
||||
BC_ERR_POSIX_MULTIREL,
|
||||
|
||||
/// Empty statements in POSIX for loop error.
|
||||
BC_ERR_POSIX_FOR,
|
||||
|
||||
/// Non-POSIX exponential (scientific or engineering) number used error.
|
||||
BC_ERR_POSIX_EXP_NUM,
|
||||
|
||||
/// Non-POSIX array reference error.
|
||||
BC_ERR_POSIX_REF,
|
||||
|
||||
/// Non-POSIX void error.
|
||||
BC_ERR_POSIX_VOID,
|
||||
|
||||
/// Non-POSIX brace position used error.
|
||||
BC_ERR_POSIX_BRACE,
|
||||
|
||||
/// String used in expression.
|
||||
BC_ERR_POSIX_EXPR_STRING,
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
// Number of elements.
|
||||
BC_ERR_NELEMS,
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// A marker for the start of POSIX errors.
|
||||
BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN,
|
||||
BC_ERR_POSIX_END = BC_ERR_POSIX_BRACE,
|
||||
|
||||
/// A marker for the end of POSIX errors.
|
||||
BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING,
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
} BcErr;
|
||||
|
||||
// The indices of each category of error in bc_errs[], and used in bc_err_ids[]
|
||||
// to associate actual errors with their categories.
|
||||
|
||||
/// Math error category.
|
||||
#define BC_ERR_IDX_MATH (0)
|
||||
|
||||
/// Parse (and lex) error category.
|
||||
#define BC_ERR_IDX_PARSE (1)
|
||||
|
||||
/// Runtime error category.
|
||||
#define BC_ERR_IDX_EXEC (2)
|
||||
|
||||
/// Fatal error category.
|
||||
#define BC_ERR_IDX_FATAL (3)
|
||||
|
||||
/// Number of categories.
|
||||
#define BC_ERR_IDX_NELEMS (4)
|
||||
|
||||
// If bc is enabled, we add an extra category for POSIX warnings.
|
||||
#if BC_ENABLED
|
||||
|
||||
/// POSIX warning category.
|
||||
#define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS)
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/// 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.
|
||||
#if BC_DEBUG_CODE
|
||||
#define BC_JMP bc_vm_jmp(__func__)
|
||||
#else // BC_DEBUG_CODE
|
||||
#define BC_JMP bc_vm_jmp()
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
/// Returns true if an exception is in flight, false otherwise.
|
||||
#define BC_SIG_EXC \
|
||||
BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig)
|
||||
|
||||
/// Returns true if there is *no* exception in flight, false otherwise.
|
||||
#define BC_NO_SIG_EXC \
|
||||
BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig)
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/// Assert that signals are locked. There are non-async-signal-safe functions in
|
||||
/// bc, and they *must* have signals locked. Other functions are expected to
|
||||
/// *not* have signals locked, for reasons. So this is a pre-built assert
|
||||
/// (no-op in non-debug mode) that check that signals are locked.
|
||||
#define BC_SIG_ASSERT_LOCKED do { assert(vm.sig_lock); } while (0)
|
||||
|
||||
/// Assert that signals are unlocked. There are non-async-signal-safe functions
|
||||
/// in bc, and they *must* have signals locked. Other functions are expected to
|
||||
/// *not* have signals locked, for reasons. So this is a pre-built assert
|
||||
/// (no-op in non-debug mode) that check that signals are unlocked.
|
||||
#define BC_SIG_ASSERT_NOT_LOCKED do { assert(vm.sig_lock == 0); } while (0)
|
||||
|
||||
#else // NDEBUG
|
||||
|
||||
/// Assert that signals are locked. There are non-async-signal-safe functions in
|
||||
/// bc, and they *must* have signals locked. Other functions are expected to
|
||||
/// *not* have signals locked, for reasons. So this is a pre-built assert
|
||||
/// (no-op in non-debug mode) that check that signals are locked.
|
||||
#define BC_SIG_ASSERT_LOCKED
|
||||
|
||||
/// Assert that signals are unlocked. There are non-async-signal-safe functions
|
||||
/// in bc, and they *must* have signals locked. Other functions are expected to
|
||||
/// *not* have signals locked, for reasons. So this is a pre-built assert
|
||||
/// (no-op in non-debug mode) that check that signals are unlocked.
|
||||
#define BC_SIG_ASSERT_NOT_LOCKED
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
/// Locks signals.
|
||||
#define BC_SIG_LOCK \
|
||||
do { \
|
||||
BC_SIG_ASSERT_NOT_LOCKED; \
|
||||
vm.sig_lock = 1; \
|
||||
} while (0)
|
||||
|
||||
/// Unlocks signals. If a signal happened, then this will cause a jump.
|
||||
#define BC_SIG_UNLOCK \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
vm.sig_lock = 0; \
|
||||
if (vm.sig) BC_JMP; \
|
||||
} while (0)
|
||||
|
||||
/// Locks signals, regardless of if they are already locked. This is really only
|
||||
/// used after labels that longjmp() goes to after the jump because the cleanup
|
||||
/// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it
|
||||
/// doesn't jump.
|
||||
#define BC_SIG_MAYLOCK \
|
||||
do { \
|
||||
vm.sig_lock = 1; \
|
||||
} while (0)
|
||||
|
||||
/// Unlocks signals, regardless of if they were already unlocked. If a signal
|
||||
/// happened, then this will cause a jump.
|
||||
#define BC_SIG_MAYUNLOCK \
|
||||
do { \
|
||||
vm.sig_lock = 0; \
|
||||
if (vm.sig) BC_JMP; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Locks signals, but stores the old lock state, to be restored later by
|
||||
* BC_SIG_TRYUNLOCK.
|
||||
* @param v The variable to store the old lock state to.
|
||||
*/
|
||||
#define BC_SIG_TRYLOCK(v) \
|
||||
do { \
|
||||
v = vm.sig_lock; \
|
||||
vm.sig_lock = 1; \
|
||||
} while (0)
|
||||
|
||||
/* Restores the previous state of a signal lock, and if it is now unlocked,
|
||||
* initiates an exception/jump.
|
||||
* @param v The old lock state.
|
||||
*/
|
||||
#define BC_SIG_TRYUNLOCK(v) \
|
||||
do { \
|
||||
vm.sig_lock = (v); \
|
||||
if (!(v) && vm.sig) BC_JMP; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Sets a jump, and sets it up as well so that if a longjmp() happens, bc will
|
||||
* immediately goto a label where some cleanup code is. This one assumes that
|
||||
* signals are not locked and will lock them, set the jump, and unlock them.
|
||||
* Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack.
|
||||
* This grows the jmp_bufs vector first to prevent a fatal error from happening
|
||||
* after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used
|
||||
* *before* the actual initialization calls that need the setjmp().
|
||||
* param l The label to jump to on a longjmp().
|
||||
*/
|
||||
#define BC_SETJMP(l) \
|
||||
do { \
|
||||
sigjmp_buf sjb; \
|
||||
BC_SIG_LOCK; \
|
||||
bc_vec_grow(&vm.jmp_bufs, 1); \
|
||||
if (sigsetjmp(sjb, 0)) { \
|
||||
assert(BC_SIG_EXC); \
|
||||
goto l; \
|
||||
} \
|
||||
bc_vec_push(&vm.jmp_bufs, &sjb); \
|
||||
BC_SIG_UNLOCK; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are
|
||||
* locked and will just set the jump. This does *not* have a call to
|
||||
* bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after*
|
||||
* the initializations that need the setjmp().
|
||||
* param l The label to jump to on a longjmp().
|
||||
*/
|
||||
#define BC_SETJMP_LOCKED(l) \
|
||||
do { \
|
||||
sigjmp_buf sjb; \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
if (sigsetjmp(sjb, 0)) { \
|
||||
assert(BC_SIG_EXC); \
|
||||
goto l; \
|
||||
} \
|
||||
bc_vec_push(&vm.jmp_bufs, &sjb); \
|
||||
} while (0)
|
||||
|
||||
/// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to
|
||||
/// the next place. This is what continues the stack unwinding. This basically
|
||||
/// copies BC_SIG_UNLOCK into itself, but that is because its condition for
|
||||
/// jumping is BC_SIG_EXC, not just that a signal happened.
|
||||
#define BC_LONGJMP_CONT \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \
|
||||
vm.sig_lock = 0; \
|
||||
if (BC_SIG_EXC) BC_JMP; \
|
||||
} while (0)
|
||||
|
||||
/// Unsets a jump. It always assumes signals are locked. This basically just
|
||||
/// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism
|
||||
/// always jumps to the location at the top of the stack, this effectively
|
||||
/// undoes a setjmp().
|
||||
#define BC_UNSETJMP \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
bc_vec_pop(&vm.jmp_bufs); \
|
||||
} while (0)
|
||||
|
||||
/// Stops a stack unwinding. Technically, a stack unwinding needs to be done
|
||||
/// manually, but it will always be done unless certain flags are cleared. This
|
||||
/// clears the flags.
|
||||
#define BC_LONGJMP_STOP \
|
||||
do { \
|
||||
vm.sig_pop = 0; \
|
||||
vm.sig = 0; \
|
||||
} while (0)
|
||||
|
||||
// Various convenience macros for calling the bc's error handling routine.
|
||||
#if BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Call bc's error handling routine.
|
||||
* @param e The error.
|
||||
* @param l The line of the script that the error happened.
|
||||
* @param ... Extra arguments for error messages as necessary.
|
||||
*/
|
||||
#define bc_error(e, l, ...) (bc_vm_handleError((e)))
|
||||
|
||||
/**
|
||||
* Call bc's error handling routine.
|
||||
* @param e The error.
|
||||
*/
|
||||
#define bc_err(e) (bc_vm_handleError((e)))
|
||||
|
||||
/**
|
||||
* Call bc's error handling routine.
|
||||
* @param e The error.
|
||||
*/
|
||||
#define bc_verr(e, ...) (bc_vm_handleError((e)))
|
||||
|
||||
#else // BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Call bc's error handling routine.
|
||||
* @param e The error.
|
||||
* @param l The line of the script that the error happened.
|
||||
* @param ... Extra arguments for error messages as necessary.
|
||||
*/
|
||||
#define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* Call bc's error handling routine.
|
||||
* @param e The error.
|
||||
*/
|
||||
#define bc_err(e) (bc_vm_handleError((e), 0))
|
||||
|
||||
/**
|
||||
* Call bc's error handling routine.
|
||||
* @param e The error.
|
||||
*/
|
||||
#define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__))
|
||||
|
||||
#endif // BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Returns true if status @a s is an error, false otherwise.
|
||||
* @param s The status to test.
|
||||
* @return True if @a s is an error, false otherwise.
|
||||
*/
|
||||
#define BC_STATUS_IS_ERROR(s) \
|
||||
((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL)
|
||||
|
||||
// Convenience macros that can be placed at the beginning and exits of functions
|
||||
// for easy marking of where functions are entered and exited.
|
||||
#if BC_DEBUG_CODE
|
||||
#define BC_FUNC_ENTER \
|
||||
do { \
|
||||
size_t bc_func_enter_i; \
|
||||
for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
|
||||
++bc_func_enter_i) \
|
||||
{ \
|
||||
bc_file_puts(&vm.ferr, bc_flush_none, " "); \
|
||||
} \
|
||||
vm.func_depth += 1; \
|
||||
bc_file_printf(&vm.ferr, "Entering %s\n", __func__); \
|
||||
bc_file_flush(&vm.ferr, bc_flush_none); \
|
||||
} while (0);
|
||||
|
||||
#define BC_FUNC_EXIT \
|
||||
do { \
|
||||
size_t bc_func_enter_i; \
|
||||
vm.func_depth -= 1; \
|
||||
for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
|
||||
++bc_func_enter_i) \
|
||||
{ \
|
||||
bc_file_puts(&vm.ferr, bc_flush_none, " "); \
|
||||
} \
|
||||
bc_file_printf(&vm.ferr, "Leaving %s\n", __func__); \
|
||||
bc_file_flush(&vm.ferr, bc_flush_none); \
|
||||
} while (0);
|
||||
#else // BC_DEBUG_CODE
|
||||
#define BC_FUNC_ENTER
|
||||
#define BC_FUNC_EXIT
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
#endif // BC_STATUS_H
|
||||
|
|
378
include/vector.h
378
include/vector.h
|
@ -42,62 +42,420 @@
|
|||
|
||||
#include <status.h>
|
||||
|
||||
/// An invalid index for a map to mark when an item does not exist.
|
||||
#define BC_VEC_INVALID_IDX (SIZE_MAX)
|
||||
|
||||
/// The starting capacity for vectors. This is based on the minimum allocation
|
||||
/// for 64-bit systems.
|
||||
#define BC_VEC_START_CAP (UINTMAX_C(1)<<5)
|
||||
|
||||
/// An alias.
|
||||
typedef unsigned char uchar;
|
||||
|
||||
typedef void (*BcVecFree)(void*);
|
||||
/**
|
||||
* A destructor. Frees the object that @a ptr points to. This is used by vectors
|
||||
* to free the memory they own.
|
||||
* @param ptr Pointer to the data to free.
|
||||
*/
|
||||
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.
|
||||
typedef uint32_t BcSize;
|
||||
|
||||
#else // BC_LONG_BIT >= 64
|
||||
|
||||
/// An integer to shrink the size of a vector by using these instead of size_t.
|
||||
typedef uint16_t BcSize;
|
||||
|
||||
#endif // BC_LONG_BIT >= 64
|
||||
|
||||
/// An enum of all of the destructors. We use an enum to save space.
|
||||
typedef enum BcDtorType {
|
||||
|
||||
/// No destructor needed.
|
||||
BC_DTOR_NONE,
|
||||
|
||||
/// Vector destructor.
|
||||
BC_DTOR_VEC,
|
||||
|
||||
/// BcNum destructor.
|
||||
BC_DTOR_NUM,
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/// BcFunc destructor.
|
||||
BC_DTOR_FUNC,
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
/// BcSlab destructor.
|
||||
BC_DTOR_SLAB,
|
||||
|
||||
/// BcConst destructor.
|
||||
BC_DTOR_CONST,
|
||||
|
||||
/// BcResult destructor.
|
||||
BC_DTOR_RESULT,
|
||||
|
||||
#if BC_ENABLE_HISTORY
|
||||
|
||||
/// String destructor for history, which is *special*.
|
||||
BC_DTOR_HISTORY_STRING,
|
||||
|
||||
#endif // BC_ENABLE_HISTORY
|
||||
#else // !BC_ENABLE_LIBRARY
|
||||
|
||||
/// Destructor for bcl numbers.
|
||||
BC_DTOR_BCL_NUM,
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
} BcDtorType;
|
||||
|
||||
/// The actual vector struct.
|
||||
typedef struct BcVec {
|
||||
char *v;
|
||||
|
||||
/// The vector array itself. This uses a char* because it is compatible with
|
||||
/// pointers of all other types, and I can do pointer arithmetic on it.
|
||||
char *restrict v;
|
||||
|
||||
/// The length of the vector, which is how many items actually exist.
|
||||
size_t len;
|
||||
|
||||
/// The capacity of the vector, which is how many items can fit in the
|
||||
/// current allocation.
|
||||
size_t cap;
|
||||
size_t size;
|
||||
BcVecFree dtor;
|
||||
|
||||
/// The size of the items in the vector, as returned by sizeof().
|
||||
BcSize size;
|
||||
|
||||
/// The destructor as a BcDtorType enum.
|
||||
BcSize dtor;
|
||||
|
||||
} BcVec;
|
||||
|
||||
void bc_vec_init(BcVec *restrict v, size_t esize, BcVecFree dtor);
|
||||
/**
|
||||
* Initializes a vector.
|
||||
* @param v The vector to initialize.
|
||||
* @param esize The size of the elements, as returned by sizeof().
|
||||
* @param dtor The destructor of the elements, as a BcDtorType enum.
|
||||
*/
|
||||
void bc_vec_init(BcVec *restrict v, size_t esize, BcDtorType dtor);
|
||||
|
||||
/**
|
||||
* Expands the vector to have a capacity of @a req items, if it doesn't have
|
||||
* enough already.
|
||||
* @param v The vector to expand.
|
||||
* @param req The requested capacity.
|
||||
*/
|
||||
void bc_vec_expand(BcVec *restrict v, size_t req);
|
||||
|
||||
/**
|
||||
* Grow a vector by at least @a n elements.
|
||||
* @param v The vector to grow.
|
||||
* @param n The number of elements to grow the vector by.
|
||||
*/
|
||||
void bc_vec_grow(BcVec *restrict v, size_t n);
|
||||
|
||||
/**
|
||||
* Pops @a n items off the back of the vector. The vector must have at least
|
||||
* @a n elements.
|
||||
* @param v The vector to pop off of.
|
||||
* @param n The number of elements to pop off.
|
||||
*/
|
||||
void bc_vec_npop(BcVec *restrict v, size_t n);
|
||||
|
||||
/**
|
||||
* Pops @a n items, starting at index @a idx, off the vector. The vector must
|
||||
* have at least @a n elements after the @a idx index. Any remaining elements at
|
||||
* the end are moved up to fill the hole.
|
||||
* @param v The vector to pop off of.
|
||||
* @param n The number of elements to pop off.
|
||||
* @param idx The index to start popping at.
|
||||
*/
|
||||
void bc_vec_npopAt(BcVec *restrict v, size_t n, size_t idx);
|
||||
|
||||
/**
|
||||
* Pushes one item on the back of the vector. It does a memcpy(), but it assumes
|
||||
* that the vector takes ownership of the data.
|
||||
* @param v The vector to push onto.
|
||||
* @param data A pointer to the data to push.
|
||||
*/
|
||||
void bc_vec_push(BcVec *restrict v, const void *data);
|
||||
|
||||
/**
|
||||
* Pushes @a n items on the back of the vector. It does a memcpy(), but it
|
||||
* assumes that the vector takes ownership of the data.
|
||||
* @param v The vector to push onto.
|
||||
* @param data A pointer to the elements of data to push.
|
||||
*/
|
||||
void bc_vec_npush(BcVec *restrict v, size_t n, const void *data);
|
||||
|
||||
/**
|
||||
* Push an empty element and return a pointer to it. This is done as an
|
||||
* optimization where initializing an item needs a pointer anyway. It removes an
|
||||
* extra memcpy().
|
||||
* @param v The vector to push onto.
|
||||
* @return A pointer to the newly-pushed element.
|
||||
*/
|
||||
void* bc_vec_pushEmpty(BcVec *restrict v);
|
||||
|
||||
/**
|
||||
* Pushes a byte onto a bytecode vector. This is a convenience function for the
|
||||
* parsers pushing instructions. The vector must be a bytecode vector.
|
||||
* @param v The vector to push onto.
|
||||
* @param data The byte to push.
|
||||
*/
|
||||
void bc_vec_pushByte(BcVec *restrict v, uchar data);
|
||||
|
||||
/**
|
||||
* Pushes and index onto a bytecode vector. The vector must be a bytecode
|
||||
* vector. For more info about why and how this is done, see the development
|
||||
* manual (manuals/development#bytecode-indices).
|
||||
* @param v The vector to push onto.
|
||||
* @param idx The index to push.
|
||||
*/
|
||||
void bc_vec_pushIndex(BcVec *restrict v, size_t idx);
|
||||
|
||||
/**
|
||||
* Push an item onto the vector at a certain index. The index must be valid
|
||||
* (either exists or is equal to the length of the vector). The elements at that
|
||||
* index and after are moved back one element and kept in the same order. This
|
||||
* is how the map vectors are kept sorted.
|
||||
* @param v The vector to push onto.
|
||||
* @param data A pointer to the data to push.
|
||||
* @param idx The index to push at.
|
||||
*/
|
||||
void bc_vec_pushAt(BcVec *restrict v, const void *data, size_t idx);
|
||||
|
||||
/**
|
||||
* Empties the vector and sets it to the string. The vector must be a valid
|
||||
* vector and must have chars as its elements.
|
||||
* @param v The vector to set to the string.
|
||||
* @param len The length of the string. This can be less than the actual length
|
||||
* of the string, but must never be more.
|
||||
* @param str The string to push.
|
||||
*/
|
||||
void bc_vec_string(BcVec *restrict v, size_t len, const char *restrict str);
|
||||
|
||||
/**
|
||||
* Appends the string to the end of the vector, which must be holding a string
|
||||
* (nul byte-terminated) already.
|
||||
* @param v The vector to append to.
|
||||
* @param str The string to append (by copying).
|
||||
*/
|
||||
void bc_vec_concat(BcVec *restrict v, const char *restrict str);
|
||||
|
||||
/**
|
||||
* Empties a vector and pushes a nul-byte at the first index. The vector must be
|
||||
* a char vector.
|
||||
*/
|
||||
void bc_vec_empty(BcVec *restrict v);
|
||||
|
||||
#if BC_ENABLE_HISTORY
|
||||
|
||||
/**
|
||||
* Replaces an item at a particular index. No elements are moved. The index must
|
||||
* exist.
|
||||
* @param v The vector to replace an item on.
|
||||
* @param idx The index of the item to replace.
|
||||
* @param data The data to replace the item with.
|
||||
*/
|
||||
void bc_vec_replaceAt(BcVec *restrict v, size_t idx, const void *data);
|
||||
|
||||
#endif // BC_ENABLE_HISTORY
|
||||
|
||||
/**
|
||||
* Returns a pointer to the item in the vector at the index. This is the key
|
||||
* function for vectors. The index must exist.
|
||||
* @param v The vector.
|
||||
* @param idx The index to the item to get a pointer to.
|
||||
* @return A pointer to the item at @a idx.
|
||||
*/
|
||||
void* bc_vec_item(const BcVec *restrict v, size_t idx);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the item in the vector at the index, reversed. This is
|
||||
* another key function for vectors. The index must exist.
|
||||
* @param v The vector.
|
||||
* @param idx The index to the item to get a pointer to.
|
||||
* @return A pointer to the item at len - @a idx - 1.
|
||||
*/
|
||||
void* bc_vec_item_rev(const BcVec *restrict v, size_t idx);
|
||||
|
||||
/**
|
||||
* Zeros a vector. The vector must not be allocated.
|
||||
* @param v The vector to clear.
|
||||
*/
|
||||
void bc_vec_clear(BcVec *restrict v);
|
||||
|
||||
/**
|
||||
* Frees a vector and its elements. This is a destructor.
|
||||
* @param vec A vector as a void pointer.
|
||||
*/
|
||||
void bc_vec_free(void *vec);
|
||||
|
||||
/**
|
||||
* Attempts to insert an item 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
|
||||
* by another entity.
|
||||
* @param idx The index of the partner array where the actual item is.
|
||||
* @param i A pointer to an index that will be set to the index of the item
|
||||
* in the map.
|
||||
* @return True if the item was inserted, false if the item already exists.
|
||||
*/
|
||||
bool bc_map_insert(BcVec *restrict v, const char *name,
|
||||
size_t idx, size_t *restrict i);
|
||||
|
||||
/**
|
||||
* Returns the index of the item with @a name in the map, or BC_VEC_INVALID_IDX
|
||||
* if it doesn't exist.
|
||||
* @param v The map vector.
|
||||
* @param name The name of the item to find.
|
||||
* @return The index in the map of the item with @a name, or
|
||||
* BC_VEC_INVALID_IDX if the item does not exist.
|
||||
*/
|
||||
size_t bc_map_index(const BcVec *restrict v, const char *name);
|
||||
|
||||
#if DC_ENABLED
|
||||
|
||||
/**
|
||||
* Returns the name of the item at index @a idx in the map.
|
||||
* @param v The map vector.
|
||||
* @param idx The index.
|
||||
* @return The name of the item at @a idx.
|
||||
*/
|
||||
const char* bc_map_name(const BcVec *restrict v, size_t idx);
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
/**
|
||||
* Pops one item off of the vector.
|
||||
* @param v The vector to pop one item off of.
|
||||
*/
|
||||
#define bc_vec_pop(v) (bc_vec_npop((v), 1))
|
||||
|
||||
/**
|
||||
* Pops all items off of the vector.
|
||||
* @param v The vector to pop all items off of.
|
||||
*/
|
||||
#define bc_vec_popAll(v) (bc_vec_npop((v), (v)->len))
|
||||
|
||||
/**
|
||||
* Return a pointer to the last item in the vector, or first if it's being
|
||||
* treated as a stack.
|
||||
* @param v The vector to get the top of stack of.
|
||||
*/
|
||||
#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
|
||||
#else // NDEBUG
|
||||
#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), NULL))
|
||||
#endif // NDEBUG
|
||||
/**
|
||||
* Initializes a vector to serve as a map.
|
||||
* @param v The vector to initialize.
|
||||
*/
|
||||
#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), BC_DTOR_NONE))
|
||||
|
||||
/// A reference to the array of destructors.
|
||||
extern const BcVecFree bc_vec_dtors[];
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
/// The allocated size of slabs.
|
||||
#define BC_SLAB_SIZE (4096)
|
||||
|
||||
/// A slab for allocating strings.
|
||||
typedef struct BcSlab {
|
||||
|
||||
/// The actual allocation.
|
||||
char *s;
|
||||
|
||||
/// How many bytes of the slab are taken.
|
||||
size_t len;
|
||||
|
||||
} BcSlab;
|
||||
|
||||
/**
|
||||
* Frees a slab. This is a destructor.
|
||||
* @param slab The slab as a void pointer.
|
||||
*/
|
||||
void bc_slab_free(void *slab);
|
||||
|
||||
/**
|
||||
* Initializes a slab vector.
|
||||
* @param v The vector to initialize.
|
||||
*/
|
||||
void bc_slabvec_init(BcVec *restrict v);
|
||||
|
||||
/**
|
||||
* Duplicates the string using slabs in the slab vector.
|
||||
* @param v The slab vector.
|
||||
* @param str The string to duplicate.
|
||||
* @return A pointer to the duplicated string, owned by the slab vector.
|
||||
*/
|
||||
char* bc_slabvec_strdup(BcVec *restrict v, const char *str);
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/**
|
||||
* Undoes the last allocation on the slab vector. This allows bc to have a
|
||||
* heap-based stacks for strings. This is used by the bc parser.
|
||||
*/
|
||||
void bc_slabvec_undo(BcVec *restrict v, size_t len);
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
/**
|
||||
* Clears a slab vector. This deallocates all but the first slab and clears the
|
||||
* first slab.
|
||||
* @param v The slab vector to clear.
|
||||
*/
|
||||
void bc_slabvec_clear(BcVec *restrict v);
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
|
||||
/**
|
||||
* Prints all of the items in a slab vector, in order.
|
||||
* @param v The vector whose items will be printed.
|
||||
*/
|
||||
void bc_slabvec_print(BcVec *v, const char *func);
|
||||
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
/// A convenience macro for freeing a vector of slabs.
|
||||
#define bc_slabvec_free bc_vec_free
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/**
|
||||
* A macro to get rid of a warning on Windows.
|
||||
* @param d The destination string.
|
||||
* @param l The length of the destination string. This has to be big enough to
|
||||
* contain @a s.
|
||||
* @param s The source string.
|
||||
*/
|
||||
#define strcpy(d, l, s) strcpy(d, s)
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
/**
|
||||
* A macro to get rid of a warning on Windows.
|
||||
* @param d The destination string.
|
||||
* @param l The length of the destination string. This has to be big enough to
|
||||
* contain @a s.
|
||||
* @param s The source string.
|
||||
*/
|
||||
#define strcpy(d, l, s) strcpy_s(d, l, s)
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
#endif // BC_VECTOR_H
|
||||
|
|
|
@ -29,13 +29,14 @@
|
|||
*
|
||||
* *****************************************************************************
|
||||
*
|
||||
* Definitions for processing command-line arguments.
|
||||
* The version of bc.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BC_VERSION_H
|
||||
#define BC_VERSION_H
|
||||
|
||||
#define VERSION 4.0.2
|
||||
/// The current version.
|
||||
#define VERSION 5.0.0
|
||||
|
||||
#endif // BC_VERSION_H
|
||||
|
|
682
include/vm.h
682
include/vm.h
|
@ -44,9 +44,9 @@
|
|||
|
||||
#if BC_ENABLE_NLS
|
||||
|
||||
# ifdef _WIN32
|
||||
# error NLS is not supported on Windows.
|
||||
# endif // _WIN32
|
||||
#ifdef _WIN32
|
||||
#error NLS is not supported on Windows.
|
||||
#endif // _WIN32
|
||||
|
||||
#include <nl_types.h>
|
||||
|
||||
|
@ -55,23 +55,30 @@
|
|||
#include <version.h>
|
||||
#include <status.h>
|
||||
#include <num.h>
|
||||
#include <lex.h>
|
||||
#include <parse.h>
|
||||
#include <program.h>
|
||||
#include <history.h>
|
||||
#include <bc.h>
|
||||
|
||||
// We don't want to include this file for the library because it's unused.
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
#include <file.h>
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
// This should be obvious. If neither calculator is enabled, barf.
|
||||
#if !BC_ENABLED && !DC_ENABLED
|
||||
#error Must define BC_ENABLED, DC_ENABLED, or both
|
||||
#endif
|
||||
|
||||
// CHAR_BIT must be at least 6.
|
||||
// CHAR_BIT must be at least 6, for various reasons. I might want to bump this
|
||||
// to 8 in the future.
|
||||
#if CHAR_BIT < 6
|
||||
#error CHAR_BIT must be at least 6.
|
||||
#endif
|
||||
|
||||
// Set defaults.
|
||||
//
|
||||
#ifndef BC_ENABLE_NLS
|
||||
#define BC_ENABLE_NLS (0)
|
||||
#endif // BC_ENABLE_NLS
|
||||
|
@ -88,13 +95,32 @@
|
|||
#undef EXECPREFIX
|
||||
#endif // _WIN32
|
||||
|
||||
/**
|
||||
* Generate a string from text.
|
||||
* @parm V The text to generate a string for.
|
||||
*/
|
||||
#define GEN_STR(V) #V
|
||||
|
||||
/**
|
||||
* Help generate a string from text. The preprocessor requires this two-step
|
||||
* process. Trust me.
|
||||
* @parm V The text to generate a string for.
|
||||
*/
|
||||
#define GEN_STR2(V) GEN_STR(V)
|
||||
|
||||
/// The version as a string. VERSION must be defined previously, usually by the
|
||||
/// build system.
|
||||
#define BC_VERSION GEN_STR2(VERSION)
|
||||
|
||||
/// The main executable name as a string. MAINEXEC must be defined previously,
|
||||
/// usually by the build system.
|
||||
#define BC_MAINEXEC GEN_STR2(MAINEXEC)
|
||||
|
||||
/// The build type as a string. BUILD_TYPE must be defined previously, usually
|
||||
/// by the build system.
|
||||
#define BC_BUILD_TYPE GEN_STR2(BUILD_TYPE)
|
||||
|
||||
// We only allow an empty executable prefix on Windows.
|
||||
#ifndef _WIN32
|
||||
#define BC_EXECPREFIX GEN_STR2(EXECPREFIX)
|
||||
#else // _WIN32
|
||||
|
@ -104,372 +130,734 @@
|
|||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
#if DC_ENABLED
|
||||
|
||||
/// The flag for the extended register option.
|
||||
#define DC_FLAG_X (UINTMAX_C(1)<<0)
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// The flag for the POSIX warning option.
|
||||
#define BC_FLAG_W (UINTMAX_C(1)<<1)
|
||||
|
||||
/// The flag for the POSIX error option.
|
||||
#define BC_FLAG_S (UINTMAX_C(1)<<2)
|
||||
|
||||
/// The flag for the math library option.
|
||||
#define BC_FLAG_L (UINTMAX_C(1)<<3)
|
||||
|
||||
/// The flag for the global stacks option.
|
||||
#define BC_FLAG_G (UINTMAX_C(1)<<4)
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#define BC_FLAG_I (UINTMAX_C(1)<<5)
|
||||
#define BC_FLAG_P (UINTMAX_C(1)<<6)
|
||||
#define BC_FLAG_R (UINTMAX_C(1)<<7)
|
||||
#define BC_FLAG_TTYIN (UINTMAX_C(1)<<8)
|
||||
#define BC_FLAG_TTY (UINTMAX_C(1)<<9)
|
||||
/// The flag for quiet, though this one is reversed; the option clears the flag.
|
||||
#define BC_FLAG_Q (UINTMAX_C(1)<<5)
|
||||
|
||||
/// The flag for interactive.
|
||||
#define BC_FLAG_I (UINTMAX_C(1)<<6)
|
||||
|
||||
/// The flag for prompt. This is also reversed; the option clears the flag.
|
||||
#define BC_FLAG_P (UINTMAX_C(1)<<7)
|
||||
|
||||
/// The flag for read prompt. This is also reversed; the option clears the flag.
|
||||
#define BC_FLAG_R (UINTMAX_C(1)<<8)
|
||||
|
||||
/// The flag for stdin being a TTY.
|
||||
#define BC_FLAG_TTYIN (UINTMAX_C(1)<<9)
|
||||
|
||||
/// The flag for TTY mode.
|
||||
#define BC_FLAG_TTY (UINTMAX_C(1)<<10)
|
||||
|
||||
/// The flag for reset on SIGINT.
|
||||
#define BC_FLAG_SIGINT (UINTMAX_C(1)<<11)
|
||||
|
||||
/// A convenience macro for getting the TTYIN flag.
|
||||
#define BC_TTYIN (vm.flags & BC_FLAG_TTYIN)
|
||||
|
||||
/// A convenience macro for getting the TTY flag.
|
||||
#define BC_TTY (vm.flags & BC_FLAG_TTY)
|
||||
|
||||
/// A convenience macro for getting the SIGINT flag.
|
||||
#define BC_SIGINT (vm.flags & BC_FLAG_SIGINT)
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// A convenience macro for getting the POSIX error flag.
|
||||
#define BC_S (vm.flags & BC_FLAG_S)
|
||||
|
||||
/// A convenience macro for getting the POSIX warning flag.
|
||||
#define BC_W (vm.flags & BC_FLAG_W)
|
||||
|
||||
/// A convenience macro for getting the math library flag.
|
||||
#define BC_L (vm.flags & BC_FLAG_L)
|
||||
|
||||
/// A convenience macro for getting the global stacks flag.
|
||||
#define BC_G (vm.flags & BC_FLAG_G)
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#if DC_ENABLED
|
||||
|
||||
/// A convenience macro for getting the extended register flag.
|
||||
#define DC_X (vm.flags & DC_FLAG_X)
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
/// A convenience macro for getting the interactive flag.
|
||||
#define BC_I (vm.flags & BC_FLAG_I)
|
||||
|
||||
/// A convenience macro for getting the prompt flag.
|
||||
#define BC_P (vm.flags & BC_FLAG_P)
|
||||
|
||||
/// A convenience macro for getting the read prompt flag.
|
||||
#define BC_R (vm.flags & BC_FLAG_R)
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// A convenience macro for checking if bc is in POSIX mode.
|
||||
#define BC_IS_POSIX (BC_S || BC_W)
|
||||
|
||||
#if DC_ENABLED
|
||||
|
||||
/// Returns true if bc is running.
|
||||
#define BC_IS_BC (vm.name[0] != 'd')
|
||||
|
||||
/// Returns true if dc is running.
|
||||
#define BC_IS_DC (vm.name[0] == 'd')
|
||||
|
||||
#else // DC_ENABLED
|
||||
|
||||
/// Returns true if bc is running.
|
||||
#define BC_IS_BC (1)
|
||||
|
||||
/// Returns true if dc is running.
|
||||
#define BC_IS_DC (0)
|
||||
|
||||
#endif // DC_ENABLED
|
||||
|
||||
#else // BC_ENABLED
|
||||
|
||||
/// A convenience macro for checking if bc is in POSIX mode.
|
||||
#define BC_IS_POSIX (0)
|
||||
|
||||
/// Returns true if bc is running.
|
||||
#define BC_IS_BC (0)
|
||||
|
||||
/// Returns true if dc is running.
|
||||
#define BC_IS_DC (1)
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#if BC_ENABLED
|
||||
#define BC_USE_PROMPT (!BC_P && BC_TTY && !BC_IS_POSIX)
|
||||
#else // BC_ENABLED
|
||||
#define BC_USE_PROMPT (!BC_P && BC_TTY)
|
||||
#endif // BC_ENABLED
|
||||
/// A convenience macro for checking if the prompt is enabled.
|
||||
#define BC_PROMPT (BC_P)
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Returns the max of its two arguments. This evaluates arguments twice, so be
|
||||
* careful what args you give it.
|
||||
* @param a The first argument.
|
||||
* @param b The second argument.
|
||||
* @return The max of the two arguments.
|
||||
*/
|
||||
#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
/**
|
||||
* Returns the min of its two arguments. This evaluates arguments twice, so be
|
||||
* careful what args you give it.
|
||||
* @param a The first argument.
|
||||
* @param b The second argument.
|
||||
* @return The min of the two arguments.
|
||||
*/
|
||||
#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
/// Returns the max obase that is allowed.
|
||||
#define BC_MAX_OBASE ((BcBigDig) (BC_BASE_POW))
|
||||
|
||||
/// Returns the max array size that is allowed.
|
||||
#define BC_MAX_DIM ((BcBigDig) (SIZE_MAX - 1))
|
||||
|
||||
/// Returns the max scale that is allowed.
|
||||
#define BC_MAX_SCALE ((BcBigDig) (BC_NUM_BIGDIG_MAX - 1))
|
||||
|
||||
/// Returns the max string length that is allowed.
|
||||
#define BC_MAX_STRING ((BcBigDig) (BC_NUM_BIGDIG_MAX - 1))
|
||||
|
||||
/// Returns the max identifier length that is allowed.
|
||||
#define BC_MAX_NAME BC_MAX_STRING
|
||||
|
||||
/// Returns the max number size that is allowed.
|
||||
#define BC_MAX_NUM BC_MAX_SCALE
|
||||
|
||||
#if BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Returns the max random integer that can be returned.
|
||||
#define BC_MAX_RAND ((BcBigDig) (((BcRand) 0) - 1))
|
||||
|
||||
#endif // BC_ENABLE_EXTRA_MATH
|
||||
|
||||
/// Returns the max exponent that is allowed.
|
||||
#define BC_MAX_EXP ((ulong) (BC_NUM_BIGDIG_MAX))
|
||||
|
||||
/// Returns the max number of variables that is allowed.
|
||||
#define BC_MAX_VARS ((ulong) (SIZE_MAX - 1))
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
#define BC_VM_JMP bc_vm_jmp(__func__)
|
||||
#else // BC_DEBUG_CODE
|
||||
#define BC_VM_JMP bc_vm_jmp()
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
#define BC_SIG_EXC \
|
||||
BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig)
|
||||
#define BC_NO_SIG_EXC \
|
||||
BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define BC_SIG_ASSERT_LOCKED do { assert(vm.sig_lock); } while (0)
|
||||
#define BC_SIG_ASSERT_NOT_LOCKED do { assert(vm.sig_lock == 0); } while (0)
|
||||
#else // NDEBUG
|
||||
#define BC_SIG_ASSERT_LOCKED
|
||||
#define BC_SIG_ASSERT_NOT_LOCKED
|
||||
#endif // NDEBUG
|
||||
|
||||
#define BC_SIG_LOCK \
|
||||
do { \
|
||||
BC_SIG_ASSERT_NOT_LOCKED; \
|
||||
vm.sig_lock = 1; \
|
||||
} while (0)
|
||||
|
||||
#define BC_SIG_UNLOCK \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
vm.sig_lock = 0; \
|
||||
if (BC_SIG_EXC) BC_VM_JMP; \
|
||||
} while (0)
|
||||
|
||||
#define BC_SIG_MAYLOCK \
|
||||
do { \
|
||||
vm.sig_lock = 1; \
|
||||
} while (0)
|
||||
|
||||
#define BC_SIG_MAYUNLOCK \
|
||||
do { \
|
||||
vm.sig_lock = 0; \
|
||||
if (BC_SIG_EXC) BC_VM_JMP; \
|
||||
} while (0)
|
||||
|
||||
#define BC_SIG_TRYLOCK(v) \
|
||||
do { \
|
||||
v = vm.sig_lock; \
|
||||
vm.sig_lock = 1; \
|
||||
} while (0)
|
||||
|
||||
#define BC_SIG_TRYUNLOCK(v) \
|
||||
do { \
|
||||
vm.sig_lock = (v); \
|
||||
if (!(v) && BC_SIG_EXC) BC_VM_JMP; \
|
||||
} while (0)
|
||||
|
||||
#define BC_SETJMP(l) \
|
||||
do { \
|
||||
sigjmp_buf sjb; \
|
||||
BC_SIG_LOCK; \
|
||||
if (sigsetjmp(sjb, 0)) { \
|
||||
assert(BC_SIG_EXC); \
|
||||
goto l; \
|
||||
} \
|
||||
bc_vec_push(&vm.jmp_bufs, &sjb); \
|
||||
BC_SIG_UNLOCK; \
|
||||
} while (0)
|
||||
|
||||
#define BC_SETJMP_LOCKED(l) \
|
||||
do { \
|
||||
sigjmp_buf sjb; \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
if (sigsetjmp(sjb, 0)) { \
|
||||
assert(BC_SIG_EXC); \
|
||||
goto l; \
|
||||
} \
|
||||
bc_vec_push(&vm.jmp_bufs, &sjb); \
|
||||
} while (0)
|
||||
|
||||
#define BC_LONGJMP_CONT \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \
|
||||
BC_SIG_UNLOCK; \
|
||||
} while (0)
|
||||
|
||||
#define BC_UNSETJMP \
|
||||
do { \
|
||||
BC_SIG_ASSERT_LOCKED; \
|
||||
bc_vec_pop(&vm.jmp_bufs); \
|
||||
} while (0)
|
||||
|
||||
#define BC_LONGJMP_STOP \
|
||||
do { \
|
||||
vm.sig_pop = 0; \
|
||||
vm.sig = 0; \
|
||||
} while (0)
|
||||
|
||||
/// The size of the global buffer.
|
||||
#define BC_VM_BUF_SIZE (1<<12)
|
||||
|
||||
/// The amount of the global buffer allocated to stdout.
|
||||
#define BC_VM_STDOUT_BUF_SIZE (1<<11)
|
||||
|
||||
/// The amount of the global buffer allocated to stderr.
|
||||
#define BC_VM_STDERR_BUF_SIZE (1<<10)
|
||||
|
||||
/// The amount of the global buffer allocated to stdin.
|
||||
#define BC_VM_STDIN_BUF_SIZE (BC_VM_STDERR_BUF_SIZE - 1)
|
||||
|
||||
/// The max number of temporary BcNums that can be kept.
|
||||
#define BC_VM_MAX_TEMPS (1 << 9)
|
||||
|
||||
/// The capacity of the one BcNum, which is a constant.
|
||||
#define BC_VM_ONE_CAP (1)
|
||||
|
||||
/**
|
||||
* Returns true if a BcResult is safe for garbage collection.
|
||||
* @param r The BcResult to test.
|
||||
* @return True if @a r is safe to garbage collect.
|
||||
*/
|
||||
#define BC_VM_SAFE_RESULT(r) ((r)->t >= BC_RESULT_TEMP)
|
||||
|
||||
#if BC_ENABLE_LIBRARY
|
||||
#define bc_vm_error(e, l, ...) (bc_vm_handleError((e)))
|
||||
#define bc_vm_err(e) (bc_vm_handleError((e)))
|
||||
#define bc_vm_verr(e, ...) (bc_vm_handleError((e)))
|
||||
#else // BC_ENABLE_LIBRARY
|
||||
#define bc_vm_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__))
|
||||
#define bc_vm_err(e) (bc_vm_handleError((e), 0))
|
||||
#define bc_vm_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__))
|
||||
#endif // BC_ENABLE_LIBRARY
|
||||
|
||||
#define BC_STATUS_IS_ERROR(s) \
|
||||
((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL)
|
||||
|
||||
/// The invalid locale catalog return value.
|
||||
#define BC_VM_INVALID_CATALOG ((nl_catd) -1)
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
#define BC_VM_FUNC_ENTER \
|
||||
do { \
|
||||
bc_file_printf(&vm.ferr, "Entering %s\n", __func__); \
|
||||
bc_file_flush(&vm.ferr); \
|
||||
} while (0);
|
||||
|
||||
#define BC_VM_FUNC_EXIT \
|
||||
do { \
|
||||
bc_file_printf(&vm.ferr, "Leaving %s\n", __func__); \
|
||||
bc_file_flush(&vm.ferr); \
|
||||
} while (0);
|
||||
#else // BC_DEBUG_CODE
|
||||
#define BC_VM_FUNC_ENTER
|
||||
#define BC_VM_FUNC_EXIT
|
||||
#endif // BC_DEBUG_CODE
|
||||
/**
|
||||
* Returns true if the *unsigned* multiplication overflows.
|
||||
* @param a The first operand.
|
||||
* @param b The second operand.
|
||||
* @param r The product.
|
||||
* @return True if the multiplication of @a a and @a b overflows.
|
||||
*/
|
||||
#define BC_VM_MUL_OVERFLOW(a, b, r) \
|
||||
((r) >= SIZE_MAX || ((a) != 0 && (r) / (a) != (b)))
|
||||
|
||||
/// The global vm struct. This holds all of the global data besides the file
|
||||
/// buffers.
|
||||
typedef struct BcVm {
|
||||
|
||||
/// The current status. This is volatile sig_atomic_t because it is also
|
||||
/// used in the signal handler. See the development manual
|
||||
/// (manuals/development.md#async-signal-safe-signal-handling) for more
|
||||
/// information.
|
||||
volatile sig_atomic_t status;
|
||||
|
||||
/// Non-zero if a jump series is in progress and items should be popped off
|
||||
/// the jmp_bufs vector. This is volatile sig_atomic_t because it is also
|
||||
/// used in the signal handler. See the development manual
|
||||
/// (manuals/development.md#async-signal-safe-signal-handling) for more
|
||||
/// information.
|
||||
volatile sig_atomic_t sig_pop;
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
/// The parser.
|
||||
BcParse prs;
|
||||
|
||||
/// The program.
|
||||
BcProgram prog;
|
||||
|
||||
/// A buffer for lines for stdin.
|
||||
BcVec line_buf;
|
||||
|
||||
/// A buffer to hold a series of lines from stdin. Sometimes, multiple lines
|
||||
/// are necessary for parsing, such as a comment that spans multiple lines.
|
||||
BcVec buffer;
|
||||
|
||||
/// A parser to parse read expressions.
|
||||
BcParse read_prs;
|
||||
|
||||
/// A buffer for read expressions.
|
||||
BcVec read_buf;
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
/// A vector of jmp_bufs for doing a jump series. This allows exception-type
|
||||
/// error handling, while allowing me to do cleanup on the way.
|
||||
BcVec jmp_bufs;
|
||||
|
||||
BcVec temps;
|
||||
/// The number of temps in the temps array.
|
||||
size_t temps_len;
|
||||
|
||||
#if BC_ENABLE_LIBRARY
|
||||
|
||||
/// The vector of contexts for the library.
|
||||
BcVec ctxts;
|
||||
|
||||
/// The vector for creating strings to pass to the client.
|
||||
BcVec out;
|
||||
|
||||
/// The PRNG.
|
||||
BcRNG rng;
|
||||
|
||||
/// The current error.
|
||||
BclError err;
|
||||
|
||||
/// Whether or not bcl should abort on fatal errors.
|
||||
bool abrt;
|
||||
|
||||
/// The number of "references," or times that the library was initialized.
|
||||
unsigned int refs;
|
||||
|
||||
/// Non-zero if bcl is running. This is volatile sig_atomic_t because it is
|
||||
/// also used in the signal handler. See the development manual
|
||||
/// (manuals/development.md#async-signal-safe-signal-handling) for more
|
||||
/// information.
|
||||
volatile sig_atomic_t running;
|
||||
|
||||
#endif // BC_ENABLE_LIBRARY
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
/// A pointer to the filename of the current file. This is not owned by the
|
||||
/// BcVm struct.
|
||||
const char* file;
|
||||
|
||||
/// The message printed when SIGINT happens.
|
||||
const char *sigmsg;
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
/// Non-zero when signals are "locked." This is volatile sig_atomic_t
|
||||
/// because it is also used in the signal handler. See the development
|
||||
/// manual (manuals/development.md#async-signal-safe-signal-handling) for
|
||||
/// more information.
|
||||
volatile sig_atomic_t sig_lock;
|
||||
|
||||
/// Non-zero when a signal has been received, but not acted on. This is
|
||||
/// volatile sig_atomic_t because it is also used in the signal handler. See
|
||||
/// the development manual
|
||||
/// (manuals/development.md#async-signal-safe-signal-handling) for more
|
||||
/// information.
|
||||
volatile sig_atomic_t sig;
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
/// The length of sigmsg.
|
||||
uchar siglen;
|
||||
|
||||
/// The instruction used for returning from a read() call.
|
||||
uchar read_ret;
|
||||
|
||||
/// The flags field used by most macros above.
|
||||
uint16_t flags;
|
||||
|
||||
/// The number of characters printed in the current line. This is used
|
||||
/// because bc has a limit of the number of characters it can print per
|
||||
/// line.
|
||||
uint16_t nchars;
|
||||
|
||||
/// The length of the line we can print. The user can set this if they wish.
|
||||
uint16_t line_len;
|
||||
|
||||
bool no_exit_exprs;
|
||||
/// True if bc should error if expressions are encountered during option
|
||||
/// parsing, false otherwise.
|
||||
bool no_exprs;
|
||||
|
||||
/// True if bc should exit if expresions are encountered.
|
||||
bool exit_exprs;
|
||||
|
||||
/// True if EOF was encountered.
|
||||
bool eof;
|
||||
|
||||
/// True if bc is currently reading from stdin.
|
||||
bool is_stdin;
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// True if keywords should not be redefined. This is only true for the
|
||||
/// builtin math libraries for bc.
|
||||
bool no_redefine;
|
||||
|
||||
#endif // BC_ENABLED
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
/// An array of maxes for the globals.
|
||||
BcBigDig maxes[BC_PROG_GLOBALS_LEN + BC_ENABLE_EXTRA_MATH];
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
/// A vector of filenames to process.
|
||||
BcVec files;
|
||||
|
||||
/// A vector of expressions to process.
|
||||
BcVec exprs;
|
||||
|
||||
/// The name of the calculator under use. This is used by BC_IS_BC and
|
||||
/// BC_IS_DC.
|
||||
const char *name;
|
||||
|
||||
/// The help text for the calculator.
|
||||
const char *help;
|
||||
|
||||
#if BC_ENABLE_HISTORY
|
||||
|
||||
/// The history data.
|
||||
BcHistory history;
|
||||
|
||||
#endif // BC_ENABLE_HISTORY
|
||||
|
||||
/// The function to call to get the next lex token.
|
||||
BcLexNext next;
|
||||
|
||||
/// The function to call to parse.
|
||||
BcParseParse parse;
|
||||
|
||||
/// The function to call to parse expressions.
|
||||
BcParseExpr expr;
|
||||
|
||||
/// The text to display to label functions in error messages.
|
||||
const char *func_header;
|
||||
|
||||
/// The names of the categories of errors.
|
||||
const char *err_ids[BC_ERR_IDX_NELEMS + BC_ENABLED];
|
||||
|
||||
/// The messages for each error.
|
||||
const char *err_msgs[BC_ERR_NELEMS];
|
||||
|
||||
/// The locale.
|
||||
const char *locale;
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
/// The last base used to parse.
|
||||
BcBigDig last_base;
|
||||
|
||||
/// The last power of last_base used to parse.
|
||||
BcBigDig last_pow;
|
||||
|
||||
/// The last exponent of base that equals last_pow.
|
||||
BcBigDig last_exp;
|
||||
|
||||
/// BC_BASE_POW - last_pow.
|
||||
BcBigDig last_rem;
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
/// A buffer of environment arguments. This is the actual value of the
|
||||
/// environment variable.
|
||||
char *env_args_buffer;
|
||||
|
||||
/// A vector for environment arguments after parsing.
|
||||
BcVec env_args;
|
||||
|
||||
/// A BcNum set to constant 0.
|
||||
BcNum zero;
|
||||
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
/// A BcNum set to constant 1.
|
||||
BcNum one;
|
||||
|
||||
/// A BcNum holding the max number held by a BcBigDig plus 1.
|
||||
BcNum max;
|
||||
|
||||
/// A BcNum holding the max number held by a BcBigDig times 2 plus 1.
|
||||
BcNum max2;
|
||||
|
||||
/// The BcDig array for max.
|
||||
BcDig max_num[BC_NUM_BIGDIG_LOG10];
|
||||
|
||||
/// The BcDig array for max2.
|
||||
BcDig max2_num[BC_NUM_BIGDIG_LOG10];
|
||||
|
||||
// The BcDig array for the one BcNum.
|
||||
BcDig one_num[BC_VM_ONE_CAP];
|
||||
|
||||
#if !BC_ENABLE_LIBRARY
|
||||
|
||||
// The BcDig array for the zero BcNum.
|
||||
BcDig zero_num[BC_VM_ONE_CAP];
|
||||
|
||||
/// The stdout file.
|
||||
BcFile fout;
|
||||
|
||||
/// The stderr file.
|
||||
BcFile ferr;
|
||||
|
||||
#if BC_ENABLE_NLS
|
||||
|
||||
/// The locale catalog.
|
||||
nl_catd catalog;
|
||||
|
||||
#endif // BC_ENABLE_NLS
|
||||
|
||||
/// A pointer to the stdin buffer.
|
||||
char *buf;
|
||||
|
||||
/// 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;
|
||||
|
||||
#if BC_ENABLED
|
||||
|
||||
/// An array of booleans for which bc keywords have been redefined if
|
||||
/// BC_REDEFINE_KEYWORDS is non-zero.
|
||||
bool redefined_kws[BC_LEX_NKWS];
|
||||
|
||||
#endif // BC_ENABLED
|
||||
#endif // !BC_ENABLE_LIBRARY
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
|
||||
/// The depth for BC_FUNC_ENTER and BC_FUNC_EXIT.
|
||||
size_t func_depth;
|
||||
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
} BcVm;
|
||||
|
||||
/**
|
||||
* Print the copyright banner and help if it's non-NULL.
|
||||
* @param help The help message to print if it's non-NULL.
|
||||
*/
|
||||
void bc_vm_info(const char* const help);
|
||||
void bc_vm_boot(int argc, char *argv[], const char *env_len,
|
||||
const char* const env_args);
|
||||
|
||||
/**
|
||||
* The entrance point for bc/dc together.
|
||||
* @param argc The count of arguments.
|
||||
* @param argv The argument array.
|
||||
*/
|
||||
void bc_vm_boot(int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* Initializes some of the BcVm global. This is separate to make things easier
|
||||
* on the library code.
|
||||
*/
|
||||
void bc_vm_init(void);
|
||||
|
||||
/**
|
||||
* Frees the BcVm global.
|
||||
*/
|
||||
void bc_vm_shutdown(void);
|
||||
|
||||
/**
|
||||
* Add a temp to the temp array.
|
||||
* @param num The BcDig array to add to the temp array.
|
||||
*/
|
||||
void bc_vm_addTemp(BcDig *num);
|
||||
|
||||
/**
|
||||
* Dish out a temp, or NULL if there are none.
|
||||
* @return A temp, or NULL if none exist.
|
||||
*/
|
||||
BcDig* bc_vm_takeTemp(void);
|
||||
|
||||
/**
|
||||
* Frees all temporaries.
|
||||
*/
|
||||
void bc_vm_freeTemps(void);
|
||||
|
||||
#if !BC_ENABLE_HISTORY
|
||||
|
||||
/**
|
||||
* Erases the flush argument if history does not exist because it does not
|
||||
* matter if history does not exist.
|
||||
*/
|
||||
#define bc_vm_putchar(c, t) bc_vm_putchar(c)
|
||||
|
||||
#endif // !BC_ENABLE_HISTORY
|
||||
|
||||
/**
|
||||
* Print to stdout with limited formating.
|
||||
* @param fmt The format string.
|
||||
*/
|
||||
void bc_vm_printf(const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* Puts a char into the stdout buffer.
|
||||
* @param c The character to put on the stdout buffer.
|
||||
* @param type The flush type.
|
||||
*/
|
||||
void bc_vm_putchar(int c, BcFlushType type);
|
||||
|
||||
/**
|
||||
* Multiplies @a n and @a size and throws an allocation error if overflow
|
||||
* occurs.
|
||||
* @param n The number of elements.
|
||||
* @param size The size of each element.
|
||||
* @return The product of @a n and @a size.
|
||||
*/
|
||||
size_t bc_vm_arraySize(size_t n, size_t size);
|
||||
|
||||
/**
|
||||
* Adds @a a and @a b and throws an error if overflow occurs.
|
||||
* @param a The first operand.
|
||||
* @param b The second operand.
|
||||
* @return The sum of @a a and @a b.
|
||||
*/
|
||||
size_t bc_vm_growSize(size_t a, size_t b);
|
||||
|
||||
/**
|
||||
* Allocate @a n bytes and throw an allocation error if allocation fails.
|
||||
* @param n The bytes to allocate.
|
||||
* @return A pointer to the allocated memory.
|
||||
*/
|
||||
void* bc_vm_malloc(size_t n);
|
||||
|
||||
/**
|
||||
* Reallocate @a ptr to be @a n bytes and throw an allocation error if
|
||||
* reallocation fails.
|
||||
* @param ptr The pointer to a memory allocation to reallocate.
|
||||
* @param n The bytes to allocate.
|
||||
* @return A pointer to the reallocated memory.
|
||||
*/
|
||||
void* bc_vm_realloc(void *ptr, size_t n);
|
||||
|
||||
/**
|
||||
* Allocates space for, and duplicates, @a str.
|
||||
* @param str The string to allocate.
|
||||
* @return The allocated string.
|
||||
*/
|
||||
char* bc_vm_strdup(const char *str);
|
||||
|
||||
/**
|
||||
* Reads a line into BcVm's buffer field.
|
||||
* @param clear True if the buffer should be cleared first, false otherwise.
|
||||
* @return True if a line was read, false otherwise.
|
||||
*/
|
||||
bool bc_vm_readLine(bool clear);
|
||||
|
||||
/**
|
||||
* A convenience and portability function for OpenBSD's pledge().
|
||||
* @param promises The promises to pledge().
|
||||
* @param execpromises The exec promises to pledge().
|
||||
*/
|
||||
void bc_pledge(const char *promises, const char *execpromises);
|
||||
|
||||
/**
|
||||
* Returns the value of an environment variable.
|
||||
* @param var The environment variable.
|
||||
* @return The value of the environment variable.
|
||||
*/
|
||||
char* bc_vm_getenv(const char* var);
|
||||
void bc_vm_getenvFree(char* var);
|
||||
|
||||
/**
|
||||
* Frees an environment variable value.
|
||||
* @param val The value to free.
|
||||
*/
|
||||
void bc_vm_getenvFree(char* val);
|
||||
|
||||
#if BC_DEBUG_CODE
|
||||
|
||||
/**
|
||||
* Start executing a jump series.
|
||||
* @param f The name of the function that started the jump series.
|
||||
*/
|
||||
void bc_vm_jmp(const char *f);
|
||||
#else // BC_DEBUG_CODE
|
||||
|
||||
/**
|
||||
* Start executing a jump series.
|
||||
*/
|
||||
void bc_vm_jmp(void);
|
||||
|
||||
#endif // BC_DEBUG_CODE
|
||||
|
||||
#if BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Handle an error. This is the true error handler. It will start a jump series
|
||||
* if an error occurred. POSIX errors will not cause jumps when warnings are on
|
||||
* or no POSIX errors are enabled.
|
||||
* @param e The error.
|
||||
*/
|
||||
void bc_vm_handleError(BcErr e);
|
||||
|
||||
/**
|
||||
* Handle a fatal error.
|
||||
* @param e The error.
|
||||
*/
|
||||
void bc_vm_fatalError(BcErr e);
|
||||
|
||||
/**
|
||||
* A function to call at exit.
|
||||
*/
|
||||
void bc_vm_atexit(void);
|
||||
|
||||
#else // BC_ENABLE_LIBRARY
|
||||
|
||||
/**
|
||||
* Handle an error. This is the true error handler. It will start a jump series
|
||||
* if an error occurred. POSIX errors will not cause jumps when warnings are on
|
||||
* or no POSIX errors are enabled.
|
||||
* @param e The error.
|
||||
* @param line The source line where the error occurred.
|
||||
*/
|
||||
void bc_vm_handleError(BcErr e, size_t line, ...);
|
||||
#if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK
|
||||
|
||||
/**
|
||||
* Handle a fatal error.
|
||||
* @param e The error.
|
||||
*/
|
||||
#if !BC_ENABLE_MEMCHECK
|
||||
BC_NORETURN
|
||||
#endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK
|
||||
#endif // !BC_ENABLE_MEMCHECK
|
||||
void bc_vm_fatalError(BcErr e);
|
||||
|
||||
/**
|
||||
* A function to call at exit.
|
||||
* @param status The exit status.
|
||||
*/
|
||||
int bc_vm_atexit(int status);
|
||||
#endif // BC_ENABLE_LIBRARY
|
||||
|
||||
/// A reference to the copyright header.
|
||||
extern const char bc_copyright[];
|
||||
|
||||
/// A reference to the format string for source code line printing.
|
||||
extern const char* const bc_err_line;
|
||||
|
||||
/// A reference to the format string for source code function printing.
|
||||
extern const char* const bc_err_func_header;
|
||||
|
||||
/// A reference to the array of default error category names.
|
||||
extern const char *bc_errs[];
|
||||
|
||||
/// A reference to the array of error category indices for each error.
|
||||
extern const uchar bc_err_ids[];
|
||||
|
||||
/// A reference to the array of default error messages.
|
||||
extern const char* const bc_err_msgs[];
|
||||
|
||||
/// A reference to the pledge() promises at start.
|
||||
extern const char bc_pledge_start[];
|
||||
|
||||
#if BC_ENABLE_HISTORY
|
||||
|
||||
/// A reference to the end pledge() promises when using history.
|
||||
extern const char bc_pledge_end_history[];
|
||||
|
||||
#endif // BC_ENABLE_HISTORY
|
||||
|
||||
/// A reference to the end pledge() promises when *not* using history.
|
||||
extern const char bc_pledge_end[];
|
||||
|
||||
/// A reference to the global data.
|
||||
extern BcVm vm;
|
||||
|
||||
/// A reference to the global output buffers.
|
||||
extern char output_bufs[BC_VM_BUF_SIZE];
|
||||
|
||||
#endif // BC_VM_H
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "ungültiges Token"
|
||||
6 "ungültiger Ausdruck"
|
||||
7 "leerer Ausdruck"
|
||||
8 "Ungültige Druckanweisung"
|
||||
8 "Ungültige Druck- oder Stream-Anweisung"
|
||||
9 "Ungültige Funktionsdefinition"
|
||||
10 "Ungültige Zuweisung: Die linke Seite muss \"scale\", \"ibase\", \"obase\", \"seed\", \"last\", \"var\" oder \"array element\" sein"
|
||||
11 "keine automatische Variable gefunden"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX erlaubt keine exponentielle Notation"
|
||||
26 "POSIX erlaubt keine Feld-Referenzen als Funktionsparameter"
|
||||
27 "POSIX erfordert, dass die linke Klammer auf der gleichen Linie wie der Funktionskopf steht"
|
||||
28 "POSIX erlaubt keine Zuweisung von Strings an Variablen oder Arrays"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "rekursiver read()-Aufruf"
|
||||
6 "Variable oder Feld-Element hat den falschen Typ"
|
||||
7 "Stapel hat zu wenig Elemente"
|
||||
8 "falsche Anzahl der Parameter: benötigt %zu, hat %zu"
|
||||
9 "undefinierte Funktion: %s()"
|
||||
10 "kann keinen ungültigen Wert in einem Ausdruck verwenden"
|
||||
8 "Stapel für Register \"%s\" hat zu wenig Elemente"
|
||||
9 "falsche Anzahl der Parameter: benötigt %zu, hat %zu"
|
||||
10 "undefinierte Funktion: %s()"
|
||||
11 "kann keinen ungültigen Wert in einem Ausdruck verwenden"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "Speicherzuweisung fehlgeschlagen"
|
||||
2 "Ein-Ausgabe-Fehler"
|
||||
3 "konnte die Datei nicht öffnen: %s"
|
||||
4 "Datei ist nicht ASCII: %s"
|
||||
4 "Datei ist nicht Text: %s"
|
||||
5 "Pfad ist ein Verzeichnis: %s"
|
||||
6 "ungültige Befehlszeilenoption: \"%s\""
|
||||
7 "Option erfordert ein Argument: '%c' (\"%s\")"
|
||||
8 "Option benutzt keine Argumente: '%c' (\"%s\")"
|
||||
9 "ungültiges Argument der Befehlszeilenoption: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "ungültiges Token"
|
||||
6 "ungültiger Ausdruck"
|
||||
7 "leerer Ausdruck"
|
||||
8 "Ungültige Druckanweisung"
|
||||
8 "Ungültige Druck- oder Stream-Anweisung"
|
||||
9 "Ungültige Funktionsdefinition"
|
||||
10 "Ungültige Zuweisung: Die linke Seite muss \"scale\", \"ibase\", \"obase\", \"seed\", \"last\", \"var\" oder \"array element\" sein"
|
||||
11 "keine automatische Variable gefunden"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX erlaubt keine exponentielle Notation"
|
||||
26 "POSIX erlaubt keine Feld-Referenzen als Funktionsparameter"
|
||||
27 "POSIX erfordert, dass die linke Klammer auf der gleichen Linie wie der Funktionskopf steht"
|
||||
28 "POSIX erlaubt keine Zuweisung von Strings an Variablen oder Arrays"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "rekursiver read()-Aufruf"
|
||||
6 "Variable oder Feld-Element hat den falschen Typ"
|
||||
7 "Stapel hat zu wenig Elemente"
|
||||
8 "falsche Anzahl der Parameter: benötigt %zu, hat %zu"
|
||||
9 "undefinierte Funktion: %s()"
|
||||
10 "kann keinen ungültigen Wert in einem Ausdruck verwenden"
|
||||
8 "Stapel für Register \"%s\" hat zu wenig Elemente"
|
||||
9 "falsche Anzahl der Parameter: benötigt %zu, hat %zu"
|
||||
10 "undefinierte Funktion: %s()"
|
||||
11 "kann keinen ungültigen Wert in einem Ausdruck verwenden"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "Speicherzuweisung fehlgeschlagen"
|
||||
2 "Ein-Ausgabe-Fehler"
|
||||
3 "konnte die Datei nicht öffnen: %s"
|
||||
4 "Datei ist nicht ASCII: %s"
|
||||
4 "Datei ist nicht Text: %s"
|
||||
5 "Pfad ist ein Verzeichnis: %s"
|
||||
6 "ungültige Befehlszeilenoption: \"%s\""
|
||||
7 "Option erfordert ein Argument: '%c' (\"%s\")"
|
||||
8 "Option benutzt keine Argumente: '%c' (\"%s\")"
|
||||
9 "ungültiges Argument der Befehlszeilenoption: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "invalid token"
|
||||
6 "invalid expression"
|
||||
7 "empty expression"
|
||||
8 "invalid print statement"
|
||||
8 "invalid print or stream statement"
|
||||
9 "invalid function definition"
|
||||
10 "invalid assignment: left side must be scale, ibase, obase, seed, last, var, or array element"
|
||||
11 "no auto variable found"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX does not allow exponential notation"
|
||||
26 "POSIX does not allow array references as function parameters"
|
||||
27 "POSIX requires the left brace be on the same line as the function header"
|
||||
28 "POSIX does not allow strings to be assigned to variables or arrays"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "recursive read() call"
|
||||
6 "variable or array element is the wrong type"
|
||||
7 "stack has too few elements"
|
||||
8 "wrong number of parameters; need %zu, have %zu"
|
||||
9 "undefined function: %s()"
|
||||
10 "cannot use a void value in an expression"
|
||||
8 "stack for register \"%s\" has too few elements"
|
||||
9 "wrong number of parameters; need %zu, have %zu"
|
||||
10 "undefined function: %s()"
|
||||
11 "cannot use a void value in an expression"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "memory allocation failed"
|
||||
2 "I/O error"
|
||||
3 "cannot open file: %s"
|
||||
4 "file is not ASCII: %s"
|
||||
4 "file is not text: %s"
|
||||
5 "path is a directory: %s"
|
||||
6 "invalid command-line option: \"%s\""
|
||||
7 "option requires an argument: '%c' (\"%s\")"
|
||||
8 "option takes no arguments: '%c' (\"%s\")"
|
||||
9 "invalid command-line option argument: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "el token no es válido"
|
||||
6 "la expresión no es válida"
|
||||
7 "la expresión es vacía"
|
||||
8 "la expresión de print no es válida"
|
||||
8 "la expresión de print o de stream no es válida"
|
||||
9 "la definición de función no es válida"
|
||||
10 "la asignación no es valida: en la izquierda debe ser scale, ibase, obase, last, var, o un elemento de matriz"
|
||||
11 "no se encontró ninguna variable automática"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX no permite una notación exponencial"
|
||||
26 "POSIX no permite una referencia a una matriz como un parámetro de función"
|
||||
27 "POSIX requiere el llave de la izquierda que sea en la misma línea que los parámetros de la función"
|
||||
28 "POSIX no permite asignar cadenas a variables o matrices"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "recursion en la invocación de read()"
|
||||
6 "variable o elemento del matriz de tipo equivocado"
|
||||
7 "la pila no ha demaciado elementos"
|
||||
8 "la función no tiene un número de argumentos correcto; necessita %zu, tiene %zu"
|
||||
9 "la función no esta definida: %s()"
|
||||
10 "no puede utilizar un valor vacío en una expresión"
|
||||
8 "la pila del registro \"%s\" no ha demaciado elementos"
|
||||
9 "la función no tiene un número de argumentos correcto; necessita %zu, tiene %zu"
|
||||
10 "la función no esta definida: %s()"
|
||||
11 "no puede utilizar un valor vacío en una expresión"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "error en la asignación de memoria"
|
||||
2 "error de I/O"
|
||||
3 "no puede abrir el archivo: %s"
|
||||
4 "el archivo no es ASCII: %s"
|
||||
4 "el archivo no es texto: %s"
|
||||
5 "el ruta es un directorio: %s"
|
||||
6 "una opción de línea de comandos no es válida: \"%s\""
|
||||
7 "una opción requiere un argumento: '%c' (\"%s\")"
|
||||
8 "una opción no tiene argumento: '%c' (\"%s\")"
|
||||
9 "uno argumento de opción de línea de comandos no es válido: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "el token no es válido"
|
||||
6 "la expresión no es válida"
|
||||
7 "la expresión es vacía"
|
||||
8 "la expresión de print no es válida"
|
||||
8 "la expresión de print o de stream no es válida"
|
||||
9 "la definición de función no es válida"
|
||||
10 "la asignación no es valida: en la izquierda debe ser scale, ibase, obase, last, var, o un elemento de matriz"
|
||||
11 "no se encontró ninguna variable automática"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX no permite una notación exponencial"
|
||||
26 "POSIX no permite una referencia a una matriz como un parámetro de función"
|
||||
27 "POSIX requiere el llave de la izquierda que sea en la misma línea que los parámetros de la función"
|
||||
28 "POSIX no permite asignar cadenas a variables o matrices"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "recursion en la invocación de read()"
|
||||
6 "variable o elemento del matriz de tipo equivocado"
|
||||
7 "la pila no ha demaciado elementos"
|
||||
8 "la función no tiene un número de argumentos correcto; necessita %zu, tiene %zu"
|
||||
9 "la función no esta definida: %s()"
|
||||
10 "no puede utilizar un valor vacío en una expresión"
|
||||
8 "la pila del registro \"%s\" no ha demaciado elementos"
|
||||
9 "la función no tiene un número de argumentos correcto; necessita %zu, tiene %zu"
|
||||
10 "la función no esta definida: %s()"
|
||||
11 "no puede utilizar un valor vacío en una expresión"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "error en la asignación de memoria"
|
||||
2 "error de I/O"
|
||||
3 "no puede abrir el archivo: %s"
|
||||
4 "el archivo no es ASCII: %s"
|
||||
4 "el archivo no es texto: %s"
|
||||
5 "el ruta es un directorio: %s"
|
||||
6 "una opción de línea de comandos no es válida: \"%s\""
|
||||
7 "una opción requiere un argumento: '%c' (\"%s\")"
|
||||
8 "una opción no tiene argumento: '%c' (\"%s\")"
|
||||
9 "uno argumento de opción de línea de comandos no es válido: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "symbole invalide"
|
||||
6 "expression invalide"
|
||||
7 "expression vide"
|
||||
8 "instruction d'écriture invalide"
|
||||
8 "instruction d'écriture ou de flux invalide"
|
||||
9 "définition de fonction invalide"
|
||||
10 "affectation invalide : la partie gauche doit être 'scale', 'ibase', 'obase', 'seed', 'last', une variable ou une case de tableau"
|
||||
11 "aucune variable auto trouvée"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX interdit la notation exponentielle"
|
||||
26 "POSIX interdit les références à un tableau dans les paramètres d'une fonction"
|
||||
27 "POSIX impose que l'en-tête de la fonction et le '{' soient sur la même ligne"
|
||||
28 "POSIX interdit pas d'assigner des chaînes de caractères à des variables ou à des tableaux"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "appel read() récursif"
|
||||
6 "mauvais type de variable ou d'élément de tableau"
|
||||
7 "pile sous-remplie"
|
||||
8 "nombre incorrect de paramètres - attendus : %zu, obtenus : %zu"
|
||||
9 "fonction non définie : %s()"
|
||||
10 "une valeur 'void' est inutilisable dans une expression"
|
||||
8 "pile pour le registre \"%s\" sous-remplie"
|
||||
9 "nombre incorrect de paramètres - attendus : %zu, obtenus : %zu"
|
||||
10 "fonction non définie : %s()"
|
||||
11 "une valeur 'void' est inutilisable dans une expression"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "échec d'allocation mémoire"
|
||||
2 "erreur d'entrée-sortie"
|
||||
3 "impossible d'ouvrir le fichier : %s"
|
||||
4 "fichier non ASCII : %s"
|
||||
4 "fichier non texte: %s"
|
||||
5 "le chemin est un répertoire : %s"
|
||||
6 "option de ligne de commande invalide : \"%s\""
|
||||
7 "l'option '%c' (\"%s\") requiert un argument"
|
||||
8 "l'option '%c' (\"%s\") ne prend pas d'argument"
|
||||
9 "argument d'option de ligne de commande invalide : \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "symbole invalide"
|
||||
6 "expression invalide"
|
||||
7 "expression vide"
|
||||
8 "instruction d'écriture invalide"
|
||||
8 "instruction d'écriture ou de flux invalide"
|
||||
9 "définition de fonction invalide"
|
||||
10 "affectation invalide : la partie gauche doit être 'scale', 'ibase', 'obase', 'seed', 'last', une variable ou une case de tableau"
|
||||
11 "aucune variable auto trouvée"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX interdit la notation exponentielle"
|
||||
26 "POSIX interdit les références à un tableau dans les paramètres d'une fonction"
|
||||
27 "POSIX impose que l'en-tête de la fonction et le '{' soient sur la même ligne"
|
||||
28 "POSIX interdit pas d'assigner des chaînes de caractères à des variables ou à des tableaux"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "appel read() récursif"
|
||||
6 "mauvais type de variable ou d'élément de tableau"
|
||||
7 "pile sous-remplie"
|
||||
8 "nombre incorrect de paramètres - attendus : %zu, obtenus : %zu"
|
||||
9 "fonction non définie : %s()"
|
||||
10 "une valeur 'void' est inutilisable dans une expression"
|
||||
8 "pile pour le registre \"%s\" sous-remplie"
|
||||
9 "nombre incorrect de paramètres - attendus : %zu, obtenus : %zu"
|
||||
10 "fonction non définie : %s()"
|
||||
11 "une valeur 'void' est inutilisable dans une expression"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "échec d'allocation mémoire"
|
||||
2 "erreur d'entrée-sortie"
|
||||
3 "impossible d'ouvrir le fichier : %s"
|
||||
4 "fichier non ASCII : %s"
|
||||
4 "fichier non texte: %s"
|
||||
5 "le chemin est un répertoire : %s"
|
||||
6 "option de ligne de commande invalide : \"%s\""
|
||||
7 "l'option '%c' (\"%s\") requiert un argument"
|
||||
8 "l'option '%c' (\"%s\") ne prend pas d'argument"
|
||||
9 "argument d'option de ligne de commande invalide : \"%s\""
|
||||
|
|
|
@ -60,14 +60,14 @@ $set 4
|
|||
5 "無効なトークン"
|
||||
6 "無効な式"
|
||||
7 "空の式"
|
||||
8 "無効な印刷文"
|
||||
8 "無効なprintまたはstream文"
|
||||
9 "無効な関数定義"
|
||||
10 "無効な代入:左側は scale, ibase, obase, last, var, または配列要素でなければなりません"
|
||||
11 "自動変数が見つかりませんでした"
|
||||
12 "関数パラメータまたは自動\"%s%s\"はすでに存在します"
|
||||
12 "関数パラメータまたは自動\"%s%s\"はすでに存在します"
|
||||
13 "ブロックエンドが見つかりませんでした"
|
||||
14 "void 関数から値を返すことはできません:%s()"
|
||||
15 "varは参照にできません:%s"
|
||||
15 "varは参照にできません:%s"
|
||||
16 "POSIX は 1 文字より長い名前を許可しません:%s"
|
||||
17 "POSIX は '#' スクリプトのコメントを許可しません。"
|
||||
18 "POSIX は以下のキーワードを許可しません:%s"
|
||||
|
@ -80,20 +80,22 @@ $set 4
|
|||
25 "POSIXは指数表記を許可しません。"
|
||||
26 "POSIX は関数パラメータとして配列参照を許可しません。"
|
||||
27 "POSIXでは、関数ヘッダと同じ行に左中括弧があることが必要です。"
|
||||
28 "POSIXでは、変数や配列に文字列を割り当てることはできません。"
|
||||
|
||||
$ ランタイムエラー。
|
||||
$set 5
|
||||
|
||||
1 "無効なibase:は[%lu、%lu]でなければなりません"
|
||||
2 "無効なobase:は[%lu、%lu]でなければなりません"
|
||||
3 "無効なscale:は[%lu、%lu]でなければなりません"
|
||||
1 "無効なibase:は[%lu、%lu]でなければなりません"
|
||||
2 "無効なobase:は[%lu、%lu]でなければなりません"
|
||||
3 "無効なscale:は[%lu、%lu]でなければなりません"
|
||||
4 "式が無効read()"
|
||||
5 "再帰的読み込み()呼び出し"
|
||||
6 "変数または配列要素の型が間違っている"
|
||||
7 "スタックの要素が少なすぎる"
|
||||
8 "パラメータの数が間違っています。"
|
||||
9 "定義されていない関数:%s()"
|
||||
10 "式では void 値を使用できません"
|
||||
8 "レジスタ\"%s\"のスタックの要素が少なすぎる"
|
||||
9 "パラメータの数が間違っています。"
|
||||
10 "定義されていない関数:%s()"
|
||||
11 "式では void 値を使用できません"
|
||||
|
||||
$ 致命的なエラーが発生しました。
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "メモリの割り当てに失敗しました"
|
||||
2 "I/Oエラー"
|
||||
3 "ファイルを開けませんでした。%s"
|
||||
4 "ファイルがASCIIではありません:%s"
|
||||
4 "ファイルがテキストではない:%s"
|
||||
5 "パスはディレクトリです:%s"
|
||||
6 "無効なコマンドラインオプション:'%c'(\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "オプションには引数が必要です:'%c' (\"%s\")"
|
||||
2 "オプションは引数を取りません:'%c' (\"%s\")"
|
||||
6 "無効なコマンドラインオプション:\"%s\""
|
||||
7 "オプションには引数が必要です:'%c' (\"%s\")"
|
||||
8 "オプションは引数を取りません:'%c' (\"%s\")"
|
||||
9 "無効なコマンドラインオプション引数: \"%s\"
|
||||
|
|
|
@ -60,14 +60,14 @@ $set 4
|
|||
5 "無効なトークン"
|
||||
6 "無効な式"
|
||||
7 "空の式"
|
||||
8 "無効な印刷文"
|
||||
8 "無効なprintまたはstream文"
|
||||
9 "無効な関数定義"
|
||||
10 "無効な代入:左側は scale, ibase, obase, last, var, または配列要素でなければなりません"
|
||||
11 "自動変数が見つかりませんでした"
|
||||
12 "関数パラメータまたは自動\"%s%s\"はすでに存在します"
|
||||
12 "関数パラメータまたは自動\"%s%s\"はすでに存在します"
|
||||
13 "ブロックエンドが見つかりませんでした"
|
||||
14 "void 関数から値を返すことはできません:%s()"
|
||||
15 "varは参照にできません:%s"
|
||||
15 "varは参照にできません:%s"
|
||||
16 "POSIX は 1 文字より長い名前を許可しません:%s"
|
||||
17 "POSIX は '#' スクリプトのコメントを許可しません。"
|
||||
18 "POSIX は以下のキーワードを許可しません:%s"
|
||||
|
@ -80,20 +80,22 @@ $set 4
|
|||
25 "POSIXは指数表記を許可しません。"
|
||||
26 "POSIX は関数パラメータとして配列参照を許可しません。"
|
||||
27 "POSIXでは、関数ヘッダと同じ行に左中括弧があることが必要です。"
|
||||
28 "POSIXでは、変数や配列に文字列を割り当てることはできません。"
|
||||
|
||||
$ ランタイムエラー。
|
||||
$set 5
|
||||
|
||||
1 "無効なibase:は[%lu、%lu]でなければなりません"
|
||||
2 "無効なobase:は[%lu、%lu]でなければなりません"
|
||||
3 "無効なscale:は[%lu、%lu]でなければなりません"
|
||||
1 "無効なibase:は[%lu、%lu]でなければなりません"
|
||||
2 "無効なobase:は[%lu、%lu]でなければなりません"
|
||||
3 "無効なscale:は[%lu、%lu]でなければなりません"
|
||||
4 "式が無効read()"
|
||||
5 "再帰的読み込み()呼び出し"
|
||||
6 "変数または配列要素の型が間違っている"
|
||||
7 "スタックの要素が少なすぎる"
|
||||
8 "パラメータの数が間違っています。"
|
||||
9 "定義されていない関数:%s()"
|
||||
10 "式では void 値を使用できません"
|
||||
8 "レジスタ\"%s\"のスタックの要素が少なすぎる"
|
||||
9 "パラメータの数が間違っています。"
|
||||
10 "定義されていない関数:%s()"
|
||||
11 "式では void 値を使用できません"
|
||||
|
||||
$ 致命的なエラーが発生しました。
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "メモリの割り当てに失敗しました"
|
||||
2 "I/Oエラー"
|
||||
3 "ファイルを開けませんでした。%s"
|
||||
4 "ファイルがASCIIではありません:%s"
|
||||
4 "ファイルがテキストではない:%s"
|
||||
5 "パスはディレクトリです:%s"
|
||||
6 "無効なコマンドラインオプション:'%c'(\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "オプションには引数が必要です:'%c' (\"%s\")"
|
||||
2 "オプションは引数を取りません:'%c' (\"%s\")"
|
||||
6 "無効なコマンドラインオプション:\"%s\""
|
||||
7 "オプションには引数が必要です:'%c' (\"%s\")"
|
||||
8 "オプションは引数を取りません:'%c' (\"%s\")"
|
||||
9 "無効なコマンドラインオプション引数: \"%s\"
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "ongeldige token"
|
||||
6 "ongeldige uitdrukking"
|
||||
7 "lege uitdrukking"
|
||||
8 "ongeldige afdruk"
|
||||
8 "ongeldige print- of stream-instructie"
|
||||
9 "ongeldige functiedefinitie"
|
||||
10 "ongeldige toewijzing: linkerzijde moet scale, ibase, obase, last, var of array element zijn"
|
||||
11 "geen autovariabele gevonden"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX laat geen exponentiële notatie toe"
|
||||
26 "POSIX staat geen arrayreferenties toe als functieparameters"
|
||||
27 "POSIX vereist dat de linkse beugel op dezelfde regel staat als de functiehoofding"
|
||||
28 "POSIX staat niet toe dat strings worden toegewezen aan variabelen of arrays"
|
||||
|
||||
$ Runtime fouten.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "recursieve read() call"
|
||||
6 "Variabele of matrix-element is het verkeerde type"
|
||||
7 "Stapel heeft te weinig elementen"
|
||||
8 "Verkeerd aantal parameters; hebben %zu nodig, hebben %zu"
|
||||
9 "ongedefinieerde functie: %s()"
|
||||
10 "kan geen nietige waarde in een uitdrukking gebruiken"
|
||||
8 "Stapel voor register %s heeft te weinig elementen"
|
||||
9 "Verkeerd aantal parameters; hebben %zu nodig, hebben %zu"
|
||||
10 "ongedefinieerde functie: %s()"
|
||||
11 "kan geen nietige waarde in een uitdrukking gebruiken"
|
||||
|
||||
$ Fatale fouten.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "geheugentoewijzing mislukt"
|
||||
2 "I/O-fout"
|
||||
3 "kon geen file openen: %s"
|
||||
4 "bestand is niet ASCII: %s"
|
||||
4 "bestand is geen tekst: %s"
|
||||
5 "pad is een directory: %s"
|
||||
6 "ongeldige opdrachtregeloptie: '%c' (%s)"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "optie vereist een argument: '%c' (\"%s\")"
|
||||
2 "optie neemt geen argumenten aan: '%c' (\"%s\")"
|
||||
6 "ongeldige opdrachtregeloptie: %s"
|
||||
7 "optie vereist een argument: '%c' (\"%s\")"
|
||||
8 "optie neemt geen argumenten aan: '%c' (\"%s\")"
|
||||
9 "ongeldige opdrachtregeloptie argument: %s"
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "ongeldige token"
|
||||
6 "ongeldige uitdrukking"
|
||||
7 "lege uitdrukking"
|
||||
8 "ongeldige afdruk"
|
||||
8 "ongeldige print- of stream-instructie"
|
||||
9 "ongeldige functiedefinitie"
|
||||
10 "ongeldige toewijzing: linkerzijde moet scale, ibase, obase, last, var of array element zijn"
|
||||
11 "geen autovariabele gevonden"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX laat geen exponentiële notatie toe"
|
||||
26 "POSIX staat geen arrayreferenties toe als functieparameters"
|
||||
27 "POSIX vereist dat de linkse beugel op dezelfde regel staat als de functiehoofding"
|
||||
28 "POSIX staat niet toe dat strings worden toegewezen aan variabelen of arrays"
|
||||
|
||||
$ Runtime fouten.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "recursieve read() call"
|
||||
6 "Variabele of matrix-element is het verkeerde type"
|
||||
7 "Stapel heeft te weinig elementen"
|
||||
8 "Verkeerd aantal parameters; hebben %zu nodig, hebben %zu"
|
||||
9 "ongedefinieerde functie: %s()"
|
||||
10 "kan geen nietige waarde in een uitdrukking gebruiken"
|
||||
8 "Stapel voor register %s heeft te weinig elementen"
|
||||
9 "Verkeerd aantal parameters; hebben %zu nodig, hebben %zu"
|
||||
10 "ongedefinieerde functie: %s()"
|
||||
11 "kan geen nietige waarde in een uitdrukking gebruiken"
|
||||
|
||||
$ Fatale fouten.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "geheugentoewijzing mislukt"
|
||||
2 "I/O-fout"
|
||||
3 "kon geen file openen: %s"
|
||||
4 "bestand is niet ASCII: %s"
|
||||
4 "bestand is geen tekst: %s"
|
||||
5 "pad is een directory: %s"
|
||||
6 "ongeldige opdrachtregeloptie: '%c' (%s)"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "optie vereist een argument: '%c' (\"%s\")"
|
||||
2 "optie neemt geen argumenten aan: '%c' (\"%s\")"
|
||||
6 "ongeldige opdrachtregeloptie: %s"
|
||||
7 "optie vereist een argument: '%c' (\"%s\")"
|
||||
8 "optie neemt geen argumenten aan: '%c' (\"%s\")"
|
||||
9 "ongeldige opdrachtregeloptie argument: %s"
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "nieważny token"
|
||||
6 "nieważne wyrażenie"
|
||||
7 "puste wyrażenie"
|
||||
8 "nieważny wyciąg z wydruku"
|
||||
8 "nieprawidłowe polecenie drukowania lub przesyłania strumienia"
|
||||
9 "nieprawidłowa definicja funkcji"
|
||||
10 "nieprawidłowe przyporządkowanie: lewa strona musi być elementem scale, ibase, obase, last, var lub element array"
|
||||
11 "nie znaleziono zmiennej automatycznej"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX nie pozwala na notację wykładniczą"
|
||||
26 "POSIX nie zezwala na odniesienia do tablicy jako parametrów funkcji"
|
||||
27 "POSIX wymaga, aby lewe usztywnienie znajdowało się na tej samej linii co nagłówek funkcji"
|
||||
28 "POSIX nie pozwala na przypisywanie ciągów znaków do zmiennych lub tablic"
|
||||
|
||||
$ Błędy Runtime'u.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "powtarzalne wywołanie read()"
|
||||
6 "element zmienny lub tablicowy jest niewłaściwym typem"
|
||||
7 "stos ma zbyt mało elementów"
|
||||
8 "niewłaściwa liczba parametrów; potrzeba %zu, mają %zu"
|
||||
9 "niezdefiniowana funkcja: %s()"
|
||||
10 "nie może użyć wartości pustej w wyrażeniu"
|
||||
8 "stos dla rejestru \"%s\" ma zbyt mało elementów"
|
||||
9 "niewłaściwa liczba parametrów; potrzeba %zu, mają %zu"
|
||||
10 "niezdefiniowana funkcja: %s()"
|
||||
11 "nie może użyć wartości pustej w wyrażeniu"
|
||||
|
||||
$ Fatalne błędy.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "Alokacja pamięci nie powiodła się"
|
||||
2 "Błąd we/wy"
|
||||
3 "nie mógł otworzyć pliku: %s"
|
||||
4 "plik nie jest ASCII: %s"
|
||||
4 "plik nie jest tekstem: %s"
|
||||
5 "ścieżka to katalog: %s"
|
||||
6 "nieprawidłowa opcja wiersza poleceń: '%c' (\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "opcja wymaga argumentu: '%c' (\"%s\")"
|
||||
2 "opcja nie wymaga żadnych argumentów: '%c' (\"%s\")"
|
||||
6 "nieprawidłowa opcja wiersza poleceń: \"%s\""
|
||||
7 "opcja wymaga argumentu: '%c' (\"%s\")"
|
||||
8 "opcja nie wymaga żadnych argumentów: '%c' (\"%s\")"
|
||||
9 "nieprawidłowa argument opcja wiersza poleceń: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "nieważny token"
|
||||
6 "nieważne wyrażenie"
|
||||
7 "puste wyrażenie"
|
||||
8 "nieważny wyciąg z wydruku"
|
||||
8 "nieprawidłowe polecenie drukowania lub przesyłania strumienia"
|
||||
9 "nieprawidłowa definicja funkcji"
|
||||
10 "nieprawidłowe przyporządkowanie: lewa strona musi być elementem scale, ibase, obase, last, var lub element array"
|
||||
11 "nie znaleziono zmiennej automatycznej"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX nie pozwala na notację wykładniczą"
|
||||
26 "POSIX nie zezwala na odniesienia do tablicy jako parametrów funkcji"
|
||||
27 "POSIX wymaga, aby lewe usztywnienie znajdowało się na tej samej linii co nagłówek funkcji"
|
||||
28 "POSIX nie pozwala na przypisywanie ciągów znaków do zmiennych lub tablic"
|
||||
|
||||
$ Błędy Runtime'u.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "powtarzalne wywołanie read()"
|
||||
6 "element zmienny lub tablicowy jest niewłaściwym typem"
|
||||
7 "stos ma zbyt mało elementów"
|
||||
8 "niewłaściwa liczba parametrów; potrzeba %zu, mają %zu"
|
||||
9 "niezdefiniowana funkcja: %s()"
|
||||
10 "nie może użyć wartości pustej w wyrażeniu"
|
||||
8 "stos dla rejestru \"%s\" ma zbyt mało elementów"
|
||||
9 "niewłaściwa liczba parametrów; potrzeba %zu, mają %zu"
|
||||
10 "niezdefiniowana funkcja: %s()"
|
||||
11 "nie może użyć wartości pustej w wyrażeniu"
|
||||
|
||||
$ Fatalne błędy.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "Alokacja pamięci nie powiodła się"
|
||||
2 "Błąd we/wy"
|
||||
3 "nie mógł otworzyć pliku: %s"
|
||||
4 "plik nie jest ASCII: %s"
|
||||
4 "plik nie jest tekstem: %s"
|
||||
5 "ścieżka to katalog: %s"
|
||||
6 "nieprawidłowa opcja wiersza poleceń: '%c' (\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "opcja wymaga argumentu: '%c' (\"%s\")"
|
||||
2 "opcja nie wymaga żadnych argumentów: '%c' (\"%s\")"
|
||||
6 "nieprawidłowa opcja wiersza poleceń: \"%s\""
|
||||
7 "opcja wymaga argumentu: '%c' (\"%s\")"
|
||||
8 "opcja nie wymaga żadnych argumentów: '%c' (\"%s\")"
|
||||
9 "nieprawidłowa argument opcja wiersza poleceń: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "token inválido"
|
||||
6 "expressão inválida"
|
||||
7 "expressão vazia"
|
||||
8 "instrução de gravação inválida"
|
||||
8 "instrução de gravação ou de fluxo inválida"
|
||||
9 "definição de função inválida"
|
||||
10 "atribuição inválida: a parte esquerda deve ser 'scale', 'ibase', 'obase', 'last', uma variável ou um elemento da matriz"
|
||||
11 "nenhuma variável automática encontrada"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX não permite notação exponencial"
|
||||
26 "POSIX não permite referências de matriz como parâmetros de função"
|
||||
27 "POSIX requer que o cabeçalho da função '{' estejam na mesma linha"
|
||||
28 "POSIX não permite a atribuição de cadeias de caracteres a variáveis ou matrizes"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "chamada read() recursiva"
|
||||
6 "tipo errado de variável ou elemento de matriz"
|
||||
7 "pilha tem poucos elementos"
|
||||
8 "número incorreto de parâmetros - esperado: %zu, obtido: %zu"
|
||||
9 "função indefinida: %s()"
|
||||
10 "um valor 'void' não pode ser usado em uma expressão"
|
||||
8 "pilha para registo \"%s\" tem poucos elementos"
|
||||
9 "número incorreto de parâmetros - esperado: %zu, obtido: %zu"
|
||||
10 "função indefinida: %s()"
|
||||
11 "um valor 'void' não pode ser usado em uma expressão"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "falha na alocação de memória"
|
||||
2 "erro de entrada-saída"
|
||||
3 "impossível abrir o arquivo: %s"
|
||||
4 "arquivo não é ASCII: %s"
|
||||
4 "arquivo não é texto: %s"
|
||||
5 "caminho é um diretório: %s"
|
||||
6 "opção de linha de comando inválida: \"%s\""
|
||||
7 "opção requer um argumento: '%c' (\"%s\")"
|
||||
8 "a opção não aceita argumentos: '%c' (\"%s\")"
|
||||
9 "argumento de opção de linha de comando inválido: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "token inválido"
|
||||
6 "expressão inválida"
|
||||
7 "expressão vazia"
|
||||
8 "instrução de gravação inválida"
|
||||
8 "instrução de gravação ou de fluxo inválida"
|
||||
9 "definição de função inválida"
|
||||
10 "atribuição inválida: a parte esquerda deve ser 'scale', 'ibase', 'obase', 'last', uma variável ou um elemento da matriz"
|
||||
11 "nenhuma variável automática encontrada"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX não permite notação exponencial"
|
||||
26 "POSIX não permite referências de matriz como parâmetros de função"
|
||||
27 "POSIX requer que o cabeçalho da função '{' estejam na mesma linha"
|
||||
28 "POSIX não permite a atribuição de cadeias de caracteres a variáveis ou matrizes"
|
||||
|
||||
$ Runtime errors.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "chamada read() recursiva"
|
||||
6 "tipo errado de variável ou elemento de matriz"
|
||||
7 "pilha tem poucos elementos"
|
||||
8 "número incorreto de parâmetros - esperado: %zu, obtido: %zu"
|
||||
9 "função indefinida: %s()"
|
||||
10 "um valor 'void' não pode ser usado em uma expressão"
|
||||
8 "pilha para registo \"%s\" tem poucos elementos"
|
||||
9 "número incorreto de parâmetros - esperado: %zu, obtido: %zu"
|
||||
10 "função indefinida: %s()"
|
||||
11 "um valor 'void' não pode ser usado em uma expressão"
|
||||
|
||||
$ Fatal errors.
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "falha na alocação de memória"
|
||||
2 "erro de entrada-saída"
|
||||
3 "impossível abrir o arquivo: %s"
|
||||
4 "arquivo não é ASCII: %s"
|
||||
4 "arquivo não é texto: %s"
|
||||
5 "caminho é um diretório: %s"
|
||||
6 "opção de linha de comando inválida: \"%s\""
|
||||
7 "opção requer um argumento: '%c' (\"%s\")"
|
||||
8 "a opção não aceita argumentos: '%c' (\"%s\")"
|
||||
9 "argumento de opção de linha de comando inválido: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "недействительный жетон"
|
||||
6 "неправильное выражение"
|
||||
7 "пустое выражение"
|
||||
8 "заявление о недействительности печати"
|
||||
8 "заявление о недействительности печати или потока"
|
||||
9 "определение недействительной функции"
|
||||
10 "неверное присвоение: левая сторона должна быть scale, ibase, obase, last, варом или элементом массива"
|
||||
11 "автоматическая переменная не найдена"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX не допускает экспоненциальной нотации"
|
||||
26 "POSIX не допускает ссылки на массив в качестве параметров функции"
|
||||
27 "POSIX требует, чтобы левая скобка была на той же линии, что и заголовок функции"
|
||||
28 "POSIX не позволяет присваивать строки переменным или массивам"
|
||||
|
||||
$ Ошибки выполнения.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "рекурсивный вызов read()"
|
||||
6 "переменная или элемент массива является неправильным типом"
|
||||
7 "стопка имеет слишком мало элементов"
|
||||
8 "неправильное количество параметров; нужно %zu, нужно %zu"
|
||||
9 "неопределенная функция: %s()"
|
||||
10 "не может использовать пустое значение в выражении"
|
||||
8 "стопка для регистра \"%s\" имеет слишком мало элементов"
|
||||
9 "неправильное количество параметров; нужно %zu, нужно %zu"
|
||||
10 "неопределенная функция: %s()"
|
||||
11 "не может использовать пустое значение в выражении"
|
||||
|
||||
$ Фатальные ошибки.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "Не удалось выделить память"
|
||||
2 "Ошибка ввода/вывода"
|
||||
3 "не смог открыть файл: %s"
|
||||
4 "файл не ASCII: %s"
|
||||
4 "файл не является текстовым: %s"
|
||||
5 "путь - это каталог: %s"
|
||||
6 "неверная опция командной строки: '%c' (\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "опция требует аргумента: '%c' (\"%s\")"
|
||||
2 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
6 "неверная опция командной строки: \"%s\""
|
||||
7 "опция требует аргумента: '%c' (\"%s\")"
|
||||
8 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
9 "неверный аргумент опции командной строки: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "¥¤¥©á⢨⥫ìë© ¦¥â®"
|
||||
6 "¥¯à ¢¨«ì®¥ ¢ëà ¦¥¨¥"
|
||||
7 "¯ãá⮥ ¢ëà ¦¥¨¥"
|
||||
8 "§ ¥¨¥ ® ¥¤¥©á⢨⥫ì®á⨠¯¥ç â¨"
|
||||
8 "§ ¥¨¥ ® ¥¤¥©á⢨⥫ì®á⨠¯¥ç ⨠¨«¨ ¯®â®ª "
|
||||
9 "®¯à¥¤¥«¥¨¥ ¥¤¥©á⢨⥫쮩 äãªæ¨¨"
|
||||
10 "¥¢¥à®¥ ¯à¨á¢®¥¨¥: «¥¢ ï áâ®à® ¤®«¦ ¡ëâì scale, ibase, obase, last, ¢ ஬ ¨«¨ í«¥¬¥â®¬ ¬ áᨢ "
|
||||
11 " ¢â®¬ â¨ç¥áª ï ¯¥à¥¬¥ ï ¥ ©¤¥ "
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX ¥ ¤®¯ã᪠¥â íªá¯®¥æ¨ «ì®© ®â 樨"
|
||||
26 "POSIX ¥ ¤®¯ã᪠¥â áá뫪¨ ¬ áᨢ ¢ ª ç¥á⢥ ¯ à ¬¥â஢ äãªæ¨¨"
|
||||
27 "POSIX âॡã¥â, çâ®¡ë «¥¢ ï ᪮¡ª ¡ë« ⮩ ¦¥ «¨¨¨, çâ® ¨ § £®«®¢®ª äãªæ¨¨"
|
||||
28 "POSIX ¥ ¯®§¢®«ï¥â ¯à¨á¢ ¨¢ âì áâப¨ ¯¥à¥¬¥ë¬ ¨«¨ ¬ áᨢ ¬"
|
||||
|
||||
$ Žè¨¡ª¨ ¢ë¯®«¥¨ï.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "४ãàá¨¢ë© ¢ë§®¢ read()"
|
||||
6 "¯¥à¥¬¥ ï ¨«¨ í«¥¬¥â ¬ áᨢ ï¥âáï ¥¯à ¢¨«ìë¬ â¨¯®¬"
|
||||
7 "á⮯ª ¨¬¥¥â ᫨誮¬ ¬ «® í«¥¬¥â®¢"
|
||||
8 "¥¯à ¢¨«ì®¥ ª®«¨ç¥á⢮ ¯ à ¬¥â஢; 㦮 %zu, 㦮 %zu"
|
||||
9 "¥®¯à¥¤¥«¥ ï äãªæ¨ï: %s()"
|
||||
10 "¥ ¬®¦¥â ¨á¯®«ì§®¢ âì ¯ãá⮥ § 票¥ ¢ ¢ëà ¦¥¨¨"
|
||||
8 "á⮯ª ¨¬¥¥â ¤«ï ॣ¨áâà \"%s\" ᫨誮¬ ¬ «® í«¥¬¥â®¢"
|
||||
9 "¥¯à ¢¨«ì®¥ ª®«¨ç¥á⢮ ¯ à ¬¥â஢; 㦮 %zu, 㦮 %zu"
|
||||
10 "¥®¯à¥¤¥«¥ ï äãªæ¨ï: %s()"
|
||||
11 "¥ ¬®¦¥â ¨á¯®«ì§®¢ âì ¯ãá⮥ § 票¥ ¢ ¢ëà ¦¥¨¨"
|
||||
|
||||
$ ” â «ìë¥ ®è¨¡ª¨.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "<22>¥ 㤠«®áì ¢ë¤¥«¨âì ¯ ¬ïâì"
|
||||
2 "Žè¨¡ª ¢¢®¤ /¢ë¢®¤ "
|
||||
3 "¥ ᬮ£ ®âªàëâì ä ©«: %s"
|
||||
4 "ä ©« ¥ ASCII: %s"
|
||||
4 "ä ©« ¥ ï¥âáï ⥪á⮢ë¬: %s"
|
||||
5 "¯ãâì - íâ® ª â «®£: %s"
|
||||
6 "¥¢¥à ï ®¯æ¨ï ª®¬ ¤®© áâப¨: '%c' (\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "®¯æ¨ï âॡã¥â à£ã¬¥â : '%c' (\"%s\")"
|
||||
2 "®¯æ¨ï ¥ ¯à¨¨¬ ¥â à£ã¬¥â®¢: '%c' (\"%s\")"
|
||||
6 "¥¢¥à ï ®¯æ¨ï ª®¬ ¤®© áâப¨: \"%s\""
|
||||
7 "®¯æ¨ï âॡã¥â à£ã¬¥â : '%c' (\"%s\")"
|
||||
8 "®¯æ¨ï ¥ ¯à¨¨¬ ¥â à£ã¬¥â®¢: '%c' (\"%s\")"
|
||||
9 "¥¢¥àë© à£ã¬¥â ®¯æ¨¨ ª®¬ ¤®© áâப¨: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "недействительный жетон"
|
||||
6 "неправильное выражение"
|
||||
7 "пустое выражение"
|
||||
8 "заявление о недействительности печати"
|
||||
8 "заявление о недействительности печати или потока"
|
||||
9 "определение недействительной функции"
|
||||
10 "неверное присвоение: левая сторона должна быть scale, ibase, obase, last, варом или элементом массива"
|
||||
11 "автоматическая переменная не найдена"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX не допускает экспоненциальной нотации"
|
||||
26 "POSIX не допускает ссылки на массив в качестве параметров функции"
|
||||
27 "POSIX требует, чтобы левая скобка была на той же линии, что и заголовок функции"
|
||||
28 "POSIX не позволяет присваивать строки переменным или массивам"
|
||||
|
||||
$ Ошибки выполнения.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "рекурсивный вызов read()"
|
||||
6 "переменная или элемент массива является неправильным типом"
|
||||
7 "стопка имеет слишком мало элементов"
|
||||
8 "неправильное количество параметров; нужно %zu, нужно %zu"
|
||||
9 "неопределенная функция: %s()"
|
||||
10 "не может использовать пустое значение в выражении"
|
||||
8 "стопка имеет для регистра \"%s\" слишком мало элементов"
|
||||
9 "неправильное количество параметров; нужно %zu, нужно %zu"
|
||||
10 "неопределенная функция: %s()"
|
||||
11 "не может использовать пустое значение в выражении"
|
||||
|
||||
$ Фатальные ошибки.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "Не удалось выделить память"
|
||||
2 "Ошибка ввода/вывода"
|
||||
3 "не смог открыть файл: %s"
|
||||
4 "файл не ASCII: %s"
|
||||
4 "файл не является текстовым: %s"
|
||||
5 "путь - это каталог: %s"
|
||||
6 "неверная опция командной строки: '%c' (\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "опция требует аргумента: '%c' (\"%s\")"
|
||||
2 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
6 "неверная опция командной строки: \"%s\""
|
||||
7 "опция требует аргумента: '%c' (\"%s\")"
|
||||
8 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
9 "неверный аргумент опции командной строки: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "недействительный жетон"
|
||||
6 "неправильное выражение"
|
||||
7 "пустое выражение"
|
||||
8 "заявление о недействительности печати"
|
||||
8 "заявление о недействительности печати или потока"
|
||||
9 "определение недействительной функции"
|
||||
10 "неверное присвоение: левая сторона должна быть scale, ibase, obase, last, варом или элементом массива"
|
||||
11 "автоматическая переменная не найдена"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX не допускает экспоненциальной нотации"
|
||||
26 "POSIX не допускает ссылки на массив в качестве параметров функции"
|
||||
27 "POSIX требует, чтобы левая скобка была на той же линии, что и заголовок функции"
|
||||
28 "POSIX не позволяет присваивать строки переменным или массивам"
|
||||
|
||||
$ Ошибки выполнения.
|
||||
$set 5
|
||||
|
@ -101,11 +102,9 @@ $set 6
|
|||
1 "Не удалось выделить память"
|
||||
2 "Ошибка ввода/вывода"
|
||||
3 "не смог открыть файл: %s"
|
||||
4 "файл не ASCII: %s"
|
||||
4 "файл не является текстовым: %s"
|
||||
5 "путь - это каталог: %s"
|
||||
6 "неверная опция командной строки: '%c' (\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "опция требует аргумента: '%c' (\"%s\")"
|
||||
2 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
6 "неверная опция командной строки: \"%s\""
|
||||
7 "опция требует аргумента: '%c' (\"%s\")"
|
||||
8 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
9 "неверный аргумент опции командной строки: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "недействительный жетон"
|
||||
6 "неправильное выражение"
|
||||
7 "пустое выражение"
|
||||
8 "заявление о недействительности печати"
|
||||
8 "заявление о недействительности печати или потока"
|
||||
9 "определение недействительной функции"
|
||||
10 "неверное присвоение: левая сторона должна быть scale, ibase, obase, last, варом или элементом массива"
|
||||
11 "автоматическая переменная не найдена"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX не допускает экспоненциальной нотации"
|
||||
26 "POSIX не допускает ссылки на массив в качестве параметров функции"
|
||||
27 "POSIX требует, чтобы левая скобка была на той же линии, что и заголовок функции"
|
||||
28 "POSIX не позволяет присваивать строки переменным или массивам"
|
||||
|
||||
$ Ошибки выполнения.
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "рекурсивный вызов read()"
|
||||
6 "переменная или элемент массива является неправильным типом"
|
||||
7 "стопка имеет слишком мало элементов"
|
||||
8 "неправильное количество параметров; нужно %zu, нужно %zu"
|
||||
9 "неопределенная функция: %s()"
|
||||
10 "не может использовать пустое значение в выражении"
|
||||
8 "стопка имеет для регистра \"%s\" слишком мало элементов"
|
||||
9 "неправильное количество параметров; нужно %zu, нужно %zu"
|
||||
10 "неопределенная функция: %s()"
|
||||
11 "не может использовать пустое значение в выражении"
|
||||
|
||||
$ Фатальные ошибки.
|
||||
$set 6
|
||||
|
@ -101,11 +103,9 @@ $set 6
|
|||
1 "Не удалось выделить память"
|
||||
2 "Ошибка ввода/вывода"
|
||||
3 "не смог открыть файл: %s"
|
||||
4 "файл не ASCII: %s"
|
||||
4 "файл не является текстовым: %s"
|
||||
5 "путь - это каталог: %s"
|
||||
6 "неверная опция командной строки: '%c' (\"%s\")"
|
||||
|
||||
$set 7
|
||||
|
||||
1 "опция требует аргумента: '%c' (\"%s\")"
|
||||
2 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
6 "неверная опция командной строки: \"%s\""
|
||||
7 "опция требует аргумента: '%c' (\"%s\")"
|
||||
8 "опция не принимает аргументов: '%c' (\"%s\")"
|
||||
9 "неверный аргумент опции командной строки: \"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "无效令牌"
|
||||
6 "无效表达"
|
||||
7 “空表达”
|
||||
8 "无效打印声明"
|
||||
8 "无效的打印或流语句"
|
||||
9 "无效的功能定义"
|
||||
10 "无效分配:左侧必须是scale、ibase、obase、last、var或数组元素"
|
||||
11 "没有找到自动变量"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX不允许使用指数符号"
|
||||
26 "POSIX不允许数组引用作为函数参数"
|
||||
27 "POSIX要求左边的括号和函数头在同一行上"
|
||||
28 "POSIX不允许将字符串分配给变量或数组"
|
||||
|
||||
$ 运行时错误。
|
||||
$set 5
|
||||
|
@ -91,18 +92,20 @@ $set 5
|
|||
5 "递归读取()调用"
|
||||
6 "变量或数组元素是错误的类型"
|
||||
7 "堆栈的元素太少"
|
||||
8 "参数数量错误;需要%zu,有%zu"
|
||||
9 "未定义的函数:%s()"
|
||||
10 “不能在表达式中使用空值”
|
||||
8 "寄存器 \"%s\" 的堆栈的元素太少"
|
||||
9 "参数数量错误;需要%zu,有%zu"
|
||||
10 "未定义的函数:%s()"
|
||||
11 “不能在表达式中使用空值”
|
||||
|
||||
$ 致命错误。
|
||||
$set 6
|
||||
|
||||
1 "内存分配失败"
|
||||
2 "I/O错误"
|
||||
3 "无法打开文件。%s"
|
||||
4 "文件不是ASCII: %s"
|
||||
3 "无法打开文件:%s"
|
||||
4 "文件不是文本:%s"
|
||||
5 "路径是一个目录:%s"
|
||||
6 "无效的命令行选项:\"%s\""
|
||||
7 "选项需要一个参数:'%c'(\"%s\")"
|
||||
8 "选项不需要参数。'%c'(\"%s\")"
|
||||
8 "选项不需要参数:'%c'(\"%s\")"
|
||||
9 "无效的命令行选项参数:\"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "无效令牌"
|
||||
6 "无效表达"
|
||||
7 “空表达”
|
||||
8 "无效打印声明"
|
||||
8 "无效的打印或流语句"
|
||||
9 "无效的功能定义"
|
||||
10 "无效分配:左侧必须是scale、ibase、obase、last、var或数组元素"
|
||||
11 "没有找到自动变量"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX不允许使用指数符号"
|
||||
26 "POSIX不允许数组引用作为函数参数"
|
||||
27 "POSIX要求左边的括号和函数头在同一行上"
|
||||
28 "POSIX不允许将字符串分配给变量或数组"
|
||||
|
||||
$ 运行时错误。
|
||||
$set 5
|
||||
|
@ -91,18 +92,20 @@ $set 5
|
|||
5 "递归读取()调用"
|
||||
6 "变量或数组元素是错误的类型"
|
||||
7 "堆栈的元素太少"
|
||||
8 "参数数量错误;需要%zu,有%zu"
|
||||
9 "未定义的函数:%s()"
|
||||
10 “不能在表达式中使用空值”
|
||||
8 "寄存器 \"%s\" 的堆栈的元素太少"
|
||||
9 "参数数量错误;需要%zu,有%zu"
|
||||
10 "未定义的函数:%s()"
|
||||
11 “不能在表达式中使用空值”
|
||||
|
||||
$ 致命错误。
|
||||
$set 6
|
||||
|
||||
1 "内存分配失败"
|
||||
2 "I/O错误"
|
||||
3 "无法打开文件。%s"
|
||||
4 "文件不是ASCII: %s"
|
||||
3 "无法打开文件:%s"
|
||||
4 "文件不是文本:%s"
|
||||
5 "路径是一个目录:%s"
|
||||
6 "无效的命令行选项:\"%s\""
|
||||
7 "选项需要一个参数:'%c'(\"%s\")"
|
||||
8 "选项不需要参数。'%c'(\"%s\")"
|
||||
8 "选项不需要参数:'%c'(\"%s\")"
|
||||
9 "无效的命令行选项参数:\"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "无效令牌"
|
||||
6 "无效表达"
|
||||
7 “空表达”
|
||||
8 "无效打印声明"
|
||||
8 "无效的打印或流语句"
|
||||
9 "无效的功能定义"
|
||||
10 "无效分配:左侧必须是scale、ibase、obase、last、var或数组元素"
|
||||
11 "没有找到自动变量"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX不允许使用指数符号"
|
||||
26 "POSIX不允许数组引用作为函数参数"
|
||||
27 "POSIX要求左边的括号和函数头在同一行上"
|
||||
28 "POSIX不允许将字符串分配给变量或数组"
|
||||
|
||||
$ 运行时错误。
|
||||
$set 5
|
||||
|
@ -91,18 +92,20 @@ $set 5
|
|||
5 "递归读取()调用"
|
||||
6 "变量或数组元素是错误的类型"
|
||||
7 "堆栈的元素太少"
|
||||
8 "参数数量错误;需要%zu,有%zu"
|
||||
9 "未定义的函数:%s()"
|
||||
10 “不能在表达式中使用空值”
|
||||
8 "寄存器 \"%s\" 的堆栈的元素太少"
|
||||
9 "参数数量错误;需要%zu,有%zu"
|
||||
10 "未定义的函数:%s()"
|
||||
11 “不能在表达式中使用空值”
|
||||
|
||||
$ 致命错误。
|
||||
$set 6
|
||||
|
||||
1 "内存分配失败"
|
||||
2 "I/O错误"
|
||||
3 "无法打开文件。%s"
|
||||
4 "文件不是ASCII: %s"
|
||||
3 "无法打开文件:%s"
|
||||
4 "文件不是文本:%s"
|
||||
5 "路径是一个目录:%s"
|
||||
6 "无效的命令行选项:\"%s\""
|
||||
7 "选项需要一个参数:'%c'(\"%s\")"
|
||||
8 "选项不需要参数。'%c'(\"%s\")"
|
||||
8 "选项不需要参数:'%c'(\"%s\")"
|
||||
9 "无效的命令行选项参数:\"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "无效令牌"
|
||||
6 "无效表达"
|
||||
7 “空表达”
|
||||
8 "无效打印声明"
|
||||
8 "无效的打印或流语句"
|
||||
9 "无效的功能定义"
|
||||
10 "无效分配:左侧必须是scale、ibase、obase、last、var或数组元素"
|
||||
11 "没有找到自动变量"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX不允许使用指数符号"
|
||||
26 "POSIX不允许数组引用作为函数参数"
|
||||
27 "POSIX要求左边的括号和函数头在同一行上"
|
||||
28 "POSIX不允许将字符串分配给变量或数组"
|
||||
|
||||
$ 运行时错误。
|
||||
$set 5
|
||||
|
@ -91,9 +92,10 @@ $set 5
|
|||
5 "递归读取()调用"
|
||||
6 "变量或数组元素是错误的类型"
|
||||
7 "堆栈的元素太少"
|
||||
8 "参数数量错误:需要%zu,有%zu"
|
||||
9 "未定义的函数:%s()"
|
||||
10 “不能在表达式中使用空值”
|
||||
8 "寄存器 \"%s\" 的堆栈的元素太少"
|
||||
9 "参数数量错误:需要%zu,有%zu"
|
||||
10 "未定义的函数:%s()"
|
||||
11 “不能在表达式中使用空值”
|
||||
|
||||
$ 致命错误。
|
||||
$set 6
|
||||
|
@ -101,8 +103,9 @@ $set 6
|
|||
1 "内存分配失败"
|
||||
2 "I/O错误"
|
||||
3 "无法打开文件:%s"
|
||||
4 "文件不是ASCII: %s"
|
||||
4 "文件不是文本:%s"
|
||||
5 "路径是一个目录:%s"
|
||||
6 "无效的命令行选项:\"%s\""
|
||||
7 "选项需要一个参数:'%c'(\"%s\")"
|
||||
8 "选项不需要参数。'%c'(\"%s\")"
|
||||
8 "选项不需要参数:'%c'(\"%s\")"
|
||||
9 "无效的命令行选项参数:\"%s\""
|
||||
|
|
|
@ -60,7 +60,7 @@ $set 4
|
|||
5 "无效令牌"
|
||||
6 "无效表达"
|
||||
7 “空表达”
|
||||
8 "无效打印声明"
|
||||
8 "无效的打印或流语句"
|
||||
9 "无效的功能定义"
|
||||
10 "无效分配:左侧必须是scale、ibase、obase、last、var或数组元素"
|
||||
11 "没有找到自动变量"
|
||||
|
@ -80,6 +80,7 @@ $set 4
|
|||
25 "POSIX不允许使用指数符号"
|
||||
26 "POSIX不允许数组引用作为函数参数"
|
||||
27 "POSIX要求左边的括号和函数头在同一行上"
|
||||
28 "POSIX不允许将字符串分配给变量或数组"
|
||||
|
||||
$ 运行时错误。
|
||||
$set 5
|
||||
|
@ -91,18 +92,20 @@ $set 5
|
|||
5 "递归读取()调用"
|
||||
6 "变量或数组元素是错误的类型"
|
||||
7 "堆栈的元素太少"
|
||||
8 "参数数量错误;需要%zu,有%zu"
|
||||
9 "未定义的函数:%s()"
|
||||
10 “不能在表达式中使用空值”
|
||||
8 "寄存器 \"%s\" 的堆栈的元素太少"
|
||||
9 "参数数量错误;需要%zu,有%zu"
|
||||
10 "未定义的函数:%s()"
|
||||
11 “不能在表达式中使用空值”
|
||||
|
||||
$ 致命错误。
|
||||
$set 6
|
||||
|
||||
1 "内存分配失败"
|
||||
2 "I/O错误"
|
||||
3 "无法打开文件。%s"
|
||||
4 "文件不是ASCII: %s"
|
||||
3 "无法打开文件:%s"
|
||||
4 "文件不是文本:%s"
|
||||
5 "路径是一个目录:%s"
|
||||
6 "无效的命令行选项:\"%s\""
|
||||
7 "选项需要一个参数:'%c'(\"%s\")"
|
||||
8 "选项不需要参数。'%c'(\"%s\")"
|
||||
8 "选项不需要参数:'%c'(\"%s\")"
|
||||
9 "无效的命令行选项参数:\"%s\""
|
||||
|
|
131
manpage.sh
131
manpage.sh
|
@ -1,131 +0,0 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2018-2021 Gavin D. Howard and contributors.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
usage() {
|
||||
printf "usage: %s manpage\n" "$0" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
print_manpage() {
|
||||
|
||||
_print_manpage_md="$1"
|
||||
shift
|
||||
|
||||
_print_manpage_out="$1"
|
||||
shift
|
||||
|
||||
cat "$manualsdir/header.txt" > "$_print_manpage_out"
|
||||
cat "$manualsdir/header_${manpage}.txt" >> "$_print_manpage_out"
|
||||
|
||||
pandoc -f commonmark -t man "$_print_manpage_md" >> "$_print_manpage_out"
|
||||
|
||||
}
|
||||
|
||||
gen_manpage() {
|
||||
|
||||
_gen_manpage_args="$1"
|
||||
shift
|
||||
|
||||
_gen_manpage_status="$ALL"
|
||||
_gen_manpage_out="$manualsdir/$manpage/$_gen_manpage_args.1"
|
||||
_gen_manpage_md="$manualsdir/$manpage/$_gen_manpage_args.1.md"
|
||||
_gen_manpage_temp="$manualsdir/temp.1.md"
|
||||
_gen_manpage_ifs="$IFS"
|
||||
|
||||
rm -rf "$_gen_manpage_out" "$_gen_manpage_md"
|
||||
|
||||
while IFS= read -r line; do
|
||||
|
||||
if [ "$line" = "{{ end }}" ]; then
|
||||
|
||||
if [ "$_gen_manpage_status" -eq "$ALL" ]; then
|
||||
err_exit "{{ end }} tag without corresponding start tag" 2
|
||||
fi
|
||||
|
||||
_gen_manpage_status="$ALL"
|
||||
|
||||
elif [ "${line#\{\{* $_gen_manpage_args *\}\}}" != "$line" ]; then
|
||||
|
||||
if [ "$_gen_manpage_status" -ne "$ALL" ]; then
|
||||
err_exit "start tag nested in start tag" 3
|
||||
fi
|
||||
|
||||
_gen_manpage_status="$NOSKIP"
|
||||
|
||||
elif [ "${line#\{\{*\}\}}" != "$line" ]; then
|
||||
|
||||
if [ "$_gen_manpage_status" -ne "$ALL" ]; then
|
||||
err_exit "start tag nested in start tag" 3
|
||||
fi
|
||||
|
||||
_gen_manpage_status="$SKIP"
|
||||
|
||||
else
|
||||
if [ "$_gen_manpage_status" -ne "$SKIP" ]; then
|
||||
printf '%s\n' "$line" >> "$_gen_manpage_temp"
|
||||
fi
|
||||
fi
|
||||
|
||||
done < "$manualsdir/${manpage}.1.md.in"
|
||||
|
||||
uniq "$_gen_manpage_temp" "$_gen_manpage_md"
|
||||
rm -rf "$_gen_manpage_temp"
|
||||
|
||||
IFS="$_gen_manpage_ifs"
|
||||
|
||||
print_manpage "$_gen_manpage_md" "$_gen_manpage_out"
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
script="$0"
|
||||
scriptdir=$(dirname "$script")
|
||||
manualsdir="$scriptdir/manuals"
|
||||
|
||||
. "$scriptdir/functions.sh"
|
||||
|
||||
ARGS="A E H N P EH EN EP HN HP NP EHN EHP ENP HNP EHNP"
|
||||
ALL=0
|
||||
NOSKIP=1
|
||||
SKIP=2
|
||||
|
||||
test "$#" -eq 1 || usage
|
||||
|
||||
manpage="$1"
|
||||
shift
|
||||
|
||||
if [ "$manpage" != "bcl" ]; then
|
||||
|
||||
for a in $ARGS; do
|
||||
gen_manpage "$a"
|
||||
done
|
||||
|
||||
else
|
||||
print_manpage "$manualsdir/${manpage}.3.md" "$manualsdir/${manpage}.3"
|
||||
fi
|
|
@ -25,8 +25,8 @@ Brute force multiplication is used below `BC_NUM_KARATSUBA_LEN` digits. It is
|
|||
polynomial (`O(n^2)`), but since Karatsuba requires both more intermediate
|
||||
values (which translate to memory allocations) and a few more additions, there
|
||||
is a "break even" point in the number of digits where brute force multiplication
|
||||
is faster than Karatsuba. There is a script (`$ROOT/karatsuba.py`) that will
|
||||
find the break even point on a particular machine.
|
||||
is faster than Karatsuba. There is a script (`$ROOT/scripts/karatsuba.py`) that
|
||||
will find the break even point on a particular machine.
|
||||
|
||||
***WARNING: The Karatsuba script requires Python 3.***
|
||||
|
||||
|
@ -62,10 +62,12 @@ a complexity of `O((n*log(n))^log_2(3))` which is favorable to the
|
|||
|
||||
This `bc` implements the fast algorithm [Newton's Method][4] (also known as the
|
||||
Newton-Raphson Method, or the [Babylonian Method][5]) to perform the square root
|
||||
operation. Its complexity is `O(log(n)*n^2)` as it requires one division per
|
||||
iteration.
|
||||
operation.
|
||||
|
||||
### Sine and Cosine (`bc` Only)
|
||||
Its complexity is `O(log(n)*n^2)` as it requires one division per iteration, and
|
||||
it doubles the amount of correct digits per iteration.
|
||||
|
||||
### Sine and Cosine (`bc` Math Library Only)
|
||||
|
||||
This `bc` uses the series
|
||||
|
||||
|
@ -89,7 +91,7 @@ impossible and unnecessary.) Therefore, I recommend that users do their
|
|||
calculations with the precision (`scale`) set to at least 1 greater than is
|
||||
needed.
|
||||
|
||||
### Exponentiation (`bc` Only)
|
||||
### Exponentiation (`bc` Math Library Only)
|
||||
|
||||
This `bc` uses the series
|
||||
|
||||
|
@ -103,13 +105,15 @@ to calculate `e^x`. Since this only works when `x` is small, it uses
|
|||
e^x = (e^(x/2))^2
|
||||
```
|
||||
|
||||
to reduce `x`. It has a complexity of `O(n^3)`.
|
||||
to reduce `x`.
|
||||
|
||||
It has a complexity of `O(n^3)`.
|
||||
|
||||
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
|
||||
their calculations with the precision (`scale`) set to at least 1 greater than
|
||||
is needed.
|
||||
|
||||
### Natural Logarithm (`bc` Only)
|
||||
### Natural Logarithm (`bc` Math Library Only)
|
||||
|
||||
This `bc` uses the series
|
||||
|
||||
|
@ -124,13 +128,15 @@ and uses the relation
|
|||
ln(x^2) = 2 * ln(x)
|
||||
```
|
||||
|
||||
to sufficiently reduce `x`. It has a complexity of `O(n^3)`.
|
||||
to sufficiently reduce `x`.
|
||||
|
||||
It has a complexity of `O(n^3)`.
|
||||
|
||||
**Note**: this series can also produce errors of 1 ULP, so I recommend users do
|
||||
their calculations with the precision (`scale`) set to at least 1 greater than
|
||||
is needed.
|
||||
|
||||
### Arctangent (`bc` Only)
|
||||
### Arctangent (`bc` Math Library Only)
|
||||
|
||||
This `bc` uses the series
|
||||
|
||||
|
@ -150,7 +156,7 @@ to reduce `x` to small enough. It has a complexity of `O(n^3)`.
|
|||
their calculations with the precision (`scale`) set to at least 1 greater than
|
||||
is needed.
|
||||
|
||||
### Bessel (`bc` Only)
|
||||
### Bessel (`bc` Math Library Only)
|
||||
|
||||
This `bc` uses the series
|
||||
|
||||
|
@ -179,6 +185,137 @@ exponentiation. The complexity is `O(e*n^2)`, which may initially seem
|
|||
inefficient, but `n` is kept small by maintaining small numbers. In practice, it
|
||||
is extremely fast.
|
||||
|
||||
### Non-Integer Exponentiation (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `p(x,y)`.
|
||||
|
||||
The algorithm used is to use the formula `e(y*l(x))`.
|
||||
|
||||
It has a complexity of `O(n^3)` because both `e()` and `l()` do.
|
||||
|
||||
### Rounding (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `r(x,p)`.
|
||||
|
||||
The algorithm is a simple method to check if rounding away from zero is
|
||||
necessary, and if so, adds `1e10^p`.
|
||||
|
||||
It has a complexity of `O(n)` because of add.
|
||||
|
||||
### Ceiling (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `ceil(x,p)`.
|
||||
|
||||
The algorithm is a simple add of one less decimal place than `p`.
|
||||
|
||||
It has a complexity of `O(n)` because of add.
|
||||
|
||||
### Factorial (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `f(n)`.
|
||||
|
||||
The algorithm is a simple multiplication loop.
|
||||
|
||||
It has a complexity of `O(n^3)` because of linear amount of `O(n^2)`
|
||||
multiplications.
|
||||
|
||||
### Permutations (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `perm(n,k)`.
|
||||
|
||||
The algorithm is to use the formula `n!/(n-k)!`.
|
||||
|
||||
It has a complexity of `O(n^3)` because of the division and factorials.
|
||||
|
||||
### Combinations (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `comb(n,r)`.
|
||||
|
||||
The algorithm is to use the formula `n!/r!*(n-r)!`.
|
||||
|
||||
It has a complexity of `O(n^3)` because of the division and factorials.
|
||||
|
||||
### Logarithm of Any Base (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `log(x,b)`.
|
||||
|
||||
The algorithm is to use the formula `l(x)/l(b)` with double the `scale` because
|
||||
there is no good way of knowing how many digits of precision are needed when
|
||||
switching bases.
|
||||
|
||||
It has a complexity of `O(n^3)` because of the division and `l()`.
|
||||
|
||||
### Logarithm of Base 2 (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `l2(x)`.
|
||||
|
||||
This is a convenience wrapper around `log(x,2)`.
|
||||
|
||||
### Logarithm of Base 10 (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `l10(x)`.
|
||||
|
||||
This is a convenience wrapper around `log(x,10)`.
|
||||
|
||||
### Root (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `root(x,n)`.
|
||||
|
||||
The algorithm is [Newton's method][9]. The initial guess is calculated as
|
||||
`10^ceil(length(x)/n)`.
|
||||
|
||||
Like square root, its complexity is `O(log(n)*n^2)` as it requires one division
|
||||
per iteration, and it doubles the amount of correct digits per iteration.
|
||||
|
||||
### Cube Root (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `cbrt(x)`.
|
||||
|
||||
This is a convenience wrapper around `root(x,3)`.
|
||||
|
||||
### Greatest Common Divisor (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `gcd(a,b)`.
|
||||
|
||||
The algorithm is an iterative version of the [Euclidean Algorithm][10].
|
||||
|
||||
It has a complexity of `O(n^4)` because it has a linear number of divisions.
|
||||
|
||||
This function ensures that `a` is always bigger than `b` before starting the
|
||||
algorithm.
|
||||
|
||||
### Least Common Multiple (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `lcm(a,b)`.
|
||||
|
||||
The algorithm uses the formula `a*b/gcd(a,b)`.
|
||||
|
||||
It has a complexity of `O(n^4)` because of `gcd()`.
|
||||
|
||||
### Pi (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `pi(s)`.
|
||||
|
||||
The algorithm uses the formula `4*a(1)`.
|
||||
|
||||
It has a complexity of `O(n^3)` because of arctangent.
|
||||
|
||||
### Tangent (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `t(x)`.
|
||||
|
||||
The algorithm uses the formula `s(x)/c(x)`.
|
||||
|
||||
It has a complexity of `O(n^3)` because of sine, cosine, and division.
|
||||
|
||||
### Atan2 (`bc` Math Library 2 Only)
|
||||
|
||||
This is implemented in the function `a2(y,x)`.
|
||||
|
||||
The algorithm uses the [standard formulas][11].
|
||||
|
||||
It has a complexity of `O(n^3)` because of arctangent.
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Karatsuba_algorithm
|
||||
[2]: https://en.wikipedia.org/wiki/Long_division
|
||||
[3]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
||||
|
@ -187,3 +324,6 @@ is extremely fast.
|
|||
[6]: https://en.wikipedia.org/wiki/Unit_in_the_last_place
|
||||
[7]: https://people.eecs.berkeley.edu/~wkahan/LOG10HAF.TXT
|
||||
[8]: https://en.wikipedia.org/wiki/Modular_exponentiation#Memory-efficient_method
|
||||
[9]: https://en.wikipedia.org/wiki/Root-finding_algorithms#Newton's_method_(and_similar_derivative-based_methods)
|
||||
[10]: https://en.wikipedia.org/wiki/Euclidean_algorithm
|
||||
[11]: https://en.wikipedia.org/wiki/Atan2#Definition_and_computation
|
||||
|
|
1840
manuals/bc.1.md.in
1840
manuals/bc.1.md.in
File diff suppressed because it is too large
Load diff
2567
manuals/bc/A.1
2567
manuals/bc/A.1
File diff suppressed because it is too large
Load diff
|
@ -50,6 +50,15 @@ This bc(1) is a drop-in replacement for *any* bc(1), including (and
|
|||
especially) the GNU bc(1). It also has many extensions and extra features beyond
|
||||
other implementations.
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
The following are the options that bc(1) accepts.
|
||||
|
@ -148,6 +157,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -162,8 +174,51 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **irand**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxrand**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **rand**
|
||||
* **read**
|
||||
* **seed**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -227,6 +282,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -380,31 +451,47 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
14. **rand()**: A pseudo-random integer between **0** (inclusive) and
|
||||
17. **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**.
|
||||
15. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
|
||||
18. **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
|
||||
|
@ -415,7 +502,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**.
|
||||
16. **maxrand()**: The max integer returned by **rand()**. This is a
|
||||
19. **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
|
||||
|
@ -731,14 +818,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -776,23 +864,48 @@ either the **-s** or **-w** command-line options (or equivalents).
|
|||
Printing numbers in scientific notation and/or engineering notation is a
|
||||
**non-portable extension**.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -800,6 +913,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -1021,6 +1147,16 @@ The extended library is a **non-portable extension**.
|
|||
reset (see the **RESET** section). It also raises an error and causes bc(1)
|
||||
to reset if **r** is even and **x** is negative.
|
||||
|
||||
**gcd(a, b)**
|
||||
|
||||
: Returns the greatest common divisor (factor) of the truncated absolute value
|
||||
of **a** and the truncated absolute value of **b**.
|
||||
|
||||
**lcm(a, b)**
|
||||
|
||||
: Returns the least common multiple of the truncated absolute value of **a**
|
||||
and the truncated absolute value of **b**.
|
||||
|
||||
**pi(p)**
|
||||
|
||||
: Returns **pi** to **p** decimal places.
|
||||
|
@ -1150,6 +1286,317 @@ The extended library is a **non-portable extension**.
|
|||
|
||||
: Returns a random boolean value (either **0** or **1**).
|
||||
|
||||
**band(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **and** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **or** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bxor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **xor** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshl(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of **a** bit-shifted left by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshr(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the truncated result of **a** bit-shifted right by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnotn(x, n)**
|
||||
|
||||
: Takes the truncated absolute value of **x** and does a bitwise not as though
|
||||
it has the same number of bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot8(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**8** binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot16(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**16** binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot32(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**32** binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot64(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**64** binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brevn(x, n)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the same number of 8-bit bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev8(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 8 binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev16(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 16 binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev32(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 32 binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev64(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 64 binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**broln(x, p, n)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol8(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol16(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol32(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol64(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brorn(x, p, n)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror8(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror16(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror32(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror64(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmodn(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of the multiplication of the truncated absolute value of **n** and
|
||||
**8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod8(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod16(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod32(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod64(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bunrev(t)**
|
||||
|
||||
: Assumes **t** is a bitwise-reversed number with an extra set bit one place
|
||||
more significant than the real most significant bit (which was the least
|
||||
significant bit in the original number). This number is reversed and
|
||||
returned without the extra set bit.
|
||||
|
||||
This function is used to implement other bitwise functions; it is not meant
|
||||
to be used by users, but it can be.
|
||||
|
||||
**ubytes(x)**
|
||||
|
||||
: Returns the numbers of unsigned integer bytes required to hold the truncated
|
||||
|
@ -1160,6 +1607,20 @@ The extended library is a **non-portable extension**.
|
|||
: Returns the numbers of signed, two's-complement integer bytes required to
|
||||
hold the truncated value of **x**.
|
||||
|
||||
**s2u(x)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer and returns the
|
||||
non-negative integer that would have the same representation in binary.
|
||||
|
||||
**s2un(x,n)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer with **n** bytes and
|
||||
returns the non-negative integer that would have the same representation in
|
||||
binary. If **x** cannot fit into **n** 2's-complement signed bytes, it is
|
||||
truncated to fit.
|
||||
|
||||
**hex(x)**
|
||||
|
||||
: Outputs the hexadecimal (base **16**) representation of **x**.
|
||||
|
@ -1551,6 +2012,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -1568,8 +2084,9 @@ bc(1) returns the following exit statuses:
|
|||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, using a negative number as a bound for the pseudo-random number
|
||||
generator, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**), places (**\@**), left shift (**\<\<**), and right shift (**\>\>**)
|
||||
|
@ -1594,11 +2111,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1627,37 +2145,78 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
TTY mode is required for history to be enabled (see the **COMMAND LINE HISTORY**
|
||||
section). It is also required to enable special handling for **SIGINT** signals.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Command-Line History
|
||||
|
||||
Command-line history is only enabled if TTY mode is, i.e., that **stdin**,
|
||||
**stdout**, and **stderr** are connected to a TTY and the **BC_TTY_MODE**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section) and its default
|
||||
do not disable TTY mode. See the **COMMAND LINE HISTORY** section for more
|
||||
information.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
@ -1669,14 +2228,22 @@ continue.
|
|||
|
||||
**SIGTERM** and **SIGQUIT** cause bc(1) to clean up and exit, and it uses the
|
||||
default handler for all other signals. The one exception is **SIGHUP**; in that
|
||||
case, when bc(1) is in TTY mode, a **SIGHUP** will cause bc(1) to clean up and
|
||||
exit.
|
||||
case, and only when bc(1) is in TTY mode (see the **TTY MODE** section), a
|
||||
**SIGHUP** will cause bc(1) to clean up and exit.
|
||||
|
||||
# COMMAND LINE HISTORY
|
||||
|
||||
bc(1) supports interactive command-line editing. If bc(1) is in TTY mode (see
|
||||
the **TTY MODE** section), history is enabled. Previous lines can be recalled
|
||||
and edited with the arrow keys.
|
||||
bc(1) supports interactive command-line editing.
|
||||
|
||||
If bc(1) can be in TTY mode (see the **TTY MODE** section), history can be
|
||||
enabled. This means that command-line history can only be enabled when
|
||||
**stdin**, **stdout**, and **stderr** are all connected to a TTY.
|
||||
|
||||
Like TTY mode itself, it can be turned on or off with the environment variable
|
||||
**BC_TTY_MODE** (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If history is enabled, previous lines can be recalled and edited with the arrow
|
||||
keys.
|
||||
|
||||
**Note**: tabs are converted to 8 spaces.
|
||||
|
||||
|
|
1281
manuals/bc/E.1
1281
manuals/bc/E.1
File diff suppressed because it is too large
Load diff
|
@ -46,8 +46,17 @@ Such differences will be noted in this document.
|
|||
After parsing and handling options, this bc(1) reads any files given on the
|
||||
command line and executes them before reading from **stdin**.
|
||||
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and
|
||||
especially) the GNU bc(1).
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and especially)
|
||||
the GNU bc(1).
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
|
@ -55,7 +64,7 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
**-g**, **-\-global-stacks**
|
||||
|
||||
Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
: Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
|
||||
This has the effect that a copy of the current value of all three are pushed
|
||||
onto a stack for every function call, as well as popped when every function
|
||||
|
@ -132,6 +141,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -146,8 +158,47 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **read**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -211,6 +262,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -338,26 +405,42 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
|
||||
## Numbers
|
||||
|
@ -578,14 +661,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -612,23 +696,48 @@ is like the **quit** statement in that it is a compile-time command.
|
|||
|
||||
An expression by itself is evaluated and printed, followed by a newline.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -636,6 +745,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -942,6 +1064,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -958,8 +1135,9 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**) operator and the corresponding assignment operator.
|
||||
|
@ -983,11 +1161,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1016,37 +1195,78 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
TTY mode is required for history to be enabled (see the **COMMAND LINE HISTORY**
|
||||
section). It is also required to enable special handling for **SIGINT** signals.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Command-Line History
|
||||
|
||||
Command-line history is only enabled if TTY mode is, i.e., that **stdin**,
|
||||
**stdout**, and **stderr** are connected to a TTY and the **BC_TTY_MODE**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section) and its default
|
||||
do not disable TTY mode. See the **COMMAND LINE HISTORY** section for more
|
||||
information.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
@ -1058,14 +1278,22 @@ continue.
|
|||
|
||||
**SIGTERM** and **SIGQUIT** cause bc(1) to clean up and exit, and it uses the
|
||||
default handler for all other signals. The one exception is **SIGHUP**; in that
|
||||
case, when bc(1) is in TTY mode, a **SIGHUP** will cause bc(1) to clean up and
|
||||
exit.
|
||||
case, and only when bc(1) is in TTY mode (see the **TTY MODE** section), a
|
||||
**SIGHUP** will cause bc(1) to clean up and exit.
|
||||
|
||||
# COMMAND LINE HISTORY
|
||||
|
||||
bc(1) supports interactive command-line editing. If bc(1) is in TTY mode (see
|
||||
the **TTY MODE** section), history is enabled. Previous lines can be recalled
|
||||
and edited with the arrow keys.
|
||||
bc(1) supports interactive command-line editing.
|
||||
|
||||
If bc(1) can be in TTY mode (see the **TTY MODE** section), history can be
|
||||
enabled. This means that command-line history can only be enabled when
|
||||
**stdin**, **stdout**, and **stderr** are all connected to a TTY.
|
||||
|
||||
Like TTY mode itself, it can be turned on or off with the environment variable
|
||||
**BC_TTY_MODE** (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If history is enabled, previous lines can be recalled and edited with the arrow
|
||||
keys.
|
||||
|
||||
**Note**: tabs are converted to 8 spaces.
|
||||
|
||||
|
|
1252
manuals/bc/EH.1
1252
manuals/bc/EH.1
File diff suppressed because it is too large
Load diff
|
@ -46,13 +46,25 @@ Such differences will be noted in this document.
|
|||
After parsing and handling options, this bc(1) reads any files given on the
|
||||
command line and executes them before reading from **stdin**.
|
||||
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and especially)
|
||||
the GNU bc(1).
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
The following are the options that bc(1) accepts.
|
||||
|
||||
**-g**, **-\-global-stacks**
|
||||
|
||||
Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
: Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
|
||||
This has the effect that a copy of the current value of all three are pushed
|
||||
onto a stack for every function call, as well as popped when every function
|
||||
|
@ -129,6 +141,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -143,8 +158,47 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **read**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -208,6 +262,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -335,26 +405,42 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
|
||||
## Numbers
|
||||
|
@ -575,14 +661,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -609,23 +696,48 @@ is like the **quit** statement in that it is a compile-time command.
|
|||
|
||||
An expression by itself is evaluated and printed, followed by a newline.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -633,6 +745,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -939,6 +1064,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -955,8 +1135,9 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**) operator and the corresponding assignment operator.
|
||||
|
@ -980,11 +1161,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1013,34 +1195,70 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
|
1252
manuals/bc/EHN.1
1252
manuals/bc/EHN.1
File diff suppressed because it is too large
Load diff
|
@ -46,13 +46,25 @@ Such differences will be noted in this document.
|
|||
After parsing and handling options, this bc(1) reads any files given on the
|
||||
command line and executes them before reading from **stdin**.
|
||||
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and especially)
|
||||
the GNU bc(1).
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
The following are the options that bc(1) accepts.
|
||||
|
||||
**-g**, **-\-global-stacks**
|
||||
|
||||
Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
: Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
|
||||
This has the effect that a copy of the current value of all three are pushed
|
||||
onto a stack for every function call, as well as popped when every function
|
||||
|
@ -129,6 +141,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -143,8 +158,47 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **read**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -208,6 +262,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -335,26 +405,42 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
|
||||
## Numbers
|
||||
|
@ -575,14 +661,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -609,23 +696,48 @@ is like the **quit** statement in that it is a compile-time command.
|
|||
|
||||
An expression by itself is evaluated and printed, followed by a newline.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -633,6 +745,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -939,6 +1064,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -955,8 +1135,9 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**) operator and the corresponding assignment operator.
|
||||
|
@ -980,11 +1161,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1013,34 +1195,70 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
|
1375
manuals/bc/EHNP.1
1375
manuals/bc/EHNP.1
File diff suppressed because it is too large
Load diff
1069
manuals/bc/EHNP.1.md
1069
manuals/bc/EHNP.1.md
File diff suppressed because it is too large
Load diff
1382
manuals/bc/EHP.1
1382
manuals/bc/EHP.1
File diff suppressed because it is too large
Load diff
1077
manuals/bc/EHP.1.md
1077
manuals/bc/EHP.1.md
File diff suppressed because it is too large
Load diff
1281
manuals/bc/EN.1
1281
manuals/bc/EN.1
File diff suppressed because it is too large
Load diff
|
@ -46,8 +46,17 @@ Such differences will be noted in this document.
|
|||
After parsing and handling options, this bc(1) reads any files given on the
|
||||
command line and executes them before reading from **stdin**.
|
||||
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and
|
||||
especially) the GNU bc(1).
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and especially)
|
||||
the GNU bc(1).
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
|
@ -55,7 +64,7 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
**-g**, **-\-global-stacks**
|
||||
|
||||
Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
: Turns the globals **ibase**, **obase**, and **scale** into stacks.
|
||||
|
||||
This has the effect that a copy of the current value of all three are pushed
|
||||
onto a stack for every function call, as well as popped when every function
|
||||
|
@ -132,6 +141,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -146,8 +158,47 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **read**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -211,6 +262,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -338,26 +405,42 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
|
||||
## Numbers
|
||||
|
@ -578,14 +661,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -612,23 +696,48 @@ is like the **quit** statement in that it is a compile-time command.
|
|||
|
||||
An expression by itself is evaluated and printed, followed by a newline.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -636,6 +745,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -942,6 +1064,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -958,8 +1135,9 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**) operator and the corresponding assignment operator.
|
||||
|
@ -983,11 +1161,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1016,37 +1195,78 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
TTY mode is required for history to be enabled (see the **COMMAND LINE HISTORY**
|
||||
section). It is also required to enable special handling for **SIGINT** signals.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Command-Line History
|
||||
|
||||
Command-line history is only enabled if TTY mode is, i.e., that **stdin**,
|
||||
**stdout**, and **stderr** are connected to a TTY and the **BC_TTY_MODE**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section) and its default
|
||||
do not disable TTY mode. See the **COMMAND LINE HISTORY** section for more
|
||||
information.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
@ -1058,14 +1278,22 @@ continue.
|
|||
|
||||
**SIGTERM** and **SIGQUIT** cause bc(1) to clean up and exit, and it uses the
|
||||
default handler for all other signals. The one exception is **SIGHUP**; in that
|
||||
case, when bc(1) is in TTY mode, a **SIGHUP** will cause bc(1) to clean up and
|
||||
exit.
|
||||
case, and only when bc(1) is in TTY mode (see the **TTY MODE** section), a
|
||||
**SIGHUP** will cause bc(1) to clean up and exit.
|
||||
|
||||
# COMMAND LINE HISTORY
|
||||
|
||||
bc(1) supports interactive command-line editing. If bc(1) is in TTY mode (see
|
||||
the **TTY MODE** section), history is enabled. Previous lines can be recalled
|
||||
and edited with the arrow keys.
|
||||
bc(1) supports interactive command-line editing.
|
||||
|
||||
If bc(1) can be in TTY mode (see the **TTY MODE** section), history can be
|
||||
enabled. This means that command-line history can only be enabled when
|
||||
**stdin**, **stdout**, and **stderr** are all connected to a TTY.
|
||||
|
||||
Like TTY mode itself, it can be turned on or off with the environment variable
|
||||
**BC_TTY_MODE** (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If history is enabled, previous lines can be recalled and edited with the arrow
|
||||
keys.
|
||||
|
||||
**Note**: tabs are converted to 8 spaces.
|
||||
|
||||
|
|
1393
manuals/bc/ENP.1
1393
manuals/bc/ENP.1
File diff suppressed because it is too large
Load diff
1085
manuals/bc/ENP.1.md
1085
manuals/bc/ENP.1.md
File diff suppressed because it is too large
Load diff
1400
manuals/bc/EP.1
1400
manuals/bc/EP.1
File diff suppressed because it is too large
Load diff
1093
manuals/bc/EP.1.md
1093
manuals/bc/EP.1.md
File diff suppressed because it is too large
Load diff
2540
manuals/bc/H.1
2540
manuals/bc/H.1
File diff suppressed because it is too large
Load diff
|
@ -46,6 +46,19 @@ Such differences will be noted in this document.
|
|||
After parsing and handling options, this bc(1) reads any files given on the
|
||||
command line and executes them before reading from **stdin**.
|
||||
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and
|
||||
especially) the GNU bc(1). It also has many extensions and extra features beyond
|
||||
other implementations.
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
The following are the options that bc(1) accepts.
|
||||
|
@ -144,6 +157,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -158,8 +174,51 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **irand**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxrand**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **rand**
|
||||
* **read**
|
||||
* **seed**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -223,6 +282,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -376,31 +451,47 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
14. **rand()**: A pseudo-random integer between **0** (inclusive) and
|
||||
17. **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**.
|
||||
15. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
|
||||
18. **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
|
||||
|
@ -411,7 +502,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**.
|
||||
16. **maxrand()**: The max integer returned by **rand()**. This is a
|
||||
19. **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
|
||||
|
@ -727,14 +818,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -772,23 +864,48 @@ either the **-s** or **-w** command-line options (or equivalents).
|
|||
Printing numbers in scientific notation and/or engineering notation is a
|
||||
**non-portable extension**.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -796,6 +913,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -1017,6 +1147,16 @@ The extended library is a **non-portable extension**.
|
|||
reset (see the **RESET** section). It also raises an error and causes bc(1)
|
||||
to reset if **r** is even and **x** is negative.
|
||||
|
||||
**gcd(a, b)**
|
||||
|
||||
: Returns the greatest common divisor (factor) of the truncated absolute value
|
||||
of **a** and the truncated absolute value of **b**.
|
||||
|
||||
**lcm(a, b)**
|
||||
|
||||
: Returns the least common multiple of the truncated absolute value of **a**
|
||||
and the truncated absolute value of **b**.
|
||||
|
||||
**pi(p)**
|
||||
|
||||
: Returns **pi** to **p** decimal places.
|
||||
|
@ -1146,6 +1286,317 @@ The extended library is a **non-portable extension**.
|
|||
|
||||
: Returns a random boolean value (either **0** or **1**).
|
||||
|
||||
**band(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **and** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **or** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bxor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **xor** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshl(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of **a** bit-shifted left by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshr(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the truncated result of **a** bit-shifted right by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnotn(x, n)**
|
||||
|
||||
: Takes the truncated absolute value of **x** and does a bitwise not as though
|
||||
it has the same number of bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot8(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**8** binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot16(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**16** binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot32(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**32** binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot64(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**64** binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brevn(x, n)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the same number of 8-bit bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev8(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 8 binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev16(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 16 binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev32(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 32 binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev64(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 64 binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**broln(x, p, n)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol8(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol16(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol32(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol64(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brorn(x, p, n)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror8(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror16(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror32(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror64(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmodn(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of the multiplication of the truncated absolute value of **n** and
|
||||
**8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod8(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod16(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod32(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod64(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bunrev(t)**
|
||||
|
||||
: Assumes **t** is a bitwise-reversed number with an extra set bit one place
|
||||
more significant than the real most significant bit (which was the least
|
||||
significant bit in the original number). This number is reversed and
|
||||
returned without the extra set bit.
|
||||
|
||||
This function is used to implement other bitwise functions; it is not meant
|
||||
to be used by users, but it can be.
|
||||
|
||||
**ubytes(x)**
|
||||
|
||||
: Returns the numbers of unsigned integer bytes required to hold the truncated
|
||||
|
@ -1156,6 +1607,20 @@ The extended library is a **non-portable extension**.
|
|||
: Returns the numbers of signed, two's-complement integer bytes required to
|
||||
hold the truncated value of **x**.
|
||||
|
||||
**s2u(x)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer and returns the
|
||||
non-negative integer that would have the same representation in binary.
|
||||
|
||||
**s2un(x,n)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer with **n** bytes and
|
||||
returns the non-negative integer that would have the same representation in
|
||||
binary. If **x** cannot fit into **n** 2's-complement signed bytes, it is
|
||||
truncated to fit.
|
||||
|
||||
**hex(x)**
|
||||
|
||||
: Outputs the hexadecimal (base **16**) representation of **x**.
|
||||
|
@ -1547,6 +2012,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -1564,8 +2084,9 @@ bc(1) returns the following exit statuses:
|
|||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, using a negative number as a bound for the pseudo-random number
|
||||
generator, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**), places (**\@**), left shift (**\<\<**), and right shift (**\>\>**)
|
||||
|
@ -1590,11 +2111,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1623,34 +2145,70 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
|
2540
manuals/bc/HN.1
2540
manuals/bc/HN.1
File diff suppressed because it is too large
Load diff
|
@ -46,6 +46,19 @@ Such differences will be noted in this document.
|
|||
After parsing and handling options, this bc(1) reads any files given on the
|
||||
command line and executes them before reading from **stdin**.
|
||||
|
||||
This bc(1) is a drop-in replacement for *any* bc(1), including (and
|
||||
especially) the GNU bc(1). It also has many extensions and extra features beyond
|
||||
other implementations.
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
The following are the options that bc(1) accepts.
|
||||
|
@ -144,6 +157,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -158,8 +174,51 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **irand**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxrand**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **rand**
|
||||
* **read**
|
||||
* **seed**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -223,6 +282,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -376,31 +451,47 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
14. **rand()**: A pseudo-random integer between **0** (inclusive) and
|
||||
17. **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**.
|
||||
15. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
|
||||
18. **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
|
||||
|
@ -411,7 +502,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**.
|
||||
16. **maxrand()**: The max integer returned by **rand()**. This is a
|
||||
19. **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
|
||||
|
@ -727,14 +818,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -772,23 +864,48 @@ either the **-s** or **-w** command-line options (or equivalents).
|
|||
Printing numbers in scientific notation and/or engineering notation is a
|
||||
**non-portable extension**.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -796,6 +913,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -1017,6 +1147,16 @@ The extended library is a **non-portable extension**.
|
|||
reset (see the **RESET** section). It also raises an error and causes bc(1)
|
||||
to reset if **r** is even and **x** is negative.
|
||||
|
||||
**gcd(a, b)**
|
||||
|
||||
: Returns the greatest common divisor (factor) of the truncated absolute value
|
||||
of **a** and the truncated absolute value of **b**.
|
||||
|
||||
**lcm(a, b)**
|
||||
|
||||
: Returns the least common multiple of the truncated absolute value of **a**
|
||||
and the truncated absolute value of **b**.
|
||||
|
||||
**pi(p)**
|
||||
|
||||
: Returns **pi** to **p** decimal places.
|
||||
|
@ -1146,6 +1286,317 @@ The extended library is a **non-portable extension**.
|
|||
|
||||
: Returns a random boolean value (either **0** or **1**).
|
||||
|
||||
**band(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **and** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **or** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bxor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **xor** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshl(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of **a** bit-shifted left by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshr(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the truncated result of **a** bit-shifted right by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnotn(x, n)**
|
||||
|
||||
: Takes the truncated absolute value of **x** and does a bitwise not as though
|
||||
it has the same number of bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot8(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**8** binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot16(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**16** binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot32(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**32** binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot64(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**64** binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brevn(x, n)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the same number of 8-bit bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev8(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 8 binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev16(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 16 binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev32(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 32 binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev64(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 64 binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**broln(x, p, n)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol8(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol16(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol32(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol64(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brorn(x, p, n)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror8(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror16(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror32(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror64(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmodn(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of the multiplication of the truncated absolute value of **n** and
|
||||
**8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod8(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod16(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod32(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod64(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bunrev(t)**
|
||||
|
||||
: Assumes **t** is a bitwise-reversed number with an extra set bit one place
|
||||
more significant than the real most significant bit (which was the least
|
||||
significant bit in the original number). This number is reversed and
|
||||
returned without the extra set bit.
|
||||
|
||||
This function is used to implement other bitwise functions; it is not meant
|
||||
to be used by users, but it can be.
|
||||
|
||||
**ubytes(x)**
|
||||
|
||||
: Returns the numbers of unsigned integer bytes required to hold the truncated
|
||||
|
@ -1156,6 +1607,20 @@ The extended library is a **non-portable extension**.
|
|||
: Returns the numbers of signed, two's-complement integer bytes required to
|
||||
hold the truncated value of **x**.
|
||||
|
||||
**s2u(x)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer and returns the
|
||||
non-negative integer that would have the same representation in binary.
|
||||
|
||||
**s2un(x,n)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer with **n** bytes and
|
||||
returns the non-negative integer that would have the same representation in
|
||||
binary. If **x** cannot fit into **n** 2's-complement signed bytes, it is
|
||||
truncated to fit.
|
||||
|
||||
**hex(x)**
|
||||
|
||||
: Outputs the hexadecimal (base **16**) representation of **x**.
|
||||
|
@ -1547,6 +2012,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -1564,8 +2084,9 @@ bc(1) returns the following exit statuses:
|
|||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, using a negative number as a bound for the pseudo-random number
|
||||
generator, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**), places (**\@**), left shift (**\<\<**), and right shift (**\>\>**)
|
||||
|
@ -1590,11 +2111,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1623,34 +2145,70 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
|
2223
manuals/bc/HNP.1
2223
manuals/bc/HNP.1
File diff suppressed because it is too large
Load diff
1679
manuals/bc/HNP.1.md
1679
manuals/bc/HNP.1.md
File diff suppressed because it is too large
Load diff
2230
manuals/bc/HP.1
2230
manuals/bc/HP.1
File diff suppressed because it is too large
Load diff
1687
manuals/bc/HP.1.md
1687
manuals/bc/HP.1.md
File diff suppressed because it is too large
Load diff
2567
manuals/bc/N.1
2567
manuals/bc/N.1
File diff suppressed because it is too large
Load diff
|
@ -50,6 +50,15 @@ This bc(1) is a drop-in replacement for *any* bc(1), including (and
|
|||
especially) the GNU bc(1). It also has many extensions and extra features beyond
|
||||
other implementations.
|
||||
|
||||
**Note**: If running this bc(1) on *any* script meant for another bc(1) gives a
|
||||
parse error, it is probably because a word this bc(1) reserves as a keyword is
|
||||
used as the name of a function, variable, or array. To fix that, use the
|
||||
command-line option **-r** *keyword*, where *keyword* is the keyword that is
|
||||
used as a name in the script. For more information, see the **OPTIONS** section.
|
||||
|
||||
If parsing scripts meant for other bc(1) implementations still does not work,
|
||||
that is a bug and should be reported. See the **BUGS** section.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
The following are the options that bc(1) accepts.
|
||||
|
@ -148,6 +157,9 @@ The following are the options that bc(1) accepts.
|
|||
would want to put this option in **BC_ENV_ARGS** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
These options override the **BC_PROMPT** and **BC_TTY_MODE** environment
|
||||
variables (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-R**, **-\-no-read-prompt**
|
||||
|
@ -162,8 +174,51 @@ The following are the options that bc(1) accepts.
|
|||
This option does not disable the regular prompt because the read prompt is
|
||||
only used when the **read()** built-in function is called.
|
||||
|
||||
These options *do* override the **BC_PROMPT** and **BC_TTY_MODE**
|
||||
environment variables (see the **ENVIRONMENT VARIABLES** section), but only
|
||||
for the read prompt.
|
||||
|
||||
This is a **non-portable extension**.
|
||||
|
||||
**-r** *keyword*, **-\-redefine**=*keyword*
|
||||
|
||||
: Redefines *keyword* in order to allow it to be used as a function, variable,
|
||||
or array name. This is useful when this bc(1) gives parse errors when
|
||||
parsing scripts meant for other bc(1) implementations.
|
||||
|
||||
The keywords this bc(1) allows to be redefined are:
|
||||
|
||||
* **abs**
|
||||
* **asciify**
|
||||
* **continue**
|
||||
* **divmod**
|
||||
* **else**
|
||||
* **halt**
|
||||
* **irand**
|
||||
* **last**
|
||||
* **limits**
|
||||
* **maxibase**
|
||||
* **maxobase**
|
||||
* **maxrand**
|
||||
* **maxscale**
|
||||
* **modexp**
|
||||
* **print**
|
||||
* **rand**
|
||||
* **read**
|
||||
* **seed**
|
||||
* **stream**
|
||||
|
||||
If any of those keywords are used as a function, variable, or array name in
|
||||
a script, use this option with the keyword as the argument. If multiple are
|
||||
used, use this option for all of them; it can be used multiple times.
|
||||
|
||||
Keywords are *not* redefined when parsing the builtin math library (see the
|
||||
**LIBRARY** section).
|
||||
|
||||
It is a fatal error to redefine keywords mandated by the POSIX standard. It
|
||||
is a fatal error to attempt to redefine words that this bc(1) does not
|
||||
reserve as keywords.
|
||||
|
||||
**-q**, **-\-quiet**
|
||||
|
||||
: This option is for compatibility with the [GNU bc(1)][2]; it is a no-op.
|
||||
|
@ -227,6 +282,22 @@ The following are the options that bc(1) accepts.
|
|||
|
||||
All long options are **non-portable extensions**.
|
||||
|
||||
# STDIN
|
||||
|
||||
If no files or expressions are given by the **-f**, **-\-file**, **-e**, or
|
||||
**-\-expression** options, then bc(1) read from **stdin**.
|
||||
|
||||
However, there are a few caveats to this.
|
||||
|
||||
First, **stdin** is evaluated a line at a time. The only exception to this is if
|
||||
the parse cannot complete. That means that starting a string without ending it
|
||||
or starting a function, **if** statement, or loop without ending it will also
|
||||
cause bc(1) to not execute.
|
||||
|
||||
Second, after an **if** statement, bc(1) doesn't know if an **else** statement
|
||||
will follow, so it will not execute until it knows there will not be an **else**
|
||||
statement.
|
||||
|
||||
# STDOUT
|
||||
|
||||
Any non-error output is written to **stdout**. In addition, if history (see the
|
||||
|
@ -380,31 +451,47 @@ The following are valid operands in bc(1):
|
|||
2. Array indices (**I[E]**).
|
||||
3. **(E)**: The value of **E** (used to change precedence).
|
||||
4. **sqrt(E)**: The square root of **E**. **E** must be non-negative.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**.
|
||||
5. **length(E)**: The number of significant decimal digits in **E**. Returns
|
||||
**1** for **0** with no decimal places. If given a string, the length of the
|
||||
string is returned. Passing a string to **length(E)** is a **non-portable
|
||||
extension**.
|
||||
6. **length(I[])**: The number of elements in the array **I**. This is a
|
||||
**non-portable extension**.
|
||||
7. **scale(E)**: The *scale* of **E**.
|
||||
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
|
||||
extension**.
|
||||
9. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
9. **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
|
||||
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
|
||||
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
|
||||
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.
|
||||
10. **read()**: Reads a line from **stdin** and uses that as an expression. The
|
||||
13. **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**.
|
||||
11. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
|
||||
extension**.
|
||||
12. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
|
||||
extension**.
|
||||
13. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
|
||||
extension**.
|
||||
14. **rand()**: A pseudo-random integer between **0** (inclusive) and
|
||||
17. **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**.
|
||||
15. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
|
||||
18. **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
|
||||
|
@ -415,7 +502,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**.
|
||||
16. **maxrand()**: The max integer returned by **rand()**. This is a
|
||||
19. **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
|
||||
|
@ -731,14 +818,15 @@ The following items are statements:
|
|||
12. **limits**
|
||||
13. A string of characters, enclosed in double quotes
|
||||
14. **print** **E** **,** ... **,** **E**
|
||||
15. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
15. **stream** **E** **,** ... **,** **E**
|
||||
16. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
|
||||
a **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.
|
||||
|
||||
Numbers 4, 9, 11, 12, 14, and 15 are **non-portable extensions**.
|
||||
Numbers 4, 9, 11, 12, 14, 15, and 16 are **non-portable extensions**.
|
||||
|
||||
Also, as a **non-portable extension**, any or all of the expressions in the
|
||||
header of a for loop may be omitted. If the condition (second expression) is
|
||||
|
@ -776,23 +864,48 @@ either the **-s** or **-w** command-line options (or equivalents).
|
|||
Printing numbers in scientific notation and/or engineering notation is a
|
||||
**non-portable extension**.
|
||||
|
||||
## Strings
|
||||
|
||||
If strings appear as a statement by themselves, they are printed without a
|
||||
trailing newline.
|
||||
|
||||
In addition to appearing as a lone statement by themselves, strings can be
|
||||
assigned to variables and array elements. They can also be passed to functions
|
||||
in variable parameters.
|
||||
|
||||
If any statement that expects a string is given a variable that had a string
|
||||
assigned to it, the statement acts as though it had received a string.
|
||||
|
||||
If any math operation is attempted on a string or a variable or array element
|
||||
that has been assigned a string, an error is raised, and bc(1) resets (see the
|
||||
**RESET** section).
|
||||
|
||||
Assigning strings to variables and array elements and passing them to functions
|
||||
are **non-portable extensions**.
|
||||
|
||||
## Print Statement
|
||||
|
||||
The "expressions" in a **print** statement may also be strings. If they are, there
|
||||
are backslash escape sequences that are interpreted specially. What those
|
||||
sequences are, and what they cause to be printed, are shown below:
|
||||
|
||||
-------- -------
|
||||
**\\a** **\\a**
|
||||
**\\b** **\\b**
|
||||
**\\\\** **\\**
|
||||
**\\e** **\\**
|
||||
**\\f** **\\f**
|
||||
**\\n** **\\n**
|
||||
**\\q** **"**
|
||||
**\\r** **\\r**
|
||||
**\\t** **\\t**
|
||||
-------- -------
|
||||
**\\a**: **\\a**
|
||||
|
||||
**\\b**: **\\b**
|
||||
|
||||
**\\\\**: **\\**
|
||||
|
||||
**\\e**: **\\**
|
||||
|
||||
**\\f**: **\\f**
|
||||
|
||||
**\\n**: **\\n**
|
||||
|
||||
**\\q**: **"**
|
||||
|
||||
**\\r**: **\\r**
|
||||
|
||||
**\\t**: **\\t**
|
||||
|
||||
Any other character following a backslash causes the backslash and character to
|
||||
be printed as-is.
|
||||
|
@ -800,6 +913,19 @@ be printed as-is.
|
|||
Any non-string expression in a print statement shall be assigned to **last**,
|
||||
like any other expression that is printed.
|
||||
|
||||
## Stream Statement
|
||||
|
||||
The "expressions in a **stream** statement may also be strings.
|
||||
|
||||
If a **stream** statement is given a string, it prints the string as though the
|
||||
string had appeared as its own statement. In other words, the **stream**
|
||||
statement prints strings normally, without a newline.
|
||||
|
||||
If a **stream** statement is given a number, a copy of it is truncated and its
|
||||
absolute value is calculated. The result is then printed as though **obase** is
|
||||
**256** and each digit is interpreted as an 8-bit ASCII character, making it a
|
||||
byte stream.
|
||||
|
||||
## Order of Evaluation
|
||||
|
||||
All expressions in a statment are evaluated left to right, except as necessary
|
||||
|
@ -1021,6 +1147,16 @@ The extended library is a **non-portable extension**.
|
|||
reset (see the **RESET** section). It also raises an error and causes bc(1)
|
||||
to reset if **r** is even and **x** is negative.
|
||||
|
||||
**gcd(a, b)**
|
||||
|
||||
: Returns the greatest common divisor (factor) of the truncated absolute value
|
||||
of **a** and the truncated absolute value of **b**.
|
||||
|
||||
**lcm(a, b)**
|
||||
|
||||
: Returns the least common multiple of the truncated absolute value of **a**
|
||||
and the truncated absolute value of **b**.
|
||||
|
||||
**pi(p)**
|
||||
|
||||
: Returns **pi** to **p** decimal places.
|
||||
|
@ -1150,6 +1286,317 @@ The extended library is a **non-portable extension**.
|
|||
|
||||
: Returns a random boolean value (either **0** or **1**).
|
||||
|
||||
**band(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **and** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **or** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bxor(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of the bitwise **xor** operation between them.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshl(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the result of **a** bit-shifted left by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bshr(a, b)**
|
||||
|
||||
: Takes the truncated absolute value of both **a** and **b** and calculates
|
||||
and returns the truncated result of **a** bit-shifted right by **b** places.
|
||||
|
||||
If you want to use signed two's complement arguments, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnotn(x, n)**
|
||||
|
||||
: Takes the truncated absolute value of **x** and does a bitwise not as though
|
||||
it has the same number of bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot8(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**8** binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot16(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**16** binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot32(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**32** binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot64(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
**64** binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bnot(x)**
|
||||
|
||||
: Does a bitwise not of the truncated absolute value of **x** as though it has
|
||||
the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brevn(x, n)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the same number of 8-bit bytes as the truncated absolute value of **n**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev8(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 8 binary digits (1 unsigned byte).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev16(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 16 binary digits (2 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev32(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 32 binary digits (4 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev64(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has 64 binary digits (8 unsigned bytes).
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brev(x)**
|
||||
|
||||
: Runs a bit reversal on the truncated absolute value of **x** as though it
|
||||
has the minimum number of power of two unsigned bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**broln(x, p, n)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol8(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol16(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol32(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol64(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brol(x, p)**
|
||||
|
||||
: Does a left bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**brorn(x, p, n)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the same number of unsigned 8-bit bytes as the truncated
|
||||
absolute value of **n**, by the number of places equal to the truncated
|
||||
absolute value of **p** modded by the **2** to the power of the number of
|
||||
binary digits in **n** 8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror8(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **8** binary digits (**1** unsigned byte), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror16(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **16** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror32(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **32** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror64(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has **64** binary digits (**2** unsigned bytes), by the number of
|
||||
places equal to the truncated absolute value of **p** modded by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bror(x, p)**
|
||||
|
||||
: Does a right bitwise rotatation of the truncated absolute value of **x**, as
|
||||
though it has the minimum number of power of two unsigned 8-bit bytes, by
|
||||
the number of places equal to the truncated absolute value of **p** modded
|
||||
by 2 to the power of the number of binary digits in the minimum number of
|
||||
8-bit bytes.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmodn(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of the multiplication of the truncated absolute value of **n** and
|
||||
**8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod8(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **8**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod16(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **16**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod32(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **32**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bmod64(x, n)**
|
||||
|
||||
: Returns the modulus of the truncated absolute value of **x** by **2** to the
|
||||
power of **64**.
|
||||
|
||||
If you want to a use signed two's complement argument, use **s2u(x)** to
|
||||
convert.
|
||||
|
||||
**bunrev(t)**
|
||||
|
||||
: Assumes **t** is a bitwise-reversed number with an extra set bit one place
|
||||
more significant than the real most significant bit (which was the least
|
||||
significant bit in the original number). This number is reversed and
|
||||
returned without the extra set bit.
|
||||
|
||||
This function is used to implement other bitwise functions; it is not meant
|
||||
to be used by users, but it can be.
|
||||
|
||||
**ubytes(x)**
|
||||
|
||||
: Returns the numbers of unsigned integer bytes required to hold the truncated
|
||||
|
@ -1160,6 +1607,20 @@ The extended library is a **non-portable extension**.
|
|||
: Returns the numbers of signed, two's-complement integer bytes required to
|
||||
hold the truncated value of **x**.
|
||||
|
||||
**s2u(x)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer and returns the
|
||||
non-negative integer that would have the same representation in binary.
|
||||
|
||||
**s2un(x,n)**
|
||||
|
||||
: Returns **x** if it is non-negative. If it *is* negative, then it calculates
|
||||
what **x** would be as a 2's-complement signed integer with **n** bytes and
|
||||
returns the non-negative integer that would have the same representation in
|
||||
binary. If **x** cannot fit into **n** 2's-complement signed bytes, it is
|
||||
truncated to fit.
|
||||
|
||||
**hex(x)**
|
||||
|
||||
: Outputs the hexadecimal (base **16**) representation of **x**.
|
||||
|
@ -1551,6 +2012,61 @@ bc(1) recognizes the following environment variables:
|
|||
lines to that length, including the backslash (**\\**). The default line
|
||||
length is **70**.
|
||||
|
||||
**BC_BANNER**
|
||||
|
||||
: If this environment variable exists and contains an integer, then a non-zero
|
||||
value activates the copyright banner when bc(1) is in interactive mode,
|
||||
while zero deactivates it.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) does not print
|
||||
the banner when not in interactive mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_SIGINT_RESET**
|
||||
|
||||
: If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section),
|
||||
then this environment variable has no effect because bc(1) exits on
|
||||
**SIGINT** when not in interactive mode.
|
||||
|
||||
However, when bc(1) is in interactive mode, then if this environment
|
||||
variable exists and contains an integer, a non-zero value makes bc(1) reset
|
||||
on **SIGINT**, rather than exit, and zero makes bc(1) exit. If this
|
||||
environment variable exists and is *not* an integer, then bc(1) will exit on
|
||||
**SIGINT**.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_TTY_MODE**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, then a non-zero value makes bc(1) use TTY
|
||||
mode, and zero makes bc(1) not use TTY mode.
|
||||
|
||||
This environment variable overrides the default, which can be queried with
|
||||
the **-h** or **-\-help** options.
|
||||
|
||||
**BC_PROMPT**
|
||||
|
||||
: If TTY mode is *not* available (see the **TTY MODE** section), then this
|
||||
environment variable has no effect.
|
||||
|
||||
However, when TTY mode is available, then if this environment variable
|
||||
exists and contains an integer, a non-zero value makes bc(1) use a prompt,
|
||||
and zero or a non-integer makes bc(1) not use a prompt. If this environment
|
||||
variable does not exist and **BC_TTY_MODE** does, then the value of the
|
||||
**BC_TTY_MODE** environment variable is used.
|
||||
|
||||
This environment variable and the **BC_TTY_MODE** environment variable
|
||||
override the default, which can be queried with the **-h** or **-\-help**
|
||||
options.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
bc(1) returns the following exit statuses:
|
||||
|
@ -1568,8 +2084,9 @@ bc(1) returns the following exit statuses:
|
|||
Math errors include divide by **0**, taking the square root of a negative
|
||||
number, using a negative number as a bound for the pseudo-random number
|
||||
generator, attempting to convert a negative number to a hardware integer,
|
||||
overflow when converting a number to a hardware integer, and attempting to
|
||||
use a non-integer where an integer is required.
|
||||
overflow when converting a number to a hardware integer, overflow when
|
||||
calculating the size of a number, and attempting to use a non-integer where
|
||||
an integer is required.
|
||||
|
||||
Converting to a hardware integer happens for the second operand of the power
|
||||
(**\^**), places (**\@**), left shift (**\<\<**), and right shift (**\>\>**)
|
||||
|
@ -1594,11 +2111,12 @@ bc(1) returns the following exit statuses:
|
|||
|
||||
: A runtime error occurred.
|
||||
|
||||
Runtime errors include assigning an invalid number to **ibase**, **obase**,
|
||||
or **scale**; give a bad expression to a **read()** call, calling **read()**
|
||||
inside of a **read()** call, type errors, passing the wrong number of
|
||||
arguments to functions, attempting to call an undefined function, and
|
||||
attempting to use a **void** function call as a value in an expression.
|
||||
Runtime errors include assigning an invalid number to any global (**ibase**,
|
||||
**obase**, or **scale**), giving a bad expression to a **read()** call,
|
||||
calling **read()** inside of a **read()** call, type errors, passing the
|
||||
wrong number of arguments to functions, attempting to call an undefined
|
||||
function, and attempting to use a **void** function call as a value in an
|
||||
expression.
|
||||
|
||||
**4**
|
||||
|
||||
|
@ -1627,37 +2145,78 @@ checking, and its normal behavior can be forced by using the **-i** flag or
|
|||
Per the [standard][1], bc(1) has an interactive mode and a non-interactive mode.
|
||||
Interactive mode is turned on automatically when both **stdin** and **stdout**
|
||||
are hooked to a terminal, but the **-i** flag and **-\-interactive** option can
|
||||
turn it on in other cases.
|
||||
turn it on in other situations.
|
||||
|
||||
In interactive mode, bc(1) attempts to recover from errors (see the **RESET**
|
||||
section), and in normal execution, flushes **stdout** as soon as execution is
|
||||
done for the current input.
|
||||
done for the current input. bc(1) may also reset on **SIGINT** instead of exit,
|
||||
depending on the contents of, or default for, the **BC_SIGINT_RESET**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
# TTY MODE
|
||||
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, bc(1) turns
|
||||
on "TTY mode."
|
||||
If **stdin**, **stdout**, and **stderr** are all connected to a TTY, then "TTY
|
||||
mode" is considered to be available, and thus, bc(1) can turn on TTY mode,
|
||||
subject to some settings.
|
||||
|
||||
TTY mode is required for history to be enabled (see the **COMMAND LINE HISTORY**
|
||||
section). It is also required to enable special handling for **SIGINT** signals.
|
||||
If there is the environment variable **BC_TTY_MODE** in the environment (see the
|
||||
**ENVIRONMENT VARIABLES** section), then if that environment variable contains a
|
||||
non-zero integer, bc(1) will turn on TTY mode when **stdin**, **stdout**, and
|
||||
**stderr** are all connected to a TTY. If the **BC_TTY_MODE** environment
|
||||
variable exists but is *not* a non-zero integer, then bc(1) will not turn TTY
|
||||
mode on.
|
||||
|
||||
The prompt is enabled in TTY mode.
|
||||
If the environment variable **BC_TTY_MODE** does *not* exist, the default
|
||||
setting is used. The default setting can be queried with the **-h** or
|
||||
**-\-help** options.
|
||||
|
||||
TTY mode is different from interactive mode because interactive mode is required
|
||||
in the [bc(1) specification][1], and interactive mode requires only **stdin**
|
||||
and **stdout** to be connected to a terminal.
|
||||
|
||||
## Command-Line History
|
||||
|
||||
Command-line history is only enabled if TTY mode is, i.e., that **stdin**,
|
||||
**stdout**, and **stderr** are connected to a TTY and the **BC_TTY_MODE**
|
||||
environment variable (see the **ENVIRONMENT VARIABLES** section) and its default
|
||||
do not disable TTY mode. See the **COMMAND LINE HISTORY** section for more
|
||||
information.
|
||||
|
||||
## Prompt
|
||||
|
||||
If TTY mode is available, then a prompt can be enabled. Like TTY mode itself, it
|
||||
can be turned on or off with an environment variable: **BC_PROMPT** (see the
|
||||
**ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If the environment variable **BC_PROMPT** exists and is a non-zero integer, then
|
||||
the prompt is turned on when **stdin**, **stdout**, and **stderr** are connected
|
||||
to a TTY and the **-P** and **-\-no-prompt** options were not used. The read
|
||||
prompt will be turned on under the same conditions, except that the **-R** and
|
||||
**-\-no-read-prompt** options must also not be used.
|
||||
|
||||
However, if **BC_PROMPT** does not exist, the prompt can be enabled or disabled
|
||||
with the **BC_TTY_MODE** environment variable, the **-P** and **-\-no-prompt**
|
||||
options, and the **-R** and **-\-no-read-prompt** options. See the **ENVIRONMENT
|
||||
VARIABLES** and **OPTIONS** sections for more details.
|
||||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
Sending a **SIGINT** will cause bc(1) to stop execution of the current input. If
|
||||
bc(1) is in TTY mode (see the **TTY MODE** section), it will reset (see the
|
||||
**RESET** section). Otherwise, it will clean up and exit.
|
||||
Sending a **SIGINT** will cause bc(1) to do one of two things.
|
||||
|
||||
If bc(1) is not in interactive mode (see the **INTERACTIVE MODE** section), or
|
||||
the **BC_SIGINT_RESET** environment variable (see the **ENVIRONMENT VARIABLES**
|
||||
section), or its default, is either not an integer or it is zero, bc(1) will
|
||||
exit.
|
||||
|
||||
However, if bc(1) is in interactive mode, and the **BC_SIGINT_RESET** or its
|
||||
default is an integer and non-zero, then bc(1) will stop executing the current
|
||||
input and reset (see the **RESET** section) upon receiving a **SIGINT**.
|
||||
|
||||
Note that "current input" can mean one of two things. If bc(1) is processing
|
||||
input from **stdin** in TTY mode, it will ask for more input. If bc(1) is
|
||||
processing input from a file in TTY mode, it will stop processing the file and
|
||||
start processing the next file, if one exists, or ask for input from **stdin**
|
||||
if no other file exists.
|
||||
input from **stdin** in interactive mode, it will ask for more input. If bc(1)
|
||||
is processing input from a file in interactive mode, it will stop processing the
|
||||
file and start processing the next file, if one exists, or ask for input from
|
||||
**stdin** if no other file exists.
|
||||
|
||||
This means that if a **SIGINT** is sent to bc(1) as it is executing a file, it
|
||||
can seem as though bc(1) did not respond to the signal since it will immediately
|
||||
|
@ -1669,14 +2228,22 @@ continue.
|
|||
|
||||
**SIGTERM** and **SIGQUIT** cause bc(1) to clean up and exit, and it uses the
|
||||
default handler for all other signals. The one exception is **SIGHUP**; in that
|
||||
case, when bc(1) is in TTY mode, a **SIGHUP** will cause bc(1) to clean up and
|
||||
exit.
|
||||
case, and only when bc(1) is in TTY mode (see the **TTY MODE** section), a
|
||||
**SIGHUP** will cause bc(1) to clean up and exit.
|
||||
|
||||
# COMMAND LINE HISTORY
|
||||
|
||||
bc(1) supports interactive command-line editing. If bc(1) is in TTY mode (see
|
||||
the **TTY MODE** section), history is enabled. Previous lines can be recalled
|
||||
and edited with the arrow keys.
|
||||
bc(1) supports interactive command-line editing.
|
||||
|
||||
If bc(1) can be in TTY mode (see the **TTY MODE** section), history can be
|
||||
enabled. This means that command-line history can only be enabled when
|
||||
**stdin**, **stdout**, and **stderr** are all connected to a TTY.
|
||||
|
||||
Like TTY mode itself, it can be turned on or off with the environment variable
|
||||
**BC_TTY_MODE** (see the **ENVIRONMENT VARIABLES** section).
|
||||
|
||||
If history is enabled, previous lines can be recalled and edited with the arrow
|
||||
keys.
|
||||
|
||||
**Note**: tabs are converted to 8 spaces.
|
||||
|
||||
|
|
2243
manuals/bc/NP.1
2243
manuals/bc/NP.1
File diff suppressed because it is too large
Load diff
1696
manuals/bc/NP.1.md
1696
manuals/bc/NP.1.md
File diff suppressed because it is too large
Load diff
2250
manuals/bc/P.1
2250
manuals/bc/P.1
File diff suppressed because it is too large
Load diff
1704
manuals/bc/P.1.md
1704
manuals/bc/P.1.md
File diff suppressed because it is too large
Load diff
1749
manuals/bcl.3
1749
manuals/bcl.3
File diff suppressed because it is too large
Load diff
253
manuals/bcl.3.md
253
manuals/bcl.3.md
|
@ -45,23 +45,23 @@ Link with *-lbcl*.
|
|||
This procedure will allow clients to use signals to interrupt computations
|
||||
running in bcl(3).
|
||||
|
||||
**void bcl_handleSignal(***void***);**
|
||||
**void bcl_handleSignal(**_void_**);**
|
||||
|
||||
**bool bcl_running(***void***);**
|
||||
**bool bcl_running(**_void_**);**
|
||||
|
||||
## Setup
|
||||
|
||||
These items allow clients to set up bcl(3).
|
||||
|
||||
**BclError bcl_init(***void***);**
|
||||
**BclError bcl_init(**_void_**);**
|
||||
|
||||
**void bcl_free(***void***);**
|
||||
**void bcl_free(**_void_**);**
|
||||
|
||||
**bool bcl_abortOnFatalError(***void***);**
|
||||
**bool bcl_abortOnFatalError(**_void_**);**
|
||||
|
||||
**void bcl_setAbortOnFatalError(bool** *abrt***);**
|
||||
**void bcl_setAbortOnFatalError(bool** _abrt_**);**
|
||||
|
||||
**void bcl_gc(***void***);**
|
||||
**void bcl_gc(**_void_**);**
|
||||
|
||||
## Contexts
|
||||
|
||||
|
@ -72,29 +72,29 @@ other. This allows more than one client to use bcl(3) in the same program.
|
|||
|
||||
**typedef struct BclCtxt\* BclContext;**
|
||||
|
||||
**BclContext bcl_ctxt_create(***void***);**
|
||||
**BclContext bcl_ctxt_create(**_void_**);**
|
||||
|
||||
**void bcl_ctxt_free(BclContext** *ctxt***);**
|
||||
**void bcl_ctxt_free(BclContext** _ctxt_**);**
|
||||
|
||||
**BclError bcl_pushContext(BclContext** *ctxt***);**
|
||||
**BclError bcl_pushContext(BclContext** _ctxt_**);**
|
||||
|
||||
**void bcl_popContext(***void***);**
|
||||
**void bcl_popContext(**_void_**);**
|
||||
|
||||
**BclContext bcl_context(***void***);**
|
||||
**BclContext bcl_context(**_void_**);**
|
||||
|
||||
**void bcl_ctxt_freeNums(BclContext** *ctxt***);**
|
||||
**void bcl_ctxt_freeNums(BclContext** _ctxt_**);**
|
||||
|
||||
**size_t bcl_ctxt_scale(BclContext** *ctxt***);**
|
||||
**size_t bcl_ctxt_scale(BclContext** _ctxt_**);**
|
||||
|
||||
**void bcl_ctxt_setScale(BclContext** *ctxt***, size_t** *scale***);**
|
||||
**void bcl_ctxt_setScale(BclContext** _ctxt_**, size_t** _scale_**);**
|
||||
|
||||
**size_t bcl_ctxt_ibase(BclContext** *ctxt***);**
|
||||
**size_t bcl_ctxt_ibase(BclContext** _ctxt_**);**
|
||||
|
||||
**void bcl_ctxt_setIbase(BclContext** *ctxt***, size_t** *ibase***);**
|
||||
**void bcl_ctxt_setIbase(BclContext** _ctxt_**, size_t** _ibase_**);**
|
||||
|
||||
**size_t bcl_ctxt_obase(BclContext** *ctxt***);**
|
||||
**size_t bcl_ctxt_obase(BclContext** _ctxt_**);**
|
||||
|
||||
**void bcl_ctxt_setObase(BclContext** *ctxt***, size_t** *obase***);**
|
||||
**void bcl_ctxt_setObase(BclContext** _ctxt_**, size_t** _obase_**);**
|
||||
|
||||
## Errors
|
||||
|
||||
|
@ -102,7 +102,7 @@ These items allow clients to handle errors.
|
|||
|
||||
**typedef enum BclError BclError;**
|
||||
|
||||
**BclError bcl_err(BclNumber** *n***);**
|
||||
**BclError bcl_err(BclNumber** _n_**);**
|
||||
|
||||
## Numbers
|
||||
|
||||
|
@ -111,71 +111,71 @@ numbers managed by bcl(3).
|
|||
|
||||
**typedef struct { size_t i; } BclNumber;**
|
||||
|
||||
**BclNumber bcl_num_create(***void***);**
|
||||
**BclNumber bcl_num_create(**_void_**);**
|
||||
|
||||
**void bcl_num_free(BclNumber** *n***);**
|
||||
**void bcl_num_free(BclNumber** _n_**);**
|
||||
|
||||
**bool bcl_num_neg(BclNumber** *n***);**
|
||||
**bool bcl_num_neg(BclNumber** _n_**);**
|
||||
|
||||
**void bcl_num_setNeg(BclNumber** *n***, bool** *neg***);**
|
||||
**void bcl_num_setNeg(BclNumber** _n_**, bool** _neg_**);**
|
||||
|
||||
**size_t bcl_num_scale(BclNumber** *n***);**
|
||||
**size_t bcl_num_scale(BclNumber** _n_**);**
|
||||
|
||||
**BclError bcl_num_setScale(BclNumber** *n***, size_t** *scale***);**
|
||||
**BclError bcl_num_setScale(BclNumber** _n_**, size_t** _scale_**);**
|
||||
|
||||
**size_t bcl_num_len(BclNumber** *n***);**
|
||||
**size_t bcl_num_len(BclNumber** _n_**);**
|
||||
|
||||
## Conversion
|
||||
|
||||
These items allow clients to convert numbers into and from strings and integers.
|
||||
|
||||
**BclNumber bcl_parse(const char \*restrict** *val***);**
|
||||
**BclNumber bcl_parse(const char \*restrict** _val_**);**
|
||||
|
||||
**char\* bcl_string(BclNumber** *n***);**
|
||||
**char\* bcl_string(BclNumber** _n_**);**
|
||||
|
||||
**BclError bcl_bigdig(BclNumber** *n***, BclBigDig \****result***);**
|
||||
**BclError bcl_bigdig(BclNumber** _n_**, BclBigDig \***_result_**);**
|
||||
|
||||
**BclNumber bcl_bigdig2num(BclBigDig** *val***);**
|
||||
**BclNumber bcl_bigdig2num(BclBigDig** _val_**);**
|
||||
|
||||
## Math
|
||||
|
||||
These items allow clients to run math on numbers.
|
||||
|
||||
**BclNumber bcl_add(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_add(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_sub(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_sub(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_mul(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_mul(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_div(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_div(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_mod(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_mod(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_pow(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_pow(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_lshift(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_lshift(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_rshift(BclNumber** *a***, BclNumber** *b***);**
|
||||
**BclNumber bcl_rshift(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclNumber bcl_sqrt(BclNumber** *a***);**
|
||||
**BclNumber bcl_sqrt(BclNumber** _a_**);**
|
||||
|
||||
**BclError bcl_divmod(BclNumber** *a***, BclNumber** *b***, BclNumber \****c***, BclNumber \****d***);**
|
||||
**BclError bcl_divmod(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**);**
|
||||
|
||||
**BclNumber bcl_modexp(BclNumber** *a***, BclNumber** *b***, BclNumber** *c***);**
|
||||
**BclNumber bcl_modexp(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**);**
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
These items are miscellaneous.
|
||||
|
||||
**void bcl_zero(BclNumber** *n***);**
|
||||
**void bcl_zero(BclNumber** _n_**);**
|
||||
|
||||
**void bcl_one(BclNumber** *n***);**
|
||||
**void bcl_one(BclNumber** _n_**);**
|
||||
|
||||
**ssize_t bcl_cmp(BclNumber** *a***, BclNumber** *b***);**
|
||||
**ssize_t bcl_cmp(BclNumber** _a_**, BclNumber** _b_**);**
|
||||
|
||||
**BclError bcl_copy(BclNumber** *d***, BclNumber** *s***);**
|
||||
**BclError bcl_copy(BclNumber** _d_**, BclNumber** _s_**);**
|
||||
|
||||
**BclNumber bcl_dup(BclNumber** *s***);**
|
||||
**BclNumber bcl_dup(BclNumber** _s_**);**
|
||||
|
||||
## Pseudo-Random Number Generator
|
||||
|
||||
|
@ -190,38 +190,41 @@ generator in bcl(3).
|
|||
|
||||
**typedef unsigned long BclRandInt;**
|
||||
|
||||
**BclNumber bcl_irand(BclNumber** *a***);**
|
||||
**BclNumber bcl_irand(BclNumber** _a_**);**
|
||||
|
||||
**BclNumber bcl_frand(size_t** *places***);**
|
||||
**BclNumber bcl_frand(size_t** _places_**);**
|
||||
|
||||
**BclNumber bcl_ifrand(BclNumber** *a***, size_t** *places***);**
|
||||
**BclNumber bcl_ifrand(BclNumber** _a_**, size_t** _places_**);**
|
||||
|
||||
**BclError bcl_rand_seedWithNum(BclNumber** *n***);**
|
||||
**BclError bcl_rand_seedWithNum(BclNumber** _n_**);**
|
||||
|
||||
**BclError bcl_rand_seed(unsigned char** *seed***[***BC_SEED_SIZE***]);**
|
||||
**BclError bcl_rand_seed(unsigned char** _seed_**[**_BCL_SEED_SIZE_**]);**
|
||||
|
||||
**void bcl_rand_reseed(***void***);**
|
||||
**void bcl_rand_reseed(**_void_**);**
|
||||
|
||||
**BclNumber bcl_rand_seed2num(***void***);**
|
||||
**BclNumber bcl_rand_seed2num(**_void_**);**
|
||||
|
||||
**BclRandInt bcl_rand_int(***void***);**
|
||||
**BclRandInt bcl_rand_int(**_void_**);**
|
||||
|
||||
**BclRandInt bcl_rand_bounded(BclRandInt** *bound***);**
|
||||
**BclRandInt bcl_rand_bounded(BclRandInt** _bound_**);**
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
bcl(3) is a library that implements arbitrary-precision decimal math, as
|
||||
[standardized by POSIX][1] in bc(1).
|
||||
|
||||
bcl(3) is async-signal-safe if **bcl_handleSignal(***void***)** is used
|
||||
bcl(3) is async-signal-safe if **bcl_handleSignal(**_void_**)** is used
|
||||
properly. (See the **SIGNAL HANDLING** section.)
|
||||
|
||||
bcl(3) assumes that it is allowed to use the **bcl_** and **bc_** prefixes for
|
||||
symbol names without collision.
|
||||
|
||||
All of the items in its interface are described below. See the documentation for
|
||||
each function for what each function can return.
|
||||
|
||||
## Signals
|
||||
|
||||
**void bcl_handleSignal(***void***)**
|
||||
**void bcl_handleSignal(**_void_**)**
|
||||
|
||||
: An async-signal-safe function that can be called from a signal handler. If
|
||||
called from a signal handler on the same thread as any executing bcl(3)
|
||||
|
@ -230,26 +233,26 @@ each function for what each function can return.
|
|||
*not* executing any bcl(3) functions while any bcl(3) functions are
|
||||
executing.
|
||||
|
||||
If execution *is* interrupted, **bcl_handleSignal(***void***)** does *not*
|
||||
If execution *is* interrupted, **bcl_handleSignal(**_void_**)** does *not*
|
||||
return to its caller.
|
||||
|
||||
See the **SIGNAL HANDLING** section.
|
||||
|
||||
**bool bcl_running(***void***)**
|
||||
**bool bcl_running(**_void_**)**
|
||||
|
||||
: An async-signal-safe function that can be called from a signal handler. It
|
||||
will return **true** if any bcl(3) procedures are running, which means it is
|
||||
safe to call **bcl_handleSignal(***void***)**. Otherwise, it returns
|
||||
safe to call **bcl_handleSignal(**_void_**)**. Otherwise, it returns
|
||||
**false**.
|
||||
|
||||
See the **SIGNAL HANDLING** section.
|
||||
|
||||
## Setup
|
||||
|
||||
**BclError bcl_init(***void***)**
|
||||
**BclError bcl_init(**_void_**)**
|
||||
|
||||
: Initializes this library. This function can be called multiple times, but
|
||||
each call must be matched by a call to **bcl_free(***void***)**. This is to
|
||||
each call must be matched by a call to **bcl_free(**_void_**)**. This is to
|
||||
make it possible for multiple libraries and applications to initialize
|
||||
bcl(3) without problem.
|
||||
|
||||
|
@ -261,7 +264,7 @@ each function for what each function can return.
|
|||
This function must be the first one clients call. Calling any other
|
||||
function without calling this one first is undefined behavior.
|
||||
|
||||
**void bcl_free(***void***)**
|
||||
**void bcl_free(**_void_**)**
|
||||
|
||||
: Decrements bcl(3)'s reference count and frees the data associated with it if
|
||||
the reference count is **0**.
|
||||
|
@ -269,7 +272,7 @@ each function for what each function can return.
|
|||
This function must be the last one clients call. Calling this function
|
||||
before calling any other function is undefined behavior.
|
||||
|
||||
**bool bcl_abortOnFatalError(***void***)**
|
||||
**bool bcl_abortOnFatalError(**_void_**)**
|
||||
|
||||
: Queries and returns the current state of calling **abort()** on fatal
|
||||
errors. If **true** is returned, bcl(3) will cause a **SIGABRT** if a fatal
|
||||
|
@ -277,7 +280,7 @@ each function for what each function can return.
|
|||
|
||||
If activated, clients do not need to check for fatal errors.
|
||||
|
||||
**void bcl_setAbortOnFatalError(bool** *abrt***)**
|
||||
**void bcl_setAbortOnFatalError(bool** _abrt_**)**
|
||||
|
||||
: Sets the state of calling **abort()** on fatal errors. If *abrt* is
|
||||
**false**, bcl(3) will not cause a **SIGABRT** on fatal errors after the
|
||||
|
@ -286,7 +289,7 @@ each function for what each function can return.
|
|||
|
||||
If activated, clients do not need to check for fatal errors.
|
||||
|
||||
**void bcl_gc(***void***)**
|
||||
**void bcl_gc(**_void_**)**
|
||||
|
||||
: Garbage collects cached instances of arbitrary-precision numbers. This only
|
||||
frees the memory of numbers that are *not* in use, so it is safe to call at
|
||||
|
@ -331,19 +334,19 @@ an argument.
|
|||
are meant to isolate the numbers used by different clients in the same
|
||||
application.
|
||||
|
||||
**BclContext bcl_ctxt_create(***void***)**
|
||||
**BclContext bcl_ctxt_create(**_void_**)**
|
||||
|
||||
: Creates a context and returns it. Returns **NULL** if there was an error.
|
||||
|
||||
**void bcl_ctxt_free(BclContext** *ctxt***)**
|
||||
**void bcl_ctxt_free(BclContext** _ctxt_**)**
|
||||
|
||||
: Frees *ctxt*, after which it is no longer valid. It is undefined behavior to
|
||||
attempt to use an invalid context.
|
||||
|
||||
**BclError bcl_pushContext(BclContext** *ctxt***)**
|
||||
**BclError bcl_pushContext(BclContext** _ctxt_**)**
|
||||
|
||||
: Pushes *ctxt* onto bcl(3)'s stack of contexts. *ctxt* must have been created
|
||||
with **bcl_ctxt_create(***void***)**.
|
||||
with **bcl_ctxt_create(**_void_**)**.
|
||||
|
||||
If there was no error, **BCL_ERROR_NONE** is returned. Otherwise, this
|
||||
function can return:
|
||||
|
@ -352,44 +355,44 @@ an argument.
|
|||
|
||||
There *must* be a valid context to do any arithmetic.
|
||||
|
||||
**void bcl_popContext(***void***)**
|
||||
**void bcl_popContext(**_void_**)**
|
||||
|
||||
: Pops the current context off of the stack, if one exists.
|
||||
|
||||
**BclContext bcl_context(***void***)**
|
||||
**BclContext bcl_context(**_void_**)**
|
||||
|
||||
: Returns the current context, or **NULL** if no context exists.
|
||||
|
||||
**void bcl_ctxt_freeNums(BclContext** *ctxt***)**
|
||||
**void bcl_ctxt_freeNums(BclContext** _ctxt_**)**
|
||||
|
||||
: Frees all numbers in use that are associated with *ctxt*. It is undefined
|
||||
behavior to attempt to use a number associated with *ctxt* after calling
|
||||
this procedure unless such numbers have been created with
|
||||
**bcl_num_create(***void***)** after calling this procedure.
|
||||
**bcl_num_create(**_void_**)** after calling this procedure.
|
||||
|
||||
**size_t bcl_ctxt_scale(BclContext** *ctxt***)**
|
||||
**size_t bcl_ctxt_scale(BclContext** _ctxt_**)**
|
||||
|
||||
: Returns the **scale** for given context.
|
||||
|
||||
**void bcl_ctxt_setScale(BclContext** *ctxt***, size_t** *scale***)**
|
||||
**void bcl_ctxt_setScale(BclContext** _ctxt_**, size_t** _scale_**)**
|
||||
|
||||
: Sets the **scale** for the given context to the argument *scale*.
|
||||
|
||||
**size_t bcl_ctxt_ibase(BclContext** *ctxt***)**
|
||||
**size_t bcl_ctxt_ibase(BclContext** _ctxt_**)**
|
||||
|
||||
: Returns the **ibase** for the given context.
|
||||
|
||||
**void bcl_ctxt_setIbase(BclContext** *ctxt***, size_t** *ibase***)**
|
||||
**void bcl_ctxt_setIbase(BclContext** _ctxt_**, size_t** _ibase_**)**
|
||||
|
||||
: Sets the **ibase** for the given context to the argument *ibase*. If the
|
||||
argument *ibase* is invalid, it clamped, so an *ibase* of **0** or **1** is
|
||||
clamped to **2**, and any values above **36** are clamped to **36**.
|
||||
|
||||
**size_t bcl_ctxt_obase(BclContext** *ctxt***)**
|
||||
**size_t bcl_ctxt_obase(BclContext** _ctxt_**)**
|
||||
|
||||
: Returns the **obase** for the given context.
|
||||
|
||||
**void bcl_ctxt_setObase(BclContext** *ctxt***, size_t** *obase***)**
|
||||
**void bcl_ctxt_setObase(BclContext** _ctxt_**, size_t** _obase_**)**
|
||||
|
||||
: Sets the **obase** for the given context to the argument *obase*.
|
||||
|
||||
|
@ -400,7 +403,7 @@ an argument.
|
|||
: An **enum** of possible error codes. See the **ERRORS** section for a
|
||||
complete listing the codes.
|
||||
|
||||
**BclError bcl_err(BclNumber** *n***)**
|
||||
**BclError bcl_err(BclNumber** _n_**)**
|
||||
|
||||
: Checks for errors in a **BclNumber**. All functions that can return a
|
||||
**BclNumber** can encode an error in the number, and this function will
|
||||
|
@ -419,7 +422,7 @@ All procedures in this section require a valid current context.
|
|||
exposed; the **BclNumber** handle is the only way clients can refer to
|
||||
instances of arbitrary-precision numbers.
|
||||
|
||||
**BclNumber bcl_num_create(***void***)**
|
||||
**BclNumber bcl_num_create(**_void_**)**
|
||||
|
||||
: Creates and returns a **BclNumber**.
|
||||
|
||||
|
@ -429,27 +432,27 @@ All procedures in this section require a valid current context.
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**void bcl_num_free(BclNumber** *n***)**
|
||||
**void bcl_num_free(BclNumber** _n_**)**
|
||||
|
||||
: Frees *n*. It is undefined behavior to use *n* after calling this function.
|
||||
|
||||
**bool bcl_num_neg(BclNumber** *n***)**
|
||||
**bool bcl_num_neg(BclNumber** _n_**)**
|
||||
|
||||
: Returns **true** if *n* is negative, **false** otherwise.
|
||||
|
||||
**void bcl_num_setNeg(BclNumber** *n***, bool** *neg***)**
|
||||
**void bcl_num_setNeg(BclNumber** _n_**, bool** _neg_**)**
|
||||
|
||||
: Sets *n*'s sign to *neg*, where **true** is negative, and **false** is
|
||||
positive.
|
||||
|
||||
**size_t bcl_num_scale(BclNumber** *n***)**
|
||||
**size_t bcl_num_scale(BclNumber** _n_**)**
|
||||
|
||||
: Returns the *scale* of *n*.
|
||||
|
||||
The *scale* of a number is the number of decimal places it has after the
|
||||
radix (decimal point).
|
||||
|
||||
**BclError bcl_num_setScale(BclNumber** *n***, size_t** *scale***)**
|
||||
**BclError bcl_num_setScale(BclNumber** _n_**, size_t** _scale_**)**
|
||||
|
||||
: Sets the *scale* of *n* to the argument *scale*. If the argument *scale* is
|
||||
greater than the *scale* of *n*, *n* is extended. If the argument *scale* is
|
||||
|
@ -462,7 +465,7 @@ All procedures in this section require a valid current context.
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**size_t bcl_num_len(BclNumber** *n***)**
|
||||
**size_t bcl_num_len(BclNumber** _n_**)**
|
||||
|
||||
: Returns the number of *significant decimal digits* in *n*.
|
||||
|
||||
|
@ -474,7 +477,7 @@ All procedures in this section consume the given **BclNumber** arguments that
|
|||
are not given to pointer arguments. See the **Consumption and Propagation**
|
||||
subsection below.
|
||||
|
||||
**BclNumber bcl_parse(const char \*restrict** *val***)**
|
||||
**BclNumber bcl_parse(const char \*restrict** _val_**)**
|
||||
|
||||
: Parses a number string according to the current context's **ibase** and
|
||||
returns the resulting number.
|
||||
|
@ -491,7 +494,7 @@ subsection below.
|
|||
* **BCL_ERROR_PARSE_INVALID_STR**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**char\* bcl_string(BclNumber** *n***)**
|
||||
**char\* bcl_string(BclNumber** _n_**)**
|
||||
|
||||
: Returns a string representation of *n* according the the current context's
|
||||
**ibase**. The string is dynamically allocated and must be freed by the
|
||||
|
@ -500,7 +503,7 @@ subsection below.
|
|||
*n* is consumed; it cannot be used after the call. See the
|
||||
**Consumption and Propagation** subsection below.
|
||||
|
||||
**BclError bcl_bigdig(BclNumber** *n***, BclBigDig \****result***)**
|
||||
**BclError bcl_bigdig(BclNumber** _n_**, BclBigDig \***_result_**)**
|
||||
|
||||
: Converts *n* into a **BclBigDig** and returns the result in the space
|
||||
pointed to by *result*.
|
||||
|
@ -517,7 +520,7 @@ subsection below.
|
|||
*n* is consumed; it cannot be used after the call. See the
|
||||
**Consumption and Propagation** subsection below.
|
||||
|
||||
**BclNumber bcl_bigdig2num(BclBigDig** *val***)**
|
||||
**BclNumber bcl_bigdig2num(BclBigDig** _val_**)**
|
||||
|
||||
: Creates a **BclNumber** from *val*.
|
||||
|
||||
|
@ -537,7 +540,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_add(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_add(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Adds *a* and *b* and returns the result. The *scale* of the result is the
|
||||
max of the *scale*s of *a* and *b*.
|
||||
|
@ -554,7 +557,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_sub(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_sub(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Subtracts *b* from *a* and returns the result. The *scale* of the result is
|
||||
the max of the *scale*s of *a* and *b*.
|
||||
|
@ -571,7 +574,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_mul(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_mul(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Multiplies *a* and *b* and returns the result. If *ascale* is the *scale* of
|
||||
*a* and *bscale* is the *scale* of *b*, the *scale* of the result is equal
|
||||
|
@ -590,7 +593,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_div(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_div(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Divides *a* by *b* and returns the result. The *scale* of the result is the
|
||||
*scale* of the current context.
|
||||
|
@ -610,7 +613,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_mod(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_mod(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Divides *a* by *b* to the *scale* of the current context, computes the
|
||||
modulus **a-(a/b)\*b**, and returns the modulus.
|
||||
|
@ -630,7 +633,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_pow(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_pow(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Calculates *a* to the power of *b* to the *scale* of the current context.
|
||||
*b* must be an integer, but can be negative. If it is negative, *a* must
|
||||
|
@ -655,7 +658,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_lshift(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_lshift(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Shifts *a* left (moves the radix right) by *b* places and returns the
|
||||
result. This is done in decimal. *b* must be an integer.
|
||||
|
@ -675,7 +678,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_MATH_NON_INTEGER**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_rshift(BclNumber** *a***, BclNumber** *b***)**
|
||||
**BclNumber bcl_rshift(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Shifts *a* right (moves the radix left) by *b* places and returns the
|
||||
result. This is done in decimal. *b* must be an integer.
|
||||
|
@ -695,7 +698,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_MATH_NON_INTEGER**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_sqrt(BclNumber** *a***)**
|
||||
**BclNumber bcl_sqrt(BclNumber** _a_**)**
|
||||
|
||||
: Calculates the square root of *a* and returns the result. The *scale* of the
|
||||
result is equal to the **scale** of the current context.
|
||||
|
@ -713,7 +716,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_MATH_NEGATIVE**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclError bcl_divmod(BclNumber** *a***, BclNumber** *b***, BclNumber \****c***, BclNumber \****d***)**
|
||||
**BclError bcl_divmod(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**)**
|
||||
|
||||
: Divides *a* by *b* and returns the quotient in a new number which is put
|
||||
into the space pointed to by *c*, and puts the modulus in a new number which
|
||||
|
@ -735,7 +738,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_modexp(BclNumber** *a***, BclNumber** *b***, BclNumber** *c***)**
|
||||
**BclNumber bcl_modexp(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**)**
|
||||
|
||||
: Computes a modular exponentiation where *a* is the base, *b* is the
|
||||
exponent, and *c* is the modulus, and returns the result. The *scale* of the
|
||||
|
@ -759,20 +762,20 @@ All procedures in this section can return the following errors:
|
|||
|
||||
## Miscellaneous
|
||||
|
||||
**void bcl_zero(BclNumber** *n***)**
|
||||
**void bcl_zero(BclNumber** _n_**)**
|
||||
|
||||
: Sets *n* to **0**.
|
||||
|
||||
**void bcl_one(BclNumber** *n***)**
|
||||
**void bcl_one(BclNumber** _n_**)**
|
||||
|
||||
: Sets *n* to **1**.
|
||||
|
||||
**ssize_t bcl_cmp(BclNumber** *a***, BclNumber** *b***)**
|
||||
**ssize_t bcl_cmp(BclNumber** _a_**, BclNumber** _b_**)**
|
||||
|
||||
: Compares *a* and *b* and returns **0** if *a* and *b* are equal, **<0** if
|
||||
*a* is less than *b*, and **>0** if *a* is greater than *b*.
|
||||
|
||||
**BclError bcl_copy(BclNumber** *d***, BclNumber** *s***)**
|
||||
**BclError bcl_copy(BclNumber** _d_**, BclNumber** _s_**)**
|
||||
|
||||
: Copies *s* into *d*.
|
||||
|
||||
|
@ -783,7 +786,7 @@ All procedures in this section can return the following errors:
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_dup(BclNumber** *s***)**
|
||||
**BclNumber bcl_dup(BclNumber** _s_**)**
|
||||
|
||||
: Creates and returns a new **BclNumber** that is a copy of *s*.
|
||||
|
||||
|
@ -810,8 +813,8 @@ remaining fairly portable.
|
|||
If necessary, the PRNG can be reseeded with one of the following functions:
|
||||
|
||||
* **bcl_rand_seedWithNum(BclNumber)**
|
||||
* **bcl_rand_seed(unsigned char[BC_SEED_SIZE])**
|
||||
* **bcl_rand_reseed(***void***)**
|
||||
* **bcl_rand_seed(unsigned char[**_BCL_SEED_SIZE_**])**
|
||||
* **bcl_rand_reseed(**_void_**)**
|
||||
|
||||
The following items allow clients to use the pseudo-random number generator. All
|
||||
procedures require a valid current context.
|
||||
|
@ -833,7 +836,7 @@ procedures require a valid current context.
|
|||
|
||||
: An unsigned integer type returned by bcl(3)'s random number generator.
|
||||
|
||||
**BclNumber bcl_irand(BclNumber** *a***)**
|
||||
**BclNumber bcl_irand(BclNumber** _a_**)**
|
||||
|
||||
: Returns a random number that is not larger than *a* in a new number. If *a*
|
||||
is **0** or **1**, the new number is equal to **0**. The bound is unlimited,
|
||||
|
@ -857,7 +860,7 @@ procedures require a valid current context.
|
|||
* **BCL_ERROR_MATH_NON_INTEGER**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_frand(size_t** *places***)**
|
||||
**BclNumber bcl_frand(size_t** _places_**)**
|
||||
|
||||
: Returns a random number between **0** (inclusive) and **1** (exclusive) that
|
||||
has *places* decimal digits after the radix (decimal point). There are no
|
||||
|
@ -871,7 +874,7 @@ procedures require a valid current context.
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclNumber bcl_ifrand(BclNumber** *a***, size_t** *places***)**
|
||||
**BclNumber bcl_ifrand(BclNumber** _a_**, size_t** _places_**)**
|
||||
|
||||
: Returns a random number less than *a* with *places* decimal digits after the
|
||||
radix (decimal point). There are no limits on *a* or *places*.
|
||||
|
@ -892,7 +895,7 @@ procedures require a valid current context.
|
|||
* **BCL_ERROR_MATH_NON_INTEGER**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclError bcl_rand_seedWithNum(BclNumber** *n***)**
|
||||
**BclError bcl_rand_seedWithNum(BclNumber** _n_**)**
|
||||
|
||||
: Seeds the PRNG with *n*.
|
||||
|
||||
|
@ -906,11 +909,11 @@ procedures require a valid current context.
|
|||
* **BCL_ERROR_INVALID_NUM**
|
||||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
|
||||
Note that if **bcl_rand_seed2num(***void***)** or
|
||||
Note that if **bcl_rand_seed2num(**_void_**)** or
|
||||
**bcl_rand_seed2num_err(BclNumber)** are called right after this function,
|
||||
they are not guaranteed to return a number equal to *n*.
|
||||
|
||||
**BclError bcl_rand_seed(unsigned char** *seed***[***BC_SEED_SIZE***])**
|
||||
**BclError bcl_rand_seed(unsigned char** _seed_**[**_BCL_SEED_SIZE_**])**
|
||||
|
||||
: Seeds the PRNG with the bytes in *seed*.
|
||||
|
||||
|
@ -919,14 +922,14 @@ procedures require a valid current context.
|
|||
|
||||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
|
||||
**void bcl_rand_reseed(***void***)**
|
||||
**void bcl_rand_reseed(**_void_**)**
|
||||
|
||||
: Reseeds the PRNG with the default reseeding behavior. First, it attempts to
|
||||
read data from **/dev/urandom** and falls back to **libc**'s **rand()**.
|
||||
|
||||
This procedure cannot fail.
|
||||
|
||||
**BclNumber bcl_rand_seed2num(***void***)**
|
||||
**BclNumber bcl_rand_seed2num(**_void_**)**
|
||||
|
||||
: Returns the current seed of the PRNG as a **BclNumber**.
|
||||
|
||||
|
@ -938,13 +941,13 @@ procedures require a valid current context.
|
|||
* **BCL_ERROR_INVALID_CONTEXT**
|
||||
* **BCL_ERROR_FATAL_ALLOC_ERR**
|
||||
|
||||
**BclRandInt bcl_rand_int(***void***)**
|
||||
**BclRandInt bcl_rand_int(**_void_**)**
|
||||
|
||||
: Returns a random integer between **0** and **BC_RAND_MAX** (inclusive).
|
||||
|
||||
This procedure cannot fail.
|
||||
|
||||
**BclRandInt bcl_rand_bounded(BclRandInt** *bound***)**
|
||||
**BclRandInt bcl_rand_bounded(BclRandInt** _bound_**)**
|
||||
|
||||
: Returns a random integer between **0** and *bound* (exclusive). Bias is
|
||||
removed before returning the integer.
|
||||
|
@ -1062,7 +1065,7 @@ codes defined in **BclError**. The complete list of codes is the following:
|
|||
|
||||
# ATTRIBUTES
|
||||
|
||||
When **bcl_handleSignal(***void***)** is used properly, bcl(3) is
|
||||
When **bcl_handleSignal(**_void_**)** is used properly, bcl(3) is
|
||||
async-signal-safe.
|
||||
|
||||
bcl(3) is *MT-Unsafe*: it is unsafe to call any functions from more than one
|
||||
|
@ -1140,16 +1143,16 @@ be hit.
|
|||
|
||||
# SIGNAL HANDLING
|
||||
|
||||
If a signal handler calls **bcl_handleSignal(***void***)** from the same thread
|
||||
If a signal handler calls **bcl_handleSignal(**_void_**)** from the same thread
|
||||
that there are bcl(3) functions executing in, it will cause all execution to
|
||||
stop as soon as possible, interrupting long-running calculations, if necessary
|
||||
and cause the function that was executing to return. If possible, the error code
|
||||
**BC_ERROR_SIGNAL** is returned.
|
||||
|
||||
If execution *is* interrupted, **bcl_handleSignal(***void***)** does *not*
|
||||
If execution *is* interrupted, **bcl_handleSignal(**_void_**)** does *not*
|
||||
return to its caller.
|
||||
|
||||
It is undefined behavior if **bcl_handleSignal(***void***)** is called from
|
||||
It is undefined behavior if **bcl_handleSignal(**_void_**)** is called from
|
||||
a thread that is not executing bcl(3) functions, if bcl(3) functions are
|
||||
executing.
|
||||
|
||||
|
|
|
@ -1,673 +0,0 @@
|
|||
# Benchmarks
|
||||
|
||||
The results of these benchmarks suggest that building this `bc` with
|
||||
optimization at `-O3` with link-time optimization (`-flto`) will result in the
|
||||
best performance. However, using `-march=native` can result in **WORSE**
|
||||
performance.
|
||||
|
||||
*Note*: all benchmarks were run four times, and the fastest run is the one
|
||||
shown. Also, `[bc]` means whichever `bc` was being run, and the assumed working
|
||||
directory is the root directory of this repository. Also, this `bc` was at
|
||||
version `3.0.0` while GNU `bc` was at version `1.07.1`, and all tests were
|
||||
conducted on an `x86_64` machine running Gentoo Linux with `clang` `9.0.1` as
|
||||
the compiler.
|
||||
|
||||
## Typical Optimization Level
|
||||
|
||||
These benchmarks were run with both `bc`'s compiled with the typical `-O2`
|
||||
optimizations and no link-time optimization.
|
||||
|
||||
### Addition
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc add.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 2.54
|
||||
user 1.21
|
||||
sys 1.32
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.88
|
||||
user 0.85
|
||||
sys 0.02
|
||||
```
|
||||
|
||||
### Subtraction
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc subtract.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 2.51
|
||||
user 1.05
|
||||
sys 1.45
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.91
|
||||
user 0.85
|
||||
sys 0.05
|
||||
```
|
||||
|
||||
### Multiplication
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc multiply.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 7.15
|
||||
user 4.69
|
||||
sys 2.46
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 2.20
|
||||
user 2.10
|
||||
sys 0.09
|
||||
```
|
||||
|
||||
### Division
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc divide.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 3.36
|
||||
user 1.87
|
||||
sys 1.48
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 1.61
|
||||
user 1.57
|
||||
sys 0.03
|
||||
```
|
||||
|
||||
### Power
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
printf '1234567890^100000; halt\n' | time -p [bc] -q > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 11.30
|
||||
user 11.30
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.73
|
||||
user 0.72
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
### Scripts
|
||||
|
||||
[This file][1] was downloaded, saved at `../timeconst.bc` and the following
|
||||
patch was applied:
|
||||
|
||||
```
|
||||
--- ../timeconst.bc 2018-09-28 11:32:22.808669000 -0600
|
||||
+++ ../timeconst.bc 2019-06-07 07:26:36.359913078 -0600
|
||||
@@ -110,8 +110,10 @@
|
||||
|
||||
print "#endif /* KERNEL_TIMECONST_H */\n"
|
||||
}
|
||||
- halt
|
||||
}
|
||||
|
||||
-hz = read();
|
||||
-timeconst(hz)
|
||||
+for (i = 0; i <= 50000; ++i) {
|
||||
+ timeconst(i)
|
||||
+}
|
||||
+
|
||||
+halt
|
||||
```
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
time -p [bc] ../timeconst.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 16.71
|
||||
user 16.06
|
||||
sys 0.65
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 13.16
|
||||
user 13.15
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
Because this `bc` is faster when doing math, it might be a better comparison to
|
||||
run a script that is not running any math. As such, I put the following into
|
||||
`../test.bc`:
|
||||
|
||||
```
|
||||
for (i = 0; i < 100000000; ++i) {
|
||||
y = i
|
||||
}
|
||||
|
||||
i
|
||||
y
|
||||
|
||||
halt
|
||||
```
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
time -p [bc] ../test.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 16.60
|
||||
user 16.59
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 22.76
|
||||
user 22.75
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
I also put the following into `../test2.bc`:
|
||||
|
||||
```
|
||||
i = 0
|
||||
|
||||
while (i < 100000000) {
|
||||
i += 1
|
||||
}
|
||||
|
||||
i
|
||||
|
||||
halt
|
||||
```
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
time -p [bc] ../test2.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 17.32
|
||||
user 17.30
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 16.98
|
||||
user 16.96
|
||||
sys 0.01
|
||||
```
|
||||
|
||||
It seems that the improvements to the interpreter helped a lot in certain cases.
|
||||
|
||||
Also, I have no idea why GNU `bc` did worse when it is technically doing less
|
||||
work.
|
||||
|
||||
## Recommended Optimizations from `2.7.0`
|
||||
|
||||
Note that, when running the benchmarks, the optimizations used are not the ones
|
||||
I recommended for version `2.7.0`, which are `-O3 -flto -march=native`.
|
||||
|
||||
This `bc` separates its code into modules that, when optimized at link time,
|
||||
removes a lot of the inefficiency that comes from function overhead. This is
|
||||
most keenly felt with one function: `bc_vec_item()`, which should turn into just
|
||||
one instruction (on `x86_64`) when optimized at link time and inlined. There are
|
||||
other functions that matter as well.
|
||||
|
||||
I also recommended `-march=native` on the grounds that newer instructions would
|
||||
increase performance on math-heavy code. We will see if that assumption was
|
||||
correct. (Spoiler: **NO**.)
|
||||
|
||||
When compiling both `bc`'s with the optimizations I recommended for this `bc`
|
||||
for version `2.7.0`, the results are as follows.
|
||||
|
||||
### Addition
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc add.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 2.44
|
||||
user 1.11
|
||||
sys 1.32
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.59
|
||||
user 0.54
|
||||
sys 0.05
|
||||
```
|
||||
|
||||
### Subtraction
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc subtract.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 2.42
|
||||
user 1.02
|
||||
sys 1.40
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.64
|
||||
user 0.57
|
||||
sys 0.06
|
||||
```
|
||||
|
||||
### Multiplication
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc multiply.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 7.01
|
||||
user 4.50
|
||||
sys 2.50
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 1.59
|
||||
user 1.53
|
||||
sys 0.05
|
||||
```
|
||||
|
||||
### Division
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc divide.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 3.26
|
||||
user 1.82
|
||||
sys 1.44
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 1.24
|
||||
user 1.20
|
||||
sys 0.03
|
||||
```
|
||||
|
||||
### Power
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
printf '1234567890^100000; halt\n' | time -p [bc] -q > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 11.08
|
||||
user 11.07
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.71
|
||||
user 0.70
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
### Scripts
|
||||
|
||||
The command for the `../timeconst.bc` script was:
|
||||
|
||||
```
|
||||
time -p [bc] ../timeconst.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 15.62
|
||||
user 15.08
|
||||
sys 0.53
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 10.09
|
||||
user 10.08
|
||||
sys 0.01
|
||||
```
|
||||
|
||||
The command for the next script, the `for` loop script, was:
|
||||
|
||||
```
|
||||
time -p [bc] ../test.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 14.76
|
||||
user 14.75
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 17.95
|
||||
user 17.94
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
The command for the next script, the `while` loop script, was:
|
||||
|
||||
```
|
||||
time -p [bc] ../test2.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 14.84
|
||||
user 14.83
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 13.53
|
||||
user 13.52
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
## Link-Time Optimization Only
|
||||
|
||||
Just for kicks, let's see if `-march=native` is even useful.
|
||||
|
||||
The optimizations I used for both `bc`'s were `-O3 -flto`.
|
||||
|
||||
### Addition
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc add.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 2.41
|
||||
user 1.05
|
||||
sys 1.35
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.58
|
||||
user 0.52
|
||||
sys 0.05
|
||||
```
|
||||
|
||||
### Subtraction
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc subtract.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 2.39
|
||||
user 1.10
|
||||
sys 1.28
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.65
|
||||
user 0.57
|
||||
sys 0.07
|
||||
```
|
||||
|
||||
### Multiplication
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc multiply.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 6.82
|
||||
user 4.30
|
||||
sys 2.51
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 1.57
|
||||
user 1.49
|
||||
sys 0.08
|
||||
```
|
||||
|
||||
### Division
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
tests/script.sh bc divide.bc 1 0 1 1 [bc]
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 3.25
|
||||
user 1.81
|
||||
sys 1.43
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 1.27
|
||||
user 1.23
|
||||
sys 0.04
|
||||
```
|
||||
|
||||
### Power
|
||||
|
||||
The command used was:
|
||||
|
||||
```
|
||||
printf '1234567890^100000; halt\n' | time -p [bc] -q > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 10.50
|
||||
user 10.49
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 0.72
|
||||
user 0.71
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
### Scripts
|
||||
|
||||
The command for the `../timeconst.bc` script was:
|
||||
|
||||
```
|
||||
time -p [bc] ../timeconst.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 15.50
|
||||
user 14.81
|
||||
sys 0.68
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 10.17
|
||||
user 10.15
|
||||
sys 0.01
|
||||
```
|
||||
|
||||
The command for the next script, the `for` loop script, was:
|
||||
|
||||
```
|
||||
time -p [bc] ../test.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 14.99
|
||||
user 14.99
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 16.85
|
||||
user 16.84
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
The command for the next script, the `while` loop script, was:
|
||||
|
||||
```
|
||||
time -p [bc] ../test2.bc > /dev/null
|
||||
```
|
||||
|
||||
For GNU `bc`:
|
||||
|
||||
```
|
||||
real 14.92
|
||||
user 14.91
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
For this `bc`:
|
||||
|
||||
```
|
||||
real 12.75
|
||||
user 12.75
|
||||
sys 0.00
|
||||
```
|
||||
|
||||
It turns out that `-march=native` can be a problem. As such, I have removed the
|
||||
recommendation to build with `-march=native`.
|
||||
|
||||
## Recommended Compiler
|
||||
|
||||
When I ran these benchmarks with my `bc` compiled under `clang` vs. `gcc`, it
|
||||
performed much better under `clang`. I recommend compiling this `bc` with
|
||||
`clang`.
|
||||
|
||||
[1]: https://github.com/torvalds/linux/blob/master/kernel/time/timeconst.bc
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue