/* * rpn.cpp * * Copyright 2013 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * */ #include #ifdef WIN32 #include #else #define _TCHAR char #define _tmain main #endif #include #include #include #include #include #include //#include using namespace std; #include "stack.h" //TODO faut-il que ces variables soient globales ? static const char g_cursor[] = "> "; static const string g_show_stack_separator = ":\t"; static const int g_max_commands = 100; // static int g_verbose = 0; // #include "version.h" typedef enum { ret_ok, ret_unknown_err, ret_missing_operand, ret_bad_operand_type, ret_unknown_variable, ret_internal, ret_deadly, ret_good_bye, ret_not_impl, ret_nop, ret_syntax, ret_div_by_zero, ret_max } ret_value; const char* ret_value_string[ret_max] = { "ok", "unknown command", "missing operand", "bad operand type", "unknown variable", "internal error, aborting", "deadly", "goodbye", "not implemented", "no operation", "syntax", "division by zero" }; typedef enum { cmd_undef, cmd_number,/* floating value to put in stack */ cmd_binary,/* binary (integer) value to put in stack */ cmd_symbol,/* symbol value to put in stack */ cmd_keyword,/* langage keyword */ cmd_branch,/* langage branch keyword */ cmd_max } cmd_type_t; const char* cmd_type_string[cmd_max] = { "undef", "number", "binary", "symbol", "keyword", "keyword" }; // typedef long double floating_t; typedef long long integer_t; class program; class object; class branch; typedef void (program::*program_fn_t)(void); typedef union { program_fn_t _fn; } operand; typedef int (program::*branch_fn_t)(branch&); // class object { public: cmd_type_t _type;// object type object(cmd_type_t type = cmd_undef):_type(type) { } virtual void show(ostream& stream = cout) { } }; class number : public object { public: number(floating_t value) : object(cmd_number) { _value = value; } virtual void show(ostream& stream = cout) { stream << _value; } floating_t _value; // representation mode typedef enum { std, fix, sci } mode_enum; static mode_enum s_default_mode; static mode_enum s_mode; // precision static int s_default_precision; static int s_current_precision; }; number::mode_enum number::s_default_mode = number::std; number::mode_enum number::s_mode = number::s_default_mode; int number::s_default_precision = 20; int number::s_current_precision = number::s_default_precision; class binary : public object { public: binary(integer_t value) : object(cmd_binary) { _value = value; } virtual void show(ostream& stream = cout) { cout << "# "; switch(s_mode) { case dec: cout<=0; i--) { if (_value & (1 << i)) mybin+='1'; else mybin+='0'; } cout<= 2) { cout << "(" << i << ") "; ((object*)seq_obj(i))->show(); cout << endl; } // not a command, but a stack entry, manage it if ((type == cmd_number) || (type == cmd_binary)) { stk.push_back(seq_obj(i), seq_len(i), type); i++; } // could be an auto-evaluated symbol else 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 tmp = (this->*(b->_fn))(*b); if (tmp == -1) i++; else i = tmp; } } return ret; } ret_value preprocess(void) { // for if-then-else-end vector vlayout; int layout_index=-1;// TODO remplaçable par vlayout.size()-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(k->_name->compare("end") == 0) { 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' ((branch*)seq_obj(vlayout[layout_index].index_then))->arg2 = i; layout_index--; } } else if (type == cmd_branch) { branch* k = (branch*)seq_obj(i); if (k->_name->compare("if") == 0) { if_layout_t layout; layout.index_if = i; vlayout.push_back(layout); layout_index++; } else if(k->_name->compare("then") == 0) { 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(k->_name->compare("else") == 0) { 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(k->_name->compare("start") == 0) { vstartindex.push_back(i); } else if(k->_name->compare("for") == 0) { vstartindex.push_back(i); k->arg1 = i + 1;// arg1 points on symbol variable } else if(k->_name->compare("next") == 0) { 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];// fill 'next' branch1 = 'start' index vstartindex.pop_back(); } else if(k->_name->compare("step") == 0) { 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 vstartindex.pop_back(); } } } 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; } static ret_value show_error(ret_value err, string& context) { cerr<0) && (fn_name == _keywords[i].name)) { fn = _keywords[i].fn; type = _keywords[i].type; return ret_ok; } } return ret_unknown_err; } ret_value get_err(void) { return _err; } // interactive entry and decoding static ret_value entry(program& prog) { ret_value ret; string entry; // show cursor cout<show(); cout<=0; i--) { if (show_sep) cout<show(); cout<back())->_value; _stack->pop_back(); return a; } void putf(floating_t value) { /* warning, caller must check object type before */ number num(value); _stack->push_back(&num, sizeof(number), cmd_number); } integer_t getb() { /* warning, caller must check object type before */ integer_t a = ((binary*)_stack->back())->_value; _stack->pop_back(); return a; } void putb(integer_t value) { /* warning, caller must check object type before */ binary num(value); _stack->push_back(&num, sizeof(binary), cmd_binary); } string getn() { /* warning, caller must check object type before */ string* a = ((symbol*)_stack->back())->_name; _stack->pop_back(); return *a; } void putn(string& a) { /* warning, caller must check object type before */ symbol sym(a); _stack->push_back(&sym, sizeof(symbol), cmd_symbol); } int stack_size() { return _stack->size(); } private: // 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)) // keywords implementation #include "rpn-general.h" #include "rpn-algebra.h" #include "rpn-binary.h" #include "rpn-test.h" #include "rpn-stack.h" #include "rpn-branch.h" #include "rpn-store.h" #include "rpn-trig.h" #include "rpn-logs.h" }; //keywords declaration #include "rpn-cmd.h" #include "rpn-test-core.h" // static void apply_default(void) { //default precision cout << setprecision(number::s_default_precision); number::s_mode = number::s_default_mode; //default binary mode binary::s_mode = binary::s_default_mode; } // int _tmain(int argc, _TCHAR* argv[]) { heap hp; stack st; int ret = 0; // apply default configuration 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(st, hp) == ret_good_bye) break; else program::show_stack(st); } } } // run with cmd line arguments else { program prog; string entry; int i; // make one string from entry for (i=1; i