1. C++ / Говнокод #12937

    +12

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    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, 26 Апреля 2013

    Комментарии (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кб ошибок спирита
                        Как ты это осилил? Это вообще пушка. Я от этого столько плювался в ускорении::духа
                        Ответить
                        • Никак не осилил ;( Смотрел на номер строки, и путем ее созерцания пытался угадать в чем же я не прав.
                          Ответить
                      • > 40кб ошибок спирита
                        Померещилось 40 литров спирта
                        Ответить
      • У лиспера, должно быть, розовые очки с тоо-о-о-о-олстыми стеклами..
        Ответить
    • Бусто-духом пахнет.
      Ответить
    • OP OR
      Ответить
    • > // ... скучные реализации операторов ...
      А можно парочку?
      Ответить
    • А тебя не накажут за публикацию корпоративных секретов? Ты ведь не знал, что я знаю твоего начальника?
      Ответить
      • Это проект не с работы, а для души в свободное время ;) Наказывать за него пока некому.
        Ответить
    • Откуда в C++ такая любовь к предшествующему нижнему подчеркиванию в именах?
      В этом коде еще не так заметно, но вот такое часто вижу http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01437_source.html
      Ответить
      • Ну в 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.
        Ответить

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