Improve type safety on string->numeric conversions. (nw)

Also fixed an issue with 7497.

./nltool -t 5 -f src/mame/machine/nl_tp1983.cpp -v

now runs again.
This commit is contained in:
couriersud 2019-01-10 00:30:51 +01:00
parent f8d5b95e37
commit 4213a396d8
18 changed files with 212 additions and 148 deletions

View File

@ -74,7 +74,7 @@ namespace netlist
ENTRYX(7485, TTL_7485, "+A0,+A1,+A2,+A3,+B0,+B1,+B2,+B3,+LTIN,+EQIN,+GTIN") 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(7490, TTL_7490, "+A,+B,+R1,+R2,+R91,+R92")
ENTRYX(7493, TTL_7493, "+CLKA,+CLKB,+R1,+R2") 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(74107, TTL_74107, "+CLK,+J,+K,+CLRQ")
ENTRYX(74107A, TTL_74107A, "+CLK,+J,+K,+CLRQ") ENTRYX(74107A, TTL_74107A, "+CLK,+J,+K,+CLRQ")
ENTRYX(74123, TTL_74123, "") ENTRYX(74123, TTL_74123, "")

View File

@ -136,7 +136,9 @@ namespace netlist
unsigned long total = 0; unsigned long total = 0;
for (unsigned i=0; i<m_size; i++) for (unsigned i=0; i<m_size; i++)
{ {
pati[i] = static_cast<unsigned long>(plib::pstol(pat[i])); // FIXME: use pstonum_ne
//pati[i] = plib::pstonum<decltype(pati[i])>(pat[i]);
pati[i] = plib::pstonum<unsigned long>(pat[i]);
total += pati[i]; total += pati[i];
} }
netlist_time ttotal = netlist_time::zero(); netlist_time ttotal = netlist_time::zero();

View File

@ -407,7 +407,8 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable)
val.set(j); val.set(j);
else else
nl_assert_always(outs == "0", "Unknown value (not 0 or 1"); nl_assert_always(outs == "0", "Unknown value (not 0 or 1");
netlist_time t = netlist_time::from_nsec(static_cast<unsigned long>(plib::pstol(plib::trim(times[j])))); // FIXME: error handling
netlist_time t = netlist_time::from_nsec(plib::pstonum<unsigned long>(plib::trim(times[j])));
uint_least8_t k=0; uint_least8_t k=0;
while (m_timing_nt[k] != netlist_time::zero() && m_timing_nt[k] != t) while (m_timing_nt[k] != netlist_time::zero() && m_timing_nt[k] != t)
k++; k++;

View File

@ -343,8 +343,8 @@ void netlist_t::start()
auto p = setup().m_param_values.find(d->name() + ".HINT_NO_DEACTIVATE"); auto p = setup().m_param_values.find(d->name() + ".HINT_NO_DEACTIVATE");
if (p != setup().m_param_values.end()) if (p != setup().m_param_values.end())
{ {
//FIXME: turn this into a proper function //FIXME: check for errors ...
auto v = plib::pstod(p->second);; double v = plib::pstonum<double>(p->second);;
if (std::abs(v - std::floor(v)) > 1e-6 ) if (std::abs(v - std::floor(v)) > 1e-6 )
log().fatal(MF_1_HND_VAL_NOT_SUPPORTED, p->second); log().fatal(MF_1_HND_VAL_NOT_SUPPORTED, p->second);
d->set_hint_deactivate(v == 0.0); d->set_hint_deactivate(v == 0.0);

View File

@ -26,7 +26,6 @@
* linear memory pool. This is based of the assumption that * linear memory pool. This is based of the assumption that
* due to enhanced locality there will be less cache misses. * due to enhanced locality there will be less cache misses.
* Your mileage may vary. * Your mileage may vary.
* This will cause crashes on OSX and thus is ignored on OSX.
* *
*/ */
#define USE_MEMPOOL (0) #define USE_MEMPOOL (0)

View File

@ -403,7 +403,6 @@ nl_double parser_t::eval_param(const token_t tok)
int i; int i;
int f=0; int f=0;
nl_double ret; nl_double ret;
pstring val;
for (i=1; i<6;i++) for (i=1; i<6;i++)
if (tok.str() == macs[i]) if (tok.str() == macs[i])
@ -416,9 +415,10 @@ nl_double parser_t::eval_param(const token_t tok)
} }
else else
{ {
val = tok.str(); bool err;
if (!plib::pstod_ne(val, ret)) ret = plib::pstonum_ne<nl_double>(tok.str(), err);
error(plib::pfmt("Parameter value <{1}> not double \n")(val)); if (err)
error(plib::pfmt("Parameter value <{1}> not double \n")(tok.str()));
} }
return ret * facs[f]; return ret * facs[f];

View File

@ -159,8 +159,9 @@ double setup_t::get_initial_param_val(const pstring &name, const double def)
auto i = m_param_values.find(name); auto i = m_param_values.find(name);
if (i != m_param_values.end()) if (i != m_param_values.end())
{ {
double vald = 0; bool err = false;
if (!plib::pstod_ne(i->second, vald)) double vald = plib::pstonum_ne<double>(i->second, err);
if (err)
log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second);
return vald; 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); auto i = m_param_values.find(name);
if (i != m_param_values.end()) if (i != m_param_values.end())
{ {
long vald = 0; bool err;
if (!plib::pstod_ne(i->second, vald)) double vald = plib::pstonum_ne<double>(i->second, err);
if (err)
log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second);
if (vald - std::floor(vald) != 0.0) if (vald - std::floor(vald) != 0.0)
log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); 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)) if (factor != NL_FCONST(1.0))
tmp = plib::left(tmp, tmp.size() - 1); tmp = plib::left(tmp, tmp.size() - 1);
return plib::pstod(tmp) * factor; // FIXME: check for errors
return plib::pstonum<nl_double>(tmp) * factor;
} }
class logic_family_std_proxy_t : public logic_family_desc_t class logic_family_std_proxy_t : public logic_family_desc_t

View File

@ -69,7 +69,9 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs,
if (rc.m_cmd != PUSH_INPUT) if (rc.m_cmd != PUSH_INPUT)
{ {
rc.m_cmd = PUSH_CONST; rc.m_cmd = PUSH_CONST;
if (!plib::pstod_ne(cmd, rc.m_param)) bool err;
rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err);
if (err)
throw plib::pexception(plib::pfmt("nld_function: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); throw plib::pexception(plib::pfmt("nld_function: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
stk += 1; stk += 1;
} }

View File

@ -46,49 +46,13 @@ namespace plib {
return 0; 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) int option_bool::parse(const pstring &argument)
{ {
unused_var(argument);
m_val = true; m_val = true;
return 0; 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) int option_vec::parse(const pstring &argument)
{ {
bool err = false; bool err = false;
@ -233,7 +197,7 @@ namespace plib {
if (opt->has_argument()) if (opt->has_argument())
{ {
line += "="; line += "=";
option_str_limit *ol = dynamic_cast<option_str_limit *>(opt); option_str_limit_base *ol = dynamic_cast<option_str_limit_base *>(opt);
if (ol) if (ol)
{ {
for (auto &v : ol->limit()) for (auto &v : ol->limit())

View File

@ -102,24 +102,52 @@ private:
pstring m_val; pstring m_val;
}; };
class option_str_limit : public option class option_str_limit_base : public option
{ {
public: public:
option_str_limit(options &parent, pstring ashort, pstring along, pstring defval, pstring limit, pstring help) option_str_limit_base(options &parent, pstring ashort, pstring along, std::vector<pstring> &&limit, pstring help)
: option(parent, ashort, along, help, true), m_val(defval) : option(parent, ashort, along, help, true)
, m_limit(plib::psplit(limit, ":")) , m_limit(limit)
{
}
const std::vector<pstring> &limit() const { return m_limit; }
protected:
private:
std::vector<pstring> m_limit;
};
template <typename T>
class option_str_limit : public option_str_limit_base
{
public:
option_str_limit(options &parent, pstring ashort, pstring along, const T &defval, std::vector<pstring> &&limit, pstring help)
: option_str_limit_base(parent, ashort, along, std::move(limit), help), m_val(defval)
{ {
} }
pstring operator ()() { return m_val; } T operator ()() { return m_val; }
const std::vector<pstring> &limit() { return m_limit; }
pstring as_string() const { return limit()[m_val]; }
protected: 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<T>(raw);
return 0;
}
else
return 1;
}
private: private:
pstring m_val; T m_val;
std::vector<pstring> m_limit;
}; };
class option_bool : public option class option_bool : public option
@ -138,36 +166,34 @@ private:
bool m_val; bool m_val;
}; };
class option_double : public option template <typename T>
class option_num : public option
{ {
public: public:
option_double(options &parent, pstring ashort, pstring along, double defval, pstring help) option_num(options &parent, pstring ashort, pstring along, T defval,
: option(parent, ashort, along, help, true), m_val(defval) pstring help,
T minval = std::numeric_limits<T>::min(),
T maxval = std::numeric_limits<T>::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: protected:
virtual int parse(const pstring &argument) override; virtual int parse(const pstring &argument) override
{
bool err;
m_val = pstonum_ne<T>(argument, err);
return (err ? 1 : (m_val < m_min || m_val > m_max));
}
private: private:
double m_val; T m_val;
}; T m_min;
T m_max;
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;
}; };
class option_vec : public option class option_vec : public option
@ -207,6 +233,17 @@ private:
static pstring split_paragraphs(pstring text, unsigned width, unsigned indent, static pstring split_paragraphs(pstring text, unsigned width, unsigned indent,
unsigned firstline_indent); unsigned firstline_indent);
template <typename T>
T *getopt_type()
{
for (auto & optbase : m_opts )
{
if (auto opt = dynamic_cast<T *>(optbase))
return opt;
}
return nullptr;
}
option *getopt_short(pstring arg); option *getopt_short(pstring arg);
option *getopt_long(pstring arg); option *getopt_long(pstring arg);

View File

@ -122,6 +122,7 @@ pstring ptokenizer::get_identifier_or_number()
return tok.str(); return tok.str();
} }
// FIXME: combine into template
double ptokenizer::get_number_double() double ptokenizer::get_number_double()
{ {
token_t tok = get_token(); token_t tok = get_token();
@ -129,9 +130,9 @@ double ptokenizer::get_number_double()
{ {
error(pfmt("Expected a number, got <{1}>")(tok.str()) ); error(pfmt("Expected a number, got <{1}>")(tok.str()) );
} }
double ret = 0.0; bool err;
double ret = plib::pstonum_ne<double>(tok.str(), err);
if (!plib::pstod_ne(tok.str(), ret)) if (err)
error(pfmt("Expected a number, got <{1}>")(tok.str()) ); error(pfmt("Expected a number, got <{1}>")(tok.str()) );
return ret; return ret;
} }
@ -143,8 +144,9 @@ long ptokenizer::get_number_long()
{ {
error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); error(pfmt("Expected a long int, got <{1}>")(tok.str()) );
} }
long ret = 0; bool err;
if (!plib::pstol_ne(tok.str(), ret)) long ret = plib::pstonum_ne<long>(tok.str(), err);
if (err)
error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); error(pfmt("Expected a long int, got <{1}>")(tok.str()) );
return ret; return ret;
} }
@ -326,7 +328,8 @@ double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start
else else
{ {
tok=sexpr[start]; tok=sexpr[start];
val = plib::pstod(tok); // FIXME: error handling
val = plib::pstonum<decltype(val)>(tok);
start++; start++;
} }
while (start < sexpr.size()) while (start < sexpr.size())

View File

@ -9,8 +9,10 @@
#include <cstring> #include <cstring>
#include <exception> #include <exception>
#include <stdexcept>
#include <iterator> #include <iterator>
#include <string> #include <string>
#include <limits>
#include <type_traits> #include <type_traits>
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
@ -518,57 +520,72 @@ namespace plib
return pwstring(std::to_wstring(v)); return pwstring(std::to_wstring(v));
} }
#if (PSTRING_USE_STD_STRING) template <typename T, typename E = void>
inline double pstod(const std::string &str, std::size_t *e = nullptr) struct pstonum_helper;
{
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<typename T>
double pstod(const T &str, std::size_t *e = nullptr)
{
return std::stod(str.cpp_string(), e);
}
template<typename T> template<typename T>
long pstol(const T &str, std::size_t *e = nullptr, int base = 10) struct pstonum_helper<T, typename std::enable_if<std::is_integral<T>::value
&& std::is_signed<T>::value>::type>
{ {
return std::stol(str.cpp_string(), e, base); template <typename S>
} long long operator()(const S &arg, std::size_t *idx)
#endif {
return std::stoll(arg, idx);
}
};
template<typename T, typename R> template<typename T>
bool pstol_ne(const T &str, R &ret) struct pstonum_helper<T, typename std::enable_if<std::is_integral<T>::value
&& !std::is_signed<T>::value>::type>
{
template <typename S>
unsigned long long operator()(const S &arg, std::size_t *idx)
{
return std::stoull(arg, idx);
}
};
template<typename T>
struct pstonum_helper<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
template <typename S>
long double operator()(const S &arg, std::size_t *idx)
{
return std::stold(arg, idx);
}
};
template<typename T, typename S>
T pstonum(const S &arg)
{
decltype(arg.c_str()) cstr = arg.c_str();
std::size_t idx(0);
auto ret = pstonum_helper<T>()(cstr, &idx);
if (ret >= std::numeric_limits<T>::lowest() && ret <= std::numeric_limits<T>::max())
//&& (ret == T(0) || std::abs(ret) >= std::numeric_limits<T>::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<T>(ret);
}
template<typename R, typename T>
R pstonum_ne(const T &str, bool &err) noexcept
{ {
try try
{ {
std::size_t e = 0; err = false;
ret = pstol(str, &e); return pstonum<R>(str);
return str.c_str()[e] == 0;
} }
catch (...) catch (...)
{ {
return false; err = true;
} return R(0);
}
template<typename T, typename R>
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;
} }
} }

View File

@ -64,6 +64,36 @@ namespace plib
return ret; return ret;
} }
std::vector<std::string> psplit_r(const std::string &stri,
const std::string &token,
const std::size_t maxsplit)
{
std::string str(stri);
std::vector<std::string> 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<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl) std::vector<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl)
{ {
pstring col = ""; pstring col = "";

View File

@ -16,6 +16,11 @@
namespace plib namespace plib
{ {
// Avoid unused variable warnings
template<typename... Ts>
inline void unused_var(Ts&&...) {}
namespace util namespace util
{ {
const pstring buildpath(std::initializer_list<pstring> list ); const pstring buildpath(std::initializer_list<pstring> list );

View File

@ -23,7 +23,7 @@ public:
tool_app_t() : tool_app_t() :
plib::app(), plib::app(),
opt_grp1(*this, "General options", "The following options apply to all commands."), 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<pstring>({"run","convert","listdevices","static","header","docheader"}), "run|convert|listdevices|static|header|docheader"),
opt_file(*this, "f", "file", "-", "file to process (default is stdin)"), 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_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"), 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_loadstate(*this,"", "loadstate", "", "load state from file and continue from there"),
opt_savestate(*this,"", "savestate", "", "save state to file at end of run"), 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_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<pstring>({"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", 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"), "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_group opt_grp1;
plib::option_str_limit opt_cmd; plib::option_str_limit<unsigned> opt_cmd;
plib::option_str opt_file; plib::option_str opt_file;
plib::option_vec opt_defines; plib::option_vec opt_defines;
plib::option_vec opt_rfolders; plib::option_vec opt_rfolders;
@ -60,13 +60,13 @@ public:
plib::option_group opt_grp2; plib::option_group opt_grp2;
plib::option_str opt_name; plib::option_str opt_name;
plib::option_group opt_grp3; plib::option_group opt_grp3;
plib::option_double opt_ttr; plib::option_num<double> opt_ttr;
plib::option_vec opt_logs; plib::option_vec opt_logs;
plib::option_str opt_inp; plib::option_str opt_inp;
plib::option_str opt_loadstate; plib::option_str opt_loadstate;
plib::option_str opt_savestate; plib::option_str opt_savestate;
plib::option_group opt_grp4; plib::option_group opt_grp4;
plib::option_str_limit opt_type; plib::option_str_limit<unsigned> opt_type;
plib::option_example opt_ex1; plib::option_example opt_ex1;
plib::option_example opt_ex2; plib::option_example opt_ex2;
@ -706,7 +706,7 @@ int tool_app_t::execute()
try try
{ {
pstring cmd = opt_cmd(); pstring cmd = opt_cmd.as_string();
if (cmd == "listdevices") if (cmd == "listdevices")
listdevices(); listdevices();
else if (cmd == "run") else if (cmd == "run")
@ -734,19 +734,19 @@ int tool_app_t::execute()
contents = ostrm.str(); contents = ostrm.str();
pstring result; pstring result;
if (opt_type() == "spice") if (opt_type.as_string() == "spice")
{ {
nl_convert_spice_t c; nl_convert_spice_t c;
c.convert(contents); c.convert(contents);
result = c.result(); result = c.result();
} }
else if (opt_type() == "eagle") else if (opt_type.as_string() == "eagle")
{ {
nl_convert_eagle_t c; nl_convert_eagle_t c;
c.convert(contents); c.convert(contents);
result = c.result(); result = c.result();
} }
else if (opt_type() == "rinf") else if (opt_type.as_string() == "rinf")
{ {
nl_convert_rinf_t c; nl_convert_rinf_t c;
c.convert(contents); c.convert(contents);

View File

@ -24,8 +24,8 @@ public:
{} {}
plib::option_str opt_inp; plib::option_str opt_inp;
plib::option_str opt_out; plib::option_str opt_out;
plib::option_double opt_amp; plib::option_num<double> opt_amp;
plib::option_long opt_rate; plib::option_num<long> opt_rate;
plib::option_bool opt_verb; plib::option_bool opt_verb;
plib::option_bool opt_quiet; plib::option_bool opt_quiet;
plib::option_bool opt_version; plib::option_bool opt_version;

View File

@ -268,7 +268,7 @@ void NETLIB_NAME(solver)::post_start()
// Override log statistics // Override log statistics
pstring p = plib::util::environment("NL_STATS", ""); pstring p = plib::util::environment("NL_STATS", "");
if (p != "") if (p != "")
m_params.m_log_stats = plib::pstol(p); m_params.m_log_stats = plib::pstonum<decltype(m_params.m_log_stats)>(p);
else else
m_params.m_log_stats = m_log_stats(); m_params.m_log_stats = m_log_stats();

View File

@ -214,7 +214,7 @@ double nl_convert_base_t::get_sp_val(const pstring &sin)
++p; ++p;
pstring val = plib::left(sin, p); pstring val = plib::left(sin, p);
pstring unit = sin.substr(p); pstring unit = sin.substr(p);
double ret = get_sp_unit(unit) * plib::pstod(val); double ret = get_sp_unit(unit) * plib::pstonum<double>(val);
return ret; return ret;
} }
@ -304,11 +304,12 @@ void nl_convert_spice_t::process_line(const pstring &line)
/* check for fourth terminal ... should be numeric net /* check for fourth terminal ... should be numeric net
* including "0" or start with "N" (ltspice) * including "0" or start with "N" (ltspice)
*/ */
long nval = 0;
pstring model; pstring model;
pstring pins ="CBE"; pstring pins ="CBE";
bool err;
ATTR_UNUSED long nval = plib::pstonum_ne<long>(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]; model = tt[5];
else else
model = tt[4]; model = tt[4];
@ -492,7 +493,7 @@ void nl_convert_eagle_t::convert(const pstring &contents)
else if (plib::ucase(sval) == "LOW") else if (plib::ucase(sval) == "LOW")
add_device("TTL_INPUT", name, 0); add_device("TTL_INPUT", name, 0);
else else
add_device("ANALOG_INPUT", name, plib::pstod(sval)); add_device("ANALOG_INPUT", name, plib::pstonum<double>(sval));
add_pin_alias(name, "1", "Q"); add_pin_alias(name, "1", "Q");
break; break;
case 'D': case 'D':