usr.bin/ghä-bc, contrib/bc: update to version 5.0.0

Merge commit 2f57ecae4b

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.

MFC after:	1 week
This commit is contained in:
Stefan Eßer 2021-08-10 10:42:54 +02:00
parent f61cb12aac
commit 44d4804d19
429 changed files with 54549 additions and 73052 deletions

View File

@ -1,3 +1,3 @@
*.vcxproj eol=crlf
*.vcxproj.filters eol=crlf
*.sln eol= crlf
*.sln eol=crlf

View File

@ -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

View File

@ -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

View File

@ -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%%

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" />

View File

@ -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>

View File

@ -0,0 +1,21 @@
#! /usr/bin/bc -lq
print "scale = 20\n"
print "x = 1234567890 / scale\n"
print "len = length(x) + 1 + scale\n"
print "len *= 2\n"
scale = 20
x = 1234567890 / scale
len = length(x) + 1 + scale
len *= 2
for (i = 0; i <= len; ++i) {
print "a[", i, "] = x * (10^", i, ")\n"
}
for (i = 1; i <= 10000; ++i) {
for (j = 0; j < len; ++j) {
print "v = a[", i, "] + a[", j, "]\n"
}
}

View File

@ -1,3 +1,4 @@
#! /usr/bin/bc
#
# SPDX-License-Identifier: BSD-2-Clause
#
@ -25,44 +26,9 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# AFL dictionary for bc
#
keyword_abs="abs"
keyword_auto="auto"
keyword_break="break"
keyword_continue="continue"
keyword_define="define"
keyword_else="else"
keyword_for="for"
keyword_halt="halt"
keyword_ibase="ibase"
keyword_if="if"
keyword_irand="irand"
keyword_last="last"
keyword_length="length"
keyword_limits="limits"
keyword_maxibase="maxibase"
keyword_maxobase="maxobase"
keyword_maxrand="maxrand"
keyword_maxscale="maxscale"
keyword_obase="obase"
keyword_print="print"
keyword_quit="quit"
keyword_rand="rand"
keyword_read="read"
keyword_return="return"
keyword_scale="scale"
keyword_seed="seed"
keyword_sqrt="sqrt"
keyword_while="while"
max = 1000000
"{"
"}"
","
"["
"]"
"1"
"1.234"
"-3.2892"
"3e4"
for (i = 0; i < max; ++i) {
print "a", i, "[0] = ", i, "\n"
}

View File

@ -0,0 +1,35 @@
#! /usr/bin/bc
#
# 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.
#
max = 1000000
for (i = 0; i < max; ++i) {
print "b", i, "[100] = ", i, "\n"
}

View File

@ -0,0 +1,18 @@
#! /usr/bin/bc -lq
scale = 0
max = 10000
print "scale = 0\n"
for (i = 0; i < max; ++i) {
a = rand()
b = rand()
print "band(", a, ", ", b, ")\n"
print "bor(", a, ", ", b, ")\n"
print "bxor(", a, ", ", b, ")\n"
print "blshift(", a, ", ", b % 32, ")\n"
print "brshift(", a, ", ", b % 32, ")\n"
}

View File

@ -1,4 +1,4 @@
#! /bin/sh
#! /usr/bin/bc
#
# SPDX-License-Identifier: BSD-2-Clause
#
@ -27,25 +27,15 @@
# POSSIBILITY OF SUCH DAMAGE.
#
set -e
max = 1000
max2 = 1000
script="$0"
for (i = 0; i < max; ++i) {
testdir=$(dirname "$script")
print "c = ", i, "\n"
print "e = 0.", i, "\n"
if [ "$#" -lt 2 ]; then
printf 'usage: %s dir test\n' "$0"
printf 'valid dirs are:\n'
printf '\n'
cat "$testdir/all.txt"
printf '\n'
exit 1
fi
d="$1"
shift
t="$1"
shift
exec diff "$testdir/$d/${t}_results.txt" "$testdir/${d}_outputs/${t}_results.txt"
for (j = 0; j < max2; ++j) {
print "d = ", i, ".", j, "\n"
}
}

View File

@ -0,0 +1,26 @@
#! /usr/bin/bc -lq
print "scale = 20\n"
print "x = 1234567890 * 10^(-scale)\n"
print "len = 1 + 2 * scale\n"
print "scale += 10\n"
scale = 20
x = 1234567890 * 10^(-scale)
len = 1 + 2 * scale
scale += 10
for (i = 0; i <= len; ++i) {
print "a[", i, "] = x * (10^", i, ")\n"
}
for (i = 1; i <= 10000; ++i) {
for (j = 0; j < len; ++j) {
print "v = a[0] / a[", j, "]\n"
print "v = a[", i, "] / a[", j, "]\n"
print "v = (a[0] * ", i, ") / a[", j, "]\n"
print "v = a[0] / (a[", j, "] * ", i, ")\n"
print "v = (a[0] * ", i, ") / (a[", j, "] * ", i, ")\n"
}
}

View File

@ -0,0 +1,34 @@
#! /usr/bin/bc
#
# 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.
#
max = 1000000
for (i = 0; i < max; ++i) {
print "define etsna", i, "(n) {\n\tn\n}\n"
}

View File

@ -0,0 +1,9 @@
#! /usr/bin/bc -lq
start = 2^256
end = start + 10000000
for (i = start; i < end; ++i) {
print "irand(", i, ")\n"
}

View File

@ -0,0 +1,5 @@
#! /usr/bin/bc -lq
for (i = 2; i < 10000000; ++i) {
print "irand(", i, ")\n"
}

View File

@ -0,0 +1,7 @@
#! /usr/bin/bc -lq
print "for (i = 100; i < 1000; ++i) {\n"
print " v = pi(i)\n"
print " v = e(v)\n"
print " v = l(v)\n"
print "}\n"

View File

@ -0,0 +1,23 @@
#! /usr/bin/bc -lq
print "scale = 20\n"
print "x = 1234567890 / scale\n"
print "len = length(x) + 1 + scale\n"
scale = 20
x = 1234567890 / scale
len = length(x) + 1 + scale
for (i = 0; i <= len; ++i) {
print "a[", i, "] = x * (10^", i, ")\n"
}
for (i = 1; i <= 10000; ++i) {
for (j = 0; j < len; ++j) {
print "v = a[0] * a[", j, "]\n"
print "v = a[", i, "] * a[", j, "]\n"
print "v = (a[0] * ", i, ") * a[", j, "]\n"
print "v = a[0] * (a[", j, "] * ", i, ")\n"
print "v = (a[0] * ", i, ") * (a[", j, "] * ", i, ")\n"
}
}

View File

@ -0,0 +1,7 @@
#! /usr/bin/bc -lq
max = 1000000
for (i = 0; i < max; ++i) {
print "i++\ni--\n"
}

View File

@ -0,0 +1,2 @@
#! /usr/bin/bc -lq

View File

@ -0,0 +1,36 @@
#! /usr/bin/bc
#
# 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.
#
max = 1000000
print "\qasotehnuasnotehustnaoheusntaoheustnaoheusntaoehunsatoheuastoehuaosnetuhaosetnuhaosentuahoesntuahoeuhstoeunhatoehusanotehusatnoheus\q\n"
for (i = 0; i < max; ++i) {
print "\qabc", i, " = ", i, "\\n\q\n"
}

View File

@ -0,0 +1,22 @@
#! /usr/bin/bc -lq
print "scale = 20\n"
print "x = 1234567890 / scale\n"
print "len = length(x) + 1 + scale\n"
print "len *= 2\n"
scale = 20
x = 1234567890 / scale
len = length(x) + 1 + scale
len *= 2
for (i = 0; i <= len; ++i) {
print "a[", i, "] = x * (10^", i, ")\n"
}
for (i = 1; i <= 10000; ++i) {
for (j = 0; j < len; ++j) {
print "v = a[", i, "] - a[", j, "]\n"
}
}

View File

@ -0,0 +1,42 @@
#! /usr/bin/dc
#
# 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.
[ ]ss
[|]so
100sm 0si
[
li1+si 0sj
[
lj1+sj 0sk
[
lk1+sk lin lsn ljn lsn lkn lsn lon 10P lk lm !<z
]dszx
lj lm !<y
]dsyx
li lm !<x
]dsxx

1321
contrib/bc/configure vendored

File diff suppressed because it is too large Load Diff

1
contrib/bc/configure vendored Symbolic link
View File

@ -0,0 +1 @@
configure.sh

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -33,7 +33,7 @@
*
*/
scale=20
scale=2*A
define e(x){
auto b,s,n,r,d,i,p,f,v
b=ibase

View File

@ -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)}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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[];

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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')

View File

@ -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];

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -60,14 +60,14 @@ $set 4
5 "無効なトークン"
6 "無効な式"
7 "空の式"
8 "無効な印刷文"
8 "無効なprintまたはstream文"
9 "無効な関数定義"
10 "無効な代入:左側は scale, ibase, obase, last, var, または配列要素でなければなりません"
11 "自動変数が見つかりませんでした"
12 "関数パラメータまたは自動\"ss\"はすでに存在します"
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\"

View File

@ -60,14 +60,14 @@ $set 4
5 "無効なトークン"
6 "無効な式"
7 "空の式"
8 "無効な印刷文"
8 "無効なprintまたはstream文"
9 "無効な関数定義"
10 "無効な代入:左側は scale, ibase, obase, last, var, または配列要素でなければなりません"
11 "自動変数が見つかりませんでした"
12 "関数パラメータまたは自動\"ss\"はすでに存在します"
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\"

View File

@ -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"

View File

@ -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"

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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\""

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More