加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

GNU / Flex C是否可以工作?

发布时间:2020-12-15 02:10:11 所属栏目:百科 来源:网络整理
导读:引用本书flex amp;野牛(O’Reilly,John Levine,2009): “Bison can create parsers in C++. Although flex appears to be able to create C++,scanners,the C++ code doesn’t work.[21] Fortunately,C scanners created by flex compile under C++ and it
引用本书flex& amp;野牛(O’Reilly,John Levine,2009):

“Bison can create parsers in C++. Although flex appears to be able to create C++,scanners,the C++ code doesn’t work.[21] Fortunately,C scanners created by flex compile under C++ and it is not hard to use a flex C scanner with a bison C++ parser”. (Footnote [21]: “This is confirmed by the guy who wrote it. It will probably be fixed eventually,but it turned out to be surprisingly hard to design a good C++ interface for flex scanners.”)

在我努力编写一个相当复杂的Flex扫描程序之前,我(我想我们很多人)想知道自2009年以来是否有任何关于这方面的变化.是否有人成功编写Flex / C解析器?如果是这样,是否值得努力,或者C扫描仪是否仍然是最安全的C解析器?

解决方法

这是完全可能的,一旦设置它就会很好用.不幸的是,关于纯C Flex / Bison词法分析器的文档并不那么容易找到和遵循.

我可以向你揭示我编写的解析器的准确性,但这只是你如何做到这一点的一个例子.

请注意,这些代码中的一些是通过反复试验设置的,因为文档很少,所以可能是多余的操作或不完全正确但可行的事情.

ypp文件

%skeleton "lalr1.cc"
%require "3.0.2"

%defines
%define api.namespace {script}
%define parser_class_name {Parser}

%define api.token.constructor
%define api.value.type variant
%define parse.assert true

%code requires {

  namespace script
  {
    class Compiler;
    class Lexer;
  }
}

%lex-param { script::Lexer &lexer }
%lex-param { script::Compiler &compiler }
%parse-param { script::Lexer &lexer }
%parse-param { script::Compiler &compiler }

%locations
%initial-action
{
  @$.begin.filename = @$.end.filename = &compiler.file;
};

%define parse.trace
%define parse.error verbose

%code top {
  #include "Compiler.h"
  #include "MyLexer.h"
  #include "MyParser.hpp"

  static script::Parser::symbol_type yylex(script::Lexer &scanner,script::Compiler &compiler) {
    return scanner.get_next_token();
  }

  using namespace script;
}

// tokens and grammar

void script::Parser::error(const location_type& l,const std::string& m)
{
  compiler.error(l,m);
}

例如,您可以在这里使用C.

%type<std::list<Statement*>> statement_list for_statement
...
statement_list:
  { $$= std::list<Statement*>(); }
  | statement_list statement { $1.push_back($2); $$= $1; }
;

我的文件

%{
  #include "MyParser.hpp"
  #include "MyLexer.h"
  #include "Compiler.h"
  #include <string>

  typedef script::Parser::token token;

  #define yyterminate() script::Parser::make_END(loc);

  static script::location loc;

  using namespace script;
%}

%x sstring
%x scomment

%option nodefault
%option noyywrap
%option c++
%option yyclass="Lexer"
%option prefix="My"


%{
  # define YY_USER_ACTION  loc.columns((int)yyleng);
%}


%%

%{
  loc.step();
%}

然后你需要一个头文件来定义你的Lexer类,它将继承yyFlexLexer,这就是C Flex的工作方式,就像这样

#if ! defined(yyFlexLexerOnce)
#undef yyFlexLexer
#define yyFlexLexer NanoFlexLexer
#include <FlexLexer.h>
#endif

#undef YY_DECL
#define YY_DECL script::Parser::symbol_type script::Lexer::get_next_token()

#include "MyParser.hpp"

namespace script
{
  class Compiler;

  class Lexer : public yyFlexLexer
  {
  public:

    Lexer(Compiler &compiler,std::istream *in) : yyFlexLexer(in),compiler(compiler) {}

    virtual script::Parser::symbol_type get_next_token();
    virtual ~Lexer() { }

  private:

    Compiler &compiler;
  };

}

最后一步是定义你的Compiler类,它将从Bison语法规则中调用(这就是ypp文件中parse-param属性的用途).就像是:

#include "parser/MyParser.hpp"
#include "parser/MyLexer.h"
#include "parser/location.hh"

#include "Symbols.h"

namespace script
{
  class Compiler
  {

  public:
    Compiler();

    std::string file;

    void error(const location& l,const std::string& m);
    void error(const std::string& m);

    vm::Script* compile(const std::string& text);

    bool parseString(const std::string& text);

    void setRoot(ASTRoot* root);
    Node* getRoot() { return root.get(); }
  };
}

现在您可以轻松地执行解析并完全通过C代码,例如:

bool Compiler::parseString(const std::string &text)
{      
  constexpr bool shouldGenerateTrace = false;

  istringstream ss(text);

  script::Lexer lexer = script::Lexer(*this,&ss);
  script::Parser parser(lexer,*this);
  parser.set_debug_level(shouldGenerateTrace);
  return parser.parse() == 0;
}

您必须注意的唯一事情是使用-c参数调用.l文件上的flex,以使其生成C词法分析器.

实际上,通过一些谨慎的操作,我也可以在同一个项目中拥有多个独立且可自我重入的词法分析器/解析器.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读