Jump to content
  • Advertisement
Sign in to follow this  
MaulingMonkey

Am I totally misusing/abusing boost::spirit?

This topic is 4994 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

After finally getting my originally believed simple first use of boost::spirit to parse a simple config file format (inspired by an earlier post interpreting a more limited syntax in C, which I decided to do in boost for learning purpouses) I have finally squashed all my errors (including 3 pages worth that resulted from a single missing const function specification) and actually gotten my code to parse config files that have the format:

#leading blank lines AOK
#comments
   #comments are allowed to have leading whitespace
key=value pairs
#blank lines allowed, including with just whitespaces:


   keys_have_surrounding_whitespace_trimmed    =    same with values   

#trailing blank lines AOK

But now that I've finally wrestled closures out of a couple of examples, I'd like to get feedback on better ways to write this same parser (USING BOOST::SPIRIT) since I've probably made many novice mistakes, and to be quite frank, I can barely understand the documentation OR the examples. main.cc (yes, only one file, since I just wanted to get the thing working and compiling for the purpouse of understanding it - yes this code compiles and runs and it successfully parses all the examples I've thrown at it):
#include <boost/spirit.hpp>
#include <boost/format.hpp>
#include <boost/spirit/phoenix/binders.hpp>
#include <boost/lambda/bind.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <map>
#include <list>

using namespace boost::spirit;
using namespace boost;
using namespace phoenix;
using namespace std;

struct keyval_pair_closure : boost::spirit::closure<keyval_pair_closure,string,string>
{
	member1 key;
	member2 val;
};

struct string_closure : boost::spirit::closure<string_closure,string>
{
	member1 val;
};

struct config_grammar : public grammar<config_grammar>
{
	map<string,string> & tokens;
	config_grammar( map<string,string> & tokens_ ) : tokens(tokens_) {}
	void add_keyval(const string & key , const string & val ) const { tokens[key] = val; }
	template < typename ScannerT > struct definition
	{
		definition(config_grammar const& self)
		{
			top
				=	*(eol_p)
				>>	!(any_line
					>>	*( +(eol_p) >> any_line)
					)
				>>	*(eol_p) >> end_p
				;
			any_line
				=	comment_line
				|	keyval_line
				|	blank_line
				;
			comment_line
				=	*(blank_p)
				>>	'#'
				>>	*(anychar_p - eol_p)
				;
			blank_line
				=	+(blank_p)
				;
			identifier
				= lexeme_d
				[
					( alpha_p | '_')
					>> *( alnum_p | '_')
				][identifier.val = construct_<std::string>(arg1, arg2)]
				;
			value
				= lexeme_d
				[
					*( anychar_p - eol_p )
				][value.val = construct_<std::string>(arg1, arg2)]
				;
			keyval_line
				=	*(blank_p)
				>>	identifier[keyval_line.key = arg1]
				>>	*(blank_p)
				>>	'='
				>>	*(blank_p)
				>>	value[keyval_line.val = arg1]
					[bind(&config_grammar::add_keyval)(self,keyval_line.key,keyval_line.val)]
				;
		}
		rule<ScannerT> top,comment_line,blank_line,any_line;
		rule<ScannerT,keyval_pair_closure::context_t> keyval_line;
		rule<ScannerT,string_closure::context_t> identifier,value;
		
		rule<ScannerT> const& start() const { return top; }
	};
};

config_grammar config_p( map<string,string> & output ) { return config_grammar( output ); }

bool parse_cfg_file( const string & filename , map<string,string> & output )
{
	file_iterator<> first( filename.c_str() );
	if (!first)
	{
		cout << "File does not exist" << endl;
		return false;
	}
	file_iterator<> last = first.make_end();
	

	if (!parse( first , last , config_p(output) ).full) return false;
	
	return true;
}

int main ( int argc , char ** argv )
{
	string filename = "C:\\eclipse\\workspace\\boostfun\\test.cfg";
	if (argc >= 2) filename = argv[1];
	
	map<string,string> keys;
	keys["test"] = "123";

	if (parse_cfg_file( filename , keys ))
	{
		cout << format("Parsed file: %1% OK") % filename << endl;
	}
	else
	{
		cout << format("Parse of file: %1% FAILED") % filename << endl;
	}
	for ( map<string,string>::iterator i = keys.begin() ; i != keys.end() ; ++i )
	{
		cout << format("Key: %1% Value: %2%") % i->first % i->second << endl;
	}
	cin.get();
}

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by antareus
Looks okay to me, but I'm a spirit newbie. There is a definite learning curve involved with spirit.


Definately. I had some problems earlier on with key/value temp values not being both set (I think) at the time I tried to insert them into my map, resulting in a map with a single blank key, the corresponding value of which was the value of the last valid key/value pair of the file read... which I fixed either by switching the location of the statement, or more likely by using insert_a instead of map[key]=value (which one I'm not sure, I restarted the work on the parser from scratch when I couldn't get the 1st one to work)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!