In Boost :: Spirit, wie kann ich einen expectation_failure
von einer Funktion auslösen, die an Boost::Bind
gebunden ist?Wie man einen expectation_failure von einer Funktion in Boost Spirit wirft?
Hintergrund: Ich analysiere eine große Datei, die komplexe Einträge enthält. Wenn ein Eintrag mit einem vorherigen Eintrag inkonsistent ist, möchte ich einen Fehler auslösen und einen expectation_failure
(der die richtige Syntaxanalyse enthält) auslösen. Wenn ich einen Eintrag analysiere, binde ich eine Funktion, die entscheidet, ob der Eintrag mit etwas übereinstimmt, das vorher gesehen wurde.
Ich habe ein kleines Spielzeugbeispiel erfunden, das den Punkt zeigt. Hier möchte ich einfach ein expectation_failure
werfen, wenn die int
nicht teilbar ist um 10:
#include <iostream>
#include <iomanip>
#include <boost/spirit/include/qi.hpp>
#include <boost/bind.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
namespace qi = boost::spirit::qi;
namespace classic = boost::spirit::classic;
void checkNum(int const& i) {
if (i % 10 != 0) // >> How to throw proper expectation_failure? <<
std::cerr << "ERROR: Number check failed" << std::endl;
}
template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, int(), Skipper> {
MyGrammar() : MyGrammar::base_type(start) {
start %= qi::eps > qi::int_[boost::bind(&checkNum, _1)];
}
qi::rule<Iterator, int(), Skipper> start;
};
template<class PosIter>
std::string errorMsg(PosIter const& iter) {
const classic::file_position_base<std::string>& pos = iter.get_position();
std::stringstream msg;
msg << "parse error at file " << pos.file
<< " line " << pos.line << " column " << pos.column << std::endl
<< "'" << iter.get_currentline() << "'" << std::endl
<< std::setw(pos.column) << " " << "^- here";
return msg.str();
}
int main() {
std::string in = "11";
typedef std::string::const_iterator Iter;
typedef classic::position_iterator2<Iter> PosIter;
MyGrammar<PosIter, qi::space_type> grm;
int i;
PosIter it(in.begin(), in.end(), "<string>");
PosIter end;
try {
qi::phrase_parse(it, end, grm, qi::space, i);
if (it != end)
throw std::runtime_error(errorMsg(it));
} catch(const qi::expectation_failure<PosIter>& e) {
throw std::runtime_error(errorMsg(e.first));
}
return 0;
}
ein expectation_failure
Werfen würde bedeuten, dass ich eine Fehlermeldung wie diese auf ein int bekommen, die nicht teilbar ist um 10:
parse error at file <string> line 1 column 2
'11'
^- here
Können Sie anstelle von int_ eine andere Regel erstellen, die nur dann der Ganzzahl entspricht, wenn Ihre Bedingung erfüllt ist? Ich kenne Spirit nicht gut, aber ich würde annehmen, dass es eine ähnliche Regel wie r_bool in AX gibt, die ein Prädikat umschließt, das ist eine ganz normale Situation. –
Ich denke, ich werde so etwas brauchen, leider: http://boost-spirit.com/home/articles/qi-example/creating-your-own-parser-component-for-spirit-qi/ – Frank
Entschuldigung Das ist sehr benutzerunfreundlich. Deshalb brauchst du AX :-) –