2

I need to match some input, construct a complex object and then match the rest input in two ways, depending on some props. of constructed object. I've tried the qi::eps(/condition/) >> p1 | p2 but results is obvious for me. The simplified code http://liveworkspace.org/code/1NzThA$6

In code snippet I match int_ from input and if the value == 0 try to match 'a' either - 'b' But I've got OK for '0b' input! I've tried to play with braces but no luck.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Possible workaround via qi::lazy http://liveworkspace.org/code/2B4VCK$8 – user2008982 Jan 25 '13 at 18:57
  • I've added an answer without semantic actions ([Boost Spirit: “Semantic actions are evil”?](http://stackoverflow.com/questions/8259440/boost-spirit-semantic-actions-are-evil/8259585#8259585)) – sehe Jan 29 '13 at 08:33
  • @sehe: semantic actions are evil: a good part of your post is devoted to when they are actually essential :) Point taken though, but IMHO the question related to context sensitivity in the parser, rather than making it an actual parsing problem, and the example was a trivial expression of that. My 2c. Still, it would be nice if one of us got accepted ... – FatalFlaw Jan 30 '13 at 13:12
  • @FatalFlaw: That was the title of the _question_, not my answer :) My point is, avoiding semantic actions keeps your grammar simple and easy to maintain (and compiletimes and dependencies on e.g. Phoenix low). I have patience, I'm sure the OP will someday revisit this – sehe Jan 30 '13 at 14:16

2 Answers2

3

I personally wouldn't use semantic actions (or phoenix) this lightly. It's not the "Spirit" of Qi (pun half-intended).

This is my take:

rule<char const*, char()> r = 
   (omit [ int_(0) ] >> char_('a')) |
   (omit [ int_(1) ] >> char_('b'))
   ;

See? Much cleaner. Also: automatic attribute propagation. See it live on http://liveworkspace.org/code/1T9h5

Output:

ok: a
fail
fail
ok: b

Full sample code:

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;

template <typename P>
inline
void test_parser(char const* input, P const& p, bool full_match = true)
{
    char const* f(input);
    char const* l(f + strlen(f));
    char result;
    if (qi::parse(f, l, p, result) && (!full_match || (f == l)))
        std::cout << "ok: " << result << std::endl;
    else
        std::cout << "fail" << std::endl;
}

int main()
{
   int p;
   using namespace qi;
   rule<char const*, char()> r = 
       (omit [ int_(0) ] >> char_('a')) |
       (omit [ int_(1) ] >> char_('b'))
       ;

   BOOST_SPIRIT_DEBUG_NODE(r);

   test_parser("0a", r); //should match
   test_parser("0b", r); //should not match
   test_parser("1a", r); //should not match
   test_parser("1b", r); //should match
}
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
1

Here's your rule:

qi::rule<char const*> r =
    qi::int_ [phoenix::ref(p) = qi::_1]
    >> (qi::eps(phoenix::ref(p) == 0)
        >> qi::char_('a') | qi::char_('b'))

That to me says: accept '0a' or anything that ends with 'b'. That matches the results you get in your code snippet.

I confess I don't entirely understand your question, but if you are trying to get a kind of 'exclusive or' thing happening (as indicated by the comments in your code snippet), then this rule is incomplete. The workaround (actually more of a 'fix' than a 'workaround') you presented in your comment is one solution, though you don't need the qi::lazy as the phoenix-based Qi locals are already lazy, but you are on the right track. Here's another (more readable?) solution.

qi::rule<char const*> r =
    qi::int_ [phoenix::ref(p) = qi::_1]
    >> ((qi::eps(phoenix::ref(p) == 0) >> qi::char_('a')) | 
        (qi::eps(phoenix::ref(p) == 1) >> qi::char_('b')))
;

If you prefer to use the locals<> you added in your comment, that's fine too, but using the reference to p adds less overhead to the code, as long as you remember not to set p anywhere else in your grammar, and you don't end up building a grammar that recurses that rule :)

FatalFlaw
  • 1,077
  • 11
  • 19