Анализатор Boost.Spirit X3 "нет именованного типа в (...)" - PullRequest
0 голосов
/ 09 мая 2018


Я играл с калькулятором 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>
        ^~~~~~~~~~~~~~~

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

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

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

1 Ответ

0 голосов
/ 09 мая 2018

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

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

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

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

Другие примечания:

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

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

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

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

Live On Coliru

#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'
...