diff --git a/CMakeLists.txt b/CMakeLists.txt index c6bde2f..801a9d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ endif() message(STATUS "Build mode: ${CMAKE_BUILD_TYPE}") # INFO -set(RPN_VERSION "2.3.2") +set(RPN_VERSION "2.4") set(RPN_DISPLAY_NAME "rpn") set(RPN_URL_INFO_ABOUT "https://github.com/louisrubet/rpn") set(RPN_CONTACT "Louis Rubet ") @@ -25,7 +25,7 @@ set(RPN_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md") if(CMAKE_COMPILER_IS_GNUCXX) message(STATUS "Compiler type GNU: ${CMAKE_CXX_COMPILER}") # TODO still up to date? - set(BASE_COMPILER_OPTIONS "-std=c++14 -Wl,--no-as-needed") + set(BASE_COMPILER_OPTIONS "-std=c++17 -Wl,--no-as-needed") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILER_OPTIONS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${BASE_COMPILER_OPTIONS} -O0 -g") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${BASE_COMPILER_OPTIONS} -O3 -s") diff --git a/Changelog.md b/Changelog.md index 6f2cf35..9b89648 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,13 @@ Changelog - SonarCloud integration, Sonar way profile - clang-format now based on google style - [google c++ style guide](https://google.github.io/styleguide/cppguide.html) applied + - c++17 + - define guard + - name and order of inclusions + - static and global variables + - common patterns (ex: no static maps or vectors) + - classes (explicit) + - cpplint used with a CPPLINT.cfg removing some warnings - Test files are now markdown (.md) files, tests result are slightly changed - Delivery as flatpak and snap - it seems cosh was giving sinh (!) @@ -38,6 +45,7 @@ Compatibility is broken on these points - `sto+` `sto-` `sto*` `sto/` don't accept anymore the syntax `'varname' value stoX`, but only `value 'varname' stoX`, ex: `3 'a' sto*` - incomplete entry `(1,` is not available anymore - signed zero is the sign of zero is subject to change compared to previous version, for example `-3 sqrt` now equals `(0.000000,1.732051)` instead of `(-0.000000,1.732051)` +- removed CtrlC for interrupting a program (considered useless) Debug - `sub` now only accepts boundaries between 1 and the string length diff --git a/TODO.md b/TODO.md index 0412908..ffb181b 100644 --- a/TODO.md +++ b/TODO.md @@ -3,4 +3,5 @@ TODO missing tests / problems - les arguments d'une fonction en erreur doivent ils être consommés ? ex embettant : sto+ -- `1 'i' sto while i 2 <= repeat 0 'j' sto while 1 <= j repeat i (1,0) * j (0,1) * + 1 'j' sto+ end 1 'i' sto+ end` plante +- supprimer les vector et map static (il y en a 3 dans program) +- cpplint to install and run automatically diff --git a/src/.clang-format b/src/.clang-format index becb115..b5a7d96 100644 --- a/src/.clang-format +++ b/src/.clang-format @@ -7,3 +7,4 @@ Language: Cpp DerivePointerAlignment: false PointerAlignment: Left ColumnLimit: 120 +AccessModifierOffset: -3 \ No newline at end of file diff --git a/src/CPPLINT.cfg b/src/CPPLINT.cfg new file mode 100644 index 0000000..d771828 --- /dev/null +++ b/src/CPPLINT.cfg @@ -0,0 +1,7 @@ +set noparent + +filter=-whitespace/line_length + +// avoid "Is this a non-const reference? If so, make const or use a pointer" +// as it seems to be allowed by google now , cf https://github.com/cpplint/cpplint/issues/148 +filter=-runtime/references diff --git a/src/constant.h b/src/constant.h deleted file mode 100644 index 084c96f..0000000 --- a/src/constant.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef CONSTANT_H -#define CONSTANT_H - -#define MPFR_USE_NO_MACRO -#include - -// default values -// - -// default mode and number of printed digits -// -#define DEFAULT_MODE number::std - -/* directly calculated from 128 bits precision - ceil(128 * log10(2)) - 1 = 38 */ -#define DEFAULT_DECIMAL_DIGITS 38 - -// MPFR related defaults -// - -// 128 bits significand precision -#define MPFR_DEFAULT_PREC_BITS 128 - -// return values, used by all classes -// -typedef enum { - ret_ok, - ret_unknown_err, - ret_missing_operand, - ret_bad_operand_type, - ret_out_of_range, - ret_unknown_variable, - ret_internal, - ret_deadly, - ret_good_bye, - ret_not_impl, - ret_nop, - ret_syntax, - ret_div_by_zero, - ret_runtime_error, - ret_abort_current_entry, - ret_out_of_memory, - ret_bad_value, - ret_test_failed -} ret_value; - -// base min and max -#define BASE_MIN 2 -#define BASE_MAX 62 - -#endif diff --git a/src/escape.h b/src/escape.h deleted file mode 100644 index ba20c2c..0000000 --- a/src/escape.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ESCAPE_H -#define ESCAPE_H - -// ANSI escape sequences - -// foreground colors -#define FG_BLACK "\33[30m" -#define FG_RED "\33[31m" -#define FG_GREEN "\33[32m" - -// background colors -#define COLOR_OFF "\33[m" - -// attributes -#define ATTR_BOLD "\33[1m" -#define ATTR_OFF "\33[0m" - -#endif diff --git a/src/input.cpp b/src/input.cpp index f93c46d..c41f1bf 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,10 +1,13 @@ -#include "string.h" +// Copyright (c) 2014-2022 Louis Rubet + #include "input.hpp" +#include + vector* Input::_acWords = nullptr; Input::Input(string& entry, vector& autocompletionWords, string prompt, string mlPrompt) : status(cont) { - char* c_entry; + char* c_entry = nullptr; bool multiline = false; int entry_len; @@ -35,10 +38,12 @@ Input::Input(string& entry, vector& autocompletionWords, string prompt, // keep history if (c_entry[0] != 0) (void)linenoiseHistoryAdd(entry.c_str()); status = ok; - } else + } else { status = error; + } } } + free(c_entry); } /// @brief completion callback as asked by linenoise-ng @@ -48,24 +53,20 @@ Input::Input(string& entry, vector& autocompletionWords, string prompt, /// @param lc the completion object to add strings with linenoiseAddCompletion() /// void Input::entry_completion_generator(const char* text, linenoiseCompletions* lc) { - if (Input::_acWords == nullptr || text == nullptr) - return; - + if (Input::_acWords == nullptr || text == nullptr) return; + int text_len = strnlen(text, 6); - // propose all keywords if (text_len == 0) - for (string& ac : *Input::_acWords) - // add all keywords - linenoiseAddCompletion(lc, ac.c_str()); - // propose keywords matching to text begining + // propose all keywords + for (string& ac : *Input::_acWords) linenoiseAddCompletion(lc, ac.c_str()); else + // propose only keywords matching to text begining for (string& ac : *Input::_acWords) // compare list entry with text, return if match if (ac.compare(0, text_len, text) == 0) linenoiseAddCompletion(lc, ac.c_str()); } void Input::preload(const char* preloadText) { - if (preloadText != nullptr) - linenoisePreloadBuffer(preloadText); + if (preloadText != nullptr) linenoisePreloadBuffer(preloadText); } diff --git a/src/input.hpp b/src/input.hpp index 55a7b23..cec0079 100644 --- a/src/input.hpp +++ b/src/input.hpp @@ -1,23 +1,25 @@ -#ifndef _ENTRY_HPP_ -#define _ENTRY_HPP_ +// Copyright (c) 2014-2022 Louis Rubet +#ifndef SRC_INPUT_HPP_ +#define SRC_INPUT_HPP_ + +#include #include #include using namespace std; -#include #include "linenoise.h" class Input { - public: + public: Input(string& entry, vector& autocompletionWords, string prompt = "rpn> ", string mlPrompt = ">"); - enum {ok, cont, abort, ctrlc, error} status; + enum { ok, cont, abort, ctrlc, error } status; static void preload(const char* preloadText); - private: + private: static void entry_completion_generator(const char* text, linenoiseCompletions* lc); static vector* _acWords; }; -#endif +#endif // SRC_INPUT_HPP_ diff --git a/src/lexer.cpp b/src/lexer.cpp index 309a7eb..e4428f3 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "lexer.hpp" bool Lexer::lexer(string& entry, map& keywords, vector& elements, @@ -85,17 +87,18 @@ bool Lexer::parseProgram(string& entry, size_t idx, size_t& nextIdx, vector>" or "»" int countNested = 0; for (size_t i = idx + 2; i < entry.size() - 1; i++) { - if ((entry[i] == '<' && entry[i + 1] == '<') || (entry.substr(i, 2) == "«")) + if ((entry[i] == '<' && entry[i + 1] == '<') || (entry.substr(i, 2) == "«")) { countNested++; - else if ((entry[i] == '>' && entry[i + 1] == '>') || (entry.substr(i, 2) == "»")) { + } else if ((entry[i] == '>' && entry[i + 1] == '>') || (entry.substr(i, 2) == "»")) { if (countNested == 0) { string prg = entry.substr(idx + 2, i - idx - 2); trim(prg); elements.push_back({cmd_program, .value = prg}); nextIdx = i + 2; return true; - } else + } else { countNested--; + } } } string prg = entry.substr(idx + 2, entry.size() - idx - 2); @@ -138,11 +141,11 @@ int Lexer::getBaseAt(string& entry, size_t& nextIdx, bool& positive) { } else if (isdigit(a)) { if (b == 'b' || b == 'B') { nextIdx = scan + 2; - return int(a - '0'); + return static_cast(a - '0'); } if (isdigit(b) && (c == 'b' || c == 'B')) { nextIdx = scan + 3; - return 10 * int(a - '0') + int(b - '0'); + return 10 * static_cast(a - '0') + static_cast(b - '0'); } } return 10; @@ -162,7 +165,7 @@ bool Lexer::getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, m nextIdx = token.size() + idx + 1; trim(token); base = getBaseAt(token, numberIdx, positive); - if (base < BASE_MIN || base > BASE_MAX) return false; + if (base < 2 || base > 62) return false; if (numberIdx != 0) token = token.substr(numberIdx); *r = new mpreal; if (mpfr_set_str((*r)->mpfr_ptr(), token.c_str(), base, mpreal::get_default_rnd()) == 0) { @@ -170,7 +173,7 @@ bool Lexer::getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, m return true; } else { delete *r; - return false; + return false; } } nextIdx = token.size() + idx + 1; diff --git a/src/lexer.hpp b/src/lexer.hpp index 34c4964..08fc468 100644 --- a/src/lexer.hpp +++ b/src/lexer.hpp @@ -1,20 +1,20 @@ -#ifndef _PARSER_HPP_ -#define _PARSER_HPP_ +// Copyright (c) 2014-2022 Louis Rubet -#include -#include -using namespace std; +#ifndef SRC_LEXER_HPP_ +#define SRC_LEXER_HPP_ -#define MPFR_USE_NO_MACRO -#include #include using namespace mpfr; -#include "constant.h" +#include +#include +#include +using namespace std; + #include "object.hpp" class Lexer { - public: + public: // a structure to describe a syntaxical element and its value struct SynElement { cmd_type_t type; @@ -50,7 +50,7 @@ class Lexer { bool lexer(string& entry, map& keywords, vector& elements, vector& errors); - private: + private: bool parseString(string& entry, size_t idx, size_t& nextIdx, vector& errors, vector& elements); bool parseSymbol(string& entry, size_t idx, size_t& nextIdx, vector& errors, @@ -70,4 +70,4 @@ class Lexer { bool getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, mpreal** r, char delim = ' '); }; -#endif +#endif // SRC_LEXER_HPP_ diff --git a/src/main.cpp b/src/main.cpp index 3db8aeb..a88ee26 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,10 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include #include -#include #include +#include #include using namespace std; @@ -10,10 +12,6 @@ using namespace std; #include "input.hpp" #include "program.hpp" -static heap _global_heap; -static rpnstack _global_stack; -static program* _prog_to_interrupt = nullptr; - /// @brief actions to be done at rpn exit /// static void exit_interactive_rpn() { @@ -54,26 +52,7 @@ static void init_interactive_rpn() { /// @param siginfo signal info, see POSIX sigaction /// @param context see POSIX sigaction /// -static void ctrlc_handler(int sig, siginfo_t* siginfo, void* context) { - if (_prog_to_interrupt != nullptr) { - _prog_to_interrupt->stop(); - _prog_to_interrupt = nullptr; - } - - exit_interactive_rpn(); -} - -/// @brief handle SIGSEGV signal (sigaction handler): stop and exit rpn -/// -/// @param sig signal, see POSIX sigaction -/// @param siginfo signal info, see POSIX sigaction -/// @param context see POSIX sigaction -/// -static void segv_handler(int sig, siginfo_t* siginfo, void* context) { - cerr << "Internal error" << endl; - _prog_to_interrupt->stop(); - _prog_to_interrupt = nullptr; -} +static void ctrlc_handler(int sig, siginfo_t* siginfo, void* context) { exit_interactive_rpn(); } /// @brief setup signals handlers to stop with honours /// @@ -82,17 +61,10 @@ static void segv_handler(int sig, siginfo_t* siginfo, void* context) { static void catch_signals(program* prog) { struct sigaction act = {0}; - _prog_to_interrupt = prog; - act.sa_sigaction = &ctrlc_handler; act.sa_flags = SA_SIGINFO; if (sigaction(SIGINT, &act, nullptr) < 0) cerr << "Warning, Ctrl-C cannot be caught [errno=" << errno << ' ' << strerror(errno) << "']" << endl; - - act.sa_sigaction = &segv_handler; - act.sa_flags = SA_SIGINFO; - if (sigaction(SIGSEGV, &act, nullptr) < 0) - cerr << "Warning, SIGSEGV cannot be caught [errno=" << errno << ' ' << strerror(errno) << "']" << endl; } /// @brief rpn entry point @@ -114,9 +86,12 @@ int main(int argc, char* argv[]) { init_interactive_rpn(); // entry loop + heap heap; + rpnstack stack; while (go_on) { + // // make program from interactive entry - program prog(_global_stack, _global_heap); + program prog(stack, heap); string entry; switch (Input(entry, program::getAutocompletionWords()).status) { case Input::ok: @@ -126,7 +101,7 @@ int main(int argc, char* argv[]) { if (prog.parse(entry) == ret_ok && prog.run() == ret_good_bye) go_on = false; else - program::show_stack(_global_stack); + prog.show_stack(); break; case Input::ctrlc: go_on = false; @@ -139,15 +114,14 @@ int main(int argc, char* argv[]) { // manage history and exit exit_interactive_rpn(); } else { // run with cmd line arguments - program prog(_global_stack, _global_heap); + heap heap; + rpnstack stack; + program prog(stack, heap); string entry; int i; // make one string from entry - for (i = 1; i < argc; i++) { - entry += argv[i]; - entry += ' '; - } + for (i = 1; i < argc; i++) entry += string(argv[i]) + ' '; // make program ret = prog.parse(entry); @@ -157,7 +131,7 @@ int main(int argc, char* argv[]) { // run it ret = prog.run(); - program::show_stack(_global_stack, false); + prog.show_stack(false); } } diff --git a/src/mpreal-out.cpp b/src/mpreal-out.cpp index 0c58a3e..276852d 100644 --- a/src/mpreal-out.cpp +++ b/src/mpreal-out.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "mpreal-out.hpp" #define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -43,7 +45,7 @@ ostream& mpreal_output10base(ostream& out, const string& fmt, const mpreal& valu static bool is_min(const mpreal& p, mpfr_prec_t prec) { // see mpfr_vasprintf code - // TODO here use mpreal functions like <=0, isinf etc + // TODO(louis): here use mpreal functions like <=0, isinf etc bool ret; int round_away; switch (mpreal::get_default_rnd()) { @@ -98,9 +100,9 @@ static void _out_base(ostream& out, int base) { ostream& _out_singular(ostream& out, int base, const mpreal& value) { const char* write_after_sign = NULL; // unused for now int digits = 0; // forced 0 digits after separator - if (MPFR_IS_NAN(value.mpfr_srcptr())) + if (MPFR_IS_NAN(value.mpfr_srcptr())) { out << "nan"; - else if (MPFR_IS_INF(value.mpfr_srcptr())) { + } else if (MPFR_IS_INF(value.mpfr_srcptr())) { if (MPFR_IS_NEG(value.mpfr_srcptr())) out << '-'; out << "inf"; } else { @@ -142,7 +144,9 @@ ostream& _out_number(ostream& out, int base, const mpreal& value) { int digits = 0; // forced 0 digits after separator mpfr_exp_t exp = mpfr_get_exp(value.mpfr_srcptr()); - char* str = mpfr_get_str(NULL, &exp, base, digits + exp + 1, value.mpfr_srcptr(), mpreal::get_default_rnd()); + char* str = mpfr_get_str(NULL, &exp, base, digits + static_cast(exp) + 1, value.mpfr_srcptr(), + mpreal::get_default_rnd()); + int nexp = static_cast(exp); char* print_from; if (str != NULL) { int len = strlen(str); @@ -163,25 +167,26 @@ ostream& _out_number(ostream& out, int base, const mpreal& value) { out << "0b"; else out << base << "b"; - if (exp < 0) { + if (nexp < 0) { out << '0'; if (digits > 0) { out << '.'; - for (int i = 0; i < -(int)exp; i++) out << '0'; + for (int i = 0; i < -nexp; i++) out << '0'; out << str; - for (int i = 0; i < (int)(digits - len + exp); i++) out << '0'; + for (int i = 0; i < digits - len + nexp; i++) out << '0'; } } else { - if (exp == 0) + if (nexp == 0) { out << '0'; - else - for (int i = 0; i < (int)exp; i++) out << print_from[i]; + } else { + for (int i = 0; i < nexp; i++) out << print_from[i]; + } if (digits > 0) { out << '.'; - int remaining = (int)MIN(strlen(print_from) - exp - 1, digits) + 1; - for (int i = (int)exp; i < remaining + (int)exp; i++) out << print_from[i]; - for (int i = 0; i < (int)(exp + digits - len); i++) out << '0'; + int remaining = MIN(strlen(print_from) - nexp - 1, digits) + 1; + for (int i = nexp; i < remaining + nexp; i++) out << print_from[i]; + for (int i = 0; i < nexp + digits - len; i++) out << '0'; } } } diff --git a/src/mpreal-out.hpp b/src/mpreal-out.hpp index f2e8e65..cac8f10 100644 --- a/src/mpreal-out.hpp +++ b/src/mpreal-out.hpp @@ -1,11 +1,16 @@ +// Copyright (c) 2014-2022 Louis Rubet + +#ifndef SRC_MPREAL_OUT_HPP_ +#define SRC_MPREAL_OUT_HPP_ + +#include +using namespace mpfr; + #include #include using namespace std; -#define MPFR_USE_NO_MACRO -#include -#include -using namespace mpfr; - ostream& mpreal_output10base(ostream& out, const string& fmt, const mpreal& value); ostream& mpreal_outputNbase(ostream& out, int base, const mpreal& value); + +#endif // SRC_MPREAL_OUT_HPP_ diff --git a/src/object.cpp b/src/object.cpp index e9af391..43b8d49 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -1,6 +1,7 @@ -#include "constant.h" +// Copyright (c) 2014-2022 Louis Rubet + #include "object.hpp" // number statics -number::mode_enum number::s_mode = DEFAULT_MODE; +number::mode_enum number::s_mode = number::DEFAULT_MODE; int number::s_digits = DEFAULT_DECIMAL_DIGITS; diff --git a/src/object.hpp b/src/object.hpp index 994e1ab..0c52665 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -1,20 +1,41 @@ -#ifndef OBJECT_HPP -#define OBJECT_HPP +// Copyright (c) 2014-2022 Louis Rubet + +#ifndef SRC_OBJECT_HPP_ +#define SRC_OBJECT_HPP_ -#define MPFR_USE_NO_MACRO -#include #include + +#include "mpreal-out.hpp" using namespace mpfr; #include -#include #include +#include using namespace std; -#include "mpreal-out.hpp" - // definitions for objects /// +typedef enum { + ret_ok, + ret_unknown_err, + ret_missing_operand, + ret_bad_operand_type, + ret_out_of_range, + ret_unknown_variable, + ret_internal, + ret_deadly, + ret_good_bye, + ret_not_impl, + ret_nop, + ret_syntax, + ret_div_by_zero, + ret_runtime_error, + ret_abort_current_entry, + ret_out_of_memory, + ret_bad_value, + ret_test_failed +} ret_value; + typedef enum { cmd_undef, cmd_number, // floating point number @@ -36,7 +57,7 @@ typedef size_t (program::*branch_fn_t)(branch&); /// @brief object - a generic stack object /// struct object { - object(cmd_type_t type = cmd_undef) : _type(type) {} + explicit object(cmd_type_t type = cmd_undef) : _type(type) {} virtual ~object() {} cmd_type_t _type; virtual object* clone() { @@ -59,8 +80,8 @@ struct object { /// struct number : object { number() : object(cmd_number), base(10) {} - number(const mpreal& value_, int base_ = 10) : object(cmd_number), base(base_), value(value_) {} - number(long value_, int base_ = 10) : object(cmd_number), base(base_), value(value_) {} + explicit number(const mpreal& value_, int base_ = 10) : object(cmd_number), base(base_), value(value_) {} + explicit number(int value_, int base_ = 10) : object(cmd_number), base(base_), value(value_) {} int base; mpreal value; @@ -72,18 +93,21 @@ struct number : object { // representation mode typedef enum { std, fix, sci } mode_enum; static mode_enum s_mode; + static constexpr mode_enum DEFAULT_MODE = number::std; // precision + static constexpr mpfr_prec_t MPFR_DEFAULT_PREC_BITS = 128; + static constexpr int DEFAULT_DECIMAL_DIGITS = 38; static int s_digits; // clang-format off static string _makeNumberFormat(mode_enum mode, int digits) { stringstream format; - format<<"%."<& value_, int reb = 10, int imb = 10) : object(cmd_complex), reBase(reb), imBase(imb) { + explicit ocomplex(complex& value_, int reb = 10, int imb = 10) + : object(cmd_complex), reBase(reb), imBase(imb) { value = value_; } - ocomplex(mpreal& re_, mpreal& im_, int reb = 10, int imb = 10) : object(cmd_complex), reBase(reb), imBase(imb) { + explicit ocomplex(mpreal& re_, mpreal& im_, int reb = 10, int imb = 10) + : object(cmd_complex), reBase(reb), imBase(imb) { value.real(re_); value.imag(im_); } @@ -127,7 +153,7 @@ struct ocomplex : object { /// struct ostring : object { ostring() : object(cmd_string) {} - ostring(const string& value_) : object(cmd_string), value(value_) {} + explicit ostring(const string& value_) : object(cmd_string), value(value_) {} virtual object* clone() { return new ostring(value); } virtual string name() { return string("string"); } virtual ostream& show(ostream& out) { return out << "\"" << value << "\""; } @@ -138,7 +164,7 @@ struct ostring : object { /// struct oprogram : object { oprogram() : object(cmd_program) {} - oprogram(const string& value_) : object(cmd_program), value(value_) {} + explicit oprogram(const string& value_) : object(cmd_program), value(value_) {} virtual object* clone() { return new oprogram(value); } virtual string name() { return string("program"); } virtual ostream& show(ostream& out) { return out << "«" << value << "»"; } @@ -148,8 +174,9 @@ struct oprogram : object { /// @brief object symbol /// struct symbol : object { - symbol(bool autoEval_ = true) : object(cmd_symbol), autoEval(autoEval_) {} - symbol(const string& value_, bool autoEval_ = true) : object(cmd_symbol), value(value_), autoEval(autoEval_) {} + explicit symbol(bool autoEval_ = true) : object(cmd_symbol), autoEval(autoEval_) {} + explicit symbol(const string& value_, bool autoEval_ = true) + : object(cmd_symbol), value(value_), autoEval(autoEval_) {} virtual object* clone() { return new symbol(value, autoEval); } virtual string name() { return string("symbol"); } virtual ostream& show(ostream& out) { return out << "'" << value << "'"; } @@ -161,7 +188,7 @@ struct symbol : object { /// struct keyword : object { keyword() : object(cmd_keyword) {} - keyword(program_fn_t fn_, const string& value_) : object(cmd_keyword), fn(fn_), value(value_) {} + explicit keyword(program_fn_t fn_, const string& value_) : object(cmd_keyword), fn(fn_), value(value_) {} virtual object* clone() { return new keyword(fn, value); } virtual string name() { return string("keyword"); } program_fn_t fn; @@ -172,15 +199,15 @@ struct keyword : object { /// struct branch : object { branch() : object(cmd_branch) {} - branch(branch_fn_t fn_, const string& value_) : object(cmd_branch) { + explicit branch(branch_fn_t fn_, const string& value_) : object(cmd_branch) { fn = fn_; - arg1 = (size_t)-1; - arg2 = (size_t)-1; - arg3 = (size_t)-1; + arg1 = static_cast(-1); + arg2 = static_cast(-1); + arg3 = static_cast(-1); arg_bool = 0; value = value_; } - branch(branch& other) : object(cmd_branch) { + explicit branch(branch& other) : object(cmd_branch) { fn = other.fn; arg1 = other.arg1; arg2 = other.arg2; @@ -197,4 +224,4 @@ struct branch : object { string value; }; -#endif +#endif // SRC_OBJECT_HPP_ diff --git a/src/program.cpp b/src/program.cpp index 5ae1757..918b2ab 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" //< language reserved keywords (allowed types are cmd_keyword, cmd_branch or cmd_undef) @@ -201,17 +203,13 @@ vector program::_keywords{ {cmd_keyword, "ticks", &program::rpn_ticks, "system tick in µs"}, }; -/// keywords map for lexer -map program::_keywordsMap; - /// autocompletion vector for linenoise autocompletion -vector program::_autocompletionWords; - vector& program::getAutocompletionWords() { - if (_autocompletionWords.empty()) + static vector autocompletionWords; + if (autocompletionWords.empty()) for (auto& kw : _keywords) - if (!kw.name.empty()) _autocompletionWords.push_back(kw.name); - return _autocompletionWords; + if (!kw.name.empty()) autocompletionWords.push_back(kw.name); + return autocompletionWords; } /// @brief run a program on a stack and a heap @@ -236,18 +234,18 @@ ret_value program::run() { } // iterate commands - for (size_t i = 0; (go_out == false) && (interrupt_now == false) && (i < size());) { + for (size_t i = 0; (go_out == false) && (i < size());) { object* o = at(i); switch (o->_type) { // could be an auto-evaluated symbol case cmd_symbol: - auto_rcl((symbol*)o); + auto_rcl(reinterpret_cast(o)); i++; break; // a keyword case cmd_keyword: { - keyword* k = (keyword*)o; + keyword* k = reinterpret_cast(o); // call the matching function (this->*(k->fn))(); switch (_err) { @@ -264,8 +262,7 @@ ret_value program::run() { go_out = true; // test error: make rpn return EXIT_FAILURE - if (_err == ret_test_failed) - ret = ret_test_failed; + if (_err == ret_test_failed) ret = ret_test_failed; // error: show it if (show_error(_err, _err_context) == ret_deadly) @@ -280,13 +277,13 @@ ret_value program::run() { // a branch keyword case cmd_branch: { // call matching function - branch* b = (branch*)o; + branch* b = reinterpret_cast(o); size_t next_cmd = (this->*(b->fn))(*b); switch (next_cmd) { - case step_out: // step out - i++; // meaning 'next command' + case step_out: // step out + i++; // meaning 'next command' break; - case runtime_error: // runtime error + case runtime_error: // runtime error (void)show_error(_err, _err_context); go_out = true; break; @@ -310,34 +307,9 @@ ret_value program::run() { for (object* o : *this) delete o; _local_heap.clear(); - if (interrupt_now) { - cerr << endl << "Interrupted" << endl; - interrupt_now = false; - } - return ret; } -/// @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 -/// @return true the branch name is str_to_compare -/// @return false the branch name is NOT str_to_compare -/// -bool program::compare_branch(branch* b, const char* str_to_compare, int len) { - if (str_to_compare != nullptr) - return b->value == str_to_compare; - else - return false; -} - /// @brief prepare a program for execution /// this is needed before a program can be run /// inner members of branch or keyword objects are filled by this function @@ -346,6 +318,20 @@ bool program::compare_branch(branch* b, const char* str_to_compare, int len) { /// @return ret_value see this type /// ret_value program::preprocess(void) { + struct if_layout_t { + if_layout_t() + : index_then_or_unti_or_repeat(-1), + index_else(-1), + index_end(-1), + is_do_unti(false), + is_while_repeat(false) {} + int index_if_or_do_or_while; + int index_then_or_unti_or_repeat; + int index_else; + int index_end; + bool is_do_unti; + bool is_while_repeat; + }; // for if-then-else-end vector vlayout; int layout_index = -1; @@ -354,20 +340,20 @@ ret_value program::preprocess(void) { // analyse if-then-else-end branches // analyse start-{next, step} branches - for (int i = 0; i < (int)size(); i++) { - if ((*this)[i]->_type == cmd_branch) { - branch* k = (branch*)(*this)[i]; - if (compare_branch(k, "if", 2)) { + for (size_t i = 0; i < size(); i++) { + if (at(i)->_type == cmd_branch) { + branch* k = reinterpret_cast(at(i)); + if (k->value == "if") { if_layout_t layout; layout.index_if_or_do_or_while = i; vlayout.push_back(layout); layout_index++; - } else if (compare_branch(k, "then", 4)) { - int next = i + 1; - if (next >= (int)size()) next = -1; + } else if (k->value == "then") { + size_t next = i + 1; + if (next >= size()) next = step_out; // nothing after 'then' -> error - if (next == -1) { + if (next == step_out) { // error: show it show_syntax_error("missing end after then"); return ret_syntax; @@ -385,12 +371,12 @@ ret_value program::preprocess(void) { vlayout[layout_index].index_then_or_unti_or_repeat = i; k->arg1 = next; k->arg3 = vlayout[layout_index].index_if_or_do_or_while; - } else if (compare_branch(k, "else", 4)) { - int next = i + 1; - if (next >= (int)size()) next = -1; + } else if (k->value == "else") { + size_t next = i + 1; + if (next >= size()) next = step_out; // nothing after 'else' -> error - if (next == -1) { + if (next == step_out) { // error: show it show_syntax_error("missing end after else"); return ret_syntax; @@ -413,47 +399,47 @@ ret_value program::preprocess(void) { vlayout[layout_index].index_else = i; k->arg1 = next; // fill branch1 (if was false) of 'else' k->arg3 = vlayout[layout_index].index_if_or_do_or_while; - ((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg2 = + reinterpret_cast(at(vlayout[layout_index].index_then_or_unti_or_repeat))->arg2 = next; // fill branch2 (if was false) of 'then' - } else if (compare_branch(k, "start", 5)) + } else if (k->value == "start") { vstartindex.push_back(i); - else if (compare_branch(k, "for", 3)) { + } else if (k->value == "for") { vstartindex.push_back(i); k->arg1 = i + 1; // arg1 points on symbol variable - } else if (compare_branch(k, "next", 4)) { + } else if (k->value == "next") { if (vstartindex.size() == 0) { // error: show it show_syntax_error("missing start or for before next"); return ret_syntax; } k->arg1 = vstartindex[vstartindex.size() - 1]; // 'next' arg1 = 'start' index - ((branch*)(*this)[vstartindex[vstartindex.size() - 1]])->arg2 = + reinterpret_cast(at(vstartindex[vstartindex.size() - 1]))->arg2 = i; // 'for' or 'start' arg2 = 'next' index vstartindex.pop_back(); - } else if (compare_branch(k, "step", 4)) { + } else if (k->value == "step") { if (vstartindex.size() == 0) { // error: show it show_syntax_error("missing start or for before step"); return ret_syntax; } k->arg1 = vstartindex[vstartindex.size() - 1]; // fill 'step' branch1 = 'start' index - ((branch*)(*this)[vstartindex[vstartindex.size() - 1]])->arg2 = + reinterpret_cast(at(vstartindex[vstartindex.size() - 1]))->arg2 = i; // 'for' or 'start' arg2 = 'next' index vstartindex.pop_back(); - } else if (compare_branch(k, "->", 2)) { + } else if (k->value == "->") { k->arg1 = i; // arg1 is '->' command index in program - } else if (compare_branch(k, "do", 2)) { + } else if (k->value == "do") { if_layout_t layout; layout.index_if_or_do_or_while = i; layout.is_do_unti = true; vlayout.push_back(layout); layout_index++; - } else if (compare_branch(k, "until", 4)) { - int next = i + 1; - if (next >= (int)size()) next = -1; + } else if (k->value == "until") { + size_t next = i + 1; + if (next >= size()) next = step_out; // nothing after 'unti' -> error - if (next == -1) { + if (next == step_out) { // error: show it show_syntax_error("missing end"); return ret_syntax; @@ -469,13 +455,13 @@ ret_value program::preprocess(void) { return ret_syntax; } vlayout[layout_index].index_then_or_unti_or_repeat = i; - } else if (compare_branch(k, "while", 4)) { + } else if (k->value == "while") { if_layout_t layout; layout.index_if_or_do_or_while = i; layout.is_while_repeat = true; vlayout.push_back(layout); layout_index++; - } else if (compare_branch(k, "repeat", 5)) { + } else if (k->value == "repeat") { if (layout_index < 0 || !vlayout[layout_index].is_while_repeat) { // error: show it show_syntax_error("missing while"); @@ -487,9 +473,9 @@ ret_value program::preprocess(void) { return ret_syntax; } vlayout[layout_index].index_then_or_unti_or_repeat = i; - } else if (compare_branch(k, "end", 3)) { - int next = i + 1; - if (next >= (int)size()) next = -1; + } else if (k->value == "end") { + size_t next = i + 1; + if (next >= size()) next = step_out; if (layout_index < 0) { // error: show it @@ -529,7 +515,8 @@ ret_value program::preprocess(void) { } // fill 'repeat' arg1 with 'end+1' - ((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg1 = i + 1; + reinterpret_cast(at(vlayout[layout_index].index_then_or_unti_or_repeat))->arg1 = + i + 1; layout_index--; } else { // this end closes an if..then..(else) @@ -538,14 +525,15 @@ ret_value program::preprocess(void) { show_syntax_error("duplicate end"); return ret_syntax; } - if (vlayout[layout_index].index_else != -1) + if (vlayout[layout_index].index_else != -1) { // fill 'end' branch of 'else' - ((branch*)(*this)[vlayout[layout_index].index_else])->arg2 = i; - else { + reinterpret_cast(at(vlayout[layout_index].index_else))->arg2 = i; + } else { // fill 'end' branch of 'then' - if (vlayout[layout_index].index_then_or_unti_or_repeat != -1) - ((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg2 = i; - else { + if (vlayout[layout_index].index_then_or_unti_or_repeat != -1) { + reinterpret_cast(at(vlayout[layout_index].index_then_or_unti_or_repeat)) + ->arg2 = i; + } else { // error: show it show_syntax_error("missing then"); return ret_syntax; @@ -577,17 +565,18 @@ ret_value program::preprocess(void) { /// @return ret_value see this type /// ret_value program::parse(string& entry) { + static map keywordsMap; vector elements; vector errors; ret_value ret = ret_ok; // prepare map for finding reserved keywords - if (_keywordsMap.empty()) + if (keywordsMap.empty()) for (auto& kw : _keywords) - if (!kw.name.empty()) _keywordsMap[kw.name] = {kw.type, kw.fn}; + if (!kw.name.empty()) keywordsMap[kw.name] = {kw.type, kw.fn}; // separate the entry string - if (lexer(entry, _keywordsMap, elements, errors)) { + if (lexer(entry, keywordsMap, elements, errors)) { // make objects from parsed elements for (Lexer::SynElement& element : elements) { switch (element.type) { @@ -619,8 +608,9 @@ ret_value program::parse(string& entry) { if (element.re != nullptr) delete element.re; if (element.im != nullptr) delete element.im; } - } else + } else { for (SynError& err : errors) show_syntax_error(err.err.c_str()); + } return ret; } @@ -638,7 +628,7 @@ ret_value program::show_error() { "bad value", "test failed"}; // clang-format on // show last recorded error - if ((size_t)_err < errorStrings.size()) + if (static_cast(_err) < errorStrings.size()) cerr << _err_context << ": error " << _err << ": " << errorStrings[_err] << endl; else cerr << _err_context << " (unknown error code)" << endl; @@ -701,26 +691,26 @@ 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 /// -void program::show_stack(rpnstack& st, bool show_separator) { - if (st.size() == 1) - cout << st[0] << endl; - else - for (int i = st.size() - 1; i >= 0; i--) { +void program::show_stack(bool show_separator) { + if (_stack.size() == 1) { + cout << _stack[0] << endl; + } else { + for (int i = _stack.size() - 1; i >= 0; i--) { if (show_separator) cout << i + 1 << "> "; - cout << st[i] << endl; + cout << _stack[i] << endl; } + } } /// @brief apply default precision mode and digits /// void program::apply_default() { // default float precision, float mode - number::s_mode = DEFAULT_MODE; - number::s_digits = DEFAULT_DECIMAL_DIGITS; - mpreal::set_default_prec(MPFR_DEFAULT_PREC_BITS); + number::s_mode = number::DEFAULT_MODE; + number::s_digits = number::DEFAULT_DECIMAL_DIGITS; + mpreal::set_default_prec(number::MPFR_DEFAULT_PREC_BITS); static mp_rnd_t def_rnd = mpreal::get_default_rnd(); mpreal::set_default_rnd(def_rnd); diff --git a/src/program.hpp b/src/program.hpp index 02b5eb9..3571bbf 100644 --- a/src/program.hpp +++ b/src/program.hpp @@ -1,40 +1,27 @@ -#ifndef PROGRAM_HPP -#define PROGRAM_HPP +// Copyright (c) 2014-2022 Louis Rubet + +#ifndef SRC_PROGRAM_HPP_ +#define SRC_PROGRAM_HPP_ // std c++ +#include #include +#include #include using namespace std; -#define MPFR_USE_NO_MACRO -#include #include using namespace mpfr; // internal includes -#include "constant.h" #include "lexer.hpp" #include "object.hpp" #include "stack.hpp" -//< convinient structure to preprocess a program -struct if_layout_t { - if_layout_t() - : index_then_or_unti_or_repeat(-1), index_else(-1), index_end(-1), is_do_unti(false), is_while_repeat(false) {} - int index_if_or_do_or_while; - int index_then_or_unti_or_repeat; - int index_else; - int index_end; - bool is_do_unti; - bool is_while_repeat; -}; - //< program class: the class containing a string parser, all the programs keywords, a stack for running the program class program : public deque, public Lexer { - public: - program(rpnstack& stk, heap& hp, program* parent = nullptr) : _stack(stk), _heap(hp), _parent(parent) { - interrupt_now = false; - } + public: + program(rpnstack& stk, heap& hp, program* parent = nullptr) : _stack(stk), _heap(hp), _parent(parent) {} virtual ~program() { _local_heap.clear(); clear(); @@ -47,7 +34,6 @@ class program : public deque, public Lexer { // running ret_value run(); void stop(); - bool compare_branch(branch* b, const char* str_to_compare, int len); ret_value preprocess(void); ret_value show_error(); @@ -56,15 +42,13 @@ class program : public deque, public Lexer { void show_syntax_error(const char* context); ret_value get_err(void); - static void show_stack(rpnstack& st, bool show_separator = true); + void show_stack(bool show_separator = true); static void apply_default(); static vector& getAutocompletionWords(); - private: - bool interrupt_now; - + private: // current error and its context ret_value _err; string _err_context; @@ -81,9 +65,7 @@ class program : public deque, public Lexer { // parent prog for inheriting heaps program* _parent; - int stack_size() { return _stack.size(); } - - private: + private: // keywords struct keyword_t { cmd_type_t type; @@ -92,8 +74,6 @@ class program : public deque, public Lexer { string comment; }; static vector _keywords; - static map _keywordsMap; - static vector _autocompletionWords; // keywords implementation //// @@ -113,7 +93,7 @@ class program : public deque, public Lexer { size_t rpn_for(branch& myobj); size_t rpn_next(branch& myobj); size_t rpn_step(branch& myobj); - enum { step_out = (size_t)-1, runtime_error = (size_t)-2 }; + enum { step_out = static_cast(-1), runtime_error = static_cast(-2) }; // complex void rpn_re(); @@ -233,14 +213,11 @@ class program : public deque, public Lexer { void rpn_strsub(); // test-core - void test_get_stack(string& stack_is, rpnstack& stk); - void test_show_result(string title, int tests, int tests_failed, int steps, int steps_failed); void rpn_test(); void test(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps, int& total_steps_failed); // test - long cmp_strings_on_stack_top(); void rpn_sup(void); void rpn_sup_eq(void); void rpn_inf(void); @@ -270,26 +247,45 @@ class program : public deque, public Lexer { void rpn_ticks(); }; -// clang-format off - // convenience macros for rpn_xx function // carefull : some of these macros modify program flow -#define setErrorContext(err) do { _err = (err); _err_context = __FUNCTION__; } while (0) -#define MIN_ARGUMENTS(num) do { \ - if (stack_size() < (num)) { setErrorContext(ret_missing_operand); return; } \ +#define setErrorContext(err) \ + do { \ + _err = (err); \ + _err_context = __FUNCTION__; \ } while (0) -#define MIN_ARGUMENTS_RET(num, ret) do { \ - if (stack_size() < (num)) { setErrorContext(ret_missing_operand); return (ret); } \ +#define MIN_ARGUMENTS(num) \ + do { \ + if ((num) >= 0 && _stack.size() < (num)) { \ + setErrorContext(ret_missing_operand); \ + return; \ + } \ } while (0) -#define ARG_MUST_BE_OF_TYPE(num, type) do { \ - if (_stack.at(num)->_type != (type)) { setErrorContext(ret_bad_operand_type); return; } \ +#define MIN_ARGUMENTS_RET(num, ret) \ + do { \ + if ((num) >= 0 && _stack.size() < (num)) { \ + setErrorContext(ret_missing_operand); \ + return (ret); \ + } \ } while (0) -#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) do { \ - if (_stack.at(num)->_type != (type)) { setErrorContext(ret_bad_operand_type); return (ret); } \ +#define ARG_MUST_BE_OF_TYPE(num, type) \ + do { \ + if ((num) >= 0 && _stack.at(num)->_type != (type)) { \ + setErrorContext(ret_bad_operand_type); \ + return; \ + } \ } while (0) -#endif +#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) \ + do { \ + if ((num) >= 0 && _stack.at(num)->_type != (type)) { \ + setErrorContext(ret_bad_operand_type); \ + return (ret); \ + } \ + } while (0) + +#endif // SRC_PROGRAM_HPP_ diff --git a/src/rpn-branch.cpp b/src/rpn-branch.cpp index d9c42e0..182cc03 100644 --- a/src/rpn-branch.cpp +++ b/src/rpn-branch.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief if keyword (branch) implementation @@ -38,7 +40,7 @@ size_t program::rpn_then(branch& myobj) { setErrorContext(ret_missing_operand); return runtime_error; } - if_cmd = (branch*)at(myobj.arg3); + if_cmd = reinterpret_cast(at(myobj.arg3)); if (if_cmd->arg1 == 1) return myobj.arg1; else @@ -63,7 +65,7 @@ size_t program::rpn_else(branch& myobj) { setErrorContext(ret_missing_operand); return runtime_error; } - if_cmd = (branch*)at(myobj.arg3); + if_cmd = reinterpret_cast(at(myobj.arg3)); if (if_cmd->arg1 == 1) return myobj.arg2; else @@ -89,10 +91,10 @@ size_t program::rpn_end(branch& myobj) { // check arg if (_stack.value(0) == 0) ret = myobj.arg1; _stack.pop(); - } - // arg2 = index of while+1 in case of while..repeat..end - else if (myobj.arg2 != step_out) + } else if (myobj.arg2 != step_out) { + // arg2 = index of while+1 in case of while..repeat..end ret = myobj.arg2; + } return ret; } @@ -134,11 +136,10 @@ void program::rpn_ift(void) { // check ift arg // arg is true if number != 0 or if is nan or +/-inf - if (_stack.value(1) != 0) { + if (_stack.value(1) != 0) _stack.erase(1); - } else { - _stack.pop_front(2); - } + else + _stack.erase(0, 2); } /// @brief ifte keyword (branch) implementation @@ -212,7 +213,7 @@ size_t program::rpn_start(branch& myobj) { // loop boundaries myobj.firstIndex = _stack.value(1); myobj.lastIndex = _stack.value(0); - _stack.pop_front(2); + _stack.erase(0, 2); // test value if (myobj.firstIndex > myobj.lastIndex) @@ -243,19 +244,19 @@ size_t program::rpn_for(branch& myobj) { setErrorContext(ret_missing_operand); return runtime_error; } - sym = (symbol*)at(myobj.arg1); // arg1 = loop variable index + sym = reinterpret_cast(at(myobj.arg1)); // arg1 = loop variable index // loop boundaries myobj.firstIndex = _stack.value(1); myobj.lastIndex = _stack.value(0); // test value - if (myobj.firstIndex > myobj.lastIndex) + if (myobj.firstIndex > myobj.lastIndex) { // last boundary lower than first boundary // -> next command shall be after 'next' // arg2 holds index of 'next' ret = myobj.arg2 + 1; - else { + } else { // store symbol with first value auto it = _local_heap.find(sym->value); if (it != _local_heap.end()) { @@ -266,7 +267,7 @@ size_t program::rpn_for(branch& myobj) { ret = myobj.arg1 + 1; } - _stack.pop_front(2); + _stack.erase(0, 2); return ret; } @@ -286,7 +287,7 @@ size_t program::rpn_next(branch& myobj) { setErrorContext(ret_missing_operand); return runtime_error; } - start_or_for = (branch*)at(myobj.arg1); + start_or_for = reinterpret_cast(at(myobj.arg1)); if (!myobj.arg_bool) { myobj.arg_bool = true; myobj.firstIndex = start_or_for->firstIndex; @@ -304,10 +305,10 @@ size_t program::rpn_next(branch& myobj) { setErrorContext(ret_missing_operand); return runtime_error; } - var = (symbol*)at(start_or_for->arg1); + var = reinterpret_cast(at(start_or_for->arg1)); // store symbol variable (asserted existing in the local heap) - ((number*)_local_heap[var->value])->value = myobj.firstIndex; + reinterpret_cast(_local_heap[var->value])->value = myobj.firstIndex; } // test value @@ -340,9 +341,9 @@ size_t program::rpn_step(branch& myobj) { _stack.pop(); // end of loop if step is negative or zero - if (step <= 0) + if (step <= 0) { ret = step_out; - else { + } else { // arg1 = loop variable index // firstIndex = current count branch* start_or_for; @@ -350,7 +351,7 @@ size_t program::rpn_step(branch& myobj) { setErrorContext(ret_missing_operand); return runtime_error; } - start_or_for = (branch*)at(myobj.arg1); + start_or_for = reinterpret_cast(at(myobj.arg1)); if (!myobj.arg_bool) { myobj.arg_bool = true; myobj.firstIndex = start_or_for->firstIndex; @@ -369,9 +370,9 @@ size_t program::rpn_step(branch& myobj) { setErrorContext(ret_missing_operand); return runtime_error; } - var = (symbol*)at(start_or_for->arg1); + var = reinterpret_cast(at(start_or_for->arg1)); // increase symbol variable - ((number*)_local_heap[var->value])->value = myobj.firstIndex; + reinterpret_cast(_local_heap[var->value])->value = myobj.firstIndex; } // test loop value is out of range diff --git a/src/rpn-complex.cpp b/src/rpn-complex.cpp index 3444fbc..ca94145 100644 --- a/src/rpn-complex.cpp +++ b/src/rpn-complex.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief re keyword implementation diff --git a/src/rpn-general.cpp b/src/rpn-general.cpp index 962b91d..cd04390 100644 --- a/src/rpn-general.cpp +++ b/src/rpn-general.cpp @@ -1,34 +1,39 @@ -#include -#include "linenoise.h" +// Copyright (c) 2014-2022 Louis Rubet + +#include +#include + +#include "linenoise.h" +using namespace std; -#include "escape.h" #include "program.hpp" #include "version.h" // description +static const string ATTR_BOLD = "\33[1m"; +static const string ATTR_OFF = "\33[0m"; + #define XSTR(a) STR(a) #define STR(a) #a -static const string _description{ - ATTR_BOLD "R" ATTR_OFF "everse " ATTR_BOLD "P" ATTR_OFF "olish " ATTR_BOLD "N" ATTR_OFF - "otation language\n\n" - "using " ATTR_BOLD "GMP" ATTR_OFF " v" XSTR(__GNU_MP_VERSION) "." XSTR(__GNU_MP_VERSION_MINOR) "." XSTR( - __GNU_MP_VERSION_PATCHLEVEL) " under GNU LGPL\n" ATTR_BOLD "MPFR" ATTR_OFF " v" MPFR_VERSION_STRING - " under GNU LGPL\n" - "and " ATTR_BOLD "linenoise-ng" ATTR_OFF " v" LINENOISE_VERSION - " under BSD\n"}; +static const string _description{ATTR_BOLD + "R" + ATTR_OFF + "everse " + ATTR_BOLD + "P" + ATTR_OFF + "olish " + + ATTR_BOLD + "N" + ATTR_OFF + "otation language\n\nusing " + ATTR_BOLD + "GMP" + + ATTR_OFF + + " v" XSTR(__GNU_MP_VERSION) "." XSTR(__GNU_MP_VERSION_MINOR) "." XSTR( + __GNU_MP_VERSION_PATCHLEVEL) " under GNU LGPL\n" + + ATTR_BOLD + "MPFR" + ATTR_OFF + " v" MPFR_VERSION_STRING " under GNU LGPL\nand " + + ATTR_BOLD + "linenoise-ng" + ATTR_OFF + " v" LINENOISE_VERSION " under BSD\n"}; // syntax -static const string _syntax{ATTR_BOLD "Syntax" ATTR_OFF - ": rpn [command]\n" - "with optional command = list of commands"}; +static const string _syntax{ATTR_BOLD + "Syntax" + ATTR_OFF + + ": rpn [command]\nwith optional command = list of commands"}; static const map _mpfr_round{{"nearest (even)", MPFR_RNDN}, - {"toward zero", MPFR_RNDZ}, - {"toward +inf", MPFR_RNDU}, - {"toward -inf", MPFR_RNDD}, - {"away from zero", MPFR_RNDA}, - {"faithful rounding", MPFR_RNDF}, - {"nearest (away from zero)", MPFR_RNDNA}}; + {"toward zero", MPFR_RNDZ}, + {"toward +inf", MPFR_RNDU}, + {"toward -inf", MPFR_RNDD}, + {"away from zero", MPFR_RNDA}, + {"faithful rounding", MPFR_RNDF}, + {"nearest (away from zero)", MPFR_RNDNA}}; /// @brief nop keyword implementation /// @@ -84,7 +89,7 @@ void program::rpn_help() { // bits precision, decimal digits and rounding mode cout << " with " << number::s_digits << " digits after the decimal point" << endl; - cout << "Current floating point precision is " << (int)mpreal::get_default_prec() << " bits" << endl; + cout << "Current floating point precision is " << static_cast(mpreal::get_default_prec()) << " bits" << endl; for (auto& rn : _mpfr_round) if (rn.second == mpreal::get_default_rnd()) { cout << "Current rounding mode is '" << rn.first << '\'' << endl; @@ -93,23 +98,14 @@ void program::rpn_help() { cout << endl << endl; } -/// @brief whether a precision is in the precision min/max +/// @brief whether a printed precision is in the precision min/max /// -/// @param precision the precision in bits +/// @param precision the precision in digits /// @return true the precision is good /// @return false the precision is not good /// -static bool check_decimal_digits(double precision) { - bool ret = true; - - // MPFR_PREC_MAX mpfr_prec_t depends on _MPFR_PREC_FORMAT macro (see mpfr.h) - // this could not exceed 63 bits max (0x7FFFFFFFFFFFFFFF) - double prec_max = (double)MPFR_PREC_MAX; - double prec_min = 0.0; - - if (precision < prec_min || precision > prec_max) ret = false; - - return ret; +static bool check_decimal_digits(int precision) { + return precision >= 0; } /// @brief std keyword implementation @@ -118,15 +114,16 @@ void program::rpn_std() { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - double digits = double(_stack.value(0)); + int digits = static_cast(_stack.value(0).toLong()); if (check_decimal_digits(digits)) { // set mode, decimal digits and print format number::s_mode = number::std; - number::s_digits = (int)digits; + number::s_digits = digits; _stack.pop(); - } else + } else { setErrorContext(ret_out_of_range); + } } /// @brief fix keyword implementation @@ -135,15 +132,16 @@ void program::rpn_fix() { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - double digits = double(_stack.value(0)); + int digits = static_cast(_stack.value(0).toLong()); if (check_decimal_digits(digits)) { // set mode, decimal digits and print format number::s_mode = number::fix; - number::s_digits = (int)digits; + number::s_digits = digits; _stack.pop(); - } else + } else { setErrorContext(ret_out_of_range); + } } /// @brief sci keyword implementation @@ -152,15 +150,16 @@ void program::rpn_sci() { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - double digits = double(_stack.value(0)); + int digits = static_cast(_stack.value(0).toLong()); if (check_decimal_digits(digits)) { // set mode, decimal digits and print format number::s_mode = number::sci; - number::s_digits = (int)digits; + number::s_digits = digits; _stack.pop(); - } else + } else { setErrorContext(ret_out_of_range); + } } /// @brief _version keyword implementation @@ -203,8 +202,8 @@ void program::rpn_precision() { ARG_MUST_BE_OF_TYPE(0, cmd_number); // set precision - unsigned long prec = _stack.value(0).toULong(); - if (prec >= (unsigned long)MPFR_PREC_MIN && prec <= (unsigned long)MPFR_PREC_MAX) { + int prec = static_cast(_stack.value(0).toLong()); + if (prec >= MPFR_PREC_MIN && prec <= MPFR_PREC_MAX) { mpreal::set_default_prec(prec); // modify digits seen by user if std mode @@ -213,8 +212,9 @@ void program::rpn_precision() { number::s_digits = bits2digits(mpreal::get_default_prec()); } _stack.pop(); - } else + } else { setErrorContext(ret_out_of_range); + } } /// @brief round keyword implementation diff --git a/src/rpn-logs.cpp b/src/rpn-logs.cpp index 0a45f92..0ee199b 100644 --- a/src/rpn-logs.cpp +++ b/src/rpn-logs.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief e keyword implementation diff --git a/src/rpn-program.cpp b/src/rpn-program.cpp index f3196a4..d6ea074 100644 --- a/src/rpn-program.cpp +++ b/src/rpn-program.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief find variable by its name in local heap, successive parents heaps, global heap @@ -11,9 +13,9 @@ bool program::find_variable(string& variable, object*& obj) { bool found = false; program* parent = _parent; - if (_local_heap.get(variable, obj)) + if (_local_heap.get(variable, obj)) { found = true; - else { + } else { while (parent != nullptr) { if (parent->_local_heap.get(variable, obj)) { found = true; @@ -52,15 +54,17 @@ void program::rpn_eval(void) { // else recall this variable (i.e. stack its content) _stack.push_front(obj); } - } else + } else { setErrorContext(ret_unknown_variable); + } } else if (_stack.type(0) == cmd_program) { // eval a program prog_text = _stack.value(0); _stack.pop(); run_prog = true; - } else + } else { setErrorContext(ret_bad_operand_type); + } // run prog if any if (run_prog) { @@ -92,14 +96,14 @@ int program::rpn_inprog(branch& myobj) { // find next oprogram object for (unsigned int i = myobj.arg1 + 1; i < size(); i++) { // count symbol - if (at(i)->_type == cmd_symbol) count_symbols++; - // stop if prog - else if (at(i)->_type == cmd_program) { + if (at(i)->_type == cmd_symbol) { + count_symbols++; + } else if (at(i)->_type == cmd_program) { + // stop if prog prog_found = true; break; - } - // found something other than symbol - else { + } else { + // found something other than symbol setErrorContext(ret_bad_operand_type); show_error(_err, context); return -1; @@ -121,7 +125,7 @@ int program::rpn_inprog(branch& myobj) { } // check symbols number vs stack size - if (stack_size() < count_symbols) { + if (_stack.size() < count_symbols) { setErrorContext(ret_missing_operand); show_error(_err, context); return -1; @@ -129,12 +133,12 @@ int program::rpn_inprog(branch& myobj) { // load variables for (unsigned int i = myobj.arg1 + count_symbols; i > myobj.arg1; i--) { - _local_heap[string(((symbol*)at(i))->value)] = _stack.at(0)->clone(); - _stack.pop_front(); + _local_heap[reinterpret_cast(at(i))->value] = _stack.at(0)->clone(); + _stack.pop(); } // run the program - string entry(((oprogram*)at(myobj.arg1 + count_symbols + 1))->value); + string& entry = reinterpret_cast(at(myobj.arg1 + count_symbols + 1))->value; program prog(_stack, _heap, this); // make the program from entry diff --git a/src/rpn-real.cpp b/src/rpn-real.cpp index ad618a0..471046e 100644 --- a/src/rpn-real.cpp +++ b/src/rpn-real.cpp @@ -1,131 +1,102 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief + keyword implementation /// void program::rpn_plus() { MIN_ARGUMENTS(2); - - // strings if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { _stack.value(1) += _stack.value(0); _stack.pop(); - } - // numbers - else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { + } else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.value(1) += _stack.value(0); _stack.pop(); - } - // complexes - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { _stack.value(1) += _stack.value(0); _stack.pop(); - } - // complex+number - else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { _stack.value(1) += _stack.value(0); _stack.pop(); - } - // number+complex - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { rpn_swap(); _stack.value(1) += _stack.value(0); _stack.pop(); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief - keyword implementation /// void program::rpn_minus() { MIN_ARGUMENTS(2); - - // numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.value(1) -= _stack.value(0); _stack.pop(); - } - // complexes - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { _stack.value(1) -= _stack.value(0); _stack.pop(); - } - // subbing complex-number - else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { _stack.value(1) -= _stack.value(0); _stack.pop(); - } - // number-complex - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { rpn_swap(); _stack.value(1) = _stack.value(0) - _stack.value(1); _stack.pop(); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief * keyword implementation /// void program::rpn_mul() { MIN_ARGUMENTS(2); - - // mutiplying numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.value(1) *= _stack.value(0); _stack.pop(); - } - // mutiplying complexes - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { _stack.value(1) *= _stack.value(0); _stack.pop(); - } - // mutiplying complex*number - else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { _stack.value(1) *= _stack.value(0); _stack.pop(); - } - // mutiplying number*complex - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { rpn_swap(); _stack.value(1) *= _stack.value(0); _stack.pop(); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief / keyword implementation /// void program::rpn_div() { MIN_ARGUMENTS(2); - - // dividing numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.value(1) /= _stack.value(0); _stack.pop(); - } - // dividing complexes - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { _stack.value(1) /= _stack.value(0); _stack.pop(); - } - // dividing complex/number - else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) { _stack.value(1) /= _stack.value(0); _stack.pop(); - } - // dividing number/complex - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) { rpn_swap(); _stack.value(1) = _stack.value(0) / _stack.value(1); _stack.pop(); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief neg keyword implementation /// void program::rpn_neg() { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = -_stack.value(0); else if (_stack.type(0) == cmd_complex) @@ -138,11 +109,10 @@ void program::rpn_neg() { /// void program::rpn_inv() { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = 1 / _stack.value(0); else if (_stack.type(0) == cmd_complex) - _stack.value(0) = mpreal{1} / _stack.value(0); + _stack.value(0) = mpreal(1) / _stack.value(0); else setErrorContext(ret_bad_operand_type); } @@ -171,8 +141,9 @@ void program::rpn_power() { rpn_swap(); _stack.value(1) = pow(_stack.value(0), _stack.value(1)); _stack.pop(); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief sqrt keyword implementation @@ -185,53 +156,58 @@ void program::rpn_squareroot() { } else { // negative number -> square root is complex mpreal zero; - _stack.push(new ocomplex(_stack.value(0), zero, _stack.obj(0).base)); // TODO manage new errors + _stack.push(new ocomplex(_stack.value(0), zero, + _stack.obj(0).base)); // TODO(louis) manage new errors _stack.value(0) = sqrt(_stack.value(0)); _stack.erase(1); } - } else if (_stack.type(0) == cmd_complex) + } else if (_stack.type(0) == cmd_complex) { _stack.value(0) = sqrt(_stack.value(0)); - else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief hex keyword implementation /// void program::rpn_hex() { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) + if (_stack.type(0) == cmd_number) { _stack.obj(0).base = 16; - else if (_stack.type(0) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex) { _stack.obj(0).reBase = 16; _stack.obj(0).imBase = 16; - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief bin keyword implementation /// void program::rpn_bin() { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) + if (_stack.type(0) == cmd_number) { _stack.obj(0).base = 2; - else if (_stack.type(0) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex) { _stack.obj(0).reBase = 2; _stack.obj(0).imBase = 2; - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief dec keyword implementation /// void program::rpn_dec() { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) + if (_stack.type(0) == cmd_number) { _stack.obj(0).base = 10; - else if (_stack.type(0) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex) { _stack.obj(0).reBase = 10; _stack.obj(0).imBase = 10; - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief base keyword implementation @@ -239,19 +215,21 @@ void program::rpn_dec() { void program::rpn_base() { MIN_ARGUMENTS(2); if (_stack.type(1) == cmd_number || _stack.type(1) == cmd_complex) { - int base = (int)_stack.value(0).toLong(); + int base = static_cast(_stack.value(0).toLong()); _stack.pop(); - if (base >= BASE_MIN && base <= BASE_MAX) { - if (_stack.type(0) == cmd_number) + if (base >= 2 && base <= 62) { + if (_stack.type(0) == cmd_number) { _stack.obj(0).base = base; - else { + } else { _stack.obj(0).reBase = base; _stack.obj(0).imBase = base; } - } else + } else { setErrorContext(ret_out_of_range); - } else + } + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief % (purcent) keyword implementation @@ -300,13 +278,14 @@ void program::rpn_modulo() { /// void program::rpn_abs() { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) + if (_stack.type(0) == cmd_number) { _stack.value(0) = abs(_stack.value(0)); - else if (_stack.type(0) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex) { _stack.push(new number(abs(_stack.value(0)))); _stack.erase(1); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief fact (factorial) keyword implementation diff --git a/src/rpn-stack.cpp b/src/rpn-stack.cpp index fc142a7..646a845 100644 --- a/src/rpn-stack.cpp +++ b/src/rpn-stack.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief swap keyword implementation @@ -20,7 +22,7 @@ void program::rpn_drop(void) { /// void program::rpn_drop2(void) { MIN_ARGUMENTS(2); - _stack.pop_front(2); + _stack.erase(0, 2); } /// @brief dropn keyword implementation @@ -29,7 +31,7 @@ void program::rpn_dropn(void) { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - int args = (int)_stack.value(0).toLong(); + int args = static_cast(_stack.value(0).toLong()); MIN_ARGUMENTS(args + 1); _stack.erase(0, args + 1); } @@ -42,7 +44,7 @@ void program::rpn_erase(void) { _stack.erase(0, _stack.size()); } /// void program::rpn_dup(void) { MIN_ARGUMENTS(1); - rpnstack::copy_and_push_front(_stack, 0, _stack); + _stack.push_front(_stack.at(0)->clone()); } /// @brief dupn keyword implementation @@ -51,19 +53,19 @@ void program::rpn_dupn(void) { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - int args = (int)((number*)_stack.front())->value.toLong(); + int args = static_cast(_stack.value(0).toLong()); _stack.pop(); MIN_ARGUMENTS(args); - for (int i = 0; i < args; i++) rpnstack::copy_and_push_front(_stack, args - 1, _stack); + for (int i = 0; i < args; i++) _stack.push_front(_stack.at(args - 1)->clone()); } /// @brief dup2 keyword implementation /// void program::rpn_dup2(void) { MIN_ARGUMENTS(2); - rpnstack::copy_and_push_front(_stack, 1, _stack); - rpnstack::copy_and_push_front(_stack, 1, _stack); + _stack.push_front(_stack.at(1)->clone()); + _stack.push_front(_stack.at(1)->clone()); } /// @brief pick keyword implementation @@ -72,7 +74,7 @@ void program::rpn_pick(void) { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - unsigned int to_pick = (unsigned int)_stack.value(0); + int to_pick = static_cast(_stack.value(0).toLong()); _stack.pop(); // treat stack depth errors @@ -81,7 +83,7 @@ void program::rpn_pick(void) { return; } - rpnstack::copy_and_push_front(_stack, to_pick - 1, _stack); + _stack.push_front(_stack.at(to_pick - 1)->clone()); } /// @brief rot keyword implementation @@ -103,7 +105,7 @@ void program::rpn_roll(void) { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - size_t args = (int)((number*)_stack.front())->value; + int args = static_cast(_stack.value(0).toLong()); _stack.pop(); MIN_ARGUMENTS(args); @@ -118,7 +120,7 @@ void program::rpn_rolld(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_number); - int args = (int)((number*)_stack.front())->value.toLong(); + int args = static_cast(_stack.value(0).toLong()); _stack.pop(); MIN_ARGUMENTS(args); @@ -131,7 +133,5 @@ void program::rpn_rolld(void) { /// void program::rpn_over(void) { MIN_ARGUMENTS(2); - - rpnstack::copy_and_push_front(_stack, 1, _stack); + _stack.push_front(_stack.at(1)->clone()); } - diff --git a/src/rpn-store.cpp b/src/rpn-store.cpp index fac153e..4e9f195 100644 --- a/src/rpn-store.cpp +++ b/src/rpn-store.cpp @@ -1,5 +1,7 @@ -#include "program.hpp" +// Copyright (c) 2014-2022 Louis Rubet + #include "input.hpp" +#include "program.hpp" /// @brief sto keyword implementation /// @@ -14,7 +16,7 @@ void program::rpn_sto(void) { _heap.erase(it); } _heap[_stack.value(0)] = _stack.at(1)->clone(); - _stack.pop_front(2); + _stack.erase(0, 2); } /// @brief sto+ keyword implementation @@ -27,7 +29,7 @@ void program::rpn_stoadd(void) { return; } rpn_dup(); - rpn_rcl(); // TODO is rcl the good one? it will recall local variables too + rpn_rcl(); // TODO(louis) is rcl the good one? it will recall local variables too rpn_rot(); rpn_plus(); rpn_swap(); @@ -129,10 +131,11 @@ void program::rpn_rcl(void) { // mind the order of heaps if (find_variable(variable, obj)) { - (void)_stack.pop_front(); + (void)_stack.pop(); _stack.push_front(obj->clone()); - } else + } else { setErrorContext(ret_unknown_variable); + } } /// @brief edit keyword implementation @@ -163,10 +166,12 @@ void program::auto_rcl(symbol* symb) { if (find_variable(variable, obj)) { _stack.push_front(obj->clone()); if (obj->_type == cmd_program) rpn_eval(); - } else + } else { _stack.push_front(symb->clone()); - } else + } + } else { _stack.push_front(symb->clone()); + } } /// @brief purge keyword implementation @@ -179,8 +184,9 @@ void program::rpn_purge(void) { if (i != _heap.end()) { delete i->second; _heap.erase(i); - } else + } else { setErrorContext(ret_unknown_variable); + } _stack.pop(); } @@ -190,33 +196,28 @@ void program::rpn_vars(void) { object* obj; program* parent = _parent; string name; + int index = 1; // heap variables - for (int i = 0; i < (int)_heap.size(); i++) { - (void)_heap.get_by_index(i, name, obj); - cout<<"var "<name()<<", value "; - obj->show(cout); - cout<name() << ", value "; + i.second->show(cout) << endl; + } + + // local variables + for (auto i : _local_heap) { + cout << "var " << index++ << ": name '" << i.first << "', type " << i.second->name() << ", value "; + i.second->show(cout) << endl; } // parents local variables while (parent != nullptr) { - for (int i = 0; i < (int)parent->_local_heap.size(); i++) { - (void)parent->_local_heap.get_by_index(i, name, obj); - cout<<"var "<name()<<", value "; - obj->show(cout); - cout<_local_heap) { + cout << "parent var " << index++ << ": name '" << i.first << "', type " << i.second->name() << ", value "; + obj->show(cout) << endl; } parent = parent->_parent; } - - // local variables - for (int i = 0; i < (int)_local_heap.size(); i++) { - (void)_local_heap.get_by_index(i, name, obj); - cout<<"var "<name()<<", value "; - obj->show(cout); - cout< #include "program.hpp" @@ -37,7 +39,7 @@ void program::rpn_strout() { void program::rpn_chr() { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - char the_chr = (char)(int)_stack.value(0); + char the_chr = static_cast(_stack.value(0).toLong()); _stack.pop(); if (the_chr < 32 || the_chr > 126) the_chr = '.'; _stack.push_front(new ostring(string(1, the_chr))); @@ -72,7 +74,7 @@ void program::rpn_strpos() { ARG_MUST_BE_OF_TYPE(1, cmd_string); size_t pos = _stack.value(1).find(_stack.value(0)) + 1; - _stack.pop_front(2); + _stack.erase(0, 2); _stack.push_front(new number(pos)); } @@ -84,8 +86,8 @@ void program::rpn_strsub() { ARG_MUST_BE_OF_TYPE(1, cmd_number); ARG_MUST_BE_OF_TYPE(2, cmd_string); - size_t first = (size_t)_stack.value(1); - size_t len = (size_t)_stack.value(0) - first + 1; + size_t first = _stack.value(1).toULong(); + size_t len = _stack.value(0).toULong() - first + 1; first--; if (first > _stack.value(2).size()) first = len = 0; diff --git a/src/rpn-test-framework.cpp b/src/rpn-test-framework.cpp index 47f3cc4..60d26b1 100644 --- a/src/rpn-test-framework.cpp +++ b/src/rpn-test-framework.cpp @@ -1,18 +1,25 @@ -#include "escape.h" +// Copyright (c) 2014-2022 Louis Rubet + +#include +using namespace std; + #include "program.hpp" #include "version.h" -static void _findAndReplaceAll(std::string & data, std::string toSearch, std::string replaceStr) -{ +// foreground colors +static const string FG_RED = "\33[31m"; +static const string FG_GREEN = "\33[32m"; +static const string COLOR_OFF = "\33[m"; + +static void _findAndReplaceAll(std::string& data, std::string toSearch, std::string replaceStr) { // Get the first occurrence size_t pos = data.find(toSearch); // Repeat till end is reached - while( pos != std::string::npos) - { + while (pos != std::string::npos) { // Replace this occurrence of Sub String data.replace(pos, toSearch.size(), replaceStr); // Get the next occurrence from the current position - pos =data.find(toSearch, pos + replaceStr.size()); + pos = data.find(toSearch, pos + replaceStr.size()); } } @@ -21,7 +28,7 @@ static void _findAndReplaceAll(std::string & data, std::string toSearch, std::st /// @param stack_is the output string /// @param stk the stack /// -void program::test_get_stack(string& stack_is, rpnstack& stk) { +static void getStackAsString(string& stack_is, rpnstack& stk) { ostringstream st; if (stk.empty()) { stack_is.clear(); @@ -29,7 +36,7 @@ void program::test_get_stack(string& stack_is, rpnstack& stk) { } stk[stk.size() - 1]->show(st); stack_is += st.str(); - for (int i = (int)stk.size() - 2; i >= 0; i--) { + for (int i = static_cast(stk.size()) - 2; i >= 0; i--) { ostringstream st; stk[i]->show(st); stack_is += ", " + st.str(); @@ -44,7 +51,7 @@ void program::test_get_stack(string& stack_is, rpnstack& stk) { /// @param steps steps nb /// @param steps_failed failed steps nb /// -void program::test_show_result(string title, int tests, int tests_failed, int steps, int steps_failed) { +static void testShowResult(string title, int tests, int tests_failed, int steps, int steps_failed) { if (!title.empty()) cout << title << ": "; cout << "run " << tests << " tests: " << tests - tests_failed << " passed, "; if (tests_failed > 0) cout << FG_RED; @@ -73,7 +80,7 @@ void program::rpn_test() { _stack.pop(); cout << endl << "rpn version is " << RPN_VERSION << endl; test(test_filename, total_tests, total_tests_failed, total_steps, total_steps_failed); - test_show_result("\nTotal", total_tests, total_tests_failed, total_steps, total_steps_failed); + testShowResult("\nTotal", total_tests, total_tests_failed, total_steps, total_steps_failed); // notify to caller that test succeeded or not if (total_tests_failed > 0) { @@ -123,11 +130,11 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail getline(test_file, entry); if (entry.empty()) continue; - if (entry.substr(0, 8) == "@include") + if (entry.substr(0, 8) == "@include") { test(entry.substr(9), total_tests, total_tests_failed, total_steps, total_steps_failed); - else if (entry.substr(0, 2) == "# ") + } else if (entry.substr(0, 2) == "# ") { cout << endl << test_filename << ": " << entry.substr(2) << endl; - else if (entry.substr(0, 3) == "## ") { + } else if (entry.substr(0, 3) == "## ") { // indicates the status of previous test if (failed == false && tests > 0) cout << FG_GREEN << " PASSED" << COLOR_OFF << endl; failed = false; @@ -137,9 +144,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail is_first_step = true; is_test_error_shown = false; cout << test_title; - } - // treat "-> stack size should be " - else if (entry.find(stack_size, 0) == 0) { + } else if (entry.find(stack_size, 0) == 0) { // treat "-> stack size should be " // count test and step if (is_first_step) tests++; steps++; @@ -150,7 +155,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail isub.str(entry.substr(stack_size.size())); isub >> size; - if (size != (int)stk.size()) { + if (size != static_cast(stk.size())) { // count fail test and step if (!is_test_error_shown) { cout << FG_RED << " FAIL" << COLOR_OFF << endl; @@ -165,9 +170,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail failed = true; } is_first_step = false; - } - // treat "-> stack should be " - else if (entry.find(stack_value, 0) == 0) { + } else if (entry.find(stack_value, 0) == 0) { // treat "-> stack should be " // count test if (is_first_step) tests++; steps++; @@ -176,7 +179,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail string stack_should_be = entry.substr(stack_value.size()); string stack_is; - test_get_stack(stack_is, stk); + getStackAsString(stack_is, stk); if (stack_is != stack_should_be) { // count fail test and step @@ -193,9 +196,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail failed = true; } is_first_step = false; - } - // treat "-> error should be " - else if (entry.find(cmd_error, 0) == 0) { + } else if (entry.find(cmd_error, 0) == 0) { // treat "-> error should be " // count test if (is_first_step) tests++; steps++; @@ -223,9 +224,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail } else if (entry.find(cmd_exit, 0) == 0) { // forced test end break; - } - // treat unknown "->" - else if (entry.find("->", 0) == 0) { + } else if (entry.find("->", 0) == 0) { // treat unknown "->" // count test if (is_first_step) tests++; steps++; @@ -250,7 +249,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail if (ret == ret_ok) { // run it (void)prog.run(); - last_err = (int)prog.get_err(); + last_err = static_cast(prog.get_err()); } } } @@ -265,13 +264,14 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail // conclusion: show and keep for total if (tests != 0) { - test_show_result("", tests, tests_failed, steps, steps_failed); + testShowResult("", tests, tests_failed, steps, steps_failed); total_tests += tests; total_tests_failed += tests_failed; total_steps += steps; total_steps_failed += steps_failed; } - } else + } else { cerr << "test file '" << test_filename << "' not found" << endl; + } } diff --git a/src/rpn-test.cpp b/src/rpn-test.cpp index 351e890..8b80d52 100644 --- a/src/rpn-test.cpp +++ b/src/rpn-test.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief compared 2 strings on top of the stack @@ -5,11 +7,11 @@ /// @return 0 strings are equal /// @return !0 strings are not equal (see strcmp output) /// -long program::cmp_strings_on_stack_top() { +static int cmpStringsOnStackTop(rpnstack& stk) { // _stack should have 2 strings at level 1 and 2 // this function removes these 2 entries - long res = (long)_stack.value(1).compare(_stack.value(0)); - (void)_stack.pop_front(2); + int res = stk.value(1).compare(stk.value(0)); + stk.erase(0, 2); return res; } @@ -17,112 +19,97 @@ long program::cmp_strings_on_stack_top() { /// void program::rpn_sup(void) { MIN_ARGUMENTS(2); - // numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.push_front(new number(_stack.value(1) > _stack.value(0))); _stack.erase(1, 2); - } - // strings - else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { - _stack.push_front(new number(cmp_strings_on_stack_top() == 1)); + } else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { + _stack.push_front(new number(cmpStringsOnStackTop(_stack) == 1)); _stack.erase(1, 2); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief >= keyword implementation /// void program::rpn_sup_eq(void) { MIN_ARGUMENTS(2); - // numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.push_front(new number(_stack.value(1) >= _stack.value(0))); _stack.erase(1, 2); - } - // strings - else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { - _stack.push_front(new number(cmp_strings_on_stack_top() != -1)); + } else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { + _stack.push_front(new number(cmpStringsOnStackTop(_stack) != -1)); _stack.erase(1, 2); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief < keyword implementation /// void program::rpn_inf(void) { MIN_ARGUMENTS(2); - // numbers + if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.push_front(new number(_stack.value(1) < _stack.value(0))); _stack.erase(1, 2); - } - // strings - else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { - _stack.push_front(new number(cmp_strings_on_stack_top() == -1)); + } else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { + _stack.push_front(new number(cmpStringsOnStackTop(_stack) == -1)); _stack.erase(1, 2); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief <= keyword implementation /// void program::rpn_inf_eq(void) { MIN_ARGUMENTS(2); - // numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.push_front(new number(_stack.value(1) <= _stack.value(0))); _stack.erase(1, 2); - } - // strings - else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { - _stack.push_front(new number(cmp_strings_on_stack_top() != 1)); + } else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { + _stack.push_front(new number(cmpStringsOnStackTop(_stack) != 1)); _stack.erase(1, 2); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief != keyword implementation /// void program::rpn_diff(void) { MIN_ARGUMENTS(2); - // numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.push_front(new number(_stack.value(1) != _stack.value(0))); _stack.erase(1, 2); - } - // complexes - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { _stack.push_front(new number(_stack.value(1) != _stack.value(0))); _stack.erase(1, 2); - } - // strings - else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { - _stack.push_front(new number(cmp_strings_on_stack_top() != 0)); + } else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { + _stack.push_front(new number(cmpStringsOnStackTop(_stack) != 0)); _stack.erase(1, 2); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief == keyword implementation /// void program::rpn_eq(void) { MIN_ARGUMENTS(2); - // numbers if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) { _stack.push_front(new number(_stack.value(1) == _stack.value(0))); _stack.erase(1, 2); - } - // complexes - else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { + } else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) { _stack.push_front(new number(_stack.value(1) == _stack.value(0))); _stack.erase(1, 2); - } - // strings - else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { - _stack.push_front(new number(cmp_strings_on_stack_top() == 0)); + } else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) { + _stack.push_front(new number(cmpStringsOnStackTop(_stack) == 0)); _stack.erase(1, 2); - } else + } else { setErrorContext(ret_bad_operand_type); + } } /// @brief and keyword implementation @@ -131,7 +118,6 @@ void program::rpn_test_and(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_number); ARG_MUST_BE_OF_TYPE(1, cmd_number); - if (_stack.value(0) != 0 && _stack.value(1) != 0) _stack.push(new number(1)); else @@ -145,7 +131,6 @@ void program::rpn_test_or(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_number); ARG_MUST_BE_OF_TYPE(1, cmd_number); - if (_stack.value(0) != 0 || _stack.value(1) != 0) _stack.push(new number(1)); else @@ -159,7 +144,6 @@ void program::rpn_test_xor(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_number); ARG_MUST_BE_OF_TYPE(1, cmd_number); - if (_stack.value(0) != 0 ^ _stack.value(1) != 0) _stack.push(new number(1)); else @@ -173,7 +157,7 @@ void program::rpn_test_not(void) { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); - _stack.push(new number(_stack.value(0) == 0?1:0)); + _stack.push(new number(_stack.value(0) == 0 ? 1 : 0)); _stack.erase(1, 1); } diff --git a/src/rpn-time.cpp b/src/rpn-time.cpp index 8ca0a02..ad37b3f 100644 --- a/src/rpn-time.cpp +++ b/src/rpn-time.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include #include "program.hpp" @@ -15,15 +17,16 @@ void program::rpn_time() { tm = localtime(&time); if (tm != nullptr) { // 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); + date = (static_cast(tm->tm_hour) * 10000000000.0 + static_cast(tm->tm_min) * 100000000.0 + + static_cast(tm->tm_sec) * 1000000.0 + static_cast(ts.tv_nsec / 1000)); // push it // division after push for real precision _stack.push(new number(date)); _stack.value(0) /= 10000000000.0; - } else + } else { setErrorContext(ret_internal); + } } /// @brief date keyword implementation @@ -39,15 +42,17 @@ void program::rpn_date() { tm = localtime(&time); if (tm != nullptr) { // date format = (M)M.DDYYYY - date = (double)(tm->tm_mon + 1) * 1000000.0 + (double)(tm->tm_mday) * 10000.0 + (double)(tm->tm_year + 1900); + date = static_cast(tm->tm_mon + 1) * 1000000.0 + static_cast(tm->tm_mday) * 10000.0 + + static_cast(tm->tm_year + 1900); // push it number* num; // division after push for real precision _stack.push(new number(date)); _stack.value(0) /= 1000000.0; - } else + } else { setErrorContext(ret_internal); + } } /// @brief ticks keyword implementation @@ -63,8 +68,9 @@ void program::rpn_ticks() { tm = localtime(&time); if (tm != nullptr) { // date in µs - date = 1000000.0 * (double)ts.tv_sec + (double)(ts.tv_nsec / 1000); + date = 1000000.0 * static_cast(ts.tv_sec) + static_cast(ts.tv_nsec / 1000); _stack.push(new number(date)); - } else + } else { setErrorContext(ret_internal); + } } diff --git a/src/rpn-trig.cpp b/src/rpn-trig.cpp index 7eeca55..678c42d 100644 --- a/src/rpn-trig.cpp +++ b/src/rpn-trig.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2014-2022 Louis Rubet + #include "program.hpp" /// @brief pi keyword implementation @@ -28,7 +30,6 @@ void program::rpn_r2d(void) { /// void program::rpn_sin(void) { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = sin(_stack.value(0)); else if (_stack.type(0) == cmd_complex) @@ -41,7 +42,6 @@ void program::rpn_sin(void) { /// void program::rpn_asin(void) { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = asin(_stack.value(0)); else if (_stack.type(0) == cmd_complex) @@ -54,7 +54,6 @@ void program::rpn_asin(void) { /// void program::rpn_cos(void) { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = cos(_stack.value(0)); else if (_stack.type(0) == cmd_complex) @@ -67,7 +66,6 @@ void program::rpn_cos(void) { /// void program::rpn_acos(void) { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = acos(_stack.value(0)); else if (_stack.type(0) == cmd_complex) @@ -80,7 +78,6 @@ void program::rpn_acos(void) { /// void program::rpn_tan(void) { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = tan(_stack.value(0)); else if (_stack.type(0) == cmd_complex) @@ -93,7 +90,6 @@ void program::rpn_tan(void) { /// void program::rpn_atan(void) { MIN_ARGUMENTS(1); - if (_stack.type(0) == cmd_number) _stack.value(0) = atan(_stack.value(0)); else if (_stack.type(0) == cmd_complex) diff --git a/src/stack.hpp b/src/stack.hpp index 8e30ebb..1e55024 100644 --- a/src/stack.hpp +++ b/src/stack.hpp @@ -1,56 +1,37 @@ -#ifndef __stack_h__ -#define __stack_h__ +// Copyright (c) 2014-2022 Louis Rubet -#include +#ifndef SRC_STACK_HPP_ +#define SRC_STACK_HPP_ #include #include #include +#include +using namespace std; #include "object.hpp" -using namespace std; /// @brief stack object, parens of program, storing execution stack values or programs /// class rpnstack : public deque { - public: + public: rpnstack() {} virtual ~rpnstack() { for_each(begin(), end(), [](object* o) { delete o; }); deque::erase(begin(), end()); } - /// @brief copy a whole stack entry and push it back to another stack - /// - /// @param from copy from - /// @param index_from index t ocopy from - /// @param to copy to - /// - static void copy_and_push_front(rpnstack& from, unsigned int index_from, rpnstack& to) { - // carefull: caller must ensure that index_from is correct - to.push_front(from[index_from]->clone()); - } - - /// @brief erase a stack entry from it index - /// - /// @param first index to start - /// @param last index to stop - /// + // stack manipulation void erase(size_t first = 0, size_t nb = 1, bool del = true) { size_t last = std::min(first + nb, size()); - if (del) - for_each(begin() + first, begin() + last, [](object* o) { delete o; }); + if (del) for_each(begin() + first, begin() + last, [](object* o) { delete o; }); deque::erase(begin() + first, begin() + last); } - /// @brief pop front several entries - /// - /// @param levels nb of entries - /// - void pop_front(size_t levels = 1) { erase(0, levels); } void pop() { erase(); } // access helpers + // cmd_type_t type(int level) { // carefull: caller must ensure that level is correct return at(level)->_type; @@ -74,7 +55,7 @@ class rpnstack : public deque { /// @brief heap object, storing variables (=named object) /// class heap : public map { - public: + public: heap() {} virtual ~heap() { clear(); } @@ -83,43 +64,14 @@ class heap : public map { map::erase(begin(), end()); } - /// @brief get a variable - /// - /// @param name the variable name - /// @param obj the variable content - /// @return true the variable was found - /// @return false the variable was not found - /// bool get(const string name, object*& obj) { - bool ret = false; auto i = find(name); if (i != end()) { obj = i->second; - ret = true; - } - return ret; - } - - /// @brief get a variable by its index in heap - /// - /// @param num the variable index - /// @param name the variable name - /// @param obj the variable content - /// @return true the variable was found - /// @return false the variable was not found - /// - bool get_by_index(int num, string& name, object*& obj) { - if (num >= 0 && num < (int)size()) { - object* local; - auto i = begin(); - for (; num > 0; num--, i++) - ; - obj = i->second; - name = i->first; return true; - } else - return false; + } + return false; } }; -#endif // __stack_h__ +#endif // SRC_STACK_HPP_ diff --git a/src/version.h b/src/version.h index 52d5a96..c05594a 100644 --- a/src/version.h +++ b/src/version.h @@ -1,2 +1,9 @@ +// Copyright (c) 2014-2022 Louis Rubet + +#ifndef SRC_VERSION_H_ +#define SRC_VERSION_H_ + #define RPN_VERSION "2.4" #define RPN_UNAME "rpn v" RPN_VERSION ", (c) 2017 , GNU LGPL v3" + +#endif // SRC_VERSION_H_ diff --git a/test/090-program.md b/test/090-program.md index 119d833..8042afc 100644 --- a/test/090-program.md +++ b/test/090-program.md @@ -96,6 +96,7 @@ ``` «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 7 fibo 13 == if then 'ok!' end ```