Проблемы с реентерабельным Flex и Bison

Я изучаю, как использовать реентерабельные Bison и Flex вместе. У меня уже есть простой калькулятор, работающий без возможности повторного входа. Однако, когда я активировал функцию повторного входа и внес необходимые изменения, я не смог заставить это работать.

Вот код:

scanner.l

%{
#include <stdio.h>
#include "parser.tab.h"
%}

%option 8bit reentrant bison-bridge
%option warn noyywrap nodefault
%option header-file="lex.yy.h"

DIGIT [0-9]

%%

"+"    { return ADD; }
"-"    { return SUB; }
"*"    { return MUL; }
"/"    { return DIV; }
{DIGIT}+ { *yylval = atof(yytext); return NUM; }
\n     { return EOL; }
[ \t]  {  }
.      { printf("What is this: %s.\n", yytext); }
%%

parser.y

%{
#include <stdio.h>
#include "lex.yy.h"

void yyerror(yyscan_t scanner, char const *msg);
%}

%define api.value.type {double}
%define parse.error verbose
%define api.pure 
%lex-param {yyscan_t scanner}
%parse-param {yyscan_t scanner}

%token NUM EOL                  
%left ADD SUB
%left MUL DIV

%%

input: %empty
| input line
;

line: EOL { printf("|> ");}
| exp EOL { printf("|R> %.4lf\n", $exp); }
;

exp: NUM { $$ = $1; }
| exp ADD exp { $$ = $1 + $3; }
| exp SUB exp { $$ = $1 - $3; }
| exp MUL exp { $$ = $1 * $3; }
| exp DIV exp { $$ = $1 / $3; }
;

%%

void yyerror(yyscan_t scanner, char const *msg) {
    fprintf(stderr, "Error: %s\n", msg);
}

main.c

#include <stdio.h>
#include "parser.tab.h"
#include "lex.yy.h"

int main(void) {

  yyscan_t scanner;

  yylex_init(&scanner);
  yyset_in(stdin, scanner);

  yyparse(scanner);

  yylex_destroy(scanner);

  return 0;
}

и это Makefile, который я использую:

all: calc.x

parser.tab.c parser.tab.h: parser.y
    bison -d parser.y

lex.yy.c lex.yy.h: scanner.l parser.tab.h
    flex scanner.l

calc.x: lex.yy.c lex.yy.h parser.tab.c parser.tab.h
    gcc main.c parser.tab.c lex.yy.c -o calc.x

clean:
    rm calc.x lex.yy.c lex.yy.h parser.tab.c parser.tab.h *.o

Запустив make, я получил следующую ошибку:

In file included from main.c:2:0:
parser.tab.h:66:14: error: unknown type name ‘yyscan_t’
 int yyparse (yyscan_t scanner);
              ^
main.c: In function ‘main’:
main.c:12:3: warning: implicit declaration of function ‘yyparse’ [-Wimplicit-function-declaration]
   yyparse(scanner);
   ^
In file included from parser.y:5:0:
lex.yy.h:282:1: error: unknown type name ‘YYSTYPE’
 YYSTYPE * yyget_lval (yyscan_t yyscanner );
 ^
lex.yy.h:284:18: error: unknown type name ‘YYSTYPE’
 void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
                  ^
lex.yy.h:332:17: error: unknown type name ‘YYSTYPE’
                (YYSTYPE * yylval_param ,yyscan_t yyscanner);
                 ^
parser.tab.c: In function ‘yyparse’:
parser.tab.c:1130:16: warning: implicit declaration of function ‘yylex’ [-Wimplicit-function-declaration]
       yychar = yylex (&yylval, scanner);
                ^
Makefile:10: recipe for target 'calc.x' failed
make: *** [calc.x] Error 1

Но я не понимаю происхождение этой ошибки и предупреждающих сообщений, например:

main.c:12:3: warning: implicit declaration of function ‘yyparse’

Но yyparse уже определен в parser.tab.h и включен в main.c. Другой пример:

parser.tab.h:66:14: error: unknown type name ‘yyscan_t’

А внутри parser.y включаю заголовок сканера lex.yy.h.

Я нашел эти решения в Интернете:

Но ни один из них не работает, что приводит к аналогичным ошибкам. Буду признателен, если кто-нибудь сможет направить меня в этом квесте.

Версия программного обеспечения

ОС: Debian (тестирование), Bison: 3.0.4, Flex: 2.5.39, GCC: 5.2.1, Make: 4.0.


person Fabricio    schedule 12.09.2015    source источник


Ответы (2)


Я нашел решение, немного повозившись. Итак, проблемы возникают из-за круговой зависимости между flex и bison.

Синтаксический анализатор сгенерировал гибкую процедуру вызова следующим образом:

yychar = yylex (&yylval, scanner);

Итак, во входные данные bison мы должны включить файл заголовка сканера lex.yy.h, который определяется как:

int yylex (YYSTYPE * yylval_param ,yyscan_t yyscanner);

Но YYSTYPE определяется внутри заголовка парсера parser.tab.h, в моем случае я сказал bison, что мой тип будет double:

typedef double YYSTYPE;

Теперь решение. Внутри scanner.l вы должны включить заголовки парсера, чтобы flex мог возвращать правильные токены (ничего не изменилось).

Но внутри parser.y вы должны включить оба файла заголовков, если вы включите только lex.yy.h, он будет жаловаться:

lex.yy.h:282:1: error: unknown type name ‘YYSTYPE‘

потому что YYSTYPE определен внутри parser.tab.h. И, наконец, по какой-то причине парсер bison не знает, что yyscan_t даже включая заголовок лексера:

error: unknown type name ‘yyscan_t’

Одним из способов решения этой проблемы является определение его недействительным:

%lex-param {void *scanner}
%parse-param {void *scanner}

см. yyscan_t определение: flex yyscan_t

Итак, вот окончательный результат:

scanner.l

%{
#include <stdio.h>
#include "parser.tab.h"
%}

%option 8bit reentrant bison-bridge
%option warn noyywrap nodefault
%option header-file="lex.yy.h"

//rest of the scanner

parser.y

%{
#include <stdio.h>
#include "parser.tab.h"
#include "lex.yy.h"

void yyerror(yyscan_t scanner, char const *msg);
%}

%define api.value.type {double}
%define parse.error verbose
%define api.pure 
%lex-param {void *scanner}
%parse-param {void *scanner}

//rest of the input

main.c

#include <stdio.h>

#include "parser.tab.h"
#include "lex.yy.h"

int main(void) {

  yyscan_t scanner;

  yylex_init(&scanner);
  yyset_in(stdin, scanner);

  yyparse(scanner);

  yylex_destroy(scanner);

  return 0;
}
person Fabricio    schedule 12.09.2015

Принятый ответ Фабрицио Санчеса помог мне решить две проблемы:

  1. error: unknown type name ‘yyscan_t’ действительно был решен путем перехода на void *.

  2. Конфликты, связанные с циклическими зависимостями, требуют очень строгого порядка импорта:

Ваш код, в котором вызывается yyparse Flex / Bison:

#import "parser.h"
#import "lexer.h"

Flex (Lexer.lm):

%{
#import "parser.h"
%}

Бизон (Parser.ym):

%{
#import "parser.h"
#import "lexer.h"
%}

Я написал сообщение в блоге о процессе создания реентерабельного парсера с использованием Flex и Bison в Mac OS с примером его интеграции в проект Xcode: Реентерабельный синтаксический анализатор с использованием Flex и Bison.

person Stanislav Pankevich    schedule 29.03.2016
comment
Вопрос: Ваша установка работает из вашего связанного блога. Не могли бы вы объяснить, почему я не могу включать такие файлы, как #include ‹iostream›? - person Dylan_Larkin; 31.10.2016
comment
Без спешки. Просто читаю ваш блог и т. Д. Я хочу создать компилятор в Xcode. Или, другими словами, я хочу разработать что-то с использованием Flex / Bison в Xcode, которое также будет использовать C ++ STL. - person Dylan_Larkin; 31.10.2016
comment
Переименуйте .lm в .lmm и .ym в .ymm и соответственно обновите Makefile. Это должно сообщить Xcode о вашем намерении использовать Clang ++. - person Stanislav Pankevich; 31.10.2016
comment
Давайте продолжим это обсуждение в чате. - person Dylan_Larkin; 31.10.2016