2016-11-03 6 views
3

Ich habe versucht, einen Parser zu definieren, wo die Regeln nicht vollständig vordefiniert sind, d. H. Sie enthalten einen variablen Teil. Das war kein Problem mit Spirit Qi, aber ich konnte es wegen der statischen Natur von X3 nicht implementieren. Ich habe versucht, die mit Direktive, die leider undokumentiert ist, aber bisher ohne Glück. Die einzigen Beispiele, die ich bisher gefunden habe, sind in einem Lambda-Ausdruck.Parser-Regel abhängig von Parameter

Ich konstruierte ein einfaches Beispiel, um das Problem zu demonstrieren: Ganzzahlen analysieren, wobei das Trennzeichen als Parameter angegeben ist.

#include <boost/spirit/home/x3.hpp> 
#include <iostream> 

namespace x3 = boost::spirit::x3; 

namespace parsing { 
    x3::rule<struct parser> parser {"parser"}; 

    //struct separator {}; 
    char separator(','); 

    //auto parser_def = x3::int_ % x3::lit(x3::get<separator>(/* context */)); // candidate function template not viable: requires single argument 'context' 
    auto parser_def = x3::int_ % x3::lit(separator); 

    BOOST_SPIRIT_DEFINE(parser) 
} 

void parse(const std::string &data, const char separator) { 
    using namespace std; 

    //auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi; 
    auto parser = parsing::parser >> x3::eoi; 

    if (x3::parse(data.begin(), data.end(), parser)) 
     cout << "Parse succeeded\n"; 
    else 
     cout << "Parse failed\n"; 
} 

int main() { 
    parse("1 2 3", ' '); 
    parse("1,2,3", ','); 
    parse("1;2;3", ';'); 
} 

bemerkte ich aus den Teilen, wo ich die mit der Richtlinie zu verwenden versucht.

Ist das derzeit mit X3 möglich? Hat jemand das schon mal gemacht?

+0

Gerade laut hier denken heraus ... können Sie Ihre eigene 'parse' Funktion erstellen, die den Aufruf der Parse-Funktion entsprechend'% 'weiterleitet. In diesem Fall können Sie den Separator wahrscheinlich aus dem 'Kontext' (was ein Argument ist, das der Parse-Funktion gegeben wird) mit 'x3 :: get' erhalten? – Arunmu

Antwort

1

Nachdem bei einigen mehr X3 Beiträge suchen, war ich von dieser Antwort von sehe erleuchtet: https://stackoverflow.com/a/38303379/7110782

über x3 Wissen :: _ Pass mich zu dieser Lösung geführt:

#include <boost/spirit/home/x3.hpp> 
#include <iostream> 

namespace x3 = boost::spirit::x3; 

namespace parsing { 
    x3::rule<struct parser> parser {"parser"}; 

    struct separator {}; 

    // only the separator which is currently in the context is allowed (passes) 
    auto isSeparator = [](auto& ctx){ x3::_pass(ctx) = x3::_attr(ctx) == x3::get<separator>(ctx); }; 

    // at first match any char and then check whether it is the separator 
    auto parser_def = x3::int_ % x3::char_[isSeparator]; 

    BOOST_SPIRIT_DEFINE(parser) 
} 

void parse(const std::string &data, const char separator) { 
    using namespace std; 

    auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi; 

    if (x3::parse(data.begin(), data.end(), parser)) 
     cout << "Parse succeeded\n"; 
    else 
     cout << "Parse failed\n"; 
} 

int main() { 
    // succeed 
    parse("1 2 3", ' '); 
    parse("1,2,3", ','); 
    parse("1;2;3", ';'); 

    // fail 
    parse("1,2,3", ' '); 
    parse("1;2;3", ','); 
} 

Was zu testen bleibt ein weiterer Schritt ist die Möglichkeit mehrere Parameter zu setzen (wahrscheinlich über Cascading x3 :: mit <>).

Edit:

Ja, mehrere Parameter durch Kaskadierung x3 :: mit < Einstellung> scheint zu funktionieren. Zum Beispiel:

auto parser = x3::with<parsing::separator>(ref(separator))[x3::with<parsing::separator2>(ref(separator2))[parsing::parser]] >> x3::eoi; 
Verwandte Themen