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 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/home/phoenix/statement.hpp>
#include <string>
#include <vector>
#include <iostream>
namespace wml{
namespace ast
{
struct attribute
{
attribute(const std::string& key, const std::string& value):key(key), value(value){}
attribute(const std::string& key):key(key){}
std::string key;
std::string value;
};
typedef std::vector<attribute> multi_attribute;
}}
namespace wml {
namespace grammar {
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
struct multi_attribute : qi::grammar<Iterator, ast::multi_attribute(), qi::locals<int>, ascii::space_type>
{
multi_attribute() : multi_attribute::base_type(multi_attribute_rule, "multi attribute")
{
using ascii::char_;
using qi::lexeme;
using qi::eol;
using qi::eoi;
using qi::eps;
using namespace qi::labels;
using phoenix::bind;
using phoenix::ref;
using phoenix::construct;
using phoenix::val;
using phoenix::at;
using phoenix::push_back;
using phoenix::if_;
using phoenix::back;
using phoenix::size;
string_rule = lexeme[+(char_("a-zA-Z0-9") | char_('.'))];
key = string_rule;
value = string_rule;
multi_attribute_rule =
eps[_a = 0] // utilisation du parser eps qui réussit toujours pour initialiser la variable locale _a
> key[push_back(_val, construct<ast::attribute>(_1))] % ',' // constructeur ast::attribute(const std::string& key)
> '='
// le texte est parsé de gauche à droite donc à ce stade le std::vector<attribute> _val possède déjà sa taille finale (nombre de clé)
> value[if_( _a < size(_val))
[
phoenix::bind(&ast::attribute::value, at(_val, _a)) = _1,
_a++
]
.else_
[
phoenix::bind(&ast::attribute::value, back(_val)) += ',' + _1
]
]
% ','
> (eol | eoi)
;
multi_attribute_rule.name("multi attribute");
qi::on_error<qi::fail>
(
multi_attribute_rule,
std::cout
<< val("Error! Expecting ")
<< _4 // what failed?
<< val(" here: \"")
<< construct<std::string>(_3, _2) // iterators to error-pos, end
<< val("\"")
<< std::endl
);
}
qi::rule<Iterator, ast::multi_attribute(), qi::locals<int>, ascii::space_type> multi_attribute_rule;
qi::rule<Iterator, std::string(), ascii::space_type> key;
qi::rule<Iterator, std::string(), ascii::space_type> value;
qi::rule<Iterator, std::string(), ascii::space_type> string_rule;
};
}
namespace printer
{
struct multi_attribute
{
multi_attribute(){}
void operator()(const ast::multi_attribute& multi_attr)
{
for(const wml::ast::attribute& attr : multi_attr)
{
std::cout << attr.key << ":" << attr.value << "\n";
}
}
};
}}
template <typename grammar, typename ast>
struct wml_test
{
wml_test(){}
void operator()(const std::string& value)
{
ast wml_tree;
grammar wml;
using boost::spirit::ascii::space;
using namespace boost::spirit::qi;
std::string::const_iterator iter = value.begin();
std::string::const_iterator end = value.end();
bool r = phrase_parse(iter, end, wml, space, wml_tree);
if (r && iter == end)
{
std::cout << "ok" << std::endl;
wml::printer::multi_attribute()(wml_tree);
}
else
{
std::string::const_iterator some = iter+2;
std::string context(iter, (some>end)?end:some);
std::cout << "ko\n";
std::cout << "stopped at: \": " << context << "...\"\n";
}
}
};
int main(int argc, char **argv)
{
typedef wml::grammar::multi_attribute<std::string::const_iterator> grammar;
wml_test<grammar, wml::ast::multi_attribute> test;
test("key=value\n");
test("key = value\n");
test("key1, key2 = value1, value2\n");
test("key1, key2, key3, key4 = value1, value2, value3, value4\n");
test("key1 = value1, value2\n");
test("key1, key2 = value1\n");
test("key1 , key2 , key3 = value1 , value2");
test("key1 , key2 = value1 , value2, value3 , value4");
return 0;
} |