diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b33886..2eca5a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,8 @@ add_executable( ${PROJECT_SOURCE_DIR}/src/object.cpp ${PROJECT_SOURCE_DIR}/src/mpreal-out.cpp ${PROJECT_SOURCE_DIR}/src/program.cpp - ${PROJECT_SOURCE_DIR}/src/parse.cpp + ${PROJECT_SOURCE_DIR}/src/lexer.cpp + ${PROJECT_SOURCE_DIR}/src/input.cpp ${PROJECT_SOURCE_DIR}/src/rpn-branch.cpp ${PROJECT_SOURCE_DIR}/src/rpn-complex.cpp ${PROJECT_SOURCE_DIR}/src/rpn-general.cpp diff --git a/src/constant.h b/src/constant.h index 6297526..8ee2408 100644 --- a/src/constant.h +++ b/src/constant.h @@ -10,7 +10,6 @@ // default mode and number of printed digits // #define DEFAULT_MODE number::std -#define MPFR_DEFAULT_FORMAT "%.xxRg" /* directly calculated from 128 bits precision ceil(128 * log10(2)) - 1 = 38 */ @@ -19,34 +18,9 @@ // MPFR related defaults // -// rounding method -#define MPFR_DEFAULT_RND MPFR_RNDN -#define MPFR_ROUND_STRINGS \ - {"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 \ - } - // 128 bits significand precision #define MPFR_DEFAULT_PREC_BITS 128 -// constants -// - -// commands and entry related constants -#define MAX_COMMAND_LENGTH 24 -#define AUTOCOMPLETE_KEY '\t' -#define SHOW_STACK_SEPARATOR "> " -#define PROMPT "rpn> " -#define MULTILINE_PROMPT "> " - -// show formats -#define MPFR_FORMAT_BEG "%." -#define MPFR_FORMAT_STD "Rg" -#define MPFR_FORMAT_FIX "Rf" -#define MPFR_FORMAT_SCI "Re" -#define MPFR_FORMAT_HEX "%Ra" - // return values, used by all classes // typedef enum { @@ -70,20 +44,6 @@ typedef enum { ret_max } ret_value; -#define RET_VALUE_STRINGS \ - { \ - "ok", "unknown command", "missing operand", "bad operand type", "out of range", "unknown variable", \ - "internal error, aborting", "deadly", "goodbye", "not implemented", "no operation", "syntax error", \ - "division by zero", "runtime error", "aborted current entry", "out of memory", "bad value", \ - } - -// command types -// - -// history -#define HISTORY_FILE ".rpn_history" -#define HISTORY_FILE_MAX_LINES (100) - // base min and max #define BASE_MIN 2 #define BASE_MAX 62 diff --git a/src/parse.cpp b/src/lexer.cpp similarity index 54% rename from src/parse.cpp rename to src/lexer.cpp index 60b9294..bde5fa1 100644 --- a/src/parse.cpp +++ b/src/lexer.cpp @@ -1,299 +1,10 @@ #include +using namespace std; -#include "program.hpp" +#include "lexer.hpp" -/// @brief completion callback as asked by linenoise-ng -/// this is called by linenoise-ng whenever the user enters TAB -/// -/// @param text the text after wich the user entered TAB -/// @param lc the completion object to add strings with linenoiseAddCompletion() -/// -void program::entry_completion_generator(const char* text, linenoiseCompletions* lc) { - int i = 0; - int text_len = strnlen(text, 6); - - // propose all keywords - if (text_len == 0) { - while (program::s_keywords[i].type != cmd_max) { - if (program::s_keywords[i].fn != NULL) - // add all keywords - linenoiseAddCompletion(lc, program::s_keywords[i].name); - i++; - } - } - // propose keywords matching to text begining - else { - while (program::s_keywords[i].type != cmd_max) { - if (program::s_keywords[i].fn != NULL) { - // compare list entry with text, return if match - if (strncmp(program::s_keywords[i].name, text, text_len) == 0) - linenoiseAddCompletion(lc, program::s_keywords[i].name); - } - i++; - } - } -} - -/// @brief interactive entry and decoding -/// -/// @param prog the program to add entered objects -/// @return ret_value see this type -/// -ret_value program::entry(program& prog) { - string entry_str; - char* entry; - int entry_len; - int total_entry_len; - ret_value ret = ret_max; - bool multiline = false; - - // linenoise for entry - linenoiseSetCompletionCallback(entry_completion_generator); - - while (ret == ret_max) { - // get user entry - if (multiline) - entry = linenoise(MULTILINE_PROMPT, &entry_len); - else - entry = linenoise(PROMPT, &entry_len); - - // Ctrl-C - if (linenoiseKeyType() == 1) { - if (entry_len > 0 || multiline) - ret = ret_abort_current_entry; - else - ret = ret_good_bye; - } else if (linenoiseKeyType() == 3) { - multiline = true; - if (entry != NULL) entry_str += entry; - entry_str += " "; - } else { - if (entry != NULL) { - entry_str += entry; - - // parse it - ret = parse(entry_str, prog); - - // keep history - if (entry[0] != 0) (void)linenoiseHistoryAdd(entry_str.c_str()); - } else - ret = ret_internal; - } - - free(entry); - } - - return ret; -} - -struct SynElement { - cmd_type_t type; - string value; - mpreal re; - mpreal im; - int reBase; - int imBase; - program_fn_t fn; - bool autoEval; -}; - -struct SynError { - size_t indx; - string err; -}; - -struct ReservedWord { - cmd_type_t type; - program_fn_t fn; -}; - -static map _keywordsMap; - -static void trim(string& s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); - s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); -} - -static bool parseString(string& entry, size_t idx, size_t& nextIdx, vector& errors, - vector& elements) { - // here we are sure that entry[0] is at least '"' - for (size_t i = idx + 1; i < entry.size(); i++) { - if (entry[i] == '"') { - if (entry[i] - 1 != '\\') { - elements.push_back({cmd_string, .value = entry.substr(idx + 1, i - idx - 1)}); - nextIdx = i + 1; - return true; - } - } - } - elements.push_back({cmd_string, .value = entry.substr(idx + 1, entry.size() - idx - 1)}); - nextIdx = entry.size(); - return true; -} - -static bool parseSymbol(string& entry, size_t idx, size_t& nextIdx, vector& errors, - vector& elements) { - // here we are sure that entry[0] is at least '\'' - for (size_t i = idx + 1; i < entry.size(); i++) { - if (entry[i] == '\'') { - elements.push_back({cmd_symbol, .value = entry.substr(idx + 1, i - idx - 1), .autoEval = false}); - nextIdx = i + 1; - return true; - } - } - elements.push_back({cmd_symbol, .value = entry.substr(idx + 1, entry.size() - idx - 1)}); - nextIdx = entry.size(); - return true; -} - -static bool parseProgram(string& entry, size_t idx, size_t& nextIdx, vector& errors, - vector& elements) { - // here we are sure that entry is at least "<<" - // find last ">>" 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) == "«")) - countNested++; - 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 - countNested--; - } - } - string prg = entry.substr(idx + 2, entry.size() - idx - 2); - trim(prg); - elements.push_back({cmd_program, .value = prg}); - nextIdx = entry.size(); - return true; -} - -static int getBase(string& entry, int idxStart, bool& positive) { - regex baseRegex("([+-])?((0[xX])|([0-9][0-9]?[bB]))"); - smatch match; - if (regex_search(entry, match, baseRegex) && match.size() >= 5) { - string sign = match[1].str(); - string base = match[2].str(); - // sign out, permits expressions like -0xAB3F - positive = sign.size() > 0 && sign[0] == '-' ? false : true; - // base - entry = entry.substr(base.size() + sign.size()); - if (base[1] == 'X' || base[1] == 'x') return 16; - if (base.size() > 0) { - int b = stoi(base.substr(0, base.size() - 1)); - if (b == 0) b = 2; // admit "0b" as binary suffix - return b; - } - } - return 10; -} - -static bool getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, mpreal& r, char delim = ' ') { - stringstream ss; - int idxNumber = 0; - string token; - bool positive = true; - - ss.str(entry.substr(idx)); - if (getline(ss, token, delim)) { - nextIdx = token.size() + idx + 1; - base = getBase(token, idx, positive); - if (base < BASE_MIN || base > BASE_MAX) return false; - trim(token); - if (mpfr_set_str(r.mpfr_ptr(), token.c_str(), base, mpreal::get_default_rnd()) == 0) { - if (!positive) r = -r; - return true; - } else - return false; - } - nextIdx = token.size() + idx + 1; - return false; -} - -static bool parseNumber(string& entry, size_t idx, size_t& nextIdx, vector& errors, - vector& elements) { - mpreal r; - int base = 10; - if (getNumberAt(entry, idx, nextIdx, base, r)) { - elements.push_back({cmd_number, .re = r, .reBase = base}); - return true; - } else { - errors.push_back({entry.size(), "unterminated number"}); - return false; - } -} - -static bool parseComplex(string& entry, size_t idx, size_t& nextIdx, vector& errors, - vector& elements) { - mpreal re, im; - int reBase, imBase = 10; - if (idx + 1 == entry.size()) { - elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); - nextIdx = entry.size(); - return true; // complex format error, return a symbol - } - if (!getNumberAt(entry, idx + 1, nextIdx, reBase, re, ',')) { - elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); - nextIdx = entry.size(); - return true; // complex format error, return a symbol - } - - size_t i = nextIdx; - //while (i < entry.size() && entry[i] != ',') i++; - if (i >= entry.size()) { - elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); - nextIdx = entry.size(); - return true; // complex format error, return a symbol - } - - if (!getNumberAt(entry, i, nextIdx, imBase, im, ')')) { - elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); - nextIdx = entry.size(); - return true; // complex format error, return a symbol - } - elements.push_back({cmd_complex, .re = re, .im = im, .reBase = reBase, .imBase = imBase}); - nextIdx++; - return true; -} - -static bool parseReserved(string& entry, size_t idx, size_t& nextIdx, vector& elements, - map& keywords) { - stringstream ss(entry.substr(idx)); - string token; - ss >> token; - - auto resa = keywords.find(token); - if (resa != keywords.end()) { - elements.push_back({resa->second.type, .value = token, .fn = resa->second.fn}); - nextIdx = token.size() + idx; - return true; - } - return false; -} - -static bool parseUnknown(string& entry, size_t idx, size_t& nextIdx, vector& elements) { - stringstream ss(entry.substr(idx)); - string token; - ss >> token; - elements.push_back({cmd_symbol, .value = token, .autoEval = true}); - nextIdx = token.size() + idx; - return true; -} - -/// @brief lexical analysis of an entry string -/// -/// @param entry the entry string -/// @param elements syntax elements vector -/// @param errors errors vector -/// @param keywords reserved keywords -/// @return false=errors, the lexer must stop -/// -static bool lexer(string& entry, vector& elements, vector& errors, - map& keywords) { +bool Lexer::lexer(string& entry, map& keywords, vector& elements, + vector& errors) { size_t jump; for (size_t i = 0; i < entry.size(); i++) { if (isspace(entry[i])) continue; @@ -332,60 +43,177 @@ static bool lexer(string& entry, vector& elements, vector& return true; } -static bool progFromElements(vector& elements, program& prog) { - // TODO control elements creation - for (SynElement& element : elements) { - switch (element.type) { - case cmd_number: - prog.push_back(new number(element.re, element.reBase)); - break; - case cmd_complex: - prog.push_back(new ocomplex(element.re, element.im, element.reBase, element.imBase)); - break; - case cmd_string: - prog.push_back(new ostring(element.value)); - break; - case cmd_symbol: - prog.push_back(new symbol(element.value, element.autoEval)); - break; - case cmd_program: - prog.push_back(new oprogram(element.value)); - break; - case cmd_keyword: - prog.push_back(new keyword(element.fn, element.value)); - break; - case cmd_branch: - prog.push_back(new branch((branch_fn_t)element.fn, element.value)); - break; - default: - return false; +void Lexer::trim(string& s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); +} + +bool Lexer::parseString(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements) { + // here we are sure that entry[0] is at least '"' + for (size_t i = idx + 1; i < entry.size(); i++) { + if (entry[i] == '"') { + if (entry[i] - 1 != '\\') { + elements.push_back({cmd_string, .value = entry.substr(idx + 1, i - idx - 1)}); + nextIdx = i + 1; + return true; + } } } + elements.push_back({cmd_string, .value = entry.substr(idx + 1, entry.size() - idx - 1)}); + nextIdx = entry.size(); return true; } -/// @brief parse an entry string: cut it into objects chunks and add them to a program -/// -/// @param entry the entry string -/// @param prog the program to be filled -/// @return ret_value see this type -/// -ret_value program::parse(string& entry, program& prog) { - vector elements; - vector errors; - ret_value ret = ret_ok; - - // prepare map for finding reserved keywords - if (_keywordsMap.size() == 0) - for (int i = 0; s_keywords[i].type != cmd_max; i++) - _keywordsMap[s_keywords[i].name] = {s_keywords[i].type, s_keywords[i].fn}; - - // separate the entry string - if (lexer(entry, elements, errors, _keywordsMap)) { - // make objects from parsed elements - if (!progFromElements(elements, prog)) prog.show_error(ret_unknown_err, "error creating program from entry"); - } else - for (SynError& err : errors) prog.show_syntax_error(err.err.c_str()); - - return ret; +bool Lexer::parseSymbol(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements) { + // here we are sure that entry[0] is at least '\'' + for (size_t i = idx + 1; i < entry.size(); i++) { + if (entry[i] == '\'') { + elements.push_back({cmd_symbol, .value = entry.substr(idx + 1, i - idx - 1), .autoEval = false}); + nextIdx = i + 1; + return true; + } + } + elements.push_back({cmd_symbol, .value = entry.substr(idx + 1, entry.size() - idx - 1)}); + nextIdx = entry.size(); + return true; +} + +bool Lexer::parseProgram(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements) { + // here we are sure that entry is at least "<<" + // find last ">>" 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) == "«")) + countNested++; + 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 + countNested--; + } + } + string prg = entry.substr(idx + 2, entry.size() - idx - 2); + trim(prg); + elements.push_back({cmd_program, .value = prg}); + nextIdx = entry.size(); + return true; +} + +int Lexer::getBaseAt(string& entry, int idxStart, bool& positive) { + regex baseRegex("([+-])?((0[xX])|([0-9][0-9]?[bB]))"); + smatch match; + if (regex_search(entry, match, baseRegex) && match.size() >= 5) { + string sign = match[1].str(); + string base = match[2].str(); + // sign out, permits expressions like -0xAB3F + positive = sign.size() > 0 && sign[0] == '-' ? false : true; + // base + entry = entry.substr(base.size() + sign.size()); + if (base[1] == 'X' || base[1] == 'x') return 16; + if (base.size() > 0) { + int b = stoi(base.substr(0, base.size() - 1)); + if (b == 0) b = 2; // admit "0b" as binary suffix + return b; + } + } + return 10; +} + +bool Lexer::getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, mpreal& r, char delim) { + stringstream ss; + int idxNumber = 0; + string token; + bool positive = true; + + ss.str(entry.substr(idx)); + if (getline(ss, token, delim)) { + nextIdx = token.size() + idx + 1; + base = getBaseAt(token, idx, positive); + if (base < BASE_MIN || base > BASE_MAX) return false; + trim(token); + if (mpfr_set_str(r.mpfr_ptr(), token.c_str(), base, mpreal::get_default_rnd()) == 0) { + if (!positive) r = -r; + return true; + } else + return false; + } + nextIdx = token.size() + idx + 1; + return false; +} + +bool Lexer::parseNumber(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements) { + mpreal r; + int base = 10; + if (getNumberAt(entry, idx, nextIdx, base, r)) { + elements.push_back({cmd_number, .re = r, .reBase = base}); + return true; + } else { + errors.push_back({entry.size(), "unterminated number"}); + return false; + } +} + +bool Lexer::parseComplex(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements) { + mpreal re, im; + int reBase, imBase = 10; + if (idx + 1 == entry.size()) { + elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); + nextIdx = entry.size(); + return true; // complex format error, return a symbol + } + if (!getNumberAt(entry, idx + 1, nextIdx, reBase, re, ',')) { + elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); + nextIdx = entry.size(); + return true; // complex format error, return a symbol + } + + size_t i = nextIdx; + // while (i < entry.size() && entry[i] != ',') i++; + if (i >= entry.size()) { + elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); + nextIdx = entry.size(); + return true; // complex format error, return a symbol + } + + if (!getNumberAt(entry, i, nextIdx, imBase, im, ')')) { + elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)}); + nextIdx = entry.size(); + return true; // complex format error, return a symbol + } + elements.push_back({cmd_complex, .re = re, .im = im, .reBase = reBase, .imBase = imBase}); + nextIdx++; + return true; +} + +bool Lexer::parseReserved(string& entry, size_t idx, size_t& nextIdx, vector& elements, + map& keywords) { + stringstream ss(entry.substr(idx)); + string token; + ss >> token; + + auto resa = keywords.find(token); + if (resa != keywords.end()) { + elements.push_back({resa->second.type, .value = token, .fn = resa->second.fn}); + nextIdx = token.size() + idx; + return true; + } + return false; +} + +bool Lexer::parseUnknown(string& entry, size_t idx, size_t& nextIdx, vector& elements) { + stringstream ss(entry.substr(idx)); + string token; + ss >> token; + elements.push_back({cmd_symbol, .value = token, .autoEval = true}); + nextIdx = token.size() + idx; + return true; } diff --git a/src/lexer.hpp b/src/lexer.hpp new file mode 100644 index 0000000..4491910 --- /dev/null +++ b/src/lexer.hpp @@ -0,0 +1,73 @@ +#ifndef _PARSER_HPP_ +#define _PARSER_HPP_ + +#include +#include +using namespace std; + +#define MPFR_USE_NO_MACRO +#include +#include +using namespace mpfr; + +#include "constant.h" +#include "object.hpp" + +class Lexer { + public: + // a structure to describe a syntaxical element and its value + struct SynElement { + cmd_type_t type; + string value; + mpreal re; + mpreal im; + int reBase; + int imBase; + program_fn_t fn; + bool autoEval; + }; + + struct SynError { + size_t indx; + string err; + }; + + struct ReservedWord { + cmd_type_t type; + program_fn_t fn; + }; + + Lexer() {} + + /// @brief lexical analysis of an entry string + /// + /// @param[in] entry the entry to lex + /// @param[out] elements syntax elements vector + /// @param[out] errors errors vector + /// @param[in] keywords reserved keywords + /// @return false=errors, the lexer must stop + /// + bool lexer(string& entry, map& keywords, vector& elements, + vector& errors); + + 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, + vector& elements); + bool parseProgram(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements); + bool parseNumber(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements); + bool parseComplex(string& entry, size_t idx, size_t& nextIdx, vector& errors, + vector& elements); + bool parseReserved(string& entry, size_t idx, size_t& nextIdx, vector& elements, + map& keywords); + bool parseUnknown(string& entry, size_t idx, size_t& nextIdx, vector& elements); + + void trim(string& s); + int getBaseAt(string& entry, int idxStart, bool& positive); + bool getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, mpreal& r, char delim = ' '); +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 9d881b3..f92355b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -7,19 +6,20 @@ using namespace std; // internal includes +#include "input.hpp" #include "program.hpp" static heap _global_heap; static rpnstack _global_stack; -static program* _prog_to_interrupt = NULL; +static program* _prog_to_interrupt = nullptr; /// @brief actions to be done at rpn exit /// static void exit_interactive_rpn() { struct passwd* pw = getpwuid(getuid()); - if (pw != NULL) { + if (pw != nullptr) { stringstream history_path; - history_path << pw->pw_dir << '/' << HISTORY_FILE; + history_path << pw->pw_dir << "/.rpn_history"; // trunc current history ofstream history(history_path.str(), ios_base::out | ios_base::trunc); @@ -37,12 +37,12 @@ static void exit_interactive_rpn() { /// static void init_interactive_rpn() { struct passwd* pw = getpwuid(getuid()); - if (pw != NULL) { + if (pw != nullptr) { stringstream history_path; - history_path << pw->pw_dir << '/' << HISTORY_FILE; + history_path << pw->pw_dir << "/.rpn_history"; // don't care about errors - linenoiseHistorySetMaxLen(HISTORY_FILE_MAX_LINES); + linenoiseHistorySetMaxLen(100); linenoiseHistoryLoad(history_path.str().c_str()); } } @@ -54,9 +54,9 @@ static void init_interactive_rpn() { /// @param context see POSIX sigaction /// static void ctrlc_handler(int sig, siginfo_t* siginfo, void* context) { - if (_prog_to_interrupt != NULL) { + if (_prog_to_interrupt != nullptr) { _prog_to_interrupt->stop(); - _prog_to_interrupt = NULL; + _prog_to_interrupt = nullptr; } exit_interactive_rpn(); @@ -71,12 +71,12 @@ static void ctrlc_handler(int sig, siginfo_t* siginfo, void* context) { static void segv_handler(int sig, siginfo_t* siginfo, void* context) { cerr << "Internal error" << endl; _prog_to_interrupt->stop(); - _prog_to_interrupt = NULL; + _prog_to_interrupt = nullptr; } /// @brief setup signals handlers to stop with honours /// -/// @param prog the prog to catch the signals to, must be checked not NULL by user +/// @param prog the prog to catch the signals to, must be checked not nullptr by user /// static void catch_signals(program* prog) { struct sigaction act = {0}; @@ -85,12 +85,12 @@ static void catch_signals(program* prog) { act.sa_sigaction = &ctrlc_handler; act.sa_flags = SA_SIGINFO; - if (sigaction(SIGINT, &act, NULL) < 0) + 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, NULL) < 0) + if (sigaction(SIGSEGV, &act, nullptr) < 0) cerr << "Warning, SIGSEGV cannot be caught [errno=" << errno << ' ' << strerror(errno) << "']" << endl; } @@ -116,30 +116,28 @@ int main(int argc, char* argv[]) { while (go_on) { // make program from interactive entry program prog(_global_stack, _global_heap); - switch (program::entry(prog)) { - case ret_good_bye: - go_on = false; - break; - case ret_abort_current_entry: - break; - default: + string entry; + switch (Input(entry, program::getAutocompletionWords()).status) { + case Input::ok: // user could stop prog with CtrlC catch_signals(&prog); - // run it - if (prog.run() == ret_good_bye) + if (prog.parse(entry) == ret_ok && prog.run() == ret_good_bye) go_on = false; else program::show_stack(_global_stack); break; + case Input::ctrlc: + go_on = false; + break; + default: + break; } } // manage history and exit exit_interactive_rpn(); - } - // run with cmd line arguments - else { + } else { // run with cmd line arguments program prog(_global_stack, _global_heap); string entry; int i; @@ -151,7 +149,7 @@ int main(int argc, char* argv[]) { } // make program - ret = program::parse(entry, prog); + ret = prog.parse(entry); if (ret == ret_ok) { // user could stop prog with CtrlC catch_signals(&prog); diff --git a/src/object.cpp b/src/object.cpp index 265636d..e9af391 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -1,10 +1,4 @@ -#include -#include -using namespace std; - #include "constant.h" -#define MPFR_USE_NO_MACRO -#include #include "object.hpp" // number statics diff --git a/src/object.hpp b/src/object.hpp index dfd0d7c..6b83186 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -1,13 +1,14 @@ #ifndef OBJECT_HPP #define OBJECT_HPP +#define MPFR_USE_NO_MACRO +#include #include using namespace mpfr; -#include -#include -#include #include +#include +#include using namespace std; #include "mpreal-out.hpp" @@ -127,7 +128,6 @@ struct ocomplex : object { struct ostring : object { ostring() : object(cmd_string) {} ostring(const string& value_) : object(cmd_string), value(value_) {} - ostring(const char* value_) : object(cmd_string) { value = string(value_); } virtual object* clone() { return new ostring(value); } virtual string name() { return string("string"); } virtual ostream& show(ostream& out) { return out << "\"" << value << "\""; } diff --git a/src/program.cpp b/src/program.cpp index 97a8f5c..8ec91b0 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -1,12 +1,9 @@ #include "program.hpp" -//< return type strings -const char* program::s_ret_value_string[ret_max] = RET_VALUE_STRINGS; - //< language reserved keywords (allowed types are cmd_keyword, cmd_branch or cmd_undef) -program::keyword_t program::s_keywords[] = { +vector program::_keywords{ // GENERAL - {cmd_undef, "", NULL, "\nGENERAL"}, + {cmd_undef, "", nullptr, "\nGENERAL"}, {cmd_keyword, "nop", &program::rpn_nop, "no operation"}, {cmd_keyword, "help", &program::rpn_help, "this help message"}, {cmd_keyword, "h", &program::rpn_help, ""}, @@ -20,7 +17,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "history", &program::rpn_history, "see commands history"}, // USUAL OPERATIONS ON REALS AND COMPLEXES - {cmd_undef, "", NULL, "\nUSUAL OPERATIONS ON REALS AND COMPLEXES"}, + {cmd_undef, "", nullptr, "\nUSUAL OPERATIONS ON REALS AND COMPLEXES"}, {cmd_keyword, "+", &program::rpn_plus, "addition"}, {cmd_keyword, "-", &program::rpn_minus, "substraction"}, {cmd_keyword, "*", &program::rpn_mul, "multiplication"}, @@ -36,7 +33,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "sign", &program::rpn_sign, "sign of a number or z/|z| for a complex"}, // OPERATIONS ON REALS - {cmd_undef, "", NULL, "\nOPERATIONS ON REALS"}, + {cmd_undef, "", nullptr, "\nOPERATIONS ON REALS"}, {cmd_keyword, "%", &program::rpn_purcent, "purcent"}, {cmd_keyword, "%CH", &program::rpn_purcentCH, "inverse purcent"}, {cmd_keyword, "mod", &program::rpn_modulo, "modulo"}, @@ -51,7 +48,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "max", &program::rpn_max, "max of 2 real numbers"}, // OPERATIONS ON COMPLEXES - {cmd_undef, "", NULL, "\nOPERATIONS ON COMPLEXES"}, + {cmd_undef, "", nullptr, "\nOPERATIONS ON COMPLEXES"}, {cmd_keyword, "re", &program::rpn_re, "complex real part"}, {cmd_keyword, "im", &program::rpn_im, "complex imaginary part"}, {cmd_keyword, "conj", &program::rpn_conj, "complex conjugate"}, @@ -62,7 +59,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "r->p", &program::rpn_r2p, "polar to cartesian"}, // MODE - {cmd_undef, "", NULL, "\nMODE"}, + {cmd_undef, "", nullptr, "\nMODE"}, {cmd_keyword, "std", &program::rpn_std, "standard floating numbers representation. ex: std"}, {cmd_keyword, "fix", &program::rpn_fix, "fixed point representation. ex: 6 fix"}, {cmd_keyword, "sci", &program::rpn_sci, "scientific floating point representation. ex: 20 sci"}, @@ -79,7 +76,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "base", &program::rpn_base, "arbitrary base representation, applies on stack level 0 only"}, // TESTS - {cmd_undef, "", NULL, "\nTEST"}, + {cmd_undef, "", nullptr, "\nTEST"}, {cmd_keyword, ">", &program::rpn_sup, "binary operator >"}, {cmd_keyword, ">=", &program::rpn_sup_eq, "binary operator >="}, {cmd_keyword, "<", &program::rpn_inf, "binary operator <"}, @@ -93,7 +90,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "same", &program::rpn_same, "boolean operator same (equal)"}, // STACK - {cmd_undef, "", NULL, "\nSTACK"}, + {cmd_undef, "", nullptr, "\nSTACK"}, {cmd_keyword, "swap", &program::rpn_swap, "swap 2 first stack entries"}, {cmd_keyword, "drop", &program::rpn_drop, "drop first stack entry"}, {cmd_keyword, "drop2", &program::rpn_drop2, "drop 2 first stack entries"}, @@ -111,7 +108,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "over", &program::rpn_over, "push a copy of the element in stack level 2 onto the stack"}, // STRING - {cmd_undef, "", NULL, "\nSTRING"}, + {cmd_undef, "", nullptr, "\nSTRING"}, {cmd_keyword, "->str", &program::rpn_instr, "convert an object into a string"}, {cmd_keyword, "str->", &program::rpn_strout, "convert a string into an object"}, {cmd_keyword, "chr", &program::rpn_chr, "convert ASCII character code in stack level 1 into a string"}, @@ -122,7 +119,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "sub", &program::rpn_strsub, "return a substring of the string in level 3"}, // BRANCH - {cmd_undef, "", NULL, "\nBRANCH"}, + {cmd_undef, "", nullptr, "\nBRANCH"}, {cmd_branch, "if", (program_fn_t)&program::rpn_if, "if then else " "end"}, @@ -144,7 +141,7 @@ program::keyword_t program::s_keywords[] = { {cmd_branch, "repeat", (program_fn_t)&program::rpn_repeat, "used with while"}, // STORE - {cmd_undef, "", NULL, "\nSTORE"}, + {cmd_undef, "", nullptr, "\nSTORE"}, {cmd_keyword, "sto", &program::rpn_sto, "store a variable. ex: 1 'name' sto"}, {cmd_keyword, "rcl", &program::rpn_rcl, "recall a variable. ex: 'name' rcl"}, {cmd_keyword, "purge", &program::rpn_purge, "delete a variable. ex: 'name' purge"}, @@ -158,14 +155,14 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "sneg", &program::rpn_stoneg, "negate a variable. ex: 'name' sneg"}, {cmd_keyword, "sinv", &program::rpn_stoinv, "inverse a variable. ex: 1 'name' sinv"}, // PROGRAM - {cmd_undef, "", NULL, "\nPROGRAM"}, + {cmd_undef, "", nullptr, "\nPROGRAM"}, {cmd_keyword, "eval", &program::rpn_eval, "evaluate (run) a program, or recall a variable. ex: 'my_prog' eval"}, {cmd_branch, "->", (program_fn_t)&program::rpn_inprog, "load program local variables. ex: << -> n m << 0 n m for i i + next >> " ">>"}, // TRIG ON REALS AND COMPLEXES - {cmd_undef, "", NULL, "\nTRIG ON REALS AND COMPLEXES"}, + {cmd_undef, "", nullptr, "\nTRIG ON REALS AND COMPLEXES"}, {cmd_keyword, "pi", &program::rpn_pi, "pi constant"}, {cmd_keyword, "sin", &program::rpn_sin, "sinus"}, {cmd_keyword, "asin", &program::rpn_asin, "arg sinus"}, @@ -177,7 +174,7 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "r->d", &program::rpn_r2d, "convert radians to degrees"}, // LOGS ON REALS AND COMPLEXES - {cmd_undef, "", NULL, "\nLOGS ON REALS AND COMPLEXES"}, + {cmd_undef, "", nullptr, "\nLOGS ON REALS AND COMPLEXES"}, {cmd_keyword, "e", &program::rpn_e, "Euler constant"}, {cmd_keyword, "ln", &program::rpn_ln, "logarithm base e"}, {cmd_keyword, "log", &program::rpn_ln, ""}, @@ -198,15 +195,25 @@ program::keyword_t program::s_keywords[] = { {cmd_keyword, "atanh", &program::rpn_atanh, "inverse hyperbolic tangent"}, // TIME AND DATE - {cmd_undef, "", NULL, "\nTIME AND DATE"}, + {cmd_undef, "", nullptr, "\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, ""}, }; +/// keywords map for lexer +map program::_keywordsMap; + +/// autocompletion vector for linenoise autocompletion +vector program::_autocompletionWords; + +vector& program::getAutocompletionWords() { + if (_autocompletionWords.empty()) + for (auto& kw : _keywords) + if (!kw.name.empty()) _autocompletionWords.push_back(kw.name); + return _autocompletionWords; +} + /// @brief run a program on a stack and a heap /// /// @return ret_value see this type @@ -302,7 +309,7 @@ ret_value program::run() { _local_heap.clear(); if (interrupt_now) { - fprintf(stderr, "\nInterrupted\n"); + cerr << endl << "Interrupted" << endl; interrupt_now = false; } @@ -561,15 +568,75 @@ ret_value program::preprocess(void) { return ret_ok; } +/// @brief parse an entry string: cut it into objects chunks and add them to a program +/// +/// @param entry the entry string +/// @param prog the program to be filled +/// @return ret_value see this type +/// +ret_value program::parse(string& entry) { + vector elements; + vector errors; + ret_value ret = ret_ok; + + // prepare map for finding reserved keywords + if (_keywordsMap.empty()) + for (auto& kw : _keywords) + if (!kw.name.empty()) _keywordsMap[kw.name] = {kw.type, kw.fn}; + + // separate the entry string + if (lexer(entry, _keywordsMap, elements, errors)) { + // make objects from parsed elements + for (Lexer::SynElement& element : elements) { + switch (element.type) { + case cmd_number: + push_back(new number(element.re, element.reBase)); + break; + case cmd_complex: + push_back(new ocomplex(element.re, element.im, element.reBase, element.imBase)); + break; + case cmd_string: + push_back(new ostring(element.value)); + break; + case cmd_symbol: + push_back(new symbol(element.value, element.autoEval)); + break; + case cmd_program: + push_back(new oprogram(element.value)); + break; + case cmd_keyword: + push_back(new keyword(element.fn, element.value)); + break; + case cmd_branch: + push_back(new branch((branch_fn_t)element.fn, element.value)); + break; + default: + show_error(ret_unknown_err, "error creating program from entry"); + } + } + } else + for (SynError& err : errors) show_syntax_error(err.err.c_str()); + + return ret; +} + /// @brief show the last error set /// /// @return ret_value see this type /// ret_value program::show_error() { ret_value ret; - + // clang-format off + vector errorStrings {"ok", "unknown command", "missing operand", "bad operand type", + "out of range", "unknown variable", "internal error, aborting", "deadly", "goodbye", "not implemented", + "no operation", "syntax error", "division by zero", "runtime error", "aborted current entry", "out of memory", + "bad value"}; + // clang-format on // show last recorded error - cerr << _err_context << ": error " << _err << ": " << s_ret_value_string[_err] << endl; + if ((size_t)_err < errorStrings.size()) + cerr << _err_context << ": error " << _err << ": " << errorStrings[_err] << endl; + else + cerr << _err_context << " (unknown error code)" << endl; switch (_err) { case ret_internal: case ret_deadly: @@ -637,7 +704,7 @@ void program::show_stack(rpnstack& st, bool show_separator) { cout << st[0] << endl; else for (int i = st.size() - 1; i >= 0; i--) { - if (show_separator) cout << i + 1 << SHOW_STACK_SEPARATOR; + if (show_separator) cout << i + 1 << "> "; cout << st[i] << endl; } } diff --git a/src/program.hpp b/src/program.hpp index a22939c..1c98f09 100644 --- a/src/program.hpp +++ b/src/program.hpp @@ -1,33 +1,21 @@ #ifndef PROGRAM_HPP #define PROGRAM_HPP -// std c -#include -#include -#include -#include - // std c++ #include -#include -#include -#include -#include #include using namespace std; -// external libs #define MPFR_USE_NO_MACRO #include - -#include "linenoise.h" +#include +using namespace mpfr; // internal includes #include "constant.h" -#include "escape.h" #include "object.hpp" #include "stack.hpp" -#include "version.h" +#include "lexer.hpp" //< convinient structure to preprocess a program struct if_layout_t { @@ -42,7 +30,7 @@ struct if_layout_t { }; //< program class: the class containing a string parser, all the programs keywords, a stack for running the program -class program : public deque { +class program : public deque, public Lexer { public: program(rpnstack& stk, heap& hp, program* parent = nullptr):_stack(stk),_heap(hp),_parent(parent) { interrupt_now = false; @@ -53,9 +41,7 @@ class program : public deque { } // parser - static ret_value parse(string& entry, program& prog); - static ret_value entry(program& prog); - static void entry_completion_generator(const char* text, linenoiseCompletions* lc); + ret_value parse(string& entry); static ret_value get_fn(const char* fn_name, program_fn_t& fn, cmd_type_t& type); // running @@ -74,6 +60,8 @@ class program : public deque { static void apply_default(); + static vector& getAutocompletionWords(); + private: bool interrupt_now; @@ -96,16 +84,16 @@ class program : public deque { int stack_size() { return _stack.size(); } private: - static const char* s_ret_value_string[ret_max]; - // keywords struct keyword_t { cmd_type_t type; - char name[MAX_COMMAND_LENGTH]; + string name; program_fn_t fn; string comment; }; - static keyword_t s_keywords[]; + static vector _keywords; + static map _keywordsMap; + static vector _autocompletionWords; // keywords implementation //// @@ -285,26 +273,22 @@ class program : public deque { // convenience macros for rpn_xx function // carefull : some of these macros modify program flow -#define ERR_CONTEXT(err) do { _err = (err); _err_context = __FUNCTION__; } while (0) +#define setErrorContext(err) do { _err = (err); _err_context = __FUNCTION__; } while (0) #define MIN_ARGUMENTS(num) do { \ - if (stack_size() < (num)) { ERR_CONTEXT(ret_missing_operand); return; } \ + if (stack_size() < (num)) { setErrorContext(ret_missing_operand); return; } \ } while (0) #define MIN_ARGUMENTS_RET(num, ret) do { \ - if (stack_size() < (num)) { ERR_CONTEXT(ret_missing_operand); return (ret); } \ + if (stack_size() < (num)) { setErrorContext(ret_missing_operand); return (ret); } \ } while (0) #define ARG_MUST_BE_OF_TYPE(num, type) do { \ - if (_stack.at(num)->_type != (type)) { ERR_CONTEXT(ret_bad_operand_type); return; } \ + if (_stack.at(num)->_type != (type)) { setErrorContext(ret_bad_operand_type); return; } \ } while (0) #define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) do { \ - if (_stack.at(num)->_type != (type)) { ERR_CONTEXT(ret_bad_operand_type); return (ret); } \ + if (_stack.at(num)->_type != (type)) { setErrorContext(ret_bad_operand_type); return (ret); } \ } while (0) -#define IS_ARG_TYPE(num, type) (_stack.at(num)->_type == (type)) - -#define CHECK_MPFR(op) do { (void)(op); } while (0) - #endif diff --git a/src/rpn-general.cpp b/src/rpn-general.cpp index 06b113e..c19a934 100644 --- a/src/rpn-general.cpp +++ b/src/rpn-general.cpp @@ -1,4 +1,34 @@ +#include + +#include "escape.h" +#include "linenoise.h" #include "program.hpp" +#include "version.h" + +// description +#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"}; + +// syntax +static const string _syntax{ATTR_BOLD "Syntax" ATTR_OFF + ": rpn [command]\n" + "with 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}}; /// @brief nop keyword implementation /// @@ -8,33 +38,31 @@ void program::rpn_nop() { /// @brief quit keyword implementation /// -void program::rpn_good_bye() { ERR_CONTEXT(ret_good_bye); } +void program::rpn_good_bye() { setErrorContext(ret_good_bye); } /// @brief nop keyword implementation /// the result is written on stdout /// void program::rpn_help() { // software name - cout << endl << ATTR_BOLD << uname << ATTR_OFF << endl; + cout << endl << ATTR_BOLD << RPN_UNAME << ATTR_OFF << endl; - // description - cout << description << endl << endl; + // _description + cout << _description << endl << endl; - // syntax - cout << syntax << endl; + // _syntax + cout << _syntax << endl; // keywords unsigned int i = 0; - while (s_keywords[i].type != cmd_max) { - if (s_keywords[i].comment.size() != 0) { + for (auto& kw : _keywords) + if (!kw.comment.empty()) { // titles in bold - if (s_keywords[i].type == cmd_undef) cout << ATTR_BOLD; + if (kw.type == cmd_undef) cout << ATTR_BOLD; // show title or keyword + comment - cout << s_keywords[i].name << '\t' << s_keywords[i].comment << endl; - if (s_keywords[i].type == cmd_undef) cout << ATTR_OFF; + cout << kw.name << '\t' << kw.comment << endl; + if (kw.type == cmd_undef) cout << ATTR_OFF; } - i++; - } cout << endl; // show mode @@ -57,14 +85,9 @@ 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; - struct RndStrings { - string name; - mp_rnd_t rnd; - }; - vector rndStrings{MPFR_ROUND_STRINGS}; - for (RndStrings r : rndStrings) - if (r.rnd == mpreal::get_default_rnd()) { - cout << "Current rounding mode is " << r.name << endl; + for (auto& rn : _mpfr_round) + if (rn.second == mpreal::get_default_rnd()) { + cout << "Current rounding mode is '" << rn.first << '\'' << endl; break; } cout << endl << endl; @@ -103,7 +126,7 @@ void program::rpn_std() { number::s_digits = (int)digits; _stack.pop(); } else - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); } /// @brief fix keyword implementation @@ -120,7 +143,7 @@ void program::rpn_fix() { number::s_digits = (int)digits; _stack.pop(); } else - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); } /// @brief sci keyword implementation @@ -137,16 +160,16 @@ void program::rpn_sci() { number::s_digits = (int)digits; _stack.pop(); } else - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); } -/// @brief version keyword implementation +/// @brief _version keyword implementation /// -void program::rpn_version() { _stack.push_front(new ostring(version)); } +void program::rpn_version() { _stack.push_front(new ostring(RPN_VERSION)); } -/// @brief uname keyword implementation +/// @brief _uname keyword implementation /// -void program::rpn_uname() { _stack.push_front(new ostring(uname)); } +void program::rpn_uname() { _stack.push_front(new ostring(RPN_UNAME)); } /// @brief history keyword implementation /// @@ -154,7 +177,7 @@ void program::rpn_history() { // see command history on stdout int index = 0; char* line = linenoiseHistoryLine(index); - while (line != NULL) { + while (line != nullptr) { cout << line << endl; free(line); line = linenoiseHistoryLine(++index); @@ -191,7 +214,7 @@ void program::rpn_precision() { } _stack.pop(); } else - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); } /// @brief round keyword implementation @@ -200,12 +223,12 @@ void program::rpn_round() { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_string); - map matchRound{MPFR_ROUND_STRINGS}; + map matchRound{_mpfr_round}; auto found = matchRound.find(_stack.value(0)); if (found != matchRound.end()) mpreal::set_default_rnd(found->second); else - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); _stack.pop(); } diff --git a/src/rpn-logs.cpp b/src/rpn-logs.cpp index 4b6582e..0a45f92 100644 --- a/src/rpn-logs.cpp +++ b/src/rpn-logs.cpp @@ -13,7 +13,7 @@ void program::rpn_log10() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = log10(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief alog10 keyword implementation @@ -25,7 +25,7 @@ void program::rpn_alog10() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = exp(log(mpreal(10)) * _stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief log2 keyword implementation @@ -37,7 +37,7 @@ void program::rpn_log2() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = log(_stack.value(0)) / const_log2(); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief alog2 keyword implementation @@ -49,7 +49,7 @@ void program::rpn_alog2() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = exp(const_log2() * _stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief ln keyword implementation @@ -61,7 +61,7 @@ void program::rpn_ln() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = log(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief exp keyword implementation @@ -73,7 +73,7 @@ void program::rpn_exp() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = exp(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief expm keyword implementation @@ -85,7 +85,7 @@ void program::rpn_expm() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = exp(_stack.value(0)) - mpreal(1); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief lnp1 keyword implementation @@ -97,7 +97,7 @@ void program::rpn_lnp1() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = log(_stack.value(0) + mpreal(1)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief sinh keyword implementation @@ -109,7 +109,7 @@ void program::rpn_sinh() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = sinh(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief asinh keyword implementation @@ -121,7 +121,7 @@ void program::rpn_asinh() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = asinh(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief cosh keyword implementation @@ -133,7 +133,7 @@ void program::rpn_cosh() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = cosh(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief acosh keyword implementation @@ -145,7 +145,7 @@ void program::rpn_acosh() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = acosh(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief tanh keyword implementation @@ -157,7 +157,7 @@ void program::rpn_tanh() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = tanh(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief atanh keyword implementation @@ -169,5 +169,5 @@ void program::rpn_atanh() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = atanh(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } diff --git a/src/rpn-program.cpp b/src/rpn-program.cpp index 8dbf217..f3196a4 100644 --- a/src/rpn-program.cpp +++ b/src/rpn-program.cpp @@ -14,7 +14,7 @@ bool program::find_variable(string& variable, object*& obj) { if (_local_heap.get(variable, obj)) found = true; else { - while (parent != NULL) { + while (parent != nullptr) { if (parent->_local_heap.get(variable, obj)) { found = true; break; @@ -36,7 +36,7 @@ void program::rpn_eval(void) { string prog_text; MIN_ARGUMENTS(1); - if (IS_ARG_TYPE(0, cmd_symbol)) { + if (_stack.type(0) == cmd_symbol) { // recall a variable object* obj; string variable(_stack.value(0)); @@ -53,21 +53,21 @@ void program::rpn_eval(void) { _stack.push_front(obj); } } else - ERR_CONTEXT(ret_unknown_variable); - } else if (IS_ARG_TYPE(0, cmd_program)) { + 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 - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); // run prog if any if (run_prog) { program prog(_stack, _heap, this); // make program from entry - if (program::parse(prog_text, prog) == ret_ok) { + if (prog.parse(prog_text) == ret_ok) { // run it prog.run(); } @@ -82,7 +82,7 @@ int program::rpn_inprog(branch& myobj) { bool prog_found = false; if (myobj.arg1 == -1) { - ERR_CONTEXT(ret_unknown_err); + setErrorContext(ret_unknown_err); return -1; } @@ -92,15 +92,15 @@ int program::rpn_inprog(branch& myobj) { // find next oprogram object for (unsigned int i = myobj.arg1 + 1; i < size(); i++) { // count symbol - if ((*this)[i]->_type == cmd_symbol) count_symbols++; + if (at(i)->_type == cmd_symbol) count_symbols++; // stop if prog - else if ((*this)[i]->_type == cmd_program) { + else if (at(i)->_type == cmd_program) { prog_found = true; break; } // found something other than symbol else { - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); show_error(_err, context); return -1; } @@ -108,37 +108,37 @@ int program::rpn_inprog(branch& myobj) { // found 0 symbols if (count_symbols == 0) { - ERR_CONTEXT(ret_syntax); + setErrorContext(ret_syntax); show_error(_err, context); return -1; } // is missing if (!prog_found) { - ERR_CONTEXT(ret_syntax); + setErrorContext(ret_syntax); show_error(_err, context); return -1; } // check symbols number vs stack size if (stack_size() < count_symbols) { - ERR_CONTEXT(ret_missing_operand); + setErrorContext(ret_missing_operand); show_error(_err, context); return -1; } // load variables for (unsigned int i = myobj.arg1 + count_symbols; i > myobj.arg1; i--) { - _local_heap[string(((symbol*)(*this)[i])->value)] = _stack.at(0)->clone(); + _local_heap[string(((symbol*)at(i))->value)] = _stack.at(0)->clone(); _stack.pop_front(); } // run the program - string entry(((oprogram*)(*this)[myobj.arg1 + count_symbols + 1])->value); + string entry(((oprogram*)at(myobj.arg1 + count_symbols + 1))->value); program prog(_stack, _heap, this); // make the program from entry - if (program::parse(entry, prog) == ret_ok) { + if (prog.parse(entry) == ret_ok) { // run it prog.run(); } diff --git a/src/rpn-real.cpp b/src/rpn-real.cpp index e1b6257..ad618a0 100644 --- a/src/rpn-real.cpp +++ b/src/rpn-real.cpp @@ -31,7 +31,7 @@ void program::rpn_plus() { _stack.value(1) += _stack.value(0); _stack.pop(); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief - keyword implementation @@ -60,7 +60,7 @@ void program::rpn_minus() { _stack.value(1) = _stack.value(0) - _stack.value(1); _stack.pop(); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief * keyword implementation @@ -89,7 +89,7 @@ void program::rpn_mul() { _stack.value(1) *= _stack.value(0); _stack.pop(); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief / keyword implementation @@ -118,7 +118,7 @@ void program::rpn_div() { _stack.value(1) = _stack.value(0) / _stack.value(1); _stack.pop(); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief neg keyword implementation @@ -131,7 +131,7 @@ void program::rpn_neg() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = -_stack.value(0); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief inv keyword implementation @@ -144,7 +144,7 @@ void program::rpn_inv() { else if (_stack.type(0) == cmd_complex) _stack.value(0) = mpreal{1} / _stack.value(0); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief power keyword implementation @@ -172,7 +172,7 @@ void program::rpn_power() { _stack.value(1) = pow(_stack.value(0), _stack.value(1)); _stack.pop(); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief sqrt keyword implementation @@ -192,7 +192,7 @@ void program::rpn_squareroot() { } else if (_stack.type(0) == cmd_complex) _stack.value(0) = sqrt(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief hex keyword implementation @@ -205,7 +205,7 @@ void program::rpn_hex() { _stack.obj(0).reBase = 16; _stack.obj(0).imBase = 16; } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief bin keyword implementation @@ -218,7 +218,7 @@ void program::rpn_bin() { _stack.obj(0).reBase = 2; _stack.obj(0).imBase = 2; } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief dec keyword implementation @@ -231,7 +231,7 @@ void program::rpn_dec() { _stack.obj(0).reBase = 10; _stack.obj(0).imBase = 10; } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief base keyword implementation @@ -249,9 +249,9 @@ void program::rpn_base() { _stack.obj(0).imBase = base; } } else - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief % (purcent) keyword implementation @@ -283,7 +283,7 @@ void program::rpn_square() { else if (_stack.at(0)->_type == cmd_complex) _stack.value(0) *= _stack.value(0); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief mod keyword implementation @@ -306,7 +306,7 @@ void program::rpn_abs() { _stack.push(new number(abs(_stack.value(0)))); _stack.erase(1); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief fact (factorial) keyword implementation @@ -327,7 +327,7 @@ void program::rpn_sign() { else if (_stack.at(0)->_type == cmd_complex) _stack.value(0) = _stack.value(0) / abs(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief mant keyword implementation @@ -336,7 +336,7 @@ void program::rpn_mant() { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); if (!isfinite(_stack.value(0))) { - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); return; } mp_exp_t exp; @@ -349,7 +349,7 @@ void program::rpn_xpon() { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_number); if (!isfinite(_stack.value(0))) { - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); return; } mp_exp_t exp; diff --git a/src/rpn-stack.cpp b/src/rpn-stack.cpp index 8b864bc..fc142a7 100644 --- a/src/rpn-stack.cpp +++ b/src/rpn-stack.cpp @@ -77,7 +77,7 @@ void program::rpn_pick(void) { // treat stack depth errors if ((to_pick == 0) || (to_pick > _stack.size())) { - ERR_CONTEXT(ret_out_of_range); + setErrorContext(ret_out_of_range); return; } diff --git a/src/rpn-store.cpp b/src/rpn-store.cpp index 4a424c8..fac153e 100644 --- a/src/rpn-store.cpp +++ b/src/rpn-store.cpp @@ -1,4 +1,5 @@ #include "program.hpp" +#include "input.hpp" /// @brief sto keyword implementation /// @@ -22,7 +23,7 @@ void program::rpn_stoadd(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_symbol); if (_heap.find(_stack.value(0)) == _heap.end()) { - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); return; } rpn_dup(); @@ -39,7 +40,7 @@ void program::rpn_stosub(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_symbol); if (_heap.find(_stack.value(0)) == _heap.end()) { - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); return; } rpn_dup(); @@ -56,7 +57,7 @@ void program::rpn_stomul(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_symbol); if (_heap.find(_stack.value(0)) == _heap.end()) { - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); return; } rpn_dup(); @@ -73,7 +74,7 @@ void program::rpn_stodiv(void) { MIN_ARGUMENTS(2); ARG_MUST_BE_OF_TYPE(0, cmd_symbol); if (_heap.find(_stack.value(0)) == _heap.end()) { - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); return; } rpn_dup(); @@ -90,7 +91,7 @@ void program::rpn_stoneg(void) { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_symbol); if (_heap.find(_stack.value(0)) == _heap.end()) { - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); return; } rpn_dup(); @@ -106,7 +107,7 @@ void program::rpn_stoinv(void) { MIN_ARGUMENTS(1); ARG_MUST_BE_OF_TYPE(0, cmd_symbol); if (_heap.find(_stack.value(0)) == _heap.end()) { - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); return; } rpn_dup(); @@ -131,7 +132,7 @@ void program::rpn_rcl(void) { (void)_stack.pop_front(); _stack.push_front(obj->clone()); } else - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); } /// @brief edit keyword implementation @@ -146,7 +147,7 @@ void program::rpn_edit(void) { _stack.pop(); // set it as the linenoise line entry - linenoisePreloadBuffer((const char*)st.str().c_str()); + Input::preload(st.str().c_str()); } /// @brief recall then eval a symbol variable if it is auto-evaluable @@ -179,7 +180,7 @@ void program::rpn_purge(void) { delete i->second; _heap.erase(i); } else - ERR_CONTEXT(ret_unknown_variable); + setErrorContext(ret_unknown_variable); _stack.pop(); } @@ -199,7 +200,7 @@ void program::rpn_vars(void) { } // parents local variables - while (parent != NULL) { + 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 "; diff --git a/src/rpn-string.cpp b/src/rpn-string.cpp index c4b4ad6..b78b3c4 100644 --- a/src/rpn-string.cpp +++ b/src/rpn-string.cpp @@ -27,7 +27,7 @@ void program::rpn_strout() { _stack.pop(); // make program from string in stack level 1 - if (program::parse(entry, prog) == ret_ok) + if (prog.parse(entry) == ret_ok) // run it prog.run(); } diff --git a/src/rpn-test-framework.cpp b/src/rpn-test-framework.cpp index a127bdb..1b4dd5b 100644 --- a/src/rpn-test-framework.cpp +++ b/src/rpn-test-framework.cpp @@ -1,5 +1,8 @@ #include +using namespace std; +#include "version.h" +#include "escape.h" #include "program.hpp" /// @brief write stack in a string, each entry separated between commas @@ -59,9 +62,9 @@ void program::rpn_test() { string test_filename = _stack.value(0); _stack.pop(); - cout << endl << "rpn version is " << version << endl; + cout << endl << "rpn version is " << RPN_VERSION << endl; test(test_filename, total_tests, total_tests_failed, total_steps, total_steps_failed); - test_show_result("Total", total_tests, total_tests_failed, total_steps, total_steps_failed); + test_show_result("\nTotal", total_tests, total_tests_failed, total_steps, total_steps_failed); } /// @brief load a test file and run its tests @@ -228,7 +231,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail entry = regex_replace(entry, regex("`"), ""); if (!entry.empty()) { program prog(stk, hp); - ret = program::parse(entry, prog); + ret = prog.parse(entry); if (ret == ret_ok) { // run it (void)prog.run(); diff --git a/src/rpn-test.cpp b/src/rpn-test.cpp index feaefe9..09ec315 100644 --- a/src/rpn-test.cpp +++ b/src/rpn-test.cpp @@ -28,7 +28,7 @@ void program::rpn_sup(void) { _stack.push_front(new number(cmp_strings_on_stack_top() == 1)); _stack.erase(1, 2); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief >= keyword implementation @@ -46,7 +46,7 @@ void program::rpn_sup_eq(void) { _stack.push_front(new number(cmp_strings_on_stack_top() != -1)); _stack.erase(1, 2); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief < keyword implementation @@ -64,7 +64,7 @@ void program::rpn_inf(void) { _stack.push_front(new number(cmp_strings_on_stack_top() == -1)); _stack.erase(1, 2); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief <= keyword implementation @@ -80,7 +80,7 @@ void program::rpn_inf_eq(void) { _stack.push_front(new number(cmp_strings_on_stack_top() != 1)); _stack.erase(1, 2); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief != keyword implementation @@ -103,7 +103,7 @@ void program::rpn_diff(void) { _stack.push_front(new number(cmp_strings_on_stack_top() != 0)); _stack.erase(1, 2); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief == keyword implementation @@ -126,7 +126,7 @@ void program::rpn_eq(void) { _stack.push_front(new number(cmp_strings_on_stack_top() == 0)); _stack.erase(1, 2); } else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief and keyword implementation diff --git a/src/rpn-time.cpp b/src/rpn-time.cpp index cb75cec..4a75a1c 100644 --- a/src/rpn-time.cpp +++ b/src/rpn-time.cpp @@ -13,7 +13,7 @@ void program::rpn_time() { clock_gettime(CLOCK_REALTIME, &ts); time_t time = (time_t)ts.tv_sec; tm = localtime(&time); - if (tm != NULL) { + 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); @@ -23,7 +23,7 @@ void program::rpn_time() { _stack.push(new number(date)); _stack.value(0) /= 10000000000.0; } else - ERR_CONTEXT(ret_internal); + setErrorContext(ret_internal); } /// @brief date keyword implementation @@ -37,7 +37,7 @@ void program::rpn_date() { clock_gettime(CLOCK_REALTIME, &ts); time_t time = (time_t)ts.tv_sec; tm = localtime(&time); - if (tm != NULL) { + 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); @@ -47,7 +47,7 @@ void program::rpn_date() { _stack.push(new number(date)); _stack.value(0) /= 1000000.0; } else - ERR_CONTEXT(ret_internal); + setErrorContext(ret_internal); } /// @brief ticks keyword implementation @@ -61,10 +61,10 @@ void program::rpn_ticks() { clock_gettime(CLOCK_REALTIME, &ts); time_t time = (time_t)ts.tv_sec; tm = localtime(&time); - if (tm != NULL) { + if (tm != nullptr) { // date in µs date = 1000000.0 * (double)ts.tv_sec + (double)(ts.tv_nsec / 1000); _stack.push(new number(date)); } else - ERR_CONTEXT(ret_internal); + setErrorContext(ret_internal); } diff --git a/src/rpn-trig.cpp b/src/rpn-trig.cpp index 3bec3d6..7eeca55 100644 --- a/src/rpn-trig.cpp +++ b/src/rpn-trig.cpp @@ -34,7 +34,7 @@ void program::rpn_sin(void) { else if (_stack.type(0) == cmd_complex) _stack.value(0) = sin(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief asin keyword implementation @@ -47,7 +47,7 @@ void program::rpn_asin(void) { else if (_stack.type(0) == cmd_complex) _stack.value(0) = asin(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief cos keyword implementation @@ -60,7 +60,7 @@ void program::rpn_cos(void) { else if (_stack.type(0) == cmd_complex) _stack.value(0) = cos(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief acos keyword implementation @@ -73,7 +73,7 @@ void program::rpn_acos(void) { else if (_stack.type(0) == cmd_complex) _stack.value(0) = acos(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief tan keyword implementation @@ -86,7 +86,7 @@ void program::rpn_tan(void) { else if (_stack.type(0) == cmd_complex) _stack.value(0) = tan(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } /// @brief atan keyword implementation @@ -99,5 +99,5 @@ void program::rpn_atan(void) { else if (_stack.type(0) == cmd_complex) _stack.value(0) = atan(_stack.value(0)); else - ERR_CONTEXT(ret_bad_operand_type); + setErrorContext(ret_bad_operand_type); } diff --git a/src/version.h b/src/version.h index f84606b..52d5a96 100644 --- a/src/version.h +++ b/src/version.h @@ -1,23 +1,2 @@ -// version and soft name #define RPN_VERSION "2.4" -static const string version{RPN_VERSION}; -static const string uname{"rpn v" RPN_VERSION ", (c) 2017 , GNU LGPL v3"}; - -#define XSTR(a) STR(a) -#define STR(a) #a - -// description -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"}; - -// syntax -static const string syntax{ATTR_BOLD "Syntax" ATTR_OFF - ": rpn [command]\n" - "with optional command = list of commands"}; +#define RPN_UNAME "rpn v" RPN_VERSION ", (c) 2017 , GNU LGPL v3"