diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..00aae22 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,63 @@ +#include "program.hpp" + +static heap s_global_heap; +static stack s_global_stack; + +// +int main(int argc, char* argv[]) +{ + int ret = 0; + + // apply default configuration + program::apply_default(); + + // run with interactive prompt + if (argc == 1) + { + // + for (;;) + { + // make program from interactive entry + program prog; + if (program::entry(prog) == ret_good_bye) + break; + else + { + // run it + if (prog.run(s_global_stack, s_global_heap) == ret_good_bye) + break; + else + program::show_stack(s_global_stack); + } + } + } + // run with cmd line arguments + else + { + program prog; + string entry; + int i; + + // make one string from entry + for (i=1; i +using namespace std; + +#include "constant.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; + +// number statics +number::mode_enum number::s_mode = DEFAULT_MODE; +int number::s_current_precision = DEFAULT_PRECISION; +string number::s_mpfr_printf_format = string(MPFR_DEFAULT_FORMAT); + +// +const char* object::s_cmd_type_string[cmd_max] = CMD_TYPE_STRINGS; + +void object::show(FILE* stream) +{ + switch(_type) + { + case cmd_number: + switch(((number*)this)->_representation) + { + case number::dec: + mpfr_fprintf(stream, number::s_mpfr_printf_format.c_str(), ((number*)this)->_value.mpfr); + break; + case number::hex: + mpfr_fprintf(stream, string(MPFR_FORMAT_HEX).c_str(), ((number*)this)->_value.mpfr); + break; + case number::bin: + fprintf(stream, "\n"); + } + break; + case cmd_string: + fprintf(stream, "\"%s\"", ((ostring*)this)->_value); + break; + case cmd_program: + fprintf(stream, "<<%s>>", ((oprogram*)this)->_value); + break; + case cmd_symbol: + fprintf(stream, "'%s'", ((symbol*)this)->_value); + break; + case cmd_keyword: + case cmd_branch: + fprintf(stream, "%s", ((keyword*)this)->_value); + break; + default: + fprintf(stream, "< unknown object representation >"); + break; + } +} diff --git a/src/object.hpp b/src/object.hpp new file mode 100644 index 0000000..425c3af --- /dev/null +++ b/src/object.hpp @@ -0,0 +1,290 @@ +#ifndef OBJECT_HPP +#define OBJECT_HPP + +#include +#include + +// definitions for objects +//// +typedef enum { + cmd_undef, + cmd_number,/* floating value to put in stack */ + cmd_string,/* string value to put in stack */ + cmd_symbol,/* symbol value to put in stack */ + cmd_program,/* program */ + cmd_keyword,/* langage keyword */ + cmd_branch,/* langage branch keyword */ + cmd_max +} cmd_type_t; + +class program; +class branch; + +typedef void (program::*program_fn_t)(void); +typedef int (program::*branch_fn_t)(branch&); + +// MPFR object +//// +struct floating_t +{ + mpfr_t mpfr; + + void init(void* significand) + { + mpfr_custom_init(significand, MPFR_DEFAULT_PREC_BITS); + mpfr_custom_init_set(mpfr, MPFR_ZERO_KIND, 0, s_mpfr_prec, significand); + } + + void set_significand(void* significand) + { + mpfr->_mpfr_d = (mp_limb_t*)significand; + } + + floating_t& operator=(const long int val) + { + mpfr_set_si(mpfr, val, s_mpfr_rnd); + } + + floating_t& operator=(const unsigned long val) + { + mpfr_set_ui(mpfr, val, s_mpfr_rnd); + } + + operator int() + { + return (int)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]; +}; + +// object - a generic stack object +//// +struct object +{ + // object type + cmd_type_t _type; + unsigned int _size; + + // + unsigned int size() { return _size; } + + void show(FILE* stream = stdout); + + // + static const char* s_cmd_type_string[cmd_max]; +}; + +// stack objects derived from object +//// +struct number : public object +{ + number() { _type = cmd_number; } + floating_t _value; + + void init(void* significand) + { + _type = cmd_number; + _representation = dec; + _value.init(significand); + } + + void copy(number& op) + { + _value = op._value; + memcpy(_value.mpfr->_mpfr_d, op._value.mpfr->_mpfr_d, floating_t::s_mpfr_prec_bytes); + } + + // + void set(const floating_t& value) + { + _type = cmd_number; + _value.mpfr->_mpfr_d = value.mpfr->_mpfr_d; + } + + void set(long value) + { + _type = cmd_number; + _value = value; + } + + 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); + } + + // + number operator=(const number& op) + { + number num; + num.set((const floating_t&)op._value); + return num; + } + + // representation mode + typedef enum { + std, + fix, + sci + } mode_enum; + static mode_enum s_mode; + + enum { + dec, + hex, + bin + } _representation; + + // precision + static int s_current_precision; + static string s_mpfr_printf_format; +}; + +struct ostring : public object +{ + // + 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 + len = 0; + } + + // + unsigned int _len; + char _value[0]; +}; + +struct oprogram : public object +{ + // + 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 + len = 0; + } + + // + unsigned int _len; + char _value[0]; +}; + +struct symbol : public object +{ + // + void set(const char* value, unsigned int len, bool auto_eval) + { + _type = cmd_symbol; + _auto_eval = auto_eval; + + if (value != NULL) + { + if (len>0) + (void)memcpy(_value, value, len); + _value[len] = 0; + _len = len; + } + else + len = 0; + } + + // + bool _auto_eval; + unsigned int _len; + char _value[0]; +}; + +struct keyword : public object +{ + // + void set(program_fn_t fn, const char* value, unsigned int len) + { + _type = cmd_keyword; + _fn = fn; + if (value != NULL) + { + if (len>0) + (void)memcpy(_value, value, len); + _value[len] = 0; + _len = len; + } + else + len = 0; + } + + // + program_fn_t _fn; + unsigned int _len; + char _value[0]; +}; + +struct branch : public object +{ + // + void set(branch_fn_t fn, const char* value, unsigned int len) + { + _type = cmd_branch; + _fn = fn; + arg1 = -1; + arg2 = -1; + arg3 = -1; + farg1 = NULL; + farg2 = NULL; + arg_bool = 0; + if (value != NULL) + { + if (len>0) + (void)memcpy(_value, value, len); + _value[len] = 0; + _len = len; + } + else + len = 0; + } + + // branch function + branch_fn_t _fn; + // args used by cmd_branch cmds + int arg1, arg2, arg3; + number *farg1, *farg2; + bool arg_bool; + unsigned int _len; + char _value[0]; +}; + +#endif diff --git a/src/program.cpp b/src/program.cpp new file mode 100644 index 0000000..cdad770 --- /dev/null +++ b/src/program.cpp @@ -0,0 +1,141 @@ +#include "program.hpp" + +// +const char* program::s_ret_value_string[ret_max] = RET_VALUE_STRINGS; + +// +program::keyword_t program::s_keywords[] = +{ + //GENERAL + { cmd_undef, "", NULL, "\nGENERAL"}, + { cmd_keyword, "nop", &program::nop, "no operation"}, + { cmd_keyword, "?", &program::help, "" }, + { cmd_keyword, "h", &program::help, "" }, + { cmd_keyword, "help", &program::help, "(or h or ?) this help message" }, + { cmd_keyword, "q", &program::good_bye, "" }, + { cmd_keyword, "quit", &program::good_bye, "(or q or exit) quit software" }, + { cmd_keyword, "exit", &program::good_bye, "" }, + { cmd_keyword, "test", &program::test, "" }, //not seen by user + { cmd_keyword, "version", &program::rpn_version, "show rpn version" }, + { cmd_keyword, "uname", &program::rpn_uname, "show rpn complete identification string" }, + { cmd_keyword, "type", &program::type, "show type of stack first entry" }, + { cmd_keyword, "default", &program::rpn_default, "set float representation and precision to default" }, + { cmd_keyword, "prec", &program::precision, "get float precision in bits when first stack is not a number\n\t" + "set float precision in bits when first stack entry is a number. ex: 256 prec\n\t" }, + { cmd_keyword, "round", &program::round, "set float rounding mode.\n\tex: [\"nearest\", \"toward zero\", \"toward +inf\", \"toward -inf\", \"away from zero\"] round" }, + + //REAL + { cmd_undef, "", NULL, "\nREAL"}, + { cmd_keyword, "+", &program::plus, "addition" }, + { cmd_keyword, "-", &program::minus, "substraction" }, + { cmd_keyword, "neg", &program::neg , "negation" }, + { cmd_keyword, "*", &program::mul, "multiplication" }, + { cmd_keyword, "/", &program::div, "division" }, + { cmd_keyword, "inv", &program::inv, "inverse" }, + { cmd_keyword, "%", &program::purcent, "purcent" }, + { cmd_keyword, "%CH", &program::purcentCH, "inverse purcent" }, + { cmd_keyword, "^", &program::power, "(or pow) power" }, + { cmd_keyword, "pow", &program::power, "" }, + { cmd_keyword, "sqrt", &program::squareroot, "square root" }, + { cmd_keyword, "sq", &program::square, "(or sqr) square" }, + { cmd_keyword, "sqr", &program::square, "" }, + { cmd_keyword, "mod", &program::modulo, "modulo" }, + { cmd_keyword, "abs", &program::rpn_abs, "absolute value" }, + + //REAL representation + { cmd_undef, "", NULL, "\nREAL REPRESENTATION"}, + { cmd_keyword, "dec", &program::dec, "decimal representation" }, + { cmd_keyword, "hex", &program::hex, "hexadecimal representation" }, + { cmd_keyword, "bin", &program::bin, "binary representation" }, + { cmd_keyword, "std", &program::std, "standard floating numbers representation. ex: [25] std" }, + { cmd_keyword, "fix", &program::fix, "fixed point representation. ex: 6 fix" }, + { cmd_keyword, "sci", &program::sci, "scientific floating point representation. ex: 20 sci" }, + + //TEST + { cmd_undef, "", NULL, "\nTEST"}, + { cmd_keyword, ">", &program::sup, "binary operator >" }, + { cmd_keyword, ">=", &program::sup_eq, "binary operator >=" }, + { cmd_keyword, "<", &program::inf, "binary operator <" }, + { cmd_keyword, "<=", &program::inf_eq, "binary operator <=" }, + { cmd_keyword, "!=", &program::diff, "binary operator != (different)" }, + { cmd_keyword, "==", &program::eq , "binary operator == (equal)" }, + { cmd_keyword, "and", &program::test_and , "boolean operator and" }, + { cmd_keyword, "or", &program::test_or , "boolean operator or" }, + { cmd_keyword, "xor", &program::test_xor , "boolean operator xor" }, + { cmd_keyword, "not", &program::test_not , "boolean operator not" }, + { cmd_keyword, "same", &program::same , "boolean operator same (equal)" }, + + //STACK + { cmd_undef, "", NULL, "\nSTACK"}, + { cmd_keyword, "swap", &program::swap, "swap 2 first stack entries" }, + { cmd_keyword, "drop", &program::drop, "drop first stack entry" }, + { cmd_keyword, "drop2", &program::drop2, "drop 2 first stack entries" }, + { cmd_keyword, "erase", &program::erase, "drop all stack entries" }, + { cmd_keyword, "rot", &program::rot, "rotate 3 first stack entries" }, + { cmd_keyword, "dup", &program::dup, "duplicate first stack entry" }, + { cmd_keyword, "dup2", &program::dup2, "duplicate 2 first stack entries" }, + { cmd_keyword, "pick", &program::pick, "push a copy of the given stack level onto the stack" }, + { cmd_keyword, "depth", &program::depth, "give stack depth" }, + + //STRING + { cmd_undef, "", NULL, "\nSTRING"}, + { cmd_keyword, "->str", &program::instr, "convert an object into a string" }, + { cmd_keyword, "str->", &program::strout, "convert a string into an object" }, + + //BRANCH + { cmd_undef, "", NULL, "\nBRANCH"}, + { cmd_branch, "if", (program_fn_t)&program::rpn_if, "" }, + { cmd_branch, "then", (program_fn_t)&program::rpn_then, "" }, + { cmd_branch, "else", (program_fn_t)&program::rpn_else, "" }, + { cmd_keyword, "end", &program::rpn_end, "(end of if structure)" }, + { cmd_branch, "start", (program_fn_t)&program::rpn_start, "repeat instructions several times" }, + { cmd_branch, "for", (program_fn_t)&program::rpn_for, "repeat instructions several times with variable" }, + { cmd_branch, "next", (program_fn_t)&program::rpn_next, "ex: 1 10 start next" }, + { cmd_branch, "step", (program_fn_t)&program::rpn_step, "ex: 1 100 start 4 step" }, + + //STORE + { cmd_undef, "", NULL, "\nSTORE"}, + { cmd_keyword, "sto", &program::sto, "store a variable. ex: 1 'name' sto" }, + { cmd_keyword, "rcl", &program::rcl, "recall a variable. ex: 'name' rcl" }, + { cmd_keyword, "purge", &program::purge, "delete a variable. ex: 'name' purge" }, + { cmd_keyword, "vars", &program::vars, "list all variables" }, + { cmd_keyword, "edit", &program::edit, "edit a variable content" }, + + //PROGRAM + { cmd_undef, "", NULL, "\nPROGRAM"}, + { cmd_keyword, "eval", &program::eval, "evaluate (run) a program, or recall a variable. ex: 'my_prog' eval" }, + { cmd_branch, "->", (program_fn_t)&program::inprog, "load program local variables. ex: << -> n m << 0 n m for i i + next >> >>" }, + + //TRIG + { cmd_undef, "", NULL, "\nTRIG"}, + { cmd_keyword, "pi", &program::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::d2r, "convert degrees to radians" }, + { cmd_keyword, "r->d", &program::r2d, "convert radians to degrees" }, + + //LOGS + { cmd_undef, "", NULL, "\nLOGS"}, + { cmd_keyword, "e", &program::rpn_e, "exp(1) constant" }, + { cmd_keyword, "log", &program::rpn_log, "logarithm base 10" }, + { cmd_keyword, "alog", &program::rpn_alog, "(or exp10) exponential base 10" }, + { cmd_keyword, "exp10", &program::rpn_alog, "" }, + { cmd_keyword, "log2", &program::rpn_log2, "logarithm base 2" }, + { cmd_keyword, "alog2", &program::rpn_alog2, "(or exp2) exponential base 2" }, + { cmd_keyword, "exp2", &program::rpn_alog2, "" }, + { cmd_keyword, "ln", &program::rpn_ln, "logarithm base e" }, + { cmd_keyword, "exp", &program::rpn_exp, "exponential" }, + { 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" }, + + // end + { cmd_max, "", NULL, "" }, +}; diff --git a/src/program.hpp b/src/program.hpp new file mode 100644 index 0000000..2300323 --- /dev/null +++ b/src/program.hpp @@ -0,0 +1,479 @@ +#ifndef PROGRAM_HPP +#define PROGRAM_HPP + +#include +#include +#include +#include + +extern "C" { +#include +#include +} + +#include +#include +#include +#include +#include +using namespace std; + +#include "constant.h" +#include "escape.h" +#include "version.h" +#include "debug.h" +#include "object.hpp" +#include "stack.hpp" + +// +struct if_layout_t +{ + if_layout_t():index_then(-1),index_else(-1),index_end(-1) { } + int index_if; + int index_then; + int index_else; + int index_end; +}; + +// program +class program : public stack +{ +public: + program(program* parent_prog = NULL) { _parent_prog = parent_prog; } + + // run this program + ret_value run(stack& stk, heap& hp, heap* parent_local_hp = NULL) + { + bool go_out = false; + ret_value ret = ret_ok; + cmd_type_t type; + + // stack comes from outside + _stack = &stk; + + // global heap comes from outside + _heap = &hp; + + _err = ret_ok; + _err_context = ""; + + // branches for 'if' + ret = preprocess(); + if (ret != ret_ok) + return ret; + + // iterate commands + for(int i = 0; (go_out==false) && (i<(int)size());) + { + type = (cmd_type_t)seq_type(i); + + // could be an auto-evaluated symbol + if (type == cmd_symbol) + { + auto_rcl((symbol*)seq_obj(i)); + i++; + } + + // a keyword + else if (type == cmd_keyword) + { + keyword* k = (keyword*)seq_obj(i); + // call matching function + (this->*(k->_fn))(); + switch(_err) + { + // no pb -> go on + case ret_ok: + break; + // explicit go out software + case ret_good_bye: + go_out = true; + ret = ret_good_bye; + break; + default: + // error: abort prog + go_out = true; + + // error: show it + if (show_error(_err, _err_context) == ret_deadly) + { + // pb showing error -> go out software + ret = ret_good_bye; + } + break; + } + i++; + } + + // a branch keyword + else if (type == cmd_branch) + { + // call matching function + branch* b = (branch*)seq_obj(i); + int next_cmd = (this->*(b->_fn))(*b); + switch (next_cmd) + { + case -1: + i++; // meaning 'next command' + break; + case -(int)ret_runtime_error: + // error: show it + (void)show_error(_err, _err_context); + go_out = true;// end of run + break; + default: + i = next_cmd;// new direction + break; + } + } + + // 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); + i++; + } + } + + return ret; + } + + bool 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; + } + + bool compare_branch(branch* b, const char* str_to_compare, int len) + { + if (b->_len >= len) + return strncmp(b->_value, str_to_compare, len) == 0; + else + return false; + } + + ret_value preprocess(void) + { + // for if-then-else-end + vector vlayout; + int layout_index=-1; + // for start-end-step + vector vstartindex; + + // 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_keyword) + { + keyword* k = (keyword*)seq_obj(i); + if (compare_keyword(k, "end", 3)) + { + int next = i + 1; + if (next >= (int)size()) + next = -1; + + if (layout_index<0) + { + // error: show it + show_syntax_error("missing if before end"); + return ret_syntax; + } + if (vlayout[layout_index].index_end != -1) + { + // error: show it + show_syntax_error("duplicate end"); + return ret_syntax; + } + if (vlayout[layout_index].index_else != -1) + //fill 'end' branch of 'else' + ((branch*)seq_obj(vlayout[layout_index].index_else))->arg2 = i; + else + { + //fill 'end' branch of 'then' + if (vlayout[layout_index].index_then != -1) + ((branch*)seq_obj(vlayout[layout_index].index_then))->arg2 = i; + else + { + // error: show it + show_syntax_error("missing then before end"); + return ret_syntax; + } + } + layout_index--; + } + } + else if (type == cmd_branch) + { + branch* k = (branch*)seq_obj(i); + if (compare_branch(k, "if", 2)) + { + if_layout_t layout; + layout.index_if = i; + vlayout.push_back(layout); + layout_index++; + } + else if (compare_branch(k, "then", 4)) + { + int next = i + 1; + if (next >= (int)size()) + next = -1; + + // nothing after 'then' -> error + if (next == -1) + { + // error: show it + show_syntax_error("missing end after then"); + return ret_syntax; + } + if (layout_index<0) + { + // error: show it + show_syntax_error("missing if before then"); + return ret_syntax; + } + if (vlayout[layout_index].index_then != -1) + { + // error: show it + show_syntax_error("duplicate then"); + return ret_syntax; + } + vlayout[layout_index].index_then = i; + k->arg1 = next; + k->arg3 = vlayout[layout_index].index_if; + } + else if (compare_branch(k, "else", 4)) + { + int next = i + 1; + if (next >= (int)size()) + next = -1; + + // nothing after 'else' -> error + if (next == -1) + { + // error: show it + show_syntax_error("missing end after else"); + return ret_syntax; + } + if (layout_index<0) + { + // error: show it + show_syntax_error("missing if before else"); + return ret_syntax; + } + if (vlayout[layout_index].index_then == -1) + { + // error: show it + show_syntax_error("missing then before else"); + return ret_syntax; + } + if (vlayout[layout_index].index_else != -1) + { + // error: show it + show_syntax_error("duplicate else"); + return ret_syntax; + } + vlayout[layout_index].index_else = i; + k->arg1 = next;// fill branch1 (if was false) of 'else' + k->arg3 = vlayout[layout_index].index_if; + ((branch*)seq_obj(vlayout[layout_index].index_then))->arg2 = next;// fill branch2 (if was false) of 'then' + } + else if (compare_branch(k, "start", 5)) + { + vstartindex.push_back(i); + } + else if (compare_branch(k, "for", 3)) + { + vstartindex.push_back(i); + k->arg1 = i + 1;// arg1 points on symbol variable + } + else if(compare_branch(k, "next", 4)) + { + if (vstartindex.size() == 0) + { + // error: show it + show_syntax_error("missing start or for before next"); + return ret_syntax; + } + k->arg1 = vstartindex[vstartindex.size() - 1]; // 'next' arg1 = 'start' index + ((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 = i; // 'for' or 'start' arg2 = 'next' index + vstartindex.pop_back(); + } + else if (compare_branch(k, "step", 4)) + { + if (vstartindex.size() == 0) + { + // error: show it + show_syntax_error("missing start or for before step"); + return ret_syntax; + } + k->arg1 = vstartindex[vstartindex.size() - 1];// fill 'step' branch1 = 'start' index + ((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 = i; // 'for' or 'start' arg2 = 'next' index + vstartindex.pop_back(); + } + else if (compare_branch(k, "->", 2)) + { + k->arg1 = i;// arg1 is '->' command index in program + } + } + } + if (layout_index >= 0) + { + // error: show it + show_syntax_error("missing end"); + return ret_syntax; + } + if (vstartindex.size() > 0) + { + // error: show it + show_syntax_error("missing next or step after for or start"); + return ret_syntax; + } + return ret_ok; + } + + ret_value show_error() + { + ret_value ret; + + // show last recorded error + cerr<show(); + printf("\n"); + } + else + { + bool show_sep = (! separator.empty()); + for (int i = st.size()-1; i>=0; i--) + { + if (show_sep) + printf("%d%s", i+1, separator.c_str()); + ((object*)st[i])->show(); + printf("\n"); + } + } + } + + static void apply_default() + { + //default float precision, float mode, verbosity + number::s_mode = DEFAULT_MODE; + number::s_current_precision = DEFAULT_PRECISION; + + // format for mpfr_printf + stringstream ss; + ss << number::s_current_precision; + number::s_mpfr_printf_format = string(MPFR_FORMAT_BEG) + ss.str() + string(MPFR_FORMAT_STD); + } + +private: + // current error and its context + ret_value _err; + string _err_context; + + // global stack holding results for user + stack* _stack; + + // global heap (sto, rcl) + heap* _heap; + + // local heap for local loop vairables (for..next) + heap _local_heap; + + // local stack internally used by branch commands (start, for, next, ..) + stack _branch_stack; + + // parent prog for inheriting heaps + program* _parent_prog; + + int stack_size() + { + return _stack->size(); + } + +private: + static const char* s_ret_value_string[ret_max]; + + // carefull : some of these macros modify program flow + #define ERR_CONTEXT(err) do { _err = (err); _err_context = __FUNCTION__; } while(0) + #define MIN_ARGUMENTS(num) do { if (stack_size()<(num)) { ERR_CONTEXT(ret_missing_operand); return; } } while(0) + #define MIN_ARGUMENTS_RET(num, ret) do { if (stack_size()<(num)) { ERR_CONTEXT(ret_missing_operand); return (ret); } } while(0) + #define ARG_MUST_BE_OF_TYPE(num, type) do { if (_stack->get_type(num) != (type)) { ERR_CONTEXT(ret_bad_operand_type); return; } } while(0) + #define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) do { if (_stack->get_type(num) != (type)) { ERR_CONTEXT(ret_bad_operand_type); return (ret); } } while(0) + #define IS_ARG_TYPE(num, type) (_stack->get_type(num) == (type)) + #define CHECK_MPFR(op) do { (void)(op); } while(0) + + // keywords + struct keyword_t + { + cmd_type_t type; + char name[24]; + program_fn_t fn; + string comment; + }; + static keyword_t s_keywords[]; + + // keywords implementation + #include "rpn-general.hpp" + #include "rpn-real.hpp" + #include "rpn-test.hpp" + #include "rpn-stack.hpp" + #include "rpn-string.hpp" + #include "rpn-branch.hpp" + #include "rpn-store.hpp" + #include "rpn-program.hpp" + #include "rpn-trig.hpp" + #include "rpn-logs.hpp" + #include "rpn-test-core.hpp" + + // parser + #include "parse.hpp" +}; + +#endif