野牛解析器在输入结束时给出错误

时间:2018-06-13 05:49:40

标签: c++ bison flex-lexer

我是flex&的新手bison,我正在按照教程来帮助将用c编写的解析器转换为c ++。但是,在我按照本教程后,我的解析器不起作用。 从文件读取是好的,但从stdin读取会导致麻烦,按下ctrl D终止后,它会抛出错误,它会说语法错误。 这是我跟随的 picture of results showing syntax error

tutorial address

我搜索了很长时间,并尝试从#define yyterminate() return(token::END)中移除mc_lexer.l,正如其他人建议的那样,并没有成功。

我想这与eof令牌有关。但我现在不知道该怎么办。

这里是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;
   }

// The following definitions is missing when %locations isn't used
# ifndef YY_NULLPTR
#  if defined __cplusplus && 201103L <= __cplusplus
#   define YY_NULLPTR nullptr
#  else
#   define YY_NULLPTR 0
#  endif
# endif

}

%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
}

%define api.value.type variant
%define parse.assert

%token               END    0     "end of file"
%token               UPPER
%token               LOWER
%token <std::string> WORD
%token               NEWLINE
%token               CHAR

%locations

%%

list_option : END | list END;

list
  : item
  | list item
  ;

item
  : UPPER   { driver.add_upper(); }
  | LOWER   { driver.add_lower(); }
  | WORD    { driver.add_word( $1 ); }
  | NEWLINE { driver.add_newline(); }
  | CHAR    { driver.add_char(); }
  ;

%%


void 
MC::MC_Parser::error( const location_type &l, const std::string &err_message )
{
   std::cerr << "Error: " << err_message << " at " << l << "\n";
}

这里是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 );
            }

\n          {
               // Update line number
               loc->lines();
               return( token::NEWLINE );
            }

.           {
               return( token::CHAR );
            }

%%

mc_scanner.hpp

#ifndef __MCSCANNER_HPP__
#define __MCSCANNER_HPP__ 1

#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)
   {
      loc = new MC::MC_Parser::location_type();
   };

   //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;
   /* location ptr */
   MC::MC_Parser::location_type *loc    = nullptr;
};

} /* end namespace MC */

#endif /* END __MCSCANNER_HPP__ */

mc_driver.cpp

 #include <cctype>
    #include <fstream>
    #include <cassert>

    #include "mc_driver.hpp"

    MC::MC_Driver::~MC_Driver()
    {
       delete(scanner);
       scanner = nullptr;
       delete(parser);
       parser = nullptr;
    }

    void 
    MC::MC_Driver::parse( const char * const filename )
    {
       assert( filename != nullptr );
       std::ifstream in_file( filename );
       if( ! in_file.good() )
       {
           exit( EXIT_FAILURE );
       }
       parse_helper( in_file );
       return;
    }

    void
    MC::MC_Driver::parse( std::istream &stream )
    {
       if( ! stream.good()  && stream.eof() )
       {
           return;
       }
       //else
       parse_helper( stream ); 
       return;
    }


    void 
    MC::MC_Driver::parse_helper( std::istream &stream )
    {

       delete(scanner);
       try
       {
          scanner = new MC::MC_Scanner( &stream );
       }
       catch( std::bad_alloc &ba )
       {
          std::cerr << "Failed to allocate scanner: (" <<
             ba.what() << "), exiting!!\n";
          exit( EXIT_FAILURE );
       }

       delete(parser); 
       try
       {
          parser = new MC::MC_Parser( (*scanner) /* scanner */, 
                                      (*this) /* driver */ );
       }
       catch( std::bad_alloc &ba )
       {
          std::cerr << "Failed to allocate parser: (" << 
             ba.what() << "), exiting!!\n";
          exit( EXIT_FAILURE );
       }
       const int accept( 0 );
       if( parser->parse() != accept )
       {
          std::cerr << "Parse failed!!\n";
       }
       return;
    }

    void 
    MC::MC_Driver::add_upper()
    { 
       uppercase++; 
       chars++; 
       words++; 
    }

    void 
    MC::MC_Driver::add_lower()
    { 
       lowercase++; 
       chars++; 
       words++; 
    }

    void 
    MC::MC_Driver::add_word( const std::string &word )
    {
       words++; 
       chars += word.length();
       for(const char &c : word ){
          if( islower( c ) )
          { 
             lowercase++; 
          }
          else if ( isupper( c ) ) 
          { 
             uppercase++; 
          }
       }
    }

    void 
    MC::MC_Driver::add_newline()
    { 
       lines++; 
       chars++; 
    }

    void 
    MC::MC_Driver::add_char()
    { 
       chars++; 
    }


    std::ostream& 
    MC::MC_Driver::print( std::ostream &stream )
    {
       stream << red  << "Results: " << norm << "\n";
       stream << blue << "Uppercase: " << norm << uppercase << "\n";
       stream << blue << "Lowercase: " << norm << lowercase << "\n";
       stream << blue << "Lines: " << norm << lines << "\n";
       stream << blue << "Words: " << norm << words << "\n";
       stream << blue << "Characters: " << norm << chars << "\n";
       return(stream);
    }

这里是main.cpp

#include <iostream>
#include <cstdlib>
#include <cstring>

#include "mc_driver.hpp"

int 
main( const int argc, const char **argv )
{
   /** check for the right # of arguments **/
   if( argc == 2 )
   {
      MC::MC_Driver driver;
      /** example for piping input from terminal, i.e., using cat **/ 
      if( std::strncmp( argv[ 1 ], "-o", 2 ) == 0 )
      {
         driver.parse( std::cin );
      }
      /** simple help menu **/
      else if( std::strncmp( argv[ 1 ], "-h", 2 ) == 0 )
      {
         std::cout << "use -o for pipe to std::cin\n";
         std::cout << "just give a filename to count from a file\n";
         std::cout << "use -h to get this menu\n";
         return( EXIT_SUCCESS );
      }
      /** example reading input from a file **/
      else
      {
          std::cout << "2333333"<< std::endl;
         /** assume file, prod code, use stat to check **/
         driver.parse( argv[1] );
         std::cout << "2333333"<< std::endl;
      }
      driver.print( std::cout ) << "\n";
   }
   else
   {
      /** exit with failure condition **/
      return ( EXIT_FAILURE );
   }
   return( EXIT_SUCCESS );
}

这里是makefile

CC    ?= clang
CXX   ?= clang++

EXE = minisql

CDEBUG = -g -Wall

CXXDEBUG = -g -Wall

CSTD = -std=c99
CXXSTD = -std=c++11

CFLAGS = -Wno-deprecated-register -O0  $(CDEBUG) $(CSTD) 
CXXFLAGS = -Wno-deprecated-register -O0  $(CXXDEBUG) $(CXXSTD)


CPPOBJ = main mc_driver
SOBJ =  parser lexer

FILES = $(addsuffix .cpp, $(CPPOBJ))

OBJS  = $(addsuffix .o, $(CPPOBJ))

CLEANLIST =  $(addsuffix .o, $(OBJ)) $(OBJS) \
                 mc_parser.tab.cc mc_parser.tab.hh \
                 location.hh position.hh \
                stack.hh mc_parser.output parser.o \
                 lexer.o mc_lexer.yy.cc $(EXE)\

.PHONY: all
all: wc

wc: $(FILES)
    $(MAKE) $(SOBJ)
    $(MAKE) $(OBJS)
    $(CXX) $(CXXFLAGS) -o $(EXE) $(OBJS) parser.o lexer.o $(LIBS)


parser: mc_parser.yy
    bison -d -v mc_parser.yy
    $(CXX) $(CXXFLAGS) -c -o parser.o mc_parser.tab.cc

lexer: mc_lexer.l
    flex --outfile=mc_lexer.yy.cc  $<
    $(CXX)  $(CXXFLAGS) -c mc_lexer.yy.cc -o lexer.o

.PHONY: test
test:
    cd test && ./test0.pl

.PHONY: clean
clean:
    rm -rf $(CLEANLIST)

完整的代码可以在github下载

github code address

0 个答案:

没有答案
相关问题