Fixed various bugs and fixed number representation error
This commit is contained in:
parent
09985c928b
commit
195fb4476a
4
.gitignore
vendored
4
.gitignore
vendored
@ -30,3 +30,7 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
dc
|
||||
|
||||
# Manual
|
||||
dc.1
|
||||
|
@ -58,6 +58,11 @@ $> make clean all
|
||||
|
||||
A new binary called `dc` will be created in your local folder.
|
||||
|
||||
To generate a man page from the `man.md` document, use the following command(note: needs pandoc):
|
||||
```sh
|
||||
$> pandoc man.md -s -t man > dc.1
|
||||
```
|
||||
|
||||
## Usage
|
||||
dc can be used in three different ways:
|
||||
1. From the interactive REPL(run it without any argument);
|
||||
|
523
dc.1
523
dc.1
@ -1,523 +0,0 @@
|
||||
.\" 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]
|
||||
RPN desktop calculator with macro support. Usage:
|
||||
-e, --expression <EXPRESSION> | Evaluate an expression
|
||||
-f, --file <FILE> | Evaluate a file
|
||||
-h, --help | Show this helper
|
||||
-V, --version | Show version
|
||||
\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>.
|
1
main.cpp
1
main.cpp
@ -68,6 +68,7 @@ int main(int argc, char **argv) {
|
||||
// Handle errors
|
||||
if(err != std::nullopt) {
|
||||
std::cerr << err.value() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
14
man.md
14
man.md
@ -163,20 +163,6 @@ Pops one value, computes its `cos`, and pushes that.
|
||||
|
||||
Pops one value, computes its `tan`, and pushes that.
|
||||
|
||||
## Base Conversion
|
||||
|
||||
**pb**
|
||||
|
||||
Prints the value on top of the stack in base 2, without altering the stack. A newline is printed after the value.
|
||||
|
||||
**po**
|
||||
|
||||
Prints the value on top of the stack in base 8, without altering the stack. A newline is printed after the value.
|
||||
|
||||
**px**
|
||||
|
||||
Prints the value on top of the stack in base 16, without altering the stack. A newline is printed after the value.
|
||||
|
||||
## Stack Control
|
||||
|
||||
**c**
|
||||
|
130
src/eval.cpp
130
src/eval.cpp
@ -1,3 +1,5 @@
|
||||
#include <memory>
|
||||
|
||||
#include "eval.h"
|
||||
#include "math.h"
|
||||
#include "stack.h"
|
||||
@ -13,217 +15,165 @@ std::optional<std::string> Evaluate::eval() {
|
||||
// NUMERICAL OPERATIONS
|
||||
//
|
||||
if(val == "+") {
|
||||
IOperation *math = new Math(OPType::ADD);
|
||||
auto math = std::make_unique<Math>(OPType::ADD);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "-") {
|
||||
IOperation *math = new Math(OPType::SUB);
|
||||
auto math = std::make_unique<Math>(OPType::SUB);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "*") {
|
||||
IOperation *math = new Math(OPType::MUL);
|
||||
auto math = std::make_unique<Math>(OPType::MUL);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val =="/") {
|
||||
IOperation *math = new Math(OPType::DIV);
|
||||
auto math = std::make_unique<Math>(OPType::DIV);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "%") {
|
||||
IOperation *math = new Math(OPType::MOD);
|
||||
auto math = std::make_unique<Math>(OPType::MOD);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "~") {
|
||||
IOperation *math = new Math(OPType::DIV_MOD);
|
||||
auto math = std::make_unique<Math>(OPType::DIV_MOD);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "|") {
|
||||
IOperation *math = new Math(OPType::MOD_EXP);
|
||||
auto math = std::make_unique<Math>(OPType::MOD_EXP);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "^") {
|
||||
IOperation *math = new Math(OPType::EXP);
|
||||
auto math = std::make_unique<Math>(OPType::EXP);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "v") {
|
||||
IOperation *math = new Math(OPType::SQRT);
|
||||
auto math = std::make_unique<Math>(OPType::SQRT);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "sin") {
|
||||
IOperation *math = new Math(OPType::SIN);
|
||||
auto math = std::make_unique<Math>(OPType::SIN);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "cos") {
|
||||
IOperation *math = new Math(OPType::COS);
|
||||
auto math = std::make_unique<Math>(OPType::COS);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "tan") {
|
||||
IOperation *math = new Math(OPType::TAN);
|
||||
auto math = std::make_unique<Math>(OPType::TAN);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "!") {
|
||||
IOperation *math = new Math(OPType::FACT);
|
||||
auto math = std::make_unique<Math>(OPType::FACT);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "pi") {
|
||||
IOperation *math = new Math(OPType::PI);
|
||||
auto math = std::make_unique<Math>(OPType::PI);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
} else if(val == "e") {
|
||||
IOperation *math = new Math(OPType::E);
|
||||
auto math = std::make_unique<Math>(OPType::E);
|
||||
err = math->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete math;
|
||||
}
|
||||
//
|
||||
// STACK OPERATIONS
|
||||
//
|
||||
else if(val == "p") { // PRINT TOP ELEMENT OF STACK
|
||||
IOperation *stack = new Stack(OPType::PCG);
|
||||
auto stack = std::make_unique<Stack>(OPType::PCG);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "P") { // PRINT TOP ELEMENT WITHOUT NEWLINE
|
||||
IOperation *stack = new Stack(OPType::P);
|
||||
auto stack = std::make_unique<Stack>(OPType::P);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "c") { // CLEAR THE STACK
|
||||
IOperation *stack = new Stack(OPType::CLR);
|
||||
auto stack = std::make_unique<Stack>(OPType::CLR);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "R") { // POP HEAD OF THE STACK WITHOUT PRINTING IT
|
||||
IOperation *stack = new Stack(OPType::PH);
|
||||
auto stack = std::make_unique<Stack>(OPType::PH);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "r") { // SWAP ORDER OF THE TWO TOP ELEMENTS
|
||||
IOperation *stack = new Stack(OPType::SO);
|
||||
auto stack = std::make_unique<Stack>(OPType::SO);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "d") { // DUPLICATE THE HEAD OF THE STACK
|
||||
IOperation *stack = new Stack(OPType::DP);
|
||||
auto stack = std::make_unique<Stack>(OPType::DP);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "f") { // PRINT THE WHOLE STACK
|
||||
IOperation *stack = new Stack(OPType::PS);
|
||||
auto stack = std::make_unique<Stack>(OPType::PS);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "Z") { // COMPUTE HEAD SIZE(NUM. OF CHARS/DIGITS)
|
||||
IOperation *stack = new Stack(OPType::CH);
|
||||
auto stack = std::make_unique<Stack>(OPType::CH);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "z") { // COMPUTE STACK SIZE
|
||||
IOperation *stack = new Stack(OPType::CS);
|
||||
auto stack = std::make_unique<Stack>(OPType::CS);
|
||||
err = stack->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
} else if(val == "x") { // EXECUTE MACRO
|
||||
IOperation *macro = new Macro(OPType::EX, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::EX, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
} else if(val == "?") { // READ LINE FROM STDIN
|
||||
IOperation *macro = new Macro(OPType::RI, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::RI, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
} else if(val == "q") { // QUIT GRACEFULLY
|
||||
std::exit(0);
|
||||
} else {
|
||||
@ -328,53 +278,41 @@ std::optional<std::string> Evaluate::parse_macro_command(std::string val) {
|
||||
// execute register's content as a macro
|
||||
std::optional<std::string> err = std::nullopt;
|
||||
if(operation == ">") {
|
||||
IOperation *macro = new Macro(OPType::CMP, Operator::GT, dc_register, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GT, dc_register, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
} else if(operation == "<") {
|
||||
IOperation *macro = new Macro(OPType::CMP, Operator::LT, dc_register, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LT, dc_register, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
} else if(operation == "=") {
|
||||
IOperation *macro = new Macro(OPType::CMP, Operator::EQ, dc_register, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::EQ, dc_register, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
} else if(operation == ">=") {
|
||||
IOperation *macro = new Macro(OPType::CMP, Operator::GEQ, dc_register, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GEQ, dc_register, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
} else if(operation == "<=") {
|
||||
IOperation *macro = new Macro(OPType::CMP, Operator::LEQ, dc_register, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LEQ, dc_register, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
} else if(operation == "!=") {
|
||||
IOperation *macro = new Macro(OPType::CMP, Operator::NEQ, dc_register, this->regs);
|
||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::NEQ, dc_register, this->regs);
|
||||
err = macro->exec(this->stack);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
||||
delete macro;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
41
src/math.cpp
41
src/math.cpp
@ -50,7 +50,7 @@ std::optional<std::string> Math::fn_add(stack_t &stack) {
|
||||
stack.pop_back();
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(lhs + rhs));
|
||||
stack.push_back(trim_zeros(lhs + rhs));
|
||||
} else {
|
||||
return "'+' requires numeric values";
|
||||
}
|
||||
@ -80,7 +80,7 @@ std::optional<std::string> Math::fn_sub(stack_t &stack) {
|
||||
stack.pop_back();
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(-(lhs - rhs)));
|
||||
stack.push_back(trim_zeros(-(lhs - rhs)));
|
||||
} else {
|
||||
return "'-' requires numeric values";
|
||||
}
|
||||
@ -110,7 +110,7 @@ std::optional<std::string> Math::fn_mul(stack_t &stack) {
|
||||
stack.pop_back();
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(lhs * rhs));
|
||||
stack.push_back(trim_zeros(lhs * rhs));
|
||||
} else {
|
||||
return "'*' requires numeric values";
|
||||
}
|
||||
@ -145,7 +145,7 @@ std::optional<std::string> Math::fn_div(stack_t &stack) {
|
||||
}
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(dividend / divisor));
|
||||
stack.push_back(trim_zeros(dividend / divisor));
|
||||
} else {
|
||||
return "'/' requires numeric values";
|
||||
}
|
||||
@ -180,7 +180,7 @@ std::optional<std::string> Math::fn_mod(stack_t &stack) {
|
||||
}
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string((int)lhs % (int)rhs));
|
||||
stack.push_back(trim_zeros((int)lhs % (int)rhs));
|
||||
} else {
|
||||
return "'%' requires numeric values";
|
||||
}
|
||||
@ -214,8 +214,8 @@ std::optional<std::string> Math::fn_div_mod(stack_t &stack) {
|
||||
auto quotient = std::trunc(dividend / divisor);
|
||||
auto remainder = ((int)dividend % (int)divisor);
|
||||
|
||||
stack.push_back(std::to_string(quotient));
|
||||
stack.push_back(std::to_string(remainder));
|
||||
stack.push_back(trim_zeros(quotient));
|
||||
stack.push_back(trim_zeros(remainder));
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -270,7 +270,7 @@ std::optional<std::string> Math::fn_mod_exp(stack_t &stack) {
|
||||
c = (c * base) % modulus;
|
||||
}
|
||||
|
||||
stack.push_back(std::to_string(c));
|
||||
stack.push_back(trim_zeros(c));
|
||||
} else {
|
||||
return "'|' requires numeric values";
|
||||
}
|
||||
@ -300,7 +300,7 @@ std::optional<std::string> Math::fn_exp(stack_t &stack) {
|
||||
stack.pop_back();
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(pow(base, exp)));
|
||||
stack.push_back(trim_zeros(pow(base, exp)));
|
||||
} else {
|
||||
return "'^' requires numeric values";
|
||||
}
|
||||
@ -329,7 +329,7 @@ std::optional<std::string> Math::fn_sqrt(stack_t &stack) {
|
||||
}
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(sqrt(x)));
|
||||
stack.push_back(trim_zeros(sqrt(x)));
|
||||
} else {
|
||||
return "'v' requires numeric values";
|
||||
}
|
||||
@ -354,7 +354,7 @@ std::optional<std::string> Math::fn_sin(stack_t &stack) {
|
||||
stack.pop_back();
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(sin(x)));
|
||||
stack.push_back(trim_zeros(sin(x)));
|
||||
} else {
|
||||
return "'sin' requires numeric values";
|
||||
}
|
||||
@ -379,7 +379,7 @@ std::optional<std::string> Math::fn_cos(stack_t &stack) {
|
||||
stack.pop_back();
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(cos(x)));
|
||||
stack.push_back(trim_zeros(cos(x)));
|
||||
} else {
|
||||
return "'cos' requires numeric values";
|
||||
}
|
||||
@ -404,7 +404,7 @@ std::optional<std::string> Math::fn_tan(stack_t &stack) {
|
||||
stack.pop_back();
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(tan(x)));
|
||||
stack.push_back(trim_zeros(tan(x)));
|
||||
} else {
|
||||
return "'tan' requires numeric values";
|
||||
}
|
||||
@ -438,7 +438,7 @@ std::optional<std::string> Math::fn_fact(stack_t &stack) {
|
||||
}
|
||||
|
||||
// Push back the result as a string
|
||||
stack.push_back(std::to_string(factorial));
|
||||
stack.push_back(trim_zeros(factorial));
|
||||
} else {
|
||||
return "'!' requires numeric values";
|
||||
}
|
||||
@ -447,13 +447,22 @@ std::optional<std::string> Math::fn_fact(stack_t &stack) {
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_pi(stack_t &stack) {
|
||||
stack.push_back(std::to_string(std::numbers::pi));
|
||||
stack.push_back(trim_zeros(std::numbers::pi));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_e(stack_t &stack) {
|
||||
stack.push_back(std::to_string(std::numbers::e));
|
||||
stack.push_back(trim_zeros(std::numbers::e));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string Math::trim_zeros(double number) {
|
||||
std::string s = std::to_string(number);
|
||||
|
||||
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
|
||||
s.erase(s.find_last_not_of('.') + 1, std::string::npos);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ private:
|
||||
std::optional<std::string> fn_fact(stack_t &stack);
|
||||
std::optional<std::string> fn_pi(stack_t &stack);
|
||||
std::optional<std::string> fn_e(stack_t &stack);
|
||||
static std::string trim_zeros(double number);
|
||||
|
||||
OPType op_type;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user