簡體   English   中英

Boost :: spirit :: qi解析器不消耗整個字符串

[英]Boost::spirit::qi parser not consuming entire string

我正在為一個簡單的計算器創建語法,但是我很難確定一個特定測試用例無法正常工作的原因。 這是解析器的一個功能示例:

#include <iostream>
#include <vector>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
using namespace boost::spirit;
using namespace boost::phoenix;
using std::endl;
using std::cout;
using std::string;
using std::vector;

void fPushOp(const string& op){
  cout << "PushOp: " << op << endl;
}

void fPushInt(string& my_str){
  cout << "PushInt: " << my_str << endl;
}

template<class Iterator>
struct Calculator : public qi::grammar<Iterator> {

    qi::rule<Iterator>  
      expression, logical_or_expression, logical_and_expression, negate_expression, series_expression,
      single_expression, inclusive_or_expression, exclusive_or_expression, and_expression, equality_expression, 
      relational_expression, shift_expression, additive_expression, multiplicative_expression, 
      term, complement_factor, factor, number, integer, variable, variable_combo, word, result;

    Calculator() : Calculator::base_type(result)
    {
          number = 
              lexeme[
                qi::as_string[
                    ("0x" >> +qi::char_("0-9a-fA-F"))     
                  | ("0b" >> +qi::char_("0-1"))
                  | ("0" >>  +qi::char_("0-7"))
                  | +qi::char_("0-9")
                ] [bind(&fPushInt, qi::_1)]
              ] 
             ;

          complement_factor = number
              | ('~' >> number)[bind(&fPushOp, "OP_COMPLEMENT")]
              | ('!' >> number)[bind(&fPushOp, "OP_NEGATE")];
              ;
          term = complement_factor
            >> *( (".." >> complement_factor)[bind(&fPushOp, "OP_LEGER")]
                | ('\\' >> complement_factor)[bind(&fPushOp, "OP_MASK")]
                ); 
          multiplicative_expression = term
            >> *( ('/' >> term)[bind(&fPushOp, "OP_DIV")]
                | ('%' >> term)[bind(&fPushOp, "OP_MOD")]
                | ('*' >> term)[bind(&fPushOp, "OP_MUL")]
                );
          additive_expression = multiplicative_expression
            >> *( ('+' >> multiplicative_expression)[bind(&fPushOp, "OP_ADD")]
                | ('-' >> multiplicative_expression)[bind(&fPushOp, "OP_SUB")]
                );
          shift_expression = additive_expression
            >> *( (">>" >> additive_expression)[bind(&fPushOp, "OP_SRL")]
                | ("<<" >> additive_expression)[bind(&fPushOp, "OP_SLL")]
                );
          relational_expression = shift_expression
            >> *( ('<' >> shift_expression)[bind(&fPushOp, "OP_LT")]
                | ('>' >> shift_expression)[bind(&fPushOp, "OP_GT")]
                | ("<=" >> shift_expression)[bind(&fPushOp, "OP_LET")]
                | (">=" >> shift_expression)[bind(&fPushOp, "OP_GET")]
                );
          equality_expression = relational_expression 
            >> *( ("==" >> relational_expression)[bind(&fPushOp, "OP_EQ")]
                | ("!=" >> relational_expression)[bind(&fPushOp, "OP_NEQ")] 
                );
          and_expression = equality_expression 
            >> *(('&' >> equality_expression)[bind(&fPushOp, "OP_AND")]); 
          exclusive_or_expression = and_expression 
            >> *(('^' >> and_expression)[bind(&fPushOp, "OP_XOR")]); 
          inclusive_or_expression = exclusive_or_expression 
            >> *(('|' >> exclusive_or_expression)[bind(&fPushOp, "OP_OR")]); 
          single_expression = inclusive_or_expression;
          series_expression = inclusive_or_expression 
            >> *((',' >> inclusive_or_expression)[bind(&fPushOp, "OP_SERIES")]);
          logical_and_expression = series_expression
            >> *(("&&" >> series_expression)[bind(&fPushOp, "OP_LOGICAL_AND")]); 
          logical_or_expression = logical_and_expression 
            >> *(("||" >> logical_and_expression)[bind(&fPushOp, "OP_LOGICAL_OR")]);
          expression = logical_or_expression;

          result = expression;
    }
};

int main(){
  Calculator<string::const_iterator> calc;
  const string expr("!3 && 0,1");
  string::const_iterator it = expr.begin();
  parse(it, expr.end(), calc, qi::space);
  cout << "Remaining: " << (string(it,expr.end())) << endl;

  return 0;
}

預期的輸出如下:

PushInt: 3
PushOp: OP_NEGATE
PushInt: 0
PushInt: 1
PushOp: OP_SERIES
PushOp: OP_LOGICAL_AND
Remaining: 

expr!3 && 0,1時的當前輸出似乎表明&& 0,1沒有被消耗:

PushInt: 3
PushOp: OP_NEGATE
Remaining:  && 0,1

如果expr!3&&0,1 ,那么它可以正常工作。 在調用qi::parse時使用qi::space跳線時,我看不出這兩個字符串的區別。 誰能指出我的問題?

您的規則不會聲明船長:

qi::rule<Iterator>  

因此,它們隱式為lexeme 有關與船長有關的lexeme[]的背景信息,請參見Boost Spirit船長問題

正確應用船長

  • 您需要在語法和規則定義中聲明船長

     template<class Iterator, typename Skipper = qi::space_type> struct Calculator : public qi::grammar<Iterator, Skipper> { qi::rule<Iterator, Skipper> expression, logical_or_expression, logical_and_expression, negate_expression, series_expression, single_expression, inclusive_or_expression, exclusive_or_expression, and_expression, equality_expression, relational_expression, shift_expression, additive_expression, multiplicative_expression, term, complement_factor, factor, result; qi::rule<Iterator> number, integer, variable, variable_combo, word; 
  • 傳遞船長類型的實例時需要使用phrase_parse

     phrase_parse(it, expr.end(), calc, qi::space); 

固定碼

進一步說明:

  • 清理包含文件(最好包含完整的phoenix.hpp因為如果您遺漏了一些細微的位,您被莫名其妙的bug所咬。當然,如果您知道哪些位,可以通過選擇性地包含子頭來減少編譯時間)
  • 除非絕對必要,否則我強烈建議不要using namespace 在這種情況下,您很容易在bind的多個品牌之一之間產生混淆。 而且,不,僅說using boost::phoenix::ref是不夠的,因為

     using boost::phoenix::ref; std::string s; bind(foo, ref(s))(); 

    由於ADL而最終使用std::ref而不是boost::phoenix::ref

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

void fPushOp(const std::string& op){
    std::cout << "PushOp: " << op << std::endl;
}

void fPushInt(std::string& my_str){
    std::cout << "PushInt: " << my_str << std::endl;
}

template<class Iterator, typename Skipper = qi::space_type>
struct Calculator : public qi::grammar<Iterator, Skipper> {

    qi::rule<Iterator, Skipper>  
      expression, logical_or_expression, logical_and_expression,
        negate_expression, series_expression, single_expression,
        inclusive_or_expression, exclusive_or_expression, and_expression,
        equality_expression, relational_expression, shift_expression,
        additive_expression, multiplicative_expression, term,
        complement_factor, factor, result;

    qi::rule<Iterator>  
        number, integer, variable, variable_combo, word;

    Calculator() : Calculator::base_type(result)
    {
        number = 
            qi::lexeme[
              qi::as_string[
                  ("0x" >> +qi::char_("0-9a-fA-F"))     
                | ("0b" >> +qi::char_("0-1"))
                | ("0" >>  +qi::char_("0-7"))
                | +qi::char_("0-9")
              ] [phx::bind(&fPushInt, qi::_1)]
            ] 
           ;

        complement_factor = number
            | ('~' >> number)[phx::bind(&fPushOp, "OP_COMPLEMENT")]
            | ('!' >> number)[phx::bind(&fPushOp, "OP_NEGATE")];
            ;
        term = complement_factor
          >> *( (".." >> complement_factor)[phx::bind(&fPushOp, "OP_LEGER")]
              | ('\\' >> complement_factor)[phx::bind(&fPushOp, "OP_MASK")]
              ); 
        multiplicative_expression = term
          >> *( ('/' >> term)[phx::bind(&fPushOp, "OP_DIV")]
              | ('%' >> term)[phx::bind(&fPushOp, "OP_MOD")]
              | ('*' >> term)[phx::bind(&fPushOp, "OP_MUL")]
              );
        additive_expression = multiplicative_expression
          >> *( ('+' >> multiplicative_expression)[phx::bind(&fPushOp, "OP_ADD")]
              | ('-' >> multiplicative_expression)[phx::bind(&fPushOp, "OP_SUB")]
              );
        shift_expression = additive_expression
          >> *( (">>" >> additive_expression)[phx::bind(&fPushOp, "OP_SRL")]
              | ("<<" >> additive_expression)[phx::bind(&fPushOp, "OP_SLL")]
              );
        relational_expression = shift_expression
          >> *( ('<' >> shift_expression)[phx::bind(&fPushOp, "OP_LT")]
              | ('>' >> shift_expression)[phx::bind(&fPushOp, "OP_GT")]
              | ("<=" >> shift_expression)[phx::bind(&fPushOp, "OP_LET")]
              | (">=" >> shift_expression)[phx::bind(&fPushOp, "OP_GET")]
              );
        equality_expression = relational_expression 
          >> *( ("==" >> relational_expression)[phx::bind(&fPushOp, "OP_EQ")]
              | ("!=" >> relational_expression)[phx::bind(&fPushOp, "OP_NEQ")] 
              );
        and_expression = equality_expression 
          >> *(('&' >> equality_expression)[phx::bind(&fPushOp, "OP_AND")]); 
        exclusive_or_expression = and_expression 
          >> *(('^' >> and_expression)[phx::bind(&fPushOp, "OP_XOR")]); 
        inclusive_or_expression = exclusive_or_expression 
          >> *(('|' >> exclusive_or_expression)[phx::bind(&fPushOp, "OP_OR")]); 
        single_expression = inclusive_or_expression;
        series_expression = inclusive_or_expression 
          >> *((',' >> inclusive_or_expression)[phx::bind(&fPushOp, "OP_SERIES")]);
        logical_and_expression = series_expression
          >> *(("&&" >> series_expression)[phx::bind(&fPushOp, "OP_LOGICAL_AND")]); 
        logical_or_expression = logical_and_expression 
          >> *(("||" >> logical_and_expression)[phx::bind(&fPushOp, "OP_LOGICAL_OR")]);
        expression = logical_or_expression;

        result = expression;
    }
};

int main(){
  Calculator<std::string::const_iterator> calc;

  const std::string expr("!3 && 0,1");
  std::string::const_iterator it = expr.begin();

  phrase_parse(it, expr.end(), calc, qi::space);

  std::cout << "Remaining: " << std::string(it,expr.end()) << std::endl;

  return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM