code_device/sdk/sane_opt_json/simple_logic.cpp

595 lines
10 KiB
C++

#include "simple_logic.h"
#include <string.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// logic_expression
namespace string_util
{
// Function: find the ending position in str
//
// Parameter: str - the string beginning after the first letter 'head'
//
// head - the leading letter, can be emblaced
//
// tail - the ending letter
//
// Return: position at the ending letter, or '\0' in the string
int find_end_of_pair(const char* str, char head, char tail)
{
int end = 0, banlance = 1;
while (str[end])
{
if (str[end] == '\\')
{
end++;
if (!str[end])
break;
// skip this translating-letter
end++;
continue;
}
if (str[end] == head)
{
banlance++;
}
else if (str[end] == tail)
{
if (--banlance == 0)
break;
}
end++;
}
return end;
}
void skip_space(const char*& ptr, const char* space)
{
char mark[2] = { 0 };
while (*ptr)
{
mark[0] = *ptr;
if (!strstr(space, mark))
break;
ptr++;
}
}
void trim(std::string& str, int type)
{
int pos = 0;
if (type & TRIM_LEFT)
{
for (; pos < str.length(); ++pos)
{
if (str[pos] != ' ')
break;
}
if (pos)
str.erase(0, pos);
}
if (type & TRIM_RIGHT)
{
pos = str.length() - 1;
for (; pos >= 0; --pos)
{
if (str[pos] != ' ')
break;
}
str.erase(pos + 1);
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// simple_logic
simple_logic::simple_logic() : l_(nullptr), r_(nullptr), oper_(LOGIC_OPER_NONE), expr_(""), not_(false)
{}
simple_logic::simple_logic(const simple_logic& r) : l_(nullptr), r_(nullptr)
{
copy(r);
}
simple_logic::~simple_logic()
{
clear();
}
void simple_logic::clear(void)
{
if (l_)
delete l_;
if (r_)
delete r_;
l_ = r_ = nullptr;
oper_ = LOGIC_OPER_NONE;
expr_ = "";
not_ = false;
}
void simple_logic::copy(const simple_logic& r)
{
clear();
oper_ = r.oper_;
not_ = r.not_;
expr_ = r.expr_;
if (r.l_)
{
l_ = new simple_logic();
l_->copy(*r.l_);
}
if (r.r_)
{
r_ = new simple_logic();
r_->copy(*r.r_);
}
}
void simple_logic::set_not(bool notv)
{
not_ = notv;
}
bool simple_logic::parse_internal(const char* expr, int* end, void(*leaf)(const char*, void*), void* leaf_param)
{
const char* ptr = expr, * first = nullptr;
std::vector<simple_logic*> ele;
std::vector<int> oper;
bool need_oper = false, good = true;
string_util::skip_space(ptr);
if (*ptr == 0)
return false;
while (*ptr)
{
if (*ptr == '(')
{
if (need_oper)
{
good = false;
*end = ptr - expr;
break;
}
int len = string_util::find_end_of_pair(ptr + 1, '(', ')');
if (ptr[++len] != ')')
{
*end = ptr - expr + len;
good = false;
break;
}
std::string sub(ptr + 1, len - 1);
if (sub.find("||") == std::string::npos &&
sub.find("&&") == std::string::npos &&
sub.find("^") == std::string::npos)
{
// count as function ...
ptr += len;
}
else
{
simple_logic* e = new simple_logic();
int over = 0;
bool not_v = false;
if (first)
{
while (first < ptr)
{
if (*first == '!')
not_v ^= true;
else
break;
first++;
}
if (first < ptr)
{
*end = first - expr;
good = false;
delete e;
break;
}
first = nullptr;
}
if (e->parse(sub.c_str(), &over, leaf, leaf_param))
{
e->set_not(not_v);
ele.push_back(e);
ptr += len;
need_oper = true;
}
else
{
*end = ptr - expr + 1 + over;
good = false;
delete e;
break;
}
}
}
else if (*ptr == '|')
{
if (*(ptr + 1) == '|')
{
if (need_oper || first)
{
if (first)
{
simple_logic* e = new simple_logic();
e->expr_ = std::string(first, ptr - first);
string_util::trim(e->expr_);
e->oper_ = LOGIC_OPER_LEAF;
ele.push_back(e);
first = nullptr;
if (leaf)
leaf(e->expr_.c_str(), leaf_param);
}
ptr++;
oper.push_back(LOGIC_OPER_OR);
need_oper = false;
}
else
{
good = false;
*end = ptr - expr;
break;
}
}
else
{
good = false;
*end = ptr - expr + 1;
break;
}
}
else if (*ptr == '&')
{
if (*(ptr + 1) == '&')
{
if (need_oper || first)
{
if (first)
{
simple_logic* e = new simple_logic();
e->expr_ = std::string(first, ptr - first);
string_util::trim(e->expr_);
e->oper_ = LOGIC_OPER_LEAF;
ele.push_back(e);
first = nullptr;
if (leaf)
leaf(e->expr_.c_str(), leaf_param);
}
ptr++;
oper.push_back(LOGIC_OPER_AND);
need_oper = false;
}
else
{
good = false;
*end = ptr - expr;
break;
}
}
else
{
good = false;
*end = ptr - expr + 1;
break;
}
}
else if (*ptr == '^')
{
if (need_oper || first)
{
if (first)
{
simple_logic* e = new simple_logic();
e->expr_ = std::string(first, ptr - first);
string_util::trim(e->expr_);
e->oper_ = LOGIC_OPER_LEAF;
ele.push_back(e);
first = nullptr;
if (leaf)
leaf(e->expr_.c_str(), leaf_param);
}
oper.push_back(LOGIC_OPER_XOR);
need_oper = false;
}
else
{
good = false;
*end = ptr - expr;
break;
}
}
else
{
// expression ...
if (need_oper)
{
good = false;
*end = ptr - expr;
break;
}
if (!first)
first = ptr;
}
ptr++;
string_util::skip_space(ptr);
}
if (good && first)
{
if (need_oper)
{
*end = first - expr;
good = false;
}
else
{
simple_logic* e = new simple_logic();
int over = 0;
if (e->parse(first, &over))
{
ele.push_back(e);
if (e->oper_ == LOGIC_OPER_LEAF && leaf)
leaf(e->expr_.c_str(), leaf_param);
}
else
{
good = false;
*end = first - expr + over;
delete e;
}
}
}
if (good && oper.size() == ele.size() - 1)
{
simple_logic* root = make_binary(ele, oper);
l_ = root->l_;
r_ = root->r_;
oper_ = root->oper_;
expr_ = root->expr_;
root->l_ = root->r_ = nullptr;
delete root;
*end = ptr - expr;
}
else
{
for (auto& v : ele)
delete v;
}
return good;
}
simple_logic* simple_logic::make_binary(const std::vector<simple_logic*>& eles, const std::vector<int>& opers)
{
if (eles.size() == 0 && opers.size() == 0)
return nullptr;
else if (eles.size() == 1)
return eles[0];
int or_pos = -1;
for (int i = 0; i < opers.size(); ++i)
{
if (opers[i] == LOGIC_OPER_OR)
{
or_pos = i;
break;
}
}
simple_logic* node = new simple_logic();
if (or_pos == -1)
{
//node->l_ = eles[0];
//node->oper_ = opers[0];
//
//std::vector<simple_logic*> re;
//std::vector<int> ro;
//for (int i = 1; i < eles.size(); ++i)
// re.push_back(eles[i]);
//for (int i = 1; i < opers.size(); ++i)
// ro.push_back(opers[i]);
//node->r_ = make_binary(re, ro);
node->r_ = eles[eles.size() - 1];
node->l_ = eles[eles.size() - 2];
node->oper_ = opers[opers.size() - 1];
simple_logic** left = &node->l_;
int cnt = 2;
while (++cnt <= eles.size())
{
simple_logic* n = new simple_logic();
n->oper_ = opers[opers.size() - cnt + 1];
n->l_ = eles[eles.size() - cnt];
n->r_ = *left;
*left = n;
left = &n->l_;
}
}
else
{
std::vector<simple_logic*> re;
std::vector<int> ro;
node->oper_ = LOGIC_OPER_OR;
for (int i = 0; i < or_pos + 1; ++i)
re.push_back(eles[i]);
for (int i = 0; i < or_pos; ++i)
ro.push_back(opers[i]);
node->l_ = make_binary(re, ro);
re.clear();
ro.clear();
for (int i = or_pos + 1; i < eles.size(); ++i)
re.push_back(eles[i]);
for (int i = or_pos + 1; i < opers.size(); ++i)
ro.push_back(opers[i]);
node->r_ = make_binary(re, ro);
}
return node;
}
std::string simple_logic::to_string_internal(bool& single)
{
single = true;
if (oper_ == LOGIC_OPER_LEAF)
return expr_;
else if (oper_ == LOGIC_OPER_AND || oper_ == LOGIC_OPER_OR || oper_ == LOGIC_OPER_XOR)
{
std::string exp("");
if (l_)
{
exp = l_->to_string_internal(single);
if (!single)
{
exp += ")";
exp.insert(0, "(");
}
}
if (oper_ == LOGIC_OPER_AND)
exp += " && ";
else if (oper_ == LOGIC_OPER_OR)
exp += " || ";
else
exp += " ^ ";
if (r_)
{
bool s = false;
std::string r(r_->to_string_internal(s));
if (!s)
{
r.insert(0, "(");
r += ")";
}
exp += r;
}
if (not_)
{
exp.insert(0, "!(");
exp += ")";
single = true;
}
else
single = false;
return std::move(exp);
}
else
return "";
}
simple_logic& simple_logic::operator=(const simple_logic& r)
{
copy(r);
return *this;
}
bool simple_logic::parse(const char* expr, int* end_pos, void(*leaf)(const char*, void*), void* leaf_param)
{
bool ret = false;
clear();
if (strstr(expr, "||") == nullptr &&
strstr(expr, "&&") == nullptr &&
strstr(expr, "^") == nullptr)
{
oper_ = LOGIC_OPER_LEAF;
expr_ = expr;
ret = true;
if (leaf)
leaf(expr_.c_str(), leaf_param);
}
else
{
int end = 0;
ret = parse_internal(expr, &end, leaf, leaf_param);
if (end_pos)
*end_pos = end;
}
return ret;
}
bool simple_logic::value(bool(*simple_expr_value)(const char*, void*), void* param)
{
if (oper_ == LOGIC_OPER_LEAF)
return simple_expr_value(expr_.c_str(), param);
else if (oper_ == LOGIC_OPER_AND)
{
bool ret = true;
if (l_)
ret = l_->value(simple_expr_value, param);
if (ret && r_)
ret &= r_->value(simple_expr_value, param);
return ret ^ not_;
}
else if (oper_ == LOGIC_OPER_OR)
{
bool ret = false;
if (l_)
ret = l_->value(simple_expr_value, param);
if (!ret && r_)
ret = r_->value(simple_expr_value, param);
return ret ^ not_;
}
else if (oper_ == LOGIC_OPER_XOR)
{
bool ret = false;
if (l_)
ret = l_->value(simple_expr_value, param);
if (r_)
ret ^= r_->value(simple_expr_value, param);
return ret ^ not_;
}
else
{
return false;
}
}
std::string simple_logic::to_expression(void)
{
bool single = false;
return std::move(to_string_internal(single));
}