Spirit::Qi - iterator ist nicht an letzter geparster Stelle



  • Ich habe das Problem, dass der übergebene Iterator an phrase_parse nicht an der erwarteten Stelle liegt (hinter dem geparsten Teil) trotz Erfolg.
    Die Qi Grammatik hat schon ein paar Zeilen, aber mit dem Code sieht man vermutlich eher wo das Problem liegt:

    namespace QiSubroutines {
        namespace qi = boost::spirit::qi;
        namespace ascii = boost::spirit::ascii;
        namespace fusion = boost::fusion;
        namespace phoenix = boost::phoenix;
    
        typedef std::vector <std::pair <std::string, std::string> > paramContainerType;
    
        struct SubroutineBase {
            std::string name;
            paramContainerType parameters;
            std::string rType;
            char definition;
        };
    }
    
    BOOST_FUSION_ADAPT_STRUCT(
        QiSubroutines::SubroutineBase,
        (std::string, name)
        (QiSubroutines::paramContainerType, parameters)
        (std::string, rType)
        (char, definition)
    )
    
    namespace QiSubroutines {
        template <typename iterator_type>
        struct subroutine_parser : qi::grammar <iterator_type, SubroutineBase(), ascii::space_type>
        {
            subroutine_parser(): subroutine_parser::base_type(start, "subroutine")
            {
                using qi::lexeme;
                using ascii::char_;
                using qi::alpha;
                using qi::space;
                using qi::on_error;
                using qi::fail;
                using qi::lit;
                using qi::on_success;
    
                using phoenix::at_c;
                using phoenix::push_back;
                using namespace qi::labels;
    
                using phoenix::construct;
                using phoenix::val;
    
                valid_text %= lexeme[+alpha];
    
                argpair =
                       lexeme[+alpha            [at_c<0>(_val) += _1]]
                    >  lexeme[+alpha            [at_c<1>(_val) += _1]]
                    >> -char_(',')
                ;
    
                retType =
                        lit("->")
                    >   valid_text              [_val = _1]
                ;
    
                start =
                       valid_text                   [at_c<0>(_val) = _1]
                    >  char_('(')
                    >  *argpair                     [phoenix::push_back(at_c<1>(_val), _1)]
                    >  char_(')')
                    >  -retType                     [at_c<2>(_val) = _1]
                    >  (char_(';') | char_('{'))    [at_c<3>(_val) = _1]
                ;
    
                start.name("qi_subroutine");
                argpair.name("argpair");
                valid_text.name("valid_text");
                retType.name("return_value");
    
                on_error<fail>
                (
                    start,
                    std::cout   << val("Error in subroutine parser - expecting: ")
                                << _4
                                << val(" at: ")
                                << (_3 - _1)
                                << val(" in expression: ")
                                << construct<std::string> (_1, _3)
                                << val("\n")
                 );
            }
    
            qi::rule <iterator_type, std::string(), ascii::space_type> valid_text;
            qi::rule <iterator_type, std::pair<std::string, std::string> (), ascii::space_type> argpair;
            qi::rule <iterator_type, std::string(), ascii::space_type> retType;
            qi::rule <iterator_type, SubroutineBase(), ascii::space_type> start;
        };
    }
    

    Ich verwende diese Grammatik um folgende Ausdrücke zu parsen:

    functionName(int one, float two, double three) -> int

    Aufruf: (seeker hat den typ: memoryStream::const_iterator, was eigentlich std::vector<char>::const_iterator bedeutet.)

    SubroutineBase base;
    auto startpoint = seeker;
    bool ret = phrase_parse<memoryStream::const_iterator>
        (seeker,
        cleanedScript._data.end(),
        subroutine_parser<memoryStream::const_iterator>(),
        space,
        base);
    if (!ret)
        THROW("Subroutine parser could not parse subroutine", seeker);
    else {
        std::cout << "Success!\n";
        if (startpoint == seeker)
            std::cout << "wait what?";
    }
    

    Ich sehe in der Ausgabe aber leider:

    Success!
    wait what?

    (Die Daten wurden auch erfolgreich in die Struktur kopiert)

    Ich zitiere dazu das Tutorial

    The parse function returns true or false depending on the result of the parse. The first iterator is passed by reference. On a successful parse, this iterator is repositioned to the rightmost position consumed by the parser. If this becomes equal to last, then we have a full match. If not, then we have a partial match

    Dieses Verhalten ist mir sehr wichtig, denn sonst kann ich nicht sauber weiterparsen.

    Notiz: Hinter dem Ausdruck geht es weiter mit Daten.
    Notiz2: Ich tippe darauf, dass der Iterator an der richtigen Stelle landet, wenn ich die Fehlerbehandlungsfeatures nicht einsetze. (ungetestet)

    EDIT: Wie kann ich das ändern?



  • Wenn der iterator nicht gleich last ist, gibt es doch noch das erfolgreiche Parsen eines partial match, das sollte also eigentlich gültig sein, aber ich hab qi seit Ewigkeiten nicht mehr angerührt. Was ist denn eigentlich in den Elementen vom zurückgegebenen iterator? Wenn es nur whitespaces sind, sollte das doch noch OK sein. Schon mal den Wert geprüft, der geparst wurde? Ist er denn Korrekt?

    Wenn das trotzdem nicht akzeptiert werden soll, kann man doch immernoch zu der Rückgabewertprüfung hinzufügen, dass die iteratoren verglichen werden.

    PS: Ich kann das Beispiel auch nicht testen.



  • Der Typname memoryStream::const_iterator macht mich misstrauisch. Ist das ein Forward-Iterator?



  • mit einem "iterator" anstatt dem "const_iterator" funktioniert es prima.



  • Inwiefern soll die constness eine Rolle spielen? Der Parser ließt doch eigentlich nur. Ist der Input der gleiche?



  • Inwiefern soll die constness eine Rolle spielen?

    Keine Ahnung, aber ich habe eine Sache nach der anderen geändert und wieder zurückgeändert, und bei dieser Änderung hat es dann geklappt.

    EDIT: letztes Edit zurück ^^ Ich bleibe bei der Aussage.


Anmelden zum Antworten