如何让精神之气::as_string重复工作?

how to get spirit's qi::as_string to work with repeat?

本文关键字:string 工作 as      更新时间:2023-10-16

由于一些奇怪的原因,我不能让qi::as_string[]repeat()[]一起工作。

解析std::string str = { "{ +100S+++ ;n }" };,我得到以下输出
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 succeededn";
        std::cout << "-------------------------n";
    }
    else
    {
        std::cout << "-------------------------n";
        std::cout << "Parsing failedn";
        std::cout << "-------------------------n";
    }
}

Try

    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?为+++设置一个标记不是很有意义吗?