2 #include <msp/strings/format.h>
3 #include "booleanevaluator.h"
8 BooleanEvaluator::BooleanEvaluator(const ValueFunction &f):
9 func([f](const string &value, const string *){ return f(value); }),
13 BooleanEvaluator::BooleanEvaluator(const CompareFunction &f):
18 bool BooleanEvaluator::evaluate(const string &str)
22 for(auto i=str.begin();; ++i)
24 if(i!=str.end() && (isalnum(*i) || (!buf.empty() && (*i=='_' || *i=='-'))))
31 throw runtime_error("syntax error at "+buf);
33 char op = (op_stack.empty() ? 0 : op_stack.back());
34 if(op=='=' || op=='^')
37 string var = var_stack.back();
39 bool value = (func(var, &buf) == (op=='='));
40 value_stack.push_back(value);
43 var_stack.push_back(buf);
53 else if(ops.find(*i)!=string::npos)
56 throw runtime_error(format("syntax error at %c", *i));
62 bool value = pop_value();
63 if(!value_stack.empty())
64 throw runtime_error("too many values");
69 void BooleanEvaluator::push_op(char op)
71 if(last_was_op!=is_unary(op))
72 throw runtime_error(format("syntax error at %c", op));
73 // TODO Disallow mixing of ! and =/^
74 if(is_logic(op) && !var_stack.empty())
75 value_stack.push_back(pop_value());
78 collapse(precedence(op));
79 op_stack.push_back(op);
83 bool BooleanEvaluator::pop_value()
85 if(!var_stack.empty())
87 string var = var_stack.back();
91 else if(!value_stack.empty())
93 bool value = value_stack.back();
94 value_stack.pop_back();
98 throw runtime_error("value stack underflow");
101 void BooleanEvaluator::collapse(unsigned until)
103 while(!op_stack.empty())
105 char op = op_stack.back();
106 if(precedence(op)<until)
110 bool value1 = pop_value();
118 bool value2 = pop_value();
120 value1 = (value1 && value2);
122 value1 = (value1 || value2);
124 value_stack.push_back(value1);
128 unsigned BooleanEvaluator::precedence(char op)
132 else if(op=='=' || op=='^')
140 bool BooleanEvaluator::is_unary(char op)
145 bool BooleanEvaluator::is_logic(char op)
147 return (op=='&' || op=='|' || op=='!');