diff options
Diffstat (limited to 'src/lib/netlist/plib/pfunction.cpp')
-rw-r--r-- | src/lib/netlist/plib/pfunction.cpp | 350 |
1 files changed, 179 insertions, 171 deletions
diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index e4ea2d57163..44254706636 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -16,207 +16,215 @@ namespace plib { -void pfunction::compile(const std::vector<pstring> &inputs, const pstring &expr) -{ - if (plib::startsWith(expr, "rpn:")) - compile_postfix(inputs, expr.substr(4)); - else - compile_infix(inputs, expr); -} - -void pfunction::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr) -{ - std::vector<pstring> cmds(plib::psplit(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 (const pstring &cmd : cmds) + template <typename NT> + void pfunction<NT>::compile(const std::vector<pstring> &inputs, const pstring &expr) { - 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 == "pow") - { rc.m_cmd = POW; stk -= 1; } - else if (cmd == "sin") - { rc.m_cmd = SIN; stk -= 0; } - else if (cmd == "cos") - { rc.m_cmd = COS; stk -= 0; } - else if (cmd == "trunc") - { rc.m_cmd = TRUNC; stk -= 0; } - else if (cmd == "rand") - { rc.m_cmd = RAND; stk += 1; } + if (plib::startsWith(expr, "rpn:")) + compile_postfix(inputs, expr.substr(4)); else + compile_infix(inputs, expr); + } + + template <typename NT> + void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr) + { + std::vector<pstring> cmds(plib::psplit(expr, " ")); + compile_postfix(inputs, cmds, expr); + } + + template <typename NT> + void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs, + const std::vector<pstring> &cmds, const pstring &expr) + { + m_precompiled.clear(); + int stk = 0; + + for (const pstring &cmd : cmds) { - for (std::size_t i = 0; i < inputs.size(); i++) + 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 == "pow") + { rc.m_cmd = POW; stk -= 1; } + else if (cmd == "sin") + { rc.m_cmd = SIN; stk -= 0; } + else if (cmd == "cos") + { rc.m_cmd = COS; stk -= 0; } + else if (cmd == "trunc") + { rc.m_cmd = TRUNC; stk -= 0; } + else if (cmd == "rand") + { rc.m_cmd = RAND; stk += 1; } + else { - if (inputs[i] == cmd) + for (std::size_t i = 0; i < inputs.size(); i++) + { + if (inputs[i] == cmd) + { + rc.m_cmd = PUSH_INPUT; + rc.m_param = static_cast<double>(i); + stk += 1; + break; + } + } + if (rc.m_cmd != PUSH_INPUT) { - rc.m_cmd = PUSH_INPUT; - rc.m_param = static_cast<double>(i); + rc.m_cmd = PUSH_CONST; + bool err(false); + rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err); + if (err) + throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); stk += 1; - break; } } - if (rc.m_cmd != PUSH_INPUT) - { - rc.m_cmd = PUSH_CONST; - bool err(false); - rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err); - if (err) - throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); - stk += 1; - } + if (stk < 1) + throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr)); + m_precompiled.push_back(rc); } - if (stk < 1) - throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr)); - m_precompiled.push_back(rc); + if (stk != 1) + throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr)); } - if (stk != 1) - throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr)); -} - -static int get_prio(const pstring &v) -{ - if (v == "(" || v == ")") - return 1; - else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") - return 0; - else if (v == "*" || v == "/") - return 20; - else if (v == "+" || 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("pfunction: 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 = {"(", ")", ",", "*", "/", "+", "-", "^"}; - std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep)); - std::stack<pstring> opstk; - std::vector<pstring> postfix; - - for (std::size_t i = 0; i < sexpr.size(); i++) + + static int get_prio(const pstring &v) { - 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==",") + if (v == "(" || v == ")") + return 1; + else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") + return 0; + else if (v == "*" || v == "/") + return 20; + else if (v == "+" || 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("pfunction: stack underflow during infix parsing of: <{1}>")(expr)); + pstring res = stk.top(); + stk.pop(); + return res; + } + + template <typename NT> + void pfunction<NT>::compile_infix(const std::vector<pstring> &inputs, const pstring &expr) + { + // Shunting-yard infix parsing + std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"}; + std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep)); + std::stack<pstring> opstk; + std::vector<pstring> postfix; + + for (std::size_t i = 0; i < sexpr.size(); i++) { - pstring x = pop_check(opstk, expr); - while (x != "(") + pstring &s = sexpr[i]; + if (s=="(") + opstk.push(s); + else if (s==")") { - postfix.push_back(x); - x = pop_check(opstk, expr); + 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)); } - opstk.push(x); - } - else { - int p = get_prio(s); - if (p>0) + else if (s==",") { - if (opstk.size() == 0) - opstk.push(s); - else + pstring x = pop_check(opstk, expr); + while (x != "(") { - if (get_prio(opstk.top()) >= get_prio(s)) - postfix.push_back(pop_check(opstk, expr)); - opstk.push(s); + postfix.push_back(x); + x = pop_check(opstk, expr); } + opstk.push(x); } - else if (p == 0) // Function or variable - { - if (sexpr[i+1] == "(") - opstk.push(s); + 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); } - else - postfix.push_back(s); } + while (opstk.size() > 0) + { + postfix.push_back(opstk.top()); + opstk.pop(); + } + compile_postfix(inputs, postfix, expr); } - 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] + #define ST1 stack[ptr] + #define ST2 stack[ptr-1] -#define OP(OP, ADJ, EXPR) \ -case OP: \ - ptr-= (ADJ); \ - stack[ptr-1] = (EXPR); \ - break; + #define OP(OP, ADJ, EXPR) \ + case OP: \ + ptr-= (ADJ); \ + stack[ptr-1] = (EXPR); \ + break; -double pfunction::evaluate(const std::vector<double> &values) noexcept -{ - std::array<double, 20> stack = { 0 }; - unsigned ptr = 0; - stack[0] = 0.0; - for (auto &rc : m_precompiled) + template <typename NT> + NT pfunction<NT>::evaluate(const std::vector<NT> &values) noexcept { - switch (rc.m_cmd) + std::array<NT, 20> stack = { 0 }; + unsigned ptr = 0; + stack[0] = 0.0; + for (auto &rc : m_precompiled) { - OP(ADD, 1, ST2 + ST1) - OP(MULT, 1, ST2 * ST1) - OP(SUB, 1, ST2 - ST1) - OP(DIV, 1, ST2 / ST1) - OP(POW, 1, std::pow(ST2, ST1)) - OP(SIN, 0, std::sin(ST2)) - OP(COS, 0, std::cos(ST2)) - OP(TRUNC, 0, std::trunc(ST2)) - case RAND: - stack[ptr++] = lfsr_random(); - break; - case PUSH_INPUT: - stack[ptr++] = values[static_cast<unsigned>(rc.m_param)]; - break; - case PUSH_CONST: - stack[ptr++] = rc.m_param; - break; + switch (rc.m_cmd) + { + OP(ADD, 1, ST2 + ST1) + OP(MULT, 1, ST2 * ST1) + OP(SUB, 1, ST2 - ST1) + OP(DIV, 1, ST2 / ST1) + OP(POW, 1, std::pow(ST2, ST1)) + OP(SIN, 0, std::sin(ST2)) + OP(COS, 0, std::cos(ST2)) + OP(TRUNC, 0, std::trunc(ST2)) + case RAND: + stack[ptr++] = lfsr_random(); + break; + case PUSH_INPUT: + stack[ptr++] = values[static_cast<unsigned>(rc.m_param)]; + break; + case PUSH_CONST: + stack[ptr++] = rc.m_param; + break; + } } + return stack[ptr-1]; } - return stack[ptr-1]; -} + + template struct pfunction<float>; + template struct pfunction<double>; } // namespace plib |