Анализатор Boost.Spirit X3 "нет именованного типа в (...)"


Я играл с калькулятором Boost.Spirit X3, когда столкнулся с ошибкой, но не смог разобраться.
Я свернул программу, чтобы уменьшить сложность, по-прежнему выбрасывая ту же ошибку. Скажем, я хочу проанализировать входные данные как список операторов (строк), за которыми следует разделитель (';').

Это моя структура:


namespace client { namespace ast
 {    
     struct program
    {
        std::list<std::string> stmts;
    };
 }}

BOOST_FUSION_ADAPT_STRUCT(client::ast::program,
            (std::list<std::string>, stmts)
)

Грамматика выглядит следующим образом:

namespace client
{ 
    namespace grammar
    {

   x3::rule<class program, ast::program> const program("program");

    auto const program_def =
            *((*char_) > ';')
            ;

   BOOST_SPIRIT_DEFINE(
       program
    );
    auto calculator = program;
}

using grammar::calculator;

}

Вызванный


    int
    main()
    {
    std::cout <<"///////////////////////////////////////////\n\n";
    std::cout << "Expression parser...\n\n";
    std::cout << //////////////////////////////////////////////////\n\n";
    std::cout << "Type an expression...or [q or Q] to quit\n\n";

    typedef std::string::const_iterator iterator_type;
    typedef client::ast::program ast_program;

    std::string str;
    while (std::getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        auto& calc = client::calculator;    // Our grammar
        ast_program program;                // Our program (AST)

        iterator_type iter = str.begin();
        iterator_type end = str.end();
        boost::spirit::x3::ascii::space_type space;
        bool r = phrase_parse(iter, end, calc, space, program);

        if (r && iter == end)
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing succeeded\n";
            std::cout<< '\n';
            std::cout << "-------------------------\n";
        }
        else
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

Я получаю ошибку

/opt/boost_1_66_0/boost/spirit/home/x3/support/traits/container_traits.hpp: In instantiation of ‘struct boost::spirit::x3::traits::container_value<client::ast::program, void>’:
.
.
.

/opt/boost_1_66_0/boost/spirit/home/x3/support/traits/container_traits.hpp:76:12: error: no type named ‘value_type’ in ‘struct client::ast::program’
         struct container_value
/opt/boost_1_66_0/boost/spirit/home/x3/operator/detail/sequence.hpp:497:72: error: no type named ‘type’ in ‘struct boost::spirit::x3::traits::container_value<client::ast::program, void>’
          , typename traits::is_substitute<attribute_type, value_type>::type());
                                                                        ^~~~~~

Вещи, которые я пытался:


После получения boost:: spirit:: qi для использования контейнеров stl
Хотя он использует Ци, я все же попробовал:

namespace boost{namespace spirit{ namespace traits{
template<>
struct container_value<client::ast::program> 
//also with struct container<client::ast::program, void>
{
      typedef std::list<std::string> type;
};
}}}

Видишь ли, я вроде как в темноте, так что, вероятно, безрезультатно.

parser2.cpp:41:8: error: ‘container_value’ is not a class template
 struct container_value<client::ast::program>
        ^~~~~~~~~~~~~~~

В этом же вопросе я, автор, говорю
"Существует одно известное ограничение, когда вы пытаетесь использовать структуру, которая имеет один элемент, который также является контейнером, компиляция завершится неудачно, если вы не добавите qi::eps >> ... в ваше правило".

Я попытался добавить фиктивный EPS также безуспешно.

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

1 ответ

Решение

Ага. Это выглядит как еще одно ограничение с автоматическим распространением атрибутов, когда задействованы одноэлементные последовательности.

Я бы, вероятно, укусил бы пулю и изменил бы определение правила с того, что это (и что вы ожидаете работать) на:

x3::rule<class program_, std::vector<std::string> >

Это удаляет корень путаницы.

Другие заметки:

  • ты имел char_ который также ест ';' поэтому грамматика никогда не будет успешной, потому что нет ';' будет следовать "заявлению".

  • ваши утверждения не лексемы, поэтому пробелы отбрасываются (это то, что вы имели ввиду?

  • Ваше утверждение может быть пустым, что означало, что синтаксический анализ ВСЕГДА потерпит неудачу в конце ввода (где он всегда будет читать пустое состояние, а затем обнаружит, что ожидаемый ';' скучал). Исправьте это, требуя по крайней мере 1 символ, прежде чем принимать заявление.

С некоторыми упрощениями / изменениями стиля:

Жить на Колиру

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <list>

namespace x3 = boost::spirit::x3;

namespace ast {
    using statement = std::string;

    struct program {
        std::list<statement> stmts;
    };
} 

BOOST_FUSION_ADAPT_STRUCT(ast::program, stmts)

namespace grammar {
    auto statement 
        = x3::rule<class statement_, ast::statement> {"statement"}
        = +~x3::char_(';');
    auto program 
        = x3::rule<class program_, std::list<ast::statement> > {"program"}
        = *(statement >> ';');
} 

#include <iostream>
#include <iomanip>

int main() {
    std::cout << "Type an expression...or [q or Q] to quit\n\n";

    using It = std::string::const_iterator;

    for (std::string str; std::getline(std::cin, str);) {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        auto &parser = grammar::program;
        ast::program program; // Our program (AST)

        It iter = str.begin(), end = str.end();
        if (phrase_parse(iter, end, parser, x3::space, program)) {
            std::cout << "Parsing succeeded\n";
            for (auto& s : program.stmts) {
                std::cout << "Statement: " << std::quoted(s, '\'') << "\n";
            }
        }
        else
            std::cout << "Parsing failed\n";

        if (iter != end)
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter, end), '\'') << "\n";
    }
}

Который для ввода "a;b;c;d;" печатает:

Parsing succeeded
Statement: 'a'
Statement: 'b'
Statement: 'c'
Statement: 'd'
Другие вопросы по тегам