mirror of
https://github.com/louisrubet/rpn
synced 2025-01-29 20:34:21 +01:00
#72: added by refactoring
This commit is contained in:
parent
a11767a745
commit
4f0d9c0d27
5 changed files with 1028 additions and 0 deletions
63
src/main.cpp
Normal file
63
src/main.cpp
Normal 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
55
src/object.cpp
Normal 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
290
src/object.hpp
Normal 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
141
src/program.cpp
Normal 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
479
src/program.hpp
Normal 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
|
Loading…
Add table
Reference in a new issue