boost::spirit und kopfschmerzen mit semantic actions
-
Nabend zusammen!
Ich habe mich seit einigen Tagen mit boost::spirit beschäftigt, und komme momentan an die Grenzen meines Verständnisses.
Es geht darum, eine momentan noch recht simple Konfigurationsdatei zu parsen.
(Bevor ich mich an kommaseparierte Listen wage versuche ich mich zuerst einmal mit einem relativ trivialen Beispiel).aus dieser zeile möchte ich mit spirit die daten extrahieren, aber mir will es nicht gelingen einen vernünftigen funktor zu konstruieren.
define material red 1 0 0 1 0 0 1 0 0 1mein ansatz war bisher:
typedef struct { float r; float g; float b; } RGB_DATA; float rgbval; rule<> _RGBVALUE = longest_d[limit_d(0u, 1u)[int_p[assign_a(rgbval)]] | limit_d(0.0, 1.0)[real_p[assign_a(rgbval)]]]; RGB_DATA color; rule<> _RGB = _RGBVALUE[assign_a(color.r, rgbval)] >> space_p >> _RGBVALUE[assign_a(color.g, rgbval)] >> space_p >> _RGBVALUE[assign_a(color.b, rgbval)]; std::string name; rule<> _NAME = ((alpha_p) | chlit<>('_')) >> *((alnum_p) | chlit<>('_')); double exponent; rule<> _EXPONENT = longest_d[int_p[assign_a(exponent)] | real_p[assign_a(exponent)]]; typedef struct { std::string name; RGB_DATA ka; RGB_DATA kd; RGB_DATA ks; double exp; } MATERIAL_DATA; MATERIAL_DATA m; rule<> DEF_MATERIAL = _DEFINE >> space_p >> strlit<>("material") >> space_p >> _NAME[assign_a(name)] >> space_p>> _RGB >> space_p >> _RGB >> space_p >> _RGB >> space_p >> _EXPONENT >> _EOL;ab hier stößt meine spielerei mit assign_a() an seine grenzen.
meine versuche einen funktionierenden funktor (nach inspiration der Einführung mit dem INI-Parser) zu schreiben sind kläglich gescheitert. Hat jemand eine Idee wie ich hier weiterkommen kann? Oder kann mich jemand in die richtige Richtung stupsen?Lieben Gruß
Ike
-
Und wo liegt das Problem? Was ist das gewünschte Resultat? Was passiert stattdessen?
IIRC parst real_p auch Integer. Die Unterscheidung in _RGBVALUE und _EXPONENT kannst du dir also sparen.
-
ja, schon klar...
ich verstehe nur nicht wie ich so eine etwas "komplexere" datenstruktur wie MATERIAL_DATA vernünftig gefüllt kriege
-
Versuchs mal so:
MATERIAL_DATA m; rule<> DEF_MATERIAL = _DEFINE >> space_p >> strlit<>("material") >> space_p >> _NAME[assign_a(m.name)] >> space_p >> _RGB[assign_a(m.ka, color)] >> space_p >> _RGB[assign_a(m.kd, color)] >> space_p >> _RGB[assign_a(m.ks, color)] >> space_p >> _EXPONENT[assign_a(m.exp, exponent)] >> _EOL;Und dann evtl. noch die üblichen Konventionen/Vorsichtsmaßnahmen beachten und die führenden unterstriche vermeiden...
-
Ich habe mir dafür dann extra Parser geschrieben, die einen entsprechenden
Resulttype hatten. Da kannst du dann auch einfach assign_a auf einen komplexeren Datentyp anwenden (sofern Assignment unterstützt wird).Zum Beispiel folgende Datenstruktur:
const unsigned int RGB = 0; const unsigned int GRAY = 1; struct Color { unsigned int type; unsigned char c1, c2, c3; Color() : type(RGB), c1(0), c2(0), c3(0) { } Color(unsigned int type, unsigned char c1, unsigned char c2, unsigned char c3) : type(type), c1(c1), c2(c2), c3(c3) { } };Dann hatte ich dafür folgenden Parser:
struct ColorParser : public boost::spirit::parser<ColorParser> { typedef ColorParser self_t; template<typename ScannerT> struct result { typedef typename boost::spirit::match_result<ScannerT, Color>::type type; }; template <typename ScannerT> typename boost::spirit::parser_result<self_t, ScannerT>::type parse(ScannerT const& scan) const { using namespace boost::spirit; typedef typename ScannerT::iterator_t Iterator; typedef typename boost::spirit::parser_result<self_t, ScannerT>::type ResultType; Color color; Iterator save = scan.first; ResultType result = ( (str_p("RGB(")[assign_a(color.type, RGB)] >> limit_d(0u, 255u)[uint_p[assign_a(color.c1)]] >> "," >> limit_d(0u, 255u)[uint_p[assign_a(color.c2)]] >> "," >> limit_d(0u, 255u)[uint_p[assign_a(color.c3)]] >> ")") | (str_p("GRAY(")[assign_a(color.type, GRAY)] >> limit_d(0u, 255u)[uint_p[assign_a(color.c1)]] >> ")") ).parse(scan); if (result) { return match<Color>(result.length(), color); } scan.first = save; return scan.no_match(); } }; const ColorParser color_p = ColorParser();Einsetzen kann man sowas dann (sinngemäß) wiefolgt:
Color c1, c2; parse("RGB(255, 0, 0) GRAY(192)", color_p[assign_a(c1)] >> color_p[assign_a(c2)], space_p);Leider ließen sich die Farbtypen nicht als Enums festlegen, assign_a hat dann immer irgendwelche unsinnigen Werte zugewiesen.