Merge pull request #258 from louisrubet/intro-and-date

Intro and date
This commit is contained in:
Louis Rubet 2022-03-02 15:45:48 +01:00 committed by GitHub
commit 0b1b2dd2c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 100 additions and 126 deletions

View file

@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.4.1] - 2022-03-02
### Added
- A welcome message has been added in interactive mode.
### Changed
- The function `date` return format is now a string `"YYY-MM-DD"` (local ISO 8601).
- The function `time` return format is now a string `"HH:MM:SS"` (local ISO 8601).
### Removed
- The useless function `nop` has been removed.
- GENERATION.md file has been removed, the generation instructions are in README.md.
- The useless file TODO.md has been removed.
### Fixed
- The function `ticks` now returns correctly the current date in µs
## [2.4.0] - 2022-02-28 ## [2.4.0] - 2022-02-28
### Added ### Added

View file

@ -12,7 +12,7 @@ endif()
message(STATUS "Build mode: ${CMAKE_BUILD_TYPE}") message(STATUS "Build mode: ${CMAKE_BUILD_TYPE}")
if(EXISTS "${PROJECT_SOURCE_DIR}/.git") if(EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND git describe --long HEAD OUTPUT_VARIABLE "GIT_VERSION" OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND git describe HEAD OUTPUT_VARIABLE "GIT_VERSION" OUTPUT_STRIP_TRAILING_WHITESPACE)
add_definitions(-DGIT_VERSION="${GIT_VERSION}") add_definitions(-DGIT_VERSION="${GIT_VERSION}")
else(EXISTS ${PROJECT_SOURCE_DIR}/.git) else(EXISTS ${PROJECT_SOURCE_DIR}/.git)
set(GIT_VERSION "unknown") set(GIT_VERSION "unknown")

View file

@ -1,29 +0,0 @@
# Generation
rpn is proposed for **GNU/Linux**.
It can be generated following the steps below.
rpn is dynamically linked against GNU MP and GNU MPFR and integrates [linenoise-ng](https://github.com/louisrubet/linenoise-ng.git) and [mpreal](http://www.holoborodko.com/pavel/mpfr/) code as git submodules.
## Generate and install under Ubuntu 20.04 LTS
```shell
sudo apt install git cmake g++ libmpfr6 libmpfr-dev
git clone https://github.com/louisrubet/rpn/
mkdir -p rpn/build && cd rpn/build
cmake ..
make -j
sudo make install
```
## Generate and install under Fedora 35
```shell
sudo dnf install git cmake g++ mpfrf mpfr-devel
git clone https://github.com/louisrubet/rpn/
mkdir -p rpn/build && cd rpn/build
cmake ..
make -j
sudo make install
```

View file

@ -17,14 +17,13 @@ A help command is provided by rpn:
```rpn ```rpn
rpn> help rpn> help
rpn v2.4.0, (c) 2022 <louis@rubet.fr> rpn v2.4.1, (c) 2022 <louis@rubet.fr>
Reverse Polish Notation CLI calculator Reverse Polish Notation CLI calculator
Syntax: rpn [command] Syntax: rpn [command]
with optional command = list of commands with optional command = list of commands
GENERAL GENERAL
nop no operation
help this help message help this help message
(...) (...)
``` ```
@ -123,7 +122,6 @@ rpn> 7b1252 dec
| keyword | description | | keyword | description |
|-------------------|-----------------------------------------| |-------------------|-----------------------------------------|
| `nop` | no operation |
| `help` `h` `?` | this help message | | `help` `h` `?` | this help message |
| `quit` `q` `exit` | quit software | | `quit` `q` `exit` | quit software |
| `version` | show rpn version | | `version` | show rpn version |
@ -316,9 +314,9 @@ rpn> 7b1252 dec
| `acosh` | inverse hyperbolic cosine | | `acosh` | inverse hyperbolic cosine |
| `tanh` | hyperbolic tangent | | `tanh` | hyperbolic tangent |
| `atanh` | inverse hyperbolic tangent | | `atanh` | inverse hyperbolic tangent |
| `time` | time in format HH.MMSSssssss | | `time` | local time in ISO 8601 format HH:MM:SS |
| `date` | date in format (M)M.DDYYYY | | `date` | local date in ISO 8601 format YYYY-MM-DD |
| `ticks` | system tick in µs | | `ticks` | local date and time in µs |
### default ### default

View file

@ -1,14 +1,16 @@
# **rpn** - **R**everse **P**olish **N**otation CLI calculator [![License: LGPLv3](https://www.gnu.org/graphics/lgplv3-88x31.png)](https://www.gnu.org/licenses/lgpl-3.0.en.html) # **rpn** - **R**everse **P**olish **N**otation CLI calculator [![License: LGPLv3](https://www.gnu.org/graphics/lgplv3-88x31.png)](https://www.gnu.org/licenses/lgpl-3.0.en.html)
### A math functional language using reverse polish notation ### A math functional language using reverse (postfix) polish notation
```rpn ```rpn
rpn> 1 2 + 2 sqrt rpn> 1 2 +
3
rpn> 2 sqrt
2> 3 2> 3
1> 1.4142135623730950488 1> 1.4142135623730950488016887242096980786
``` ```
### Manipulating reals, complexes, strings, variables on a stack ### Manipulating reals, complexes, strings, symbols on a stack
```rpn ```rpn
rpn> 1 2 + 2 rpn> 1 2 + 2
@ -19,8 +21,15 @@ rpn> r->c sq conj (1,1) /
``` ```
```rpn ```rpn
rpn> "sqrt of 2 is " 2 sqrt ->str + rpn> 0x1234 dec
"sqrt of 2 is 1.4142135623730950488016887242096980786" 4660
rpn> bin
0b1001000110100
```
```rpn
rpn> 4 fix "sqrt of 2 is about " 2 sqrt ->str +
"sqrt of 2 is about 1.4142"
``` ```
```rpn ```rpn
@ -31,7 +40,7 @@ rpn> (1,2) f
(-10,-6) (-10,-6)
``` ```
### Arbitrary precision provided by GNU MPFR ### Arbitrary precision
```rpn ```rpn
rpn> 256 prec rpn> 256 prec
@ -43,18 +52,31 @@ rpn>
### Variables, structured programming ### Variables, structured programming
```rpn ```rpn
rpn> « rot * swap 2 / chs dup sq rot - sqrt » 'quad' sto
rpn> 0 1 10000 for i i sq + next rpn> 0 1 10000 for i i sq + next
333383335000 333383335000
```
```rpn
rpn> a 1 > if then a sq 'calc' eval else 'stop' eval end rpn> a 1 > if then a sq 'calc' eval else 'stop' eval end
``` ```
```rpn
rpn> << dup
> 1 > if then
> dup 1 - fibo swap 2 - fibo +
> else
> 1 == 1 0 ifte
> end >>
>'fibo' sto
rpn> 12 fibo
144
```
### Available functions ### Available functions
```rpn ```rpn
rpn> rpn>
Display all 146 possibilities? (y or n) Display all 145 possibilities? (y or n)
nop pow conj < pick step eval exp10
help sqrt arg <= depth ift -> log2 help sqrt arg <= depth ift -> log2
h sq c->r != roll ifte pi alog2 h sq c->r != roll ifte pi alog2
? abs r->c == rolld do sin exp2 ? abs r->c == rolld do sin exp2
@ -73,6 +95,7 @@ inv min bin rot end sto* exp
chs max base dup start sto/ expm chs max base dup start sto/ expm
neg re > dup2 for sneg log10 neg re > dup2 for sneg log10
^ im >= dupn next sinv alog10 ^ im >= dupn next sinv alog10
pow conj < pick step eval exp10
``` ```
## Download ## Download
@ -85,12 +108,12 @@ A reference manual is provided [here](MANUAL.md)
## Generation ## Generation
rpn is written in C++ and is dynamically linked against GNU MP and GNU MPFR. rpn is written in C++ and is dynamically linked to GNU MP and GNU MPFR.
It integrates [linenoise-ng](https://github.com/louisrubet/linenoise-ng.git) and [mpreal](http://www.holoborodko.com/pavel/mpfr/) code as git submodules. It integrates [linenoise-ng](https://github.com/louisrubet/linenoise-ng.git) and [mpreal](http://www.holoborodko.com/pavel/mpfr/) source code as git submodules.
It can be generated following the steps below: It can be generated following the steps below:
## Generate and install under Ubuntu 20.04 LTS ## Generate and install under Ubuntu 20.04 LTS and superior
```shell ```shell
sudo apt install git cmake g++ libmpfr6 libmpfr-dev sudo apt install git cmake g++ libmpfr6 libmpfr-dev
@ -104,7 +127,7 @@ sudo make install
## Generate and install under Fedora 35 ## Generate and install under Fedora 35
```shell ```shell
sudo dnf install git cmake g++ mpfrf mpfr-devel sudo dnf install git cmake g++ mpfr mpfr-devel
git clone https://github.com/louisrubet/rpn/ git clone https://github.com/louisrubet/rpn/
mkdir -p rpn/build && cd rpn/build mkdir -p rpn/build && cd rpn/build
cmake .. cmake ..

View file

@ -1,7 +0,0 @@
TODO
missing tests / problems
- les arguments d'une fonction en erreur doivent ils être consommés ?
ex embettant : sto+
- supprimer les vector et map static (il y en a 3 dans program)
- cpplint to install and run automatically

View file

@ -85,6 +85,8 @@ int main(int argc, char* argv[]) {
// run with interactive prompt // run with interactive prompt
if (argc == 1) { if (argc == 1) {
program::Welcome();
// init history // init history
EnterInteractive(); EnterInteractive();

View file

@ -80,6 +80,7 @@ struct Number : Object {
Number() : Object(kNumber), base(10) {} Number() : Object(kNumber), base(10) {}
explicit Number(const mpreal& value__, int base__ = 10) : Object(kNumber), base(base__), value(value__) {} explicit Number(const mpreal& value__, int base__ = 10) : Object(kNumber), base(base__), value(value__) {}
explicit Number(int value__, int base__ = 10) : Object(kNumber), base(base__), value(value__) {} explicit Number(int value__, int base__ = 10) : Object(kNumber), base(base__), value(value__) {}
explicit Number(uint64_t value__, int base__ = 10) : Object(kNumber), base(base__), value(value__) {}
int base; int base;
mpreal value; mpreal value;

View file

@ -8,7 +8,6 @@
vector<program::keyword_t> program::keywords_{ vector<program::keyword_t> program::keywords_{
// GENERAL // GENERAL
{kUndef, "", nullptr, "\nGENERAL"}, {kUndef, "", nullptr, "\nGENERAL"},
{kKeyword, "nop", &program::RpnNop, "no operation"},
{kKeyword, "help", &program::RpnHelp, "this help message"}, {kKeyword, "help", &program::RpnHelp, "this help message"},
{kKeyword, "h", &program::RpnHelp, ""}, {kKeyword, "h", &program::RpnHelp, ""},
{kKeyword, "?", &program::RpnHelp, ""}, {kKeyword, "?", &program::RpnHelp, ""},
@ -199,9 +198,9 @@ vector<program::keyword_t> program::keywords_{
// TIME AND DATE // TIME AND DATE
{kUndef, "", nullptr, "\nTIME AND DATE"}, {kUndef, "", nullptr, "\nTIME AND DATE"},
{kKeyword, "time", &program::RpnTime, "time in local format"}, {kKeyword, "time", &program::RpnTime, "local time in ISO 8601 format"},
{kKeyword, "date", &program::RpnDate, "date in local format"}, {kKeyword, "date", &program::RpnDate, "local date in ISO 8601 format"},
{kKeyword, "ticks", &program::RpnTicks, "system tick in µs"}, {kKeyword, "ticks", &program::RpnTicks, "local date and time in µs"}
}; };
#pragma GCC diagnostic pop #pragma GCC diagnostic pop

View file

@ -44,6 +44,7 @@ class program : public deque<Object*>, public Lexer {
void ShowStack(bool show_separator = true); void ShowStack(bool show_separator = true);
static void ApplyDefault(); static void ApplyDefault();
static void Welcome();
static vector<string>& GetAutocompletionWords(); static vector<string>& GetAutocompletionWords();
@ -105,7 +106,6 @@ class program : public deque<Object*>, public Lexer {
void RpnP2r(); void RpnP2r();
// general // general
void RpnNop();
void RpnQuit(); void RpnQuit();
void RpnHelp(); void RpnHelp();
void RpnStd(); void RpnStd();

View file

@ -23,13 +23,9 @@ static const char _description[] =
static const char _syntax[] = ATTR_BOLD "Syntax" ATTR_OFF ": rpn [command]\nwith optional command = list of commands"; static const char _syntax[] = ATTR_BOLD "Syntax" ATTR_OFF ": rpn [command]\nwith optional command = list of commands";
static const char _uname[] = ATTR_BOLD "rpn v" RPN_VERSION ", (c) 2022 <louis@rubet.fr>" ATTR_OFF; static const char _uname[] = ATTR_BOLD "rpn " RPN_VERSION ", (c) 2022 <louis@rubet.fr>" ATTR_OFF;
/// @brief nop keyword implementation static const char _welcome[] = ATTR_BOLD "rpn " RPN_VERSION ATTR_OFF "\nType h or help for more information.";
///
void program::RpnNop() {
// nop
}
/// @brief quit keyword implementation /// @brief quit keyword implementation
/// ///
@ -88,6 +84,10 @@ void program::RpnHelp() {
cout << endl; cout << endl;
} }
/// @brief welcome string
///
void program::Welcome() { cout << _welcome << endl; }
/// @brief whether a printed precision is in the precision min/max /// @brief whether a printed precision is in the precision min/max
/// ///
/// @param precision the precision in digits /// @param precision the precision in digits

View file

@ -1,29 +1,24 @@
// Copyright (c) 2014-2022 Louis Rubet // Copyright (c) 2014-2022 Louis Rubet
#include <chrono>
#include <ctime> #include <ctime>
using namespace std::chrono;
#include "program.h" #include "program.h"
/// @brief time keyword implementation /// @brief time keyword implementation
/// ///
void program::RpnTime() { void program::RpnTime() {
struct timespec ts; std::time_t rawtime = system_clock::to_time_t(system_clock::now());
struct tm* tm; struct tm tm;
double date;
// get local date if (localtime_r(&rawtime, &tm) != nullptr) {
clock_gettime(CLOCK_REALTIME, &ts); char buffer[80];
time_t time = (time_t)ts.tv_sec; size_t sz = strftime(buffer, sizeof(buffer), "%T", &tm);
tm = localtime(&time); if (sz > 0)
if (tm != nullptr) { stack_.push(new String(buffer));
// date format = HH.MMSSssssss else
date = (static_cast<double>(tm->tm_hour) * 10000000000.0 + static_cast<double>(tm->tm_min) * 100000000.0 + ERROR_CONTEXT(kInternalError);
static_cast<double>(tm->tm_sec) * 1000000.0 + static_cast<double>(ts.tv_nsec / 1000));
// push it
// division after push for real precision
stack_.push(new Number(date));
stack_.value<Number>(0) /= 10000000000.0;
} else { } else {
ERROR_CONTEXT(kInternalError); ERROR_CONTEXT(kInternalError);
} }
@ -32,21 +27,16 @@ void program::RpnTime() {
/// @brief date keyword implementation /// @brief date keyword implementation
/// ///
void program::RpnDate() { void program::RpnDate() {
struct timespec ts; std::time_t rawtime = system_clock::to_time_t(system_clock::now());
struct tm* tm; struct tm tm;
double date;
// get local date if (localtime_r(&rawtime, &tm) != nullptr) {
clock_gettime(CLOCK_REALTIME, &ts); char buffer[80];
time_t time = (time_t)ts.tv_sec; size_t sz = strftime(buffer, sizeof(buffer), "%F", &tm);
tm = localtime(&time); if (sz > 0)
if (tm != nullptr) { stack_.push(new String(buffer));
// date format = (M)M.DDYYYY else
date = static_cast<double>(tm->tm_mon + 1) * 1000000.0 + static_cast<double>(tm->tm_mday) * 10000.0 + ERROR_CONTEXT(kInternalError);
static_cast<double>(tm->tm_year + 1900);
// division after push for real precision
stack_.push(new Number(date));
stack_.value<Number>(0) /= 1000000.0;
} else { } else {
ERROR_CONTEXT(kInternalError); ERROR_CONTEXT(kInternalError);
} }
@ -55,19 +45,6 @@ void program::RpnDate() {
/// @brief ticks keyword implementation /// @brief ticks keyword implementation
/// ///
void program::RpnTicks() { void program::RpnTicks() {
struct timespec ts; uint64_t time_span = (uint64_t)duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count();
struct tm* tm; stack_.push(new Number(time_span));
double date;
// get local date
clock_gettime(CLOCK_REALTIME, &ts);
time_t time = (time_t)ts.tv_sec;
tm = localtime(&time);
if (tm != nullptr) {
// date in µs
date = 1000000.0 * static_cast<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec / 1000);
stack_.push(new Number(date));
} else {
ERROR_CONTEXT(kInternalError);
}
} }

View file

@ -30,16 +30,6 @@
`del` `del`
## nop
`nop`
-> stack size should be 0
-> error should be 0
`del`
## quit ## quit
`q` `q`

View file

@ -95,7 +95,6 @@
## fibo ## fibo
``` ```
«dup 1 > if then dup 1 - fibo swap 2 - fibo + else 1 == if then 1 else 0 end end» 'fibo' sto
«dup 1 > if then dup 1 - fibo swap 2 - fibo + else 1 == 1 0 ifte end» 'fibo' sto «dup 1 > if then dup 1 - fibo swap 2 - fibo + else 1 == 1 0 ifte end» 'fibo' sto
7 fibo 7 fibo
13 == if then 'ok!' end 13 == if then 'ok!' end

View file

@ -8,7 +8,7 @@
-> error should be 0 -> error should be 0
-> stack should be "number" -> stack should be "string"
`del` `del`
@ -18,7 +18,7 @@
-> error should be 0 -> error should be 0
-> stack should be "number" -> stack should be "string"
`del` `del`