1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#ifndef TDF_GRAMMAR_H
#define TDF_GRAMMAR_H
#include <map>
#include <list>
#include <iostream>
#include <string>
#include <boost/version.hpp>
#include <boost/spirit/include/classic.hpp>
#include <boost/spirit/include/phoenix1_binders.hpp>
using namespace boost::spirit::classic;
#include "System/TdfParser.h"
/**
* \brief Simple std::ostream Actor, with fixed prefix or suffix.
* This actor prints the item parsed using the ostream, enclosed
* by suffix and prefix string.
*/
class ostream_actor
{
private:
std::ostream & ref;
std::string prefix, suffix;
public:
ostream_actor(std::ostream & ref_, std::string const& addition = "")
: ref(ref_), suffix(addition)
{}
ostream_actor(std::string prefix, std::ostream & ref_, std::string const& addition = "")
: ref(ref_), prefix(prefix), suffix(addition)
{}
template<typename T2> void operator()(T2 const& val) const { ref << prefix << val << suffix; }
template<typename IteratorT>
void operator()(IteratorT const& first, IteratorT const& last) const { ref << prefix << std::string(first, last) << suffix; }
};
/**
* \name Actor functions
* use these two functions to create a semantic action with ostream_actor.
* \{
*/
inline ostream_actor ostream_a(std::string const& prefix, std::ostream& ref, std::string const& suffix = "")
{
return ostream_actor(prefix, ref, suffix);
}
inline ostream_actor ostream_a(std::ostream& ref, std::string const& suffix = "")
{
return ostream_actor(ref, suffix);
}
/**
* \}
*/
struct tdf_grammar : public grammar<tdf_grammar>
{
enum Errors {
semicolon_expected
, equals_sign_expected
, square_bracket_expected
, brace_expected
};
struct section_closure : closure<section_closure, TdfParser::TdfSection*> {
member1 context;
};
struct string_closure : closure<string_closure, std::string> {
member1 name;
};
tdf_grammar(TdfParser::TdfSection* sec, std::list<std::string>* junk_data)
: section(sec), junk(junk_data)
{}
template<typename ScannerT>
struct definition
{
definition(tdf_grammar const& self)
: expect_semicolon(semicolon_expected)
, expect_equals_sign(equals_sign_expected)
, expect_square_bracket(square_bracket_expected)
, expect_brace(brace_expected)
{
using namespace boost::spirit;
using namespace phoenix;
tdf = *(
section(self.section)
| gather_junk_line // if this rule gets hit, then section did not consume everything,
)
>> end_p
;
gather_junk_line =
lexeme_d[
(+(~chset<>("}[\n")))
[ push_back_a(* self.junk ) ]
// [ ostream_a("Junk detected:", std::cout, "\n") ] // debug printouts
]
;
name = (+(~chset<>(";{[]}=\n"))) // allows pretty much everything that isnt already used
[ name.name = construct_<std::string>(arg1, arg2) ]
;
section = '['
>> name
// [ ostream_a("Just parsed a section: ", std::cout, "\n") ] // prints section name
[ section.context = phoenix::bind(&TdfParser::TdfSection::construct_subsection)(section.context, arg1) ]
>> expect_square_bracket(ch_p(']'))
>> expect_brace (ch_p('{'))
>> *
(
(
name
[var(temp1) = arg1]
>> ch_p('=') // turn this into expect_equals_sign(ch_p('=')) if you want more strict parsing
>> lexeme_d[ (*~ch_p(';')) // might be empty too!
[ phoenix::bind(&TdfParser::TdfSection::add_name_value)(section.context, var(temp1), construct_<std::string>(arg1,arg2)) ]
]
>> expect_semicolon(ch_p(';'))
)
| section(section.context)
| gather_junk_line // if this rule gets touched we either hit a closing section } or there really is junk
)
>> expect_brace(ch_p('}'))
;
}
rule<ScannerT> const& start() const { return tdf; }
rule<ScannerT> tdf, gather_junk_line;
rule<ScannerT, string_closure::context_t> name;
rule<ScannerT, section_closure::context_t> section;
assertion<Errors> expect_semicolon, expect_equals_sign, expect_square_bracket, expect_brace;
std::string temp1;
};
TdfParser::TdfSection* section;
mutable std::list<std::string>* junk;
};
#endif // TDF_GRAMMAR_H
|