diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f1664a..8093c44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,8 +56,9 @@ add_executable( ${PROJECT_SOURCE_DIR}/src/rpn-stack.cpp ${PROJECT_SOURCE_DIR}/src/rpn-store.cpp ${PROJECT_SOURCE_DIR}/src/rpn-string.cpp - ${PROJECT_SOURCE_DIR}/src/rpn-test-core.cpp ${PROJECT_SOURCE_DIR}/src/rpn-test.cpp + ${PROJECT_SOURCE_DIR}/src/rpn-test-core.cpp + ${PROJECT_SOURCE_DIR}/src/rpn-time.cpp ${PROJECT_SOURCE_DIR}/src/rpn-trig.cpp ${PROJECT_SOURCE_DIR}/linenoise-ng/src/ConvertUTF.cpp ${PROJECT_SOURCE_DIR}/linenoise-ng/src/linenoise.cpp diff --git a/MANUAL.md b/MANUAL.md index f0bd3dc..8d49eda 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -128,8 +128,8 @@ rpn> 7b1252 dec |keyword|description| |-|-| |`nop` | no operation -|`help\|h\|?` | this help message -|`quit\|q\|exit` | quit software +|`help` `h` `?` | this help message +|`quit` `q` `exit` | quit software |`version` | show rpn version |`uname` | show rpn complete identification string |`history`| see commands history @@ -140,13 +140,13 @@ rpn> 7b1252 dec |-|-| |`+`| addition |`-`| substraction -|`neg\|chs`| negation +|`neg` `chs`| negation |`*`| multiplication |`/`| division |`inv`| inverse -|`^\|pow`| power +|`^` `pow`| power |`sqrt`| square root -|`sq\|sqr`| square +|`sq` `sqr`| square |`abs`| absolute value for a number or `sqrt(re*re+im*im)` for a complex |`dec`| decimal representation |`hex`| hexadecimal representation @@ -220,7 +220,7 @@ rpn> 7b1252 dec |`drop`| drop first stack entry |`drop2`| drop 2 first stack entries |`dropn`| drop n first stack entries -|`del\|erase`| drop all stack entries +|`del` `erase`| drop all stack entries |`rot`| rotate 3 first stack entries |`dup`| duplicate first stack entry |`dup2`| duplicate 2 first stack entries @@ -258,9 +258,9 @@ rpn> 7b1252 dec |`next`| used with start and for |`step`| used with start and for |`do`| do (instructions) until (condition) end -|`until\|unti` | used with do -|`while\|whil`| while (test-instruction) repeat (loop-instructions) end -|`repeat\|repea`| used with while +|`until` `unti` | used with do +|`while` `whil`| while (test-instruction) repeat (loop-instructions) end +|`repeat` `repea`| used with while ### store @@ -305,20 +305,23 @@ rpn> 7b1252 dec |keyword|description| |-|-| |`e`| Euler constant -|`ln\|log`| logarithm base e +|`ln` `log`| logarithm base e |`lnp1`| ln(1+x) which is useful when x is close to 0 |`exp`| exponential |`expm`| exp(x)-1 which is useful when x is close to 0 |`log10`| logarithm base 10 -|`alog10\|exp10`| exponential base 10 +|`alog10` `exp10`| exponential base 10 |`log2`| logarithm base 2 -|`alog2\|exp2`| exponential base 2 +|`alog2` `exp2`| exponential base 2 |`sinh`| hyperbolic sine |`asinh`| inverse hyperbolic sine |`cosh`| hyperbolic cosine |`acosh`| inverse hyperbolic cosine |`tanh`| hyperbolic tangent |`atanh`| inverse hyperbolic tangent +|`time`| time in format HH.MMSSssssss +|`date`| date in format (M)M.DDYYYY +|`ticks`| system tick in µs ### default diff --git a/README.md b/README.md index b6345b0..f9001c2 100644 --- a/README.md +++ b/README.md @@ -25,25 +25,31 @@ rpn> << -> x y << x y + ln >> >> 'P' sto ### and a bunch of functions ``` rpn> -Display all 147 possibilities? (y or n) -nop chs bin min prec not depth else repeat sinv ln cosh -help neg base max round same roll end repea eval log acosh -h * sign re default swap rolld start sto -> lnp1 tanh -? / % im type drop over for rcl pi exp atanh -quit inv %CH conj > drop2 ->str next purge sin expm -q ^ mod arg >= dropn str-> step vars asin log10 -exit pow fact c->r < del chr ift clusr cos alog10 -test sqrt mant r->c <= erase num ifte edit acos exp10 -version sq xpon p->r != rot size do sto+ tan log2 -uname sqr floor r->p == dup pos until sto- atan alog2 -history abs ceil std and dup2 sub unti sto* d->r exp2 -+ dec ip fix or dupn if while sto/ r->d sinh -- hex fp sci xor pick then whil sneg e asinh +Display all 150 possibilities? (y or n) +nop pow fp >= dupn next sto* exp +help sqrt min < pick step sto/ expm +h sq max <= depth ift sneg log10 +? sqr re != roll ifte sinv alog10 +quit abs im == rolld do eval exp10 +q dec conj and over until -> log2 +exit hex arg or ->str unti pi alog2 +test bin c->r xor str-> while sin exp2 +version base r->c not chr whil asin sinh +uname sign p->r same num repeat cos asinh +history % r->p swap size repea acos cosh ++ %CH std drop pos sto tan acosh +- mod fix drop2 sub rcl atan tanh +chs fact sci dropn if purge d->r atanh +neg mant prec del then vars r->d time +* xpon round erase else clusr e date +/ floor default rot end edit ln ticks +inv ceil type dup start sto+ log +^ ip > dup2 for sto- lnp1 ``` ## Download -deb, rpm and tgz files can be found [there](http://nvie.com/img/git-model@2x.png) +deb, rpm and tgz files can be found [there](liv/) ## Manual diff --git a/src/parse.cpp b/src/parse.cpp index a130bc7..b14c1f6 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -11,7 +11,7 @@ void program::entry_completion_generator(const char* text, linenoiseCompletions* int text_len = strnlen(text, 6); // propose all keywords - if (text_len == 0) { + if (text_len == 0) { while (program::s_keywords[i].type != cmd_max) { if (program::s_keywords[i].fn != NULL) // add all keywords diff --git a/src/program.cpp b/src/program.cpp index 4bc3809..5bb4729 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -202,12 +202,18 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "tanh", &program::rpn_tanh, "hyperbolic tangent"}, {cmd_keyword, "atanh", &program::rpn_atanh, "inverse hyperbolic tangent"}, + // TIME AND DATE + {cmd_undef, "", NULL, "\nTIME AND DATE"}, + {cmd_keyword, "time", &program::rpn_time, "time in local format"}, + {cmd_keyword, "date", &program::rpn_date, "date in local format"}, + {cmd_keyword, "ticks", &program::rpn_ticks, "system tick in µs"}, + // end {cmd_max, "", NULL, ""}, }; /// @brief run a program on a stack and a heap -/// +/// /// @param stk the stack, storing prog result /// @param hp the heap, storing variables /// @return ret_value see this type @@ -305,12 +311,12 @@ ret_value program::run(stack& stk, heap& hp) { } /// @brief stop a program -/// +/// /// void program::stop() { interrupt_now = true; } /// @brief return whether a branch object has a given name -/// +/// /// @param b the branch object /// @param str_to_compare the name /// @param len the name length @@ -328,7 +334,7 @@ bool program::compare_branch(branch* b, const char* str_to_compare, int len) { /// this is needed before a program can be run /// inner members of branch or keyword objects are filled by this function /// these inner members store for example the index of the next keyword to execute etc. -/// +/// /// @return ret_value see this type /// ret_value program::preprocess(void) { @@ -558,7 +564,7 @@ ret_value program::preprocess(void) { } /// @brief show the last error set -/// +/// /// @return ret_value see this type /// ret_value program::show_error() { @@ -578,7 +584,7 @@ ret_value program::show_error() { } /// @brief record an error as the last error set and show it -/// +/// /// @param err the error to record /// @param context a context string /// @return ret_value see this type @@ -591,7 +597,7 @@ ret_value program::show_error(ret_value err, string& context) { } /// @brief record an error as the last error set and show it -/// +/// /// @param err the error to record /// @param context a context string /// @return ret_value see this type @@ -604,7 +610,7 @@ ret_value program::show_error(ret_value err, const char* context) { } /// @brief set the last error as being a syntax error and show it -/// +/// /// @param err the error to record /// @param context a context string /// @return ret_value see this type @@ -617,14 +623,14 @@ void program::show_syntax_error(const char* context) { } /// @brief return the last error set -/// +/// /// @return ret_value see this type /// ret_value program::get_err(void) { return _err; } /// @brief show a stack (show its different objects) /// generally a stack is associated to a running program -/// +/// /// @param st the stack to show /// @param show_separator whether to show a stack level prefix or not /// diff --git a/src/program.hpp b/src/program.hpp index e94ef73..b36b9a7 100644 --- a/src/program.hpp +++ b/src/program.hpp @@ -273,6 +273,11 @@ class program : public stack { void rpn_acos(void); void rpn_tan(void); void rpn_atan(void); + + // time + void rpn_time(); + void rpn_date(); + void rpn_ticks(); }; // convinience macros for rpn_xx function diff --git a/src/rpn-time.cpp b/src/rpn-time.cpp new file mode 100644 index 0000000..fd03c5e --- /dev/null +++ b/src/rpn-time.cpp @@ -0,0 +1,73 @@ +#include +#include "program.hpp" + +/// @brief time keyword implementation +/// +void program::rpn_time() { + struct timespec ts; + struct tm* tm; + double date; + + // get local date + clock_gettime(CLOCK_REALTIME, &ts); + time_t time = (time_t)ts.tv_sec; + tm = localtime(&time); + if (tm != NULL) { + // date format = HH.MMSSssssss + date = ((double)tm->tm_hour) * 10000000000.0 + ((double)tm->tm_min) * 100000000.0 + + ((double)tm->tm_sec) * 1000000.0 + (double)(ts.tv_nsec / 1000); + + // push it + number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number); + CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd)); + // division is done here because of real precision) + CHECK_MPFR(mpfr_div_d(num->_value.mpfr, num->_value.mpfr, 10000000000.0, floating_t::s_mpfr_rnd)); + } else + ERR_CONTEXT(ret_internal); +} + +/// @brief date keyword implementation +/// +void program::rpn_date() { + struct timespec ts; + struct tm* tm; + double date; + + // get local date + clock_gettime(CLOCK_REALTIME, &ts); + time_t time = (time_t)ts.tv_sec; + tm = localtime(&time); + if (tm != NULL) { + // date format = (M)M.DDYYYY + date = (double)(tm->tm_mon + 1) * 1000000.0 + (double)(tm->tm_mday) * 10000.0 + (double)(tm->tm_year + 1900); + + // push it + number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number); + CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd)); + // division is done here because of real precision) + CHECK_MPFR(mpfr_div_d(num->_value.mpfr, num->_value.mpfr, 1000000.0, floating_t::s_mpfr_rnd)); + } else + ERR_CONTEXT(ret_internal); +} + +/// @brief ticks keyword implementation +/// +void program::rpn_ticks() { + struct timespec ts; + struct tm* tm; + double date; + + // get local date + clock_gettime(CLOCK_REALTIME, &ts); + time_t time = (time_t)ts.tv_sec; + tm = localtime(&time); + if (tm != NULL) { + // date in µs + date = 1000000.0 * (double)ts.tv_sec + (double)(ts.tv_nsec / 1000); + + // push it + number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number); + CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd)); + } else + ERR_CONTEXT(ret_internal); +} diff --git a/test/12-time.txt b/test/12-time.txt new file mode 100644 index 0000000..2364a1f --- /dev/null +++ b/test/12-time.txt @@ -0,0 +1,25 @@ +## date and time +default del + +# date +date type +-> error should be 0 +-> stack should be "number" +del + +# time +time type +-> error should be 0 +-> stack should be "number" +del + +# ticks (1) +ticks type +-> error should be 0 +-> stack should be "number" +del + +# ticks (2) +ticks ticks - 0 <= +-> stack should be 1 +del diff --git a/test/all.txt b/test/all.txt index 40da188..7d9e2d8 100644 --- a/test/all.txt +++ b/test/all.txt @@ -9,4 +9,5 @@ #include 09-program.txt #include 10-complex.txt #include 11-base-entry.txt +#include 12-time.txt #include 99-manual-tests.txt