【问题标题】:how to get spirit's qi::as_string to work with repeat?如何让精神的 qi::as_string 与重复一起工作?
【发布时间】:2012-12-29 18:38:33
【问题描述】:

由于某些奇怪的原因,我无法让 qi::as_string[]repeat()[] 合作。

解析std::string str = { "{ +100S+++ ;\n }" };,我得到以下OUTPUT

PLUS OR MINUS+
THREE PLUS OR MINUS
PARSED FINE
-------------------------
Parsing succeeded
-------------------------

说明解析没问题,第一个+被抓到了,后面三个+++没抓到。

注意 我只是想让three_plus_or_minus 连续捕获一到三个正负作为字符串。不使用as_string[] 的替代解决方案也将不胜感激。

对于冗长的列表,我深表歉意,但我需要在我的真实代码中同时使用词法分析器和解析器。

代码

// --------------  Third Party  --------------
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

// --------------  C++ stdlib   --------------
#include <iostream>
#include <fstream>
#include <string>

using namespace boost::spirit;
using boost::phoenix::val;

enum token_ids
{
    ID_CONSTANT = 1000,
        ID_INTEGER,
        ID_TAG,
    ID_IDENTIFIER
};

template <typename Lexer>
struct example6_tokens : lex::lexer<Lexer>
{
    example6_tokens()
    {
        identifier = "[a-zA-Z_][a-zA-Z0-9_]*";
        constant   = "[0-9]+";

        tag           = "sl|s|l|tl|SL|S|L|TSL|"    
                                    "z|r|i|Z|R|I|"              
                                    "<>|><|<<>>|>><<|><><|<><>";

        this->self = lex::token_def<>('(') | ')' | '{' | '}' 
            | '=' | ';' | ':' | '+' | '-';

        this->self.add
        (constant,        ID_CONSTANT       )
        (tag,             ID_TAG            )
        (identifier,      ID_IDENTIFIER     )
        ;

        this->self("WS")
            =   lex::token_def<>("[ \\t\\n]+")
                |   "\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/"
                |   "\\/\\/[^\n]*"
                ;
    }
    lex::token_def<std::string>   identifier, tag;
    lex::token_def<unsigned int>  constant;
};

// ----------------------------------------------------------------------------
template <typename Iterator, typename Lexer>
struct example6_grammar
        : qi::grammar<Iterator, qi::in_state_skipper<Lexer> >
{
    template <typename TokenDef>
    example6_grammar(TokenDef const& tok)
        : example6_grammar::base_type(program)
    {
        using boost::spirit::_val;

        program
            =  +block
               ;

        block
            =   '{' >> *slsltl_stmt >> '}'
                ;

        plus_or_minus
                %=   ( qi::as_string[ qi::lit( '+' ) ] | qi::as_string[ '-' ])
                    [
                 std::cout << val("PLUS OR MINUS") << val( _1 ) << "\n"
                    ]
                        ;

        three_plus_or_minus
                %=   ( qi::as_string[ repeat(1,3)['+'] ] | qi::as_string[ repeat(1,3)['-'] ] )
                    [
                 std::cout << val("THREE PLUS OR MINUS") << val( _1 ) << "\n"
                    ]
                        ;

        slsltl_stmt
        =  (  - plus_or_minus
                    >> token(ID_CONSTANT) 
                    >> token(ID_TAG)
                    >> three_plus_or_minus
                    >> ';'
                )
                        [
                    std::cout << val("PARSED FINE") << "\n"
                        ]
                ;

        expression
            =   tok.identifier [ _val = _1 ]
                |   tok.constant   [ _val = _1 ]
                ;
    }

    typedef boost::variant<unsigned int, std::string> expression_type;

    qi::rule<Iterator, qi::in_state_skipper<Lexer> > program, block;
    qi::rule<Iterator, std::string(), qi::in_state_skipper<Lexer> > 
        plus_or_minus, three_plus_or_minus;
    qi::rule<Iterator, std::string(), qi::in_state_skipper<Lexer> > slsltl_stmt;
    qi::rule<Iterator, expression_type(), qi::in_state_skipper<Lexer> >  expression;
};

int
main( int argv, char* argc[] )
{
    typedef std::string::iterator base_iterator_type;
    typedef lex::lexertl::token<
    base_iterator_type, boost::mpl::vector<unsigned int, std::string>
    > token_type;

    typedef lex::lexertl::lexer<token_type> lexer_type;
    typedef example6_tokens<lexer_type> example6_tokens;
    typedef example6_tokens::iterator_type iterator_type;
    typedef example6_grammar<iterator_type, example6_tokens::lexer_def> example6_grammar;

    example6_tokens tokens;                         // Our lexer
    example6_grammar calc(tokens);                  // Our parser
    std::string str = { "{ +100S+++ ;\n }" };

    std::string::iterator it = str.begin();
    iterator_type iter = tokens.begin(it, str.end());
    iterator_type end = tokens.end();

    std::string ws("WS");
    bool r = qi::phrase_parse(iter, end, calc, qi::in_state(ws)[tokens.self]);
    if (r && iter == end)
    {
        std::cout << "-------------------------\n";
        std::cout << "Parsing succeeded\n";
        std::cout << "-------------------------\n";
    }
    else
    {
        std::cout << "-------------------------\n";
        std::cout << "Parsing failed\n";
        std::cout << "-------------------------\n";
    }
}

【问题讨论】:

    标签: c++ c++11 boost-spirit boost-spirit-qi boost-spirit-lex


    【解决方案1】:

    试试

        slsltl_stmt %=  /*....*/;
    

    而不是slsltl_stmt =。使用语义动作会禁用自动属性传播。

    (我还没有查看您的其余代码。可能还有更多地方需要调整此/其他内容)


    编辑

    我做了更多测试,认为这符合您的预期:

    three_plus_or_minus
            =   (qi::as_string[ repeat(1,3)[qi::char_('+')] | repeat(1,3)[qi::char_('-')] ])
                [ std::cout << val("THREE PLUS OR MINUS") << _1 << "\n" ]
                    ;
    

    一个开箱即用的问题:您为什么要使用 Lexer?拥有+++ 的令牌不是很有意义吗?

    【讨论】:

    • 我最初在词法分析器中将它作为大型复杂标记的一部分(作为字符串出现)。然后我尝试将其分解为单个令牌,但我不知道+++ 是否会与+ 作为加法运算符出现在boost::spirit::lex::token_def&lt;&gt; 中产生不良交互。但根据你的建议,我会尝试重试。
    猜你喜欢
    • 1970-01-01
    • 2021-11-17
    • 2023-02-02
    • 1970-01-01
    • 2017-06-25
    • 2020-12-13
    • 2012-02-02
    • 2011-02-22
    • 2013-03-24
    相关资源
    最近更新 更多