Получить текущую строку в грамматике повышения духа

Я пытаюсь получить текущую строку файла, который я анализирую, используя Boost Spirit. Я создал класс грамматики и свои структуры для анализа моих команд. Я также хотел бы отследить, на какой линии была найдена команда, и проанализировать ее в моих структурах. Я обернул свой итератор файла istream в итератор multi_pass, а затем обернул его в boost::spirit::classic::position_iterator2. В моих правилах моей грамматики, как я могу получить текущую позицию итератора, или это невозможно?

Обновление: это похоже на эту проблему, но мне просто нужно иметь возможность вести подсчет всех обработанных строк. Мне не нужно делать всю дополнительную буферизацию, которая была сделана в решении.

1 ответ

Решение

Обновление: это похоже на эту проблему, но мне просто нужно иметь возможность вести подсчет всех обработанных строк. Мне не нужно делать всю дополнительную буферизацию, которая была сделана в решении.

Ведение подсчета всех обработанных строк - это не то же самое, что "получение текущей строки".

Простой дубль

Если это то, что вам нужно, просто проверьте это после разбора:

Live On Wandbox

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_line_pos_iterator.hpp>
#include <fstream>
#include <set>
namespace qi = boost::spirit::qi;

int main() {
    using It = boost::spirit::istream_iterator;

    std::ifstream ifs("main.cpp");
    boost::spirit::line_pos_iterator<It> f(It(ifs >> std::noskipws)), l;

    std::set<std::string> words;
    if (qi::phrase_parse(f, l, *qi::lexeme[+qi::graph], qi::space, words)) {
        std::cout << "Parsed " << words.size() << " words";
        if (!words.empty())
            std::cout << " (from '" << *words.begin() << "' to '" << *words.rbegin() << "')";
        std::cout << "\nLast line processed: " << boost::spirit::get_line(f) << "\n";
    }
}

Печать

Parsed 50 words (from '"' to '}')
Last line processed: 22

Чуть более сложный дубль

Если вы скажете "нет, подождите, я действительно хочу получить текущую строку / во время синтаксического анализа /". Настоящий полный Монти здесь:

Вот полностью урезанная версия с использованием iter_pos:

Live On Wandbox

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/support_line_pos_iterator.hpp>
#include <boost/spirit/repository/include/qi_iter_pos.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <fstream>
#include <map>

namespace qi = boost::spirit::qi;
namespace qr = boost::spirit::repository::qi;

using LineNum = size_t;

struct line_number_f {
    template <typename It> LineNum operator()(It it) const { return get_line(it); }
};

static boost::phoenix::function<line_number_f> line_number_;

int main() {
    using Underlying = boost::spirit::istream_iterator;
    using It = boost::spirit::line_pos_iterator<Underlying>;
    qi::rule<It, LineNum()> line_no = qr::iter_pos [ qi::_val = line_number_(qi::_1) ];

    std::ifstream ifs("main.cpp");
    It f(Underlying{ifs >> std::noskipws}), l;

    std::multimap<LineNum, std::string> words;

    if (qi::phrase_parse(f, l, +(line_no >> qi::lexeme[+qi::graph]), qi::space, words)) {
        std::cout << "Parsed " << words.size() << " words.\n";

        if (!words.empty()) {
            auto& first = *words.begin();
            std::cout << "First word: '" << first.second << "' (in line " << first.first << ")\n";
            auto& last = *words.rbegin();
            std::cout << "Last word: '" << last.second << "' (in line " << last.first << ")\n";
        }

        std::cout << "Line 20 contains:\n";
        auto p = words.equal_range(20);
        for (auto it = p.first; it != p.second; ++it)
            std::cout << " - '" << it->second << "'\n";

    }
}

Печать:

Parsed 166 words.
First word: '#include' (in line 1)
Last word: '}' (in line 46)
Line 20 contains:
 - 'int'
 - 'main()'
 - '{'
Другие вопросы по тегам