595 lines
10 KiB
C++
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));
|
|
}
|