Once again I couldn't really resist the finger exercise in using Boost Spirit for this purpose.
Explanation
Behold this very adhoc and minimalistic sample that
parses the given text (using Spirit Qi) into
- a points collection (vector of pair)
- a dynamic map of lookup tables (identified by a name - e.g. "pressure") and containing vector)
does rudimentary error reporting on unpexpected input
prints the parsed data back into compact formatting (this uses Spirit Karma)
it is whitespace tolerant (though the newlines are required as in the input)
Flaws:
- it is really quick and dirty: it should really be a grammar class with
- separate rule definitions
- more readable
- more debuggable
- explicit semantic input checks (lookup table names, number of elements in each data table (the counts in
POINTS
_n
and POINT_DATA
n
are being handsomely ignored now)
- use phoenix (or c++0x
std::move
) to prevent the copying of the lookup table data
Sample
Output of the code/input as shown (note the intentional 'bogus' input demonstrating the error reporting):
Parse failed remaining: 'bogus'
Points: [1.0,2.0], [3.0,4.0]
density: 7.0, 8.0
pressure: 5.0, 6.0
And the code (c++, tested with boost 1_47_0):
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <map>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
typedef std::vector<double> lookuptable_t;
typedef std::map<std::string, lookuptable_t> lookuptables_t;
typedef std::pair<double, double> point_t;
typedef std::vector<point_t> points_t;
int main()
{
std::string input =
"POINTS 2 double\n"
"1 2\n"
"3 4\n"
"POINT_DATA 2\n"
"SCALARS pressure double\n"
"LOOKUP_TABLE default\n"
"5\n"
"6\n"
"SCALARS density double\n"
"LOOKUP_TABLE default\n"
"7\n"
"8 bogus";
points_t points;
lookuptables_t lookuptables;
{
std::string::const_iterator f(input.begin()), l(input.end());
using namespace qi;
bool ok = phrase_parse(f, l,
"POINTS" > omit[ uint_ ] > "double" > eol >>
(double_ >> double_) % eol > eol >>
"POINT_DATA" > omit [ uint_ ],
char_(" \t"), points);
while (ok && f!=l)
{
std::string name;
lookuptable_t table;
ok = phrase_parse(f, l,
eol >> "SCALARS" > +raw [ eps >> "pressure"|"density" ] > "double" > eol >
"LOOKUP_TABLE" > "default" > eol >
double_ % eol,
char_(" \t"), name, table);
if (ok && !lookuptables.insert(std::make_pair(name, table)).second)
std::cerr << "duplicate table for '" << name << "' ignored" << std::endl;
}
if (!ok || (f!=l))
std::cerr << "Parse " << (ok?"success":"failed") << " remaining: '" <<
std::string(f, std::min(f+10, l)) << "'" << std::endl;
}
{
using namespace karma;
std::cout << format(
"Points: " << ('[' << double_ << ',' << double_ << ']') % ", " << eol <<
+(string << ": " << auto_ % ", " << eol),
points, lookuptables);
}
}