From 8d9fde525da9d3972b8728fadcec2b05287b4d36 Mon Sep 17 00:00:00 2001 From: couriersud Date: Fri, 10 Jul 2020 18:41:42 +0200 Subject: netlist: pfunction supports unary minus and removed duplicate code. --- src/lib/netlist/plib/pfunction.cpp | 152 ++++++++++++++++++------------------- 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 #include #include +#include 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 &pcmds() + { + static const std::map 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 static const std::map &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(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().find(rs); if (r == units_si().end()) - rc.m_param = plib::pstonum_ne(cmd, err); + rc.m_param.val = plib::pstonum_ne(cmd, err); else - rc.m_param = plib::pstonum_ne(plib::left(cmd, cmd.size()-1), err) * r->second; + rc.m_param.val = plib::pstonum_ne(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(lfsr) / narrow_cast(0xffffU); // NOLINT } - +#if 0 + // Currently unused since no integral type pfunction defined template static inline std::enable_if_t::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(lfsr); } - +#endif #define ST0 stack[ptr+1] #define ST1 stack[ptr] #define ST2 stack[ptr-1] @@ -360,6 +354,8 @@ namespace plib { { std::array stack = { plib::constants::zero() }; unsigned ptr = 0; + constexpr auto zero = plib::constants::zero(); + constexpr auto one = plib::constants::one(); stack[0] = plib::constants::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(m_lfsr); break; case PUSH_INPUT: - stack[ptr++] = values[narrow_cast(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 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::zero()) { } + rpn_inst() : m_cmd(ADD) + { + m_param.val = plib::constants::zero(); + } rpn_cmd m_cmd; - NT m_param; + union + { + NT val; + std::size_t index; + } m_param; }; public: -- cgit v1.2.3