Ваш гибкий файл содержит серию правил, каждое из которых состоит из шаблона и действия. Вопреки распространенному мнению, вам не нужно «объявлять» свои шаблоны перед их использованием.
Если вы хотите игнорировать пробелы в вашем лексере, вам нужно правило, которое ничего не делает.
Вы в вашем шаблоне ключей была ошибка, которую я исправил; ваш шаблон не принял бы ключи с более чем одной буквой. Кроме того, набирать exit
в вашем сканере - это очень плохой стиль. Позвольте синтаксическому анализатору обрабатывать ошибки.
%{
#include "y.tab.h"
%}
%option noyywrap
%%
/* Removed the COMMA rule. See text below. */
/* "," {return COMMA;} */
/* Compare this pattern with the one you used */
[[:alpha:]][[:alnum:]]* {return KEY;}
/* Recognise and ignore whitespace. */
[[:space:]]+ ; /* Do nothing */
/* Send unrecognised input to the parser. */
. {return *yytext;}
Вашему синтаксическому анализатору не требуется IGNORE
, что в любом случае было бессмысленно, потому что грамматика не производит его. Bison, вероятно, предупреждал вас об этом.
Вы можете упростить свой синтаксический анализатор другими способами:
yywrap
не требуется, так как ваш лексер имеет %option noyywrap
. - Терминал
COMMA
может быть записан как ','
, если вы просто удалите шаблон ","
из лексера (поскольку резервное правило . { return *yytext; }
будет работать правильно для любого односимвольного литерала).
Для тестирования вы, вероятно, захотите анализировать одну строку за раз вместо игнорирования синтаксических ошибок.
Я бы также рекомендовал не использовать флаг «устаревшего» * 1028 * при вызове bison; этот флаг следует использовать только для старых существующих файлов грамматики ya cc, поскольку он может мешать работе современных функций Bison. Без -y
bison запишет сгенерированный код C в <i>filename</i>.tab.c
, а сгенерированный заголовок - в <i>filename</i>.tab.h
. Если вам не нравятся эти имена, вы можете использовать флаг -o
, чтобы указать имя сгенерированного кода C (и заголовок будет иметь то же имя с расширением, измененным на .h
).
Это может дать что-то вроде этого:
(Обратите внимание, что я изменил KEY_SET
на key_set
, потому что обычный стиль в грамматиках таков, что ALL_CAPS - это токены, а нетерминальные - строчные. Я также изменил его с праворекурсивного на леворекурсивный, чтобы избежать проблемы, которую вы могли бы заметить, если бы ваше производственное действие напечатало значение токена KEY
, если ваш лексер дал ему значение.)
file parser.y
%{
#include<stdio.h>
void yyerror (char const *s);
int yylex(void);
/* Defined in the flex file */
void set_input(const char* input);
%}
%token KEY
%%
key_set : KEY { printf("keyset 1\n"); }
| key_set ',' KEY { printf("keyset 2\n"); };
%%
int main(int argc, char **argv)
{
char buffer[BUFSIZ];
while (1)
{
printf("****************\n");
char* input = fgets(buffer, sizeof buffer, stdin);
if (buffer == NULL) break;
set_input(input);
yyparse();
}
return 0;
}
void yyerror (char const *s) {
fprintf (stderr, "%s\n", s);
}
файл lexer.l
%{
#include "parser.tab.h"
%}
%option noinput nounput nodefault yylineno
%option noyywrap
%%
[[:alpha:]][[:alnum:]]* {return KEY;}
[[:space:]]+ ; /* Do nothing */
. {return *yytext;}
%%
static YY_BUFFER_STATE flex_buffer;
void set_input(const char* input) {
yy_delete_buffer(flex_buffer);
flex_buffer = yy_scan_string(input);
}
Процедура сборки:
flex lexer.l
bison -d parser.y
gcc lex.yy.c parser.tab.c -o parser.exe
Ваша грамматика не допускает пустой ввод, но это нормально. Однако в целях тестирования вы можете добавить тест в l oop, который считывает строки ввода, чтобы вызывать синтаксический анализатор только в том случае, если строка не пуста.