бодрость духа с альтернативным оператором '|' Потерпеть поражение! когда есть два возможных правила, чтобы пойти - PullRequest
2 голосов
/ 18 сентября 2011

Я работаю над парсером http.Это нашло проблему, когда я пытаюсь разобрать, используя альтернативный оператор.дело не в значениях атрибута, которые я могу исправить, используя hold [].Проблема возникает, когда есть два правила, которые похожи в начале правила.Вот несколько простых правил, чтобы продемонстрировать мою проблему:

qi::rule<string_iterator> some_rule(
        (char_('/') >> *char_("0-9")) /*first rule accept  /123..*/
      | (char_('/') >> *char_("a-z")) /*second rule accept /abc..*/
    );

Затем я анализирую это правило, используя qi::parse, оно потерпит неудачу, если нравится входная строка;"/abcd"

Однако, когда я переключаю второе правило перед первым правилом.Парсер вернет true, я думаю, что проблема в том, что когда парсер использует ввод с первым правилом, а затем обнаруживает, что первое правило - Fail.Это не вернется ко второму правилу, которое является альтернативой первому правилу.

Я пытаюсь поставить hold[] к первому правилу, но это помогает только для генерации атрибута.Это не решает эту проблему.Я понятия не имею, как решить эту проблему, так как в HTTP есть много правил, у которых начало правил такое же, как и у других.


=========== Подробнее о моем коде ===========================
вот моя функция для разбора строки

typedef std::string::const_iterator string_iterator;
typedef qi::rule<string_iterator, std::string()> rules_t;
void parse_to_string(const std::string& s, rules_t& r, std::string& result)
{
    using namespace rule;
    using qi::parse;

    std::string::const_iterator iter = s.begin();
    std::string::const_iterator end = s.end();

    bool err = parse(iter, end, r, result);

    if ( err && (iter==end) )
    {
           std::cout << "[correct]" << result << std::endl;
    }
    else
    {
          std::cout << "[incorrect]" << s << std::endl;
          std::cout << "[dead with]" << result << std::endl;
    }
}

В основном у меня есть этот код;

std::string result;
result = "";
str = "/htmlquery?";
qi::rule<string_iterator, std::string()> rule_wo_question( char_('/') >> *char_("a-z"));
qi::rule<string_iterator, std::string()> rule_w_question( char_('/') >> *char_("a-z") >> char_('?'));
qi::rule<string_iterator, std::string()> whatever_rule( rule_wo_question
                                                        | rule_w_question
                                                       );
parse_to_string(str, whatever_rule, result);

Я получаю этот результат;

[неверно] / htmlquery?[dead with] / htmlquery <= вы можете видеть, что он не может потреблять '?' </p>

однако, когда я переключаю правило таким образом;(Я поставил "rule_w_question" перед "rule_wo_question")

std::string result;
    result = "";
    str = "/htmlquery?";
    qi::rule<string_iterator, std::string()> rule_wo_question( char_('/') >> *char_("a-z"));
    qi::rule<string_iterator, std::string()> rule_w_question( char_('/') >> *char_("a-z") >> char_('?'));
    qi::rule<string_iterator, std::string()> whatever_rule( rule_w_question
                                                            | rule_wo_question
                                                           );
    parse_to_string(str, whatever_rule, result);

Вывод будет;[правильное] / htmlquery?

Первые версии (неправильные) выглядят так, будто анализ использует '/ htmlquery' ("rule_wo_question"), а затем обнаруживает, что не может использовать "?"которые делают это правило несостоятельным.Тогда это правило не может перейти к альтернативному правилу ("rule_w_question").Наконец программа возвращает «[Неправильно]»

Во второй версии я переключаю «rule_w_question» перед «rule_wo_question».Это причина, почему анализатор возвращает «[правильное]» в результате.


============================================================== весь мой код с boost 1.47, связанный с pthread и boost_filesystem, вот мой основной .c

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/network/protocol.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/bind.hpp>
#include <boost/spirit/include/qi_uint.hpp>

using namespace boost::spirit::qi;
namespace qi = boost::spirit::qi;

typedef std::string::const_iterator string_iterator;
typedef qi::rule<string_iterator, std::string()> rules_t;
void parse_to_string(const std::string& s, rules_t& r, std::string& result)
{
    using qi::parse;

    std::string::const_iterator iter = s.begin();
    std::string::const_iterator end = s.end();

    bool err = parse(iter, end, r, result);

    if ( err && (iter==end) )
    {
           std::cout << "[correct]" << result << std::endl;
    }
    else
    {
          std::cout << "[incorrect]" << s << std::endl;
          std::cout << "[dead with]" << result << std::endl;
    }
}





int main()
{
    std::string str, result;
    result = "";
    str = "/htmlquery?";
    qi::rule<string_iterator, std::string()> rule_wo_question( char_('/') >> *char_("a-z"));
    qi::rule<string_iterator, std::string()> rule_w_question( char_('/') >> *char_("a-z") >> char_('?'));
    qi::rule<string_iterator, std::string()> whatever_rule( rule_wo_question
                                                           | rule_w_question
                                                           );
    parse_to_string(str, whatever_rule, result);
    return 0;
}

результат

[incorrect]/htmlquery?

[dead with]/htmlquery

Ответы [ 4 ]

2 голосов
/ 19 сентября 2011

Дух пробует заданные альтернативы в указанной последовательности и прекращает синтаксический анализ после сопоставления с первым.Исчерпывающее сопоставление не выполняется.Если один из вариантов совпадает, он перестает искать.Итак, последовательность альтернатив важна.Вы всегда должны сначала перечислить «самые длинные» альтернативы.

1 голос
/ 18 сентября 2011

Любая причина, почему вы не делаете это вместо этого?

some_rule(
     char_('/')
     >> (
         *char_("0-9")  /\*first rule accept /123..\*/
       | *char_("a-z") /\*second rule accept/abc..\*/
     )
);

Редактировать: На самом деле это будет соответствовать / с последующим пустым ("0-9" 0 раз) и не будет беспокоиться о поиске "az", измените * на +.

0 голосов
/ 22 июля 2013

Это потому, что есть соответствие для вашего первого правила, а Дух жадный.

(char_('/') >> *char_("0-9"))

Подача "/ abcd" в это правило приведет к следующей логике:

  • "/ abcd" -> Является ли '/' следующим символом?Да.Subrule совпадения.-> «abcd» остается.
  • «abcd» -> Есть 0 или более цифр?Да.Есть 0 цифр.Subrule совпадения.-> «abcd» остается.
  • Первое предложение альтернативных ('|') совпадений операторов;пропустить остальные альтернативные пункты.-> «abcd» остается.
  • Соответствует правилу с оставшимся «abcd».Который, вероятно, не анализирует и приводит к вашей ошибке.

Вы можете подумать о замене '*', что означает «0 или более», на «+», что означает «1 или более».

0 голосов
/ 20 сентября 2011
qi::rule<string_iterator> some_rule(
    (char_('/') >> *char_("0-9")) >> qi::eol /*first rule accept  /123..*/
  | (char_('/') >> *char_("a-z")) >> qi::eol /*second rule accept /abc..*/
);

Вместо eol вы можете использовать ',' или какой-либо другой терминатор. Проблема в том, что char_('/') >> *char_("0-9")) соответствует '/', за которым следуют 0 или более чисел. Таким образом, «/ abcd» соответствует «/», а затем прекращает анализ. Решение К-балла - это то, что я хотел бы сделать в этом случае, но это решение предоставляется в качестве альтернативы в случае (по какой-то причине) его неприемлемого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...