/* * Copyright (c) 2008 Andrew Garrett. * Copyright (c) 2008 River Tarnell * Derived from public domain code contributed by Victor Vasiliev. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely. This software is provided 'as-is', without any express or * implied warranty. */ #ifndef EXPRESSOR_H #define EXPRESSOR_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aftypes.h" #include "afstring.h" #include "affunctions.h" #include "fray.h" #include "ast.h" namespace afp { template struct parser_grammar; template struct basic_expressor : boost::noncopyable { typedef boost::function (std::vector >)> func_t; basic_expressor(); ~basic_expressor(); basic_datum evaluate(basic_fray const &expr) const; void print_xml(std::ostream &strm, basic_fray const &expr) const; void add_variable(basic_fray const &name, basic_datum const &value); void add_function(basic_fray const &name, func_t value); void clear(); void clear_functions(); void clear_variables(); private: parser_grammar *grammar_; }; typedef basic_expressor expressor; typedef basic_expressor u32expressor; using namespace boost::spirit; /* * ABUSEFILTER EXPRESSION PARSER * ============================= * * This is the basic expression parser. It doesn't contain any AF logic * itself, but rather presents an interface for the user to add custom * functions and variables. * * The interface to the parser is the 'expressor' class. Use it like this: * * expressor e; * e.add_variable("ONE", 1); * e.evaluate("ONE + 2"); -- returns 3 * * Custom functions should have the following prototype: * * datum (std::vector b * a >= b * a === b returns true if a==b and both are the same type * a !== b return true if a != b or they are different types * * The parser uses afp::datum for its variables. This means it supports * strings, ints and floats, with automatic conversion between types. */ struct parse_error : std::runtime_error { parse_error(char const *what) : std::runtime_error(what) {} }; /* * The grammar itself. */ template struct parser_grammar : public grammar > { static const int id_value = 1; static const int id_variable = 2; static const int id_basic = 3; static const int id_bool_expr = 4; static const int id_ord_expr = 5; static const int id_eq_expr = 6; static const int id_pow_expr = 7; static const int id_mult_expr = 8; static const int id_plus_expr = 9; static const int id_in_expr = 10; static const int id_function = 12; static const int id_tern_expr = 13; static const int id_string = 14; /* User-defined variables. */ symbols, charT > variables; void add_variable(basic_fray const &name, basic_datum const &value) { variables.add(name.c_str(), value); } /* User-defined functions. */ symbols (std::vector >)>, charT > functions; void add_function( basic_fray const &name, boost::function (std::vector >)> func) { functions.add(name.c_str(), func); } symbols eq_opers, ord_opers, plus_opers, mult_opers, in_opers, bool_opers; parser_grammar() { eq_opers.add("=", 0); eq_opers.add("==", 0); eq_opers.add("===", 0); eq_opers.add("!=", 0); eq_opers.add("!==", 0); eq_opers.add("/=", 0); ord_opers.add("<", 0); ord_opers.add("<=", 0); ord_opers.add(">", 0); ord_opers.add(">=", 0); plus_opers.add("+", 0); plus_opers.add("-", 0); mult_opers.add("*", 0); mult_opers.add("/", 0); mult_opers.add("%", 0); bool_opers.add("&", 0); bool_opers.add("|", 0); bool_opers.add("^", 0); in_opers.add("in", 0); in_opers.add("contains", 0); in_opers.add("matches", 0); in_opers.add("like", 0); in_opers.add("rlike", 0); in_opers.add("regex", 0); } template struct definition { parser_grammar const &self_; definition(parser_grammar const &self) : self_(self) { /* * A literal value. Either a string, a floating * pointer number or an integer. */ value = strict_real_p | as_lower_d[ leaf_node_d[ oct_p >> 'o' | hex_p >> 'x' | bin_p >> 'b' | int_p ] ] | string ; /* * config_p can't be used here, because it will rewrite * *(c_escape_ch_p[x]) into (*c_escape_ch_p)[x] */ string = inner_node_d[ '"' >> leaf_node_d[ *(lex_escape_ch_p - '"') ] >> '"' ] ; /* * A variable. If the variable is found in the * user-supplied variable list, we use that. * Otherwise, unknown variables (containing uppercase * letters and underscore only) are returned as the * empty string. */ variable = longest_d[ self.variables | leaf_node_d[ (+ (upper_p | '_') ) ] ] ; /* * A function call: func([arg[, arg...]]). */ function = ( root_node_d[self.functions] >> inner_node_d[ '(' >> ( tern_expr % discard_node_d[ch_p(',')] ) >> ')' ] ) ; /* * A basic atomic value. Either a variable, function * or literal, or a negated expression !a, or a * parenthesised expression (a). */ basic = value | variable | function | inner_node_d[ '(' >> tern_expr >> ')' ] | root_node_d[ch_p('!')] >> tern_expr | root_node_d[ch_p('+')] >> tern_expr | root_node_d[ch_p('-')] >> tern_expr ; /* * "a in b" operator */ in_expr = basic >> *( root_node_d[ self.in_opers ] >> basic ) ; /* * power-of. This is right-associative. */ pow_expr = in_expr >> !( root_node_d[ str_p("**") ] >> pow_expr ) ; /* * Multiplication and operators with the same * precedence. */ mult_expr = pow_expr >> *( root_node_d[ self.mult_opers ] >> pow_expr ) ; /* * Additional and operators with the same precedence. */ plus_expr = mult_expr >> *( root_node_d[ self.plus_opers ] >> mult_expr ) ; /* * Ordinal comparisons and operators with the same * precedence. */ ord_expr = plus_expr >> *( root_node_d[ self.ord_opers ] >> plus_expr ) ; /* * Equality comparisons. */ eq_expr = ord_expr >> *( root_node_d[ self.eq_opers ] >> ord_expr ) ; /* * Boolean expressions. */ bool_expr = eq_expr >> *( root_node_d[ self.bool_opers ] >> eq_expr ) ; /* * The ternary operator. Notice this is * right-associative: a ? b ? c : d : e * is supported. */ tern_expr = bool_expr >> !( root_node_d[ch_p('?')] >> tern_expr >> discard_node_d[ch_p(':')] >> tern_expr ) ; } rule, parser_tag > const &start() const { return tern_expr; } rule, parser_tag > value; rule, parser_tag > variable; rule, parser_tag > basic; rule, parser_tag > bool_expr; rule, parser_tag > ord_expr; rule, parser_tag > eq_expr; rule, parser_tag > pow_expr; rule, parser_tag > mult_expr; rule, parser_tag > plus_expr; rule, parser_tag > in_expr; rule, parser_tag > function; rule, parser_tag > tern_expr; rule, parser_tag > string; }; }; template basic_expressor::basic_expressor() : grammar_(new parser_grammar) { /* * We provide a couple of standard variables everyone wants. */ add_variable(make_astring("true"), afp::basic_datum::from_int(true)); add_variable(make_astring("false"), afp::basic_datum::from_int(false)); /* * The cast functions. */ add_function(make_astring("int"), &f_int); add_function(make_astring("string"), &f_string); add_function(make_astring("float"), &f_float); } template basic_expressor::~basic_expressor() { delete grammar_; } /* * The user interface to evaluate an expression. It returns the result, or * throws an exception if an error occurs. */ template basic_datum basic_expressor::evaluate(basic_fray const &filter) const { using namespace boost::spirit; typedef typename basic_fray::const_iterator iterator_t; basic_datum ret; tree_parse_info info = ast_parse(filter.begin(), filter.end(), *grammar_, +chset<>("\n\t ") | comment_p("/*", "*/")); if (info.full) { ast_evaluator::tree_iterator> ae(*grammar_); return ae.tree_eval(info.trees.begin()); } else { throw parse_error("parsing failed"); } } template void basic_expressor::print_xml(std::ostream &strm, basic_fray const &filter) const { using namespace boost::spirit; typedef typename basic_fray::const_iterator iterator_t; tree_parse_info info = ast_parse(filter.begin(), filter.end(), *grammar_, +chset<>("\n\t ") | comment_p("/*", "*/")); if (info.full) { std::map rule_names; rule_names[parser_grammar::id_value] = "value"; rule_names[parser_grammar::id_variable] = "variable"; rule_names[parser_grammar::id_basic] = "basic"; rule_names[parser_grammar::id_bool_expr] = "bool_expr"; rule_names[parser_grammar::id_ord_expr] = "ord_expr"; rule_names[parser_grammar::id_eq_expr] = "eq_expr"; rule_names[parser_grammar::id_pow_expr] = "pow_expr"; rule_names[parser_grammar::id_mult_expr] = "mult_expr"; rule_names[parser_grammar::id_plus_expr] = "plus_expr"; rule_names[parser_grammar::id_in_expr] = "in_expr"; rule_names[parser_grammar::id_function] = "function"; rule_names[parser_grammar::id_tern_expr] = "tern_expr"; rule_names[parser_grammar::id_string] = "string"; tree_to_xml(strm, info.trees, "", rule_names); } else { throw parse_error("parsing failed"); } } template void basic_expressor::clear() { clear_variables(); clear_functions(); } template void basic_expressor::clear_variables() { symbols, charT > variables; grammar_->variables = variables; } template void basic_expressor::clear_functions() { symbols (std::vector >)>, charT > functions; grammar_->functions = functions; } template void basic_expressor::add_variable(basic_fray const &name, basic_datum const &value) { grammar_->add_variable(name, value); } template void basic_expressor::add_function(basic_fray const &name, func_t value) { grammar_->add_function(name, value); } } // namespace afp #endif /* !EXPRESSOR_H */