Как сломать следующую круговую зависимость с помощью flex и bison - PullRequest
0 голосов
/ 12 июля 2019

Я пытаюсь найти простой пример, который я нашел в Интернете, который реализует счетчик Word с помощью flex и bison.Ниже приведены файлы .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, компилятор жалуется, что тип сканеранеизвестноТеперь я не могу включить «mc_scanner.hpp» в файл .y, потому что он вводит циклическую зависимость.

Круговая зависимость: файл сканера mc_scanner.hpp зависит от mc_parser.tab.hh, потому что он должен знать, что такое semantic_type.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_scanner.hpp в mc_parser.y из-за этой циклической зависимости.

Есть какие-нибудь идеи относительно того, как я мог бы сломать эту зависимость?

1 Ответ

0 голосов
/ 12 июля 2019

Я решил проблему.Мне пришлось включить заголовочный файл класса сканера как раз перед началом грамматического блока.

...