Skip to content

Instantly share code, notes, and snippets.

@sehe
Created October 13, 2012 20:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sehe/3886058 to your computer and use it in GitHub Desktop.
Save sehe/3886058 to your computer and use it in GitHub Desktop.
Parsing a number of named sets of other named sets
test
*.o
*~
*.sw?
# comment
# other comment
set "Myset A"
{
figure "AF 1"
{
i 0 0 0
i 1 2 5
i 1 1 1
f 3.1 45.11 5.3
i 3 1 5
f 1.1 2.33 5.166
}
figure "AF 2"
{
i 25 5 1
i 3 1 3
}
}
# comment
set "Myset B"
{
figure "BF 1"
{
f 23.1 4.3 5.11
}
}
set "Myset C"
{
include "Myset A" # includes all figures from Myset A
figure "CF"
{
i 1 1 1
f 3.11 5.33 3
}
}
all:test output.txt
CPPFLAGS+=-std=c++0x
CPPFLAGS+=-g -O0
CPPFLAGS+=-I ~/custom/boost/
CPPFLAGS+=-march=native
# CXX=/usr/lib/gcc-snapshot/bin/g++
# CC=/usr/lib/gcc-snapshot/bin/gcc
# CXX=~/Projects/CLANG/build/Debug+Asserts/bin/clang++
# CC=~/Projects/CLANG/build/Debug+Asserts/bin/clang
%:%.cpp
$(CXX) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)
output.txt: test
./test > $@
# figure sets exported automatically by karma
set "Myset A"
{
figure "AF 1"
{
i 0 0 0
i 1 2 5
i 1 1 1
f 3.1 45.11 5.3
i 3 1 5
f 1.1 2.33 5.166
}
figure "AF 2"
{
i 25 5 1
i 3 1 3
}
}
set "Myset B"
{
figure "BF 1"
{
f 23.1 4.3 5.11
}
}
set "Myset C"
{
include "Myset A"
figure "CF"
{
i 1 1 1
f 3.11 5.33 3.0
}
}
//#define BOOST_SPIRIT_DEBUG // before including Spirit
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <fstream>
namespace Format
{
struct int_point { int x, y, z; };
struct float_point { float x, y, z; };
typedef boost::variant<int_point, float_point> if_point;
struct figure
{
std::string name;
std::vector<if_point> if_points;
};
struct figure_set
{
std::string name;
std::set<std::string> includes;
std::vector<figure> figures;
};
typedef std::vector<figure_set> file_data;
}
BOOST_FUSION_ADAPT_STRUCT(Format::int_point,
(int, x)(int, y)(int, z))
BOOST_FUSION_ADAPT_STRUCT(Format::float_point,
(float, x)(float, y)(float, z))
BOOST_FUSION_ADAPT_STRUCT(Format::figure,
(std::string, name)
(std::vector<Format::if_point>, if_points))
BOOST_FUSION_ADAPT_STRUCT(Format::figure_set,
(std::string, name)
(std::set<std::string>, includes)
(std::vector<Format::figure>, figures))
namespace /*anon*/
{
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
template <typename Iterator> struct skipper
: public qi::grammar<Iterator>
{
skipper() : skipper::base_type(start, "skipper")
{
using namespace qi;
comment = '#' >> *(char_ - eol) >> (eol|eoi);
start = comment | qi::space;
BOOST_SPIRIT_DEBUG_NODE(start);
BOOST_SPIRIT_DEBUG_NODE(comment);
}
private:
qi::rule<Iterator> start, comment;
};
template <typename Iterator> struct parser
: public qi::grammar<Iterator, Format::file_data(), skipper<Iterator> >
{
parser() : parser::base_type(start, "parser")
{
using namespace qi;
using phx::push_back;
using phx::at_c;
name = lexeme [ '"' >> *~char_('"') >> '"' ];
include = "include" >> name;
ipoints = "i" >> int_ >> int_ >> int_;
fpoints = "f" >> float_ >> float_ >> float_;
figure = "figure" >> name >> '{' >> *(ipoints | fpoints) >> '}';
set = "set" >> name >> '{' >> *include >> *figure >> '}';
start = *set;
}
private:
qi::rule<Iterator, std::string() , skipper<Iterator> > name, include;
qi::rule<Iterator, Format::int_point() , skipper<Iterator> > ipoints;
qi::rule<Iterator, Format::float_point(), skipper<Iterator> > fpoints;
qi::rule<Iterator, Format::figure() , skipper<Iterator> > figure;
qi::rule<Iterator, Format::figure_set() , skipper<Iterator> > set;
qi::rule<Iterator, Format::file_data() , skipper<Iterator> > start;
};
template <typename Iterator> struct generator
: public karma::grammar<Iterator, Format::file_data(), char>
{
generator() : generator::base_type(start, "generator")
{
using namespace karma;
name = no_delimit ['"' << string << '"'];
include = "include" << name;
ipoints = "\n i" << int_ << int_ << int_;
fpoints = "\n f" << float_ << float_ << float_;
figure = "figure" << name << "\n {" << *(ipoints | fpoints) << "\n }";
set = "set" << name << "\n{"
<< *("\n " << include)
<< *("\n " << figure) << "\n}";
start = "# figure sets exported automatically by karma\n\n" << set % eol;
}
private:
karma::rule<Iterator, std::string() , char> name, include;
karma::rule<Iterator, Format::int_point() , char> ipoints;
karma::rule<Iterator, Format::float_point(), char> fpoints;
karma::rule<Iterator, Format::figure() , char> figure;
karma::rule<Iterator, Format::figure_set() , char> set;
karma::rule<Iterator, Format::file_data() , char> start;
};
}
namespace Parser {
bool parsefile(const std::string& spec, Format::file_data& data)
{
std::ifstream in(spec.c_str());
in.unsetf(std::ios::skipws);
std::string v;
v.reserve(4096);
v.insert(v.end(), std::istreambuf_iterator<char>(in.rdbuf()), std::istreambuf_iterator<char>());
if (!in)
return false;
typedef char const * iterator_type;
iterator_type first = &v[0];
iterator_type last = first+v.size();
try
{
parser<iterator_type> p;
skipper<iterator_type> s;
bool r = qi::phrase_parse(first, last, p, s, data);
r = r && (first == last);
if (!r)
std::cerr << spec << ": parsing failed at: \"" << std::string(first, last) << "\"\n";
return r;
}
catch (const qi::expectation_failure<char const *>& e)
{
std::cerr << "FIXME: expected " << e.what_ << ", got '" << std::string(e.first, e.last) << "'" << std::endl;
return false;
}
}
}
int main()
{
Format::file_data data;
bool ok = Parser::parsefile("input.txt", data);
std::cerr << "Parse " << (ok?"success":"failed") << std::endl;
generator<boost::spirit::karma::ostream_iterator<char> > g;
std::cout << format_delimited(g, ' ', data);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment