Parsing logic expressions in strings with known variables - c++

What I want to do is create a function that would take an input string with 1-3 variables (and it would require at least one), then parse that input for an expression. This expression would then be considered logical and return true or false.
For example,
"X == Y && 0.1 <= X < 1.0 && Z > 0.0"
Then first the variables in that string would be iterated through and replaced with actual values. After all of the variables have been replaced the modified string would be like this:
"1.0 == 1.0 && 0.1 <= 1.0 < 1.0 && 0.6 > 0.0"
Then that string would be logically tested. If it is true the function would return true, else false.
I was thinking the function would be something like this:
IsLogical(string, float X, float Y, float Z)
I've been searching for the past few hours for ways to do this and all I have found were arithmetic math equation parsers. So far all I have got done is the part where the variables are replaced with the three input values.
So if anyone is willing to help, can you tell me how it would be done? Showing me examples would definitely be great too.
This function can't use any external resources like boost or embedded Lua.
EDIT: This should include all the basic comparison operators in C++, such as less than, more than, less than or equal to, more than or equal to, equal to, not equal to, and, or, parenthesis. It would all be in C++ format. If the format of the input isn't correct the function would automatically return false.

This is a wild stab at your problem. I'm not going to code it in detail, and I'm not focusing on language semantics, perfect compilation etc.
Wrap your variables with a new type (ExpresionVar). Register each variable with an ExpressionBuilder, that contains logical operators registered in the beginning of the program. Refer to the comments (psuedo code) in result...
ExpressionVar
{
float value_;
std::string name_;
};
LogicalOp
{
virtual std::string id() const = 0;
virtual bool operator()(
const ExpressionVar& lhs, const ExpressionVar& rhs) const = 0;
};
IsEqual : LogicalOp
{
std::string id() const override{ return "=="; }
bool operator()(
const ExpressionVar& lhs, const ExpressionVar& rhs) const override
{
returns lhs.value_ == rhs.value_;
}
};
//etc...
ExpressionBuilder
{
void registerVar(std::initializer_list<const ExpressionVar&>);
static void registerLogical(LogicalOp&&);
bool result(const std::string& expression) const
{
//run through expression.
// Search for known ExpressionVariable (EV), if variable found,
// store as lhs, else throw.
// Then search for LogicalOp until found, if another EV found
// throw, else store op, whereafter searching of rhs, etc...
}
};
bool IsLogical(
const std::string& input,
std::initializer_list<ExpressionVar> variables)
{
//Logical ops registered prior...
return ExpressionBuilder().registerVar(variables).result(input);
}

Related

String array to C++ function

I want to check if a given name is inside an array of possible names. I wrote this small debugging function ( yeah... I know it always return true ) trying to understand why it does not work and why I get the below error.
Code
char[] people_names = ["Mario","Luigi"];
bool lookupTerm (string term, string possible_names[]){
for(const string &possible_name : possible_names)
cout << possible_name << endl;
return true;
}
Error
jdoodle.cpp: In function 'bool lookupTerm(std::__cxx11::string, std::__cxx11::string*)':
jdoodle.cpp:19:38: error: no matching function for call to 'begin(std::__cxx11::basic_string<char>*&)'
I know that it must be really obvious but according to what I have searched for, it should work. Can someone point me in the right direction?
The problem is that when you pass an array to a function, it decays to a pointer to its first element.
It doesn't matter if you attempt to declare the argument as an array, the compiler still translates it as a pointer. string possible_names[] is equal to string* possible_names when you declare arguments.
The simple solution is to use either std::vector or std::array depending on your needs and use-case.
Using std::vector your code would look something like this:
std::vector<std::string> people_names = { "Mario", "Luigi" };
bool lookupTerm(const std::string& term, const std::vector<std::string>& possible_names) {
for (const std::string &possible_name : possible_names)
{
if (possible_name == term)
return true;
}
return false;
}
One line using std::find:
bool lookupTerm(const std::string& term, const std::vector<std::string>& possible_names) {
return std::find(possible_names.begin(), possible_names.end(), term) != possible_names.end();
}
If performance becomes a problem you can increase the performance of this by using a sorted vector (using std::sort) and std::lower_bound:
//at one point:
std::sort(people_names.begin(), people_names.end());
bool lookupTerm(const std::string& term, const std::vector<std::string>& sorted_possible_names) {
//sorted_possible_names must be always sorted when you call this!
auto i = std::lower_bound(sorted_possible_names.begin(), sorted_possible_names.end(), term);
return (i != sorted_possible_names.end() && *i == term);
}

std map find is always true

I have a problem using the std::map, specifically when using find.
I have the following code.
class MyClass
{
update(const QVariant&);
QVariant m_itemInfo;
std::map<QVariant, int> m_testMap;
}
void update(const QVariant& itemInfo)
{
if(m_itemInfo != itemInfo)
{
// The items are not equal
m_itemInfo = itemInfo;
}
if(m_testMap.find(itemInfo) == m_testMap.end())
{
// TestMap doesnt contain key itemInfo.
m_testMap.insert(std::make_pair(itemInfo, 1));
}
// More code
}
The function update is called several times (with different itemInfo objects) in my code. Now when I start to debug it, I see that the first time update is called, both the first and the second if loop are entered. So far so good. However the second time update is called I do see that the first if loop is called, but the second is skipped! What am I missing here?
I guess the problem that the first and second QVariants that you pass to your Update method have different type (for example, bool and uint). std::map::find doesn't use !=operator to compare keys, it uses operator < (less) by default. If two compared QVariant values have different types operators != and < may work contradictory.
std::map::find compares keys in the following way:
Two keys are considered equivalent if the container's comparison object returns false reflexively (i.e., no matter the order in which the elements are passed as arguments).
i.e. std::map::find considers that v1 is equal to v2
if(!(v1<v2) && !(v2>v1)) { //is TRUE !!!
}
To solve your problem, you should define a less comparison for std:map.
class QVariantLessCompare {
bool operator()(const QVariant& v1, QVariant& v2) const {
// ==== You SHOULD IMPLEMENT appropriate comparison here!!! ====
// Implementation will depend on type of QVariant values you use
//return v1 < v2;
}
};
And use QVariantCompare in a such way:
std::map<QVariant, int, QVariantLessCompare> m_testMap;
A more paradigmatic solution is to use QMap which correctly implements the comparison of most QVariant types. It won't do userTypes() out of the box, but this still might suit your application.
A cleaner version of the solution proposed by Володин Андрей, that builds, might look like:
struct QVariantLessCompare {
bool operator()(const QVariant& v1,const QVariant& v2) const
{
return v1.toInt() < v2.toInt();
}
};

C++ STL priority_queue , the way to compare objects

I have no idea how to implement priority_queue, when comparing an objects integer field , it's is clear.
For example
bool operator()(const Toast &t1, const Toast &t2) const
{
int t1value = t1.bread * 1000 + t1.butter;
int t2value = t2.bread * 1000 + t2.butter;
return t1value < t2value;
}
This will place the objects in the heap according to the values.
The question is how to compare objects according to the bool fields? How to store several objects according to the boolean type?
For example :
vip=true, notvip=false;
Vip1 , notVip2, Vip3.
The result should be: Vip1,Vip3,notVip2;
Can you give me an idea.
Your question is a bit unclear. I'm going to assume that the structure that you want to sort is Toast.
If you simply want to prioritize Toasts based on a bool, say status, your comparison object is pretty easy:
class mycomparison
{
public:
bool operator() (const Toast& lhs, const Toast& rhs) const
{
return lhs.status < rhs.status;
}
};
Now I'm going to assume the following to expand on this, given Toast has the following bool members listed in order of most significant to least significant: vip, notvip, Vip1,Vip3, andnotVip2`, I'm also assuming that the comparison on "not" members should be inverted:
class mycomparison
{
public:
bool operator() (const Toast& lhs, const Toast& rhs) const
{
return lhs.vip < rhs.vip || lhs.vip == rhs.vip && // return true if rhs.vip is the only true or continue to test
( lhs.noVip > rhs.noVip || lhs.noVip == rhs.noVip && // return true if rhs.noVip is the only false or continue to test
( lhs.Vip1 < rhs.Vip1 || lhs.Vip1 == rhs.Vip1 && // return true if lhs.Vip1 is less than rhs.Vip1 or continue to test
( lhs.Vip3 < rhs.Vip3 || lhs.Vip3 == rhs.Vip3 && // return true if lhs.Vip3 is less than rhs.Vip3 or continue to test
lhs.notVip2 > rhs.notVip2 ) ) ); // return true if lhs.notVip2 is greater than rhs.notVip2 or return false
}
};
Note that either of these mycomparison classes works fine if the members are bools or any other type for which operator<, operator> and operator== is defined. To use mycomparision in a std::priority_queue you'll just need to pass it as the comparison object in std::priority_queue's ctor, for example: std::priority_queue< Toast > foo( mycomparison() );

std::find not using my defined == operator

I have a simple class that I am storing in a vector as pointers. I want to use a find on the vector but it is failing to find my object. Upon debugging it doesn't seem to call the == operator I've provided. I can 'see' the object in the debugger so I know its there. The code below even uses a copy of the first item in the list, but still fails. The only way I can make it pass is to use MergeLine* mlt = LineList.begin(), which shows me that it is comparing the objects and not using my equality operator at all.
class MergeLine {
public:
std::string linename;
int StartIndex;
double StartValue;
double FidStart;
int Length;
bool operator < (const MergeLine &ml) const {return FidStart < ml.FidStart;}
bool operator == (const MergeLine &ml) const {
return linename.compare( ml.linename) == 0;}
};
Class OtherClass{
public:
std::vector<MergeLine*>LineList;
std::vector<MergeLine*>::iterator LL_iter;
void DoSomething( std::string linename){
// this is the original version that returned LineList.end()
// MergeLine * mlt
// mlt->linename = linename;
// this version doesn't work either (I thought it would for sure!)
MergeLine *mlt =new MergeLine(*LineList.front());
LL_iter = std::find(LineList.begin(), LineList.end(), mlt);
if (LL_iter == LineList.end()) {
throw(Exception("line not found in LineList : " + mlt->linename));
}
MergeLine * ml = *LL_iter;
}
};
cheers,
Marc
Since your container contains pointers and not objects, the comparison will be between the pointers. The only way the pointers will be equal is when they point to the exact same object. As you've noticed the comparison operator for the objects themselves will never be called.
You can use std::find_if and pass it a comparison object to use.
class MergeLineCompare
{
MergeLine * m_p;
public:
MergeLineCompare(MergeLine * p) : m_p(p)
{
}
bool operator()(MergeLine * p)
{
return *p == *m_p;
}
};
LL_iter = std::find_if(LineList.begin(), LineList.end(), MergeLineCompare(mlt));
I think what you really want is to use std::find_if like this:
struct MergeLineNameCompare
{
std::string seachname;
MergeLineNameComp(const std::string &name) : seachname(name)
{
}
bool operator()(const MergeLine * line)
{
return seachname.compare( line->linename ) == 0;
}
};
LL_iter = std::find_if(LineList.begin(), LineList.end(), MergeLineNameCompare(linename) );
The operator == (no matter wich form) is better saved for real comparison of equality.
Operator overloading can't work with pointers as it is ambiguous.
Bjarne Stroustrup :-
References were introduced primarily to support operator overloading.
C passes every function argument by value, and where passing an object
by value would be inefficient or inappropriate the user can pass a
pointer. This strategy doesn’t work where operator overloading is
used. In that case, notational convenience is essential so that a user
cannot be expected to insert address− of operators if the objects are
large.
So, may be not best but still :-
std::vector<MergeLine>LineList;
std::vector<MergeLine>::iterator LL_iter;

Object comparison with Sorting. C++

I'm having a hard time trying to understand other people's codes here.
I would really appreciate if someone helps me.
Let's say there is an array of object : vpair_list and this vpair_list has a type of class of vpair. So, it would be like this:
class vpair
{
public:
int vid;
int vlabel;
};
bool operator < (const vpair& x, const vpair& y);
vpair* vpair_list;
vpair_list = new vpair[25];
..
sort(vpair_list, vpair_list+j);
What I know from that is sort() compares each element of array vpair_list and sorts them.
The thing is that I just can't understand how that sorting works since the object vpair has two different properties.
Does the sorting work like comparing each property(vid and vlabel) or....? What I thought was the sorting was supposed to be done by comparing specific field or property (either vid or vlabel here).
But this code hasn't got anything to do with that and seems like it just compares the whole object. Could someone tell me how that works?
Thank you in advance.
The standard approach:
class vpair
{
public:
int vid;
int vlabel;
};
bool operator < (vpair const& x, vpair const& y)
{
return std::tie(x.vid, x.vlabel) < std::tie(y.vid, y.vlabel);
}
Of course, the operator can be a member:
class vpair
{
int vid;
int vlabel;
public:
bool operator < (vpair const& y) const
{
return std::tie(vid, vlabel) < std::tie(y.vid, y.vlabel);
}
};
Sort, by default, compares with the operator<. You can implement this operator for your class like so:
public:
bool operator < (const vpair& other) const
{
return (vid < other.vid); // Uses vid but this can be vlable or something else.
}
If you don't have an overload for the operator< with the class you're using, you can always pass in a comparison function as std::sort's third argument:
bool compare_func(vpair i,vpair j) { return (i.vid < j.vid); }
sort(vpair_list, vpair_list+j, compare_func);
Does the sorting work like comparing each property(vid and vlabel) or....?
It happens exactly how you want it to happen.
By default as people have mentioned, the < operator is used by various sort algorithms to arrange elements in ascending order of that operator. However for classes/structs there is no default way to compare them meaning you the programmer has to code it in.
That is what
bool operator < (const vpair& x, const vpair& y);
is. It is just a declaration to the definition of the function the programmer has provided to compare 2 vpair order. The programmer uses his rules to decide and ultimately returns true or false. This is used to sort.
So you can decide exactly how you want it to sort.
bool operator < (const vpair& x, const vpair& y)
{
if(x.vid != y.vid)
return x.vid<y.vid;
return x.vlabel <y.vlabel;
}
This would sort by ascending order of ID, if they are equal, It then sorts by ascending order of vlabel.