Реализация функции, которая разбирает строку, используя bison и flex - PullRequest
1 голос
/ 10 октября 2019

Я реализовал парсер и сканер, используя bison и flex. Сначала он читал входные данные из stdin, а позже я изменил чтение строки. Есть несколько сообщений на stackoverflow по этой теме. В частности, помогло руководство по flex , описывающее использование нескольких буферов и использование строки в памяти, а не файла в качестве входных данных.

Итак, я заставил парсер / лексер работать для одной строки, как в:

%{
//Bunch of includes, typedefs, etc..
extern char * yytext;
void yyerror(char *);
int yylex();
typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern int yyparse();
extern int yylex_destroy(void);
extern YY_BUFFER_STATE yy_scan_string(char * str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
...

%%
int main(int argc, char **argv) {

  char *string = "abcd\n\0";
  YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
  yyparse();

}

Это была простая часть. Правила грамматики / лекса немного длинны, чтобы воспроизвести их здесь. Я хочу реализовать функцию, которая будет вызываться неоднократно со строковым параметром. Так как правила грамматики / lex могут заботиться о выводе, я могу справиться с этим. Проблема состоит в том, чтобы иметь механизм для реализации классической функции, которой передается строка для анализа и анализа. Итак, я попытался это проверить ...

int main(int argc, char **argv) {
  int i=10;
  char *string;
  string = malloc(16);
  while (1) {

     sprintf(string, "someString to be parsed...%d\n\0", i++);
     YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));   
     yyparse();
     yylex_destroy();
     printf("%d\n", i); 

   }
}

Сбой после примерно 10000 с этой ошибкой:

 fatal flex scanner internal error--end of buffer missed

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

Я пробовал разные подходы, но безуспешно. Есть простой способ справиться с этим?

1 Ответ

1 голос
/ 11 октября 2019
string = malloc(16);

Довольно скупо, учитывая, что вы собираетесь написать:

sprintf(string, "someString to be parsed...%d\n\0", ++i);

, что составляет не менее 28 байтов, если i - одна цифра, и достигает 32 байтов, когда i достигает10000. (Вероятно, это не совпадение.)

Сделайте себе одолжение и используйте asprintf, если можете. Если он недоступен, достаточно просто написать его, используя snprintf, или вы можете просто использовать snprintf с гораздо большим буфером. (В этом случае динамическое выделение не требуется.)

Обратите внимание, что \0 в конце строки формата абсолютно бессмысленно. Я предполагаю, что вы намеревались гарантировать, что есть два NUL-терминатора, как того требует yy_scan_buffer, но \0 не будет скопирован в вывод sprintf, так как это приведет к завершению строки формата. (Строки C заканчиваются символом NUL, запомните.)

Также обратите внимание, что sizeof(string) в yy_scan_buffer(string, sizeof(string)); - это sizeof(char*), поскольку string - это char*. Это, скорее всего, 8 дней, но это может быть 4, если вы используете 32-битную среду. В любом случае, он не имеет отношения к количеству символов, которые написал sprintf. Вы можете использовать strlen для подсчета длины string, но было бы более эффективно использовать тот факт, что sprintf возвращает количество записанных им байтов.

И, говоря о возвращаемых значениях,вы не проверяете возвращаемое значение из yy_scan_buffer, которое, вероятно, пыталось сообщить вам о вашей ошибке:

Если вам не удалось настроить базу таким образом (т.е. забыть последние дваYY_END_OF_BUFFER_CHAR), затем yy_scan_buffer() возвращает указатель NULL вместо создания нового входного буфера.

...