parse and link program only once at input time

This commit is contained in:
Louis Rubet 2022-03-07 18:46:33 +01:00
parent d705cf277b
commit 29c839c873
24 changed files with 453 additions and 434 deletions

View file

@ -50,10 +50,11 @@ include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/linenoise-ng
# src
set(RPN_SRC_FILES
${PROJECT_SOURCE_DIR}/src/object.cc
${PROJECT_SOURCE_DIR}/src/program.cc
${PROJECT_SOURCE_DIR}/src/main.cc
${PROJECT_SOURCE_DIR}/src/object.cc
${PROJECT_SOURCE_DIR}/src/mpreal-out.cc
${PROJECT_SOURCE_DIR}/src/program.cc
${PROJECT_SOURCE_DIR}/src/lexer.cc
${PROJECT_SOURCE_DIR}/src/input.cc
${PROJECT_SOURCE_DIR}/src/rpn-branch.cc

View file

@ -5,7 +5,7 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" // allow designated initializers
bool Lexer::Analyse(string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
bool Lexer::Analyse(const string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
vector<SynError>& errors) {
size_t jump;
for (size_t i = 0; i < entry.size(); i++) {
@ -52,7 +52,7 @@ void Lexer::Trim(string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
}
bool Lexer::ParseString(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
bool Lexer::ParseString(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
vector<SynElement>& elements) {
// here we are sure that entry[0] is at least '"'
for (size_t i = idx + 1; i < entry.size(); i++) {
@ -69,7 +69,7 @@ bool Lexer::ParseString(string& entry, size_t idx, size_t& next_idx, vector<SynE
return true;
}
bool Lexer::ParseSymbol(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
bool Lexer::ParseSymbol(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
vector<SynElement>& elements) {
// here we are sure that entry[0] is at least '\''
for (size_t i = idx + 1; i < entry.size(); i++) {
@ -84,7 +84,7 @@ bool Lexer::ParseSymbol(string& entry, size_t idx, size_t& next_idx, vector<SynE
return true;
}
bool Lexer::ParseProgram(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
bool Lexer::ParseProgram(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
vector<SynElement>& elements) {
// here we are sure that entry is at least "<<"
// find last ">>" or "»"
@ -111,7 +111,7 @@ bool Lexer::ParseProgram(string& entry, size_t idx, size_t& next_idx, vector<Syn
return true;
}
int Lexer::GetBaseAt(string& entry, size_t& next_idx, bool& positive) {
int Lexer::GetBaseAt(const string& entry, size_t& next_idx, bool& positive) {
// a regex could be "([+-])?((0[xX])|([0-9][0-9]?[bB]))"
// regex is not use because dramatically slow
// entry is scanned from idxStart, searching for [s]abc (sign and 3 first chars)
@ -154,7 +154,7 @@ int Lexer::GetBaseAt(string& entry, size_t& next_idx, bool& positive) {
return 10;
}
bool Lexer::GetNUmberAt(string& entry, size_t idx, size_t& next_idx, int& base, mpreal** r, char delim) {
bool Lexer::GetNumberAt(const string& entry, size_t idx, size_t& next_idx, int& base, mpreal** r, char delim) {
stringstream ss;
string token;
bool positive = true;
@ -182,11 +182,11 @@ bool Lexer::GetNUmberAt(string& entry, size_t idx, size_t& next_idx, int& base,
return false;
}
bool Lexer::ParseNumber(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
bool Lexer::ParseNumber(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
vector<SynElement>& elements) {
mpreal* r = nullptr;
int base = 10;
if (GetNUmberAt(entry, idx, next_idx, base, &r)) {
if (GetNumberAt(entry, idx, next_idx, base, &r)) {
elements.push_back({kNumber, .re = r, .re_base = base});
return true;
} else {
@ -195,7 +195,7 @@ bool Lexer::ParseNumber(string& entry, size_t idx, size_t& next_idx, vector<SynE
}
}
bool Lexer::ParseComplex(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
bool Lexer::ParseComplex(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
vector<SynElement>& elements) {
mpreal* re = nullptr;
mpreal* im = nullptr;
@ -205,7 +205,7 @@ bool Lexer::ParseComplex(string& entry, size_t idx, size_t& next_idx, vector<Syn
next_idx = entry.size();
return true; // complex format error, return a symbol
}
if (!GetNUmberAt(entry, idx + 1, next_idx, re_base, &re, ',')) {
if (!GetNumberAt(entry, idx + 1, next_idx, re_base, &re, ',')) {
elements.push_back({kSymbol, .value = entry.substr(idx, entry.size() - idx)});
next_idx = entry.size();
return true; // complex format error, return a symbol
@ -220,7 +220,7 @@ bool Lexer::ParseComplex(string& entry, size_t idx, size_t& next_idx, vector<Syn
return true; // complex format error, return a symbol
}
if (!GetNUmberAt(entry, i, next_idx, im_base, &im, ')')) {
if (!GetNumberAt(entry, i, next_idx, im_base, &im, ')')) {
elements.push_back({kSymbol, .value = entry.substr(idx, entry.size() - idx)});
next_idx = entry.size();
if (re != nullptr) delete re;
@ -232,7 +232,7 @@ bool Lexer::ParseComplex(string& entry, size_t idx, size_t& next_idx, vector<Syn
return true;
}
bool Lexer::ParseReserved(string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements,
bool Lexer::ParseReserved(const string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements,
map<string, ReservedWord>& keywords) {
stringstream ss(entry.substr(idx));
string token;
@ -247,7 +247,7 @@ bool Lexer::ParseReserved(string& entry, size_t idx, size_t& next_idx, vector<Sy
return false;
}
bool Lexer::ParseUnknown(string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements) {
bool Lexer::ParseUnknown(const string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements) {
stringstream ss(entry.substr(idx));
string token;
ss >> token;

View file

@ -1,7 +1,7 @@
// Copyright (c) 2014-2022 Louis Rubet
#ifndef SRC_LEXER_HPP_
#define SRC_LEXER_HPP_
#ifndef SRC_LEXER_H_
#define SRC_LEXER_H_
#include <mpreal.h>
using mpfr::mpreal;
@ -47,27 +47,27 @@ class Lexer {
/// @param[in] keywords reserved keywords
/// @return false=errors, the lexer must stop
///
bool Analyse(string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
bool Analyse(const string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
vector<SynError>& errors);
private:
bool ParseString(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
bool ParseString(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
vector<SynElement>& elements);
bool ParseSymbol(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
bool ParseSymbol(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
vector<SynElement>& elements);
bool ParseProgram(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
bool ParseProgram(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
vector<SynElement>& elements);
bool ParseNumber(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
bool ParseNumber(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
vector<SynElement>& elements);
bool ParseComplex(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
bool ParseComplex(const string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
vector<SynElement>& elements);
bool ParseReserved(string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements,
bool ParseReserved(const string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements,
map<string, ReservedWord>& keywords);
bool ParseUnknown(string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements);
bool ParseUnknown(const string& entry, size_t idx, size_t& next_idx, vector<SynElement>& elements);
void Trim(string& s);
int GetBaseAt(string& entry, size_t& next_idx, bool& positive);
bool GetNUmberAt(string& entry, size_t idx, size_t& next_idx, int& base, mpreal** r, char delim = ' ');
int GetBaseAt(const string& entry, size_t& next_idx, bool& positive);
bool GetNumberAt(const string& entry, size_t idx, size_t& next_idx, int& base, mpreal** r, char delim = ' ');
};
#endif // SRC_LEXER_HPP_
#endif // SRC_LEXER_H_

View file

@ -81,11 +81,11 @@ int main(int argc, char* argv[]) {
bool go_on = true;
// apply default configuration
program::ApplyDefault();
Program::ApplyDefault();
// run with interactive prompt
if (argc == 1) {
program::Welcome();
Program::Welcome();
// init history
EnterInteractive();
@ -99,9 +99,9 @@ int main(int argc, char* argv[]) {
while (go_on) {
//
// make program from interactive entry
program prog(stack, heap);
Program prog(stack, heap);
string entry;
switch (Input(entry, program::GetAutocompletionWords()).status) {
switch (Input(entry, Program::GetAutocompletionWords()).status) {
case Input::InputStatus::kOk:
// run it
if (prog.Parse(entry) == kOk && prog.Run() == kGoodbye)
@ -122,7 +122,7 @@ int main(int argc, char* argv[]) {
} else { // run with cmd line arguments
heap heap;
rpnstack stack;
program prog(stack, heap);
Program prog(stack, heap);
string entry;
int i;

View file

@ -48,12 +48,6 @@ typedef enum {
kBranch // langage (reserved) branch keyword (for, if, then ..)
} ObjectType;
class program;
class Branch;
typedef void (program::*program_fn_t)(void);
typedef size_t (program::*branch_fn_t)(Branch&);
/// @brief Object - a generic stack object
///
struct Object {
@ -74,6 +68,11 @@ struct Object {
friend ostream& operator<<(ostream& os, Object* o) { return o->Show(os); }
};
class Program;
class Branch;
typedef void (Program::*program_fn_t)(void);
typedef size_t (Program::*branch_fn_t)(Branch&);
/// @brief stack objects derived from Object
///
struct Number : Object {
@ -140,22 +139,18 @@ struct String : Object {
string value;
};
struct Program : Object {
Program() : Object(kProgram) {}
explicit Program(const string& value__) : Object(kProgram), value(value__) {}
virtual Object* Clone() { return new Program(value); }
virtual string Name() { return string("program"); }
virtual ostream& Show(ostream& out) { return out << "«" << value << "»"; }
string value;
};
struct Symbol : Object {
explicit Symbol(bool auto_eval__ = true) : Object(kSymbol), auto_eval(auto_eval__) {}
explicit Symbol(const string& value__, bool auto_eval__ = true)
: Object(kSymbol), value(value__), auto_eval(auto_eval__) {}
virtual Object* Clone() { return new Symbol(value, auto_eval); }
virtual string Name() { return string("symbol"); }
virtual ostream& Show(ostream& out) { return out << "'" << value << "'"; }
virtual ostream& Show(ostream& out) {
if (auto_eval)
return out << value;
else
return out << "'" << value << "'";
}
string value;
bool auto_eval;
};
@ -165,6 +160,7 @@ struct Keyword : Object {
explicit Keyword(program_fn_t fn__, const string& value__) : Object(kKeyword), fn(fn__), value(value__) {}
virtual Object* Clone() { return new Keyword(fn, value); }
virtual string Name() { return string("keyword"); }
virtual ostream& Show(ostream& out) { return out << value; }
program_fn_t fn;
string value;
};
@ -189,6 +185,7 @@ struct Branch : Object {
}
virtual Object* Clone() { return new Branch(*this); }
virtual string Name() { return string("branch"); }
virtual ostream& Show(ostream& out) { return out << value; }
branch_fn_t fn;
size_t arg1, arg2, arg3;
mpreal first_index, last_index;

View file

@ -5,207 +5,207 @@
//< language reserved keywords (allowed types are kKeyword, kBranch or kUndef)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type" // allow casting kBranch callbacks
vector<program::keyword_t> program::keywords_{
#pragma GCC diagnostic ignored "-Wpedantic" // allow designated initializers
vector<Program::keyword_t> Program::keywords_{
// GENERAL
{kUndef, "", nullptr, "\nGENERAL"},
{kKeyword, "help", &program::RpnHelp, "this help message"},
{kKeyword, "h", &program::RpnHelp, ""},
{kKeyword, "?", &program::RpnHelp, ""},
{kKeyword, "quit", &program::RpnQuit, "quit software"},
{kKeyword, "q", &program::RpnQuit, ""},
{kKeyword, "exit", &program::RpnQuit, ""},
{kKeyword, "test", &program::RpnTest, ""}, // not seen by user
{kKeyword, "version", &program::RpnVersion, "show rpn version"},
{kKeyword, "uname", &program::RpnUname, "show rpn complete identification string"},
{kKeyword, "history", &program::RpnHistory, "see commands history"},
{kKeyword, "help", &Program::RpnHelp, "this help message"},
{kKeyword, "h", &Program::RpnHelp, ""},
{kKeyword, "?", &Program::RpnHelp, ""},
{kKeyword, "quit", &Program::RpnQuit, "quit software"},
{kKeyword, "q", &Program::RpnQuit, ""},
{kKeyword, "exit", &Program::RpnQuit, ""},
{kKeyword, "test", &Program::RpnTest, ""}, // not seen by user
{kKeyword, "version", &Program::RpnVersion, "show rpn version"},
{kKeyword, "uname", &Program::RpnUname, "show rpn complete identification string"},
{kKeyword, "history", &Program::RpnHistory, "see commands history"},
// USUAL OPERATIONS ON REALS AND COMPLEXES
{kUndef, "", nullptr, "\nUSUAL OPERATIONS ON REALS AND COMPLEXES"},
{kKeyword, "+", &program::RpnPlus, "addition"},
{kKeyword, "-", &program::RpnMinus, "substraction"},
{kKeyword, "*", &program::RpnMul, "multiplication"},
{kKeyword, "/", &program::RpnDiv, "division"},
{kKeyword, "inv", &program::RpnInv, "inverse"},
{kKeyword, "chs", &program::RpnNeg, "negation"},
{kKeyword, "neg", &program::RpnNeg, ""},
{kKeyword, "^", &program::RpnPower, "power"},
{kKeyword, "pow", &program::RpnPower, ""},
{kKeyword, "sqrt", &program::RpnSquareroot, "RpnSquare root"},
{kKeyword, "sq", &program::RpnSquare, "RpnSquare"},
{kKeyword, "abs", &program::RpnAbs, "absolute value (norm for a complex)"},
{kKeyword, "sign", &program::RpnSign, "sign of a number or z/|z| for a complex"},
{kKeyword, "+", &Program::RpnPlus, "addition"},
{kKeyword, "-", &Program::RpnMinus, "substraction"},
{kKeyword, "*", &Program::RpnMul, "multiplication"},
{kKeyword, "/", &Program::RpnDiv, "division"},
{kKeyword, "inv", &Program::RpnInv, "inverse"},
{kKeyword, "chs", &Program::RpnNeg, "negation"},
{kKeyword, "neg", &Program::RpnNeg, ""},
{kKeyword, "^", &Program::RpnPower, "power"},
{kKeyword, "pow", &Program::RpnPower, ""},
{kKeyword, "sqrt", &Program::RpnSquareroot, "RpnSquare root"},
{kKeyword, "sq", &Program::RpnSquare, "RpnSquare"},
{kKeyword, "abs", &Program::RpnAbs, "absolute value (norm for a complex)"},
{kKeyword, "sign", &Program::RpnSign, "sign of a number or z/|z| for a complex"},
// OPERATIONS ON REALS
{kUndef, "", nullptr, "\nOPERATIONS ON REALS"},
{kKeyword, "%", &program::RpnPurcent, "purcent"},
{kKeyword, "%CH", &program::RpnPurcentCH, "inverse purcent"},
{kKeyword, "mod", &program::RpnModulo, "modulo"},
{kKeyword, "fact", &program::RpnFact, "n! for integer n or Gamma(x+1) for fractional x"},
{kKeyword, "mant", &program::RpnMant, "mantissa of a real number"},
{kKeyword, "xpon", &program::RpnXpon, "exponant of a real number"},
{kKeyword, "floor", &program::RpnFloor, "largest number <="},
{kKeyword, "ceil", &program::RpnCeil, "smallest number >="},
{kKeyword, "ip", &program::RpnIp, "integer part"},
{kKeyword, "fp", &program::RpnFp, "fractional part"},
{kKeyword, "min", &program::RpnMin, "min of 2 real numbers"},
{kKeyword, "max", &program::RpnMax, "max of 2 real numbers"},
{kKeyword, "%", &Program::RpnPurcent, "purcent"},
{kKeyword, "%CH", &Program::RpnPurcentCH, "inverse purcent"},
{kKeyword, "mod", &Program::RpnModulo, "modulo"},
{kKeyword, "fact", &Program::RpnFact, "n! for integer n or Gamma(x+1) for fractional x"},
{kKeyword, "mant", &Program::RpnMant, "mantissa of a real number"},
{kKeyword, "xpon", &Program::RpnXpon, "exponant of a real number"},
{kKeyword, "floor", &Program::RpnFloor, "largest number <="},
{kKeyword, "ceil", &Program::RpnCeil, "smallest number >="},
{kKeyword, "ip", &Program::RpnIp, "integer part"},
{kKeyword, "fp", &Program::RpnFp, "fractional part"},
{kKeyword, "min", &Program::RpnMin, "min of 2 real numbers"},
{kKeyword, "max", &Program::RpnMax, "max of 2 real numbers"},
// OPERATIONS ON COMPLEXES
{kUndef, "", nullptr, "\nOPERATIONS ON COMPLEXES"},
{kKeyword, "re", &program::RpnReal, "complex real part"},
{kKeyword, "im", &program::RpnImag, "complex imaginary part"},
{kKeyword, "conj", &program::RpnConj, "complex conjugate"},
{kKeyword, "arg", &program::RpnArg, "complex argument in radians"},
{kKeyword, "c->r", &program::RpnC2r, "transform a complex in 2 reals"},
{kKeyword, "r->c", &program::RpnR2c, "transform 2 reals in a complex"},
{kKeyword, "p->r", &program::RpnP2r, "cartesian to polar"},
{kKeyword, "r->p", &program::RpnR2p, "polar to cartesian"},
{kKeyword, "re", &Program::RpnReal, "complex real part"},
{kKeyword, "im", &Program::RpnImag, "complex imaginary part"},
{kKeyword, "conj", &Program::RpnConj, "complex conjugate"},
{kKeyword, "arg", &Program::RpnArg, "complex argument in radians"},
{kKeyword, "c->r", &Program::RpnC2r, "transform a complex in 2 reals"},
{kKeyword, "r->c", &Program::RpnR2c, "transform 2 reals in a complex"},
{kKeyword, "p->r", &Program::RpnP2r, "cartesian to polar"},
{kKeyword, "r->p", &Program::RpnR2p, "polar to cartesian"},
// MODE
{kUndef, "", nullptr, "\nMODE"},
{kKeyword, "std", &program::RpnStd, "standard floating numbers representation. ex: std"},
{kKeyword, "fix", &program::RpnFix, "fixed point representation. ex: 6 fix"},
{kKeyword, "sci", &program::RpnSci, "scientific floating point representation. ex: 20 sci"},
{kKeyword, "prec", &program::RpnPrecision, "set float precision in bits. ex: 256 prec"},
{kKeyword, "round", &program::RpnRound,
{kKeyword, "std", &Program::RpnStd, "standard floating numbers representation. ex: std"},
{kKeyword, "fix", &Program::RpnFix, "fixed point representation. ex: 6 fix"},
{kKeyword, "sci", &Program::RpnSci, "scientific floating point representation. ex: 20 sci"},
{kKeyword, "prec", &Program::RpnPrecision, "set float precision in bits. ex: 256 prec"},
{kKeyword, "round", &Program::RpnRound,
"set float rounding mode in \n\t\"nearest (even)\", \"toward zero\", \"toward "
"+inf\", \"toward -inf\", \"away from zero\", \"faithful rounding\", \"nearest (away from zero)\""
"\n\tex: \"nearest (even)\" round"},
{kKeyword, "default", &program::RpnDefault, "set float representation and precision to default"},
{kKeyword, "type", &program::RpnType, "show type of stack first entry"},
{kKeyword, "hex", &program::RpnHex, "hexadecimal representation, applies on stack level 0 only"},
{kKeyword, "dec", &program::RpnDec, "decimal representation, applies on stack level 0 only"},
{kKeyword, "bin", &program::RpnBin, "binary representation, applies on stack level 0 only"},
{kKeyword, "base", &program::RpnBase, "arbitrary base representation, applies on stack level 0 only"},
{kKeyword, "default", &Program::RpnDefault, "set float representation and precision to default"},
{kKeyword, "type", &Program::RpnType, "show type of stack first entry"},
{kKeyword, "hex", &Program::RpnHex, "hexadecimal representation, applies on stack level 0 only"},
{kKeyword, "dec", &Program::RpnDec, "decimal representation, applies on stack level 0 only"},
{kKeyword, "bin", &Program::RpnBin, "binary representation, applies on stack level 0 only"},
{kKeyword, "base", &Program::RpnBase, "arbitrary base representation, applies on stack level 0 only"},
// TESTS
{kUndef, "", nullptr, "\nTEST"},
{kKeyword, ">", &program::RpnSup, "binary operator >"},
{kKeyword, ">=", &program::RpnSupEq, "binary operator >="},
{kKeyword, "<", &program::RpnInf, "binary operator <"},
{kKeyword, "<=", &program::RpnInfEq, "binary operator <="},
{kKeyword, "!=", &program::RpnDiff, "binary operator != (different)"},
{kKeyword, "==", &program::RpnEq, "binary operator == (equal)"},
{kKeyword, "and", &program::RpnTestAnd, "boolean operator and"},
{kKeyword, "or", &program::RpnTestOr, "boolean operator or"},
{kKeyword, "xor", &program::RpnTestXor, "boolean operator xor"},
{kKeyword, "not", &program::RpnTestNot, "boolean operator not"},
{kKeyword, "same", &program::RpnSame, "boolean operator same (equal)"},
{kKeyword, ">", &Program::RpnSup, "binary operator >"},
{kKeyword, ">=", &Program::RpnSupEq, "binary operator >="},
{kKeyword, "<", &Program::RpnInf, "binary operator <"},
{kKeyword, "<=", &Program::RpnInfEq, "binary operator <="},
{kKeyword, "!=", &Program::RpnDiff, "binary operator != (different)"},
{kKeyword, "==", &Program::RpnEq, "binary operator == (equal)"},
{kKeyword, "and", &Program::RpnTestAnd, "boolean operator and"},
{kKeyword, "or", &Program::RpnTestOr, "boolean operator or"},
{kKeyword, "xor", &Program::RpnTestXor, "boolean operator xor"},
{kKeyword, "not", &Program::RpnTestNot, "boolean operator not"},
{kKeyword, "same", &Program::RpnSame, "boolean operator same (equal)"},
// STACK
{kUndef, "", nullptr, "\nSTACK"},
{kKeyword, "swap", &program::RpnSwap, "swap 2 first stack entries"},
{kKeyword, "drop", &program::RpnDrop, "drop first stack entry"},
{kKeyword, "drop2", &program::RpnDrop2, "drop 2 first stack entries"},
{kKeyword, "dropn", &program::RpnDropn, "drop n first stack entries"},
{kKeyword, "del", &program::RpnErase, "drop all stack entries"},
{kKeyword, "erase", &program::RpnErase, ""},
{kKeyword, "rot", &program::RpnRot, "rotate 3 first stack entries"},
{kKeyword, "dup", &program::RpnDup, "duplicate first stack entry"},
{kKeyword, "dup2", &program::RpnDup2, "duplicate 2 first stack entries"},
{kKeyword, "dupn", &program::RpnDupn, "duplicate n first stack entries"},
{kKeyword, "pick", &program::RpnPick, "push a copy of the given stack level onto the stack"},
{kKeyword, "depth", &program::RpnDepth, "give stack depth"},
{kKeyword, "roll", &program::RpnRoll, "move a stack entry to the top of the stack"},
{kKeyword, "rolld", &program::RpnRolld, "move the element on top of the stack to a higher stack position"},
{kKeyword, "over", &program::RpnOver, "push a copy of the element in stack level 2 onto the stack"},
{kKeyword, "swap", &Program::RpnSwap, "swap 2 first stack entries"},
{kKeyword, "drop", &Program::RpnDrop, "drop first stack entry"},
{kKeyword, "drop2", &Program::RpnDrop2, "drop 2 first stack entries"},
{kKeyword, "dropn", &Program::RpnDropn, "drop n first stack entries"},
{kKeyword, "del", &Program::RpnErase, "drop all stack entries"},
{kKeyword, "erase", &Program::RpnErase, ""},
{kKeyword, "rot", &Program::RpnRot, "rotate 3 first stack entries"},
{kKeyword, "dup", &Program::RpnDup, "duplicate first stack entry"},
{kKeyword, "dup2", &Program::RpnDup2, "duplicate 2 first stack entries"},
{kKeyword, "dupn", &Program::RpnDupn, "duplicate n first stack entries"},
{kKeyword, "pick", &Program::RpnPick, "push a copy of the given stack level onto the stack"},
{kKeyword, "depth", &Program::RpnDepth, "give stack depth"},
{kKeyword, "roll", &Program::RpnRoll, "move a stack entry to the top of the stack"},
{kKeyword, "rolld", &Program::RpnRolld, "move the element on top of the stack to a higher stack position"},
{kKeyword, "over", &Program::RpnOver, "push a copy of the element in stack level 2 onto the stack"},
// STRING
{kUndef, "", nullptr, "\nSTRING"},
{kKeyword, "->str", &program::RpnInstr, "convert an object into a string"},
{kKeyword, "str->", &program::RpnStrout, "convert a string into an object"},
{kKeyword, "chr", &program::RpnChr, "convert ASCII character code in stack level 1 into a string"},
{kKeyword, "num", &program::RpnNum,
{kKeyword, "->str", &Program::RpnInstr, "convert an object into a string"},
{kKeyword, "str->", &Program::RpnStrout, "convert a string into an object"},
{kKeyword, "chr", &Program::RpnChr, "convert ASCII character code in stack level 1 into a string"},
{kKeyword, "num", &Program::RpnNum,
"return ASCII code of the first character of the string in stack level 1 as a real number"},
{kKeyword, "size", &program::RpnStrsize, "return the length of the string"},
{kKeyword, "pos", &program::RpnStrpos, "seach for the string in level 1 within the string in level 2"},
{kKeyword, "sub", &program::RpnStrsub, "return a substring of the string in level 3"},
{kKeyword, "size", &Program::RpnStrsize, "return the length of the string"},
{kKeyword, "pos", &Program::RpnStrpos, "seach for the string in level 1 within the string in level 2"},
{kKeyword, "sub", &Program::RpnStrsub, "return a substring of the string in level 3"},
// BRANCH
{kUndef, "", nullptr, "\nBRANCH"},
{kBranch, "if", (program_fn_t)&program::RpnIf,
{kBranch, "if", (program_fn_t)&Program::RpnIf,
"if <test-instruction> then <true-instructions> else <false-instructions> "
"end"},
{kBranch, "then", (program_fn_t)&program::RpnThen, "used with if"},
{kBranch, "else", (program_fn_t)&program::RpnElse, "used with if"},
{kBranch, "end", (program_fn_t)&program::RpnEnd, "used with various branch instructions"},
{kBranch, "start", (program_fn_t)&program::RpnStart, "<start> <end> start <instructions> next|<step> step"},
{kBranch, "for", (program_fn_t)&program::RpnFor, "<start> <end> for <variable> <instructions> next|<step> step"},
{kBranch, "next", (program_fn_t)&program::RpnNext, "used with start and for"},
{kBranch, "step", (program_fn_t)&program::RpnStep, "used with start and for"},
{kKeyword, "ift", &program::RpnIft, "similar to if-then-end, <test-instruction> <true-instruction> ift"},
{kKeyword, "ifte", &program::RpnIfte,
{kBranch, "then", (program_fn_t)&Program::RpnThen, "used with if"},
{kBranch, "else", (program_fn_t)&Program::RpnElse, "used with if"},
{kBranch, "end", (program_fn_t)&Program::RpnEnd, "used with various branch instructions"},
{kBranch, "start", (program_fn_t)&Program::RpnStart, "<start> <end> start <instructions> next|<step> step"},
{kBranch, "for", (program_fn_t)&Program::RpnFor, "<start> <end> for <variable> <instructions> next|<step> step"},
{kBranch, "next", (program_fn_t)&Program::RpnNext, "used with start and for"},
{kBranch, "step", (program_fn_t)&Program::RpnStep, "used with start and for"},
{kKeyword, "ift", &Program::RpnIft, "similar to if-then-end, <test-instruction> <true-instruction> ift"},
{kKeyword, "ifte", &Program::RpnIfte,
"similar to if-then-else-end, <test-instruction> <true-instruction> "
"<false-instruction> ifte"},
{kBranch, "do", (program_fn_t)&program::RpnDo, "do <instructions> until <condition> end"},
{kBranch, "until", (program_fn_t)&program::RpnUntil, "used with do"},
{kBranch, "while", (program_fn_t)&program::RpnWhile, "while <test-instruction> repeat <loop-instructions> end"},
{kBranch, "repeat", (program_fn_t)&program::RpnRepeat, "used with while"},
{kBranch, "do", (program_fn_t)&Program::RpnDo, "do <instructions> until <condition> end"},
{kBranch, "until", (program_fn_t)&Program::RpnUntil, "used with do"},
{kBranch, "while", (program_fn_t)&Program::RpnWhile, "while <test-instruction> repeat <loop-instructions> end"},
{kBranch, "repeat", (program_fn_t)&Program::RpnRepeat, "used with while"},
// STORE
{kUndef, "", nullptr, "\nSTORE"},
{kKeyword, "sto", &program::RpnSto, "store a variable. ex: 1 'name' sto"},
{kKeyword, "rcl", &program::RpnRcl, "recall a variable. ex: 'name' rcl"},
{kKeyword, "purge", &program::RpnPurge, "delete a variable. ex: 'name' purge"},
{kKeyword, "vars", &program::RpnVars, "list all variables"},
{kKeyword, "clusr", &program::RpnClusr, "erase all variables"},
{kKeyword, "edit", &program::RpnEdit, "edit a variable content"},
{kKeyword, "sto+", &program::RpnStoadd, "add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+"},
{kKeyword, "sto-", &program::RpnStosub, "substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto-"},
{kKeyword, "sto*", &program::RpnStomul, "multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto*"},
{kKeyword, "sto/", &program::RpnStodiv, "divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/"},
{kKeyword, "sneg", &program::RpnStoneg, "negate a variable. ex: 'name' sneg"},
{kKeyword, "sinv", &program::RpnStoinv, "inverse a variable. ex: 1 'name' sinv"},
{kKeyword, "sto", &Program::RpnSto, "store a variable. ex: 1 'name' sto"},
{kKeyword, "rcl", &Program::RpnRcl, "recall a variable. ex: 'name' rcl"},
{kKeyword, "purge", &Program::RpnPurge, "delete a variable. ex: 'name' purge"},
{kKeyword, "vars", &Program::RpnVars, "list all variables"},
{kKeyword, "clusr", &Program::RpnClusr, "erase all variables"},
{kKeyword, "edit", &Program::RpnEdit, "edit a variable content"},
{kKeyword, "sto+", &Program::RpnStoadd, "add to a stored variable. ex: 1 'name' sto+ 'name' 2 sto+"},
{kKeyword, "sto-", &Program::RpnStosub, "substract to a stored variable. ex: 1 'name' sto- 'name' 2 sto-"},
{kKeyword, "sto*", &Program::RpnStomul, "multiply a stored variable. ex: 3 'name' sto* 'name' 2 sto*"},
{kKeyword, "sto/", &Program::RpnStodiv, "divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/"},
{kKeyword, "sneg", &Program::RpnStoneg, "negate a variable. ex: 'name' sneg"},
{kKeyword, "sinv", &Program::RpnStoinv, "inverse a variable. ex: 1 'name' sinv"},
// PROGRAM
{kUndef, "", nullptr, "\nPROGRAM"},
{kKeyword, "eval", &program::RpnEval, "evaluate (run) a program, or recall a variable. ex: 'my_prog' eval"},
{kBranch, "->", (program_fn_t)&program::RpnInprog,
{kKeyword, "eval", &Program::RpnEval, "evaluate (run) a program, or recall a variable. ex: 'my_prog' eval"},
{kBranch, "->", (program_fn_t)&Program::RpnInprog,
"load program local variables. ex: << -> n m << 0 n m for i i + next >> "
">>"},
// TRIG ON REALS AND COMPLEXES
{kUndef, "", nullptr, "\nTRIG ON REALS AND COMPLEXES"},
{kKeyword, "pi", &program::RpnPi, "pi constant"},
{kKeyword, "sin", &program::RpnSin, "sinus"},
{kKeyword, "asin", &program::RpnAsin, "arg sinus"},
{kKeyword, "cos", &program::RpnCos, "cosinus"},
{kKeyword, "acos", &program::RpnAcos, "arg cosinus"},
{kKeyword, "tan", &program::RpnTan, "tangent"},
{kKeyword, "atan", &program::RpnAtan, "arg tangent"},
{kKeyword, "d->r", &program::RpnD2r, "convert degrees to radians"},
{kKeyword, "r->d", &program::RpnR2d, "convert radians to degrees"},
{kKeyword, "pi", &Program::RpnPi, "pi constant"},
{kKeyword, "sin", &Program::RpnSin, "sinus"},
{kKeyword, "asin", &Program::RpnAsin, "arg sinus"},
{kKeyword, "cos", &Program::RpnCos, "cosinus"},
{kKeyword, "acos", &Program::RpnAcos, "arg cosinus"},
{kKeyword, "tan", &Program::RpnTan, "tangent"},
{kKeyword, "atan", &Program::RpnAtan, "arg tangent"},
{kKeyword, "d->r", &Program::RpnD2r, "convert degrees to radians"},
{kKeyword, "r->d", &Program::RpnR2d, "convert radians to degrees"},
// LOGS ON REALS AND COMPLEXES
{kUndef, "", nullptr, "\nLOGS ON REALS AND COMPLEXES"},
{kKeyword, "e", &program::RpnE, "Euler constant"},
{kKeyword, "ln", &program::RpnLn, "logarithm base e"},
{kKeyword, "log", &program::RpnLn, ""},
{kKeyword, "lnp1", &program::RpnLnp1, "ln(1+x) which is useful when x is close to 0"},
{kKeyword, "exp", &program::RpnExp, "exponential"},
{kKeyword, "expm", &program::RpnExpm, "exp(x)-1 which is useful when x is close to 0"},
{kKeyword, "log10", &program::RpnLog10, "logarithm base 10"},
{kKeyword, "alog10", &program::RpnAlog10, "exponential base 10"},
{kKeyword, "exp10", &program::RpnAlog10, ""},
{kKeyword, "log2", &program::RpnLog2, "logarithm base 2"},
{kKeyword, "alog2", &program::RpnAlog2, "exponential base 2"},
{kKeyword, "exp2", &program::RpnAlog2, ""},
{kKeyword, "sinh", &program::RpnSinh, "hyperbolic sine"},
{kKeyword, "asinh", &program::RpnAsinh, "inverse hyperbolic sine"},
{kKeyword, "cosh", &program::RpnCosh, "hyperbolic cosine"},
{kKeyword, "acosh", &program::RpnAcosh, "inverse hyperbolic cosine"},
{kKeyword, "tanh", &program::RpnTanh, "hyperbolic tangent"},
{kKeyword, "atanh", &program::RpnAtanh, "inverse hyperbolic tangent"},
{kKeyword, "e", &Program::RpnE, "Euler constant"},
{kKeyword, "ln", &Program::RpnLn, "logarithm base e"},
{kKeyword, "log", &Program::RpnLn, ""},
{kKeyword, "lnp1", &Program::RpnLnp1, "ln(1+x) which is useful when x is close to 0"},
{kKeyword, "exp", &Program::RpnExp, "exponential"},
{kKeyword, "expm", &Program::RpnExpm, "exp(x)-1 which is useful when x is close to 0"},
{kKeyword, "log10", &Program::RpnLog10, "logarithm base 10"},
{kKeyword, "alog10", &Program::RpnAlog10, "exponential base 10"},
{kKeyword, "exp10", &Program::RpnAlog10, ""},
{kKeyword, "log2", &Program::RpnLog2, "logarithm base 2"},
{kKeyword, "alog2", &Program::RpnAlog2, "exponential base 2"},
{kKeyword, "exp2", &Program::RpnAlog2, ""},
{kKeyword, "sinh", &Program::RpnSinh, "hyperbolic sine"},
{kKeyword, "asinh", &Program::RpnAsinh, "inverse hyperbolic sine"},
{kKeyword, "cosh", &Program::RpnCosh, "hyperbolic cosine"},
{kKeyword, "acosh", &Program::RpnAcosh, "inverse hyperbolic cosine"},
{kKeyword, "tanh", &Program::RpnTanh, "hyperbolic tangent"},
{kKeyword, "atanh", &Program::RpnAtanh, "inverse hyperbolic tangent"},
// TIME AND DATE
{kUndef, "", nullptr, "\nTIME AND DATE"},
{kKeyword, "time", &program::RpnTime, "local time in ISO 8601 format"},
{kKeyword, "date", &program::RpnDate, "local date in ISO 8601 format"},
{kKeyword, "ticks", &program::RpnTicks, "local date and time in µs"}
};
{kKeyword, "time", &Program::RpnTime, "local time in ISO 8601 format"},
{kKeyword, "date", &Program::RpnDate, "local date in ISO 8601 format"},
{kKeyword, "ticks", &Program::RpnTicks, "local date and time in µs"}};
#pragma GCC diagnostic pop
/// autocompletion vector for linenoise autocompletion
vector<string>& program::GetAutocompletionWords() {
vector<string>& Program::GetAutocompletionWords() {
static vector<string> autocompletion_words;
if (autocompletion_words.empty())
for (auto& kw : keywords_)
@ -217,22 +217,13 @@ vector<string>& program::GetAutocompletionWords() {
///
/// @return RetValue see this type
///
RetValue program::Run() {
RetValue Program::Run() {
bool go_out = false;
RetValue ret = kOk;
err_ = kOk;
err_context_ = "";
// branches for 'if'
ret = Preprocess();
if (ret != kOk) {
// free allocated
for (Object* o : *this) delete o;
local_heap_.clear();
return ret;
}
// iterate commands
for (size_t i = 0; (go_out == false) && (i < size());) {
Object* o = at(i);
@ -317,7 +308,7 @@ RetValue program::Run() {
///
/// @return RetValue see this type
///
RetValue program::Preprocess() {
RetValue Program::Preprocess() {
struct if_layout_t {
if_layout_t()
: index_then_or_unti_or_repeat(-1),
@ -563,7 +554,7 @@ RetValue program::Preprocess() {
/// @param prog the program to be filled
/// @return RetValue see this type
///
RetValue program::Parse(string& entry) {
RetValue Program::Parse(const string& entry) {
static map<string, Lexer::ReservedWord> keywords_map;
vector<Lexer::SynElement> elements;
vector<Lexer::SynError> errors;
@ -591,9 +582,19 @@ RetValue program::Parse(string& entry) {
case kSymbol:
push_back(new Symbol(element.value, element.auto_eval));
break;
case kProgram:
push_back(new Program(element.value));
break;
case kProgram: {
Program* p = new Program(stack_, heap_, this);
if (p->Parse(element.value) == kOk) {
stringstream ss;
for (size_t i = 0; i < p->size(); i++)
if (i > 0)
ss << ' ' << p->at(i);
else
ss << p->at(i);
p->value = ss.str();
push_back(p);
}
} break;
case kKeyword:
push_back(new Keyword(element.fn, element.value));
break;
@ -610,6 +611,9 @@ RetValue program::Parse(string& entry) {
if (element.re != nullptr) delete element.re;
if (element.im != nullptr) delete element.im;
}
// compute links between the objects
return Preprocess();
} else {
for (SynError& err : errors) ShowSyntaxError(err.err.c_str());
}
@ -621,7 +625,7 @@ RetValue program::Parse(string& entry) {
///
/// @return RetValue see this type
///
RetValue program::ShowError() {
RetValue Program::ShowError() {
RetValue ret;
// clang-format off
map<RetValue, string> errorStrings{{kOk, "ok"}, {kUnknownError, "unknown command"},
@ -655,7 +659,7 @@ RetValue program::ShowError() {
/// @param context a context string
/// @return RetValue see this type
///
RetValue program::ShowError(RetValue err, string& context) {
RetValue Program::ShowError(RetValue err, string& context) {
// record error
err_ = err;
err_context_ = context;
@ -668,7 +672,7 @@ RetValue program::ShowError(RetValue err, string& context) {
/// @param context a context string
/// @return RetValue see this type
///
RetValue program::ShowError(RetValue err, const char* context) {
RetValue Program::ShowError(RetValue err, const char* context) {
// record error
err_ = err;
err_context_ = context;
@ -681,7 +685,7 @@ RetValue program::ShowError(RetValue err, const char* context) {
/// @param context a context string
/// @return RetValue see this type
///
void program::ShowSyntaxError(const char* context) {
void Program::ShowSyntaxError(const char* context) {
// record error
err_ = kSyntaxError;
err_context_ = context;
@ -692,14 +696,14 @@ void program::ShowSyntaxError(const char* context) {
///
/// @return RetValue see this type
///
RetValue program::GetLastError(void) { return err_; }
RetValue Program::GetLastError(void) { return err_; }
/// @brief show a stack (show its different objects)
/// generally a stack is associated to a running program
///
/// @param show_separator whether to show a stack level prefix or not
///
void program::ShowStack(bool show_separator) {
void Program::ShowStack(bool show_separator) {
if (stack_.size() == 1) {
cout << stack_[0] << endl;
} else {
@ -712,7 +716,7 @@ void program::ShowStack(bool show_separator) {
/// @brief apply default precision mode and digits
///
void program::ApplyDefault() {
void Program::ApplyDefault() {
// default float precision, float mode
Number::mode = Number::kDefaultMode;
Number::digits = Number::kDefaultDecimalDigits;

View file

@ -1,7 +1,7 @@
// Copyright (c) 2014-2022 Louis Rubet
#ifndef SRC_PROGRAM_HPP_
#define SRC_PROGRAM_HPP_
#ifndef SRC_PROGRAM_H_
#define SRC_PROGRAM_H_
// std c++
#include <deque>
@ -18,18 +18,39 @@ using mpfr::mpreal;
#include "object.h"
#include "stack.h"
// struct Program : Object {
// Program() : Object(kProgram) {}
// explicit Program(const string& value__) : Object(kProgram), value(value__) {}
// virtual Object* Clone() { return new Program(value); }
// virtual string Name() { return string("program"); }
// virtual ostream& Show(ostream& out) { return out << "«" << value << "»"; }
// string value;
// };
//< 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 {
class Program : public deque<Object*>, public Lexer, public Object {
public:
program(rpnstack& stack__, heap& heap__, program* parent__ = nullptr)
: stack_(stack__), heap_(heap__), parent_(parent__) {}
virtual ~program() {
Program(rpnstack& stack__, heap& heap__, Program* parent__ = nullptr)
: Object(kProgram), stack_(stack__), heap_(heap__), parent_(parent__) {}
Program(const string& value__, rpnstack& stack__, heap& heap__, Program* parent__ = nullptr)
: Object(kProgram), value(value__), stack_(stack__), heap_(heap__), parent_(parent__) {}
virtual ~Program() {
local_heap_.clear();
clear();
}
virtual Object* Clone() {
Program* prog = new Program(value, stack_, heap_, parent_);
prog->value = value;
for (auto& obj : *this) prog->push_back(obj->Clone());
return prog;
}
virtual string Name() { return string("program"); }
virtual ostream& Show(ostream& out) { return out << "« " << value << " »"; }
// parser
RetValue Parse(string& entry);
RetValue Parse(const string& entry);
// running
RetValue Run();
@ -43,6 +64,8 @@ class program : public deque<Object*>, public Lexer {
void ShowStack(bool show_separator = true);
string value;
static void ApplyDefault();
static void Welcome();
@ -63,9 +86,8 @@ class program : public deque<Object*>, public Lexer {
heap local_heap_;
// parent prog for inheriting heaps
program* parent_;
Program* parent_;
private:
// keywords
struct keyword_t {
ObjectType type;
@ -245,7 +267,7 @@ class program : public deque<Object*>, public Lexer {
void RpnTicks();
};
// convenience macros for rpn_xx function
// convenience macros for RpnXxx functions
// carefull : some of these macros modify program flow
#define ERROR_CONTEXT(err) \
@ -254,36 +276,36 @@ class program : public deque<Object*>, public Lexer {
err_context_ = __FUNCTION__; \
} while (0)
#define MIN_ARGUMENTS(num) \
do { \
if (stack_.size() < (num)) { \
ERROR_CONTEXT(kMissingOperand); \
return; \
} \
#define MIN_ARGUMENTS(num) \
do { \
if (stack_.size() < (num)) { \
ERROR_CONTEXT(kMissingOperand); \
return; \
} \
} while (0)
#define MIN_ARGUMENTS_RET(num, ret) \
do { \
if (stack_.size() < (num)) { \
ERROR_CONTEXT(kMissingOperand); \
return (ret); \
} \
#define MIN_ARGUMENTS_RET(num, ret) \
do { \
if (stack_.size() < (num)) { \
ERROR_CONTEXT(kMissingOperand); \
return (ret); \
} \
} while (0)
#define ARG_MUST_BE_OF_TYPE(num, type) \
do { \
#define ARG_MUST_BE_OF_TYPE(num, type) \
do { \
if (stack_.at(num)->_type != (type)) { \
ERROR_CONTEXT(kBadOperandType); \
return; \
} \
ERROR_CONTEXT(kBadOperandType); \
return; \
} \
} while (0)
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) \
do { \
if (stack_.at(num)->_type != (type)) { \
ERROR_CONTEXT(kBadOperandType); \
return (ret); \
} \
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) \
do { \
if (stack_.at(num)->_type != (type)) { \
ERROR_CONTEXT(kBadOperandType); \
return (ret); \
} \
} while (0)
#endif // SRC_PROGRAM_HPP_
#endif // SRC_PROGRAM_H_

View file

@ -9,7 +9,7 @@
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnIf(Branch& myobj) {
size_t Program::RpnIf(Branch& myobj) {
// myobj.arg1 = 'if' condition evaluation value
MIN_ARGUMENTS_RET(1, kRtError);
ARG_MUST_BE_OF_TYPE_RET(0, kNumber, kRtError);
@ -29,7 +29,7 @@ size_t program::RpnIf(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort Branch
///
size_t program::RpnThen(Branch& myobj) {
size_t Program::RpnThen(Branch& myobj) {
// myobj.arg1 = index of then + 1
// myobj.arg2 = index of else + 1 or end + 1
// myobj.arg3 = index of if
@ -54,7 +54,7 @@ size_t program::RpnThen(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnElse(Branch& myobj) {
size_t Program::RpnElse(Branch& myobj) {
// myobj.arg1 = index of else + 1
// myobj.arg2 = index of end + 1
// myobj.arg3 = index of if
@ -79,7 +79,7 @@ size_t program::RpnElse(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnEnd(Branch& myobj) {
size_t Program::RpnEnd(Branch& myobj) {
size_t ret = kStepOut;
// arg1 = index of do+1 in case of do..unti..end
@ -106,7 +106,7 @@ size_t program::RpnEnd(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnDo(Branch& myobj __attribute__((unused))) {
size_t Program::RpnDo(Branch& myobj __attribute__((unused))) {
// nothing
return kStepOut;
}
@ -118,7 +118,7 @@ size_t program::RpnDo(Branch& myobj __attribute__((unused))) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort Branch
///
size_t program::RpnUntil(Branch& myobj __attribute__((unused))) {
size_t Program::RpnUntil(Branch& myobj __attribute__((unused))) {
// nothing
return kStepOut;
}
@ -130,7 +130,7 @@ size_t program::RpnUntil(Branch& myobj __attribute__((unused))) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
void program::RpnIft(void) {
void Program::RpnIft(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -149,7 +149,7 @@ void program::RpnIft(void) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
void program::RpnIfte(void) {
void Program::RpnIfte(void) {
MIN_ARGUMENTS(3);
ARG_MUST_BE_OF_TYPE(2, kNumber);
@ -170,7 +170,7 @@ void program::RpnIfte(void) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnWhile(Branch& myobj __attribute__((unused))) {
size_t Program::RpnWhile(Branch& myobj __attribute__((unused))) {
// nothing
return kStepOut;
}
@ -182,7 +182,7 @@ size_t program::RpnWhile(Branch& myobj __attribute__((unused))) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnRepeat(Branch& myobj) {
size_t Program::RpnRepeat(Branch& myobj) {
size_t ret = kStepOut;
MIN_ARGUMENTS_RET(1, kRtError);
@ -203,7 +203,7 @@ size_t program::RpnRepeat(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnStart(Branch& myobj) {
size_t Program::RpnStart(Branch& myobj) {
size_t ret = kStepOut;
MIN_ARGUMENTS_RET(2, kRtError);
@ -232,7 +232,7 @@ size_t program::RpnStart(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnFor(Branch& myobj) {
size_t Program::RpnFor(Branch& myobj) {
size_t ret;
MIN_ARGUMENTS_RET(2, kRtError);
@ -279,7 +279,7 @@ size_t program::RpnFor(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnNext(Branch& myobj) {
size_t Program::RpnNext(Branch& myobj) {
// arg1 = loop variable index
// first_index = current point in the loop
Branch* start_or_for;
@ -331,7 +331,7 @@ size_t program::RpnNext(Branch& myobj) {
/// @return kStepOut next object to run in the current program is current + 1
/// @return kRtError something went wrong with preprocess, abort branch
///
size_t program::RpnStep(Branch& myobj) {
size_t Program::RpnStep(Branch& myobj) {
size_t ret;
MIN_ARGUMENTS_RET(1, kRtError);
ARG_MUST_BE_OF_TYPE_RET(0, kNumber, kRtError);

View file

@ -5,7 +5,7 @@
/// @brief re keyword implementation
/// the result is stacked on current program stack
///
void program::RpnReal() {
void Program::RpnReal() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kComplex);
stack_.push_front(new Number(real(stack_.value<Complex>(0))));
@ -15,7 +15,7 @@ void program::RpnReal() {
/// @brief im keyword implementation
/// the result is stacked on current program stack
///
void program::RpnImag() {
void Program::RpnImag() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kComplex);
stack_.push_front(new Number(imag(stack_.value<Complex>(0))));
@ -25,7 +25,7 @@ void program::RpnImag() {
/// @brief arg keyword implementation
/// the result is stacked on current program stack
///
void program::RpnArg() {
void Program::RpnArg() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kComplex);
stack_.push_front(new Number(arg(stack_.value<Complex>(0))));
@ -35,7 +35,7 @@ void program::RpnArg() {
/// @brief conj keyword implementation
/// the result is stacked on current program stack
///
void program::RpnConj() {
void Program::RpnConj() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kComplex);
stack_.value<Complex>(0) = conj(stack_.value<Complex>(0));
@ -44,7 +44,7 @@ void program::RpnConj() {
/// @brief r2c keyword implementation
/// the result is stacked on current program stack
///
void program::RpnR2c() {
void Program::RpnR2c() {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -55,7 +55,7 @@ void program::RpnR2c() {
/// @brief c2r keyword implementation
/// the result is stacked on current program stack
///
void program::RpnC2r() {
void Program::RpnC2r() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kComplex);
stack_.push(new Number(real(stack_.value<Complex>(0)), stack_.obj<Complex>(0).re_base));
@ -66,7 +66,7 @@ void program::RpnC2r() {
/// @brief r2p keyword implementation
/// the result is stacked on current program stack
///
void program::RpnR2p() {
void Program::RpnR2p() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kComplex);
mpreal rho = abs(stack_.value<Complex>(0));
@ -78,7 +78,7 @@ void program::RpnR2p() {
/// @brief p2r keyword implementation
/// the result is stacked on current program stack
///
void program::RpnP2r() {
void Program::RpnP2r() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kComplex);
stack_.value<Complex>(0) = polar(abs(stack_.value<Complex>(0)), arg(stack_.value<Complex>(0)));

View file

@ -29,12 +29,12 @@ static const char _welcome[] = ATTR_BOLD "rpn " RPN_VERSION ATTR_OFF "\nType h o
/// @brief quit keyword implementation
///
void program::RpnQuit() { ERROR_CONTEXT(kGoodbye); }
void Program::RpnQuit() { ERROR_CONTEXT(kGoodbye); }
/// @brief nop keyword implementation
/// the result is written on stdout
///
void program::RpnHelp() {
void Program::RpnHelp() {
// software name
cout << endl << _uname << endl;
@ -86,7 +86,7 @@ void program::RpnHelp() {
/// @brief welcome string
///
void program::Welcome() { cout << _welcome << endl; }
void Program::Welcome() { cout << _welcome << endl; }
/// @brief whether a printed precision is in the precision min/max
///
@ -98,7 +98,7 @@ static bool check_decimal_digits(int precision) { return precision >= 0; }
/// @brief std keyword implementation
///
void program::RpnStd() {
void Program::RpnStd() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -116,7 +116,7 @@ void program::RpnStd() {
/// @brief fix keyword implementation
///
void program::RpnFix() {
void Program::RpnFix() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -134,7 +134,7 @@ void program::RpnFix() {
/// @brief sci keyword implementation
///
void program::RpnSci() {
void Program::RpnSci() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -152,15 +152,15 @@ void program::RpnSci() {
/// @brief _version keyword implementation
///
void program::RpnVersion() { stack_.push_front(new String(RPN_VERSION)); }
void Program::RpnVersion() { stack_.push_front(new String(RPN_VERSION)); }
/// @brief _uname keyword implementation
///
void program::RpnUname() { stack_.push_front(new String(_uname)); }
void Program::RpnUname() { stack_.push_front(new String(_uname)); }
/// @brief history keyword implementation
///
void program::RpnHistory() {
void Program::RpnHistory() {
// see command history on stdout
int index = 0;
char* line = linenoiseHistoryLine(index);
@ -173,7 +173,7 @@ void program::RpnHistory() {
/// @brief type keyword implementation
///
void program::RpnType() {
void Program::RpnType() {
MIN_ARGUMENTS(1);
stack_.push(new String(stack_.at(0)->Name()));
stack_.erase(1);
@ -181,11 +181,11 @@ void program::RpnType() {
/// @brief default keyword implementation
///
void program::RpnDefault() { program::ApplyDefault(); }
void Program::RpnDefault() { Program::ApplyDefault(); }
/// @brief prec keyword implementation
///
void program::RpnPrecision() {
void Program::RpnPrecision() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -207,7 +207,7 @@ void program::RpnPrecision() {
/// @brief round keyword implementation
///
void program::RpnRound() {
void Program::RpnRound() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kString);

View file

@ -4,11 +4,11 @@
/// @brief e keyword implementation
///
void program::RpnE(void) { stack_.push(new Number(mpfr::const_euler())); }
void Program::RpnE(void) { stack_.push(new Number(mpfr::const_euler())); }
/// @brief log10 keyword implementation
///
void program::RpnLog10() {
void Program::RpnLog10() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = log10(stack_.value<Number>(0));
@ -20,7 +20,7 @@ void program::RpnLog10() {
/// @brief alog10 keyword implementation
///
void program::RpnAlog10() {
void Program::RpnAlog10() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = exp(log(mpreal(10)) * stack_.value<Number>(0));
@ -32,7 +32,7 @@ void program::RpnAlog10() {
/// @brief log2 keyword implementation
///
void program::RpnLog2() {
void Program::RpnLog2() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = log(stack_.value<Number>(0)) / mpfr::const_log2();
@ -44,7 +44,7 @@ void program::RpnLog2() {
/// @brief alog2 keyword implementation
///
void program::RpnAlog2() {
void Program::RpnAlog2() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = exp(mpfr::const_log2() * stack_.value<Number>(0));
@ -56,7 +56,7 @@ void program::RpnAlog2() {
/// @brief ln keyword implementation
///
void program::RpnLn() {
void Program::RpnLn() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = log(stack_.value<Number>(0));
@ -68,7 +68,7 @@ void program::RpnLn() {
/// @brief exp keyword implementation
///
void program::RpnExp() {
void Program::RpnExp() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = exp(stack_.value<Number>(0));
@ -80,7 +80,7 @@ void program::RpnExp() {
/// @brief expm keyword implementation
///
void program::RpnExpm() {
void Program::RpnExpm() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = exp(stack_.value<Number>(0)) - mpreal(1);
@ -92,7 +92,7 @@ void program::RpnExpm() {
/// @brief lnp1 keyword implementation
///
void program::RpnLnp1() {
void Program::RpnLnp1() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = log(stack_.value<Number>(0) + 1);
@ -104,7 +104,7 @@ void program::RpnLnp1() {
/// @brief sinh keyword implementation
///
void program::RpnSinh() {
void Program::RpnSinh() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = sinh(stack_.value<Number>(0));
@ -116,7 +116,7 @@ void program::RpnSinh() {
/// @brief asinh keyword implementation
///
void program::RpnAsinh() {
void Program::RpnAsinh() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = asinh(stack_.value<Number>(0));
@ -128,7 +128,7 @@ void program::RpnAsinh() {
/// @brief cosh keyword implementation
///
void program::RpnCosh() {
void Program::RpnCosh() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = cosh(stack_.value<Number>(0));
@ -140,7 +140,7 @@ void program::RpnCosh() {
/// @brief acosh keyword implementation
///
void program::RpnAcosh() {
void Program::RpnAcosh() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = acosh(stack_.value<Number>(0));
@ -152,7 +152,7 @@ void program::RpnAcosh() {
/// @brief tanh keyword implementation
///
void program::RpnTanh() {
void Program::RpnTanh() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = tanh(stack_.value<Number>(0));
@ -164,7 +164,7 @@ void program::RpnTanh() {
/// @brief atanh keyword implementation
///
void program::RpnAtanh() {
void Program::RpnAtanh() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = atanh(stack_.value<Number>(0));

View file

@ -9,9 +9,9 @@
/// @return true variable was found
/// @return false variable was not found
///
bool program::FindVariable(string& variable, Object*& obj) {
bool Program::FindVariable(string& variable, Object*& obj) {
bool found = false;
program* parent = parent_;
Program* parent = parent_;
if (local_heap_.get(variable, obj)) {
found = true;
@ -33,9 +33,9 @@ bool program::FindVariable(string& variable, Object*& obj) {
/// @brief eval keyword implementation
///
void program::RpnEval(void) {
void Program::RpnEval(void) {
bool run_prog = false;
string prog_text;
Program* prog = nullptr;
MIN_ARGUMENTS(1);
if (stack_.type(0) == kSymbol) {
@ -47,8 +47,8 @@ void program::RpnEval(void) {
// if variable holds a program, run this program
if (FindVariable(variable, obj)) {
if (obj->_type == kProgram) {
prog_text = stack_.value<Program>(0);
stack_.pop();
prog = reinterpret_cast<Program*>(stack_[0]);
stack_.erase(0, 1, false);
run_prog = true;
} else {
// else recall this variable (i.e. stack_ its content)
@ -59,28 +59,23 @@ void program::RpnEval(void) {
}
} else if (stack_.type(0) == kProgram) {
// eval a program
prog_text = stack_.value<Program>(0);
stack_.pop();
prog = reinterpret_cast<Program*>(stack_[0]);
stack_.erase(0, 1, false);
run_prog = true;
} else {
ERROR_CONTEXT(kBadOperandType);
}
// run prog if any
if (run_prog) {
program prog(stack_, heap_, this);
// make program from entry
if (prog.Parse(prog_text) == kOk) {
// run it
prog.Run();
}
if (run_prog && prog != nullptr) {
prog->Run();
delete prog;
}
}
/// @brief -> keyword (Branch) implementation
///
int program::RpnInprog(Branch& inprog_obj) {
int Program::RpnInprog(Branch& inprog_obj) {
string context("->"); // for showing errors
size_t count_symbols = 0;
bool prog_found = false;
@ -139,7 +134,7 @@ int program::RpnInprog(Branch& inprog_obj) {
// run the program
string& entry = reinterpret_cast<Program*>(at(inprog_obj.arg1 + count_symbols + 1))->value;
program prog(stack_, heap_, this);
Program prog(stack_, heap_, this);
// make the program from entry
if (prog.Parse(entry) == kOk) {

View file

@ -4,7 +4,7 @@
/// @brief + keyword implementation
///
void program::RpnPlus() {
void Program::RpnPlus() {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kString && stack_.type(1) == kString) {
stack_.value<String>(1) += stack_.value<String>(0);
@ -29,7 +29,7 @@ void program::RpnPlus() {
/// @brief - keyword implementation
///
void program::RpnMinus() {
void Program::RpnMinus() {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.value<Number>(1) -= stack_.value<Number>(0);
@ -51,7 +51,7 @@ void program::RpnMinus() {
/// @brief * keyword implementation
///
void program::RpnMul() {
void Program::RpnMul() {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.value<Number>(1) *= stack_.value<Number>(0);
@ -73,7 +73,7 @@ void program::RpnMul() {
/// @brief / keyword implementation
///
void program::RpnDiv() {
void Program::RpnDiv() {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.value<Number>(1) /= stack_.value<Number>(0);
@ -95,7 +95,7 @@ void program::RpnDiv() {
/// @brief neg keyword implementation
///
void program::RpnNeg() {
void Program::RpnNeg() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = -stack_.value<Number>(0);
@ -107,7 +107,7 @@ void program::RpnNeg() {
/// @brief inv keyword implementation
///
void program::RpnInv() {
void Program::RpnInv() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = 1 / stack_.value<Number>(0);
@ -119,7 +119,7 @@ void program::RpnInv() {
/// @brief power keyword implementation
///
void program::RpnPower() {
void Program::RpnPower() {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
if (stack_.value<Number>(1) >= 0) {
@ -148,7 +148,7 @@ void program::RpnPower() {
/// @brief sqrt keyword implementation
///
void program::RpnSquareroot() {
void Program::RpnSquareroot() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber) {
if (stack_.value<Number>(0) >= 0) {
@ -170,7 +170,7 @@ void program::RpnSquareroot() {
/// @brief hex keyword implementation
///
void program::RpnHex() {
void Program::RpnHex() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber) {
stack_.obj<Number>(0).base = 16;
@ -184,7 +184,7 @@ void program::RpnHex() {
/// @brief bin keyword implementation
///
void program::RpnBin() {
void Program::RpnBin() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber) {
stack_.obj<Number>(0).base = 2;
@ -198,7 +198,7 @@ void program::RpnBin() {
/// @brief dec keyword implementation
///
void program::RpnDec() {
void Program::RpnDec() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber) {
stack_.obj<Number>(0).base = 10;
@ -212,7 +212,7 @@ void program::RpnDec() {
/// @brief base keyword implementation
///
void program::RpnBase() {
void Program::RpnBase() {
MIN_ARGUMENTS(2);
if (stack_.type(1) == kNumber || stack_.type(1) == kComplex) {
int base = static_cast<int>(stack_.value<Number>(0).toLong());
@ -234,7 +234,7 @@ void program::RpnBase() {
/// @brief % (purcent) keyword implementation
///
void program::RpnPurcent() {
void Program::RpnPurcent() {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -244,7 +244,7 @@ void program::RpnPurcent() {
/// @brief %CH keyword implementation
///
void program::RpnPurcentCH() {
void Program::RpnPurcentCH() {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -254,7 +254,7 @@ void program::RpnPurcentCH() {
/// @brief sq keyword implementation
///
void program::RpnSquare() {
void Program::RpnSquare() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) *= stack_.value<Number>(0);
@ -266,7 +266,7 @@ void program::RpnSquare() {
/// @brief mod keyword implementation
///
void program::RpnModulo() {
void Program::RpnModulo() {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -276,7 +276,7 @@ void program::RpnModulo() {
/// @brief abs keyword implementation
///
void program::RpnAbs() {
void Program::RpnAbs() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber) {
stack_.value<Number>(0) = abs(stack_.value<Number>(0));
@ -290,7 +290,7 @@ void program::RpnAbs() {
/// @brief fact (factorial) keyword implementation
///
void program::RpnFact() {
void Program::RpnFact() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
// fact(n) = gamma(n+1)
@ -299,7 +299,7 @@ void program::RpnFact() {
/// @brief sign keyword implementation
///
void program::RpnSign() {
void Program::RpnSign() {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = sgn(stack_.value<Number>(0));
@ -311,7 +311,7 @@ void program::RpnSign() {
/// @brief mant keyword implementation
///
void program::RpnMant() {
void Program::RpnMant() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
if (!isfinite(stack_.value<Number>(0))) {
@ -324,7 +324,7 @@ void program::RpnMant() {
/// @brief xpon keyword implementation
///
void program::RpnXpon() {
void Program::RpnXpon() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
if (!isfinite(stack_.value<Number>(0))) {
@ -338,7 +338,7 @@ void program::RpnXpon() {
/// @brief floor keyword implementation
///
void program::RpnFloor() {
void Program::RpnFloor() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
stack_.value<Number>(0) = floor(stack_.value<Number>(0));
@ -346,7 +346,7 @@ void program::RpnFloor() {
/// @brief ceil keyword implementation
///
void program::RpnCeil() {
void Program::RpnCeil() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
stack_.value<Number>(0) = ceil(stack_.value<Number>(0));
@ -354,7 +354,7 @@ void program::RpnCeil() {
/// @brief fp keyword implementation
///
void program::RpnFp() {
void Program::RpnFp() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
stack_.value<Number>(0) = frac(stack_.value<Number>(0));
@ -362,7 +362,7 @@ void program::RpnFp() {
/// @brief ip keyword implementation
///
void program::RpnIp() {
void Program::RpnIp() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
stack_.value<Number>(0) = trunc(stack_.value<Number>(0));
@ -370,7 +370,7 @@ void program::RpnIp() {
/// @brief min keyword implementation
///
void program::RpnMin() {
void Program::RpnMin() {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -380,7 +380,7 @@ void program::RpnMin() {
/// @brief max keyword implementation
///
void program::RpnMax() {
void Program::RpnMax() {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);

View file

@ -4,7 +4,7 @@
/// @brief swap keyword implementation
///
void program::RpnSwap(void) {
void Program::RpnSwap(void) {
MIN_ARGUMENTS(2);
Object* tmp = stack_.front();
stack_.erase(0, 1, false);
@ -13,21 +13,21 @@ void program::RpnSwap(void) {
/// @brief drop keyword implementation
///
void program::RpnDrop(void) {
void Program::RpnDrop(void) {
MIN_ARGUMENTS(1);
stack_.pop();
}
/// @brief drop2 keyword implementation
///
void program::RpnDrop2(void) {
void Program::RpnDrop2(void) {
MIN_ARGUMENTS(2);
stack_.erase(0, 2);
}
/// @brief dropn keyword implementation
///
void program::RpnDropn(void) {
void Program::RpnDropn(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -38,18 +38,18 @@ void program::RpnDropn(void) {
/// @brief erase / del keyword implementation
///
void program::RpnErase(void) { stack_.erase(0, stack_.size()); }
void Program::RpnErase(void) { stack_.erase(0, stack_.size()); }
/// @brief dup keyword implementation
///
void program::RpnDup(void) {
void Program::RpnDup(void) {
MIN_ARGUMENTS(1);
stack_.push_front(stack_.at(0)->Clone());
}
/// @brief dupn keyword implementation
///
void program::RpnDupn(void) {
void Program::RpnDupn(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -66,7 +66,7 @@ void program::RpnDupn(void) {
/// @brief dup2 keyword implementation
///
void program::RpnDup2(void) {
void Program::RpnDup2(void) {
MIN_ARGUMENTS(2);
stack_.push_front(stack_.at(1)->Clone());
stack_.push_front(stack_.at(1)->Clone());
@ -74,7 +74,7 @@ void program::RpnDup2(void) {
/// @brief pick keyword implementation
///
void program::RpnPick(void) {
void Program::RpnPick(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -92,7 +92,7 @@ void program::RpnPick(void) {
/// @brief rot keyword implementation
///
void program::RpnRot(void) {
void Program::RpnRot(void) {
MIN_ARGUMENTS(3);
Object* tmp = stack_.at(2);
stack_.erase(2, 1, false);
@ -101,11 +101,11 @@ void program::RpnRot(void) {
/// @brief depth keyword implementation
///
void program::RpnDepth(void) { stack_.push_front(new Number(stack_.size())); }
void Program::RpnDepth(void) { stack_.push_front(new Number(stack_.size())); }
/// @brief roll keyword implementation
///
void program::RpnRoll(void) {
void Program::RpnRoll(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -124,7 +124,7 @@ void program::RpnRoll(void) {
/// @brief rolld keyword implementation
///
void program::RpnRolld(void) {
void Program::RpnRolld(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -143,7 +143,7 @@ void program::RpnRolld(void) {
/// @brief over keyword implementation
///
void program::RpnOver(void) {
void Program::RpnOver(void) {
MIN_ARGUMENTS(2);
stack_.push_front(stack_.at(1)->Clone());
}

View file

@ -5,7 +5,7 @@
/// @brief sto keyword implementation
///
void program::RpnSto(void) {
void Program::RpnSto(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
@ -21,7 +21,7 @@ void program::RpnSto(void) {
/// @brief sto+ keyword implementation
///
void program::RpnStoadd(void) {
void Program::RpnStoadd(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
if (heap_.find(stack_.value<String>(0)) == heap_.end()) {
@ -38,7 +38,7 @@ void program::RpnStoadd(void) {
/// @brief sto- keyword implementation
///
void program::RpnStosub(void) {
void Program::RpnStosub(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
if (heap_.find(stack_.value<String>(0)) == heap_.end()) {
@ -55,7 +55,7 @@ void program::RpnStosub(void) {
/// @brief sto* keyword implementation
///
void program::RpnStomul(void) {
void Program::RpnStomul(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
if (heap_.find(stack_.value<String>(0)) == heap_.end()) {
@ -72,7 +72,7 @@ void program::RpnStomul(void) {
/// @brief sto/ keyword implementation
///
void program::RpnStodiv(void) {
void Program::RpnStodiv(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
if (heap_.find(stack_.value<String>(0)) == heap_.end()) {
@ -89,7 +89,7 @@ void program::RpnStodiv(void) {
/// @brief stosneg keyword implementation
///
void program::RpnStoneg(void) {
void Program::RpnStoneg(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
if (heap_.find(stack_.value<String>(0)) == heap_.end()) {
@ -105,7 +105,7 @@ void program::RpnStoneg(void) {
/// @brief sinv keyword implementation
///
void program::RpnStoinv(void) {
void Program::RpnStoinv(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
if (heap_.find(stack_.value<String>(0)) == heap_.end()) {
@ -121,7 +121,7 @@ void program::RpnStoinv(void) {
/// @brief rcl keyword implementation
///
void program::RpnRcl(void) {
void Program::RpnRcl(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
@ -140,7 +140,7 @@ void program::RpnRcl(void) {
/// @brief edit keyword implementation
///
void program::RpnEdit(void) {
void Program::RpnEdit(void) {
MIN_ARGUMENTS(1);
ostringstream st;
@ -157,7 +157,7 @@ void program::RpnEdit(void) {
///
/// @param symb the smlbol to recall and autoeval
///
void program::AutoRcl(Symbol* symb) {
void Program::AutoRcl(Symbol* symb) {
if (symb->auto_eval) {
Object* obj;
string variable(symb->value);
@ -167,7 +167,10 @@ void program::AutoRcl(Symbol* symb) {
stack_.push_front(obj->Clone());
if (obj->_type == kProgram) RpnEval();
} else {
stack_.push_front(symb->Clone());
// not found, keep it as a simple symbol
Symbol* s = reinterpret_cast<Symbol*>(symb->Clone());
s->auto_eval = false;
stack_.push_front(s);
}
} else {
stack_.push_front(symb->Clone());
@ -176,7 +179,7 @@ void program::AutoRcl(Symbol* symb) {
/// @brief purge keyword implementation
///
void program::RpnPurge(void) {
void Program::RpnPurge(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kSymbol);
@ -192,8 +195,8 @@ void program::RpnPurge(void) {
/// @brief vars keyword implementation
///
void program::RpnVars(void) {
program* parent = parent_;
void Program::RpnVars(void) {
Program* parent = parent_;
string name;
int index = 1;
@ -221,4 +224,4 @@ void program::RpnVars(void) {
/// @brief clusr keyword implementation
///
void program::RpnClusr(void) { heap_.clear(); }
void Program::RpnClusr(void) { heap_.clear(); }

View file

@ -6,7 +6,7 @@
/// @brief ->str keyword implementation
///
void program::RpnInstr() {
void Program::RpnInstr() {
MIN_ARGUMENTS(1);
// stringify only if not already a string
@ -20,12 +20,12 @@ void program::RpnInstr() {
/// @brief str-> keyword implementation
///
void program::RpnStrout() {
void Program::RpnStrout() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kString);
string entry(stack_.value<String>(0));
program prog(stack_, heap_);
Program prog(stack_, heap_);
stack_.pop();
// make program from string in stack_ level 1
@ -36,7 +36,7 @@ void program::RpnStrout() {
/// @brief chr keyword implementation
///
void program::RpnChr() {
void Program::RpnChr() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
char the_chr = static_cast<char>(stack_.value<Number>(0).toLong());
@ -47,7 +47,7 @@ void program::RpnChr() {
/// @brief num keyword implementation
///
void program::RpnNum() {
void Program::RpnNum() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kString);
if (stack_.value<String>(0).size() > 0)
@ -59,7 +59,7 @@ void program::RpnNum() {
/// @brief size keyword implementation
///
void program::RpnStrsize() {
void Program::RpnStrsize() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kString);
stack_.push_front(new Number(stack_.value<String>(0).size()));
@ -68,7 +68,7 @@ void program::RpnStrsize() {
/// @brief pos keyword implementation
///
void program::RpnStrpos() {
void Program::RpnStrpos() {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kString);
ARG_MUST_BE_OF_TYPE(1, kString);
@ -80,7 +80,7 @@ void program::RpnStrpos() {
/// @brief sub keyword implementation
///
void program::RpnStrsub() {
void Program::RpnStrsub() {
MIN_ARGUMENTS(3);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);

View file

@ -67,7 +67,7 @@ static void ShowTestResult(string title, int tests, int tests_failed, int steps,
/// @brief test keyword implementation
///
void program::RpnTest() {
void Program::RpnTest() {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kString);
@ -97,8 +97,8 @@ void program::RpnTest() {
/// @param total_steps the total steps nb
/// @param total_steps_failed the total failed steps nb
///
void program::RunTestFile(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps,
int& total_steps_failed) {
void Program::RunTestFile(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps,
int& total_steps_failed) {
const string stack_size("-> stack size should be ");
const string stack_value("-> stack should be ");
const string cmd_error("-> error should be ");
@ -244,13 +244,10 @@ void program::RunTestFile(string test_filename, int& total_tests, int& total_tes
// parse entry and run line
FindAndReplaceAll(entry, "`", "");
if (!entry.empty()) {
program prog(stk, hp);
Program prog(stk, hp);
ret = prog.Parse(entry);
if (ret == kOk) {
// run it
(void)prog.Run();
last_err = static_cast<int>(prog.GetLastError());
}
if (ret == kOk) (void)prog.Run();
last_err = static_cast<int>(prog.GetLastError());
}
}
}

View file

@ -17,7 +17,7 @@ static int CmpStringOnStackTop(rpnstack& stk) {
/// @brief > keyword implementation
///
void program::RpnSup(void) {
void Program::RpnSup(void) {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.push_front(new Number(stack_.value<Number>(1) > stack_.value<Number>(0)));
@ -32,7 +32,7 @@ void program::RpnSup(void) {
/// @brief >= keyword implementation
///
void program::RpnSupEq(void) {
void Program::RpnSupEq(void) {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.push_front(new Number(stack_.value<Number>(1) >= stack_.value<Number>(0)));
@ -47,7 +47,7 @@ void program::RpnSupEq(void) {
/// @brief < keyword implementation
///
void program::RpnInf(void) {
void Program::RpnInf(void) {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
@ -63,7 +63,7 @@ void program::RpnInf(void) {
/// @brief <= keyword implementation
///
void program::RpnInfEq(void) {
void Program::RpnInfEq(void) {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.push_front(new Number(stack_.value<Number>(1) <= stack_.value<Number>(0)));
@ -78,7 +78,7 @@ void program::RpnInfEq(void) {
/// @brief != keyword implementation
///
void program::RpnDiff(void) {
void Program::RpnDiff(void) {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.push_front(new Number(stack_.value<Number>(1) != stack_.value<Number>(0)));
@ -96,7 +96,7 @@ void program::RpnDiff(void) {
/// @brief == keyword implementation
///
void program::RpnEq(void) {
void Program::RpnEq(void) {
MIN_ARGUMENTS(2);
if (stack_.type(0) == kNumber && stack_.type(1) == kNumber) {
stack_.push_front(new Number(stack_.value<Number>(1) == stack_.value<Number>(0)));
@ -114,7 +114,7 @@ void program::RpnEq(void) {
/// @brief and keyword implementation
///
void program::RpnTestAnd(void) {
void Program::RpnTestAnd(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -127,7 +127,7 @@ void program::RpnTestAnd(void) {
/// @brief or keyword implementation
///
void program::RpnTestOr(void) {
void Program::RpnTestOr(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -140,7 +140,7 @@ void program::RpnTestOr(void) {
/// @brief xor keyword implementation
///
void program::RpnTestXor(void) {
void Program::RpnTestXor(void) {
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, kNumber);
ARG_MUST_BE_OF_TYPE(1, kNumber);
@ -153,7 +153,7 @@ void program::RpnTestXor(void) {
/// @brief not keyword implementation
///
void program::RpnTestNot(void) {
void Program::RpnTestNot(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
@ -163,4 +163,4 @@ void program::RpnTestNot(void) {
/// @brief test same implementation
///
void program::RpnSame(void) { RpnEq(); }
void Program::RpnSame(void) { RpnEq(); }

View file

@ -8,7 +8,7 @@ using namespace std::chrono;
/// @brief time keyword implementation
///
void program::RpnTime() {
void Program::RpnTime() {
std::time_t rawtime = system_clock::to_time_t(system_clock::now());
struct tm tm;
@ -26,7 +26,7 @@ void program::RpnTime() {
/// @brief date keyword implementation
///
void program::RpnDate() {
void Program::RpnDate() {
std::time_t rawtime = system_clock::to_time_t(system_clock::now());
struct tm tm;
@ -44,7 +44,7 @@ void program::RpnDate() {
/// @brief ticks keyword implementation
///
void program::RpnTicks() {
void Program::RpnTicks() {
uint64_t time_span = (uint64_t)duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count();
stack_.push(new Number(time_span));
}

View file

@ -4,13 +4,13 @@
/// @brief pi keyword implementation
///
void program::RpnPi(void) {
void Program::RpnPi(void) {
stack_.push_front(new Number(mpfr::const_pi()));
}
/// @brief d->r keyword implementation
///
void program::RpnD2r(void) {
void Program::RpnD2r(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
stack_.value<Number>(0) *= mpfr::const_pi();
@ -19,7 +19,7 @@ void program::RpnD2r(void) {
/// @brief r->d keyword implementation
///
void program::RpnR2d(void) {
void Program::RpnR2d(void) {
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, kNumber);
stack_.value<Number>(0) /= mpfr::const_pi();
@ -28,7 +28,7 @@ void program::RpnR2d(void) {
/// @brief sin keyword implementation
///
void program::RpnSin(void) {
void Program::RpnSin(void) {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = sin(stack_.value<Number>(0));
@ -40,7 +40,7 @@ void program::RpnSin(void) {
/// @brief asin keyword implementation
///
void program::RpnAsin(void) {
void Program::RpnAsin(void) {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = asin(stack_.value<Number>(0));
@ -52,7 +52,7 @@ void program::RpnAsin(void) {
/// @brief cos keyword implementation
///
void program::RpnCos(void) {
void Program::RpnCos(void) {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = cos(stack_.value<Number>(0));
@ -64,7 +64,7 @@ void program::RpnCos(void) {
/// @brief acos keyword implementation
///
void program::RpnAcos(void) {
void Program::RpnAcos(void) {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = acos(stack_.value<Number>(0));
@ -76,7 +76,7 @@ void program::RpnAcos(void) {
/// @brief tan keyword implementation
///
void program::RpnTan(void) {
void Program::RpnTan(void) {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = tan(stack_.value<Number>(0));
@ -88,7 +88,7 @@ void program::RpnTan(void) {
/// @brief atan keyword implementation
///
void program::RpnAtan(void) {
void Program::RpnAtan(void) {
MIN_ARGUMENTS(1);
if (stack_.type(0) == kNumber)
stack_.value<Number>(0) = atan(stack_.value<Number>(0));

View file

@ -14,7 +14,7 @@
`<< I am a program >>`
-> stack should be «I am a program»
-> stack should be « I am a program »
`del`
@ -22,7 +22,7 @@
`<<I am a program>>`
-> stack should be «I am a program»
-> stack should be « I am a program »
`del`
@ -30,7 +30,7 @@
`<< I am a program >>`
-> stack should be «I am a program»
-> stack should be « I am a program »
`del`
@ -38,7 +38,7 @@
`«I am a program»`
-> stack should be «I am a program»
-> stack should be « I am a program »
`del`
@ -46,7 +46,7 @@
`« I am a program »`
-> stack should be «I am a program»
-> stack should be « I am a program »
`del`
@ -54,7 +54,7 @@
`<< prog`
-> stack should be «prog»
-> stack should be « prog »
`del`
@ -62,7 +62,7 @@
`« prog`
-> stack should be «prog»
-> stack should be « prog »
`del`
@ -70,7 +70,7 @@
`<< prog>`
-> stack should be «prog>»
-> stack should be « prog> »
`del`
@ -81,6 +81,6 @@
«
```
-> stack should be «», «»
-> stack should be « », « »
`del`

View file

@ -288,7 +288,7 @@
`1 2 start «ok» next`
-> stack should be «ok», «ok»
-> stack should be « ok », « ok »
`del`

View file

@ -136,7 +136,7 @@
`"<< -> n << n >> >>" str->`
-> stack should be «-> n << n >>»
-> stack should be « -> n « n » »
`del`

View file

@ -8,7 +8,7 @@
-> stack size should be 1
-> stack should be «'one'»
-> stack should be « 'one' »
`del`
@ -18,7 +18,7 @@
-> stack size should be 1
-> stack should be «'one' 2»
-> stack should be « 'one' 2 »
`del`
@ -28,7 +28,7 @@
-> stack size should be 1
-> stack should be «»
-> stack should be « »
`del`
@ -38,7 +38,7 @@
-> stack size should be 1
-> stack should be «<< << <<»
-> stack should be « « « « » » » »
`del`
@ -48,7 +48,7 @@
-> stack size should be 1
-> stack should be «-> n << n 2 * >>»
-> stack should be « -> n « n 2 * » »
`del`
@ -56,7 +56,7 @@
`<< 1 << 2 >> >>`
-> stack should be «1 << 2 >>»
-> stack should be « 1 « 2 » »
`del`
@ -64,7 +64,7 @@
`<< 1 << 2 >> >> dup eval`
-> stack should be «1 << 2 >>», 1, «2»
-> stack should be « 1 « 2 » », 1, « 2 »
`del`