Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使boost::spirit解析器和lexer能够处理包含文件_C++_Boost Spirit - Fatal编程技术网

C++ 如何使boost::spirit解析器和lexer能够处理包含文件

C++ 如何使boost::spirit解析器和lexer能够处理包含文件,c++,boost-spirit,C++,Boost Spirit,这是一个不做任何事情的词法分析器&它返回读取的字符串。 我希望扩展它,以便能够处理类似C++的include语句。 我可以想象如何做到这一点——但我想知道是否有更简单或已经可用的方法。 如果必须这样做,我将实现自己的迭代器(传递给lexer)。这个迭代器将包含 字符串的索引(可能使用-1表示end()迭代器) 指向此字符串的指针 lexer遇到某个include语句时会将文件插入当前位置的字符串中,覆盖include语句。 你会怎么做 下面是我的不做任何事情的词法分析器/解析器: #incl

这是一个不做任何事情的词法分析器&它返回读取的字符串。 我希望扩展它,以便能够处理类似C++的include语句。 我可以想象如何做到这一点——但我想知道是否有更简单或已经可用的方法。 如果必须这样做,我将实现自己的迭代器(传递给lexer)。这个迭代器将包含

  • 字符串的索引(可能使用-1表示end()迭代器)
  • 指向此字符串的指针
lexer遇到某个include语句时会将文件插入当前位置的字符串中,覆盖include语句。 你会怎么做

下面是我的不做任何事情的词法分析器/解析器:

#include <boost/phoenix.hpp>
#include <boost/bind.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

namespace lex     = boost::spirit::lex;
namespace qi      = boost::spirit::qi;
namespace phoenix = boost::phoenix;


template<typename Lexer>
class lexer:public lex::lexer<Lexer>
{   public:
    typedef lex::token_def<char> char_token_type;
    char_token_type m_sChar;
    //lex::token_def<lex::omit> m_sInclude;
    lexer(void)
        : m_sChar(".")//,
        //m_sInclude("^#include \"[^\"]*\"")
    {   this->self += m_sChar;
    }
};

template<typename Iterator>
class grammar : public qi::grammar<Iterator, std::string()>
{   public:
    qi::rule<Iterator, std::string()> m_sStart;
    template<typename Tokens>
    explicit grammar(Tokens const& tokens)
        : grammar::base_type(m_sStart)
    {   m_sStart %= *tokens.m_sChar >> qi::eoi;
    }
};


int main(int, char**)
{
    typedef lex::lexertl::token<std::string::const_iterator, boost::mpl::vector<char> > token_type;
    typedef lexer<lex::lexertl::actor_lexer<token_type> > expression_lexer_type;
    typedef expression_lexer_type::iterator_type expression_lexer_iterator_type;
    typedef grammar<expression_lexer_iterator_type> expression_grammar_type;

    expression_lexer_type lexer;
    expression_grammar_type grammar(lexer);
    const std::string s_ac = "this is a test\n\
#include \"test.dat\"\n\
";
    std::string s;
    auto pBegin = std::begin(s_ac);
        lex::tokenize_and_parse(pBegin, std::end(s_ac), lexer, grammar, s);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间lex=boost::spirit::lex;
名称空间qi=boost::spirit::qi;
名称空间phoenix=boost::phoenix;
模板
类lexer:public lex::lexer
{公众:
typedef lex::token_def char_token_type;
char_token_类型m_sChar;
//lex::token_def m_sInclude;
lexer(无效)
:m_sChar(“.”/,
//m#u sInclude(“^#include\”[^\“]*\”)
{this->self+=m_sChar;
}
};
模板
类语法:公共qi::语法
{公众:
qi::规则m_sStart;
模板
显式语法(令牌常量和令牌)
:语法::基本类型(m\u sStart)
{m_sStart%=*tokens.m_sChar>>qi::eoi;
}
};
int main(int,char**)
{
typedef lex::lexertl::token token_type;
typedef lexer表达式\u lexer\u类型;
typedef expression_lexer_type::迭代器_type expression_lexer_iterator_type;
typedef语法表达式\ u语法\ u类型;
表达式\ lexer \类型lexer;
表达式语法类型语法(lexer);
const std::string s_ac=“这是一个测试\n\
#包括\“test.dat\”\n\
";
std::字符串s;
auto pBegin=std::begin(s_ac);
lex::tokenize_和_parse(pBegin,std::end(s_ac),lexer,grammar,s);
}

首先,存在一个基于Spirit的预处理器:(另请参见)

其次,“将include文件的内容插入字符串值”既没有用处(用于词法分析),又效率极低:

  • 这是无用的,因为include文件将形成一个标记(!?),这意味着您的解析器无法对包含的内容进行操作
  • 它不是泛型的,因为嵌套包含不会以这种方式发生
  • 即使目标只是将include文件逐字复制到一个等效的输出流中,但将内容完全复制到内存中,通过lexer将其复制到解析器中,然后将其流出来,这样做的效率也非常低。您只需以最小的分配将输入流虹吸到输出流中即可
我建议以下任何组合:

  • 单独关注点:不要将解析和解释混为一谈。所以,若要解析include指令,您将返回include语句的表示形式,然后可以将其传递给解释它的代码

  • 关注点分离的一个特殊、更强的例子是将包含处理移动到预处理阶段。事实上,自定义迭代器类型可以做到这一点,但我会在其上构建lexer,因此lexer不必知道包含,而只需对源进行lexer,而不必知道确切的来源


    • 下面的代码将include语句替换为“abcd”--这应该是文件的内容

      #include <boost/phoenix.hpp>
      #include <boost/bind.hpp>
      #include <boost/fusion/adapted/struct.hpp>
      #include <boost/spirit/include/lex_lexertl.hpp>
      #include <boost/spirit/include/qi.hpp>
      #include <boost/config/warning_disable.hpp>
      #include <boost/spirit/include/qi.hpp>
      #include <boost/spirit/include/phoenix_core.hpp>
      #include <boost/spirit/include/phoenix_operator.hpp>
      #include <boost/phoenix/object.hpp>
      #include <boost/spirit/include/qi_char_class.hpp>
      #include <boost/spirit/include/phoenix_bind.hpp>
      #include <boost/mpl/index_of.hpp>
      #include <boost/spirit/include/lex_lexertl.hpp>
      
      #include <algorithm>
      #include <iostream>
      #include <string>
      #include <utility>
      #include <vector>
      #include <iterator>
      
      
      namespace lex     = boost::spirit::lex;
      namespace qi      = boost::spirit::qi;
      namespace phoenix = boost::phoenix;
      
      struct myIterator:std::iterator<std::random_access_iterator_tag, char>
      {   std::string *m_p;
          std::size_t m_iPos;
          myIterator(void)
              :m_p(nullptr),
              m_iPos(~std::size_t(0))
          {
          }
          myIterator(std::string &_r, const bool _bEnd = false)
              :m_p(&_r),
              m_iPos(_bEnd ? ~std::size_t(0) : 0)
          {
          }
          myIterator(const myIterator &_r)
              :m_p(_r.m_p),
              m_iPos(_r.m_iPos)
          {
          }
          myIterator &operator=(const myIterator &_r)
          {   if (this != &_r)
              {   m_p = _r.m_p;
                  m_iPos = _r.m_iPos;
              }
              return *this;
          }
          const char &operator*(void) const
          {   return m_p->at(m_iPos);
          }
          bool operator==(const myIterator &_r) const
          {   return m_p == _r.m_p && m_iPos == _r.m_iPos;
          }
          bool operator!=(const myIterator &_r) const
          {   return m_p != _r.m_p || m_iPos != _r.m_iPos;
          }
          myIterator &operator++(void)
          {   ++m_iPos;
              if (m_iPos == m_p->size())
                  m_iPos = ~std::size_t(0);
              return *this;
          }
          myIterator operator++(int)
          {   const myIterator s(*this);
              operator++();
              return s;
          }
      };
      struct include
      {   auto operator()(myIterator &_rStart, myIterator &_rEnd) const
          {       // erase what has been matched (the include statement)
              _rStart.m_p->erase(_rStart.m_iPos, _rEnd.m_iPos - _rStart.m_iPos);
                  // and insert the contents of the file
              _rStart.m_p->insert(_rStart.m_iPos, "abcd");
              _rEnd = _rStart;
              return lex::pass_flags::pass_ignore;
      //lex::_pass = lex::pass_flags::pass_ignore
          }
      };
      template<typename Lexer>
      class lexer:public lex::lexer<Lexer>
      {   public:
          typedef lex::token_def<char> char_token_type;
          char_token_type m_sChar;
          lex::token_def<lex::omit> m_sInclude;
          lexer(void)
              : m_sChar("."),
              m_sInclude("#include [\"][^\"]*[\"]")
          {   this->self += m_sInclude[lex::_pass = boost::phoenix::bind(include(), lex::_start, lex::_end)]
                  | m_sChar;
          }
      };
      
      template<typename Iterator>
      class grammar : public qi::grammar<Iterator, std::string()>
      {   public:
          qi::rule<Iterator, std::string()> m_sStart;
          template<typename Tokens>
          explicit grammar(Tokens const& tokens)
              : grammar::base_type(m_sStart)
          {   m_sStart %= *tokens.m_sChar >> qi::eoi;
          }
      };
      
      
      int main(int, char**)
      {
          typedef lex::lexertl::token<myIterator, boost::mpl::vector<char> > token_type;
          typedef lexer<lex::lexertl::actor_lexer<token_type> > expression_lexer_type;
          typedef expression_lexer_type::iterator_type expression_lexer_iterator_type;
          typedef grammar<expression_lexer_iterator_type> expression_grammar_type;
      
          expression_lexer_type lexer;
          expression_grammar_type grammar(lexer);
          std::string s_ac = "this is a test\n\
      #include \"test.dat\"\n\
      ";
          std::string s;
          myIterator pBegin(s_ac);
              lex::tokenize_and_parse(pBegin, myIterator(s_ac, true), lexer, grammar, s);
      }
      
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      #包括
      名称空间lex=boost::spirit::lex;
      名称空间qi=boost::spirit::qi;
      名称空间phoenix=boost::phoenix;
      结构myIterator:std::iterator
      {std::string*m_p;
      标准:首次公开募股的规模;
      My迭代器(void)
      :m_p(nullptr),
      m_IPO(~std::size_t(0))
      {
      }
      My迭代器(std::string&\u r,const bool\u bEnd=false)
      :m_p(&u r),
      m_IPO(_bEnd?~std::size_t(0):0)
      {
      }
      myIterator(常量myIterator&\r)
      :m_p(_r.m_p),
      m_IPO(_r.m_IPO)
      {
      }
      myIterator&运算符=(常量myIterator&\u r)
      {如果(这个!=&\r)
      {m_p=\u r.m_p;
      m_IPO=_r.m_IPO;
      }
      归还*这个;
      }
      常量字符和运算符*(无效)常量
      {返回m_p->at(m_IPO);
      }
      布尔运算符==(常量myIterator&_r)常量
      {return m_p===u r.m_p&&m_ipo===u r.m_ipo;
      }
      布尔运算符!=(常量myIterator&_r)常量
      {返回m|p!=|r.m|p | m|U IPO!=|r.m|U IPO;
      }
      My迭代器和运算符++(void)
      {++m_IPO;
      如果(m_IPO==m_p->size())
      m_iPos=~std::size_t(0);
      归还*这个;
      }
      myIterator运算符++(int)
      {const myIterator s(*this);
      运算符++();
      返回s;
      }
      };
      结构包括
      {auto operator()(myIterator&\u rStart,myIterator&\u rEnd)常量
      {//删除已匹配的内容(include语句)
      _rStart.m\u p->erase(\u rStart.m\u iPos,\u rEnd.m\u iPos-\u rStart.m\u iPos);
      //并插入文件的内容
      _rStart.m_p->insert(rStart.m_ipo,“abcd”);
      _rEnd=_rStart;
      返回lex::pass\u flags::pass\u ignore;
      //lex::_pass=lex::pass\u标志::pass\u忽略
      }
      };
      模板
      类lexer:public lex::lexer
      {公众:
      typedef lex::token_def char_token_type;
      char_token_类型m_sChar;
      lex::token_def m_sInclude;
      lexer(无效)
      :m_sChar(“.”),
      m#u包括(“#include[\”][^\“]*[\”]”)
      {this->self+=m_sInclude[lex::_pass=boost::phoenix::bind(include(),lex::_start,lex:_end)]
      |穆沙尔;
      }
      };
      模板
      类语法:公共qi::语法
      {公众:
      qi::规则m_sStart;
      模板