diff --git a/src/lib/netlist/devices/net_lib.cpp b/src/lib/netlist/devices/net_lib.cpp index 30ddf3af84c..dd77be5a9a2 100644 --- a/src/lib/netlist/devices/net_lib.cpp +++ b/src/lib/netlist/devices/net_lib.cpp @@ -74,7 +74,7 @@ namespace netlist ENTRYX(7485, TTL_7485, "+A0,+A1,+A2,+A3,+B0,+B1,+B2,+B3,+LTIN,+EQIN,+GTIN") ENTRYX(7490, TTL_7490, "+A,+B,+R1,+R2,+R91,+R92") ENTRYX(7493, TTL_7493, "+CLKA,+CLKB,+R1,+R2") - ENTRYX(7497, TTL_7497, "+CLK,+STRB,+EN,+UNITY,+CLR,+B0,+B1,+B2,+B3,+B4,+B5") + ENTRYX(7497, TTL_7497, "+CLK,+STRBQ,+ENQ,+UNITYQ,+CLR,+B0,+B1,+B2,+B3,+B4,+B5") ENTRYX(74107, TTL_74107, "+CLK,+J,+K,+CLRQ") ENTRYX(74107A, TTL_74107A, "+CLK,+J,+K,+CLRQ") ENTRYX(74123, TTL_74123, "") diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h index 881cce03592..5a874aef3df 100644 --- a/src/lib/netlist/devices/nlid_system.h +++ b/src/lib/netlist/devices/nlid_system.h @@ -136,7 +136,9 @@ namespace netlist unsigned long total = 0; for (unsigned i=0; i(plib::pstol(pat[i])); + // FIXME: use pstonum_ne + //pati[i] = plib::pstonum(pat[i]); + pati[i] = plib::pstonum(pat[i]); total += pati[i]; } netlist_time ttotal = netlist_time::zero(); diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp index c3449d5b604..dbb9401425d 100644 --- a/src/lib/netlist/devices/nlid_truthtable.cpp +++ b/src/lib/netlist/devices/nlid_truthtable.cpp @@ -407,7 +407,8 @@ void truthtable_parser::parse(const std::vector &truthtable) val.set(j); else nl_assert_always(outs == "0", "Unknown value (not 0 or 1"); - netlist_time t = netlist_time::from_nsec(static_cast(plib::pstol(plib::trim(times[j])))); + // FIXME: error handling + netlist_time t = netlist_time::from_nsec(plib::pstonum(plib::trim(times[j]))); uint_least8_t k=0; while (m_timing_nt[k] != netlist_time::zero() && m_timing_nt[k] != t) k++; diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 5b132ebd554..a0eabcc7fbe 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -343,8 +343,8 @@ void netlist_t::start() auto p = setup().m_param_values.find(d->name() + ".HINT_NO_DEACTIVATE"); if (p != setup().m_param_values.end()) { - //FIXME: turn this into a proper function - auto v = plib::pstod(p->second);; + //FIXME: check for errors ... + double v = plib::pstonum(p->second);; if (std::abs(v - std::floor(v)) > 1e-6 ) log().fatal(MF_1_HND_VAL_NOT_SUPPORTED, p->second); d->set_hint_deactivate(v == 0.0); diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h index d2f4dc75511..20ddf5c71a3 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -26,7 +26,6 @@ * linear memory pool. This is based of the assumption that * due to enhanced locality there will be less cache misses. * Your mileage may vary. - * This will cause crashes on OSX and thus is ignored on OSX. * */ #define USE_MEMPOOL (0) diff --git a/src/lib/netlist/nl_parser.cpp b/src/lib/netlist/nl_parser.cpp index a6a805826ce..1ff6ef6c6b7 100644 --- a/src/lib/netlist/nl_parser.cpp +++ b/src/lib/netlist/nl_parser.cpp @@ -403,7 +403,6 @@ nl_double parser_t::eval_param(const token_t tok) int i; int f=0; nl_double ret; - pstring val; for (i=1; i<6;i++) if (tok.str() == macs[i]) @@ -416,9 +415,10 @@ nl_double parser_t::eval_param(const token_t tok) } else { - val = tok.str(); - if (!plib::pstod_ne(val, ret)) - error(plib::pfmt("Parameter value <{1}> not double \n")(val)); + bool err; + ret = plib::pstonum_ne(tok.str(), err); + if (err) + error(plib::pfmt("Parameter value <{1}> not double \n")(tok.str())); } return ret * facs[f]; diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp index cf89e4a8fae..28385d984cf 100644 --- a/src/lib/netlist/nl_setup.cpp +++ b/src/lib/netlist/nl_setup.cpp @@ -159,8 +159,9 @@ double setup_t::get_initial_param_val(const pstring &name, const double def) auto i = m_param_values.find(name); if (i != m_param_values.end()) { - double vald = 0; - if (!plib::pstod_ne(i->second, vald)) + bool err = false; + double vald = plib::pstonum_ne(i->second, err); + if (err) log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); return vald; } @@ -173,8 +174,9 @@ int setup_t::get_initial_param_val(const pstring &name, const int def) auto i = m_param_values.find(name); if (i != m_param_values.end()) { - long vald = 0; - if (!plib::pstod_ne(i->second, vald)) + bool err; + double vald = plib::pstonum_ne(i->second, err); + if (err) log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); if (vald - std::floor(vald) != 0.0) log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); @@ -872,7 +874,8 @@ nl_double setup_t::model_value(detail::model_map_t &map, const pstring &entity) } if (factor != NL_FCONST(1.0)) tmp = plib::left(tmp, tmp.size() - 1); - return plib::pstod(tmp) * factor; + // FIXME: check for errors + return plib::pstonum(tmp) * factor; } class logic_family_std_proxy_t : public logic_family_desc_t diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index e9e2de009c8..f2ef3522813 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -69,7 +69,9 @@ void pfunction::compile_postfix(const std::vector &inputs, if (rc.m_cmd != PUSH_INPUT) { rc.m_cmd = PUSH_CONST; - if (!plib::pstod_ne(cmd, rc.m_param)) + bool err; + rc.m_param = plib::pstonum_ne(cmd, err); + if (err) throw plib::pexception(plib::pfmt("nld_function: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); stk += 1; } diff --git a/src/lib/netlist/plib/poptions.cpp b/src/lib/netlist/plib/poptions.cpp index d576eff0bb2..c790d1f55af 100644 --- a/src/lib/netlist/plib/poptions.cpp +++ b/src/lib/netlist/plib/poptions.cpp @@ -46,49 +46,13 @@ namespace plib { return 0; } - int option_str_limit::parse(const pstring &argument) - { - if (plib::container::contains(m_limit, argument)) - { - m_val = argument; - return 0; - } - else - return 1; - } - int option_bool::parse(const pstring &argument) { + unused_var(argument); m_val = true; return 0; } - int option_double::parse(const pstring &argument) - { - try - { - m_val = plib::pstod(argument); - return 0; - } - catch (...) - { - return 1; - } - } - - int option_long::parse(const pstring &argument) - { - try - { - m_val = plib::pstol(argument); - return 0; - } - catch (...) - { - return 1; - } - } - int option_vec::parse(const pstring &argument) { bool err = false; @@ -233,7 +197,7 @@ namespace plib { if (opt->has_argument()) { line += "="; - option_str_limit *ol = dynamic_cast(opt); + option_str_limit_base *ol = dynamic_cast(opt); if (ol) { for (auto &v : ol->limit()) diff --git a/src/lib/netlist/plib/poptions.h b/src/lib/netlist/plib/poptions.h index 491ac0b4d91..f3be4b061dd 100644 --- a/src/lib/netlist/plib/poptions.h +++ b/src/lib/netlist/plib/poptions.h @@ -102,24 +102,52 @@ private: pstring m_val; }; -class option_str_limit : public option +class option_str_limit_base : public option { public: - option_str_limit(options &parent, pstring ashort, pstring along, pstring defval, pstring limit, pstring help) - : option(parent, ashort, along, help, true), m_val(defval) - , m_limit(plib::psplit(limit, ":")) + option_str_limit_base(options &parent, pstring ashort, pstring along, std::vector &&limit, pstring help) + : option(parent, ashort, along, help, true) + , m_limit(limit) + { + } + const std::vector &limit() const { return m_limit; } + +protected: + +private: + std::vector m_limit; +}; + + +template +class option_str_limit : public option_str_limit_base +{ +public: + option_str_limit(options &parent, pstring ashort, pstring along, const T &defval, std::vector &&limit, pstring help) + : option_str_limit_base(parent, ashort, along, std::move(limit), help), m_val(defval) { } - pstring operator ()() { return m_val; } - const std::vector &limit() { return m_limit; } + T operator ()() { return m_val; } + + pstring as_string() const { return limit()[m_val]; } protected: - virtual int parse(const pstring &argument) override; + virtual int parse(const pstring &argument) override + { + auto raw = plib::container::indexof(limit(), argument); + + if (raw != plib::container::npos) + { + m_val = static_cast(raw); + return 0; + } + else + return 1; + } private: - pstring m_val; - std::vector m_limit; + T m_val; }; class option_bool : public option @@ -138,36 +166,34 @@ private: bool m_val; }; -class option_double : public option +template +class option_num : public option { public: - option_double(options &parent, pstring ashort, pstring along, double defval, pstring help) - : option(parent, ashort, along, help, true), m_val(defval) + option_num(options &parent, pstring ashort, pstring along, T defval, + pstring help, + T minval = std::numeric_limits::min(), + T maxval = std::numeric_limits::max() ) + : option(parent, ashort, along, help, true) + , m_val(defval) + , m_min(minval) + , m_max(maxval) {} - double operator ()() { return m_val; } + T operator ()() { return m_val; } protected: - virtual int parse(const pstring &argument) override; + virtual int parse(const pstring &argument) override + { + bool err; + m_val = pstonum_ne(argument, err); + return (err ? 1 : (m_val < m_min || m_val > m_max)); + } private: - double m_val; -}; - -class option_long : public option -{ -public: - option_long(options &parent, pstring ashort, pstring along, long defval, pstring help) - : option(parent, ashort, along, help, true), m_val(defval) - {} - - long operator ()() { return m_val; } - -protected: - virtual int parse(const pstring &argument) override; - -private: - long m_val; + T m_val; + T m_min; + T m_max; }; class option_vec : public option @@ -207,6 +233,17 @@ private: static pstring split_paragraphs(pstring text, unsigned width, unsigned indent, unsigned firstline_indent); + template + T *getopt_type() + { + for (auto & optbase : m_opts ) + { + if (auto opt = dynamic_cast(optbase)) + return opt; + } + return nullptr; + } + option *getopt_short(pstring arg); option *getopt_long(pstring arg); diff --git a/src/lib/netlist/plib/pparser.cpp b/src/lib/netlist/plib/pparser.cpp index 298fa589fba..b18b3265440 100644 --- a/src/lib/netlist/plib/pparser.cpp +++ b/src/lib/netlist/plib/pparser.cpp @@ -122,6 +122,7 @@ pstring ptokenizer::get_identifier_or_number() return tok.str(); } +// FIXME: combine into template double ptokenizer::get_number_double() { token_t tok = get_token(); @@ -129,9 +130,9 @@ double ptokenizer::get_number_double() { error(pfmt("Expected a number, got <{1}>")(tok.str()) ); } - double ret = 0.0; - - if (!plib::pstod_ne(tok.str(), ret)) + bool err; + double ret = plib::pstonum_ne(tok.str(), err); + if (err) error(pfmt("Expected a number, got <{1}>")(tok.str()) ); return ret; } @@ -143,8 +144,9 @@ long ptokenizer::get_number_long() { error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); } - long ret = 0; - if (!plib::pstol_ne(tok.str(), ret)) + bool err; + long ret = plib::pstonum_ne(tok.str(), err); + if (err) error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); return ret; } @@ -326,7 +328,8 @@ double ppreprocessor::expr(const std::vector &sexpr, std::size_t &start else { tok=sexpr[start]; - val = plib::pstod(tok); + // FIXME: error handling + val = plib::pstonum(tok); start++; } while (start < sexpr.size()) diff --git a/src/lib/netlist/plib/pstring.h b/src/lib/netlist/plib/pstring.h index 67104a54213..677ce9e43b8 100644 --- a/src/lib/netlist/plib/pstring.h +++ b/src/lib/netlist/plib/pstring.h @@ -9,8 +9,10 @@ #include #include +#include #include #include +#include #include // ---------------------------------------------------------------------------------------- @@ -518,57 +520,72 @@ namespace plib return pwstring(std::to_wstring(v)); } -#if (PSTRING_USE_STD_STRING) - inline double pstod(const std::string &str, std::size_t *e = nullptr) - { - return std::stod(str, e); - } - - inline long pstol(const std::string &str, std::size_t *e = nullptr, int base = 10) - { - return std::stol(str, e, base); - } -#else - template - double pstod(const T &str, std::size_t *e = nullptr) - { - return std::stod(str.cpp_string(), e); - } + template + struct pstonum_helper; template - long pstol(const T &str, std::size_t *e = nullptr, int base = 10) + struct pstonum_helper::value + && std::is_signed::value>::type> { - return std::stol(str.cpp_string(), e, base); - } -#endif + template + long long operator()(const S &arg, std::size_t *idx) + { + return std::stoll(arg, idx); + } + }; - template - bool pstol_ne(const T &str, R &ret) + template + struct pstonum_helper::value + && !std::is_signed::value>::type> + { + template + unsigned long long operator()(const S &arg, std::size_t *idx) + { + return std::stoull(arg, idx); + } + }; + + template + struct pstonum_helper::value>::type> + { + template + long double operator()(const S &arg, std::size_t *idx) + { + return std::stold(arg, idx); + } + }; + + template + T pstonum(const S &arg) + { + decltype(arg.c_str()) cstr = arg.c_str(); + std::size_t idx(0); + auto ret = pstonum_helper()(cstr, &idx); + if (ret >= std::numeric_limits::lowest() && ret <= std::numeric_limits::max()) + //&& (ret == T(0) || std::abs(ret) >= std::numeric_limits::min() )) + { + if (cstr[idx] != 0) + throw std::invalid_argument(std::string("Continuation after numeric value ends: ") + cstr); + } + else + { + throw std::out_of_range(std::string("Out of range: ") + cstr); + } + return static_cast(ret); + } + + template + R pstonum_ne(const T &str, bool &err) noexcept { try { - std::size_t e = 0; - ret = pstol(str, &e); - return str.c_str()[e] == 0; + err = false; + return pstonum(str); } catch (...) { - return false; - } - } - - template - bool pstod_ne(const T &str, R &ret) - { - try - { - std::size_t e = 0; - ret = pstod(str, &e); - return str.c_str()[e] == 0; - } - catch (...) - { - return false; + err = true; + return R(0); } } diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp index 0d3a0ebca3f..92e0e6b3ab1 100644 --- a/src/lib/netlist/plib/putil.cpp +++ b/src/lib/netlist/plib/putil.cpp @@ -64,6 +64,36 @@ namespace plib return ret; } + std::vector psplit_r(const std::string &stri, + const std::string &token, + const std::size_t maxsplit) + { + std::string str(stri); + std::vector result; + std::size_t splits = 0; + + while(str.size()) + { + std::size_t index = str.rfind(token); + bool found = index!=std::string::npos; + if (found) + splits++; + if ((splits <= maxsplit || maxsplit == 0) && found) + { + result.push_back(str.substr(index+token.size())); + str = str.substr(0, index); + if (str.size()==0) + result.push_back(str); + } + else + { + result.push_back(str); + str = ""; + } + } + return result; + } + std::vector psplit(const pstring &str, const std::vector &onstrl) { pstring col = ""; diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 8d59c0357e2..914d9820560 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -16,6 +16,11 @@ namespace plib { + + // Avoid unused variable warnings + template + inline void unused_var(Ts&&...) {} + namespace util { const pstring buildpath(std::initializer_list list ); diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp index 4fcb4ebdc30..4395bd3bd17 100644 --- a/src/lib/netlist/prg/nltool.cpp +++ b/src/lib/netlist/prg/nltool.cpp @@ -23,7 +23,7 @@ public: tool_app_t() : plib::app(), opt_grp1(*this, "General options", "The following options apply to all commands."), - opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header:docheader", "run|convert|listdevices|static|header"), + opt_cmd (*this, "c", "cmd", 0, std::vector({"run","convert","listdevices","static","header","docheader"}), "run|convert|listdevices|static|header|docheader"), opt_file(*this, "f", "file", "-", "file to process (default is stdin)"), opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."), opt_rfolders(*this, "r", "rom", "where to look for data files"), @@ -40,7 +40,7 @@ public: opt_loadstate(*this,"", "loadstate", "", "load state from file and continue from there"), opt_savestate(*this,"", "savestate", "", "save state to file at end of run"), opt_grp4(*this, "Options for convert command", "These options are only used by the convert command."), - opt_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"), + opt_type(*this, "y", "type", 0, std::vector({"spice","eagle","rinf"}), "type of file to be converted: spice,eagle,rinf"), opt_ex1(*this, "nltool -c run -t 3.5 -f nl_examples/cdelay.c -n cap_delay", "Run netlist \"cap_delay\" from file nl_examples/cdelay.c for 3.5 seconds"), @@ -49,7 +49,7 @@ public: {} plib::option_group opt_grp1; - plib::option_str_limit opt_cmd; + plib::option_str_limit opt_cmd; plib::option_str opt_file; plib::option_vec opt_defines; plib::option_vec opt_rfolders; @@ -60,13 +60,13 @@ public: plib::option_group opt_grp2; plib::option_str opt_name; plib::option_group opt_grp3; - plib::option_double opt_ttr; + plib::option_num opt_ttr; plib::option_vec opt_logs; plib::option_str opt_inp; plib::option_str opt_loadstate; plib::option_str opt_savestate; plib::option_group opt_grp4; - plib::option_str_limit opt_type; + plib::option_str_limit opt_type; plib::option_example opt_ex1; plib::option_example opt_ex2; @@ -706,7 +706,7 @@ int tool_app_t::execute() try { - pstring cmd = opt_cmd(); + pstring cmd = opt_cmd.as_string(); if (cmd == "listdevices") listdevices(); else if (cmd == "run") @@ -734,19 +734,19 @@ int tool_app_t::execute() contents = ostrm.str(); pstring result; - if (opt_type() == "spice") + if (opt_type.as_string() == "spice") { nl_convert_spice_t c; c.convert(contents); result = c.result(); } - else if (opt_type() == "eagle") + else if (opt_type.as_string() == "eagle") { nl_convert_eagle_t c; c.convert(contents); result = c.result(); } - else if (opt_type() == "rinf") + else if (opt_type.as_string() == "rinf") { nl_convert_rinf_t c; c.convert(contents); diff --git a/src/lib/netlist/prg/nlwav.cpp b/src/lib/netlist/prg/nlwav.cpp index 23491e88349..a1f14692364 100644 --- a/src/lib/netlist/prg/nlwav.cpp +++ b/src/lib/netlist/prg/nlwav.cpp @@ -24,8 +24,8 @@ public: {} plib::option_str opt_inp; plib::option_str opt_out; - plib::option_double opt_amp; - plib::option_long opt_rate; + plib::option_num opt_amp; + plib::option_num opt_rate; plib::option_bool opt_verb; plib::option_bool opt_quiet; plib::option_bool opt_version; diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp index 2158d725694..ad62ba17c28 100644 --- a/src/lib/netlist/solver/nld_solver.cpp +++ b/src/lib/netlist/solver/nld_solver.cpp @@ -268,7 +268,7 @@ void NETLIB_NAME(solver)::post_start() // Override log statistics pstring p = plib::util::environment("NL_STATS", ""); if (p != "") - m_params.m_log_stats = plib::pstol(p); + m_params.m_log_stats = plib::pstonum(p); else m_params.m_log_stats = m_log_stats(); diff --git a/src/lib/netlist/tools/nl_convert.cpp b/src/lib/netlist/tools/nl_convert.cpp index aff7d0da81b..4488396a131 100644 --- a/src/lib/netlist/tools/nl_convert.cpp +++ b/src/lib/netlist/tools/nl_convert.cpp @@ -214,7 +214,7 @@ double nl_convert_base_t::get_sp_val(const pstring &sin) ++p; pstring val = plib::left(sin, p); pstring unit = sin.substr(p); - double ret = get_sp_unit(unit) * plib::pstod(val); + double ret = get_sp_unit(unit) * plib::pstonum(val); return ret; } @@ -304,11 +304,12 @@ void nl_convert_spice_t::process_line(const pstring &line) /* check for fourth terminal ... should be numeric net * including "0" or start with "N" (ltspice) */ - long nval = 0; pstring model; pstring pins ="CBE"; + bool err; + ATTR_UNUSED long nval = plib::pstonum_ne(tt[4], err); - if ((!plib::pstol_ne(tt[4], nval) || plib::startsWith(tt[4], "N")) && tt.size() > 5) + if ((err || plib::startsWith(tt[4], "N")) && tt.size() > 5) model = tt[5]; else model = tt[4]; @@ -492,7 +493,7 @@ void nl_convert_eagle_t::convert(const pstring &contents) else if (plib::ucase(sval) == "LOW") add_device("TTL_INPUT", name, 0); else - add_device("ANALOG_INPUT", name, plib::pstod(sval)); + add_device("ANALOG_INPUT", name, plib::pstonum(sval)); add_pin_alias(name, "1", "Q"); break; case 'D':