mirror of
https://github.com/louisrubet/rpn
synced 2025-02-07 08:45:48 +01:00
Harden branch checks on command flow indexes
This commit is contained in:
parent
be1f0d54ac
commit
e034a7834c
6 changed files with 155 additions and 111 deletions
2
TODO.md
2
TODO.md
|
@ -3,4 +3,4 @@ TODO
|
|||
missing tests / problems
|
||||
- les arguments d'une fonction en erreur doivent ils être consommés ?
|
||||
ex embettant : sto+
|
||||
- `1 'i' sto while i <= 2 repeat 0 'j' sto while j <= 1 repeat i (1,0) * j (0,1) * + 1 'j' sto+ end 1 'i' sto+ end` plante
|
||||
- `1 'i' sto while i 2 <= repeat 0 'j' sto while 1 <= j repeat i (1,0) * j (0,1) * + 1 'j' sto+ end 1 'i' sto+ end` plante
|
||||
|
|
|
@ -31,7 +31,7 @@ class program;
|
|||
class branch;
|
||||
|
||||
typedef void (program::*program_fn_t)(void);
|
||||
typedef int (program::*branch_fn_t)(branch&);
|
||||
typedef size_t (program::*branch_fn_t)(branch&);
|
||||
|
||||
/// @brief object - a generic stack object
|
||||
///
|
||||
|
@ -174,9 +174,9 @@ struct branch : object {
|
|||
branch() : object(cmd_branch) {}
|
||||
branch(branch_fn_t fn_, const string& value_) : object(cmd_branch) {
|
||||
fn = fn_;
|
||||
arg1 = -1;
|
||||
arg2 = -1;
|
||||
arg3 = -1;
|
||||
arg1 = (size_t)-1;
|
||||
arg2 = (size_t)-1;
|
||||
arg3 = (size_t)-1;
|
||||
arg_bool = 0;
|
||||
value = value_;
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ struct branch : object {
|
|||
virtual object* clone() { return new branch(*this); }
|
||||
virtual string name() { return string("branch"); }
|
||||
branch_fn_t fn;
|
||||
int arg1, arg2, arg3;
|
||||
size_t arg1, arg2, arg3;
|
||||
mpreal firstIndex, lastIndex;
|
||||
bool arg_bool;
|
||||
string value;
|
||||
|
|
|
@ -236,8 +236,8 @@ ret_value program::run() {
|
|||
}
|
||||
|
||||
// iterate commands
|
||||
for (int i = 0; (go_out == false) && (interrupt_now == false) && (i < (int)size());) {
|
||||
object* o = (*this)[i];
|
||||
for (size_t i = 0; (go_out == false) && (interrupt_now == false) && (i < size());) {
|
||||
object* o = at(i);
|
||||
switch (o->_type) {
|
||||
// could be an auto-evaluated symbol
|
||||
case cmd_symbol:
|
||||
|
@ -281,18 +281,17 @@ ret_value program::run() {
|
|||
case cmd_branch: {
|
||||
// call matching function
|
||||
branch* b = (branch*)o;
|
||||
int next_cmd = (this->*(b->fn))(*b);
|
||||
size_t next_cmd = (this->*(b->fn))(*b);
|
||||
switch (next_cmd) {
|
||||
case -1:
|
||||
case step_out: // step out
|
||||
i++; // meaning 'next command'
|
||||
break;
|
||||
case -(int)ret_runtime_error:
|
||||
// error: show it
|
||||
case runtime_error: // runtime error
|
||||
(void)show_error(_err, _err_context);
|
||||
go_out = true; // end of run
|
||||
go_out = true;
|
||||
break;
|
||||
default:
|
||||
i = next_cmd; // new direction
|
||||
i = next_cmd;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -13,9 +13,9 @@ using namespace mpfr;
|
|||
|
||||
// internal includes
|
||||
#include "constant.h"
|
||||
#include "lexer.hpp"
|
||||
#include "object.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "lexer.hpp"
|
||||
|
||||
//< convinient structure to preprocess a program
|
||||
struct if_layout_t {
|
||||
|
@ -32,7 +32,7 @@ struct if_layout_t {
|
|||
//< program class: the class containing a string parser, all the programs keywords, a stack for running the program
|
||||
class program : public deque<object*>, public Lexer {
|
||||
public:
|
||||
program(rpnstack& stk, heap& hp, program* parent = nullptr):_stack(stk),_heap(hp),_parent(parent) {
|
||||
program(rpnstack& stk, heap& hp, program* parent = nullptr) : _stack(stk), _heap(hp), _parent(parent) {
|
||||
interrupt_now = false;
|
||||
}
|
||||
virtual ~program() {
|
||||
|
@ -99,20 +99,21 @@ class program : public deque<object*>, public Lexer {
|
|||
////
|
||||
|
||||
// branch
|
||||
int rpn_if(branch& myobj);
|
||||
int rpn_then(branch& myobj);
|
||||
int rpn_else(branch& myobj);
|
||||
int rpn_end(branch& myobj);
|
||||
int rpn_do(branch& myobj);
|
||||
int rpn_until(branch& myobj);
|
||||
size_t rpn_if(branch& myobj);
|
||||
size_t rpn_then(branch& myobj);
|
||||
size_t rpn_else(branch& myobj);
|
||||
size_t rpn_end(branch& myobj);
|
||||
size_t rpn_do(branch& myobj);
|
||||
size_t rpn_until(branch& myobj);
|
||||
void rpn_ift(void);
|
||||
void rpn_ifte(void);
|
||||
int rpn_while(branch& myobj);
|
||||
int rpn_repeat(branch& myobj);
|
||||
int rpn_start(branch& myobj);
|
||||
int rpn_for(branch& myobj);
|
||||
int rpn_next(branch& myobj);
|
||||
int rpn_step(branch& myobj);
|
||||
size_t rpn_while(branch& myobj);
|
||||
size_t rpn_repeat(branch& myobj);
|
||||
size_t rpn_start(branch& myobj);
|
||||
size_t rpn_for(branch& myobj);
|
||||
size_t rpn_next(branch& myobj);
|
||||
size_t rpn_step(branch& myobj);
|
||||
enum { step_out = (size_t)-1, runtime_error = (size_t)-2 };
|
||||
|
||||
// complex
|
||||
void rpn_re();
|
||||
|
|
|
@ -3,34 +3,42 @@
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_if(branch& myobj) {
|
||||
size_t program::rpn_if(branch& myobj) {
|
||||
// myobj.arg1 = 'if' condition evaluation value
|
||||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
MIN_ARGUMENTS_RET(1, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, runtime_error);
|
||||
|
||||
if (_stack.value<number>(0) != 0)
|
||||
myobj.arg1 = 1;
|
||||
else
|
||||
myobj.arg1 = 0;
|
||||
_stack.pop();
|
||||
return -1;
|
||||
return step_out;
|
||||
}
|
||||
|
||||
/// @brief then keyword (branch) implementation
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_then(branch& myobj) {
|
||||
size_t program::rpn_then(branch& myobj) {
|
||||
// myobj.arg1 = index of then + 1
|
||||
// myobj.arg2 = index of else + 1 or end + 1
|
||||
// myobj.arg3 = index of if
|
||||
// if condition is true -> arg1 (= jump to then + 1)
|
||||
// else -> arg2 (= jump to else + 1 or end + 1)
|
||||
branch* if_cmd = (branch*)at(myobj.arg3);
|
||||
branch* if_cmd;
|
||||
if (myobj.arg3 >= size() || at(myobj.arg3)->_type != cmd_branch) {
|
||||
setErrorContext(ret_missing_operand);
|
||||
return runtime_error;
|
||||
}
|
||||
if_cmd = (branch*)at(myobj.arg3);
|
||||
if (if_cmd->arg1 == 1)
|
||||
return myobj.arg1;
|
||||
else
|
||||
|
@ -40,16 +48,22 @@ int program::rpn_then(branch& myobj) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_else(branch& myobj) {
|
||||
size_t program::rpn_else(branch& myobj) {
|
||||
// myobj.arg1 = index of else + 1
|
||||
// myobj.arg2 = index of end + 1
|
||||
// myobj.arg3 = index of if
|
||||
// if condition was false -> arg1 (= jump to else + 1)
|
||||
// if condition was true -> arg2 (= jump to end + 1)
|
||||
branch* if_cmd = (branch*)at(myobj.arg3);
|
||||
branch* if_cmd;
|
||||
if (myobj.arg3 >= size() || at(myobj.arg3)->_type != cmd_branch) {
|
||||
setErrorContext(ret_missing_operand);
|
||||
return runtime_error;
|
||||
}
|
||||
if_cmd = (branch*)at(myobj.arg3);
|
||||
if (if_cmd->arg1 == 1)
|
||||
return myobj.arg2;
|
||||
else
|
||||
|
@ -59,24 +73,25 @@ int program::rpn_else(branch& myobj) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_end(branch& myobj) {
|
||||
int ret = -1;
|
||||
size_t program::rpn_end(branch& myobj) {
|
||||
size_t ret = step_out;
|
||||
|
||||
// arg1 = index of do+1 in case of do..unti..end
|
||||
if (myobj.arg1 != -1) {
|
||||
// in a template do..unti..end
|
||||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
// in a template do..until..end
|
||||
MIN_ARGUMENTS_RET(1, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, runtime_error);
|
||||
|
||||
// check arg
|
||||
if (_stack.value<number>(0) == 0) ret = myobj.arg1;
|
||||
_stack.pop();
|
||||
}
|
||||
// arg2 = index of while+1 in case of while..repeat..end
|
||||
else if (myobj.arg2 != -1)
|
||||
else if (myobj.arg2 != step_out)
|
||||
ret = myobj.arg2;
|
||||
|
||||
return ret;
|
||||
|
@ -85,30 +100,33 @@ int program::rpn_end(branch& myobj) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_do(branch& myobj) {
|
||||
size_t program::rpn_do(branch& myobj) {
|
||||
// nothing
|
||||
return -1;
|
||||
return step_out;
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_until(branch& myobj) {
|
||||
size_t program::rpn_until(branch& myobj) {
|
||||
// nothing
|
||||
return -1;
|
||||
return step_out;
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
void program::rpn_ift(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
@ -126,8 +144,9 @@ void program::rpn_ift(void) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
void program::rpn_ifte(void) {
|
||||
MIN_ARGUMENTS(3);
|
||||
|
@ -146,25 +165,27 @@ void program::rpn_ifte(void) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_while(branch& myobj) {
|
||||
size_t program::rpn_while(branch& myobj) {
|
||||
// nothing
|
||||
return -1;
|
||||
return step_out;
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_repeat(branch& myobj) {
|
||||
int ret = -1;
|
||||
size_t program::rpn_repeat(branch& myobj) {
|
||||
size_t ret = step_out;
|
||||
|
||||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
MIN_ARGUMENTS_RET(1, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, runtime_error);
|
||||
|
||||
// check arg
|
||||
// myobj.arg1 is end+1
|
||||
|
@ -177,15 +198,16 @@ int program::rpn_repeat(branch& myobj) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_start(branch& myobj) {
|
||||
int ret = -1;
|
||||
size_t program::rpn_start(branch& myobj) {
|
||||
size_t ret = step_out;
|
||||
|
||||
MIN_ARGUMENTS_RET(2, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -(int)ret_runtime_error);
|
||||
MIN_ARGUMENTS_RET(2, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, runtime_error);
|
||||
|
||||
// loop boundaries
|
||||
myobj.firstIndex = _stack.value<number>(1);
|
||||
|
@ -205,17 +227,23 @@ int program::rpn_start(branch& myobj) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_for(branch& myobj) {
|
||||
int ret;
|
||||
size_t program::rpn_for(branch& myobj) {
|
||||
size_t ret;
|
||||
|
||||
MIN_ARGUMENTS_RET(2, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -(int)ret_runtime_error);
|
||||
MIN_ARGUMENTS_RET(2, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, runtime_error);
|
||||
|
||||
symbol* sym = (symbol*)at(myobj.arg1); // arg1 = loop variable index
|
||||
symbol* sym;
|
||||
if (myobj.arg1 >= size() || at(myobj.arg1)->_type != cmd_symbol) {
|
||||
setErrorContext(ret_missing_operand);
|
||||
return runtime_error;
|
||||
}
|
||||
sym = (symbol*)at(myobj.arg1); // arg1 = loop variable index
|
||||
|
||||
// loop boundaries
|
||||
myobj.firstIndex = _stack.value<number>(1);
|
||||
|
@ -246,13 +274,19 @@ int program::rpn_for(branch& myobj) {
|
|||
/// @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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_next(branch& myobj) {
|
||||
size_t program::rpn_next(branch& myobj) {
|
||||
// arg1 = loop variable index
|
||||
// firstIndex = current point in the loop
|
||||
branch* start_or_for = (branch*)at(myobj.arg1);
|
||||
branch* start_or_for;
|
||||
if (myobj.arg1 >= size() || at(myobj.arg1)->_type != cmd_branch) {
|
||||
setErrorContext(ret_missing_operand);
|
||||
return runtime_error;
|
||||
}
|
||||
start_or_for = (branch*)at(myobj.arg1);
|
||||
if (!myobj.arg_bool) {
|
||||
myobj.arg_bool = true;
|
||||
myobj.firstIndex = start_or_for->firstIndex;
|
||||
|
@ -265,8 +299,12 @@ int program::rpn_next(branch& myobj) {
|
|||
// for command: increment symbol too
|
||||
if (start_or_for->arg1 != -1) {
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
symbol* var = (symbol*)at(start_or_for->arg1);
|
||||
symbol* var;
|
||||
if (start_or_for->arg1 >= size() || at(start_or_for->arg1)->_type != cmd_symbol) {
|
||||
setErrorContext(ret_missing_operand);
|
||||
return runtime_error;
|
||||
}
|
||||
var = (symbol*)at(start_or_for->arg1);
|
||||
|
||||
// store symbol variable (asserted existing in the local heap)
|
||||
((number*)_local_heap[var->value])->value = myobj.firstIndex;
|
||||
|
@ -276,7 +314,7 @@ int program::rpn_next(branch& myobj) {
|
|||
if (myobj.firstIndex > start_or_for->lastIndex) {
|
||||
// end of loop
|
||||
myobj.arg_bool = false; // init again next time
|
||||
return -1;
|
||||
return step_out;
|
||||
} else {
|
||||
// for command: next instruction will be after symbol variable
|
||||
if (start_or_for->arg1 != -1) return start_or_for->arg1 + 1;
|
||||
|
@ -289,24 +327,30 @@ 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
|
||||
/// @return size_t index of the next object to run in the current program
|
||||
/// @return step_out next object to run in the current program is current + 1
|
||||
/// @return runtime_error something went wrong with preprocess, abort branch
|
||||
///
|
||||
int program::rpn_step(branch& myobj) {
|
||||
int ret;
|
||||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
size_t program::rpn_step(branch& myobj) {
|
||||
size_t ret;
|
||||
MIN_ARGUMENTS_RET(1, runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, runtime_error);
|
||||
|
||||
mpreal step = _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
|
||||
// end of loop if step is negative or zero
|
||||
if (step <= 0)
|
||||
ret = -1;
|
||||
ret = step_out;
|
||||
else {
|
||||
// arg1 = loop variable index
|
||||
// firstIndex = current count
|
||||
branch* start_or_for = (branch*)at(myobj.arg1);
|
||||
branch* start_or_for;
|
||||
if (myobj.arg1 >= size() || at(myobj.arg1)->_type != cmd_branch) {
|
||||
setErrorContext(ret_missing_operand);
|
||||
return runtime_error;
|
||||
}
|
||||
start_or_for = (branch*)at(myobj.arg1);
|
||||
if (!myobj.arg_bool) {
|
||||
myobj.arg_bool = true;
|
||||
myobj.firstIndex = start_or_for->firstIndex;
|
||||
|
@ -316,21 +360,25 @@ int program::rpn_step(branch& myobj) {
|
|||
// carefull: round toward minus infinity to avoid missing last boundary (because growing step)
|
||||
mpfr_add(myobj.firstIndex.mpfr_ptr(), myobj.firstIndex.mpfr_srcptr(), step.mpfr_srcptr(), MPFR_RNDD);
|
||||
|
||||
// for command: increment symbol too
|
||||
if (start_or_for->arg1 != -1) {
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
symbol* var = (symbol*)at(start_or_for->arg1);
|
||||
symbol* var;
|
||||
|
||||
// for command: increment symbol too
|
||||
if (start_or_for->arg1 >= size() || at(start_or_for->arg1)->_type != cmd_symbol) {
|
||||
setErrorContext(ret_missing_operand);
|
||||
return runtime_error;
|
||||
}
|
||||
var = (symbol*)at(start_or_for->arg1);
|
||||
// increase symbol variable
|
||||
((number*)_local_heap[var->value])->value = myobj.firstIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// test loop value is out of range
|
||||
if (myobj.firstIndex > start_or_for->lastIndex) {
|
||||
// end of loop
|
||||
myobj.arg_bool = false; // init again next time
|
||||
ret = -1;
|
||||
ret = step_out;
|
||||
} else {
|
||||
// for command: next instruction will be after symbol variable
|
||||
if (start_or_for->arg1 != -1) ret = start_or_for->arg1 + 1;
|
||||
|
|
|
@ -17,7 +17,6 @@ long program::cmp_strings_on_stack_top() {
|
|||
///
|
||||
void program::rpn_sup(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) > _stack.value<number>(0)));
|
||||
|
@ -35,7 +34,6 @@ void program::rpn_sup(void) {
|
|||
///
|
||||
void program::rpn_sup_eq(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) >= _stack.value<number>(0)));
|
||||
|
@ -53,7 +51,6 @@ void program::rpn_sup_eq(void) {
|
|||
///
|
||||
void program::rpn_inf(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) < _stack.value<number>(0)));
|
||||
|
@ -70,6 +67,7 @@ void program::rpn_inf(void) {
|
|||
/// @brief <= keyword implementation
|
||||
///
|
||||
void program::rpn_inf_eq(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
// numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) <= _stack.value<number>(0)));
|
||||
|
@ -87,7 +85,6 @@ void program::rpn_inf_eq(void) {
|
|||
///
|
||||
void program::rpn_diff(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) != _stack.value<number>(0)));
|
||||
|
@ -110,7 +107,6 @@ void program::rpn_diff(void) {
|
|||
///
|
||||
void program::rpn_eq(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) == _stack.value<number>(0)));
|
||||
|
|
Loading…
Add table
Reference in a new issue