2014-12-24 2 views
1

Я пытаюсь проанализировать цитированную строку с помощью escape-последовательностей с помощью Boost :: Spirit. К сожалению, кажется, что включение котировок в определение грамматики вызывает массовые (-не бесполезные) ошибки времени компиляции (как можно было бы ожидать с помощью Boost). Опускание котировок позволяет компилировать программу, но, очевидно, она не будет вести себя так, как предполагалось. Это код (на самом деле часть более широкой картины, но она демонстрирует проблему):Boost :: Spirit не удается скомпилировать при попытке выполнить синтаксический анализ цитируемого строкового литерала

#include "boost/spirit/include/qi.hpp" 
#include "boost/proto/deep_copy.hpp" 
#include "boost/optional.hpp" 

#include <string> 

using boost::spirit::qi::char_; 
using boost::spirit::qi::lexeme; 
using boost::proto::deep_copy; 


auto string_literal = deep_copy(
    lexeme[ 
      // char_('"') 
      /* >> */ *((char_ - '"' - '\\') | (char_('\\') >> char_)) 
      // >> char_('"') 
      ]); 


template <class Iterator, class Grammar> 
boost::optional<std::string> parse_string(Iterator first, Iterator last, Grammar&& gr) 
{ 
    using boost::spirit::qi::space; 
    using boost::spirit::qi::phrase_parse; 

    std::string temp; 
    bool success = phrase_parse(
     first, 
     last, 
     gr, 
     space, 
     temp 
    ); 

    if (first == last && success) 
     return temp; 
    else return boost::none; 
} 


int main() 
{ 
    std::string str; 
    std::cout << "string_literal: "; 

    getline(std::cin, str); 

    auto presult = parse_string(str.begin(), str.end(), string_literal); 
    if (presult) { 
     std::cout << "parsed: " << *presult; 
    } else 
     std::cout << "failure\n"; 

    return 0; 
} 

раскомментирован комментировали части string_literal «s определение приводит к ошибкам. В текущем состоянии (с комментариями) код компилируется. Я пробовал несколько вещей, таких как перемещение котировок в parse_string, а также использование менее конкретного определения (одно из них является наименее конкретным, я мог бы придумать, что все еще полезно, правильная грамматика находится в OCaml language manual, но я что я могу просто проверять escape-последовательности отдельно), но ничего не получилось.

Моя версия Boost 1.56.0, а мой компилятор MinGW-w64 g ++ 4.9.1. Любая помощь вообще ценится.

ответ

1

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

Проблема в том, - в конечном счете - с тем, что [1]

(qi::char_('\\') >> qi::char_) | (qi::char_ - '"') 

синтезирует в

boost::variant< 
    boost::fusion::vector2<char, char>, 
    char> 

и не так, как вы, вероятно, ожидали char или std::vector<char>. Правила совместимости атрибутов Духа близки к magic, и они позволяют вам уйти с ним (это довольно чертовски изящно), но это также спрятало проблему из вашего сознания.

Только жаловаться на это, когда вы еще больше усложнили правило.

Теперь я вижу два возможных пути: либо вы хотите вернуть де маскирование значение строки (без кавычек) и изменить его: [2]

qi::lexeme [ 
      '"' >> 
       *(('\\' >> qi::char_) | (qi::char_ - '"')) 
      >> '"' 
     ] 

Или вы хотите, чтобы захватить необработанную строку в кавычках, и вы не заботитесь о выставленных атрибутах на всех:

qi::raw [ 
      '"' >> 
       *(('\\' >> qi::char_) | (qi::char_ - '"')) 
      >> '"' 
     ] 

Последнее использует неявное преобразование атрибута из пары источник-итератор (qi::raw[]) в std::string (связанный атрибут).

Смотрите полную вещь живую:

Live On Coliru

#include <boost/spirit/include/qi.hpp> 
#include <boost/proto/deep_copy.hpp> 
#include <boost/optional.hpp> 

#include <string> 

namespace qi = boost::spirit::qi; 

namespace { 

    auto string_literal = boost::proto::deep_copy(
#if 1 
     qi::lexeme [ 
       '"' >> 
        *(('\\' >> qi::char_) | (qi::char_ - '"')) 
       >> '"' 
      ] 
#else 
     qi::raw [ 
       '"' >> 
        *(('\\' >> qi::char_) | (qi::char_ - '"')) 
       >> '"' 
      ] 
#endif 
     ); 

} 

template <class Iterator, class Grammar> 
boost::optional<std::string> parse_string(Iterator first, Iterator last, Grammar&& gr) 
{ 
    std::string temp; 

    bool success = qi::phrase_parse(
     first, 
     last, 
     std::forward<Grammar>(gr), 
     qi::space, 
     temp 
    ); 

    if (success && first == last) 
     return temp; 
    else return boost::none; 
} 


int main() 
{ 
    std::string str; 
    std::cout << "string_literal: "; 

    getline(std::cin, str); 

    auto presult = parse_string(str.begin(), str.end(), string_literal); 
    if (presult) { 
     std::cout << "parsed: '" << *presult << "'\n"; 
    } else 
     std::cout << "failure\n"; 

    return 0; 
} 

[1] несколько упрощено переупорядочивания ветвей

[2] (обратите внимание, что '\\' эквивалентно qi::lit('\\') неявные преобразования операндов шаблона выражения)

+0

спасибо. Я, честно говоря, не уверен, что думать о Духе больше, все эти ужасы утомляют, и документация, скорее всего, отсутствует. Я бы это знал, если бы я прочитал документацию с обложки до крышки? Независимо от того, это было очень полезно - я, скорее всего, подойду с подходом 'qi :: raw []', так как мой текущий проект сначала рассматривает все литералы как исходные строки, а затем использует отдельную функцию для «извлечения» фактических значений из них , –

+0

Я предполагаю, что вы бы знали: я просто связал http://tinyurl.com/alternative-attributes с http://tinyurl.com/sequence-attributes docs, чтобы добраться до 'варианта , char> там. Если вам нравится, есть ** [способы его обнаружения] (http://stackoverflow.com/questions/9404189/detecting-the-parameter-types-in-a-spirit-semantic -action) **. Тем не менее, да, у Духа есть свои подводные камни (хотя вы немного подталкиваете их, не придерживаясь общих идиом, например, используя «deep_copy», таким образом, обходят края того, что возможно в Spirit v2, мне понравился результирующий стиль, Кстати). – sehe

+0

Мне потребовалось около 10 минут, чтобы действительно увидеть проблему здесь, поэтому вы не услышите, что я говорю, что проблем нет. Опять же, я хорошо знаю дух, и я бы не написал эту ошибку сам (я понял бы эффект 'char _ ('\\')' на синтезированные атрибуты при написании его). Так что, возможно, вам просто нужно дать ему некоторое время. Там определенно компромиссы, и я делал случаи _againt_ Spirit в прошлом. Но я по-прежнему рассматриваю его как очень ценный инструмент для некоторых работ. Я бы не хотел быть без него. – sehe