1

if in a qi::grammar I use this base rule

expression = (boost::spirit::ascii::string("aaa"));

it will parse "aaa" and nothing else

when I use this one ( notice the ! ) it parses nothing at all while I expect it to be successful on everything but "aaa"

expression = !(boost::spirit::ascii::string("aaa"));

Could I be missing some include? I'm using boost 1.54.0.

EDIT:

Sorry this is a bit drafty I modified the calculator example for my first trials...

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#include <iostream>
#include <string>
#include <boost/spirit/include/qi_lit.hpp>
#include <boost/spirit/include/qi_not_predicate.hpp>
/*
 * \
    __grammar_calculator.cpp

HEADERS += \
    __grammar_calculator.h
 */
namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    ///////////////////////////////////////////////////////////////////////////
    //  Our calculator grammar
    ///////////////////////////////////////////////////////////////////////////
    template <typename Iterator>
    struct calculator : qi::grammar<Iterator, int(), ascii::space_type>
    {
        calculator() : calculator::base_type(expression)
        {
            using qi::_val;
            using qi::_1;
            using qi::uint_;
            using boost::spirit::qi::lit;
            using boost::spirit::ascii::string;

            expression = !(boost::spirit::ascii::string("aaa"));
        }

        qi::rule<Iterator, int(), ascii::space_type> expression, term, factor;
    };
}

///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int
main()
{
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Expression parser...\n\n";
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Type an expression...or [q or Q] to quit\n\n";

    using boost::spirit::ascii::space;
    typedef std::string::const_iterator iterator_type;
    typedef client::calculator<iterator_type> calculator;

    calculator calc; // Our grammar

    std::string str;
    int result;
    while (std::getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        bool r = phrase_parse(iter, end, calc, space, result);

        if (r && iter == end)
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing succeeded\n";
            //std::cout << "result = " << result << std::endl;
            std::cout << "-------------------------\n";
        }
        else
        {
            std::string rest(iter, end);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            //std::cout << "stopped at: \": " << rest << "\"\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

EDIT 2:

Same one a bit cleaner:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>
#include <string>
#include <boost/spirit/include/qi_not_predicate.hpp>

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    template <typename Iterator>
    struct test : qi::grammar<Iterator>
    {
        test() : test::base_type(expression)
        {
            using boost::spirit::ascii::string;

            expression = (boost::spirit::ascii::string("aaa"));
        }

        qi::rule<Iterator> expression;
    };
}

int main()
{
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Expression parser...\n\n";
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Type an expression...or [q or Q] to quit\n\n";

    using boost::spirit::ascii::space;
    typedef std::string::const_iterator iterator_type;
    typedef client::test<iterator_type> test;

    test tester; // Our grammar

    std::string str;
    while (std::getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        bool r = phrase_parse(iter, end, tester, space);

        if (r && iter == end)
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing succeeded\n";
            std::cout << "-------------------------\n";
        }
        else
        {
            std::string rest(iter, end);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

ANSWER:

the problem came from the test:

if (r && iter == end)

as pointed out operator consumed nothing so iter!=end

in the below, sehe provided some alternatives.

  • 1
    `operator!` is [*supposed*](http://www.boost.org/doc/libs/1_54_0/libs/spirit/doc/html/spirit/qi/reference/operator/not_predicate.html) to consume nothing, and indeed with be successful on everything but `aaa`. How have you determined otherwise? Please show a [SSCCE](http://sscce.org/). – GManNickG Sep 05 '13 at 06:48
  • well i used the parse function. It returned true or false. I tested both expression. The second one always return false. –  Sep 05 '13 at 06:50
  • Show that code in your question. – GManNickG Sep 05 '13 at 06:51
  • You are not missing any include. The [not-**predicate** parser](http://www.boost.org/libs/spirit/doc/html/spirit/qi/reference/operator/not_predicate.html) (just as the [and-predicate parser](http://www.boost.org/libs/spirit/doc/html/spirit/qi/reference/operator/and_predicate.html)) simply return a zero length match when its condition succeeds without consuming any input. If you explain exactly what you want to accomplish I'm sure you'll get good alternatives. – llonesmiz Sep 05 '13 at 06:52
  • 1
    @user2346536 Come on, don't be ridiculous. If that's your question, just drop the original question completely and write your question properly in the ... question box! This is illegible in the comment and I will not try to read it. – sehe Sep 05 '13 at 07:36
  • @sehe no this is not my question. All I want to know is why the not predicate is not working there. But since "cv_and_he" asked me my final goal I told him. But right now my question is in my question...And the above code is just a simple test case of the ! operator not my future parser. You know what you might be right. I'm taking this comment off. –  Sep 05 '13 at 07:43
  • 1
    Okay, fair enough. Though, "If you explain exactly what you want to accomplish I'm sure you'll get good alternatives" wasn't fishing for your life goals :) It was asking were exactly you think you needed the `operator!` – sehe Sep 05 '13 at 07:45
  • well, i'll need somehting like expression = !(boost::spirit::ascii::string("{%")); to keep going as long as I do not meet a new interpretable node... but it was not working so comes my question :) –  Sep 05 '13 at 07:47
  • @user2346536 see my answer for how to do that – sehe Sep 05 '13 at 07:49

1 Answers1

1

For what it's worth:

  • As others have pointed out operator& and operator! are zero-width lookahead assertions (they don't match but 'peek' and either succeed or fail on match).

You'll want to know about

  • negating character-sets:

    qi::char_("a-z")    // matches lowercase letters
    

    ~qi::char_("a-z") // matches anything but lowercase letters

  • 'parser subtraction' - think of exceptions:

    qi::char_ - qi::char_("a-z")  // equivalent to ~qi::char_("a-z") 
    qi::char_("a-z") - "keyword"  // any lowercase letters, but not if it spells "keyword" 
    

Edit so to scan forward to the next "%{" you'd do something like

qi::omit [ qi::char_ - "{%" ] >> "{%"

Note that you don't always need to 'wrap' literals in qi::lit unless the expression doesn't already involve proto-expressions in the Qi domain.


Edit 2 An example of how to use ! and &:

&qi::int_ >> +qi::char_   // parse a string, **iff** it starts with an integer

or

!keyword_list >> identifier // parse any identifier that's not a known keyword
sehe
  • 374,641
  • 47
  • 450
  • 633
  • thanks: expression = *(qi::char_ - "{%"); was what i was looking for. even so I'm still not sure what the ! is supposed to do ! –  Sep 05 '13 at 08:03
  • @user2346536 See my '**Edit 2**' (and there's always the [documentation](http://www.boost.org/doc/libs/1_54_0/libs/spirit/doc/html/spirit/qi/reference/operator/not_predicate.html) which contains [examples](http://www.boost.org/doc/libs/1_54_0/libs/spirit/doc/html/spirit/qi/reference/operator/not_predicate.html#spirit.qi.reference.operator.not_predicate.example)) – sehe Sep 05 '13 at 08:07
  • 1
    I understood !!!!!! if (r && iter == end ) fails but if(r) succeeds so the operator ! does its job but the zero match length ==> iter != end since nothing was consumed by "!" –  Sep 05 '13 at 08:07