1

I have a grammar that works properly, now I want to use it to parse a string without case sensitivity.

I am running Boost 1.46 on Ubuntu 12.04 Linux.

I tried the following code:

bool parseSuccess = qi::phrase_parse(begin, end,
                    qi::no_case[grammar], ascii::space, result);

However the no_case directive has no effect.

Am I doing something wrong, or the directive cannot be used with non-terminals?

giulatona
  • 137
  • 2
  • 9

1 Answers1

1

Two things:

  • no_case[] requires to contained parser expressions to be specified in lower-case
  • it doesn't seem to be documented anywhere, but the no_case directive does not propagate across Non-Terminal parsers.

In that sense no_case is similar to e.g. locals<>, or the Skipper in that they are part of the parser context; Only in this case, case-sensitive happens to not be controlled from the rule's template arguments.

I seem to remember that Spirit X3 will be getting a more general facility here that might remove these limitations.

Example program showing the limitation in action:

Live On Coliru

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

namespace qi = boost::spirit::qi;

template <typename It, typename Skipper> 
struct Parser : qi::grammar<It, std::string(), Skipper> {
    Parser() : Parser::base_type(start)  {
        using namespace qi;

        a_symbol      += "aap", "noot", "mies";
        start          = raw [ no_case [ a_symbol >> "literal" >> char_("qwerty") >> -subrule_lexeme ] ];
        subrule_lexeme = "also works";

        BOOST_SPIRIT_DEBUG_NODES((start)(subrule_lexeme))
    }
  private:
    qi::symbols<char, qi::unused_type> a_symbol;
    qi::rule<It, std::string(), Skipper> start;
    qi::rule<It, std::string()> subrule_lexeme;
};

// test
using It = std::string::const_iterator;

template <typename S = qi::space_type> void test(S const& s = S()) {
    Parser<It, S> g;

    for (std::string const& input : { 
            "aap\t literal r",
            "aAp\t liTeral R",
            // hitting subrule_lexeme:
            "aap\t literal r\talso works",
            "aAp\t liTeral R\tALSO WoRkS",
        })
    {
        It f = input.begin(), l = input.end();

        std::string parsed;
        bool ok = qi::phrase_parse(f, l, g, s, parsed);

        if (ok)
            std::cout << "Parsed successfully: '" << parsed << "'\n";
        else
            std::cout << "Not matched ('" << input << "')\n";

        if (f!=l)
            std::cout << " -- remaining unparsed input: '" << std::string(f,l) << "'\n";
    }
}

int main()
{
    test(qi::space);
}

Prints:

Parsed successfully: 'aap    literal r'
Parsed successfully: 'aAp    liTeral R'
Parsed successfully: 'aap    literal r  also works'
Parsed successfully: 'aAp    liTeral R  '
 -- remaining unparsed input: 'ALSO WoRkS'

And with full debug trace:

<start>
  <try>aap\t literal r</try>
  <subrule_lexeme>
    <try></try>
    <fail/>
  </subrule_lexeme>
  <success></success>
  <attributes>[[a, a, p,    ,  , l, i, t, e, r, a, l,  , r]]</attributes>
</start>
Parsed successfully: 'aap    literal r'
<start>
  <try>aAp\t liTeral R</try>
  <subrule_lexeme>
    <try></try>
    <fail/>
  </subrule_lexeme>
  <success></success>
  <attributes>[[a, A, p,    ,  , l, i, T, e, r, a, l,  , R]]</attributes>
</start>
Parsed successfully: 'aAp    liTeral R'
<start>
  <try>aap\t literal r\talso </try>
  <subrule_lexeme>
    <try>also works</try>
    <success></success>
    <attributes>[[a, l, s, o,  , w, o, r, k, s]]</attributes>
  </subrule_lexeme>
  <success></success>
  <attributes>[[a, a, p,    ,  , l, i, t, e, r, a, l,  , r,     , a, l, s, o,  , w, o, r, k, s]]</attributes>
</start>
Parsed successfully: 'aap    literal r  also works'
<start>
  <try>aAp\t liTeral R\tALSO </try>
  <subrule_lexeme>
    <try>ALSO WoRkS</try>
    <fail/>
  </subrule_lexeme>
  <success>ALSO WoRkS</success>
  <attributes>[[a, A, p,    ,  , l, i, T, e, r, a, l,  , R,     ]]</attributes>
</start>
Parsed successfully: 'aAp    liTeral R  '
 -- remaining unparsed input: 'ALSO WoRkS'
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thank you. Unfortunately however I cannot upgrade right now. Is there a way that I can work around this problem? – giulatona Jul 09 '15 at 13:45
  • It's not a problem, except maybe the lack of documentation. Upgrading won't change it. That suggestion was not part of my answer for this reason – sehe Jul 09 '15 at 14:12
  • it is a limitation as you said, and I would like to parse a string without worrying about case. Is adding no_case to the definition of all of my rules the only solution? – giulatona Jul 09 '15 at 14:18
  • 1
    Yes. (short of writing a hack based on the iterator or using experimental Spirit X3) – sehe Jul 09 '15 at 14:19