boost::spiritに手を出してみる

噂に違わぬ変態ぶりに感動しつつ、mqoを読むだけの実験コードを書いてみた。
これはいいものだ。
bison, flexの勉強しないといかんなぁと常々思っていたのだが
むしろこっちの方が使うの簡単だし申し分ないです。

http://luxla.net/project/mqo
blenderのmqoインポータをちょっと参考にしました。

まだ、シンボルの使い方がよくわからないので要練習デス。

#include <boost/spirit/core.hpp>
#include <boost/spirit/iterator/file_iterator.hpp>
#include <boost/spirit/utility.hpp>
#include <boost/lambda/bind.hpp>
#include <iostream>

void print(const char *text)
{
  std::cout << text << std::endl;
}

struct MQOParser : boost::spirit::grammar<MQOParser>
{
  template<typename ScannerT>
    struct definition
    {
      boost::spirit::rule<ScannerT> top, header, line, scene, material, object, vertex, face, includexml, backimage;

      definition(const MQOParser &)
      {
        using namespace boost::spirit;

        top=header >> *(scene | material | object | includexml | backimage | eol_p ) >> "Eof" >> eol_p;

        line=*(~chset<>("\r}")) >> eol_p;

        header
          =str_p("Metasequoia Document\r\nFormat Text Ver 1.0\r\n\r\n")
          [ boost::lambda::bind(&print, "Header") ];

        scene=("Scene " >> confix_p('{', *(~ch_p('}')), '}') >> eol_p)
          [ boost::lambda::bind(&print, "Scene") ];

        material=("Material " >> uint_p >> ' ' >> confix_p('{', *(~ch_p('}')), '}') >> eol_p)
          [ boost::lambda::bind(&print, "Material") ];

        object=("Object " >> confix_p('"', *(~ch_p('"')), '"') >> ' ' >> confix_p('{', *(vertex|face|line), '}') >> eol_p)
          [ boost::lambda::bind(&print, "Object") ], 

        vertex=("\tvertex " >> uint_p >> ' ' >> confix_p('{', *(~ch_p('}')), '}') >> eol_p)
            [ boost::lambda::bind(&print, "vertex") ];

        face=("\tface " >> uint_p >> ' ' >> confix_p('{', *(~ch_p('}')), '}') >> eol_p)
          [ boost::lambda::bind(&print, "face") ];

        includexml=("IncludeXml " >> confix_p('"', *(~ch_p('"')), '"') >> eol_p)
          [ boost::lambda::bind(&print, "includexml") ];

        backimage=("BackImage " >> confix_p('{', *(~ch_p('}')), '}') >> eol_p)
          [ boost::lambda::bind(&print, "backimage") ];
      }

      const boost::spirit::rule<ScannerT> &start() const { return top; };
    };

};

int main(int argc, char **argv)
{
  if(argc<2){
    std::cerr << "usage: " << argv[0] << " {mqo_file}" << std::endl;
    return 1;
  }

  boost::spirit::file_iterator<char> in(argv[1]);
  if(!in){
    std::cerr << "fail to open file: " << argv[1] << std::endl;
    return 1;
  }

  MQOParser parser;

  if(boost::spirit::parse(in, in.make_end(), MQOParser()).full){
    std::cout << "## SUCCESS ##" << std::endl;
    return 0;
  }
  else{
    std::cout << "## FAILED ##" << std::endl;
    return 1;
  }
}