#72: added by refactoring

This commit is contained in:
Louis Rubet 2017-05-25 19:00:44 +02:00
parent a11767a745
commit 4f0d9c0d27
5 changed files with 1028 additions and 0 deletions

63
src/main.cpp Normal file
View file

@ -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<argc; i++)
{
entry += argv[i];
entry += ' ';
}
// make program
ret = program::parse(entry.c_str(), prog);
if (ret == ret_ok)
{
string separator = "";
// run it
ret = prog.run(s_global_stack, s_global_heap);
program::show_stack(s_global_stack, separator);
}
}
mpfr_free_cache();
return ret;
}

55
src/object.cpp Normal file
View file

@ -0,0 +1,55 @@
#include <string>
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, "<binary representation TODO>\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;
}
}

290
src/object.hpp Normal file
View file

@ -0,0 +1,290 @@
#ifndef OBJECT_HPP
#define OBJECT_HPP
#include <mpfr.h>
#include <string.h>
// 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

141
src/program.cpp Normal file
View file

@ -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, "<test-instructions>" },
{ cmd_branch, "then", (program_fn_t)&program::rpn_then, "<true-instructions>" },
{ cmd_branch, "else", (program_fn_t)&program::rpn_else, "<false-instructions>" },
{ 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 <instructions> next" },
{ cmd_branch, "step", (program_fn_t)&program::rpn_step, "ex: 1 100 start <instructions> 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, "" },
};

479
src/program.hpp Normal file
View file

@ -0,0 +1,479 @@
#ifndef PROGRAM_HPP
#define PROGRAM_HPP
#include <stdlib.h>
#include <stdint.h>
#include <mpfr.h>
#include <math.h>
extern "C" {
#include <readline/readline.h>
#include <readline/history.h>
}
#include <iostream>
#include <iomanip>
#include <vector>
#include <sstream>
#include <fstream>
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<struct if_layout_t> vlayout;
int layout_index=-1;
// for start-end-step
vector<int> 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<<s_ret_value_string[_err]<<"("<<_err<<"): "<<_err_context<<endl;
switch(_err)
{
case ret_internal:
case ret_deadly:
ret = ret_deadly;
default:
ret = ret_ok;
}
return ret;
}
ret_value show_error(ret_value err, string& context)
{
// record error
_err = err;
_err_context = context;
return show_error();
}
ret_value show_error(ret_value err, const char* context)
{
// record error
_err = err;
_err_context = context;
return show_error();
}
void show_syntax_error(const char* context)
{
// record error
_err = ret_syntax;
_err_context = context;
(void)show_error();
}
ret_value get_err(void) { return _err; }
static void show_stack(stack& st, const string& separator = g_show_stack_separator)
{
if (st.size() == 1)
{
((object*)st.back())->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