5

Basically I'm doing an expression parser. As I'm in need of as good as possible performance, and according to the documentation construction of a grammar can be rather slow, I'd like to reuse the grammar and bind the symbol table just before parsing. As the client of the grammar is likely to have a symbol table that's constructed and maintained ahead of parsing, I'd ideally like to avoid copying of the actual table as well which leads me to the following code ( simplified ) for translating terms:

qi::symbols< char, double >* m_Symbols;
qi::rule< Iterator, double(), ascii::space_type > m_Val;

m_Val = qi::int_[ _val = boost::phoenix::static_cast_< double >( boost::spirit::_1 ) ] | qi::double_ | m_Symbols;

The problem here is m_Symbols. What I'd like is to m_Val to hold m_Symbols by reference, as when we're binding the symbol table I'm naturally modifying the pointer, which I presume can somehow be solved by the use of boost::phoenix::ref? But the larger problem is that I can't seem to use pointer to parsers when compositing new parser. Using dereference in the expression dereferences m_Symbols straight away, which is unwanted, I want to delay the dereferencing to parse time.

Xeo
  • 129,499
  • 52
  • 291
  • 397
Ylisar
  • 4,293
  • 21
  • 27
  • This really seems like the wrong approach to reducing the number of grammar instances. Why not just have a static/singleton instance of the grammar and make it non-copyable? – ildjarn Mar 09 '11 at 19:16
  • Sadly I'd still have to bind the symbol table before parsing, which would result in the same problem. – Ylisar Mar 10 '11 at 12:16

1 Answers1

2

I believe a simple

qi::symbols<char, double>* m_Symbols;
qi::rule<Iterator, double(), ascii::space_type> m_Val;

m_Val = qi::int_ | qi::double_ | qi::lazy(*m_Symbols);

should do what you need. The lazy parser (see here) evaluates its argument (repeatedly) at parse time only.

hkaiser
  • 11,403
  • 1
  • 30
  • 35
  • Thanks for the assistance, awesome with an expert to help out! Sadly I've already tried that solution and it would seem qi::lazy() isn't very happy to accept that expression. I get the following error from MSVC 2008: 1>/main.cpp(75) : error C2784: 'proto::terminal>::type boost::spirit::lazy(const boost::phoenix::actor &)' : could not deduce template argument for 'const boost::phoenix::actor &' from 'boost::spirit::qi::symbols' Which leads me to believe m_Symbols gets dereferenced before passed to lazy()? – Ylisar Mar 10 '11 at 10:48
  • 2
    It would seem the following does the trick: qi::lazy( *boost::phoenix::val( boost::phoenix::ref( m_Symbols ) ) ) . Val acting as a wrapper to deffer the dereference, ref to make sure that the pointer isn't copied. – Ylisar Mar 10 '11 at 12:40