mirror of
https://github.com/louisrubet/rpn
synced 2025-02-11 20:48:30 +01:00
Merge pull request #239 from louisrubet/#218/enhanced_gcc_warnings
Add enhanced gcc warnings
This commit is contained in:
commit
db0e7f6ebb
15 changed files with 134 additions and 110 deletions
|
@ -46,16 +46,6 @@ set(RPN_LICENSE "LGPLv3")
|
||||||
set(RPN_LICENSE_FILE "${PROJECT_SOURCE_DIR}/LICENSE")
|
set(RPN_LICENSE_FILE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||||
set(RPN_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
|
set(RPN_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
|
||||||
|
|
||||||
# compiler options
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
|
||||||
message(STATUS "Compiler type GNU: ${CMAKE_CXX_COMPILER}")
|
|
||||||
# TODO still up to date?
|
|
||||||
set(BASE_COMPILER_OPTIONS "-std=c++17 -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 -s")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# custom linenoise-ng
|
# custom linenoise-ng
|
||||||
if(NOT EXISTS "${PROJECT_SOURCE_DIR}/linenoise-ng/.git")
|
if(NOT EXISTS "${PROJECT_SOURCE_DIR}/linenoise-ng/.git")
|
||||||
execute_process(command git submodule init ${PROJECT_SOURCE_DIR}/linenoise-ng)
|
execute_process(command git submodule init ${PROJECT_SOURCE_DIR}/linenoise-ng)
|
||||||
|
@ -73,32 +63,47 @@ endif()
|
||||||
# includes
|
# includes
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/linenoise-ng/include ${PROJECT_SOURCE_DIR}/mpreal)
|
include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/linenoise-ng/include ${PROJECT_SOURCE_DIR}/mpreal)
|
||||||
|
|
||||||
# build
|
# src
|
||||||
add_executable(
|
set(RPN_SRC_FILES
|
||||||
rpn
|
${PROJECT_SOURCE_DIR}/src/main.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/main.cc
|
${PROJECT_SOURCE_DIR}/src/object.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/object.cc
|
${PROJECT_SOURCE_DIR}/src/mpreal-out.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/mpreal-out.cc
|
${PROJECT_SOURCE_DIR}/src/program.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/program.cc
|
${PROJECT_SOURCE_DIR}/src/lexer.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/lexer.cc
|
${PROJECT_SOURCE_DIR}/src/input.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/input.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-branch.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-branch.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-complex.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-complex.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-general.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-general.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-logs.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-logs.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-program.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-program.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-real.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-real.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-stack.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-stack.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-store.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-store.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-string.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-string.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-test.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-test.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-test-framework.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-test-framework.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-time.cc
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-time.cc
|
${PROJECT_SOURCE_DIR}/src/rpn-trig.cc)
|
||||||
${PROJECT_SOURCE_DIR}/src/rpn-trig.cc
|
|
||||||
${PROJECT_SOURCE_DIR}/linenoise-ng/src/ConvertUTF.cpp
|
set(LINENOISE_NG_SRC_FILES
|
||||||
${PROJECT_SOURCE_DIR}/linenoise-ng/src/linenoise.cpp
|
${PROJECT_SOURCE_DIR}/linenoise-ng/src/ConvertUTF.cpp
|
||||||
${PROJECT_SOURCE_DIR}/linenoise-ng/src/wcwidth.cpp
|
${PROJECT_SOURCE_DIR}/linenoise-ng/src/linenoise.cpp
|
||||||
)
|
${PROJECT_SOURCE_DIR}/linenoise-ng/src/wcwidth.cpp)
|
||||||
|
|
||||||
|
# compiler options
|
||||||
|
set_source_files_properties(${RPN_SRC_FILES} COMPILE_FLAGS # some harder warnings
|
||||||
|
"-Wall -Wextra -pedantic -Wno-missing-field-initializers")
|
||||||
|
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
message(STATUS "Compiler type GNU: ${CMAKE_CXX_COMPILER}")
|
||||||
|
# TODO still up to date?
|
||||||
|
set(BASE_COMPILER_OPTIONS "-std=c++17 -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 -s")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(rpn ${RPN_SRC_FILES} ${LINENOISE_NG_SRC_FILES})
|
||||||
|
|
||||||
target_link_libraries(rpn mpfr)
|
target_link_libraries(rpn mpfr)
|
||||||
target_link_libraries(rpn gmp)
|
target_link_libraries(rpn gmp)
|
||||||
|
|
16
src/lexer.cc
16
src/lexer.cc
|
@ -2,8 +2,11 @@
|
||||||
|
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpedantic" // allow designated initializers
|
||||||
|
|
||||||
bool Lexer::Analyse(string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
|
bool Lexer::Analyse(string& entry, map<string, ReservedWord>& keywords, vector<SynElement>& elements,
|
||||||
vector<SynError>& errors) {
|
vector<SynError>& errors) {
|
||||||
size_t jump;
|
size_t jump;
|
||||||
for (size_t i = 0; i < entry.size(); i++) {
|
for (size_t i = 0; i < entry.size(); i++) {
|
||||||
if (isspace(entry[i])) continue;
|
if (isspace(entry[i])) continue;
|
||||||
|
@ -49,7 +52,7 @@ void Lexer::Trim(string& s) {
|
||||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::ParseString(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
|
bool Lexer::ParseString(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
|
||||||
vector<SynElement>& elements) {
|
vector<SynElement>& elements) {
|
||||||
// here we are sure that entry[0] is at least '"'
|
// here we are sure that entry[0] is at least '"'
|
||||||
for (size_t i = idx + 1; i < entry.size(); i++) {
|
for (size_t i = idx + 1; i < entry.size(); i++) {
|
||||||
|
@ -66,7 +69,7 @@ bool Lexer::ParseString(string& entry, size_t idx, size_t& next_idx, vector<SynE
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::ParseSymbol(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
|
bool Lexer::ParseSymbol(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
|
||||||
vector<SynElement>& elements) {
|
vector<SynElement>& elements) {
|
||||||
// here we are sure that entry[0] is at least '\''
|
// here we are sure that entry[0] is at least '\''
|
||||||
for (size_t i = idx + 1; i < entry.size(); i++) {
|
for (size_t i = idx + 1; i < entry.size(); i++) {
|
||||||
|
@ -81,7 +84,7 @@ bool Lexer::ParseSymbol(string& entry, size_t idx, size_t& next_idx, vector<SynE
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::ParseProgram(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
|
bool Lexer::ParseProgram(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
|
||||||
vector<SynElement>& elements) {
|
vector<SynElement>& elements) {
|
||||||
// here we are sure that entry is at least "<<"
|
// here we are sure that entry is at least "<<"
|
||||||
// find last ">>" or "»"
|
// find last ">>" or "»"
|
||||||
|
@ -153,7 +156,6 @@ int Lexer::GetBaseAt(string& entry, size_t& next_idx, bool& positive) {
|
||||||
|
|
||||||
bool Lexer::GetNUmberAt(string& entry, size_t idx, size_t& next_idx, int& base, mpreal** r, char delim) {
|
bool Lexer::GetNUmberAt(string& entry, size_t idx, size_t& next_idx, int& base, mpreal** r, char delim) {
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
int idxNumber = 0;
|
|
||||||
string token;
|
string token;
|
||||||
bool positive = true;
|
bool positive = true;
|
||||||
|
|
||||||
|
@ -193,7 +195,7 @@ bool Lexer::ParseNumber(string& entry, size_t idx, size_t& next_idx, vector<SynE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::ParseComplex(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors,
|
bool Lexer::ParseComplex(string& entry, size_t idx, size_t& next_idx, vector<SynError>& errors __attribute__((unused)),
|
||||||
vector<SynElement>& elements) {
|
vector<SynElement>& elements) {
|
||||||
mpreal* re = nullptr;
|
mpreal* re = nullptr;
|
||||||
mpreal* im = nullptr;
|
mpreal* im = nullptr;
|
||||||
|
@ -253,3 +255,5 @@ bool Lexer::ParseUnknown(string& entry, size_t idx, size_t& next_idx, vector<Syn
|
||||||
next_idx = token.size() + idx;
|
next_idx = token.size() + idx;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
14
src/main.cc
14
src/main.cc
|
@ -52,13 +52,16 @@ static void EnterInteractive() {
|
||||||
/// @param siginfo signal info, see POSIX sigaction
|
/// @param siginfo signal info, see POSIX sigaction
|
||||||
/// @param context see POSIX sigaction
|
/// @param context see POSIX sigaction
|
||||||
///
|
///
|
||||||
static void CtrlHandler(int sig, siginfo_t* siginfo, void* context) { ExitInteractive(); }
|
static void CtrlHandler(int sig __attribute__((unused)), siginfo_t* siginfo __attribute__((unused)),
|
||||||
|
void* context __attribute__((unused))) {
|
||||||
|
ExitInteractive();
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief setup signals handlers to stop with honours
|
/// @brief setup signals handlers to stop with honours
|
||||||
///
|
///
|
||||||
/// @param prog the prog to catch the signals to, must be checked not nullptr by user
|
/// @param prog the prog to catch the signals to, must be checked not nullptr by user
|
||||||
///
|
///
|
||||||
static void CatchSignals(program* prog) {
|
static void CatchSignals() {
|
||||||
struct sigaction act = {0};
|
struct sigaction act = {0};
|
||||||
|
|
||||||
act.sa_sigaction = &CtrlHandler;
|
act.sa_sigaction = &CtrlHandler;
|
||||||
|
@ -85,6 +88,9 @@ int main(int argc, char* argv[]) {
|
||||||
// init history
|
// init history
|
||||||
EnterInteractive();
|
EnterInteractive();
|
||||||
|
|
||||||
|
// user could stop prog with CtrlC
|
||||||
|
CatchSignals();
|
||||||
|
|
||||||
// entry loop
|
// entry loop
|
||||||
heap heap;
|
heap heap;
|
||||||
rpnstack stack;
|
rpnstack stack;
|
||||||
|
@ -95,8 +101,6 @@ int main(int argc, char* argv[]) {
|
||||||
string entry;
|
string entry;
|
||||||
switch (Input(entry, program::GetAutocompletionWords()).status) {
|
switch (Input(entry, program::GetAutocompletionWords()).status) {
|
||||||
case Input::InputStatus::kOk:
|
case Input::InputStatus::kOk:
|
||||||
// user could stop prog with CtrlC
|
|
||||||
CatchSignals(&prog);
|
|
||||||
// run it
|
// run it
|
||||||
if (prog.Parse(entry) == kOk && prog.Run() == kGoodbye)
|
if (prog.Parse(entry) == kOk && prog.Run() == kGoodbye)
|
||||||
go_on = false;
|
go_on = false;
|
||||||
|
@ -127,7 +131,7 @@ int main(int argc, char* argv[]) {
|
||||||
ret = prog.Parse(entry);
|
ret = prog.Parse(entry);
|
||||||
if (ret == kOk) {
|
if (ret == kOk) {
|
||||||
// user could stop prog with CtrlC
|
// user could stop prog with CtrlC
|
||||||
CatchSignals(&prog);
|
CatchSignals();
|
||||||
|
|
||||||
// run it
|
// run it
|
||||||
ret = prog.Run();
|
ret = prog.Run();
|
||||||
|
|
|
@ -184,7 +184,7 @@ ostream& _out_number(ostream& out, int base, const mpreal& value) {
|
||||||
if (digits > 0) {
|
if (digits > 0) {
|
||||||
out << '.';
|
out << '.';
|
||||||
|
|
||||||
int remaining = MIN(strlen(print_from) - nexp - 1, digits) + 1;
|
int remaining = MIN(static_cast<int>(strlen(print_from)) - nexp - 1, digits) + 1;
|
||||||
for (int i = nexp; i < remaining + nexp; i++) out << print_from[i];
|
for (int i = nexp; i < remaining + nexp; i++) out << print_from[i];
|
||||||
for (int i = 0; i < nexp + digits - len; i++) out << '0';
|
for (int i = 0; i < nexp + digits - len; i++) out << '0';
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,8 +172,8 @@ struct Symbol : Object {
|
||||||
virtual Object* Clone() { return new Symbol(value, auto_eval); }
|
virtual Object* Clone() { return new Symbol(value, auto_eval); }
|
||||||
virtual string Name() { return string("symbol"); }
|
virtual string Name() { return string("symbol"); }
|
||||||
virtual ostream& Show(ostream& out) { return out << "'" << value << "'"; }
|
virtual ostream& Show(ostream& out) { return out << "'" << value << "'"; }
|
||||||
bool auto_eval;
|
|
||||||
string value;
|
string value;
|
||||||
|
bool auto_eval;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Keyword : Object {
|
struct Keyword : Object {
|
||||||
|
@ -187,19 +187,19 @@ struct Keyword : Object {
|
||||||
|
|
||||||
struct Branch : Object {
|
struct Branch : Object {
|
||||||
Branch() : Object(kBranch) {}
|
Branch() : Object(kBranch) {}
|
||||||
explicit Branch(branch_fn_t fn__, const string& value__) : Object(kBranch) {
|
explicit Branch(branch_fn_t fn__, const string& value__) : Object(kBranch), fn(fn__), value(value__) {
|
||||||
fn = fn__;
|
|
||||||
arg1 = static_cast<size_t>(-1);
|
arg1 = static_cast<size_t>(-1);
|
||||||
arg2 = static_cast<size_t>(-1);
|
arg2 = static_cast<size_t>(-1);
|
||||||
arg3 = static_cast<size_t>(-1);
|
arg3 = static_cast<size_t>(-1);
|
||||||
arg_bool = 0;
|
arg_bool = 0;
|
||||||
value = value__;
|
|
||||||
}
|
}
|
||||||
explicit Branch(Branch& other) : Object(kBranch) {
|
explicit Branch(Branch& other) : Object(kBranch) {
|
||||||
fn = other.fn;
|
fn = other.fn;
|
||||||
arg1 = other.arg1;
|
arg1 = other.arg1;
|
||||||
arg2 = other.arg2;
|
arg2 = other.arg2;
|
||||||
arg3 = other.arg3;
|
arg3 = other.arg3;
|
||||||
|
first_index = other.first_index;
|
||||||
|
last_index = other.last_index;
|
||||||
arg_bool = other.arg_bool;
|
arg_bool = other.arg_bool;
|
||||||
value = other.value;
|
value = other.value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "program.h"
|
#include "program.h"
|
||||||
|
|
||||||
//< language reserved keywords (allowed types are kKeyword, kBranch or kUndef)
|
//< language reserved keywords (allowed types are kKeyword, kBranch or kUndef)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-function-type" // allow casting kBranch callbacks
|
||||||
vector<program::keyword_t> program::keywords_{
|
vector<program::keyword_t> program::keywords_{
|
||||||
// GENERAL
|
// GENERAL
|
||||||
{kUndef, "", nullptr, "\nGENERAL"},
|
{kUndef, "", nullptr, "\nGENERAL"},
|
||||||
|
@ -129,8 +131,7 @@ vector<program::keyword_t> program::keywords_{
|
||||||
{kBranch, "else", (program_fn_t)&program::RpnElse, "used with if"},
|
{kBranch, "else", (program_fn_t)&program::RpnElse, "used with if"},
|
||||||
{kBranch, "end", (program_fn_t)&program::RpnEnd, "used with various branch instructions"},
|
{kBranch, "end", (program_fn_t)&program::RpnEnd, "used with various branch instructions"},
|
||||||
{kBranch, "start", (program_fn_t)&program::RpnStart, "<start> <end> start <instructions> next|<step> step"},
|
{kBranch, "start", (program_fn_t)&program::RpnStart, "<start> <end> start <instructions> next|<step> step"},
|
||||||
{kBranch, "for", (program_fn_t)&program::RpnFor,
|
{kBranch, "for", (program_fn_t)&program::RpnFor, "<start> <end> for <variable> <instructions> next|<step> step"},
|
||||||
"<start> <end> for <variable> <instructions> next|<step> step"},
|
|
||||||
{kBranch, "next", (program_fn_t)&program::RpnNext, "used with start and for"},
|
{kBranch, "next", (program_fn_t)&program::RpnNext, "used with start and for"},
|
||||||
{kBranch, "step", (program_fn_t)&program::RpnStep, "used with start and for"},
|
{kBranch, "step", (program_fn_t)&program::RpnStep, "used with start and for"},
|
||||||
{kKeyword, "ift", &program::RpnIft, "similar to if-then-end, <test-instruction> <true-instruction> ift"},
|
{kKeyword, "ift", &program::RpnIft, "similar to if-then-end, <test-instruction> <true-instruction> ift"},
|
||||||
|
@ -202,6 +203,7 @@ vector<program::keyword_t> program::keywords_{
|
||||||
{kKeyword, "date", &program::RpnDate, "date in local format"},
|
{kKeyword, "date", &program::RpnDate, "date in local format"},
|
||||||
{kKeyword, "ticks", &program::RpnTicks, "system tick in µs"},
|
{kKeyword, "ticks", &program::RpnTicks, "system tick in µs"},
|
||||||
};
|
};
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
/// autocompletion vector for linenoise autocompletion
|
/// autocompletion vector for linenoise autocompletion
|
||||||
vector<string>& program::GetAutocompletionWords() {
|
vector<string>& program::GetAutocompletionWords() {
|
||||||
|
@ -219,7 +221,6 @@ vector<string>& program::GetAutocompletionWords() {
|
||||||
RetValue program::Run() {
|
RetValue program::Run() {
|
||||||
bool go_out = false;
|
bool go_out = false;
|
||||||
RetValue ret = kOk;
|
RetValue ret = kOk;
|
||||||
ObjectType type;
|
|
||||||
|
|
||||||
err_ = kOk;
|
err_ = kOk;
|
||||||
err_context_ = "";
|
err_context_ = "";
|
||||||
|
@ -598,7 +599,10 @@ RetValue program::Parse(string& entry) {
|
||||||
push_back(new Keyword(element.fn, element.value));
|
push_back(new Keyword(element.fn, element.value));
|
||||||
break;
|
break;
|
||||||
case kBranch:
|
case kBranch:
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-function-type" // allow casting kBranch callbacks
|
||||||
push_back(new Branch((branch_fn_t)element.fn, element.value));
|
push_back(new Branch((branch_fn_t)element.fn, element.value));
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ShowError(kUnknownError, "error creating program from entry");
|
ShowError(kUnknownError, "error creating program from entry");
|
||||||
|
@ -637,8 +641,10 @@ RetValue program::ShowError() {
|
||||||
case kInternalError:
|
case kInternalError:
|
||||||
case kDeadlyError:
|
case kDeadlyError:
|
||||||
ret = kDeadlyError;
|
ret = kDeadlyError;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = kOk;
|
ret = kOk;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -213,7 +213,7 @@ class program : public deque<Object*>, public Lexer {
|
||||||
// test-core
|
// test-core
|
||||||
void RpnTest();
|
void RpnTest();
|
||||||
void RunTestFile(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps,
|
void RunTestFile(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps,
|
||||||
int& total_steps_failed);
|
int& total_steps_failed);
|
||||||
|
|
||||||
// test
|
// test
|
||||||
void RpnSup(void);
|
void RpnSup(void);
|
||||||
|
@ -248,42 +248,42 @@ class program : public deque<Object*>, public Lexer {
|
||||||
// convenience macros for rpn_xx function
|
// convenience macros for rpn_xx function
|
||||||
// carefull : some of these macros modify program flow
|
// carefull : some of these macros modify program flow
|
||||||
|
|
||||||
#define ERROR_CONTEXT(err) \
|
#define ERROR_CONTEXT(err) \
|
||||||
do { \
|
do { \
|
||||||
err_ = (err); \
|
err_ = (err); \
|
||||||
err_context_ = __FUNCTION__; \
|
err_context_ = __FUNCTION__; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MIN_ARGUMENTS(num) \
|
#define MIN_ARGUMENTS(num) \
|
||||||
do { \
|
do { \
|
||||||
if ((num) >= 0 && stack_.size() < (num)) { \
|
if (stack_.size() < (num)) { \
|
||||||
ERROR_CONTEXT(kMissingOperand); \
|
ERROR_CONTEXT(kMissingOperand); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MIN_ARGUMENTS_RET(num, ret) \
|
#define MIN_ARGUMENTS_RET(num, ret) \
|
||||||
do { \
|
do { \
|
||||||
if ((num) >= 0 && stack_.size() < (num)) { \
|
if (stack_.size() < (num)) { \
|
||||||
ERROR_CONTEXT(kMissingOperand); \
|
ERROR_CONTEXT(kMissingOperand); \
|
||||||
return (ret); \
|
return (ret); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ARG_MUST_BE_OF_TYPE(num, type) \
|
#define ARG_MUST_BE_OF_TYPE(num, type) \
|
||||||
do { \
|
do { \
|
||||||
if ((num) >= 0 && stack_.at(num)->_type != (type)) { \
|
if (stack_.at(num)->_type != (type)) { \
|
||||||
ERROR_CONTEXT(kBadOperandType); \
|
ERROR_CONTEXT(kBadOperandType); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) \
|
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) \
|
||||||
do { \
|
do { \
|
||||||
if ((num) >= 0 && stack_.at(num)->_type != (type)) { \
|
if (stack_.at(num)->_type != (type)) { \
|
||||||
ERROR_CONTEXT(kBadOperandType); \
|
ERROR_CONTEXT(kBadOperandType); \
|
||||||
return (ret); \
|
return (ret); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif // SRC_PROGRAM_HPP_
|
#endif // SRC_PROGRAM_HPP_
|
||||||
|
|
|
@ -83,7 +83,7 @@ size_t program::RpnEnd(Branch& myobj) {
|
||||||
size_t ret = kStepOut;
|
size_t ret = kStepOut;
|
||||||
|
|
||||||
// arg1 = index of do+1 in case of do..unti..end
|
// arg1 = index of do+1 in case of do..unti..end
|
||||||
if (myobj.arg1 != -1) {
|
if (myobj.arg1 != kStepOut) {
|
||||||
// in a template do..until..end
|
// in a template do..until..end
|
||||||
MIN_ARGUMENTS_RET(1, kRtError);
|
MIN_ARGUMENTS_RET(1, kRtError);
|
||||||
ARG_MUST_BE_OF_TYPE_RET(0, kNumber, kRtError);
|
ARG_MUST_BE_OF_TYPE_RET(0, kNumber, kRtError);
|
||||||
|
@ -106,7 +106,7 @@ size_t program::RpnEnd(Branch& myobj) {
|
||||||
/// @return kStepOut next object to run in the current program is current + 1
|
/// @return kStepOut next object to run in the current program is current + 1
|
||||||
/// @return kRtError something went wrong with preprocess, abort branch
|
/// @return kRtError something went wrong with preprocess, abort branch
|
||||||
///
|
///
|
||||||
size_t program::RpnDo(Branch& myobj) {
|
size_t program::RpnDo(Branch& myobj __attribute__((unused))) {
|
||||||
// nothing
|
// nothing
|
||||||
return kStepOut;
|
return kStepOut;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ size_t program::RpnDo(Branch& myobj) {
|
||||||
/// @return kStepOut next object to run in the current program is current + 1
|
/// @return kStepOut next object to run in the current program is current + 1
|
||||||
/// @return kRtError something went wrong with preprocess, abort Branch
|
/// @return kRtError something went wrong with preprocess, abort Branch
|
||||||
///
|
///
|
||||||
size_t program::RpnUntil(Branch& myobj) {
|
size_t program::RpnUntil(Branch& myobj __attribute__((unused))) {
|
||||||
// nothing
|
// nothing
|
||||||
return kStepOut;
|
return kStepOut;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ void program::RpnIfte(void) {
|
||||||
/// @return kStepOut next object to run in the current program is current + 1
|
/// @return kStepOut next object to run in the current program is current + 1
|
||||||
/// @return kRtError something went wrong with preprocess, abort branch
|
/// @return kRtError something went wrong with preprocess, abort branch
|
||||||
///
|
///
|
||||||
size_t program::RpnWhile(Branch& myobj) {
|
size_t program::RpnWhile(Branch& myobj __attribute__((unused))) {
|
||||||
// nothing
|
// nothing
|
||||||
return kStepOut;
|
return kStepOut;
|
||||||
}
|
}
|
||||||
|
@ -298,8 +298,7 @@ size_t program::RpnNext(Branch& myobj) {
|
||||||
mpfr_add(myobj.first_index.mpfr_ptr(), myobj.first_index.mpfr_srcptr(), mpreal(1).mpfr_srcptr(), MPFR_RNDD);
|
mpfr_add(myobj.first_index.mpfr_ptr(), myobj.first_index.mpfr_srcptr(), mpreal(1).mpfr_srcptr(), MPFR_RNDD);
|
||||||
|
|
||||||
// for command: increment symbol too
|
// for command: increment symbol too
|
||||||
if (start_or_for->arg1 != -1) {
|
if (start_or_for->arg1 != kStepOut) {
|
||||||
Object* obj;
|
|
||||||
Symbol* var;
|
Symbol* var;
|
||||||
if (start_or_for->arg1 >= size() || at(start_or_for->arg1)->_type != kSymbol) {
|
if (start_or_for->arg1 >= size() || at(start_or_for->arg1)->_type != kSymbol) {
|
||||||
ERROR_CONTEXT(kMissingOperand);
|
ERROR_CONTEXT(kMissingOperand);
|
||||||
|
@ -318,7 +317,7 @@ size_t program::RpnNext(Branch& myobj) {
|
||||||
return kStepOut;
|
return kStepOut;
|
||||||
} else {
|
} else {
|
||||||
// for command: next instruction will be after symbol variable
|
// for command: next instruction will be after symbol variable
|
||||||
if (start_or_for->arg1 != -1) return start_or_for->arg1 + 1;
|
if (start_or_for->arg1 != kStepOut) return start_or_for->arg1 + 1;
|
||||||
// start command: next instruction will be after start command
|
// start command: next instruction will be after start command
|
||||||
else
|
else
|
||||||
return myobj.arg1 + 1;
|
return myobj.arg1 + 1;
|
||||||
|
@ -361,8 +360,7 @@ size_t program::RpnStep(Branch& myobj) {
|
||||||
// carefull: round toward minus infinity to avoid missing last boundary (because growing step)
|
// carefull: round toward minus infinity to avoid missing last boundary (because growing step)
|
||||||
mpfr_add(myobj.first_index.mpfr_ptr(), myobj.first_index.mpfr_srcptr(), step.mpfr_srcptr(), MPFR_RNDD);
|
mpfr_add(myobj.first_index.mpfr_ptr(), myobj.first_index.mpfr_srcptr(), step.mpfr_srcptr(), MPFR_RNDD);
|
||||||
|
|
||||||
if (start_or_for->arg1 != -1) {
|
if (start_or_for->arg1 != kStepOut) {
|
||||||
Object* obj;
|
|
||||||
Symbol* var;
|
Symbol* var;
|
||||||
|
|
||||||
// for command: increment symbol too
|
// for command: increment symbol too
|
||||||
|
@ -382,7 +380,7 @@ size_t program::RpnStep(Branch& myobj) {
|
||||||
ret = kStepOut;
|
ret = kStepOut;
|
||||||
} else {
|
} else {
|
||||||
// for command: next instruction will be after symbol variable
|
// for command: next instruction will be after symbol variable
|
||||||
if (start_or_for->arg1 != -1) ret = start_or_for->arg1 + 1;
|
if (start_or_for->arg1 != kStepOut) ret = start_or_for->arg1 + 1;
|
||||||
// start command: next instruction will be after start command
|
// start command: next instruction will be after start command
|
||||||
else
|
else
|
||||||
ret = myobj.arg1 + 1;
|
ret = myobj.arg1 + 1;
|
||||||
|
|
|
@ -54,7 +54,6 @@ void program::RpnHelp() {
|
||||||
cout << _syntax << endl;
|
cout << _syntax << endl;
|
||||||
|
|
||||||
// keywords
|
// keywords
|
||||||
unsigned int i = 0;
|
|
||||||
for (auto& kw : keywords_)
|
for (auto& kw : keywords_)
|
||||||
if (!kw.comment.empty()) {
|
if (!kw.comment.empty()) {
|
||||||
// titles in bold
|
// titles in bold
|
||||||
|
|
|
@ -82,10 +82,10 @@ void program::RpnEval(void) {
|
||||||
///
|
///
|
||||||
int program::RpnInprog(Branch& inprog_obj) {
|
int program::RpnInprog(Branch& inprog_obj) {
|
||||||
string context("->"); // for showing errors
|
string context("->"); // for showing errors
|
||||||
int count_symbols = 0;
|
size_t count_symbols = 0;
|
||||||
bool prog_found = false;
|
bool prog_found = false;
|
||||||
|
|
||||||
if (inprog_obj.arg1 == -1) {
|
if (inprog_obj.arg1 == kStepOut) {
|
||||||
ERROR_CONTEXT(kUnknownError);
|
ERROR_CONTEXT(kUnknownError);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ int program::RpnInprog(Branch& inprog_obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load variables
|
// load variables
|
||||||
for (unsigned int i = inprog_obj.arg1 + count_symbols; i > inprog_obj.arg1; i--) {
|
for (size_t i = inprog_obj.arg1 + count_symbols; i > inprog_obj.arg1; i--) {
|
||||||
local_heap_[reinterpret_cast<Symbol*>(at(i))->value] = stack_.at(0)->Clone();
|
local_heap_[reinterpret_cast<Symbol*>(at(i))->value] = stack_.at(0)->Clone();
|
||||||
stack_.pop();
|
stack_.pop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ void program::RpnDropn(void) {
|
||||||
MIN_ARGUMENTS(1);
|
MIN_ARGUMENTS(1);
|
||||||
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
||||||
|
|
||||||
int args = static_cast<int>(stack_.value<Number>(0).toLong());
|
size_t args = stack_.value<Number>(0).toULong();
|
||||||
MIN_ARGUMENTS(args + 1);
|
MIN_ARGUMENTS(args + 1);
|
||||||
stack_.erase(0, args + 1);
|
stack_.erase(0, args + 1);
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,15 @@ void program::RpnDupn(void) {
|
||||||
MIN_ARGUMENTS(1);
|
MIN_ARGUMENTS(1);
|
||||||
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
||||||
|
|
||||||
int args = static_cast<int>(stack_.value<Number>(0).toLong());
|
size_t args = stack_.value<Number>(0).toULong();
|
||||||
stack_.pop();
|
stack_.pop();
|
||||||
|
if (args == 0) {
|
||||||
|
ERROR_CONTEXT(kOutOfRange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MIN_ARGUMENTS(args);
|
MIN_ARGUMENTS(args);
|
||||||
for (int i = 0; i < args; i++) stack_.push_front(stack_.at(args - 1)->Clone());
|
for (size_t i = 0; i < args; i++) stack_.push_front(stack_.at(args - 1)->Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief dup2 keyword implementation
|
/// @brief dup2 keyword implementation
|
||||||
|
@ -74,7 +78,7 @@ void program::RpnPick(void) {
|
||||||
MIN_ARGUMENTS(1);
|
MIN_ARGUMENTS(1);
|
||||||
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
||||||
|
|
||||||
int to_pick = static_cast<int>(stack_.value<Number>(0).toLong());
|
size_t to_pick = static_cast<int>(stack_.value<Number>(0).toLong());
|
||||||
stack_.pop();
|
stack_.pop();
|
||||||
|
|
||||||
// treat stack_ depth errors
|
// treat stack_ depth errors
|
||||||
|
@ -105,9 +109,13 @@ void program::RpnRoll(void) {
|
||||||
MIN_ARGUMENTS(1);
|
MIN_ARGUMENTS(1);
|
||||||
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
||||||
|
|
||||||
int args = static_cast<int>(stack_.value<Number>(0).toLong());
|
size_t args = static_cast<int>(stack_.value<Number>(0).toLong());
|
||||||
stack_.pop();
|
stack_.pop();
|
||||||
MIN_ARGUMENTS(args);
|
MIN_ARGUMENTS(args);
|
||||||
|
if (args == 0) {
|
||||||
|
ERROR_CONTEXT(kOutOfRange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Object* tmp = stack_.at(args - 1);
|
Object* tmp = stack_.at(args - 1);
|
||||||
stack_.erase(args - 1, 1, false);
|
stack_.erase(args - 1, 1, false);
|
||||||
|
@ -120,9 +128,13 @@ void program::RpnRolld(void) {
|
||||||
MIN_ARGUMENTS(2);
|
MIN_ARGUMENTS(2);
|
||||||
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
||||||
|
|
||||||
int args = static_cast<int>(stack_.value<Number>(0).toLong());
|
size_t args = static_cast<int>(stack_.value<Number>(0).toLong());
|
||||||
stack_.pop();
|
stack_.pop();
|
||||||
MIN_ARGUMENTS(args);
|
MIN_ARGUMENTS(args);
|
||||||
|
if (args == 0) {
|
||||||
|
ERROR_CONTEXT(kOutOfRange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Object* tmp = stack_.at(0);
|
Object* tmp = stack_.at(0);
|
||||||
stack_.erase(0, 1, false);
|
stack_.erase(0, 1, false);
|
||||||
|
|
|
@ -193,7 +193,6 @@ void program::RpnPurge(void) {
|
||||||
/// @brief vars keyword implementation
|
/// @brief vars keyword implementation
|
||||||
///
|
///
|
||||||
void program::RpnVars(void) {
|
void program::RpnVars(void) {
|
||||||
Object* obj;
|
|
||||||
program* parent = parent_;
|
program* parent = parent_;
|
||||||
string name;
|
string name;
|
||||||
int index = 1;
|
int index = 1;
|
||||||
|
@ -214,7 +213,7 @@ void program::RpnVars(void) {
|
||||||
while (parent != nullptr) {
|
while (parent != nullptr) {
|
||||||
for (auto i : parent->local_heap_) {
|
for (auto i : parent->local_heap_) {
|
||||||
cout << "parent var " << index++ << ": name '" << i.first << "', type " << i.second->Name() << ", value ";
|
cout << "parent var " << index++ << ": name '" << i.first << "', type " << i.second->Name() << ", value ";
|
||||||
obj->Show(cout) << endl;
|
i.second->Show(cout) << endl;
|
||||||
}
|
}
|
||||||
parent = parent->parent_;
|
parent = parent->parent_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,9 +117,9 @@ void program::RunTestFile(string test_filename, int& total_tests, int& total_tes
|
||||||
rpnstack stk;
|
rpnstack stk;
|
||||||
heap hp;
|
heap hp;
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
bool is_first_step;
|
bool is_first_step = true;
|
||||||
bool is_test_error_shown;
|
bool is_test_error_shown = false;
|
||||||
int last_err;
|
int last_err = static_cast<int>(kOk);
|
||||||
stringstream cerr_buffer;
|
stringstream cerr_buffer;
|
||||||
streambuf* cerr_old_buffer;
|
streambuf* cerr_old_buffer;
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ void program::RpnTestXor(void) {
|
||||||
MIN_ARGUMENTS(2);
|
MIN_ARGUMENTS(2);
|
||||||
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
ARG_MUST_BE_OF_TYPE(0, kNumber);
|
||||||
ARG_MUST_BE_OF_TYPE(1, kNumber);
|
ARG_MUST_BE_OF_TYPE(1, kNumber);
|
||||||
if (stack_.value<Number>(0) != 0 ^ stack_.value<Number>(1) != 0)
|
if ((stack_.value<Number>(0) != 0) ^ (stack_.value<Number>(1) != 0))
|
||||||
stack_.push(new Number(1));
|
stack_.push(new Number(1));
|
||||||
else
|
else
|
||||||
stack_.push(new Number(0));
|
stack_.push(new Number(0));
|
||||||
|
|
|
@ -44,9 +44,6 @@ void program::RpnDate() {
|
||||||
// date format = (M)M.DDYYYY
|
// date format = (M)M.DDYYYY
|
||||||
date = static_cast<double>(tm->tm_mon + 1) * 1000000.0 + static_cast<double>(tm->tm_mday) * 10000.0 +
|
date = static_cast<double>(tm->tm_mon + 1) * 1000000.0 + static_cast<double>(tm->tm_mday) * 10000.0 +
|
||||||
static_cast<double>(tm->tm_year + 1900);
|
static_cast<double>(tm->tm_year + 1900);
|
||||||
|
|
||||||
// push it
|
|
||||||
Number* num;
|
|
||||||
// division after push for real precision
|
// division after push for real precision
|
||||||
stack_.push(new Number(date));
|
stack_.push(new Number(date));
|
||||||
stack_.value<Number>(0) /= 1000000.0;
|
stack_.value<Number>(0) /= 1000000.0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue