如何用flex和bison打破以下循环依赖

时间:2019-07-11 21:41:08

标签: bison flex-lexer

我正在尝试一个在网上找到的简单示例,该示例使用flex和bison实现了Word计数器。以下是.y和.l文件:

mc_lexer.l

%{
/* C++ string header, for string ops below */
#include <string>

/* Implementation of yyFlexScanner */ 
#include "mc_scanner.hpp"
#undef  YY_DECL
#define YY_DECL int MC::MC_Scanner::yylex( MC::MC_Parser::semantic_type * 
const lval, MC::MC_Parser::location_type *loc )

/* typedef to make the returns for the tokens shorter */
using token = MC::MC_Parser::token;

/* define yyterminate as this instead of NULL */
#define yyterminate() return( token::END )

/* msvc2010 requires that we exclude this header file. */
#define YY_NO_UNISTD_H

/* update location on matching */
#define YY_USER_ACTION loc->step(); loc->columns(yyleng);

%}

%option debug
%option nodefault
%option yyclass="MC::MC_Scanner"
%option noyywrap
%option c++

%%
%{          /** Code executed at the beginning of yylex **/
            yylval = lval;
%}

[a-z]       {
               return( token::LOWER );
            }

[A-Z]       {
               return( token::UPPER );
            }

[a-zA-Z]+   {
               yylval->build< std::string >( yytext );
               return( token::WORD );
            }

 %%

mc_parser.yy

%skeleton "lalr1.cc"
%require  "3.0"
%debug 
%defines 
%define api.namespace {MC}
%define parser_class_name {MC_Parser}

%code requires{
   namespace MC {
      class MC_Driver;
      class MC_Scanner;
 }

 %parse-param { MC_Scanner  &scanner  }
 %parse-param { MC_Driver  &driver  }

 %code{
 #include <iostream>
 #include <cstdlib>
 #include <fstream>

 /* include for all driver functions */
 #include "mc_driver.hpp"

 #undef yylex
 #define yylex scanner.yylex
 }

... / *文件的其余部分* /

mc_scanner.hpp

#if ! defined(yyFlexLexerOnce)
#include <FlexLexer.h>
#endif

#include "mc_parser.tab.hh"
#include "location.hh"

namespace MC{

    class MC_Scanner : public yyFlexLexer{
    public:

      MC_Scanner(std::istream *in) : yyFlexLexer(in)
      {};
      virtual ~MC_Scanner() {};

      //get rid of override virtual function warning
      using FlexLexer::yylex;

      virtual
      int yylex( MC::MC_Parser::semantic_type * const lval, 
                 MC::MC_Parser::location_type *location );
      // YY_DECL defined in mc_lexer.l
      // Method body created by flex in mc_lexer.yy.cc


     private:
       /* yyval ptr */
      MC::MC_Parser::semantic_type *yylval = nullptr;
   };

} /* end namespace MC */

当我使用在网上找到的Makefile进行构建时,构建成功。当我尝试使用构建系统对其进行测试时,编译器抱怨以下代码行:

#undef yylex
#define yylex scanner.yylex

由于MC_Scanner正好在.yy文件中声明,因此编译器会抱怨扫描器的类型未知。现在,我无法在.y文件中包含“ mc_scanner.hpp”,因为它将引入循环依赖关系。

循环依赖项:扫描程序文件mc_scanner.hpp依赖于mc_parser.tab.hh,因为它需要知道什么是语义类型。 mc_parser.tab.hh由mc_parser.y生成。

现在mc_parser.y具有以下代码行:

#undef yylex
#define yylex scanner.yylex

扫描仪声明如下:

%code requires{
   namespace MC {
      class MC_Driver;
      class MC_Scanner;
 }

 %parse-param { MC_Scanner  &scanner  }
 %parse-param { MC_Driver  &driver  }

因此,编译器抱怨无法确定扫描仪的类型。而且由于这种循环依赖性,我无法在mc_parser.y中加入mc_scanner.hpp。

关于如何消除这种依赖性的任何想法?

1 个答案:

答案 0 :(得分:0)

我解决了这个问题。我必须在语法块开始之前包括扫描程序类的头文件。