mirror of
https://github.com/louisrubet/rpn
synced 2025-01-30 20:34:30 +01:00
#214: doxy comments
This commit is contained in:
parent
7e19b195f0
commit
e5dd31560e
19 changed files with 995 additions and 304 deletions
31
src/main.cpp
31
src/main.cpp
|
@ -15,7 +15,8 @@ static heap s_global_heap;
|
|||
static stack s_global_stack;
|
||||
static program* s_prog_to_interrupt = NULL;
|
||||
|
||||
// actions to be done at rpn exit
|
||||
/// @brief actions to be done at rpn exit
|
||||
///
|
||||
void exit_interactive_rpn() {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
if (pw != NULL) {
|
||||
|
@ -32,7 +33,8 @@ void exit_interactive_rpn() {
|
|||
}
|
||||
}
|
||||
|
||||
// actions to be done at rpn exit
|
||||
/// @brief actions to be done at rpn exit
|
||||
///
|
||||
void init_interactive_rpn() {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
if (pw != NULL) {
|
||||
|
@ -45,7 +47,12 @@ void init_interactive_rpn() {
|
|||
}
|
||||
}
|
||||
|
||||
// handle CtrlC signal
|
||||
/// @brief handle CtrlC signal (sigaction handler): exit rpn
|
||||
///
|
||||
/// @param sig signal, see POSIX sigaction
|
||||
/// @param siginfo signal info, see POSIX sigaction
|
||||
/// @param context see POSIX sigaction
|
||||
///
|
||||
static void ctrlc_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
if (s_prog_to_interrupt != NULL) {
|
||||
s_prog_to_interrupt->stop();
|
||||
|
@ -55,13 +62,22 @@ static void ctrlc_handler(int sig, siginfo_t* siginfo, void* context) {
|
|||
exit_interactive_rpn();
|
||||
}
|
||||
|
||||
// handle SIGSEGV signal
|
||||
/// @brief handle SIGSEGV signal (sigaction handler): stop and exit rpn
|
||||
///
|
||||
/// @param sig signal, see POSIX sigaction
|
||||
/// @param siginfo signal info, see POSIX sigaction
|
||||
/// @param context see POSIX sigaction
|
||||
///
|
||||
static void segv_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
fprintf(stderr, "Internal error\n");
|
||||
s_prog_to_interrupt->stop();
|
||||
s_prog_to_interrupt = NULL;
|
||||
}
|
||||
|
||||
/// @brief setup signals handlers to stop with honours
|
||||
///
|
||||
/// @param prog the prog to catch the signals to, must be checked not NULL by user
|
||||
///
|
||||
static void catch_signals(program* prog) {
|
||||
struct sigaction act;
|
||||
|
||||
|
@ -78,7 +94,12 @@ static void catch_signals(program* prog) {
|
|||
(void)fprintf(stderr, "Warning, SIGSEGV cannot be catched [errno=%d '%s']", errno, strerror(errno));
|
||||
}
|
||||
|
||||
//
|
||||
/// @brief rpn entry point
|
||||
///
|
||||
/// @param argc command line args nb
|
||||
/// @param argv command line args nb
|
||||
/// @return int 0=ok
|
||||
///
|
||||
int main(int argc, char* argv[]) {
|
||||
int ret = 0;
|
||||
bool go_on = true;
|
||||
|
|
|
@ -20,6 +20,14 @@ string number::s_mpfr_printf_format = string(MPFR_DEFAULT_FORMAT);
|
|||
//
|
||||
const char* object::s_cmd_type_string[cmd_max] = CMD_TYPE_STRINGS;
|
||||
|
||||
/// @brief return if a mpfr is higher to a given precision
|
||||
/// this function is directly copied from mpfr
|
||||
///
|
||||
/// @param p the mpfr to test
|
||||
/// @param prec the precision
|
||||
/// @return true p is higher than 10^prec
|
||||
/// @return false p is lower than 10^prec
|
||||
///
|
||||
static bool is_min(mpfr_t p, mpfr_prec_t prec) {
|
||||
// see mpfr_vasprintf code
|
||||
bool ret;
|
||||
|
@ -64,6 +72,14 @@ static bool is_min(mpfr_t p, mpfr_prec_t prec) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief print a mpfr in fixed format according to a base
|
||||
/// this function is based copied on mpfr library
|
||||
///
|
||||
/// @param stream the stream to write to
|
||||
/// @param real the real to print
|
||||
/// @param base the base to print the real
|
||||
/// @param write_after_sign substring to write between the sign and the real
|
||||
///
|
||||
static void print_fix(FILE* stream, mpfr_t real, int base, const char* write_after_sign = NULL) {
|
||||
// see mpfr_vasprintf code
|
||||
mpfr_exp_t exp = mpfr_get_exp(real);
|
||||
|
@ -142,6 +158,10 @@ static void print_fix(FILE* stream, mpfr_t real, int base, const char* write_aft
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief show an object representation according to its type
|
||||
///
|
||||
/// @param stream the stream to write to
|
||||
///
|
||||
void object::show(FILE* stream) {
|
||||
int digits;
|
||||
char* str;
|
||||
|
|
|
@ -24,8 +24,8 @@ class branch;
|
|||
typedef void (program::*program_fn_t)(void);
|
||||
typedef int (program::*branch_fn_t)(branch&);
|
||||
|
||||
// MPFR object
|
||||
////
|
||||
/// @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
|
||||
|
@ -67,8 +67,8 @@ struct floating_t {
|
|||
static const char* s_mpfr_rnd_str[5];
|
||||
};
|
||||
|
||||
// object - a generic stack object
|
||||
////
|
||||
/// @brief object - a generic stack object
|
||||
///
|
||||
struct object {
|
||||
// object type
|
||||
cmd_type_t _type;
|
||||
|
@ -83,8 +83,8 @@ struct object {
|
|||
static const char* s_cmd_type_string[cmd_max];
|
||||
};
|
||||
|
||||
// stack objects derived from object
|
||||
////
|
||||
/// @brief stack objects derived from object
|
||||
///
|
||||
struct number : public object {
|
||||
// members
|
||||
enum { dec, hex, bin, base } _representation;
|
||||
|
@ -122,8 +122,8 @@ struct number : public object {
|
|||
static string s_mpfr_printf_format;
|
||||
};
|
||||
|
||||
// stack objects derived from object
|
||||
////
|
||||
/// @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
|
||||
|
@ -153,6 +153,8 @@ struct complex : public object {
|
|||
}
|
||||
};
|
||||
|
||||
/// @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) {
|
||||
|
@ -172,6 +174,8 @@ struct ostring : public object {
|
|||
char _value[0];
|
||||
};
|
||||
|
||||
/// @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) {
|
||||
|
@ -191,6 +195,8 @@ struct oprogram : public object {
|
|||
char _value[0];
|
||||
};
|
||||
|
||||
/// @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) {
|
||||
|
@ -214,6 +220,8 @@ struct symbol : public object {
|
|||
char _value[0];
|
||||
};
|
||||
|
||||
/// @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) {
|
||||
|
@ -236,6 +244,8 @@ struct keyword : public object {
|
|||
char _value[0];
|
||||
};
|
||||
|
||||
/// @brief object branch
|
||||
///
|
||||
struct branch : public object {
|
||||
//
|
||||
void set(branch_fn_t fn, const char* value, unsigned int len) {
|
||||
|
|
613
src/parse.cpp
613
src/parse.cpp
|
@ -1,5 +1,11 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief completion callback as asked by linenoise-ng
|
||||
/// this is called by linenoise-ng whenever the user enters TAB
|
||||
///
|
||||
/// @param text the text after wich the user entered TAB
|
||||
/// @param lc the completion object to add strings with linenoiseAddCompletion()
|
||||
///
|
||||
void program::entry_completion_generator(const char* text, linenoiseCompletions* lc) {
|
||||
int i = 0;
|
||||
int text_len = strnlen(text, 6);
|
||||
|
@ -26,7 +32,11 @@ void program::entry_completion_generator(const char* text, linenoiseCompletions*
|
|||
}
|
||||
}
|
||||
|
||||
// interactive entry and decoding
|
||||
/// @brief interactive entry and decoding
|
||||
///
|
||||
/// @param prog the program to add entered objects
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::entry(program& prog) {
|
||||
string entry_str;
|
||||
char* entry;
|
||||
|
@ -63,7 +73,7 @@ ret_value program::entry(program& prog) {
|
|||
ret = parse(entry_str.c_str(), prog);
|
||||
|
||||
// keep history
|
||||
if (entry[0] != 0) linenoiseHistoryAdd(entry_str.c_str());
|
||||
if (entry[0] != 0) (void)linenoiseHistoryAdd(entry_str.c_str());
|
||||
} else
|
||||
ret = ret_internal;
|
||||
}
|
||||
|
@ -74,6 +84,13 @@ 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) {
|
||||
|
@ -87,6 +104,14 @@ ret_value program::get_fn(const char* fn_name, program_fn_t& fn, cmd_type_t& typ
|
|||
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;
|
||||
|
@ -113,6 +138,330 @@ static bool get_keyword(const string& entry, program& prog, string& remaining_en
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @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;
|
||||
|
||||
if (entry_len >= 1 && entry[0] == '\'') {
|
||||
if (entry_len == 1) {
|
||||
// void symbol entry, like '
|
||||
// total object length
|
||||
obj_len = sizeof(symbol) + 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("", 0, false);
|
||||
} 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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @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);
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @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();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
ret = true;
|
||||
} else
|
||||
(void)prog.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @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
|
||||
///
|
||||
/// @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
|
||||
///
|
||||
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);
|
||||
|
@ -245,260 +594,12 @@ static bool _cut(const char* entry, vector<string>& entries) {
|
|||
return entries.size() > 0;
|
||||
}
|
||||
|
||||
static bool get_symbol(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[0] == '\'') {
|
||||
if (entry_len == 1) {
|
||||
// void symbol entry, like '
|
||||
// total object length
|
||||
obj_len = sizeof(symbol) + 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("", 0, false);
|
||||
} 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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
} 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
ret = true;
|
||||
} else
|
||||
(void)prog.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool get_comment(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] == '#') {
|
||||
// entry (complete line) is ignored
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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, prog, remaining_entry))
|
||||
ret = true;
|
||||
else
|
||||
// nothing, considered as an auto-evaluated symbol
|
||||
if (get_other(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief parse an entry string: cut it into objects chunks and add them to a program
|
||||
///
|
||||
/// @param entry the entry string
|
||||
/// @param prog the program
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::parse(const char* entry, program& prog) {
|
||||
vector<string> entries;
|
||||
ret_value ret = ret_ok;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//
|
||||
//< return type strings
|
||||
const char* program::s_ret_value_string[ret_max] = RET_VALUE_STRINGS;
|
||||
|
||||
//
|
||||
//< kanguage reserved keywords (allowed types are cmd_keyword, cmd_branch or cmd_undef)
|
||||
program::keyword_t program::s_keywords[] = {
|
||||
// GENERAL
|
||||
{cmd_undef, "", NULL, "\nGENERAL"},
|
||||
|
@ -206,6 +206,12 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_max, "", NULL, ""},
|
||||
};
|
||||
|
||||
/// @brief run a program on a stack and a heap
|
||||
///
|
||||
/// @param stk the stack, storing prog result
|
||||
/// @param hp the heap, storing variables
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::run(stack& stk, heap& hp) {
|
||||
bool go_out = false;
|
||||
ret_value ret = ret_ok;
|
||||
|
@ -298,15 +304,19 @@ ret_value program::run(stack& stk, heap& hp) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief stop a program
|
||||
///
|
||||
///
|
||||
void program::stop() { interrupt_now = true; }
|
||||
|
||||
bool program::compare_keyword(keyword* k, const char* str_to_compare, int len) {
|
||||
if (k->_len >= len)
|
||||
return strncmp(k->_value, str_to_compare, len) == 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief return whether a branch object has a given name
|
||||
///
|
||||
/// @param b the branch object
|
||||
/// @param str_to_compare the name
|
||||
/// @param len the name length
|
||||
/// @return true the branch name is str_to_compare
|
||||
/// @return false the branch name is NOT str_to_compare
|
||||
///
|
||||
bool program::compare_branch(branch* b, const char* str_to_compare, int len) {
|
||||
if (b->_len >= len)
|
||||
return strncasecmp(b->_value, str_to_compare, len) == 0;
|
||||
|
@ -314,6 +324,13 @@ bool program::compare_branch(branch* b, const char* str_to_compare, int len) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// @brief prepare a program for execution
|
||||
/// this is needed before a program can be run
|
||||
/// inner members of branch or keyword objects are filled by this function
|
||||
/// these inner members store for example the index of the next keyword to execute etc.
|
||||
///
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::preprocess(void) {
|
||||
// for if-then-else-end
|
||||
vector<struct if_layout_t> vlayout;
|
||||
|
@ -540,6 +557,10 @@ ret_value program::preprocess(void) {
|
|||
return ret_ok;
|
||||
}
|
||||
|
||||
/// @brief show the last error set
|
||||
///
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::show_error() {
|
||||
ret_value ret;
|
||||
|
||||
|
@ -556,6 +577,12 @@ ret_value program::show_error() {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief record an error as the last error set and show it
|
||||
///
|
||||
/// @param err the error to record
|
||||
/// @param context a context string
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::show_error(ret_value err, string& context) {
|
||||
// record error
|
||||
_err = err;
|
||||
|
@ -563,6 +590,12 @@ ret_value program::show_error(ret_value err, string& context) {
|
|||
return show_error();
|
||||
}
|
||||
|
||||
/// @brief record an error as the last error set and show it
|
||||
///
|
||||
/// @param err the error to record
|
||||
/// @param context a context string
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::show_error(ret_value err, const char* context) {
|
||||
// record error
|
||||
_err = err;
|
||||
|
@ -570,6 +603,12 @@ ret_value program::show_error(ret_value err, const char* context) {
|
|||
return show_error();
|
||||
}
|
||||
|
||||
/// @brief set the last error as being a syntax error and show it
|
||||
///
|
||||
/// @param err the error to record
|
||||
/// @param context a context string
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
void program::show_syntax_error(const char* context) {
|
||||
// record error
|
||||
_err = ret_syntax;
|
||||
|
@ -577,8 +616,18 @@ void program::show_syntax_error(const char* context) {
|
|||
(void)show_error();
|
||||
}
|
||||
|
||||
/// @brief return the last error set
|
||||
///
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::get_err(void) { return _err; }
|
||||
|
||||
/// @brief show a stack (show its different objects)
|
||||
/// generally a stack is associated to a running program
|
||||
///
|
||||
/// @param st the stack to show
|
||||
/// @param show_separator whether to show a stack level prefix or not
|
||||
///
|
||||
void program::show_stack(stack& st, bool show_separator) {
|
||||
if (st.size() == 1) {
|
||||
((object*)st.back())->show();
|
||||
|
@ -592,6 +641,8 @@ void program::show_stack(stack& st, bool show_separator) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief apply default precision mode and digits
|
||||
///
|
||||
void program::apply_default() {
|
||||
// default float precision, float mode
|
||||
number::s_mode = DEFAULT_MODE;
|
||||
|
|
|
@ -27,7 +27,7 @@ using namespace std;
|
|||
#include "stack.hpp"
|
||||
#include "version.h"
|
||||
|
||||
//
|
||||
//< convinient structure to preprocess a program
|
||||
struct if_layout_t {
|
||||
if_layout_t()
|
||||
: index_then_or_unti_or_repeat(-1), index_else(-1), index_end(-1), is_do_unti(false), is_while_repeat(false) {}
|
||||
|
@ -39,7 +39,7 @@ struct if_layout_t {
|
|||
bool is_while_repeat;
|
||||
};
|
||||
|
||||
// program
|
||||
//< program class: the class containing a string parser, all the programs keywords, a stack for running the program
|
||||
class program : public stack {
|
||||
public:
|
||||
program(program* parent_prog = NULL) {
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//
|
||||
/// @brief if keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_if(branch& myobj) {
|
||||
// myobj.arg1 = 'if' condition evaluation value
|
||||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
|
@ -14,6 +19,11 @@ int program::rpn_if(branch& myobj) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// @brief then keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
///
|
||||
int program::rpn_then(branch& myobj) {
|
||||
// myobj.arg1 = index of then + 1
|
||||
// myobj.arg2 = index of else + 1 or end + 1
|
||||
|
@ -27,6 +37,12 @@ int program::rpn_then(branch& myobj) {
|
|||
return myobj.arg2;
|
||||
}
|
||||
|
||||
/// @brief else keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_else(branch& myobj) {
|
||||
// myobj.arg1 = index of else + 1
|
||||
// myobj.arg2 = index of end + 1
|
||||
|
@ -40,6 +56,12 @@ int program::rpn_else(branch& myobj) {
|
|||
return myobj.arg1;
|
||||
}
|
||||
|
||||
/// @brief end keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_end(branch& myobj) {
|
||||
int ret = -1;
|
||||
|
||||
|
@ -60,17 +82,34 @@ int program::rpn_end(branch& myobj) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief do keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_do(branch& myobj) {
|
||||
// nothing
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// @brief until keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_until(branch& myobj) {
|
||||
// nothing
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
/// @brief ift keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
void program::rpn_ift(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
@ -89,6 +128,12 @@ void program::rpn_ift(void) {
|
|||
(void)_stack->pop_back(2);
|
||||
}
|
||||
|
||||
/// @brief ifte keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
void program::rpn_ifte(void) {
|
||||
MIN_ARGUMENTS(3);
|
||||
ARG_MUST_BE_OF_TYPE(2, cmd_number);
|
||||
|
@ -108,12 +153,23 @@ void program::rpn_ifte(void) {
|
|||
(void)_calc_stack.pop_back();
|
||||
}
|
||||
|
||||
//
|
||||
/// @brief while keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_while(branch& myobj) {
|
||||
// nothing
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// @brief repeat keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_repeat(branch& myobj) {
|
||||
int ret = -1;
|
||||
|
||||
|
@ -128,6 +184,12 @@ int program::rpn_repeat(branch& myobj) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief start keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_start(branch& myobj) {
|
||||
int ret = -1;
|
||||
|
||||
|
@ -155,6 +217,12 @@ int program::rpn_start(branch& myobj) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief for keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_for(branch& myobj) {
|
||||
int ret;
|
||||
|
||||
|
@ -190,6 +258,12 @@ int program::rpn_for(branch& myobj) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief next keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_next(branch& myobj) {
|
||||
// arg1 = index of start or for command in program
|
||||
// farg1 = current count
|
||||
|
@ -228,6 +302,12 @@ int program::rpn_next(branch& myobj) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief step keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return -1 the next object index to run in the current program is the current+1
|
||||
///
|
||||
int program::rpn_step(branch& myobj) {
|
||||
int ret;
|
||||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief re keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_re() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
@ -12,6 +15,9 @@ void program::rpn_re() {
|
|||
_calc_stack.pop_back();
|
||||
}
|
||||
|
||||
/// @brief im keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_im() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
@ -24,6 +30,9 @@ void program::rpn_im() {
|
|||
_calc_stack.pop_back();
|
||||
}
|
||||
|
||||
/// @brief arg keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_arg() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
@ -38,6 +47,9 @@ void program::rpn_arg() {
|
|||
_calc_stack.pop_back();
|
||||
}
|
||||
|
||||
/// @brief conj keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_conj() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
@ -46,6 +58,9 @@ void program::rpn_conj() {
|
|||
CHECK_MPFR(mpfr_neg(cplx->im()->mpfr, cplx->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief r2c keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_r2c() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -62,6 +77,9 @@ void program::rpn_r2c() {
|
|||
_calc_stack.pop_back(2);
|
||||
}
|
||||
|
||||
/// @brief c2r keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_c2r() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
@ -77,6 +95,9 @@ void program::rpn_c2r() {
|
|||
_calc_stack.pop_back();
|
||||
}
|
||||
|
||||
/// @brief r2p keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_r2p() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
@ -96,6 +117,9 @@ void program::rpn_r2p() {
|
|||
_stack->pop_back();
|
||||
}
|
||||
|
||||
/// @brief p2r keyword implementation
|
||||
/// the result is stacked on current program stack
|
||||
///
|
||||
void program::rpn_p2r() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//
|
||||
/// @brief nop keyword implementation
|
||||
///
|
||||
void program::rpn_nop() {
|
||||
// nop
|
||||
}
|
||||
|
||||
/// @brief quit keyword implementation
|
||||
///
|
||||
void program::rpn_good_bye() { ERR_CONTEXT(ret_good_bye); }
|
||||
|
||||
/// @brief nop keyword implementation
|
||||
/// the result is written on stdout
|
||||
///
|
||||
void program::rpn_help() {
|
||||
// software name
|
||||
printf("\n" ATTR_BOLD "%s" ATTR_OFF "\n", uname);
|
||||
|
@ -55,10 +61,22 @@ void program::rpn_help() {
|
|||
printf("\n\n");
|
||||
}
|
||||
|
||||
/// @brief calculate a number of digits for a given base from a precision in bits
|
||||
///
|
||||
/// @param base the base
|
||||
/// @param bit_precision the precision in bits
|
||||
/// @return int the number of digits
|
||||
///
|
||||
static int base_digits_from_bit_precision(int base, int bit_precision) {
|
||||
return (int)ceil(bit_precision * log(2.0) / log((double)base)) - 1;
|
||||
}
|
||||
|
||||
/// @brief print a decimal digit in a given MPFR format
|
||||
///
|
||||
/// @param decimal_digits the number
|
||||
/// @param printf_format the format
|
||||
/// @return string the result string
|
||||
///
|
||||
static string make_digit_format(int decimal_digits, const char* printf_format) {
|
||||
stringstream ss;
|
||||
ss << MPFR_FORMAT_BEG;
|
||||
|
@ -67,6 +85,12 @@ static string make_digit_format(int decimal_digits, const char* printf_format) {
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
/// @brief whether a precision is in the precision min/max
|
||||
///
|
||||
/// @param precision the precision in bits
|
||||
/// @return true the precision is good
|
||||
/// @return false the precision is not good
|
||||
///
|
||||
static bool check_decimal_digits(double precision) {
|
||||
bool ret = true;
|
||||
|
||||
|
@ -80,6 +104,8 @@ static bool check_decimal_digits(double precision) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief std keyword implementation
|
||||
///
|
||||
void program::rpn_std() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -95,6 +121,8 @@ void program::rpn_std() {
|
|||
ERR_CONTEXT(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief fix keyword implementation
|
||||
///
|
||||
void program::rpn_fix() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -110,6 +138,8 @@ void program::rpn_fix() {
|
|||
ERR_CONTEXT(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief sci keyword implementation
|
||||
///
|
||||
void program::rpn_sci() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -125,6 +155,8 @@ void program::rpn_sci() {
|
|||
ERR_CONTEXT(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief version keyword implementation
|
||||
///
|
||||
void program::rpn_version() {
|
||||
// allocate and set object
|
||||
unsigned int naked_entry_len = strlen(version);
|
||||
|
@ -132,6 +164,8 @@ void program::rpn_version() {
|
|||
str->set(version, naked_entry_len);
|
||||
}
|
||||
|
||||
/// @brief uname keyword implementation
|
||||
///
|
||||
void program::rpn_uname() {
|
||||
// allocate and set object
|
||||
unsigned int naked_entry_len = strlen(uname);
|
||||
|
@ -139,6 +173,8 @@ void program::rpn_uname() {
|
|||
str->set(uname, naked_entry_len);
|
||||
}
|
||||
|
||||
/// @brief history keyword implementation
|
||||
///
|
||||
void program::rpn_history() {
|
||||
// see command history on stdout
|
||||
int index = 0;
|
||||
|
@ -150,6 +186,8 @@ void program::rpn_history() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief type keyword implementation
|
||||
///
|
||||
void program::rpn_type() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -162,8 +200,12 @@ void program::rpn_type() {
|
|||
typ->set(object::s_cmd_type_string[type], string_size);
|
||||
}
|
||||
|
||||
/// @brief default keyword implementation
|
||||
///
|
||||
void program::rpn_default() { program::apply_default(); }
|
||||
|
||||
/// @brief prec keyword implementation
|
||||
///
|
||||
void program::rpn_precision() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -184,6 +226,8 @@ void program::rpn_precision() {
|
|||
ERR_CONTEXT(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief round keyword implementation
|
||||
///
|
||||
void program::rpn_round() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief e keyword implementation
|
||||
///
|
||||
void program::rpn_e(void) {
|
||||
number* euler = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
euler->_value = 1L;
|
||||
CHECK_MPFR(mpfr_exp(euler->_value.mpfr, euler->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief log10 keyword implementation
|
||||
///
|
||||
void program::rpn_log10() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -21,6 +25,8 @@ void program::rpn_log10() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief alog10 keyword implementation
|
||||
///
|
||||
void program::rpn_alog10() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -34,6 +40,8 @@ void program::rpn_alog10() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief log2 keyword implementation
|
||||
///
|
||||
void program::rpn_log2() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -49,6 +57,8 @@ void program::rpn_log2() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief alog2 keyword implementation
|
||||
///
|
||||
void program::rpn_alog2() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -62,6 +72,8 @@ void program::rpn_alog2() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief ln keyword implementation
|
||||
///
|
||||
void program::rpn_ln() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -106,6 +118,8 @@ void program::rpn_ln() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief exp keyword implementation
|
||||
///
|
||||
void program::rpn_exp() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -133,6 +147,8 @@ void program::rpn_exp() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief expm keyword implementation
|
||||
///
|
||||
void program::rpn_expm() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -147,6 +163,8 @@ void program::rpn_expm() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief lnp1 keyword implementation
|
||||
///
|
||||
void program::rpn_lnp1() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -161,6 +179,8 @@ void program::rpn_lnp1() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sinh keyword implementation
|
||||
///
|
||||
void program::rpn_sinh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -191,6 +211,8 @@ void program::rpn_sinh() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief asinh keyword implementation
|
||||
///
|
||||
void program::rpn_asinh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -211,6 +233,8 @@ void program::rpn_asinh() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief cosh keyword implementation
|
||||
///
|
||||
void program::rpn_cosh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -241,6 +265,8 @@ void program::rpn_cosh() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief acosh keyword implementation
|
||||
///
|
||||
void program::rpn_acosh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -265,6 +291,8 @@ void program::rpn_acosh() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief tanh keyword implementation
|
||||
///
|
||||
void program::rpn_tanh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -293,6 +321,8 @@ void program::rpn_tanh() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief atanh keyword implementation
|
||||
///
|
||||
void program::rpn_atanh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//
|
||||
/// @brief find variable by its name in local heap, parens heaps, global heap
|
||||
///
|
||||
/// @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 found = false;
|
||||
program* parent = _parent_prog;
|
||||
|
||||
// find variable in local heap, parens heaps, global heap
|
||||
if (_local_heap.get(variable, obj, size))
|
||||
found = true;
|
||||
else {
|
||||
|
@ -24,6 +30,8 @@ bool program::find_variable(string& variable, object*& obj, unsigned int& size)
|
|||
return found;
|
||||
}
|
||||
|
||||
/// @brief eval keyword implementation
|
||||
///
|
||||
void program::rpn_eval(void) {
|
||||
bool run_prog = false;
|
||||
string prog_text;
|
||||
|
@ -67,7 +75,8 @@ void program::rpn_eval(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// carefull, this not a command but a branch
|
||||
/// @brief -> keyword (branch) implementation
|
||||
///
|
||||
int program::rpn_inprog(branch& myobj) {
|
||||
string context("->"); // for showing errors
|
||||
int count_symbols = 0;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief + keyword implementation
|
||||
///
|
||||
void program::rpn_plus() {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -51,6 +53,8 @@ void program::rpn_plus() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief - keyword implementation
|
||||
///
|
||||
void program::rpn_minus() {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -83,6 +87,8 @@ void program::rpn_minus() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief * keyword implementation
|
||||
///
|
||||
void program::rpn_mul() {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -133,6 +139,9 @@ void program::rpn_mul() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief divide the 2 complexes on stack
|
||||
/// result on the prog stack
|
||||
///
|
||||
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
|
||||
|
@ -177,6 +186,8 @@ void program::do_divide_complexes() {
|
|||
_calc_stack.pop_back(4);
|
||||
}
|
||||
|
||||
/// @brief / keyword implementation
|
||||
///
|
||||
void program::rpn_div() {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -224,6 +235,8 @@ void program::rpn_div() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief neg keyword implementation
|
||||
///
|
||||
void program::rpn_neg() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -238,6 +251,8 @@ void program::rpn_neg() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief inv keyword implementation
|
||||
///
|
||||
void program::rpn_inv() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -257,6 +272,8 @@ void program::rpn_inv() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief % (purcent) keyword implementation
|
||||
///
|
||||
void program::rpn_purcent() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -269,6 +286,8 @@ void program::rpn_purcent() {
|
|||
CHECK_MPFR(mpfr_div_si(left->_value.mpfr, left->_value.mpfr, 100L, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief %CH keyword implementation
|
||||
///
|
||||
void program::rpn_purcentCH() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -281,6 +300,8 @@ void program::rpn_purcentCH() {
|
|||
CHECK_MPFR(mpfr_div(left->_value.mpfr, right->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief power keyword implementation
|
||||
///
|
||||
void program::rpn_power() {
|
||||
MIN_ARGUMENTS(2);
|
||||
bool done_on_real = false;
|
||||
|
@ -338,6 +359,8 @@ void program::rpn_power() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief sqrt keyword implementation
|
||||
///
|
||||
void program::rpn_squareroot() {
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
number* left = (number*)_stack->back();
|
||||
|
@ -362,6 +385,8 @@ void program::rpn_squareroot() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sq keyword implementation
|
||||
///
|
||||
void program::rpn_square() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -375,6 +400,8 @@ void program::rpn_square() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief mod keyword implementation
|
||||
///
|
||||
void program::rpn_modulo() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -386,6 +413,8 @@ void program::rpn_modulo() {
|
|||
CHECK_MPFR(mpfr_fmod(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief abs keyword implementation
|
||||
///
|
||||
void program::rpn_abs() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -416,6 +445,8 @@ void program::rpn_abs() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief hex keyword implementation
|
||||
///
|
||||
void program::rpn_hex() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -423,18 +454,24 @@ void program::rpn_hex() {
|
|||
number::s_decimal_digits = 0;
|
||||
}
|
||||
|
||||
/// @brief bin keyword implementation
|
||||
///
|
||||
void program::rpn_bin() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
((number*)_stack->back())->_representation = number::bin;
|
||||
}
|
||||
|
||||
/// @brief dec keyword implementation
|
||||
///
|
||||
void program::rpn_dec() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
((number*)_stack->back())->_representation = number::dec;
|
||||
}
|
||||
|
||||
/// @brief base keyword implementation
|
||||
///
|
||||
void program::rpn_base() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -448,6 +485,8 @@ void program::rpn_base() {
|
|||
ERR_CONTEXT(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief fact (factorial) keyword implementation
|
||||
///
|
||||
void program::rpn_fact() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -461,6 +500,8 @@ void program::rpn_fact() {
|
|||
CHECK_MPFR(mpfr_gamma(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief sign keyword implementation
|
||||
///
|
||||
void program::rpn_sign() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -478,6 +519,8 @@ void program::rpn_sign() {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief mant keyword implementation
|
||||
///
|
||||
void program::rpn_mant() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -508,6 +551,8 @@ void program::rpn_mant() {
|
|||
ERR_CONTEXT(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief xpon keyword implementation
|
||||
///
|
||||
void program::rpn_xpon() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -546,6 +591,8 @@ void program::rpn_xpon() {
|
|||
ERR_CONTEXT(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief floor keyword implementation
|
||||
///
|
||||
void program::rpn_floor() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -555,6 +602,8 @@ void program::rpn_floor() {
|
|||
CHECK_MPFR(mpfr_floor(left->_value.mpfr, left->_value.mpfr));
|
||||
}
|
||||
|
||||
/// @brief ceil keyword implementation
|
||||
///
|
||||
void program::rpn_ceil() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -564,6 +613,8 @@ void program::rpn_ceil() {
|
|||
CHECK_MPFR(mpfr_ceil(left->_value.mpfr, left->_value.mpfr));
|
||||
}
|
||||
|
||||
/// @brief fp keyword implementation
|
||||
///
|
||||
void program::rpn_fp() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -573,6 +624,8 @@ void program::rpn_fp() {
|
|||
CHECK_MPFR(mpfr_frac(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief ip keyword implementation
|
||||
///
|
||||
void program::rpn_ip() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -582,6 +635,8 @@ void program::rpn_ip() {
|
|||
CHECK_MPFR(mpfr_trunc(left->_value.mpfr, left->_value.mpfr));
|
||||
}
|
||||
|
||||
/// @brief min keyword implementation
|
||||
///
|
||||
void program::rpn_min() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -593,6 +648,8 @@ void program::rpn_min() {
|
|||
CHECK_MPFR(mpfr_min(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief max keyword implementation
|
||||
///
|
||||
void program::rpn_max() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//
|
||||
/// @brief swap keyword implementation
|
||||
///
|
||||
void program::rpn_swap(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
@ -10,16 +11,23 @@ void program::rpn_swap(void) {
|
|||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
_calc_stack.pop_back(2);
|
||||
}
|
||||
|
||||
/// @brief drop keyword implementation
|
||||
///
|
||||
void program::rpn_drop(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
(void)_stack->pop_back();
|
||||
}
|
||||
|
||||
/// @brief drop2 keyword implementation
|
||||
///
|
||||
void program::rpn_drop2(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
(void)_stack->pop_back(2);
|
||||
}
|
||||
|
||||
/// @brief dropn keyword implementation
|
||||
///
|
||||
void program::rpn_dropn(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -30,19 +38,27 @@ void program::rpn_dropn(void) {
|
|||
(void)_stack->pop_back(args + 1);
|
||||
}
|
||||
|
||||
/// @brief erase / del keyword implementation
|
||||
///
|
||||
void program::rpn_erase(void) { (void)_stack->pop_back(_stack->size()); }
|
||||
|
||||
/// @brief dup keyword implementation
|
||||
///
|
||||
void program::rpn_dup(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
stack::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);
|
||||
}
|
||||
|
||||
/// @brief dupn keyword implementation
|
||||
///
|
||||
void program::rpn_dupn(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -54,6 +70,8 @@ void program::rpn_dupn(void) {
|
|||
for (int i = 0; i < args; i++) stack::copy_and_push_back(*_stack, _stack->size() - args, *_stack);
|
||||
}
|
||||
|
||||
/// @brief pick keyword implementation
|
||||
///
|
||||
void program::rpn_pick(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -69,6 +87,8 @@ void program::rpn_pick(void) {
|
|||
stack::copy_and_push_back(*_stack, _stack->size() - to_pick, *_stack);
|
||||
}
|
||||
|
||||
/// @brief rot keyword implementation
|
||||
///
|
||||
void program::rpn_rot(void) {
|
||||
MIN_ARGUMENTS(3);
|
||||
|
||||
|
@ -82,12 +102,16 @@ void program::rpn_rot(void) {
|
|||
_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);
|
||||
}
|
||||
|
||||
/// @brief roll keyword implementation
|
||||
///
|
||||
void program::rpn_roll(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -107,6 +131,8 @@ void program::rpn_roll(void) {
|
|||
_calc_stack.pop_back(args);
|
||||
}
|
||||
|
||||
/// @brief rolld keyword implementation
|
||||
///
|
||||
void program::rpn_rolld(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -127,6 +153,8 @@ void program::rpn_rolld(void) {
|
|||
_calc_stack.pop_back(args);
|
||||
}
|
||||
|
||||
/// @brief over keyword implementation
|
||||
///
|
||||
void program::rpn_over(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//
|
||||
/// @brief sto keyword implementation
|
||||
///
|
||||
void program::rpn_sto(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
|
@ -10,7 +11,8 @@ void program::rpn_sto(void) {
|
|||
(void)_stack->pop_back();
|
||||
}
|
||||
|
||||
//
|
||||
/// @brief sto+ keyword implementation
|
||||
///
|
||||
void program::rpn_stoadd(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -41,6 +43,8 @@ void program::rpn_stoadd(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sto- keyword implementation
|
||||
///
|
||||
void program::rpn_stosub(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -71,6 +75,8 @@ void program::rpn_stosub(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sto* keyword implementation
|
||||
///
|
||||
void program::rpn_stomul(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -101,6 +107,8 @@ void program::rpn_stomul(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sto/ keyword implementation
|
||||
///
|
||||
void program::rpn_stodiv(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -131,6 +139,8 @@ void program::rpn_stodiv(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief stosneg keyword implementation
|
||||
///
|
||||
void program::rpn_stoneg(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -147,6 +157,8 @@ void program::rpn_stoneg(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sinv keyword implementation
|
||||
///
|
||||
void program::rpn_stoinv(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -163,6 +175,8 @@ void program::rpn_stoinv(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief rcl keyword implementation
|
||||
///
|
||||
void program::rpn_rcl(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
|
@ -180,6 +194,8 @@ void program::rpn_rcl(void) {
|
|||
ERR_CONTEXT(ret_unknown_variable);
|
||||
}
|
||||
|
||||
/// @brief edit keyword implementation
|
||||
///
|
||||
void program::rpn_edit(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -206,7 +222,10 @@ void program::rpn_edit(void) {
|
|||
ERR_CONTEXT(ret_runtime_error);
|
||||
}
|
||||
|
||||
// carefull : this is not a langage command
|
||||
/// @brief recall then eval a symbol variable if it is auto-evaluable
|
||||
///
|
||||
/// @param symb the smlbol to recall and autoeval
|
||||
///
|
||||
void program::auto_rcl(symbol* symb) {
|
||||
if (symb->_auto_eval) {
|
||||
object* obj;
|
||||
|
@ -223,6 +242,8 @@ void program::auto_rcl(symbol* symb) {
|
|||
stack::copy_and_push_back(symb, *_stack, symb->size());
|
||||
}
|
||||
|
||||
/// @brief purge keyword implementation
|
||||
///
|
||||
void program::rpn_purge(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
|
@ -231,6 +252,8 @@ void program::rpn_purge(void) {
|
|||
if (!_heap->erase(name)) ERR_CONTEXT(ret_unknown_variable);
|
||||
}
|
||||
|
||||
/// @brief vars keyword implementation
|
||||
///
|
||||
void program::rpn_vars(void) {
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
|
@ -266,4 +289,6 @@ void program::rpn_vars(void) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief clusr keyword implementation
|
||||
///
|
||||
void program::rpn_clusr(void) { _heap->erase_all(); }
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief ->str keyword implementation
|
||||
///
|
||||
void program::rpn_instr() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -25,6 +27,8 @@ void program::rpn_instr() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief str-> keyword implementation
|
||||
///
|
||||
void program::rpn_strout() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
@ -39,6 +43,8 @@ void program::rpn_strout() {
|
|||
prog.run(*_stack, *_heap);
|
||||
}
|
||||
|
||||
/// @brief chr keyword implementation
|
||||
///
|
||||
void program::rpn_chr() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -55,6 +61,8 @@ void program::rpn_chr() {
|
|||
str->_value[1] = 0;
|
||||
}
|
||||
|
||||
/// @brief num keyword implementation
|
||||
///
|
||||
void program::rpn_num() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
@ -64,6 +72,8 @@ void program::rpn_num() {
|
|||
numb->_value = the_chr;
|
||||
}
|
||||
|
||||
/// @brief size keyword implementation
|
||||
///
|
||||
void program::rpn_strsize() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
@ -73,6 +83,8 @@ void program::rpn_strsize() {
|
|||
numb->_value = len;
|
||||
}
|
||||
|
||||
/// @brief pos keyword implementation
|
||||
///
|
||||
void program::rpn_strpos() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
@ -89,6 +101,8 @@ void program::rpn_strpos() {
|
|||
numb->_value = pos;
|
||||
}
|
||||
|
||||
/// @brief sub keyword implementation
|
||||
///
|
||||
void program::rpn_strsub() {
|
||||
MIN_ARGUMENTS(3);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief write stack in a string, each entry separated between commas
|
||||
///
|
||||
/// @param stack_is the output string
|
||||
/// @param stk the stack
|
||||
///
|
||||
void program::test_get_stack(string& stack_is, stack& stk) {
|
||||
// write stack in a string, each entry separated between commas
|
||||
for (int i = 0; i < (int)stk.size(); i++) {
|
||||
FILE* tmp_file = tmpfile();
|
||||
char* line = NULL;
|
||||
|
@ -24,6 +28,14 @@ void program::test_get_stack(string& stack_is, stack& stk) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief show the tests results
|
||||
///
|
||||
/// @param title test title
|
||||
/// @param tests tests nb
|
||||
/// @param tests_failed failed tests nb
|
||||
/// @param steps steps nb
|
||||
/// @param steps_failed failed steps nb
|
||||
///
|
||||
void program::test_show_result(string title, int tests, int tests_failed, int steps, int steps_failed) {
|
||||
printf("%s: run %d tests: %d passed, ", title.c_str(), tests, tests - tests_failed);
|
||||
if (tests_failed > 0) printf(FG_RED);
|
||||
|
@ -37,6 +49,8 @@ void program::test_show_result(string title, int tests, int tests_failed, int st
|
|||
printf(")\n");
|
||||
}
|
||||
|
||||
/// @brief test keyword implementation
|
||||
///
|
||||
void program::rpn_test() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
@ -52,6 +66,14 @@ void program::rpn_test() {
|
|||
test_show_result("Total", total_tests, total_tests_failed, total_steps, total_steps_failed);
|
||||
}
|
||||
|
||||
/// @brief load a test file and run its tests
|
||||
///
|
||||
/// @param test_filename the test file filename
|
||||
/// @param total_tests the total tests nb
|
||||
/// @param total_tests_failed the total failed tests nb
|
||||
/// @param total_steps the total steps nb
|
||||
/// @param total_steps_failed the total failed steps nb
|
||||
///
|
||||
void program::test(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps,
|
||||
int& total_steps_failed) {
|
||||
const string stack_size("-> stack size should be ");
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief compared 2 strings on top of the stack
|
||||
///
|
||||
/// @return 0 strings are equal
|
||||
/// @return !0 strings are not equal (see strcmp output)
|
||||
///
|
||||
int program::cmp_strings_on_stack_top() {
|
||||
// _stack sould have 2 strings at level 1 and 2
|
||||
// this function removes these 2 entries
|
||||
|
@ -8,6 +13,8 @@ int program::cmp_strings_on_stack_top() {
|
|||
return strncmp(left->_value, right->_value, min(left->_len, right->_len));
|
||||
}
|
||||
|
||||
/// @brief > keyword implementation
|
||||
///
|
||||
void program::rpn_sup(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -30,6 +37,8 @@ void program::rpn_sup(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief >= keyword implementation
|
||||
///
|
||||
void program::rpn_sup_eq(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -52,6 +61,8 @@ void program::rpn_sup_eq(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief < keyword implementation
|
||||
///
|
||||
void program::rpn_inf(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -74,6 +85,8 @@ void program::rpn_inf(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief <= keyword implementation
|
||||
///
|
||||
void program::rpn_inf_eq(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -96,6 +109,8 @@ void program::rpn_inf_eq(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief != keyword implementation
|
||||
///
|
||||
void program::rpn_diff(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -133,6 +148,8 @@ void program::rpn_diff(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief == keyword implementation
|
||||
///
|
||||
void program::rpn_eq(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
|
@ -170,6 +187,8 @@ void program::rpn_eq(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief and keyword implementation
|
||||
///
|
||||
void program::rpn_test_and(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -184,6 +203,8 @@ void program::rpn_test_and(void) {
|
|||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
}
|
||||
|
||||
/// @brief or keyword implementation
|
||||
///
|
||||
void program::rpn_test_or(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -198,6 +219,8 @@ void program::rpn_test_or(void) {
|
|||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
}
|
||||
|
||||
/// @brief xor keyword implementation
|
||||
///
|
||||
void program::rpn_test_xor(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -219,6 +242,8 @@ void program::rpn_test_xor(void) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief not keyword implementation
|
||||
///
|
||||
void program::rpn_test_not(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -230,4 +255,6 @@ void program::rpn_test_not(void) {
|
|||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
}
|
||||
|
||||
/// @brief test same implementation
|
||||
///
|
||||
void program::rpn_same(void) { rpn_eq(); }
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//
|
||||
/// @brief pi keyword implementation
|
||||
///
|
||||
void program::rpn_pi(void) {
|
||||
number* pi = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_const_pi(pi->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief d->r keyword implementation
|
||||
///
|
||||
void program::rpn_d2r(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -20,6 +23,8 @@ void program::rpn_d2r(void) {
|
|||
CHECK_MPFR(mpfr_div_si(left->mpfr, left->mpfr, 180, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief r->d keyword implementation
|
||||
///
|
||||
void program::rpn_r2d(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
@ -34,6 +39,8 @@ void program::rpn_r2d(void) {
|
|||
CHECK_MPFR(mpfr_mul_si(left->mpfr, left->mpfr, 180, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief sin keyword implementation
|
||||
///
|
||||
void program::rpn_sin(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -64,6 +71,8 @@ void program::rpn_sin(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief asin keyword implementation
|
||||
///
|
||||
void program::rpn_asin(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -101,6 +110,8 @@ void program::rpn_asin(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief cos keyword implementation
|
||||
///
|
||||
void program::rpn_cos(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -132,6 +143,8 @@ void program::rpn_cos(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief acos keyword implementation
|
||||
///
|
||||
void program::rpn_acos(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -151,6 +164,8 @@ void program::rpn_acos(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief tan keyword implementation
|
||||
///
|
||||
void program::rpn_tan(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
@ -191,6 +206,8 @@ void program::rpn_tan(void) {
|
|||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief atan keyword implementation
|
||||
///
|
||||
void program::rpn_atan(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
|
|
133
src/stack.hpp
133
src/stack.hpp
|
@ -8,7 +8,8 @@ using namespace std;
|
|||
// allocation base size
|
||||
#define ALLOC_STACK_CHUNK (64 * 1024)
|
||||
|
||||
//
|
||||
/// @brief stack object, parens of program, storing execution stack values or programs
|
||||
///
|
||||
class stack {
|
||||
public:
|
||||
stack() {
|
||||
|
@ -24,14 +25,20 @@ class stack {
|
|||
if (_base_pointer != NULL) free(_base_pointer);
|
||||
}
|
||||
|
||||
/// @brief remove all the stack elements
|
||||
///
|
||||
void erase() {
|
||||
_current = _base;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
//
|
||||
/// @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(stack& from, unsigned int index_from, stack& to) {
|
||||
// copy a whole stack entry and push it back to another stack
|
||||
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));
|
||||
|
||||
|
@ -41,9 +48,13 @@ class stack {
|
|||
((complex*)allocated)->move();
|
||||
}
|
||||
|
||||
//
|
||||
/// @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) {
|
||||
// copy a whole stack entry and push it back to another stack
|
||||
object* allocated = to.allocate_back(size, from->_type);
|
||||
memcpy(allocated, from, size);
|
||||
|
||||
|
@ -53,6 +64,14 @@ class stack {
|
|||
((complex*)allocated)->move();
|
||||
}
|
||||
|
||||
/// @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
|
||||
///
|
||||
/// @param size the object size in bytes
|
||||
/// @param type the object type
|
||||
/// @return object* the allocated object
|
||||
///
|
||||
object* allocate_back(unsigned int size, cmd_type_t type) {
|
||||
object* allocated;
|
||||
bool data_is_reallocated = false;
|
||||
|
@ -119,36 +138,77 @@ class stack {
|
|||
return back;
|
||||
}
|
||||
|
||||
/// @brief the number of objects on stack
|
||||
///
|
||||
/// @return unsigned int
|
||||
///
|
||||
unsigned int size() { return _count; }
|
||||
|
||||
// stack access (stack_level=0=first out)
|
||||
/// @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); }
|
||||
|
||||
// sequential access (index is counted from front)
|
||||
/// @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;
|
||||
|
@ -160,17 +220,25 @@ class stack {
|
|||
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
|
||||
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 {
|
||||
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;
|
||||
|
@ -195,6 +263,14 @@ class heap : public stack {
|
|||
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 ret = false;
|
||||
map<string, unsigned int>::iterator i = _map.find(name);
|
||||
|
@ -207,6 +283,14 @@ class heap : public stack {
|
|||
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);
|
||||
|
@ -224,8 +308,23 @@ class heap : public stack {
|
|||
}
|
||||
}
|
||||
|
||||
/// @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()) {
|
||||
object* local;
|
||||
|
@ -242,6 +341,12 @@ class heap : public stack {
|
|||
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;
|
||||
|
@ -256,6 +361,8 @@ class heap : public stack {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// @brief erase all variables
|
||||
///
|
||||
void erase_all(void) {
|
||||
// map
|
||||
_map.erase(_map.begin(), _map.end());
|
||||
|
@ -264,6 +371,10 @@ class heap : public stack {
|
|||
((stack*)this)->erase();
|
||||
}
|
||||
|
||||
/// @brief get the variables nb
|
||||
///
|
||||
/// @return unsigned int the variables nb
|
||||
///
|
||||
unsigned int count_vars() { return _map.size(); }
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Reference in a new issue