mirror of
https://github.com/louisrubet/rpn
synced 2025-02-01 07:57:52 +01:00
Merge pull request #236 from louisrubet/#218/google_c++_style
google c++ style
This commit is contained in:
commit
1ffd59e376
34 changed files with 583 additions and 694 deletions
|
@ -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 <louis@rubet.fr>")
|
||||
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
3
TODO.md
3
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
|
||||
|
|
|
@ -7,3 +7,4 @@ Language: Cpp
|
|||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
ColumnLimit: 120
|
||||
AccessModifierOffset: -3
|
7
src/CPPLINT.cfg
Normal file
7
src/CPPLINT.cfg
Normal file
|
@ -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
|
|
@ -1,51 +0,0 @@
|
|||
#ifndef CONSTANT_H
|
||||
#define CONSTANT_H
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
|
||||
// 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
|
18
src/escape.h
18
src/escape.h
|
@ -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
|
|
@ -1,10 +1,13 @@
|
|||
#include "string.h"
|
||||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include "input.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
vector<string>* Input::_acWords = nullptr;
|
||||
|
||||
Input::Input(string& entry, vector<string>& autocompletionWords, string prompt, string mlPrompt) : status(cont) {
|
||||
char* c_entry;
|
||||
char* c_entry = nullptr;
|
||||
bool multiline = false;
|
||||
int entry_len;
|
||||
|
||||
|
@ -35,11 +38,13 @@ Input::Input(string& entry, vector<string>& 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
|
||||
/// this is called by linenoise-ng whenever the user enters TAB
|
||||
|
@ -48,24 +53,20 @@ Input::Input(string& entry, vector<string>& 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);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#ifndef _ENTRY_HPP_
|
||||
#define _ENTRY_HPP_
|
||||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#ifndef SRC_INPUT_HPP_
|
||||
#define SRC_INPUT_HPP_
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#include <cstdio>
|
||||
#include "linenoise.h"
|
||||
|
||||
class Input {
|
||||
|
@ -20,4 +22,4 @@ class Input {
|
|||
static vector<string>* _acWords;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_INPUT_HPP_
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include "lexer.hpp"
|
||||
|
||||
bool Lexer::lexer(string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
|
||||
|
@ -85,19 +87,20 @@ bool Lexer::parseProgram(string& entry, size_t idx, size_t& nextIdx, vector<SynE
|
|||
// 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) == "«"))
|
||||
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);
|
||||
trim(prg);
|
||||
elements.push_back({cmd_program, .value = prg});
|
||||
|
@ -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<int>(a - '0');
|
||||
}
|
||||
if (isdigit(b) && (c == 'b' || c == 'B')) {
|
||||
nextIdx = scan + 3;
|
||||
return 10 * int(a - '0') + int(b - '0');
|
||||
return 10 * static_cast<int>(a - '0') + static_cast<int>(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) {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#ifndef _PARSER_HPP_
|
||||
#define _PARSER_HPP_
|
||||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
#ifndef SRC_LEXER_HPP_
|
||||
#define SRC_LEXER_HPP_
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
#include <mpreal.h>
|
||||
using namespace mpfr;
|
||||
|
||||
#include "constant.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#include "object.hpp"
|
||||
|
||||
class Lexer {
|
||||
|
@ -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_
|
||||
|
|
54
src/main.cpp
54
src/main.cpp
|
@ -1,8 +1,10 @@
|
|||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <csignal>
|
||||
#include <cerrno>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<int>(exp) + 1, value.mpfr_srcptr(),
|
||||
mpreal::get_default_rnd());
|
||||
int nexp = static_cast<int>(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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#ifndef SRC_MPREAL_OUT_HPP_
|
||||
#define SRC_MPREAL_OUT_HPP_
|
||||
|
||||
#include <mpreal.h>
|
||||
using namespace mpfr;
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
using namespace std;
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
#include <mpreal.h>
|
||||
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_
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <mpfr.h>
|
||||
#include <mpreal.h>
|
||||
|
||||
#include "mpreal-out.hpp"
|
||||
using namespace mpfr;
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
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,8 +93,11 @@ 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
|
||||
|
@ -101,10 +125,12 @@ struct number : object {
|
|||
///
|
||||
struct ocomplex : object {
|
||||
ocomplex() : object(cmd_complex), reBase(10), imBase(10) {}
|
||||
ocomplex(complex<mpreal>& value_, int reb = 10, int imb = 10) : object(cmd_complex), reBase(reb), imBase(imb) {
|
||||
explicit ocomplex(complex<mpreal>& 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<size_t>(-1);
|
||||
arg2 = static_cast<size_t>(-1);
|
||||
arg3 = static_cast<size_t>(-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_
|
||||
|
|
172
src/program.cpp
172
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::keyword_t> program::_keywords{
|
|||
{cmd_keyword, "ticks", &program::rpn_ticks, "system tick in µs"},
|
||||
};
|
||||
|
||||
/// keywords map for lexer
|
||||
map<string, Lexer::ReservedWord> program::_keywordsMap;
|
||||
|
||||
/// autocompletion vector for linenoise autocompletion
|
||||
vector<string> program::_autocompletionWords;
|
||||
|
||||
vector<string>& program::getAutocompletionWords() {
|
||||
if (_autocompletionWords.empty())
|
||||
static vector<string> 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<symbol*>(o));
|
||||
i++;
|
||||
break;
|
||||
|
||||
// a keyword
|
||||
case cmd_keyword: {
|
||||
keyword* k = (keyword*)o;
|
||||
keyword* k = reinterpret_cast<keyword*>(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,7 +277,7 @@ ret_value program::run() {
|
|||
// a branch keyword
|
||||
case cmd_branch: {
|
||||
// call matching function
|
||||
branch* b = (branch*)o;
|
||||
branch* b = reinterpret_cast<branch*>(o);
|
||||
size_t next_cmd = (this->*(b->fn))(*b);
|
||||
switch (next_cmd) {
|
||||
case step_out: // step out
|
||||
|
@ -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<struct if_layout_t> 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<branch*>(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<branch*>(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<branch*>(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<branch*>(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<branch*>(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<branch*>(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<branch*>(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<string, Lexer::ReservedWord> keywordsMap;
|
||||
vector<Lexer::SynElement> elements;
|
||||
vector<Lexer::SynError> 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<size_t>(_err) < errorStrings.size())
|
||||
cerr << _err_context << ": error " << _err << ": " << errorStrings[_err] << endl;
|
||||
else
|
||||
cerr << _err_context << " (unknown error code)" << endl;
|
||||
|
@ -701,16 +691,16 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -718,9 +708,9 @@ void program::show_stack(rpnstack& st, bool show_separator) {
|
|||
///
|
||||
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);
|
||||
|
|
|
@ -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 <deque>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
#include <mpreal.h>
|
||||
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<object*>, public Lexer {
|
||||
public:
|
||||
program(rpnstack& stk, heap& hp, program* parent = nullptr) : _stack(stk), _heap(hp), _parent(parent) {
|
||||
interrupt_now = false;
|
||||
}
|
||||
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<object*>, 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<object*>, 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<string>& getAutocompletionWords();
|
||||
|
||||
private:
|
||||
bool interrupt_now;
|
||||
|
||||
// current error and its context
|
||||
ret_value _err;
|
||||
string _err_context;
|
||||
|
@ -81,8 +65,6 @@ class program : public deque<object*>, public Lexer {
|
|||
// parent prog for inheriting heaps
|
||||
program* _parent;
|
||||
|
||||
int stack_size() { return _stack.size(); }
|
||||
|
||||
private:
|
||||
// keywords
|
||||
struct keyword_t {
|
||||
|
@ -92,8 +74,6 @@ class program : public deque<object*>, public Lexer {
|
|||
string comment;
|
||||
};
|
||||
static vector<keyword_t> _keywords;
|
||||
static map<string, Lexer::ReservedWord> _keywordsMap;
|
||||
static vector<string> _autocompletionWords;
|
||||
|
||||
// keywords implementation
|
||||
////
|
||||
|
@ -113,7 +93,7 @@ class program : public deque<object*>, 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<size_t>(-1), runtime_error = static_cast<size_t>(-2) };
|
||||
|
||||
// complex
|
||||
void rpn_re();
|
||||
|
@ -233,14 +213,11 @@ class program : public deque<object*>, 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<object*>, 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_
|
||||
|
|
|
@ -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<branch*>(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<branch*>(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<number>(0) == 0) ret = myobj.arg1;
|
||||
_stack.pop();
|
||||
}
|
||||
} else if (myobj.arg2 != step_out) {
|
||||
// arg2 = index of while+1 in case of while..repeat..end
|
||||
else if (myobj.arg2 != step_out)
|
||||
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<number>(1) != 0) {
|
||||
if (_stack.value<number>(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<number>(1);
|
||||
myobj.lastIndex = _stack.value<number>(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<symbol*>(at(myobj.arg1)); // arg1 = loop variable index
|
||||
|
||||
// loop boundaries
|
||||
myobj.firstIndex = _stack.value<number>(1);
|
||||
myobj.lastIndex = _stack.value<number>(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<branch*>(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<symbol*>(at(start_or_for->arg1));
|
||||
|
||||
// store symbol variable (asserted existing in the local heap)
|
||||
((number*)_local_heap[var->value])->value = myobj.firstIndex;
|
||||
reinterpret_cast<number*>(_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<branch*>(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<symbol*>(at(start_or_for->arg1));
|
||||
// increase symbol variable
|
||||
((number*)_local_heap[var->value])->value = myobj.firstIndex;
|
||||
reinterpret_cast<number*>(_local_heap[var->value])->value = myobj.firstIndex;
|
||||
}
|
||||
|
||||
// test loop value is out of range
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include "program.hpp"
|
||||
|
||||
/// @brief re keyword implementation
|
||||
|
|
|
@ -1,26 +1,31 @@
|
|||
#include <cstdio>
|
||||
#include "linenoise.h"
|
||||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#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<string, mpfr_rnd_t> _mpfr_round{{"nearest (even)", MPFR_RNDN},
|
||||
{"toward zero", MPFR_RNDZ},
|
||||
|
@ -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<int>(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,16 +114,17 @@ void program::rpn_std() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
double digits = double(_stack.value<number>(0));
|
||||
int digits = static_cast<int>(_stack.value<number>(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,16 +132,17 @@ void program::rpn_fix() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
double digits = double(_stack.value<number>(0));
|
||||
int digits = static_cast<int>(_stack.value<number>(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,16 +150,17 @@ void program::rpn_sci() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
double digits = double(_stack.value<number>(0));
|
||||
int digits = static_cast<int>(_stack.value<number>(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<number>(0).toULong();
|
||||
if (prec >= (unsigned long)MPFR_PREC_MIN && prec <= (unsigned long)MPFR_PREC_MAX) {
|
||||
int prec = static_cast<int>(_stack.value<number>(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,9 +212,10 @@ 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
|
||||
///
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include "program.hpp"
|
||||
|
||||
/// @brief e keyword implementation
|
||||
|
|
|
@ -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<oprogram>(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++;
|
||||
if (at(i)->_type == cmd_symbol) {
|
||||
count_symbols++;
|
||||
} else if (at(i)->_type == cmd_program) {
|
||||
// stop if prog
|
||||
else if (at(i)->_type == cmd_program) {
|
||||
prog_found = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// found something other than symbol
|
||||
else {
|
||||
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<symbol*>(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<oprogram*>(at(myobj.arg1 + count_symbols + 1))->value;
|
||||
program prog(_stack, _heap, this);
|
||||
|
||||
// make the program from entry
|
||||
|
|
131
src/rpn-real.cpp
131
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<ostring>(1) += _stack.value<ostring>(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<number>(1) += _stack.value<number>(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<ocomplex>(1) += _stack.value<ocomplex>(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<ocomplex>(1) += _stack.value<number>(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<ocomplex>(1) += _stack.value<number>(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<number>(1) -= _stack.value<number>(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<ocomplex>(1) -= _stack.value<ocomplex>(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<ocomplex>(1) -= _stack.value<number>(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<ocomplex>(1) = _stack.value<number>(0) - _stack.value<ocomplex>(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<number>(1) *= _stack.value<number>(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<ocomplex>(1) *= _stack.value<ocomplex>(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<ocomplex>(1) *= _stack.value<number>(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<ocomplex>(1) *= _stack.value<number>(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<number>(1) /= _stack.value<number>(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<ocomplex>(1) /= _stack.value<ocomplex>(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<ocomplex>(1) /= _stack.value<number>(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<ocomplex>(1) = _stack.value<number>(0) / _stack.value<ocomplex>(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<number>(0) = -_stack.value<number>(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<number>(0) = 1 / _stack.value<number>(0);
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = mpreal{1} / _stack.value<ocomplex>(0);
|
||||
_stack.value<ocomplex>(0) = mpreal(1) / _stack.value<ocomplex>(0);
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
@ -171,9 +141,10 @@ void program::rpn_power() {
|
|||
rpn_swap();
|
||||
_stack.value<ocomplex>(1) = pow(_stack.value<number>(0), _stack.value<ocomplex>(1));
|
||||
_stack.pop();
|
||||
} else
|
||||
} else {
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief sqrt keyword implementation
|
||||
///
|
||||
|
@ -185,74 +156,81 @@ void program::rpn_squareroot() {
|
|||
} else {
|
||||
// negative number -> square root is complex
|
||||
mpreal zero;
|
||||
_stack.push(new ocomplex(_stack.value<number>(0), zero, _stack.obj<number>(0).base)); // TODO manage new errors
|
||||
_stack.push(new ocomplex(_stack.value<number>(0), zero,
|
||||
_stack.obj<number>(0).base)); // TODO(louis) manage new errors
|
||||
_stack.value<ocomplex>(0) = sqrt(_stack.value<ocomplex>(0));
|
||||
_stack.erase(1);
|
||||
}
|
||||
} else if (_stack.type(0) == cmd_complex)
|
||||
} else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.value<ocomplex>(0) = sqrt(_stack.value<ocomplex>(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<number>(0).base = 16;
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
} else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.obj<ocomplex>(0).reBase = 16;
|
||||
_stack.obj<ocomplex>(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<number>(0).base = 2;
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
} else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.obj<ocomplex>(0).reBase = 2;
|
||||
_stack.obj<ocomplex>(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<number>(0).base = 10;
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
} else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.obj<ocomplex>(0).reBase = 10;
|
||||
_stack.obj<ocomplex>(0).imBase = 10;
|
||||
} else
|
||||
} else {
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief base keyword implementation
|
||||
///
|
||||
void program::rpn_base() {
|
||||
MIN_ARGUMENTS(2);
|
||||
if (_stack.type(1) == cmd_number || _stack.type(1) == cmd_complex) {
|
||||
int base = (int)_stack.value<number>(0).toLong();
|
||||
int base = static_cast<int>(_stack.value<number>(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<number>(0).base = base;
|
||||
else {
|
||||
} else {
|
||||
_stack.obj<ocomplex>(0).reBase = base;
|
||||
_stack.obj<ocomplex>(0).imBase = base;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
setErrorContext(ret_out_of_range);
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief % (purcent) keyword implementation
|
||||
///
|
||||
|
@ -300,14 +278,15 @@ 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<number>(0) = abs(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
} else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.push(new number(abs(_stack.value<ocomplex>(0))));
|
||||
_stack.erase(1);
|
||||
} else
|
||||
} else {
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief fact (factorial) keyword implementation
|
||||
///
|
||||
|
|
|
@ -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<number>(0).toLong();
|
||||
int args = static_cast<int>(_stack.value<number>(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<int>(_stack.value<number>(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<number>(0);
|
||||
int to_pick = static_cast<int>(_stack.value<number>(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<int>(_stack.value<number>(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<int>(_stack.value<number>(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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ostring>(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,11 +131,12 @@ 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,11 +166,13 @@ 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 "<<i+1<<": name '"<<name<<"', type "<<obj->name()<<", value ";
|
||||
obj->show(cout);
|
||||
cout<<endl;
|
||||
for (auto i : _heap) {
|
||||
cout << "var " << index++ << ": name '" << i.first << "', type " << i.second->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 "<<i+1<<": name '"<<name<<"', type "<<obj->name()<<", value ";
|
||||
obj->show(cout);
|
||||
cout<<endl;
|
||||
for (auto i : parent->_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 "<<i+1<<": name '"<<name<<"', type "<<obj->name()<<", value ";
|
||||
obj->show(cout);
|
||||
cout<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief clusr keyword implementation
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#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<number>(0);
|
||||
char the_chr = static_cast<char>(_stack.value<number>(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<ostring>(1).find(_stack.value<ostring>(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<number>(1);
|
||||
size_t len = (size_t)_stack.value<number>(0) - first + 1;
|
||||
size_t first = _stack.value<number>(1).toULong();
|
||||
size_t len = _stack.value<number>(0).toULong() - first + 1;
|
||||
first--;
|
||||
|
||||
if (first > _stack.value<ostring>(2).size()) first = len = 0;
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
#include "escape.h"
|
||||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include <string>
|
||||
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
|
||||
|
@ -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<int>(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<int>(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<int>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ostring>(1).compare(_stack.value<ostring>(0));
|
||||
(void)_stack.pop_front(2);
|
||||
int res = stk.value<ostring>(1).compare(stk.value<ostring>(0));
|
||||
stk.erase(0, 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -17,113 +19,98 @@ 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<number>(1) > _stack.value<number>(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<number>(1) >= _stack.value<number>(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<number>(1) < _stack.value<number>(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<number>(1) <= _stack.value<number>(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<number>(1) != _stack.value<number>(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<ocomplex>(1) != _stack.value<ocomplex>(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<number>(1) == _stack.value<number>(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<ocomplex>(1) == _stack.value<ocomplex>(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<number>(0) != 0 && _stack.value<number>(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<number>(0) != 0 || _stack.value<number>(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<number>(0) != 0 ^ _stack.value<number>(1) != 0)
|
||||
_stack.push(new number(1));
|
||||
else
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "program.hpp"
|
||||
|
@ -15,16 +17,17 @@ 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<double>(tm->tm_hour) * 10000000000.0 + static_cast<double>(tm->tm_min) * 100000000.0 +
|
||||
static_cast<double>(tm->tm_sec) * 1000000.0 + static_cast<double>(ts.tv_nsec / 1000));
|
||||
|
||||
// push it
|
||||
// division after push for real precision
|
||||
_stack.push(new number(date));
|
||||
_stack.value<number>(0) /= 10000000000.0;
|
||||
} else
|
||||
} else {
|
||||
setErrorContext(ret_internal);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief date keyword implementation
|
||||
///
|
||||
|
@ -39,16 +42,18 @@ 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<double>(tm->tm_mon + 1) * 1000000.0 + static_cast<double>(tm->tm_mday) * 10000.0 +
|
||||
static_cast<double>(tm->tm_year + 1900);
|
||||
|
||||
// push it
|
||||
number* num;
|
||||
// division after push for real precision
|
||||
_stack.push(new number(date));
|
||||
_stack.value<number>(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<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec / 1000);
|
||||
_stack.push(new number(date));
|
||||
} else
|
||||
} else {
|
||||
setErrorContext(ret_internal);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<number>(0) = sin(_stack.value<number>(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<number>(0) = asin(_stack.value<number>(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<number>(0) = cos(_stack.value<number>(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<number>(0) = acos(_stack.value<number>(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<number>(0) = tan(_stack.value<number>(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<number>(0) = atan(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
#ifndef __stack_h__
|
||||
#define __stack_h__
|
||||
// Copyright (c) 2014-2022 Louis Rubet
|
||||
|
||||
#include <string.h>
|
||||
#ifndef SRC_STACK_HPP_
|
||||
#define SRC_STACK_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#include "object.hpp"
|
||||
using namespace std;
|
||||
|
||||
/// @brief stack object, parens of program, storing execution stack values or programs
|
||||
///
|
||||
|
@ -20,37 +21,17 @@ class rpnstack : public deque<object*> {
|
|||
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;
|
||||
|
@ -83,43 +64,14 @@ class heap : public map<string, object*> {
|
|||
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;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __stack_h__
|
||||
#endif // SRC_STACK_HPP_
|
||||
|
|
|
@ -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 <louis@rubet.fr>, GNU LGPL v3"
|
||||
|
||||
#endif // SRC_VERSION_H_
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
Loading…
Add table
Reference in a new issue