Showing posts with label boost::spirit. Show all posts
Showing posts with label boost::spirit. Show all posts

Thursday, 24 October 2013

boost spirit2--01 : match recursive braces

   Matching recursive patterns by boost::spirit::qi is very simple, easy to maintain and enhance.

Example : match recursive braces

   case 1 : ( () )         --> match
   case 2 : (               --> unmatch
   case 3 : (() ())       --> match
   case 4 : ((((( )))))  --> match
   case 5 : (((( ( ))))  --> match

   Following grammar can detect case1~case5

  

template<typename Iterator>
struct recursiveBraces : qi::grammar<Iterator, qi::ascii::space_type>
{
    recursiveBraces() : recursiveBraces::base_type(finalRules)
    {
        braces = "(" >> *expression >> ")";
        expression = +braces;
    }

    qi::rule<Iterator, qi::ascii::space_type> braces;
    qi::rule<Iterator, qi::ascii::space_type> expression;    
};

  braces call expression, expression call braces, so the form a recursive loop.If we do some enhancement, we could match more complicated pattern.
  
case 6 : (() ()) ((())) (())     --> match
case 7 : (() ()) ((( ( ))) (())  --> umatch


template<typename Iterator>
struct recursiveBraces : qi::grammar<Iterator, qi::ascii::space_type>
{
    recursiveBraces() : recursiveBraces::base_type(finalRules)
    {
        braces = "(" >> *expression >> ")";
        expression = +braces;
        finalRules += expression;
    }

    qi::rule<Iterator, qi::ascii::space_type> braces;
    qi::rule<Iterator, qi::ascii::space_type> expression;
    qi::rule<Iterator, qi::ascii::space_type> finalRules;    
};


  The grammar express by spirit are elegant and easy to read(you do need to invest your times to study the tutorial), the performance are very good too.It is worth to have some play with it.The full codes are available at github.

Tuesday, 22 October 2013

boost spirit2--00 : exercise00

  Boost spirit is a robust and efficiency parser and output generators libs for c++. Although it is very fast, the learning curve is steep.To better understand the library, I write down this post to record what I have learn from the exercises.

  The implementation of spirit involve a lot of TMP skills, unfortunately, c++11 still do not support concepts, therefore the error messages of compile time are almost unreadable, this is the biggest draw back for me.The other serious issue is long compile time, spirit X3 may reduce the compile times more than 50%, hope it come out quickly.The merits of spirit are obvious too, very fast, clear syntax(similar to EBNF), seamless integration with other c++ codes.

   In this post I would try to transform the input from


0.5">If you are a premiere member of the lynda.com online training library, 
 or if you

5.19">are watching this tutorial on a DVD, you have access to the  
exercise files used throughout the title.

To something like

 
1
00:00:00,500 --> 00:00:05,190
If you are a premiere member of the lynda.com online training library, 
 or if you

2
00:00:05,190 --> 00:00:11,800
are watching this tutorial on a DVD, you have access to  
the exercise files used throughout the title.
 
 
step 1 : parse the string
 
template<typename Iterator>
bool parse_video_data(Iterator begin, Iterator end, 
                      std::vector<std::pair<float, std::string>> 
                      &data)
{
  //if you don't want to insert the "\n\n" in to the string
  bool const r = qi::parse(begin, end, 
                           (qi::float_ >> qi::omit["\">"] >> 
                           *~qi::char_('\n')) % *(qi::eol), 
                           data);
  //if you want to insert the "\n\n" to the string
  //bool const r = qi::parse(begin, end, 
  //                         +(qi::float_ >> qi::omit["\">"] >> 
  //                           qi::raw[*~qi::char_('\n') >> *(qi::eol)]), 
  //                           data);

  if(!r || begin != end){
    return false;
  }

  return r;
}

  This function will parse the time and the string into the vector "data".

ex : 0.5">if you are something
will parse to
float : 0.5
std::string :  "if you are something"

step 2 : transform the times

  There are many solutions to transform the times, like sscanf, stringstream, regular expression, hand made loop, spirit::karma and so on.For the sake of practice, I chose spirit::karma.


BOOST_FUSION_ADAPT_STRUCT(
spiritParser::transformData,
(size_t, index)
(std::vector<std::vector<int>>, nums)
)

template<typename OutputIterator>
struct videoGrammar : karma::grammar<OutputIterator, transformData()>
{
   videoGrammar()
   : videoGrammar::base_type(final_rule)
   {
      using karma::int_;
      using karma::repeat;
      using karma::right_align;
      using karma::uint_;

      first_rule = repeat(2)[right_align(2, '0')[int_ <<":"]]>>
                   right_align(2, '0')[int_] >>",">> 
                   right_align(2, '0')[int_];

      second_rule = first_rule >> " --> " >> first_rule >> "\n";
      final_rule = uint_ >> "\n">> second_rule;

   }

   karma::rule<OutputIterator, transformData()> final_rule;
   karma::rule<OutputIterator, std::vector<std::vector<int>>()> second_rule;
   karma::rule<OutputIterator, std::vector<int>()> first_rule;
};

inline void generate_nums(std::vector<int> &nums, float data)
{
   nums[0] = static_cast<int>(data / 3600);
   nums[1] = static_cast<int>(std::floor(data) / 60) % 60;
   nums[2] = static_cast<int>(std::floor(data)) % 60;
   nums[3] = static_cast<int>((data - std::floor(data)) * 1000.0);
}

template<typename Iterator, typename Grammar>
bool generate_times(Iterator sink, Grammar &grammar, transformData &data, 
                    size_t index, float fir, float sec)
{        
   data.index = index;
   generate_nums(data.nums[0], fir);
   generate_nums(data.nums[1], sec);
   bool r = karma::generate(sink,
                            grammar,
                            data
                           );

   return r;
}

Now we could transform the times from (0.5, 5.19) to (00:00:00,500 --> 00:00:05,190).

 The codes can download from github.