Generating Spirit parser expressions from a variadic list of alternative parser expressions

前端 未结 2 440
别跟我提以往
别跟我提以往 2020-11-30 13:27

I\'m looking for the simplest way to implement variadic function which takes list of boost::spirit::qi rules and expands the list into expression of format: rule1 | rule2 |

2条回答
  •  伪装坚强ぢ
    2020-11-30 13:36

    You accidentally returned the TStruct type from the expandBitwise helper. Fix it like so:

    template
    auto expandBitwise(T const& t) -> decltype(t.rule_)
    {
        return t.rule_;
    }
    
    template
    auto expandBitwise(T const& t,Tail const&... tail) -> decltype(t.rule_)
    {
        return t.rule_ | expandBitwise(tail...);
    }
    

    If you want to expose attributes, the return type deduction rules become more involved. Basically, what you're doing is replicating the EDSL part of Spirit.


    Let's swap stories...

    Clippy: It looks like you are trying to write a commandline argument parser. Would you like help with that?

    Implementing the DSL mechanics for your option parser could be done more systematically by creating a new Proto Domain and actually creating the terminals. This would somehow appeal to me now.

    Alternatively you could take this from another angle completely, using the Nabialek Trick. This happens to be an approach I played with just a few weeks ago, and I'll share with you the design I had come up with: https://gist.github.com/sehe/2a556a8231606406fe36#file-test-cpp

    The important part is, where the grammar is "fixed":

    start    = -argument % '\0';
    unparsed = as_string  [ +~nul ] [ std::cerr << phx::val("ignoring unparsed argument: '") << _1 << "'\n" ];
    argument = ('-' >> +shortopt) | ("--" >> longopt) >> -unparsed | unparsed;
    

    The trick being in:

    shortopt = shortNames [_a = _1] >> lazy(_a);
    longopt  = longNames  [_a = _1] >> lazy(_a);
    

    Where shortNames and longNames are qi::symbols tables of parsers, built dynamically, based on a variadic list of CliOptions and CliFlags (I pass them as a tuple, because I wanted to store the result inside the CliOption struct as well).

    The qi::lazy(_a) invokes the parser that was stored in the symbol table.

    As a bonus, my CliOptions parser has a feature to generate "Usage" information as well. The builders for parse expressions as well as usage informations are extensible.

    int main(int argc, char* argv[])
    {
        using CliParsing::make_option;
    
        typedef std::string::const_iterator It;
    
        auto config = std::make_tuple(
            make_option('a', "absolutely", "absolutely"),
            make_option('b', "borked"    , "borked")    ,
            make_option('c', "completion", "completion"),
            make_option('d', "debug",      "turn on debugging"),
            make_option('e', "",           "no long name")  ,
            //make_option('f', "flungeons" , "flungeons") ,
            //make_option('g', "goofing"   , "")   ,
            //make_option('m', "monitor",    "monitoring level"),
            make_option('t', "testing"   , "testing flags"),
            make_option('\0',"file"      , "with a filename (no short name)"),
    
            make_option('y', "assume-yes", "always assume yes"),
            make_option('v', "verbose",    "increase verbosity level"),
            make_option('i', "increment",  "stepsize to increment with", 5)
            );
    
        CliParsing::OptionGrammar parser(config);
    
        using namespace phx::arg_names;
        const auto cmdline = std::accumulate(argv+1, argv+argc, std::string(), arg1 + arg2 + '\0');
    
        bool ok = qi::parse(begin(cmdline), end(cmdline), parser);
    
        std::cout << "Parse success " << std::boolalpha << ok << "\n";
        std::cout << parser.getUsage();
    
        return ok? 0 : 255;
    }
    

    When invoked with some random arguments -i 3 --completion -t --file=SOME.TXT -b huh?, prints:

    short form option --increment parsed
    ignoring unparsed argument: '3'
    long form switch --completion parsed
    short form switch --testing parsed
    long form switch --file parsed
    ignoring unparsed argument: '=SOME.TXT'
    short form switch --borked parsed
    ignoring unparsed argument: 'huh?'
    
    Parse success true
     --absolutely (-a)
        absolutely (flag)
     --borked (-b)
        borked (flag)
     --completion (-c)
        completion (flag)
     --debug (-d)
        turn on debugging (flag)
     -e
        no long name (flag)
     --testing (-t)
        testing flags (flag)
     --file
        with a filename (no short name) (flag)
     --assume-yes (-y)
        always assume yes (flag)
     --verbose (-v)
        increase verbosity level (flag)
     --increment (-i)
        stepsize to increment with (option with value; default '5')
    

    As you can see, not all options have been implemented yet (notably, -- to mark the end of the option list).

提交回复
热议问题