mirror of
https://github.com/louisrubet/rpn
synced 2024-12-26 09:58:55 +01:00
refactoring I (objects)
This commit is contained in:
parent
84f54d073b
commit
d3970d403b
25 changed files with 1149 additions and 1778 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -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
|
||||
|
|
|
@ -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
1
mpreal
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit c45d0d522c9bd0dd16d7aac25fa0862dd074ddb0
|
|
@ -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
|
||||
|
|
|
@ -83,6 +83,4 @@ static void chrono_print(int chrono) {
|
|||
}
|
||||
}
|
||||
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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 = "";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
299
src/object.hpp
299
src/object.hpp
|
@ -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
|
||||
|
|
714
src/parse.cpp
714
src/parse.cpp
|
@ -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;
|
||||
|
|
301
src/program.cpp
301
src/program.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 { \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
161
src/rpn-logs.cpp
161
src/rpn-logs.cpp
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
157
src/rpn-real.cpp
157
src/rpn-real.cpp
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
165
src/rpn-test.cpp
165
src/rpn-test.cpp
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
110
src/rpn-trig.cpp
110
src/rpn-trig.cpp
|
@ -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();
|
||||
|
|
360
src/stack.hpp
360
src/stack.hpp
|
@ -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__
|
||||
|
|
Loading…
Reference in a new issue