использование логического атрибута вместо необязательного в духе x3

В грамматике, которую я хочу реализовать, есть некоторые ключевые слова, где значение перечисления имеет значение (хранение идентификатора перечисления конкретного ключевого слова внутри узла ast) или даже только существование одного и того же конкретного ключевого слова — следовательно, необязательно в логическом контексте. Мне нравится иметь самовыразительное выражение синтаксического анализатора и узел ast, поэтому я придумал следующее (компилируемое) решение:

#include <iostream>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace x3 = boost::spirit::x3;

namespace ast {
    enum class keyword_token {
        UNSPECIFIED, FOO, BAR
    };
    struct buz {
        bool            foo;
        int             dummy;
    };
}

BOOST_FUSION_ADAPT_STRUCT( ast::buz, foo, dummy )

namespace boost { namespace spirit { namespace x3 { namespace traits {
    template <>
    inline void
    move_to(ast::keyword_token&& src, bool& dest) {
        dest = static_cast<bool>(src);
    }
} } } } // boost.spirit.x3.traits


namespace parser {
    auto const FOO = x3::rule<struct _, ast::keyword_token> { "FOO" } = 
        x3::lexeme[ x3::no_case[ "foo" ] >> !(x3::alnum | '_') ]
        >> x3::attr(ast::keyword_token::FOO);
    auto const buz = x3::rule<struct _, ast::buz> { "buz" } = 
        -FOO >> x3::int_;
}

int main() {
    for(std::string const str: {
           "FOO 42",
           "42"
    }) {
      auto iter = str.begin(), end = str.end();
      ast::buz attr;
      bool r = x3::phrase_parse(iter, end, parser::buz, x3::space, attr);

      std::cout << "parse '" << str << "': ";
      if (r && iter == end) {
        std::cout << "succeeded:\n";
        std::cout << (attr.foo ? "FOO " : "") << attr.dummy << "\n";
        std::cout << "\n";
      } else {
        std::cout << "*** failed ***\n";
      }
    }
    return 0;
}

Здесь узел buz ast имеет логический атрибут, а синтаксический анализатор — «необязательный» синтаксис. Идея заключается в том, что bool является конструируемым по умолчанию, а стандартные гарантии инициализируются значением 0, также известным как false, что и предполагалось. Кроме того, у меня есть резервное решение keyword::UNSPECIFIED, которое (должно, поскольку я не уверен на 100% для классов перечисления) было равно 0 - что imo никогда не должно запускаться - также оценивается как false внутри признаков move_to(...) x3 в худший вариант развития событий.

Выполнение этого этапа синтаксического анализа прошло успешно для обоих тестовых случаев, как и ожидалось, но атрибут 2-го тестового примера не ожидается; очевидно, что подход «логический как необязательный» не работает должным образом:

<buz>
  <try>FOO 42</try>
  <FOO>
    <try>FOO 42</try>
    <success> 42</success>
    <attributes>1</attributes>
  </FOO>
  <success></success>
  <attributes>[1, 42]</attributes>
</buz>
parse 'FOO 42': succeeded:
FOO 42

<buz>
  <try>42</try>
  <FOO>
    <try>42</try>
    <fail/>
  </FOO>
  <success></success>
  <attributes>[1, 42]</attributes>
</buz>
parse '42': succeeded:
FOO 42

В режиме отладки отображаются синтезированные атрибуты [1, 42]. Итак, правдоподобно ли мое соображение и может ли оно работать, если да, то как исправить, чтобы оно работало, как задумано? Может быть другая проблема: Без определенного BOOST_SPIRIT_X3_DEBUG я получаю предупреждение:

warning: 'attr' may be used uninitialized in this function
...
warning: 'attr.ast::buz::dummy' may be used uninitialized in this function

на линии cout. Вероятно, я неправильно понимаю предупреждение, поскольку ast::buz по умолчанию конструируется со значениями, которые я не хочу иметь по умолчанию (false, 0).

Решение грубой силы состоит в том, чтобы написать что-то вроде:

auto bool_attr = [](auto p) {
    return x3::omit[ p ] >> x3::attr(true) | x3::attr(false);
};

и использовать его внутри правил, но я предпочитаю «необязательный» синтаксис вместо написания bool_attr(FOO) >> x3::int_etc.

Источник также находится по адресу Coliru.


person Olx    schedule 09.06.2017    source источник
comment
Связано.   -  person llonesmiz    schedule 09.06.2017


Ответы (1)


llonesmiz понял, что требуется ли для инициализации объекта класса POD конструктор?; Я должен явно написать конструктор для узла ast:

struct buz {
    bool            foo;
    int             dummy;

    buz() : foo{}, dummy{}
    { }
};

чем атрибуты, как и ожидалось:

parse 'FOO 42': succeeded:
FOO 42

parse '42': succeeded:
42

При этом упомянутое выше предупреждение без определенного BOOST_SPIRIT_X3_DEBUG также исчезло, и предупреждение имеет для меня больше смысла ...

person Olx    schedule 09.06.2017
comment
Вы также можете просто использовать ast::buz attr{}; для принудительной инициализации значения attr, которая вызывает attr.fooattr.dummy) для инициализации нулями, как вы и ожидали. - person llonesmiz; 09.06.2017