Используя повышение:: дух, как я требую, чтобы часть записи была на ее собственной строке?

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

Вступительная часть:

#include 
#include 
#include 
#include 

#include 
#include 
#include 

using namespace boost::spirit;
using namespace boost::spirit::ascii;
using namespace boost::spirit::qi;
using namespace boost::spirit::qi::labels;

using boost::phoenix::function;
using boost::phoenix::ref;
using boost::spirit::qi::eol;
using boost::spirit::qi::fail;
using boost::spirit::qi::lit;
using boost::spirit::qi::on_error;

using BOOST_SPIRIT_CLASSIC_NS::file_position;
using BOOST_SPIRIT_CLASSIC_NS::position_iterator;

Мы используем position_iterator от Духа. Классик, таким образом, следующий оператор потоковой вставки удобен.

std::ostream&
operator<<(std::ostream& o, const file_position &fp)
{
  o << fp.file << ": " << fp.line << ',' << fp.column;
  return o;
}

Шаблон err_t факторизует шаблон для выдачи исключений, связанных с различными формами отказа синтаксического анализа.

template 
struct err_t {
  template 
  struct result { typedef void type; };

  template 
  void operator() (info const &what, Iterator errPos, Iterator last) const
  {
    std::stringstream ss;
    ss << errPos.get_position()
       << ": expecting " << what
       << " near '" << std::string(errPos, last) << "'\n";
    throw Exception(ss.str());
  }
};

Исключения, используемые наряду с их err_t обертки:

class MissingA : public std::runtime_error {
  public: MissingA(const std::string &s) : std::runtime_error(s) {}
};

class MissingB : public std::runtime_error {
  public: MissingB(const std::string &s) : std::runtime_error(s) {}
};

class MissingC : public std::runtime_error {
  public: MissingC(const std::string &s) : std::runtime_error(s) {}
};

function > const missingA = err_t();
function > const missingB = err_t();
function > const missingC = err_t();
function > const other_error =
  err_t();

Грамматика ищет простые последовательности. Без eps, start управляйте сбоями, а не a на пустом входе.

template 
struct my_grammar
  : grammar
{
  my_grammar(int &result)
    : my_grammar::base_type(start)
    , result(result)
  {
    a = eps > lit("Header A") > eol;
    b = eps > lit("Header B") > eol;
    c = eps > lit("C:") > int_[ref(result) = _1] > eol;
    start = a > b > c;

    a.name("A");
    b.name("B");
    c.name("C");

    on_error(start, other_error(_4, _3, _2));
    on_error(a, missingA(_4, _3, _2));
    on_error(b, missingB(_4, _3, _2));
    on_error(c, missingC(_4, _3, _2));
  }

  rule start;
  rule a;
  rule b;
  rule c;
  int &result;
};

В my_parse, мы выводим содержание потока в a std::string и используйте position_iterator отслеживать местоположение синтаксического анализа.

int
my_parse(const std::string &path, std::istream &is)
{
  std::string buf;
  is.unsetf(std::ios::skipws);
  std::copy(std::istream_iterator(is),
            std::istream_iterator(),
            std::back_inserter(buf));

  typedef position_iterator itertype;
  typedef my_grammar grammar;
  itertype it(buf.begin(), buf.end(), path);
  itertype end;

  int result;
  grammar g(result);

  bool r = phrase_parse(it, end, g, boost::spirit::ascii::space);
  if (r && it == end) {
    std::cerr << "success!\n";
    return result;
  }
  else {
    file_position fpos = it.get_position();
    std::cerr << "parse failed at " << fpos << '\n';
    return -9999;
  }
}

Наконец, основная программа

int main()
{
  std::stringstream ss;
  ss << "Header A\n"
     << "Header B\n"
     << "C: 3\n";

  int val = my_parse("path", ss);
  std::cout << "val = " << val << '\n';

  return 0;
}

Код выше бросков MissingA:

terminate called after throwing an instance of 'MissingA'
  what():  path: 2,1: expecting  near 'Header B
C: 3
'

Я думал, что шкипер, возможно, использовал новую строку, но попытку lexeme[eol] вместо этого приведенный тот же результат.

Я должен пропускать что-то очевидное, потому что это кажется одним из самого тривиального вида синтаксических анализаторов для записи. Что я делаю неправильно?

6
задан Greg Bacon 11 March 2010 в 22:30
поделиться

1 ответ

Да, шкипер ест символы новой строки. лексема [eol] тоже не помогает, потому что директива lexeme вызывает шкипера перед переключением в режим без шкипера (подробнее см. здесь ).

Чтобы избежать пропуска новой строки, либо используйте другой тип пропуска, либо оберните компоненты eol в no_skip [eol] , что семантически эквивалентно лексеме [ ] , за исключением того, что он не вызывает шкипера. Однако обратите внимание, что no_skip [] был добавлен только недавно, поэтому он будет доступен только в следующем выпуске (Boost V1.43). Но он уже есть в Boost SVN (предварительную документацию см. здесь ).

7
ответ дан 17 December 2019 в 00:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: