dimba
dimba

Reputation: 27581

Man machine interface command syntax and parsing

What I want is to add possibility to interact with application, and be able to extract information from application or event ask it to change some states.

For that purpose I though of building cli utility. The utility will connect to the application and send user commands (one line strings) to the application and wait for response from the application.

The command should contain: - command name (e.g. display-session-table/set-log-level etc.) - optionally command may have several arguments (e.g. log-level=10)

The question to choose syntax and to learn parse it fast and correctly.

I don't want to reinvent the wheel, so maybe there's already an answer out there.

Upvotes: 2

Views: 357

Answers (5)

McBeth
McBeth

Reputation: 1207

I use an unholy mix of readline, boost::spirit, and the factory pattern to handle all that. It wouldn't be nearly as unholy if it weren't for readlines unapologetic C syntax :)

The outer loop looks like this

    while(true)
    {
            char *line(NULL);
            line = readline((cmd.leaf() + " > ").c_str());
            if (line && *line)
            {
                    add_history(line);
                    int error = ParseLine(line,*s_g, std::cout);
                    free(line);

                    if (error == ErrQuit)
                            break;
                    if (error == ErrSave)
                    ....

Each command has a completion function and a parser/completion function

char **completeCreate(const std::vector<std::string> &, const char *text, int depth)
{
    switch (depth)
    {
            case 1:
            case 2:
            {
                    return  rl_completion_matches(text, rl_filename_completion_function);
                    break;
            }
            case 3:
            {
                    return rl_completion_matches(text, rulesFill);
                    break;
            }
    }
    return NULL;
}

Defines the completer for a command that takes two arguments, a filename and a string, which gets registered with the completion mechanism of readline through a factory + macro, that lets me register everything with something that looks like this

REG_COMP(Create, completeCreate);

On the parser side, I have a similar factory setup

int parseCreate(const std::vector<std::string> &names, Game &g, std::ostream &out)
{
    if (names.size() != 4)
            return parseHelpC(names, g, out);

    if (!CreateGame(names[1],names[2],names[3],g))
            return ErrGameCreation;

    return ErrNone;
}
REG_PARSE(Create,"CardList PowerList RuleSet");

that provides the actual logic and help text

I've left out huge swaths of code that glues everything together, but would be happy to share the hideousness that is the code base (it is currently a private git repository) I look forward to see if someone has something that works better.

Upvotes: 0

caf
caf

Reputation: 239041

The Readline library could be useful.

Upvotes: 1

Paul Nathan
Paul Nathan

Reputation: 40319

I would suggest using a JSON library.

Upvotes: 0

Georg Fritzsche
Georg Fritzsche

Reputation: 98974

Take a look at the interpreter example (example usage) from Boost.FunctionTypes. Note however that as it is it only supports free functions.

Upvotes: 2

David
David

Reputation: 7153

boost::program_options is worth a look.

Upvotes: 1

Related Questions