Boost logo

Boost :

From: David B. Held (dheld_at_[hidden])
Date: 2002-01-17 18:10:19


-----Original Message-----
From: rogeeff <rogeeff_at_[hidden]>
To: boost_at_[hidden] <boost_at_[hidden]>
Date: Thursday, January 17, 2002 02:47 PM
Subject: [boost] Re: Any interest for a parser class?

>[...]
>--- In boost_at_y..., Dan Nuffer <dnuffer_at_c...> wrote:
>> [...]
>> Learning EBNF is trivial, and I think most programmers already
>> are familiar with it or are familiar with it's concepts (regular
>> expression syntax).
>
>Are you so sure? I do not think so. More over I think that maintanance
>programmer that will encounter need to enhance/change CLA
>parsing would choose to implement something in 2 hours instead of
>spending at least 2 weaks learning Spirit/EBNF. The tool sould be
>simple and obvios enough to encourage to use it even unfamiliar user
>(this is not a general rule, this is applicable just to bacis
>facilities).
>[...]

I honestly don't think anyone who can't grasp EBNF should be
maintaining a CLA parser in the first place. And anyone who takes
2 weeks to learn EBNF *or* Spirit probably shouldn't be programming
at all. I'm just an average programmer, and I learned more than
enough Spirit to write a simple CLA parser in about 2 hours.
Actually writing a parser would take me about 20 minutes. Going
back later and modifying it to do something else would probably
take even less time. Analyzing someone else's Spirit implementation
would not be difficult, since I can already expect a certain form.

Analyzing someone else's hand-coded scratch-made CLA parser
would probably take agonizing hours of precious time that could
have been saved using a common framework. Modifying a hand-made
CLA parser that was made in the 2 hours you allocate would almost
certainly be painful, and even reasonable modifications may require
a complete redesign of the parser, depending on what shortcuts
were used for the original format. Spirit does not impose a heavy
maintenance burden; rather, it relieves quite a bit of it. For just a
few hours of investment, you get all the power of a general-purpose
parser generator that can be used for everything from CLA parsing
to config-file parsing, to internet protocol parsing. Personally, I
would be disinclined to use a constellation of special-purpose
parsers all hand-coded all with their own syntax and rules. I don't
see that as a good use of my time investment. I would much rather
leverage my learning time across a wide range of problems, and
I think Spirit allows me to do that.

Dave

P.S. It doesn't look like some posts I sent earlier made it, so here
is my solution to your sample problem:

globals.h:

extern bool opt_roll;
extern int opt_repeat_count;

main.cpp:

#include <iostream>
#include <boost/spirit/spirit.hpp> // or whatever I need to include
                                   // with current version od Spirit

bool opt_roll = false;
int opt_repeat_count = 0;

void set_opt_roll(char const*, char const*)
{
    opt_roll = true;
}

void show_usage(char const* = 0, char const* = 0)
{
    std::cout << "Usage: blah, blah, blah" << std::endl;
}

int main( int argc, char* argv[] )
{
    std::string cmd_line;

    // Assemble arguments into single command line
    for (int i = 1; i < argc; ++i) {
        cmd_line += argv[i];
        cmd_line += ' ';
    }

   // Here I would like to see the definition of CLA parser that
   // will accept following options:
   // -repeat_number <integer value>
   // -roll
   // -help
   // substrings are accepted (i.e. -repeat 3 should pass)
   // -help should automatically generate usage message to std::cout
   // it also should be generated in case of parsing errors like
   // -rep 3.5

    // -roll
    if ( !(lexeme[strlit("-ro") >> !( chlit('l') >>
!chlit('l') )][&set_opt_roll] |
    // -help
     lexeme[strlit("-h") >> !( chlit('e') >> !( chlit('l') >>
!chlit('p') ) )][&show_usage] |
    // -repeat_number <n>
     (lexeme[strlit("-re") >> !( chlit('p') >> !( chlit('e') >> !(
chlit('a') >>
        !( chlit('t') >> !( chlit('_') >> !( chlit('n') >> !( chlit('u') >>
!( chlit('m') >>
        !( chlit('b') >> !( chlit('e') >> !chlit('r') ) ) ) ) ) ) ) ) ) )]
>>
        int_p[ref(&opt_repeat_count)])

   // Here I would like to see How will I parse using the parser
   // defined

        ).parse(cmd_line.begin(), cmd_line.end())
    ) {
        show_usage();
    }

   // Here I would like to see CLA values access

    if (opt_roll) {
        do_roll();
    }

    if (opt_repeat_count > 0) {
        do_repeat_action();
    }
}

In addition I would like to see how would I access CLA value from
different file in my project:

second.cpp:
#include "globals.h"

void foo()
{
   // Here I would like to see CLA values access

    if (opt_roll) {
        do_roll();
    }

    if (opt_repeat_count > 0) {
        do_repeat_action();
    }
}

Now, granted, the substring matching isn't exactly elegant, but it is
precise; and I'm sure someone with just a little more cleverness than I
could come up with a more elegant solution. Now, let's see a
hand-rolled parser that does the same thing. Later, we can change
the requirements, and see which version is easier to maintain.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk