help-flex
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: About C++ and flex


From: Hans Aberg
Subject: Re: About C++ and flex
Date: Thu, 22 Nov 2001 10:42:27 +0100

At 17:41 -0500 2001/11/21, Jesus M. Diaz Hernandez wrote:
>First, i'm trying to use the -+ option to generate an C++ scanner, but i
>need to use the scanner  with a generated bison function. So: how can i
>especify that yylex() is really yyFlexLexer::yylex()? Is that a clean way
>to do that? -diferent that #define ;)

In my .y file, I have put:
  %{
  ...
  #include "op_parser.h"

  FlexLexer* op_lexer;
  inline int yylex() { return op_lexer->yylex(); }
  ...
  %}
Here, "op_lexer" is just a name for the lexer in this particular project
(which parses operator names).

Before you start to use op_lexer, you must create it using "new". So the
header op_parser.h contains:

class op_parser_type {
public:
  std::string text;
  op::table::iterator index;
};

#define YYSTYPE op_parser_type

int yyerror(const std::string& errstr);

class op_parser {
  std::istream* isp;  // istream being parsed
  std::ostream* osp;  // ostream being output to
  FlexLexer* lex;     // Lexical analyzer to use;
public:
  op_parser(std::istream* isp = 0, std::ostream* osp = 0);
  ~op_parser();

  friend std::istream& operator>>(std::istream&, op_parser&);
};

Then in the .y file, I hav eput the definitions:
%%

op_parser::op_parser(std::istream* ip, std::ostream* op)
 : isp(ip), osp(op) { lex = new yyFlexLexer(isp, osp); }

op_parser::~op_parser() { delete lex; }


std::istream& operator>>(std::istream& is, op_parser& parser) {
  parser.isp = &is;
  parser.lex->yyrestart(&is);
  op_lexer = parser.lex;
  if (yyparse() != 0)
    is.setstate(std::ios::failbit);
  else
    is.clear(is.rdstate() & ~(std::ios::failbit | std::ios::badbit));
  return is;
}

int yyerror(const std::string& errstr) {
  std::cerr << "Error line " << op_lexer->lineno() << ": "
            << errstr << "." << std::endl;
  return EXIT_FAILURE;
}

Bison is called using the option --name-prefix=op_parser, because I often
use more than one parser in the same program. Flex then is compiled with
the corresponding option -Pop_parser. One should probably do a version
using the Bison pure-parser option, but I have not done that one yet (Bison
has been extended in a way facilitating such a version).

I then call it as in the example below. It should give an idea of how to
call it both from a file, and line-by-line from the console. In the latter
case, it might have been better to not re-invoke the parser for every new
line, because on some consoles one can enter more than one line at once,
and it is then better to let the parser parse the whole chunk. But it
should give you an input on how to do such a setup.

#include "op_parser.h"

int main() {
try {
  std::cout << "Operator Precedence Parser" << std::endl;

  std::ifstream ifs("operator.def");
  if (!ifs)  std::cout << "No definitions file." << std::endl;
  else {
    std::cout << "Reading definitions file: " << std::flush;
    ifs >> op_parser();
    std::cout << "Done." << std::endl;
  }

  std::cout << "For help, type \":?\"." << std::endl;

  for (;;) {
    try {
      std::cout << "> ";
      std::string str;
      std::getline(std::cin, str);
      std::istringstream iss(str);
      iss >> op_parser();
    } catch (op::parse_error& ex) {
      std::cerr << "Parse error: " << ex.what() << std::endl;
      op::stack_.clear();
    }
  }

} catch (std::exception& ex) {
  std::cerr << "Unexpected exception: " << ex.what()
            << "\nBye, bye!" << std::endl;
  return EXIT_FAILURE;
} catch (...) {
  std::cerr << "Unexpected exception. Bye, bye!" << std::endl;
  return EXIT_FAILURE;
}

  return EXIT_SUCCESS;
}

  Hans Aberg





reply via email to

[Prev in Thread] Current Thread [Next in Thread]