diff options
-rw-r--r-- | src/lib/netlist/plib/pfunction.cpp | 108 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfunction.h | 1 | ||||
-rw-r--r-- | src/lib/netlist/tests/test_pfunction.cpp | 37 |
3 files changed, 91 insertions, 55 deletions
diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index f977059ff69..7113ab7bd4e 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -98,7 +98,9 @@ namespace plib { { rc.m_cmd = GE; stk -= 1; } else if (cmd == "if") { rc.m_cmd = IF; stk -= 2; } - else if (cmd == "pow") + 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; } @@ -149,25 +151,43 @@ namespace plib { m_precompiled.push_back(rc); } if (stk != 1) - throw pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr)); + throw pexception(plib::pfmt("pfunction: stack count {1] different to one on <{2}>")(stk, expr)); + } + + static bool is_number(const pstring &n) + { + if (n.empty()) + return false; + const auto l = n.substr(0,1); + return (l >= "0" && l <= "9"); + } + + static bool is_id(const pstring &n) + { + if (n.empty()) + return false; + const auto l = n.substr(0,1); + return ((l >= "a" && l <= "z") || (l >= "A" && l <= "Z")); } static int get_prio(const pstring &v) { - if (v == "(" || v == ")") - return 1; + if (v == "neg") + return 25; if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") return 0; - if (v == "^") - return 30; - if (v == "*" || v == "/") - return 20; - if (v == "+" || v == "-") - return 10; - if (v == "<" || v == ">" || v == "<=" || v == ">=") - return 9; + 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; } @@ -186,52 +206,55 @@ namespace plib { { // Shunting-yard infix parsing std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^", "<=", ">=", "==", "!=", "<", ">"}; - std::vector<pstring> sexpr1(plib::psplit(plib::replace_all(expr, " ", ""), sep)); + std::vector<pstring> sexpr2(plib::psplit(plib::replace_all(expr, " ", ""), sep)); std::stack<pstring> opstk; std::vector<pstring> postfix; + std::vector<pstring> sexpr1; std::vector<pstring> sexpr; // FIXME: We really need to switch to ptokenizer and fix negative number // handling in ptokenizer. - // Fix numbers - for (std::size_t i = 0; i < sexpr1.size(); ) + // Fix numbers exponential numbers + for (std::size_t i = 0; i < sexpr2.size(); ) { - if ((i == 0) && (sexpr1.size() > 1) && (sexpr1[0] == "-") - && (plib::left(sexpr1[1],1) >= "0") && (plib::left(sexpr1[1],1) <= "9")) + if (i + 2 < sexpr2.size() && sexpr2[i].length() > 1) { - if (sexpr1.size() < 4) + auto r(plib::right(sexpr2[i], 1)); + auto ne(sexpr2[i+1]); + if ((is_number(sexpr2[i])) + && (r == "e" || r == "E") + && (ne == "-" || ne == "+")) { - sexpr.push_back(sexpr1[0] + sexpr1[1]); - i+=2; + sexpr1.push_back(sexpr2[i] + ne + sexpr2[i+2]); + i+=3; } else + sexpr1.push_back(sexpr2[i++]); + } + else + sexpr1.push_back(sexpr2[i++]); + } + // Fix numbers with unary minus/plus + for (std::size_t i = 0; i < sexpr1.size(); ) + { + if (sexpr1[i]=="-" && (i+1 < sexpr1.size()) && is_number(sexpr1[i+1])) + { + if (i==0 || !(is_number(sexpr1[i-1]) || sexpr1[i-1] == ")" || is_id(sexpr1[i-1]))) { - auto r(plib::right(sexpr1[1], 1)); - auto ne(sexpr1[2]); - if ((r == "e" || r == "E") && (ne == "-" || ne == "+")) - { - sexpr.push_back(sexpr1[0] + sexpr1[1] + ne + sexpr1[3]); - i+=4; - } - else - { - sexpr.push_back(sexpr1[0] + sexpr1[1]); - i+=2; - } + sexpr.push_back("-" + sexpr1[i+1]); + i+=2; } + else + sexpr.push_back(sexpr1[i++]); } - else if (i + 2 < sexpr1.size() && sexpr1[i].length() > 1) + else if (sexpr1[i]=="-" && (i+1 < sexpr1.size()) && (is_id(sexpr1[i+1]) || sexpr1[i+1] == "(")) { - auto l(plib::left(sexpr1[i], 1)); - auto r(plib::right(sexpr1[i], 1)); - auto ne(sexpr1[i+1]); - if ((l >= "0") && (l <= "9") - && (r == "e" || r == "E") - && (ne == "-" || ne == "+")) + if (i==0 || !(is_number(sexpr1[i-1]) || sexpr1[i-1] == ")" || is_id(sexpr1[i-1]))) { - sexpr.push_back(sexpr1[i] + ne + sexpr1[i+2]); - i+=3; + sexpr.push_back("neg"); + sexpr.push_back(sexpr1[i+1]); + i+=2; } else sexpr.push_back(sexpr1[i++]); @@ -296,7 +319,7 @@ namespace plib { opstk.pop(); } //for (auto &e : postfix) - // printf("\t %s\n", e.c_str()); + // printf("\t%s\n", e.c_str()); compile_postfix(inputs, postfix, expr); } @@ -353,6 +376,7 @@ namespace plib { 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(NEG, 0, -ST2) OP(POW, 1, plib::pow(ST2, ST1)) OP(LOG, 0, plib::log(ST2)) OP(SIN, 0, plib::sin(ST2)) diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h index 6b5e94b2900..7f754d3cfad 100644 --- a/src/lib/netlist/plib/pfunction.h +++ b/src/lib/netlist/plib/pfunction.h @@ -39,6 +39,7 @@ namespace plib { LE, GE, IF, + NEG, // unary minus POW, LOG, SIN, diff --git a/src/lib/netlist/tests/test_pfunction.cpp b/src/lib/netlist/tests/test_pfunction.cpp index 847865b4a4f..c82617659ec 100644 --- a/src/lib/netlist/tests/test_pfunction.cpp +++ b/src/lib/netlist/tests/test_pfunction.cpp @@ -12,27 +12,27 @@ #include "plib/pfunction.h" #define PFUNCEXPECT(formula, val) \ - EXPECT_EQ(val, plib::pfunction<double>(formula)()); + EXPECT_EQ(val, plib::pfunction<double>(formula)()) TEST(pfunction, operators) { - PFUNCEXPECT("1==1", 1.0) - PFUNCEXPECT("1 *0 == 2-1-1", 1.0) - PFUNCEXPECT("0!=1", 1.0) - PFUNCEXPECT("0<1", 1.0) - PFUNCEXPECT("1>0", 1.0) - PFUNCEXPECT("0<=1", 1.0) - PFUNCEXPECT("1>=0", 1.0) - PFUNCEXPECT("1<=1", 1.0) - PFUNCEXPECT("1>=1", 1.0) + PFUNCEXPECT("1==1", 1.0); + PFUNCEXPECT("1 *0 == 2-1-1", 1.0); + PFUNCEXPECT("0!=1", 1.0); + PFUNCEXPECT("0<1", 1.0); + PFUNCEXPECT("1>0", 1.0); + PFUNCEXPECT("0<=1", 1.0); + PFUNCEXPECT("1>=0", 1.0); + PFUNCEXPECT("1<=1", 1.0); + PFUNCEXPECT("1>=1", 1.0); EXPECT_EQ(1.0, plib::pfunction<double>("0!=a", {"a"})({1.0})); } TEST(pfunction, func_if) { - PFUNCEXPECT("if(1>0, 2, 0)", 2.0) - PFUNCEXPECT("if(0>1, 2, 3)", 3.0) - PFUNCEXPECT("if(sin(1)>0, 2, 3)", 3.0) // fail + PFUNCEXPECT("if(1>0, 2, 0)", 2.0); + PFUNCEXPECT("if(0>1, 2, 3)", 3.0); + PFUNCEXPECT("if(sin(1)>0, 2, 3)", 3.0); // fail EXPECT_EQ( 1.0, plib::pfunction<double>("if(A2>2.5, 0-A1, (0.07-(0.005*A1))*if(A0>2.5,1,0-1))", {"A0","A1","A2"})({1.0,-1.0,3.0})); EXPECT_EQ(-0.065, plib::pfunction<double>("if(A2>2.5, 0-A1, (0.07-(0.005*A1))*if(A0>2.5,1,0-1))", {"A0","A1","A2"})({1.0,1.0,1.0})); EXPECT_EQ( 0.065, plib::pfunction<double>("if(A2>2.5, 0-A1, (0.07-(0.005*A1))*if(A0>2.5,1,0-1))", {"A0","A1","A2"})({3.0,1.0,1.0})); @@ -41,3 +41,14 @@ TEST(pfunction, func_if) EXPECT_TRUE(1.0 == plib::pfunction<double>("0!=a", {"a"})({1.0})); } +TEST(pfunction, unary_minus) +{ + PFUNCEXPECT("-1>-2", 1.0); + PFUNCEXPECT("(-3)*(-4)", 12.0); + PFUNCEXPECT("(-3)*-4", 12.0); + PFUNCEXPECT("-3*-4", 12.0); + EXPECT_EQ( -3.0, plib::pfunction<double>("-A0", {"A0"})({3.0})); + PFUNCEXPECT("3*-trunc(3.2)", -9.0); + PFUNCEXPECT("3*-(3*2)", -18.0); + PFUNCEXPECT("3*-(2*1)^2", -12.0); +} |