2016-11-02 3 views
4

Я следующий мир кода:повышение :: дух по умолчанию семантическое действие и строка композиции

#include <gtest/gtest.h> 
#include <boost/config/warning_disable.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/qi_eps.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/spirit/include/phoenix_object.hpp> 
#include <boost/spirit/include/phoenix_bind.hpp> 
#include <boost/spirit/include/classic_core.hpp> 
#include <boost/spirit/include/classic_confix.hpp> 
#include <boost/spirit/include/classic_chset.hpp> 
#include <boost/spirit/include/classic_utility.hpp> 
#include <boost/fusion/include/cons.hpp> 
#include <boost/fusion/include/at_c.hpp> 
#include <boost/fusion/include/std_pair.hpp> 
#include <boost/bind.hpp> 
#include <boost/optional/optional_io.hpp> 
#include <boost/variant.hpp> 

namespace spi = boost::spirit; 
namespace qi = boost::spirit::qi; 

TEST(TestBoost, cpp_comment) 
{ 
    using qi::char_; 
    using qi::omit; 
    using qi::eoi; 
    typedef std::string::const_iterator iter; 

    const std::string example = "/* this should be ignored */"; 
    auto b = std::begin(example); 
    auto e = std::end(example); 

    qi::rule<iter, std::string()> cpp_comment = char_('/') >> char_('/') >> *(char_ - '\n') >> (char_('\n') | omit[eoi]); 
    qi::rule<iter, std::string()> c_comment = char_('/') >> char_('*') >> *(char_ - "*/") >> char_('*') >> char_('/'); 
    qi::rule<iter, std::string()> shell_comment = char_('#') >> *(char_ - '\n') >> (char_('\n') | omit[eoi]); 
    qi::rule<iter, std::string()> comment = cpp_comment 
      | c_comment 
      | shell_comment 
      ; 

    std::string result; 

    EXPECT_TRUE(qi::parse(b, e, comment, result)); 
    EXPECT_EQ(b, e); 
    EXPECT_EQ(result, example); 
} 

что терпит неудачу с ошибкой при слежении:

[----------] 1 test from TestBoost 
[ RUN  ] TestBoost.cpp_comment 
tests/spirit.cpp:56: Failure 
     Expected: result 
     Which is: "//* this should be ignored */" 
To be equal to: example 
     Which is: "/* this should be ignored */" 
[ FAILED ] TestBoost.cpp_comment (0 ms) 
[----------] 1 test from TestBoost (0 ms total) 

, и я не понимаю, почему. Вероятно, где-то в документации по ускорению упоминается это поведение, но я не могу его найти. Кто-нибудь знает, почему это происходит?

Если я ставлю семантическое действие, как это:

qi::rule<iter, std::string()> comment = cpp_comment[spi::_val = spi::_1] 
      | c_comment[spi::_val = spi::_1] 
      | shell_comment[spi::_val = spi::_1] 
      ; 

или это

qi::rule<iter, std::string()> comment = cpp_comment[spi::_val += spi::_1] 
      | c_comment[spi::_val += spi::_1] 
      | shell_comment[spi::_val += spi::_1] 
      ; 

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

+0

Пожалуйста, не используйте ненужные вещи, как тест Google или десятки включает в вашем минимальном коде. – sehe

ответ

3

Это классическая проблема с возвратом контейнера атрибуты:

Идея заключается в том, чтобы использовать qi::hold, или еще лучше в этом случае использовать qi::raw потому, что он похоже, что вы хотите выставить всю согласованную входную последовательность в качестве атрибута:

qi::rule<iter, std::string()> 
     cpp_comment = "//" >> *~char_('\n') >> (eol|eoi), 
     c_comment  = "/*" >> *(char_ - "*/") >> "*/", 
     shell_comment = '#' >> *~char_('\n') >> (eol|eoi), 
     comment  = qi::raw [ cpp_comment | c_comment | shell_comment ]; 

Live On Coliru

#include <boost/spirit/include/qi.hpp> 
#include <cassert> 

namespace qi = boost::spirit::qi; 

void test() { 
    using qi::char_; 
    using qi::eol; 
    using qi::eoi; 

    std::string const example = "/* this should be ignored */"; 

    qi::rule<std::string::const_iterator, std::string()> 
      cpp_comment = "//" >> *~char_('\n') >> (eol|eoi), 
      c_comment  = "/*" >> *(char_ - "*/") >> "*/", 
      shell_comment = '#' >> *~char_('\n') >> (eol|eoi), 
      comment  = qi::raw [ cpp_comment | c_comment | shell_comment ]; 

    std::string result; 

    bool ok = qi::parse(std::begin(example), std::end(example), comment >> eoi, result); 
    assert(ok); 

    std::cout << "expected: " << example << "\n"; 
    std::cout << "actual: " << result << "\n"; 
    assert(result == example); 
} 

int main() { 
    test(); 
} 

Печать

expected: /* this should be ignored */ 
actual: /* this should be ignored */ 
+0

Только что реализовано: с 'raw' вам не нужно синтезировать' std :: string' на подправах. – sehe

+0

Большое спасибо за такой хороший ответ. Я просто понял, что в моей сложной грамматике есть потенциально много мест, где этот эффект может произойти, страшная мысль. Помимо альтернативного оператора, есть ли другой известный оператор, где это может произойти? – Sasa

+0

Это может произойти для атрибутов контейнера с неатомическим назначением. См. Связанные ресурсы :) – sehe

 Смежные вопросы

  • Нет связанных вопросов^_^