diff options
-rw-r--r-- | src/lib/netlist/plib/pfunction.cpp | 152 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfunction.h | 66 |
2 files changed, 115 insertions, 103 deletions
diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index 7113ab7bd4e..c8049315276 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -14,11 +14,50 @@ #include <stack> #include <type_traits> #include <utility> +#include <map> namespace plib { static constexpr const std::size_t MAX_STACK = 32; + struct pcmd_t + { + rpn_cmd cmd; + int adj; + int prio; + }; + + static const std::map<pstring, pcmd_t> &pcmds() + { + static const std::map<pstring, pcmd_t> lpcmds = + { + { "^", { POW, 1, 30 } }, + { "neg", { NEG, 0, 25 } }, + { "+", { ADD, 1, 10 } }, + { "-", { SUB, 1, 10 } }, + { "*", { MULT, 1, 20 } }, + { "/", { DIV, 1, 20 } }, + { "<", { LT, 1, 9 } }, + { ">", { GT, 1, 9 } }, + { "<=", { LE, 1, 9 } }, + { ">=", { GE, 1, 9 } }, + { "==", { EQ, 1, 8 } }, + { "!=", { NE, 1, 8 } }, + { "if", { IF, 2, 0 } }, + { "pow", { POW, 1, 0 } }, + { "log", { LOG, 0, 0 } }, + { "sin", { SIN, 0, 0 } }, + { "cos", { COS, 0, 0 } }, + { "max", { MAX, 1, 0 } }, + { "min", { MIN, 1, 0 } }, + { "trunc", { TRUNC, 0, 0 } }, + { "rand", { RAND, -1, 0 } }, + + { "(", { LP, 0, 1 } }, + { ")", { RP, 0, 1 } }, + }; + return lpcmds; + } // FIXME: Exa parsing conflicts with e,E parsing template<typename F> static const std::map<pstring, F> &units_si() @@ -76,46 +115,12 @@ namespace plib { for (const pstring &cmd : cmds) { rpn_inst rc; - if (cmd == "+") - { rc.m_cmd = ADD; stk -= 1; } - else if (cmd == "-") - { rc.m_cmd = SUB; stk -= 1; } - else if (cmd == "*") - { rc.m_cmd = MULT; stk -= 1; } - else if (cmd == "/") - { rc.m_cmd = DIV; stk -= 1; } - else if (cmd == "==") - { rc.m_cmd = EQ; stk -= 1; } - else if (cmd == "!=") - { rc.m_cmd = NE; stk -= 1; } - else if (cmd == "<") - { rc.m_cmd = LT; stk -= 1; } - else if (cmd == ">") - { rc.m_cmd = GT; stk -= 1; } - else if (cmd == "<=") - { rc.m_cmd = LE; stk -= 1; } - else if (cmd == ">=") - { rc.m_cmd = GE; stk -= 1; } - else if (cmd == "if") - { rc.m_cmd = IF; stk -= 2; } - else if (cmd == "neg") - { rc.m_cmd = NEG; stk -= 0; } - else if (cmd == "pow" || cmd == "^") - { rc.m_cmd = POW; stk -= 1; } - else if (cmd == "log") - { rc.m_cmd = LOG; stk -= 0; } - else if (cmd == "sin") - { rc.m_cmd = SIN; stk -= 0; } - else if (cmd == "cos") - { rc.m_cmd = COS; stk -= 0; } - else if (cmd == "max") - { rc.m_cmd = MAX; stk -= 1; } - else if (cmd == "min") - { rc.m_cmd = MIN; stk -= 1; } - else if (cmd == "trunc") - { rc.m_cmd = TRUNC; stk -= 0; } - else if (cmd == "rand") - { rc.m_cmd = RAND; stk += 1; } + auto p = pcmds().find(cmd); + if (p != pcmds().end()) + { + rc.m_cmd = p->second.cmd; + stk -= p->second.adj; + } else { for (std::size_t i = 0; i < inputs.size(); i++) @@ -123,22 +128,22 @@ namespace plib { if (inputs[i] == cmd) { rc.m_cmd = PUSH_INPUT; - rc.m_param = narrow_cast<NT>(i); + rc.m_param.index = i; stk += 1; break; } } if (rc.m_cmd != PUSH_INPUT) { - using fl_t = decltype(rc.m_param); + using fl_t = decltype(rc.m_param.val); rc.m_cmd = PUSH_CONST; bool err(false); auto rs(plib::right(cmd,1)); auto r=units_si<fl_t>().find(rs); if (r == units_si<fl_t>().end()) - rc.m_param = plib::pstonum_ne<fl_t>(cmd, err); + rc.m_param.val = plib::pstonum_ne<fl_t>(cmd, err); else - rc.m_param = plib::pstonum_ne<fl_t>(plib::left(cmd, cmd.size()-1), err) * r->second; + rc.m_param.val = plib::pstonum_ne<fl_t>(plib::left(cmd, cmd.size()-1), err) * r->second; if (err) throw pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); stk += 1; @@ -151,7 +156,7 @@ namespace plib { m_precompiled.push_back(rc); } if (stk != 1) - throw pexception(plib::pfmt("pfunction: stack count {1] different to one on <{2}>")(stk, expr)); + throw pexception(plib::pfmt("pfunction: stack count {1} different to one on <{2}>")(stk, expr)); } static bool is_number(const pstring &n) @@ -172,23 +177,11 @@ namespace plib { static int get_prio(const pstring &v) { - if (v == "neg") - return 25; + auto p = pcmds().find(v); + if (p != pcmds().end()) + return p->second.prio; if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") return 0; - if (v == "(" || v == ")") - return 1; - if (v == "==" || v == "!=") - return 8; - if (v == "<" || v == ">" || v == "<=" || v == ">=") - return 9; - if (v == "+" || v == "-") - return 10; - if (v == "*" || v == "/") - return 20; - if (v == "^") - return 30; - return -1; } @@ -252,7 +245,7 @@ namespace plib { { if (i==0 || !(is_number(sexpr1[i-1]) || sexpr1[i-1] == ")" || is_id(sexpr1[i-1]))) { - sexpr.push_back("neg"); + sexpr.emplace_back("neg"); sexpr.push_back(sexpr1[i+1]); i+=2; } @@ -290,19 +283,19 @@ namespace plib { opstk.push(x); } else { - int p = get_prio(s); - if (p>0) + int prio = get_prio(s); + if (prio>0) { if (opstk.empty()) opstk.push(s); else { - if (get_prio(opstk.top()) >= get_prio(s)) + if (get_prio(opstk.top()) >= prio) postfix.push_back(pop_check(opstk, expr)); opstk.push(s); } } - else if (p == 0) // Function or variable + else if (prio == 0) // Function or variable { if ((i+1<sexpr.size()) && sexpr[i+1] == "(") opstk.push(s); @@ -333,7 +326,8 @@ namespace plib { lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10 return narrow_cast<NT>(lfsr) / narrow_cast<NT>(0xffffU); // NOLINT } - +#if 0 + // Currently unused since no integral type pfunction defined template <typename NT> static inline std::enable_if_t<plib::is_integral<NT>::value, NT> lfsr_random(std::uint16_t &lfsr) noexcept @@ -344,7 +338,7 @@ namespace plib { lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10 return narrow_cast<NT>(lfsr); } - +#endif #define ST0 stack[ptr+1] #define ST1 stack[ptr] #define ST2 stack[ptr-1] @@ -360,6 +354,8 @@ namespace plib { { std::array<value_type, MAX_STACK> stack = { plib::constants<value_type>::zero() }; unsigned ptr = 0; + constexpr auto zero = plib::constants<value_type>::zero(); + constexpr auto one = plib::constants<value_type>::one(); stack[0] = plib::constants<value_type>::zero(); for (auto &rc : m_precompiled) { @@ -369,13 +365,13 @@ namespace plib { OP(MULT, 1, ST2 * ST1) OP(SUB, 1, ST2 - ST1) OP(DIV, 1, ST2 / ST1) - OP(EQ, 1, ST2 == ST1 ? 1.0 : 0.0) - OP(NE, 1, ST2 != ST1 ? 1.0 : 0.0) - OP(GT, 1, ST2 > ST1 ? 1.0 : 0.0) - OP(LT, 1, ST2 < ST1 ? 1.0 : 0.0) - OP(LE, 1, ST2 <= ST1 ? 1.0 : 0.0) - OP(GE, 1, ST2 >= ST1 ? 1.0 : 0.0) - OP(IF, 2, (ST2 != 0.0) ? ST1 : ST0) + OP(EQ, 1, ST2 == ST1 ? one : zero) + OP(NE, 1, ST2 != ST1 ? one : zero) + OP(GT, 1, ST2 > ST1 ? one : zero) + OP(LT, 1, ST2 < ST1 ? one : zero) + OP(LE, 1, ST2 <= ST1 ? one : zero) + OP(GE, 1, ST2 >= ST1 ? one : zero) + OP(IF, 2, (ST2 != zero) ? ST1 : ST0) OP(NEG, 0, -ST2) OP(POW, 1, plib::pow(ST2, ST1)) OP(LOG, 0, plib::log(ST2)) @@ -388,10 +384,14 @@ namespace plib { stack[ptr++] = lfsr_random<value_type>(m_lfsr); break; case PUSH_INPUT: - stack[ptr++] = values[narrow_cast<unsigned>(rc.m_param)]; + stack[ptr++] = values[rc.m_param.index]; break; case PUSH_CONST: - stack[ptr++] = rc.m_param; + stack[ptr++] = rc.m_param.val; + break; + // please compiler + case LP: + case RP: break; } } diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h index 7f754d3cfad..be6d6e64f9e 100644 --- a/src/lib/netlist/plib/pfunction.h +++ b/src/lib/netlist/plib/pfunction.h @@ -19,6 +19,36 @@ namespace plib { // function evaluation //============================================================ + enum rpn_cmd + { + ADD, + MULT, + SUB, + DIV, + EQ, + NE, + LT, + GT, + LE, + GE, + IF, + NEG, // unary minus + POW, + LOG, + SIN, + COS, + MIN, + MAX, + RAND, /// random number between 0 and 1 + TRUNC, + + PUSH_CONST, + PUSH_INPUT, + + LP, // Left parenthesis - for infix parsing + RP // right parenthesis - for infix parsing + }; + /// \brief Class providing support for evaluating expressions /// /// \tparam NT Number type, should be float or double @@ -26,36 +56,18 @@ namespace plib { template <typename NT> class pfunction { - enum rpn_cmd - { - ADD, - MULT, - SUB, - DIV, - EQ, - NE, - LT, - GT, - LE, - GE, - IF, - NEG, // unary minus - POW, - LOG, - SIN, - COS, - MIN, - MAX, - RAND, /// random number between 0 and 1 - TRUNC, - PUSH_CONST, - PUSH_INPUT - }; struct rpn_inst { - rpn_inst() : m_cmd(ADD), m_param(plib::constants<NT>::zero()) { } + rpn_inst() : m_cmd(ADD) + { + m_param.val = plib::constants<NT>::zero(); + } rpn_cmd m_cmd; - NT m_param; + union + { + NT val; + std::size_t index; + } m_param; }; public: |