Boost logo

Boost Users :

From: Todd Day (today_at_[hidden])
Date: 2006-02-25 20:05:07


>> "ParmName: ParmValue"
>> I'm looking for certain ParmNames, and I have to grab the associated
>> ParmValue.

>[Nat] Maybe the Spirit parser is the wrong place to get specific about
>the ParmNames you're seeking? Maybe what you should do is parse *every*
>item of that form, stuffing the pairs into a std::map. Then you can
>extract from that map the specific items you want.

Nat, thanks for the reply. In the course of writing a reply to you
explaining what I'm really trying to do, I had an "aha" head-slapping
moment. You know how it is... sometimes, just trying to explain a
problem is enough to generate the answer.

In reply to your quoted text above, yes, I should not be specific about
which ParmNames I'm seeking at this level. I was actually using a map;
I had just removed that from my example to make it a bit easier to
understand.

There is a bigger problem that the files I'm looking at may have
mismatched single quotes in the parts of the file I don't care about.
Like this

random-text " random-text random-text

In other words, to a parser looking for quoted text, these single quotes
would appear as damaged, and the parser would still halt like it does
now. The only thing I can be sure of is that "ParmName: ParmValue" will
be properly quoted and non-damaged and consistent within itself.

So it turns out my basic comprehension problem here is similar to one I
had actually gone through when I was first learning pattern matching and
regular expressions under Perl. I went and dug up some old Perl code of
mine that did a similar search to see how I did it back then.

My basic problem is thinking that the parser would continue grinding
through non-matches just by putting a kleene-star on the front of it.
Once I took this into account, a new strategy emerged.

First, search for a single quote. Then try and see if there is a match
at that point. If a match, move to just beyond the match, else just
move to the next character. Repeat.

The code is not as simple as my previous non-working version, since now
I have to use iterators. This example also looks for multiple types of
ParmNames. It comes out looking like the code below. I love that you
can load up a complex map assignment right in the middle of the rule.

map<string,string> smap;
string key;
typedef string::const_iterator iterator_t;
typedef scanner<iterator_t> scanner_t;
typedef rule<scanner_t> rule_t;
typedef parse_info<iterator_t> parse_info_t;

rule_t quote = ch_p('"');
rule_t colon = ch_p(':');
rule_t eat_all_non_quotes = *~ch_p('"');

rule_t parm_names = str_p(DWARF_DEVICE_NAME) | DWARF_DEVICE_TYPE |
DWARF_DEVICE_SOFTWARE_VERSION | DWARF_DEVICE_COMMENTS;
rule_t parm_string = quote >> parm_names[assign_a(key)] >> colon >>
*blank_p >> eat_all_non_quotes[insert_at_a(smap, key)] >> quote;

string str = "\"broken\" (text \"DeviceName: Altera in Controller\"
(blah))";
iterator_t first = str.begin();
iterator_t last = str.end();
parse_info_t pi;
while (first != last)
{
        // skip to first quote character
        pi = parse(first, last, eat_all_non_quotes);
        first = pi.stop;

        // make sure we haven't gone past the end
        if (first != last)
        {
                // eat up any matching parms here
                pi = parse(first, last, parm_string);
                if (pi.hit)
                        first = pi.stop;
                else
                        first++;
        }
}

Thanks for the help,
-todd-


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net