2

Consider the following parser:

class test
{
public:
  static test from_string(const string &str); //throws!
};

template <typename Iterator = string::const_iterator>
struct test_parser : grammar<Iterator, test(), blank_type>
{
  test_parser() : test_parser::base_type(query)
  {
    query = id[_val = phx::bind(&test::from_string, qi::_1)];
    id = lexeme[*char_("a-zA-Z_0-9")];
  }
  rule<Iterator, test(), blank_type> query;
  rule<Iterator, string(), blank_type> id;
};

I'd like to catch exceptions that test::from_string might throw and to fail the match on exception. I couldn't find direct way to do this, so I'm trying to use an "adapter" function that would accept the context explicitly. But how to access the context and how to attach such an action to the grammar? Please, see the questions within the code:

template<class Context>
void match_test(const string &attr, Context &context, bool &mFlag)
{
  try
  {
    test t = test::from_string(attr);
    // how do I access the context to put t into _val?
  }
  catch(...)
  {
    mFlag = false;
  }
}

//...
test_parser() : test_parser::base_type(query)
{
  query = id[?match_test<?>? /*how to instantiate and use the above semantic action?*/];
  id = lexeme[*char_("a-zA-Z_0-9")];
}
Igor R.
  • 14,716
  • 2
  • 49
  • 83
  • As you can see in [this excellent answer](http://stackoverflow.com/a/3067881/2417774) you'll need to use `boost::fusion::at_c<0>(context.attributes) = t;`. Another alternative that I think should work, but I've never tested, would be using `query = id[phx::try_[_val = phx::bind(&test::from_string, qi::_1)].catch_all[_pass=false] ];`. – llonesmiz Oct 28 '13 at 09:07
  • The `phx::try_[].catch_all[]` alternative seems to only work with phoenix v2. – llonesmiz Oct 28 '13 at 09:34
  • @cv_and_he maybe... we should think of filing bugs here. I don't see why it doesn't work, really – sehe Oct 28 '13 at 10:07
  • 1
    @sehe If you put the `try_catch` in a sequence, for example adding `std::cout << phx::val("testing...")` or something silly such as `qi::_1=qi::_1`, [it compiles](http://coliru.stacked-crooked.com/a/4ff960cb534dc2be). I don't know enough to be confident, but I think the code that deals with semantic actions implicitly expects some requirements from the phoenix expressions, and try_catch doesn't match them. – llonesmiz Oct 28 '13 at 10:28
  • @cv_and_he nice work, I've added a workaround to my answer. Would you care to report this on the list? It's probably just a missing 'statement' trait for `try_catch` expression templates, I reckon – sehe Oct 28 '13 at 10:52

1 Answers1

2

Like the commenter said, use

    query = id[
            phx::try_ [
                qi::_val = phx::bind(&test::from_string, qi::_1)
            ].catch_all [ 
                qi::_pass = false 
            ]
        ];

See it Live on Coliru

A version that compiles even with BOOST_SPIRIT_USE_PHOENIX_V3: Live on Coliru

    query = id[
            phx::try_ [
                qi::_val = phx::bind(&test::from_string, qi::_1)
            ].catch_all [ 
                qi::_pass = false 
            ],
            qi::_pass = qi::_pass // to appease the spirit expression compilation gods
        ];
sehe
  • 374,641
  • 47
  • 450
  • 633
  • I've moved to V3, and it turns out that the above workaround doesn't work: the semantic action just doesn't get invoked at all. – Igor R. Dec 03 '13 at 15:37
  • 1
    @IgorR. Did you forget to include a relevant header? Sounds like a case of the standard comma operator behaviour (a.k.a. The _coma operator_) – sehe Dec 03 '13 at 16:37