1

this is my first time asking a question here. It has already taken me a lot of time and research to get this working and I can't. I really hope you can help me with it. I am a newbie using Spirit, I do not fully understand all the terms; however, even after reading tons of articles and posts I do not know what am I missing.

So, I have the following struct and class in a header file.

typedef std::string::const_iterator iterator_type;
struct GrammarRules
{
    qi::rule<iterator_type, ascii::space_type> create_char;
};

class Parser
{
    public:
        Parser();
        bool parse(std::string const& to_parse);

    private:
        GrammarRules rules_;
        gtor::World * world_;
};

Then I have the following in the .cpp file:

Parser::Parser()
    : rules_()
    , world_(nullptr)
{
    world_ = new gtor::World();

    qi::rule<iterator_type, std::string(), ascii::space_type> qg_string;
    qg_string %= qi::lexeme[ +(ascii::alnum) ];

    rules_.create_char =
        (
            qi::lit("CreateChar")
            >> '('
            >> qg_string >> ','
            >> qg_string >> ','
            >> qi::int_
            >> ')'
        )
        [
            phx::bind(&gtor::World::createCharacter, world_, qi::_1, qi::_2, qi::_3)
        ]
        ;
}

...

bool Parser::parse(std::string const& to_parse)
{
    iterator_type it  = to_parse.begin();
    iterator_type end = to_parse.end();
    bool success = qi::phrase_parse(it, end, rules_.create_char, ascii::space);

    /*qi::rule<iterator_type, std::string(), ascii::space_type> qg_string;
        qg_string %= qi::lexeme[ +(ascii::alnum) ];

    qi::rule<iterator_type, ascii::space_type> create_char1 =
        (
            qi::lit("CreateChar")
            >> '('
            >> qg_string >> ','
            >> qg_string >> ','
            >> qi::int_
            >> ')'
        )
        [
            phx::bind(&gtor::World::createCharacter, world_, qi::_1, qi::_2, qi::_3)
        ]
        ;
    bool success = qi::phrase_parse(it, end, create_char1, ascii::space);*/

    if (success && it == end)
        return true;

    return false;
}

The code which is not commented on the parse() method doesn't work, I get an Access Violation as soon as the parser gets to the qg_string rule. However, the code that is commented works perfectly. It looks exactly the same to me, except for the obvious differences. Maybe I am missing something very obvious, but I am unable to find it.

It already took me a lot to find that my code worked if I used everything as local variables. And still can't find the problem.

Thank you in advance for any help. Sorry if there are any mistakes in the post (5AM).

FannyVH
  • 11
  • 1
  • I solved it by adding the `qg_string` rule to the structure. Although I do not fully understand why that solved it. Any hints will be greatly appreciated. – FannyVH Mar 01 '12 at 13:25

2 Answers2

2

I have to say, I didn't fully understand the depth of Spirit. But if you declare your qg_string parser in the constructor it does not exist when you call the parse method. As far as I know the rules in a hierarchy still depend on each other. They are not copied into the "parent" rule.

Smittii
  • 187
  • 1
  • 10
1

Like Smittii said, the problem is that the rule no longer exist when parse is called because it is declared locally in the constructor (which will be done executing when parse is called). The one in comment still exist for the whole parse so it works.

Basically the problem is that when you write:

rules_.create_char =
        (
            qi::lit("CreateChar")
            >> '('
            >> qg_string >> ','
            >> qg_string >> ','
            >> qi::int_
            >> ')'
        )

the qg_string is sort of (I don't really know spirit internals so don't quote me on this) only referenced (i.e. not copyed) in the rules_.create_char rule, so when the qg_string rule is destroyed when leaving the constructor it leaves dangling reference to it, leading to the crash you experience.

There exist a copy() function that you could probably make to work but for your problem the obvious solution would be to be the rule in your struct, like you said you did (see how they do in most spirit examples).

(Just in case, you can check this example for an example of using the copy() function but this should not be necessary for your case).

Community
  • 1
  • 1
n1ckp
  • 1,481
  • 1
  • 14
  • 21