Boost logo

Boost Users :

From: Joel de Guzman (djowel_at_[hidden])
Date: 2003-04-04 20:47:01


Hi,

Spirit has its own mailing list. I'll reply to your questions but
it would be best to contibue our discussion there 1) to save
bandwidth, and 2) so that other Spirit users (and experts :-)
can chime in.... More replies at the bottom...

brockpeabody wrote:
> Does anyone know the best way to return a rule from a function by
> value? I know that the following does not work, but what's the best
> workaround?
>
> struct calculator : grammar<calculator> {
>
> template <typename ScannerT> struct definition {
>
> definition(const calculator&) {
>
> r = make_complex_rule('A') | make_complex_rule('B');
> }
>
> typedef rule<ScannerT> rule_type;
>
> rule_type const& start() { return r;}
>
> private:
>
> rule_type make_complex_rule(char c) {
>
> return c >> real_p; //boom
> }
>
> rule_type r;
> };
> };
>
> my current workaround is the following nastiness:
>
> //inside struct calculator::definition<>
>
> rule_type& anonymous_rule() {
>
> anonymous_rules.push_back(
> boost::shared_ptr<rule_type>(new rule_type));
>
> return *anonymous_rules.back();
> }
>
> rule_type& make_complex_rule(char c) {
>
> return anonymous_rule() = c >> real_p;
> }
>
> std::vector<boost::shared_ptr<rule_type> > anonymous_rules;
>
> Is there a better way?

Short story: Rules *CANNOT* be stored in containers.

Long story:

Actually, Spirit v1.5.1 rules can be stored as you've tried to do. Unfortunately,
the C++ copy/assignment semantics differ too much from EBNF that
when I tried to merge a hybrid, people complained and it caused lots of
confusion (see the Boost Spirit review sometime in October 2002).

That said, there is *really* a pressing need to store rules in containers.
Such an ability will open the possibility to do quite interesting dynamic
parsing. The consensus was to leave the rule as it is and have another
class "rule_holder" that has the behavior that you desire, i.e. storable
in containers.

Hmmm, maybe this reply is not too helpful. Well, before we have the
rule_holder, you can probably rip-off Spirit 1.5.1's rule, rename it and
use it as such:

http://spirit.sourceforge.net/index.php?doc=download/v1_5.html

<< you have to massage it a bit, e.g. change the namespace to
boost::spirit, etc. >>

If you wish to go this route, tell me and I'd gladly help out.

>
> Also, I've got an easy one... Why is a grammar passed by const
> reference to its definition? Does Spirit make copies of the grammars
> internally? I ask because otherwise the grammar class seems like the
> ideal place to store state information (like numbers on a calculator's
> stack).

Short story: Grammar definitions are created upon entering the grammar's
parse function. Parser parse functions are const.

Long story: Arghhhh.... do you really want to hear the long story? :-)

Anyway, parsers, and thus grammars, are best be lightweight. The
best way to store state information in the grammar is through a
reference to external state. Example:

struct state
{
    /* some vars here */
};

struct my_grammar
{
    my_grammar(state& compiler_) state(state_) {}

    state& compiler;
};

Then when you instantiate your grammar:

    state my_compiler;
    my_grammar g(my_compiler);

>
> Thanks ahead of time!

Welcome ahead of time :-)

-- 
Joel de Guzman
joel at boost-consulting.com
http://www.boost-consulting.com
http://spirit.sf.net

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