refactoring I (objects)

This commit is contained in:
Louis Rubet 2022-02-07 16:36:27 +01:00
parent 84f54d073b
commit d3970d403b
25 changed files with 1149 additions and 1778 deletions

3
.gitmodules vendored
View file

@ -4,3 +4,6 @@
[submodule "linenoise-ng"]
path = linenoise-ng
url = git@github.com:louisrubet/linenoise-ng.git
[submodule "mpreal"]
path = mpreal
url = https://github.com/advanpix/mpreal

View file

@ -24,7 +24,8 @@ set(RPN_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
# compiler options
if(CMAKE_COMPILER_IS_GNUCXX)
message(STATUS "Compiler type GNU: ${CMAKE_CXX_COMPILER}")
set(BASE_COMPILER_OPTIONS "-std=c++0x -Wl,--no-as-needed")
# TODO still up to date?
set(BASE_COMPILER_OPTIONS "-std=c++14 -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 -fomit-frame-pointer -s")
@ -37,8 +38,15 @@ if(NOT EXISTS "${PROJECT_SOURCE_DIR}/linenoise-ng/.git")
execute_process(COMMAND git checkout v1.1.1-rpn WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/linenoise-ng)
endif()
# custom mpreal
if(NOT EXISTS "${PROJECT_SOURCE_DIR}/mpreal/.git")
execute_process(COMMAND git submodule init ${PROJECT_SOURCE_DIR}/mpreal)
execute_process(COMMAND git submodule update ${PROJECT_SOURCE_DIR}/mpreal)
execute_process(COMMAND git checkout mpfrc++-3.6.9 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/mpreal)
endif()
# includes
include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/linenoise-ng/include)
include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/linenoise-ng/include ${PROJECT_SOURCE_DIR}/mpreal)
# build
add_executable(
@ -47,19 +55,19 @@ add_executable(
${PROJECT_SOURCE_DIR}/src/object.cpp
${PROJECT_SOURCE_DIR}/src/program.cpp
${PROJECT_SOURCE_DIR}/src/parse.cpp
${PROJECT_SOURCE_DIR}/src/rpn-branch.cpp
${PROJECT_SOURCE_DIR}/src/rpn-complex.cpp
#${PROJECT_SOURCE_DIR}/src/rpn-branch.cpp
#${PROJECT_SOURCE_DIR}/src/rpn-complex.cpp
${PROJECT_SOURCE_DIR}/src/rpn-general.cpp
${PROJECT_SOURCE_DIR}/src/rpn-logs.cpp
#${PROJECT_SOURCE_DIR}/src/rpn-logs.cpp
${PROJECT_SOURCE_DIR}/src/rpn-program.cpp
${PROJECT_SOURCE_DIR}/src/rpn-real.cpp
#${PROJECT_SOURCE_DIR}/src/rpn-real.cpp
${PROJECT_SOURCE_DIR}/src/rpn-stack.cpp
${PROJECT_SOURCE_DIR}/src/rpn-store.cpp
${PROJECT_SOURCE_DIR}/src/rpn-string.cpp
#${PROJECT_SOURCE_DIR}/src/rpn-string.cpp
${PROJECT_SOURCE_DIR}/src/rpn-test.cpp
${PROJECT_SOURCE_DIR}/src/rpn-test-core.cpp
${PROJECT_SOURCE_DIR}/src/rpn-time.cpp
${PROJECT_SOURCE_DIR}/src/rpn-trig.cpp
#${PROJECT_SOURCE_DIR}/src/rpn-time.cpp
#${PROJECT_SOURCE_DIR}/src/rpn-trig.cpp
${PROJECT_SOURCE_DIR}/linenoise-ng/src/ConvertUTF.cpp
${PROJECT_SOURCE_DIR}/linenoise-ng/src/linenoise.cpp
${PROJECT_SOURCE_DIR}/linenoise-ng/src/wcwidth.cpp

1
mpreal Submodule

@ -0,0 +1 @@
Subproject commit c45d0d522c9bd0dd16d7aac25fa0862dd074ddb0

View file

@ -1,6 +1,7 @@
#ifndef CONSTANT_H
#define CONSTANT_H
#define MPFR_USE_NO_MACRO
#include <mpfr.h>
// default values
@ -66,6 +67,7 @@ typedef enum {
ret_div_by_zero,
ret_runtime_error,
ret_abort_current_entry,
ret_out_of_memory,
ret_max
} ret_value;
@ -73,7 +75,7 @@ typedef enum {
{ \
"ok", "unknown command", "missing operand", "bad operand type", "out of range", "unknown variable", \
"internal error, aborting", "deadly", "goodbye", "not implemented", "no operation", "syntax error", \
"division by zero", "runtime error", "aborted current entry" \
"division by zero", "runtime error", "aborted current entry", "out of memory" \
}
// command types

View file

@ -83,6 +83,4 @@ static void chrono_print(int chrono) {
}
}
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif

View file

@ -12,7 +12,7 @@
#include "program.hpp"
static heap s_global_heap;
static stack s_global_stack;
static rpnstack s_global_stack;
static program* s_prog_to_interrupt = NULL;
/// @brief actions to be done at rpn exit
@ -151,7 +151,7 @@ int main(int argc, char* argv[]) {
}
// make program
ret = program::parse(entry.c_str(), prog);
ret = program::parse(entry, prog);
if (ret == ret_ok) {
string separator = "";

View file

@ -3,23 +3,27 @@
using namespace std;
#include "constant.h"
#include "mpfr.h"
#define MPFR_USE_NO_MACRO
#include <mpfr.h>
#include "object.hpp"
// floating_t statics
mpfr_prec_t floating_t::s_mpfr_prec = MPFR_DEFAULT_PREC_BITS;
mpfr_rnd_t floating_t::s_mpfr_rnd = MPFR_DEFAULT_RND;
unsigned int floating_t::s_mpfr_prec_bytes = MPFR_DEFAULT_STORING_LENGTH_BYTES;
const char* floating_t::s_mpfr_rnd_str[5] = MPFR_RND_STRINGS;
// TODO remove
// some statics
// mpfr_prec_t floating_t::s_mpfr_prec = MPFR_DEFAULT_PREC_BITS;
// mpfr_rnd_t floating_t::s_mpfr_rnd = MPFR_DEFAULT_RND;
// number statics
number::mode_enum number::s_mode = DEFAULT_MODE;
int number::s_decimal_digits = DEFAULT_DECIMAL_DIGITS;
mpfr_prec_t number::s_mpfr_prec = MPFR_DEFAULT_PREC_BITS;
mpfr_rnd_t number::s_mpfr_rnd = MPFR_DEFAULT_RND;
string number::s_mpfr_printf_format = string(MPFR_DEFAULT_FORMAT);
const char* number::s_mpfr_rnd_str[5] = MPFR_RND_STRINGS;
//
const char* object::s_cmd_type_string[cmd_max] = CMD_TYPE_STRINGS;
#if 0
/// @brief return if a mpfr is higher to a given precision
/// this function is directly copied from mpfr
///
@ -226,3 +230,4 @@ void object::show(FILE* stream) {
break;
}
}
#endif

View file

@ -1,11 +1,15 @@
#ifndef OBJECT_HPP
#define OBJECT_HPP
#include <mpfr.h>
#include <string.h>
#include <mpreal.h>
using namespace mpfr;
#include <ostream>
#include <iomanip>
using namespace std;
// definitions for objects
////
///
typedef enum {
cmd_undef,
cmd_number, // floating point number
@ -24,60 +28,20 @@ class branch;
typedef void (program::*program_fn_t)(void);
typedef int (program::*branch_fn_t)(branch&);
/// @brief MPFR (floating point) object
///
struct floating_t {
mpfr_prec_t mpfr_prec; // precision in bits
unsigned int mpfr_prec_bytes; // significand storing length in bytes
mpfr_t mpfr; // mpfr object
void init() {
void* significand = (void*)(this + 1);
mpfr_prec = s_mpfr_prec;
mpfr_prec_bytes = s_mpfr_prec_bytes;
mpfr_custom_init(significand, MPFR_DEFAULT_PREC_BITS);
mpfr_custom_init_set(mpfr, MPFR_ZERO_KIND, 0, mpfr_prec, significand);
}
void move() {
void* significand = (void*)(this + 1);
mpfr_custom_move(mpfr, significand);
}
floating_t& operator=(const double val) { mpfr_set_d(mpfr, val, s_mpfr_rnd); return *this; }
floating_t& operator=(const long int val) { mpfr_set_si(mpfr, val, s_mpfr_rnd); return *this; }
floating_t& operator=(const unsigned long val) { mpfr_set_ui(mpfr, val, s_mpfr_rnd); return *this; }
operator double() { return mpfr_get_d(mpfr, s_mpfr_rnd); }
operator int() { return (int)mpfr_get_si(mpfr, s_mpfr_rnd); }
operator long() { return mpfr_get_si(mpfr, s_mpfr_rnd); }
bool operator>(const floating_t right) { return mpfr_cmp(mpfr, right.mpfr) > 0; }
bool operator<(const floating_t right) { return mpfr_cmp(mpfr, right.mpfr) < 0; }
// default precision in bits, precision length in bytes, rounding mode
static mpfr_prec_t s_mpfr_prec;
static unsigned int s_mpfr_prec_bytes;
static mpfr_rnd_t s_mpfr_rnd;
static const char* s_mpfr_rnd_str[5];
};
/// @brief object - a generic stack object
///
struct object {
object(cmd_type_t type = cmd_undef) : _type(type) {}
// object type
cmd_type_t _type;
unsigned int _size;
//
unsigned int size() { return _size; }
void show(FILE* stream = stdout);
auto duplicate() {
cout << "typeid(this).name()=" << typeid(this).name() << endl;
return *new decltype(this);
}
virtual string name() { return string("object"); }
virtual void show(ostream& out) { out << "(" << name() << " - unknown representation)"; }
unsigned int size() { return sizeof(*this); }
//
static const char* s_cmd_type_string[cmd_max];
@ -85,33 +49,45 @@ struct object {
/// @brief stack objects derived from object
///
struct number : public object {
// members
enum { dec, hex, bin, base } _representation;
// base
// carefull: _base is used only if _representation = base
int _base;
// mind that float value is at the end of the object
// because its mantissa is just after the obj in memory
floating_t _value;
struct number : object {
typedef enum { dec, hex, bin, base } repr_enum;
number(repr_enum representation = dec) : object(cmd_number), _representation(representation) { _value = 0L; }
number(mpreal& value, repr_enum representation = dec) : number(representation) { _value = value; }
number(long value, repr_enum representation = dec) : number(representation) { _value = value; }
number(unsigned long value, repr_enum representation = dec) : number(representation) { _value = value; }
number(double value, repr_enum representation = dec) : number(representation) { _value = value; }
// publics
number() { _type = cmd_number; }
repr_enum _representation;
int _base; // carefull: _base is used only if _representation = base
void init() {
_type = cmd_number;
_representation = dec;
_value.init();
mpreal _value;
void init() {}
void set(unsigned long value) { _value = value; }
virtual string name() { return string("number"); }
virtual void show(ostream& out) {
if (_representation != number::dec) {
object::show(out);
return;
}
switch (number::s_mode) {
case number::std:
out.unsetf(ios::floatfield);
out << setprecision(s_decimal_digits) << _value;
break;
case number::fix:
out << fixed << setprecision(s_decimal_digits) << _value;
break;
case number::sci:
out << scientific << setprecision(s_decimal_digits) << _value;
break;
default:
object::show(out);
break;
}
void move() { _value.move(); }
void set(unsigned long value) {
_type = cmd_number;
_value = value;
}
static unsigned int calc_size() { return (unsigned int)(sizeof(number) + floating_t::s_mpfr_prec_bytes); }
// representation mode
typedef enum { std, fix, sci } mode_enum;
@ -119,137 +95,115 @@ struct number : public object {
// precision
static int s_decimal_digits;
static mpfr_prec_t s_mpfr_prec;
static mpfr_rnd_t s_mpfr_rnd;
static string s_mpfr_printf_format;
static const char* s_mpfr_rnd_str[5];
};
/// @brief stack objects derived from object
///
struct complex : public object {
enum { dec, hex } _representation;
// mind that re float value is at the end of the object
// because its mantissa is just after the obj in memory
floating_t _re;
struct ocomplex : object {
number::repr_enum _representation;
ocomplex() : object(cmd_complex) { init(); }
complex() { _type = cmd_complex; }
mpreal _re;
mpreal _im;
// re and im float values are at the end of the object
floating_t* re() { return &_re; }
floating_t* im() { return (floating_t*)((char*)&_re + sizeof(floating_t) + _re.mpfr_prec_bytes); }
mpreal* re() { return &_re; }
mpreal* im() { return &_im; }
void init() {
_type = cmd_complex;
_representation = dec;
re()->init();
im()->init();
void init() {}
virtual string name() { return string("complex"); }
virtual void show(ostream& out) {
if (_representation != number::dec) {
object::show(out);
return;
}
void move() {
re()->move();
im()->move();
switch (number::s_mode) {
case number::std:
out.unsetf(ios::floatfield);
out << setprecision(number::s_decimal_digits) << "(" << _re << ", " << _im << ")";
case number::fix:
out << fixed << setprecision(number::s_decimal_digits) << "(" << _re << ", " << _im << ")";
break;
case number::sci:
out << scientific << setprecision(number::s_decimal_digits) << "(" << _re << ", " << _im << ")";
break;
default:
object::show(out);
break;
}
static unsigned int calc_size() {
return (unsigned int)(sizeof(complex) + 2 * (sizeof(floating_t) + floating_t::s_mpfr_prec_bytes));
}
};
/// @brief object string
///
struct ostring : public object {
// ostring may first have been allocated with len+1 bytes
void set(const char* value, unsigned int len) {
_type = cmd_string;
if (value != NULL) {
if (len > 0) (void)memcpy(_value, value, len);
_value[len] = 0;
_len = len;
} else {
_value[_len] = 0;
_len = 0;
}
}
struct ostring : object {
ostring() : object(cmd_string) {}
ostring(const string& value) : object(cmd_string) { set(value); }
ostring(const char* value) : object(cmd_string) { _value = string(value); }
void set(const string& value) { _value = value; }
virtual string name() { return string("complex"); }
virtual void show(ostream& out) { out << "\"" << _value << "\""; }
// length of _value, not including the terminal '\0'
unsigned int _len;
char _value[0];
string _value;
};
/// @brief object program
///
struct oprogram : public object {
// oprogram may first have been allocated with len+1 bytes
void set(const char* value, unsigned int len) {
_type = cmd_program;
if (value != NULL) {
if (len > 0) (void)memcpy(_value, value, len);
_value[len] = 0;
_len = len;
} else {
_value[0] = 0;
_len = 0;
}
}
// length of _value, not includiong the terminal '\0'
unsigned int _len;
char _value[0];
struct oprogram : object {
oprogram() : object(cmd_program) {}
oprogram(const string& value) : object(cmd_program) { set(value); }
void set(const string& value) { _value = value; }
virtual string name() { return string("program"); }
virtual void show(ostream& out) { out << "<< " << _value << " >>"; }
string _value;
};
/// @brief object symbol
///
struct symbol : public object {
// symbol may first have been allocated with len+1 bytes
void set(const char* value, unsigned int len, bool auto_eval) {
_type = cmd_symbol;
struct symbol : object {
symbol(bool auto_eval = true) : object(cmd_symbol), _auto_eval(auto_eval) {}
symbol(const string& value, bool auto_eval = true) : object(cmd_symbol) { set(value, auto_eval); }
void set(string& value, bool auto_eval) {
_value = value;
_auto_eval = auto_eval;
if (value != NULL) {
if (len > 0) (void)memcpy(_value, value, len);
_value[len] = 0;
_len = len;
} else {
_value[0] = 0;
_len = 0;
}
void set(const string& value, bool auto_eval) {
_value = value;
_auto_eval = auto_eval;
}
//
virtual string name() { return string("symbol"); }
virtual void show(ostream& out) { out << "'" << _value << "'"; }
bool _auto_eval;
// length of _value, not includiong the terminal '\0'
unsigned int _len;
char _value[0];
string _value;
};
/// @brief object keyword
///
struct keyword : public object {
// keyword may first have been allocated with len+1 bytes
void set(program_fn_t fn, const char* value, unsigned int len) {
_type = cmd_keyword;
struct keyword : object {
keyword() : object(cmd_keyword) {}
keyword(program_fn_t fn, const string& value) : object(cmd_keyword) { set(fn, value); }
void set(program_fn_t fn, const string& value) {
_fn = fn;
if (value != NULL) {
if (len > 0) (void)memcpy(_value, value, len);
_value[len] = 0;
_len = len;
} else {
_value[0] = 0;
_len = 0;
_value = value;
}
}
//
virtual string name() { return string("keyword"); }
program_fn_t _fn;
// length of _value, not includiong the terminal '\0'
unsigned int _len;
char _value[0];
string _value;
};
/// @brief object branch
///
struct branch : public object {
struct branch : object {
branch() : object(cmd_branch) {}
branch(branch_fn_t fn, const string& value) : object(cmd_branch) { set(fn, value); }
virtual string name() { return string("branch"); }
//
void set(branch_fn_t fn, const char* value, unsigned int len) {
_type = cmd_branch;
void set(branch_fn_t fn, const string& value) {
_fn = fn;
arg1 = -1;
arg2 = -1;
@ -257,26 +211,13 @@ struct branch : public object {
farg1 = NULL;
farg2 = NULL;
arg_bool = 0;
if (value != NULL) {
if (len > 0) (void)memcpy(_value, value, len);
_value[len] = 0;
_len = len;
} else {
_value[0] = 0;
_len = 0;
_value = value;
}
}
// branch function
branch_fn_t _fn;
// args used by cmd_branch cmds
int arg1, arg2, arg3;
number *farg1, *farg2;
bool arg_bool;
// length of _value, not includiong the terminal '\0'
unsigned int _len;
char _value[0];
string _value;
};
#endif

View file

@ -70,7 +70,7 @@ ret_value program::entry(program& prog) {
entry_str += entry;
// parse it
ret = parse(entry_str.c_str(), prog);
ret = parse(entry_str, prog);
// keep history
if (entry[0] != 0) (void)linenoiseHistoryAdd(entry_str.c_str());
@ -84,514 +84,256 @@ ret_value program::entry(program& prog) {
return ret;
}
/// @brief return function pointer from function name
///
/// @param fn_name function name
/// @param fn function pointer
/// @param type the function type (cmd_keyword or cmd_branch)
/// @return ret_value see this type
///
ret_value program::get_fn(const char* fn_name, program_fn_t& fn, cmd_type_t& type) {
unsigned int i = 0;
while (s_keywords[i].type != cmd_max) {
if (strncasecmp(fn_name, s_keywords[i].name, sizeof(s_keywords[i].name)) == 0) {
fn = s_keywords[i].fn;
type = s_keywords[i].type;
return ret_ok;
}
i++;
}
return ret_unknown_err;
}
/// @brief get a keyword object from entry and add it to a program
///
/// @param entry the entry
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added
/// @return false no object was added
///
static bool get_keyword(const string& entry, program& prog, string& remaining_entry) {
program_fn_t fn;
unsigned int obj_len;
struct SynElement {
cmd_type_t type;
bool ret = false;
string value;
mpreal re;
mpreal im;
program_fn_t fn;
bool operator==(SynElement& other) {
return type == other.type && value == other.value && (re == other.re || (isnan(re) && isnan(other.re))) &&
(im == other.im || (isnan(im) && isnan(other.im)));
}
};
// could be a command
if (program::get_fn(entry.c_str(), fn, type) == ret_ok) {
if (type == cmd_keyword) {
// allocate keyword object
obj_len = sizeof(keyword) + entry.size() + 1;
keyword* new_obj = (keyword*)prog.allocate_back(obj_len, cmd_keyword);
new_obj->set(fn, entry.c_str(), entry.size());
ret = true;
} else if (type == cmd_branch) {
// allocate branch object
obj_len = sizeof(branch) + entry.size() + 1;
branch* new_obj = (branch*)prog.allocate_back(obj_len, cmd_branch);
new_obj->set((branch_fn_t)fn, entry.c_str(), entry.size());
ret = true;
struct SynError {
size_t indx;
string err;
bool operator==(SynError& other) { return err == other.err; }
};
struct ReservedWord {
cmd_type_t type;
program_fn_t fn;
};
static map<string, ReservedWord> _keywordsMap;
static bool parseString(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
vector<SynElement>& elements) {
// here we are sure that entry[0] is '"'
for (size_t i = idx + 1; i < entry.size(); i++) {
if (entry[i] == '"') {
if (entry[i] - 1 != '\\') {
elements.push_back({cmd_string, .value = entry.substr(idx + 1, i - idx - 1)});
nextIdx = i + 1;
return true;
}
}
return ret;
}
errors.push_back({entry.size(), "unterminated string"});
return false;
}
/// @brief get a symbol object from entry and add it to a program
///
/// @param entry the entry
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added
/// @return false no object was added
///
static bool get_symbol(const string& entry, program& prog, string& remaining_entry) {
bool ret = false;
int entry_len = entry.size();
unsigned int obj_len;
static bool parseSymbol(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
vector<SynElement>& elements) {
// here we are sure that entry[0] is '\''
for (size_t i = idx + 1; i < entry.size(); i++) {
if (entry[i] == '\'') {
elements.push_back({cmd_symbol, .value = entry.substr(idx + 1, i - idx - 1)});
nextIdx = i + 1;
return true;
}
}
errors.push_back({entry.size(), "unterminated symbol"});
return false;
}
if (entry_len >= 1 && entry[0] == '\'') {
if (entry_len == 1) {
// void symbol entry, like '
// total object length
obj_len = sizeof(symbol) + 1;
static bool parseProgram(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
vector<SynElement>& elements) {
// here we are sure that entry is at least "<<""
for (size_t i = idx + 2; i < entry.size() - 1; i++) {
if ((entry[i] == '>' && entry[i + 1] == '>') || (entry.substr(i, 2) == "»")) {
elements.push_back({cmd_program, .value = entry.substr(idx + 2, i - idx - 2)});
nextIdx = i + 2;
return true;
}
}
errors.push_back({entry.size(), "unterminated program"});
return false;
}
// allocate and set object
// symbol beginning with ' is not autoevaluated
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
new_obj->set("", 0, false);
static void trim(string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
}
static bool getNumberAt(string& entry, size_t idx, size_t& nextIdx, mpreal& r, char delim = ' ') {
stringstream ss;
string token;
string input;
int base;
string baseStr = entry.substr(idx, 2);
if (baseStr == "0x" || baseStr == "0X") {
input = entry.substr(idx + 2);
base = 16;
} else if (baseStr == "0b") {
input = entry.substr(idx + 2);
base = 2;
} else {
// symbol entry, like 'toto' or 'toto
int naked_entry_len;
// entry length without prefix / postfix
naked_entry_len = entry[entry_len - 1] == '\'' ? (entry_len - 2) : (entry_len - 1);
// total object length
obj_len = sizeof(symbol) + naked_entry_len + 1;
// allocate and set object
// symbol beginning with ' is not autoevaluated
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
new_obj->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len, false);
}
ret = true;
input = entry.substr(idx);
base = 10;
}
return ret;
ss.str(input);
if (getline(ss, token, delim)) {
nextIdx = token.size() + idx + (base != 10 ? 2 : 0);
trim(token);
if (mpfr_set_str(r.mpfr_ptr(), token.c_str(), base, mpreal::get_default_rnd()) == 0)
return true;
else
return false;
}
nextIdx = token.size() + idx + (base != 10 ? 2 : 0);
return false;
}
/// @brief get an object other from known ones from entry and add it to a program
///
/// @param entry the entry
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added
/// @return false no object was added
///
static bool get_other(const string& entry, program& prog, string& remaining_entry) {
bool ret = false;
int entry_len = entry.size();
unsigned int obj_len;
if (entry_len >= 1) {
// entry which is nothing is considered as an auto-evaluated symbol
int naked_entry_len;
// entry length without prefix / postfix
naked_entry_len = entry[entry_len - 1] == '\'' ? (entry_len - 1) : (entry_len);
// total object length
obj_len = sizeof(symbol) + naked_entry_len + 1;
// allocate and set object
// symbol not beginning with ' is autoevaluated (ie is evaluated when pushed
// on stack)
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
new_obj->set(entry.c_str(), naked_entry_len, true);
ret = true;
}
return ret;
}
/// @brief get a string object from entry and add it to a program
///
/// @param entry the entry
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added
/// @return false no object was added
///
static bool get_string(const string& entry, program& prog, string& remaining_entry) {
bool ret = false;
unsigned int obj_len;
int entry_len = entry.size();
if (entry_len >= 1 && entry[0] == '"') {
if (entry_len == 1) {
// total object length
obj_len = sizeof(ostring) + 1;
// allocate and set object
ostring* new_obj = (ostring*)prog.allocate_back(obj_len, cmd_string);
new_obj->set("", 0);
static bool parseNumber(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
vector<SynElement>& elements) {
mpreal r;
if (getNumberAt(entry, idx, nextIdx, r)) {
elements.push_back({cmd_number, .re = r});
return true;
} else {
int naked_entry_len;
// entry length without prefix / postfix
naked_entry_len = entry[entry_len - 1] == '"' ? (entry_len - 2) : (entry_len - 1);
// total object length
obj_len = sizeof(ostring) + naked_entry_len + 1;
// allocate and set object
ostring* new_obj = (ostring*)prog.allocate_back(obj_len, cmd_string);
new_obj->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len);
}
ret = true;
}
return ret;
}
/// @brief get a program object from entry and add it to a program
///
/// @param entry the entry
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added
/// @return false no object was added
///
static bool get_program(string& entry, program& prog, string& remaining_entry) {
bool ret = false;
unsigned int obj_len;
int entry_len = entry.size();
if (entry_len >= 2 && entry[0] == '<' && entry[1] == '<') {
int naked_entry_len;
// entry length without prefix / postfix
if (entry_len >= 4 && entry[entry_len - 1] == '>' && entry[entry_len - 2] == '>')
naked_entry_len = entry_len - 4;
else
naked_entry_len = entry_len - 2;
// total object length
obj_len = sizeof(oprogram) + naked_entry_len + 1;
// allocate and set object
oprogram* new_obj = (oprogram*)prog.allocate_back(obj_len, cmd_program);
new_obj->set(&entry[2], naked_entry_len);
ret = true;
}
return ret;
}
/// @brief get a number object from entry and add it to a program
///
/// @param entry the entry
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added
/// @return false no object was added
///
static bool get_number(string& entry, program& prog, string& remaining_entry) {
char* endptr;
bool ret = false;
if (entry.size() > 0) {
// pre parse to avoid doing a useless allocation
// detect the begining of a number including nan, inf, @nan@, @inf@
if (entry.find_first_of("+-0123456789.ni@", 0) == 0) {
// detect an arbitrary base entry like 3bXXX or 27bYYY
int base = 0;
size_t base_detect = entry.find_first_of("b", 0);
if (base_detect == 1 || base_detect == 2)
if (sscanf(entry.c_str(), "%db", &base) == 1 && base >= 2 && base <= 62)
entry = entry.substr(base_detect + 1);
else
base = 0;
number* num = (number*)prog.allocate_back(number::calc_size(), cmd_number);
int mpfr_ret = mpfr_strtofr(num->_value.mpfr, entry.c_str(), &endptr, base, MPFR_DEFAULT_RND);
if (endptr != NULL && endptr != entry.c_str()) {
// determine representation
if (base != 0) {
num->_representation = number::base;
num->_base = base;
} else {
string beg = entry.substr(0, 2);
if (beg == "0x" || beg == "0X")
num->_representation = number::hex;
else if (beg == "0b" || beg == "0B")
num->_representation = number::bin;
else
num->_representation = number::dec;
}
ret = true;
// remaining string if any
remaining_entry = endptr;
} else
(void)prog.pop_back();
errors.push_back({entry.size(), "unterminated number"});
return false;
}
}
return ret;
static bool parseComplex(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
vector<SynElement>& elements) {
mpreal re, im;
if (idx + 1 == entry.size()) {
errors.push_back({entry.size(), "unterminated complex"});
return false;
}
if (!getNumberAt(entry, idx + 1, nextIdx, re, ',')) {
errors.push_back({entry.size(), "unterminated complex"});
return false;
}
/// @brief get a complex object from entry and add it to a program
///
/// @param entry the entry
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added
/// @return false no object was added
///
static bool get_complex(const string& entry, program& prog, string& remaining_entry) {
char* endptr;
bool ret = false;
if (entry.size() > 0) {
size_t comma = entry.find(',');
if (comma != string::npos) {
complex* cplx;
// pre parse RE to avoid doing a useless allocation
// detect the begining of a number, including nan, inf, @nan@, @inf@
string re_str = entry.substr(1, comma - 1).c_str();
if (re_str.find_first_of(" +-0123456789.ni@", 0) == 0) {
cplx = (complex*)prog.allocate_back(complex::calc_size(), cmd_complex);
int mpfr_ret = mpfr_strtofr(cplx->re()->mpfr, re_str.c_str(), &endptr, 0, MPFR_DEFAULT_RND);
if (endptr != NULL && endptr != re_str.c_str()) {
// determine representation
string beg = re_str.substr(0, 2);
if (beg == "0x" || beg == "0X")
cplx->_representation = complex::hex;
else
cplx->_representation = complex::dec;
ret = true;
} else
(void)prog.pop_back();
size_t i = nextIdx;
while (i < entry.size() && entry[i] != ',') i++;
if (i == entry.size()) {
errors.push_back({entry.size(), "unterminated complex"});
return false;
}
if (!getNumberAt(entry, i + 1, nextIdx, im, ')')) {
errors.push_back({entry.size(), "unterminated complex"});
return false;
}
if (nextIdx == entry.size() || entry[nextIdx] != ')') {
errors.push_back({entry.size(), "unterminated complex"});
return false;
}
elements.push_back({cmd_complex, .re = re, .im = im});
nextIdx++;
return true;
}
// pre parse IM to avoid doing a useless allocation
// detect the begining of a number, including nan, inf, @nan@, @inf@
string im_str = entry.substr(comma + 1).c_str();
if (ret == true && im_str.find_first_of(" +-0123456789.ni@", 0) == 0) {
ret = false;
int mpfr_ret = mpfr_strtofr(cplx->im()->mpfr, im_str.c_str(), &endptr, 0, MPFR_DEFAULT_RND);
if (endptr != NULL && endptr != im_str.c_str()) {
// determine representation
string beg = im_str.substr(0, 2);
if (beg == "0x" || beg == "0X")
cplx->_representation = complex::hex;
else
cplx->_representation = complex::dec;
static bool parseReserved(string& entry, size_t idx, size_t& nextIdx, vector<SynElement>& elements,
map<string, ReservedWord>& keywords) {
stringstream ss(entry.substr(idx));
string token;
ss >> token;
ret = true;
} else
(void)prog.pop_back();
}
auto resa = keywords.find(token);
if (resa != keywords.end()) {
elements.push_back({resa->second.type, .value = token, .fn = resa->second.fn});
nextIdx = token.size() + idx;
return true;
}
return false;
}
return ret;
static bool parseUnknown(string& entry, size_t idx, size_t& nextIdx, vector<SynElement>& elements) {
stringstream ss(entry.substr(idx));
string token;
ss >> token;
elements.push_back({cmd_symbol, token});
nextIdx = token.size() + idx;
return true;
}
/// @brief recognize a comment object from entry
///
/// @param entry the entry
/// @param remaining_entry the remaining entry after the comment was found
/// @return true a comment was found
/// @return false no comment was found
///
static bool get_comment(string& entry, string& remaining_entry) {
bool ret = false;
unsigned int obj_len;
int entry_len = entry.size();
if (entry_len >= 1 && entry[0] == '#') {
// entry (complete line) is ignored
ret = true;
}
return ret;
}
/// @brief get an object from an entry string and add it to a program
/// @brief lexical analysis of an entry string
///
/// @param entry the entry string
/// @param prog the program
/// @param remaining_entry the remaining entry after the object was added
/// @return true an object was added to the prog
/// @return false no object was added to the prog
/// @param elements syntax elements vector
/// @param errors errors vector
/// @param keywords reserved keywords
/// @return false=errors, the lexer must stop
///
static bool _obj_from_string(string& entry, program& prog, string& remaining_entry) {
bool ret = false;
remaining_entry.erase();
if (get_number(entry, prog, remaining_entry))
ret = true;
else if (get_symbol(entry, prog, remaining_entry))
ret = true;
else if (get_string(entry, prog, remaining_entry))
ret = true;
else if (get_program(entry, prog, remaining_entry))
ret = true;
else if (get_keyword(entry, prog, remaining_entry))
ret = true;
else if (get_complex(entry, prog, remaining_entry))
ret = true;
else if (get_comment(entry, remaining_entry))
ret = true;
else
// nothing, considered as an auto-evaluated symbol
if (get_other(entry, prog, remaining_entry))
ret = true;
return ret;
}
/// @brief cut an entry string into entry chunks with respect of types separators
///
/// @param entry the entry
/// @param entries the cut entriy vector
/// @return true entries not vempty
/// @return false entries empty
///
static bool _cut(const char* entry, vector<string>& entries) {
string tmp;
int len = strlen(entry);
for (int i = 0; i < len; i++) {
static bool lexer(string& entry, vector<SynElement>& elements, vector<SynError>& errors,
map<string, ReservedWord>& keywords) {
size_t jump;
for (size_t i = 0; i < entry.size(); i++) {
if (isspace(entry[i])) continue;
SynElement element;
switch (entry[i]) {
// symbol
case '\'':
// push prec entry if exists
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
}
// get symbol
tmp = '\'';
i++;
while ((i < len) && entry[i] != '\'') tmp += entry[i++];
if ((i < len) && entry[i] != '\'') tmp += '\'';
entries.push_back(tmp);
tmp.clear();
break;
// string
case '"':
// push prec entry if exists
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
}
// get expression
tmp = '"';
i++;
while (i < len && entry[i] != '"') tmp += entry[i++];
if ((i < len) && entry[i] != '"') tmp += '"';
entries.push_back(tmp);
tmp.clear();
break;
// program
case '<':
// push prec entry if exists
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
}
if (strncmp(&entry[i], "<<", 2) == 0) {
int up = 1;
// found a program begin
i += 2;
tmp = "<< ";
// trim leading spaces
while (i < len && isspace(entry[i])) i++;
while (i < len) {
if (strncmp(&entry[i], "<<", 2) == 0) {
up++;
i += 2;
tmp += "<< ";
// trim leading spaces
while (i < len && isspace(entry[i])) i++;
} else if (strncmp(&entry[i], ">>", 2) == 0) {
if (isspace(entry[i - 1]) && entry[i - 2] != '>')
tmp += ">>";
else
tmp += " >>";
up--;
i += 2;
// trim trailing spaces
while (i < len && isspace(entry[i])) i++;
// found end
if (up == 0) break;
} else {
tmp += entry[i];
i++;
}
}
while ((up--) > 0) tmp += " >>";
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
}
i--; // i has move 1 too far
} else
// reinject '<'' which is not a prog begin
tmp = "<";
break;
// complex
if (!parseString(entry, i, jump, errors, elements)) return false;
i = jump - 1;
continue;
case '\'':
if (!parseSymbol(entry, i, jump, errors, elements)) return false;
i = jump - 1;
continue;
case '(':
// push prec entry if exists
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
if (!parseComplex(entry, i, jump, errors, elements)) return false;
i = jump - 1;
continue;
// clang-format off
case '.': case '+': case '-':
// clang-format on
// inf, +inf, -inf and nan are treated as reserved keywords
if (i < entry.size() - 1 && entry[i + 1] < '0' && entry[i + 1] > '9') break;
case '0' ... '9':
if (!parseNumber(entry, i, jump, errors, elements)) return false;
i = jump - 1;
continue;
}
// get complex
while ((i < len) && entry[i] != ')') tmp += entry[i++];
if ((i < len) && entry[i] != ')') tmp += ')';
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
if (i < entry.size() - 1 && (entry.substr(i, 2) == "<<" || entry.substr(i, 2) == "«")) {
if (!parseProgram(entry, i, jump, errors, elements)) return false;
i = jump - 1;
continue;
} else if (parseReserved(entry, i, jump, elements, keywords))
// found a keywords word, add it with its correct type
i = jump - 1;
else if (parseUnknown(entry, i, jump, elements))
// last chance, this unknown entry is treated as a symbol
i = jump - 1;
}
break;
// other
default:
if (!isspace(entry[i]))
tmp += entry[i];
else {
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
}
return true;
}
static bool progFromElements(vector<SynElement>& elements, program& prog) {
for_each(elements.begin(), elements.end(), [&](SynElement& element) {
switch (element.type) {
case cmd_number:
prog.insert(prog.begin(), 1, new number(element.re));
break;
// case cmd_complex: prog.insert(prog.begin(), 1, new ocomplex(element.re, element.im)); break;
case cmd_string:
prog.insert(prog.begin(), 1, new ostring(element.value));
break;
case cmd_symbol:
prog.insert(prog.begin(), 1, new symbol(element.value));
break;
// case cmd_program: prog.insert(prog.begin(), 1, new program(element.value)); break;
case cmd_keyword:
prog.insert(prog.begin(), 1, new keyword(element.fn, element.value));
break;
case cmd_branch:
prog.insert(prog.begin(), 1, new branch((branch_fn_t)element.fn, element.value));
break;
default:
return false;
}
}
if (tmp.size() > 0) {
entries.push_back(tmp);
tmp.clear();
}
return entries.size() > 0;
return true;
});
return true;
}
/// @brief parse an entry string: cut it into objects chunks and add them to a program
@ -600,27 +342,23 @@ static bool _cut(const char* entry, vector<string>& entries) {
/// @param prog the program
/// @return ret_value see this type
///
ret_value program::parse(const char* entry, program& prog) {
vector<string> entries;
ret_value program::parse(string& entry, program& prog) {
vector<SynElement> elements;
vector<SynError> errors;
ret_value ret = ret_ok;
// 1. cut global entry string into shorter strings
if (_cut(entry, entries)) {
// 2. make an object from each entry, and add it to the program
for (vector<string>::iterator it = entries.begin(); it != entries.end(); it++) {
string remaining_entry;
string main_entry = (*it);
while (main_entry.size() > 0) {
// remaining_entry is used only in case of concatenated entry
// ex: entry="1 2+" -> vector<string> = {"1", "2+"} -> first "1",
// second "2" and remaining_entry="+" this remaining entry is treated as
// an entry
// prepare map for finding reserved keywords
if (_keywordsMap.size() == 0)
for (int i = 0; s_keywords[i].type != cmd_max; i++)
_keywordsMap[s_keywords[i].name] = {s_keywords[i].type, s_keywords[i].fn};
// TODO errors ?
_obj_from_string(main_entry, prog, remaining_entry);
main_entry = remaining_entry;
}
}
// separate the entry string
if (lexer(entry, elements, errors, _keywordsMap)) {
// make objects from parsed elements
if (!progFromElements(elements, prog)) prog.show_error(ret_unknown_err, "error creating program from entry");
} else {
for(SynError& err: errors)
prog.show_syntax_error(err.err.c_str());
}
return ret;

View file

@ -20,51 +20,55 @@ program::keyword_t program::s_keywords[] = {
{cmd_keyword, "history", &program::rpn_history, "see commands history"},
// USUAL OPERATIONS ON REALS AND COMPLEXES
{cmd_undef, "", NULL, "\nUSUAL OPERATIONS ON REALS AND COMPLEXES"},
{cmd_keyword, "+", &program::rpn_plus, "addition"},
{cmd_keyword, "-", &program::rpn_minus, "substraction"},
{cmd_keyword, "chs", &program::rpn_neg, "negation"},
{cmd_keyword, "neg", &program::rpn_neg, ""},
{cmd_keyword, "*", &program::rpn_mul, "multiplication"},
{cmd_keyword, "/", &program::rpn_div, "division"},
{cmd_keyword, "inv", &program::rpn_inv, "inverse"},
{cmd_keyword, "^", &program::rpn_power, "power"},
{cmd_keyword, "pow", &program::rpn_power, ""},
{cmd_keyword, "sqrt", &program::rpn_squareroot, "rpn_square root"},
{cmd_keyword, "sq", &program::rpn_square, "rpn_square"},
{cmd_keyword, "sqr", &program::rpn_square, ""},
{cmd_keyword, "abs", &program::rpn_abs, "absolute value"},
{cmd_keyword, "dec", &program::rpn_dec, "decimal representation"},
{cmd_keyword, "hex", &program::rpn_hex, "hexadecimal representation"},
{cmd_keyword, "bin", &program::rpn_bin, "decimal representation"},
{cmd_keyword, "base", &program::rpn_base, "arbitrary base representation"},
{cmd_keyword, "sign", &program::rpn_sign, "1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0"},
// {cmd_undef, "", NULL, "\nUSUAL OPERATIONS ON REALS AND COMPLEXES"},
// {cmd_keyword, "+", &program::rpn_plus, "addition"},
// {cmd_keyword, "-", &program::rpn_minus, "substraction"},
// {cmd_keyword, "chs", &program::rpn_neg, "negation"},
// {cmd_keyword, "neg", &program::rpn_neg, ""},
// {cmd_keyword, "*", &program::rpn_mul, "multiplication"},
// {cmd_keyword, "/", &program::rpn_div, "division"},
// {cmd_keyword, "inv", &program::rpn_inv, "inverse"},
// {cmd_keyword, "^", &program::rpn_power, "power"},
// {cmd_keyword, "pow", &program::rpn_power, ""},
// {cmd_keyword, "sqrt", &program::rpn_squareroot, "rpn_square root"},
// {cmd_keyword, "sq", &program::rpn_square, "rpn_square"},
// {cmd_keyword, "sqr", &program::rpn_square, ""},
// {cmd_keyword, "abs", &program::rpn_abs, "absolute value"},
// {cmd_keyword, "dec", &program::rpn_dec, "decimal representation"},
// {cmd_keyword, "hex", &program::rpn_hex, "hexadecimal representation"},
// {cmd_keyword, "bin", &program::rpn_bin, "decimal representation"},
// {cmd_keyword, "base", &program::rpn_base, "arbitrary base representation"},
// {cmd_keyword, "sign", &program::rpn_sign, "1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0"},
// {cmd_keyword, "inf", &program::rpn_inf, "positive infinite"},
// {cmd_keyword, "+inf", &program::rpn_inf, "positive infinite"},
// {cmd_keyword, "-inf", &program::rpn_minf, "negative infinite"},
// {cmd_keyword, "nan", &program::rpn_nan, "not a number"},
// OPERATIONS ON REALS
{cmd_undef, "", NULL, "\nOPERATIONS ON REALS"},
{cmd_keyword, "%", &program::rpn_purcent, "purcent"},
{cmd_keyword, "%CH", &program::rpn_purcentCH, "inverse purcent"},
{cmd_keyword, "mod", &program::rpn_modulo, "modulo"},
{cmd_keyword, "fact", &program::rpn_fact, "n! for integer n or Gamma(x+1) for fractional x"},
{cmd_keyword, "mant", &program::rpn_mant, "mantissa of a real number"},
{cmd_keyword, "xpon", &program::rpn_xpon, "exponant of a real number"},
{cmd_keyword, "floor", &program::rpn_floor, "largest number <="},
{cmd_keyword, "ceil", &program::rpn_ceil, "smallest number >="},
{cmd_keyword, "ip", &program::rpn_ip, "integer part"},
{cmd_keyword, "fp", &program::rpn_fp, "fractional part"},
{cmd_keyword, "min", &program::rpn_min, "min of 2 real numbers"},
{cmd_keyword, "max", &program::rpn_max, "max of 2 real numbers"},
// {cmd_undef, "", NULL, "\nOPERATIONS ON REALS"},
// {cmd_keyword, "%", &program::rpn_purcent, "purcent"},
// {cmd_keyword, "%CH", &program::rpn_purcentCH, "inverse purcent"},
// {cmd_keyword, "mod", &program::rpn_modulo, "modulo"},
// {cmd_keyword, "fact", &program::rpn_fact, "n! for integer n or Gamma(x+1) for fractional x"},
// {cmd_keyword, "mant", &program::rpn_mant, "mantissa of a real number"},
// {cmd_keyword, "xpon", &program::rpn_xpon, "exponant of a real number"},
// {cmd_keyword, "floor", &program::rpn_floor, "largest number <="},
// {cmd_keyword, "ceil", &program::rpn_ceil, "smallest number >="},
// {cmd_keyword, "ip", &program::rpn_ip, "integer part"},
// {cmd_keyword, "fp", &program::rpn_fp, "fractional part"},
// {cmd_keyword, "min", &program::rpn_min, "min of 2 real numbers"},
// {cmd_keyword, "max", &program::rpn_max, "max of 2 real numbers"},
// nOPERATIONS ON COMPLEXES
{cmd_undef, "", NULL, "\nOPERATIONS ON COMPLEXES"},
{cmd_keyword, "re", &program::rpn_re, "complex real part"},
{cmd_keyword, "im", &program::rpn_im, "complex imaginary part"},
{cmd_keyword, "conj", &program::rpn_conj, "complex conjugate"},
{cmd_keyword, "arg", &program::rpn_arg, "complex argument in radians"},
{cmd_keyword, "c->r", &program::rpn_c2r, "transform a complex in 2 reals"},
{cmd_keyword, "r->c", &program::rpn_r2c, "transform 2 reals in a complex"},
{cmd_keyword, "p->r", &program::rpn_p2r, "cartesian to polar"},
{cmd_keyword, "r->p", &program::rpn_r2p, "polar to cartesian"},
// OPERATIONS ON COMPLEXES
// {cmd_undef, "", NULL, "\nOPERATIONS ON COMPLEXES"},
// {cmd_keyword, "re", &program::rpn_re, "complex real part"},
// {cmd_keyword, "im", &program::rpn_im, "complex imaginary part"},
// {cmd_keyword, "conj", &program::rpn_conj, "complex conjugate"},
// {cmd_keyword, "arg", &program::rpn_arg, "complex argument in radians"},
// {cmd_keyword, "c->r", &program::rpn_c2r, "transform a complex in 2 reals"},
// {cmd_keyword, "r->c", &program::rpn_r2c, "transform 2 reals in a complex"},
// {cmd_keyword, "p->r", &program::rpn_p2r, "cartesian to polar"},
// {cmd_keyword, "r->p", &program::rpn_r2p, "polar to cartesian"},
// MODE
{cmd_undef, "", NULL, "\nMODE"},
@ -111,41 +115,42 @@ program::keyword_t program::s_keywords[] = {
{cmd_keyword, "over", &program::rpn_over, "push a copy of the element in stack level 2 onto the stack"},
// STRING
{cmd_undef, "", NULL, "\nSTRING"},
{cmd_keyword, "->str", &program::rpn_instr, "convert an object into a string"},
{cmd_keyword, "str->", &program::rpn_strout, "convert a string into an object"},
{cmd_keyword, "chr", &program::rpn_chr, "convert ASCII character code in stack level 1 into a string"},
{cmd_keyword, "num", &program::rpn_num,
"return ASCII code of the first character of the string in stack level 1 "
"as a real number"},
{cmd_keyword, "size", &program::rpn_strsize, "return the length of the string"},
{cmd_keyword, "pos", &program::rpn_strpos, "seach for the string in level 1 within the string in level 2"},
{cmd_keyword, "sub", &program::rpn_strsub, "return a substring of the string in level 3"},
// {cmd_undef, "", NULL, "\nSTRING"},
// {cmd_keyword, "->str", &program::rpn_instr, "convert an object into a string"},
// {cmd_keyword, "str->", &program::rpn_strout, "convert a string into an object"},
// {cmd_keyword, "chr", &program::rpn_chr, "convert ASCII character code in stack level 1 into a string"},
// {cmd_keyword, "num", &program::rpn_num,
// "return ASCII code of the first character of the string in stack level 1 "
// "as a real number"},
// {cmd_keyword, "size", &program::rpn_strsize, "return the length of the string"},
// {cmd_keyword, "pos", &program::rpn_strpos, "seach for the string in level 1 within the string in level 2"},
// {cmd_keyword, "sub", &program::rpn_strsub, "return a substring of the string in level 3"},
// BRANCH
{cmd_undef, "", NULL, "\nBRANCH"},
{cmd_branch, "if", (program_fn_t)&program::rpn_if,
"if <test-instruction> then <true-instructions> else <false-instructions> "
"end"},
{cmd_branch, "then", (program_fn_t)&program::rpn_then, "used with if"},
{cmd_branch, "else", (program_fn_t)&program::rpn_else, "used with if"},
{cmd_branch, "end", (program_fn_t)&program::rpn_end, "used with various branch instructions"},
{cmd_branch, "start", (program_fn_t)&program::rpn_start, "<start> <end> start <instructions> next|<step> step"},
{cmd_branch, "for", (program_fn_t)&program::rpn_for,
"<start> <end> for <variable> <instructions> next|<step> step"},
{cmd_branch, "next", (program_fn_t)&program::rpn_next, "used with start and for"},
{cmd_branch, "step", (program_fn_t)&program::rpn_step, "used with start and for"},
{cmd_keyword, "ift", &program::rpn_ift, "similar to if-then-end, <test-instruction> <true-instruction> ift"},
{cmd_keyword, "ifte", &program::rpn_ifte,
"similar to if-then-else-end, <test-instruction> <true-instruction> "
"<false-instruction> ifte"},
{cmd_branch, "do", (program_fn_t)&program::rpn_do, "do <instructions> until <condition> end"},
{cmd_branch, "until", (program_fn_t)&program::rpn_until, "used with do"},
{cmd_branch, "unti", (program_fn_t)&program::rpn_until, ""},
{cmd_branch, "while", (program_fn_t)&program::rpn_while, "while <test-instruction> repeat <loop-instructions> end"},
{cmd_branch, "whil", (program_fn_t)&program::rpn_while, ""},
{cmd_branch, "repeat", (program_fn_t)&program::rpn_repeat, "used with while"},
{cmd_branch, "repea", (program_fn_t)&program::rpn_repeat, ""},
// {cmd_undef, "", NULL, "\nBRANCH"},
// {cmd_branch, "if", (program_fn_t)&program::rpn_if,
// "if <test-instruction> then <true-instructions> else <false-instructions> "
// "end"},
// {cmd_branch, "then", (program_fn_t)&program::rpn_then, "used with if"},
// {cmd_branch, "else", (program_fn_t)&program::rpn_else, "used with if"},
// {cmd_branch, "end", (program_fn_t)&program::rpn_end, "used with various branch instructions"},
// {cmd_branch, "start", (program_fn_t)&program::rpn_start, "<start> <end> start <instructions> next|<step> step"},
// {cmd_branch, "for", (program_fn_t)&program::rpn_for,
// "<start> <end> for <variable> <instructions> next|<step> step"},
// {cmd_branch, "next", (program_fn_t)&program::rpn_next, "used with start and for"},
// {cmd_branch, "step", (program_fn_t)&program::rpn_step, "used with start and for"},
// {cmd_keyword, "ift", &program::rpn_ift, "similar to if-then-end, <test-instruction> <true-instruction> ift"},
// {cmd_keyword, "ifte", &program::rpn_ifte,
// "similar to if-then-else-end, <test-instruction> <true-instruction> "
// "<false-instruction> ifte"},
// {cmd_branch, "do", (program_fn_t)&program::rpn_do, "do <instructions> until <condition> end"},
// {cmd_branch, "until", (program_fn_t)&program::rpn_until, "used with do"},
// {cmd_branch, "unti", (program_fn_t)&program::rpn_until, ""},
// {cmd_branch, "while", (program_fn_t)&program::rpn_while, "while <test-instruction> repeat <loop-instructions>
// end"},
// {cmd_branch, "whil", (program_fn_t)&program::rpn_while, ""},
// {cmd_branch, "repeat", (program_fn_t)&program::rpn_repeat, "used with while"},
// {cmd_branch, "repea", (program_fn_t)&program::rpn_repeat, ""},
// STORE
{cmd_undef, "", NULL, "\nSTORE"},
@ -155,13 +160,12 @@ program::keyword_t program::s_keywords[] = {
{cmd_keyword, "vars", &program::rpn_vars, "list all variables"},
{cmd_keyword, "clusr", &program::rpn_clusr, "erase all variables"},
{cmd_keyword, "edit", &program::rpn_edit, "edit a variable content"},
{cmd_keyword, "sto+", &program::rpn_stoadd, "add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+"},
{cmd_keyword, "sto-", &program::rpn_stosub, "substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto-"},
{cmd_keyword, "sto*", &program::rpn_stomul, "multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto*"},
{cmd_keyword, "sto/", &program::rpn_stodiv, "divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/"},
{cmd_keyword, "sneg", &program::rpn_stoneg, "negate a variable. ex: 'name' sneg"},
{cmd_keyword, "sinv", &program::rpn_stoinv, "inverse a variable. ex: 1 'name' sinv"},
// {cmd_keyword, "sto+", &program::rpn_stoadd, "add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+"},
// {cmd_keyword, "sto-", &program::rpn_stosub, "substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto-"},
// {cmd_keyword, "sto*", &program::rpn_stomul, "multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto*"},
// {cmd_keyword, "sto/", &program::rpn_stodiv, "divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/"},
// {cmd_keyword, "sneg", &program::rpn_stoneg, "negate a variable. ex: 'name' sneg"},
// {cmd_keyword, "sinv", &program::rpn_stoinv, "inverse a variable. ex: 1 'name' sinv"},
// PROGRAM
{cmd_undef, "", NULL, "\nPROGRAM"},
{cmd_keyword, "eval", &program::rpn_eval, "evaluate (run) a program, or recall a variable. ex: 'my_prog' eval"},
@ -170,43 +174,43 @@ program::keyword_t program::s_keywords[] = {
">>"},
// TRIG ON REALS AND COMPLEXES
{cmd_undef, "", NULL, "\nTRIG ON REALS AND COMPLEXES"},
{cmd_keyword, "pi", &program::rpn_pi, "pi constant"},
{cmd_keyword, "sin", &program::rpn_sin, "sinus"},
{cmd_keyword, "asin", &program::rpn_asin, "arg sinus"},
{cmd_keyword, "cos", &program::rpn_cos, "cosinus"},
{cmd_keyword, "acos", &program::rpn_acos, "arg cosinus"},
{cmd_keyword, "tan", &program::rpn_tan, "tangent"},
{cmd_keyword, "atan", &program::rpn_atan, "arg tangent"},
{cmd_keyword, "d->r", &program::rpn_d2r, "convert degrees to radians"},
{cmd_keyword, "r->d", &program::rpn_r2d, "convert radians to degrees"},
// {cmd_undef, "", NULL, "\nTRIG ON REALS AND COMPLEXES"},
// {cmd_keyword, "pi", &program::rpn_pi, "pi constant"},
// {cmd_keyword, "sin", &program::rpn_sin, "sinus"},
// {cmd_keyword, "asin", &program::rpn_asin, "arg sinus"},
// {cmd_keyword, "cos", &program::rpn_cos, "cosinus"},
// {cmd_keyword, "acos", &program::rpn_acos, "arg cosinus"},
// {cmd_keyword, "tan", &program::rpn_tan, "tangent"},
// {cmd_keyword, "atan", &program::rpn_atan, "arg tangent"},
// {cmd_keyword, "d->r", &program::rpn_d2r, "convert degrees to radians"},
// {cmd_keyword, "r->d", &program::rpn_r2d, "convert radians to degrees"},
// LOGS ON REALS AND COMPLEXES
{cmd_undef, "", NULL, "\nLOGS ON REALS AND COMPLEXES"},
{cmd_keyword, "e", &program::rpn_e, "Euler constant"},
{cmd_keyword, "ln", &program::rpn_ln, "logarithm base e"},
{cmd_keyword, "log", &program::rpn_ln, ""},
{cmd_keyword, "lnp1", &program::rpn_lnp1, "ln(1+x) which is useful when x is close to 0"},
{cmd_keyword, "exp", &program::rpn_exp, "exponential"},
{cmd_keyword, "expm", &program::rpn_expm, "exp(x)-1 which is useful when x is close to 0"},
{cmd_keyword, "log10", &program::rpn_log10, "logarithm base 10"},
{cmd_keyword, "alog10", &program::rpn_alog10, "exponential base 10"},
{cmd_keyword, "exp10", &program::rpn_alog10, ""},
{cmd_keyword, "log2", &program::rpn_log2, "logarithm base 2"},
{cmd_keyword, "alog2", &program::rpn_alog2, "exponential base 2"},
{cmd_keyword, "exp2", &program::rpn_alog2, ""},
{cmd_keyword, "sinh", &program::rpn_sinh, "hyperbolic sine"},
{cmd_keyword, "asinh", &program::rpn_asinh, "inverse hyperbolic sine"},
{cmd_keyword, "cosh", &program::rpn_sinh, "hyperbolic cosine"},
{cmd_keyword, "acosh", &program::rpn_acosh, "inverse hyperbolic cosine"},
{cmd_keyword, "tanh", &program::rpn_tanh, "hyperbolic tangent"},
{cmd_keyword, "atanh", &program::rpn_atanh, "inverse hyperbolic tangent"},
// {cmd_undef, "", NULL, "\nLOGS ON REALS AND COMPLEXES"},
// {cmd_keyword, "e", &program::rpn_e, "Euler constant"},
// {cmd_keyword, "ln", &program::rpn_ln, "logarithm base e"},
// {cmd_keyword, "log", &program::rpn_ln, ""},
// {cmd_keyword, "lnp1", &program::rpn_lnp1, "ln(1+x) which is useful when x is close to 0"},
// {cmd_keyword, "exp", &program::rpn_exp, "exponential"},
// {cmd_keyword, "expm", &program::rpn_expm, "exp(x)-1 which is useful when x is close to 0"},
// {cmd_keyword, "log10", &program::rpn_log10, "logarithm base 10"},
// {cmd_keyword, "alog10", &program::rpn_alog10, "exponential base 10"},
// {cmd_keyword, "exp10", &program::rpn_alog10, ""},
// {cmd_keyword, "log2", &program::rpn_log2, "logarithm base 2"},
// {cmd_keyword, "alog2", &program::rpn_alog2, "exponential base 2"},
// {cmd_keyword, "exp2", &program::rpn_alog2, ""},
// {cmd_keyword, "sinh", &program::rpn_sinh, "hyperbolic sine"},
// {cmd_keyword, "asinh", &program::rpn_asinh, "inverse hyperbolic sine"},
// {cmd_keyword, "cosh", &program::rpn_sinh, "hyperbolic cosine"},
// {cmd_keyword, "acosh", &program::rpn_acosh, "inverse hyperbolic cosine"},
// {cmd_keyword, "tanh", &program::rpn_tanh, "hyperbolic tangent"},
// {cmd_keyword, "atanh", &program::rpn_atanh, "inverse hyperbolic tangent"},
// TIME AND DATE
{cmd_undef, "", NULL, "\nTIME AND DATE"},
{cmd_keyword, "time", &program::rpn_time, "time in local format"},
{cmd_keyword, "date", &program::rpn_date, "date in local format"},
{cmd_keyword, "ticks", &program::rpn_ticks, "system tick in µs"},
// {cmd_undef, "", NULL, "\nTIME AND DATE"},
// {cmd_keyword, "time", &program::rpn_time, "time in local format"},
// {cmd_keyword, "date", &program::rpn_date, "date in local format"},
// {cmd_keyword, "ticks", &program::rpn_ticks, "system tick in µs"},
// end
{cmd_max, "", NULL, ""},
@ -218,7 +222,7 @@ program::keyword_t program::s_keywords[] = {
/// @param hp the heap, storing variables
/// @return ret_value see this type
///
ret_value program::run(stack& stk, heap& hp) {
ret_value program::run(rpnstack& stk, heap& hp) {
bool go_out = false;
ret_value ret = ret_ok;
cmd_type_t type;
@ -238,18 +242,17 @@ ret_value program::run(stack& stk, heap& hp) {
// iterate commands
for (int i = 0; (go_out == false) && (interrupt_now == false) && (i < (int)size());) {
type = (cmd_type_t)seq_type(i);
switch((cmd_type_t)(*this)[i]->_type) {
// could be an auto-evaluated symbol
if (type == cmd_symbol) {
auto_rcl((symbol*)seq_obj(i));
case cmd_symbol:
auto_rcl((symbol*)(*this)[i]);
i++;
}
break;
// a keyword
else if (type == cmd_keyword) {
keyword* k = (keyword*)seq_obj(i);
// call matching function
case cmd_keyword: {
keyword* k = (keyword*)(*this)[i];
// call the matching function
(this->*(k->_fn))();
switch (_err) {
// no pb -> go on
@ -272,12 +275,13 @@ ret_value program::run(stack& stk, heap& hp) {
break;
}
i++;
break;
}
// a branch keyword
else if (type == cmd_branch) {
case cmd_branch: {
// call matching function
branch* b = (branch*)seq_obj(i);
branch* b = (branch*)(*this)[i];
int next_cmd = (this->*(b->_fn))(*b);
switch (next_cmd) {
case -1:
@ -292,13 +296,15 @@ ret_value program::run(stack& stk, heap& hp) {
i = next_cmd; // new direction
break;
}
break;
}
default:
// not a command, but a stack entry, manage it
else {
// copy the program stack entry to the running stack
stack::copy_and_push_back(*this, i, stk);
stk.push_back((*this)[i]);
i++;
break;
}
}
@ -324,8 +330,8 @@ void program::stop() { interrupt_now = true; }
/// @return false the branch name is NOT str_to_compare
///
bool program::compare_branch(branch* b, const char* str_to_compare, int len) {
if (b->_len >= len)
return strncasecmp(b->_value, str_to_compare, len) == 0;
if (str_to_compare != nullptr)
return b->_value == str_to_compare;
else
return false;
}
@ -347,9 +353,8 @@ ret_value program::preprocess(void) {
// analyse if-then-else-end branches
// analyse start-{next, step} branches
for (int i = 0; i < (int)size(); i++) {
int type = seq_type(i);
if (type == cmd_branch) {
branch* k = (branch*)seq_obj(i);
if ((*this)[i]->_type == cmd_branch) {
branch* k = (branch*)(*this)[i];
if (compare_branch(k, "if", 2)) {
if_layout_t layout;
layout.index_if_or_do_or_while = i;
@ -406,7 +411,7 @@ 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*)seq_obj(vlayout[layout_index].index_then_or_unti_or_repeat))->arg2 =
((branch*)(*this)[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))
vstartindex.push_back(i);
@ -420,7 +425,7 @@ ret_value program::preprocess(void) {
return ret_syntax;
}
k->arg1 = vstartindex[vstartindex.size() - 1]; // 'next' arg1 = 'start' index
((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 =
((branch*)(*this)[vstartindex[vstartindex.size() - 1]])->arg2 =
i; // 'for' or 'start' arg2 = 'next' index
vstartindex.pop_back();
} else if (compare_branch(k, "step", 4)) {
@ -430,7 +435,7 @@ ret_value program::preprocess(void) {
return ret_syntax;
}
k->arg1 = vstartindex[vstartindex.size() - 1]; // fill 'step' branch1 = 'start' index
((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 =
((branch*)(*this)[vstartindex[vstartindex.size() - 1]])->arg2 =
i; // 'for' or 'start' arg2 = 'next' index
vstartindex.pop_back();
} else if (compare_branch(k, "->", 2)) {
@ -522,7 +527,7 @@ ret_value program::preprocess(void) {
}
// fill 'repeat' arg1 with 'end+1'
((branch*)seq_obj(vlayout[layout_index].index_then_or_unti_or_repeat))->arg1 = i + 1;
((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg1 = i + 1;
layout_index--;
} else {
// this end closes an if..then..(else)
@ -533,11 +538,11 @@ ret_value program::preprocess(void) {
}
if (vlayout[layout_index].index_else != -1)
// fill 'end' branch of 'else'
((branch*)seq_obj(vlayout[layout_index].index_else))->arg2 = i;
((branch*)(*this)[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*)seq_obj(vlayout[layout_index].index_then_or_unti_or_repeat))->arg2 = i;
((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg2 = i;
else {
// error: show it
show_syntax_error("missing then");
@ -634,15 +639,15 @@ ret_value program::get_err(void) { return _err; }
/// @param st the stack to show
/// @param show_separator whether to show a stack level prefix or not
///
void program::show_stack(stack& st, bool show_separator) {
void program::show_stack(rpnstack& st, bool show_separator) {
if (st.size() == 1) {
((object*)st.back())->show();
printf("\n");
st.front()->show(cout);
cout << endl;
} else {
for (int i = st.size() - 1; i >= 0; i--) {
if (show_separator) printf("%d%s", i + 1, SHOW_STACK_SEPARATOR);
((object*)st[i])->show();
printf("\n");
for (int i = 0; i < st.size(); i++) {
if (show_separator) cout << st.size() - i << SHOW_STACK_SEPARATOR;
st[i]->show(cout);
cout << endl;
}
}
}
@ -658,8 +663,4 @@ void program::apply_default() {
stringstream ss;
ss << number::s_decimal_digits;
number::s_mpfr_printf_format = string(MPFR_FORMAT_BEG) + ss.str() + string(MPFR_FORMAT_STD);
// default calc precision for MPFR
floating_t::s_mpfr_prec = (mpfr_prec_t)MPFR_DEFAULT_PREC_BITS;
floating_t::s_mpfr_prec_bytes = MPFR_DEFAULT_STORING_LENGTH_BYTES;
}

View file

@ -11,12 +11,15 @@
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
// external libs
#define MPFR_USE_NO_MACRO
#include <mpfr.h>
#include "linenoise.h"
// internal includes
@ -40,7 +43,7 @@ struct if_layout_t {
};
//< program class: the class containing a string parser, all the programs keywords, a stack for running the program
class program : public stack {
class program : public vector<object*> {
public:
program(program* parent_prog = NULL) {
_parent_prog = parent_prog;
@ -48,15 +51,15 @@ class program : public stack {
}
// parser
static ret_value parse(const char* entry, program& prog);
static ret_value parse(string& entry, program& prog);
static ret_value entry(program& prog);
static void entry_completion_generator(const char* text, linenoiseCompletions* lc);
static ret_value get_fn(const char* fn_name, program_fn_t& fn, cmd_type_t& type);
// running
ret_value run(stack& stk, heap& hp);
ret_value run(rpnstack& stk, heap& hp);
void stop();
bool compare_keyword(keyword* k, const char* str_to_compare, int len);
// bool compare_keyword(keyword* k, const char* str_to_compare, int len);
bool compare_branch(branch* b, const char* str_to_compare, int len);
ret_value preprocess(void);
@ -66,7 +69,7 @@ class program : public stack {
void show_syntax_error(const char* context);
ret_value get_err(void);
static void show_stack(stack& st, bool show_separator = true);
static void show_stack(rpnstack& st, bool show_separator = true);
static void apply_default();
@ -78,7 +81,7 @@ class program : public stack {
string _err_context;
// global stack holding results for user
stack* _stack;
rpnstack* _stack;
// global heap (sto, rcl)
heap* _heap;
@ -87,7 +90,7 @@ class program : public stack {
heap _local_heap;
// calc stack internally used by branch and calc commands
stack _calc_stack;
rpnstack _calc_stack;
// parent prog for inheriting heaps
program* _parent_prog;
@ -168,7 +171,7 @@ class program : public stack {
void rpn_atanh();
// program
bool find_variable(string& variable, object*& obj, unsigned int& size);
bool find_variable(string& variable, object*& obj);
void rpn_eval(void);
int rpn_inprog(branch& myobj);
@ -243,14 +246,14 @@ class program : public stack {
void rpn_strsub();
// test-core
void test_get_stack(string& stack_is, stack& stk);
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
int cmp_strings_on_stack_top();
long cmp_strings_on_stack_top();
void rpn_sup(void);
void rpn_sup_eq(void);
void rpn_inf(void);
@ -306,7 +309,7 @@ class program : public stack {
#define ARG_MUST_BE_OF_TYPE(num, type) \
do { \
if (_stack->get_type(num) != (type)) { \
if (_stack->at(num)->_type != (type)) { \
ERR_CONTEXT(ret_bad_operand_type); \
return; \
} \
@ -314,13 +317,13 @@ class program : public stack {
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) \
do { \
if (_stack->get_type(num) != (type)) { \
if (_stack->at(num)->_type != (type)) { \
ERR_CONTEXT(ret_bad_operand_type); \
return (ret); \
} \
} while (0)
#define IS_ARG_TYPE(num, type) (_stack->get_type(num) == (type))
#define IS_ARG_TYPE(num, type) (_stack->at(num)->_type == (type))
#define CHECK_MPFR(op) \
do { \

View file

@ -11,7 +11,7 @@ int program::rpn_if(branch& myobj) {
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
if (mpfr_cmp_si(((number*)_stack->get_obj(0))->_value.mpfr, 0UL) != 0)
if (mpfr_cmp_si(((number*)_stack->at(0))->_value.mpfr, 0UL) != 0)
myobj.arg1 = 1;
else
myobj.arg1 = 0;
@ -30,7 +30,7 @@ int program::rpn_then(branch& myobj) {
// myobj.arg3 = index of if
// if condition is true -> arg1 (= jump to then + 1)
// else -> arg2 (= jump to else + 1 or end + 1)
branch* if_cmd = (branch*)seq_obj(myobj.arg3);
branch* if_cmd = (branch*)(*this)[myobj.arg3];
if (if_cmd->arg1 == 1)
return myobj.arg1;
else
@ -49,7 +49,7 @@ int program::rpn_else(branch& myobj) {
// myobj.arg3 = index of if
// if condition was false -> arg1 (= jump to else + 1)
// if condition was true -> arg2 (= jump to end + 1)
branch* if_cmd = (branch*)seq_obj(myobj.arg3);
branch* if_cmd = (branch*)(*this)[myobj.arg3];
if (if_cmd->arg1 == 1)
return myobj.arg2;
else
@ -116,13 +116,13 @@ void program::rpn_ift(void) {
// check ift arg
// arg is true if number != 0 or if is nan or +/-inf
number* testee = ((number*)_stack->get_obj(1));
number* testee = ((number*)_stack->at(1));
if (!mpfr_zero_p(testee->_value.mpfr)) {
CHECK_MPFR(stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack));
CHECK_MPFR(rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack));
(void)_stack->pop_back(2);
CHECK_MPFR(stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack));
CHECK_MPFR(rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack));
(void)_calc_stack.pop_back();
} else
(void)_stack->pop_back(2);
@ -140,16 +140,16 @@ void program::rpn_ifte(void) {
// check ifte arg
// arg is true if number != 0 or if is nan or +/-inf
number* testee = ((number*)_stack->get_obj(2));
number* testee = ((number*)_stack->at(2));
if (!mpfr_zero_p(testee->_value.mpfr))
CHECK_MPFR(stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack));
CHECK_MPFR(rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack));
else
CHECK_MPFR(stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack));
CHECK_MPFR(rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack));
(void)_stack->pop_back(3);
CHECK_MPFR(stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack));
CHECK_MPFR(rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack));
(void)_calc_stack.pop_back();
}
@ -198,12 +198,12 @@ int program::rpn_start(branch& myobj) {
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -(int)ret_runtime_error);
// farg2 = last value of start command
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
myobj.farg2 = (number*)_calc_stack.back();
_stack->pop_back();
// farg1 = first value of start command
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
myobj.farg1 = (number*)_calc_stack.back();
_stack->pop_back();
@ -230,16 +230,16 @@ int program::rpn_for(branch& myobj) {
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -(int)ret_runtime_error);
symbol* sym = ((symbol*)seq_obj(myobj.arg1));
symbol* sym = (symbol*)(*this)[myobj.arg1];
// farg2 = last value of for command
// arg1 = index of symbol to increase
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
myobj.farg2 = (number*)_calc_stack.back();
_stack->pop_back();
// farg1 = first value of for command
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
myobj.farg1 = (number*)_calc_stack.back();
_stack->pop_back();
@ -251,7 +251,7 @@ int program::rpn_for(branch& myobj) {
ret = myobj.arg2 + 1;
else {
// store symbol with first value
_local_heap.add(sym->_value, (object*)myobj.farg1, myobj.farg1->size());
_local_heap[sym->_value] = myobj.farg1;
ret = myobj.arg1 + 1;
}
@ -267,7 +267,7 @@ int program::rpn_for(branch& myobj) {
int program::rpn_next(branch& myobj) {
// arg1 = index of start or for command in program
// farg1 = current count
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
branch* start_or_for = (branch*)(*this)[myobj.arg1];
if (!myobj.arg_bool) {
myobj.arg_bool = true;
myobj.farg1 = start_or_for->farg1;
@ -281,10 +281,10 @@ int program::rpn_next(branch& myobj) {
if (start_or_for->arg1 != -1) {
object* obj;
unsigned int size;
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
symbol* var = (symbol*)(*this)[start_or_for->arg1];
// increase symbol variable
_local_heap.replace_value(string(var->_value), myobj.farg1, myobj.farg1->size());
_local_heap[var->_value] = myobj.farg1;
}
// test value
@ -321,7 +321,7 @@ int program::rpn_step(branch& myobj) {
else {
// arg1 = index of start or for command in program
// farg1 = current count
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
branch* start_or_for = (branch*)(*this)[myobj.arg1];
if (!myobj.arg_bool) {
myobj.arg_bool = true;
myobj.farg1 = start_or_for->farg1;
@ -335,10 +335,10 @@ int program::rpn_step(branch& myobj) {
if (start_or_for->arg1 != -1) {
object* obj;
unsigned int size;
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
symbol* var = (symbol*)(*this)[start_or_for->arg1];
// increase symbol variable
_local_heap.replace_value(string(var->_value), myobj.farg1, myobj.farg1->size());
_local_heap[var->_value] = myobj.farg1;
}
// test loop value is out of range

View file

@ -7,11 +7,12 @@ void program::rpn_re() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
number* re = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
CHECK_MPFR(mpfr_set(re->_value.mpfr, ((complex*)_calc_stack.get_obj(0))->re()->mpfr, floating_t::s_mpfr_rnd));
number* re = new number();
_stack->push_back(re);
CHECK_MPFR(mpfr_set(re->_value.mpfr, ((complex*)_calc_stack.at(0))->re()->mpfr, floating_t::s_mpfr_rnd));
_calc_stack.pop_back();
}
@ -22,11 +23,12 @@ void program::rpn_im() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
number* im = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
CHECK_MPFR(mpfr_set(im->_value.mpfr, ((complex*)_calc_stack.get_obj(0))->im()->mpfr, floating_t::s_mpfr_rnd));
number* im = new number();
_stack->push_back(im);
CHECK_MPFR(mpfr_set(im->_value.mpfr, ((complex*)_calc_stack.at(0))->im()->mpfr, floating_t::s_mpfr_rnd));
_calc_stack.pop_back();
}
@ -39,11 +41,12 @@ void program::rpn_arg() {
// calc atan2(x/y)
complex* cplx = (complex*)_stack->pop_back();
number* num = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
number* num = new number();
_calc_stack.push_back(num);
CHECK_MPFR(mpfr_atan2(num->_value.mpfr, cplx->im()->mpfr, cplx->re()->mpfr, floating_t::s_mpfr_rnd));
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
_calc_stack.pop_back();
}
@ -66,14 +69,15 @@ void program::rpn_r2c() {
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
_stack->pop_back();
complex* cplx = (complex*)_stack->allocate_back(complex::calc_size(), cmd_complex);
CHECK_MPFR(mpfr_set(cplx->re()->mpfr, ((number*)_calc_stack.get_obj(1))->_value.mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_set(cplx->im()->mpfr, ((number*)_calc_stack.get_obj(0))->_value.mpfr, floating_t::s_mpfr_rnd));
complex* cplx = new complex();
_stack->push_back(cplx);
CHECK_MPFR(mpfr_set(cplx->re()->mpfr, ((number*)_calc_stack.at(1))->_value.mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_set(cplx->im()->mpfr, ((number*)_calc_stack.at(0))->_value.mpfr, floating_t::s_mpfr_rnd));
_calc_stack.pop_back(2);
}
@ -84,11 +88,13 @@ void program::rpn_c2r() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
number* re = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* im = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* re = new number();
_stack->push_back(re);
number* im = new number();
_stack->push_back(im);
CHECK_MPFR(mpfr_set(re->_value.mpfr, ((complex*)_calc_stack.back())->re()->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_set(im->_value.mpfr, ((complex*)_calc_stack.back())->im()->mpfr, floating_t::s_mpfr_rnd));
@ -106,13 +112,13 @@ void program::rpn_r2p() {
rpn_dup();
rpn_arg();
complex* cplx = (complex*)_stack->get_obj(1);
complex* cplx = (complex*)_stack->at(1);
CHECK_MPFR(mpfr_set(cplx->im()->mpfr, ((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd));
_stack->pop_back();
rpn_swap();
rpn_abs();
cplx = (complex*)_stack->get_obj(1);
cplx = (complex*)_stack->at(1);
CHECK_MPFR(mpfr_set(cplx->re()->mpfr, ((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd));
_stack->pop_back();
}
@ -124,12 +130,12 @@ void program::rpn_p2r() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_calc_stack.allocate_back(number::calc_size(), cmd_number);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_calc_stack.push_back(new number());
// assert complex is polar
complex* rhotheta = (complex*)_calc_stack.get_obj(1);
number* tmp = (number*)_calc_stack.get_obj(0);
complex* rhotheta = (complex*)_calc_stack.at(1);
number* tmp = (number*)_calc_stack.at(0);
complex* result = (complex*)_stack->back();
// calc cos(theta)

View file

@ -56,8 +56,8 @@ void program::rpn_help() {
printf(" with %d digits after the decimal point\n", number::s_decimal_digits);
// bits precision, decimal digits and rounding mode
printf("Current floating point precision is %d bits\n", (int)floating_t::s_mpfr_prec);
printf("Current rounding mode is \"%s\"\n", floating_t::s_mpfr_rnd_str[floating_t::s_mpfr_rnd]);
printf("Current floating point precision is %d bits\n", (int)number::s_mpfr_prec);
printf("Current rounding mode is \"%s\"\n", number::s_mpfr_rnd_str[number::s_mpfr_rnd]);
printf("\n\n");
}
@ -158,19 +158,13 @@ void program::rpn_sci() {
/// @brief version keyword implementation
///
void program::rpn_version() {
// allocate and set object
unsigned int naked_entry_len = strlen(version);
ostring* str = (ostring*)_stack->allocate_back(sizeof(ostring) + naked_entry_len + 1, cmd_string);
str->set(version, naked_entry_len);
_stack->push_back(new ostring(version));
}
/// @brief uname keyword implementation
///
void program::rpn_uname() {
// allocate and set object
unsigned int naked_entry_len = strlen(uname);
ostring* str = (ostring*)_stack->allocate_back(sizeof(ostring) + naked_entry_len + 1, cmd_string);
str->set(uname, naked_entry_len);
_stack->push_back(new ostring(uname));
}
/// @brief history keyword implementation
@ -193,11 +187,7 @@ void program::rpn_type() {
int type = _stack->pop_back()->_type;
if (type < 0 || type >= (int)cmd_max) type = (int)cmd_undef;
unsigned int string_size = strlen(object::s_cmd_type_string[type]);
unsigned int size = sizeof(symbol) + string_size + 1;
ostring* typ = (ostring*)_stack->allocate_back(size, cmd_string);
typ->set(object::s_cmd_type_string[type], string_size);
_stack->push_back(new ostring(object::s_cmd_type_string[type]));
}
/// @brief default keyword implementation
@ -211,15 +201,14 @@ void program::rpn_precision() {
ARG_MUST_BE_OF_TYPE(0, cmd_number);
// set precision
unsigned long prec = mpfr_get_ui(((number*)_stack->pop_back())->_value.mpfr, floating_t::s_mpfr_rnd);
unsigned long prec = static_cast<number*>(_stack->pop_back())->_value.toULong();
if (prec >= (unsigned long)MPFR_PREC_MIN && prec <= (unsigned long)MPFR_PREC_MAX) {
floating_t::s_mpfr_prec = (mpfr_prec_t)prec;
floating_t::s_mpfr_prec_bytes = mpfr_custom_get_size(prec);
number::s_mpfr_prec = (mpfr_prec_t)prec;
// modify digits seen by user if std mode
if (number::s_mode == number::std) {
// calc max nb of digits user can see with the current bit precision
number::s_decimal_digits = base_digits_from_bit_precision(10, floating_t::s_mpfr_prec);
number::s_decimal_digits = base_digits_from_bit_precision(10, number::s_mpfr_prec);
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_STD);
}
} else
@ -235,8 +224,8 @@ void program::rpn_round() {
ostring* str = (ostring*)_stack->pop_back();
bool done = false;
for (int rnd = (int)MPFR_DEFAULT_RND; rnd <= (int)MPFR_RNDA; rnd++) {
if (string(floating_t::s_mpfr_rnd_str[rnd]) == str->_value) {
floating_t::s_mpfr_rnd = (mpfr_rnd_t)rnd;
if (string(number::s_mpfr_rnd_str[rnd]) == str->_value) {
number::s_mpfr_rnd = (mpfr_rnd_t)rnd;
done = true;
}
}

View file

@ -3,7 +3,8 @@
/// @brief e keyword implementation
///
void program::rpn_e(void) {
number* euler = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* euler = new number();
_stack->push_back(euler);
euler->_value = 1L;
CHECK_MPFR(mpfr_exp(euler->_value.mpfr, euler->_value.mpfr, floating_t::s_mpfr_rnd));
}
@ -13,11 +14,12 @@ void program::rpn_e(void) {
void program::rpn_log10() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
if (_stack->at(0)->_type == cmd_number || _stack->at(0)->_type == cmd_complex) {
// log10(z)=ln(z)/ln(10)
rpn_ln();
number* ten = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* ten = new number();
_stack->push_back(ten);
CHECK_MPFR(mpfr_set_d(ten->_value.mpfr, 10.0, floating_t::s_mpfr_rnd));
rpn_ln();
rpn_div();
@ -30,9 +32,10 @@ void program::rpn_log10() {
void program::rpn_alog10() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
number* ten = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
if (_stack->at(0)->_type == cmd_number || _stack->at(0)->_type == cmd_complex) {
floating_t* left = &((number*)_stack->at(0))->_value;
number* ten = new number();
_stack->push_back(ten);
CHECK_MPFR(mpfr_set_d(ten->_value.mpfr, 10.0, floating_t::s_mpfr_rnd));
rpn_ln();
rpn_mul();
@ -45,11 +48,12 @@ void program::rpn_alog10() {
void program::rpn_log2() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
if (_stack->at(0)->_type == cmd_number || _stack->at(0)->_type == cmd_complex) {
// log2(z)=ln(z)/ln(2)
rpn_ln();
number* two = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* two = new number();
_stack->push_back(two);
CHECK_MPFR(mpfr_set_d(two->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
rpn_ln();
rpn_div();
@ -62,9 +66,10 @@ void program::rpn_log2() {
void program::rpn_alog2() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
number* two = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
if (_stack->at(0)->_type == cmd_number || _stack->at(0)->_type == cmd_complex) {
floating_t* left = &((number*)_stack->at(0))->_value;
number* two = new number();
_stack->push_back(two);
CHECK_MPFR(mpfr_set_d(two->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
rpn_ln();
rpn_mul();
@ -77,31 +82,32 @@ void program::rpn_alog2() {
void program::rpn_ln() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
if (_stack->at(0)->_type == cmd_number) {
number* left = (number*)_stack->back();
// x<0 -> ln(x) = ln(-x)+i*pi
if (mpfr_cmp_si(left->_value.mpfr, 0) < 0) {
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
left = (number*)_calc_stack.back();
complex* cplx = (complex*)_stack->allocate_back(complex::calc_size(), cmd_complex);
complex* cplx = new complex();
_stack->push_back(cplx);
CHECK_MPFR(mpfr_neg(cplx->re()->mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_log(cplx->re()->mpfr, cplx->re()->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_const_pi(cplx->im()->mpfr, floating_t::s_mpfr_rnd));
_calc_stack.pop_back();
} else
CHECK_MPFR(mpfr_log(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// ln(x+iy) = 0.5*ln(x*x+y*y) + i atan(x/y)
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
floating_t* x = ((complex*)_calc_stack.get_obj(0))->re();
floating_t* y = ((complex*)_calc_stack.get_obj(0))->im();
floating_t* x = ((complex*)_calc_stack.at(0))->re();
floating_t* y = ((complex*)_calc_stack.at(0))->im();
floating_t* re = ((complex*)_stack->get_obj(0))->re();
floating_t* im = ((complex*)_stack->get_obj(0))->im();
floating_t* re = ((complex*)_stack->at(0))->re();
floating_t* im = ((complex*)_stack->at(0))->im();
// 1. atan(x/y)
CHECK_MPFR(mpfr_atan2(im->mpfr, y->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
@ -123,18 +129,18 @@ void program::rpn_ln() {
void program::rpn_exp() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_exp(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// exp(x)*(cos(y)+i sin(y))
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
floating_t* x = ((complex*)_calc_stack.get_obj(0))->re();
floating_t* y = ((complex*)_calc_stack.get_obj(0))->im();
floating_t* x = ((complex*)_calc_stack.at(0))->re();
floating_t* y = ((complex*)_calc_stack.at(0))->im();
floating_t* re = ((complex*)_stack->get_obj(0))->re();
floating_t* im = ((complex*)_stack->get_obj(0))->im();
floating_t* re = ((complex*)_stack->at(0))->re();
floating_t* im = ((complex*)_stack->at(0))->im();
CHECK_MPFR(mpfr_cos(re->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_sin(im->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
@ -152,11 +158,12 @@ void program::rpn_exp() {
void program::rpn_expm() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
if (_stack->at(0)->_type == cmd_number || _stack->at(0)->_type == cmd_complex) {
// exp(x)-1
rpn_exp();
number* one = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* one = new number();
_stack->push_back(one);
CHECK_MPFR(mpfr_set_d(one->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_minus();
} else
@ -168,9 +175,10 @@ void program::rpn_expm() {
void program::rpn_lnp1() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
if (_stack->at(0)->_type == cmd_number || _stack->at(0)->_type == cmd_complex) {
// ln(x+1)
number* one = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* one = new number();
_stack->push_back(one);
CHECK_MPFR(mpfr_set_d(one->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_plus();
@ -184,19 +192,21 @@ void program::rpn_lnp1() {
void program::rpn_sinh() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_sinh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// sinh(x+iy)=sinh(x)cos(y)+icosh(x)sin(y)
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
number* num = new number();
_stack->push_back(num);
floating_t* tmp = &num->_value;
floating_t* x = ((complex*)_calc_stack.at(1))->re();
floating_t* y = ((complex*)_calc_stack.at(1))->im();
floating_t* re = ((complex*)_stack->get_obj(0))->re();
floating_t* im = ((complex*)_stack->get_obj(0))->im();
floating_t* re = ((complex*)_stack->at(0))->re();
floating_t* im = ((complex*)_stack->at(0))->im();
CHECK_MPFR(mpfr_sinh(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_cos(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
@ -216,14 +226,15 @@ void program::rpn_sinh() {
void program::rpn_asinh() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_asinh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// asinh(z)=ln(z+sqrt(1+z*z))
rpn_dup();
rpn_square();
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* num = new number();
_stack->push_back(num);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_plus();
rpn_squareroot();
@ -238,19 +249,21 @@ void program::rpn_asinh() {
void program::rpn_cosh() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_cosh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// acosh(x+iy)=cosh(x)cos(y)+isinh(x)sin(y)
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
number* num = new number();
_stack->push_back(num);
floating_t* tmp = &num->_value;
floating_t* x = ((complex*)_calc_stack.at(1))->re();
floating_t* y = ((complex*)_calc_stack.at(1))->im();
floating_t* re = ((complex*)_stack->get_obj(0))->re();
floating_t* im = ((complex*)_stack->get_obj(0))->im();
floating_t* re = ((complex*)_stack->at(0))->re();
floating_t* im = ((complex*)_stack->at(0))->im();
CHECK_MPFR(mpfr_cosh(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_cos(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
@ -270,17 +283,19 @@ void program::rpn_cosh() {
void program::rpn_acosh() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_acosh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// acosh(z)=ln(z+sqrt(z+1)sqrt(z-1))
rpn_dup();
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* num = new number();
_stack->push_back(num);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_plus();
rpn_dup();
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
num = (number*)new number();
_stack->push_back(num);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
rpn_minus();
rpn_mul();
@ -296,18 +311,18 @@ void program::rpn_acosh() {
void program::rpn_tanh() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_tanh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// tanh(x+iy)=(tanh(x)+itan(y)) / (1 + itanh(x)tan(y))
rpn_dup();
floating_t* x = ((complex*)_stack->get_obj(1))->re();
floating_t* y = ((complex*)_stack->get_obj(1))->im();
floating_t* x = ((complex*)_stack->at(1))->re();
floating_t* y = ((complex*)_stack->at(1))->im();
floating_t* re = ((complex*)_stack->get_obj(1))->re();
floating_t* im = ((complex*)_stack->get_obj(1))->im();
floating_t* re = ((complex*)_stack->at(1))->re();
floating_t* im = ((complex*)_stack->at(1))->im();
CHECK_MPFR(mpfr_tanh(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_tan(im->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
@ -326,23 +341,25 @@ void program::rpn_tanh() {
void program::rpn_atanh() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_atanh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// atanh(z)=0.5*ln((1+z)/(1-z))
rpn_dup();
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* num;
_stack->push_back(num = new number);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_plus();
rpn_swap();
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(num = new number);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_minus();
rpn_neg();
rpn_div();
rpn_ln();
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(num = new number);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 0.5, floating_t::s_mpfr_rnd));
rpn_mul();
} else

View file

@ -4,26 +4,25 @@
///
/// @param variable the variable name to find
/// @param obj the variable object found
/// @param size its size
/// @return true variable was found
/// @return false variable was not found
///
bool program::find_variable(string& variable, object*& obj, unsigned int& size) {
bool program::find_variable(string& variable, object*& obj) {
bool found = false;
program* parent = _parent_prog;
if (_local_heap.get(variable, obj, size))
if (_local_heap.get(variable, obj))
found = true;
else {
while (parent != NULL) {
if (parent->_local_heap.get(variable, obj, size)) {
if (parent->_local_heap.get(variable, obj)) {
found = true;
break;
}
parent = parent->_parent_prog;
}
if (!found) {
if (_heap->get(variable, obj, size)) found = true;
if (_heap->get(variable, obj)) found = true;
}
}
@ -40,11 +39,10 @@ void program::rpn_eval(void) {
if (IS_ARG_TYPE(0, cmd_symbol)) {
// recall a variable
object* obj;
unsigned int size;
string variable(((symbol*)_stack->back())->_value);
// if variable holds a program, run this program
if (find_variable(variable, obj, size)) {
if (find_variable(variable, obj)) {
if (obj->_type == cmd_program) {
prog_text = ((oprogram*)obj)->_value;
(void)_stack->pop_back();
@ -52,7 +50,7 @@ void program::rpn_eval(void) {
} else {
// else recall this variable (i.e. stack its content)
(void)_stack->pop_back();
stack::copy_and_push_back(obj, *_stack, size);
_stack->push_back(obj);
}
} else
ERR_CONTEXT(ret_unknown_variable);
@ -68,7 +66,7 @@ void program::rpn_eval(void) {
program prog(this);
// make program from entry
if (program::parse(prog_text.c_str(), prog) == ret_ok) {
if (program::parse(prog_text, prog) == ret_ok) {
// run it
prog.run(*_stack, *_heap);
}
@ -93,9 +91,9 @@ int program::rpn_inprog(branch& myobj) {
// find next oprogram object
for (unsigned int i = myobj.arg1 + 1; i < size(); i++) {
// count symbol
if (seq_type(i) == cmd_symbol) count_symbols++;
if ((*this)[i]->_type == cmd_symbol) count_symbols++;
// stop if prog
else if (seq_type(i) == cmd_program) {
else if ((*this)[i]->_type == cmd_program) {
prog_found = true;
break;
}
@ -130,16 +128,16 @@ int program::rpn_inprog(branch& myobj) {
// load variables
for (unsigned int i = myobj.arg1 + count_symbols; i > myobj.arg1; i--) {
_local_heap.add(string(((symbol*)seq_obj(i))->_value), _stack->get_obj(0), _stack->get_len(0));
_local_heap[string(((symbol*)(*this)[i])->_value)] = _stack->at(0);
(void)_stack->pop_back();
}
// run the program
string entry(((oprogram*)seq_obj(myobj.arg1 + count_symbols + 1))->_value);
string entry(((oprogram*)(*this)[myobj.arg1 + count_symbols + 1])->_value);
program prog(this);
// make the program from entry
if (program::parse(entry.c_str(), prog) == ret_ok) {
if (program::parse(entry, prog) == ret_ok) {
// run it
prog.run(*_stack, *_heap);
}

View file

@ -6,45 +6,33 @@ void program::rpn_plus() {
MIN_ARGUMENTS(2);
// adding strings
if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
unsigned int left_str_size = ((ostring*)_stack->get_obj(1))->_len;
unsigned int right_str_size = ((ostring*)_stack->get_obj(0))->_len;
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
(void)_stack->pop_back();
(void)_stack->pop_back();
ostring* str =
(ostring*)_stack->allocate_back(left_str_size + right_str_size + 1 + sizeof(ostring), cmd_string);
str->_len = left_str_size + right_str_size;
strncpy(str->_value, ((ostring*)_calc_stack.get_obj(1))->_value, left_str_size);
strncat(str->_value, ((ostring*)_calc_stack.get_obj(0))->_value, right_str_size);
_calc_stack.pop_back();
_calc_stack.pop_back();
if (_stack->at(0)->_type == cmd_string && _stack->at(1)->_type == cmd_string) {
string str =
static_cast<ostring*>(_stack->at(1))->_value + static_cast<ostring*>(_stack->at(0))->_value;
_stack->pop_back(2);
_stack->push_back(new ostring(str));
}
// adding numbers
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
else if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_add(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// adding complexes
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_complex) {
complex* right = (complex*)_stack->pop_back();
complex* left = (complex*)_stack->back();
CHECK_MPFR(mpfr_add(left->re()->mpfr, left->re()->mpfr, right->re()->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_add(left->im()->mpfr, left->im()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
}
// adding complex+number
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_complex) {
number* right = (number*)_stack->pop_back();
complex* left = (complex*)_stack->back();
CHECK_MPFR(mpfr_add(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// adding number+complex
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_number) {
rpn_swap();
number* right = (number*)_stack->pop_back();
complex* left = (complex*)_stack->back();
@ -59,26 +47,26 @@ void program::rpn_minus() {
MIN_ARGUMENTS(2);
// substracting numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_sub(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// substracting complexes
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_complex) {
complex* right = (complex*)_stack->pop_back();
complex* left = (complex*)_stack->back();
CHECK_MPFR(mpfr_sub(left->re()->mpfr, left->re()->mpfr, right->re()->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_sub(left->im()->mpfr, left->im()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
}
// substracting complex-number
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_complex) {
number* right = (number*)_stack->pop_back();
complex* left = (complex*)_stack->back();
CHECK_MPFR(mpfr_sub(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// substracting number-complex
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_number) {
rpn_swap();
number* right = (number*)_stack->pop_back();
complex* left = (complex*)_stack->back();
@ -93,17 +81,17 @@ void program::rpn_mul() {
MIN_ARGUMENTS(2);
// multiplying numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_mul(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// multiplying complexes (a+ib)*(x+iy)=(ax-by)+i(ay+bx)=a(x+iy)+b(-y+ix)
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_complex) {
complex* right = (complex*)_stack->pop_back(); // x+iy
complex* left = (complex*)_stack->back(); // a+ib
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
complex* left_sav = (complex*)_calc_stack.back(); // a+ib
// left: (a+ib)->(ax+iay)
@ -122,14 +110,14 @@ void program::rpn_mul() {
_calc_stack.pop_back();
}
// multiplying complex*number
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_complex) {
number* right = (number*)_stack->pop_back();
complex* left = (complex*)_stack->back();
CHECK_MPFR(mpfr_mul(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_mul(left->im()->mpfr, left->im()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// multiplying number*complex
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_number) {
rpn_swap();
number* right = (number*)_stack->pop_back();
complex* left = (complex*)_stack->back();
@ -144,23 +132,25 @@ void program::rpn_mul() {
///
void program::do_divide_complexes() {
//(a+ib)/(x+iy)=(a+ib)(x-iy)/(x^2+y^2)=(ax+by+i(bx-ay))/(x^2+y^2)
complex* right = (complex*)_stack->get_obj(0); // x+iy
complex* left = (complex*)_stack->get_obj(1); // a+ib
complex* right = (complex*)_stack->at(0); // x+iy
complex* left = (complex*)_stack->at(1); // a+ib
// 1. calc (x^2-y^2) in _calc_stack
number* ex = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
number* ex;
_calc_stack.push_back(ex = new number);
CHECK_MPFR(mpfr_mul(ex->_value.mpfr, right->re()->mpfr, right->re()->mpfr,
floating_t::s_mpfr_rnd)); // x2
number* wy = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
number* wy;
_calc_stack.push_back(wy = new number);
CHECK_MPFR(mpfr_mul(wy->_value.mpfr, right->im()->mpfr, right->im()->mpfr,
floating_t::s_mpfr_rnd)); // y2
CHECK_MPFR(mpfr_add(ex->_value.mpfr, ex->_value.mpfr, wy->_value.mpfr,
floating_t::s_mpfr_rnd)); // ex=x2+y2
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack); // x+iy
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
complex* left_sav = (complex*)_calc_stack.get_obj(1); // a+ib
complex* right_sav = (complex*)_calc_stack.get_obj(0); // x+iy
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack); // x+iy
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
complex* left_sav = (complex*)_calc_stack.at(1); // a+ib
complex* right_sav = (complex*)_calc_stack.at(0); // x+iy
// 2. left.re=ax+by
CHECK_MPFR(mpfr_mul(left->re()->mpfr, left_sav->re()->mpfr, right_sav->re()->mpfr,
@ -192,40 +182,40 @@ void program::rpn_div() {
MIN_ARGUMENTS(2);
// dividing numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_div(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// dividing complexes
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex)
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_complex)
do_divide_complexes();
// dividing complex/number
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_complex) {
number* right = (number*)_stack->pop_back();
complex* left = (complex*)_stack->back();
CHECK_MPFR(mpfr_div(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_div(left->im()->mpfr, left->im()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
}
// dividing number/complex
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_number) {
// 1. copy out
stack::copy_and_push_back(*_stack, _stack->size() - 1,
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1,
_calc_stack); // complex
stack::copy_and_push_back(*_stack, _stack->size() - 2,
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2,
_calc_stack); // number
_stack->pop_back(2);
// 2. copy back (2 complexes on stack)
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2,
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2,
*_stack); // complex back to stack
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2,
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2,
*_stack); // complex back to stack
// 3. set complex level 2 to (number,0)
complex* new_cplx = (complex*)_stack->get_obj(1);
complex* new_cplx = (complex*)_stack->at(1);
CHECK_MPFR(
mpfr_set(new_cplx->re()->mpfr, ((number*)_calc_stack.get_obj(0))->_value.mpfr, floating_t::s_mpfr_rnd));
mpfr_set(new_cplx->re()->mpfr, ((number*)_calc_stack.at(0))->_value.mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_set_ui(new_cplx->im()->mpfr, 0UL, floating_t::s_mpfr_rnd));
_calc_stack.pop_back(2);
@ -240,10 +230,10 @@ void program::rpn_div() {
void program::rpn_neg() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
if (_stack->at(0)->_type == cmd_number) {
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_neg(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
complex* left = (complex*)_stack->back();
CHECK_MPFR(mpfr_neg(left->re()->mpfr, left->re()->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_neg(left->im()->mpfr, left->im()->mpfr, floating_t::s_mpfr_rnd));
@ -256,14 +246,14 @@ void program::rpn_neg() {
void program::rpn_inv() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
if (_stack->at(0)->_type == cmd_number) {
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_si_div(left->_value.mpfr, 1L, left->_value.mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// 1. duplicate
rpn_dup();
// 2. set complex level 2 to (1,0)
complex* cplx = (complex*)_stack->get_obj(1);
complex* cplx = (complex*)_stack->at(1);
CHECK_MPFR(mpfr_set_ui(cplx->re()->mpfr, 1UL, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_set_ui(cplx->im()->mpfr, 0UL, floating_t::s_mpfr_rnd));
// 3. divide
@ -306,10 +296,10 @@ void program::rpn_power() {
MIN_ARGUMENTS(2);
bool done_on_real = false;
if (_stack->get_type(1) == cmd_number) {
if (_stack->at(1)->_type == cmd_number) {
ARG_MUST_BE_OF_TYPE(0, cmd_number);
number* right = (number*)_stack->get_obj(0);
number* left = (number*)_stack->get_obj(1);
number* right = (number*)_stack->at(0);
number* left = (number*)_stack->at(1);
if (mpfr_cmp_d(left->_value.mpfr, 0.0) >= 0) {
CHECK_MPFR(mpfr_pow(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
@ -317,27 +307,27 @@ void program::rpn_power() {
done_on_real = true;
} else {
// copy power out
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
// negative number -> complex number
_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(new number);
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.0, floating_t::s_mpfr_rnd));
rpn_r2c();
// copy power back
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
_calc_stack.pop_back();
}
}
// carrefull, no 'else' here
if (!done_on_real) {
if (_stack->get_type(1) == cmd_complex) {
if (_stack->at(1)->_type == cmd_complex) {
ARG_MUST_BE_OF_TYPE(0, cmd_number);
// power on tmp stack
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
// switch complex to polar
@ -362,23 +352,23 @@ void program::rpn_power() {
/// @brief sqrt keyword implementation
///
void program::rpn_squareroot() {
if (_stack->get_type(0) == cmd_number) {
if (_stack->at(0)->_type == cmd_number) {
number* left = (number*)_stack->back();
if (mpfr_cmp_d(left->_value.mpfr, 0.0) >= 0)
CHECK_MPFR(mpfr_sqrt(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
else {
// negative number -> complex square root
_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(new number);
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.0, floating_t::s_mpfr_rnd));
rpn_r2c();
_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(new number);
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.5, floating_t::s_mpfr_rnd));
rpn_power();
}
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// calc cplx^0.5
_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(new number);
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.5, floating_t::s_mpfr_rnd));
rpn_power();
} else
@ -390,10 +380,10 @@ void program::rpn_squareroot() {
void program::rpn_square() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
if (_stack->at(0)->_type == cmd_number) {
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_sqr(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
rpn_dup();
rpn_mul();
} else
@ -418,12 +408,12 @@ void program::rpn_modulo() {
void program::rpn_abs() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
if (_stack->at(0)->_type == cmd_number) {
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_abs(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// 1. copy out -> calc x2+iy2
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
// 2. calc x2+iy2
@ -432,7 +422,7 @@ void program::rpn_abs() {
CHECK_MPFR(mpfr_mul(cplx->im()->mpfr, cplx->im()->mpfr, cplx->im()->mpfr, floating_t::s_mpfr_rnd));
// 3. new real on stack
_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(new number);
number* module = (number*)_stack->back();
// 4. set it to |x2+y2| then take sqrt
@ -479,8 +469,8 @@ void program::rpn_base() {
if (mpfr_cmp_d(((number*)_stack->back())->_value.mpfr, (double)BASE_MIN) >= 0 &&
mpfr_cmp_d(((number*)_stack->back())->_value.mpfr, (double)BASE_MAX) <= 0) {
int base = (int)mpfr_get_d(((number*)_stack->pop_back())->_value.mpfr, floating_t::s_mpfr_rnd);
((number*)_stack->get_obj(0))->_base = base;
((number*)_stack->get_obj(0))->_representation = number::base;
((number*)_stack->at(0))->_base = base;
((number*)_stack->at(0))->_representation = number::base;
} else
ERR_CONTEXT(ret_out_of_range);
}
@ -493,7 +483,8 @@ void program::rpn_fact() {
// fact(n) = gamma(n+1)
number* left = (number*)_stack->back();
number* right = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* right;
_stack->push_back(right = new number);
right->_value = 1L;
rpn_plus();
@ -505,12 +496,12 @@ void program::rpn_fact() {
void program::rpn_sign() {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
if (_stack->at(0)->_type == cmd_number) {
// fact(n) = gamma(n+1)
number* left = (number*)_stack->back();
int result = mpfr_sgn(left->_value.mpfr);
left->_value = (long)result;
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// calc x/sqrt(x*x+y*y) +iy/sqrt(x*x+y*y)
rpn_dup();
rpn_abs();
@ -533,8 +524,10 @@ void program::rpn_mant() {
else {
mpfr_abs(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd);
number* one = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
number* ten = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
number* one;
_stack->push_back(one = new number);
number* ten;
_stack->push_back(ten = new number);
ten->_value = 10L;
one->_value = 1L;
@ -566,8 +559,10 @@ void program::rpn_xpon() {
double exponant = 0.0;
mpfr_abs(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd);
number* one = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
number* ten = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
number* one;
_stack->push_back(one = new number);
number* ten;
_stack->push_back(ten = new number);
ten->_value = 10L;
one->_value = 1L;

View file

@ -4,11 +4,11 @@
///
void program::rpn_swap(void) {
MIN_ARGUMENTS(2);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
(void)_stack->pop_back(2);
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2, *_stack);
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
_calc_stack.pop_back(2);
}
@ -32,7 +32,7 @@ void program::rpn_dropn(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
int args = (int)((number*)_stack->back())->_value.toLong();
MIN_ARGUMENTS(args + 1);
(void)_stack->pop_back(args + 1);
@ -46,15 +46,15 @@ void program::rpn_erase(void) { (void)_stack->pop_back(_stack->size()); }
///
void program::rpn_dup(void) {
MIN_ARGUMENTS(1);
stack::copy_and_push_back(*_stack, _stack->size() - 1, *_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, *_stack);
}
/// @brief dup2 keyword implementation
///
void program::rpn_dup2(void) {
MIN_ARGUMENTS(2);
stack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
stack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
}
/// @brief dupn keyword implementation
@ -63,11 +63,11 @@ void program::rpn_dupn(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
int args = (int)((number*)_stack->back())->_value.toLong();
MIN_ARGUMENTS(args + 1);
_stack->pop_back();
for (int i = 0; i < args; i++) stack::copy_and_push_back(*_stack, _stack->size() - args, *_stack);
for (int i = 0; i < args; i++) rpnstack::copy_and_push_back(*_stack, _stack->size() - args, *_stack);
}
/// @brief pick keyword implementation
@ -84,7 +84,7 @@ void program::rpn_pick(void) {
return;
}
stack::copy_and_push_back(*_stack, _stack->size() - to_pick, *_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - to_pick, *_stack);
}
/// @brief rot keyword implementation
@ -92,23 +92,19 @@ void program::rpn_pick(void) {
void program::rpn_rot(void) {
MIN_ARGUMENTS(3);
stack::copy_and_push_back(*_stack, _stack->size() - 3, _calc_stack);
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 3, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
(void)_stack->pop_back(3);
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2, *_stack);
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 3, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 3, *_stack);
_calc_stack.pop_back(3);
}
/// @brief depth keyword implementation
///
void program::rpn_depth(void) {
unsigned long depth = (unsigned long)_stack->size();
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
num->set(depth);
}
void program::rpn_depth(void) { _stack->push_back(new number(_stack->size())); }
/// @brief roll keyword implementation
///
@ -116,17 +112,17 @@ void program::rpn_roll(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
int args = (int)((number*)_stack->back())->_value.toLong();
MIN_ARGUMENTS(args + 1);
_stack->pop_back();
for (int i = 0; i < args; i++) {
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
(void)_stack->pop_back();
}
for (int i = 1; i < args; i++) stack::copy_and_push_back(_calc_stack, args - 1 - i, *_stack);
stack::copy_and_push_back(_calc_stack, args - 1, *_stack);
for (int i = 1; i < args; i++) rpnstack::copy_and_push_back(_calc_stack, args - 1 - i, *_stack);
rpnstack::copy_and_push_back(_calc_stack, args - 1, *_stack);
_calc_stack.pop_back(args);
}
@ -137,18 +133,18 @@ void program::rpn_rolld(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
int args = (int)((number*)_stack->back())->_value.toLong();
MIN_ARGUMENTS(args + 1);
_stack->pop_back();
for (int i = 0; i < args; i++) {
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
(void)_stack->pop_back();
}
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - args, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - args, *_stack);
for (int i = 1; i < args; i++) stack::copy_and_push_back(_calc_stack, _calc_stack.size() - i, *_stack);
for (int i = 1; i < args; i++) rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - i, *_stack);
_calc_stack.pop_back(args);
}
@ -158,5 +154,5 @@ void program::rpn_rolld(void) {
void program::rpn_over(void) {
MIN_ARGUMENTS(2);
stack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
}

View file

@ -7,36 +7,37 @@ void program::rpn_sto(void) {
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
string name(((symbol*)_stack->pop_back())->_value);
_heap->add(name, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[name] = _stack->at(0);
(void)_stack->pop_back();
}
/// @brief sto+ keyword implementation
///
#if 0
void program::rpn_stoadd(void) {
MIN_ARGUMENTS(2);
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_symbol && _stack->at(1)->_type == cmd_number) {
// get variable value on stack level 1, make op then modify variable
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
rpn_plus();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
} else if (_stack->at(1)->_type == cmd_symbol && _stack->at(0)->_type == cmd_number) {
// copy value, get variable value on stack level 1,
// put back value on stack level 1, make op then modify variable
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpn_plus();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else
@ -48,27 +49,27 @@ void program::rpn_stoadd(void) {
void program::rpn_stosub(void) {
MIN_ARGUMENTS(2);
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_symbol && _stack->at(1)->_type == cmd_number) {
// get variable value on stack level 1, make op then modify variable
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
rpn_minus();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
} else if (_stack->at(1)->_type == cmd_symbol && _stack->at(0)->_type == cmd_number) {
// copy value, get variable value on stack level 1,
// put back value on stack level 1, make op then modify variable
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpn_minus();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else
@ -80,27 +81,27 @@ void program::rpn_stosub(void) {
void program::rpn_stomul(void) {
MIN_ARGUMENTS(2);
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_symbol && _stack->at(1)->_type == cmd_number) {
// get variable value on stack level 1, make op then modify variable
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
rpn_mul();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
} else if (_stack->at(1)->_type == cmd_symbol && _stack->at(0)->_type == cmd_number) {
// copy value, get variable value on stack level 1,
// put back value on stack level 1, make op then modify variable
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpn_mul();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else
@ -112,27 +113,27 @@ void program::rpn_stomul(void) {
void program::rpn_stodiv(void) {
MIN_ARGUMENTS(2);
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_symbol && _stack->at(1)->_type == cmd_number) {
// get variable value on stack level 1, make op then modify variable
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
rpn_div();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
} else if (_stack->at(1)->_type == cmd_symbol && _stack->at(0)->_type == cmd_number) {
// copy value, get variable value on stack level 1,
// put back value on stack level 1, make op then modify variable
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
_stack->pop_back();
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpn_div();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else
@ -144,13 +145,13 @@ void program::rpn_stodiv(void) {
void program::rpn_stoneg(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_symbol) {
if (_stack->at(0)->_type == cmd_symbol) {
// get variable value on stack level 1, make op then modify variable
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
rpn_neg();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else
@ -162,18 +163,19 @@ void program::rpn_stoneg(void) {
void program::rpn_stoinv(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_symbol) {
if (_stack->at(0)->_type == cmd_symbol) {
// get variable value on stack level 1, make op then modify variable
string variable(((symbol*)_stack->back())->_value);
rpn_rcl();
if (_err == ret_ok) {
rpn_inv();
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
(*_heap)[variable] = _stack->at(0);
_stack->pop_back();
}
} else
ERR_CONTEXT(ret_bad_operand_type);
}
#endif
/// @brief rcl keyword implementation
///
@ -183,13 +185,12 @@ void program::rpn_rcl(void) {
// recall a variable
object* obj;
unsigned int size;
string variable(((symbol*)_stack->back())->_value);
// mind the order of heaps
if (find_variable(variable, obj, size)) {
if (find_variable(variable, obj)) {
(void)_stack->pop_back();
stack::copy_and_push_back(obj, *_stack, size);
_stack->push_back(obj);
} else
ERR_CONTEXT(ret_unknown_variable);
}
@ -199,27 +200,12 @@ void program::rpn_rcl(void) {
void program::rpn_edit(void) {
MIN_ARGUMENTS(1);
FILE* tmp = tmpfile();
if (tmp != NULL) {
ostringstream st;
// re-write stack objet in a stream
((object*)_stack->pop_back())->show(tmp);
((object*)_stack->pop_back())->show(st);
// edit: stuff chars using linenoise facility
int len = (int)ftell(tmp);
rewind(tmp);
// get stream data
void* file_data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(tmp), 0);
if (file_data != MAP_FAILED) {
// set it as the linenoise line entry
linenoisePreloadBuffer((const char*)file_data);
munmap(file_data, len);
} else
ERR_CONTEXT(ret_runtime_error);
fclose(tmp);
} else
ERR_CONTEXT(ret_runtime_error);
linenoisePreloadBuffer((const char*)st.str().c_str());
}
/// @brief recall then eval a symbol variable if it is auto-evaluable
@ -229,17 +215,16 @@ void program::rpn_edit(void) {
void program::auto_rcl(symbol* symb) {
if (symb->_auto_eval) {
object* obj;
unsigned int size;
string variable(symb->_value);
// mind the order of heaps
if (find_variable(variable, obj, size)) {
stack::copy_and_push_back(obj, *_stack, size);
if (find_variable(variable, obj)) {
_stack->push_back(obj);
if (obj->_type == cmd_program) rpn_eval();
} else
stack::copy_and_push_back(symb, *_stack, symb->size());
_stack->push_back(symb);
} else
stack::copy_and_push_back(symb, *_stack, symb->size());
_stack->push_back(symb);
}
/// @brief purge keyword implementation
@ -256,25 +241,24 @@ void program::rpn_purge(void) {
///
void program::rpn_vars(void) {
object* obj;
unsigned int size;
program* parent = _parent_prog;
string name;
// heap variables
for (int i = 0; i < (int)_heap->count_vars(); i++) {
(void)_heap->get_by_index(i, name, obj, size);
for (int i = 0; i < (int)_heap->size(); i++) {
(void)_heap->get_by_index(i, name, obj);
printf("var %d: name '%s', type %s, value ", i + 1, name.c_str(), object::s_cmd_type_string[obj->_type]);
obj->show();
obj->show(cout);
printf("\n");
}
// parents local variables
while (parent != NULL) {
for (int i = 0; i < (int)parent->_local_heap.size(); i++) {
(void)parent->_local_heap.get_by_index(i, name, obj, size);
(void)parent->_local_heap.get_by_index(i, name, obj);
printf("local var %d: name '%s', type %s, value ", i + 1, name.c_str(),
object::s_cmd_type_string[obj->_type]);
obj->show();
obj->show(cout);
printf("\n");
}
parent = parent->_parent_prog;
@ -282,13 +266,13 @@ void program::rpn_vars(void) {
// local variables
for (int i = 0; i < (int)_local_heap.size(); i++) {
(void)_local_heap.get_by_index(i, name, obj, size);
(void)_local_heap.get_by_index(i, name, obj);
printf("local var %d: name '%s', type %s, value ", i + 1, name.c_str(), object::s_cmd_type_string[obj->_type]);
obj->show();
obj->show(cout);
printf("\n");
}
}
/// @brief clusr keyword implementation
///
void program::rpn_clusr(void) { _heap->erase_all(); }
void program::rpn_clusr(void) { _heap->clear(); }

View file

@ -1,3 +1,5 @@
#include <fcntl.h>
#include "program.hpp"
/// @brief ->str keyword implementation
@ -6,7 +8,8 @@ void program::rpn_instr() {
MIN_ARGUMENTS(1);
// stringify only if not already a string
if (_stack->get_type(0) != cmd_string) {
if (_stack->at(0)->_type != cmd_string) {
// TODO really ugly, to change
// write the object in stack(0) in a string and remove this obj
FILE* tmp = tmpfile();
if (tmp != NULL) {
@ -14,14 +17,21 @@ void program::rpn_instr() {
// reserve the correct size on stack
unsigned int str_size = (unsigned int)ftell(tmp);
ostring* str = (ostring*)_stack->allocate_back(str_size + 1 + sizeof(ostring), cmd_string);
str->_len = str_size;
char* buf = (char*)malloc(str_size);
if (buf == nullptr) {
ERR_CONTEXT(ret_out_of_memory);
goto destroy_file;
}
// fill the obj
rewind(tmp);
if (fread(str->_value, str_size, 1, tmp) != 1) ERR_CONTEXT(ret_runtime_error);
str->_value[str_size] = 0;
if (fread(buf, str_size, 1, tmp) != 1) ERR_CONTEXT(ret_runtime_error);
_stack->push_back(new ostring(buf));
destroy_file:
char filePath[PATH_MAX];
fclose(tmp);
if (fcntl(fileno(tmp), 12 /*F_GETPATH*/, filePath) != -1) remove(filePath);
} else
ERR_CONTEXT(ret_runtime_error);
}
@ -38,7 +48,7 @@ void program::rpn_strout() {
program prog;
// make program from string in stack level 1
if (program::parse(entry.c_str(), prog) == ret_ok)
if (program::parse(entry, prog) == ret_ok)
// run it
prog.run(*_stack, *_heap);
}
@ -52,13 +62,7 @@ void program::rpn_chr() {
// get arg as number % 256
char the_chr = (char)mpfr_get_d(((number*)_stack->pop_back())->_value.mpfr, floating_t::s_mpfr_rnd);
if (the_chr < 32 || the_chr > 126) the_chr = '.';
// reserve the correct size on stack (1 char)
unsigned int str_size = 1;
ostring* str = (ostring*)_stack->allocate_back(str_size + 1 + sizeof(ostring), cmd_string);
str->_len = str_size;
str->_value[0] = the_chr;
str->_value[1] = 0;
_stack->push_back(new ostring(string(1, the_chr)));
}
/// @brief num keyword implementation
@ -68,8 +72,7 @@ void program::rpn_num() {
ARG_MUST_BE_OF_TYPE(0, cmd_string);
double the_chr = (double)((ostring*)_stack->pop_back())->_value[0];
number* numb = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
numb->_value = the_chr;
_stack->push_back(new number(the_chr));
}
/// @brief size keyword implementation
@ -78,9 +81,8 @@ void program::rpn_strsize() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_string);
double len = ((ostring*)_stack->pop_back())->_len;
number* numb = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
numb->_value = len;
double len = ((ostring*)_stack->pop_back())->_value.size();
_stack->push_back(new number(len));
}
/// @brief pos keyword implementation
@ -90,28 +92,23 @@ void program::rpn_strpos() {
ARG_MUST_BE_OF_TYPE(0, cmd_string);
ARG_MUST_BE_OF_TYPE(1, cmd_string);
long pos = 0;
char* src = ((ostring*)_stack->get_obj(1))->_value;
char* found = strstr(src, ((ostring*)_stack->get_obj(0))->_value);
if (found != NULL) pos = (long)(found - src) + 1L;
size_t pos = static_cast<ostring*>(_stack->at(1))->_value.find(((ostring*)_stack->at(0))->_value);
_stack->pop_back(2);
number* numb = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
numb->_value = pos;
_stack->push_back(new number(pos));
}
/// @brief sub keyword implementation
///
void program::rpn_strsub() {
#if 0
MIN_ARGUMENTS(3);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
ARG_MUST_BE_OF_TYPE(2, cmd_string);
long first = long(((number*)_stack->get_obj(1))->_value) - 1;
long last = long(((number*)_stack->get_obj(0))->_value) - 1;
long len = ((ostring*)_stack->get_obj(2))->_len;
long first = long(((number*)_stack->at(1))->_value) - 1;
long last = long(((number*)_stack->at(0))->_value) - 1;
long len = ((ostring*)_stack->at(2))->_len;
bool result_is_void = false;
_stack->pop_back(2);
@ -131,11 +128,11 @@ void program::rpn_strsub() {
ostring* str = (ostring*)_calc_stack.allocate_back(str_size + 1 + sizeof(ostring), cmd_string);
str->_len = str_size;
memcpy(((ostring*)_calc_stack.back())->_value, ((ostring*)_stack->get_obj(0))->_value + first, str_size);
memcpy(((ostring*)_calc_stack.back())->_value, ((ostring*)_stack->at(0))->_value + first, str_size);
((ostring*)_calc_stack.back())->_value[str_size] = 0;
_stack->pop_back();
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
rpnstack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
_calc_stack.pop_back();
} else {
_stack->pop_back();
@ -143,4 +140,5 @@ void program::rpn_strsub() {
str->_len = 0;
str->_value[0] = 0;
}
#endif
}

View file

@ -5,26 +5,13 @@
/// @param stack_is the output string
/// @param stk the stack
///
void program::test_get_stack(string& stack_is, stack& stk) {
void program::test_get_stack(string& stack_is, rpnstack& stk) {
for (int i = 0; i < (int)stk.size(); i++) {
FILE* tmp_file = tmpfile();
char* line = NULL;
size_t len;
if (i > 0) stack_is += ", ";
if (tmp_file != NULL) {
((object*)stk.seq_obj(i))->show(tmp_file);
// write stack in a tmp file
(void)rewind(tmp_file);
if (getline(&line, &len, tmp_file) >= 0) {
stack_is += line;
free(line);
}
(void)fclose(tmp_file);
} else
ERR_CONTEXT(ret_runtime_error);
ostringstream st;
stk[stk.size() - i - 1]->show(st);
stack_is += st.str();
}
}
@ -91,7 +78,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
string test_title;
string entry;
ret_value ret;
stack stk;
rpnstack stk;
heap hp;
bool failed = false;
bool is_first_step;
@ -209,7 +196,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
} else if (entry.size() > 0) {
// parse entry and run line
program prog;
ret = program::parse(entry.c_str(), prog);
ret = program::parse(entry, prog);
if (ret == ret_ok) {
// run it
(void)prog.run(stk, hp);

View file

@ -5,12 +5,13 @@
/// @return 0 strings are equal
/// @return !0 strings are not equal (see strcmp output)
///
int program::cmp_strings_on_stack_top() {
long program::cmp_strings_on_stack_top() {
// _stack sould have 2 strings at level 1 and 2
// this function removes these 2 entries
ostring* right = (ostring*)_stack->pop_back();
ostring* left = (ostring*)_stack->pop_back();
return strncmp(left->_value, right->_value, min(left->_len, right->_len));
long res = (long)static_cast<ostring*>(_stack->at(0))->_value.compare(static_cast<ostring*>(_stack->at(1))->_value);
(void)_stack->pop_back();
(void)_stack->pop_back();
return res;
}
/// @brief > keyword implementation
@ -19,21 +20,19 @@ void program::rpn_sup(void) {
MIN_ARGUMENTS(2);
// numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) > 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp(left->_value.mpfr_ptr(), right->_value.mpfr_ptr()) > 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
// strings
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
int res_cmp = cmp_strings_on_stack_top();
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
res->_value = (res_cmp > 0) ? 1L : 0L;
} else
else if (_stack->at(0)->_type == cmd_string && _stack->at(1)->_type == cmd_string)
_stack->push_back(new number(cmp_strings_on_stack_top()));
else
ERR_CONTEXT(ret_bad_operand_type);
}
@ -43,21 +42,19 @@ void program::rpn_sup_eq(void) {
MIN_ARGUMENTS(2);
// numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) >= 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp(left->_value.mpfr_ptr(), right->_value.mpfr_ptr()) >= 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
// strings
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
int res_cmp = cmp_strings_on_stack_top();
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
res->_value = (res_cmp >= 0) ? 1L : 0L;
} else
else if (_stack->at(0)->_type == cmd_string && _stack->at(1)->_type == cmd_string)
_stack->push_back(new number(cmp_strings_on_stack_top()));
else
ERR_CONTEXT(ret_bad_operand_type);
}
@ -67,21 +64,19 @@ void program::rpn_inf(void) {
MIN_ARGUMENTS(2);
// numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) < 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp(left->_value.mpfr_ptr(), right->_value.mpfr_ptr()) < 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
// strings
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
int res_cmp = cmp_strings_on_stack_top();
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
res->_value = (res_cmp < 0) ? 1L : 0L;
} else
else if (_stack->at(0)->_type == cmd_string && _stack->at(1)->_type == cmd_string)
_stack->push_back(new number(cmp_strings_on_stack_top()));
else
ERR_CONTEXT(ret_bad_operand_type);
}
@ -91,21 +86,19 @@ void program::rpn_inf_eq(void) {
MIN_ARGUMENTS(2);
// numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) <= 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp(left->_value.mpfr_ptr(), right->_value.mpfr_ptr()) <= 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
// strings
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
int res_cmp = cmp_strings_on_stack_top();
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
res->_value = (res_cmp <= 0) ? 1L : 0L;
} else
else if (_stack->at(0)->_type == cmd_string && _stack->at(1)->_type == cmd_string)
_stack->push_back(new number(cmp_strings_on_stack_top()));
else
ERR_CONTEXT(ret_bad_operand_type);
}
@ -115,36 +108,30 @@ void program::rpn_diff(void) {
MIN_ARGUMENTS(2);
// numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) != 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp(left->_value.mpfr_ptr(), right->_value.mpfr_ptr()) != 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
// complexes
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_complex) {
bool diff = false;
complex* right = (complex*)_stack->pop_back();
complex* left = (complex*)_stack->pop_back();
ocomplex* right = (ocomplex*)_stack->pop_back();
ocomplex* left = (ocomplex*)_stack->pop_back();
if (mpfr_cmp(left->re()->mpfr, right->re()->mpfr) != 0 || mpfr_cmp(left->im()->mpfr, right->im()->mpfr) != 0)
if (mpfr_cmp(left->re()->mpfr_ptr(), right->re()->mpfr_ptr()) != 0 || mpfr_cmp(left->im()->mpfr_ptr(), right->im()->mpfr_ptr()) != 0)
diff = true;
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
if (diff)
mpfr_set_si(num->_value.mpfr, 1, floating_t::s_mpfr_rnd);
else
mpfr_set_si(num->_value.mpfr, 0, floating_t::s_mpfr_rnd);
_stack->push_back(new number(diff?1L:0L));
}
// strings
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
int res_cmp = cmp_strings_on_stack_top();
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
res->_value = (res_cmp != 0) ? 1L : 0L;
} else
else if (_stack->at(0)->_type == cmd_string && _stack->at(1)->_type == cmd_string)
_stack->push_back(new number(cmp_strings_on_stack_top()));
else
ERR_CONTEXT(ret_bad_operand_type);
}
@ -154,36 +141,30 @@ void program::rpn_eq(void) {
MIN_ARGUMENTS(2);
// numbers
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
if (_stack->at(0)->_type == cmd_number && _stack->at(1)->_type == cmd_number) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) == 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp(left->_value.mpfr_ptr(), right->_value.mpfr_ptr()) == 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
// complexes
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
else if (_stack->at(0)->_type == cmd_complex && _stack->at(1)->_type == cmd_complex) {
bool diff = false;
complex* right = (complex*)_stack->pop_back();
complex* left = (complex*)_stack->pop_back();
ocomplex* right = (ocomplex*)_stack->pop_back();
ocomplex* left = (ocomplex*)_stack->pop_back();
if (mpfr_cmp(left->re()->mpfr, right->re()->mpfr) != 0 || mpfr_cmp(left->im()->mpfr, right->im()->mpfr) != 0)
if (mpfr_cmp(left->re()->mpfr_ptr(), right->re()->mpfr_ptr()) != 0 || mpfr_cmp(left->im()->mpfr_ptr(), right->im()->mpfr_ptr()) != 0)
diff = true;
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
if (diff)
mpfr_set_si(num->_value.mpfr, 0, floating_t::s_mpfr_rnd);
else
mpfr_set_si(num->_value.mpfr, 1, floating_t::s_mpfr_rnd);
_stack->push_back(new number(diff?0L:1L));
}
// strings
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
int res_cmp = cmp_strings_on_stack_top();
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
res->_value = (res_cmp == 0) ? 1L : 0L;
} else
else if (_stack->at(0)->_type == cmd_string && _stack->at(1)->_type == cmd_string)
_stack->push_back(new number(cmp_strings_on_stack_top()));
else
ERR_CONTEXT(ret_bad_operand_type);
}
@ -197,10 +178,10 @@ void program::rpn_test_and(void) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if ((mpfr_cmp_si(left->_value.mpfr, 0) != 0) && (mpfr_cmp_si(right->_value.mpfr, 0) != 0))
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if ((mpfr_cmp_si(left->_value.mpfr_ptr(), 0) != 0) && (mpfr_cmp_si(right->_value.mpfr_ptr(), 0) != 0))
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
/// @brief or keyword implementation
@ -213,10 +194,10 @@ void program::rpn_test_or(void) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if ((mpfr_cmp_si(left->_value.mpfr, 0) != 0) || (mpfr_cmp_si(right->_value.mpfr, 0) != 0))
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if ((mpfr_cmp_si(left->_value.mpfr_ptr(), 0) != 0) || (mpfr_cmp_si(right->_value.mpfr_ptr(), 0) != 0))
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
/// @brief xor keyword implementation
@ -229,16 +210,16 @@ void program::rpn_test_xor(void) {
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp_si(left->_value.mpfr, 0) == 0) {
if (mpfr_cmp_si(right->_value.mpfr, 0) != 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp_si(left->_value.mpfr_ptr(), 0) == 0) {
if (mpfr_cmp_si(right->_value.mpfr_ptr(), 0) != 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
} else {
if (mpfr_cmp_si(right->_value.mpfr, 0) == 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp_si(right->_value.mpfr_ptr(), 0) == 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
}
@ -249,10 +230,10 @@ void program::rpn_test_not(void) {
ARG_MUST_BE_OF_TYPE(0, cmd_number);
number* left = (number*)_stack->back();
if (mpfr_cmp_si(left->_value.mpfr, 0) == 0)
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
if (mpfr_cmp_si(left->_value.mpfr_ptr(), 0) == 0)
mpfr_set_si(left->_value.mpfr_ptr(), 1, number::s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
mpfr_set_si(left->_value.mpfr_ptr(), 0, number::s_mpfr_rnd);
}
/// @brief test same implementation

View file

@ -1,4 +1,5 @@
#include <time.h>
#include "program.hpp"
/// @brief time keyword implementation
@ -18,8 +19,8 @@ void program::rpn_time() {
((double)tm->tm_sec) * 1000000.0 + (double)(ts.tv_nsec / 1000);
// push it
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd));
number* num;
_stack->push_back(num = static_cast<number*>(new number(date)));
// division is done here because of real precision)
CHECK_MPFR(mpfr_div_d(num->_value.mpfr, num->_value.mpfr, 10000000000.0, floating_t::s_mpfr_rnd));
} else
@ -42,8 +43,8 @@ void program::rpn_date() {
date = (double)(tm->tm_mon + 1) * 1000000.0 + (double)(tm->tm_mday) * 10000.0 + (double)(tm->tm_year + 1900);
// push it
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd));
number* num;
_stack->push_back(num = static_cast<number*>(new number(date)));
// division is done here because of real precision)
CHECK_MPFR(mpfr_div_d(num->_value.mpfr, num->_value.mpfr, 1000000.0, floating_t::s_mpfr_rnd));
} else
@ -66,8 +67,7 @@ void program::rpn_ticks() {
date = 1000000.0 * (double)ts.tv_sec + (double)(ts.tv_nsec / 1000);
// push it
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd));
_stack->push_back(static_cast<number*>(new number(date)));
} else
ERR_CONTEXT(ret_internal);
}

View file

@ -3,7 +3,8 @@
/// @brief pi keyword implementation
///
void program::rpn_pi(void) {
number* pi = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* pi;
_stack->push_back(pi = static_cast<number*>(new number));
CHECK_MPFR(mpfr_const_pi(pi->_value.mpfr, floating_t::s_mpfr_rnd));
}
@ -17,7 +18,7 @@ void program::rpn_d2r(void) {
rpn_pi();
floating_t* pi = &((number*)_stack->pop_back())->_value;
floating_t* left = &((number*)_stack->get_obj(0))->_value;
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_mul(left->mpfr, left->mpfr, pi->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_div_si(left->mpfr, left->mpfr, 180, floating_t::s_mpfr_rnd));
@ -33,7 +34,7 @@ void program::rpn_r2d(void) {
rpn_pi();
floating_t* pi = &((number*)_stack->pop_back())->_value;
floating_t* left = &((number*)_stack->get_obj(0))->_value;
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_div(left->mpfr, left->mpfr, pi->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_mul_si(left->mpfr, left->mpfr, 180, floating_t::s_mpfr_rnd));
@ -44,19 +45,21 @@ void program::rpn_r2d(void) {
void program::rpn_sin(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_sin(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// sin(x+iy)=sin(x)cosh(y)+icos(x)sinh(y)
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
number* num = static_cast<number*>(new number);
_stack->push_back(num);
floating_t* tmp = &num->_value;
floating_t* x = ((complex*)_calc_stack.at(1))->re();
floating_t* y = ((complex*)_calc_stack.at(1))->im();
floating_t* re = ((complex*)_stack->get_obj(0))->re();
floating_t* im = ((complex*)_stack->get_obj(0))->im();
floating_t* re = ((complex*)_stack->at(0))->re();
floating_t* im = ((complex*)_stack->at(0))->im();
CHECK_MPFR(mpfr_sin(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_cosh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
@ -76,33 +79,33 @@ void program::rpn_sin(void) {
void program::rpn_asin(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_asin(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
number* num;
complex* i;
// asin(z)=-iln(iz+sqrt(1-z*z))
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
i = (complex*)_calc_stack.get_obj(0);
i = (complex*)_calc_stack.at(0);
CHECK_MPFR(mpfr_set_d(i->re()->mpfr, 0.0, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_set_d(i->im()->mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_dup();
rpn_square();
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(num = static_cast<number*>(new number));
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_minus();
rpn_neg();
rpn_squareroot();
rpn_swap();
stack::copy_and_push_back(_calc_stack, 0, *_stack);
rpnstack::copy_and_push_back(_calc_stack, 0, *_stack);
rpn_mul();
rpn_plus();
rpn_ln();
stack::copy_and_push_back(_calc_stack, 0, *_stack);
rpnstack::copy_and_push_back(_calc_stack, 0, *_stack);
rpn_mul();
rpn_neg();
_calc_stack.pop_back();
@ -115,19 +118,21 @@ void program::rpn_asin(void) {
void program::rpn_cos(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_cos(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// cos(x+iy) = cos(x)cosh(y) - isin(x)sinh(y)
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
number* num = static_cast<number*>(new number);
_stack->push_back(num);
floating_t* tmp = &num->_value;
floating_t* x = ((complex*)_calc_stack.at(1))->re();
floating_t* y = ((complex*)_calc_stack.at(1))->im();
floating_t* re = ((complex*)_stack->get_obj(0))->re();
floating_t* im = ((complex*)_stack->get_obj(0))->im();
floating_t* re = ((complex*)_stack->at(0))->re();
floating_t* im = ((complex*)_stack->at(0))->im();
CHECK_MPFR(mpfr_cos(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_cosh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
@ -148,14 +153,15 @@ void program::rpn_cos(void) {
void program::rpn_acos(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_acos(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// acos(z)=pi/2-asin(z)
rpn_asin();
rpn_pi();
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
number* num;
_stack->push_back(num = static_cast<number*>(new number));
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
rpn_div();
rpn_minus();
@ -169,19 +175,21 @@ void program::rpn_acos(void) {
void program::rpn_tan(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_tan(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
// tan(x+iy) = (sin(2x)+isinh(2y)) / cosh(2y)+cos(2x)
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
number* num = static_cast<number*>(new number);
_stack->push_back(num);
floating_t* tmp = &num->_value;
floating_t* x = ((complex*)_calc_stack.at(1))->re();
floating_t* y = ((complex*)_calc_stack.at(1))->im();
floating_t* re = ((complex*)_stack->get_obj(0))->re();
floating_t* im = ((complex*)_stack->get_obj(0))->im();
floating_t* re = ((complex*)_stack->at(0))->re();
floating_t* im = ((complex*)_stack->at(0))->im();
// x->2x
CHECK_MPFR(mpfr_mul_si(x->mpfr, x->mpfr, 2, floating_t::s_mpfr_rnd));
@ -211,36 +219,36 @@ void program::rpn_tan(void) {
void program::rpn_atan(void) {
MIN_ARGUMENTS(1);
if (_stack->get_type(0) == cmd_number) {
floating_t* left = &((number*)_stack->get_obj(0))->_value;
if (_stack->at(0)->_type == cmd_number) {
floating_t* left = &((number*)_stack->at(0))->_value;
CHECK_MPFR(mpfr_atan(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
} else if (_stack->get_type(0) == cmd_complex) {
} else if (_stack->at(0)->_type == cmd_complex) {
number* num;
complex* i;
// atan(z)=0.5i(ln((1-iz)/(1+iz))
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
rpnstack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
i = (complex*)_calc_stack.get_obj(0);
i = (complex*)_calc_stack.at(0);
CHECK_MPFR(mpfr_set_d(i->re()->mpfr, 0.0, floating_t::s_mpfr_rnd));
CHECK_MPFR(mpfr_set_d(i->im()->mpfr, 1.0, floating_t::s_mpfr_rnd));
stack::copy_and_push_back(_calc_stack, 0, *_stack);
rpnstack::copy_and_push_back(_calc_stack, 0, *_stack);
rpn_mul();
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(num = static_cast<number*>(new number));
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
rpn_minus(); // iz-1
rpn_neg(); // 1-iz
rpn_dup();
rpn_neg(); // iz-1
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
_stack->push_back(num = static_cast<number*>(new number));
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
rpn_plus(); // iz+1
rpn_div();
rpn_ln();
CHECK_MPFR(mpfr_set_d(i->im()->mpfr, 0.5, floating_t::s_mpfr_rnd));
stack::copy_and_push_back(_calc_stack, 0, *_stack);
rpnstack::copy_and_push_back(_calc_stack, 0, *_stack);
rpn_mul();
_calc_stack.pop_back();

View file

@ -2,35 +2,20 @@
#define __stack_h__
#include <string.h>
#include <map>
using namespace std;
// allocation base size
#define ALLOC_STACK_CHUNK (64 * 1024)
#include <algorithm>
#include <deque>
#include <map>
#include "object.hpp"
using namespace std;
/// @brief stack object, parens of program, storing execution stack values or programs
///
class stack {
class rpnstack : public deque<object*> {
public:
stack() {
_base = NULL;
_base_pointer = NULL;
_total_size = 0;
_total_count_pointer = 0;
erase();
}
virtual ~stack() {
if (_base != NULL) free(_base);
if (_base_pointer != NULL) free(_base_pointer);
}
/// @brief remove all the stack elements
///
void erase() {
_current = _base;
_count = 0;
}
rpnstack() {}
virtual ~rpnstack() {}
/// @brief copy a whole stack entry and push it back to another stack
///
@ -38,349 +23,76 @@ class stack {
/// @param index_from index t ocopy from
/// @param to copy to
///
static void copy_and_push_back(stack& from, unsigned int index_from, stack& to) {
object* allocated = to.allocate_back(from.seq_len(index_from), from.seq_type(index_from));
memcpy(allocated, from.seq_obj(index_from), from.seq_len(index_from));
if (allocated->_type == cmd_number)
((number*)allocated)->move();
else if (allocated->_type == cmd_complex)
((complex*)allocated)->move();
static void copy_and_push_back(rpnstack& from, unsigned int index_from, rpnstack& to) {
to.push_back(from[index_from]);
}
/// @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_back(object* from, stack& to, unsigned int size) {
object* allocated = to.allocate_back(size, from->_type);
memcpy(allocated, from, size);
if (allocated->_type == cmd_number)
((number*)allocated)->move();
else if (allocated->_type == cmd_complex)
((complex*)allocated)->move();
static void copy_and_push_front(rpnstack& from, unsigned int index_from, rpnstack& to) {
to.push_front(from[index_from]);
}
/// @brief allocate one object back on an already populated (or not) stack
/// the object function move is called on every reallocated object on the stack
/// the object function init is called on the new allocated object if its type is cmd_number or cmd_complex
/// @brief pop back several entries
///
/// @param size the object size in bytes
/// @param type the object type
/// @return object* the allocated object
/// @param levels nb of entries
///
object* allocate_back(unsigned int size, cmd_type_t type) {
object* allocated;
bool data_is_reallocated = false;
char* old_base;
// manage data memory allocation (add as much as memory it is needed)
if (((_current - _base) + size) > _total_size) {
// calc nb of needed pages
unsigned long page_number = 1 + ((_current - _base) + size - _total_size) / ALLOC_STACK_CHUNK;
_total_size += page_number * ALLOC_STACK_CHUNK;
old_base = _base;
_base = (char*)realloc(_base, _total_size);
_current = _base + (_current - old_base);
data_is_reallocated = true;
void pop_back(int levels) {
for (int i = 0; i < levels; i++) deque::pop_back();
}
// manage pointers memory allocation (add one page if needed)
if ((_count + 1) > _total_count_pointer) {
_base_pointer =
(object**)realloc(_base_pointer, (_total_count_pointer * sizeof(object*)) + ALLOC_STACK_CHUNK);
_total_count_pointer += (ALLOC_STACK_CHUNK / sizeof(object));
/// @brief pop back 1 entry
///
/// @return retrieved object
///
object* pop_back() {
object* o = back();
pop_back(1);
return o;
}
// recalc object pointers in case of base reallocation
if (data_is_reallocated) {
for (int i = 0; i < _count; i++) {
_base_pointer[i] = (object*)(_base + ((char*)_base_pointer[i] - old_base));
if (_base_pointer[i]->_type == cmd_number)
((number*)_base_pointer[i])->move();
else if (_base_pointer[i]->_type == cmd_complex)
((complex*)_base_pointer[i])->move();
}
}
// manage stack itself
_base_pointer[_count++] = (object*)_current;
allocated = (object*)_current;
_current += size;
// init object
allocated->_type = type;
allocated->_size = size;
if (type == cmd_number)
((number*)allocated)->init();
else if (type == cmd_complex)
((complex*)allocated)->init();
return allocated;
}
object* pop_back(int pop_count = 1) {
object* back = NULL;
// pop several entries, return the last
while (pop_count-- > 0) {
if (_count > 0) {
_current = (char*)_base_pointer[--_count];
back = (object*)_current;
}
}
return back;
}
/// @brief the number of objects on stack
///
/// @return unsigned int
///
unsigned int size() { return _count; }
/// @brief stack access (stack_level=0=first out)
///
/// @param stack_level the object stack level
/// @return object* pointer on object at this stack level
///
object* get_obj(unsigned int stack_level) { return seq_obj(_count - stack_level - 1); }
/// @brief same as get_obj
///
/// @param stack_level the object stack level
/// @return object* pointer on object at this stack level
///
object* operator[](unsigned int stack_level) { return seq_obj(_count - stack_level - 1); }
/// @brief returns the last object on stack
///
/// @return object* the object
///
object* back() {
object* obj = NULL;
if (_count > 0) obj = _base_pointer[_count - 1];
return obj;
}
/// @brief get an object len
///
/// @param index the object stack level
/// @return unsigned int the length in bytes
///
unsigned int get_len(unsigned int index) { return seq_len(_count - index - 1); }
/// @brief get an object type
///
/// @param index the object stack level
/// @return cmd_type_t the object type
///
cmd_type_t get_type(unsigned int index) { return seq_type(_count - index - 1); }
/// @brief sequential object access (index is counted from front)
///
/// @param index object index from front
/// @return object* the object pointer
///
object* seq_obj(unsigned int index) {
object* obj = NULL;
if (index < _count) obj = _base_pointer[index];
return obj;
}
/// @brief get an object len
///
/// @param index the object stack level from front
/// @return unsigned int the length in bytes
///
unsigned int seq_len(unsigned int index) {
unsigned int len = 0;
if (index < _count) len = _base_pointer[index]->_size;
return len;
}
/// @brief get an object len
///
/// @param index the object stack level from front
/// @return cmd_type_t the object type
///
cmd_type_t seq_type(unsigned int index) {
cmd_type_t type = cmd_undef;
if (index < _count) type = _base_pointer[index]->_type;
return type;
}
private:
char* _base;
char* _current;
object** _base_pointer;
unsigned int _count; //< stack count
unsigned int _total_count_pointer; //< total number of possible pointers
unsigned int _total_size; //< total allocated data size in bytes
};
/// @brief heap object, storing variables (=named object)
///
class heap : public stack {
class heap : public map<string, object*> {
public:
heap() {}
virtual ~heap() {}
/// @brief add a variable on the heap
///
/// @param name the variable name
/// @param obj the variable content
/// @param size the variable size in bytes
/// @return object*
///
object* add(const string name, object* obj, unsigned int size) {
map<string, unsigned int>::iterator i = _map.find(name);
object* local = NULL;
// variable does not exist in heap or already exists but its size is too
// short -> allocate
if (i != _map.end()) local = seq_obj(i->second);
if (local == NULL || (local != NULL && size > local->_size)) {
copy_and_push_back(obj, *this, size);
_map[name] = ((stack*)this)->size() - 1;
} else {
// variable already exists in heap but previous was larger -> don't
// reallocate copy a whole stack entry and push it back to another stack
memcpy(local, obj, size);
if (local->_type == cmd_number)
((number*)local)->move();
else if (local->_type == cmd_complex)
((complex*)local)->move();
}
return local;
}
/// @brief get a variable
///
/// @param name the variable name
/// @param obj the variable content
/// @param size the variable size in bytes
/// @return true the variable was found
/// @return false the variable was not found
///
bool get(const string name, object*& obj, unsigned int& size) {
bool get(const string name, object*& obj) {
bool ret = false;
map<string, unsigned int>::iterator i = _map.find(name);
if (i != _map.end()) {
obj = seq_obj(i->second);
size = obj->_size;
auto i = find(name);
if (i != end()) {
obj = i->second;
ret = true;
}
return ret;
}
/// @brief replace a variable value by another
///
/// @param name the variable name
/// @param obj the new value
/// @param size the variable size in bytes
/// @return true the variable was found
/// @return false the variable was not found
///
bool replace_value(const string name, object* obj, unsigned int size) {
bool ret = false;
map<string, unsigned int>::iterator i = _map.find(name);
if (i != _map.end()) {
object* obj_dst = seq_obj(i->second);
if (size <= obj_dst->_size) {
(void)memcpy(obj_dst, obj, size);
if (obj_dst->_type == cmd_number)
((number*)obj_dst)->move();
else if (obj_dst->_type == cmd_complex)
((complex*)obj_dst)->move();
ret = true;
}
}
return ret;
}
/// @brief whether a variable exists in heap or not
///
/// @param name the variable name
/// @return true the variable exists
/// @return false variable does not exist
///
bool exist(const string name) { return (_map.find(name) != _map.end()); }
/// @brief get a variable by its index in heap
///
/// @param num the variable index
/// @param name the variable name
/// @param obj the variable content
/// @param size the variable size in bytes
/// @return true the variable was found
/// @return false the variable was not found
///
bool get_by_index(int num, string& name, object*& obj, unsigned int& size) {
if (num >= 0 && num < (int)_map.size()) {
bool get_by_index(int num, string& name, object*& obj) {
if (num >= 0 && num < (int)size()) {
object* local;
map<string, unsigned int>::iterator i = _map.begin();
for (int j = 0; j < num; j++) i++;
local = (object*)seq_obj(i->second);
name = i->first;
obj = local;
size = local->_size;
auto i = begin();
for (; num > 0; num--, i++)
;
obj = i->second;
return true;
} else
return false;
}
/// @brief erase a variable
///
/// @param name the variable name
/// @return true the variable was found
/// @return false the variable was not found
///
bool erase(const string& name) {
map<string, unsigned int>::iterator i = _map.find(name);
bool ret = false;
if (i != _map.end()) {
// remove variable from map
_map.erase(i->first);
ret = true;
// TODO: remove unused stack entries
}
return ret;
}
/// @brief erase all variables
///
void erase_all(void) {
// map
_map.erase(_map.begin(), _map.end());
// and stack
((stack*)this)->erase();
}
/// @brief get the variables nb
///
/// @return unsigned int the variables nb
///
unsigned int count_vars() { return _map.size(); }
private:
map<string, unsigned int> _map;
};
#endif // __stack_h__