f



Best choice for command interpreter?

Hello,

     I'm facing a rather simple problem as part of a program that needs some
kind of command interpreter. Basically, the user has a prompt at which he
enters various commands, and these commands result in the execution of
various functions. Nothing new or difficult here.

     At some point, though, I've been asking myself a question about the
right way(TM) to do this. Assuming each different command has an associated
function to execute, what are the good and bad sides of the possible
mechanisms that can be used to implement that.

     Specifically, I've been looking at the following possibilities:

     1. The simplest and most obvious way would probably be to keep some kind
of mapping between the command names and function pointers. So, when the
user enters say, "quit", I do a lookup for the word "quit" in the map, and
obtain the pointer to the function DoQuit(), and all is well.

     My only concern about this is the fact that it is exactly what I would
do in C... That is, since I'm programming in C++, there must be a
better/nicer/cooler way... A way that would make good use of the wonders of
OO programming, templates, or anything... That being said, if I could
convince myself that this is the way with more advantages, I would of course
not hesitate to use it.

     2. Another possibility I've been looking at is to have a hierarchy of
"Command" classes, which would contain some kind of "execute()" virtual
function. I would then use a factory that would be able to create the right
derived class according to the command name, and call the execute() function
through a pointer to the base Command class.

     That, however, seems awfully complicated for such a simple problem, not
to mention the fact that it would entail creating/destroying a heap object
for each command called, for apparently no good reason. Unless there is some
advantage I can't see here, it doesn't seem to make much sense.

     3. I've also been wondering if it could be possible to replace to
function pointers in solution (1) with functors, giving me about the same
facility, plus some of the small added value functors can sometimes allow.

     However, I couldn't find a clean way to map the names to the functors,
as they would obviously all be different types(and thus couldn't be used as
the value of, say, an std::map).

     That being said, I'm still trying to find more possibilities, but the
more I look at it, the more the function pointers solution appeals to me,
and I just wanted to know if someone else had a better way of doing this, or
a better justification for the solutions presented above.

     Thanks

     -Nicholas


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Nicholas
6/30/2003 9:19:45 AM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8509) is leader. Post Follow

2 Replies
645 Views

Similar Articles

[PageSpeed] 10

"Nicholas Mongeau" <Lazar_Dobrescu@hotmail.com> wrote in message
news:<LBMLa.3233$Ec2.107177@news20.bellglobal.com>...

>      I'm facing a rather simple problem as part of a program that
> needs some kind of command interpreter. Basically, the user has a
> prompt at which he enters various commands, and these commands result
> in the execution of various functions. Nothing new or difficult here.

>      At some point, though, I've been asking myself a question about
> the right way(TM) to do this. Assuming each different command has an
> associated function to execute, what are the good and bad sides of the
> possible mechanisms that can be used to implement that.

>      Specifically, I've been looking at the following possibilities:

>      1. The simplest and most obvious way would probably be to keep
> some kind of mapping between the command names and function
> pointers. So, when the user enters say, "quit", I do a lookup for the
> word "quit" in the map, and obtain the pointer to the function
> DoQuit(), and all is well.

>      My only concern about this is the fact that it is exactly what I
> would do in C... That is, since I'm programming in C++, there must be
> a better/nicer/cooler way... A way that would make good use of the
> wonders of OO programming, templates, or anything... That being said,
> if I could convince myself that this is the way with more advantages,
> I would of course not hesitate to use it.

The fact that it is exactly what one might do in C isn't an argument, if
it is the best solution.

>      2. Another possibility I've been looking at is to have a
> hierarchy of "Command" classes, which would contain some kind of
> "execute()" virtual function. I would then use a factory that would be
> able to create the right derived class according to the command name,
> and call the execute() function through a pointer to the base Command
> class.

>      That, however, seems awfully complicated for such a simple
> problem, not to mention the fact that it would entail
> creating/destroying a heap object for each command called, for
> apparently no good reason. Unless there is some advantage I can't see
> here, it doesn't seem to make much sense.

Why would you have to create a new object each time?  My usual solution
for this sort of thing is to use a field array (see my site) to break
the input into fields, then a std::map< std::string, Command* > to get
the correct handler -- the individual handlers are static variables
whose constructor registered them with the map.

In fact, I have a general wrapper for this particular use of map, which
allows a default as well.  An unknown command handler registers as the
default, which means that even error handling falls out as a standard
case.  Comments and continuation lines are handled by filtering
streambuf's, so the basic command loop looks something like:

    GB_BlankSeparatedFields
                        commandLine ;
    std::string         line ;
    while ( std::getline( source, line ) ) {
        commandLine = line ;
        if ( commandLine.fieldCount() > 0 ) {
            commandMapInstance()[ commandLine[ 1 ] ]
                ->processCommand( commandLine ) ;
        }
    }

(The command map uses the singleton pattern to handle order of
initialization issues.)

>      3. I've also been wondering if it could be possible to replace to
> function pointers in solution (1) with functors, giving me about the
> same facility, plus some of the small added value functors can
> sometimes allow.

>      However, I couldn't find a clean way to map the names to the
> functors, as they would obviously all be different types(and thus
> couldn't be used as the value of, say, an std::map).

They can all have a common base class, and the std::map contains a
pointer to the base.

>      That being said, I'm still trying to find more possibilities, but
> the more I look at it, the more the function pointers solution appeals
> to me, and I just wanted to know if someone else had a better way of
> doing this, or a better justification for the solutions presented
> above.

To tell the truth, the only advantage of my prefered method over
function pointers is that the static objects can take care of their own
registration, so the map fills itself automatically.  With function
pointers, you have to fill it somewhere yourself.  (The static objects
can also have state, but given that there is always exactly one of each
type, this is not a big deal.)

--
James Kanze             GABI Software
mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/
http://www.gabi-soft.fr
                           Beratung in objektorientierter
Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T�l. : +33 (0)1 30 23 45
16

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
kanze
7/1/2003 1:45:38 PM
"Nicholas Mongeau" <Lazar_Dobrescu@hotmail.com> wrote in message
news:<LBMLa.3233$Ec2.107177@news20.bellglobal.com>...
> Hello,
> 
>      I'm facing a rather simple problem as part of a program that needs some
> kind of command interpreter. Basically, the user has a prompt at which he
> enters various commands, and these commands result in the execution of
> various functions. Nothing new or difficult here.

[...]

>      3. I've also been wondering if it could be possible to replace to
> function pointers in solution (1) with functors, giving me about the same
> facility, plus some of the small added value functors can sometimes allow.

Yes, it's possible, use map<string, boost::function<void()> >.

void quit();

struct X
{
  void set_visible(bool visible);
} x;

std::map< std::string, boost::function<void()> > commands;

int main()
{
  commands["quit"] = &quit;
  commands["show"] = boost::bind(&X::set_visible, &x, true);
  commands["hide"] = boost::bind(&X::set_visible, &x, false);
}

HTH

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
pdimov
7/2/2003 2:51:34 AM
Reply: