mirror of
https://github.com/louisrubet/rpn
synced 2025-02-01 07:57:52 +01:00
Merge pull request #226 from louisrubet/#218/stack_heap_refactoring
Code refactoring - mpreal, md tests, std allocation
This commit is contained in:
commit
d590642a6c
71 changed files with 6960 additions and 6541 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -22,5 +22,9 @@
|
|||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# editors garbage
|
||||
# Tools workfiles
|
||||
*~
|
||||
.scannerwork/*
|
||||
*bw-output*/*
|
||||
.vscode/*
|
||||
build/*
|
||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
|||
[submodule "linenoise-ng"]
|
||||
path = linenoise-ng
|
||||
url = git@github.com:louisrubet/linenoise-ng.git
|
||||
[submodule "mpreal"]
|
||||
path = mpreal
|
||||
url = https://github.com/advanpix/mpreal
|
||||
|
|
|
@ -24,7 +24,8 @@ set(RPN_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
|
|||
# compiler options
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
message(STATUS "Compiler type GNU: ${CMAKE_CXX_COMPILER}")
|
||||
set(BASE_COMPILER_OPTIONS "-std=c++0x -Wl,--no-as-needed")
|
||||
# TODO still up to date?
|
||||
set(BASE_COMPILER_OPTIONS "-std=c++14 -Wl,--no-as-needed")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILER_OPTIONS}")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${BASE_COMPILER_OPTIONS} -O0 -g")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${BASE_COMPILER_OPTIONS} -O3 -fomit-frame-pointer -s")
|
||||
|
@ -37,16 +38,25 @@ if(NOT EXISTS "${PROJECT_SOURCE_DIR}/linenoise-ng/.git")
|
|||
execute_process(COMMAND git checkout v1.1.1-rpn WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/linenoise-ng)
|
||||
endif()
|
||||
|
||||
# custom mpreal
|
||||
if(NOT EXISTS "${PROJECT_SOURCE_DIR}/mpreal/.git")
|
||||
execute_process(COMMAND git submodule init ${PROJECT_SOURCE_DIR}/mpreal)
|
||||
execute_process(COMMAND git submodule update ${PROJECT_SOURCE_DIR}/mpreal)
|
||||
execute_process(COMMAND git checkout mpfrc++-3.6.9 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/mpreal)
|
||||
endif()
|
||||
|
||||
# includes
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/linenoise-ng/include)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/linenoise-ng/include ${PROJECT_SOURCE_DIR}/mpreal)
|
||||
|
||||
# build
|
||||
add_executable(
|
||||
rpn
|
||||
${PROJECT_SOURCE_DIR}/src/main.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/object.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mpreal-out.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/program.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/parse.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/lexer.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/input.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-branch.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-complex.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-general.cpp
|
||||
|
@ -57,7 +67,7 @@ add_executable(
|
|||
${PROJECT_SOURCE_DIR}/src/rpn-store.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-string.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-test.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-test-core.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-test-framework.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-time.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/rpn-trig.cpp
|
||||
${PROJECT_SOURCE_DIR}/linenoise-ng/src/ConvertUTF.cpp
|
||||
|
|
45
Changelog.md
Normal file
45
Changelog.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
Changelog
|
||||
|
||||
- Better parser (now called lexer)
|
||||
- Use of mpreal instead of raw mpfr for calc on reals
|
||||
- Use of C++ complex class
|
||||
- Removing old memory management, efficient but poorly maintainable
|
||||
- Enhanced code quality and memory usage checks
|
||||
- Added CircleCI checks: passing functional tests and valgrind mem checks at each pull request
|
||||
- SonarCloud integration, Sonar way profile
|
||||
- clang-format now based on google style
|
||||
- [google c++ style guide](https://google.github.io/styleguide/cppguide.html) applied
|
||||
- Test files are now markdown (.md) files, tests result are slightly changed
|
||||
- Delivery as flatpak and snap
|
||||
- it seems cosh was giving sinh (!)
|
||||
|
||||
grosse perte en performances (!)
|
||||
- v2.3.2 fibo: 0,01s user 0,01s system 97% cpu 0,017 total
|
||||
- v3.0.0 fibo: 2,60s user 0,00s system 99% cpu 2,611 total
|
||||
- facteur 150 environ
|
||||
cf https://gmplib.org/manual/Custom-Allocation
|
||||
cf https://www.geeksforgeeks.org/overloading-new-delete-operator-c/
|
||||
|
||||
New
|
||||
- `«` and `»` are now valid as program delimiters. `<<` and `>>` are still valid
|
||||
- entering the sign after the base (ex: 0x-1e2) is allowed
|
||||
- rpn is delivered as flatpak and snap packages to be compatible with a maximum of Linux distribs. rpm and deb are no longer generated
|
||||
|
||||
Compatibility is broken on these points
|
||||
- `<< <<` input doesn't lead to `««»»` but to `«<< »`, preventing to eval the real program content
|
||||
- `1 2+` not allowed anymore, keep `1 2 +`, this corrects bad behaviors like `3b114` pushing `3b11` and `4`
|
||||
- complexes are written in the form `(1,2)` instead of `(1, 2)` (space is removed)
|
||||
- removed useless `unti`, `repea`, `whil` (prev.existing for HP28S compatibility)
|
||||
- removed `sqr` function, please use `sq` instead (prev.existing for HP28S compatibility)
|
||||
- the binary prefix is always 0b on display, but still can be 0b, 0B, 2b or 2B at input
|
||||
- the hex prefix is always 0x on display, but still can be 0x, 0X or 16B at input
|
||||
- `mant` and `xpon` now give binary (and not decimal) significand and exponent, as it is the norm in standard libs (libC, standard C++, mpfr, gmp)
|
||||
- `dupn`, `roll`, `rolld` are not leaving anymore their argument in front of the stack in case of error
|
||||
- `sto+` `sto-` `sto*` `sto/` don't accept anymore the syntax `'varname' value stoX`, but only `value 'varname' stoX`, ex: `3 'a' sto*`
|
||||
- incomplete entry `(1,` is not available anymore
|
||||
- signed zero is the sign of zero is subject to change compared to previous version, for example `-3 sqrt` now equals `(0.000000,1.732051)` instead of `(-0.000000,1.732051)`
|
||||
|
||||
Debug
|
||||
- `sub` now only accepts boundaries between 1 and the string length
|
||||
- `sto/` behavior: sto/ now correctly stores variable / constant and not constant / variable
|
||||
- `cosh` now returns the hyp cosinus instead of the hyp sinus (!)
|
6
TODO.md
Normal file
6
TODO.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
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
mpreal
Submodule
1
mpreal
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit c45d0d522c9bd0dd16d7aac25fa0862dd074ddb0
|
|
@ -1,3 +1,9 @@
|
|||
BasedOnStyle: Google
|
||||
IndentWidth: '4'
|
||||
ColumnLimit: 120
|
||||
---
|
||||
BasedOnStyle: google
|
||||
IndentWidth: 4
|
||||
---
|
||||
Language: Cpp
|
||||
# Force pointers to the type for C++.
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
ColumnLimit: 120
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef CONSTANT_H
|
||||
#define CONSTANT_H
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
|
||||
// default values
|
||||
|
@ -9,7 +10,6 @@
|
|||
// default mode and number of printed digits
|
||||
//
|
||||
#define DEFAULT_MODE number::std
|
||||
#define MPFR_DEFAULT_FORMAT "%.xxRg"
|
||||
|
||||
/* directly calculated from 128 bits precision
|
||||
ceil(128 * log10(2)) - 1 = 38 */
|
||||
|
@ -18,36 +18,9 @@
|
|||
// MPFR related defaults
|
||||
//
|
||||
|
||||
// rounding method
|
||||
#define MPFR_DEFAULT_RND MPFR_RNDN
|
||||
|
||||
// 128 bits significand precision
|
||||
#define MPFR_DEFAULT_PREC_BITS 128
|
||||
|
||||
// 128 bits significand storing length in bytes, result of
|
||||
// mpfr_custom_get_size(128)
|
||||
#define MPFR_DEFAULT_STORING_LENGTH_BYTES 16
|
||||
|
||||
// constants
|
||||
//
|
||||
|
||||
// commands and entry related constants
|
||||
#define MAX_COMMAND_LENGTH 24
|
||||
#define AUTOCOMPLETE_KEY '\t'
|
||||
#define SHOW_STACK_SEPARATOR "> "
|
||||
#define PROMPT "rpn> "
|
||||
#define MULTILINE_PROMPT "> "
|
||||
|
||||
// show formats
|
||||
#define MPFR_FORMAT_BEG "%."
|
||||
#define MPFR_FORMAT_STD "Rg"
|
||||
#define MPFR_FORMAT_FIX "Rf"
|
||||
#define MPFR_FORMAT_SCI "Re"
|
||||
#define MPFR_FORMAT_HEX "%Ra"
|
||||
|
||||
#define MPFR_RND_STRINGS \
|
||||
{ "nearest", "toward zero", "toward +inf", "toward -inf", "away from zero" }
|
||||
|
||||
// return values, used by all classes
|
||||
//
|
||||
typedef enum {
|
||||
|
@ -66,58 +39,13 @@ typedef enum {
|
|||
ret_div_by_zero,
|
||||
ret_runtime_error,
|
||||
ret_abort_current_entry,
|
||||
ret_out_of_memory,
|
||||
ret_bad_value,
|
||||
ret_max
|
||||
} ret_value;
|
||||
|
||||
#define RET_VALUE_STRINGS \
|
||||
{ \
|
||||
"ok", "unknown command", "missing operand", "bad operand type", "out of range", "unknown variable", \
|
||||
"internal error, aborting", "deadly", "goodbye", "not implemented", "no operation", "syntax error", \
|
||||
"division by zero", "runtime error", "aborted current entry" \
|
||||
}
|
||||
|
||||
// command types
|
||||
//
|
||||
#define CMD_TYPE_STRINGS \
|
||||
{ "undef", "number", "complex", "string", "symbol", "program", "keyword", "keyword" }
|
||||
|
||||
// history
|
||||
#define HISTORY_FILE ".rpn_history"
|
||||
#define HISTORY_FILE_MAX_LINES (100)
|
||||
|
||||
// base min and max
|
||||
#define BASE_MIN 2
|
||||
#define BASE_MAX 62
|
||||
|
||||
// some defs for mpfr
|
||||
#if _MPFR_EXP_FORMAT == 1
|
||||
#define MPFR_EXP_MAX (SHRT_MAX)
|
||||
#define MPFR_EXP_MIN (SHRT_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 2
|
||||
#define MPFR_EXP_MAX (INT_MAX)
|
||||
#define MPFR_EXP_MIN (INT_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 3
|
||||
#define MPFR_EXP_MAX (LONG_MAX)
|
||||
#define MPFR_EXP_MIN (LONG_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 4
|
||||
#define MPFR_EXP_MAX (MPFR_INTMAX_MAX)
|
||||
#define MPFR_EXP_MIN (MPFR_INTMAX_MIN)
|
||||
#else
|
||||
#error "Invalid MPFR Exp format"
|
||||
#endif
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(h, i) ((h) > (i) ? (h) : (i))
|
||||
|
||||
#define MPFR_EXP_INF (MPFR_EXP_MIN + 3)
|
||||
#define MPFR_EXP_NAN (MPFR_EXP_MIN + 2)
|
||||
#define MPFR_EXP(x) ((x)->_mpfr_exp)
|
||||
#define MPFR_IS_SINGULAR(x) (MPFR_EXP(x) <= MPFR_EXP_INF)
|
||||
#define MPFR_UNLIKELY(x) (__builtin_expect(!!(x), 0))
|
||||
#define MPFR_IS_NAN(x) (MPFR_EXP(x) == MPFR_EXP_NAN)
|
||||
#define MPFR_IS_INF(x) (MPFR_EXP(x) == MPFR_EXP_INF)
|
||||
#define MPFR_IS_NEG(x) (MPFR_SIGN(x) < 0)
|
||||
#define MPFR_IS_POS(x) (MPFR_SIGN(x) > 0)
|
||||
#define MPFR_PREC(x) ((x)->_mpfr_prec)
|
||||
|
||||
#endif
|
||||
|
|
88
src/debug.h
88
src/debug.h
|
@ -1,88 +0,0 @@
|
|||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void dump8(unsigned char* to_dump, unsigned long offset, unsigned long size) {
|
||||
const int block_size = 1;
|
||||
const int block_per_line = 16;
|
||||
int max_line = size / block_size;
|
||||
unsigned char mychar;
|
||||
int i;
|
||||
int j;
|
||||
for (i = 0; i < max_line; i++) {
|
||||
if ((i % block_per_line) == 0) {
|
||||
if (i > 0) {
|
||||
printf(" ");
|
||||
for (j = i - block_per_line; j < i; j++) {
|
||||
mychar = *(to_dump + j);
|
||||
if ((mychar < 32) || (mychar >= 127)) mychar = '.';
|
||||
printf("%c", mychar);
|
||||
}
|
||||
}
|
||||
printf("\n%08lX:", offset + i * block_size);
|
||||
}
|
||||
printf(" %02hhX", *(to_dump + i));
|
||||
}
|
||||
if (i > 0) {
|
||||
printf(" ");
|
||||
for (j = (i >= block_per_line) ? (i - block_per_line) : 0; j < i; j++) {
|
||||
mychar = *(to_dump + j);
|
||||
if ((mychar < 32) || (mychar >= 127)) mychar = '.';
|
||||
printf("%c", mychar);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//
|
||||
#define TRACE(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
// chrono
|
||||
#include <time.h>
|
||||
|
||||
static int chrono_next = 0;
|
||||
static struct {
|
||||
struct timespec ts_point;
|
||||
char comment[256];
|
||||
} chrono_point[24];
|
||||
|
||||
static void chrono_start() {
|
||||
clock_gettime(CLOCK_REALTIME, &chrono_point[0].ts_point);
|
||||
strcpy(chrono_point[0].comment, "START");
|
||||
chrono_next = 1;
|
||||
}
|
||||
|
||||
static void chrono_add(const char* comment) {
|
||||
clock_gettime(CLOCK_REALTIME, &chrono_point[chrono_next].ts_point);
|
||||
strcpy(chrono_point[chrono_next].comment, comment);
|
||||
chrono_next++;
|
||||
}
|
||||
|
||||
static uint64_t chrono_diff_us(struct timespec* ts_from, struct timespec* ts_to) {
|
||||
uint64_t from = (uint64_t)ts_from->tv_sec * 1000000UL + ((uint64_t)ts_from->tv_nsec) / 1000UL;
|
||||
uint64_t to = (uint64_t)ts_to->tv_sec * 1000000UL + ((uint64_t)ts_to->tv_nsec) / 1000UL;
|
||||
return to - from;
|
||||
}
|
||||
|
||||
static void chrono_all_print(void) {
|
||||
for (int i = 1; i < chrono_next; i++) {
|
||||
printf("CHRONO [%lu us] %s\n", chrono_diff_us(&chrono_point[i - 1].ts_point, &chrono_point[i].ts_point),
|
||||
chrono_point[i].comment);
|
||||
}
|
||||
}
|
||||
|
||||
static void chrono_print(int chrono) {
|
||||
if (chrono >= 1) {
|
||||
printf("CHRONO [%lu us] %s\n",
|
||||
chrono_diff_us(&chrono_point[chrono - 1].ts_point, &chrono_point[chrono].ts_point),
|
||||
chrono_point[chrono].comment);
|
||||
}
|
||||
}
|
||||
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#endif
|
19
src/escape.h
19
src/escape.h
|
@ -7,31 +7,12 @@
|
|||
#define FG_BLACK "\33[30m"
|
||||
#define FG_RED "\33[31m"
|
||||
#define FG_GREEN "\33[32m"
|
||||
#define FG_YELLOW "\33[33m"
|
||||
#define FG_BLUE "\33[34m"
|
||||
#define FG_MAJENTA "\33[35m"
|
||||
#define FG_CYAN "\33[36m"
|
||||
#define FG_WHITE "\33[37m"
|
||||
|
||||
// background colors
|
||||
#define BG_BLACK "\33[40m"
|
||||
#define BG_RED "\33[41m"
|
||||
#define BG_GREEN "\33[42m"
|
||||
#define BG_YELLOW "\33[43m"
|
||||
#define BG_BLUE "\33[44m"
|
||||
#define BG_MAJENTA "\33[45m"
|
||||
#define BG_CYAN "\33[46m"
|
||||
#define BG_WHITE "\33[47m"
|
||||
|
||||
#define COLOR_OFF "\33[m"
|
||||
|
||||
// attributes
|
||||
#define ATTR_BOLD "\33[1m"
|
||||
#define ATTR_UNDERSCORE "\33[4m"
|
||||
#define ATTR_BLINK "\33[5m"
|
||||
#define ATTR_REVERSE "\33[7m"
|
||||
#define ATTR_CONCEALED "\33[8m"
|
||||
|
||||
#define ATTR_OFF "\33[0m"
|
||||
|
||||
#endif
|
||||
|
|
219
src/lexer.cpp
Normal file
219
src/lexer.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
#include <regex>
|
||||
using namespace std;
|
||||
|
||||
#include "lexer.hpp"
|
||||
|
||||
bool Lexer::lexer(string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
|
||||
vector<SynError>& errors) {
|
||||
size_t jump;
|
||||
for (size_t i = 0; i < entry.size(); i++) {
|
||||
if (isspace(entry[i])) continue;
|
||||
SynElement element;
|
||||
switch (entry[i]) {
|
||||
case '"':
|
||||
if (!parseString(entry, i, jump, errors, elements)) return false;
|
||||
i = jump - 1;
|
||||
continue;
|
||||
case '\'':
|
||||
if (!parseSymbol(entry, i, jump, errors, elements)) return false;
|
||||
i = jump - 1;
|
||||
continue;
|
||||
case '(':
|
||||
if (!parseComplex(entry, i, jump, errors, elements)) return false;
|
||||
i = jump - 1;
|
||||
continue;
|
||||
}
|
||||
if (i < entry.size() - 1 && (entry.substr(i, 2) == "<<" || entry.substr(i, 2) == "«")) {
|
||||
if (!parseProgram(entry, i, jump, errors, elements)) return false;
|
||||
i = jump - 1;
|
||||
continue;
|
||||
} else if (parseReserved(entry, i, jump, elements, keywords)) {
|
||||
// found a keywords word, add it with its correct type
|
||||
i = jump - 1;
|
||||
continue;
|
||||
} else if (parseNumber(entry, i, jump, errors, elements)) {
|
||||
i = jump - 1;
|
||||
continue;
|
||||
}
|
||||
if (parseUnknown(entry, i, jump, elements))
|
||||
// last chance, this unknown entry is treated as a symbol
|
||||
i = jump - 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Lexer::trim(string& s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
|
||||
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& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements) {
|
||||
// here we are sure that entry[0] is at least '"'
|
||||
for (size_t i = idx + 1; i < entry.size(); i++) {
|
||||
if (entry[i] == '"') {
|
||||
if (entry[i] - 1 != '\\') {
|
||||
elements.push_back({cmd_string, .value = entry.substr(idx + 1, i - idx - 1)});
|
||||
nextIdx = i + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
elements.push_back({cmd_string, .value = entry.substr(idx + 1, entry.size() - idx - 1)});
|
||||
nextIdx = entry.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Lexer::parseSymbol(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements) {
|
||||
// here we are sure that entry[0] is at least '\''
|
||||
for (size_t i = idx + 1; i < entry.size(); i++) {
|
||||
if (entry[i] == '\'') {
|
||||
elements.push_back({cmd_symbol, .value = entry.substr(idx + 1, i - idx - 1), .autoEval = false});
|
||||
nextIdx = i + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elements.push_back({cmd_symbol, .value = entry.substr(idx + 1, entry.size() - idx - 1)});
|
||||
nextIdx = entry.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Lexer::parseProgram(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements) {
|
||||
// here we are sure that entry is at least "<<"
|
||||
// find last ">>" or "»"
|
||||
int countNested = 0;
|
||||
for (size_t i = idx + 2; i < entry.size() - 1; i++) {
|
||||
if ((entry[i] == '<' && entry[i + 1] == '<') || (entry.substr(i, 2) == "«"))
|
||||
countNested++;
|
||||
else if ((entry[i] == '>' && entry[i + 1] == '>') || (entry.substr(i, 2) == "»")) {
|
||||
if (countNested == 0) {
|
||||
string prg = entry.substr(idx + 2, i - idx - 2);
|
||||
trim(prg);
|
||||
elements.push_back({cmd_program, .value = prg});
|
||||
nextIdx = i + 2;
|
||||
return true;
|
||||
} else
|
||||
countNested--;
|
||||
}
|
||||
}
|
||||
string prg = entry.substr(idx + 2, entry.size() - idx - 2);
|
||||
trim(prg);
|
||||
elements.push_back({cmd_program, .value = prg});
|
||||
nextIdx = entry.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
int Lexer::getBaseAt(string& entry, int idxStart, bool& positive) {
|
||||
regex baseRegex("([+-])?((0[xX])|([0-9][0-9]?[bB]))");
|
||||
smatch match;
|
||||
if (regex_search(entry, match, baseRegex) && match.size() >= 5) {
|
||||
string sign = match[1].str();
|
||||
string base = match[2].str();
|
||||
// sign out, permits expressions like -0xAB3F
|
||||
positive = sign.size() > 0 && sign[0] == '-' ? false : true;
|
||||
// base
|
||||
entry = entry.substr(base.size() + sign.size());
|
||||
if (base[1] == 'X' || base[1] == 'x') return 16;
|
||||
if (base.size() > 0) {
|
||||
int b = stoi(base.substr(0, base.size() - 1));
|
||||
if (b == 0) b = 2; // admit "0b" as binary suffix
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return 10;
|
||||
}
|
||||
|
||||
bool Lexer::getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, mpreal& r, char delim) {
|
||||
stringstream ss;
|
||||
int idxNumber = 0;
|
||||
string token;
|
||||
bool positive = true;
|
||||
|
||||
ss.str(entry.substr(idx));
|
||||
if (getline(ss, token, delim)) {
|
||||
nextIdx = token.size() + idx + 1;
|
||||
base = getBaseAt(token, idx, positive);
|
||||
if (base < BASE_MIN || base > BASE_MAX) return false;
|
||||
trim(token);
|
||||
if (mpfr_set_str(r.mpfr_ptr(), token.c_str(), base, mpreal::get_default_rnd()) == 0) {
|
||||
if (!positive) r = -r;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
nextIdx = token.size() + idx + 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Lexer::parseNumber(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements) {
|
||||
mpreal r;
|
||||
int base = 10;
|
||||
if (getNumberAt(entry, idx, nextIdx, base, r)) {
|
||||
elements.push_back({cmd_number, .re = r, .reBase = base});
|
||||
return true;
|
||||
} else {
|
||||
errors.push_back({entry.size(), "unterminated number"});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Lexer::parseComplex(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements) {
|
||||
mpreal re, im;
|
||||
int reBase, imBase = 10;
|
||||
if (idx + 1 == entry.size()) {
|
||||
elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)});
|
||||
nextIdx = entry.size();
|
||||
return true; // complex format error, return a symbol
|
||||
}
|
||||
if (!getNumberAt(entry, idx + 1, nextIdx, reBase, re, ',')) {
|
||||
elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)});
|
||||
nextIdx = entry.size();
|
||||
return true; // complex format error, return a symbol
|
||||
}
|
||||
|
||||
size_t i = nextIdx;
|
||||
// while (i < entry.size() && entry[i] != ',') i++;
|
||||
if (i >= entry.size()) {
|
||||
elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)});
|
||||
nextIdx = entry.size();
|
||||
return true; // complex format error, return a symbol
|
||||
}
|
||||
|
||||
if (!getNumberAt(entry, i, nextIdx, imBase, im, ')')) {
|
||||
elements.push_back({cmd_symbol, .value = entry.substr(idx, entry.size() - idx)});
|
||||
nextIdx = entry.size();
|
||||
return true; // complex format error, return a symbol
|
||||
}
|
||||
elements.push_back({cmd_complex, .re = re, .im = im, .reBase = reBase, .imBase = imBase});
|
||||
nextIdx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Lexer::parseReserved(string& entry, size_t idx, size_t& nextIdx, vector<SynElement>& elements,
|
||||
map<string, ReservedWord>& keywords) {
|
||||
stringstream ss(entry.substr(idx));
|
||||
string token;
|
||||
ss >> token;
|
||||
|
||||
auto resa = keywords.find(token);
|
||||
if (resa != keywords.end()) {
|
||||
elements.push_back({resa->second.type, .value = token, .fn = resa->second.fn});
|
||||
nextIdx = token.size() + idx;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Lexer::parseUnknown(string& entry, size_t idx, size_t& nextIdx, vector<SynElement>& elements) {
|
||||
stringstream ss(entry.substr(idx));
|
||||
string token;
|
||||
ss >> token;
|
||||
elements.push_back({cmd_symbol, .value = token, .autoEval = true});
|
||||
nextIdx = token.size() + idx;
|
||||
return true;
|
||||
}
|
73
src/lexer.hpp
Normal file
73
src/lexer.hpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef _PARSER_HPP_
|
||||
#define _PARSER_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
#include <mpreal.h>
|
||||
using namespace mpfr;
|
||||
|
||||
#include "constant.h"
|
||||
#include "object.hpp"
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
// a structure to describe a syntaxical element and its value
|
||||
struct SynElement {
|
||||
cmd_type_t type;
|
||||
string value;
|
||||
mpreal re;
|
||||
mpreal im;
|
||||
int reBase;
|
||||
int imBase;
|
||||
program_fn_t fn;
|
||||
bool autoEval;
|
||||
};
|
||||
|
||||
struct SynError {
|
||||
size_t indx;
|
||||
string err;
|
||||
};
|
||||
|
||||
struct ReservedWord {
|
||||
cmd_type_t type;
|
||||
program_fn_t fn;
|
||||
};
|
||||
|
||||
Lexer() {}
|
||||
|
||||
/// @brief lexical analysis of an entry string
|
||||
///
|
||||
/// @param[in] entry the entry to lex
|
||||
/// @param[out] elements syntax elements vector
|
||||
/// @param[out] errors errors vector
|
||||
/// @param[in] keywords reserved keywords
|
||||
/// @return false=errors, the lexer must stop
|
||||
///
|
||||
bool lexer(string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
|
||||
vector<SynError>& errors);
|
||||
|
||||
private:
|
||||
bool parseString(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements);
|
||||
bool parseSymbol(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements);
|
||||
bool parseProgram(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements);
|
||||
bool parseNumber(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements);
|
||||
bool parseComplex(string& entry, size_t idx, size_t& nextIdx, vector<SynError>& errors,
|
||||
vector<SynElement>& elements);
|
||||
bool parseReserved(string& entry, size_t idx, size_t& nextIdx, vector<SynElement>& elements,
|
||||
map<string, ReservedWord>& keywords);
|
||||
bool parseUnknown(string& entry, size_t idx, size_t& nextIdx, vector<SynElement>& elements);
|
||||
|
||||
void trim(string& s);
|
||||
int getBaseAt(string& entry, int idxStart, bool& positive);
|
||||
bool getNumberAt(string& entry, size_t idx, size_t& nextIdx, int& base, mpreal& r, char delim = ' ');
|
||||
};
|
||||
|
||||
#endif
|
116
src/main.cpp
116
src/main.cpp
|
@ -1,101 +1,101 @@
|
|||
// std c
|
||||
#include <errno.h>
|
||||
#include <linux/limits.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
// internal includes
|
||||
#include "input.hpp"
|
||||
#include "program.hpp"
|
||||
|
||||
static heap s_global_heap;
|
||||
static stack s_global_stack;
|
||||
static program* s_prog_to_interrupt = NULL;
|
||||
static heap _global_heap;
|
||||
static rpnstack _global_stack;
|
||||
static program* _prog_to_interrupt = nullptr;
|
||||
|
||||
/// @brief actions to be done at rpn exit
|
||||
///
|
||||
void exit_interactive_rpn() {
|
||||
static void exit_interactive_rpn() {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
if (pw != NULL) {
|
||||
char history_path[PATH_MAX];
|
||||
sprintf(history_path, "%s/%s", pw->pw_dir, HISTORY_FILE);
|
||||
if (pw != nullptr) {
|
||||
stringstream history_path;
|
||||
history_path << pw->pw_dir << "/.rpn_history";
|
||||
|
||||
// trunc current history
|
||||
ofstream history(history_path, ios_base::out | ios_base::trunc);
|
||||
ofstream history(history_path.str(), ios_base::out | ios_base::trunc);
|
||||
history.close();
|
||||
|
||||
// save it
|
||||
if (linenoiseHistorySave(history_path) != 0)
|
||||
fprintf(stderr, "warning, could not save %s (errno=%d, '%s')\n", history_path, errno, strerror(errno));
|
||||
if (linenoiseHistorySave(history_path.str().c_str()) != 0)
|
||||
cerr << "warning, could not save " << history_path.str() << " [errno=" << errno << ' ' << strerror(errno)
|
||||
<< "']" << endl;
|
||||
linenoiseHistoryFree();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief actions to be done at rpn exit
|
||||
///
|
||||
void init_interactive_rpn() {
|
||||
static void init_interactive_rpn() {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
if (pw != NULL) {
|
||||
char history_path[PATH_MAX];
|
||||
sprintf(history_path, "%s/%s", pw->pw_dir, HISTORY_FILE);
|
||||
if (pw != nullptr) {
|
||||
stringstream history_path;
|
||||
history_path << pw->pw_dir << "/.rpn_history";
|
||||
|
||||
// don't care about errors
|
||||
linenoiseHistorySetMaxLen(HISTORY_FILE_MAX_LINES);
|
||||
linenoiseHistoryLoad(history_path);
|
||||
linenoiseHistorySetMaxLen(100);
|
||||
linenoiseHistoryLoad(history_path.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief handle CtrlC signal (sigaction handler): exit rpn
|
||||
///
|
||||
///
|
||||
/// @param sig signal, see POSIX sigaction
|
||||
/// @param siginfo signal info, see POSIX sigaction
|
||||
/// @param context see POSIX sigaction
|
||||
///
|
||||
static void ctrlc_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
if (s_prog_to_interrupt != NULL) {
|
||||
s_prog_to_interrupt->stop();
|
||||
s_prog_to_interrupt = NULL;
|
||||
if (_prog_to_interrupt != nullptr) {
|
||||
_prog_to_interrupt->stop();
|
||||
_prog_to_interrupt = nullptr;
|
||||
}
|
||||
|
||||
exit_interactive_rpn();
|
||||
}
|
||||
|
||||
/// @brief handle SIGSEGV signal (sigaction handler): stop and exit rpn
|
||||
///
|
||||
///
|
||||
/// @param sig signal, see POSIX sigaction
|
||||
/// @param siginfo signal info, see POSIX sigaction
|
||||
/// @param context see POSIX sigaction
|
||||
///
|
||||
static void segv_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
fprintf(stderr, "Internal error\n");
|
||||
s_prog_to_interrupt->stop();
|
||||
s_prog_to_interrupt = NULL;
|
||||
cerr << "Internal error" << endl;
|
||||
_prog_to_interrupt->stop();
|
||||
_prog_to_interrupt = nullptr;
|
||||
}
|
||||
|
||||
/// @brief setup signals handlers to stop with honours
|
||||
///
|
||||
/// @param prog the prog to catch the signals to, must be checked not NULL by user
|
||||
///
|
||||
/// @param prog the prog to catch the signals to, must be checked not nullptr by user
|
||||
///
|
||||
static void catch_signals(program* prog) {
|
||||
struct sigaction act;
|
||||
struct sigaction act = {0};
|
||||
|
||||
s_prog_to_interrupt = prog;
|
||||
_prog_to_interrupt = prog;
|
||||
|
||||
act.sa_sigaction = &ctrlc_handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGINT, &act, NULL) < 0)
|
||||
(void)fprintf(stderr, "Warning, Ctrl-C cannot be catched [errno=%d '%s']", errno, strerror(errno));
|
||||
if (sigaction(SIGINT, &act, nullptr) < 0)
|
||||
cerr << "Warning, Ctrl-C cannot be caught [errno=" << errno << ' ' << strerror(errno) << "']" << endl;
|
||||
|
||||
act.sa_sigaction = &segv_handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGSEGV, &act, NULL) < 0)
|
||||
(void)fprintf(stderr, "Warning, SIGSEGV cannot be catched [errno=%d '%s']", errno, strerror(errno));
|
||||
if (sigaction(SIGSEGV, &act, nullptr) < 0)
|
||||
cerr << "Warning, SIGSEGV cannot be caught [errno=" << errno << ' ' << strerror(errno) << "']" << endl;
|
||||
}
|
||||
|
||||
/// @brief rpn entry point
|
||||
///
|
||||
///
|
||||
/// @param argc command line args nb
|
||||
/// @param argv command line args nb
|
||||
/// @return int 0=ok
|
||||
|
@ -115,32 +115,30 @@ int main(int argc, char* argv[]) {
|
|||
// entry loop
|
||||
while (go_on) {
|
||||
// make program from interactive entry
|
||||
program prog;
|
||||
switch (program::entry(prog)) {
|
||||
case ret_good_bye:
|
||||
go_on = false;
|
||||
break;
|
||||
case ret_abort_current_entry:
|
||||
break;
|
||||
default:
|
||||
program prog(_global_stack, _global_heap);
|
||||
string entry;
|
||||
switch (Input(entry, program::getAutocompletionWords()).status) {
|
||||
case Input::ok:
|
||||
// user could stop prog with CtrlC
|
||||
catch_signals(&prog);
|
||||
|
||||
// run it
|
||||
if (prog.run(s_global_stack, s_global_heap) == ret_good_bye)
|
||||
if (prog.parse(entry) == ret_ok && prog.run() == ret_good_bye)
|
||||
go_on = false;
|
||||
else
|
||||
program::show_stack(s_global_stack);
|
||||
program::show_stack(_global_stack);
|
||||
break;
|
||||
case Input::ctrlc:
|
||||
go_on = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// manage history and exit
|
||||
exit_interactive_rpn();
|
||||
}
|
||||
// run with cmd line arguments
|
||||
else {
|
||||
program prog;
|
||||
} else { // run with cmd line arguments
|
||||
program prog(_global_stack, _global_heap);
|
||||
string entry;
|
||||
int i;
|
||||
|
||||
|
@ -151,16 +149,14 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
// make program
|
||||
ret = program::parse(entry.c_str(), prog);
|
||||
ret = prog.parse(entry);
|
||||
if (ret == ret_ok) {
|
||||
string separator = "";
|
||||
|
||||
// user could stop prog with CtrlC
|
||||
catch_signals(&prog);
|
||||
|
||||
// run it
|
||||
ret = prog.run(s_global_stack, s_global_heap);
|
||||
program::show_stack(s_global_stack, false);
|
||||
ret = prog.run();
|
||||
program::show_stack(_global_stack, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
203
src/mpreal-out.cpp
Normal file
203
src/mpreal-out.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
#include "mpreal-out.hpp"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(h, i) ((h) > (i) ? (h) : (i))
|
||||
|
||||
// some defs for mpfr
|
||||
#if _MPFR_EXP_FORMAT == 1
|
||||
#define MPFR_EXP_MAX (SHRT_MAX)
|
||||
#define MPFR_EXP_MIN (SHRT_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 2
|
||||
#define MPFR_EXP_MAX (INT_MAX)
|
||||
#define MPFR_EXP_MIN (INT_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 3
|
||||
#define MPFR_EXP_MAX (LONG_MAX)
|
||||
#define MPFR_EXP_MIN (LONG_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 4
|
||||
#define MPFR_EXP_MAX (MPFR_INTMAX_MAX)
|
||||
#define MPFR_EXP_MIN (MPFR_INTMAX_MIN)
|
||||
#else
|
||||
#error "Invalid MPFR Exp format"
|
||||
#endif
|
||||
|
||||
#define MPFR_EXP_INF (MPFR_EXP_MIN + 3)
|
||||
#define MPFR_EXP_NAN (MPFR_EXP_MIN + 2)
|
||||
#define MPFR_EXP(x) ((x)->_mpfr_exp)
|
||||
#define MPFR_IS_SINGULAR(x) (MPFR_EXP(x) <= MPFR_EXP_INF)
|
||||
#define MPFR_UNLIKELY(x) (__builtin_expect(!!(x), 0))
|
||||
#define MPFR_IS_NAN(x) (MPFR_EXP(x) == MPFR_EXP_NAN)
|
||||
#define MPFR_IS_INF(x) (MPFR_EXP(x) == MPFR_EXP_INF)
|
||||
#define MPFR_IS_NEG(x) (MPFR_SIGN(x) < 0)
|
||||
#define MPFR_IS_POS(x) (MPFR_SIGN(x) > 0)
|
||||
#define MPFR_PREC(x) ((x)->_mpfr_prec)
|
||||
|
||||
ostream& mpreal_output10base(ostream& out, const string& fmt, const mpreal& value) {
|
||||
// cf std::ostream& mpreal::output(std::ostream& os) const
|
||||
char* s = NULL;
|
||||
if (!(mpfr_asprintf(&s, fmt.c_str(), mpreal::get_default_rnd(), value.mpfr_srcptr()) < 0)) {
|
||||
out << string(s);
|
||||
mpfr_free_str(s);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool is_min(const mpreal& p, mpfr_prec_t prec) {
|
||||
// see mpfr_vasprintf code
|
||||
// TODO here use mpreal functions like <=0, isinf etc
|
||||
bool ret;
|
||||
int round_away;
|
||||
switch (mpreal::get_default_rnd()) {
|
||||
case MPFR_RNDA:
|
||||
round_away = 1;
|
||||
break;
|
||||
case MPFR_RNDD:
|
||||
round_away = MPFR_IS_NEG(p.mpfr_srcptr());
|
||||
break;
|
||||
case MPFR_RNDU:
|
||||
round_away = MPFR_IS_POS(p.mpfr_srcptr());
|
||||
break;
|
||||
case MPFR_RNDN: {
|
||||
/* compare |p| to y = 0.5*10^(-prec) */
|
||||
mpfr_t y;
|
||||
mpfr_exp_t e = MAX(MPFR_PREC(p.mpfr_srcptr()), 56);
|
||||
mpfr_init2(y, e + 8);
|
||||
do {
|
||||
/* find a lower approximation of
|
||||
0.5*10^(-prec) different from |p| */
|
||||
e += 8;
|
||||
mpfr_set_prec(y, e);
|
||||
mpfr_set_si(y, -prec, MPFR_RNDN);
|
||||
mpfr_exp10(y, y, MPFR_RNDD);
|
||||
mpfr_div_2ui(y, y, 1, MPFR_RNDN);
|
||||
} while (mpfr_cmpabs(y, p.mpfr_srcptr()) == 0);
|
||||
|
||||
round_away = mpfr_cmpabs(y, p.mpfr_srcptr()) < 0;
|
||||
mpfr_clear(y);
|
||||
} break;
|
||||
default:
|
||||
round_away = 0;
|
||||
}
|
||||
|
||||
if (round_away) /* round away from zero: the last output digit is '1' */
|
||||
ret = true;
|
||||
else
|
||||
/* only zeros in fractional part */
|
||||
ret = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _out_base(ostream& out, int base) {
|
||||
if (base == 16)
|
||||
out << "0x";
|
||||
else if (base == 2)
|
||||
out << "0b";
|
||||
else
|
||||
out << base << "b";
|
||||
}
|
||||
|
||||
ostream& _out_singular(ostream& out, int base, const mpreal& value) {
|
||||
const char* write_after_sign = NULL; // unused for now
|
||||
int digits = 0; // forced 0 digits after separator
|
||||
if (MPFR_IS_NAN(value.mpfr_srcptr()))
|
||||
out << "nan";
|
||||
else if (MPFR_IS_INF(value.mpfr_srcptr())) {
|
||||
if (MPFR_IS_NEG(value.mpfr_srcptr())) out << '-';
|
||||
out << "inf";
|
||||
} else {
|
||||
// zero
|
||||
if (MPFR_IS_NEG(value.mpfr_srcptr())) out << '-'; // signed zero is allowed
|
||||
if (write_after_sign != NULL) out << write_after_sign;
|
||||
_out_base(out, base);
|
||||
out << '0';
|
||||
if (digits > 0) {
|
||||
out << '.';
|
||||
for (int i = 0; i < digits; i++) out << '0';
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream& _out_little_number(ostream& out, int base, const mpreal& value) {
|
||||
const char* write_after_sign = NULL; // unused for now
|
||||
int digits = 0; // forced 0 digits after separator
|
||||
|
||||
if (MPFR_IS_NEG(value.mpfr_srcptr())) out << '-';
|
||||
if (write_after_sign != NULL) out << write_after_sign;
|
||||
_out_base(out, base);
|
||||
out << '0';
|
||||
if (digits > 0) {
|
||||
out << '.';
|
||||
for (int i = 0; i < digits - 1; i++) out << '0';
|
||||
|
||||
if (is_min(value.mpfr_srcptr(), digits))
|
||||
out << '1';
|
||||
else
|
||||
out << '0';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream& _out_number(ostream& out, int base, const mpreal& value) {
|
||||
const char* write_after_sign = NULL; // unused for now
|
||||
int digits = 0; // forced 0 digits after separator
|
||||
mpfr_exp_t exp = mpfr_get_exp(value.mpfr_srcptr());
|
||||
|
||||
char* str = mpfr_get_str(NULL, &exp, base, digits + exp + 1, value.mpfr_srcptr(), mpreal::get_default_rnd());
|
||||
char* print_from;
|
||||
if (str != NULL) {
|
||||
int len = strlen(str);
|
||||
print_from = str;
|
||||
if (len > 0) {
|
||||
if (print_from[0] == '-') {
|
||||
out << print_from[0];
|
||||
len--;
|
||||
print_from++;
|
||||
} else if (print_from[0] == '+') {
|
||||
len--;
|
||||
print_from++;
|
||||
}
|
||||
if (write_after_sign != NULL) out << write_after_sign;
|
||||
if (base == 16)
|
||||
out << "0x";
|
||||
else if (base == 2)
|
||||
out << "0b";
|
||||
else
|
||||
out << base << "b";
|
||||
if (exp < 0) {
|
||||
out << '0';
|
||||
if (digits > 0) {
|
||||
out << '.';
|
||||
for (int i = 0; i < -(int)exp; i++) out << '0';
|
||||
out << str;
|
||||
for (int i = 0; i < (int)(digits - len + exp); i++) out << '0';
|
||||
}
|
||||
} else {
|
||||
if (exp == 0)
|
||||
out << '0';
|
||||
else
|
||||
for (int i = 0; i < (int)exp; i++) out << print_from[i];
|
||||
if (digits > 0) {
|
||||
out << '.';
|
||||
|
||||
int remaining = (int)MIN(strlen(print_from) - exp - 1, digits) + 1;
|
||||
for (int i = (int)exp; i < remaining + (int)exp; i++) out << print_from[i];
|
||||
for (int i = 0; i < (int)(exp + digits - len); i++) out << '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
mpfr_free_str(str);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream& mpreal_outputNbase(ostream& out, int base, const mpreal& value) {
|
||||
// see mpfr_vasprintf code
|
||||
int digits = 0; // forced 0 digits after separator
|
||||
|
||||
if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(value.mpfr_srcptr()))) return _out_singular(out, base, value);
|
||||
|
||||
mpfr_exp_t exp = mpfr_get_exp(value.mpfr_srcptr());
|
||||
if (exp < -digits) return _out_little_number(out, base, value);
|
||||
|
||||
return _out_number(out, base, value);
|
||||
}
|
11
src/mpreal-out.hpp
Normal file
11
src/mpreal-out.hpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <string>
|
||||
#include <ostream>
|
||||
using namespace std;
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
#include <mpreal.h>
|
||||
using namespace mpfr;
|
||||
|
||||
ostream& mpreal_output10base(ostream& out, const string& fmt, const mpreal& value);
|
||||
ostream& mpreal_outputNbase(ostream& out, int base, const mpreal& value);
|
224
src/object.cpp
224
src/object.cpp
|
@ -1,228 +1,6 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#include "constant.h"
|
||||
#include "mpfr.h"
|
||||
#include "object.hpp"
|
||||
|
||||
// floating_t statics
|
||||
mpfr_prec_t floating_t::s_mpfr_prec = MPFR_DEFAULT_PREC_BITS;
|
||||
mpfr_rnd_t floating_t::s_mpfr_rnd = MPFR_DEFAULT_RND;
|
||||
unsigned int floating_t::s_mpfr_prec_bytes = MPFR_DEFAULT_STORING_LENGTH_BYTES;
|
||||
const char* floating_t::s_mpfr_rnd_str[5] = MPFR_RND_STRINGS;
|
||||
|
||||
// number statics
|
||||
number::mode_enum number::s_mode = DEFAULT_MODE;
|
||||
int number::s_decimal_digits = DEFAULT_DECIMAL_DIGITS;
|
||||
string number::s_mpfr_printf_format = string(MPFR_DEFAULT_FORMAT);
|
||||
|
||||
//
|
||||
const char* object::s_cmd_type_string[cmd_max] = CMD_TYPE_STRINGS;
|
||||
|
||||
/// @brief return if a mpfr is higher to a given precision
|
||||
/// this function is directly copied from mpfr
|
||||
///
|
||||
/// @param p the mpfr to test
|
||||
/// @param prec the precision
|
||||
/// @return true p is higher than 10^prec
|
||||
/// @return false p is lower than 10^prec
|
||||
///
|
||||
static bool is_min(mpfr_t p, mpfr_prec_t prec) {
|
||||
// see mpfr_vasprintf code
|
||||
bool ret;
|
||||
int round_away;
|
||||
switch (floating_t::s_mpfr_rnd) {
|
||||
case MPFR_RNDA:
|
||||
round_away = 1;
|
||||
break;
|
||||
case MPFR_RNDD:
|
||||
round_away = MPFR_IS_NEG(p);
|
||||
break;
|
||||
case MPFR_RNDU:
|
||||
round_away = MPFR_IS_POS(p);
|
||||
break;
|
||||
case MPFR_RNDN: {
|
||||
/* compare |p| to y = 0.5*10^(-prec) */
|
||||
mpfr_t y;
|
||||
mpfr_exp_t e = MAX(MPFR_PREC(p), 56);
|
||||
mpfr_init2(y, e + 8);
|
||||
do {
|
||||
/* find a lower approximation of
|
||||
0.5*10^(-prec) different from |p| */
|
||||
e += 8;
|
||||
mpfr_set_prec(y, e);
|
||||
mpfr_set_si(y, -prec, MPFR_RNDN);
|
||||
mpfr_exp10(y, y, MPFR_RNDD);
|
||||
mpfr_div_2ui(y, y, 1, MPFR_RNDN);
|
||||
} while (mpfr_cmpabs(y, p) == 0);
|
||||
|
||||
round_away = mpfr_cmpabs(y, p) < 0;
|
||||
mpfr_clear(y);
|
||||
} break;
|
||||
default:
|
||||
round_away = 0;
|
||||
}
|
||||
|
||||
if (round_away) /* round away from zero: the last output digit is '1' */
|
||||
ret = true;
|
||||
else
|
||||
/* only zeros in fractional part */
|
||||
ret = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief print a mpfr in fixed format according to a base
|
||||
/// this function is based copied on mpfr library
|
||||
///
|
||||
/// @param stream the stream to write to
|
||||
/// @param real the real to print
|
||||
/// @param base the base to print the real
|
||||
/// @param write_after_sign substring to write between the sign and the real
|
||||
///
|
||||
static void print_fix(FILE* stream, mpfr_t real, int base, const char* write_after_sign = NULL) {
|
||||
// see mpfr_vasprintf code
|
||||
mpfr_exp_t exp = mpfr_get_exp(real);
|
||||
int digits = 0; // forced 0 digits after separator
|
||||
int i;
|
||||
|
||||
if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(real))) {
|
||||
if (MPFR_IS_NAN(real))
|
||||
fputs("nan", stream);
|
||||
else if (MPFR_IS_INF(real)) {
|
||||
if (MPFR_IS_NEG(real)) fputc('-', stream);
|
||||
fputs("inf", stream);
|
||||
} else {
|
||||
// zero
|
||||
if (MPFR_IS_NEG(real)) fputc('-', stream); // signed zero is allowed
|
||||
if (write_after_sign != NULL) fputs(write_after_sign, stream);
|
||||
fputc('0', stream);
|
||||
if (digits > 0) {
|
||||
fputc('.', stream);
|
||||
for (i = 0; i < digits; i++) fputc('0', stream);
|
||||
}
|
||||
}
|
||||
} else if (exp < -digits) {
|
||||
if (MPFR_IS_NEG(real)) fputc('-', stream);
|
||||
if (write_after_sign != NULL) fputs(write_after_sign, stream);
|
||||
fputc('0', stream);
|
||||
if (digits > 0) {
|
||||
fputc('.', stream);
|
||||
for (i = 0; i < digits - 1; i++) fputc('0', stream);
|
||||
|
||||
if (is_min(real, digits))
|
||||
fputc('1', stream);
|
||||
else
|
||||
fputc('0', stream);
|
||||
}
|
||||
} else {
|
||||
char* str = mpfr_get_str(NULL, &exp, base, digits + exp + 1, real, floating_t::s_mpfr_rnd);
|
||||
char* print_from;
|
||||
if (str != NULL) {
|
||||
int len = strlen(str);
|
||||
print_from = str;
|
||||
if (len > 0) {
|
||||
if (print_from[0] == '-') {
|
||||
fputc(print_from[0], stream);
|
||||
len--;
|
||||
print_from++;
|
||||
} else if (print_from[0] == '+') {
|
||||
len--;
|
||||
print_from++;
|
||||
}
|
||||
if (write_after_sign != NULL) fputs(write_after_sign, stream);
|
||||
if (exp < 0) {
|
||||
fputc('0', stream);
|
||||
if (digits > 0) {
|
||||
fputc('.', stream);
|
||||
for (i = 0; i < -(int)exp; i++) fputc('0', stream);
|
||||
fputs(str, stream);
|
||||
for (i = 0; i < (int)(digits - len + exp); i++) fputc('0', stream);
|
||||
}
|
||||
} else {
|
||||
if (exp == 0)
|
||||
fputc('0', stream);
|
||||
else
|
||||
for (i = 0; i < (int)exp; i++) fputc(print_from[i], stream);
|
||||
if (digits > 0) {
|
||||
fputc('.', stream);
|
||||
|
||||
int remaining = (int)MIN(strlen(print_from) - exp - 1, digits) + 1;
|
||||
for (i = (int)exp; i < remaining + (int)exp; i++) fputc(print_from[i], stream);
|
||||
for (i = 0; i < (int)(exp + digits - len); i++) fputc('0', stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
mpfr_free_str(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief show an object representation according to its type
|
||||
///
|
||||
/// @param stream the stream to write to
|
||||
///
|
||||
void object::show(FILE* stream) {
|
||||
int digits;
|
||||
char* str;
|
||||
char base[32];
|
||||
|
||||
switch (_type) {
|
||||
case cmd_number:
|
||||
switch (((number*)this)->_representation) {
|
||||
case number::dec:
|
||||
mpfr_fprintf(stream, number::s_mpfr_printf_format.c_str(), ((number*)this)->_value.mpfr);
|
||||
break;
|
||||
case number::hex:
|
||||
print_fix(stream, ((number*)this)->_value.mpfr, 16, "0x");
|
||||
break;
|
||||
case number::bin:
|
||||
print_fix(stream, ((number*)this)->_value.mpfr, 2, "0b");
|
||||
break;
|
||||
case number::base:
|
||||
sprintf(base, "%db", ((number*)this)->_base);
|
||||
print_fix(stream, ((number*)this)->_value.mpfr, ((number*)this)->_base, base);
|
||||
break;
|
||||
default:
|
||||
fprintf(stream, "<unknown number representation>");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case cmd_complex:
|
||||
switch (((complex*)this)->_representation) {
|
||||
case number::dec:
|
||||
fprintf(stream, "(");
|
||||
mpfr_fprintf(stream, number::s_mpfr_printf_format.c_str(), ((complex*)this)->re()->mpfr);
|
||||
fprintf(stream, ",");
|
||||
mpfr_fprintf(stream, number::s_mpfr_printf_format.c_str(), ((complex*)this)->im()->mpfr);
|
||||
fprintf(stream, ")");
|
||||
break;
|
||||
case number::hex:
|
||||
fprintf(stream, "(");
|
||||
mpfr_fprintf(stream, string(MPFR_FORMAT_HEX).c_str(), ((complex*)this)->re()->mpfr);
|
||||
fprintf(stream, ",");
|
||||
mpfr_fprintf(stream, string(MPFR_FORMAT_HEX).c_str(), ((complex*)this)->im()->mpfr);
|
||||
fprintf(stream, ")");
|
||||
break;
|
||||
default:
|
||||
fprintf(stream, "<unknown complex representation>");
|
||||
}
|
||||
break;
|
||||
case cmd_string:
|
||||
fprintf(stream, "\"%s\"", ((ostring*)this)->_value);
|
||||
break;
|
||||
case cmd_program:
|
||||
fprintf(stream, "<<%s>>", ((oprogram*)this)->_value);
|
||||
break;
|
||||
case cmd_symbol:
|
||||
fprintf(stream, "'%s'", ((symbol*)this)->_value);
|
||||
break;
|
||||
case cmd_keyword:
|
||||
case cmd_branch:
|
||||
fprintf(stream, "%s", ((keyword*)this)->_value);
|
||||
break;
|
||||
default:
|
||||
fprintf(stream, "< unknown object representation >");
|
||||
break;
|
||||
}
|
||||
}
|
||||
int number::s_digits = DEFAULT_DECIMAL_DIGITS;
|
||||
|
|
332
src/object.hpp
332
src/object.hpp
|
@ -1,11 +1,20 @@
|
|||
#ifndef OBJECT_HPP
|
||||
#define OBJECT_HPP
|
||||
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
#include <string.h>
|
||||
#include <mpreal.h>
|
||||
using namespace mpfr;
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include "mpreal-out.hpp"
|
||||
|
||||
// definitions for objects
|
||||
////
|
||||
///
|
||||
typedef enum {
|
||||
cmd_undef,
|
||||
cmd_number, // floating point number
|
||||
|
@ -24,259 +33,168 @@ class branch;
|
|||
typedef void (program::*program_fn_t)(void);
|
||||
typedef int (program::*branch_fn_t)(branch&);
|
||||
|
||||
/// @brief MPFR (floating point) object
|
||||
///
|
||||
struct floating_t {
|
||||
mpfr_prec_t mpfr_prec; // precision in bits
|
||||
unsigned int mpfr_prec_bytes; // significand storing length in bytes
|
||||
mpfr_t mpfr; // mpfr object
|
||||
|
||||
void init() {
|
||||
void* significand = (void*)(this + 1);
|
||||
mpfr_prec = s_mpfr_prec;
|
||||
mpfr_prec_bytes = s_mpfr_prec_bytes;
|
||||
mpfr_custom_init(significand, MPFR_DEFAULT_PREC_BITS);
|
||||
mpfr_custom_init_set(mpfr, MPFR_ZERO_KIND, 0, mpfr_prec, significand);
|
||||
}
|
||||
|
||||
void move() {
|
||||
void* significand = (void*)(this + 1);
|
||||
mpfr_custom_move(mpfr, significand);
|
||||
}
|
||||
|
||||
floating_t& operator=(const double val) { mpfr_set_d(mpfr, val, s_mpfr_rnd); }
|
||||
|
||||
floating_t& operator=(const long int val) { mpfr_set_si(mpfr, val, s_mpfr_rnd); }
|
||||
|
||||
floating_t& operator=(const unsigned long val) { mpfr_set_ui(mpfr, val, s_mpfr_rnd); }
|
||||
|
||||
operator double() { return mpfr_get_d(mpfr, s_mpfr_rnd); }
|
||||
|
||||
operator int() { return (int)mpfr_get_si(mpfr, s_mpfr_rnd); }
|
||||
|
||||
operator long() { return mpfr_get_si(mpfr, s_mpfr_rnd); }
|
||||
|
||||
bool operator>(const floating_t right) { return mpfr_cmp(mpfr, right.mpfr) > 0; }
|
||||
|
||||
bool operator<(const floating_t right) { return mpfr_cmp(mpfr, right.mpfr) < 0; }
|
||||
|
||||
// default precision in bits, precision length in bytes, rounding mode
|
||||
static mpfr_prec_t s_mpfr_prec;
|
||||
static unsigned int s_mpfr_prec_bytes;
|
||||
static mpfr_rnd_t s_mpfr_rnd;
|
||||
static const char* s_mpfr_rnd_str[5];
|
||||
};
|
||||
|
||||
/// @brief object - a generic stack object
|
||||
///
|
||||
struct object {
|
||||
// object type
|
||||
object(cmd_type_t type = cmd_undef) : _type(type) {}
|
||||
virtual ~object() {}
|
||||
cmd_type_t _type;
|
||||
unsigned int _size;
|
||||
virtual object* clone() {
|
||||
object* o = new object();
|
||||
if (o != nullptr) *o = *this;
|
||||
return o;
|
||||
}
|
||||
|
||||
//
|
||||
unsigned int size() { return _size; }
|
||||
virtual string name() { return string("object"); }
|
||||
virtual ostream& show(ostream& out) {
|
||||
out << "(" << name() << " - unknown representation)";
|
||||
return out;
|
||||
}
|
||||
friend ostream& operator<<(ostream& os, object* o) { return o->show(os); }
|
||||
|
||||
void show(FILE* stream = stdout);
|
||||
|
||||
//
|
||||
static const char* s_cmd_type_string[cmd_max];
|
||||
unsigned int size() { return sizeof(*this); }
|
||||
};
|
||||
|
||||
/// @brief stack objects derived from object
|
||||
///
|
||||
struct number : public object {
|
||||
// members
|
||||
enum { dec, hex, bin, base } _representation;
|
||||
// base
|
||||
// carefull: _base is used only if _representation = base
|
||||
int _base;
|
||||
// mind that float value is at the end of the object
|
||||
// because its mantissa is just after the obj in memory
|
||||
floating_t _value;
|
||||
struct number : object {
|
||||
number() : object(cmd_number), base(10) {}
|
||||
number(const mpreal& value_, int base_ = 10) : object(cmd_number), base(base_), value(value_) {}
|
||||
number(long value_, int base_ = 10) : object(cmd_number), base(base_), value(value_) {}
|
||||
|
||||
// publics
|
||||
number() { _type = cmd_number; }
|
||||
int base;
|
||||
mpreal value;
|
||||
|
||||
void init() {
|
||||
_type = cmd_number;
|
||||
_representation = dec;
|
||||
_value.init();
|
||||
}
|
||||
|
||||
void move() { _value.move(); }
|
||||
|
||||
void set(unsigned long value) {
|
||||
_type = cmd_number;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
static unsigned int calc_size() { return (unsigned int)(sizeof(number) + floating_t::s_mpfr_prec_bytes); }
|
||||
virtual object* clone() { return new number(value, base); }
|
||||
virtual string name() { return string("number"); }
|
||||
virtual ostream& show(ostream& out) { return showValue(out, value, s_mode, s_digits, base); }
|
||||
|
||||
// representation mode
|
||||
typedef enum { std, fix, sci } mode_enum;
|
||||
static mode_enum s_mode;
|
||||
|
||||
// precision
|
||||
static int s_decimal_digits;
|
||||
static string s_mpfr_printf_format;
|
||||
static int s_digits;
|
||||
|
||||
// clang-format off
|
||||
static string _makeNumberFormat(mode_enum mode, int digits) {
|
||||
stringstream format;
|
||||
format<<"%."<<digits;
|
||||
switch(mode) {
|
||||
case std: format<<"R*g"; break;
|
||||
case fix: format<<"R*f"; break;
|
||||
case sci: format<<"R*e"; break;
|
||||
}
|
||||
return format.str();
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
static ostream& showValue(ostream& out, const mpreal& value, mode_enum mode, int digits, int base) {
|
||||
if (base == 10)
|
||||
return mpreal_output10base(out, _makeNumberFormat(s_mode, s_digits), value);
|
||||
else
|
||||
return mpreal_outputNbase(out, base, value);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief stack objects derived from object
|
||||
///
|
||||
struct complex : public object {
|
||||
enum { dec, hex } _representation;
|
||||
// mind that re float value is at the end of the object
|
||||
// because its mantissa is just after the obj in memory
|
||||
floating_t _re;
|
||||
|
||||
complex() { _type = cmd_complex; }
|
||||
|
||||
// re and im float values are at the end of the object
|
||||
floating_t* re() { return &_re; }
|
||||
floating_t* im() { return (floating_t*)((char*)&_re + sizeof(floating_t) + _re.mpfr_prec_bytes); }
|
||||
|
||||
void init() {
|
||||
_type = cmd_complex;
|
||||
_representation = dec;
|
||||
re()->init();
|
||||
im()->init();
|
||||
struct ocomplex : object {
|
||||
ocomplex() : object(cmd_complex), reBase(10), imBase(10) {}
|
||||
ocomplex(complex<mpreal>& value_, int reb = 10, int imb = 10) : object(cmd_complex), reBase(reb), imBase(imb) {
|
||||
value = value_;
|
||||
}
|
||||
ocomplex(mpreal& re_, mpreal& im_, int reb = 10, int imb = 10) : object(cmd_complex), reBase(reb), imBase(imb) {
|
||||
value.real(re_);
|
||||
value.imag(im_);
|
||||
}
|
||||
|
||||
void move() {
|
||||
re()->move();
|
||||
im()->move();
|
||||
}
|
||||
int reBase, imBase;
|
||||
complex<mpreal> value;
|
||||
|
||||
static unsigned int calc_size() {
|
||||
return (unsigned int)(sizeof(complex) + 2 * (sizeof(floating_t) + floating_t::s_mpfr_prec_bytes));
|
||||
virtual object* clone() { return new ocomplex(value, reBase, imBase); }
|
||||
virtual string name() { return string("complex"); }
|
||||
virtual ostream& show(ostream& out) {
|
||||
out << '(';
|
||||
number::showValue(out, value.real(), number::s_mode, number::s_digits, reBase);
|
||||
out << ',';
|
||||
number::showValue(out, value.imag(), number::s_mode, number::s_digits, imBase);
|
||||
return out << ')';
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief object string
|
||||
///
|
||||
struct ostring : public object {
|
||||
// ostring may first have been allocated with len+1 bytes
|
||||
void set(const char* value, unsigned int len) {
|
||||
_type = cmd_string;
|
||||
if (value != NULL) {
|
||||
if (len > 0) (void)memcpy(_value, value, len);
|
||||
_value[len] = 0;
|
||||
_len = len;
|
||||
} else {
|
||||
_value[_len] = 0;
|
||||
_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// length of _value, not including the terminal '\0'
|
||||
unsigned int _len;
|
||||
char _value[0];
|
||||
///
|
||||
struct ostring : object {
|
||||
ostring() : object(cmd_string) {}
|
||||
ostring(const string& value_) : object(cmd_string), value(value_) {}
|
||||
virtual object* clone() { return new ostring(value); }
|
||||
virtual string name() { return string("string"); }
|
||||
virtual ostream& show(ostream& out) { return out << "\"" << value << "\""; }
|
||||
string value;
|
||||
};
|
||||
|
||||
/// @brief object program
|
||||
///
|
||||
struct oprogram : public object {
|
||||
// oprogram may first have been allocated with len+1 bytes
|
||||
void set(const char* value, unsigned int len) {
|
||||
_type = cmd_program;
|
||||
if (value != NULL) {
|
||||
if (len > 0) (void)memcpy(_value, value, len);
|
||||
_value[len] = 0;
|
||||
_len = len;
|
||||
} else {
|
||||
_value[0] = 0;
|
||||
_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// length of _value, not includiong the terminal '\0'
|
||||
unsigned int _len;
|
||||
char _value[0];
|
||||
///
|
||||
struct oprogram : object {
|
||||
oprogram() : object(cmd_program) {}
|
||||
oprogram(const string& value_) : object(cmd_program), value(value_) {}
|
||||
virtual object* clone() { return new oprogram(value); }
|
||||
virtual string name() { return string("program"); }
|
||||
virtual ostream& show(ostream& out) { return out << "«" << value << "»"; }
|
||||
string value;
|
||||
};
|
||||
|
||||
/// @brief object symbol
|
||||
///
|
||||
struct symbol : public object {
|
||||
// symbol may first have been allocated with len+1 bytes
|
||||
void set(const char* value, unsigned int len, bool auto_eval) {
|
||||
_type = cmd_symbol;
|
||||
_auto_eval = auto_eval;
|
||||
|
||||
if (value != NULL) {
|
||||
if (len > 0) (void)memcpy(_value, value, len);
|
||||
_value[len] = 0;
|
||||
_len = len;
|
||||
} else {
|
||||
_value[0] = 0;
|
||||
_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
bool _auto_eval;
|
||||
// length of _value, not includiong the terminal '\0'
|
||||
unsigned int _len;
|
||||
char _value[0];
|
||||
///
|
||||
struct symbol : object {
|
||||
symbol(bool autoEval_ = true) : object(cmd_symbol), autoEval(autoEval_) {}
|
||||
symbol(const string& value_, bool autoEval_ = true) : object(cmd_symbol), value(value_), autoEval(autoEval_) {}
|
||||
virtual object* clone() { return new symbol(value, autoEval); }
|
||||
virtual string name() { return string("symbol"); }
|
||||
virtual ostream& show(ostream& out) { return out << "'" << value << "'"; }
|
||||
bool autoEval;
|
||||
string value;
|
||||
};
|
||||
|
||||
/// @brief object keyword
|
||||
///
|
||||
struct keyword : public object {
|
||||
// keyword may first have been allocated with len+1 bytes
|
||||
void set(program_fn_t fn, const char* value, unsigned int len) {
|
||||
_type = cmd_keyword;
|
||||
_fn = fn;
|
||||
if (value != NULL) {
|
||||
if (len > 0) (void)memcpy(_value, value, len);
|
||||
_value[len] = 0;
|
||||
_len = len;
|
||||
} else {
|
||||
_value[0] = 0;
|
||||
_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
program_fn_t _fn;
|
||||
// length of _value, not includiong the terminal '\0'
|
||||
unsigned int _len;
|
||||
char _value[0];
|
||||
///
|
||||
struct keyword : object {
|
||||
keyword() : object(cmd_keyword) {}
|
||||
keyword(program_fn_t fn_, const string& value_) : object(cmd_keyword), fn(fn_), value(value_) {}
|
||||
virtual object* clone() { return new keyword(fn, value); }
|
||||
virtual string name() { return string("keyword"); }
|
||||
program_fn_t fn;
|
||||
string value;
|
||||
};
|
||||
|
||||
/// @brief object branch
|
||||
///
|
||||
struct branch : public object {
|
||||
//
|
||||
void set(branch_fn_t fn, const char* value, unsigned int len) {
|
||||
_type = cmd_branch;
|
||||
_fn = fn;
|
||||
///
|
||||
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;
|
||||
farg1 = NULL;
|
||||
farg2 = NULL;
|
||||
arg_bool = 0;
|
||||
if (value != NULL) {
|
||||
if (len > 0) (void)memcpy(_value, value, len);
|
||||
_value[len] = 0;
|
||||
_len = len;
|
||||
} else {
|
||||
_value[0] = 0;
|
||||
_len = 0;
|
||||
}
|
||||
value = value_;
|
||||
}
|
||||
|
||||
// branch function
|
||||
branch_fn_t _fn;
|
||||
// args used by cmd_branch cmds
|
||||
branch(branch& other) : object(cmd_branch) {
|
||||
fn = other.fn;
|
||||
arg1 = other.arg1;
|
||||
arg2 = other.arg2;
|
||||
arg3 = other.arg3;
|
||||
arg_bool = other.arg_bool;
|
||||
value = other.value;
|
||||
}
|
||||
virtual object* clone() { return new branch(*this); }
|
||||
virtual string name() { return string("branch"); }
|
||||
branch_fn_t fn;
|
||||
int arg1, arg2, arg3;
|
||||
number *farg1, *farg2;
|
||||
mpreal firstIndex, lastIndex;
|
||||
bool arg_bool;
|
||||
|
||||
// length of _value, not includiong the terminal '\0'
|
||||
unsigned int _len;
|
||||
char _value[0];
|
||||
string value;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
627
src/parse.cpp
627
src/parse.cpp
|
@ -1,627 +0,0 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief completion callback as asked by linenoise-ng
|
||||
/// this is called by linenoise-ng whenever the user enters TAB
|
||||
///
|
||||
/// @param text the text after wich the user entered TAB
|
||||
/// @param lc the completion object to add strings with linenoiseAddCompletion()
|
||||
///
|
||||
void program::entry_completion_generator(const char* text, linenoiseCompletions* lc) {
|
||||
int i = 0;
|
||||
int text_len = strnlen(text, 6);
|
||||
|
||||
// propose all keywords
|
||||
if (text_len == 0) {
|
||||
while (program::s_keywords[i].type != cmd_max) {
|
||||
if (program::s_keywords[i].fn != NULL)
|
||||
// add all keywords
|
||||
linenoiseAddCompletion(lc, program::s_keywords[i].name);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// propose keywords matching to text begining
|
||||
else {
|
||||
while (program::s_keywords[i].type != cmd_max) {
|
||||
if (program::s_keywords[i].fn != NULL) {
|
||||
// compare list entry with text, return if match
|
||||
if (strncmp(program::s_keywords[i].name, text, text_len) == 0)
|
||||
linenoiseAddCompletion(lc, program::s_keywords[i].name);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief interactive entry and decoding
|
||||
///
|
||||
/// @param prog the program to add entered objects
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::entry(program& prog) {
|
||||
string entry_str;
|
||||
char* entry;
|
||||
int entry_len;
|
||||
int total_entry_len;
|
||||
ret_value ret = ret_max;
|
||||
bool multiline = false;
|
||||
|
||||
// linenoise for entry
|
||||
linenoiseSetCompletionCallback(entry_completion_generator);
|
||||
|
||||
while (ret == ret_max) {
|
||||
// get user entry
|
||||
if (multiline)
|
||||
entry = linenoise(MULTILINE_PROMPT, &entry_len);
|
||||
else
|
||||
entry = linenoise(PROMPT, &entry_len);
|
||||
|
||||
// Ctrl-C
|
||||
if (linenoiseKeyType() == 1) {
|
||||
if (entry_len > 0 || multiline)
|
||||
ret = ret_abort_current_entry;
|
||||
else
|
||||
ret = ret_good_bye;
|
||||
} else if (linenoiseKeyType() == 3) {
|
||||
multiline = true;
|
||||
if (entry != NULL) entry_str += entry;
|
||||
entry_str += " ";
|
||||
} else {
|
||||
if (entry != NULL) {
|
||||
entry_str += entry;
|
||||
|
||||
// parse it
|
||||
ret = parse(entry_str.c_str(), prog);
|
||||
|
||||
// keep history
|
||||
if (entry[0] != 0) (void)linenoiseHistoryAdd(entry_str.c_str());
|
||||
} else
|
||||
ret = ret_internal;
|
||||
}
|
||||
|
||||
free(entry);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief return function pointer from function name
|
||||
///
|
||||
/// @param fn_name function name
|
||||
/// @param fn function pointer
|
||||
/// @param type the function type (cmd_keyword or cmd_branch)
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::get_fn(const char* fn_name, program_fn_t& fn, cmd_type_t& type) {
|
||||
unsigned int i = 0;
|
||||
while (s_keywords[i].type != cmd_max) {
|
||||
if (strncasecmp(fn_name, s_keywords[i].name, sizeof(s_keywords[i].name)) == 0) {
|
||||
fn = s_keywords[i].fn;
|
||||
type = s_keywords[i].type;
|
||||
return ret_ok;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ret_unknown_err;
|
||||
}
|
||||
|
||||
/// @brief get a keyword object from entry and add it to a program
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added
|
||||
/// @return false no object was added
|
||||
///
|
||||
static bool get_keyword(const string& entry, program& prog, string& remaining_entry) {
|
||||
program_fn_t fn;
|
||||
unsigned int obj_len;
|
||||
cmd_type_t type;
|
||||
bool ret = false;
|
||||
|
||||
// could be a command
|
||||
if (program::get_fn(entry.c_str(), fn, type) == ret_ok) {
|
||||
if (type == cmd_keyword) {
|
||||
// allocate keyword object
|
||||
obj_len = sizeof(keyword) + entry.size() + 1;
|
||||
keyword* new_obj = (keyword*)prog.allocate_back(obj_len, cmd_keyword);
|
||||
new_obj->set(fn, entry.c_str(), entry.size());
|
||||
ret = true;
|
||||
} else if (type == cmd_branch) {
|
||||
// allocate branch object
|
||||
obj_len = sizeof(branch) + entry.size() + 1;
|
||||
branch* new_obj = (branch*)prog.allocate_back(obj_len, cmd_branch);
|
||||
new_obj->set((branch_fn_t)fn, entry.c_str(), entry.size());
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief get a symbol object from entry and add it to a program
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added
|
||||
/// @return false no object was added
|
||||
///
|
||||
static bool get_symbol(const string& entry, program& prog, string& remaining_entry) {
|
||||
bool ret = false;
|
||||
int entry_len = entry.size();
|
||||
unsigned int obj_len;
|
||||
|
||||
if (entry_len >= 1 && entry[0] == '\'') {
|
||||
if (entry_len == 1) {
|
||||
// void symbol entry, like '
|
||||
// total object length
|
||||
obj_len = sizeof(symbol) + 1;
|
||||
|
||||
// allocate and set object
|
||||
// symbol beginning with ' is not autoevaluated
|
||||
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
|
||||
new_obj->set("", 0, false);
|
||||
} else {
|
||||
// symbol entry, like 'toto' or 'toto
|
||||
int naked_entry_len;
|
||||
|
||||
// entry length without prefix / postfix
|
||||
naked_entry_len = entry[entry_len - 1] == '\'' ? (entry_len - 2) : (entry_len - 1);
|
||||
// total object length
|
||||
obj_len = sizeof(symbol) + naked_entry_len + 1;
|
||||
|
||||
// allocate and set object
|
||||
// symbol beginning with ' is not autoevaluated
|
||||
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
|
||||
new_obj->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len, false);
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief get an object other from known ones from entry and add it to a program
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added
|
||||
/// @return false no object was added
|
||||
///
|
||||
static bool get_other(const string& entry, program& prog, string& remaining_entry) {
|
||||
bool ret = false;
|
||||
int entry_len = entry.size();
|
||||
unsigned int obj_len;
|
||||
|
||||
if (entry_len >= 1) {
|
||||
// entry which is nothing is considered as an auto-evaluated symbol
|
||||
int naked_entry_len;
|
||||
|
||||
// entry length without prefix / postfix
|
||||
naked_entry_len = entry[entry_len - 1] == '\'' ? (entry_len - 1) : (entry_len);
|
||||
// total object length
|
||||
obj_len = sizeof(symbol) + naked_entry_len + 1;
|
||||
|
||||
// allocate and set object
|
||||
// symbol not beginning with ' is autoevaluated (ie is evaluated when pushed
|
||||
// on stack)
|
||||
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
|
||||
new_obj->set(entry.c_str(), naked_entry_len, true);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief get a string object from entry and add it to a program
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added
|
||||
/// @return false no object was added
|
||||
///
|
||||
static bool get_string(const string& entry, program& prog, string& remaining_entry) {
|
||||
bool ret = false;
|
||||
unsigned int obj_len;
|
||||
int entry_len = entry.size();
|
||||
if (entry_len >= 1 && entry[0] == '"') {
|
||||
if (entry_len == 1) {
|
||||
// total object length
|
||||
obj_len = sizeof(ostring) + 1;
|
||||
|
||||
// allocate and set object
|
||||
ostring* new_obj = (ostring*)prog.allocate_back(obj_len, cmd_string);
|
||||
new_obj->set("", 0);
|
||||
} else {
|
||||
int naked_entry_len;
|
||||
|
||||
// entry length without prefix / postfix
|
||||
naked_entry_len = entry[entry_len - 1] == '"' ? (entry_len - 2) : (entry_len - 1);
|
||||
|
||||
// total object length
|
||||
obj_len = sizeof(ostring) + naked_entry_len + 1;
|
||||
|
||||
// allocate and set object
|
||||
ostring* new_obj = (ostring*)prog.allocate_back(obj_len, cmd_string);
|
||||
new_obj->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len);
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief get a program object from entry and add it to a program
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added
|
||||
/// @return false no object was added
|
||||
///
|
||||
static bool get_program(string& entry, program& prog, string& remaining_entry) {
|
||||
bool ret = false;
|
||||
unsigned int obj_len;
|
||||
int entry_len = entry.size();
|
||||
if (entry_len >= 2 && entry[0] == '<' && entry[1] == '<') {
|
||||
int naked_entry_len;
|
||||
|
||||
// entry length without prefix / postfix
|
||||
if (entry_len >= 4 && entry[entry_len - 1] == '>' && entry[entry_len - 2] == '>')
|
||||
naked_entry_len = entry_len - 4;
|
||||
else
|
||||
naked_entry_len = entry_len - 2;
|
||||
|
||||
// total object length
|
||||
obj_len = sizeof(oprogram) + naked_entry_len + 1;
|
||||
|
||||
// allocate and set object
|
||||
oprogram* new_obj = (oprogram*)prog.allocate_back(obj_len, cmd_program);
|
||||
new_obj->set(&entry[2], naked_entry_len);
|
||||
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief get a number object from entry and add it to a program
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added
|
||||
/// @return false no object was added
|
||||
///
|
||||
static bool get_number(string& entry, program& prog, string& remaining_entry) {
|
||||
char* endptr;
|
||||
bool ret = false;
|
||||
|
||||
if (entry.size() > 0) {
|
||||
// pre parse to avoid doing a useless allocation
|
||||
// detect the begining of a number including nan, inf, @nan@, @inf@
|
||||
if (entry.find_first_of("+-0123456789.ni@", 0) == 0) {
|
||||
// detect an arbitrary base entry like 3bXXX or 27bYYY
|
||||
int base = 0;
|
||||
size_t base_detect = entry.find_first_of("b", 0);
|
||||
if (base_detect == 1 || base_detect == 2)
|
||||
if (sscanf(entry.c_str(), "%db", &base) == 1 && base >= 2 && base <= 62)
|
||||
entry = entry.substr(base_detect + 1);
|
||||
else
|
||||
base = 0;
|
||||
|
||||
number* num = (number*)prog.allocate_back(number::calc_size(), cmd_number);
|
||||
|
||||
int mpfr_ret = mpfr_strtofr(num->_value.mpfr, entry.c_str(), &endptr, base, MPFR_DEFAULT_RND);
|
||||
if (endptr != NULL && endptr != entry.c_str()) {
|
||||
// determine representation
|
||||
if (base != 0) {
|
||||
num->_representation = number::base;
|
||||
num->_base = base;
|
||||
} else {
|
||||
string beg = entry.substr(0, 2);
|
||||
if (beg == "0x" || beg == "0X")
|
||||
num->_representation = number::hex;
|
||||
else if (beg == "0b" || beg == "0B")
|
||||
num->_representation = number::bin;
|
||||
else
|
||||
num->_representation = number::dec;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
||||
// remaining string if any
|
||||
remaining_entry = endptr;
|
||||
} else
|
||||
(void)prog.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief get a complex object from entry and add it to a program
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added
|
||||
/// @return false no object was added
|
||||
///
|
||||
static bool get_complex(const string& entry, program& prog, string& remaining_entry) {
|
||||
char* endptr;
|
||||
bool ret = false;
|
||||
|
||||
if (entry.size() > 0) {
|
||||
size_t comma = entry.find(',');
|
||||
if (comma != string::npos) {
|
||||
complex* cplx;
|
||||
|
||||
// pre parse RE to avoid doing a useless allocation
|
||||
// detect the begining of a number, including nan, inf, @nan@, @inf@
|
||||
string re_str = entry.substr(1, comma - 1).c_str();
|
||||
if (re_str.find_first_of(" +-0123456789.ni@", 0) == 0) {
|
||||
cplx = (complex*)prog.allocate_back(complex::calc_size(), cmd_complex);
|
||||
|
||||
int mpfr_ret = mpfr_strtofr(cplx->re()->mpfr, re_str.c_str(), &endptr, 0, MPFR_DEFAULT_RND);
|
||||
if (endptr != NULL && endptr != re_str.c_str()) {
|
||||
// determine representation
|
||||
string beg = re_str.substr(0, 2);
|
||||
if (beg == "0x" || beg == "0X")
|
||||
cplx->_representation = complex::hex;
|
||||
else
|
||||
cplx->_representation = complex::dec;
|
||||
|
||||
ret = true;
|
||||
} else
|
||||
(void)prog.pop_back();
|
||||
}
|
||||
|
||||
// pre parse IM to avoid doing a useless allocation
|
||||
// detect the begining of a number, including nan, inf, @nan@, @inf@
|
||||
string im_str = entry.substr(comma + 1).c_str();
|
||||
if (ret == true && im_str.find_first_of(" +-0123456789.ni@", 0) == 0) {
|
||||
ret = false;
|
||||
int mpfr_ret = mpfr_strtofr(cplx->im()->mpfr, im_str.c_str(), &endptr, 0, MPFR_DEFAULT_RND);
|
||||
if (endptr != NULL && endptr != im_str.c_str()) {
|
||||
// determine representation
|
||||
string beg = im_str.substr(0, 2);
|
||||
if (beg == "0x" || beg == "0X")
|
||||
cplx->_representation = complex::hex;
|
||||
else
|
||||
cplx->_representation = complex::dec;
|
||||
|
||||
ret = true;
|
||||
} else
|
||||
(void)prog.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief recognize a comment object from entry
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param remaining_entry the remaining entry after the comment was found
|
||||
/// @return true a comment was found
|
||||
/// @return false no comment was found
|
||||
///
|
||||
static bool get_comment(string& entry, string& remaining_entry) {
|
||||
bool ret = false;
|
||||
unsigned int obj_len;
|
||||
int entry_len = entry.size();
|
||||
if (entry_len >= 1 && entry[0] == '#') {
|
||||
// entry (complete line) is ignored
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief get an object from an entry string and add it to a program
|
||||
///
|
||||
/// @param entry the entry string
|
||||
/// @param prog the program
|
||||
/// @param remaining_entry the remaining entry after the object was added
|
||||
/// @return true an object was added to the prog
|
||||
/// @return false no object was added to the prog
|
||||
///
|
||||
static bool _obj_from_string(string& entry, program& prog, string& remaining_entry) {
|
||||
bool ret = false;
|
||||
|
||||
remaining_entry.erase();
|
||||
|
||||
if (get_number(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
else if (get_symbol(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
else if (get_string(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
else if (get_program(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
else if (get_keyword(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
else if (get_complex(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
else if (get_comment(entry, remaining_entry))
|
||||
ret = true;
|
||||
else
|
||||
// nothing, considered as an auto-evaluated symbol
|
||||
if (get_other(entry, prog, remaining_entry))
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief cut an entry string into entry chunks with respect of types separators
|
||||
///
|
||||
/// @param entry the entry
|
||||
/// @param entries the cut entriy vector
|
||||
/// @return true entries not vempty
|
||||
/// @return false entries empty
|
||||
///
|
||||
static bool _cut(const char* entry, vector<string>& entries) {
|
||||
string tmp;
|
||||
int len = strlen(entry);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
switch (entry[i]) {
|
||||
// symbol
|
||||
case '\'':
|
||||
// push prec entry if exists
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
// get symbol
|
||||
tmp = '\'';
|
||||
i++;
|
||||
while ((i < len) && entry[i] != '\'') tmp += entry[i++];
|
||||
if ((i < len) && entry[i] != '\'') tmp += '\'';
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
break;
|
||||
|
||||
// string
|
||||
case '"':
|
||||
// push prec entry if exists
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
// get expression
|
||||
tmp = '"';
|
||||
i++;
|
||||
while (i < len && entry[i] != '"') tmp += entry[i++];
|
||||
|
||||
if ((i < len) && entry[i] != '"') tmp += '"';
|
||||
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
break;
|
||||
|
||||
// program
|
||||
case '<':
|
||||
// push prec entry if exists
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
|
||||
if (strncmp(&entry[i], "<<", 2) == 0) {
|
||||
int up = 1;
|
||||
|
||||
// found a program begin
|
||||
i += 2;
|
||||
tmp = "<< ";
|
||||
|
||||
// trim leading spaces
|
||||
while (i < len && isspace(entry[i])) i++;
|
||||
|
||||
while (i < len) {
|
||||
if (strncmp(&entry[i], "<<", 2) == 0) {
|
||||
up++;
|
||||
i += 2;
|
||||
tmp += "<< ";
|
||||
// trim leading spaces
|
||||
while (i < len && isspace(entry[i])) i++;
|
||||
} else if (strncmp(&entry[i], ">>", 2) == 0) {
|
||||
if (isspace(entry[i - 1]) && entry[i - 2] != '>')
|
||||
tmp += ">>";
|
||||
else
|
||||
tmp += " >>";
|
||||
|
||||
up--;
|
||||
i += 2;
|
||||
|
||||
// trim trailing spaces
|
||||
while (i < len && isspace(entry[i])) i++;
|
||||
|
||||
// found end
|
||||
if (up == 0) break;
|
||||
} else {
|
||||
tmp += entry[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
while ((up--) > 0) tmp += " >>";
|
||||
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
i--; // i has move 1 too far
|
||||
} else
|
||||
// reinject '<'' which is not a prog begin
|
||||
tmp = "<";
|
||||
break;
|
||||
|
||||
// complex
|
||||
case '(':
|
||||
// push prec entry if exists
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
// get complex
|
||||
while ((i < len) && entry[i] != ')') tmp += entry[i++];
|
||||
if ((i < len) && entry[i] != ')') tmp += ')';
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
break;
|
||||
|
||||
// other
|
||||
default:
|
||||
if (!isspace(entry[i]))
|
||||
tmp += entry[i];
|
||||
else {
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tmp.size() > 0) {
|
||||
entries.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
return entries.size() > 0;
|
||||
}
|
||||
|
||||
/// @brief parse an entry string: cut it into objects chunks and add them to a program
|
||||
///
|
||||
/// @param entry the entry string
|
||||
/// @param prog the program
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::parse(const char* entry, program& prog) {
|
||||
vector<string> entries;
|
||||
ret_value ret = ret_ok;
|
||||
|
||||
// 1. cut global entry string into shorter strings
|
||||
if (_cut(entry, entries)) {
|
||||
// 2. make an object from each entry, and add it to the program
|
||||
for (vector<string>::iterator it = entries.begin(); it != entries.end(); it++) {
|
||||
string remaining_entry;
|
||||
string main_entry = (*it);
|
||||
while (main_entry.size() > 0) {
|
||||
// remaining_entry is used only in case of concatenated entry
|
||||
// ex: entry="1 2+" -> vector<string> = {"1", "2+"} -> first "1",
|
||||
// second "2" and remaining_entry="+" this remaining entry is treated as
|
||||
// an entry
|
||||
|
||||
// TODO errors ?
|
||||
_obj_from_string(main_entry, prog, remaining_entry);
|
||||
main_entry = remaining_entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
335
src/program.cpp
335
src/program.cpp
|
@ -1,12 +1,9 @@
|
|||
#include "program.hpp"
|
||||
|
||||
//< return type strings
|
||||
const char* program::s_ret_value_string[ret_max] = RET_VALUE_STRINGS;
|
||||
|
||||
//< kanguage reserved keywords (allowed types are cmd_keyword, cmd_branch or cmd_undef)
|
||||
program::keyword_t program::s_keywords[] = {
|
||||
//< language reserved keywords (allowed types are cmd_keyword, cmd_branch or cmd_undef)
|
||||
vector<program::keyword_t> program::_keywords{
|
||||
// GENERAL
|
||||
{cmd_undef, "", NULL, "\nGENERAL"},
|
||||
{cmd_undef, "", nullptr, "\nGENERAL"},
|
||||
{cmd_keyword, "nop", &program::rpn_nop, "no operation"},
|
||||
{cmd_keyword, "help", &program::rpn_help, "this help message"},
|
||||
{cmd_keyword, "h", &program::rpn_help, ""},
|
||||
|
@ -20,28 +17,23 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "history", &program::rpn_history, "see commands history"},
|
||||
|
||||
// USUAL OPERATIONS ON REALS AND COMPLEXES
|
||||
{cmd_undef, "", NULL, "\nUSUAL OPERATIONS ON REALS AND COMPLEXES"},
|
||||
{cmd_undef, "", nullptr, "\nUSUAL OPERATIONS ON REALS AND COMPLEXES"},
|
||||
{cmd_keyword, "+", &program::rpn_plus, "addition"},
|
||||
{cmd_keyword, "-", &program::rpn_minus, "substraction"},
|
||||
{cmd_keyword, "chs", &program::rpn_neg, "negation"},
|
||||
{cmd_keyword, "neg", &program::rpn_neg, ""},
|
||||
{cmd_keyword, "*", &program::rpn_mul, "multiplication"},
|
||||
{cmd_keyword, "/", &program::rpn_div, "division"},
|
||||
{cmd_keyword, "inv", &program::rpn_inv, "inverse"},
|
||||
{cmd_keyword, "chs", &program::rpn_neg, "negation"},
|
||||
{cmd_keyword, "neg", &program::rpn_neg, ""},
|
||||
{cmd_keyword, "^", &program::rpn_power, "power"},
|
||||
{cmd_keyword, "pow", &program::rpn_power, ""},
|
||||
{cmd_keyword, "sqrt", &program::rpn_squareroot, "rpn_square root"},
|
||||
{cmd_keyword, "sq", &program::rpn_square, "rpn_square"},
|
||||
{cmd_keyword, "sqr", &program::rpn_square, ""},
|
||||
{cmd_keyword, "abs", &program::rpn_abs, "absolute value"},
|
||||
{cmd_keyword, "dec", &program::rpn_dec, "decimal representation"},
|
||||
{cmd_keyword, "hex", &program::rpn_hex, "hexadecimal representation"},
|
||||
{cmd_keyword, "bin", &program::rpn_bin, "decimal representation"},
|
||||
{cmd_keyword, "base", &program::rpn_base, "arbitrary base representation"},
|
||||
{cmd_keyword, "sign", &program::rpn_sign, "1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0"},
|
||||
{cmd_keyword, "abs", &program::rpn_abs, "absolute value (norm for a complex)"},
|
||||
{cmd_keyword, "sign", &program::rpn_sign, "sign of a number or z/|z| for a complex"},
|
||||
|
||||
// OPERATIONS ON REALS
|
||||
{cmd_undef, "", NULL, "\nOPERATIONS ON REALS"},
|
||||
{cmd_undef, "", nullptr, "\nOPERATIONS ON REALS"},
|
||||
{cmd_keyword, "%", &program::rpn_purcent, "purcent"},
|
||||
{cmd_keyword, "%CH", &program::rpn_purcentCH, "inverse purcent"},
|
||||
{cmd_keyword, "mod", &program::rpn_modulo, "modulo"},
|
||||
|
@ -55,8 +47,8 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "min", &program::rpn_min, "min of 2 real numbers"},
|
||||
{cmd_keyword, "max", &program::rpn_max, "max of 2 real numbers"},
|
||||
|
||||
// nOPERATIONS ON COMPLEXES
|
||||
{cmd_undef, "", NULL, "\nOPERATIONS ON COMPLEXES"},
|
||||
// OPERATIONS ON COMPLEXES
|
||||
{cmd_undef, "", nullptr, "\nOPERATIONS ON COMPLEXES"},
|
||||
{cmd_keyword, "re", &program::rpn_re, "complex real part"},
|
||||
{cmd_keyword, "im", &program::rpn_im, "complex imaginary part"},
|
||||
{cmd_keyword, "conj", &program::rpn_conj, "complex conjugate"},
|
||||
|
@ -67,19 +59,24 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "r->p", &program::rpn_r2p, "polar to cartesian"},
|
||||
|
||||
// MODE
|
||||
{cmd_undef, "", NULL, "\nMODE"},
|
||||
{cmd_undef, "", nullptr, "\nMODE"},
|
||||
{cmd_keyword, "std", &program::rpn_std, "standard floating numbers representation. ex: std"},
|
||||
{cmd_keyword, "fix", &program::rpn_fix, "fixed point representation. ex: 6 fix"},
|
||||
{cmd_keyword, "sci", &program::rpn_sci, "scientific floating point representation. ex: 20 sci"},
|
||||
{cmd_keyword, "prec", &program::rpn_precision, "set float precision in bits. ex: 256 prec"},
|
||||
{cmd_keyword, "round", &program::rpn_round,
|
||||
"set float rounding mode.\n\tex: [\"nearest\", \"toward zero\", \"toward "
|
||||
"+inf\", \"toward -inf\", \"away from zero\"] round"},
|
||||
"set float rounding mode.\n\tex: [\"nearest (even)\", \"toward zero\", \"toward "
|
||||
"+inf\", \"toward -inf\", \"away from zero\", \"faithful rounding\", \"nearest (away from zero)\"] round"},
|
||||
|
||||
{cmd_keyword, "default", &program::rpn_default, "set float representation and precision to default"},
|
||||
{cmd_keyword, "type", &program::rpn_type, "show type of stack first entry"},
|
||||
{cmd_keyword, "hex", &program::rpn_hex, "hexadecimal representation, applies on stack level 0 only"},
|
||||
{cmd_keyword, "dec", &program::rpn_dec, "decimal representation, applies on stack level 0 only"},
|
||||
{cmd_keyword, "bin", &program::rpn_bin, "binary representation, applies on stack level 0 only"},
|
||||
{cmd_keyword, "base", &program::rpn_base, "arbitrary base representation, applies on stack level 0 only"},
|
||||
|
||||
// TESTS
|
||||
{cmd_undef, "", NULL, "\nTEST"},
|
||||
{cmd_undef, "", nullptr, "\nTEST"},
|
||||
{cmd_keyword, ">", &program::rpn_sup, "binary operator >"},
|
||||
{cmd_keyword, ">=", &program::rpn_sup_eq, "binary operator >="},
|
||||
{cmd_keyword, "<", &program::rpn_inf, "binary operator <"},
|
||||
|
@ -93,7 +90,7 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "same", &program::rpn_same, "boolean operator same (equal)"},
|
||||
|
||||
// STACK
|
||||
{cmd_undef, "", NULL, "\nSTACK"},
|
||||
{cmd_undef, "", nullptr, "\nSTACK"},
|
||||
{cmd_keyword, "swap", &program::rpn_swap, "swap 2 first stack entries"},
|
||||
{cmd_keyword, "drop", &program::rpn_drop, "drop first stack entry"},
|
||||
{cmd_keyword, "drop2", &program::rpn_drop2, "drop 2 first stack entries"},
|
||||
|
@ -111,19 +108,18 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "over", &program::rpn_over, "push a copy of the element in stack level 2 onto the stack"},
|
||||
|
||||
// STRING
|
||||
{cmd_undef, "", NULL, "\nSTRING"},
|
||||
{cmd_undef, "", nullptr, "\nSTRING"},
|
||||
{cmd_keyword, "->str", &program::rpn_instr, "convert an object into a string"},
|
||||
{cmd_keyword, "str->", &program::rpn_strout, "convert a string into an object"},
|
||||
{cmd_keyword, "chr", &program::rpn_chr, "convert ASCII character code in stack level 1 into a string"},
|
||||
{cmd_keyword, "num", &program::rpn_num,
|
||||
"return ASCII code of the first character of the string in stack level 1 "
|
||||
"as a real number"},
|
||||
"return ASCII code of the first character of the string in stack level 1 as a real number"},
|
||||
{cmd_keyword, "size", &program::rpn_strsize, "return the length of the string"},
|
||||
{cmd_keyword, "pos", &program::rpn_strpos, "seach for the string in level 1 within the string in level 2"},
|
||||
{cmd_keyword, "sub", &program::rpn_strsub, "return a substring of the string in level 3"},
|
||||
|
||||
// BRANCH
|
||||
{cmd_undef, "", NULL, "\nBRANCH"},
|
||||
{cmd_undef, "", nullptr, "\nBRANCH"},
|
||||
{cmd_branch, "if", (program_fn_t)&program::rpn_if,
|
||||
"if <test-instruction> then <true-instructions> else <false-instructions> "
|
||||
"end"},
|
||||
|
@ -141,14 +137,11 @@ program::keyword_t program::s_keywords[] = {
|
|||
"<false-instruction> ifte"},
|
||||
{cmd_branch, "do", (program_fn_t)&program::rpn_do, "do <instructions> until <condition> end"},
|
||||
{cmd_branch, "until", (program_fn_t)&program::rpn_until, "used with do"},
|
||||
{cmd_branch, "unti", (program_fn_t)&program::rpn_until, ""},
|
||||
{cmd_branch, "while", (program_fn_t)&program::rpn_while, "while <test-instruction> repeat <loop-instructions> end"},
|
||||
{cmd_branch, "whil", (program_fn_t)&program::rpn_while, ""},
|
||||
{cmd_branch, "repeat", (program_fn_t)&program::rpn_repeat, "used with while"},
|
||||
{cmd_branch, "repea", (program_fn_t)&program::rpn_repeat, ""},
|
||||
|
||||
// STORE
|
||||
{cmd_undef, "", NULL, "\nSTORE"},
|
||||
{cmd_undef, "", nullptr, "\nSTORE"},
|
||||
{cmd_keyword, "sto", &program::rpn_sto, "store a variable. ex: 1 'name' sto"},
|
||||
{cmd_keyword, "rcl", &program::rpn_rcl, "recall a variable. ex: 'name' rcl"},
|
||||
{cmd_keyword, "purge", &program::rpn_purge, "delete a variable. ex: 'name' purge"},
|
||||
|
@ -161,16 +154,15 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "sto/", &program::rpn_stodiv, "divide a stored variable. ex: 3 'name' sto/ 'name' 2 sto/"},
|
||||
{cmd_keyword, "sneg", &program::rpn_stoneg, "negate a variable. ex: 'name' sneg"},
|
||||
{cmd_keyword, "sinv", &program::rpn_stoinv, "inverse a variable. ex: 1 'name' sinv"},
|
||||
|
||||
// PROGRAM
|
||||
{cmd_undef, "", NULL, "\nPROGRAM"},
|
||||
{cmd_undef, "", nullptr, "\nPROGRAM"},
|
||||
{cmd_keyword, "eval", &program::rpn_eval, "evaluate (run) a program, or recall a variable. ex: 'my_prog' eval"},
|
||||
{cmd_branch, "->", (program_fn_t)&program::rpn_inprog,
|
||||
"load program local variables. ex: << -> n m << 0 n m for i i + next >> "
|
||||
">>"},
|
||||
|
||||
// TRIG ON REALS AND COMPLEXES
|
||||
{cmd_undef, "", NULL, "\nTRIG ON REALS AND COMPLEXES"},
|
||||
{cmd_undef, "", nullptr, "\nTRIG ON REALS AND COMPLEXES"},
|
||||
{cmd_keyword, "pi", &program::rpn_pi, "pi constant"},
|
||||
{cmd_keyword, "sin", &program::rpn_sin, "sinus"},
|
||||
{cmd_keyword, "asin", &program::rpn_asin, "arg sinus"},
|
||||
|
@ -182,7 +174,7 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "r->d", &program::rpn_r2d, "convert radians to degrees"},
|
||||
|
||||
// LOGS ON REALS AND COMPLEXES
|
||||
{cmd_undef, "", NULL, "\nLOGS ON REALS AND COMPLEXES"},
|
||||
{cmd_undef, "", nullptr, "\nLOGS ON REALS AND COMPLEXES"},
|
||||
{cmd_keyword, "e", &program::rpn_e, "Euler constant"},
|
||||
{cmd_keyword, "ln", &program::rpn_ln, "logarithm base e"},
|
||||
{cmd_keyword, "log", &program::rpn_ln, ""},
|
||||
|
@ -197,113 +189,127 @@ program::keyword_t program::s_keywords[] = {
|
|||
{cmd_keyword, "exp2", &program::rpn_alog2, ""},
|
||||
{cmd_keyword, "sinh", &program::rpn_sinh, "hyperbolic sine"},
|
||||
{cmd_keyword, "asinh", &program::rpn_asinh, "inverse hyperbolic sine"},
|
||||
{cmd_keyword, "cosh", &program::rpn_sinh, "hyperbolic cosine"},
|
||||
{cmd_keyword, "cosh", &program::rpn_cosh, "hyperbolic cosine"},
|
||||
{cmd_keyword, "acosh", &program::rpn_acosh, "inverse hyperbolic cosine"},
|
||||
{cmd_keyword, "tanh", &program::rpn_tanh, "hyperbolic tangent"},
|
||||
{cmd_keyword, "atanh", &program::rpn_atanh, "inverse hyperbolic tangent"},
|
||||
|
||||
// TIME AND DATE
|
||||
{cmd_undef, "", NULL, "\nTIME AND DATE"},
|
||||
{cmd_undef, "", nullptr, "\nTIME AND DATE"},
|
||||
{cmd_keyword, "time", &program::rpn_time, "time in local format"},
|
||||
{cmd_keyword, "date", &program::rpn_date, "date in local format"},
|
||||
{cmd_keyword, "ticks", &program::rpn_ticks, "system tick in µs"},
|
||||
|
||||
// end
|
||||
{cmd_max, "", NULL, ""},
|
||||
};
|
||||
|
||||
/// keywords map for lexer
|
||||
map<string, Lexer::ReservedWord> program::_keywordsMap;
|
||||
|
||||
/// autocompletion vector for linenoise autocompletion
|
||||
vector<string> program::_autocompletionWords;
|
||||
|
||||
vector<string>& program::getAutocompletionWords() {
|
||||
if (_autocompletionWords.empty())
|
||||
for (auto& kw : _keywords)
|
||||
if (!kw.name.empty()) _autocompletionWords.push_back(kw.name);
|
||||
return _autocompletionWords;
|
||||
}
|
||||
|
||||
/// @brief run a program on a stack and a heap
|
||||
///
|
||||
/// @param stk the stack, storing prog result
|
||||
/// @param hp the heap, storing variables
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::run(stack& stk, heap& hp) {
|
||||
ret_value program::run() {
|
||||
bool go_out = false;
|
||||
ret_value ret = ret_ok;
|
||||
cmd_type_t type;
|
||||
|
||||
// stack comes from outside
|
||||
_stack = &stk;
|
||||
|
||||
// global heap comes from outside
|
||||
_heap = &hp;
|
||||
|
||||
_err = ret_ok;
|
||||
_err_context = "";
|
||||
|
||||
// branches for 'if'
|
||||
ret = preprocess();
|
||||
if (ret != ret_ok) return ret;
|
||||
if (ret != ret_ok) {
|
||||
// free allocated
|
||||
for (object* o : *this) delete o;
|
||||
_local_heap.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// iterate commands
|
||||
for (int i = 0; (go_out == false) && (interrupt_now == false) && (i < (int)size());) {
|
||||
type = (cmd_type_t)seq_type(i);
|
||||
object* o = (*this)[i];
|
||||
switch (o->_type) {
|
||||
// could be an auto-evaluated symbol
|
||||
case cmd_symbol:
|
||||
auto_rcl((symbol*)o);
|
||||
i++;
|
||||
break;
|
||||
|
||||
// could be an auto-evaluated symbol
|
||||
if (type == cmd_symbol) {
|
||||
auto_rcl((symbol*)seq_obj(i));
|
||||
i++;
|
||||
}
|
||||
|
||||
// a keyword
|
||||
else if (type == cmd_keyword) {
|
||||
keyword* k = (keyword*)seq_obj(i);
|
||||
// call matching function
|
||||
(this->*(k->_fn))();
|
||||
switch (_err) {
|
||||
// no pb -> go on
|
||||
case ret_ok:
|
||||
break;
|
||||
// explicit go out software
|
||||
case ret_good_bye:
|
||||
go_out = true;
|
||||
ret = ret_good_bye;
|
||||
break;
|
||||
default:
|
||||
// error: abort prog
|
||||
go_out = true;
|
||||
|
||||
// error: show it
|
||||
if (show_error(_err, _err_context) == ret_deadly) {
|
||||
// pb showing error -> go out software
|
||||
// a keyword
|
||||
case cmd_keyword: {
|
||||
keyword* k = (keyword*)o;
|
||||
// call the matching function
|
||||
(this->*(k->fn))();
|
||||
switch (_err) {
|
||||
// no pb -> go on
|
||||
case ret_ok:
|
||||
break;
|
||||
// explicit go out software
|
||||
case ret_good_bye:
|
||||
go_out = true;
|
||||
ret = ret_good_bye;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// error: abort prog
|
||||
go_out = true;
|
||||
|
||||
// a branch keyword
|
||||
else if (type == cmd_branch) {
|
||||
// call matching function
|
||||
branch* b = (branch*)seq_obj(i);
|
||||
int next_cmd = (this->*(b->_fn))(*b);
|
||||
switch (next_cmd) {
|
||||
case -1:
|
||||
i++; // meaning 'next command'
|
||||
break;
|
||||
case -(int)ret_runtime_error:
|
||||
// error: show it
|
||||
(void)show_error(_err, _err_context);
|
||||
go_out = true; // end of run
|
||||
break;
|
||||
default:
|
||||
i = next_cmd; // new direction
|
||||
break;
|
||||
// error: show it
|
||||
if (show_error(_err, _err_context) == ret_deadly) {
|
||||
// pb showing error -> go out software
|
||||
ret = ret_good_bye;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not a command, but a stack entry, manage it
|
||||
else {
|
||||
// copy the program stack entry to the running stack
|
||||
stack::copy_and_push_back(*this, i, stk);
|
||||
i++;
|
||||
// a branch keyword
|
||||
case cmd_branch: {
|
||||
// call matching function
|
||||
branch* b = (branch*)o;
|
||||
int next_cmd = (this->*(b->fn))(*b);
|
||||
switch (next_cmd) {
|
||||
case -1:
|
||||
i++; // meaning 'next command'
|
||||
break;
|
||||
case -(int)ret_runtime_error:
|
||||
// error: show it
|
||||
(void)show_error(_err, _err_context);
|
||||
go_out = true; // end of run
|
||||
break;
|
||||
default:
|
||||
i = next_cmd; // new direction
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// not a command, but a stack entry, manage it
|
||||
// copy the program stack entry to the running stack
|
||||
_stack.push_front(o->clone());
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// free allocated
|
||||
for (object* o : *this) delete o;
|
||||
_local_heap.clear();
|
||||
|
||||
if (interrupt_now) {
|
||||
fprintf(stderr, "\nInterrupted\n");
|
||||
cerr << endl << "Interrupted" << endl;
|
||||
interrupt_now = false;
|
||||
}
|
||||
|
||||
|
@ -324,8 +330,8 @@ void program::stop() { interrupt_now = true; }
|
|||
/// @return false the branch name is NOT str_to_compare
|
||||
///
|
||||
bool program::compare_branch(branch* b, const char* str_to_compare, int len) {
|
||||
if (b->_len >= len)
|
||||
return strncasecmp(b->_value, str_to_compare, len) == 0;
|
||||
if (str_to_compare != nullptr)
|
||||
return b->value == str_to_compare;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -347,9 +353,8 @@ ret_value program::preprocess(void) {
|
|||
// analyse if-then-else-end branches
|
||||
// analyse start-{next, step} branches
|
||||
for (int i = 0; i < (int)size(); i++) {
|
||||
int type = seq_type(i);
|
||||
if (type == cmd_branch) {
|
||||
branch* k = (branch*)seq_obj(i);
|
||||
if ((*this)[i]->_type == cmd_branch) {
|
||||
branch* k = (branch*)(*this)[i];
|
||||
if (compare_branch(k, "if", 2)) {
|
||||
if_layout_t layout;
|
||||
layout.index_if_or_do_or_while = i;
|
||||
|
@ -406,7 +411,7 @@ ret_value program::preprocess(void) {
|
|||
vlayout[layout_index].index_else = i;
|
||||
k->arg1 = next; // fill branch1 (if was false) of 'else'
|
||||
k->arg3 = vlayout[layout_index].index_if_or_do_or_while;
|
||||
((branch*)seq_obj(vlayout[layout_index].index_then_or_unti_or_repeat))->arg2 =
|
||||
((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg2 =
|
||||
next; // fill branch2 (if was false) of 'then'
|
||||
} else if (compare_branch(k, "start", 5))
|
||||
vstartindex.push_back(i);
|
||||
|
@ -420,7 +425,7 @@ ret_value program::preprocess(void) {
|
|||
return ret_syntax;
|
||||
}
|
||||
k->arg1 = vstartindex[vstartindex.size() - 1]; // 'next' arg1 = 'start' index
|
||||
((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 =
|
||||
((branch*)(*this)[vstartindex[vstartindex.size() - 1]])->arg2 =
|
||||
i; // 'for' or 'start' arg2 = 'next' index
|
||||
vstartindex.pop_back();
|
||||
} else if (compare_branch(k, "step", 4)) {
|
||||
|
@ -430,7 +435,7 @@ ret_value program::preprocess(void) {
|
|||
return ret_syntax;
|
||||
}
|
||||
k->arg1 = vstartindex[vstartindex.size() - 1]; // fill 'step' branch1 = 'start' index
|
||||
((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 =
|
||||
((branch*)(*this)[vstartindex[vstartindex.size() - 1]])->arg2 =
|
||||
i; // 'for' or 'start' arg2 = 'next' index
|
||||
vstartindex.pop_back();
|
||||
} else if (compare_branch(k, "->", 2)) {
|
||||
|
@ -522,7 +527,7 @@ ret_value program::preprocess(void) {
|
|||
}
|
||||
|
||||
// fill 'repeat' arg1 with 'end+1'
|
||||
((branch*)seq_obj(vlayout[layout_index].index_then_or_unti_or_repeat))->arg1 = i + 1;
|
||||
((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg1 = i + 1;
|
||||
layout_index--;
|
||||
} else {
|
||||
// this end closes an if..then..(else)
|
||||
|
@ -533,11 +538,11 @@ ret_value program::preprocess(void) {
|
|||
}
|
||||
if (vlayout[layout_index].index_else != -1)
|
||||
// fill 'end' branch of 'else'
|
||||
((branch*)seq_obj(vlayout[layout_index].index_else))->arg2 = i;
|
||||
((branch*)(*this)[vlayout[layout_index].index_else])->arg2 = i;
|
||||
else {
|
||||
// fill 'end' branch of 'then'
|
||||
if (vlayout[layout_index].index_then_or_unti_or_repeat != -1)
|
||||
((branch*)seq_obj(vlayout[layout_index].index_then_or_unti_or_repeat))->arg2 = i;
|
||||
((branch*)(*this)[vlayout[layout_index].index_then_or_unti_or_repeat])->arg2 = i;
|
||||
else {
|
||||
// error: show it
|
||||
show_syntax_error("missing then");
|
||||
|
@ -563,15 +568,75 @@ ret_value program::preprocess(void) {
|
|||
return ret_ok;
|
||||
}
|
||||
|
||||
/// @brief parse an entry string: cut it into objects chunks and add them to a program
|
||||
///
|
||||
/// @param entry the entry string
|
||||
/// @param prog the program to be filled
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::parse(string& entry) {
|
||||
vector<Lexer::SynElement> elements;
|
||||
vector<Lexer::SynError> errors;
|
||||
ret_value ret = ret_ok;
|
||||
|
||||
// prepare map for finding reserved keywords
|
||||
if (_keywordsMap.empty())
|
||||
for (auto& kw : _keywords)
|
||||
if (!kw.name.empty()) _keywordsMap[kw.name] = {kw.type, kw.fn};
|
||||
|
||||
// separate the entry string
|
||||
if (lexer(entry, _keywordsMap, elements, errors)) {
|
||||
// make objects from parsed elements
|
||||
for (Lexer::SynElement& element : elements) {
|
||||
switch (element.type) {
|
||||
case cmd_number:
|
||||
push_back(new number(element.re, element.reBase));
|
||||
break;
|
||||
case cmd_complex:
|
||||
push_back(new ocomplex(element.re, element.im, element.reBase, element.imBase));
|
||||
break;
|
||||
case cmd_string:
|
||||
push_back(new ostring(element.value));
|
||||
break;
|
||||
case cmd_symbol:
|
||||
push_back(new symbol(element.value, element.autoEval));
|
||||
break;
|
||||
case cmd_program:
|
||||
push_back(new oprogram(element.value));
|
||||
break;
|
||||
case cmd_keyword:
|
||||
push_back(new keyword(element.fn, element.value));
|
||||
break;
|
||||
case cmd_branch:
|
||||
push_back(new branch((branch_fn_t)element.fn, element.value));
|
||||
break;
|
||||
default:
|
||||
show_error(ret_unknown_err, "error creating program from entry");
|
||||
}
|
||||
}
|
||||
} else
|
||||
for (SynError& err : errors) show_syntax_error(err.err.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief show the last error set
|
||||
///
|
||||
/// @return ret_value see this type
|
||||
///
|
||||
ret_value program::show_error() {
|
||||
ret_value ret;
|
||||
|
||||
// clang-format off
|
||||
vector<string> errorStrings {"ok", "unknown command", "missing operand", "bad operand type",
|
||||
"out of range", "unknown variable", "internal error, aborting", "deadly", "goodbye", "not implemented",
|
||||
"no operation", "syntax error", "division by zero", "runtime error", "aborted current entry", "out of memory",
|
||||
"bad value"};
|
||||
// clang-format on
|
||||
// show last recorded error
|
||||
cerr << _err_context << ": error " << _err << ": " << s_ret_value_string[_err] << endl;
|
||||
if ((size_t)_err < errorStrings.size())
|
||||
cerr << _err_context << ": error " << _err << ": " << errorStrings[_err] << endl;
|
||||
else
|
||||
cerr << _err_context << " (unknown error code)" << endl;
|
||||
switch (_err) {
|
||||
case ret_internal:
|
||||
case ret_deadly:
|
||||
|
@ -634,17 +699,14 @@ ret_value program::get_err(void) { return _err; }
|
|||
/// @param st the stack to show
|
||||
/// @param show_separator whether to show a stack level prefix or not
|
||||
///
|
||||
void program::show_stack(stack& st, bool show_separator) {
|
||||
if (st.size() == 1) {
|
||||
((object*)st.back())->show();
|
||||
printf("\n");
|
||||
} else {
|
||||
void program::show_stack(rpnstack& st, bool show_separator) {
|
||||
if (st.size() == 1)
|
||||
cout << st[0] << endl;
|
||||
else
|
||||
for (int i = st.size() - 1; i >= 0; i--) {
|
||||
if (show_separator) printf("%d%s", i + 1, SHOW_STACK_SEPARATOR);
|
||||
((object*)st[i])->show();
|
||||
printf("\n");
|
||||
if (show_separator) cout << i + 1 << "> ";
|
||||
cout << st[i] << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief apply default precision mode and digits
|
||||
|
@ -652,14 +714,9 @@ void program::show_stack(stack& st, bool show_separator) {
|
|||
void program::apply_default() {
|
||||
// default float precision, float mode
|
||||
number::s_mode = DEFAULT_MODE;
|
||||
number::s_decimal_digits = DEFAULT_DECIMAL_DIGITS;
|
||||
number::s_digits = DEFAULT_DECIMAL_DIGITS;
|
||||
mpreal::set_default_prec(MPFR_DEFAULT_PREC_BITS);
|
||||
|
||||
// format for mpfr_printf
|
||||
stringstream ss;
|
||||
ss << number::s_decimal_digits;
|
||||
number::s_mpfr_printf_format = string(MPFR_FORMAT_BEG) + ss.str() + string(MPFR_FORMAT_STD);
|
||||
|
||||
// default calc precision for MPFR
|
||||
floating_t::s_mpfr_prec = (mpfr_prec_t)MPFR_DEFAULT_PREC_BITS;
|
||||
floating_t::s_mpfr_prec_bytes = MPFR_DEFAULT_STORING_LENGTH_BYTES;
|
||||
static mp_rnd_t def_rnd = mpreal::get_default_rnd();
|
||||
mpreal::set_default_rnd(def_rnd);
|
||||
}
|
||||
|
|
114
src/program.hpp
114
src/program.hpp
|
@ -1,31 +1,21 @@
|
|||
#ifndef PROGRAM_HPP
|
||||
#define PROGRAM_HPP
|
||||
|
||||
// std c
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
// std c++
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
// external libs
|
||||
#define MPFR_USE_NO_MACRO
|
||||
#include <mpfr.h>
|
||||
#include "linenoise.h"
|
||||
#include <mpreal.h>
|
||||
using namespace mpfr;
|
||||
|
||||
// internal includes
|
||||
#include "constant.h"
|
||||
#include "debug.h"
|
||||
#include "escape.h"
|
||||
#include "object.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "version.h"
|
||||
#include "lexer.hpp"
|
||||
|
||||
//< convinient structure to preprocess a program
|
||||
struct if_layout_t {
|
||||
|
@ -40,23 +30,23 @@ 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 stack {
|
||||
class program : public deque<object*>, public Lexer {
|
||||
public:
|
||||
program(program* parent_prog = NULL) {
|
||||
_parent_prog = parent_prog;
|
||||
program(rpnstack& stk, heap& hp, program* parent = nullptr):_stack(stk),_heap(hp),_parent(parent) {
|
||||
interrupt_now = false;
|
||||
}
|
||||
virtual ~program() {
|
||||
_local_heap.clear();
|
||||
clear();
|
||||
}
|
||||
|
||||
// parser
|
||||
static ret_value parse(const char* entry, program& prog);
|
||||
static ret_value entry(program& prog);
|
||||
static void entry_completion_generator(const char* text, linenoiseCompletions* lc);
|
||||
ret_value parse(string& entry);
|
||||
static ret_value get_fn(const char* fn_name, program_fn_t& fn, cmd_type_t& type);
|
||||
|
||||
// running
|
||||
ret_value run(stack& stk, heap& hp);
|
||||
ret_value run();
|
||||
void stop();
|
||||
bool compare_keyword(keyword* k, const char* str_to_compare, int len);
|
||||
bool compare_branch(branch* b, const char* str_to_compare, int len);
|
||||
ret_value preprocess(void);
|
||||
|
||||
|
@ -66,10 +56,12 @@ class program : public stack {
|
|||
void show_syntax_error(const char* context);
|
||||
ret_value get_err(void);
|
||||
|
||||
static void show_stack(stack& st, bool show_separator = true);
|
||||
static void show_stack(rpnstack& st, bool show_separator = true);
|
||||
|
||||
static void apply_default();
|
||||
|
||||
static vector<string>& getAutocompletionWords();
|
||||
|
||||
private:
|
||||
bool interrupt_now;
|
||||
|
||||
|
@ -78,33 +70,30 @@ class program : public stack {
|
|||
string _err_context;
|
||||
|
||||
// global stack holding results for user
|
||||
stack* _stack;
|
||||
rpnstack& _stack;
|
||||
|
||||
// global heap (sto, rcl)
|
||||
heap* _heap;
|
||||
heap& _heap;
|
||||
|
||||
// local heap for local loop variables (for..next)
|
||||
heap _local_heap;
|
||||
|
||||
// calc stack internally used by branch and calc commands
|
||||
stack _calc_stack;
|
||||
|
||||
// parent prog for inheriting heaps
|
||||
program* _parent_prog;
|
||||
program* _parent;
|
||||
|
||||
int stack_size() { return _stack->size(); }
|
||||
int stack_size() { return _stack.size(); }
|
||||
|
||||
private:
|
||||
static const char* s_ret_value_string[ret_max];
|
||||
|
||||
// keywords
|
||||
struct keyword_t {
|
||||
cmd_type_t type;
|
||||
char name[MAX_COMMAND_LENGTH];
|
||||
string name;
|
||||
program_fn_t fn;
|
||||
string comment;
|
||||
};
|
||||
static keyword_t s_keywords[];
|
||||
static vector<keyword_t> _keywords;
|
||||
static map<string, Lexer::ReservedWord> _keywordsMap;
|
||||
static vector<string> _autocompletionWords;
|
||||
|
||||
// keywords implementation
|
||||
////
|
||||
|
@ -168,7 +157,7 @@ class program : public stack {
|
|||
void rpn_atanh();
|
||||
|
||||
// program
|
||||
bool find_variable(string& variable, object*& obj, unsigned int& size);
|
||||
bool find_variable(string& variable, object*& obj);
|
||||
void rpn_eval(void);
|
||||
int rpn_inprog(branch& myobj);
|
||||
|
||||
|
@ -243,14 +232,14 @@ class program : public stack {
|
|||
void rpn_strsub();
|
||||
|
||||
// test-core
|
||||
void test_get_stack(string& stack_is, stack& stk);
|
||||
void test_get_stack(string& stack_is, rpnstack& stk);
|
||||
void test_show_result(string title, int tests, int tests_failed, int steps, int steps_failed);
|
||||
void rpn_test();
|
||||
void test(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps,
|
||||
int& total_steps_failed);
|
||||
|
||||
// test
|
||||
int cmp_strings_on_stack_top();
|
||||
long cmp_strings_on_stack_top();
|
||||
void rpn_sup(void);
|
||||
void rpn_sup_eq(void);
|
||||
void rpn_inf(void);
|
||||
|
@ -280,51 +269,26 @@ class program : public stack {
|
|||
void rpn_ticks();
|
||||
};
|
||||
|
||||
// convinience macros for rpn_xx function
|
||||
// clang-format off
|
||||
|
||||
// convenience macros for rpn_xx function
|
||||
// carefull : some of these macros modify program flow
|
||||
#define ERR_CONTEXT(err) \
|
||||
do { \
|
||||
_err = (err); \
|
||||
_err_context = __FUNCTION__; \
|
||||
#define setErrorContext(err) do { _err = (err); _err_context = __FUNCTION__; } while (0)
|
||||
|
||||
#define MIN_ARGUMENTS(num) do { \
|
||||
if (stack_size() < (num)) { setErrorContext(ret_missing_operand); return; } \
|
||||
} while (0)
|
||||
|
||||
#define MIN_ARGUMENTS(num) \
|
||||
do { \
|
||||
if (stack_size() < (num)) { \
|
||||
ERR_CONTEXT(ret_missing_operand); \
|
||||
return; \
|
||||
} \
|
||||
#define MIN_ARGUMENTS_RET(num, ret) do { \
|
||||
if (stack_size() < (num)) { setErrorContext(ret_missing_operand); return (ret); } \
|
||||
} while (0)
|
||||
|
||||
#define MIN_ARGUMENTS_RET(num, ret) \
|
||||
do { \
|
||||
if (stack_size() < (num)) { \
|
||||
ERR_CONTEXT(ret_missing_operand); \
|
||||
return (ret); \
|
||||
} \
|
||||
#define ARG_MUST_BE_OF_TYPE(num, type) do { \
|
||||
if (_stack.at(num)->_type != (type)) { setErrorContext(ret_bad_operand_type); return; } \
|
||||
} while (0)
|
||||
|
||||
#define ARG_MUST_BE_OF_TYPE(num, type) \
|
||||
do { \
|
||||
if (_stack->get_type(num) != (type)) { \
|
||||
ERR_CONTEXT(ret_bad_operand_type); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) \
|
||||
do { \
|
||||
if (_stack->get_type(num) != (type)) { \
|
||||
ERR_CONTEXT(ret_bad_operand_type); \
|
||||
return (ret); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define IS_ARG_TYPE(num, type) (_stack->get_type(num) == (type))
|
||||
|
||||
#define CHECK_MPFR(op) \
|
||||
do { \
|
||||
(void)(op); \
|
||||
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) do { \
|
||||
if (_stack.at(num)->_type != (type)) { setErrorContext(ret_bad_operand_type); return (ret); } \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @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
|
||||
|
@ -11,16 +11,16 @@ int program::rpn_if(branch& myobj) {
|
|||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
|
||||
if (mpfr_cmp_si(((number*)_stack->get_obj(0))->_value.mpfr, 0UL) != 0)
|
||||
if (_stack.value<number>(0) != 0)
|
||||
myobj.arg1 = 1;
|
||||
else
|
||||
myobj.arg1 = 0;
|
||||
(void)_stack->pop_back();
|
||||
_stack.pop();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// @brief then keyword (branch) implementation
|
||||
///
|
||||
///
|
||||
/// @param myobj the current branch object
|
||||
/// @return int index of the next object to run in the current program
|
||||
///
|
||||
|
@ -30,7 +30,7 @@ int program::rpn_then(branch& myobj) {
|
|||
// 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*)seq_obj(myobj.arg3);
|
||||
branch* if_cmd = (branch*)at(myobj.arg3);
|
||||
if (if_cmd->arg1 == 1)
|
||||
return myobj.arg1;
|
||||
else
|
||||
|
@ -38,7 +38,7 @@ 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
|
||||
|
@ -49,7 +49,7 @@ int program::rpn_else(branch& myobj) {
|
|||
// 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*)seq_obj(myobj.arg3);
|
||||
branch* if_cmd = (branch*)at(myobj.arg3);
|
||||
if (if_cmd->arg1 == 1)
|
||||
return myobj.arg2;
|
||||
else
|
||||
|
@ -57,7 +57,7 @@ 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
|
||||
|
@ -72,8 +72,8 @@ int program::rpn_end(branch& myobj) {
|
|||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
|
||||
// check arg
|
||||
number* arg = (number*)_stack->pop_back();
|
||||
if (mpfr_cmp_si(arg->_value.mpfr, 0UL) == 0) ret = myobj.arg1;
|
||||
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)
|
||||
|
@ -83,7 +83,7 @@ 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
|
||||
|
@ -94,7 +94,7 @@ int program::rpn_do(branch& myobj) {
|
|||
}
|
||||
|
||||
/// @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
|
||||
|
@ -105,7 +105,7 @@ int program::rpn_until(branch& myobj) {
|
|||
}
|
||||
|
||||
/// @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
|
||||
|
@ -116,20 +116,15 @@ void program::rpn_ift(void) {
|
|||
|
||||
// check ift arg
|
||||
// arg is true if number != 0 or if is nan or +/-inf
|
||||
number* testee = ((number*)_stack->get_obj(1));
|
||||
|
||||
if (!mpfr_zero_p(testee->_value.mpfr)) {
|
||||
CHECK_MPFR(stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack));
|
||||
(void)_stack->pop_back(2);
|
||||
|
||||
CHECK_MPFR(stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack));
|
||||
(void)_calc_stack.pop_back();
|
||||
} else
|
||||
(void)_stack->pop_back(2);
|
||||
if (_stack.value<number>(1) != 0) {
|
||||
_stack.erase(1);
|
||||
} else {
|
||||
_stack.pop_front(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// @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
|
||||
|
@ -139,22 +134,17 @@ void program::rpn_ifte(void) {
|
|||
ARG_MUST_BE_OF_TYPE(2, cmd_number);
|
||||
|
||||
// check ifte arg
|
||||
// arg is true if number != 0 or if is nan or +/-inf
|
||||
number* testee = ((number*)_stack->get_obj(2));
|
||||
|
||||
if (!mpfr_zero_p(testee->_value.mpfr))
|
||||
CHECK_MPFR(stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack));
|
||||
else
|
||||
CHECK_MPFR(stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack));
|
||||
|
||||
(void)_stack->pop_back(3);
|
||||
|
||||
CHECK_MPFR(stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack));
|
||||
(void)_calc_stack.pop_back();
|
||||
if (_stack.value<number>(2) != 0) {
|
||||
_stack.erase(2);
|
||||
_stack.pop();
|
||||
} else {
|
||||
_stack.erase(2);
|
||||
_stack.erase(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// @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
|
||||
|
@ -165,7 +155,7 @@ int program::rpn_while(branch& myobj) {
|
|||
}
|
||||
|
||||
/// @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
|
||||
|
@ -178,14 +168,14 @@ int program::rpn_repeat(branch& myobj) {
|
|||
|
||||
// check arg
|
||||
// myobj.arg1 is end+1
|
||||
number* arg = (number*)_stack->pop_back();
|
||||
if (mpfr_cmp_si(arg->_value.mpfr, 0UL) == 0) ret = myobj.arg1;
|
||||
if (_stack.value<number>(0) == 0) ret = myobj.arg1;
|
||||
_stack.pop();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @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
|
||||
|
@ -197,18 +187,13 @@ int program::rpn_start(branch& myobj) {
|
|||
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);
|
||||
|
||||
// farg2 = last value of start command
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
myobj.farg2 = (number*)_calc_stack.back();
|
||||
_stack->pop_back();
|
||||
|
||||
// farg1 = first value of start command
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
myobj.farg1 = (number*)_calc_stack.back();
|
||||
_stack->pop_back();
|
||||
// loop boundaries
|
||||
myobj.firstIndex = _stack.value<number>(1);
|
||||
myobj.lastIndex = _stack.value<number>(0);
|
||||
_stack.pop_front(2);
|
||||
|
||||
// test value
|
||||
if (myobj.farg1->_value > myobj.farg2->_value)
|
||||
if (myobj.firstIndex > myobj.lastIndex)
|
||||
// last boundary lower than first boundary
|
||||
// -> next command shall be after 'next'
|
||||
// arg2 holds index of 'next'
|
||||
|
@ -218,7 +203,7 @@ 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
|
||||
|
@ -230,68 +215,67 @@ int program::rpn_for(branch& myobj) {
|
|||
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);
|
||||
|
||||
symbol* sym = ((symbol*)seq_obj(myobj.arg1));
|
||||
symbol* sym = (symbol*)at(myobj.arg1); // arg1 = loop variable index
|
||||
|
||||
// farg2 = last value of for command
|
||||
// arg1 = index of symbol to increase
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
myobj.farg2 = (number*)_calc_stack.back();
|
||||
_stack->pop_back();
|
||||
|
||||
// farg1 = first value of for command
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
myobj.farg1 = (number*)_calc_stack.back();
|
||||
_stack->pop_back();
|
||||
// loop boundaries
|
||||
myobj.firstIndex = _stack.value<number>(1);
|
||||
myobj.lastIndex = _stack.value<number>(0);
|
||||
|
||||
// test value
|
||||
if (myobj.farg1->_value > myobj.farg2->_value)
|
||||
if (myobj.firstIndex > myobj.lastIndex)
|
||||
// last boundary lower than first boundary
|
||||
// -> next command shall be after 'next'
|
||||
// arg2 holds index of 'next'
|
||||
ret = myobj.arg2 + 1;
|
||||
else {
|
||||
// store symbol with first value
|
||||
_local_heap.add(sym->_value, (object*)myobj.farg1, myobj.farg1->size());
|
||||
auto it = _local_heap.find(sym->value);
|
||||
if (it != _local_heap.end()) {
|
||||
delete it->second;
|
||||
_local_heap.erase(it);
|
||||
}
|
||||
_local_heap[sym->value] = _stack.obj<number>(1).clone();
|
||||
ret = myobj.arg1 + 1;
|
||||
}
|
||||
|
||||
_stack.pop_front(2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @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
|
||||
///
|
||||
int program::rpn_next(branch& myobj) {
|
||||
// arg1 = index of start or for command in program
|
||||
// farg1 = current count
|
||||
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
|
||||
// arg1 = loop variable index
|
||||
// firstIndex = current point in the loop
|
||||
branch* start_or_for = (branch*)at(myobj.arg1);
|
||||
if (!myobj.arg_bool) {
|
||||
myobj.arg_bool = true;
|
||||
myobj.farg1 = start_or_for->farg1;
|
||||
myobj.firstIndex = start_or_for->firstIndex;
|
||||
}
|
||||
|
||||
// increment then test
|
||||
// carefull: round toward minus infinity to avoid missing last boundary (because growing step)
|
||||
mpfr_add_si(myobj.farg1->_value.mpfr, myobj.farg1->_value.mpfr, 1UL, MPFR_RNDD);
|
||||
mpfr_add(myobj.firstIndex.mpfr_ptr(), myobj.firstIndex.mpfr_srcptr(), mpreal(1).mpfr_srcptr(), MPFR_RNDD);
|
||||
|
||||
// for command: increment symbol too
|
||||
if (start_or_for->arg1 != -1) {
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
|
||||
symbol* var = (symbol*)at(start_or_for->arg1);
|
||||
|
||||
// increase symbol variable
|
||||
_local_heap.replace_value(string(var->_value), myobj.farg1, myobj.farg1->size());
|
||||
// store symbol variable (asserted existing in the local heap)
|
||||
((number*)_local_heap[var->value])->value = myobj.firstIndex;
|
||||
}
|
||||
|
||||
// test value
|
||||
if (myobj.farg1->_value > start_or_for->farg2->_value) {
|
||||
if (myobj.firstIndex > start_or_for->lastIndex) {
|
||||
// end of loop
|
||||
myobj.arg_bool = false; // init again next time
|
||||
_calc_stack.pop_back(2);
|
||||
return -1;
|
||||
} else {
|
||||
// for command: next instruction will be after symbol variable
|
||||
|
@ -303,7 +287,7 @@ 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
|
||||
|
@ -313,39 +297,39 @@ int program::rpn_step(branch& myobj) {
|
|||
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
|
||||
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
|
||||
|
||||
number* step = (number*)_stack->pop_back();
|
||||
mpreal step = _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
|
||||
// end of loop if step is negative or zero
|
||||
if (mpfr_cmp_d(step->_value.mpfr, 0.0) <= 0)
|
||||
if (step <= 0)
|
||||
ret = -1;
|
||||
else {
|
||||
// arg1 = index of start or for command in program
|
||||
// farg1 = current count
|
||||
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
|
||||
// arg1 = loop variable index
|
||||
// firstIndex = current count
|
||||
branch* start_or_for = (branch*)at(myobj.arg1);
|
||||
if (!myobj.arg_bool) {
|
||||
myobj.arg_bool = true;
|
||||
myobj.farg1 = start_or_for->farg1;
|
||||
myobj.firstIndex = start_or_for->firstIndex;
|
||||
}
|
||||
|
||||
// increment then test
|
||||
// carefull: round toward minus infinity to avoid missing last boundary (because growing step)
|
||||
mpfr_add(myobj.farg1->_value.mpfr, myobj.farg1->_value.mpfr, step->_value.mpfr, MPFR_RNDD);
|
||||
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*)seq_obj(start_or_for->arg1);
|
||||
symbol* var = (symbol*)at(start_or_for->arg1);
|
||||
|
||||
// increase symbol variable
|
||||
_local_heap.replace_value(string(var->_value), myobj.farg1, myobj.farg1->size());
|
||||
}
|
||||
((number*)_local_heap[var->value])->value = myobj.firstIndex;
|
||||
}
|
||||
|
||||
// test loop value is out of range
|
||||
if (myobj.farg1->_value > start_or_for->farg2->_value) {
|
||||
if (myobj.firstIndex > start_or_for->lastIndex) {
|
||||
// end of loop
|
||||
myobj.arg_bool = false; // init again next time
|
||||
_calc_stack.pop_back(2);
|
||||
ret = -1;
|
||||
} else {
|
||||
// for command: next instruction will be after symbol variable
|
||||
|
|
|
@ -6,13 +6,8 @@
|
|||
void program::rpn_re() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
number* re = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set(re->_value.mpfr, ((complex*)_calc_stack.get_obj(0))->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
_calc_stack.pop_back();
|
||||
_stack.push_front(new number(real(_stack.value<ocomplex>(0))));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
||||
/// @brief im keyword implementation
|
||||
|
@ -21,13 +16,8 @@ void program::rpn_re() {
|
|||
void program::rpn_im() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
number* im = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set(im->_value.mpfr, ((complex*)_calc_stack.get_obj(0))->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
_calc_stack.pop_back();
|
||||
_stack.push_front(new number(imag(_stack.value<ocomplex>(0))));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
||||
/// @brief arg keyword implementation
|
||||
|
@ -36,15 +26,8 @@ void program::rpn_im() {
|
|||
void program::rpn_arg() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
||||
// calc atan2(x/y)
|
||||
complex* cplx = (complex*)_stack->pop_back();
|
||||
number* num = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
|
||||
CHECK_MPFR(mpfr_atan2(num->_value.mpfr, cplx->im()->mpfr, cplx->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
_calc_stack.pop_back();
|
||||
_stack.push_front(new number(arg(_stack.value<ocomplex>(0))));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
||||
/// @brief conj keyword implementation
|
||||
|
@ -53,9 +36,7 @@ void program::rpn_arg() {
|
|||
void program::rpn_conj() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
||||
complex* cplx = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_neg(cplx->im()->mpfr, cplx->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<ocomplex>(0) = conj(_stack.value<ocomplex>(0));
|
||||
}
|
||||
|
||||
/// @brief r2c keyword implementation
|
||||
|
@ -65,16 +46,8 @@ void program::rpn_r2c() {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
_stack->pop_back();
|
||||
|
||||
complex* cplx = (complex*)_stack->allocate_back(complex::calc_size(), cmd_complex);
|
||||
CHECK_MPFR(mpfr_set(cplx->re()->mpfr, ((number*)_calc_stack.get_obj(1))->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_set(cplx->im()->mpfr, ((number*)_calc_stack.get_obj(0))->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_calc_stack.pop_back(2);
|
||||
_stack.push(new ocomplex(_stack.value<number>(1), _stack.value<number>(0), _stack.obj<ocomplex>(1).reBase, _stack.obj<ocomplex>(0).reBase));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
|
||||
/// @brief c2r keyword implementation
|
||||
|
@ -83,16 +56,9 @@ void program::rpn_r2c() {
|
|||
void program::rpn_c2r() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
number* re = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
number* im = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
|
||||
CHECK_MPFR(mpfr_set(re->_value.mpfr, ((complex*)_calc_stack.back())->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_set(im->_value.mpfr, ((complex*)_calc_stack.back())->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
_calc_stack.pop_back();
|
||||
_stack.push(new number(real(_stack.value<ocomplex>(0)), _stack.obj<ocomplex>(0).reBase));
|
||||
_stack.push(new number(imag(_stack.value<ocomplex>(1)), _stack.obj<ocomplex>(1).imBase));
|
||||
_stack.erase(2);
|
||||
}
|
||||
|
||||
/// @brief r2p keyword implementation
|
||||
|
@ -101,20 +67,10 @@ void program::rpn_c2r() {
|
|||
void program::rpn_r2p() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
||||
rpn_dup();
|
||||
rpn_dup();
|
||||
rpn_arg();
|
||||
|
||||
complex* cplx = (complex*)_stack->get_obj(1);
|
||||
CHECK_MPFR(mpfr_set(cplx->im()->mpfr, ((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack->pop_back();
|
||||
|
||||
rpn_swap();
|
||||
rpn_abs();
|
||||
cplx = (complex*)_stack->get_obj(1);
|
||||
CHECK_MPFR(mpfr_set(cplx->re()->mpfr, ((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack->pop_back();
|
||||
mpreal rho = abs(_stack.value<ocomplex>(0));
|
||||
mpreal theta = arg(_stack.value<ocomplex>(0));
|
||||
_stack.value<ocomplex>(0).real(rho);
|
||||
_stack.value<ocomplex>(0).imag(theta);
|
||||
}
|
||||
|
||||
/// @brief p2r keyword implementation
|
||||
|
@ -123,26 +79,5 @@ void program::rpn_r2p() {
|
|||
void program::rpn_p2r() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_complex);
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
|
||||
// assert complex is polar
|
||||
complex* rhotheta = (complex*)_calc_stack.get_obj(1);
|
||||
number* tmp = (number*)_calc_stack.get_obj(0);
|
||||
complex* result = (complex*)_stack->back();
|
||||
|
||||
// calc cos(theta)
|
||||
CHECK_MPFR(mpfr_set(tmp->_value.mpfr, rhotheta->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_cos(tmp->_value.mpfr, tmp->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// calc rcos(theta)
|
||||
CHECK_MPFR(mpfr_mul(result->re()->mpfr, rhotheta->re()->mpfr, tmp->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// calc sin(theta)
|
||||
CHECK_MPFR(mpfr_set(tmp->_value.mpfr, rhotheta->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sin(tmp->_value.mpfr, tmp->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// calc rsin(theta)
|
||||
CHECK_MPFR(mpfr_mul(result->im()->mpfr, rhotheta->re()->mpfr, tmp->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<ocomplex>(0) = polar(abs(_stack.value<ocomplex>(0)), arg(_stack.value<ocomplex>(0)));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,34 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "escape.h"
|
||||
#include "linenoise.h"
|
||||
#include "program.hpp"
|
||||
#include "version.h"
|
||||
|
||||
// description
|
||||
#define XSTR(a) STR(a)
|
||||
#define STR(a) #a
|
||||
static const string _description{
|
||||
ATTR_BOLD "R" ATTR_OFF "everse " ATTR_BOLD "P" ATTR_OFF "olish " ATTR_BOLD "N" ATTR_OFF
|
||||
"otation language\n\n"
|
||||
"using " ATTR_BOLD "GMP" ATTR_OFF " v" XSTR(__GNU_MP_VERSION) "." XSTR(__GNU_MP_VERSION_MINOR) "." XSTR(
|
||||
__GNU_MP_VERSION_PATCHLEVEL) " under GNU LGPL\n" ATTR_BOLD "MPFR" ATTR_OFF " v" MPFR_VERSION_STRING
|
||||
" under GNU LGPL\n"
|
||||
"and " ATTR_BOLD "linenoise-ng" ATTR_OFF " v" LINENOISE_VERSION
|
||||
" under BSD\n"};
|
||||
|
||||
// syntax
|
||||
static const string _syntax{ATTR_BOLD "Syntax" ATTR_OFF
|
||||
": rpn [command]\n"
|
||||
"with optional command = list of commands"};
|
||||
|
||||
static const map<string, mpfr_rnd_t> _mpfr_round{{"nearest (even)", MPFR_RNDN},
|
||||
{"toward zero", MPFR_RNDZ},
|
||||
{"toward +inf", MPFR_RNDU},
|
||||
{"toward -inf", MPFR_RNDD},
|
||||
{"away from zero", MPFR_RNDA},
|
||||
{"faithful rounding", MPFR_RNDF},
|
||||
{"nearest (away from zero)", MPFR_RNDNA}};
|
||||
|
||||
/// @brief nop keyword implementation
|
||||
///
|
||||
|
@ -8,85 +38,63 @@ void program::rpn_nop() {
|
|||
|
||||
/// @brief quit keyword implementation
|
||||
///
|
||||
void program::rpn_good_bye() { ERR_CONTEXT(ret_good_bye); }
|
||||
void program::rpn_good_bye() { setErrorContext(ret_good_bye); }
|
||||
|
||||
/// @brief nop keyword implementation
|
||||
/// the result is written on stdout
|
||||
///
|
||||
void program::rpn_help() {
|
||||
// software name
|
||||
printf("\n" ATTR_BOLD "%s" ATTR_OFF "\n", uname);
|
||||
cout << endl << ATTR_BOLD << RPN_UNAME << ATTR_OFF << endl;
|
||||
|
||||
// description
|
||||
printf("%s\n\n", description);
|
||||
// _description
|
||||
cout << _description << endl << endl;
|
||||
|
||||
// syntax
|
||||
printf("%s\n", syntax);
|
||||
// _syntax
|
||||
cout << _syntax << endl;
|
||||
|
||||
// keywords
|
||||
unsigned int i = 0;
|
||||
while (s_keywords[i].type != cmd_max) {
|
||||
if (s_keywords[i].comment.size() != 0) {
|
||||
for (auto& kw : _keywords)
|
||||
if (!kw.comment.empty()) {
|
||||
// titles in bold
|
||||
if (s_keywords[i].type == cmd_undef) printf(ATTR_BOLD);
|
||||
if (kw.type == cmd_undef) cout << ATTR_BOLD;
|
||||
// show title or keyword + comment
|
||||
printf("%s\t%s\n", s_keywords[i].name, s_keywords[i].comment.c_str());
|
||||
if (s_keywords[i].type == cmd_undef) printf(ATTR_OFF);
|
||||
cout << kw.name << '\t' << kw.comment << endl;
|
||||
if (kw.type == cmd_undef) cout << ATTR_OFF;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
printf("\n");
|
||||
cout << endl;
|
||||
|
||||
// show mode
|
||||
printf("Current float mode is ");
|
||||
cout << "Current float mode is ";
|
||||
switch (number::s_mode) {
|
||||
case number::std:
|
||||
printf("'std'");
|
||||
cout << "'std'";
|
||||
break;
|
||||
case number::fix:
|
||||
printf("'fix'");
|
||||
cout << "'fix'";
|
||||
break;
|
||||
case number::sci:
|
||||
printf("'sci'");
|
||||
cout << "'sci'";
|
||||
break;
|
||||
default:
|
||||
printf("unknown");
|
||||
cout << "unknown";
|
||||
break;
|
||||
}
|
||||
printf(" with %d digits after the decimal point\n", number::s_decimal_digits);
|
||||
|
||||
// bits precision, decimal digits and rounding mode
|
||||
printf("Current floating point precision is %d bits\n", (int)floating_t::s_mpfr_prec);
|
||||
printf("Current rounding mode is \"%s\"\n", floating_t::s_mpfr_rnd_str[floating_t::s_mpfr_rnd]);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
/// @brief calculate a number of digits for a given base from a precision in bits
|
||||
///
|
||||
/// @param base the base
|
||||
/// @param bit_precision the precision in bits
|
||||
/// @return int the number of digits
|
||||
///
|
||||
static int base_digits_from_bit_precision(int base, int bit_precision) {
|
||||
return (int)ceil(bit_precision * log(2.0) / log((double)base)) - 1;
|
||||
}
|
||||
|
||||
/// @brief print a decimal digit in a given MPFR format
|
||||
///
|
||||
/// @param decimal_digits the number
|
||||
/// @param printf_format the format
|
||||
/// @return string the result string
|
||||
///
|
||||
static string make_digit_format(int decimal_digits, const char* printf_format) {
|
||||
stringstream ss;
|
||||
ss << MPFR_FORMAT_BEG;
|
||||
ss << number::s_decimal_digits;
|
||||
ss << printf_format;
|
||||
return ss.str();
|
||||
cout << " with " << number::s_digits << " digits after the decimal point" << endl;
|
||||
cout << "Current floating point precision is " << (int)mpreal::get_default_prec() << " bits" << endl;
|
||||
for (auto& rn : _mpfr_round)
|
||||
if (rn.second == mpreal::get_default_rnd()) {
|
||||
cout << "Current rounding mode is '" << rn.first << '\'' << endl;
|
||||
break;
|
||||
}
|
||||
cout << endl << endl;
|
||||
}
|
||||
|
||||
/// @brief whether a precision is in the precision min/max
|
||||
///
|
||||
///
|
||||
/// @param precision the precision in bits
|
||||
/// @return true the precision is good
|
||||
/// @return false the precision is not good
|
||||
|
@ -110,15 +118,15 @@ void program::rpn_std() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
double digits = double(((number*)_stack->pop_back())->_value);
|
||||
double digits = double(_stack.value<number>(0));
|
||||
|
||||
if (check_decimal_digits(digits)) {
|
||||
// set mode, decimal digits and print format
|
||||
number::s_mode = number::std;
|
||||
number::s_decimal_digits = (int)digits;
|
||||
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_STD);
|
||||
number::s_digits = (int)digits;
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
setErrorContext(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief fix keyword implementation
|
||||
|
@ -127,15 +135,15 @@ void program::rpn_fix() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
double digits = double(((number*)_stack->pop_back())->_value);
|
||||
double digits = double(_stack.value<number>(0));
|
||||
|
||||
if (check_decimal_digits(digits)) {
|
||||
// set mode, decimal digits and print format
|
||||
number::s_mode = number::fix;
|
||||
number::s_decimal_digits = (int)digits;
|
||||
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_FIX);
|
||||
number::s_digits = (int)digits;
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
setErrorContext(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief sci keyword implementation
|
||||
|
@ -144,34 +152,24 @@ void program::rpn_sci() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
double digits = double(((number*)_stack->pop_back())->_value);
|
||||
double digits = double(_stack.value<number>(0));
|
||||
|
||||
if (check_decimal_digits(digits)) {
|
||||
// set mode, decimal digits and print format
|
||||
number::s_mode = number::sci;
|
||||
number::s_decimal_digits = (int)digits;
|
||||
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_SCI);
|
||||
number::s_digits = (int)digits;
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
setErrorContext(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief version keyword implementation
|
||||
/// @brief _version keyword implementation
|
||||
///
|
||||
void program::rpn_version() {
|
||||
// allocate and set object
|
||||
unsigned int naked_entry_len = strlen(version);
|
||||
ostring* str = (ostring*)_stack->allocate_back(sizeof(ostring) + naked_entry_len + 1, cmd_string);
|
||||
str->set(version, naked_entry_len);
|
||||
}
|
||||
void program::rpn_version() { _stack.push_front(new ostring(RPN_VERSION)); }
|
||||
|
||||
/// @brief uname keyword implementation
|
||||
/// @brief _uname keyword implementation
|
||||
///
|
||||
void program::rpn_uname() {
|
||||
// allocate and set object
|
||||
unsigned int naked_entry_len = strlen(uname);
|
||||
ostring* str = (ostring*)_stack->allocate_back(sizeof(ostring) + naked_entry_len + 1, cmd_string);
|
||||
str->set(uname, naked_entry_len);
|
||||
}
|
||||
void program::rpn_uname() { _stack.push_front(new ostring(RPN_UNAME)); }
|
||||
|
||||
/// @brief history keyword implementation
|
||||
///
|
||||
|
@ -179,7 +177,7 @@ void program::rpn_history() {
|
|||
// see command history on stdout
|
||||
int index = 0;
|
||||
char* line = linenoiseHistoryLine(index);
|
||||
while (line != NULL) {
|
||||
while (line != nullptr) {
|
||||
cout << line << endl;
|
||||
free(line);
|
||||
line = linenoiseHistoryLine(++index);
|
||||
|
@ -190,14 +188,8 @@ void program::rpn_history() {
|
|||
///
|
||||
void program::rpn_type() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
int type = _stack->pop_back()->_type;
|
||||
if (type < 0 || type >= (int)cmd_max) type = (int)cmd_undef;
|
||||
|
||||
unsigned int string_size = strlen(object::s_cmd_type_string[type]);
|
||||
unsigned int size = sizeof(symbol) + string_size + 1;
|
||||
ostring* typ = (ostring*)_stack->allocate_back(size, cmd_string);
|
||||
typ->set(object::s_cmd_type_string[type], string_size);
|
||||
_stack.push(new ostring(_stack.at(0)->name()));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
||||
/// @brief default keyword implementation
|
||||
|
@ -211,19 +203,18 @@ void program::rpn_precision() {
|
|||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
// set precision
|
||||
unsigned long prec = mpfr_get_ui(((number*)_stack->pop_back())->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
unsigned long prec = _stack.value<number>(0).toULong();
|
||||
if (prec >= (unsigned long)MPFR_PREC_MIN && prec <= (unsigned long)MPFR_PREC_MAX) {
|
||||
floating_t::s_mpfr_prec = (mpfr_prec_t)prec;
|
||||
floating_t::s_mpfr_prec_bytes = mpfr_custom_get_size(prec);
|
||||
mpreal::set_default_prec(prec);
|
||||
|
||||
// modify digits seen by user if std mode
|
||||
if (number::s_mode == number::std) {
|
||||
// calc max nb of digits user can see with the current bit precision
|
||||
number::s_decimal_digits = base_digits_from_bit_precision(10, floating_t::s_mpfr_prec);
|
||||
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_STD);
|
||||
number::s_digits = bits2digits(mpreal::get_default_prec());
|
||||
}
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
setErrorContext(ret_out_of_range);
|
||||
}
|
||||
|
||||
/// @brief round keyword implementation
|
||||
|
@ -232,13 +223,12 @@ void program::rpn_round() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
||||
ostring* str = (ostring*)_stack->pop_back();
|
||||
bool done = false;
|
||||
for (int rnd = (int)MPFR_DEFAULT_RND; rnd <= (int)MPFR_RNDA; rnd++) {
|
||||
if (string(floating_t::s_mpfr_rnd_str[rnd]) == str->_value) {
|
||||
floating_t::s_mpfr_rnd = (mpfr_rnd_t)rnd;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (!done) ERR_CONTEXT(ret_out_of_range);
|
||||
map<string, mpfr_rnd_t> matchRound{_mpfr_round};
|
||||
|
||||
auto found = matchRound.find(_stack.value<ostring>(0));
|
||||
if (found != matchRound.end())
|
||||
mpreal::set_default_rnd(found->second);
|
||||
else
|
||||
setErrorContext(ret_out_of_range);
|
||||
_stack.pop();
|
||||
}
|
||||
|
|
347
src/rpn-logs.cpp
347
src/rpn-logs.cpp
|
@ -2,349 +2,172 @@
|
|||
|
||||
/// @brief e keyword implementation
|
||||
///
|
||||
void program::rpn_e(void) {
|
||||
number* euler = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
euler->_value = 1L;
|
||||
CHECK_MPFR(mpfr_exp(euler->_value.mpfr, euler->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
void program::rpn_e(void) { _stack.push(new number(const_euler())); }
|
||||
|
||||
/// @brief log10 keyword implementation
|
||||
///
|
||||
void program::rpn_log10() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
|
||||
// log10(z)=ln(z)/ln(10)
|
||||
rpn_ln();
|
||||
|
||||
number* ten = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(ten->_value.mpfr, 10.0, floating_t::s_mpfr_rnd));
|
||||
rpn_ln();
|
||||
rpn_div();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = log10(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = log10(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief alog10 keyword implementation
|
||||
///
|
||||
void program::rpn_alog10() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
number* ten = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(ten->_value.mpfr, 10.0, floating_t::s_mpfr_rnd));
|
||||
rpn_ln();
|
||||
rpn_mul();
|
||||
rpn_exp();
|
||||
}
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = exp(log(mpreal(10)) * _stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = exp(log(mpreal(10)) * _stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief log2 keyword implementation
|
||||
///
|
||||
void program::rpn_log2() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
|
||||
// log2(z)=ln(z)/ln(2)
|
||||
rpn_ln();
|
||||
|
||||
number* two = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(two->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
|
||||
rpn_ln();
|
||||
rpn_div();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = log(_stack.value<number>(0)) / const_log2();
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = log(_stack.value<ocomplex>(0)) / const_log2();
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief alog2 keyword implementation
|
||||
///
|
||||
void program::rpn_alog2() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
number* two = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(two->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
|
||||
rpn_ln();
|
||||
rpn_mul();
|
||||
rpn_exp();
|
||||
}
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = exp(const_log2() * _stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = exp(const_log2() * _stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief ln keyword implementation
|
||||
///
|
||||
void program::rpn_ln() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
// x<0 -> ln(x) = ln(-x)+i*pi
|
||||
if (mpfr_cmp_si(left->_value.mpfr, 0) < 0) {
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
left = (number*)_calc_stack.back();
|
||||
|
||||
complex* cplx = (complex*)_stack->allocate_back(complex::calc_size(), cmd_complex);
|
||||
CHECK_MPFR(mpfr_neg(cplx->re()->mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_log(cplx->re()->mpfr, cplx->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_const_pi(cplx->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
_calc_stack.pop_back();
|
||||
} else
|
||||
CHECK_MPFR(mpfr_log(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// ln(x+iy) = 0.5*ln(x*x+y*y) + i atan(x/y)
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
floating_t* x = ((complex*)_calc_stack.get_obj(0))->re();
|
||||
floating_t* y = ((complex*)_calc_stack.get_obj(0))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(0))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(0))->im();
|
||||
|
||||
// 1. atan(x/y)
|
||||
CHECK_MPFR(mpfr_atan2(im->mpfr, y->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// 2. 0.5*ln(x*x+y*y)
|
||||
CHECK_MPFR(mpfr_mul(x->mpfr, x->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(y->mpfr, y->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_add(re->mpfr, x->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_log(re->mpfr, re->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul_d(re->mpfr, re->mpfr, 0.5, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = log(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = log(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief exp keyword implementation
|
||||
///
|
||||
void program::rpn_exp() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_exp(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// exp(x)*(cos(y)+i sin(y))
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
floating_t* x = ((complex*)_calc_stack.get_obj(0))->re();
|
||||
floating_t* y = ((complex*)_calc_stack.get_obj(0))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(0))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(0))->im();
|
||||
|
||||
CHECK_MPFR(mpfr_cos(re->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sin(im->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_exp(x->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(re->mpfr, re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(im->mpfr, im->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = exp(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = exp(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief expm keyword implementation
|
||||
///
|
||||
void program::rpn_expm() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
|
||||
// exp(x)-1
|
||||
rpn_exp();
|
||||
|
||||
number* one = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(one->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_minus();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = exp(_stack.value<number>(0)) - mpreal(1);
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = exp(_stack.value<ocomplex>(0)) - mpreal(1);
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief lnp1 keyword implementation
|
||||
///
|
||||
void program::rpn_lnp1() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number || _stack->get_type(0) == cmd_complex) {
|
||||
// ln(x+1)
|
||||
number* one = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(one->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_plus();
|
||||
|
||||
rpn_ln();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = log(_stack.value<number>(0) + 1);
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = log(_stack.value<ocomplex>(0) + mpreal(1));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sinh keyword implementation
|
||||
///
|
||||
void program::rpn_sinh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_sinh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// sinh(x+iy)=sinh(x)cos(y)+icosh(x)sin(y)
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
|
||||
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
|
||||
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(0))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(0))->im();
|
||||
|
||||
CHECK_MPFR(mpfr_sinh(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_cos(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(re->mpfr, re->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
CHECK_MPFR(mpfr_cosh(im->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sin(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(im->mpfr, im->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back(2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = sinh(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = sinh(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief asinh keyword implementation
|
||||
///
|
||||
void program::rpn_asinh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_asinh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// asinh(z)=ln(z+sqrt(1+z*z))
|
||||
rpn_dup();
|
||||
rpn_square();
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_plus();
|
||||
rpn_squareroot();
|
||||
rpn_plus();
|
||||
rpn_ln();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = asinh(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = asinh(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief cosh keyword implementation
|
||||
///
|
||||
void program::rpn_cosh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_cosh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// acosh(x+iy)=cosh(x)cos(y)+isinh(x)sin(y)
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
|
||||
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
|
||||
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(0))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(0))->im();
|
||||
|
||||
CHECK_MPFR(mpfr_cosh(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_cos(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(re->mpfr, re->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
CHECK_MPFR(mpfr_sinh(im->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sin(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(im->mpfr, im->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back(2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = cosh(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = cosh(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief acosh keyword implementation
|
||||
///
|
||||
void program::rpn_acosh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_acosh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// acosh(z)=ln(z+sqrt(z+1)sqrt(z-1))
|
||||
rpn_dup();
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_plus();
|
||||
rpn_dup();
|
||||
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
|
||||
rpn_minus();
|
||||
rpn_mul();
|
||||
rpn_squareroot();
|
||||
rpn_plus();
|
||||
rpn_ln();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = acosh(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = acosh(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief tanh keyword implementation
|
||||
///
|
||||
void program::rpn_tanh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_tanh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// tanh(x+iy)=(tanh(x)+itan(y)) / (1 + itanh(x)tan(y))
|
||||
rpn_dup();
|
||||
|
||||
floating_t* x = ((complex*)_stack->get_obj(1))->re();
|
||||
floating_t* y = ((complex*)_stack->get_obj(1))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(1))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(1))->im();
|
||||
|
||||
CHECK_MPFR(mpfr_tanh(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_tan(im->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
CHECK_MPFR(mpfr_tanh(x->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_tan(y->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(y->mpfr, y->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_set_d(x->mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_div();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = tanh(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = tanh(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief atanh keyword implementation
|
||||
///
|
||||
void program::rpn_atanh() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_atanh(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// atanh(z)=0.5*ln((1+z)/(1-z))
|
||||
rpn_dup();
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_plus();
|
||||
rpn_swap();
|
||||
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_minus();
|
||||
rpn_neg();
|
||||
rpn_div();
|
||||
rpn_ln();
|
||||
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 0.5, floating_t::s_mpfr_rnd));
|
||||
rpn_mul();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = atanh(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = atanh(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
|
|
@ -1,29 +1,28 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief find variable by its name in local heap, parens heaps, global heap
|
||||
///
|
||||
/// @brief find variable by its name in local heap, successive parents heaps, global heap
|
||||
///
|
||||
/// @param variable the variable name to find
|
||||
/// @param obj the variable object found
|
||||
/// @param size its size
|
||||
/// @return true variable was found
|
||||
/// @return false variable was not found
|
||||
///
|
||||
bool program::find_variable(string& variable, object*& obj, unsigned int& size) {
|
||||
bool program::find_variable(string& variable, object*& obj) {
|
||||
bool found = false;
|
||||
program* parent = _parent_prog;
|
||||
program* parent = _parent;
|
||||
|
||||
if (_local_heap.get(variable, obj, size))
|
||||
if (_local_heap.get(variable, obj))
|
||||
found = true;
|
||||
else {
|
||||
while (parent != NULL) {
|
||||
if (parent->_local_heap.get(variable, obj, size)) {
|
||||
while (parent != nullptr) {
|
||||
if (parent->_local_heap.get(variable, obj)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
parent = parent->_parent_prog;
|
||||
parent = parent->_parent;
|
||||
}
|
||||
if (!found) {
|
||||
if (_heap->get(variable, obj, size)) found = true;
|
||||
if (_heap.get(variable, obj)) found = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,40 +36,40 @@ void program::rpn_eval(void) {
|
|||
string prog_text;
|
||||
|
||||
MIN_ARGUMENTS(1);
|
||||
if (IS_ARG_TYPE(0, cmd_symbol)) {
|
||||
if (_stack.type(0) == cmd_symbol) {
|
||||
// recall a variable
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
string variable(_stack.value<symbol>(0));
|
||||
_stack.pop();
|
||||
|
||||
// if variable holds a program, run this program
|
||||
if (find_variable(variable, obj, size)) {
|
||||
if (find_variable(variable, obj)) {
|
||||
if (obj->_type == cmd_program) {
|
||||
prog_text = ((oprogram*)obj)->_value;
|
||||
(void)_stack->pop_back();
|
||||
prog_text = _stack.value<oprogram>(0);
|
||||
_stack.pop();
|
||||
run_prog = true;
|
||||
} else {
|
||||
// else recall this variable (i.e. stack its content)
|
||||
(void)_stack->pop_back();
|
||||
stack::copy_and_push_back(obj, *_stack, size);
|
||||
_stack.push_front(obj);
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_unknown_variable);
|
||||
} else if (IS_ARG_TYPE(0, cmd_program)) {
|
||||
setErrorContext(ret_unknown_variable);
|
||||
} else if (_stack.type(0) == cmd_program) {
|
||||
// eval a program
|
||||
prog_text = ((oprogram*)_stack->pop_back())->_value;
|
||||
prog_text = _stack.value<oprogram>(0);
|
||||
_stack.pop();
|
||||
run_prog = true;
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
|
||||
// run prog if any
|
||||
if (run_prog) {
|
||||
program prog(this);
|
||||
program prog(_stack, _heap, this);
|
||||
|
||||
// make program from entry
|
||||
if (program::parse(prog_text.c_str(), prog) == ret_ok) {
|
||||
if (prog.parse(prog_text) == ret_ok) {
|
||||
// run it
|
||||
prog.run(*_stack, *_heap);
|
||||
prog.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +82,7 @@ int program::rpn_inprog(branch& myobj) {
|
|||
bool prog_found = false;
|
||||
|
||||
if (myobj.arg1 == -1) {
|
||||
ERR_CONTEXT(ret_unknown_err);
|
||||
setErrorContext(ret_unknown_err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -93,15 +92,15 @@ int program::rpn_inprog(branch& myobj) {
|
|||
// find next oprogram object
|
||||
for (unsigned int i = myobj.arg1 + 1; i < size(); i++) {
|
||||
// count symbol
|
||||
if (seq_type(i) == cmd_symbol) count_symbols++;
|
||||
if (at(i)->_type == cmd_symbol) count_symbols++;
|
||||
// stop if prog
|
||||
else if (seq_type(i) == cmd_program) {
|
||||
else if (at(i)->_type == cmd_program) {
|
||||
prog_found = true;
|
||||
break;
|
||||
}
|
||||
// found something other than symbol
|
||||
else {
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
show_error(_err, context);
|
||||
return -1;
|
||||
}
|
||||
|
@ -109,39 +108,39 @@ int program::rpn_inprog(branch& myobj) {
|
|||
|
||||
// found 0 symbols
|
||||
if (count_symbols == 0) {
|
||||
ERR_CONTEXT(ret_syntax);
|
||||
setErrorContext(ret_syntax);
|
||||
show_error(_err, context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// <oprogram> is missing
|
||||
if (!prog_found) {
|
||||
ERR_CONTEXT(ret_syntax);
|
||||
setErrorContext(ret_syntax);
|
||||
show_error(_err, context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check symbols number vs stack size
|
||||
if (stack_size() < count_symbols) {
|
||||
ERR_CONTEXT(ret_missing_operand);
|
||||
setErrorContext(ret_missing_operand);
|
||||
show_error(_err, context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// load variables
|
||||
for (unsigned int i = myobj.arg1 + count_symbols; i > myobj.arg1; i--) {
|
||||
_local_heap.add(string(((symbol*)seq_obj(i))->_value), _stack->get_obj(0), _stack->get_len(0));
|
||||
(void)_stack->pop_back();
|
||||
_local_heap[string(((symbol*)at(i))->value)] = _stack.at(0)->clone();
|
||||
_stack.pop_front();
|
||||
}
|
||||
|
||||
// run the program
|
||||
string entry(((oprogram*)seq_obj(myobj.arg1 + count_symbols + 1))->_value);
|
||||
program prog(this);
|
||||
string entry(((oprogram*)at(myobj.arg1 + count_symbols + 1))->value);
|
||||
program prog(_stack, _heap, this);
|
||||
|
||||
// make the program from entry
|
||||
if (program::parse(entry.c_str(), prog) == ret_ok) {
|
||||
if (prog.parse(entry) == ret_ok) {
|
||||
// run it
|
||||
prog.run(*_stack, *_heap);
|
||||
prog.run();
|
||||
}
|
||||
|
||||
// point on next command
|
||||
|
|
720
src/rpn-real.cpp
720
src/rpn-real.cpp
|
@ -5,52 +5,33 @@
|
|||
void program::rpn_plus() {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// adding strings
|
||||
if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
|
||||
unsigned int left_str_size = ((ostring*)_stack->get_obj(1))->_len;
|
||||
unsigned int right_str_size = ((ostring*)_stack->get_obj(0))->_len;
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
(void)_stack->pop_back();
|
||||
(void)_stack->pop_back();
|
||||
|
||||
ostring* str =
|
||||
(ostring*)_stack->allocate_back(left_str_size + right_str_size + 1 + sizeof(ostring), cmd_string);
|
||||
str->_len = left_str_size + right_str_size;
|
||||
|
||||
strncpy(str->_value, ((ostring*)_calc_stack.get_obj(1))->_value, left_str_size);
|
||||
strncat(str->_value, ((ostring*)_calc_stack.get_obj(0))->_value, right_str_size);
|
||||
_calc_stack.pop_back();
|
||||
_calc_stack.pop_back();
|
||||
// strings
|
||||
if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) {
|
||||
_stack.value<ostring>(1) += _stack.value<ostring>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// adding numbers
|
||||
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_add(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
// numbers
|
||||
else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.value<number>(1) += _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// adding complexes
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
|
||||
complex* right = (complex*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_add(left->re()->mpfr, left->re()->mpfr, right->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_add(left->im()->mpfr, left->im()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
// complexes
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) += _stack.value<ocomplex>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// adding complex+number
|
||||
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_add(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
// complex+number
|
||||
else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) += _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// adding number+complex
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
|
||||
// number+complex
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) {
|
||||
rpn_swap();
|
||||
number* right = (number*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_add(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<ocomplex>(1) += _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief - keyword implementation
|
||||
|
@ -58,33 +39,28 @@ void program::rpn_plus() {
|
|||
void program::rpn_minus() {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// substracting numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_sub(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
// numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.value<number>(1) -= _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// substracting complexes
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
|
||||
complex* right = (complex*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_sub(left->re()->mpfr, left->re()->mpfr, right->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sub(left->im()->mpfr, left->im()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
// complexes
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) -= _stack.value<ocomplex>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// substracting complex-number
|
||||
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_sub(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
// subbing complex-number
|
||||
else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) -= _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// substracting number-complex
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
|
||||
// number-complex
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) {
|
||||
rpn_swap();
|
||||
number* right = (number*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_sub(left->re()->mpfr, right->_value.mpfr, left->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<ocomplex>(1) = _stack.value<number>(0) - _stack.value<ocomplex>(1);
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief * keyword implementation
|
||||
|
@ -92,98 +68,28 @@ void program::rpn_minus() {
|
|||
void program::rpn_mul() {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// multiplying numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_mul(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
// mutiplying numbers
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.value<number>(1) *= _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// multiplying complexes (a+ib)*(x+iy)=(ax-by)+i(ay+bx)=a(x+iy)+b(-y+ix)
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
|
||||
complex* right = (complex*)_stack->pop_back(); // x+iy
|
||||
complex* left = (complex*)_stack->back(); // a+ib
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
complex* left_sav = (complex*)_calc_stack.back(); // a+ib
|
||||
|
||||
// left: (a+ib)->(ax+iay)
|
||||
CHECK_MPFR(mpfr_mul(left->re()->mpfr, left->re()->mpfr, right->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(left->im()->mpfr, left_sav->re()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// right: (x+iy)-> (bx-iby)
|
||||
CHECK_MPFR(mpfr_mul(right->im()->mpfr, left_sav->im()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_neg(right->im()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(right->re()->mpfr, left_sav->im()->mpfr, right->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// left=left+transpose(right)
|
||||
CHECK_MPFR(mpfr_add(left->re()->mpfr, left->re()->mpfr, right->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_add(left->im()->mpfr, left->im()->mpfr, right->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back();
|
||||
// mutiplying complexes
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) *= _stack.value<ocomplex>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// multiplying complex*number
|
||||
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_mul(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(left->im()->mpfr, left->im()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
// mutiplying complex*number
|
||||
else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) *= _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// multiplying number*complex
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
|
||||
// mutiplying number*complex
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) {
|
||||
rpn_swap();
|
||||
number* right = (number*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_mul(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(left->im()->mpfr, left->im()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<ocomplex>(1) *= _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief divide the 2 complexes on stack
|
||||
/// result on the prog stack
|
||||
///
|
||||
void program::do_divide_complexes() {
|
||||
//(a+ib)/(x+iy)=(a+ib)(x-iy)/(x^2+y^2)=(ax+by+i(bx-ay))/(x^2+y^2)
|
||||
complex* right = (complex*)_stack->get_obj(0); // x+iy
|
||||
complex* left = (complex*)_stack->get_obj(1); // a+ib
|
||||
|
||||
// 1. calc (x^2-y^2) in _calc_stack
|
||||
number* ex = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_mul(ex->_value.mpfr, right->re()->mpfr, right->re()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // x2
|
||||
number* wy = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_mul(wy->_value.mpfr, right->im()->mpfr, right->im()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // y2
|
||||
CHECK_MPFR(mpfr_add(ex->_value.mpfr, ex->_value.mpfr, wy->_value.mpfr,
|
||||
floating_t::s_mpfr_rnd)); // ex=x2+y2
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack); // x+iy
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
complex* left_sav = (complex*)_calc_stack.get_obj(1); // a+ib
|
||||
complex* right_sav = (complex*)_calc_stack.get_obj(0); // x+iy
|
||||
|
||||
// 2. left.re=ax+by
|
||||
CHECK_MPFR(mpfr_mul(left->re()->mpfr, left_sav->re()->mpfr, right_sav->re()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // left.re=ax
|
||||
CHECK_MPFR(mpfr_mul(right->re()->mpfr, left_sav->im()->mpfr, right_sav->im()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // right.re=by
|
||||
CHECK_MPFR(mpfr_add(left->re()->mpfr, left->re()->mpfr, right->re()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // left.re=ax+by
|
||||
|
||||
// 3. left.im=bx-ay
|
||||
CHECK_MPFR(mpfr_mul(left->im()->mpfr, left_sav->im()->mpfr, right_sav->re()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // left.im=bx
|
||||
CHECK_MPFR(mpfr_mul(right->im()->mpfr, left_sav->re()->mpfr, right_sav->im()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // right.im=ay
|
||||
CHECK_MPFR(mpfr_sub(left->im()->mpfr, left->im()->mpfr, right->im()->mpfr,
|
||||
floating_t::s_mpfr_rnd)); // left.im=bx-ay
|
||||
|
||||
// 4. left.re/=(x^2-y^2), left.im/=(x^2+y^2)
|
||||
CHECK_MPFR(mpfr_div(left->re()->mpfr, left->re()->mpfr, ex->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_div(left->im()->mpfr, left->im()->mpfr, ex->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_stack->pop_back();
|
||||
_calc_stack.pop_back(4);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief / keyword implementation
|
||||
|
@ -192,47 +98,27 @@ void program::rpn_div() {
|
|||
MIN_ARGUMENTS(2);
|
||||
|
||||
// dividing numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_div(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.value<number>(1) /= _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// dividing complexes
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex)
|
||||
do_divide_complexes();
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) /= _stack.value<ocomplex>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// dividing complex/number
|
||||
else if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_complex) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_div(left->re()->mpfr, left->re()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_div(left->im()->mpfr, left->im()->mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) /= _stack.value<number>(0);
|
||||
_stack.pop();
|
||||
}
|
||||
// dividing number/complex
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_number) {
|
||||
// 1. copy out
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1,
|
||||
_calc_stack); // complex
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2,
|
||||
_calc_stack); // number
|
||||
_stack->pop_back(2);
|
||||
|
||||
// 2. copy back (2 complexes on stack)
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2,
|
||||
*_stack); // complex back to stack
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2,
|
||||
*_stack); // complex back to stack
|
||||
|
||||
// 3. set complex level 2 to (number,0)
|
||||
complex* new_cplx = (complex*)_stack->get_obj(1);
|
||||
CHECK_MPFR(
|
||||
mpfr_set(new_cplx->re()->mpfr, ((number*)_calc_stack.get_obj(0))->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_set_ui(new_cplx->im()->mpfr, 0UL, floating_t::s_mpfr_rnd));
|
||||
_calc_stack.pop_back(2);
|
||||
|
||||
// 4. divide
|
||||
do_divide_complexes();
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) {
|
||||
rpn_swap();
|
||||
_stack.value<ocomplex>(1) = _stack.value<number>(0) / _stack.value<ocomplex>(1);
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief neg keyword implementation
|
||||
|
@ -240,15 +126,12 @@ void program::rpn_div() {
|
|||
void program::rpn_neg() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_neg(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
complex* left = (complex*)_stack->back();
|
||||
CHECK_MPFR(mpfr_neg(left->re()->mpfr, left->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_neg(left->im()->mpfr, left->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = -_stack.value<number>(0);
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = -_stack.value<ocomplex>(0);
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief inv keyword implementation
|
||||
|
@ -256,20 +139,119 @@ void program::rpn_neg() {
|
|||
void program::rpn_inv() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_si_div(left->_value.mpfr, 1L, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// 1. duplicate
|
||||
rpn_dup();
|
||||
// 2. set complex level 2 to (1,0)
|
||||
complex* cplx = (complex*)_stack->get_obj(1);
|
||||
CHECK_MPFR(mpfr_set_ui(cplx->re()->mpfr, 1UL, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_set_ui(cplx->im()->mpfr, 0UL, floating_t::s_mpfr_rnd));
|
||||
// 3. divide
|
||||
do_divide_complexes();
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = 1 / _stack.value<number>(0);
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = mpreal{1} / _stack.value<ocomplex>(0);
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief power keyword implementation
|
||||
///
|
||||
void program::rpn_power() {
|
||||
MIN_ARGUMENTS(2);
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
if (_stack.value<number>(1) >= 0) {
|
||||
_stack.value<number>(1) = pow(_stack.value<number>(1), _stack.value<number>(0));
|
||||
_stack.pop();
|
||||
} else {
|
||||
mpreal zero;
|
||||
_stack.push(new ocomplex(_stack.value<number>(1), zero, _stack.obj<number>(1).base));
|
||||
_stack.value<ocomplex>(0) = pow(_stack.value<ocomplex>(0), _stack.value<number>(1));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
} else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) = pow(_stack.value<ocomplex>(1), _stack.value<ocomplex>(0));
|
||||
_stack.pop();
|
||||
} else if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_complex) {
|
||||
_stack.value<ocomplex>(1) = pow(_stack.value<ocomplex>(1), _stack.value<number>(0));
|
||||
_stack.pop();
|
||||
} else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_number) {
|
||||
rpn_swap();
|
||||
_stack.value<ocomplex>(1) = pow(_stack.value<number>(0), _stack.value<ocomplex>(1));
|
||||
_stack.pop();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief sqrt keyword implementation
|
||||
///
|
||||
void program::rpn_squareroot() {
|
||||
MIN_ARGUMENTS(1);
|
||||
if (_stack.type(0) == cmd_number) {
|
||||
if (_stack.value<number>(0) >= 0) {
|
||||
_stack.value<number>(0) = sqrt(_stack.value<number>(0));
|
||||
} else {
|
||||
// negative number -> square root is complex
|
||||
mpreal zero;
|
||||
_stack.push(new ocomplex(_stack.value<number>(0), zero, _stack.obj<number>(0).base)); // TODO manage new errors
|
||||
_stack.value<ocomplex>(0) = sqrt(_stack.value<ocomplex>(0));
|
||||
_stack.erase(1);
|
||||
}
|
||||
} else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = sqrt(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief hex keyword implementation
|
||||
///
|
||||
void program::rpn_hex() {
|
||||
MIN_ARGUMENTS(1);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.obj<number>(0).base = 16;
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.obj<ocomplex>(0).reBase = 16;
|
||||
_stack.obj<ocomplex>(0).imBase = 16;
|
||||
} else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief bin keyword implementation
|
||||
///
|
||||
void program::rpn_bin() {
|
||||
MIN_ARGUMENTS(1);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.obj<number>(0).base = 2;
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.obj<ocomplex>(0).reBase = 2;
|
||||
_stack.obj<ocomplex>(0).imBase = 2;
|
||||
} else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief dec keyword implementation
|
||||
///
|
||||
void program::rpn_dec() {
|
||||
MIN_ARGUMENTS(1);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.obj<number>(0).base = 10;
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.obj<ocomplex>(0).reBase = 10;
|
||||
_stack.obj<ocomplex>(0).imBase = 10;
|
||||
} else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief base keyword implementation
|
||||
///
|
||||
void program::rpn_base() {
|
||||
MIN_ARGUMENTS(2);
|
||||
if (_stack.type(1) == cmd_number || _stack.type(1) == cmd_complex) {
|
||||
int base = (int)_stack.value<number>(0).toLong();
|
||||
_stack.pop();
|
||||
if (base >= BASE_MIN && base <= BASE_MAX) {
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.obj<number>(0).base = base;
|
||||
else {
|
||||
_stack.obj<ocomplex>(0).reBase = base;
|
||||
_stack.obj<ocomplex>(0).imBase = base;
|
||||
}
|
||||
} else
|
||||
setErrorContext(ret_out_of_range);
|
||||
} else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief % (purcent) keyword implementation
|
||||
|
@ -278,12 +260,8 @@ void program::rpn_purcent() {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_mul(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_div_si(left->_value.mpfr, left->_value.mpfr, 100L, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(1) *= _stack.value<number>(0) / 100;
|
||||
_stack.pop();
|
||||
}
|
||||
|
||||
/// @brief %CH keyword implementation
|
||||
|
@ -292,112 +270,20 @@ void program::rpn_purcentCH() {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_mul_si(right->_value.mpfr, right->_value.mpfr, 100L, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_div(left->_value.mpfr, right->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
}
|
||||
|
||||
/// @brief power keyword implementation
|
||||
///
|
||||
void program::rpn_power() {
|
||||
MIN_ARGUMENTS(2);
|
||||
bool done_on_real = false;
|
||||
|
||||
if (_stack->get_type(1) == cmd_number) {
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
number* right = (number*)_stack->get_obj(0);
|
||||
number* left = (number*)_stack->get_obj(1);
|
||||
|
||||
if (mpfr_cmp_d(left->_value.mpfr, 0.0) >= 0) {
|
||||
CHECK_MPFR(mpfr_pow(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack->pop_back();
|
||||
done_on_real = true;
|
||||
} else {
|
||||
// copy power out
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
// negative number -> complex number
|
||||
_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.0, floating_t::s_mpfr_rnd));
|
||||
rpn_r2c();
|
||||
|
||||
// copy power back
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
_calc_stack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// carrefull, no 'else' here
|
||||
if (!done_on_real) {
|
||||
if (_stack->get_type(1) == cmd_complex) {
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
// power on tmp stack
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
// switch complex to polar
|
||||
complex* cplx = (complex*)_stack->back();
|
||||
rpn_r2p();
|
||||
|
||||
// new abs=abs^exponent
|
||||
number* exponent = (number*)_calc_stack.back();
|
||||
CHECK_MPFR(mpfr_pow(cplx->re()->mpfr, cplx->re()->mpfr, exponent->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// new arg=arg*exponent
|
||||
CHECK_MPFR(mpfr_mul(cplx->im()->mpfr, cplx->im()->mpfr, exponent->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// back to cartesian
|
||||
rpn_p2r();
|
||||
_calc_stack.pop_back();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief sqrt keyword implementation
|
||||
///
|
||||
void program::rpn_squareroot() {
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp_d(left->_value.mpfr, 0.0) >= 0)
|
||||
CHECK_MPFR(mpfr_sqrt(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
else {
|
||||
// negative number -> complex square root
|
||||
_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.0, floating_t::s_mpfr_rnd));
|
||||
rpn_r2c();
|
||||
_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.5, floating_t::s_mpfr_rnd));
|
||||
rpn_power();
|
||||
}
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// calc cplx^0.5
|
||||
_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(((number*)_stack->back())->_value.mpfr, 0.5, floating_t::s_mpfr_rnd));
|
||||
rpn_power();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
_stack.value<number>(1) = (_stack.value<number>(0) * 100) / _stack.value<number>(1);
|
||||
_stack.pop();
|
||||
}
|
||||
|
||||
/// @brief sq keyword implementation
|
||||
///
|
||||
void program::rpn_square() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_sqr(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
rpn_dup();
|
||||
rpn_mul();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) *= _stack.value<number>(0);
|
||||
else if (_stack.at(0)->_type == cmd_complex)
|
||||
_stack.value<ocomplex>(0) *= _stack.value<ocomplex>(0);
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief mod keyword implementation
|
||||
|
@ -406,83 +292,21 @@ void program::rpn_modulo() {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_fmod(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(1) = fmod(_stack.value<number>(1), _stack.value<number>(0));
|
||||
_stack.pop();
|
||||
}
|
||||
|
||||
/// @brief abs keyword implementation
|
||||
///
|
||||
void program::rpn_abs() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
number* left = (number*)_stack->back();
|
||||
CHECK_MPFR(mpfr_abs(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// 1. copy out -> calc x2+iy2
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
// 2. calc x2+iy2
|
||||
complex* cplx = (complex*)_calc_stack.back();
|
||||
CHECK_MPFR(mpfr_mul(cplx->re()->mpfr, cplx->re()->mpfr, cplx->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(cplx->im()->mpfr, cplx->im()->mpfr, cplx->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// 3. new real on stack
|
||||
_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
number* module = (number*)_stack->back();
|
||||
|
||||
// 4. set it to |x2+y2| then take sqrt
|
||||
CHECK_MPFR(mpfr_set(module->_value.mpfr, cplx->re()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_add(module->_value.mpfr, module->_value.mpfr, cplx->im()->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sqrt(module->_value.mpfr, module->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back();
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = abs(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex) {
|
||||
_stack.push(new number(abs(_stack.value<ocomplex>(0))));
|
||||
_stack.erase(1);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief hex keyword implementation
|
||||
///
|
||||
void program::rpn_hex() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
((number*)_stack->back())->_representation = number::hex;
|
||||
number::s_decimal_digits = 0;
|
||||
}
|
||||
|
||||
/// @brief bin keyword implementation
|
||||
///
|
||||
void program::rpn_bin() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
((number*)_stack->back())->_representation = number::bin;
|
||||
}
|
||||
|
||||
/// @brief dec keyword implementation
|
||||
///
|
||||
void program::rpn_dec() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
((number*)_stack->back())->_representation = number::dec;
|
||||
}
|
||||
|
||||
/// @brief base keyword implementation
|
||||
///
|
||||
void program::rpn_base() {
|
||||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
if (mpfr_cmp_d(((number*)_stack->back())->_value.mpfr, (double)BASE_MIN) >= 0 &&
|
||||
mpfr_cmp_d(((number*)_stack->back())->_value.mpfr, (double)BASE_MAX) <= 0) {
|
||||
int base = (int)mpfr_get_d(((number*)_stack->pop_back())->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
((number*)_stack->get_obj(0))->_base = base;
|
||||
((number*)_stack->get_obj(0))->_representation = number::base;
|
||||
} else
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief fact (factorial) keyword implementation
|
||||
|
@ -490,33 +314,20 @@ void program::rpn_base() {
|
|||
void program::rpn_fact() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
// fact(n) = gamma(n+1)
|
||||
number* left = (number*)_stack->back();
|
||||
number* right = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
right->_value = 1L;
|
||||
rpn_plus();
|
||||
|
||||
CHECK_MPFR(mpfr_gamma(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(0) = gamma(_stack.value<number>(0) + 1);
|
||||
}
|
||||
|
||||
/// @brief sign keyword implementation
|
||||
///
|
||||
void program::rpn_sign() {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
// fact(n) = gamma(n+1)
|
||||
number* left = (number*)_stack->back();
|
||||
int result = mpfr_sgn(left->_value.mpfr);
|
||||
left->_value = (long)result;
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// calc x/sqrt(x*x+y*y) +iy/sqrt(x*x+y*y)
|
||||
rpn_dup();
|
||||
rpn_abs();
|
||||
rpn_div();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = sgn(_stack.value<number>(0));
|
||||
else if (_stack.at(0)->_type == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = _stack.value<ocomplex>(0) / abs(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief mant keyword implementation
|
||||
|
@ -524,31 +335,12 @@ void program::rpn_sign() {
|
|||
void program::rpn_mant() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_number_p(left->_value.mpfr)) {
|
||||
if (mpfr_zero_p(left->_value.mpfr))
|
||||
left->_value = 0.0;
|
||||
else {
|
||||
mpfr_abs(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
|
||||
number* one = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
number* ten = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
ten->_value = 10L;
|
||||
|
||||
one->_value = 1L;
|
||||
while (mpfr_greaterequal_p(left->_value.mpfr, one->_value.mpfr))
|
||||
mpfr_div(left->_value.mpfr, left->_value.mpfr, ten->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
|
||||
one->_value = 0.1;
|
||||
while (mpfr_less_p(left->_value.mpfr, one->_value.mpfr))
|
||||
mpfr_mul(left->_value.mpfr, left->_value.mpfr, ten->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
|
||||
_calc_stack.pop_back(2);
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
if (!isfinite(_stack.value<number>(0))) {
|
||||
setErrorContext(ret_out_of_range);
|
||||
return;
|
||||
}
|
||||
mp_exp_t exp;
|
||||
_stack.value<number>(0) = frexp(_stack.value<number>(0), &exp);
|
||||
}
|
||||
|
||||
/// @brief xpon keyword implementation
|
||||
|
@ -556,39 +348,13 @@ void program::rpn_mant() {
|
|||
void program::rpn_xpon() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_number_p(left->_value.mpfr)) {
|
||||
if (mpfr_zero_p(left->_value.mpfr))
|
||||
left->_value = 0.0;
|
||||
else {
|
||||
double exponant = 0.0;
|
||||
mpfr_abs(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
|
||||
number* one = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
number* ten = (number*)_calc_stack.allocate_back(number::calc_size(), cmd_number);
|
||||
ten->_value = 10L;
|
||||
|
||||
one->_value = 1L;
|
||||
while (mpfr_greaterequal_p(left->_value.mpfr, one->_value.mpfr)) {
|
||||
mpfr_div(left->_value.mpfr, left->_value.mpfr, ten->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
exponant += 1.0;
|
||||
}
|
||||
|
||||
one->_value = 0.1;
|
||||
while (mpfr_less_p(left->_value.mpfr, one->_value.mpfr)) {
|
||||
mpfr_mul(left->_value.mpfr, left->_value.mpfr, ten->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
exponant -= 1.0;
|
||||
}
|
||||
|
||||
left->_value = exponant;
|
||||
|
||||
_calc_stack.pop_back();
|
||||
_calc_stack.pop_back();
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
if (!isfinite(_stack.value<number>(0))) {
|
||||
setErrorContext(ret_out_of_range);
|
||||
return;
|
||||
}
|
||||
mp_exp_t exp;
|
||||
(void)frexp(_stack.value<number>(0), &exp);
|
||||
_stack.value<number>(0) = exp;
|
||||
}
|
||||
|
||||
/// @brief floor keyword implementation
|
||||
|
@ -596,10 +362,7 @@ void program::rpn_xpon() {
|
|||
void program::rpn_floor() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_floor(left->_value.mpfr, left->_value.mpfr));
|
||||
_stack.value<number>(0) = floor(_stack.value<number>(0));
|
||||
}
|
||||
|
||||
/// @brief ceil keyword implementation
|
||||
|
@ -607,10 +370,7 @@ void program::rpn_floor() {
|
|||
void program::rpn_ceil() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_ceil(left->_value.mpfr, left->_value.mpfr));
|
||||
_stack.value<number>(0) = ceil(_stack.value<number>(0));
|
||||
}
|
||||
|
||||
/// @brief fp keyword implementation
|
||||
|
@ -618,10 +378,7 @@ void program::rpn_ceil() {
|
|||
void program::rpn_fp() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_frac(left->_value.mpfr, left->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(0) = frac(_stack.value<number>(0));
|
||||
}
|
||||
|
||||
/// @brief ip keyword implementation
|
||||
|
@ -629,10 +386,7 @@ void program::rpn_fp() {
|
|||
void program::rpn_ip() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_trunc(left->_value.mpfr, left->_value.mpfr));
|
||||
_stack.value<number>(0) = trunc(_stack.value<number>(0));
|
||||
}
|
||||
|
||||
/// @brief min keyword implementation
|
||||
|
@ -641,11 +395,8 @@ void program::rpn_min() {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_min(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(0) = min(_stack.value<number>(0), _stack.value<number>(1));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
||||
/// @brief max keyword implementation
|
||||
|
@ -654,9 +405,6 @@ void program::rpn_max() {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
CHECK_MPFR(mpfr_max(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(0) = max(_stack.value<number>(0), _stack.value<number>(1));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
|
|
@ -4,26 +4,23 @@
|
|||
///
|
||||
void program::rpn_swap(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
|
||||
(void)_stack->pop_back(2);
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2, *_stack);
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
_calc_stack.pop_back(2);
|
||||
object* tmp = _stack.front();
|
||||
_stack.erase(0, 1, false);
|
||||
_stack.insert(_stack.begin() + 1, tmp);
|
||||
}
|
||||
|
||||
/// @brief drop keyword implementation
|
||||
///
|
||||
void program::rpn_drop(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
(void)_stack->pop_back();
|
||||
_stack.pop();
|
||||
}
|
||||
|
||||
/// @brief drop2 keyword implementation
|
||||
///
|
||||
void program::rpn_drop2(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
(void)_stack->pop_back(2);
|
||||
_stack.pop_front(2);
|
||||
}
|
||||
|
||||
/// @brief dropn keyword implementation
|
||||
|
@ -32,29 +29,20 @@ void program::rpn_dropn(void) {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
int args = (int)_stack.value<number>(0).toLong();
|
||||
MIN_ARGUMENTS(args + 1);
|
||||
|
||||
(void)_stack->pop_back(args + 1);
|
||||
_stack.erase(0, args + 1);
|
||||
}
|
||||
|
||||
/// @brief erase / del keyword implementation
|
||||
///
|
||||
void program::rpn_erase(void) { (void)_stack->pop_back(_stack->size()); }
|
||||
void program::rpn_erase(void) { _stack.erase(0, _stack.size()); }
|
||||
|
||||
/// @brief dup keyword implementation
|
||||
///
|
||||
void program::rpn_dup(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, *_stack);
|
||||
}
|
||||
|
||||
/// @brief dup2 keyword implementation
|
||||
///
|
||||
void program::rpn_dup2(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
|
||||
rpnstack::copy_and_push_front(_stack, 0, _stack);
|
||||
}
|
||||
|
||||
/// @brief dupn keyword implementation
|
||||
|
@ -63,11 +51,19 @@ void program::rpn_dupn(void) {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
MIN_ARGUMENTS(args + 1);
|
||||
_stack->pop_back();
|
||||
int args = (int)((number*)_stack.front())->value.toLong();
|
||||
_stack.pop();
|
||||
|
||||
for (int i = 0; i < args; i++) stack::copy_and_push_back(*_stack, _stack->size() - args, *_stack);
|
||||
MIN_ARGUMENTS(args);
|
||||
for (int i = 0; i < args; i++) rpnstack::copy_and_push_front(_stack, args - 1, _stack);
|
||||
}
|
||||
|
||||
/// @brief dup2 keyword implementation
|
||||
///
|
||||
void program::rpn_dup2(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
rpnstack::copy_and_push_front(_stack, 1, _stack);
|
||||
rpnstack::copy_and_push_front(_stack, 1, _stack);
|
||||
}
|
||||
|
||||
/// @brief pick keyword implementation
|
||||
|
@ -76,39 +72,30 @@ void program::rpn_pick(void) {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
unsigned int to_pick = (unsigned int)int(((number*)_stack->pop_back())->_value);
|
||||
unsigned int to_pick = (unsigned int)_stack.value<number>(0);
|
||||
_stack.pop();
|
||||
|
||||
// treat stack depth errors
|
||||
if ((to_pick == 0) || (to_pick > _stack->size())) {
|
||||
ERR_CONTEXT(ret_out_of_range);
|
||||
if ((to_pick == 0) || (to_pick > _stack.size())) {
|
||||
setErrorContext(ret_out_of_range);
|
||||
return;
|
||||
}
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - to_pick, *_stack);
|
||||
rpnstack::copy_and_push_front(_stack, to_pick - 1, _stack);
|
||||
}
|
||||
|
||||
/// @brief rot keyword implementation
|
||||
///
|
||||
void program::rpn_rot(void) {
|
||||
MIN_ARGUMENTS(3);
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 3, _calc_stack);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, _calc_stack);
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
(void)_stack->pop_back(3);
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 2, *_stack);
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 3, *_stack);
|
||||
_calc_stack.pop_back(3);
|
||||
object* tmp = _stack.at(2);
|
||||
_stack.erase(2, 1, false);
|
||||
_stack.insert(_stack.begin(), tmp);
|
||||
}
|
||||
|
||||
/// @brief depth keyword implementation
|
||||
///
|
||||
void program::rpn_depth(void) {
|
||||
unsigned long depth = (unsigned long)_stack->size();
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
num->set(depth);
|
||||
}
|
||||
void program::rpn_depth(void) { _stack.push_front(new number(_stack.size())); }
|
||||
|
||||
/// @brief roll keyword implementation
|
||||
///
|
||||
|
@ -116,19 +103,13 @@ void program::rpn_roll(void) {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
MIN_ARGUMENTS(args + 1);
|
||||
_stack->pop_back();
|
||||
size_t args = (int)((number*)_stack.front())->value;
|
||||
_stack.pop();
|
||||
MIN_ARGUMENTS(args);
|
||||
|
||||
for (int i = 0; i < args; i++) {
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
(void)_stack->pop_back();
|
||||
}
|
||||
|
||||
for (int i = 1; i < args; i++) stack::copy_and_push_back(_calc_stack, args - 1 - i, *_stack);
|
||||
stack::copy_and_push_back(_calc_stack, args - 1, *_stack);
|
||||
|
||||
_calc_stack.pop_back(args);
|
||||
object* tmp = _stack.at(args - 1);
|
||||
_stack.erase(args - 1, 1, false);
|
||||
_stack.insert(_stack.begin(), tmp);
|
||||
}
|
||||
|
||||
/// @brief rolld keyword implementation
|
||||
|
@ -137,20 +118,13 @@ void program::rpn_rolld(void) {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
int args = (int)mpfr_get_si(((number*)_stack->back())->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
MIN_ARGUMENTS(args + 1);
|
||||
_stack->pop_back();
|
||||
int args = (int)((number*)_stack.front())->value.toLong();
|
||||
_stack.pop();
|
||||
MIN_ARGUMENTS(args);
|
||||
|
||||
for (int i = 0; i < args; i++) {
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
(void)_stack->pop_back();
|
||||
}
|
||||
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - args, *_stack);
|
||||
|
||||
for (int i = 1; i < args; i++) stack::copy_and_push_back(_calc_stack, _calc_stack.size() - i, *_stack);
|
||||
|
||||
_calc_stack.pop_back(args);
|
||||
object* tmp = _stack.at(0);
|
||||
_stack.erase(0, 1, false);
|
||||
_stack.insert(_stack.begin() + args - 1, tmp);
|
||||
}
|
||||
|
||||
/// @brief over keyword implementation
|
||||
|
@ -158,5 +132,6 @@ void program::rpn_rolld(void) {
|
|||
void program::rpn_over(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 2, *_stack);
|
||||
rpnstack::copy_and_push_front(_stack, 1, _stack);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "program.hpp"
|
||||
#include "input.hpp"
|
||||
|
||||
/// @brief sto keyword implementation
|
||||
///
|
||||
|
@ -6,173 +7,114 @@ void program::rpn_sto(void) {
|
|||
MIN_ARGUMENTS(2);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
|
||||
string name(((symbol*)_stack->pop_back())->_value);
|
||||
_heap->add(name, _stack->get_obj(0), _stack->get_len(0));
|
||||
(void)_stack->pop_back();
|
||||
// store symbol with first value
|
||||
const auto it = _heap.find(_stack.value<ostring>(0));
|
||||
if (it != _heap.end()) {
|
||||
delete it->second;
|
||||
_heap.erase(it);
|
||||
}
|
||||
_heap[_stack.value<ostring>(0)] = _stack.at(1)->clone();
|
||||
_stack.pop_front(2);
|
||||
}
|
||||
|
||||
/// @brief sto+ keyword implementation
|
||||
///
|
||||
void program::rpn_stoadd(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
|
||||
// get variable value on stack level 1, make op then modify variable
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
rpn_plus();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
|
||||
// copy value, get variable value on stack level 1,
|
||||
// put back value on stack level 1, make op then modify variable
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
rpn_plus();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
if (_heap.find(_stack.value<ostring>(0)) == _heap.end()) {
|
||||
setErrorContext(ret_unknown_variable);
|
||||
return;
|
||||
}
|
||||
rpn_dup();
|
||||
rpn_rcl(); // TODO is rcl the good one? it will recall local variables too
|
||||
rpn_rot();
|
||||
rpn_plus();
|
||||
rpn_swap();
|
||||
rpn_sto();
|
||||
}
|
||||
|
||||
/// @brief sto- keyword implementation
|
||||
///
|
||||
void program::rpn_stosub(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
|
||||
// get variable value on stack level 1, make op then modify variable
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
rpn_minus();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
|
||||
// copy value, get variable value on stack level 1,
|
||||
// put back value on stack level 1, make op then modify variable
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
rpn_minus();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
if (_heap.find(_stack.value<ostring>(0)) == _heap.end()) {
|
||||
setErrorContext(ret_unknown_variable);
|
||||
return;
|
||||
}
|
||||
rpn_dup();
|
||||
rpn_rcl();
|
||||
rpn_rot();
|
||||
rpn_minus();
|
||||
rpn_swap();
|
||||
rpn_sto();
|
||||
}
|
||||
|
||||
/// @brief sto* keyword implementation
|
||||
///
|
||||
void program::rpn_stomul(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
|
||||
// get variable value on stack level 1, make op then modify variable
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
rpn_mul();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
|
||||
// copy value, get variable value on stack level 1,
|
||||
// put back value on stack level 1, make op then modify variable
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
rpn_mul();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
if (_heap.find(_stack.value<ostring>(0)) == _heap.end()) {
|
||||
setErrorContext(ret_unknown_variable);
|
||||
return;
|
||||
}
|
||||
rpn_dup();
|
||||
rpn_rcl();
|
||||
rpn_rot();
|
||||
rpn_mul();
|
||||
rpn_swap();
|
||||
rpn_sto();
|
||||
}
|
||||
|
||||
/// @brief sto/ keyword implementation
|
||||
///
|
||||
void program::rpn_stodiv(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
if (_stack->get_type(0) == cmd_symbol && _stack->get_type(1) == cmd_number) {
|
||||
// get variable value on stack level 1, make op then modify variable
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
rpn_div();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else if (_stack->get_type(1) == cmd_symbol && _stack->get_type(0) == cmd_number) {
|
||||
// copy value, get variable value on stack level 1,
|
||||
// put back value on stack level 1, make op then modify variable
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
_stack->pop_back();
|
||||
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
rpn_div();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
if (_heap.find(_stack.value<ostring>(0)) == _heap.end()) {
|
||||
setErrorContext(ret_unknown_variable);
|
||||
return;
|
||||
}
|
||||
rpn_dup();
|
||||
rpn_rcl();
|
||||
rpn_rot();
|
||||
rpn_div();
|
||||
rpn_swap();
|
||||
rpn_sto();
|
||||
}
|
||||
|
||||
/// @brief stosneg keyword implementation
|
||||
///
|
||||
void program::rpn_stoneg(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_symbol) {
|
||||
// get variable value on stack level 1, make op then modify variable
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
rpn_neg();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
if (_heap.find(_stack.value<ostring>(0)) == _heap.end()) {
|
||||
setErrorContext(ret_unknown_variable);
|
||||
return;
|
||||
}
|
||||
rpn_dup();
|
||||
rpn_rcl();
|
||||
rpn_neg();
|
||||
rpn_swap();
|
||||
rpn_sto();
|
||||
}
|
||||
|
||||
/// @brief sinv keyword implementation
|
||||
///
|
||||
void program::rpn_stoinv(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_symbol) {
|
||||
// get variable value on stack level 1, make op then modify variable
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
rpn_rcl();
|
||||
if (_err == ret_ok) {
|
||||
rpn_inv();
|
||||
_heap->add(variable, _stack->get_obj(0), _stack->get_len(0));
|
||||
_stack->pop_back();
|
||||
}
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
if (_heap.find(_stack.value<ostring>(0)) == _heap.end()) {
|
||||
setErrorContext(ret_unknown_variable);
|
||||
return;
|
||||
}
|
||||
rpn_dup();
|
||||
rpn_rcl();
|
||||
rpn_inv();
|
||||
rpn_swap();
|
||||
rpn_sto();
|
||||
}
|
||||
|
||||
/// @brief rcl keyword implementation
|
||||
|
@ -183,15 +125,14 @@ void program::rpn_rcl(void) {
|
|||
|
||||
// recall a variable
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
string variable(((symbol*)_stack->back())->_value);
|
||||
string variable(_stack.value<symbol>(0));
|
||||
|
||||
// mind the order of heaps
|
||||
if (find_variable(variable, obj, size)) {
|
||||
(void)_stack->pop_back();
|
||||
stack::copy_and_push_back(obj, *_stack, size);
|
||||
if (find_variable(variable, obj)) {
|
||||
(void)_stack.pop_front();
|
||||
_stack.push_front(obj->clone());
|
||||
} else
|
||||
ERR_CONTEXT(ret_unknown_variable);
|
||||
setErrorContext(ret_unknown_variable);
|
||||
}
|
||||
|
||||
/// @brief edit keyword implementation
|
||||
|
@ -199,47 +140,33 @@ void program::rpn_rcl(void) {
|
|||
void program::rpn_edit(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
FILE* tmp = tmpfile();
|
||||
if (tmp != NULL) {
|
||||
// re-write stack objet in a stream
|
||||
((object*)_stack->pop_back())->show(tmp);
|
||||
ostringstream st;
|
||||
|
||||
// edit: stuff chars using linenoise facility
|
||||
int len = (int)ftell(tmp);
|
||||
rewind(tmp);
|
||||
// re-write stack objet in a stream
|
||||
_stack.at(0)->show(st);
|
||||
_stack.pop();
|
||||
|
||||
// get stream data
|
||||
void* file_data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(tmp), 0);
|
||||
if (file_data != MAP_FAILED) {
|
||||
// set it as the linenoise line entry
|
||||
linenoisePreloadBuffer((const char*)file_data);
|
||||
munmap(file_data, len);
|
||||
} else
|
||||
ERR_CONTEXT(ret_runtime_error);
|
||||
|
||||
fclose(tmp);
|
||||
} else
|
||||
ERR_CONTEXT(ret_runtime_error);
|
||||
// set it as the linenoise line entry
|
||||
Input::preload(st.str().c_str());
|
||||
}
|
||||
|
||||
/// @brief recall then eval a symbol variable if it is auto-evaluable
|
||||
///
|
||||
///
|
||||
/// @param symb the smlbol to recall and autoeval
|
||||
///
|
||||
void program::auto_rcl(symbol* symb) {
|
||||
if (symb->_auto_eval) {
|
||||
if (symb->autoEval) {
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
string variable(symb->_value);
|
||||
string variable(symb->value);
|
||||
|
||||
// mind the order of heaps
|
||||
if (find_variable(variable, obj, size)) {
|
||||
stack::copy_and_push_back(obj, *_stack, size);
|
||||
if (find_variable(variable, obj)) {
|
||||
_stack.push_front(obj->clone());
|
||||
if (obj->_type == cmd_program) rpn_eval();
|
||||
} else
|
||||
stack::copy_and_push_back(symb, *_stack, symb->size());
|
||||
_stack.push_front(symb->clone());
|
||||
} else
|
||||
stack::copy_and_push_back(symb, *_stack, symb->size());
|
||||
_stack.push_front(symb->clone());
|
||||
}
|
||||
|
||||
/// @brief purge keyword implementation
|
||||
|
@ -248,47 +175,50 @@ void program::rpn_purge(void) {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
|
||||
|
||||
string name(((symbol*)_stack->pop_back())->_value);
|
||||
if (!_heap->erase(name)) ERR_CONTEXT(ret_unknown_variable);
|
||||
const auto i = _heap.find(_stack.value<symbol>(0));
|
||||
if (i != _heap.end()) {
|
||||
delete i->second;
|
||||
_heap.erase(i);
|
||||
} else
|
||||
setErrorContext(ret_unknown_variable);
|
||||
_stack.pop();
|
||||
}
|
||||
|
||||
/// @brief vars keyword implementation
|
||||
///
|
||||
void program::rpn_vars(void) {
|
||||
object* obj;
|
||||
unsigned int size;
|
||||
program* parent = _parent_prog;
|
||||
program* parent = _parent;
|
||||
string name;
|
||||
|
||||
// heap variables
|
||||
for (int i = 0; i < (int)_heap->count_vars(); i++) {
|
||||
(void)_heap->get_by_index(i, name, obj, size);
|
||||
printf("var %d: name '%s', type %s, value ", i + 1, name.c_str(), object::s_cmd_type_string[obj->_type]);
|
||||
obj->show();
|
||||
printf("\n");
|
||||
for (int i = 0; i < (int)_heap.size(); i++) {
|
||||
(void)_heap.get_by_index(i, name, obj);
|
||||
cout<<"var "<<i+1<<": name '"<<name<<"', type "<<obj->name()<<", value ";
|
||||
obj->show(cout);
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
// parents local variables
|
||||
while (parent != NULL) {
|
||||
while (parent != nullptr) {
|
||||
for (int i = 0; i < (int)parent->_local_heap.size(); i++) {
|
||||
(void)parent->_local_heap.get_by_index(i, name, obj, size);
|
||||
printf("local var %d: name '%s', type %s, value ", i + 1, name.c_str(),
|
||||
object::s_cmd_type_string[obj->_type]);
|
||||
obj->show();
|
||||
printf("\n");
|
||||
(void)parent->_local_heap.get_by_index(i, name, obj);
|
||||
cout<<"var "<<i+1<<": name '"<<name<<"', type "<<obj->name()<<", value ";
|
||||
obj->show(cout);
|
||||
cout<<endl;
|
||||
}
|
||||
parent = parent->_parent_prog;
|
||||
parent = parent->_parent;
|
||||
}
|
||||
|
||||
// local variables
|
||||
for (int i = 0; i < (int)_local_heap.size(); i++) {
|
||||
(void)_local_heap.get_by_index(i, name, obj, size);
|
||||
printf("local var %d: name '%s', type %s, value ", i + 1, name.c_str(), object::s_cmd_type_string[obj->_type]);
|
||||
obj->show();
|
||||
printf("\n");
|
||||
(void)_local_heap.get_by_index(i, name, obj);
|
||||
cout<<"var "<<i+1<<": name '"<<name<<"', type "<<obj->name()<<", value ";
|
||||
obj->show(cout);
|
||||
cout<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief clusr keyword implementation
|
||||
///
|
||||
void program::rpn_clusr(void) { _heap->erase_all(); }
|
||||
void program::rpn_clusr(void) { _heap.clear(); }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
#include "program.hpp"
|
||||
|
||||
/// @brief ->str keyword implementation
|
||||
|
@ -6,24 +8,11 @@ void program::rpn_instr() {
|
|||
MIN_ARGUMENTS(1);
|
||||
|
||||
// stringify only if not already a string
|
||||
if (_stack->get_type(0) != cmd_string) {
|
||||
// write the object in stack(0) in a string and remove this obj
|
||||
FILE* tmp = tmpfile();
|
||||
if (tmp != NULL) {
|
||||
((object*)_stack->pop_back())->show(tmp);
|
||||
|
||||
// reserve the correct size on stack
|
||||
unsigned int str_size = (unsigned int)ftell(tmp);
|
||||
ostring* str = (ostring*)_stack->allocate_back(str_size + 1 + sizeof(ostring), cmd_string);
|
||||
str->_len = str_size;
|
||||
|
||||
// fill the obj
|
||||
rewind(tmp);
|
||||
if (fread(str->_value, str_size, 1, tmp) != 1) ERR_CONTEXT(ret_runtime_error);
|
||||
str->_value[str_size] = 0;
|
||||
fclose(tmp);
|
||||
} else
|
||||
ERR_CONTEXT(ret_runtime_error);
|
||||
if (_stack.type(0) != cmd_string) {
|
||||
stringstream ss;
|
||||
ss << _stack.at(0);
|
||||
_stack.pop();
|
||||
_stack.push(new ostring(ss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,14 +22,14 @@ void program::rpn_strout() {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
||||
string entry(((ostring*)_stack->pop_back())->_value);
|
||||
|
||||
program prog;
|
||||
string entry(_stack.value<ostring>(0));
|
||||
program prog(_stack, _heap);
|
||||
_stack.pop();
|
||||
|
||||
// make program from string in stack level 1
|
||||
if (program::parse(entry.c_str(), prog) == ret_ok)
|
||||
if (prog.parse(entry) == ret_ok)
|
||||
// run it
|
||||
prog.run(*_stack, *_heap);
|
||||
prog.run();
|
||||
}
|
||||
|
||||
/// @brief chr keyword implementation
|
||||
|
@ -48,17 +37,10 @@ void program::rpn_strout() {
|
|||
void program::rpn_chr() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
// get arg as number % 256
|
||||
char the_chr = (char)mpfr_get_d(((number*)_stack->pop_back())->_value.mpfr, floating_t::s_mpfr_rnd);
|
||||
char the_chr = (char)(int)_stack.value<number>(0);
|
||||
_stack.pop();
|
||||
if (the_chr < 32 || the_chr > 126) the_chr = '.';
|
||||
|
||||
// reserve the correct size on stack (1 char)
|
||||
unsigned int str_size = 1;
|
||||
ostring* str = (ostring*)_stack->allocate_back(str_size + 1 + sizeof(ostring), cmd_string);
|
||||
str->_len = str_size;
|
||||
str->_value[0] = the_chr;
|
||||
str->_value[1] = 0;
|
||||
_stack.push_front(new ostring(string(1, the_chr)));
|
||||
}
|
||||
|
||||
/// @brief num keyword implementation
|
||||
|
@ -66,10 +48,11 @@ void program::rpn_chr() {
|
|||
void program::rpn_num() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
||||
double the_chr = (double)((ostring*)_stack->pop_back())->_value[0];
|
||||
number* numb = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
numb->_value = the_chr;
|
||||
if (_stack.value<ostring>(0).size() > 0)
|
||||
_stack.push_front(new number(_stack.value<ostring>(0)[0]));
|
||||
else
|
||||
_stack.push_front(new number(0));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
||||
/// @brief size keyword implementation
|
||||
|
@ -77,10 +60,8 @@ void program::rpn_num() {
|
|||
void program::rpn_strsize() {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
|
||||
double len = ((ostring*)_stack->pop_back())->_len;
|
||||
number* numb = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
numb->_value = len;
|
||||
_stack.push_front(new number(_stack.value<ostring>(0).size()));
|
||||
_stack.erase(1);
|
||||
}
|
||||
|
||||
/// @brief pos keyword implementation
|
||||
|
@ -90,15 +71,9 @@ void program::rpn_strpos() {
|
|||
ARG_MUST_BE_OF_TYPE(0, cmd_string);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_string);
|
||||
|
||||
long pos = 0;
|
||||
char* src = ((ostring*)_stack->get_obj(1))->_value;
|
||||
char* found = strstr(src, ((ostring*)_stack->get_obj(0))->_value);
|
||||
if (found != NULL) pos = (long)(found - src) + 1L;
|
||||
|
||||
_stack->pop_back(2);
|
||||
|
||||
number* numb = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
numb->_value = pos;
|
||||
size_t pos = _stack.value<ostring>(1).find(_stack.value<ostring>(0)) + 1;
|
||||
_stack.pop_front(2);
|
||||
_stack.push_front(new number(pos));
|
||||
}
|
||||
|
||||
/// @brief sub keyword implementation
|
||||
|
@ -109,38 +84,11 @@ void program::rpn_strsub() {
|
|||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(2, cmd_string);
|
||||
|
||||
long first = long(((number*)_stack->get_obj(1))->_value) - 1;
|
||||
long last = long(((number*)_stack->get_obj(0))->_value) - 1;
|
||||
long len = ((ostring*)_stack->get_obj(2))->_len;
|
||||
bool result_is_void = false;
|
||||
size_t first = (size_t)_stack.value<number>(1);
|
||||
size_t len = (size_t)_stack.value<number>(0) - first + 1;
|
||||
first--;
|
||||
|
||||
_stack->pop_back(2);
|
||||
|
||||
if (first < 0) first = 0;
|
||||
if (last < 0) last = 0;
|
||||
if (first > len && last > len)
|
||||
result_is_void = true;
|
||||
else {
|
||||
if (first > len) first = len - 1;
|
||||
if (last > len) last = len - 1;
|
||||
if (first > last) result_is_void = true;
|
||||
}
|
||||
|
||||
if (!result_is_void) {
|
||||
unsigned int str_size = last - first + 1;
|
||||
ostring* str = (ostring*)_calc_stack.allocate_back(str_size + 1 + sizeof(ostring), cmd_string);
|
||||
str->_len = str_size;
|
||||
|
||||
memcpy(((ostring*)_calc_stack.back())->_value, ((ostring*)_stack->get_obj(0))->_value + first, str_size);
|
||||
((ostring*)_calc_stack.back())->_value[str_size] = 0;
|
||||
|
||||
_stack->pop_back();
|
||||
stack::copy_and_push_back(_calc_stack, _calc_stack.size() - 1, *_stack);
|
||||
_calc_stack.pop_back();
|
||||
} else {
|
||||
_stack->pop_back();
|
||||
ostring* str = (ostring*)_stack->allocate_back(1 + sizeof(ostring), cmd_string);
|
||||
str->_len = 0;
|
||||
str->_value[0] = 0;
|
||||
}
|
||||
if (first > _stack.value<ostring>(2).size()) first = len = 0;
|
||||
_stack.push(new ostring(_stack.value<ostring>(2).substr(first, len)));
|
||||
_stack.erase(1, 3);
|
||||
}
|
||||
|
|
|
@ -1,35 +1,32 @@
|
|||
#include <regex>
|
||||
using namespace std;
|
||||
|
||||
#include "version.h"
|
||||
#include "escape.h"
|
||||
#include "program.hpp"
|
||||
|
||||
/// @brief write stack in a string, each entry separated between commas
|
||||
///
|
||||
///
|
||||
/// @param stack_is the output string
|
||||
/// @param stk the stack
|
||||
///
|
||||
void program::test_get_stack(string& stack_is, stack& stk) {
|
||||
for (int i = 0; i < (int)stk.size(); i++) {
|
||||
FILE* tmp_file = tmpfile();
|
||||
char* line = NULL;
|
||||
size_t len;
|
||||
|
||||
if (i > 0) stack_is += ", ";
|
||||
|
||||
if (tmp_file != NULL) {
|
||||
((object*)stk.seq_obj(i))->show(tmp_file);
|
||||
|
||||
// write stack in a tmp file
|
||||
(void)rewind(tmp_file);
|
||||
if (getline(&line, &len, tmp_file) >= 0) {
|
||||
stack_is += line;
|
||||
free(line);
|
||||
}
|
||||
(void)fclose(tmp_file);
|
||||
} else
|
||||
ERR_CONTEXT(ret_runtime_error);
|
||||
void program::test_get_stack(string& stack_is, rpnstack& stk) {
|
||||
ostringstream st;
|
||||
if (stk.empty()) {
|
||||
stack_is.clear();
|
||||
return;
|
||||
}
|
||||
stk[stk.size() - 1]->show(st);
|
||||
stack_is += st.str();
|
||||
for (int i = (int)stk.size() - 2; i >= 0; i--) {
|
||||
ostringstream st;
|
||||
stk[i]->show(st);
|
||||
stack_is += ", " + st.str();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief show the tests results
|
||||
///
|
||||
///
|
||||
/// @param title test title
|
||||
/// @param tests tests nb
|
||||
/// @param tests_failed failed tests nb
|
||||
|
@ -37,16 +34,19 @@ void program::test_get_stack(string& stack_is, stack& stk) {
|
|||
/// @param steps_failed failed steps nb
|
||||
///
|
||||
void program::test_show_result(string title, int tests, int tests_failed, int steps, int steps_failed) {
|
||||
printf("%s: run %d tests: %d passed, ", title.c_str(), tests, tests - tests_failed);
|
||||
if (tests_failed > 0) printf(FG_RED);
|
||||
printf("%d failed", tests_failed);
|
||||
if (tests_failed > 0) printf(COLOR_OFF);
|
||||
//cout << title << ": run " << tests << " tests: " << tests - tests_failed << " passed, ";
|
||||
if (!title.empty())
|
||||
cout << title << ": ";
|
||||
cout <<"run " << tests << " tests: " << tests - tests_failed << " passed, ";
|
||||
if (tests_failed > 0) cout << FG_RED;
|
||||
cout << tests_failed << " failed";
|
||||
if (tests_failed > 0) cout << COLOR_OFF;
|
||||
|
||||
printf(" (%d steps: %d passed, ", steps, steps - steps_failed);
|
||||
if (steps_failed > 0) printf(FG_RED);
|
||||
printf("%d failed", steps_failed);
|
||||
if (steps_failed > 0) printf(COLOR_OFF);
|
||||
printf(")\n");
|
||||
cout << " (" << steps << " steps: " << steps - steps_failed << " passed, ";
|
||||
if (steps_failed > 0) cout << FG_RED;
|
||||
cout << steps_failed << " failed";
|
||||
if (steps_failed > 0) cout << COLOR_OFF;
|
||||
cout << ")" << endl;
|
||||
}
|
||||
|
||||
/// @brief test keyword implementation
|
||||
|
@ -60,14 +60,15 @@ void program::rpn_test() {
|
|||
int total_steps = 0;
|
||||
int total_steps_failed = 0;
|
||||
|
||||
string test_filename = ((ostring*)_stack->pop_back())->_value;
|
||||
printf("\nrpn version is %s\n", version);
|
||||
string test_filename = _stack.value<ostring>(0);
|
||||
_stack.pop();
|
||||
cout << endl << "rpn version is " << RPN_VERSION << endl;
|
||||
test(test_filename, total_tests, total_tests_failed, total_steps, total_steps_failed);
|
||||
test_show_result("Total", total_tests, total_tests_failed, total_steps, total_steps_failed);
|
||||
test_show_result("\nTotal", total_tests, total_tests_failed, total_steps, total_steps_failed);
|
||||
}
|
||||
|
||||
/// @brief load a test file and run its tests
|
||||
///
|
||||
///
|
||||
/// @param test_filename the test file filename
|
||||
/// @param total_tests the total tests nb
|
||||
/// @param total_tests_failed the total failed tests nb
|
||||
|
@ -91,7 +92,7 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
|
|||
string test_title;
|
||||
string entry;
|
||||
ret_value ret;
|
||||
stack stk;
|
||||
rpnstack stk;
|
||||
heap hp;
|
||||
bool failed = false;
|
||||
bool is_first_step;
|
||||
|
@ -105,21 +106,22 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
|
|||
|
||||
while (!test_file.eof()) {
|
||||
getline(test_file, entry);
|
||||
if (entry.empty()) continue;
|
||||
|
||||
if (entry.substr(0, 8) == "#include")
|
||||
if (entry.substr(0, 8) == "@include")
|
||||
test(entry.substr(9), total_tests, total_tests_failed, total_steps, total_steps_failed);
|
||||
else if (entry.substr(0, 2) == "##")
|
||||
printf("\n%s: %s\n", test_filename.c_str(), entry.substr(3).c_str());
|
||||
else if (entry.substr(0, 2) == "# ") {
|
||||
else if (entry.substr(0, 2) == "# ")
|
||||
cout << endl << test_filename << ": " << entry.substr(2) << endl;
|
||||
else if (entry.substr(0, 3) == "## ") {
|
||||
// indicates the status of previous test
|
||||
if (failed == false && tests > 0) printf(FG_GREEN " PASSED" COLOR_OFF "\n");
|
||||
if (failed == false && tests > 0) cout << FG_GREEN << " PASSED" << COLOR_OFF << endl;
|
||||
failed = false;
|
||||
|
||||
// read a test title
|
||||
test_title = entry;
|
||||
is_first_step = true;
|
||||
is_test_error_shown = false;
|
||||
printf("%s", test_title.c_str());
|
||||
cout << test_title;
|
||||
}
|
||||
// treat "-> stack size should be "
|
||||
else if (entry.find(stack_size, 0) == 0) {
|
||||
|
@ -136,15 +138,15 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
|
|||
if (size != (int)stk.size()) {
|
||||
// count fail test and step
|
||||
if (!is_test_error_shown) {
|
||||
printf(FG_RED " FAIL" COLOR_OFF "\n");
|
||||
cout << FG_RED << " FAIL" << COLOR_OFF << endl;
|
||||
tests_failed++;
|
||||
is_test_error_shown = true;
|
||||
}
|
||||
steps_failed++;
|
||||
|
||||
// show failure
|
||||
printf("\t%s\n", entry.c_str());
|
||||
printf("\tbut real stack size is " FG_RED "%d" COLOR_OFF "\n", stk.size());
|
||||
cout << '\t' << entry << endl;
|
||||
cout << "\t but real stack size is " << FG_RED << stk.size() << COLOR_OFF << endl;
|
||||
failed = true;
|
||||
}
|
||||
is_first_step = false;
|
||||
|
@ -164,15 +166,15 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
|
|||
if (stack_is != stack_should_be) {
|
||||
// count fail test and step
|
||||
if (!is_test_error_shown) {
|
||||
printf(FG_RED " FAIL" COLOR_OFF "\n");
|
||||
cout << FG_RED << " FAIL" << COLOR_OFF << endl;
|
||||
tests_failed++;
|
||||
is_test_error_shown = true;
|
||||
}
|
||||
steps_failed++;
|
||||
|
||||
// show failure
|
||||
printf("\t%s\n", entry.c_str());
|
||||
printf("\tbut real stack is " FG_RED "%s" COLOR_OFF "\n", stack_is.c_str());
|
||||
cout << '\t' << entry << endl;
|
||||
cout << "\t but real stack is " << FG_RED << stack_is << COLOR_OFF << endl;
|
||||
failed = true;
|
||||
}
|
||||
is_first_step = false;
|
||||
|
@ -191,43 +193,64 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
|
|||
if (err_should_be != last_err) {
|
||||
// count fail test and step
|
||||
if (!is_test_error_shown) {
|
||||
printf(FG_RED " FAIL" COLOR_OFF "\n");
|
||||
cout << FG_RED << " FAIL" << COLOR_OFF << endl;
|
||||
tests_failed++;
|
||||
is_test_error_shown = true;
|
||||
}
|
||||
steps_failed++;
|
||||
|
||||
// show failure
|
||||
printf("\t%s\n", entry.c_str());
|
||||
printf("\tbut last error is " FG_RED "%d" COLOR_OFF "\n", last_err);
|
||||
cout << '\t' << entry << endl;
|
||||
cout << "\t but last error is " << FG_RED << last_err << COLOR_OFF << endl;
|
||||
failed = true;
|
||||
}
|
||||
is_first_step = false;
|
||||
} else if (entry.find(cmd_exit, 0) == 0) {
|
||||
// forced test end
|
||||
break;
|
||||
} else if (entry.size() > 0) {
|
||||
}
|
||||
// treat unknown "->"
|
||||
else if (entry.find("->", 0) == 0) {
|
||||
// count test
|
||||
if (is_first_step) tests++;
|
||||
steps++;
|
||||
|
||||
// count fail test and step
|
||||
if (!is_test_error_shown) {
|
||||
cout << FG_RED << " FAIL" << COLOR_OFF << endl;
|
||||
tests_failed++;
|
||||
is_test_error_shown = true;
|
||||
}
|
||||
steps_failed++;
|
||||
|
||||
// show failure
|
||||
cout << FG_RED << "\tthis test '" << entry << "' is unknown" << COLOR_OFF << endl;
|
||||
failed = true;
|
||||
} else {
|
||||
// parse entry and run line
|
||||
program prog;
|
||||
ret = program::parse(entry.c_str(), prog);
|
||||
if (ret == ret_ok) {
|
||||
// run it
|
||||
(void)prog.run(stk, hp);
|
||||
last_err = (int)prog.get_err();
|
||||
entry = regex_replace(entry, regex("`"), "");
|
||||
if (!entry.empty()) {
|
||||
program prog(stk, hp);
|
||||
ret = prog.parse(entry);
|
||||
if (ret == ret_ok) {
|
||||
// run it
|
||||
(void)prog.run();
|
||||
last_err = (int)prog.get_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// last test
|
||||
// indicates the status of previous test
|
||||
if (failed == false && tests > 0) printf(FG_GREEN " PASSED" COLOR_OFF "\n");
|
||||
if (failed == false && tests > 0) cout << FG_GREEN << " PASSED" << COLOR_OFF << endl;
|
||||
|
||||
// cerr back
|
||||
cerr.rdbuf(cerr_old_buffer);
|
||||
|
||||
// conclusion: show and keep for total
|
||||
if (tests != 0) {
|
||||
test_show_result(test_filename, tests, tests_failed, steps, steps_failed);
|
||||
test_show_result("", tests, tests_failed, steps, steps_failed);
|
||||
|
||||
total_tests += tests;
|
||||
total_tests_failed += tests_failed;
|
||||
|
@ -235,5 +258,5 @@ void program::test(string test_filename, int& total_tests, int& total_tests_fail
|
|||
total_steps_failed += steps_failed;
|
||||
}
|
||||
} else
|
||||
fprintf(stderr, "test file '%s' not found\n", test_filename.c_str());
|
||||
cerr << "test file '" << test_filename << "' not found" << endl;
|
||||
}
|
212
src/rpn-test.cpp
212
src/rpn-test.cpp
|
@ -1,16 +1,16 @@
|
|||
#include "program.hpp"
|
||||
|
||||
/// @brief compared 2 strings on top of the stack
|
||||
///
|
||||
///
|
||||
/// @return 0 strings are equal
|
||||
/// @return !0 strings are not equal (see strcmp output)
|
||||
///
|
||||
int program::cmp_strings_on_stack_top() {
|
||||
// _stack sould have 2 strings at level 1 and 2
|
||||
long program::cmp_strings_on_stack_top() {
|
||||
// _stack should have 2 strings at level 1 and 2
|
||||
// this function removes these 2 entries
|
||||
ostring* right = (ostring*)_stack->pop_back();
|
||||
ostring* left = (ostring*)_stack->pop_back();
|
||||
return strncmp(left->_value, right->_value, min(left->_len, right->_len));
|
||||
long res = (long)_stack.value<ostring>(1).compare(_stack.value<ostring>(0));
|
||||
(void)_stack.pop_front(2);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// @brief > keyword implementation
|
||||
|
@ -19,22 +19,16 @@ void program::rpn_sup(void) {
|
|||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) > 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) > _stack.value<number>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// strings
|
||||
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
|
||||
int res_cmp = cmp_strings_on_stack_top();
|
||||
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
res->_value = (res_cmp > 0) ? 1L : 0L;
|
||||
else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) {
|
||||
_stack.push_front(new number(cmp_strings_on_stack_top() == 1));
|
||||
_stack.erase(1, 2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief >= keyword implementation
|
||||
|
@ -43,22 +37,16 @@ void program::rpn_sup_eq(void) {
|
|||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) >= 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) >= _stack.value<number>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// strings
|
||||
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
|
||||
int res_cmp = cmp_strings_on_stack_top();
|
||||
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
res->_value = (res_cmp >= 0) ? 1L : 0L;
|
||||
else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) {
|
||||
_stack.push_front(new number(cmp_strings_on_stack_top() != -1));
|
||||
_stack.erase(1, 2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief < keyword implementation
|
||||
|
@ -67,46 +55,32 @@ void program::rpn_inf(void) {
|
|||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) < 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) < _stack.value<number>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// strings
|
||||
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
|
||||
int res_cmp = cmp_strings_on_stack_top();
|
||||
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
res->_value = (res_cmp < 0) ? 1L : 0L;
|
||||
else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) {
|
||||
_stack.push_front(new number(cmp_strings_on_stack_top() == -1));
|
||||
_stack.erase(1, 2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief <= keyword implementation
|
||||
///
|
||||
void program::rpn_inf_eq(void) {
|
||||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) <= 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) <= _stack.value<number>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// strings
|
||||
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
|
||||
int res_cmp = cmp_strings_on_stack_top();
|
||||
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
res->_value = (res_cmp <= 0) ? 1L : 0L;
|
||||
else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) {
|
||||
_stack.push_front(new number(cmp_strings_on_stack_top() != 1));
|
||||
_stack.erase(1, 2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief != keyword implementation
|
||||
|
@ -115,37 +89,21 @@ void program::rpn_diff(void) {
|
|||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) != 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) != _stack.value<number>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// complexes
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
|
||||
bool diff = false;
|
||||
complex* right = (complex*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->pop_back();
|
||||
|
||||
if (mpfr_cmp(left->re()->mpfr, right->re()->mpfr) != 0 || mpfr_cmp(left->im()->mpfr, right->im()->mpfr) != 0)
|
||||
diff = true;
|
||||
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
if (diff)
|
||||
mpfr_set_si(num->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(num->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) {
|
||||
_stack.push_front(new number(_stack.value<ocomplex>(1) != _stack.value<ocomplex>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// strings
|
||||
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
|
||||
int res_cmp = cmp_strings_on_stack_top();
|
||||
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
res->_value = (res_cmp != 0) ? 1L : 0L;
|
||||
else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) {
|
||||
_stack.push_front(new number(cmp_strings_on_stack_top() != 0));
|
||||
_stack.erase(1, 2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief == keyword implementation
|
||||
|
@ -154,37 +112,21 @@ void program::rpn_eq(void) {
|
|||
MIN_ARGUMENTS(2);
|
||||
|
||||
// numbers
|
||||
if (_stack->get_type(0) == cmd_number && _stack->get_type(1) == cmd_number) {
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) == 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
if (_stack.type(0) == cmd_number && _stack.type(1) == cmd_number) {
|
||||
_stack.push_front(new number(_stack.value<number>(1) == _stack.value<number>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// complexes
|
||||
else if (_stack->get_type(0) == cmd_complex && _stack->get_type(1) == cmd_complex) {
|
||||
bool diff = false;
|
||||
complex* right = (complex*)_stack->pop_back();
|
||||
complex* left = (complex*)_stack->pop_back();
|
||||
|
||||
if (mpfr_cmp(left->re()->mpfr, right->re()->mpfr) != 0 || mpfr_cmp(left->im()->mpfr, right->im()->mpfr) != 0)
|
||||
diff = true;
|
||||
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
if (diff)
|
||||
mpfr_set_si(num->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(num->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else if (_stack.type(0) == cmd_complex && _stack.type(1) == cmd_complex) {
|
||||
_stack.push_front(new number(_stack.value<ocomplex>(1) == _stack.value<ocomplex>(0)));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
// strings
|
||||
else if (_stack->get_type(0) == cmd_string && _stack->get_type(1) == cmd_string) {
|
||||
int res_cmp = cmp_strings_on_stack_top();
|
||||
number* res = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
res->_value = (res_cmp == 0) ? 1L : 0L;
|
||||
else if (_stack.type(0) == cmd_string && _stack.type(1) == cmd_string) {
|
||||
_stack.push_front(new number(cmp_strings_on_stack_top() == 0));
|
||||
_stack.erase(1, 2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief and keyword implementation
|
||||
|
@ -194,13 +136,11 @@ void program::rpn_test_and(void) {
|
|||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if ((mpfr_cmp_si(left->_value.mpfr, 0) != 0) && (mpfr_cmp_si(right->_value.mpfr, 0) != 0))
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
if (_stack.value<number>(0) != 0 && _stack.value<number>(1) != 0)
|
||||
_stack.push(new number(1));
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
_stack.push(new number(0));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
|
||||
/// @brief or keyword implementation
|
||||
|
@ -210,13 +150,11 @@ void program::rpn_test_or(void) {
|
|||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if ((mpfr_cmp_si(left->_value.mpfr, 0) != 0) || (mpfr_cmp_si(right->_value.mpfr, 0) != 0))
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
if (_stack.value<number>(0) != 0 || _stack.value<number>(1) != 0)
|
||||
_stack.push(new number(1));
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
_stack.push(new number(0));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
|
||||
/// @brief xor keyword implementation
|
||||
|
@ -226,20 +164,11 @@ void program::rpn_test_xor(void) {
|
|||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
ARG_MUST_BE_OF_TYPE(1, cmd_number);
|
||||
|
||||
number* right = (number*)_stack->pop_back();
|
||||
number* left = (number*)_stack->back();
|
||||
|
||||
if (mpfr_cmp_si(left->_value.mpfr, 0) == 0) {
|
||||
if (mpfr_cmp_si(right->_value.mpfr, 0) != 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
} else {
|
||||
if (mpfr_cmp_si(right->_value.mpfr, 0) == 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
}
|
||||
if (_stack.value<number>(0) != 0 ^ _stack.value<number>(1) != 0)
|
||||
_stack.push(new number(1));
|
||||
else
|
||||
_stack.push(new number(0));
|
||||
_stack.erase(1, 2);
|
||||
}
|
||||
|
||||
/// @brief not keyword implementation
|
||||
|
@ -248,11 +177,8 @@ void program::rpn_test_not(void) {
|
|||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
number* left = (number*)_stack->back();
|
||||
if (mpfr_cmp_si(left->_value.mpfr, 0) == 0)
|
||||
mpfr_set_si(left->_value.mpfr, 1, floating_t::s_mpfr_rnd);
|
||||
else
|
||||
mpfr_set_si(left->_value.mpfr, 0, floating_t::s_mpfr_rnd);
|
||||
_stack.push(new number(_stack.value<number>(0) == 0?1:0));
|
||||
_stack.erase(1, 1);
|
||||
}
|
||||
|
||||
/// @brief test same implementation
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <time.h>
|
||||
|
||||
#include "program.hpp"
|
||||
|
||||
/// @brief time keyword implementation
|
||||
|
@ -12,18 +13,17 @@ void program::rpn_time() {
|
|||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
time_t time = (time_t)ts.tv_sec;
|
||||
tm = localtime(&time);
|
||||
if (tm != NULL) {
|
||||
if (tm != nullptr) {
|
||||
// date format = HH.MMSSssssss
|
||||
date = ((double)tm->tm_hour) * 10000000000.0 + ((double)tm->tm_min) * 100000000.0 +
|
||||
((double)tm->tm_sec) * 1000000.0 + (double)(ts.tv_nsec / 1000);
|
||||
|
||||
// push it
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd));
|
||||
// division is done here because of real precision)
|
||||
CHECK_MPFR(mpfr_div_d(num->_value.mpfr, num->_value.mpfr, 10000000000.0, floating_t::s_mpfr_rnd));
|
||||
// division after push for real precision
|
||||
_stack.push(new number(date));
|
||||
_stack.value<number>(0) /= 10000000000.0;
|
||||
} else
|
||||
ERR_CONTEXT(ret_internal);
|
||||
setErrorContext(ret_internal);
|
||||
}
|
||||
|
||||
/// @brief date keyword implementation
|
||||
|
@ -37,17 +37,17 @@ void program::rpn_date() {
|
|||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
time_t time = (time_t)ts.tv_sec;
|
||||
tm = localtime(&time);
|
||||
if (tm != NULL) {
|
||||
if (tm != nullptr) {
|
||||
// date format = (M)M.DDYYYY
|
||||
date = (double)(tm->tm_mon + 1) * 1000000.0 + (double)(tm->tm_mday) * 10000.0 + (double)(tm->tm_year + 1900);
|
||||
|
||||
// push it
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd));
|
||||
// division is done here because of real precision)
|
||||
CHECK_MPFR(mpfr_div_d(num->_value.mpfr, num->_value.mpfr, 1000000.0, floating_t::s_mpfr_rnd));
|
||||
number* num;
|
||||
// division after push for real precision
|
||||
_stack.push(new number(date));
|
||||
_stack.value<number>(0) /= 1000000.0;
|
||||
} else
|
||||
ERR_CONTEXT(ret_internal);
|
||||
setErrorContext(ret_internal);
|
||||
}
|
||||
|
||||
/// @brief ticks keyword implementation
|
||||
|
@ -61,13 +61,10 @@ void program::rpn_ticks() {
|
|||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
time_t time = (time_t)ts.tv_sec;
|
||||
tm = localtime(&time);
|
||||
if (tm != NULL) {
|
||||
if (tm != nullptr) {
|
||||
// date in µs
|
||||
date = 1000000.0 * (double)ts.tv_sec + (double)(ts.tv_nsec / 1000);
|
||||
|
||||
// push it
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, date, floating_t::s_mpfr_rnd));
|
||||
_stack.push(new number(date));
|
||||
} else
|
||||
ERR_CONTEXT(ret_internal);
|
||||
setErrorContext(ret_internal);
|
||||
}
|
||||
|
|
228
src/rpn-trig.cpp
228
src/rpn-trig.cpp
|
@ -3,8 +3,7 @@
|
|||
/// @brief pi keyword implementation
|
||||
///
|
||||
void program::rpn_pi(void) {
|
||||
number* pi = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_const_pi(pi->_value.mpfr, floating_t::s_mpfr_rnd));
|
||||
_stack.push_front(new number(const_pi()));
|
||||
}
|
||||
|
||||
/// @brief d->r keyword implementation
|
||||
|
@ -12,15 +11,8 @@ void program::rpn_pi(void) {
|
|||
void program::rpn_d2r(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
// add pi on stack
|
||||
rpn_pi();
|
||||
|
||||
floating_t* pi = &((number*)_stack->pop_back())->_value;
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
|
||||
CHECK_MPFR(mpfr_mul(left->mpfr, left->mpfr, pi->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_div_si(left->mpfr, left->mpfr, 180, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(0) *= const_pi();
|
||||
_stack.value<number>(0) /= 180;
|
||||
}
|
||||
|
||||
/// @brief r->d keyword implementation
|
||||
|
@ -28,15 +20,8 @@ void program::rpn_d2r(void) {
|
|||
void program::rpn_r2d(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
ARG_MUST_BE_OF_TYPE(0, cmd_number);
|
||||
|
||||
// add pi on stack
|
||||
rpn_pi();
|
||||
|
||||
floating_t* pi = &((number*)_stack->pop_back())->_value;
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
|
||||
CHECK_MPFR(mpfr_div(left->mpfr, left->mpfr, pi->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul_si(left->mpfr, left->mpfr, 180, floating_t::s_mpfr_rnd));
|
||||
_stack.value<number>(0) /= const_pi();
|
||||
_stack.value<number>(0) *= 180;
|
||||
}
|
||||
|
||||
/// @brief sin keyword implementation
|
||||
|
@ -44,31 +29,12 @@ void program::rpn_r2d(void) {
|
|||
void program::rpn_sin(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_sin(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// sin(x+iy)=sin(x)cosh(y)+icos(x)sinh(y)
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
|
||||
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
|
||||
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(0))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(0))->im();
|
||||
|
||||
CHECK_MPFR(mpfr_sin(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_cosh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(re->mpfr, re->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
CHECK_MPFR(mpfr_cos(im->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sinh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(im->mpfr, im->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back(2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = sin(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = sin(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief asin keyword implementation
|
||||
|
@ -76,38 +42,12 @@ void program::rpn_sin(void) {
|
|||
void program::rpn_asin(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_asin(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
number* num;
|
||||
complex* i;
|
||||
|
||||
// asin(z)=-iln(iz+sqrt(1-z*z))
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
i = (complex*)_calc_stack.get_obj(0);
|
||||
CHECK_MPFR(mpfr_set_d(i->re()->mpfr, 0.0, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_set_d(i->im()->mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
|
||||
rpn_dup();
|
||||
rpn_square();
|
||||
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_minus();
|
||||
rpn_neg();
|
||||
rpn_squareroot();
|
||||
rpn_swap();
|
||||
stack::copy_and_push_back(_calc_stack, 0, *_stack);
|
||||
rpn_mul();
|
||||
rpn_plus();
|
||||
rpn_ln();
|
||||
stack::copy_and_push_back(_calc_stack, 0, *_stack);
|
||||
rpn_mul();
|
||||
rpn_neg();
|
||||
_calc_stack.pop_back();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = asin(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = asin(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief cos keyword implementation
|
||||
|
@ -115,32 +55,12 @@ void program::rpn_asin(void) {
|
|||
void program::rpn_cos(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_cos(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// cos(x+iy) = cos(x)cosh(y) - isin(x)sinh(y)
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
|
||||
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
|
||||
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(0))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(0))->im();
|
||||
|
||||
CHECK_MPFR(mpfr_cos(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_cosh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(re->mpfr, re->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
CHECK_MPFR(mpfr_sin(im->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sinh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_mul(im->mpfr, im->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_neg(im->mpfr, im->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back(2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = cos(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = cos(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief acos keyword implementation
|
||||
|
@ -148,20 +68,12 @@ void program::rpn_cos(void) {
|
|||
void program::rpn_acos(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_acos(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// acos(z)=pi/2-asin(z)
|
||||
rpn_asin();
|
||||
rpn_pi();
|
||||
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
|
||||
rpn_div();
|
||||
rpn_minus();
|
||||
rpn_neg();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = acos(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = acos(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief tan keyword implementation
|
||||
|
@ -169,41 +81,12 @@ void program::rpn_acos(void) {
|
|||
void program::rpn_tan(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_tan(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
// tan(x+iy) = (sin(2x)+isinh(2y)) / cosh(2y)+cos(2x)
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value;
|
||||
floating_t* x = ((complex*)_calc_stack.get_obj(1))->re();
|
||||
floating_t* y = ((complex*)_calc_stack.get_obj(1))->im();
|
||||
|
||||
floating_t* re = ((complex*)_stack->get_obj(0))->re();
|
||||
floating_t* im = ((complex*)_stack->get_obj(0))->im();
|
||||
|
||||
// x->2x
|
||||
CHECK_MPFR(mpfr_mul_si(x->mpfr, x->mpfr, 2, floating_t::s_mpfr_rnd));
|
||||
// y->2y
|
||||
CHECK_MPFR(mpfr_mul_si(y->mpfr, y->mpfr, 2, floating_t::s_mpfr_rnd));
|
||||
|
||||
// sin(2x)+sinh(2y)
|
||||
CHECK_MPFR(mpfr_sin(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_sinh(im->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// cosh(2y)+cos(2x)
|
||||
CHECK_MPFR(mpfr_cosh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_cos(x->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_add(tmp->mpfr, tmp->mpfr, x->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
// sin(2x)+sinh(2y) / (cosh(2y)+cos(2x))
|
||||
CHECK_MPFR(mpfr_div(re->mpfr, re->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_div(im->mpfr, im->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd));
|
||||
|
||||
_calc_stack.pop_back(2);
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = tan(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = tan(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
||||
/// @brief atan keyword implementation
|
||||
|
@ -211,39 +94,10 @@ void program::rpn_tan(void) {
|
|||
void program::rpn_atan(void) {
|
||||
MIN_ARGUMENTS(1);
|
||||
|
||||
if (_stack->get_type(0) == cmd_number) {
|
||||
floating_t* left = &((number*)_stack->get_obj(0))->_value;
|
||||
CHECK_MPFR(mpfr_atan(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd));
|
||||
} else if (_stack->get_type(0) == cmd_complex) {
|
||||
number* num;
|
||||
complex* i;
|
||||
|
||||
// atan(z)=0.5i(ln((1-iz)/(1+iz))
|
||||
stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack);
|
||||
|
||||
i = (complex*)_calc_stack.get_obj(0);
|
||||
CHECK_MPFR(mpfr_set_d(i->re()->mpfr, 0.0, floating_t::s_mpfr_rnd));
|
||||
CHECK_MPFR(mpfr_set_d(i->im()->mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
|
||||
stack::copy_and_push_back(_calc_stack, 0, *_stack);
|
||||
rpn_mul();
|
||||
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 1.0, floating_t::s_mpfr_rnd));
|
||||
rpn_minus(); // iz-1
|
||||
rpn_neg(); // 1-iz
|
||||
rpn_dup();
|
||||
rpn_neg(); // iz-1
|
||||
num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
|
||||
CHECK_MPFR(mpfr_set_d(num->_value.mpfr, 2.0, floating_t::s_mpfr_rnd));
|
||||
rpn_plus(); // iz+1
|
||||
rpn_div();
|
||||
|
||||
rpn_ln();
|
||||
CHECK_MPFR(mpfr_set_d(i->im()->mpfr, 0.5, floating_t::s_mpfr_rnd));
|
||||
stack::copy_and_push_back(_calc_stack, 0, *_stack);
|
||||
rpn_mul();
|
||||
|
||||
_calc_stack.pop_back();
|
||||
} else
|
||||
ERR_CONTEXT(ret_bad_operand_type);
|
||||
if (_stack.type(0) == cmd_number)
|
||||
_stack.value<number>(0) = atan(_stack.value<number>(0));
|
||||
else if (_stack.type(0) == cmd_complex)
|
||||
_stack.value<ocomplex>(0) = atan(_stack.value<ocomplex>(0));
|
||||
else
|
||||
setErrorContext(ret_bad_operand_type);
|
||||
}
|
||||
|
|
371
src/stack.hpp
371
src/stack.hpp
|
@ -2,34 +2,22 @@
|
|||
#define __stack_h__
|
||||
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
// allocation base size
|
||||
#define ALLOC_STACK_CHUNK (64 * 1024)
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#include "object.hpp"
|
||||
using namespace std;
|
||||
|
||||
/// @brief stack object, parens of program, storing execution stack values or programs
|
||||
///
|
||||
class stack {
|
||||
class rpnstack : public deque<object*> {
|
||||
public:
|
||||
stack() {
|
||||
_base = NULL;
|
||||
_base_pointer = NULL;
|
||||
_total_size = 0;
|
||||
_total_count_pointer = 0;
|
||||
erase();
|
||||
}
|
||||
|
||||
virtual ~stack() {
|
||||
if (_base != NULL) free(_base);
|
||||
if (_base_pointer != NULL) free(_base_pointer);
|
||||
}
|
||||
|
||||
/// @brief remove all the stack elements
|
||||
///
|
||||
void erase() {
|
||||
_current = _base;
|
||||
_count = 0;
|
||||
rpnstack() {}
|
||||
virtual ~rpnstack() {
|
||||
for_each(begin(), end(), [](object* o) { delete o; });
|
||||
deque::erase(begin(), end());
|
||||
}
|
||||
|
||||
/// @brief copy a whole stack entry and push it back to another stack
|
||||
|
@ -38,347 +26,100 @@ class stack {
|
|||
/// @param index_from index t ocopy from
|
||||
/// @param to copy to
|
||||
///
|
||||
static void copy_and_push_back(stack& from, unsigned int index_from, stack& to) {
|
||||
object* allocated = to.allocate_back(from.seq_len(index_from), from.seq_type(index_from));
|
||||
memcpy(allocated, from.seq_obj(index_from), from.seq_len(index_from));
|
||||
|
||||
if (allocated->_type == cmd_number)
|
||||
((number*)allocated)->move();
|
||||
else if (allocated->_type == cmd_complex)
|
||||
((complex*)allocated)->move();
|
||||
static void copy_and_push_front(rpnstack& from, unsigned int index_from, rpnstack& to) {
|
||||
// carefull: caller must ensure that index_from is correct
|
||||
to.push_front(from[index_from]->clone());
|
||||
}
|
||||
|
||||
/// @brief copy a whole stack entry and push it back to another stack
|
||||
/// @brief erase a stack entry from it index
|
||||
///
|
||||
/// @param from copy from
|
||||
/// @param index_from index t ocopy from
|
||||
/// @param to copy to
|
||||
/// @param first index to start
|
||||
/// @param last index to stop
|
||||
///
|
||||
static void copy_and_push_back(object* from, stack& to, unsigned int size) {
|
||||
object* allocated = to.allocate_back(size, from->_type);
|
||||
memcpy(allocated, from, size);
|
||||
|
||||
if (allocated->_type == cmd_number)
|
||||
((number*)allocated)->move();
|
||||
else if (allocated->_type == cmd_complex)
|
||||
((complex*)allocated)->move();
|
||||
void erase(size_t first = 0, size_t nb = 1, bool del = true) {
|
||||
size_t last = std::min(first + nb, size());
|
||||
if (del)
|
||||
for_each(begin() + first, begin() + last, [](object* o) { delete o; });
|
||||
deque::erase(begin() + first, begin() + last);
|
||||
}
|
||||
|
||||
/// @brief allocate one object back on an already populated (or not) stack
|
||||
/// the object function move is called on every reallocated object on the stack
|
||||
/// the object function init is called on the new allocated object if its type is cmd_number or cmd_complex
|
||||
/// @brief pop front several entries
|
||||
///
|
||||
/// @param size the object size in bytes
|
||||
/// @param type the object type
|
||||
/// @return object* the allocated object
|
||||
/// @param levels nb of entries
|
||||
///
|
||||
object* allocate_back(unsigned int size, cmd_type_t type) {
|
||||
object* allocated;
|
||||
bool data_is_reallocated = false;
|
||||
char* old_base;
|
||||
void pop_front(size_t levels = 1) { erase(0, levels); }
|
||||
void pop() { erase(); }
|
||||
|
||||
// manage data memory allocation (add as much as memory it is needed)
|
||||
if (((_current - _base) + size) > _total_size) {
|
||||
// calc nb of needed pages
|
||||
unsigned long page_number = 1 + ((_current - _base) + size - _total_size) / ALLOC_STACK_CHUNK;
|
||||
_total_size += page_number * ALLOC_STACK_CHUNK;
|
||||
|
||||
old_base = _base;
|
||||
_base = (char*)realloc(_base, _total_size);
|
||||
|
||||
_current = _base + (_current - old_base);
|
||||
data_is_reallocated = true;
|
||||
}
|
||||
|
||||
// manage pointers memory allocation (add one page if needed)
|
||||
if ((_count + 1) > _total_count_pointer) {
|
||||
_base_pointer =
|
||||
(object**)realloc(_base_pointer, (_total_count_pointer * sizeof(object*)) + ALLOC_STACK_CHUNK);
|
||||
_total_count_pointer += (ALLOC_STACK_CHUNK / sizeof(object));
|
||||
}
|
||||
|
||||
// recalc object pointers in case of base reallocation
|
||||
if (data_is_reallocated) {
|
||||
for (int i = 0; i < _count; i++) {
|
||||
_base_pointer[i] = (object*)(_base + ((char*)_base_pointer[i] - old_base));
|
||||
if (_base_pointer[i]->_type == cmd_number)
|
||||
((number*)_base_pointer[i])->move();
|
||||
else if (_base_pointer[i]->_type == cmd_complex)
|
||||
((complex*)_base_pointer[i])->move();
|
||||
}
|
||||
}
|
||||
|
||||
// manage stack itself
|
||||
_base_pointer[_count++] = (object*)_current;
|
||||
allocated = (object*)_current;
|
||||
_current += size;
|
||||
|
||||
// init object
|
||||
allocated->_type = type;
|
||||
allocated->_size = size;
|
||||
if (type == cmd_number)
|
||||
((number*)allocated)->init();
|
||||
else if (type == cmd_complex)
|
||||
((complex*)allocated)->init();
|
||||
|
||||
return allocated;
|
||||
// access helpers
|
||||
cmd_type_t type(int level) {
|
||||
// carefull: caller must ensure that level is correct
|
||||
return at(level)->_type;
|
||||
}
|
||||
|
||||
object* pop_back(int pop_count = 1) {
|
||||
object* back = NULL;
|
||||
|
||||
// pop several entries, return the last
|
||||
while (pop_count-- > 0) {
|
||||
if (_count > 0) {
|
||||
_current = (char*)_base_pointer[--_count];
|
||||
back = (object*)_current;
|
||||
}
|
||||
}
|
||||
|
||||
return back;
|
||||
template <class objectType>
|
||||
auto& obj(int level) {
|
||||
// carefull: caller must ensure that level is correct
|
||||
return static_cast<objectType&>(*at(level));
|
||||
}
|
||||
|
||||
/// @brief the number of objects on stack
|
||||
///
|
||||
/// @return unsigned int
|
||||
///
|
||||
unsigned int size() { return _count; }
|
||||
|
||||
/// @brief stack access (stack_level=0=first out)
|
||||
///
|
||||
/// @param stack_level the object stack level
|
||||
/// @return object* pointer on object at this stack level
|
||||
///
|
||||
object* get_obj(unsigned int stack_level) { return seq_obj(_count - stack_level - 1); }
|
||||
|
||||
/// @brief same as get_obj
|
||||
///
|
||||
/// @param stack_level the object stack level
|
||||
/// @return object* pointer on object at this stack level
|
||||
///
|
||||
object* operator[](unsigned int stack_level) { return seq_obj(_count - stack_level - 1); }
|
||||
|
||||
/// @brief returns the last object on stack
|
||||
///
|
||||
/// @return object* the object
|
||||
///
|
||||
object* back() {
|
||||
object* obj = NULL;
|
||||
if (_count > 0) obj = _base_pointer[_count - 1];
|
||||
return obj;
|
||||
template <class objectType>
|
||||
auto& value(int level) {
|
||||
// carefull: caller must ensure that level is correct
|
||||
return static_cast<objectType*>(at(level))->value;
|
||||
}
|
||||
|
||||
/// @brief get an object len
|
||||
///
|
||||
/// @param index the object stack level
|
||||
/// @return unsigned int the length in bytes
|
||||
///
|
||||
unsigned int get_len(unsigned int index) { return seq_len(_count - index - 1); }
|
||||
|
||||
/// @brief get an object type
|
||||
///
|
||||
/// @param index the object stack level
|
||||
/// @return cmd_type_t the object type
|
||||
///
|
||||
cmd_type_t get_type(unsigned int index) { return seq_type(_count - index - 1); }
|
||||
|
||||
/// @brief sequential object access (index is counted from front)
|
||||
///
|
||||
/// @param index object index from front
|
||||
/// @return object* the object pointer
|
||||
///
|
||||
object* seq_obj(unsigned int index) {
|
||||
object* obj = NULL;
|
||||
if (index < _count) obj = _base_pointer[index];
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// @brief get an object len
|
||||
///
|
||||
/// @param index the object stack level from front
|
||||
/// @return unsigned int the length in bytes
|
||||
///
|
||||
unsigned int seq_len(unsigned int index) {
|
||||
unsigned int len = 0;
|
||||
if (index < _count) len = _base_pointer[index]->_size;
|
||||
return len;
|
||||
}
|
||||
|
||||
/// @brief get an object len
|
||||
///
|
||||
/// @param index the object stack level from front
|
||||
/// @return cmd_type_t the object type
|
||||
///
|
||||
cmd_type_t seq_type(unsigned int index) {
|
||||
cmd_type_t type = cmd_undef;
|
||||
if (index < _count) type = _base_pointer[index]->_type;
|
||||
return type;
|
||||
}
|
||||
|
||||
private:
|
||||
char* _base;
|
||||
char* _current;
|
||||
object** _base_pointer;
|
||||
|
||||
unsigned int _count; //< stack count
|
||||
unsigned int _total_count_pointer; //< total number of possible pointers
|
||||
unsigned int _total_size; //< total allocated data size in bytes
|
||||
void push(object* o) { deque<object*>::push_front(o); }
|
||||
};
|
||||
|
||||
/// @brief heap object, storing variables (=named object)
|
||||
///
|
||||
class heap : public stack {
|
||||
class heap : public map<string, object*> {
|
||||
public:
|
||||
heap() {}
|
||||
virtual ~heap() {}
|
||||
virtual ~heap() { clear(); }
|
||||
|
||||
/// @brief add a variable on the heap
|
||||
///
|
||||
/// @param name the variable name
|
||||
/// @param obj the variable content
|
||||
/// @param size the variable size in bytes
|
||||
/// @return object*
|
||||
///
|
||||
object* add(const string name, object* obj, unsigned int size) {
|
||||
map<string, unsigned int>::iterator i = _map.find(name);
|
||||
object* local = NULL;
|
||||
|
||||
// variable does not exist in heap or already exists but its size is too
|
||||
// short -> allocate
|
||||
if (i != _map.end()) local = seq_obj(i->second);
|
||||
|
||||
if (local == NULL || (local != NULL && size > local->_size)) {
|
||||
copy_and_push_back(obj, *this, size);
|
||||
_map[name] = ((stack*)this)->size() - 1;
|
||||
} else {
|
||||
// variable already exists in heap but previous was larger -> don't
|
||||
// reallocate copy a whole stack entry and push it back to another stack
|
||||
memcpy(local, obj, size);
|
||||
if (local->_type == cmd_number)
|
||||
((number*)local)->move();
|
||||
else if (local->_type == cmd_complex)
|
||||
((complex*)local)->move();
|
||||
}
|
||||
|
||||
return local;
|
||||
void clear() {
|
||||
for_each(begin(), end(), [](auto it) { delete it.second; });
|
||||
map::erase(begin(), end());
|
||||
}
|
||||
|
||||
/// @brief get a variable
|
||||
///
|
||||
///
|
||||
/// @param name the variable name
|
||||
/// @param obj the variable content
|
||||
/// @param size the variable size in bytes
|
||||
/// @return true the variable was found
|
||||
/// @return false the variable was not found
|
||||
///
|
||||
bool get(const string name, object*& obj, unsigned int& size) {
|
||||
bool get(const string name, object*& obj) {
|
||||
bool ret = false;
|
||||
map<string, unsigned int>::iterator i = _map.find(name);
|
||||
|
||||
if (i != _map.end()) {
|
||||
obj = seq_obj(i->second);
|
||||
size = obj->_size;
|
||||
auto i = find(name);
|
||||
if (i != end()) {
|
||||
obj = i->second;
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief replace a variable value by another
|
||||
///
|
||||
/// @param name the variable name
|
||||
/// @param obj the new value
|
||||
/// @param size the variable size in bytes
|
||||
/// @return true the variable was found
|
||||
/// @return false the variable was not found
|
||||
///
|
||||
bool replace_value(const string name, object* obj, unsigned int size) {
|
||||
bool ret = false;
|
||||
map<string, unsigned int>::iterator i = _map.find(name);
|
||||
|
||||
if (i != _map.end()) {
|
||||
object* obj_dst = seq_obj(i->second);
|
||||
if (size <= obj_dst->_size) {
|
||||
(void)memcpy(obj_dst, obj, size);
|
||||
if (obj_dst->_type == cmd_number)
|
||||
((number*)obj_dst)->move();
|
||||
else if (obj_dst->_type == cmd_complex)
|
||||
((complex*)obj_dst)->move();
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief whether a variable exists in heap or not
|
||||
///
|
||||
/// @param name the variable name
|
||||
/// @return true the variable exists
|
||||
/// @return false variable does not exist
|
||||
///
|
||||
bool exist(const string name) { return (_map.find(name) != _map.end()); }
|
||||
|
||||
/// @brief get a variable by its index in heap
|
||||
///
|
||||
///
|
||||
/// @param num the variable index
|
||||
/// @param name the variable name
|
||||
/// @param obj the variable content
|
||||
/// @param size the variable size in bytes
|
||||
/// @return true the variable was found
|
||||
/// @return false the variable was not found
|
||||
///
|
||||
bool get_by_index(int num, string& name, object*& obj, unsigned int& size) {
|
||||
if (num >= 0 && num < (int)_map.size()) {
|
||||
bool get_by_index(int num, string& name, object*& obj) {
|
||||
if (num >= 0 && num < (int)size()) {
|
||||
object* local;
|
||||
map<string, unsigned int>::iterator i = _map.begin();
|
||||
|
||||
for (int j = 0; j < num; j++) i++;
|
||||
|
||||
local = (object*)seq_obj(i->second);
|
||||
auto i = begin();
|
||||
for (; num > 0; num--, i++)
|
||||
;
|
||||
obj = i->second;
|
||||
name = i->first;
|
||||
obj = local;
|
||||
size = local->_size;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief erase a variable
|
||||
///
|
||||
/// @param name the variable name
|
||||
/// @return true the variable was found
|
||||
/// @return false the variable was not found
|
||||
///
|
||||
bool erase(const string& name) {
|
||||
map<string, unsigned int>::iterator i = _map.find(name);
|
||||
bool ret = false;
|
||||
|
||||
if (i != _map.end()) {
|
||||
// remove variable from map
|
||||
_map.erase(i->first);
|
||||
ret = true;
|
||||
|
||||
// TODO: remove unused stack entries
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @brief erase all variables
|
||||
///
|
||||
void erase_all(void) {
|
||||
// map
|
||||
_map.erase(_map.begin(), _map.end());
|
||||
|
||||
// and stack
|
||||
((stack*)this)->erase();
|
||||
}
|
||||
|
||||
/// @brief get the variables nb
|
||||
///
|
||||
/// @return unsigned int the variables nb
|
||||
///
|
||||
unsigned int count_vars() { return _map.size(); }
|
||||
|
||||
private:
|
||||
map<string, unsigned int> _map;
|
||||
};
|
||||
|
||||
#endif // __stack_h__
|
||||
|
|
|
@ -1,22 +1,2 @@
|
|||
// version and soft name
|
||||
#define RPN_VERSION "2.3.2"
|
||||
static const char version[] = RPN_VERSION;
|
||||
static const char uname[] = "rpn v" RPN_VERSION ", (c) 2017 <louis@rubet.fr>, GNU LGPL v3\n";
|
||||
|
||||
#define STRINGIFY(a) STRINGIFY_ONE(a)
|
||||
#define STRINGIFY_ONE(a) #a
|
||||
|
||||
// description
|
||||
static const char description[] = ATTR_BOLD
|
||||
"R" ATTR_OFF "everse " ATTR_BOLD "P" ATTR_OFF "olish " ATTR_BOLD "N" ATTR_OFF
|
||||
"otation language\n\n"
|
||||
"using " ATTR_BOLD "GMP" ATTR_OFF
|
||||
" v" STRINGIFY(__GNU_MP_VERSION) "." STRINGIFY(__GNU_MP_VERSION_MINOR) "." STRINGIFY(
|
||||
__GNU_MP_VERSION_PATCHLEVEL) " under GNU LGPL\n" ATTR_BOLD "MPFR" ATTR_OFF " v" MPFR_VERSION_STRING
|
||||
" under GNU LGPL\n"
|
||||
"and " ATTR_BOLD "linenoise-ng" ATTR_OFF " v" LINENOISE_VERSION " under BSD\n";
|
||||
|
||||
// syntax
|
||||
static const char syntax[] = ATTR_BOLD "Syntax" ATTR_OFF
|
||||
": rpn [command]\n"
|
||||
"with optional command = list of commands";
|
||||
#define RPN_VERSION "2.4"
|
||||
#define RPN_UNAME "rpn v" RPN_VERSION ", (c) 2017 <louis@rubet.fr>, GNU LGPL v3"
|
||||
|
|
47
test/005-test-framework.md
Normal file
47
test/005-test-framework.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# TEST FRAMEWORK
|
||||
|
||||
`default del`
|
||||
|
||||
## testing the stack size 1
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
## testing the stack size 2
|
||||
|
||||
`1`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
## testing the stack size 3
|
||||
|
||||
`1 2 3 4 5`
|
||||
|
||||
-> stack size should be 5
|
||||
|
||||
`del`
|
||||
|
||||
## testing stack
|
||||
|
||||
`1 2 3`
|
||||
|
||||
-> stack should be 1, 2, 3
|
||||
|
||||
`del`
|
||||
|
||||
-> stack should be
|
||||
|
||||
## testing error 1
|
||||
|
||||
`del`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
## testing error 2
|
||||
|
||||
`drop`
|
||||
|
||||
-> error should be 2
|
|
@ -1,47 +0,0 @@
|
|||
## MODE
|
||||
default del
|
||||
|
||||
# std (1)
|
||||
del
|
||||
38 std
|
||||
-> stack size should be 0
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# std (2)
|
||||
1 3 /
|
||||
-> stack should be 0.33333333333333333333333333333333333333
|
||||
del
|
||||
|
||||
# fix (1)
|
||||
10 fix
|
||||
1
|
||||
-> stack should be 1.0000000000
|
||||
del
|
||||
|
||||
# fix (2)
|
||||
1 4 fix
|
||||
-> stack should be 1.0000
|
||||
del
|
||||
|
||||
# fix (3)
|
||||
-1 fix
|
||||
-> error should be 4
|
||||
del
|
||||
|
||||
# sci (1)
|
||||
1 12 sci
|
||||
-> stack should be 1.000000000000e+00
|
||||
del
|
||||
|
||||
# sci (2)
|
||||
1 2 sci
|
||||
-> stack should be 1.00e+00
|
||||
del
|
||||
|
||||
# sci (3)
|
||||
-1 sci
|
||||
-> error should be 4
|
||||
del
|
||||
|
||||
default
|
75
test/010-mode.md
Normal file
75
test/010-mode.md
Normal file
|
@ -0,0 +1,75 @@
|
|||
# MODE
|
||||
`default del`
|
||||
|
||||
## std (1)
|
||||
|
||||
```
|
||||
del
|
||||
38 std
|
||||
```
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## std (2)
|
||||
|
||||
`1 3 /`
|
||||
|
||||
-> stack should be 0.33333333333333333333333333333333333333
|
||||
|
||||
`del`
|
||||
|
||||
## fix (1)
|
||||
|
||||
`10 fix 1`
|
||||
|
||||
-> stack should be 1.0000000000
|
||||
|
||||
`del`
|
||||
|
||||
## fix (2)
|
||||
|
||||
`1 4 fix`
|
||||
|
||||
-> stack should be 1.0000
|
||||
|
||||
`del`
|
||||
|
||||
## fix (3)
|
||||
|
||||
`-1 fix`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`del`
|
||||
|
||||
## sci (1)
|
||||
|
||||
`1 12 sci`
|
||||
|
||||
-> stack should be 1.000000000000e+00
|
||||
|
||||
`del`
|
||||
|
||||
## sci (2)
|
||||
|
||||
`1 2 sci`
|
||||
|
||||
-> stack should be 1.00e+00
|
||||
|
||||
## default
|
||||
|
||||
`default`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
## sci (3)
|
||||
|
||||
`-1 sci`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`del`
|
|
@ -1,49 +0,0 @@
|
|||
## GENERAL
|
||||
default del
|
||||
|
||||
# version
|
||||
version
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
uname
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# type (1)
|
||||
1 type
|
||||
-> stack should be "number"
|
||||
del
|
||||
|
||||
# type (2)
|
||||
"hey" type
|
||||
-> stack should be "string"
|
||||
del
|
||||
|
||||
# type (3)
|
||||
<< -> n << n >> >> type
|
||||
-> stack should be "program"
|
||||
del
|
||||
|
||||
# type (4)
|
||||
(1,2) type
|
||||
-> stack should be "complex"
|
||||
del
|
||||
|
||||
# type (5)
|
||||
type
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# default
|
||||
2 sci 1
|
||||
-> stack should be 1.00e+00
|
||||
default
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# nop
|
||||
nop
|
||||
-> stack size should be 0
|
||||
-> error should be 0
|
||||
del
|
59
test/020-general.md
Normal file
59
test/020-general.md
Normal file
|
@ -0,0 +1,59 @@
|
|||
# GENERAL
|
||||
|
||||
`default del `
|
||||
|
||||
## version
|
||||
|
||||
`version`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## uname
|
||||
|
||||
`uname`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## default
|
||||
|
||||
`2 sci 1`
|
||||
|
||||
-> stack should be 1.00e+00
|
||||
|
||||
`default`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## nop
|
||||
|
||||
`nop`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## quit
|
||||
|
||||
`q`
|
||||
|
||||
-> error should be 8
|
||||
|
||||
## quit (2)
|
||||
|
||||
`quit`
|
||||
|
||||
-> error should be 8
|
||||
|
||||
## exit
|
||||
|
||||
`exit`
|
||||
|
||||
-> error should be 8
|
101
test/021-parse-string.md
Normal file
101
test/021-parse-string.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
# PARSE STRING
|
||||
|
||||
`default del`
|
||||
|
||||
## type
|
||||
|
||||
`"hey" type`
|
||||
|
||||
-> stack should be "string"
|
||||
|
||||
`del`
|
||||
|
||||
## void 1
|
||||
|
||||
`""`
|
||||
|
||||
-> stack should be ""
|
||||
|
||||
`del`
|
||||
|
||||
## void 2
|
||||
|
||||
`"`
|
||||
|
||||
-> stack should be ""
|
||||
|
||||
`del`
|
||||
|
||||
## string
|
||||
|
||||
`"abcd"`
|
||||
|
||||
-> stack should be "abcd"
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated
|
||||
|
||||
`"abcd`
|
||||
|
||||
-> stack should be "abcd"
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated 2
|
||||
|
||||
`"abcd" "abc`
|
||||
|
||||
-> stack should be "abcd", "abc"
|
||||
|
||||
`del`
|
||||
|
||||
## spaces
|
||||
|
||||
`"abc d"`
|
||||
|
||||
-> stack should be "abc d"
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 2
|
||||
|
||||
`" abcd "`
|
||||
|
||||
-> stack should be " abcd "
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 3
|
||||
|
||||
`" abcd " "def" "gh ij"`
|
||||
|
||||
-> stack should be " abcd ", "def", "gh ij"
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 4
|
||||
|
||||
`" . abcd . ;; "`
|
||||
|
||||
-> stack should be " . abcd . ;; "
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 5
|
||||
|
||||
```
|
||||
" . abcd . ;; " "ab c
|
||||
```
|
||||
|
||||
-> stack should be " . abcd . ;; ", "ab c "
|
||||
|
||||
`del`
|
||||
|
||||
## nested types
|
||||
|
||||
`"1.0 swap drop`
|
||||
|
||||
-> stack should be "1.0 swap drop"
|
||||
|
||||
`del`
|
107
test/022-parse-symbol.md
Normal file
107
test/022-parse-symbol.md
Normal file
|
@ -0,0 +1,107 @@
|
|||
# PARSE SYMBOL
|
||||
|
||||
`default del `
|
||||
|
||||
## type
|
||||
|
||||
`'hey' type`
|
||||
|
||||
-> stack should be "symbol"
|
||||
|
||||
`del`
|
||||
|
||||
## void 1
|
||||
|
||||
`''`
|
||||
|
||||
-> stack should be ''
|
||||
|
||||
`del`
|
||||
|
||||
## void 2
|
||||
|
||||
`'`
|
||||
|
||||
-> stack should be ''
|
||||
|
||||
`del`
|
||||
|
||||
## symbol
|
||||
|
||||
`'abcd'`
|
||||
|
||||
-> stack should be 'abcd'
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated
|
||||
|
||||
`'abcd`
|
||||
|
||||
-> stack should be 'abcd'
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated 2
|
||||
|
||||
`'abcd' 'abc`
|
||||
|
||||
-> stack should be 'abcd', 'abc'
|
||||
|
||||
`del`
|
||||
|
||||
## spaces
|
||||
|
||||
`'abc d'`
|
||||
|
||||
-> stack should be 'abc d'
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 2
|
||||
|
||||
`' abcd '`
|
||||
|
||||
-> stack should be ' abcd '
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 3
|
||||
|
||||
`' abcd ' 'def' 'gh ij'`
|
||||
|
||||
-> stack should be ' abcd ', 'def', 'gh ij'
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 4
|
||||
|
||||
`' . abcd . ;; '`
|
||||
|
||||
-> stack should be ' . abcd . ;; '
|
||||
|
||||
`del`
|
||||
|
||||
## spaces 5
|
||||
|
||||
`' . abcd . ;; ' 'ab c`
|
||||
|
||||
-> stack should be ' . abcd . ;; ', 'ab c'
|
||||
|
||||
`del`
|
||||
|
||||
## nested types 1
|
||||
|
||||
`'1'`
|
||||
|
||||
-> stack should be '1'
|
||||
|
||||
`del`
|
||||
|
||||
## nested types 2
|
||||
|
||||
`'1.0 swap drop`
|
||||
|
||||
-> stack should be '1.0 swap drop'
|
||||
|
||||
`del`
|
137
test/023-parse-number.md
Normal file
137
test/023-parse-number.md
Normal file
|
@ -0,0 +1,137 @@
|
|||
# PARSE NUMBER
|
||||
|
||||
`default del`
|
||||
|
||||
## type
|
||||
|
||||
`1.0 type`
|
||||
|
||||
-> stack should be "number"
|
||||
|
||||
`del`
|
||||
|
||||
## numb 1
|
||||
|
||||
`3.14 +3.14 -3.14`
|
||||
|
||||
-> stack should be 3.14, 3.14, -3.14
|
||||
|
||||
`del`
|
||||
|
||||
## spaces
|
||||
|
||||
` -3.14 -3 .14`
|
||||
|
||||
-> stack should be -3.14, -3, 0.14
|
||||
|
||||
`del`
|
||||
|
||||
## exp entry
|
||||
|
||||
`+3.14e2`
|
||||
|
||||
-> stack should be 314
|
||||
|
||||
`del`
|
||||
|
||||
## inf nan
|
||||
|
||||
`+inf inf -inf nan`
|
||||
|
||||
-> stack should be inf, inf, -inf, nan
|
||||
|
||||
`del`
|
||||
|
||||
## hex
|
||||
|
||||
`0x10 0X10`
|
||||
|
||||
-> stack should be 0x10, 0x10
|
||||
|
||||
`del`
|
||||
|
||||
## hex err
|
||||
|
||||
`0x 0X`
|
||||
|
||||
-> stack should be '0x', '0X'
|
||||
|
||||
`del`
|
||||
|
||||
## bin
|
||||
|
||||
`0b1101 0b0`
|
||||
|
||||
-> stack should be 0b1101, 0b0
|
||||
|
||||
`del`
|
||||
|
||||
## bin err
|
||||
|
||||
`0b`
|
||||
|
||||
-> stack should be '0b'
|
||||
|
||||
`del`
|
||||
|
||||
## base
|
||||
|
||||
`del 3b12`
|
||||
|
||||
-> stack should be 3b12
|
||||
|
||||
## base (2)
|
||||
`del 0x1e2`
|
||||
|
||||
-> stack should be 0x1e2
|
||||
|
||||
## base (3)
|
||||
|
||||
`del 0x-1e2 5b-1234 0b-1`
|
||||
|
||||
-> stack should be -0x1e2, -5b1234, -0b1
|
||||
|
||||
## base (4)
|
||||
|
||||
`del -0x1e2 -5b1234 -0b1`
|
||||
|
||||
-> stack should be -0x1e2, -5b1234, -0b1
|
||||
|
||||
## base err
|
||||
|
||||
`del 0b12`
|
||||
|
||||
-> stack should be '0b12'
|
||||
|
||||
## base err (2)
|
||||
|
||||
`del 1b0`
|
||||
-> stack should be '1b0'
|
||||
|
||||
`del -1b33`
|
||||
|
||||
-> stack should be '-1b33'
|
||||
|
||||
`del -63b1`
|
||||
|
||||
-> stack should be '-63b1'
|
||||
|
||||
## wrong base errors
|
||||
|
||||
`del 0b0.1100`
|
||||
`ab Xb 1b ax 0X 3X`
|
||||
|
||||
-> stack should be 0b1, 'ab', 'Xb', '1b', 'ax', '0X', '3X'
|
||||
|
||||
## particular writings
|
||||
|
||||
`del 10b12345 2b1100`
|
||||
|
||||
-> stack should be 12345, 0b1100
|
||||
|
||||
## hex powers
|
||||
`del 0x10p3 -0x2p4`
|
||||
|
||||
-> stack should be 0x80, -0x20
|
||||
|
||||
`del default`
|
63
test/024-parse-complex.md
Normal file
63
test/024-parse-complex.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
# PARSE COMPLEX
|
||||
|
||||
`default del`
|
||||
|
||||
## type
|
||||
|
||||
`(1,2) type`
|
||||
|
||||
-> stack should be "complex"
|
||||
|
||||
`del`
|
||||
|
||||
## cplx
|
||||
|
||||
`(1,2) (1, 2) ( 1 , 2 )`
|
||||
|
||||
-> stack should be (1,2), (1,2), (1,2)
|
||||
|
||||
`del`
|
||||
|
||||
## cplx inf nan
|
||||
|
||||
```
|
||||
(inf,3)
|
||||
(-inf,nan) (inf,-inf)
|
||||
```
|
||||
|
||||
-> stack should be (inf,3), (-inf,nan), (inf,-inf)
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated
|
||||
|
||||
`( 3.14e2 , -2`
|
||||
|
||||
-> stack should be (314,-2)
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated 2
|
||||
|
||||
`(-inf, nan`
|
||||
|
||||
-> stack should be (-inf,nan)
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated err
|
||||
|
||||
```
|
||||
(
|
||||
(a
|
||||
(123
|
||||
(,
|
||||
(,)
|
||||
(12,
|
||||
(,13)
|
||||
(,3.14
|
||||
```
|
||||
|
||||
-> stack should be '(', '(a', '(123', '(,', '(,)', '(12,', '(,13)', '(,3.14'
|
||||
|
||||
`del`
|
27
test/025-parse-other.md
Normal file
27
test/025-parse-other.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# PARSE SOME COMMANDS
|
||||
|
||||
`default del`
|
||||
|
||||
## some command
|
||||
|
||||
`+`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## some command 2
|
||||
|
||||
` +`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## some command 3
|
||||
|
||||
` + -`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
86
test/026-parse-program.md
Normal file
86
test/026-parse-program.md
Normal file
|
@ -0,0 +1,86 @@
|
|||
# PARSE PROGRAM
|
||||
|
||||
`default del `
|
||||
|
||||
## type
|
||||
|
||||
`<< I >> type`
|
||||
|
||||
-> stack should be "program"
|
||||
|
||||
`del`
|
||||
|
||||
## prog 1
|
||||
|
||||
`<< I am a program >>`
|
||||
|
||||
-> stack should be «I am a program»
|
||||
|
||||
`del`
|
||||
|
||||
## prog 2
|
||||
|
||||
`<<I am a program>>`
|
||||
|
||||
-> stack should be «I am a program»
|
||||
|
||||
`del`
|
||||
|
||||
## prog 3
|
||||
|
||||
`<< I am a program >>`
|
||||
|
||||
-> stack should be «I am a program»
|
||||
|
||||
`del`
|
||||
|
||||
## prog 4
|
||||
|
||||
`«I am a program»`
|
||||
|
||||
-> stack should be «I am a program»
|
||||
|
||||
`del`
|
||||
|
||||
## prog 5
|
||||
|
||||
`« I am a program »`
|
||||
|
||||
-> stack should be «I am a program»
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated 1
|
||||
|
||||
`<< prog`
|
||||
|
||||
-> stack should be «prog»
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated 2
|
||||
|
||||
`« prog`
|
||||
|
||||
-> stack should be «prog»
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated 3
|
||||
|
||||
`<< prog>`
|
||||
|
||||
-> stack should be «prog>»
|
||||
|
||||
`del`
|
||||
|
||||
## unterminated 4
|
||||
|
||||
```
|
||||
<<
|
||||
«
|
||||
```
|
||||
|
||||
-> stack should be «», «»
|
||||
|
||||
`del`
|
365
test/027-base-entry.md
Normal file
365
test/027-base-entry.md
Normal file
|
@ -0,0 +1,365 @@
|
|||
# REAL AND COMPLEX NUMERICAL ENTRIES
|
||||
|
||||
`default del`
|
||||
|
||||
## table for fixed entry, 4 fix output >= 0
|
||||
|
||||
```
|
||||
4 fix
|
||||
1 0.01 0.0001 0.00006 0.00004 0 0.012 0.001256 100 100.001 100.00006 100.00004 12345678910111213.12355
|
||||
```
|
||||
|
||||
-> stack should be 1.0000, 0.0100, 0.0001, 0.0001, 0.0000, 0.0000, 0.0120, 0.0013, 100.0000, 100.0010, 100.0001, 100.0000, 12345678910111213.1236
|
||||
|
||||
`del default`
|
||||
|
||||
## table for fixed entry, 4 fix output <= 0
|
||||
|
||||
```
|
||||
4 fix
|
||||
-1 -0.01 -0.0001 -0.00006 -0.00004 -0 -0.012 -0.001256 -100 -100.001 -100.00006 -100.00004 -12345678910111213.12355
|
||||
```
|
||||
|
||||
-> stack should be -1.0000, -0.0100, -0.0001, -0.0001, -0.0000, -0.0000, -0.0120, -0.0013, -100.0000, -100.0010, -100.0001, -100.0000, -12345678910111213.1236
|
||||
|
||||
`del default`
|
||||
|
||||
## table for sci entry, 4 fix output >= 0
|
||||
|
||||
```
|
||||
4 fix
|
||||
0e100 1e0 1.e0 1.001e0 1.e-3 1.e-4 6.e-5 4.e-5 1.00001e2 1.0000006e2 1.0000004e2 1234.5678917e2
|
||||
```
|
||||
|
||||
-> stack should be 0.0000, 1.0000, 1.0000, 1.0010, 0.0010, 0.0001, 0.0001, 0.0000, 100.0010, 100.0001, 100.0000, 123456.7892
|
||||
|
||||
`del default`
|
||||
|
||||
## table for sci entry, 4 fix output <= 0
|
||||
|
||||
```
|
||||
4 fix
|
||||
-0e100 -1e0 -1.e0 -1.001e0 -1.e-3 -1.e-4 -6.e-5 -4.e-5 -1.00001e2 -1.0000006e2 -1.0000004e2 -1234.5678917e2
|
||||
```
|
||||
|
||||
-> stack should be -0.0000, -1.0000, -1.0000, -1.0010, -0.0010, -0.0001, -0.0001, -0.0000, -100.0010, -100.0001, -100.0000, -123456.7892
|
||||
|
||||
`del default`
|
||||
|
||||
## table for singularity
|
||||
|
||||
```
|
||||
4 fix
|
||||
nan @nan@ -nan inf -inf @inf@ -@inf@
|
||||
```
|
||||
|
||||
-> stack should be nan, nan, nan, inf, -inf, inf, -inf
|
||||
|
||||
`del default`
|
||||
|
||||
## some strange behaviour (1)
|
||||
|
||||
```
|
||||
0 fix
|
||||
1 2 / dup +
|
||||
```
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del default`
|
||||
|
||||
## some strange behaviour (2)
|
||||
|
||||
```
|
||||
1 fix
|
||||
0.6
|
||||
```
|
||||
|
||||
-> stack should be 0.6
|
||||
|
||||
`del default`
|
||||
|
||||
## some strange behaviour (3)
|
||||
|
||||
```
|
||||
0 fix
|
||||
110.6 0.6
|
||||
```
|
||||
|
||||
-> stack should be 111, 1
|
||||
|
||||
`del default`
|
||||
|
||||
## hex (1)
|
||||
|
||||
`0x4000000000000`
|
||||
|
||||
-> stack should be 0x4000000000000
|
||||
|
||||
`del default`
|
||||
|
||||
## hex (2)
|
||||
|
||||
`2 50 ^ hex`
|
||||
|
||||
-> stack should be 0x4000000000000
|
||||
|
||||
`del default`
|
||||
|
||||
## hex (3)
|
||||
|
||||
`12.34 hex`
|
||||
|
||||
-> stack should be 0xc
|
||||
|
||||
`del default`
|
||||
|
||||
## dec (1)
|
||||
|
||||
`2 50 ^`
|
||||
|
||||
-> stack should be 1125899906842624
|
||||
|
||||
`del default`
|
||||
|
||||
## dec (2)
|
||||
|
||||
`0x4000000000000 dec`
|
||||
|
||||
-> stack should be 1125899906842624
|
||||
|
||||
`del default`
|
||||
|
||||
## dec (3)
|
||||
|
||||
`12.34 dec`
|
||||
|
||||
-> stack should be 12.34
|
||||
|
||||
`del default`
|
||||
|
||||
## bin (1)
|
||||
|
||||
`0b100000000000000000000000000000000000000000000000000 bin`
|
||||
|
||||
-> stack should be 0b100000000000000000000000000000000000000000000000000
|
||||
|
||||
`del default`
|
||||
|
||||
## bin (2)
|
||||
|
||||
`2 50 ^ bin`
|
||||
|
||||
-> stack should be 0b100000000000000000000000000000000000000000000000000
|
||||
|
||||
`del default`
|
||||
|
||||
## bin (3)
|
||||
|
||||
`0x4000000000000 bin`
|
||||
|
||||
-> stack should be 0b100000000000000000000000000000000000000000000000000
|
||||
|
||||
`del default`
|
||||
|
||||
## bin (4)
|
||||
|
||||
`12.34 bin`
|
||||
|
||||
-> stack should be 0b1100
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (1)
|
||||
|
||||
`3b111 dup dec`
|
||||
|
||||
-> stack should be 3b111, 13
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (2)
|
||||
|
||||
`3b114`
|
||||
|
||||
-> stack should be '3b114'
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (3)
|
||||
|
||||
`1b0`
|
||||
|
||||
-> stack should be '1b0'
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (4)
|
||||
|
||||
`62b20 dup dec`
|
||||
|
||||
-> stack should be 62b20, 124
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (5)
|
||||
|
||||
`63b20`
|
||||
|
||||
-> stack should be '63b20'
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (6)
|
||||
|
||||
`2b11001100 0b11001100 ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (7)
|
||||
|
||||
`10b1234 1234 ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del default`
|
||||
|
||||
## base entry (8)
|
||||
|
||||
`16b1234 0x1234 ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del default`
|
||||
|
||||
## base display (1)
|
||||
|
||||
`2 62 for i 62 i base next`
|
||||
|
||||
-> stack should be 0b111110, 3b2022, 4b332, 5b222, 6b142, 7b116, 8b76, 9b68, 62, 11b57, 12b52, 13b4a, 14b46, 15b42, 0x3e, 17b3b, 18b38, 19b35, 20b32, 21b2k, 22b2i, 23b2g, 24b2e, 25b2c, 26b2a, 27b28, 28b26, 29b24, 30b22, 31b20, 32b1u, 33b1t, 34b1s, 35b1r, 36b1q, 37b1P, 38b1O, 39b1N, 40b1M, 41b1L, 42b1K, 43b1J, 44b1I, 45b1H, 46b1G, 47b1F, 48b1E, 49b1D, 50b1C, 51b1B, 52b1A, 53b19, 54b18, 55b17, 56b16, 57b15, 58b14, 59b13, 60b12, 61b11, 62b10
|
||||
|
||||
`del default`
|
||||
|
||||
## base display (2)
|
||||
|
||||
`2 62 for i i 62 base next`
|
||||
|
||||
-> stack should be 62b2, 62b3, 62b4, 62b5, 62b6, 62b7, 62b8, 62b9, 62bA, 62bB, 62bC, 62bD, 62bE, 62bF, 62bG, 62bH, 62bI, 62bJ, 62bK, 62bL, 62bM, 62bN, 62bO, 62bP, 62bQ, 62bR, 62bS, 62bT, 62bU, 62bV, 62bW, 62bX, 62bY, 62bZ, 62ba, 62bb, 62bc, 62bd, 62be, 62bf, 62bg, 62bh, 62bi, 62bj, 62bk, 62bl, 62bm, 62bn, 62bo, 62bp, 62bq, 62br, 62bs, 62bt, 62bu, 62bv, 62bw, 62bx, 62by, 62bz, 62b10
|
||||
|
||||
`del default`
|
||||
|
||||
## base display (3)
|
||||
|
||||
```
|
||||
100 dup 3 base ==
|
||||
13455600 dup 5 base ==
|
||||
55756 dup 17 base ==
|
||||
2345321 dup 62 base ==
|
||||
```
|
||||
|
||||
-> stack should be 1, 1, 1, 1
|
||||
|
||||
`del default`
|
||||
|
||||
## base display (4)
|
||||
|
||||
```
|
||||
100 18 base dup 3 base == dec
|
||||
13455600 55 base dup 5 base == dec
|
||||
55756 9 base dup 17 base == dec
|
||||
2345321 57 base dup 62 base == dec
|
||||
```
|
||||
|
||||
-> stack should be 1, 1, 1, 1
|
||||
|
||||
`del default`
|
||||
|
||||
## negative base numbers (1)
|
||||
|
||||
`1000 hex neg`
|
||||
|
||||
-> stack should be -0x3e8
|
||||
|
||||
`del default`
|
||||
|
||||
## negative base numbers (2)
|
||||
|
||||
`1000 7 base neg`
|
||||
|
||||
-> stack should be -7b2626
|
||||
|
||||
`del default`
|
||||
|
||||
## negative base numbers (3)
|
||||
|
||||
`1000 bin neg`
|
||||
|
||||
-> stack should be -0b1111101000
|
||||
|
||||
`del default`
|
||||
|
||||
## negative base numbers (4)
|
||||
|
||||
`-0b1111101000 3 base`
|
||||
|
||||
-> stack should be -3b1101001
|
||||
|
||||
`del default`
|
||||
|
||||
## base on complexes
|
||||
|
||||
```
|
||||
(0b110,0x102) dup bin swap dup hex dup 5 base
|
||||
```
|
||||
|
||||
-> stack should be (0b110,0b100000010), (0b110,0x102), (0x6,0x102), (5b11,5b2013)
|
||||
|
||||
`del default`
|
||||
|
||||
## inf should not be based-represented
|
||||
|
||||
`-1 bin 0 bin / 1 3 base 0 3 base /`
|
||||
|
||||
-> stack should be -inf, inf
|
||||
|
||||
`del default`
|
||||
|
||||
## nan should not be based-represented
|
||||
|
||||
`-0 bin 0 bin / 0 3 base 0 3 base /`
|
||||
|
||||
-> stack should be nan, nan
|
||||
|
||||
`del default`
|
||||
|
||||
## complex base 16
|
||||
|
||||
`(0x10,0x20)`
|
||||
|
||||
-> stack should be (0x10,0x20)
|
||||
|
||||
## complex base 16 (2)
|
||||
|
||||
`del (16,32) hex`
|
||||
|
||||
-> stack should be (0x10,0x20)
|
||||
|
||||
## complex base 2
|
||||
|
||||
`del (0b111,0b110)`
|
||||
|
||||
-> stack should be (0b111,0b110)
|
||||
|
||||
## complex base 2 (2)
|
||||
|
||||
`del (7,6) bin`
|
||||
|
||||
-> stack should be (0b111,0b110)
|
||||
|
||||
## complex multiple bases re / im
|
||||
|
||||
`del (0x10,0b111) dup dup hex swap dec`
|
||||
|
||||
-> stack should be (0x10,0b111), (0x10,0x7), (16,7)
|
|
@ -1,397 +0,0 @@
|
|||
## BRANCH
|
||||
default del
|
||||
|
||||
# if then else end (1)
|
||||
1 if then 'ok' end
|
||||
-> stack should be 'ok'
|
||||
del
|
||||
|
||||
# if then else end (2)
|
||||
1 if 'before' then 'ok' end
|
||||
-> stack should be 'before', 'ok'
|
||||
del
|
||||
|
||||
# if then else end (3)
|
||||
0 if then 'ok' end
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# if then else end (4)
|
||||
0 if then 'ok' end
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# if then else end (5)
|
||||
1 if then 'ok' else 'KO' end
|
||||
-> stack should be 'ok'
|
||||
del
|
||||
|
||||
# if then else end (6)
|
||||
1 if then 'ok' 'dokey' else 'KO' end
|
||||
-> stack should be 'ok', 'dokey'
|
||||
del
|
||||
|
||||
# if then else end (7)
|
||||
0 if then 'ok' else 'KO' end
|
||||
-> stack should be 'KO'
|
||||
del
|
||||
|
||||
# if then else end - error case (1)
|
||||
if then end
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# if then else end - error case (2)
|
||||
0 if then
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# if then else end - error case (3)
|
||||
0 if end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# if then else end - error case (4)
|
||||
0 if end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# if then else end - error case (5)
|
||||
then
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# if then else end - error case (6)
|
||||
1 if
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# if then else end - error case (7)
|
||||
else
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# if then else end - error case (8)
|
||||
end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# if then else end - error case (9)
|
||||
"1" if then end
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# ift (1)
|
||||
1 'ok' ift
|
||||
-> stack should be 'ok'
|
||||
del
|
||||
|
||||
# ift (2)
|
||||
0 'ok' ift
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# ift (3)
|
||||
'ok' ift
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# ift (4)
|
||||
ift
|
||||
-> error should be 2
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# ifte (1)
|
||||
1 'ok' 'nok' ifte
|
||||
-> stack should be 'ok'
|
||||
del
|
||||
|
||||
# ifte (2)
|
||||
0 'ok' 'nok' ifte
|
||||
-> stack should be 'nok'
|
||||
del
|
||||
|
||||
# ifte (3)
|
||||
'ok' 'nok' ifte
|
||||
-> error should be 2
|
||||
-> stack size should be 2
|
||||
del
|
||||
|
||||
# ifte (4)
|
||||
'nok' ifte
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# ifte (5)
|
||||
ifte
|
||||
-> error should be 2
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# start next (1)
|
||||
1 2 start 0 next
|
||||
-> stack should be 0, 0
|
||||
del
|
||||
|
||||
# start next (2)
|
||||
2 1 start 0 next
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# start next (3)
|
||||
-2 -1 start 0 next
|
||||
-> stack should be 0, 0
|
||||
del
|
||||
|
||||
# start next (4)
|
||||
-1 -2 start 0 next
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# start next (5)
|
||||
1 1 start 0 next
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# start next - error case (1)
|
||||
1 start next
|
||||
->error should be 2
|
||||
del
|
||||
|
||||
# start next - error case (2)
|
||||
start next
|
||||
->error should be 2
|
||||
del
|
||||
|
||||
# start next - error case (3)
|
||||
start
|
||||
->error should be 11
|
||||
del
|
||||
|
||||
# start next - error case (4)
|
||||
next
|
||||
->error should be 11
|
||||
del
|
||||
|
||||
# start next - error case (5)
|
||||
"1" 2 start next
|
||||
->error should be 3
|
||||
del
|
||||
|
||||
# start next - error case (5)
|
||||
1 "2" start next
|
||||
->error should be 3
|
||||
del
|
||||
|
||||
# for next (1)
|
||||
23 27 for i i next
|
||||
-> stack should be 23, 24, 25, 26, 27
|
||||
del
|
||||
|
||||
# for next (2)
|
||||
1 1 for i i next
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# for next (3)
|
||||
27 23 for i i next
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# for next (4)
|
||||
-2 -1 for i i next
|
||||
-> stack should be -2, -1
|
||||
del
|
||||
|
||||
# for next (5)
|
||||
-1 -2 for i i next
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# for next - error case (1)
|
||||
1 for i i next
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# for next - error case (2)
|
||||
for i i next
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# for next - error case (3)
|
||||
"1" 2 for i i next
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# for next - error case (4)
|
||||
1 "2" for i i next
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# for next - error case (5)
|
||||
1 2 for i i
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# for next - error case (6)
|
||||
for
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# for step (1)
|
||||
23 27 for i i 1 step
|
||||
-> stack should be 23, 24, 25, 26, 27
|
||||
del
|
||||
|
||||
# for step (2)
|
||||
0 1 for i i 0.25 step
|
||||
-> stack should be 0, 0.25, 0.5, 0.75, 1
|
||||
del
|
||||
|
||||
# for step (3)
|
||||
-1 0 for i i 0.25 step
|
||||
-> stack should be -1, -0.75, -0.5, -0.25, -0
|
||||
del
|
||||
|
||||
# for step (4)
|
||||
0 -1 for i i 0.25 step
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# for step (5)
|
||||
0 -1 for i i -0.25 step
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# for step (6) - check boundary integration
|
||||
1 2 for i i 0.2 step
|
||||
-> stack should be 1, 1.2, 1.4, 1.6, 1.8, 2
|
||||
del
|
||||
|
||||
# for step (7) - check boundary integration
|
||||
1 2 for i i 0.5 step
|
||||
-> stack should be 1, 1.5, 2
|
||||
del
|
||||
|
||||
# for step - error case (1)
|
||||
0 1 for i i "0.5" step
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# for step - error case (2)
|
||||
step
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# do..unti (1)
|
||||
do 'ok' unti 1 end
|
||||
-> stack should be 'ok'
|
||||
del
|
||||
|
||||
# do..unti (2)
|
||||
do unti 1 end
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# do..unti (3)
|
||||
1 'a' sto do a unti a 0 > end
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# do..unti (4)
|
||||
1 'a' sto do a 'a' 1 sto+ unti a 3 > end
|
||||
-> stack should be 1, 2, 3
|
||||
del
|
||||
|
||||
# do..unti (5)
|
||||
"" 0 'a' sto do 'a' 1 sto+ 0 a for b b ->str + next unti a 3 > end
|
||||
-> stack should be "01012012301234"
|
||||
del
|
||||
|
||||
# do..unti error case (1)
|
||||
do
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# do..unti error case (2)
|
||||
do 8 end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# do..unti error case (3)
|
||||
unti
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# do..unti error case (4)
|
||||
do 3 unti
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# do..unti error case (5)
|
||||
unti 1 end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# do..unti error case (6)
|
||||
do 3 repeat 8 end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# do..unti error case (7)
|
||||
do 3 until 8 until 9 end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# while..repeat (1)
|
||||
while 0 repeat ok end
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# while..repeat (2)
|
||||
2 while dup 0.1 > repeat dup 2 / end
|
||||
-> stack should be 2, 1, 0.5, 0.25, 0.125, 0.0625
|
||||
del
|
||||
|
||||
# while..repeat (3)
|
||||
"" 0 'a' sto while a 3 < repeat 'a' 1 sto+ 0 a for b b ->str + next end
|
||||
-> stack should be "010120123"
|
||||
del
|
||||
|
||||
# while..repeat error case (1)
|
||||
while
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# while..repeat error case (2)
|
||||
while 3 end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# while..repeat error case (3)
|
||||
repeat
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# while..repeat error case (4)
|
||||
while 1 repeat
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# while..repeat error case (5)
|
||||
repeat 1 end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# while..repeat error case (6)
|
||||
while 3 repeat 8 repeat 9 end
|
||||
-> error should be 11
|
||||
del
|
||||
|
||||
# while..repeat error case (7)
|
||||
while 3 until 8 end
|
||||
-> error should be 11
|
||||
del
|
709
test/030-branch.md
Normal file
709
test/030-branch.md
Normal file
|
@ -0,0 +1,709 @@
|
|||
# BRANCH
|
||||
|
||||
`default del`
|
||||
|
||||
## if then else end (1)
|
||||
`1 if then 'ok' end`
|
||||
|
||||
-> stack should be 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end (2)
|
||||
|
||||
`1 if 'before' then 'ok' end`
|
||||
|
||||
-> stack should be 'before', 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end (3)
|
||||
|
||||
`0 if then 'ok' end`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end (4)
|
||||
|
||||
`0 if then 'ok' end`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end (5)
|
||||
|
||||
`1 if then 'ok' else 'KO' end`
|
||||
|
||||
-> stack should be 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end (6)
|
||||
|
||||
`1 if then 'ok' 'dokey' else 'KO' end`
|
||||
|
||||
-> stack should be 'ok', 'dokey'
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end (7)
|
||||
|
||||
`0 if then 'ok' else 'KO' end`
|
||||
|
||||
-> stack should be 'KO'
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (1)
|
||||
|
||||
`if then end`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (2)
|
||||
|
||||
`0 if then`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (3)
|
||||
|
||||
`0 if end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (4)
|
||||
|
||||
`0 if end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (5)
|
||||
|
||||
`then`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (6)
|
||||
|
||||
`1 if`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (7)
|
||||
|
||||
`else`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
|
||||
## if then else end - error case (8)
|
||||
|
||||
`end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## if then else end - error case (9)
|
||||
|
||||
`"1" if then end`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## ift (1)
|
||||
|
||||
`1 'ok' ift`
|
||||
|
||||
-> stack should be 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## ift (2)
|
||||
|
||||
`0 'ok' ift`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## ift (3)
|
||||
|
||||
`'ok' ift`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## ift (4)
|
||||
|
||||
`ift`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## ifte (1)
|
||||
|
||||
`1 'ok' 'nok' ifte`
|
||||
|
||||
-> stack should be 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## ifte (2)
|
||||
|
||||
`0 'ok' 'nok' ifte`
|
||||
|
||||
-> stack should be 'nok'
|
||||
|
||||
`del`
|
||||
|
||||
## ifte (3)
|
||||
|
||||
`'ok' 'nok' ifte`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## ifte (4)
|
||||
|
||||
`'nok' ifte`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## ifte (5)
|
||||
|
||||
`ifte`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## start next (1)
|
||||
|
||||
`1 2 start 0 next`
|
||||
|
||||
-> stack should be 0, 0
|
||||
|
||||
`del`
|
||||
|
||||
## start next (2)
|
||||
|
||||
`2 1 start 0 next`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## start next (3)
|
||||
|
||||
`-2 -1 start 0 next`
|
||||
|
||||
-> stack should be 0, 0
|
||||
|
||||
`del`
|
||||
|
||||
## start next (4)
|
||||
|
||||
`-1 -2 start 0 next`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## start next (5)
|
||||
|
||||
`1 1 start 0 next`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## start next - cloning objects (1)
|
||||
|
||||
`1 2 start 'ok' next`
|
||||
|
||||
-> stack should be 'ok', 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## start next - cloning objects (2)
|
||||
|
||||
`1 2 start ok next`
|
||||
|
||||
-> stack should be 'ok', 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## start next - cloning objects (3)
|
||||
|
||||
`1 2 start "ok" next`
|
||||
|
||||
-> stack should be "ok", "ok"
|
||||
|
||||
`del`
|
||||
|
||||
## start next - cloning objects (4)
|
||||
|
||||
`1 2 start (1,2) next`
|
||||
|
||||
-> stack should be (1,2), (1,2)
|
||||
|
||||
`del`
|
||||
|
||||
## start next - cloning objects (5)
|
||||
|
||||
`1 2 start «ok» next`
|
||||
|
||||
-> stack should be «ok», «ok»
|
||||
|
||||
`del`
|
||||
|
||||
## start next - error case (1)
|
||||
|
||||
`1 start next`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## start next - error case (2)
|
||||
|
||||
`start next`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## start next - error case (3)
|
||||
|
||||
`start`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## start next - error case (4)
|
||||
|
||||
`next`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## start next - error case (5)
|
||||
|
||||
`"1" 2 start next`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## start next - error case (6)
|
||||
|
||||
`1 "2" start next`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## for next (1)
|
||||
|
||||
`23 27 for i i next`
|
||||
|
||||
-> stack should be 23, 24, 25, 26, 27
|
||||
|
||||
`del`
|
||||
|
||||
## for next (2)
|
||||
|
||||
`1 1 for i i next`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## for next (3)
|
||||
|
||||
`27 23 for i i next`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## for next (4)
|
||||
|
||||
`-2 -1 for i i next`
|
||||
|
||||
-> stack should be -2, -1
|
||||
|
||||
`del`
|
||||
|
||||
## for next (5)
|
||||
|
||||
`-1 -2 for i i next`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## for next - loop variable overwrite
|
||||
|
||||
`123 'i' sto 1 2 for i i next`
|
||||
|
||||
-> stack should be 1, 2
|
||||
|
||||
`del`
|
||||
|
||||
## nested for next
|
||||
|
||||
`1 2 for i 0 1 for j i (1,0) * j (0,1) * + next next`
|
||||
|
||||
-> stack should be (1,0), (1,1), (2,0), (2,1)
|
||||
|
||||
`del`
|
||||
|
||||
## for next - error case (1)
|
||||
|
||||
`1 for i i next`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## for next - error case (2)
|
||||
|
||||
`for i i next`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## for next - error case (3)
|
||||
|
||||
`"1" 2 for i i next`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## for next - error case (4)
|
||||
|
||||
`1 "2" for i i next`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## for next - error case (5)
|
||||
|
||||
`1 2 for i i`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## for next - error case (6)
|
||||
|
||||
`for`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## for step (1)
|
||||
|
||||
`23 27 for i i 1 step`
|
||||
|
||||
-> stack should be 23, 24, 25, 26, 27
|
||||
|
||||
`del`
|
||||
|
||||
## for step (2)
|
||||
|
||||
`0 1 for i i 0.25 step`
|
||||
|
||||
-> stack should be 0, 0.25, 0.5, 0.75, 1
|
||||
|
||||
`del`
|
||||
|
||||
## for step (3)
|
||||
|
||||
`-1 0 for i i 0.25 step`
|
||||
|
||||
-> stack should be -1, -0.75, -0.5, -0.25, -0
|
||||
|
||||
`del`
|
||||
|
||||
## for step (4)
|
||||
|
||||
`0 -1 for i i 0.25 step`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## for step (5)
|
||||
|
||||
`0 -1 for i i -0.25 step`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## for step (6) - check boundary integration
|
||||
|
||||
`1 2 for i i 0.2 step`
|
||||
|
||||
-> stack should be 1, 1.2, 1.4, 1.6, 1.8, 2
|
||||
|
||||
`del`
|
||||
|
||||
## for step (7) - check boundary integration
|
||||
|
||||
`1 2 for i i 0.5 step`
|
||||
|
||||
-> stack should be 1, 1.5, 2
|
||||
|
||||
`del`
|
||||
|
||||
## nested for step
|
||||
|
||||
`0 2 for i 0 6 for j i (1,0) * j (0,1) * + 3 step 2 step`
|
||||
|
||||
-> stack should be (0,0), (0,3), (0,6), (2,0), (2,3), (2,6)
|
||||
|
||||
`del`
|
||||
|
||||
## for step - error case (1)
|
||||
|
||||
`0 1 for i i "0.5" step`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## for step - error case (2)
|
||||
|
||||
`step`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## do..until (1)
|
||||
|
||||
`do 'ok' until 1 end`
|
||||
|
||||
-> stack should be 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## do..until (2)
|
||||
|
||||
`do until 1 end`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## do..until (3)
|
||||
|
||||
`3 do 1 - 'ok' swap dup until 0 == end drop`
|
||||
|
||||
-> stack should be 'ok', 'ok', 'ok'
|
||||
|
||||
`del`
|
||||
|
||||
## do..until (4)
|
||||
|
||||
`1 'a' sto do a 1 + 'a' sto until a 3 > end a`
|
||||
|
||||
-> stack should be 4
|
||||
|
||||
`del`
|
||||
|
||||
## nexted do..until
|
||||
|
||||
`1 'i' sto do 0 'j' sto do i (1,0) * j (0,1) * + 1 'j' sto+ until j 1 > end 1 'i' sto+ until i 2 > end`
|
||||
|
||||
-> stack should be (1,0), (1,1), (2,0), (2,1)
|
||||
|
||||
`del`
|
||||
|
||||
## do..until error case (1)
|
||||
|
||||
`do`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## do..until error case (2)
|
||||
|
||||
`do 8 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## do..until error case (3)
|
||||
|
||||
`until`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## do..until error case (4)
|
||||
|
||||
`do 3 until`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## do..until error case (5)
|
||||
|
||||
`until 1 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## do..until error case (6)
|
||||
|
||||
`do 3 repeat 8 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## do..until error case (7)
|
||||
|
||||
`do 3 until 8 until 9 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat (1)
|
||||
|
||||
`while 0 repeat ok end`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat (2)
|
||||
|
||||
`2 while dup 0.1 > repeat dup 2 / end`
|
||||
|
||||
-> stack should be 2, 1, 0.5, 0.25, 0.125, 0.0625
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat (3)
|
||||
|
||||
`0 'a' sto while a 3 < repeat a 1 + 'a' sto 100 0 a for b b + next end`
|
||||
|
||||
-> stack should be 101, 103, 106
|
||||
|
||||
`del`
|
||||
|
||||
## nested while .. repeat
|
||||
|
||||
`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`
|
||||
|
||||
-> stack should be (1,0), (1,1), (2,0), (2,1)
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat error case (1)
|
||||
|
||||
`while`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat error case (2)
|
||||
|
||||
`while 3 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat error case (3)
|
||||
|
||||
`repeat`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat error case (4)
|
||||
|
||||
`while 1 repeat`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat error case (5)
|
||||
|
||||
`repeat 1 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat error case (6)
|
||||
|
||||
`while 3 repeat 8 repeat 9 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
||||
|
||||
## while..repeat error case (7)
|
||||
|
||||
`while 3 until 8 end`
|
||||
|
||||
-> error should be 11
|
||||
|
||||
`del`
|
|
@ -1,182 +0,0 @@
|
|||
## STACK TEST
|
||||
default del
|
||||
|
||||
# entry depth (1)
|
||||
1 depth
|
||||
-> stack size should be 2
|
||||
|
||||
# entry depth (2)
|
||||
1 del depth
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# swap
|
||||
1 2 swap
|
||||
-> stack size should be 2
|
||||
-> stack should be 2, 1
|
||||
del
|
||||
|
||||
# swap with filled stack
|
||||
5 6 1 2 swap
|
||||
-> stack size should be 4
|
||||
-> stack should be 5, 6, 2, 1
|
||||
del
|
||||
|
||||
# swap error
|
||||
5 swap
|
||||
-> stack size should be 1
|
||||
-> error should 2
|
||||
del
|
||||
|
||||
# drop
|
||||
1 2 3 drop
|
||||
-> stack size should be 2
|
||||
-> stack should be 1, 2
|
||||
del
|
||||
|
||||
# drop2
|
||||
1 2 3
|
||||
drop2
|
||||
-> stack size should be 1
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# drop error
|
||||
drop
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# drop2 error (1)
|
||||
drop2
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# drop2 error (2)
|
||||
1 drop2
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# test dup
|
||||
1 dup
|
||||
-> stack size should be 2
|
||||
-> stack should be 1, 1
|
||||
del
|
||||
|
||||
# test dup2
|
||||
1 2 dup2
|
||||
-> stack size should be 4
|
||||
-> stack should be 1, 2, 1, 2
|
||||
del
|
||||
|
||||
# test rot
|
||||
1 2 3 rot
|
||||
-> stack size should be 3
|
||||
-> stack should be 2, 3, 1
|
||||
del
|
||||
|
||||
# test rot with start
|
||||
5 6 7 1 2 start rot next
|
||||
-> stack should be 7, 5, 6
|
||||
del
|
||||
|
||||
# test rot with next
|
||||
5 6 7 1 2 for i rot next
|
||||
-> stack should be 7, 5, 6
|
||||
del
|
||||
|
||||
# test rot with filled stack
|
||||
5 6 1 2 3 rot
|
||||
-> stack size should be 5
|
||||
-> stack should be 5, 6, 2, 3, 1
|
||||
del
|
||||
|
||||
# test depth
|
||||
1 2 3
|
||||
depth
|
||||
-> stack size should be 4
|
||||
-> stack should be 1, 2, 3, 3
|
||||
del
|
||||
|
||||
# test pick
|
||||
1 2 3 4 2 pick
|
||||
-> stack size should be 5
|
||||
-> stack should be 1, 2, 3, 4, 3
|
||||
0 pick
|
||||
-> error should be 4
|
||||
7 pick
|
||||
-> error should be 4
|
||||
erase
|
||||
|
||||
# test erase
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# test del
|
||||
1 2 3 4 5
|
||||
del
|
||||
-> stack size should be 0
|
||||
|
||||
# test dropn
|
||||
1 2 2 dropn
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# test dropn error
|
||||
1 2 3 dropn
|
||||
-> stack size should be 3
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# test dupn
|
||||
1 2 3 4 3 dupn
|
||||
-> stack should be 1, 2, 3, 4, 2, 3, 4
|
||||
del
|
||||
|
||||
# test dupn error
|
||||
1 2 3 4 5 dupn
|
||||
-> stack size should be 5
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# test roll
|
||||
1 2 3 4 5 4 roll
|
||||
-> stack should be 1, 3, 4, 5, 2
|
||||
del
|
||||
|
||||
# test roll with filled stack
|
||||
10 11 1 2 3 4 5 4 roll
|
||||
-> stack should be 10, 11, 1, 3, 4, 5, 2
|
||||
del
|
||||
|
||||
# test roll error
|
||||
1 2 3 4 5 6 roll
|
||||
-> stack size should be 6
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# test rolld
|
||||
10 20 30 40 50 3 rolld
|
||||
-> stack should be 10, 20, 50, 30, 40
|
||||
del
|
||||
|
||||
# test rolld with filled stack
|
||||
80 90 10 20 30 40 50 3 rolld
|
||||
-> stack should be 80, 90, 10, 20, 50, 30, 40
|
||||
del
|
||||
|
||||
# test rolld error
|
||||
1 2 3 4 5 6 rolld
|
||||
-> stack size should be 6
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# test over
|
||||
3.14 15.16 over
|
||||
-> stack should be 3.14, 15.16, 3.14
|
||||
del
|
||||
|
||||
# test over error
|
||||
2 over
|
||||
-> stack size should be 1
|
||||
-> error should be 2
|
||||
del
|
289
test/040-stack.md
Normal file
289
test/040-stack.md
Normal file
|
@ -0,0 +1,289 @@
|
|||
# STACK
|
||||
|
||||
`default del`
|
||||
|
||||
## entry depth (1)
|
||||
|
||||
`1 depth`
|
||||
|
||||
-> stack size should be 2
|
||||
|
||||
## entry depth (2)
|
||||
|
||||
`1 del depth`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## swap
|
||||
|
||||
`1 2 swap`
|
||||
|
||||
-> stack size should be 2
|
||||
|
||||
-> stack should be 2, 1
|
||||
|
||||
`del`
|
||||
|
||||
## swap with filled stack
|
||||
|
||||
`5 6 1 2 swap`
|
||||
|
||||
-> stack size should be 4
|
||||
|
||||
-> stack should be 5, 6, 2, 1
|
||||
|
||||
`del`
|
||||
|
||||
## swap error
|
||||
|
||||
`5 swap`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## drop
|
||||
|
||||
`1 2 3 drop`
|
||||
|
||||
-> stack size should be 2
|
||||
|
||||
-> stack should be 1, 2
|
||||
|
||||
`del`
|
||||
|
||||
## drop2
|
||||
|
||||
`1 2 3 drop2`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## drop error
|
||||
|
||||
`drop`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## drop2 error (1)
|
||||
|
||||
`drop2`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## drop2 error (2)
|
||||
|
||||
`1 drop2`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## test dup
|
||||
|
||||
`1 dup`
|
||||
|
||||
-> stack size should be 2
|
||||
|
||||
-> stack should be 1, 1
|
||||
|
||||
`del`
|
||||
|
||||
## test dup2
|
||||
|
||||
`1 2 dup2`
|
||||
|
||||
-> stack size should be 4
|
||||
|
||||
-> stack should be 1, 2, 1, 2
|
||||
|
||||
`del`
|
||||
|
||||
## test rot
|
||||
|
||||
`1 2 3 rot`
|
||||
|
||||
-> stack size should be 3
|
||||
|
||||
-> stack should be 2, 3, 1
|
||||
|
||||
`del`
|
||||
|
||||
## test rot 2
|
||||
|
||||
`5 6 7 rot rot`
|
||||
|
||||
-> stack should be 7, 5, 6
|
||||
|
||||
`del`
|
||||
|
||||
## test rot with filled stack
|
||||
|
||||
`5 6 1 2 3 rot`
|
||||
|
||||
-> stack size should be 5
|
||||
|
||||
-> stack should be 5, 6, 2, 3, 1
|
||||
|
||||
`del`
|
||||
|
||||
## test depth
|
||||
|
||||
`1 2 3`
|
||||
|
||||
`depth`
|
||||
|
||||
-> stack size should be 4
|
||||
|
||||
-> stack should be 1, 2, 3, 3
|
||||
|
||||
`del`
|
||||
|
||||
## test pick
|
||||
|
||||
`1 2 3 4 2 pick`
|
||||
|
||||
-> stack size should be 5
|
||||
|
||||
-> stack should be 1, 2, 3, 4, 3
|
||||
|
||||
`0 pick`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`7 pick`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`erase`
|
||||
|
||||
## test erase
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`erase`
|
||||
|
||||
## test del
|
||||
|
||||
`1 2 3 4 5`
|
||||
|
||||
`del`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
## test dropn
|
||||
|
||||
`1 2 2 dropn`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## test dropn error
|
||||
|
||||
`1 2 3 dropn`
|
||||
|
||||
-> stack size should be 3
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## test dupn
|
||||
|
||||
`1 2 3 4 3 dupn`
|
||||
|
||||
-> stack should be 1, 2, 3, 4, 2, 3, 4
|
||||
|
||||
`del`
|
||||
|
||||
## test dupn error
|
||||
|
||||
`1 2 3 4 5 dupn`
|
||||
|
||||
-> stack size should be 4
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## test roll
|
||||
|
||||
`1 2 3 4 5 4 roll`
|
||||
|
||||
-> stack should be 1, 3, 4, 5, 2
|
||||
|
||||
`del`
|
||||
|
||||
## test roll with filled stack
|
||||
|
||||
`10 11 1 2 3 4 5 4 roll`
|
||||
|
||||
-> stack should be 10, 11, 1, 3, 4, 5, 2
|
||||
|
||||
`del`
|
||||
|
||||
## test roll error
|
||||
|
||||
`1 2 3 4 5 6 roll`
|
||||
|
||||
-> stack size should be 5
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## test rolld
|
||||
|
||||
`10 20 30 40 50 3 rolld`
|
||||
|
||||
-> stack should be 10, 20, 50, 30, 40
|
||||
|
||||
`del`
|
||||
|
||||
## test rolld with filled stack
|
||||
|
||||
`80 90 10 20 30 40 50 3 rolld`
|
||||
|
||||
-> stack should be 80, 90, 10, 20, 50, 30, 40
|
||||
|
||||
`del`
|
||||
|
||||
## test rolld error
|
||||
|
||||
`1 2 3 4 5 6 rolld`
|
||||
|
||||
-> stack size should be 5
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## test over
|
||||
|
||||
`3.14 15.16 over`
|
||||
|
||||
-> stack should be 3.14, 15.16, 3.14
|
||||
|
||||
`del`
|
||||
|
||||
## test over error
|
||||
|
||||
`2 over`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
470
test/05-real.txt
470
test/05-real.txt
|
@ -1,470 +0,0 @@
|
|||
## REAL
|
||||
|
||||
default del
|
||||
|
||||
# real decimal
|
||||
1
|
||||
-> stack size should be 1
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# real decimal (2)
|
||||
2.345
|
||||
-> stack should be 2.345
|
||||
del
|
||||
|
||||
# real decimal (3)
|
||||
1 2.345 3 4.9
|
||||
-> stack size should be 4
|
||||
-> stack should be 1, 2.345, 3, 4.9
|
||||
del
|
||||
|
||||
# real hex
|
||||
0x1234 0x10.10
|
||||
-> stack should be 0x1234, 0x10
|
||||
del
|
||||
|
||||
# real hex (2)
|
||||
0x1.234p+12 0x1.01p+4
|
||||
dec swap dec swap
|
||||
-> stack should be 4660, 16.0625
|
||||
del
|
||||
|
||||
# real binary
|
||||
0b11001100
|
||||
-> stack should be 0b11001100
|
||||
del
|
||||
|
||||
# real inf, nan
|
||||
inf
|
||||
@inf@
|
||||
+inf
|
||||
+@inf@
|
||||
-inf
|
||||
-@inf@
|
||||
nan
|
||||
@nan@
|
||||
-> stack should be inf, inf, inf, inf, -inf, -inf, nan, nan
|
||||
del
|
||||
|
||||
# prec (1)
|
||||
default
|
||||
56 prec
|
||||
pi
|
||||
-> stack should be 3.141592653589793
|
||||
del
|
||||
|
||||
# prec (2)
|
||||
default
|
||||
100 prec
|
||||
pi
|
||||
-> stack should be 3.14159265358979323846264338328
|
||||
del
|
||||
|
||||
# prec error (1)
|
||||
0 prec
|
||||
-> error should be 4
|
||||
del
|
||||
|
||||
# prec error (2)
|
||||
0x8000000000000000 prec
|
||||
-> error should be 4
|
||||
del default
|
||||
|
||||
# round (1)
|
||||
"nearest" round
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# round (2)
|
||||
"toward zero" round
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# round (3)
|
||||
"toward +inf" round
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# round (4)
|
||||
"toward -inf" round
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# round (5)
|
||||
"away from zero" round
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# round (6)
|
||||
round
|
||||
-> error should be 2
|
||||
del default
|
||||
|
||||
# add (1)
|
||||
1.2 2.3 +
|
||||
-> stack should be 3.5
|
||||
del
|
||||
|
||||
# add (2)
|
||||
1.2 2.3+
|
||||
-> stack should be 3.5
|
||||
del
|
||||
|
||||
# add (3)
|
||||
2.3 +
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# add (4)
|
||||
+
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sub (1)
|
||||
1.2 2.3 -
|
||||
-> stack should be -1.1
|
||||
del
|
||||
|
||||
# sub (2)
|
||||
1.2 2.3-
|
||||
-> stack should be -1.1
|
||||
del
|
||||
|
||||
# sub (3)
|
||||
2.3 -
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# sub (4)
|
||||
-
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# mul (1)
|
||||
1.2 2.3 *
|
||||
-> stack should be 2.76
|
||||
del
|
||||
|
||||
# mul (2)
|
||||
1.2 2.3*
|
||||
-> stack should be 2.76
|
||||
del
|
||||
|
||||
# mul (3)
|
||||
2.3 *
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# mul (4)
|
||||
*
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# div (1)
|
||||
1.2 2.3 /
|
||||
-> stack should be 0.52173913043478260869565217391304347826
|
||||
del
|
||||
|
||||
# div (2)
|
||||
1.2 2.3/
|
||||
-> stack should be 0.52173913043478260869565217391304347826
|
||||
del
|
||||
|
||||
# div (3)
|
||||
2.3 /
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# div (4)
|
||||
/
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# chs (1)
|
||||
3.14 chs
|
||||
-> stack should be -3.14
|
||||
del
|
||||
|
||||
# chs (2)
|
||||
chs
|
||||
-> error should be 2
|
||||
|
||||
# neg (1)
|
||||
3.14 neg
|
||||
-> stack should be -3.14
|
||||
del
|
||||
|
||||
# neg (2)
|
||||
neg
|
||||
-> error should be 2
|
||||
|
||||
# inv (1)
|
||||
2 inv
|
||||
-> stack should be 0.5
|
||||
del
|
||||
|
||||
# inv (2)
|
||||
inv
|
||||
-> error should be 2
|
||||
|
||||
# % (1)
|
||||
2 30 %
|
||||
-> stack should be 0.6
|
||||
del
|
||||
|
||||
# % (2)
|
||||
2 30%
|
||||
-> stack should be 0.6
|
||||
del
|
||||
|
||||
# % (3)
|
||||
2 %
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# % (4)
|
||||
%
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# %CH (1)
|
||||
2 0.6 %CH
|
||||
-> stack should be 30
|
||||
del
|
||||
|
||||
# %CH (2)
|
||||
2 0.6%CH
|
||||
-> stack should be 30
|
||||
del
|
||||
|
||||
# %CH (3)
|
||||
2 %CH
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# %CH (4)
|
||||
%CH
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# ^ (1)
|
||||
2 10 ^
|
||||
-> stack should be 1024
|
||||
del
|
||||
|
||||
# ^ (2)
|
||||
2 10^
|
||||
-> stack should be 1024
|
||||
del
|
||||
|
||||
# ^ (3)
|
||||
2 ^
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# ^ (4)
|
||||
^
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sqrt (1)
|
||||
9 sqrt
|
||||
-> stack should be 3
|
||||
del
|
||||
|
||||
# sqrt (2)
|
||||
sqrt
|
||||
-> error should be 3
|
||||
|
||||
# sq (1)
|
||||
12 sq
|
||||
-> stack should be 144
|
||||
del
|
||||
|
||||
# sq (2)
|
||||
sq
|
||||
-> error should be 2
|
||||
|
||||
# sqr (1)
|
||||
12 sqr
|
||||
-> stack should be 144
|
||||
del
|
||||
|
||||
# sqr (2)
|
||||
sqr
|
||||
-> error should be 2
|
||||
|
||||
# mod (1)
|
||||
9 4 mod
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# mod (2)
|
||||
9 mod
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# mod (3)
|
||||
mod
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# abs (1)
|
||||
-9 abs
|
||||
-> stack should be 9
|
||||
del
|
||||
|
||||
# abs (2)
|
||||
9 abs
|
||||
-> stack should be 9
|
||||
del
|
||||
|
||||
# abs (3)
|
||||
abs
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# fact (1)
|
||||
6 fact
|
||||
-> stack should be 720
|
||||
del
|
||||
|
||||
# fact (2)
|
||||
'r' fact
|
||||
-> error should be 3
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# fact (3)
|
||||
fact
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sign (1)
|
||||
23 sign -34 sign 0 sign
|
||||
-> stack should be 1, -1, 0
|
||||
del
|
||||
|
||||
# sign (2)
|
||||
sign
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# mant (1)
|
||||
123.456 mant -123.456 mant 0 mant
|
||||
-> stack should be 0.123456, 0.123456, 0
|
||||
del
|
||||
|
||||
# mant (2)
|
||||
inf mant
|
||||
-> error should be 4
|
||||
-inf mant
|
||||
-> error should be 4
|
||||
nan mant
|
||||
-> error should be 4
|
||||
del
|
||||
|
||||
# xpon (1)
|
||||
123.456 xpon -123.456 xpon 0 mant
|
||||
-> stack should be 3, 3, 0
|
||||
del
|
||||
|
||||
# xpon (2)
|
||||
inf xpon
|
||||
-> error should be 4
|
||||
-inf xpon
|
||||
-> error should be 4
|
||||
nan xpon
|
||||
-> error should be 4
|
||||
del
|
||||
|
||||
# min (1)
|
||||
1 2 min 4 3 min
|
||||
-> stack should be 1, 3
|
||||
del
|
||||
|
||||
# min (2)
|
||||
'a' 'g' min
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# min (3)
|
||||
1 min
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# min (4)
|
||||
min
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# max (1)
|
||||
1 2 max 4 3 max
|
||||
-> stack should be 2, 4
|
||||
del
|
||||
|
||||
# max (2)
|
||||
'a' 'g' max
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# max (3)
|
||||
1 max
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# max (4)
|
||||
max
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# ip (1)
|
||||
1.22 ip
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# ip (2)
|
||||
-1.22 ip
|
||||
-> stack should be -1
|
||||
del
|
||||
|
||||
# fp (1)
|
||||
1.22 fp
|
||||
-> stack should be 0.22
|
||||
del
|
||||
|
||||
# fp (2)
|
||||
-1.22 fp
|
||||
-> stack should be -0.22
|
||||
del
|
||||
|
||||
# floor (1)
|
||||
1.22 floor
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# floor (2)
|
||||
-1.22 floor
|
||||
-> stack should be -2
|
||||
del
|
||||
|
||||
# ceil (1)
|
||||
1.22 ceil
|
||||
-> stack should be 2
|
||||
del
|
||||
|
||||
# ceil (2)
|
||||
-1.22 ceil
|
||||
-> stack should be -1
|
||||
del
|
||||
|
||||
default
|
700
test/050-real.md
Normal file
700
test/050-real.md
Normal file
|
@ -0,0 +1,700 @@
|
|||
# REAL
|
||||
|
||||
`default del`
|
||||
|
||||
## real decimal
|
||||
|
||||
`1`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## real decimal (2)
|
||||
|
||||
`2.345`
|
||||
|
||||
-> stack should be 2.345
|
||||
|
||||
`del`
|
||||
|
||||
## real decimal (3)
|
||||
|
||||
`1 2.345 3 4.9`
|
||||
|
||||
-> stack size should be 4
|
||||
|
||||
-> stack should be 1, 2.345, 3, 4.9
|
||||
|
||||
`del`
|
||||
|
||||
## real hex
|
||||
|
||||
`0x1234 0x10.10`
|
||||
|
||||
-> stack should be 0x1234, 0x10
|
||||
|
||||
`del`
|
||||
|
||||
## real hex (2)
|
||||
|
||||
```
|
||||
0x1.234p+12 0x1.01p+4
|
||||
dec swap dec swap
|
||||
```
|
||||
|
||||
-> stack should be 4660, 16.0625
|
||||
|
||||
`del`
|
||||
|
||||
## real binary
|
||||
|
||||
`0b11001100`
|
||||
|
||||
-> stack should be 0b11001100
|
||||
|
||||
`del`
|
||||
|
||||
## real inf, nan
|
||||
|
||||
```
|
||||
inf
|
||||
@inf@
|
||||
+inf
|
||||
+@inf@
|
||||
-inf
|
||||
-@inf@
|
||||
nan
|
||||
@nan@
|
||||
```
|
||||
|
||||
-> stack should be inf, inf, inf, inf, -inf, -inf, nan, nan
|
||||
|
||||
`del`
|
||||
|
||||
## prec (1)
|
||||
|
||||
```
|
||||
default
|
||||
56 prec
|
||||
pi
|
||||
```
|
||||
|
||||
-> stack should be 3.141592653589793
|
||||
|
||||
`del`
|
||||
|
||||
## prec (2)
|
||||
|
||||
```
|
||||
default
|
||||
100 prec
|
||||
pi
|
||||
```
|
||||
|
||||
-> stack should be 3.14159265358979323846264338328
|
||||
|
||||
`del`
|
||||
|
||||
## prec error (1)
|
||||
|
||||
`0 prec`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`del`
|
||||
|
||||
## prec error (2)
|
||||
|
||||
`0x8000000000000000 prec`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`del default`
|
||||
|
||||
## round (1)
|
||||
|
||||
`"nearest (even)" round`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## round (2)
|
||||
|
||||
`"toward zero" round`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## round (3)
|
||||
|
||||
`"toward +inf" round`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## round (4)
|
||||
|
||||
`"toward -inf" round`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## round (5)
|
||||
|
||||
`"away from zero" round`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## round (6)
|
||||
|
||||
`"faithful rounding" round`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## round (7)
|
||||
|
||||
`"nearest (away from zero)" round`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## round error
|
||||
|
||||
`round`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del default`
|
||||
|
||||
## add (1)
|
||||
|
||||
`1.2 2.3 +`
|
||||
|
||||
-> stack should be 3.5
|
||||
|
||||
`del`
|
||||
|
||||
## add (2)
|
||||
|
||||
`2.3 +`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## add (3)
|
||||
|
||||
`+`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sub (1)
|
||||
|
||||
`1.2 2.3 -`
|
||||
|
||||
-> stack should be -1.1
|
||||
|
||||
`del`
|
||||
|
||||
## sub (2)
|
||||
|
||||
`2.3 -`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## sub (3)
|
||||
|
||||
`-`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## mul (1)
|
||||
|
||||
`1.2 2.3 *`
|
||||
|
||||
-> stack should be 2.76
|
||||
|
||||
`del`
|
||||
|
||||
## mul (2)
|
||||
|
||||
`2.3 *`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## mul (3)
|
||||
|
||||
`*`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## div (1)
|
||||
|
||||
`1.2 2.3 /`
|
||||
|
||||
-> stack should be 0.52173913043478260869565217391304347826
|
||||
|
||||
`del`
|
||||
|
||||
|
||||
## div (2)
|
||||
|
||||
`2.3 /`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## div (3)
|
||||
|
||||
`/`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## chs (1)
|
||||
|
||||
`3.14 chs`
|
||||
|
||||
-> stack should be -3.14
|
||||
|
||||
`del`
|
||||
|
||||
## chs (2)
|
||||
|
||||
`chs`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
## neg (1)
|
||||
|
||||
`3.14 neg`
|
||||
|
||||
-> stack should be -3.14
|
||||
|
||||
`del`
|
||||
|
||||
## neg (2)
|
||||
|
||||
`neg`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
## inv (1)
|
||||
|
||||
`2 inv`
|
||||
|
||||
-> stack should be 0.5
|
||||
|
||||
`del`
|
||||
|
||||
## inv (2)
|
||||
|
||||
`inv`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
## % (1)
|
||||
|
||||
`2 30 %`
|
||||
|
||||
-> stack should be 0.6
|
||||
|
||||
`del`
|
||||
|
||||
## % (2)
|
||||
|
||||
`2 %`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## % (3)
|
||||
|
||||
`%`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## %CH (1)
|
||||
|
||||
`2 0.6 %CH`
|
||||
|
||||
-> stack should be 30
|
||||
|
||||
`del`
|
||||
|
||||
## %CH (2)
|
||||
|
||||
`2 %CH`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## %CH (3)
|
||||
|
||||
`%CH`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (1)
|
||||
|
||||
`2 10 ^`
|
||||
|
||||
-> stack should be 1024
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (2)
|
||||
|
||||
`2 ^`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (3)
|
||||
|
||||
`^`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sqrt (1)
|
||||
|
||||
`9 sqrt`
|
||||
|
||||
-> stack should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## sqrt (2)
|
||||
|
||||
`sqrt`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
## sq (1)
|
||||
|
||||
`12 sq`
|
||||
|
||||
-> stack should be 144
|
||||
|
||||
`del`
|
||||
|
||||
## sq (2)
|
||||
|
||||
`sq`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
## mod (1)
|
||||
|
||||
`9 4 mod`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## mod (2)
|
||||
|
||||
`9 mod`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## mod (3)
|
||||
|
||||
`mod`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## abs (1)
|
||||
|
||||
`-9 abs`
|
||||
|
||||
-> stack should be 9
|
||||
|
||||
`del`
|
||||
|
||||
## abs (2)
|
||||
|
||||
`9 abs`
|
||||
|
||||
-> stack should be 9
|
||||
|
||||
`del`
|
||||
|
||||
## abs (3)
|
||||
|
||||
`abs`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## fact (1)
|
||||
|
||||
`6 fact`
|
||||
|
||||
-> stack should be 720
|
||||
|
||||
`del`
|
||||
|
||||
## fact (2)
|
||||
|
||||
`'r' fact`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## fact (3)
|
||||
|
||||
`fact`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sign (1)
|
||||
|
||||
`23 sign -34 sign 0 sign`
|
||||
|
||||
-> stack should be 1, -1, 0
|
||||
|
||||
`del`
|
||||
|
||||
## sign (2)
|
||||
|
||||
`sign`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## mant (1)
|
||||
|
||||
`123.456 mant -123.456 mant 0 mant`
|
||||
|
||||
-> stack should be 0.9645, -0.9645, 0
|
||||
|
||||
`del`
|
||||
|
||||
## mant (2)
|
||||
|
||||
`inf mant`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`-inf mant`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`nan mant`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`del`
|
||||
|
||||
## xpon (1)
|
||||
|
||||
`123.456 xpon -123.456 xpon 0 mant`
|
||||
|
||||
-> stack should be 7, 7, 0
|
||||
|
||||
`del`
|
||||
|
||||
## xpon (2)
|
||||
|
||||
`inf xpon`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`-inf xpon`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`nan xpon`
|
||||
|
||||
-> error should be 4
|
||||
|
||||
`del`
|
||||
|
||||
## min (1)
|
||||
|
||||
`1 2 min 4 3 min`
|
||||
|
||||
-> stack should be 1, 3
|
||||
|
||||
`del`
|
||||
|
||||
## min (2)
|
||||
|
||||
`'a' 'g' min`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## min (3)
|
||||
|
||||
`1 min`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## min (4)
|
||||
|
||||
`min`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## max (1)
|
||||
|
||||
`1 2 max 4 3 max`
|
||||
|
||||
-> stack should be 2, 4
|
||||
|
||||
`del`
|
||||
|
||||
## max (2)
|
||||
|
||||
`'a' 'g' max`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## max (3)
|
||||
|
||||
`1 max`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## max (4)
|
||||
|
||||
`max`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## ip (1)
|
||||
|
||||
`1.22 ip`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## ip (2)
|
||||
|
||||
`-1.22 ip`
|
||||
|
||||
-> stack should be -1
|
||||
|
||||
`del`
|
||||
|
||||
## fp (1)
|
||||
|
||||
`1.22 fp`
|
||||
|
||||
-> stack should be 0.22
|
||||
|
||||
`del`
|
||||
|
||||
## fp (2)
|
||||
|
||||
`-1.22 fp`
|
||||
|
||||
-> stack should be -0.22
|
||||
|
||||
`del`
|
||||
|
||||
## floor (1)
|
||||
|
||||
`1.22 floor`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## floor (2)
|
||||
|
||||
`-1.22 floor`
|
||||
|
||||
-> stack should be -2
|
||||
|
||||
`del`
|
||||
|
||||
## ceil (1)
|
||||
|
||||
`1.22 ceil`
|
||||
|
||||
-> stack should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## ceil (2)
|
||||
|
||||
`-1.22 ceil`
|
||||
|
||||
-> stack should be -1
|
||||
|
||||
`del default`
|
|
@ -1,213 +0,0 @@
|
|||
## STRING
|
||||
default del
|
||||
|
||||
# string entry
|
||||
"test string"
|
||||
-> stack size should be 1
|
||||
-> stack should be "test string"
|
||||
del
|
||||
|
||||
# string entry (2)
|
||||
"test string
|
||||
-> stack size should be 1
|
||||
-> stack should be "test string"
|
||||
del
|
||||
|
||||
# string entry (3)
|
||||
"
|
||||
-> stack size should be 1
|
||||
-> stack should be ""
|
||||
del
|
||||
|
||||
# ->str on real (1)
|
||||
1
|
||||
->str
|
||||
-> stack should be "1"
|
||||
del
|
||||
|
||||
# ->str on real (2)
|
||||
1.234
|
||||
->str
|
||||
-> stack should be "1.234"
|
||||
del
|
||||
|
||||
# ->str on real (3)
|
||||
1.234
|
||||
20 fix
|
||||
->str
|
||||
-> stack should be "1.23400000000000000000"
|
||||
del
|
||||
|
||||
# ->str on symbol (1)
|
||||
toto
|
||||
->str
|
||||
-> stack should be "'toto'"
|
||||
del
|
||||
|
||||
# ->str on symbol (2)
|
||||
'toto'
|
||||
->str
|
||||
-> stack should be "'toto'"
|
||||
del
|
||||
|
||||
default
|
||||
|
||||
# str-> on real (1)
|
||||
"1"
|
||||
str->
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# str-> on real (2)
|
||||
"1 2.345 3 4.9"
|
||||
str->
|
||||
-> stack should be 1, 2.345, 3, 4.9
|
||||
del
|
||||
|
||||
# str-> on real (3)
|
||||
4 fix
|
||||
"1 2.345 3 4.9"
|
||||
str->
|
||||
-> stack should be 1.0000, 2.3450, 3.0000, 4.9000
|
||||
del
|
||||
default
|
||||
|
||||
# str-> on constant (1)
|
||||
"pi"
|
||||
str->
|
||||
-> stack should be 3.1415926535897932384626433832795028842
|
||||
del
|
||||
|
||||
# str-> on constant (2)
|
||||
"'pi' 'e'"
|
||||
str->
|
||||
-> stack should be 'pi', 'e'
|
||||
del
|
||||
|
||||
# str-> on command (1)
|
||||
"2 dup"
|
||||
str->
|
||||
-> stack should be 2, 2
|
||||
del
|
||||
|
||||
# str-> on command (2)
|
||||
"3.14 my_pi sto"
|
||||
str->
|
||||
-> stack size should be 0
|
||||
my_pi
|
||||
-> stack should be 3.14
|
||||
del
|
||||
|
||||
# str-> on program
|
||||
"<< -> n << n >> >>"
|
||||
str->
|
||||
-> stack should be << -> n << n >> >>
|
||||
del
|
||||
|
||||
# add (1)
|
||||
12 34 "one" "two" +
|
||||
-> stack should be 12, 34, "onetwo"
|
||||
del
|
||||
|
||||
# add (2)
|
||||
"" "one" + "two" "" +
|
||||
-> stack should be "one", "two"
|
||||
del
|
||||
|
||||
# add (3)
|
||||
"one" +
|
||||
-> stack size should be 1
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# chr (1)
|
||||
"" 33 40 for i i chr + next
|
||||
-> stack should be "!"#$%&'("
|
||||
del
|
||||
|
||||
# chr (2)
|
||||
-223 chr 0 chr
|
||||
-> stack should be "!", "."
|
||||
del
|
||||
|
||||
# num (1)
|
||||
"!wait" num
|
||||
-> stack should be 33
|
||||
del
|
||||
|
||||
# num (2)
|
||||
"" num
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# size (1)
|
||||
"hello" size
|
||||
-> stack should be 5
|
||||
del
|
||||
|
||||
# size (2)
|
||||
"" size
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# size, str->, ->str
|
||||
"hello" str-> ->str size
|
||||
-> stack should be 7
|
||||
del
|
||||
|
||||
# pos (1)
|
||||
"my big string" "big" pos
|
||||
-> stack should be 4
|
||||
del
|
||||
|
||||
# pos (2)
|
||||
"my big string" "bOg" pos
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# pos (3)
|
||||
"my big string" pos
|
||||
-> error should be 2
|
||||
-> stack size should be 1
|
||||
del
|
||||
|
||||
# pos (4)
|
||||
pos
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sub (1)
|
||||
"my string to sub" 4 6
|
||||
sub
|
||||
-> stack should be "str"
|
||||
del
|
||||
|
||||
# sub (2)
|
||||
"my string to sub" -1 -2
|
||||
sub
|
||||
-> stack should be "m"
|
||||
del
|
||||
|
||||
# sub (3)
|
||||
"my string to sub" 0 0
|
||||
sub
|
||||
-> stack should be "m"
|
||||
del
|
||||
|
||||
# sub (4)
|
||||
"my string to sub" 6 5
|
||||
sub
|
||||
-> stack should be ""
|
||||
del
|
||||
|
||||
# sub (5)
|
||||
"my string to sub" 100 101
|
||||
sub
|
||||
-> stack should be ""
|
||||
del
|
||||
|
||||
# sub (6)
|
||||
"my string to sub" 14 100
|
||||
sub
|
||||
-> stack should be "sub"
|
||||
del
|
307
test/060-string.md
Normal file
307
test/060-string.md
Normal file
|
@ -0,0 +1,307 @@
|
|||
# STRING
|
||||
|
||||
`default del`
|
||||
|
||||
## string entry
|
||||
|
||||
`"test string"`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be "test string"
|
||||
|
||||
`del`
|
||||
|
||||
## string entry (2)
|
||||
|
||||
`"test string`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be "test string"
|
||||
|
||||
`del`
|
||||
|
||||
## string entry (3)
|
||||
|
||||
`"`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be ""
|
||||
|
||||
`del`
|
||||
|
||||
## ->str on real (1)
|
||||
|
||||
`1 ->str`
|
||||
|
||||
-> stack should be "1"
|
||||
|
||||
`del`
|
||||
|
||||
## ->str on real (2)
|
||||
|
||||
`1.234 ->str`
|
||||
|
||||
-> stack should be "1.234"
|
||||
|
||||
`del`
|
||||
|
||||
## ->str on real (3)
|
||||
|
||||
`1.234 20 fix ->str`
|
||||
|
||||
-> stack should be "1.23400000000000000000"
|
||||
|
||||
`del`
|
||||
|
||||
## ->str on symbol (1)
|
||||
|
||||
`toto ->str`
|
||||
|
||||
-> stack should be "'toto'"
|
||||
|
||||
`del`
|
||||
|
||||
## ->str on symbol (2)
|
||||
|
||||
`'toto' ->str`
|
||||
|
||||
-> stack should be "'toto'"
|
||||
|
||||
`del default`
|
||||
|
||||
## str-> on real (1)
|
||||
|
||||
`"1" str->`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## str-> on real (2)
|
||||
|
||||
`"1 2.345 3 4.9" str->`
|
||||
|
||||
-> stack should be 1, 2.345, 3, 4.9
|
||||
|
||||
`del`
|
||||
|
||||
## str-> on real (3)
|
||||
|
||||
`4 fix "1 2.345 3 4.9" str->`
|
||||
|
||||
-> stack should be 1.0000, 2.3450, 3.0000, 4.9000
|
||||
|
||||
`del default`
|
||||
|
||||
## str-> on constant (1)
|
||||
|
||||
`"pi" str->`
|
||||
|
||||
-> stack should be 3.1415926535897932384626433832795028842
|
||||
|
||||
`del`
|
||||
|
||||
## str-> on constant (2)
|
||||
|
||||
`"'pi' 'e'" str->`
|
||||
|
||||
-> stack should be 'pi', 'e'
|
||||
|
||||
`del`
|
||||
|
||||
## str-> on command (1)
|
||||
|
||||
`"2 dup" str->`
|
||||
|
||||
-> stack should be 2, 2
|
||||
|
||||
`del`
|
||||
|
||||
## str-> on command (2)
|
||||
|
||||
`"3.14 my_pi sto" str->`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`my_pi`
|
||||
|
||||
-> stack should be 3.14
|
||||
|
||||
`del`
|
||||
|
||||
## str-> on program
|
||||
|
||||
`"<< -> n << n >> >>" str->`
|
||||
|
||||
-> stack should be «-> n << n >>»
|
||||
|
||||
`del`
|
||||
|
||||
## add (1)
|
||||
|
||||
`12 34 "one" "two" +`
|
||||
|
||||
-> stack should be 12, 34, "onetwo"
|
||||
|
||||
`del`
|
||||
|
||||
## add (2)
|
||||
|
||||
`"" "one" + "two" "" +`
|
||||
|
||||
-> stack should be "one", "two"
|
||||
|
||||
`del`
|
||||
|
||||
## add (3)
|
||||
|
||||
`"one" +`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## chr (1)
|
||||
|
||||
`"" 33 40 for i i chr + next`
|
||||
|
||||
-> stack should be "!"#$%&'("
|
||||
|
||||
`del`
|
||||
|
||||
## chr (2)
|
||||
|
||||
`-223 chr 0 chr`
|
||||
|
||||
-> stack should be "!", "."
|
||||
|
||||
`del`
|
||||
|
||||
## num (1)
|
||||
|
||||
`"!wait" num`
|
||||
|
||||
-> stack should be 33
|
||||
|
||||
`del`
|
||||
|
||||
## num (2)
|
||||
|
||||
`"" num`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## size (1)
|
||||
|
||||
`"hello" size`
|
||||
|
||||
-> stack should be 5
|
||||
|
||||
`del`
|
||||
|
||||
## size (2)
|
||||
|
||||
`"" size`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## size, str->, ->str
|
||||
|
||||
`"hello" str-> ->str size`
|
||||
|
||||
-> stack should be 7
|
||||
|
||||
`del`
|
||||
|
||||
## pos (1)
|
||||
|
||||
`"my big string" "big" pos`
|
||||
|
||||
-> stack should be 4
|
||||
|
||||
`del`
|
||||
|
||||
## pos (2)
|
||||
|
||||
`"my big string" "bOg" pos`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## pos (3)
|
||||
|
||||
`"my big string" pos`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## pos (4)
|
||||
|
||||
`pos`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sub (1)
|
||||
|
||||
`"my string to sub" 4 6`
|
||||
|
||||
`sub`
|
||||
|
||||
-> stack should be "str"
|
||||
|
||||
`del`
|
||||
|
||||
## sub (2)
|
||||
|
||||
`"my string to sub" -1 -2 sub`
|
||||
|
||||
-> stack should be ""
|
||||
|
||||
`del`
|
||||
|
||||
## sub (3)
|
||||
|
||||
`"my string to sub" 0 0 sub`
|
||||
|
||||
-> stack should be ""
|
||||
|
||||
`del`
|
||||
|
||||
## sub (4)
|
||||
|
||||
`"my string to sub" 6 5 sub`
|
||||
|
||||
-> stack should be ""
|
||||
|
||||
`del`
|
||||
|
||||
## sub (5)
|
||||
|
||||
`"my string to sub" 100 101 sub`
|
||||
|
||||
-> stack should be ""
|
||||
|
||||
`del`
|
||||
|
||||
## sub (6)
|
||||
|
||||
`"my string to sub" 14 100 sub`
|
||||
|
||||
-> stack should be "sub"
|
||||
|
||||
`del`
|
|
@ -1,287 +1,505 @@
|
|||
## TESTS
|
||||
default del
|
||||
# LOGICAL TESTS
|
||||
|
||||
`default del`
|
||||
|
||||
## and (1)
|
||||
|
||||
`and`
|
||||
|
||||
# and (1)
|
||||
and
|
||||
-> error should be 2
|
||||
1 and
|
||||
|
||||
`1 and`
|
||||
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# and (2)
|
||||
0 0 and
|
||||
`del`
|
||||
|
||||
## and (2)
|
||||
|
||||
`0 0 and`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# and (3)
|
||||
1 0 and
|
||||
`del`
|
||||
|
||||
## and (3)
|
||||
|
||||
`1 0 and`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# and (4)
|
||||
0 1 and
|
||||
`del`
|
||||
|
||||
## and (4)
|
||||
|
||||
`0 1 and`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# and (5)
|
||||
1 1 and
|
||||
`del`
|
||||
|
||||
## and (5)
|
||||
|
||||
`1 1 and`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# or (1)
|
||||
or
|
||||
`del`
|
||||
|
||||
## or (1)
|
||||
|
||||
`or`
|
||||
|
||||
-> error should be 2
|
||||
1 or
|
||||
|
||||
`1 or`
|
||||
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# or (2)
|
||||
0 0 or
|
||||
`del`
|
||||
|
||||
## or (2)
|
||||
|
||||
`0 0 or`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# or (3)
|
||||
0 1 or
|
||||
`del`
|
||||
|
||||
## or (3)
|
||||
|
||||
`0 1 or`
|
||||
|
||||
-> stack size should be 1
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# or (4)
|
||||
1 0 or
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## or (4)
|
||||
|
||||
`1 0 or`
|
||||
|
||||
-> stack size should be 1
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# or (5)
|
||||
1 1 or
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## or (5)
|
||||
|
||||
`1 1 or`
|
||||
|
||||
-> stack size should be 1
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# xor (1)
|
||||
xor
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## xor (1)
|
||||
|
||||
`xor`
|
||||
|
||||
-> error should be 2
|
||||
1 xor
|
||||
|
||||
`1 xor`
|
||||
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# xor (2)
|
||||
0 0 xor
|
||||
`del`
|
||||
|
||||
## xor (2)
|
||||
|
||||
`0 0 xor`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# xor (3)
|
||||
0 1 xor
|
||||
`del`
|
||||
|
||||
## xor (3)
|
||||
|
||||
`0 1 xor`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# xor (4)
|
||||
1 0 xor
|
||||
`del`
|
||||
|
||||
## xor (4)
|
||||
|
||||
`1 0 xor`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# xor (5)
|
||||
1 1 xor
|
||||
`del`
|
||||
|
||||
## xor (5)
|
||||
|
||||
`1 1 xor`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# not (1)
|
||||
not
|
||||
`del`
|
||||
|
||||
## not (1)
|
||||
|
||||
`not`
|
||||
|
||||
-> error should be 2
|
||||
1 not
|
||||
|
||||
`1 not`
|
||||
|
||||
-> stack size should be 1
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# not (2)
|
||||
0 not
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## not (2)
|
||||
|
||||
`0 not`
|
||||
|
||||
-> stack size should be 1
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# >
|
||||
0 0.1 >
|
||||
-> stack should be 0
|
||||
del
|
||||
0.1 0 >
|
||||
-> stack should be 1
|
||||
del
|
||||
1 1 >
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# >=
|
||||
0 0.1 >=
|
||||
-> stack should be 0
|
||||
del
|
||||
0.1 0 >=
|
||||
-> stack should be 1
|
||||
del
|
||||
1 1 >=
|
||||
-> stack should be 1
|
||||
del
|
||||
`del`
|
||||
|
||||
# <
|
||||
0 0.1 <
|
||||
-> stack should be 1
|
||||
del
|
||||
0.1 0 <
|
||||
-> stack should be 0
|
||||
del
|
||||
1 1 <
|
||||
-> stack should be 0
|
||||
del
|
||||
## >
|
||||
|
||||
# <=
|
||||
0 0.1 <=
|
||||
-> stack should be 1
|
||||
del
|
||||
0.1 0 <=
|
||||
-> stack should be 0
|
||||
del
|
||||
1 1 <=
|
||||
-> stack should be 1
|
||||
del
|
||||
`0 0.1 >`
|
||||
|
||||
# !=
|
||||
0 0.1 !=
|
||||
-> stack should be 1
|
||||
del
|
||||
1 1 !=
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# ==
|
||||
0 0.1 ==
|
||||
-> stack should be 0
|
||||
del
|
||||
1 1 ==
|
||||
-> stack should be 1
|
||||
del
|
||||
`del`
|
||||
|
||||
# same
|
||||
0 0.1 same
|
||||
-> stack should be 0
|
||||
del
|
||||
1 1 same
|
||||
-> stack should be 1
|
||||
del
|
||||
`0.1 0 >`
|
||||
|
||||
# complex !=
|
||||
(1,2) (3,4) !=
|
||||
-> stack should be 1
|
||||
del
|
||||
(1,2) (1,0) !=
|
||||
-> stack should be 1
|
||||
del
|
||||
(1,2) (0,2) !=
|
||||
-> stack should be 1
|
||||
del
|
||||
(1,2) (1,2) !=
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# complex ==
|
||||
(1,2) (3,4) ==
|
||||
-> stack should be 0
|
||||
del
|
||||
(1,2) (1,0) ==
|
||||
-> stack should be 0
|
||||
del
|
||||
(1,2) (0,2) ==
|
||||
-> stack should be 0
|
||||
del
|
||||
(1,2) (1,2) ==
|
||||
-> stack should be 1
|
||||
del
|
||||
`del`
|
||||
|
||||
# complex same
|
||||
(1,2) (3,4) same
|
||||
-> stack should be 0
|
||||
del
|
||||
(1,2) (1,0) same
|
||||
-> stack should be 0
|
||||
del
|
||||
(1,2) (0,2) same
|
||||
-> stack should be 0
|
||||
del
|
||||
(1,2) (1,2) same
|
||||
-> stack should be 1
|
||||
del
|
||||
`1 1 >`
|
||||
|
||||
# string >
|
||||
"a" "b" >
|
||||
-> stack should be 0
|
||||
del
|
||||
"b" "a" >
|
||||
-> stack should be 1
|
||||
del
|
||||
"a" "a" >
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# string >=
|
||||
"a" "b" >=
|
||||
-> stack should be 0
|
||||
del
|
||||
"b" "a" >=
|
||||
-> stack should be 1
|
||||
del
|
||||
"a" "a" >=
|
||||
-> stack should be 1
|
||||
del
|
||||
`del`
|
||||
|
||||
# string <
|
||||
"a" "b" <
|
||||
-> stack should be 1
|
||||
del
|
||||
"b" "a" <
|
||||
-> stack should be 0
|
||||
del
|
||||
"a" "a" <
|
||||
-> stack should be 0
|
||||
del
|
||||
## >=
|
||||
|
||||
# string <=
|
||||
"a" "b" <=
|
||||
-> stack should be 1
|
||||
del
|
||||
"b" "a" <=
|
||||
-> stack should be 0
|
||||
del
|
||||
"a" "a" <=
|
||||
-> stack should be 1
|
||||
del
|
||||
`0 0.1 >=`
|
||||
|
||||
# string !=
|
||||
"a" "b" !=
|
||||
-> stack should be 1
|
||||
del
|
||||
"a" "a" !=
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# string ==
|
||||
"a" "b" ==
|
||||
-> stack should be 0
|
||||
del
|
||||
"a" "a" ==
|
||||
-> stack should be 1
|
||||
del
|
||||
`del`
|
||||
|
||||
`0.1 0 >=`
|
||||
|
||||
# string same
|
||||
"a" "b" same
|
||||
-> stack should be 0
|
||||
del
|
||||
"a" "a" same
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
`del`
|
||||
|
||||
`1 1 >=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## <
|
||||
|
||||
`0 0.1 <`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`0.1 0 <`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`1 1 <`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## <=
|
||||
|
||||
`0 0.1 <=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`0.1 0 <=`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`1 1 <=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## !=
|
||||
|
||||
`0 0.1 !=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`1 1 !=`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## ==
|
||||
|
||||
`0 0.1 ==`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`1 1 ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## same
|
||||
|
||||
`0 0.1 same`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`1 1 same`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## complex !=
|
||||
|
||||
`(1,2) (3,4) !=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (1,0) !=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (0,2) !=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (1,2) !=`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## complex ==
|
||||
|
||||
`(1,2) (3,4) ==`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (1,0) ==`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (0,2) ==`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (1,2) ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## complex same
|
||||
|
||||
`(1,2) (3,4) same`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (1,0) same`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (0,2) same`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`(1,2) (1,2) same`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## string >
|
||||
|
||||
`"a" "b" >`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`"b" "a" >`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`"a" "a" >`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## string >=
|
||||
|
||||
`"a" "b" >=`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`"b" "a" >=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`"a" "a" >=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## string <
|
||||
|
||||
`"a" "b" <`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`"b" "a" <`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`"a" "a" <`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## string <=
|
||||
|
||||
`"a" "b" <=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`"b" "a" <=`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`"a" "a" <=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## string !=
|
||||
|
||||
`"a" "b" !=`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
`"a" "a" !=`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## string ==
|
||||
|
||||
`"a" "b" ==`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`"a" "a" ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## string same
|
||||
|
||||
`"a" "b" same`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
`"a" "a" same`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
|
@ -1,226 +0,0 @@
|
|||
## STORE
|
||||
default del
|
||||
|
||||
# symbol entry
|
||||
'test'
|
||||
-> stack size should be 1
|
||||
-> stack should be 'test'
|
||||
del
|
||||
|
||||
# symbol entry (2)
|
||||
'test
|
||||
-> stack size should be 1
|
||||
-> stack should be 'test'
|
||||
del
|
||||
|
||||
# symbol entry (3)
|
||||
''
|
||||
-> stack size should be 1
|
||||
-> stack should be ''
|
||||
del
|
||||
|
||||
# symbol entry (4)
|
||||
'
|
||||
-> stack size should be 1
|
||||
-> stack should be ''
|
||||
del
|
||||
|
||||
# sto (1)
|
||||
1 'a' sto
|
||||
-> stack size should be 0
|
||||
'a' a
|
||||
-> stack should be 'a', 1
|
||||
del
|
||||
|
||||
# sto (2)
|
||||
2 'a' sto a
|
||||
-> stack should be 2
|
||||
del
|
||||
|
||||
# sto (3)
|
||||
3 'b' sto b
|
||||
-> stack should be 3
|
||||
del
|
||||
|
||||
# rcl (1)
|
||||
'a' rcl
|
||||
-> stack should be 2
|
||||
del
|
||||
|
||||
# rcl (2)
|
||||
'b' rcl
|
||||
-> stack should be 3
|
||||
del
|
||||
|
||||
# rcl (2)
|
||||
'var' rcl
|
||||
-> error should be 5
|
||||
-> stack should be 'var'
|
||||
del
|
||||
|
||||
# sto in prog then rcl
|
||||
3 << 'r' sto >> eval r 'r' rcl
|
||||
-> stack should be 3, 3
|
||||
del
|
||||
|
||||
# purge (1)
|
||||
a 'a' purge a
|
||||
-> stack should be 2, 'a'
|
||||
del
|
||||
|
||||
# purge (2)
|
||||
'a' purge
|
||||
-> error should be 5
|
||||
-> stack size should be 0
|
||||
del
|
||||
|
||||
# purge (3)
|
||||
3 'a' sto a 'a' purge
|
||||
-> stack should be 3
|
||||
del
|
||||
|
||||
# sto+ (1)
|
||||
8 'a' sto
|
||||
2 'a' sto+
|
||||
a
|
||||
-> stack should be 10
|
||||
del
|
||||
|
||||
# sto+ (2)
|
||||
2 'a' sto
|
||||
'a' 2 sto+
|
||||
a
|
||||
-> stack should be 4
|
||||
del
|
||||
|
||||
# sto+ (3)
|
||||
'a' sto+
|
||||
-> stack size should be 1
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sto+ (4)
|
||||
3 'zz' sto+
|
||||
-> stack should be 3, 'zz'
|
||||
-> error should be 5
|
||||
del
|
||||
|
||||
# sto- (1)
|
||||
2 'a' sto
|
||||
2 'a' sto-
|
||||
a
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# sto- (2)
|
||||
2 'a' sto
|
||||
'a' 2 sto-
|
||||
a
|
||||
-> stack should be 0
|
||||
del
|
||||
|
||||
# sto- (3)
|
||||
'a' sto-
|
||||
-> stack size should be 1
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sto- (4)
|
||||
3 'zz' sto-
|
||||
-> stack should be 3, 'zz'
|
||||
-> error should be 5
|
||||
del
|
||||
|
||||
# sto* (1)
|
||||
2 'a' sto
|
||||
3 'a' sto*
|
||||
a
|
||||
-> stack should be 6
|
||||
del
|
||||
|
||||
# sto* (2)
|
||||
2 'a' sto
|
||||
'a' 3 sto*
|
||||
a
|
||||
-> stack should be 6
|
||||
del
|
||||
|
||||
# sto* (3)
|
||||
'a' sto*
|
||||
-> stack size should be 1
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sto* (4)
|
||||
3 'zz' sto*
|
||||
-> stack should be 3, 'zz'
|
||||
-> error should be 5
|
||||
del
|
||||
|
||||
# sto/ (1)
|
||||
2 'a' sto
|
||||
6 'a' sto/
|
||||
a
|
||||
-> stack should be 3
|
||||
del
|
||||
|
||||
# sto/ (2)
|
||||
6 'a' sto
|
||||
'a' 2 sto/
|
||||
a
|
||||
-> stack should be 3
|
||||
del
|
||||
|
||||
# sto/ (2)
|
||||
'a' sto/
|
||||
-> stack size should be 1
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sto/ (4)
|
||||
3 'zz' sto/
|
||||
-> stack should be 3, 'zz'
|
||||
-> error should be 5
|
||||
del
|
||||
|
||||
# sneg (1)
|
||||
7 'a' sto
|
||||
'a' sneg
|
||||
a
|
||||
-> stack should be -7
|
||||
del
|
||||
|
||||
# sneg (2)
|
||||
sneg
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sneg (3)
|
||||
'zz' sneg
|
||||
-> error should be 5
|
||||
-> stack should be 'zz'
|
||||
del
|
||||
|
||||
# sinv (1)
|
||||
4 'a' sto
|
||||
'a' sinv
|
||||
a
|
||||
-> stack should be 0.25
|
||||
del
|
||||
|
||||
# sinv (2)
|
||||
sinv
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# sinv (3)
|
||||
'zz' sinv
|
||||
-> error should be 5
|
||||
-> stack should be 'zz'
|
||||
del
|
||||
|
||||
# clusr
|
||||
3.14 'abc' sto clusr 'abc' rcl
|
||||
-> error should be 5
|
||||
-> stack should be 'abc'
|
||||
del
|
325
test/080-store.md
Normal file
325
test/080-store.md
Normal file
|
@ -0,0 +1,325 @@
|
|||
# STORE
|
||||
|
||||
`default del`
|
||||
|
||||
## symbol entry
|
||||
|
||||
`'test'`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 'test'
|
||||
|
||||
`del`
|
||||
|
||||
## symbol entry (2)
|
||||
|
||||
`'test`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be 'test'
|
||||
|
||||
`del`
|
||||
|
||||
## symbol entry (3)
|
||||
|
||||
`''`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be ''
|
||||
|
||||
`del`
|
||||
|
||||
## symbol entry (4)
|
||||
|
||||
`'`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be ''
|
||||
|
||||
`del`
|
||||
|
||||
## sto (1)
|
||||
|
||||
`1 'a' sto`
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`'a' a`
|
||||
|
||||
-> stack should be 'a', 1
|
||||
|
||||
`del`
|
||||
|
||||
## sto (2)
|
||||
|
||||
`2 'a' sto a`
|
||||
|
||||
-> stack should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sto (3)
|
||||
|
||||
`3 'b' sto b`
|
||||
|
||||
-> stack should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## rcl (1)
|
||||
|
||||
`'a' rcl`
|
||||
|
||||
-> stack should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## rcl (2)
|
||||
|
||||
`'b' rcl`
|
||||
|
||||
-> stack should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## rcl (3)
|
||||
|
||||
`'var' rcl`
|
||||
|
||||
-> error should be 5
|
||||
|
||||
-> stack should be 'var'
|
||||
|
||||
`del`
|
||||
|
||||
## sto in prog then rcl
|
||||
|
||||
`3 << 'r' sto >> eval r 'r' rcl`
|
||||
|
||||
-> stack should be 3, 3
|
||||
|
||||
`del`
|
||||
|
||||
## purge (1)
|
||||
|
||||
`a 'a' purge a`
|
||||
|
||||
-> stack should be 2, 'a'
|
||||
|
||||
`del`
|
||||
|
||||
## purge (2)
|
||||
|
||||
`'a' purge`
|
||||
|
||||
-> error should be 5
|
||||
|
||||
-> stack size should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## purge (3)
|
||||
|
||||
`3 'a' sto a 'a' purge`
|
||||
|
||||
-> stack should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## sto+ (1)
|
||||
|
||||
`8 'a' sto 2 'a' sto+ a`
|
||||
|
||||
-> stack should be 10
|
||||
|
||||
`del`
|
||||
|
||||
## sto+ (2)
|
||||
|
||||
`'a' sto+`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sto+ (3)
|
||||
|
||||
`3 'zz' sto+`
|
||||
|
||||
-> stack should be 3, 'zz'
|
||||
|
||||
-> error should be 5
|
||||
|
||||
`del`
|
||||
|
||||
## sto- (1)
|
||||
|
||||
`2 'a' sto`
|
||||
|
||||
`2 'a' sto-`
|
||||
|
||||
`a`
|
||||
|
||||
-> stack should be 0
|
||||
|
||||
`del`
|
||||
|
||||
## sto- (2)
|
||||
|
||||
`'a' sto-`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sto- (3)
|
||||
|
||||
`3 'zz' sto-`
|
||||
|
||||
-> stack should be 3, 'zz'
|
||||
|
||||
-> error should be 5
|
||||
|
||||
`del`
|
||||
|
||||
## sto* (1)
|
||||
|
||||
`2 'a' sto`
|
||||
|
||||
`3 'a' sto*`
|
||||
|
||||
`a`
|
||||
|
||||
-> stack should be 6
|
||||
|
||||
`del`
|
||||
|
||||
## sto* (2)
|
||||
|
||||
`'a' sto*`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sto* (3)
|
||||
|
||||
`3 'zz' sto*`
|
||||
|
||||
-> stack should be 3, 'zz'
|
||||
|
||||
-> error should be 5
|
||||
|
||||
`del`
|
||||
|
||||
## sto/ (1)
|
||||
|
||||
`2 'a' sto`
|
||||
|
||||
`4 'a' sto/`
|
||||
|
||||
`a`
|
||||
|
||||
-> stack should be 0.5
|
||||
|
||||
`del`
|
||||
|
||||
## sto/ (2)
|
||||
|
||||
`'a' sto/`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sto/ (4)
|
||||
|
||||
`3 'zz' sto/`
|
||||
|
||||
-> stack should be 3, 'zz'
|
||||
|
||||
-> error should be 5
|
||||
|
||||
`del`
|
||||
|
||||
## sneg (1)
|
||||
|
||||
`7 'a' sto`
|
||||
|
||||
`'a' sneg`
|
||||
|
||||
`a`
|
||||
|
||||
-> stack should be -7
|
||||
|
||||
`del`
|
||||
|
||||
## sneg (2)
|
||||
|
||||
`sneg`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sneg (3)
|
||||
|
||||
`'zz' sneg`
|
||||
|
||||
-> error should be 5
|
||||
|
||||
-> stack should be 'zz'
|
||||
|
||||
`del`
|
||||
|
||||
## sinv (1)
|
||||
|
||||
`4 'a' sto`
|
||||
|
||||
`'a' sinv`
|
||||
|
||||
`a`
|
||||
|
||||
-> stack should be 0.25
|
||||
|
||||
`del`
|
||||
|
||||
## sinv (2)
|
||||
|
||||
`sinv`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## sinv (3)
|
||||
|
||||
`'zz' sinv`
|
||||
|
||||
-> error should be 5
|
||||
|
||||
-> stack should be 'zz'
|
||||
|
||||
`del`
|
||||
|
||||
## clusr
|
||||
|
||||
`3.14 'abc' sto clusr 'abc' rcl`
|
||||
|
||||
-> error should be 5
|
||||
|
||||
-> stack should be 'abc'
|
||||
|
||||
`del`
|
|
@ -1,56 +0,0 @@
|
|||
## PROGRAM
|
||||
default del
|
||||
|
||||
# program
|
||||
<< 'one' >>
|
||||
-> stack size should be 1
|
||||
-> stack should be << 'one' >>
|
||||
del
|
||||
|
||||
# program (2)
|
||||
<< 'one' 2
|
||||
-> stack size should be 1
|
||||
-> stack should be << 'one' 2 >>
|
||||
del
|
||||
|
||||
# program (3)
|
||||
<<
|
||||
-> stack size should be 1
|
||||
-> stack should be << >>
|
||||
del
|
||||
|
||||
# program (4)
|
||||
<< << << <<
|
||||
-> stack size should be 1
|
||||
-> stack should be << << << << >> >> >> >>
|
||||
del
|
||||
|
||||
# program (5)
|
||||
<< -> n << n 2 * >> >>
|
||||
-> stack size should be 1
|
||||
-> stack should be << -> n << n 2 * >> >>
|
||||
del
|
||||
|
||||
# program imbrication
|
||||
<< 1 << 2 >> >>
|
||||
-> stack should be << 1 << 2 >> >>
|
||||
del
|
||||
|
||||
# program evaluation
|
||||
<< 1 << 2 >> >> dup eval
|
||||
-> stack should be << 1 << 2 >> >>, 1, << 2 >>
|
||||
del
|
||||
|
||||
# program 1 arg
|
||||
default
|
||||
10
|
||||
<< -> n << 0 1 n for i i 2 * inv + next >> >>
|
||||
eval
|
||||
-> stack should be 1.4644841269841269841269841269841269841
|
||||
del
|
||||
|
||||
# program several args
|
||||
0 1 10 << -> u0 u1 n << u0 u1 1 n start dup2 + rot drop next swap drop >> >> eval
|
||||
eval
|
||||
-> stack should be 89
|
||||
del
|
142
test/090-program.md
Normal file
142
test/090-program.md
Normal file
|
@ -0,0 +1,142 @@
|
|||
# PROGRAM
|
||||
|
||||
`default del`
|
||||
|
||||
## program
|
||||
|
||||
`<< 'one' >>`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be «'one'»
|
||||
|
||||
`del`
|
||||
|
||||
## program (2)
|
||||
|
||||
`<< 'one' 2`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be «'one' 2»
|
||||
|
||||
`del`
|
||||
|
||||
## program (3)
|
||||
|
||||
`<<`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be «»
|
||||
|
||||
`del`
|
||||
|
||||
## program (4)
|
||||
|
||||
`<< << << <<`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be «<< << <<»
|
||||
|
||||
`del`
|
||||
|
||||
## program (5)
|
||||
|
||||
`<< -> n << n 2 * >> >>`
|
||||
|
||||
-> stack size should be 1
|
||||
|
||||
-> stack should be «-> n << n 2 * >>»
|
||||
|
||||
`del`
|
||||
|
||||
## program imbrication
|
||||
|
||||
`<< 1 << 2 >> >>`
|
||||
|
||||
-> stack should be «1 << 2 >>»
|
||||
|
||||
`del`
|
||||
|
||||
## program evaluation
|
||||
|
||||
`<< 1 << 2 >> >> dup eval`
|
||||
|
||||
-> stack should be «1 << 2 >>», 1, «2»
|
||||
|
||||
`del`
|
||||
|
||||
## program 1 arg
|
||||
|
||||
`default`
|
||||
|
||||
`10`
|
||||
|
||||
`<< -> n << 0 1 n for i i 2 * inv + next >> >>`
|
||||
|
||||
`eval`
|
||||
|
||||
-> stack should be 1.4644841269841269841269841269841269841
|
||||
|
||||
`del`
|
||||
|
||||
## nested programs
|
||||
|
||||
`0 1 10 << -> u0 u1 n << u0 u1 1 n start dup2 + rot drop next swap drop >> >> eval`
|
||||
|
||||
`eval`
|
||||
|
||||
-> stack should be 89
|
||||
|
||||
`del`
|
||||
|
||||
## fibo
|
||||
|
||||
```
|
||||
«dup 1 > if then dup 1 - fibo swap 2 - fibo + else 1 == if then 1 else 0 end end» 'fibo' sto
|
||||
7 fibo
|
||||
13 == if then 'ok!' end
|
||||
```
|
||||
|
||||
-> stack should be 'ok!'
|
||||
|
||||
`del`
|
||||
|
||||
## nested programs with local variables
|
||||
|
||||
```
|
||||
100
|
||||
10
|
||||
«dup2 * -> a b c << a b + c / -> d << << -> sym << sym ->str " is " + sym rcl ->str + >> >> 'stringify' sto 'a' stringify 'b' stringify 'c' stringify 'd' stringify >> >>»
|
||||
eval
|
||||
```
|
||||
|
||||
-> stack should be "'a' is 100", "'b' is 10", "'c' is 1000", "'d' is 0.11"
|
||||
|
||||
`del`
|
||||
|
||||
## local variables multiple entries
|
||||
|
||||
`1 2 3 << -> a b c << "a is " a ->str + "b is " b ->str + "c is " c ->str + >> >> eval`
|
||||
|
||||
-> stack should be "a is 1", "b is 2", "c is 3"
|
||||
|
||||
`del`
|
||||
|
||||
## local variables separation (1)
|
||||
|
||||
`123 'n' sto 1 << -> n << "n is " n ->str + >> >> eval`
|
||||
|
||||
-> stack should be "n is 1"
|
||||
|
||||
`del`
|
||||
|
||||
## local variables separation (2)
|
||||
|
||||
`123 'n' sto 2 << -> n << n sq << -> n << "n is " n ->str + >> >> >> eval >> eval`
|
||||
|
||||
-> stack should be "n is 4"
|
||||
|
||||
`del`
|
|
@ -1,758 +0,0 @@
|
|||
## COMPLEX
|
||||
|
||||
default del
|
||||
|
||||
# entry (1)
|
||||
(1,2) ( 1,2) (1 ,2) (1, 2) (1,2 )
|
||||
-> stack should be (1,2), (1,2), (1,2), (1,2), (1,2)
|
||||
del
|
||||
|
||||
# entry (2)
|
||||
(1.3,2.444555
|
||||
-> stack should be (1.3,2.444555)
|
||||
del
|
||||
|
||||
# entry (3)
|
||||
(1,
|
||||
-> stack should be (1,0)
|
||||
del
|
||||
|
||||
# entry (4)
|
||||
(nan,+inf)
|
||||
-> stack should be (nan,inf)
|
||||
del
|
||||
|
||||
# entry (5)
|
||||
(0x1234,0x10.10)
|
||||
-> stack should be (0x1.234p+12,0x1.01p+4)
|
||||
del
|
||||
|
||||
# entry (6)
|
||||
(0b11,0b101)
|
||||
-> stack should be (3,5)
|
||||
del
|
||||
|
||||
# add (1)
|
||||
(1.2,2.3) (1,2) +
|
||||
-> stack should be (2.2,4.3)
|
||||
del
|
||||
|
||||
# add (2)
|
||||
(1.2,2.3) (1,2)+
|
||||
-> stack should be (2.2,4.3)
|
||||
del
|
||||
|
||||
# add (3)
|
||||
(1.2,2.3) 3+
|
||||
-> stack should be (4.2,2.3)
|
||||
del
|
||||
|
||||
# add (4)
|
||||
3 (1.2,2.3)+
|
||||
-> stack should be (4.2,2.3)
|
||||
del
|
||||
|
||||
# sub (1)
|
||||
(1.2,2.3) (2,2) -
|
||||
-> stack should be (-0.8,0.3)
|
||||
del
|
||||
|
||||
# sub (2)
|
||||
(1.2,2.3) (1,2)-
|
||||
-> stack should be (0.2,0.3)
|
||||
del
|
||||
|
||||
# sub (3)
|
||||
(1.2,2.3) 1-
|
||||
-> stack should be (0.2,2.3)
|
||||
del
|
||||
|
||||
# sub (4)
|
||||
1 (1.2,2.3) -
|
||||
-> stack should be (-0.2,2.3)
|
||||
del
|
||||
|
||||
# mul (1)
|
||||
(1,2) (3,4) *
|
||||
-> stack should be (-5,10)
|
||||
del
|
||||
|
||||
# mul (2)
|
||||
(3,4) (1,2) *
|
||||
-> stack should be (-5,10)
|
||||
del
|
||||
|
||||
# mul (3)
|
||||
(3,4) 2 *
|
||||
-> stack should be (6,8)
|
||||
del
|
||||
|
||||
# mul (3)
|
||||
2 (3,4) *
|
||||
-> stack should be (6,8)
|
||||
del
|
||||
|
||||
# div (1)
|
||||
(1,2) (3,4) /
|
||||
-> stack should be (0.44,0.08)
|
||||
del
|
||||
|
||||
# div (2)
|
||||
(1,2) 2 /
|
||||
-> stack should be (0.5,1)
|
||||
del
|
||||
|
||||
# div (3)
|
||||
2 (3,4) /
|
||||
-> stack should be (0.24,-0.32)
|
||||
del
|
||||
|
||||
# re (1)
|
||||
(1.2,3.4) re
|
||||
-> stack should be 1.2
|
||||
del
|
||||
|
||||
# re (2)
|
||||
3 re
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# re (3)
|
||||
re
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# im (1)
|
||||
(1.2,3.4) im
|
||||
-> stack should be 3.4
|
||||
del
|
||||
|
||||
# im (2)
|
||||
3 re
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# im (3)
|
||||
re
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# chs
|
||||
(3.14,6.28) chs
|
||||
-> stack should be (-3.14,-6.28)
|
||||
del
|
||||
|
||||
# neg
|
||||
(-3.14,-6.28) neg
|
||||
-> stack should be (3.14,6.28)
|
||||
del
|
||||
|
||||
# inv (1)
|
||||
(2,4) inv
|
||||
-> stack should be (0.1,-0.2)
|
||||
del
|
||||
|
||||
# inv (2)
|
||||
(0.1,-0.2) inv
|
||||
-> stack should be (2,4)
|
||||
del
|
||||
|
||||
# abs
|
||||
(3,4) abs
|
||||
-> stack should be 5
|
||||
del
|
||||
|
||||
# sign (1)
|
||||
(1,0) sign
|
||||
-> stack should be (1,0)
|
||||
del
|
||||
|
||||
# sign (2)
|
||||
(0,1) sign
|
||||
-> stack should be (0,1)
|
||||
del
|
||||
|
||||
# sign (3)
|
||||
(3,-4) sign
|
||||
-> stack should be (0.6,-0.8)
|
||||
del
|
||||
|
||||
# sq (1)
|
||||
(12,10) sq
|
||||
-> stack should be (44,240)
|
||||
del
|
||||
|
||||
# sqr (1)
|
||||
(12,10) sq
|
||||
-> stack should be (44,240)
|
||||
del
|
||||
|
||||
# arg (1)
|
||||
(1,1) arg pi 4 / ==
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
# arg (2)
|
||||
1000 prec
|
||||
(-1,1) arg pi 3 * 4 / ==
|
||||
-> stack should be 1
|
||||
default
|
||||
del
|
||||
|
||||
# arg (3)
|
||||
1000 prec
|
||||
(1,-1) arg pi chs 4 / ==
|
||||
-> stack should be 1
|
||||
default
|
||||
del
|
||||
|
||||
# arg (4)
|
||||
1000 prec
|
||||
(-1,-1) arg pi -3 * 4 / ==
|
||||
-> stack should be 1
|
||||
default
|
||||
del
|
||||
|
||||
# arg (5)
|
||||
1000 prec
|
||||
(1,0) arg 0 ==
|
||||
-> stack should be 1
|
||||
default
|
||||
del
|
||||
|
||||
# arg (6)
|
||||
1000 prec
|
||||
(0,1) arg pi 2 / ==
|
||||
-> stack should be 1
|
||||
default
|
||||
del
|
||||
|
||||
# arg (7)
|
||||
1000 prec
|
||||
(-1,0) arg pi ==
|
||||
-> stack should be 1
|
||||
default
|
||||
del
|
||||
|
||||
# arg (8)
|
||||
1000 prec
|
||||
(0,-1) arg pi neg 2 / ==
|
||||
-> stack should be 1
|
||||
default
|
||||
del
|
||||
|
||||
# conj
|
||||
(1,2) conj dup conj
|
||||
-> stack should be (1,-2), (1,2)
|
||||
del
|
||||
|
||||
# r->c (1)
|
||||
1 2 r->c
|
||||
-> stack should be (1,2)
|
||||
del
|
||||
|
||||
# r->c (2)
|
||||
1 r->c
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# r->c (3)
|
||||
r->c
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# r->c (3)
|
||||
'1' '2' r->c
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# c->r (1)
|
||||
(1,2) c->r
|
||||
-> stack should be 1, 2
|
||||
del
|
||||
|
||||
# c->r (2)
|
||||
c->r
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# c->r (3)
|
||||
'4' c->r
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# r->p (1)
|
||||
6 fix
|
||||
(1,2) r->p
|
||||
-> stack should be (2.236068,1.107149)
|
||||
del
|
||||
|
||||
# r->p (2)
|
||||
19 fix
|
||||
1 r->p
|
||||
-> error should be 3.000000
|
||||
del
|
||||
|
||||
# r->p (3)
|
||||
r->p
|
||||
-> error should be 2
|
||||
del
|
||||
|
||||
# r->p (4)
|
||||
'1' '2' r->p
|
||||
-> error should be 3
|
||||
del
|
||||
|
||||
# ^ (1)
|
||||
6 fix
|
||||
(1,2) 2 ^
|
||||
-> stack should be (-3.000000,4.000000)
|
||||
del
|
||||
|
||||
# ^ (2)
|
||||
(1,2) 4 ^
|
||||
-> stack should be (-7.000000,-24.000000)
|
||||
del
|
||||
|
||||
# ^ (3)
|
||||
-3 .2 ^
|
||||
-> stack should be (1.007818,0.732222)
|
||||
del
|
||||
|
||||
# sqrt (1)
|
||||
(3,4) sqrt
|
||||
-> stack should be (2.000000,1.000000)
|
||||
del
|
||||
|
||||
# sqrt (2)
|
||||
-3 sqrt
|
||||
-> stack should be (-0.000000,1.732051)
|
||||
del
|
||||
|
||||
# sin (1)
|
||||
(1,2) sin
|
||||
-> stack should be (3.165779,1.959601)
|
||||
del
|
||||
|
||||
# sin (2)
|
||||
(1,-2) sin
|
||||
-> stack should be (3.165779,-1.959601)
|
||||
del
|
||||
|
||||
# sin (3)
|
||||
(-1,-2) sin
|
||||
-> stack should be (-3.165779,-1.959601)
|
||||
del
|
||||
|
||||
# sin (4)
|
||||
(-1,2) sin
|
||||
-> stack should be (-3.165779,1.959601)
|
||||
del
|
||||
|
||||
# asin (1)
|
||||
(1,2) asin
|
||||
-> stack should be (0.427079,1.528571)
|
||||
del
|
||||
|
||||
# asin (2)
|
||||
(1,-2) asin
|
||||
-> stack should be (0.427079,-1.528571)
|
||||
del
|
||||
|
||||
# asin (3)
|
||||
(-1,-2) asin
|
||||
-> stack should be (-0.427079,-1.528571)
|
||||
del
|
||||
|
||||
# asin (4)
|
||||
(-1,2) asin
|
||||
-> stack should be (-0.427079,1.528571)
|
||||
del
|
||||
|
||||
# cos (1)
|
||||
(1,2) cos
|
||||
-> stack should be (2.032723,-3.051898)
|
||||
del
|
||||
|
||||
# cos (2)
|
||||
(1,-2) cos
|
||||
-> stack should be (2.032723,3.051898)
|
||||
del
|
||||
|
||||
# cos (3)
|
||||
(-1,-2) cos
|
||||
-> stack should be (2.032723,-3.051898)
|
||||
del
|
||||
|
||||
# cos (4)
|
||||
(-1,2) sin
|
||||
-> stack should be (-3.165779,1.959601)
|
||||
del
|
||||
|
||||
# acos (1)
|
||||
(1,2) acos
|
||||
-> stack should be (1.143718,-1.528571)
|
||||
del
|
||||
|
||||
# acos (2)
|
||||
(1,-2) acos
|
||||
-> stack should be (1.143718,1.528571)
|
||||
del
|
||||
|
||||
# acos (3)
|
||||
(-1,-2) acos
|
||||
-> stack should be (1.997875,1.528571)
|
||||
del
|
||||
|
||||
# acos (4)
|
||||
(-1,2) acos
|
||||
-> stack should be (1.997875,-1.528571)
|
||||
del
|
||||
|
||||
# tan (1)
|
||||
(1,2) tan
|
||||
-> stack should be (0.033813,1.014794)
|
||||
del
|
||||
|
||||
# tan (2)
|
||||
(1,-2) tan
|
||||
-> stack should be (0.033813,-1.014794)
|
||||
del
|
||||
|
||||
# tan (3)
|
||||
(-1,-2) tan
|
||||
-> stack should be (-0.033813,-1.014794)
|
||||
del
|
||||
|
||||
# tan (4)
|
||||
(-1,2) tan
|
||||
-> stack should be (-0.033813,1.014794)
|
||||
del
|
||||
|
||||
# atan (1)
|
||||
(1,2) atan
|
||||
-> stack should be (1.338973,0.402359)
|
||||
del
|
||||
|
||||
# atan (2)
|
||||
(1,-2) atan
|
||||
-> stack should be (1.338973,-0.402359)
|
||||
del
|
||||
|
||||
# atan (3)
|
||||
(-1,-2) atan
|
||||
-> stack should be (-1.338973,-0.402359)
|
||||
del
|
||||
|
||||
# atan (4)
|
||||
(-1,2) atan
|
||||
-> stack should be (-1.338973,0.402359)
|
||||
del
|
||||
|
||||
# ln (1)
|
||||
(1,2) ln
|
||||
-> stack should be (0.804719,1.107149)
|
||||
del
|
||||
|
||||
# ln (2)
|
||||
(1,-2) ln
|
||||
-> stack should be (0.804719,-1.107149)
|
||||
del
|
||||
|
||||
# ln (3)
|
||||
(-1,-2) ln
|
||||
-> stack should be (0.804719,-2.034444)
|
||||
del
|
||||
|
||||
# ln (4)
|
||||
(-1,2) ln
|
||||
-> stack should be (0.804719,2.034444)
|
||||
del
|
||||
|
||||
# lnp1 (1)
|
||||
(1,2) lnp1
|
||||
(1,2) 1 + ln ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# lnp1 (2)
|
||||
(1,-2) lnp1
|
||||
(1,-2) 1 + ln ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# lnp1 (3)
|
||||
(-1,-2) lnp1
|
||||
(-1,-2) 1 + ln ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# lnp1 (4)
|
||||
(-1,2) lnp1
|
||||
(-1,2) 1 + ln ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# log (1)
|
||||
(1,2) log
|
||||
-> stack should be (0.804719,1.107149)
|
||||
del
|
||||
|
||||
# log (2)
|
||||
(1,-2) log
|
||||
-> stack should be (0.804719,-1.107149)
|
||||
del
|
||||
|
||||
# log (3)
|
||||
(-1,-2) log
|
||||
-> stack should be (0.804719,-2.034444)
|
||||
del
|
||||
|
||||
# log (4)
|
||||
(-1,2) log
|
||||
-> stack should be (0.804719,2.034444)
|
||||
del
|
||||
|
||||
# log10 (1)
|
||||
(1,2) log10
|
||||
-> stack should be (0.349485,0.480829)
|
||||
del
|
||||
|
||||
# log10 (2)
|
||||
(1,-2) log10
|
||||
-> stack should be (0.349485,-0.480829)
|
||||
del
|
||||
|
||||
# log10 (3)
|
||||
(-1,-2) log10
|
||||
-> stack should be (0.349485,-0.883548)
|
||||
del
|
||||
|
||||
# log10 (4)
|
||||
(-1,2) log10
|
||||
-> stack should be (0.349485,0.883548)
|
||||
del
|
||||
|
||||
# log2 (1)
|
||||
(1,2) log2
|
||||
-> stack should be (1.160964,1.597278)
|
||||
del
|
||||
|
||||
# log2 (2)
|
||||
(1,-2) log2
|
||||
-> stack should be (1.160964,-1.597278)
|
||||
del
|
||||
|
||||
# log2 (3)
|
||||
(-1,-2) log2
|
||||
-> stack should be (1.160964,-2.935082)
|
||||
del
|
||||
|
||||
# log2 (4)
|
||||
(-1,2) log2
|
||||
-> stack should be (1.160964,2.935082)
|
||||
del
|
||||
|
||||
# exp (1)
|
||||
(1,2) exp
|
||||
-> stack should be (-1.131204,2.471727)
|
||||
del
|
||||
|
||||
# exp (2)
|
||||
(1,-2) exp
|
||||
-> stack should be (-1.131204,-2.471727)
|
||||
del
|
||||
|
||||
# exp (3)
|
||||
(-1,-2) exp
|
||||
-> stack should be (-0.153092,-0.334512)
|
||||
del
|
||||
|
||||
# exp (4)
|
||||
(-1,2) exp
|
||||
-> stack should be (-0.153092,0.334512)
|
||||
del
|
||||
|
||||
# expm (1)
|
||||
(1,2) expm
|
||||
(1,2) exp 1 - ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# expm (2)
|
||||
(1,-2) expm
|
||||
(1,-2) exp 1 - ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# expm (3)
|
||||
(-1,-2) expm
|
||||
(-1,-2) exp 1 - ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# expm (4)
|
||||
(-1,2) expm
|
||||
(-1,2) exp 1 - ==
|
||||
-> stack should be 1.000000
|
||||
del
|
||||
|
||||
# alog2 (1)
|
||||
(1,2) alog2
|
||||
-> stack should be (0.366914,1.966055)
|
||||
del
|
||||
|
||||
# alog2 (2)
|
||||
(1,-2) alog2
|
||||
-> stack should be (0.366914,-1.966055)
|
||||
del
|
||||
|
||||
# alog2 (3)
|
||||
(-1,-2) alog2
|
||||
-> stack should be (0.091728,-0.491514)
|
||||
del
|
||||
|
||||
# alog2 (4)
|
||||
(-1,2) alog2
|
||||
-> stack should be (0.091728,0.491514)
|
||||
del
|
||||
|
||||
# alog10 (1)
|
||||
(1,2) alog10
|
||||
-> stack should be (-1.070135,-9.942576)
|
||||
del
|
||||
|
||||
# alog10 (2)
|
||||
(1,-2) alog10
|
||||
-> stack should be (-1.070135,9.942576)
|
||||
del
|
||||
|
||||
# alog10 (3)
|
||||
(-1,-2) alog10
|
||||
-> stack should be (-0.010701,0.099426)
|
||||
del
|
||||
|
||||
# alog10 (4)
|
||||
(-1,2) alog10
|
||||
-> stack should be (-0.010701,-0.099426)
|
||||
del
|
||||
|
||||
# sinh (1)
|
||||
(1,2) sinh
|
||||
-> stack should be (-0.489056,1.403119)
|
||||
del
|
||||
|
||||
# sinh (2)
|
||||
(1,-2) sinh
|
||||
-> stack should be (-0.489056,-1.403119)
|
||||
del
|
||||
|
||||
# sinh (3)
|
||||
(-1,-2) sinh
|
||||
-> stack should be (0.489056,-1.403119)
|
||||
del
|
||||
|
||||
# sinh (4)
|
||||
(-1,2) sinh
|
||||
-> stack should be (0.489056,1.403119)
|
||||
del
|
||||
|
||||
# asinh (1)
|
||||
(1,2) asinh
|
||||
-> stack should be (1.469352,1.063440)
|
||||
del
|
||||
|
||||
# asinh (2)
|
||||
(1,-2) asinh
|
||||
-> stack should be (1.469352,-1.063440)
|
||||
del
|
||||
|
||||
# asinh (3)
|
||||
(-1,-2) asinh
|
||||
-> stack should be (-1.469352,-1.063440)
|
||||
del
|
||||
|
||||
# asinh (4)
|
||||
(-1,2) asinh
|
||||
-> stack should be (-1.469352,1.063440)
|
||||
del
|
||||
|
||||
# cosh (1)
|
||||
(1,2) cosh
|
||||
-> stack should be (-0.489056,1.403119)
|
||||
del
|
||||
|
||||
# cosh (2)
|
||||
(1,-2) cosh
|
||||
-> stack should be (-0.489056,-1.403119)
|
||||
del
|
||||
|
||||
# cosh (3)
|
||||
(-1,-2) cosh
|
||||
-> stack should be (0.489056,-1.403119)
|
||||
del
|
||||
|
||||
# cosh (4)
|
||||
(-1,2) cosh
|
||||
-> stack should be (0.489056,1.403119)
|
||||
del
|
||||
|
||||
# acosh (1)
|
||||
(1,2) acosh
|
||||
-> stack should be (1.528571,1.143718)
|
||||
del
|
||||
|
||||
# acosh (2)
|
||||
(1,-2) acosh
|
||||
-> stack should be (1.528571,-1.143718)
|
||||
del
|
||||
|
||||
# acosh (3)
|
||||
(-1,-2) acosh
|
||||
-> stack should be (-1.528571,1.997875)
|
||||
del
|
||||
|
||||
# acosh (4)
|
||||
(-1,2) acosh
|
||||
-> stack should be (-1.528571,-1.997875)
|
||||
del
|
||||
|
||||
# tanh (1)
|
||||
(1,2) tanh
|
||||
-> stack should be (0.564133,-0.217934)
|
||||
del
|
||||
|
||||
# tanh (2)
|
||||
(1,-2) tanh
|
||||
-> stack should be (0.564133,0.217934)
|
||||
del
|
||||
|
||||
# tanh (3)
|
||||
(-1,-2) tanh
|
||||
-> stack should be (-0.564133,0.217934)
|
||||
del
|
||||
|
||||
# tanh (4)
|
||||
(-1,2) tanh
|
||||
-> stack should be (-0.564133,-0.217934)
|
||||
del
|
||||
|
||||
# atanh (1)
|
||||
(1,2) atanh
|
||||
-> stack should be (0.173287,1.178097)
|
||||
del
|
||||
|
||||
# atanh (2)
|
||||
(1,-2) atanh
|
||||
-> stack should be (0.173287,-1.178097)
|
||||
del
|
||||
|
||||
# atanh (3)
|
||||
(-1,-2) atanh
|
||||
-> stack should be (-0.173287,-1.178097)
|
||||
del
|
||||
|
||||
# atanh (4)
|
||||
(-1,2) atanh
|
||||
-> stack should be (-0.173287,1.178097)
|
||||
del
|
535
test/100-complex.md
Normal file
535
test/100-complex.md
Normal file
|
@ -0,0 +1,535 @@
|
|||
# COMPLEX
|
||||
|
||||
`default del`
|
||||
|
||||
## entry (1)
|
||||
|
||||
`(1,2) ( 1,2) (1 ,2) (1, 2) (1,2 )`
|
||||
|
||||
-> stack should be (1,2), (1,2), (1,2), (1,2), (1,2)
|
||||
|
||||
`del`
|
||||
|
||||
## entry (2)
|
||||
|
||||
`(1.3,2.444555`
|
||||
|
||||
-> stack should be (1.3,2.444555)
|
||||
|
||||
`del`
|
||||
|
||||
## entry (3)
|
||||
|
||||
`(1,`
|
||||
|
||||
-> stack should be '(1,'
|
||||
|
||||
`del`
|
||||
|
||||
## entry (4)
|
||||
|
||||
`(nan,+inf)`
|
||||
|
||||
-> stack should be (nan,inf)
|
||||
|
||||
`del`
|
||||
|
||||
## entry (5)
|
||||
|
||||
`(0x1234,0x10.10)`
|
||||
|
||||
-> stack should be (0x1.234p+12,0x1.01p+4)
|
||||
|
||||
`del`
|
||||
|
||||
## entry (6)
|
||||
|
||||
`(0b11,0b101)`
|
||||
|
||||
-> stack should be (0b11,0b101)
|
||||
|
||||
`del`
|
||||
|
||||
## add (1)
|
||||
|
||||
`(1.2,2.3) (1,2) +`
|
||||
|
||||
-> stack should be (2.2,4.3)
|
||||
|
||||
`del`
|
||||
|
||||
## add (2)
|
||||
|
||||
`(1.2,2.3) 3 +`
|
||||
|
||||
-> stack should be (4.2,2.3)
|
||||
|
||||
`del`
|
||||
|
||||
## add (3)
|
||||
|
||||
`3 (1.2,2.3) +`
|
||||
|
||||
-> stack should be (4.2,2.3)
|
||||
|
||||
`del`
|
||||
|
||||
## sub (1)
|
||||
|
||||
`(1.2,2.3) (2,2) -`
|
||||
|
||||
-> stack should be (-0.8,0.3)
|
||||
|
||||
`del`
|
||||
|
||||
## sub (2)
|
||||
|
||||
`(1.2,2.3) 1 -`
|
||||
|
||||
-> stack should be (0.2,2.3)
|
||||
|
||||
`del`
|
||||
|
||||
## sub (3)
|
||||
|
||||
`1 (1.2,2.3) -`
|
||||
|
||||
-> stack should be (-0.2,-2.3)
|
||||
|
||||
`del`
|
||||
|
||||
## mul (1)
|
||||
|
||||
`(1,2) (3,4) *`
|
||||
|
||||
-> stack should be (-5,10)
|
||||
|
||||
`del`
|
||||
|
||||
## mul (2)
|
||||
|
||||
`(3,4) (1,2) *`
|
||||
|
||||
-> stack should be (-5,10)
|
||||
|
||||
`del`
|
||||
|
||||
## mul (3)
|
||||
|
||||
`(3,4) 2 *`
|
||||
|
||||
-> stack should be (6,8)
|
||||
|
||||
`del`
|
||||
|
||||
## mul (3)
|
||||
|
||||
`2 (3,4) *`
|
||||
|
||||
-> stack should be (6,8)
|
||||
|
||||
`del`
|
||||
|
||||
## div (1)
|
||||
|
||||
`(1,2) (3,4) /`
|
||||
|
||||
-> stack should be (0.44,0.08)
|
||||
|
||||
`del`
|
||||
|
||||
## div (2)
|
||||
|
||||
`(1,2) 2 /`
|
||||
|
||||
-> stack should be (0.5,1)
|
||||
|
||||
`del`
|
||||
|
||||
## div (3)
|
||||
|
||||
`2 (3,4) /`
|
||||
|
||||
-> stack should be (0.24,-0.32)
|
||||
|
||||
`del`
|
||||
|
||||
## re (1)
|
||||
|
||||
`(1.2,3.4) re`
|
||||
|
||||
-> stack should be 1.2
|
||||
|
||||
`del`
|
||||
|
||||
## re (2)
|
||||
|
||||
`3 re`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## re (3)
|
||||
|
||||
`re`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## im (1)
|
||||
|
||||
`(1.2,3.4) im`
|
||||
|
||||
-> stack should be 3.4
|
||||
|
||||
`del`
|
||||
|
||||
## im (2)
|
||||
|
||||
`3 re`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## im (3)
|
||||
|
||||
`re`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## chs
|
||||
|
||||
`(3.14,6.28) chs`
|
||||
|
||||
-> stack should be (-3.14,-6.28)
|
||||
|
||||
`del`
|
||||
|
||||
## neg
|
||||
|
||||
`(-3.14,-6.28) neg`
|
||||
|
||||
-> stack should be (3.14,6.28)
|
||||
|
||||
`del`
|
||||
|
||||
## inv (1)
|
||||
|
||||
`(2,4) inv`
|
||||
|
||||
-> stack should be (0.1,-0.2)
|
||||
|
||||
`del`
|
||||
|
||||
## inv (2)
|
||||
|
||||
`(0.1,-0.2) inv`
|
||||
|
||||
-> stack should be (2,4)
|
||||
|
||||
`del`
|
||||
|
||||
## abs
|
||||
|
||||
`(3,4) abs`
|
||||
|
||||
-> stack should be 5
|
||||
|
||||
`del`
|
||||
|
||||
## sign (1)
|
||||
|
||||
`(1,0) sign`
|
||||
|
||||
-> stack should be (1,0)
|
||||
|
||||
`del`
|
||||
|
||||
## sign (2)
|
||||
|
||||
`(0,1) sign`
|
||||
|
||||
-> stack should be (0,1)
|
||||
|
||||
`del`
|
||||
|
||||
## sign (3)
|
||||
|
||||
`(3,-4) sign`
|
||||
|
||||
-> stack should be (0.6,-0.8)
|
||||
|
||||
`del`
|
||||
|
||||
## sq (1)
|
||||
|
||||
`(12,10) sq`
|
||||
|
||||
-> stack should be (44,240)
|
||||
|
||||
`del`
|
||||
|
||||
## sqr (1)
|
||||
|
||||
`(12,10) sq`
|
||||
|
||||
-> stack should be (44,240)
|
||||
|
||||
`del`
|
||||
|
||||
## arg (1)
|
||||
|
||||
`(1,1) arg pi 4 / ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`del`
|
||||
|
||||
## arg (2)
|
||||
|
||||
`1000 prec`
|
||||
|
||||
`(-1,1) arg pi 3 * 4 / ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`default del`
|
||||
|
||||
## arg (3)
|
||||
|
||||
`1000 prec`
|
||||
|
||||
`(1,-1) arg pi chs 4 / ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`default del`
|
||||
|
||||
## arg (4)
|
||||
|
||||
`1000 prec`
|
||||
|
||||
`(-1,-1) arg pi -3 * 4 / ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`default del`
|
||||
|
||||
## arg (5)
|
||||
|
||||
`1000 prec`
|
||||
|
||||
`(1,0) arg 0 ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`default del`
|
||||
|
||||
## arg (6)
|
||||
|
||||
`1000 prec`
|
||||
|
||||
`(0,1) arg pi 2 / ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`default del`
|
||||
|
||||
## arg (7)
|
||||
|
||||
`1000 prec`
|
||||
|
||||
`(-1,0) arg pi ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`default del`
|
||||
|
||||
## arg (8)
|
||||
|
||||
`1000 prec`
|
||||
|
||||
`(0,-1) arg pi neg 2 / ==`
|
||||
|
||||
-> stack should be 1
|
||||
|
||||
`default del`
|
||||
|
||||
## conj
|
||||
|
||||
`(1,2) conj dup conj`
|
||||
|
||||
-> stack should be (1,-2), (1,2)
|
||||
|
||||
`del`
|
||||
|
||||
## r->c (1)
|
||||
|
||||
`1 2 r->c`
|
||||
|
||||
-> stack should be (1,2)
|
||||
|
||||
`del`
|
||||
|
||||
## r->c (2)
|
||||
|
||||
`0x12 0b1101 r->c`
|
||||
|
||||
-> stack should be (0x12,0b1101)
|
||||
|
||||
`del`
|
||||
|
||||
## r->c error (1)
|
||||
|
||||
`1 r->c`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## r->c error (2)
|
||||
|
||||
`r->c`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## r->c error (3)
|
||||
|
||||
`'1' '2' r->c`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## c->r (1)
|
||||
|
||||
`(1,2) c->r`
|
||||
|
||||
-> stack should be 1, 2
|
||||
|
||||
`del`
|
||||
|
||||
## c->r (2)
|
||||
|
||||
`(0x12,0b1101) c->r`
|
||||
|
||||
-> stack should be 0x12, 0b1101
|
||||
|
||||
`del`
|
||||
|
||||
## c->r error (2)
|
||||
|
||||
`c->r`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## c->r error (2)
|
||||
|
||||
`'4' c->r`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## r->p (1)
|
||||
|
||||
`6 fix`
|
||||
|
||||
`(1,2) r->p`
|
||||
|
||||
-> stack should be (2.236068,1.107149)
|
||||
|
||||
`del`
|
||||
|
||||
## r->p (2)
|
||||
|
||||
`19 fix`
|
||||
|
||||
`1 r->p`
|
||||
|
||||
-> error should be 3.000000
|
||||
|
||||
`del`
|
||||
|
||||
## r->p (3)
|
||||
|
||||
`r->p`
|
||||
|
||||
-> error should be 2
|
||||
|
||||
`del`
|
||||
|
||||
## r->p (4)
|
||||
|
||||
`'1' '2' r->p`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (1)
|
||||
|
||||
`6 fix`
|
||||
|
||||
`(1,2) 2 ^`
|
||||
|
||||
-> stack should be (-3.000000,4.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (2)
|
||||
|
||||
`(1,2) 4 ^`
|
||||
|
||||
-> stack should be (-7.000000,-24.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (3)
|
||||
|
||||
`-3 .2 ^`
|
||||
|
||||
-> stack should be (1.007818,0.732222)
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (4)
|
||||
|
||||
`-3 (1,2) ^`
|
||||
|
||||
-> stack should be (0.003284,-0.004539)
|
||||
|
||||
`del`
|
||||
|
||||
## ^ (5)
|
||||
|
||||
`(1,2) (1,2) ^`
|
||||
|
||||
-> stack should be (-0.222517,0.100709)
|
||||
|
||||
`del`
|
||||
|
||||
## sqrt (1)
|
||||
|
||||
`(3,4) sqrt`
|
||||
|
||||
-> stack should be (2.000000,1.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## sqrt (2)
|
||||
|
||||
`-3 sqrt`
|
||||
|
||||
-> stack should be (0.000000,1.732051)
|
||||
|
||||
`del`
|
|
@ -1,196 +0,0 @@
|
|||
## fix entry
|
||||
default del
|
||||
|
||||
# table for fixed entry, 4 fix output >= 0
|
||||
4 fix
|
||||
1 0.01 0.0001 0.00006 0.00004 0 0.012 0.001256 100 100.001 100.00006 100.00004 12345678910111213.12355
|
||||
-> stack should be 1.0000, 0.0100, 0.0001, 0.0001, 0.0000, 0.0000, 0.0120, 0.0013, 100.0000, 100.0010, 100.0001, 100.0000, 12345678910111213.1236
|
||||
del default
|
||||
|
||||
# table for fixed entry, 4 fix output <= 0
|
||||
4 fix
|
||||
-1 -0.01 -0.0001 -0.00006 -0.00004 -0 -0.012 -0.001256 -100 -100.001 -100.00006 -100.00004 -12345678910111213.12355
|
||||
-> stack should be -1.0000, -0.0100, -0.0001, -0.0001, -0.0000, -0.0000, -0.0120, -0.0013, -100.0000, -100.0010, -100.0001, -100.0000, -12345678910111213.1236
|
||||
del default
|
||||
|
||||
# table for sci entry, 4 fix output >= 0
|
||||
4 fix
|
||||
0e100 1e0 1.e0 1.001e0 1.e-3 1.e-4 6.e-5 4.e-5 1.00001e2 1.0000006e2 1.0000004e2 1234.5678917e2
|
||||
-> stack should be 0.0000, 1.0000, 1.0000, 1.0010, 0.0010, 0.0001, 0.0001, 0.0000, 100.0010, 100.0001, 100.0000, 123456.7892
|
||||
del default
|
||||
|
||||
# table for sci entry, 4 fix output <= 0
|
||||
4 fix
|
||||
-0e100 -1e0 -1.e0 -1.001e0 -1.e-3 -1.e-4 -6.e-5 -4.e-5 -1.00001e2 -1.0000006e2 -1.0000004e2 -1234.5678917e2
|
||||
-> stack should be -0.0000, -1.0000, -1.0000, -1.0010, -0.0010, -0.0001, -0.0001, -0.0000, -100.0010, -100.0001, -100.0000, -123456.7892
|
||||
del default
|
||||
|
||||
# table for singularity
|
||||
4 fix
|
||||
nan @nan@ -nan inf -inf @inf@ -@inf@
|
||||
-> stack should be nan, nan, nan, inf, -inf, inf, -inf
|
||||
del default
|
||||
|
||||
# some strange behaviour (1)
|
||||
0 fix
|
||||
1 2 / dup +
|
||||
-> stack should be 1
|
||||
del default
|
||||
|
||||
# some strange behaviour (2)
|
||||
1 fix
|
||||
0.6
|
||||
-> stack should be 0.6
|
||||
del default
|
||||
|
||||
# some strange behaviour (3)
|
||||
0 fix
|
||||
110.6 0.6
|
||||
-> stack should be 111, 1
|
||||
del default
|
||||
|
||||
# hex (1)
|
||||
0x4000000000000
|
||||
-> stack should be 0x4000000000000
|
||||
del default
|
||||
|
||||
# hex (2)
|
||||
2 50 ^ hex
|
||||
-> stack should be 0x4000000000000
|
||||
del default
|
||||
|
||||
# hex (3)
|
||||
12.34 hex
|
||||
-> stack should be 0xc
|
||||
del default
|
||||
|
||||
# dec (1)
|
||||
2 50 ^
|
||||
-> stack should be 1125899906842624
|
||||
del default
|
||||
|
||||
# dec (2)
|
||||
0x4000000000000 dec
|
||||
-> stack should be 1125899906842624
|
||||
del default
|
||||
|
||||
# dec (3)
|
||||
12.34 dec
|
||||
-> stack should be 12.34
|
||||
del default
|
||||
|
||||
# bin (1)
|
||||
0b100000000000000000000000000000000000000000000000000 bin
|
||||
-> stack should be 0b100000000000000000000000000000000000000000000000000
|
||||
del default
|
||||
|
||||
# bin (2)
|
||||
2 50 ^ bin
|
||||
-> stack should be 0b100000000000000000000000000000000000000000000000000
|
||||
del default
|
||||
|
||||
# bin (3)
|
||||
0x4000000000000 bin
|
||||
-> stack should be 0b100000000000000000000000000000000000000000000000000
|
||||
del default
|
||||
|
||||
# bin (4)
|
||||
12.34 bin
|
||||
-> stack should be 0b1100
|
||||
del default
|
||||
|
||||
# base entry (1)
|
||||
3b111 dup dec
|
||||
-> stack should be 3b111, 13
|
||||
del default
|
||||
|
||||
# base entry (2)
|
||||
3b114
|
||||
-> stack should be 3b11, 4
|
||||
del default
|
||||
|
||||
# base entry (3)
|
||||
1b0
|
||||
-> stack should be 1, 'b0'
|
||||
del default
|
||||
|
||||
# base entry (4)
|
||||
62b20 dup dec
|
||||
-> stack should be 62b20, 124
|
||||
del default
|
||||
|
||||
# base entry (5)
|
||||
63b20
|
||||
-> stack should be 63, 'b20'
|
||||
del default
|
||||
|
||||
# base entry (6)
|
||||
2b11001100 0b11001100 ==
|
||||
-> stack should be 2b1
|
||||
del default
|
||||
|
||||
# base entry (7)
|
||||
10b1234 1234 ==
|
||||
-> stack should be 10b1
|
||||
del default
|
||||
|
||||
# base entry (8)
|
||||
16b1234 0x1234 ==
|
||||
-> stack should be 16b1
|
||||
del default
|
||||
|
||||
# base display (1)
|
||||
2 62 for i 62 i base next
|
||||
-> stack should be 2b111110, 3b2022, 4b332, 5b222, 6b142, 7b116, 8b76, 9b68, 10b62, 11b57, 12b52, 13b4a, 14b46, 15b42, 16b3e, 17b3b, 18b38, 19b35, 20b32, 21b2k, 22b2i, 23b2g, 24b2e, 25b2c, 26b2a, 27b28, 28b26, 29b24, 30b22, 31b20, 32b1u, 33b1t, 34b1s, 35b1r, 36b1q, 37b1P, 38b1O, 39b1N, 40b1M, 41b1L, 42b1K, 43b1J, 44b1I, 45b1H, 46b1G, 47b1F, 48b1E, 49b1D, 50b1C, 51b1B, 52b1A, 53b19, 54b18, 55b17, 56b16, 57b15, 58b14, 59b13, 60b12, 61b11, 62b10
|
||||
del default
|
||||
|
||||
# base display (2)
|
||||
2 62 for i i 62 base next
|
||||
-> stack should be 62b2, 62b3, 62b4, 62b5, 62b6, 62b7, 62b8, 62b9, 62bA, 62bB, 62bC, 62bD, 62bE, 62bF, 62bG, 62bH, 62bI, 62bJ, 62bK, 62bL, 62bM, 62bN, 62bO, 62bP, 62bQ, 62bR, 62bS, 62bT, 62bU, 62bV, 62bW, 62bX, 62bY, 62bZ, 62ba, 62bb, 62bc, 62bd, 62be, 62bf, 62bg, 62bh, 62bi, 62bj, 62bk, 62bl, 62bm, 62bn, 62bo, 62bp, 62bq, 62br, 62bs, 62bt, 62bu, 62bv, 62bw, 62bx, 62by, 62bz, 62b10
|
||||
del default
|
||||
|
||||
# base display (3)
|
||||
100 dup 3 base ==
|
||||
13455600 dup 5 base ==
|
||||
55756 dup 17 base ==
|
||||
2345321 dup 62 base ==
|
||||
-> stack should be 1, 1, 1, 1
|
||||
del default
|
||||
|
||||
# base display (4)
|
||||
100 18 base dup 3 base == dec
|
||||
13455600 55 base dup 5 base == dec
|
||||
55756 9 base dup 17 base == dec
|
||||
2345321 57 base dup 62 base == dec
|
||||
-> stack should be 1, 1, 1, 1
|
||||
del default
|
||||
|
||||
# negative base numbers (1)
|
||||
1000 hex neg
|
||||
-> stack should be -0x3e8
|
||||
del default
|
||||
|
||||
# negative base numbers (2)
|
||||
1000 7 base neg
|
||||
-> stack should be -7b2626
|
||||
del default
|
||||
|
||||
# negative base numbers (3)
|
||||
1000 bin neg
|
||||
-> stack should be -0b1111101000
|
||||
del default
|
||||
|
||||
# negative base numbers (4)
|
||||
-0b1111101000 3 base
|
||||
-> stack should be -3b1101001
|
||||
del default
|
||||
|
||||
# inf should not be based-represented
|
||||
-1 bin 0 bin / 1 3 base 0 3 base /
|
||||
-> stack should be -inf, inf
|
||||
del default
|
||||
|
||||
# nan should not be based-represented
|
||||
-0 bin 0 bin / 0 3 base 0 3 base /
|
||||
-> stack should be nan, nan
|
||||
del default
|
|
@ -1,25 +1,41 @@
|
|||
## date and time
|
||||
default del
|
||||
# DATE AND TIME
|
||||
|
||||
`default del`
|
||||
|
||||
## date
|
||||
|
||||
`date type`
|
||||
|
||||
# date
|
||||
date type
|
||||
-> error should be 0
|
||||
-> stack should be "number"
|
||||
del
|
||||
|
||||
# time
|
||||
time type
|
||||
-> stack should be "number"
|
||||
|
||||
`del`
|
||||
|
||||
## time
|
||||
|
||||
`time type`
|
||||
|
||||
-> error should be 0
|
||||
-> stack should be "number"
|
||||
del
|
||||
|
||||
# ticks (1)
|
||||
ticks type
|
||||
-> stack should be "number"
|
||||
|
||||
`del`
|
||||
|
||||
## ticks (1)
|
||||
|
||||
`ticks type`
|
||||
|
||||
-> error should be 0
|
||||
-> stack should be "number"
|
||||
del
|
||||
|
||||
# ticks (2)
|
||||
ticks ticks - 0 <=
|
||||
-> stack should be "number"
|
||||
|
||||
`del`
|
||||
|
||||
## ticks (2)
|
||||
|
||||
`ticks ticks - 0 <=`
|
||||
|
||||
-> stack should be 1
|
||||
del
|
||||
|
||||
`del`
|
105
test/120-trig.md
Normal file
105
test/120-trig.md
Normal file
|
@ -0,0 +1,105 @@
|
|||
# TRIGONOMETRY
|
||||
|
||||
`del default 6 fix 128 prec`
|
||||
|
||||
## pi
|
||||
|
||||
`pi`
|
||||
|
||||
-> stack should be 3.141593
|
||||
|
||||
`del`
|
||||
|
||||
## d->r
|
||||
|
||||
`180 d->r pi ==`
|
||||
|
||||
-> stack should be 1.000000
|
||||
|
||||
`del`
|
||||
|
||||
## r->d
|
||||
|
||||
`pi r->d 180 ==`
|
||||
|
||||
-> stack should be 1.000000
|
||||
|
||||
`del`
|
||||
|
||||
## sin asin
|
||||
|
||||
`0 sin pi 2 / sin pi 6 / sin`
|
||||
`0 asin 0 == 1 asin pi 2 / == 0.5 asin pi 6 / ==`
|
||||
|
||||
-> stack should be 0.000000, 1.000000, 0.500000, 1.000000, 1.000000, 1.000000
|
||||
|
||||
`del`
|
||||
|
||||
## cos acos
|
||||
|
||||
`0 cos pi 3 / cos`
|
||||
`1 acos 0 == 0.5 acos pi 3 / ==`
|
||||
|
||||
-> stack should be 1.000000, 0.500000, 1.000000, 1.000000
|
||||
|
||||
`del`
|
||||
|
||||
## tan atan
|
||||
|
||||
`pi 4 / tan 1 == 1 atan pi 4 / ==`
|
||||
|
||||
-> stack should be 1.000000, 1.000000
|
||||
|
||||
`del`
|
||||
|
||||
## sin asin
|
||||
|
||||
`(1,2) sin (3.165779,1.959601) asin`
|
||||
|
||||
-> stack should be (3.165779,1.959601), (1.000000,2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## cos acos
|
||||
|
||||
`(1,2) cos (2.032723,-3.051898) acos`
|
||||
|
||||
-> stack should be (2.032723,-3.051898), (1.000000,2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## tan atan
|
||||
|
||||
`(1,2) tan (0.033813,1.014794) atan`
|
||||
|
||||
-> stack should be (0.033813,1.014794), (1.000004,1.999996)
|
||||
|
||||
`del`
|
||||
|
||||
## sin asin cos acos tan atan error
|
||||
|
||||
`'ok' sin`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`asin`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`cos`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`acos`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`tan`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`atan`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
219
test/130-logs.md
Normal file
219
test/130-logs.md
Normal file
|
@ -0,0 +1,219 @@
|
|||
# LOGARITHMS
|
||||
|
||||
`del default 6 fix`
|
||||
|
||||
## euler constant
|
||||
|
||||
`e`
|
||||
|
||||
-> stack should be 0.577216
|
||||
|
||||
`del`
|
||||
|
||||
## ln log exp
|
||||
|
||||
`2 ln exp`
|
||||
|
||||
`2 log exp`
|
||||
|
||||
-> stack should be 2.000000, 2.000000
|
||||
|
||||
`del`
|
||||
|
||||
## lnp1 expm
|
||||
|
||||
`4 lnp1 expm`
|
||||
|
||||
-> stack should be 4.000000
|
||||
|
||||
`del`
|
||||
|
||||
|
||||
## log10 alog10 exp10
|
||||
|
||||
`5 log10 alog10`
|
||||
|
||||
`5 log10 exp10`
|
||||
|
||||
-> stack should be 5.000000, 5.000000
|
||||
|
||||
`del`
|
||||
|
||||
## log2 alog2 exp2
|
||||
|
||||
`6 log2 alog2`
|
||||
|
||||
`6 log2 exp2`
|
||||
|
||||
-> stack should be 6.000000, 6.000000
|
||||
|
||||
`del`
|
||||
|
||||
## sinh asinh
|
||||
|
||||
`1 sinh asinh`
|
||||
|
||||
-> stack should be 1.000000
|
||||
|
||||
`del`
|
||||
|
||||
## cosh acosh
|
||||
|
||||
`1.1 cosh acosh`
|
||||
|
||||
-> stack should be 1.100000
|
||||
|
||||
`del`
|
||||
|
||||
## tanh atanh
|
||||
|
||||
`1.2 tanh atanh`
|
||||
|
||||
-> stack should be 1.200000
|
||||
|
||||
`del`
|
||||
|
||||
## complex ln exp
|
||||
|
||||
`(-1,-2) ln exp`
|
||||
|
||||
-> stack should be (-1.000000,-2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## complex log exp
|
||||
|
||||
`(1,2) log exp`
|
||||
|
||||
-> stack should be (1.000000,2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## complex lnp1 expm
|
||||
|
||||
`(1,2) lnp1 expm`
|
||||
|
||||
-> stack should be (1.000000,2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## complex log10 alog10
|
||||
|
||||
`(1,-2) log10 alog10`
|
||||
|
||||
-> stack should be (1.000000,-2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
|
||||
## complex log2 alog2
|
||||
|
||||
`(-1,-2) log2 alog2`
|
||||
|
||||
-> stack should be (-1.000000,-2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## complex sinh asinh
|
||||
|
||||
`(1,1.5) sinh asinh`
|
||||
|
||||
-> stack should be (1.000000,1.500000)
|
||||
|
||||
`del`
|
||||
|
||||
## complex cosh acosh
|
||||
|
||||
`(1,2) cosh acosh`
|
||||
|
||||
-> stack should be (1.000000,2.000000)
|
||||
|
||||
`del`
|
||||
|
||||
## complex tanh atanh
|
||||
|
||||
`(1,1.5) tanh atanh`
|
||||
|
||||
-> stack should be (1.000000,1.500000)
|
||||
|
||||
`del`
|
||||
|
||||
## ln log lnp1 exp expm error
|
||||
|
||||
`'ok' ln`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`log`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`lnp1`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`exp`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`expm`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## log10 alog10 exp10 log2 alog2 exp2 error
|
||||
|
||||
`'ok' log10`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`alog10`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`exp10`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`log2`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`alog2`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`exp2`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
||||
|
||||
## sinh asinh cosh acosh tanh atanh error
|
||||
|
||||
`'ok' sinh`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`asinh`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`cosh`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`acosh`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`tanh`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`atanh`
|
||||
|
||||
-> error should be 3
|
||||
|
||||
`del`
|
|
@ -1,41 +0,0 @@
|
|||
## MANUAL TESTS
|
||||
default del
|
||||
|
||||
# GENERAL help - please type help and verify help is shown
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# GENERAL h - please type h and verify help is shown
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# GENERAL ? - please type ? and verify help is shown
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# GENERAL quit - please type quit and verify rpn exits
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# GENERAL q - please type q and verify rpn exits
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# GENERAL exit - please type exit and verify rpn exits
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# STORE vars - please type vars and verify variables are shown
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# STORE edit - please type edit and verify last line comes under the caret
|
||||
-> error should be 0
|
||||
del
|
||||
|
||||
# HISTORY - please type history and verify rpn history is shown
|
||||
-> error should be 0
|
||||
|
||||
# MULTILINE EDITING - please type a prog like 1 3 for i[ALT-ENTER]i sq[ALT-ENTER]next[ENTER] and verify output
|
||||
-> error should be 0
|
||||
del
|
25
test/999-manual-tests.md
Normal file
25
test/999-manual-tests.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# MANUAL TESTS
|
||||
|
||||
`default del`
|
||||
|
||||
## GENERAL help - please type help, h or ? and verify help is shown
|
||||
|
||||
-> error should be 0
|
||||
|
||||
## STORE vars - please type vars and verify variables are shown
|
||||
|
||||
`vars`
|
||||
|
||||
-> error should be 0
|
||||
|
||||
## STORE edit - please type edit and verify last line comes under the caret
|
||||
|
||||
-> error should be 0
|
||||
|
||||
## HISTORY - please type history and verify rpn history is shown
|
||||
|
||||
-> error should be 0
|
||||
|
||||
## MULTILINE EDITING - please type a prog like 1 3 for i[ALT-ENTER]i sq[ALT-ENTER]next[ENTER] and verify output
|
||||
|
||||
-> error should be 0
|
24
test/all.md
Normal file
24
test/all.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Chaining all tests
|
||||
|
||||
@include 005-test-framework.md
|
||||
@include 010-mode.md
|
||||
@include 020-general.md
|
||||
@include 021-parse-string.md
|
||||
@include 022-parse-symbol.md
|
||||
@include 023-parse-number.md
|
||||
@include 024-parse-complex.md
|
||||
@include 025-parse-other.md
|
||||
@include 026-parse-program.md
|
||||
@include 027-base-entry.md
|
||||
@include 030-branch.md
|
||||
@include 040-stack.md
|
||||
@include 050-real.md
|
||||
@include 060-string.md
|
||||
@include 070-test.md
|
||||
@include 080-store.md
|
||||
@include 090-program.md
|
||||
@include 100-complex.md
|
||||
@include 110-time.md
|
||||
@include 120-trig.md
|
||||
@include 130-logs.md
|
||||
@include 999-manual-tests.md
|
13
test/all.txt
13
test/all.txt
|
@ -1,13 +0,0 @@
|
|||
#include 01-mode.txt
|
||||
#include 02-general.txt
|
||||
#include 03-branch.txt
|
||||
#include 04-stack.txt
|
||||
#include 05-real.txt
|
||||
#include 06-string.txt
|
||||
#include 07-test.txt
|
||||
#include 08-store.txt
|
||||
#include 09-program.txt
|
||||
#include 10-complex.txt
|
||||
#include 11-base-entry.txt
|
||||
#include 12-time.txt
|
||||
#include 99-manual-tests.txt
|
45
test/mem_test.sh
Executable file
45
test/mem_test.sh
Executable file
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
|
||||
rpn=../build/rpn
|
||||
|
||||
FG_RED="\033[0;31m"
|
||||
FG_GREEN="\033[0;32m"
|
||||
COLOR_OFF="\033[0m"
|
||||
|
||||
failed=0
|
||||
|
||||
function checkmem {
|
||||
echo -n "${*}"
|
||||
valgrind ${rpn} "${*}" 2>&1 | grep "in use at exit: 0 bytes in 0 blocks" >/dev/null
|
||||
if [ ${?} -eq 0 ]; then
|
||||
echo -en " .. ${FG_GREEN}" && echo -n "ok" && echo -e "${COLOR_OFF}"
|
||||
else
|
||||
echo -en " .. ${FG_RED}" && echo -n "FAILED" && echo -e "${COLOR_OFF}"
|
||||
failed=1
|
||||
fi
|
||||
}
|
||||
|
||||
quick_tests=(
|
||||
"1.2 \"string\" 'ok' (2,3) << 9 nop >>" # base types inputs
|
||||
"nop help version uname history quit" # general commands
|
||||
"38 std 38 fix 38 sci 10 prec 2 default \"toward zero\" round" # modes
|
||||
"1 2 + 2 3 * / 4 - inv neg chs" # base operations on numbers
|
||||
"(1,2) (2,3) + (4,5) * (4,2) / (8,8) - inv neg chs" # base operations on complexes
|
||||
"\"ab\" \" cd\" +" # base operations on strings
|
||||
"2 3 ^ 2 ^ 2 pow" # usual operations on numbers 1
|
||||
"(2,3) (1,1) ^ 2 ^ 2 (2,3) ^" # usual operations on complexes 1
|
||||
"1 2 3 swap" # stack operations
|
||||
)
|
||||
|
||||
functional_tests=($(cat all.md | grep "^@include" | awk '{print $2}'))
|
||||
|
||||
# echo "Quick rpn memory checks"
|
||||
# for i in ${!quick_tests[@]}; do
|
||||
# checkmem "${quick_tests[$i]}"
|
||||
# done
|
||||
|
||||
echo "Functional rpn memory checks"
|
||||
for i in ${!functional_tests[@]}; do
|
||||
checkmem "\"${functional_tests[$i]}\" test"
|
||||
done
|
||||
exit ${failed}
|
Loading…
Add table
Reference in a new issue