- 01
 - 02
 - 03
 - 04
 - 05
 - 06
 - 07
 - 08
 - 09
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 
                        namespace predicate {
using ...;
typedef boost::function<bool (const object &obj)> bool_func;
typedef boost::function<int (const object &obj)> int_func;
// ... скучные реализации операторов ...
template <class I, class S> struct predicate_grammar :
    qi::grammar<I, bool_func(), S>
{
    predicate_grammar() : predicate_grammar::base_type(bool_expr)
    {
        identifier = char_("a-z") >> *(char_("a-z_0-9"));
        bool_prop = identifier [ _val = bind(&make_bool_prop_reader, _1, _pass) ];
        bool_expr = (bool_expr2 >> "||" >> bool_expr) [ _val = bind(&make_logic_op, &op_or, _1, _2) ]
                  | bool_expr2 [ _val = _1 ];
        bool_expr2 = (bool_expr3 >> "&&" >> bool_expr2) [ _val = bind(&make_logic_op, &op_and, _1, _2) ]
                   | bool_expr3 [ _val = _1 ];
        bool_expr3 = ('(' >> bool_expr >> ')') [ _val = _1 ]
                   | ('!' >> bool_expr3) [ _val = bind(&make_not, _1) ]
                   | int_comp [ _val = _1 ]
                   | bool_prop [ _val = _1];
        int_comp = (int_expr >> "<" >> int_expr) [ _val = bind(&make_cmp_op, &op_less, _1, _2) ]
                 | (int_expr >> "<=" >> int_expr) [ _val = bind(&make_cmp_op, &op_less_eq, _1, _2) ]
                 | (int_expr >> ">" >> int_expr) [ _val = bind(&make_cmp_op, &op_greater, _1, _2) ]
                 | (int_expr >> ">=" >> int_expr) [ _val = bind(&make_cmp_op, &op_greater_eq, _1, _2) ]
                 | (int_expr >> "==" >> int_expr) [ _val = bind(&make_cmp_op, &op_eq, _1, _2) ]
                 | (int_expr >> "!=" >> int_expr) [ _val = bind(&make_cmp_op, &op_not_eq, _1, _2) ];
        int_expr = int_prop [ _val = _1 ]
                 | int_const [ _val = bind(&make_int_const, _1) ];
        int_const = int_ [ _val = _1 ];
        int_prop = identifier [ _val = bind(&make_int_prop_reader, _1, _pass) ];
    }
    qi::rule<I, std::string(), S> identifier;
    qi::rule<I, int(), S> int_const;
    qi::rule<I, int_func(), S> int_expr, int_prop;
    qi::rule<I, bool_func(), S> bool_expr, bool_expr2, bool_expr3, int_comp, bool_prop;
};
boost::function<bool (const object &)> parse(const std::string &src) {
    if (src.empty())
        return make_bool_const(true);
    bool_func p;
    std::string::const_iterator b = src.begin(), e = src.end();
    predicate_grammar<std::string::const_iterator, boost::spirit::ascii::space_type> grammar;
    if (!phrase_parse(b, e, grammar, boost::spirit::ascii::space, p) || b != e) {
        std::stringstream s;
        s << "Predicate parsing failed at " << (b - src.begin()) << " in \"" << src << "\"";
        throw std::runtime_error(s.str());
    }
    return p;
}
                                 
        
где ast::bin_opтолько не спрашивай меня как это работает, ибо я не помню уже))
Да, в принципе, пока недавно с этим копался - ничего сложного. Ленивость вместо bind'а достигнута с помощью boost::phoenix::function'а. Грамматика чище чем у меня, зато сам make_binary получился пострашнее из-за структуры и "вывода типов"...
P.S. Моя примитивная грамматика компилится 20с. Хорошо, что она размещена в отдельном модуле. А сколько компилился этот паскаль?
P.P.S. Там, кстати, вроде бы был еще макрос типа ADAPT_FUNCTION, но теперь уже лень что-то менять, т.к. код работает.
например, повыносить почти всё через extern template struct в отдельные .cpp, благодаря тому, что типы итераторов были очевидны
изрядно помогло (наряду с pch, понятное дело)
А в новом стандарте внешние шаблоны запретили в их старом виде. Да и было то это только в студии.
>> хоть как-нибудь
Я думаю им в тот момент было насрать на кроссплатформенность, лишь бы собралось и работало...
не рабочий же код, а сраный курсач принести и показать, и промодифицировать на месте по требованию препода типа "а давай ка у тебя в паскале еще будет тернарная операция ?:"
зато по сравнению с yacc/bison было интересно разобраться
Ну вот собственно поэтому и решил написать этот микропарсер используя ускорение::дух::ки. С флексом+бизоном я бы его, конечно, написал быстрее, т.к. уже есть опыт, но хотелось чего-то нового. Да и не хотелось лишних зависимостей.
P.S. После 40кб ошибок спирита, типичные бустоошибки кажутся маленькими и понятными, а обычные с++ные - ничтожными и не заслуживающими внимания...
Как ты это осилил? Это вообще пушка. Я от этого столько плювался в ускорении::духа
Померещилось 40 литров спирта
А можно парочку?
В этом коде еще не так заметно, но вот такое часто вижу http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01437_source.html
Certain sets of names and function signatures are always reserved to the implementation:
— Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter
(2.11) is reserved to the implementation for any use.
— Each name that begins with an underscore is reserved to the implementation for use as a name in the global
namespace.