+++ /dev/null
-#include <stdexcept>
-#include "booleanevaluator.h"
-
-using namespace std;
-
-BooleanEvaluator::BooleanEvaluator(const ValueFunction &f):
- func([&f](const string &value, const string *){ return f(value); }),
- ops("&|!")
-{ }
-
-BooleanEvaluator::BooleanEvaluator(const CompareFunction &f):
- func(f),
- ops("&|!=^")
-{ }
-
-bool BooleanEvaluator::evaluate(const string &str)
-{
- string buf;
- last_was_op = true;
- for(auto i=str.begin();; ++i)
- {
- if(i!=str.end() && (isalnum(*i) || (!buf.empty() && (*i=='_' || *i=='-'))))
- buf += *i;
- else
- {
- if(!buf.empty())
- {
- if(!last_was_op)
- throw runtime_error("syntax error at "+buf);
-
- char op = (op_stack.empty() ? 0 : op_stack.back());
- if(op=='=' || op=='^')
- {
- op_stack.pop_back();
- string var = var_stack.back();
- var_stack.pop_back();
- bool value = (func(var, &buf) == (op=='='));
- value_stack.push_back(value);
- }
- else
- var_stack.push_back(buf);
-
- buf.clear();
- last_was_op = false;
- }
-
- if(i==str.end())
- break;
- else if(isspace(*i))
- ;
- else if(ops.find(*i)!=string::npos)
- push_op(*i);
- else
- throw runtime_error("syntax error at "+string(1, *i));
- }
- }
-
- collapse(0);
-
- bool value = pop_value();
- if(!value_stack.empty())
- throw runtime_error("too many values");
-
- return value;
-}
-
-void BooleanEvaluator::push_op(char op)
-{
- if(last_was_op!=is_unary(op))
- throw runtime_error("syntax error at "+string(1, op));
- // TODO Disallow mixing of ! and =/^
- if(is_logic(op) && !var_stack.empty())
- value_stack.push_back(pop_value());
-
- if(!is_unary(op))
- collapse(precedence(op));
- op_stack.push_back(op);
- last_was_op = true;
-}
-
-bool BooleanEvaluator::pop_value()
-{
- if(!var_stack.empty())
- {
- string var = var_stack.back();
- var_stack.pop_back();
- return func(var, 0);
- }
- else if(!value_stack.empty())
- {
- bool value = value_stack.back();
- value_stack.pop_back();
- return value;
- }
-
- throw runtime_error("value stack underflow");
-}
-
-void BooleanEvaluator::collapse(unsigned until)
-{
- while(!op_stack.empty())
- {
- char op = op_stack.back();
- if(precedence(op)<until)
- return;
-
- op_stack.pop_back();
- bool value1 = pop_value();
- if(is_unary(op))
- {
- if(op=='!')
- value1 = !value1;
- }
- else
- {
- bool value2 = pop_value();
- if(op=='&')
- value1 = (value1 && value2);
- else if(op=='|')
- value1 = (value1 || value2);
- }
- value_stack.push_back(value1);
- }
-}
-
-unsigned BooleanEvaluator::precedence(char op)
-{
- if(op=='&')
- return 1;
- else if(op=='=' || op=='^')
- return 2;
- else if(op=='!')
- return 3;
- else
- return 0;
-}
-
-bool BooleanEvaluator::is_unary(char op)
-{
- return op=='!';
-}
-
-bool BooleanEvaluator::is_logic(char op)
-{
- return (op=='&' || op=='|' || op=='!');
-}