Компиляция простого парсера с Boost.Spirit

Часть простой утилиты скелета, которую я взламываю, у меня есть грамматика для запуска замещений в тексте. Я подумал, что это прекрасный способ получить удовольствие от Boost.Spirit, но ошибки шаблона – это радость уникального вида.

Вот код целиком:

#include  #include  #include  #include  namespace bsq = boost::spirit::qi; namespace { template struct skel_grammar : public bsq::grammar { skel_grammar(); private: bsq::rule macro_b; bsq::rule macro_e; bsq::rule id; bsq::rule macro; bsq::rule text; bsq::rule start; }; template skel_grammar::skel_grammar() : skel_grammar::base_type(start) { text = bsq::no_skip[+(bsq::char_ - macro_b)[bsq::_val += bsq::_1]]; macro_b = bsq::lit("<>"); macro %= macro_b >> id >> macro_e; id %= -(bsq::ascii::alpha | bsq::char_('_')) >> +(bsq::ascii::alnum | bsq::char_('_')); start = *(text | macro); } } // namespace int main(int argc, char* argv[]) { std::string input((std::istreambuf_iterator(std::cin)), std::istreambuf_iterator()); skel_grammar grammar; bool r = bsq::parse(input.begin(), input.end(), grammar); std::cout << std::boolalpha << r << '\n'; return 0; } 

Что случилось с этим кодом?

Ммм. Я чувствую, что мы обсудили несколько подробностей в чате, чем были отражены в вопросе, как есть.

Позвольте мне развлечь вас своей реализацией «игрушек», в комплекте с тестовыми примерами, грамматики, которая будет распознавать <> как это, включая nested расширение того же.

Известные функции:

  1. Расширение выполняется с помощью обратного вызова ( process() ), что дает вам максимальную гибкость (вы можете использовать таблицу поиска, вызывать синтаксический анализ в зависимости от макросодержания или даже иметь побочные эффекты независимо от вывода
  2. синтаксический анализатор оптимизирован для поддержки режима streamовой передачи. Посмотрите на spirit::istream_iterator о том, как анализировать вход в streamовом режиме ( spirit::istream_iterator на основе streamов ). Это имеет очевидные преимущества, если ваш входной stream составляет 10 ГБ и содержит только 4 макроса – это разница между скоростью сканирования (или нехваткой памяти) и просто масштабированием.
    • обратите внимание, что демо все еще записывается в строковый буфер (через oss ). Однако вы можете легко подключить вывод напрямую к std::cout или, скажем, к экземпляру std::ofstream
  3. Расширение выполняется с нетерпением, поэтому вы можете иметь отличные эффекты с использованием косвенных макросов. Смотрите контрольные образцы
  4. Я даже продемонстрировал упрощенный способ поддержки экранов << или >> ( #define SUPPORT_ESCAPES )

Без дальнейших церемоний:

Код

Заметка из-за лени, мне требуется -std==c++0x , но только когда SUPPORT_ESCAPES определен

 //#define BOOST_SPIRIT_DEBUG #include  #include  namespace qi = boost::spirit::qi; namespace phx= boost::phoenix; namespace fsn= boost::fusion; namespace { #define SUPPORT_ESCAPES static bool process(std::string& macro) { if (macro == "error") { return false; // fail the parse } if (macro == "hello") { macro = "bye"; } else if (macro == "bye") { macro = "We meet again"; } else if (macro == "sideeffect") { std::cerr << "this is a side effect while parsing\n"; macro = "(done)"; } else if (std::string::npos != macro.find('~')) { std::reverse(macro.begin(), macro.end()); macro.erase(std::remove(macro.begin(), macro.end(), '~')); } else { macro = std::string("<<") + macro + ">>"; // this makes the unsupported macros appear unchanged } return true; } template struct skel_grammar : public qi::grammar { struct fastfwd { template struct result { typedef bool type; }; template bool operator()(const R&r,O& o) const { #ifndef SUPPORT_ESCAPES o = std::copy(r.begin(),r.end(),o); #else auto f = std::begin(r), l = std::end(r); while(f!=l) { if (('\\'==*f) && (l == ++f)) break; *o++ = *f++; } #endif return true; // false to fail the parse } } copy; skel_grammar(OutIt& out) : skel_grammar::base_type(start) { using namespace qi; #ifdef SUPPORT_ESCAPES rawch = ('\\' >> char_) | char_; #else # define rawch qi::char_ #endif macro = ("<<" >> ( (*(rawch - ">>" - "<<") [ _val += _1 ]) % macro [ _val += _1 ] // allow nests ) >> ">>") [ _pass = phx::bind(process, _val) ]; start = raw [ +(rawch - "<<") ] [ _pass = phx::bind(copy, _1, phx::ref(out)) ] % macro [ _pass = phx::bind(copy, _1, phx::ref(out)) ] ; BOOST_SPIRIT_DEBUG_NODE(start); BOOST_SPIRIT_DEBUG_NODE(macro); # undef rawch } private: #ifdef SUPPORT_ESCAPES qi::rule rawch; #endif qi::rule macro; qi::rule start; }; } int main(int argc, char* argv[]) { std::string input = "Greeting is <> world!\n" "Side effects are <> and <> vars are untouched\n" "Empty <<>> macros are ok, as are stray '>>' pairs.\n" "<> (<>?) work>>\n" "The order of expansion (evaluation) is _eager_: '<<<>>>' will expand to the same as '<>'\n" "Lastly you can do algorithmic stuff too: <>>>\n" #ifdef SUPPORT_ESCAPES // bonus: escapes "You can escape \\<> (not expanded to '<>')\n" "Demonstrate how it <> macros>>.\n" #endif ; std::ostringstream oss; std::ostream_iterator out(oss); skel_grammar > grammar(out); std::string::iterator f(input.begin()), l(input.end()); bool r = qi::parse(f, l, grammar); std::cout << "parse result: " << (r?"success":"failure") << "\n"; if (f!=l) std::cout << "unparsed remaining: '" << std::string(f,l) << "'\n"; std::cout << "Streamed output:\n\n" << oss.str() << '\n'; return 0; } Пространство //#define BOOST_SPIRIT_DEBUG #include  #include  namespace qi = boost::spirit::qi; namespace phx= boost::phoenix; namespace fsn= boost::fusion; namespace { #define SUPPORT_ESCAPES static bool process(std::string& macro) { if (macro == "error") { return false; // fail the parse } if (macro == "hello") { macro = "bye"; } else if (macro == "bye") { macro = "We meet again"; } else if (macro == "sideeffect") { std::cerr << "this is a side effect while parsing\n"; macro = "(done)"; } else if (std::string::npos != macro.find('~')) { std::reverse(macro.begin(), macro.end()); macro.erase(std::remove(macro.begin(), macro.end(), '~')); } else { macro = std::string("<<") + macro + ">>"; // this makes the unsupported macros appear unchanged } return true; } template struct skel_grammar : public qi::grammar { struct fastfwd { template struct result { typedef bool type; }; template bool operator()(const R&r,O& o) const { #ifndef SUPPORT_ESCAPES o = std::copy(r.begin(),r.end(),o); #else auto f = std::begin(r), l = std::end(r); while(f!=l) { if (('\\'==*f) && (l == ++f)) break; *o++ = *f++; } #endif return true; // false to fail the parse } } copy; skel_grammar(OutIt& out) : skel_grammar::base_type(start) { using namespace qi; #ifdef SUPPORT_ESCAPES rawch = ('\\' >> char_) | char_; #else # define rawch qi::char_ #endif macro = ("<<" >> ( (*(rawch - ">>" - "<<") [ _val += _1 ]) % macro [ _val += _1 ] // allow nests ) >> ">>") [ _pass = phx::bind(process, _val) ]; start = raw [ +(rawch - "<<") ] [ _pass = phx::bind(copy, _1, phx::ref(out)) ] % macro [ _pass = phx::bind(copy, _1, phx::ref(out)) ] ; BOOST_SPIRIT_DEBUG_NODE(start); BOOST_SPIRIT_DEBUG_NODE(macro); # undef rawch } private: #ifdef SUPPORT_ESCAPES qi::rule rawch; #endif qi::rule macro; qi::rule start; }; } int main(int argc, char* argv[]) { std::string input = "Greeting is <> world!\n" "Side effects are <> and <> vars are untouched\n" "Empty <<>> macros are ok, as are stray '>>' pairs.\n" "<> (<>?) work>>\n" "The order of expansion (evaluation) is _eager_: '<<<>>>' will expand to the same as '<>'\n" "Lastly you can do algorithmic stuff too: <>>>\n" #ifdef SUPPORT_ESCAPES // bonus: escapes "You can escape \\<> (not expanded to '<>')\n" "Demonstrate how it <> macros>>.\n" #endif ; std::ostringstream oss; std::ostream_iterator out(oss); skel_grammar > grammar(out); std::string::iterator f(input.begin()), l(input.end()); bool r = qi::parse(f, l, grammar); std::cout << "parse result: " << (r?"success":"failure") << "\n"; if (f!=l) std::cout << "unparsed remaining: '" << std::string(f,l) << "'\n"; std::cout << "Streamed output:\n\n" << oss.str() << '\n'; return 0; } в //#define BOOST_SPIRIT_DEBUG #include  #include  namespace qi = boost::spirit::qi; namespace phx= boost::phoenix; namespace fsn= boost::fusion; namespace { #define SUPPORT_ESCAPES static bool process(std::string& macro) { if (macro == "error") { return false; // fail the parse } if (macro == "hello") { macro = "bye"; } else if (macro == "bye") { macro = "We meet again"; } else if (macro == "sideeffect") { std::cerr << "this is a side effect while parsing\n"; macro = "(done)"; } else if (std::string::npos != macro.find('~')) { std::reverse(macro.begin(), macro.end()); macro.erase(std::remove(macro.begin(), macro.end(), '~')); } else { macro = std::string("<<") + macro + ">>"; // this makes the unsupported macros appear unchanged } return true; } template struct skel_grammar : public qi::grammar { struct fastfwd { template struct result { typedef bool type; }; template bool operator()(const R&r,O& o) const { #ifndef SUPPORT_ESCAPES o = std::copy(r.begin(),r.end(),o); #else auto f = std::begin(r), l = std::end(r); while(f!=l) { if (('\\'==*f) && (l == ++f)) break; *o++ = *f++; } #endif return true; // false to fail the parse } } copy; skel_grammar(OutIt& out) : skel_grammar::base_type(start) { using namespace qi; #ifdef SUPPORT_ESCAPES rawch = ('\\' >> char_) | char_; #else # define rawch qi::char_ #endif macro = ("<<" >> ( (*(rawch - ">>" - "<<") [ _val += _1 ]) % macro [ _val += _1 ] // allow nests ) >> ">>") [ _pass = phx::bind(process, _val) ]; start = raw [ +(rawch - "<<") ] [ _pass = phx::bind(copy, _1, phx::ref(out)) ] % macro [ _pass = phx::bind(copy, _1, phx::ref(out)) ] ; BOOST_SPIRIT_DEBUG_NODE(start); BOOST_SPIRIT_DEBUG_NODE(macro); # undef rawch } private: #ifdef SUPPORT_ESCAPES qi::rule rawch; #endif qi::rule macro; qi::rule start; }; } int main(int argc, char* argv[]) { std::string input = "Greeting is <> world!\n" "Side effects are <> and <> vars are untouched\n" "Empty <<>> macros are ok, as are stray '>>' pairs.\n" "<> (<>?) work>>\n" "The order of expansion (evaluation) is _eager_: '<<<>>>' will expand to the same as '<>'\n" "Lastly you can do algorithmic stuff too: <>>>\n" #ifdef SUPPORT_ESCAPES // bonus: escapes "You can escape \\<> (not expanded to '<>')\n" "Demonstrate how it <> macros>>.\n" #endif ; std::ostringstream oss; std::ostream_iterator out(oss); skel_grammar > grammar(out); std::string::iterator f(input.begin()), l(input.end()); bool r = qi::parse(f, l, grammar); std::cout << "parse result: " << (r?"success":"failure") << "\n"; if (f!=l) std::cout << "unparsed remaining: '" << std::string(f,l) << "'\n"; std::cout << "Streamed output:\n\n" << oss.str() << '\n'; return 0; } 

Выход теста

 this is a side effect while parsing parse result: success Streamed output: Greeting is bye world! Side effects are (done) and <> vars are untouched Empty <<>> macros are ok, as are stray '>>' pairs. <> (bye?) work>> The order of expansion (evaluation) is _eager_: 'We meet again' will expand to the same as 'We meet again' Lastly you can do algorithmic stuff too: eyb in reverse! You can escape <> (not expanded to 'bye') Demonstrate how it <> macros>>. 

Существует много функций, скрытых там, чтобы заглянуть. Я предлагаю вам посмотреть тестовые примеры и обратный вызов process() рядом друг с другом, чтобы узнать, что происходит.

Приветствия и HTH 🙂

  • Как я могу удалить свой stream при реализации загрузки файла в ASP.NET?
  • Преобразование значения временного интервала для форматирования «hh: mm Am / Pm» с использованием C #
  • Полная обратная передача, вызванная LinkButton внутри GridView внутри UpdatePanel
  • Каков наилучший способ реализации «таймера»?
  • открыть файл в эксклюзивном режиме в C #
  • Каковы правильные параметры ссылок для использования std :: thread в GCC под linux?
  • Как создать дерево выражений для представления «String.Contains (« term ») в C #?
  • Несколько / одиночный экземпляр Linq to SQL DataContext
  • Подавление "предупреждения CS4014: поскольку этот вызов не ожидается, выполнение текущего метода продолжается ..."
  • Спецификатор преобразования длинного двойника в C
  • Запуск процесса в C # без отвлекающего windows консоли
  • Давайте будем гением компьютера.