Added infix notation parsing to the function parser. (nw)

This commit is contained in:
couriersud 2017-01-22 23:36:54 +01:00
parent 624463dc34
commit 093bda0193
9 changed files with 154 additions and 32 deletions

View file

@ -374,7 +374,7 @@ NETLIST_START(G501534_DIP)
//AFUNC(f, 2, "A0 A1 A1 A1 * * 0.01 * *")
//AFUNC(f, 2, "A0")
//AFUNC(f, 2, "A0 6 - A1 3 pow * 0.02 * 6 +")
AFUNC(f, 2, "A0 A1 3 pow * 0.02 *")
AFUNC(f, 2, "A0 * pow(A1,3.0) * 0.02")
/*
* 12: VCC

View file

@ -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:

View file

@ -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]

View file

@ -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
};

View file

@ -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));
}

View file

@ -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 */

View file

@ -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 = "";

View file

@ -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);
};
}

View file

@ -502,6 +502,7 @@ static const pstring pmf_verbose[] =
};
#endif
int main(int argc, char *argv[])
{
tool_options_t opts;