Die Boost C++ Bibliotheken

Aktionen

Die bisherigen Beispiele konnten lediglich ermitteln, ob ein Parser auf eine Eingabe erfolgreich angewandt werden konnte und bis zu welchem Zeichen eine Eingabe erfolgreich geparst wurde. Üblicherweise sollen Parser jedoch Daten laden. So soll zum Beispiel eine Zahl, die mit Hilfe des Parsers boost::spirit::qi::int_ gelesen wurde, verarbeitet werden.

Beispiel 11.9. Aktionen mit Parsern verknüpfen
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>

using namespace boost::spirit;

int main()
{
  std::string s;
  std::getline(std::cin, s);
  auto it = s.begin();
  bool match = qi::phrase_parse(it, s.end(),
    qi::int_[([](int i){ std::cout << i << '\n'; })], ascii::space);
  std::cout << std::boolalpha << match << '\n';
  if (it != s.end())
    std::cout << std::string{it, s.end()} << '\n';
}

Beispiel 11.9 greift auf boost::spirit::qi::int_ zu, um eine Ganzzahl zu lesen. Diesmal soll die gelesene Ganzzahl zusätzlich auf die Standardausgabe ausgegeben werden. Dazu wurde boost::spirit::qi::int_ mit einer Aktion verknüpft. Aktionen sind Funktionen oder Funktionsobjekte, die aufgerufen werden, wenn ein Parser erfolgreich angewandt werden konnte. Die Verknüpfung erfolgt über den Operator operator[], der von boost::spirit::qi::int_ und anderen Parsern überladen ist. So wird im obigen Beispiel eine Lambda-Funktion übergeben, die als einzigen Parameter ein int erwartet und dieses bei Aufruf auf die Standardausgabe ausgibt.

Wenn Sie Beispiel 11.9 ausführen und eine Zahl eingeben, wird diese ausgegeben.

Beachten Sie, dass sich der Typ des Parameters der Aktion nach dem Parser richtet. Während boost::spirit::qi::int_ einen int-Wert übergibt, reicht zum Beispiel boost::spirit::qi::float_ einen float-Wert an die Aktion weiter.

Beispiel 11.10. Boost.Spirit mit Boost.Phoenix
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <string>
#include <iostream>

using namespace boost::spirit;
using boost::phoenix::ref;

int main()
{
  std::string s;
  std::getline(std::cin, s);
  auto it = s.begin();
  int i;
  bool match = qi::phrase_parse(it, s.end(), qi::int_[ref(i) = qi::_1],
    ascii::space);
  std::cout << std::boolalpha << match << '\n';
  if (match)
    std::cout << i << '\n';
  if (it != s.end())
    std::cout << std::string{it, s.end()} << '\n';
}

Beispiel 11.10 verwendet Boost.Phoenix, um den von boost::spirit::qi::int_ geparsten int-Wert in einer Variablen i zu speichern. Gibt boost::spirit::qi::phrase_parse() true zurück, wird i auf die Standardausgabe ausgegeben.

Beachten Sie, dass im obigen Beispiel das Makro BOOST_SPIRIT_USE_PHOENIX_V3 definiert wird, bevor die Headerdatei von Boost.Spirit eingebunden wird. Mit diesem Makro wird die dritte und aktuelle Boost.Phoenix-Version gewählt. Das Makro ist insofern entscheidend, als dass Boost.Phoenix aus Boost.Spirit hervorgegangen ist und Boost.Spirit die zweite Version von Boost.Phoenix enthält. Wenn Sie BOOST_SPIRIT_USE_PHOENIX_V3 nicht definieren, wird über Boost.Spirit die zweite Version von Boost.Phoenix und über die Headerdatei boost/phoenix/phoenix.hpp die dritte Version eingebunden, was zu einem Compilerfehler führt.

Beachten Sie außerdem, wie die Lambda-Funktion im Detail definiert ist. Über boost::phoenix::ref() wird eine Referenz auf die Variable i erstellt. Der Platzhalter _1 stammt jedoch nicht aus Boost.Phoenix, sondern aus Boost.Spirit. Das ist wichtig, weil über boost::spirit::qi::_1 der geparste Wert in dem Typ zur Verfügung gestellt wird, der üblicherweise erwartet wird – im obigen Beispiel ein int. Würde die Lambda-Funktion auf den Platzhalter boost::phoenix::placeholders::arg1 zugreifen, gäbe es einen Compilerfehler. boost::phoenix::placeholders::arg1 würde keinem int-Wert entsprechen, sondern einem anderen Typen aus Boost.Spirit, von dem der int-Wert erhalten werden müsste.

Die Dokumentation von Boost.Spirit enthält eine Übersicht über Hilfsmittel, die das Zusammenspiel mit Boost.Phoenix erleichtern.