diff options
author | 2017-01-22 23:36:54 +0100 | |
---|---|---|
committer | 2017-01-25 22:17:46 +0100 | |
commit | 093bda019317a5a66699b35f8b25ab73802f1f1c (patch) | |
tree | b0e35b6f83d8cba9f7d69eda8c857cf799f1bfc1 /src/lib/netlist | |
parent | 624463dc3457e2719af007a6afee3da107af4a94 (diff) |
Added infix notation parsing to the function parser. (nw)
Diffstat (limited to 'src/lib/netlist')
-rw-r--r-- | src/lib/netlist/devices/nlid_system.h | 2 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfunction.cpp | 110 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfunction.h | 22 | ||||
-rw-r--r-- | src/lib/netlist/plib/pstring.cpp | 16 | ||||
-rw-r--r-- | src/lib/netlist/plib/pstring.h | 29 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.cpp | 2 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.h | 2 | ||||
-rw-r--r-- | src/lib/netlist/prg/nltool.cpp | 1 |
8 files changed, 153 insertions, 31 deletions
diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h index f2d893c7d28..5c29d40fd94 100644 --- a/src/lib/netlist/devices/nlid_system.h +++ b/src/lib/netlist/devices/nlid_system.h @@ -323,7 +323,7 @@ namespace netlist inps.push_back(n); m_vals.push_back(0.0); } - m_precompiled.compile_postfix(inps, m_func()); + m_precompiled.compile(inps, m_func()); } protected: diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index c0f3e18a4f2..004d0f3be86 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -6,6 +6,7 @@ */ #include <cmath> +#include <stack> #include "pfunction.h" #include "pfmtlog.h" #include "putil.h" @@ -13,13 +14,27 @@ namespace plib { +void pfunction::compile(const std::vector<pstring> &inputs, const pstring expr) +{ + if (expr.startsWith("rpn:")) + compile_postfix(inputs, expr.substr(4)); + else + compile_infix(inputs, expr); +} + void pfunction::compile_postfix(const std::vector<pstring> &inputs, const pstring expr) { plib::pstring_vector_t cmds(expr, " "); + compile_postfix(inputs, cmds, expr); +} + +void pfunction::compile_postfix(const std::vector<pstring> &inputs, + const std::vector<pstring> &cmds, const pstring expr) +{ m_precompiled.clear(); int stk = 0; - for (pstring &cmd : cmds) + for (const pstring &cmd : cmds) { rpn_inst rc; if (cmd == "+") @@ -66,6 +81,99 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs, const pstrin throw plib::pexception(plib::pfmt("nld_function: stack count different to one on <{2}>")(expr)); } +int get_prio(pstring v) +{ + if (v == "(" or v == ")") + return 1; + else if (v.left(v.begin()+1) >= "a" && v.left(v.begin()+1) <= "z") + return 0; + else if (v == "*" or v == "/") + return 20; + else if (v == "+" or v == "-") + return 10; + else if (v == "^") + return 30; + else + return -1; +} + +static pstring pop_check(std::stack<pstring> &stk, const pstring &expr) +{ + if (stk.size() == 0) + throw plib::pexception(plib::pfmt("nld_function: stack underflow during infix parsing of: <{1}>")(expr)); + pstring res = stk.top(); + stk.pop(); + return res; +} + +void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring expr) +{ + // Shunting-yard infix parsing + std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"}; + plib::pstring_vector_t sexpr(expr.replace(" ",""), sep); + std::stack<pstring> opstk; + plib::pstring_vector_t postfix; + + //printf("dbg: %s\n", expr.c_str()); + for (unsigned i = 0; i < sexpr.size(); i++) + { + pstring &s = sexpr[i]; + if (s=="(") + opstk.push(s); + else if (s==")") + { + pstring x = pop_check(opstk, expr); + while (x != "(") + { + postfix.push_back(x); + x = pop_check(opstk, expr); + } + if (opstk.size() > 0 && get_prio(opstk.top()) == 0) + postfix.push_back(pop_check(opstk, expr)); + } + else if (s==",") + { + pstring x = pop_check(opstk, expr); + while (x != "(") + { + postfix.push_back(x); + x = pop_check(opstk, expr); + } + opstk.push(x); + } + else { + int p = get_prio(s); + if (p>0) + { + if (opstk.size() == 0) + opstk.push(s); + else + { + if (get_prio(opstk.top()) >= get_prio(s)) + postfix.push_back(pop_check(opstk, expr)); + opstk.push(s); + } + } + else if (p == 0) // Function or variable + { + if (sexpr[i+1] == "(") + opstk.push(s); + else + postfix.push_back(s); + } + else + postfix.push_back(s); + } + } + while (opstk.size() > 0) + { + postfix.push_back(opstk.top()); + opstk.pop(); + } + compile_postfix(inputs, postfix, expr); +} + + #define ST1 stack[ptr] #define ST2 stack[ptr-1] diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h index 2ad32106569..0f4960d4e1c 100644 --- a/src/lib/netlist/plib/pfunction.h +++ b/src/lib/netlist/plib/pfunction.h @@ -16,10 +16,10 @@ namespace plib { //============================================================ - // function evaluation - reverse polish notation + // function evaluation //============================================================ - /*! Class providing support for precompiled rpn expressions + /*! Class providing support for evaluating expressions * */ class pfunction @@ -47,12 +47,26 @@ namespace plib { { } + /*! Compile an expression + * + * @param inputs Vector of input variables, e.g. {"A","B"} + * @param expr infix or postfix expression. default is infix, postrix + * to be prefixed with rpn, e.g. "rpn:A B + 1.3 /" + */ + void compile(const std::vector<pstring> &inputs, const pstring expr); + /*! Compile a rpn expression * * @param inputs Vector of input variables, e.g. {"A","B"} * @param expr Reverse polish notation expression, e.g. "A B + 1.3 /" */ void compile_postfix(const std::vector<pstring> &inputs, const pstring expr); + /*! Compile an infix expression + * + * @param inputs Vector of input variables, e.g. {"A","B"} + * @param expr Infix expression, e.g. "(A+B)/1.3" + */ + void compile_infix(const std::vector<pstring> &inputs, const pstring expr); /*! Evaluate the expression * * @param values for input variables, e.g. {1.1, 2.2} @@ -61,6 +75,10 @@ namespace plib { double evaluate(const std::vector<double> &values); private: + + void compile_postfix(const std::vector<pstring> &inputs, + const std::vector<pstring> &cmds, const pstring expr); + std::vector<rpn_inst> m_precompiled; //!< precompiled expression }; diff --git a/src/lib/netlist/plib/pstring.cpp b/src/lib/netlist/plib/pstring.cpp index 7d676f34c0d..1a65bb152ff 100644 --- a/src/lib/netlist/plib/pstring.cpp +++ b/src/lib/netlist/plib/pstring.cpp @@ -6,10 +6,6 @@ */ #include <cstring> -//FIXME:: pstring should be locale free -#include <cctype> -#include <cstdlib> -#include <cstdio> #include <algorithm> #include <stack> @@ -17,6 +13,8 @@ #include "palloc.h" #include "plists.h" +template <typename F> pstr_t pstring_t<F>::m_zero(0); + template<typename F> pstring_t<F>::~pstring_t() { @@ -373,7 +371,7 @@ void pstringbuffer::pcat(const pstring &s) * This improves startup performance by 30%. */ -#if 1 +#if 0 static std::stack<pstr_t *> *stk = nullptr; @@ -416,8 +414,8 @@ static inline std::size_t countleadbits(std::size_t x) template<typename F> void pstring_t<F>::sfree(pstr_t *s) { - s->m_ref_count--; - if (s->m_ref_count == 0 && s != &m_zero) + bool b = s->dec_and_check(); + if ( b && s != &m_zero) { if (stk != nullptr) { @@ -472,8 +470,8 @@ void pstring_t<F>::resetmem() template<typename F> void pstring_t<F>::sfree(pstr_t *s) { - s->m_ref_count--; - if (s->m_ref_count == 0 && s != &m_zero) + bool b = s->dec_and_check(); + if ( b && s != &m_zero) { plib::pfree_array(((char *)s)); } diff --git a/src/lib/netlist/plib/pstring.h b/src/lib/netlist/plib/pstring.h index 999bd10ce6b..059df4b6376 100644 --- a/src/lib/netlist/plib/pstring.h +++ b/src/lib/netlist/plib/pstring.h @@ -10,6 +10,7 @@ #include <cstdarg> #include <cstddef> #include <iterator> +#include <exception> #include "pconfig.h" @@ -22,27 +23,24 @@ struct pstr_t { - //str_t() : m_ref_count(1), m_len(0) { m_str[0] = 0; } - pstr_t(const std::size_t alen) - { - init(alen); - } + pstr_t(const int alen) { init(alen); } void init(const std::size_t alen) { - m_ref_count = 1; - m_len = alen; - m_str[0] = 0; + m_ref_count = 1; + m_len = alen; + m_str[0] = 0; } char *str() { return &m_str[0]; } unsigned char *ustr() { return reinterpret_cast<unsigned char *>(&m_str[0]); } std::size_t len() const { return m_len; } - int m_ref_count; + void inc() { m_ref_count++; } + bool dec_and_check() { --m_ref_count; return m_ref_count == 0; } private: + int m_ref_count; std::size_t m_len; char m_str[1]; }; - template <typename F> struct pstring_t { @@ -75,7 +73,8 @@ public: pstring_t(C (&string)[N]) : m_ptr(&m_zero) { static_assert(std::is_same<C, const mem_t>::value, "pstring constructor only accepts const mem_t"); static_assert(N>0,"pstring from array of length 0"); - //static_assert(string[N-1] == 0, "pstring constructor parameter not a string literal"); + if (string[N-1] != 0) + throw std::exception(); init(string); } @@ -185,13 +184,13 @@ protected: private: void init(const mem_t *string) { - m_ptr->m_ref_count++; + m_ptr->inc(); if (string != nullptr && *string != 0) pcopy(string); } void init(const pstring_t &string) { - m_ptr->m_ref_count++; + m_ptr->inc(); pcopy(string); } @@ -206,7 +205,7 @@ private: { sfree(m_ptr); m_ptr = from.m_ptr; - m_ptr->m_ref_count++; + m_ptr->inc(); } void pcat(const mem_t *s); void pcat(const pstring_t &s); @@ -217,8 +216,6 @@ private: static pstr_t m_zero; }; -template <typename F> pstr_t pstring_t<F>::m_zero(0); - struct pu8_traits { static const unsigned MAXCODELEN = 1; /* in memory units */ diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp index b21f945662c..7007c818384 100644 --- a/src/lib/netlist/plib/putil.cpp +++ b/src/lib/netlist/plib/putil.cpp @@ -62,7 +62,7 @@ namespace plib } } - pstring_vector_t::pstring_vector_t(const pstring &str, const pstring_vector_t &onstrl) + pstring_vector_t::pstring_vector_t(const pstring &str, const std::vector<pstring> &onstrl) : std::vector<pstring>() { pstring col = ""; diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 728a475dd28..e340acbd8ec 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -71,7 +71,7 @@ namespace plib public: pstring_vector_t() : std::vector<pstring>() { } pstring_vector_t(const pstring &str, const pstring &onstr, bool ignore_empty = false); - pstring_vector_t(const pstring &str, const pstring_vector_t &onstrl); + pstring_vector_t(const pstring &str, const std::vector<pstring> &onstrl); }; } diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp index 19b453cb069..910f9078561 100644 --- a/src/lib/netlist/prg/nltool.cpp +++ b/src/lib/netlist/prg/nltool.cpp @@ -502,6 +502,7 @@ static const pstring pmf_verbose[] = }; #endif + int main(int argc, char *argv[]) { tool_options_t opts; |