2 #include "booleanevaluator.h"
6 /* I'd rather have overloads with different slots, but that creates an
7 ambiguity because slots have template constructors. */
8 BooleanEvaluator::BooleanEvaluator(const Slot &s, bool allow_compare):
10 ops(allow_compare ? "&|!=^" : "&|!")
13 bool BooleanEvaluator::evaluate(const string &str)
17 for(string::const_iterator i=str.begin();; ++i)
19 if(i!=str.end() && (isalnum(*i) || (!buf.empty() && (*i=='_' || *i=='-'))))
26 throw runtime_error("syntax error at "+buf);
28 char op = (op_stack.empty() ? 0 : op_stack.back());
29 if(op=='=' || op=='^')
32 string var = var_stack.back();
34 bool value = (slot(var, &buf) == (op=='='));
35 value_stack.push_back(value);
38 var_stack.push_back(buf);
48 else if(ops.find(*i)!=string::npos)
51 throw runtime_error("syntax error at "+string(1, *i));
57 bool value = pop_value();
58 if(!value_stack.empty())
59 throw runtime_error("too many values");
64 void BooleanEvaluator::push_op(char op)
66 if(last_was_op!=is_unary(op))
67 throw runtime_error("syntax error at "+string(1, op));
68 // TODO Disallow mixing of ! and =/^
69 if(is_logic(op) && !var_stack.empty())
70 value_stack.push_back(pop_value());
73 collapse(precedence(op));
74 op_stack.push_back(op);
78 bool BooleanEvaluator::pop_value()
80 if(!var_stack.empty())
82 string var = var_stack.back();
86 else if(!value_stack.empty())
88 bool value = value_stack.back();
89 value_stack.pop_back();
93 throw runtime_error("value stack underflow");
96 void BooleanEvaluator::collapse(unsigned until)
98 while(!op_stack.empty())
100 char op = op_stack.back();
101 if(precedence(op)<until)
105 bool value1 = pop_value();
113 bool value2 = pop_value();
115 value1 = (value1 && value2);
117 value1 = (value1 || value2);
119 value_stack.push_back(value1);
123 unsigned BooleanEvaluator::precedence(char op)
127 else if(op=='=' || op=='^')
135 bool BooleanEvaluator::is_unary(char op)
140 bool BooleanEvaluator::is_logic(char op)
142 return (op=='&' || op=='|' || op=='!');