diff options
Diffstat (limited to 'manuals/development.md')
-rw-r--r-- | manuals/development.md | 483 |
1 files changed, 380 insertions, 103 deletions
diff --git a/manuals/development.md b/manuals/development.md index f5eca786..333538df 100644 --- a/manuals/development.md +++ b/manuals/development.md @@ -1,6 +1,6 @@ # Development -Updated: 29 July 2021 +Updated: 13 Mar 2023 This document is meant for the day when I (Gavin D. Howard) get [hit by a bus][1]. In other words, it's meant to make the [bus factor][1] a non-issue. @@ -65,6 +65,8 @@ about things like fuzzing, [`scan-build`][19], [valgrind][20], [AddressSanitizer][21] (and the other sanitizers), and many other things. One of my happiest moments was when my `bc` was made the default in FreeBSD. +Another happiest moment was when I found out that my `bc` had shipped with Mac +OSX Ventura, without my knowledge. But since I believe in [finishing the software I write][22], I have done less work on `bc` over time, though there are still times when I put a lot of effort @@ -349,7 +351,22 @@ tabs, and assuming they were 4 spaces wide, but other than that, I basically kept the same style, with some exceptions that are more or less dependent on my taste. -The code style is as follows: +However, I later managed to get [ClangFormat][24] to work, so I changed the +style to that. + +### ClangFormat + +The style is now defined as whatever [ClangFormat][24] outputs using the +existing `.clang-format` file. More precisely, the style is whatever is output +when the following command is run in the root directory: + +``` +./scripts/format.sh +``` + +### Historical Style + +The code style used to be: * Tabs are 4 spaces. * Tabs are used at the beginning of lines for indent. @@ -395,52 +412,12 @@ The code style is as follows: * Besides short `if` statements and loops, there should *never* be more than one statement per line. -### ClangFormat - -I attempted three times to use [ClangFormat][24] to impose a standard, -machine-useful style on `bc`. All three failed. Otherwise, the style in this -repo would be more consistent. - ## Repo Structure Functions are documented with Doxygen-style doc comments. Functions that appear in headers are documented in the headers, while static functions are documented where they are defined. -### `bcl.sln` - -A Visual Studio solution file for [`bcl`][156]. This, along with -[`bcl.vcxproj`][63] and [`bcl.vcxproj.filters`][64] is what makes it possible to -build [`bcl`][156] on Windows. - -### `bcl.vcxproj` - -A Visual Studio project file for [`bcl`][156]. This, along with [`bcl.sln`][65] -and [`bcl.vcxproj.filters`][64] is what makes it possible to build [`bcl`][156] -on Windows. - -### `bcl.vcxproj.filters` - -A Visual Studio filters file for [`bcl`][156]. This, along with [`bcl.sln`][65] -and [`bcl.vcxproj`][63] is what makes it possible to build [`bcl`][156] on -Windows. - -### `bc.sln` - -A Visual Studio solution file for `bc`. This, along with [`bc.vcxproj`][66] -and [`bc.vcxproj.filters`][67] is what makes it possible to build `bc` on -Windows. - -### `bc.vcxproj` - -A Visual Studio project file for `bc`. This, along with [`bc.sln`][68] and -[`bc.vcxproj.filters`][67] is what makes it possible to build `bc` on Windows. - -### `bc.vcxproj.filters` - -A Visual Studio filters file for `bc`. This, along with [`bc.sln`][68] and -[`bc.vcxproj`][66] is what makes it possible to build `bc` on Windows. - ### `configure` A symlink to [`configure.sh`][69]. @@ -919,6 +896,8 @@ data structures. Vectors are what do the heavy lifting in almost all of `bc`'s data structures. Even the maps of identifiers and arrays use vectors. +The code associated with this header is in [`src/vector.c`][228]. + #### `version.h` This header defines the version of `bc`. @@ -1082,7 +1061,9 @@ template, and the manpage generated from the markdown version. ### `scripts/` This folder contains helper scripts. Most of them are written in pure [POSIX -`sh`][72], but one ([`karatsuba.py`][78]) is written in Python 3. +`sh`][72], but three ([`afl.py`][94], [`karatsuba.py`][78], and +[`randmath.py`][95]) are written in Python 3, and one ([`ministat.c`][223]) is +written in C. [`ministat.c`][223] in particular is copied from elsewhere. For more information about the shell scripts, see [POSIX Shell Scripts][76]. @@ -1563,10 +1544,18 @@ test scripts to know where the standard and other test directories are. The test for the [`bcl`][156] API. For more information, see the [`bcl` Test][157] section. +#### `error.sh` + +The script to run the file-based error tests in `tests/<calculator>/errors/` for +each calculator. For more information, see the [Error Tests][151] section. + +This is a separate script so that each error file can be run separately and in +parallel. + #### `errors.sh` -The script to run the error tests for each calculator. For more information, see -the [Error Tests][151] section. +The script to run the line-based error tests in `tests/<calculator>/errors.txt` +for each calculator. For more information, see the [Error Tests][151] section. #### `extra_required.txt` @@ -1751,6 +1740,61 @@ information, see the [Corpuses][192] subsection of the [Fuzzing][82] section. The fuzzing input directory for the inputs for `dc`. For more information, see the [Corpuses][192] subsection of the [Fuzzing][82] section. +### `vs/` + +The directory containing all of the materials needed to build `bc`, `dc`, and +`bcl` on Windows. + +#### `bcl.sln` + +A Visual Studio solution file for [`bcl`][156]. This, along with +[`bcl.vcxproj`][63] and [`bcl.vcxproj.filters`][64] is what makes it possible to +build [`bcl`][156] on Windows. + +#### `bcl.vcxproj` + +A Visual Studio project file for [`bcl`][156]. This, along with [`bcl.sln`][65] +and [`bcl.vcxproj.filters`][64] is what makes it possible to build [`bcl`][156] +on Windows. + +#### `bcl.vcxproj.filters` + +A Visual Studio filters file for [`bcl`][156]. This, along with [`bcl.sln`][65] +and [`bcl.vcxproj`][63] is what makes it possible to build [`bcl`][156] on +Windows. + +#### `bc.sln` + +A Visual Studio solution file for `bc`. This, along with [`bc.vcxproj`][66] +and [`bc.vcxproj.filters`][67] is what makes it possible to build `bc` on +Windows. + +#### `bc.vcxproj` + +A Visual Studio project file for `bc`. This, along with [`bc.sln`][68] and +[`bc.vcxproj.filters`][67] is what makes it possible to build `bc` on Windows. + +#### `bc.vcxproj.filters` + +A Visual Studio filters file for `bc`. This, along with [`bc.sln`][68] and +[`bc.vcxproj`][66] is what makes it possible to build `bc` on Windows. + +#### `tests/` + +A directory of files to run tests on Windows. + +##### `tests_bc.bat` + +A file to run basic `bc` tests on Windows. It expects that it will be run from +the directory containing it, and it also expects a `bc.exe` in the same +directory. + +##### `tests_dc.bat` + +A file to run basic `dc` tests on Windows. It expects that it will be run from +the directory containing it, and it also expects a `bc.exe` in the same +directory. + ## Build System The build system is described in detail in the [build manual][14], so @@ -1806,9 +1850,7 @@ the definition of the `BcStatus` enum.) In other words, I use `#if` instead of `#ifndef` or `#ifdef`, where possible. -There are a couple of cases where I went with standard stuff instead. For -example, to test whether I am in debug mode or not, I still use the standard -`#ifndef NDEBUG`. +There are a couple of cases where I went with standard stuff instead. #### Standard Macros @@ -1824,11 +1866,12 @@ example, to test whether I am in debug mode or not, I still use the standard : The macro expands to the build type, which is one of: `A`, `E`, `H`, `N`, `EH`, `EN`, `HN`, `EHN`. This build type is used in the help text to direct - the user to the correct markdown manual in the `git.yzena.com` website. + the user to the correct markdown manual in the `git.gavinhoward.com` + website. `EXECPREFIX` -: Thist macro expands to the prefix on the executable name. This is used to +: This macro expands to the prefix on the executable name. This is used to allow `bc` and `dc` to skip the prefix when finding out which calculator is executing. @@ -1869,7 +1912,7 @@ example, to test whether I am in debug mode or not, I still use the standard `BC_ENABLE_AFL` : This macro expands to `1` if `bc` has been built for fuzzing with - [AFL++][125], `0` otherwise.. See the [Fuzzing][82] section for more + [AFL++][125], `0` otherwise. See the [Fuzzing][82] section for more information. `BC_DEFAULT_BANNER` @@ -2014,7 +2057,7 @@ directory of all other test directories for each calculator. #### `bc` Standard Tests -The list of current (17 July 2021) standard tests for `bc` is below: +The list of current (27 February 2023) standard tests for `bc` is below: decimal @@ -2168,6 +2211,10 @@ bessel : Tests the `j()` function in the math library. +fib + +: Tests the `fib()` Fibonacci function in the extended math library. + arrays : Test arrays. @@ -2231,9 +2278,44 @@ bitfuncs : Tests the bitwise functions, `band()`, `bor()`, `bxor()`, `blshift()` and `brshift()` in [`gen/lib2.bc`][26]. +leadingzero + +: Tests the leading zero functionality and the `plz*()` and `pnlz*()` + functions in [`gen/lib2.bc`][26]. + +is_number + +: Tests the `is_number()` built-in function. + +is_string + +: Tests the `is_number()` built-in function. + +asciify_array + +: Tests the ability of `asciify()` to convert an array into a full string. + +line_by_line1 + +: Tests the line-by-line behavior of `bc` with regards to `quit` in a function + definition. + +line_by_line2 + +: Tests the line-by-line behavior of `bc` with regards to `quit`. + +line_loop_quit1 + +: Tests the behavior of `bc` with a `quit` after a single-line loop. + +line_loop_quit2 + +: Tests the behavior of `bc` with a `quit` after a single-line loop and a + newline escape. + #### `dc` Standard Tests -The list of current (17 July 2021) standard tests for `dc` is below: +The list of current (27 February 2023) standard tests for `dc` is below: decimal @@ -2247,7 +2329,7 @@ stack_len : Tests taking the length of the results stack. -stack_len +exec_stack_len : Tests taking the length of the execution stack. @@ -2309,7 +2391,7 @@ shift abs -: Tests the `abs()` builtin function. +: Tests the `abs()` builtin function (the `b` command). scientific @@ -2328,6 +2410,14 @@ misc : Miscellaneous tests. I named it this because at the time, I struggled to classify them. +misc1 + +: More miscellaneous tests. This used to be an error file + (`tests/dc/errors/15.txt`) due to the presence of a invalid `u` character. + However, starting with version `6.1.0`, `u` became a valid command + (`is_number()`), so the error file became valid. It was checked manually and + moved, and `tests/dc/errors/34.txt` became the new `tests/dc/errors/15.txt`. + strings : Tests strings. @@ -2336,9 +2426,13 @@ rand : Tests the pseudo-random number generator and its special stack handling. -exec_stack +is_number + +: Tests the `is_number()` built-in function (the `u` command). + +is_string -: Tests the execution stack depth command. +: Tests the `is_number()` built-in function (the `t` command). ### Script Tests @@ -2381,7 +2475,7 @@ to put it on the same line as others. #### `bc` Script Tests -The list of current (17 July 2021) script tests for `bc` is below: +The list of current (27 February 2023) script tests for `bc` is below: print.bc @@ -2407,10 +2501,22 @@ parse.bc : Tests parsing even harder than the parse standard test. +root.bc + +: Tests that `root()` and `cbrt()` do not go into an infinite loop on a + pathological case found by a user. + array.bc : Tests arrays even harder than the arrays standard test. +array2.bc + +: Implements a test where an array element is passed as a parameter to a + function, and then another array is passed to a later parameter that is + named the same as the first array. This was added because of a bug found + while writing a script in bc. + atan.bc : Tests arctangent even harder than the arctangent standard test. @@ -2448,9 +2554,17 @@ strings2.bc : Tests escaping in strings. +ifs.bc + +: Tests proper ending of `if` statements without `else` statements. + +ifs2.bc + +: More tests proper ending of `if` statements without `else` statements. + #### `dc` Script Tests -The list of current (17 July 2021) script tests for `dc` is below: +The list of current (27 February 2023) script tests for `dc` is below: prime.dc @@ -2488,6 +2602,11 @@ weird.dc : A miscellaneous test. +no_clamp.dc + +: A test to ensure `dc` has the same behavior as the BSD `dc` with digi + clamping off when parsing numbers. + ### Error Tests One of the most useful parts of the `bc` test suite, in my opinion, is the heavy @@ -2516,15 +2635,16 @@ treated differently. The error tests in the standard test directory, which include `errors.txt` for both calculators, `posix_errors.txt` for `bc`, and `read_errors.txt` for `dc`, -are read line-by-line and shoved through `stdin`, and each line is considered a -separate test. For this reason, there can't be any blank lines in the error -files in the standard tests directory because a blank line causes a successful -exit. +are run by [`tests/errors.sh`][226]. It reads them line-by-line and shoves the +data through `stdin`. Each line is considered a separate test. For this reason, +there can't be any blank lines in the error files in the standard tests +directory because a blank line causes a successful exit. On the other hand, the tests in the `errors/` directory below the standard tests -directory are considered to be one test per file, and they are used differently. -They are shoved into the calculator through `stdin`, but they are also executed -on the command-line. +directory are run by [`tests/error.sh`][227] and are considered to be one test +per file. As such, they are used differently. They are shoved into the +calculator through `stdin`, but they are also executed by passing them on the +command-line. To add an error test, first figure out which kind you want. @@ -2537,7 +2657,8 @@ respective `errors.txt` file. On the other hand, if you care if the error is run as a file on the command-line, or the error requires multiple lines to reproduce, then put the -test in the respective `errors/` directory. +test in the respective `errors/` directory and run the [`configure.sh`][69] +script again. After that, you are done; the test suite will automatically pick up the new test, and you don't have to tell the test suite the expected results. @@ -2606,8 +2727,16 @@ possible. I guess I could have done more, but doing so would have required a lot of time. I have tried to make it as easy as possible to run the history tests. They will -run automatically if you use the `make test` command, and they will also use -parallel execution with `make -j<cores> test`. +run automatically if you use the `make test_history` command, and they will also +use parallel execution with `make -j<cores> test_history`. + +However, the history tests are meant only to be run by maintainers of `bc`; they +are *not* meant to be run by users and packagers. The reason for this is that +they only seem to work reliably on Linux; `pexpect` seems to have issues on +other platforms, especially timeout issues. + +Thus, they are excluded from running with `make test` and [`tests/all.sh`][225]. +However, they can be run from the [`scripts/release.sh`][83] script. All of the tests are contained in [`tests/history.py`][139]. The reason for this is because they are in Python, and I don't have an easy way of including Python @@ -2805,6 +2934,19 @@ of targets to make this easy and as fast as possible. In addition to all of that, the build system is responsible for selecting the `bc`/`dc` tests or the [`bcl` test][157]. +### Output Directories + +During any run of the test suite, the test suite outputs the results of running +various tests to files. These files are usually output to `tests/bc_outputs/` +and `tests/dc_outputs/`. + +However, in some cases, it may be necessary to output test results to a +different directory. If that is the case, set the environment variable +`BC_TEST_OUTPUT_DIR` to the name of the directory. + +If that is done, then test results will be written to +`$BC_TEST_OUTPUT_DIR/bc_outputs/` and `$BC_TEST_OUTPUT_DIR/dc_outputs/`. + ### Test Suite Portability The test suite is meant to be run by users and packagers as part of their @@ -3223,13 +3365,13 @@ reported a crash or not. If so, it will copy the crashing test case to `stdin`. From there, I personally always investigate the crash and fix it. Then, when the -crash is fixed, I either move `.test.txt` to `tests/bc/errors/<idx>.txt` as an -error test (if it produces an error) or I create a new `tests/bc/misc<idx>.txt` -test for it and a corresponding results file. (See [Test Suite][124] for more -information about the test suite.) In either case, `<idx>` is the next number -for a file in that particular place. For example, if the last file in -`tests/bc/errors/` is `tests/bc/errors/18.txt`, I move `.test.txt` to -`tests/bc/error/19.txt`. +crash is fixed, I either move `.test.txt` to `tests/{bc,dc}/errors/<idx>.txt` as +an error test (if it produces an error) or I create a new +`tests/{bc,dc}/misc<idx>.txt` test for it and a corresponding results file. (See +[Test Suite][124] for more information about the test suite.) In either case, +`<idx>` is the next number for a file in that particular place. For example, if +the last file in `tests/{bc,dc}/errors/` is `tests/{bc,dc}/errors/18.txt`, I +move `.test.txt` to `tests/bc/error/19.txt`. Then I immediately run [`scripts/afl.py`][94] again to find the next crash because often, [AFL++][125] found multiple test cases that trigger the same @@ -3509,7 +3651,7 @@ bytecode because the virtual machine assumes the bytecode is valid. Sidenote: one of those bugs caused an infinite recursion when running the sine (`s()`) function in the math library, so yes, parser bugs can be *very* weird. -Anyway, they way I did `assert()`'s was like this: whenever I realized that I +Anyway, the way I did `assert()`'s was like this: whenever I realized that I had put assumptions into the code, I would put an `assert()` there to test it **and** to *document* it. @@ -3711,6 +3853,16 @@ barely worked after a lot of work and a lot of portability code, but even with all of that, it does not have at least one feature: multi-line pasting from the clipboard. +#### Editline and Readline + +I also implemented an integration with both editline and readline, though not at +the same time. This allows distributions that want to use either one in `bc` to +do so. This enables users to use their `.editrc` and `.inputrc` settings. + +The integration is custom to each library, and it does *not* involve any of +`bc`'s custom history code. It also required changes to `bc`'s [Custom +I/O][114]. + ### Error Handling The error handling on `bc` got an overhaul for version [`3.0.0`][32], and it @@ -3726,7 +3878,7 @@ if (BC_ERR(s)) return s; ``` In fact, a quick and dirty count of such lines in version `2.7.2` (the last -version before [`3.0.0`][32] turned up 252 occurrences of that sort of line. +version before [`3.0.0`][32]) turned up 252 occurrences of that sort of line. And that didn't even guarantee that return values were checked *everywhere*. @@ -3770,6 +3922,8 @@ because there are a few big snares: 2. While `longjmp()` is required to be [async-signal-safe][115], if it is invoked by a signal handler that interrupted a non-[async-signal-safe][115] function, then the behavior is undefined. +3. Any mutation that is not guaranteed to be atomic with respect to signals may + be incomplete when a signal arrives. Oh boy. @@ -3779,13 +3933,16 @@ any modifying pointer arithmetic, pointers and their data would be safe. For cases where I have local data that must change and stay changed, I needed to *undo* the `setjmp()`, do the change, and the *redo* the `setjmp()`. -For number 2, `bc` needs some way to tell the signal handler that it cannot do a -`longjmp()`. This is done by "locking" signals with a `volatile sig_atomic_t`. -(For more information, see the [Async-Signal-Safe Signal Handling][173] -section.) For every function that calls a function that is not +For number 2 and number 3, `bc` needs some way to tell the signal handler that +it cannot do a `longjmp()`. This is done by "locking" signals with a `volatile +sig_atomic_t`. (For more information, see the [Async-Signal-Safe Signal +Handling][173] section.) For every function that calls a function that is not async-signal-safe, they first need to use `BC_SIG_LOCK` to lock signals, and afterward, use `BC_SIG_UNLOCK` to unlock signals. +Code also need to do this for all global, non-atomic mutation, which means that +modifying any part of the `BcVm` global struct. + `BC_SIG_UNLOCK` has another requirement: it must check for signals or errors and jump if necessary. @@ -3849,7 +4006,7 @@ Other than that, and some common plumbing, the lexers have separate code. The `dc` lexer is remarkably simple; in fact, besides [`src/main.c`][205], [`src/bc.c`][40], and [`src/dc.c`][44], which just contain one function each, -the only file smaller that [`src/dc_lex.c`][45] is [`src/args.c`][206], which +the only file smaller than [`src/dc_lex.c`][45] is [`src/args.c`][206], which just processes command-line arguments after they are parsed by [`src/opt.c`][51]. @@ -3914,6 +4071,95 @@ Another example are conditional execution instructions; they need to produce the instruction for the condition, and then they must parse a possible "else" part, which might not exist. +##### Existing Commands + +`dc` is based on commands, which are usually one letter. The following table is +a table of which ASCII characters are already used: + +| Characters | Used? | For... | +|------------|-------|--------------------------------------------| +| Space | x | Separator | +| `!` | x | Conditional Execution of Registers | +| `"` | x | Bounded Rand Operator | +| `#` | x | Comments | +| `$` | x | Truncation | +| `%` | x | Modulus | +| `&` | | | +| `'` | x | Rand Operator | +| `(` | x | Greater Than Operator | +| `)` | x | Less Than Operator | +| `*` | x | Multiplication | +| `+` | x | Addition | +| `,` | x | Depth of Execution Stack | +| `-` | x | Subtraction | +| `.` | x | Numbers | +| `/` | x | Division | +| `0-9` | x | Numbers | +| `:` | x | Store into Array | +| `;` | x | Load from Array | +| `<` | x | Conditional Execution of Registers | +| `=` | x | Conditional Execution of Registers | +| `>` | x | Conditional Execution of Registers | +| `?` | x | Ask for User Input | +| `@` | x | Places Operator | +| `A-F` | x | Numbers | +| `G` | x | Equal Operator | +| `H` | x | Shift Left | +| `I` | x | Push `ibase` onto Stack | +| `J` | x | Push `seed` onto Stack | +| `K` | x | Push `scale` onto Stack | +| `L` | x | Pop off of Register | +| `M` | x | Boolean And Operator | +| `N` | x | Boolean Not Operator | +| `O` | x | Push `obase` onto Stack | +| `P` | x | Byte Stream Printing | +| `Q` | x | Quit Some Number of Macros | +| `R` | x | Pop Top of Stack | +| `S` | x | Push onto Register | +| `T` | x | Push Max `ibase` onto Stack | +| `U` | x | Push Max `obase` onto Stack | +| `V` | x | Push Max `scale` onto Stack | +| `W` | x | Push Max of `'` Operator | +| `X` | x | Scale of a Number | +| `Y` | x | Length of Array | +| `Z` | x | Number of Significant Digits | +| `[` | x | Strings | +| `\\` | x | Escaping Brackets in Strings | +| `]` | x | Strings | +| `^` | x | Power | +| `_` | x | Negative Numbers and Negation | +| Backtick | | | +| `a` | x | Asciify | +| `b` | x | Absolute Value | +| `c` | x | Clear Stack | +| `d` | x | Duplication of Top of Stack | +| `e` | x | Else in Conditional Execution of Registers | +| `f` | x | Printing the Stack | +| `g` | x | Global Settings | +| `h` | x | Shift Right | +| `i` | x | Set `ibase` | +| `j` | x | Set `seed` | +| `k` | x | Set `scale` | +| `l` | x | Load from Register | +| `m` | x | Boolean Or Operator | +| `n` | x | Print and Pop | +| `o` | x | Set `obase` | +| `p` | x | Print with Newline | +| `q` | x | Quit Two Macros | +| `r` | x | Swap Top Two Items | +| `s` | x | Store into Register | +| `t` | x | Equivalent of `bc`'s `is_number()` | +| `u` | x | Equivalent of `bc`'s `is_string()` | +| `v` | x | Square Root | +| `w` | | | +| `x` | x | Execute String | +| `y` | x | Current Depth of a Register | +| `z` | x | Current Depth of Stack | +| `{` | x | Greater Than or Equal Operator | +| `\|` | x | Moduler Exponentiation | +| `}` | x | Less Than or Equal Operator | +| `~` | x | Division and Modulus Combined | + #### `bc` Parsing `bc`'s parser is, by far, the most sensitive piece of code in this software, and @@ -4043,6 +4289,9 @@ another ends, it must *also* end before that other expression ends. This property ensures that operators will never interfere with each other on the operator stack. +Also, the operator precedence is reversed: a lower precedence *value* means a +higher precedence. + ###### Recursion Because expressions can stack, parsing expressions actually requires recursion. @@ -4250,8 +4499,8 @@ more elements are needed, the array is grown automatically, and new elements are given the value of zero. In fact, if *any* array is accessed and does not have an element at that index, -the array is automaticall grown to that size, and all new elements are given the -value zero. This behavior is guaranteed by the [`bc` spec][2]. +the array is automatically grown to that size, and all new elements are given +the value zero. This behavior is guaranteed by the [`bc` spec][2]. ###### Array References @@ -4324,7 +4573,7 @@ release when I change the code, and I have not released `bc` after version In order to do arbitrary-precision math, as `bc` must do, there must be some way of representing arbitrary-precision numbers. `BcNum` in [`include/num.h`][184] -is `bc`'s. +is `bc`'s way of doing that. (Note: the word ["limb"][214] is used below; it has a specific meaning when applied to arbitrary-precision numbers. It means one piece of the number. It can @@ -4348,7 +4597,7 @@ number is not reallocated; the number of limbs is just added to. There is one additional wrinkle: to make the usual operations (binary operators) fast, the decimal point is *not* allowed to be in the middle of a limb; it must -always be between limbs, after all limbs (integer) or before all limbs (real +always be between limbs, after all limbs (integer), or before all limbs (real between -1 and 1). The reason for this is because addition, subtraction, multiplication, and @@ -4407,9 +4656,9 @@ mean: This is the only case where `scale` does not have to coincide with `rdx` This can happen with division, for example, that sets a specific `scale` for the result value but may produce 0. -* `(rdx >> 1) < len`: the number is greater than or equal to 1, or less than or +* `(rdx >> 1) == len`: the number is greater than or equal to 1, or less than or equal to -1. -* `(rdx >> 1) == len`: the number is greater than -1 and less than 1, not +* `(rdx >> 1) < len`: the number is greater than -1 and less than 1, not including 0, although this will be true for 0 as well. However, 0 is always assumed to be represented by `len == 0`. * `(rdx >> 1) == 0`: the number is an integer. In this case, `scale` must also @@ -4432,6 +4681,25 @@ make it easier to understand the code. The style follows these rules: While these rules are not hard and fast, using them as a guide will probably help. +#### Digit Clamping + +There is a question of what to do when parsing numbers and coming across digits +that are greater than or equal to the current `ibase`. `bc` and `dc` do one of +two things: + +* Clamp the digit to the maximum correct digit, or +* Use the digit as-is, multiplying it by the `ibase` to the power of the digit's + position (starting from 0 at the least significant digit). + +The former behavior is what GNU `bc` does, and the latter is what GNU `dc`, the +OpenBSD `bc`, and the OpenBSD `dc` do. + +It is possible to switch between the two with the `-c` and `-C` command-line +options. However, it is important for developers to understand that both +behaviors exist and should exist. + +The library can also do both, and it is set in a global for each thread. + ### Strings as Numbers Strings can be assigned to variables. This is a problem because the vectors for @@ -4519,6 +4787,11 @@ places increases by 1: ... ``` +This happens because because every decimal representation of `1/2^p` ends with a +5 because 5 is half of 10. Because 5 is odd, half of it always ends with the +digits 25, where 2 is where the previous 5 was, and the new 5 is one decimal +place further right. + So the algorithm to convert all 255 bits of the seed is as follows: 1. Convert the increment to a `BcNum`. @@ -4561,7 +4834,7 @@ For more information, see all of the code guarded by `#if BC_DEBUG_CODE` in the Yes, all of the code is guarded by `#if` preprocessor statements; this is because the code should *never* be in a release build, and by making programmers -add this manually (not even an option to [`configure.sh`][69], it is easier to +add this manually (not even an option to [`configure.sh`][69]), it is easier to ensure that never happens. However, that said, the extra debug code is useful; that was why I kept it in. @@ -4569,10 +4842,10 @@ However, that said, the extra debug code is useful; that was why I kept it in. ## Performance While I have put in a lot of effort to make `bc` as fast as possible, there -might be some things you can do to speed it up without changing the code. +might be some things users can do to speed it up without changing the code. -First, you can probably use [profile-guided optimization][217] to optimize even -better, using the test suite to profile. +First, users can probably use [profile-guided optimization][217] to optimize +even better, using the test suite to profile. Second, I included macros that might help branch placement and prediction: @@ -4664,16 +4937,16 @@ for generating real numbers with it. (In `bc`, such support is in ### Signal Handling -Like signal handling in `bc` proper (see the [Async-Signal-Safe Signal -Handling][173] section), `bcl` has the infrastructure for signal handling. +`bcl` does not have the capability for signal handling (as of version `6.0.0`). + +### Threads -This infrastructure is different, however, as `bcl` assumes that clients will -implement their own signal handling. +It is possible to use `bcl` across multiple threads. However, `bcl` must be +initialized on each thread where it will be used. -So instead of doing signal handling on its own, `bcl` provides the capability to -interrupt executions and return to the clients almost immediately. Like in `bc`, -this is done with `setjmp()` and `longjmp()`, although the jump series is -stopped before returning normally to client code. +This is because `bcl` uses thread-specific data to store the "globals" for each +thread. This is to ensure that threads do not stomp on each other's numbers or +other data structures. ### Contexts @@ -4851,8 +5124,8 @@ However, where possible, errors are returned directly. [129]: #afl-quickstart [130]: #convenience [131]: #datac -[132]: https://git.yzena.com/gavin/vim-bc -[133]: https://git.yzena.com/gavin/bc_libs +[132]: https://git.gavinhoward.com/gavin/vim-bc +[133]: https://git.gavinhoward.com/gavin/bc_libs [134]: #debugging [135]: #asserts [136]: #portability @@ -4946,3 +5219,7 @@ However, where possible, errors are returned directly. [222]: https://www.freebsd.org/cgi/man.cgi?query=ministat&apropos=0&sektion=0&manpath=FreeBSD+13.0-RELEASE+and+Ports&arch=default&format=html [223]: #ministatc [224]: #dc +[225]: #allsh +[226]: #errorssh +[227]: #errorsh +[228]: #vectorc |