Sunday 21 August 2011

Playing around with Boost.Spirit - Parsing integer triplets

I'm exploring Boost.Spirit and while doing so, I'm trying to parse integer triplets for input of the following form:
(8,7,15)
(0,0,1) (0,3,2) (0,6,3)
(1,0,4) (1,1,5)
That is, the input would be triplets of integers and on each line there can be more than one triplet (x,y,z). This is my first attempt to parse all the integers:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
 
#include <iostream>
#include <string>
#include <vector>
 
using namespace boost::phoenix;
using namespace boost::spirit;
using namespace boost::spirit::qi;
using namespace boost::spirit::ascii;
using namespace boost::spirit::arg_names;
 
std::vector<int> ints;
 
void cint(int i)
{
    ints.push_back(i); 
}
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last)
{
    bool r = phrase_parse
    (
        first, 
        last,         
        *( '(' >> int_[&cint] >> ',' >> int_[&cint] >> ',' >> int_[&cint] >> ')' ), 
        space 
    );
 
    if (first != last) // fail if we did not get a full match
        return false;
    return r;
}
 
int main()
{
    std::string str;
    while (getline(std::cin, str))
    {           
        if (parse_numbers(str.begin(), str.end()))
            std::cout << "Succeeded : " << str << std::endl;
        else
            std::cout << "Failed : " << str << std::endl;
    }
    for(size_t i = 0 ; i < ints.size() ; i++ )
    {
        std::cout << ints[i] << " ";
    }
    return 0;
}
Output (ideone):
Succeeded : (8,7,15)
Succeeded : (0,0,1) (0,3,2) (0,6,3)
Succeeded : (1,0,4) (1,1,5)
8 7 15 0 0 1 0 3 2 0 6 3 1 0 4 1 1 5 
Then I tried to improve it, and instead of storing integer blindly, I tried storing the triplets themselves. So I defined a struct called `point`, few set functions, and redefined the cint() function as:
struct point
{
   int x,y,z;
};
 
std::vector<point> points(0);
 
void setx(int x) { points.push_back(point()); points[points.size()-1].x = x; }
void sety(int y) { points[points.size()-1].y = y; }
void setz(int z) { points[points.size()-1].z = z; }
 
typedef void (*setcallback)(int);
 
setcallback setcallbacks[] = {&setx, &sety, &setz};
 
int cindex = 0;
 
void cint(int i)
{ 
   setcallbacks[cindex](i); 
   cindex = (cindex + 1)%3;
}
And here is the output (ideone):
Succeeded : (8,7,15)
Succeeded : (0,0,1) (0,3,2) (0,6,3)
Succeeded : (1,0,4) (1,1,5)
[8,7,15]
[0,0,1]
[0,3,2]
[0,6,3]
[1,0,4]
[1,1,5]
A bit better than earlier? But I'm not sure if that is all can be done with Spirit. Anyway, I'm looking for further improvement and robust code; maybe I should save this opportunity for my post. And not to mention, there are other ways of course to parse the integers.

No comments:

Post a Comment