Question

So I'm trying to get spirit to parse the characters from this file as it's input. I'd rather not read the full string into memory if at all possible.

This is my current relevant code, the Rosters_Grammar is a grammar file that I am using to specify my desired grammar.

#include "StdAfx.h"
#include "Interpreter.h"
#include "Rosters_Grammar.h"
#include <boost\spirit\include\qi.hpp>
#include <fstream>

bool Interpreter::invoke(std::string path)
{
  //Define our parser type and iterator types.
  typedef boost::spirit::istream_iterator iter_type;
  typedef Rosters_Grammar<iter_type> parser_type;

  //Create an instance of our grammar parser and pass it an appropriate project.
  parser_type grammar_parser(project);

  //Open the target file and wrap ifstream into the iterator.
  std::ifstream in = std::ifstream(path);
  if(in.is_open()){

    //Disable Whitespace Skipping
    in.unsetf(std::ios::skipws);

    iter_type begin(in);
    iter_type end;

    //Phrase parse the grammar
    return boost::spirit::qi::phrase_parse(begin,
                                             end, 
                                       qi::int_ , 
                                       boost::spirit::qi::space);
  }
  else{
    return false;
  }
}

The issue that comes up is my parse ALWAYS succeeds for some reason. Given the roster grammar I can tell it's reading part of the input because it is performing actions accordingly, and works exactly as expected for proper input. However the parser doesn't fail on bad input, it just stops part the way through the file and returns a true.

My current file contents are a repetition of ints and strings, such that

45 Brie 23 butter_scotch

Should be read fine and accepted. Strings like

"45 Apple apple apple"

should not be. However given this sting, the parser should fail. Instead it performs actions for "45 Apple" and then returns a true for the parse. I think it's something with my iterators but I can't be sure. In the above posted code, I have qi::int_ as my parser, and it always succeeds regardless of my input data. So I don't believe my grammar file should not be relevant to the problem here. The only way I've gotten the data to fail so far is with !qi::eps as my parser input.

Thanks for any help anyone could give me!

EDIT: After looking into it a bit more, I actually think my skipper is the problem for some reason. The way I understand it, phrase_parse is passed 2 iterators, a grammar of some kind, and a skip parser. It tokenizes the input based on the skip parser, and uses those tokens in the grammar.

Without disabling whitespace skipping for the iterator type, my result parses out "45 appleappleapple", and with it it succeeds with only "45 apple."

Was it helpful?

Solution

We can't see the grammar because you didn't post it.

I can see that you donot check wheter the input has been completely consumed:

    return boost::spirit::qi::phrase_parse(
           begin, end,
           grammar_parser ,
           qi::space);

You can fix that by either requiring qi::eoi:

    return boost::spirit::qi::phrase_parse(
           begin, end,
           grammar_parser >> qi::eoi,
           qi::space);

Or you can check the iterators:

    bool ok = boost::spirit::qi::phrase_parse(
           begin, end,
           grammar_parser ,
           qi::space);

    if (begin != end)
        std::cerr << "Remaining unparsed: '" << std::string(begin, end) << "'\n";

    return ok && (begin == end);

Finally, note that side-effects of semantic actions can never be undone in the case of backtracking. See also:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top