Updated documentation
This commit is contained in:
parent
84a0704588
commit
460826cc32
14
.github/workflows/dc.yml
vendored
Normal file
14
.github/workflows/dc.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: dc
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@main
|
||||
- name: Build dc
|
||||
run: make clean all
|
14
README.md
14
README.md
@ -52,20 +52,12 @@ Some of the supported features are:
|
||||
And much more. You can find the complete manual [here](https://github.com/ice-bit/dc/blob/master/man.md).
|
||||
|
||||
## Installation
|
||||
`dc` is written in Rust. You can compile it by issuing the following command:
|
||||
`dc` is written in C++20 without using any additional dependency. In order to build it, issue the following commands:
|
||||
```sh
|
||||
$> cargo build --verbose --release
|
||||
$> make clean all
|
||||
```
|
||||
|
||||
You will find the output binary at:
|
||||
```sh
|
||||
$> target/release/dc
|
||||
```
|
||||
|
||||
To run unit tests, instead, type:
|
||||
```sh
|
||||
$> cargo test --all
|
||||
```
|
||||
A new binary called `dc` will be created in your local folder.
|
||||
|
||||
## Usage
|
||||
dc can be used in three different ways:
|
||||
|
524
dc.1
Normal file
524
dc.1
Normal file
@ -0,0 +1,524 @@
|
||||
.\" Automatically generated by Pandoc 2.17.1.1
|
||||
.\"
|
||||
.\" Define V font for inline verbatim, using C font in formats
|
||||
.\" that render this, and otherwise B font.
|
||||
.ie "\f[CB]x\f[]"x" \{\
|
||||
. ftr V B
|
||||
. ftr VI BI
|
||||
. ftr VB B
|
||||
. ftr VBI BI
|
||||
.\}
|
||||
.el \{\
|
||||
. ftr V CR
|
||||
. ftr VI CI
|
||||
. ftr VB CB
|
||||
. ftr VBI CBI
|
||||
.\}
|
||||
.TH "dc" "1" "November 02, 2023" "Marco Cetica" "General Commands Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
dc \[mi] RPN desktop calculator with macro support
|
||||
.SH SYNOPSIS
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
Usage of dc:
|
||||
-e string
|
||||
Evaluate an expression
|
||||
-f string
|
||||
Evaluate a file
|
||||
-v Show version information
|
||||
\f[R]
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\f[B]dc\f[R] is an advanced, scientific and programmable RPN desktop
|
||||
calculator with macro support (re)written in C++.
|
||||
By default, dc supports a wide range of arithmetical, trigonometrical
|
||||
and numerical functions.
|
||||
Its capabilities can be further extended by writing user-defined
|
||||
programs using the embedded, turing-complete, macro system.
|
||||
.PP
|
||||
\f[B]dc\f[R] uses the reverse polish notation(\f[B]RPN\f[R]) to parse
|
||||
mathematical expressions.
|
||||
Unlike the infix notation, where operators are placed \f[I]between\f[R]
|
||||
operands, the polish notation(also called prefix notation) places
|
||||
operators \f[I]before\f[R] the operands.
|
||||
The \f[B]reverse\f[R] polish notation takes this concept even further by
|
||||
placing the operators \f[I]after\f[R] the operands.
|
||||
As an example, consider the following infix expression:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
(((5 + 4) * (3 - 2)) / 2)
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
In RPN, this would be:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
2 5 4 + 3 2 - * r / p
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
Operands are pushed onto the stack following the LIFO policy; operators,
|
||||
on the other hand, pop one or more values from the stack and push back
|
||||
the result.
|
||||
By default \f[B]dc\f[R] is very quiet, in order to inquiry the stack you
|
||||
need to use one of the supported options(see below).
|
||||
.PP
|
||||
\f[B]dc\f[R] reads from the standard input, but it can also work with
|
||||
text files using the \f[V]-f\f[R] flag.
|
||||
Futhermore, you can decide to evaluate an expression without opening the
|
||||
REPL by using the \f[V]-e\f[R] flag.
|
||||
.SH ARCHITECTURE
|
||||
.PP
|
||||
As an advanced scientific calculator, \f[B]dc\f[R] has a complex
|
||||
architecture defined by the following two data structures:
|
||||
.IP "1." 3
|
||||
The main stack;
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
.IP "2." 3
|
||||
The register.
|
||||
.PP
|
||||
The \f[I]register\f[R] can also be extended as follows:
|
||||
.IP "1." 3
|
||||
The register stack;
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
.IP "2." 3
|
||||
The register array.
|
||||
.PP
|
||||
The \f[I]main stack\f[R] is the primary form of memory of this program.
|
||||
Every time you enter a number or execute a command, you are operating
|
||||
within the main stack.
|
||||
The \f[I]main stack\f[R] is virtually infinite and grows as much as
|
||||
needed; the \f[I]main stack\f[R] is \f[B]public\f[R], i.e.\ it is shared
|
||||
between any \f[B]dc\f[R] command.
|
||||
.PP
|
||||
The \f[B]register\f[R] is an hash map-like abstract data type that
|
||||
allows users to operate on an \f[I]isolated\f[R] environment formed by a
|
||||
\f[I]stack\f[R] and an \f[I]array\f[R].
|
||||
Each instance of the register is an ordered pair \f[V](key, value)\f[R]
|
||||
where the \f[I]key\f[R] is a character representing the name of the
|
||||
register and the \f[I]value\f[R] is a \f[B]private\f[R] instance of a
|
||||
stack and a \f[B]private\f[R] instance of an array.
|
||||
\f[B]dc\f[R] commands - exception made for registers, macro and array
|
||||
commands - cannot operate directly on the auxiliary stack or on the
|
||||
auxiliary array.
|
||||
In order to use a value stored on an auxiliary stack, you need to pop it
|
||||
and push it onto the main stack(see the register section).
|
||||
.PP
|
||||
Both the \f[I]main stack\f[R] and the \f[I]auxiliary stack\f[R]
|
||||
implement the same abstract data type, therefore any kind of data type
|
||||
supported by the main stack, as well as any other property or feature
|
||||
supported by the main stack is also supported by the register\[cq]s
|
||||
stack.
|
||||
.PP
|
||||
\f[I]Arrays\f[R] are dynamic, homogeneous and private abstract data type
|
||||
associated with a register.
|
||||
The underlying data type of a dc array is a hashmap where the index is
|
||||
represented by the map\[cq]s \f[V]key\f[R] and the associated value is
|
||||
represented by the map\[cq]s \f[V]value\f[R].
|
||||
.SH TYPE SYSTEM
|
||||
.PP
|
||||
By default each value of any kind of stack is represented by a string.
|
||||
Each operation is in charge to type convert the value before and after
|
||||
their invocation.
|
||||
The user can store both numerical and alphanumerical values on the
|
||||
stack.
|
||||
The latter using the \f[I]macro\f[R] syntax(see below).
|
||||
.PP
|
||||
Arrays are homogeneous, thus the only supported data type is the
|
||||
\f[V]string\f[R](the internal string type and not the \f[B]dc\f[R] one).
|
||||
.SH COMMANDS
|
||||
.PP
|
||||
Below, there is a list of supported \f[B]dc\f[R] commands.
|
||||
.SS Printing Commands
|
||||
.PP
|
||||
\f[B]p\f[R]
|
||||
.PP
|
||||
Prints the value on the top of the stack, without altering the stack.
|
||||
A newline is printed after the value.
|
||||
.PP
|
||||
\f[B]P\f[R]
|
||||
.PP
|
||||
Pops off the value on top of the stack, without altering the stack.
|
||||
.PP
|
||||
\f[B]f\f[R]
|
||||
.PP
|
||||
Prints the entire contents of the stack without altering anything.
|
||||
.SS Arithmetic
|
||||
.PP
|
||||
\f[B]+\f[R]
|
||||
.PP
|
||||
Pops two values off the stack, adds them, and pushes the result.
|
||||
.PP
|
||||
\f[B]-\f[R]
|
||||
.PP
|
||||
Pops two values, subtracts the first one popped from the second one
|
||||
popped, and pushes the result.
|
||||
.PP
|
||||
\f[B]*\f[R]
|
||||
.PP
|
||||
Pops two values, multiplies them, and pushes the result.
|
||||
.PP
|
||||
\f[B]/\f[R]
|
||||
.PP
|
||||
Pops two values, divides the second one popped from the first one
|
||||
popped, and pushes the result.
|
||||
.PP
|
||||
\f[B]%\f[R]
|
||||
.PP
|
||||
Pops two values, computes the remainder of the division between the
|
||||
second one popped and the first one popped.
|
||||
Pushes back the result.
|
||||
.PP
|
||||
\f[B]\[ti]\f[R]
|
||||
.PP
|
||||
Pops two values, divides the second one popped from the first one
|
||||
popped.
|
||||
The quotient is pushed first, and the remainder is pushed next.
|
||||
.PP
|
||||
\f[B]\[ha]\f[R]
|
||||
.PP
|
||||
Pops two values and computes their exponentiated, using the first value
|
||||
popped as the exponent and the second popped as the base.
|
||||
.PP
|
||||
\f[B]|\f[R]
|
||||
.PP
|
||||
Pops three values and computes a modular exponentiation.
|
||||
The first value popped is used as the reduction modulus; this value must
|
||||
be a non-zero integer.
|
||||
The second popped is used as the exponent; this value must be a
|
||||
non-negative number.
|
||||
The third value popped is the base which gets exponentiated, which
|
||||
should also be an integer.
|
||||
This function computes the following modular equivalence:
|
||||
\f[V]c \[==] b\[ha]e (mod n)\f[R]
|
||||
.PP
|
||||
\f[B]v\f[R]
|
||||
.PP
|
||||
Pops one value, computes its square root, and pushes that.
|
||||
.PP
|
||||
\f[B]!\f[R]
|
||||
.PP
|
||||
Pops one value, computes its factorial, and pushes that.
|
||||
.PP
|
||||
\f[B]pi\f[R]
|
||||
.PP
|
||||
Pushes pi approximation
|
||||
.PP
|
||||
\f[B]e\f[R]
|
||||
.PP
|
||||
Pushes e approximation
|
||||
.SS Trigonometrical
|
||||
.PP
|
||||
\f[B]sin\f[R]
|
||||
.PP
|
||||
Pops one value, computes its \f[V]sin\f[R], and pushes that.
|
||||
.PP
|
||||
\f[B]cos\f[R]
|
||||
.PP
|
||||
Pops one value, computes its \f[V]cos\f[R], and pushes that.
|
||||
.PP
|
||||
\f[B]tan\f[R]
|
||||
.PP
|
||||
Pops one value, computes its \f[V]tan\f[R], and pushes that.
|
||||
.SS Base Conversion
|
||||
.PP
|
||||
\f[B]pb\f[R]
|
||||
.PP
|
||||
Prints the value on top of the stack in base 2, without altering the
|
||||
stack.
|
||||
A newline is printed after the value.
|
||||
.PP
|
||||
\f[B]po\f[R]
|
||||
.PP
|
||||
Prints the value on top of the stack in base 8, without altering the
|
||||
stack.
|
||||
A newline is printed after the value.
|
||||
.PP
|
||||
\f[B]px\f[R]
|
||||
.PP
|
||||
Prints the value on top of the stack in base 16, without altering the
|
||||
stack.
|
||||
A newline is printed after the value.
|
||||
.SS Stack Control
|
||||
.PP
|
||||
\f[B]c\f[R]
|
||||
.PP
|
||||
Clears the stack, rendering it empty.
|
||||
.PP
|
||||
\f[B]d\f[R]
|
||||
.PP
|
||||
Duplicates the value on the top of the stack, pushing another copy of
|
||||
it.
|
||||
Thus, \f[V]4 d * p\f[R] computes 4 squared and prints it.
|
||||
.PP
|
||||
\f[B]r\f[R]
|
||||
.PP
|
||||
Reverses the order of the top two values of the stack.
|
||||
This can also be accomplished with the sequence \f[V]Sa Sb La Lb\f[R].
|
||||
.PP
|
||||
\f[B]R\f[R]
|
||||
.PP
|
||||
Pops the top-of-stack without printing it
|
||||
.SS Register(Stack)
|
||||
.PP
|
||||
As mentioned before, \f[B]dc\f[R] supports an hashmap ADT called
|
||||
\f[B]register\f[R] represented by an ordered pair
|
||||
\f[V](key, value)\f[R].
|
||||
A register maps the \f[V]key\f[R](represented by a single character)
|
||||
with a \f[V]value\f[R](represented by an auxiliary stack and a private
|
||||
array).
|
||||
At least 256 registers are available.
|
||||
Below, you can see the supported operations on register\[cq]s stack.
|
||||
.PP
|
||||
\f[B]s\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Pop the value off the top of the (main) stack and store it into top of
|
||||
the stack of register \f[I]r\f[R].
|
||||
This overwrite the top of the stack and does \f[B]NOT\f[R] follow the
|
||||
LIFO policy.
|
||||
.PP
|
||||
\f[B]l\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Copy the value in top of the stack of register \f[I]r\f[R] and push it
|
||||
onto the main stack.
|
||||
The value 0 is retrieved if the register is uninitialized.
|
||||
This does not alter the contents of \f[I]r\f[R].
|
||||
.PP
|
||||
\f[B]S\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Pop the value off the top of the (main) stack and push it onto the stack
|
||||
of register \f[I]r\f[R].
|
||||
The previous of the register becomes inaccessible, thus it follows the
|
||||
LIFO policy.
|
||||
.PP
|
||||
\f[B]L\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Pop the value off the top of register \f[I]r\f[R]\[cq]s stack and push
|
||||
it onto the main stack.
|
||||
The previous value in register \f[I]r\f[R]\[cq]s stack, if any, is now
|
||||
accessible via the \f[B]b\f[R]r command.
|
||||
.SS Register(Array)
|
||||
.PP
|
||||
Arrays support random access through an index.
|
||||
You can store a value in an array and retrieve it later.
|
||||
.PP
|
||||
\f[B]:\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Will pop the top two values off the stack.
|
||||
The second-to-top value will be stored in the array \f[V]r\f[R], indexed
|
||||
by the top-of-stack value.
|
||||
.PP
|
||||
\f[B];\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Pops the top-of-stack and uses it as an index into array \f[V]r\f[R].
|
||||
The selected value is then pushed onto the stack.
|
||||
.SS Strings
|
||||
.PP
|
||||
\f[I]dc\f[R] has a limited ability to operate on strings as well as on
|
||||
numbers; the only things you can do with strings are print them and
|
||||
execute them as macros (which means that the content of a string can
|
||||
executed as a \f[I]dc\f[R] program).
|
||||
Any kind of stack can hold strings, and \f[I]dc\f[R] always knows
|
||||
whether any given object is a string or a number.
|
||||
Some commands such as arithmetic operations demand numbers as arguments
|
||||
and print errors if given strings.
|
||||
Other commands can accept either a number or a string; for example, the
|
||||
\f[B]p\f[R] command can accept either and prints the object according to
|
||||
its type.
|
||||
.PP
|
||||
\f[B][ characters ]\f[R]
|
||||
.PP
|
||||
Makes a string containing \f[I]characters\f[R] (contained between
|
||||
balanced \f[B][\f[R] and \f[B]]\f[R] characters), and pushes it on the
|
||||
stack.
|
||||
For example, \f[B][ Hello World ] P\f[R] prints the string \f[B]Hello
|
||||
World\f[R] (with no newline).
|
||||
.PP
|
||||
\f[B]x\f[R]
|
||||
.PP
|
||||
Pops a value off the stack and executes it as a macro.
|
||||
Normally it should be a string; if it is a number, it is simply pushed
|
||||
back onto the stack.
|
||||
For example, \f[B][ 1 p ] x\f[R] executes the macro \f[B]1 p\f[R] which
|
||||
pushes \f[B]1\f[R] on the stack and prints \f[B]1\f[R] on a separate
|
||||
line.
|
||||
.PP
|
||||
Macros are most often stored in register\[cq]s stacks; \f[B][ 1 p ]
|
||||
sa\f[R] stores a macro to print \f[B]1\f[R] into register\[cq]s stack
|
||||
\f[B]a\f[R], and \f[B]la x\f[R] invokes this macro.
|
||||
.PP
|
||||
\f[B]>\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Pops two values off the stack and compares them assuming they are
|
||||
numbers, executing the contents of register \f[I]r\f[R] as a macro if
|
||||
the original top-of-stack is greater.
|
||||
Thus, \f[B]1 2>a\f[R] will invoke register \f[B]a\f[R]\[cq]s contents
|
||||
and \f[B]2 1>a\f[R] will not.
|
||||
.PP
|
||||
\f[B]=>\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Similar but invokes the macro if the original top-of-stack is greater or
|
||||
equal to the second-to-top.
|
||||
.PP
|
||||
\f[B]<\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Similar but invokes the macro if the original top-of-stack is less.
|
||||
.PP
|
||||
\f[B]<=\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Similar but invokes the macro if the original top-of-stack is less or
|
||||
equal to the second-to-top.
|
||||
.PP
|
||||
\f[B]=\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Similar but invokes the macro if the two numbers popped are equal.
|
||||
.PP
|
||||
\f[B]!=\f[R]\f[V]r\f[R]
|
||||
.PP
|
||||
Similar but invokes the macro if the two numbers popped are not equal.
|
||||
.SS Status Inquiry
|
||||
.PP
|
||||
\f[B]Z\f[R]
|
||||
.PP
|
||||
Pops a value off the stack, calculates the number of digits it has (or
|
||||
number of characters, if it is a string) and pushes that number.
|
||||
.PP
|
||||
\f[B]z\f[R]
|
||||
.PP
|
||||
Pushes the current stack depth: the number of objects on the stack
|
||||
before the execution of the \f[B]z\f[R] command.
|
||||
.SS Miscellaneous
|
||||
.PP
|
||||
\f[B]q\f[R]
|
||||
.PP
|
||||
Exit with return code \f[V]0\f[R].
|
||||
.PP
|
||||
\f[B]?\f[R]
|
||||
.PP
|
||||
Reads a line from the terminal and executes it.
|
||||
This command allows a macro to request input from the user.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Below, there are some practical problems solved using \f[B]dc\f[R].
|
||||
.IP "1." 3
|
||||
Evaluate \f[V](-5 + sqrt(25 - 16)) / 2\f[R]:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
-5 25 16 - v + 2 / p
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "2." 3
|
||||
Evaluate \f[V]sin(2pi)+cos(2pi)\f[R]:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
2 pi * sin 2 pi * cos + p
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "3." 3
|
||||
Loop from 1 to \f[V]n\f[R], where \f[V]n\f[R] is a user-defined value:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
[ p 1 + d lN >L ] sL # Print numbers from 1 through \[aq]N\[aq]
|
||||
|
||||
[ Enter limit: ] P # Ask user for limit \[aq]N\[aq]
|
||||
? 1 + sN # Read from stdin
|
||||
c 1 lL x # Clear the stack, add lower bound, load and execute macro
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "4." 3
|
||||
Sum the first \f[V]n\f[R] natural numbers, where \f[V]n\f[R] is a
|
||||
user-defined value:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
[ Enter bound: ] P ?
|
||||
[ d 1 - d 1 <F + ] d sF x p
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "5." 3
|
||||
Prints the first 20 values of \f[V]n!\f[R]:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
[ la 1 + d sa * p la 20 >y ] sy
|
||||
0 sa 1
|
||||
ly x
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "6." 3
|
||||
Computes the factorial of a given number:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
[ ln 1 - sn ln la * sa ln 1 !=f ] sf
|
||||
[ Enter value: ] P ? sn
|
||||
ln sa
|
||||
lf x
|
||||
la p
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "7." 3
|
||||
Computes the Greatest Common Divisor(GCD) between two user-defined
|
||||
numbers \f[V]A\f[R] and \f[V]B\f[R]:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
[ Enter A: ] P R ?
|
||||
[ Enter B: ] P R ?
|
||||
[ d Sa r La % d 0 <a ] d sa x +
|
||||
[ GCD(A,B)= ] P R p
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "8." 3
|
||||
Computes the Least Common Multiple(LCM) between two user-defined numbers
|
||||
\f[V]A\f[R] and \f[V]B\f[R]:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
[ Enter A: ] P R ? d sA
|
||||
[ Enter B: ] P R ? d SA
|
||||
[ d Sa r La % d 0 <a ] d sa x +
|
||||
LA lA * r /
|
||||
[ LCM(A,B)= ] P R p
|
||||
\f[R]
|
||||
.fi
|
||||
.IP "9." 3
|
||||
Find the roots of a quadratic equation
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
[ Enter A: ] P ? sA
|
||||
[ Enter B: ] P ? sB
|
||||
[ Enter C: ] P ? sC
|
||||
lB 2 \[ha] 4 lA lC * * - v sD
|
||||
lB -1 * lD - lA # NEGATIVE DELTA
|
||||
2 * / sS # FIRST SOLUTION
|
||||
lB -1 * lD + lA # POSITIVE DELTA
|
||||
2 * / SS # SECOND SOLUTION
|
||||
[ X: ] P R lS p
|
||||
[ Y: ] P R LS lS p
|
||||
\f[R]
|
||||
.fi
|
||||
.SH AUTHORS
|
||||
.PP
|
||||
The original version of the \f[B]dc\f[R] command was written by Robert
|
||||
Morris and Lorinda Cherry.
|
||||
This version of \f[B]dc\f[R] is developed by Marco Cetica.
|
||||
.SH BUGS
|
||||
.PP
|
||||
If you encounter any kind of problem, email me at
|
||||
<email@marcocetica.com> or open an issue at
|
||||
<https://github.com/ice-bit/dc>.
|
Loading…
Reference in New Issue
Block a user