Кресты / Говнокод #12937 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 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;
}

Обещанный в http://govnokod.ru/12936#comment175980 говнокодец с использованием бусто-духа.

Запостил: bormand bormand, (Updated )

Комментарии (28) RSS

    • Ок. Добавим 😉
      bool op_or(const bool_func &a, const bool_func &b, const object &obj) {
          return a(obj) || b(obj);
      }
      
      bool_func make_logic_op(bool (*f)(const bool_func &, const bool_func &, const object &),
          const bool_func &a, const bool_func &b)
      {
          return bind(f, a, b, arg1);
      }
      Вопрос к бустознатокам: это можно как-то проще записать?
      Ответить
      • я там напрямую вызывал заранее заготовленную функцию
        E_.name("expression");
        E_ =
            E1_                                 [_val = _1]
            > -(
                (token(lex::ID_NOTEQ) > E1_)    [_val = ast::bin_op(ast::pas_oper_binary_noteq, _1, _val, _2)]
                | (token(lex::ID_EQ) > E1_)     [_val = ast::bin_op(ast::pas_oper_binary_eq,    _1, _val, _2)]
                | (token(lex::ID_LT) > E1_)     [_val = ast::bin_op(ast::pas_oper_binary_lt,    _1, _val, _2)]
                | (token(lex::ID_GT) > E1_)     [_val = ast::bin_op(ast::pas_oper_binary_gt,    _1, _val, _2)]
               )
            ;
        где ast::bin_op
        struct make_binary
        {
            template <typename A, typename B = bs::unused_type, typename C = bs::unused_type, typename D = bs::unused_type>
            struct result { typedef expression_ast type; };
        
            template <typename Iterator>
            expression_ast operator()(e_pascal_operations op, boost::iterator_range<Iterator> const & ir, expression_ast const & left, expression_ast const & right) const
            {
                binary_op b(op, left, right);
                if (!b) {
                    std::ostringstream err_oss;
                    err_oss << "cannot make binary operator " << get_oper_string(op) << " with arguments ("
                        << get_type_string(left.get_pascal_type()) << ", " << get_type_string(right.get_pascal_type()) << ")";
                    throw compiler_error<Iterator>(err_oss.str(), ir.begin());
                }
                return expression_ast(b);
            }
        };
        extern boost::phoenix::function<make_binary>                    bin_op;
        только не спрашивай меня как это работает, ибо я не помню уже))
        Ответить
        • > только не спрашивай меня как это работает
          Да, в принципе, пока недавно с этим копался - ничего сложного. Ленивость вместо bind'а достигнута с помощью boost::phoenix::function'а. Грамматика чище чем у меня, зато сам make_binary получился пострашнее из-за структуры и "вывода типов"...

          P.S. Моя примитивная грамматика компилится 20с. Хорошо, что она размещена в отдельном модуле. А сколько компилился этот паскаль?

          P.P.S. Там, кстати, вроде бы был еще макрос типа ADAPT_FUNCTION, но теперь уже лень что-то менять, т.к. код работает.
          Ответить
          • чтобы этот паскаль смог скомпилиться на жёнином ноуте с 2гб оперативы хоть как-нибудь мне пришлось изрядно попотеть 🙂
            например, повыносить почти всё через extern template struct в отдельные .cpp, благодаря тому, что типы итераторов были очевидны
            изрядно помогло (наряду с pch, понятное дело)
            Ответить
            • > повыносить почти всё через extern template struct в отдельные .cpp
              А в новом стандарте внешние шаблоны запретили в их старом виде. Да и было то это только в студии.
              Ответить
              • > Да и было то это только в студии.
                >> хоть как-нибудь
                Я думаю им в тот момент было насрать на кроссплатформенность, лишь бы собралось и работало...
                Ответить
                • именно
                  не рабочий же код, а сраный курсач принести и показать, и промодифицировать на месте по требованию препода типа "а давай ка у тебя в паскале еще будет тернарная операция ?:"

                  зато по сравнению с yacc/bison было интересно разобраться
                  Ответить
                  • > зато по сравнению с yacc/bison было интересно разобраться
                    Ну вот собственно поэтому и решил написать этот микропарсер используя ускорение::дух::ки. С флексом+бизоном я бы его, конечно, написал быстрее, т.к. уже есть опыт, но хотелось чего-то нового. Да и не хотелось лишних зависимостей.

                    P.S. После 40кб ошибок спирита, типичные бустоошибки кажутся маленькими и понятными, а обычные с++ные - ничтожными и не заслуживающими внимания...
                    Ответить
                    • >После 40кб ошибок спирита
                      Как ты это осилил? Это вообще пушка. Я от этого столько плювался в ускорении::духа
                      Ответить
                      • Никак не осилил ;( Смотрел на номер строки, и путем ее созерцания пытался угадать в чем же я не прав.
                        Ответить
    • У лиспера, должно быть, розовые очки с тоо-о-о-о-олстыми стеклами..
      Ответить
  • > // ... скучные реализации операторов ...
    А можно парочку?
    Ответить
  • А тебя не накажут за публикацию корпоративных секретов? Ты ведь не знал, что я знаю твоего начальника?
    Ответить
    • Ну в libstdc++ эта любовь вполне понятна - два подчеркивания, насколько я помню, зарезервированы как раз для питонистов разрабов стандартных либ.
      Ответить
    • Стандарт, пункт 17.4.3.1.2 Global names
      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.
      Ответить

Добавить комментарий

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8