C ++ istream с lex - PullRequest
       12

C ++ istream с lex

3 голосов
/ 09 марта 2012

У меня есть рабочая грамматика (написанная на лексах и бизонах), которая разбирает полиномиальные выражения.Это как ваш стандартный синтаксис, похожий на учебник.Вот очень упрощенная версия грамматики:

Expr
: DOUBLE        {$$ = newConstExpr($1);}
| Expr '+' Expr {$$ = newBinaryExpr('+', $1, $2);}
| Expr '*' Expr {$$ = NewBinaryExpr('*', $1, $2);}
| '(' Expr ')'  {$$ = $2;}
;

Моя проблема в том, что Лекс использует FILE * для yyin, и мне нужно проанализировать ввод из istream C ++.Я знаю, что flex ++ может генерировать класс FlexLexer (который может принимать istream в своей конструкции), но трудно заставить его связываться с Bison, и даже сам автор утверждает (в комментариях в сгенерированном файле лексера), чтоглючит.

Поэтому мне интересно, если кто-нибудь знает хороший способ использовать гибкий сканер и синтаксический анализатор бизонов с объектом istream C ++ в качестве ввода вместо ФАЙЛА *.

Ответы [ 2 ]

1 голос
/ 10 марта 2012

Вы можете получить входные данные в lex, если захотите, определив пользовательский макрос YY_INPUT.

Для примера из реальной жизни взгляните на мой:

http://www.kylheku.com/cgit/txr/tree/parser.l

Здесь я перенаправляю сканер flex для работы со специальными объектами потока, которые являются частью библиотеки динамических объектов. Как и iostream с, это не FILE *.

Это позволяет мне выполнять лексический анализ командной строки при запуске программы с -c <script text>.

(Кроме того, сканер работает с 8-битными байтами. Вот почему макрос YY_INPUT использует мою функцию get_byte. Когда yyin_stream является строковым потоком, реализация get_byte фактически выдаст байты кодирования UTF-8, соответствующие символам Unicode внутри строки, поэтому может потребоваться несколько вызовов get_byte, прежде чем поток перейдет к следующему символу строки. В файловом потоке get_byte просто получает байт из основной поток ОС.)

0 голосов
/ 26 октября 2016

Это рабочий пример пользовательского макроса YY_INPUT для чтения из интерактивного потока.

%{
// Place this code in istr.l and run with:
// $ flex istr.l && c++ istr.cpp && ./a.out
// $ flex istr.l && c++ istr.cpp && ./a.out 1a2b 123 abc
#include <iostream>

// The stream the lexer will read from.
// Declared as an extern
extern std::istream *lexer_ins_;

// Define YY_INPUT to get from lexer_ins_
// This definition mirrors the functionality of the default
// interactive YY_INPUT
#define YY_INPUT(buf, result, max_size)  \
  result = 0; \
  while (1) { \
    int c = lexer_ins_->get(); \
    if (lexer_ins_->eof()) { \
      break; \
    } \
    buf[result++] = c; \
    if (result == max_size || c == '\n') { \
      break; \
    } \
  }

%}

/* Turn on all the warnings, don't call yywrap. */
%option warn nodefault noyywrap
/* stdinit not required - since using streams. */
%option nostdinit
%option outfile="istr.cpp"

%%
      /* Example rules. */
[0-9] { std::cout << 'd'; }
\n    { std::cout << std::endl; }
.     { std::cout << '.'; }
<<EOF>> { yyterminate(); }
%%

//
// Example main. This could be in its own file.
//
#include <sstream>

// Define actual lexer stream 
std::istream *lexer_ins_;

int main(int argc, char** argv) {
  if (argc == 1) {
    // Use stdin
    lexer_ins_ = &std::cin;
    yylex();
  } else {
    // Use a string stream
    std::string data;
    for (int n = 1; n < argc; n++) {
      data.append(argv[n]);
      data.append("\n");
    }
    lexer_ins_ = new std::istringstream(data);
    yylex();
  }
}

Этот стиль сканера - с использованием C ++, но сгенерированный в стиле C - отлично работает для меня.Вы также можете попробовать экспериментальную опцию Flex %option c++.См. «Создание сканеров C ++» в руководстве по Flex.Похоже, не так много информации об интеграции этих сканеров с анализатором Bison.

Наконец, если для вашего случая достаточно чтения из памяти, вы можете избежать переопределения YY_INPUT - см. yy_scan_buffer() в руководстве Flex.

...