Вывести строку совпадающего слова в flex - PullRequest
0 голосов
/ 23 сентября 2018

Я пытаюсь создать сканер с flex, который работает примерно так: grep.

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

Проблема, с которой я столкнулся, заключается в том, что я не могу понять, как лучше всего напечатать строку.Я могу напечатать все после искомого слова, но я не знаю, как правильно хранить содержимое всей строки.

Я пытался использовать yyseek(), но когда я компилировал,Я получаю сообщение о том, что yyseek является неопределенным символом.

Использование yymore() для хранения текста хорошо работает для всего, что находится после соответствующего слова в строке.

Вот код, которыйУ меня так далеко:

%option yylineno
%option noyywrap
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *search_str = NULL;
char *curr_line = NULL;
%}

%x found

letter [a-zA-Z]
word {letter}+
line (.*)\n

%%

<INITIAL,found>{word} {
    /* If a word matches the string that we are looking for, use the 'found'
     * condition, which will cause the line to be dumped at the end.
     */
    yymore();
    if (strcmp(search_str, yytext) == 0) {
        BEGIN(found);
    }
}

<found>{line} {
    yymore();
    ECHO;
    BEGIN(INITIAL);
}

. { }

\n {}

%%

int main(int argc, char *argv[])
{
    if (argc > 1) {
        unsigned int str_len = sizeof(argv[1]);
        search_str = malloc(str_len + 1);
        strcpy(search_str, argv[1]);
        yylex();
        free(search_str);
        return 0;
    }

    printf("usage: ./a.out [search word]\n");
    return 1;
}

1 Ответ

0 голосов
/ 24 сентября 2018

Это действительно не очень хороший вариант использования для flex.И мне не совсем ясно, что он будет делать то, что вы хотите, либо.(Поскольку я на самом деле не знаю, что вы хотите, поэтому я могу ошибаться. Но обратите внимание на следующее:

Target line             grep night       grep -w night        Your code
-------------------     ----------       -------------        ---------
a night to remember        Yes               Yes                 Yes
a knight to forget         Yes               No                  No
night23                    Yes               No                  Yes

В любом случае, ваш инстинкт использования yymore был верным. Вы просто должныНачните раньше, чтобы вся строка была сохранена в токене. Небольшое осложнение состоит в том, что когда вам нужно проверить слово, вы не можете проверить с начала yytext, оно содержит всю строку до этой точки.необходимо проверить последние символы strlen(search_str). Следующий код проверяет, что он выполняет эти вычисления только один раз, поскольку требует полного сканирования search_str. Также обратите внимание, что он не выходит за начало yytext.

По сути, следующий код делит текст на три вида токенов: слова, не слова и переводы строк: только символ новой строки не может вызвать yymore(), поэтому при срабатывании правила перехода на новую строку, yytext содержитвся строка. Как и в вашем коде, как только совпадение найдено в строке, остальная часть строки просто добавляется к совпадению.

(Примечание: я переписал это безмакросы, которые обычно чрезмерно используются.Я не вижу причин думать, что {letter} более читабелен, чем [[:alpha:]], и последний имеет преимущество в том, что он понятен любому, кто знает flex, без необходимости искать ваше конкретное определение.)

%x FOUND
%%
     /* Indented lines before the first rule are put at the top of yylex */
     int match_length = strlen(search_str);
[^[:alpha:]\n]+   { yymore(); }
[[:alpha:]]+      { yymore();
                    if (yyleng >= match_length
                        && 0 == strcmp(yytext + yyleng - match_length,
                                  search_str))
                      BEGIN(FOUND);
                  }
<INITIAL,FOUND>\n BEGIN(INITIAL); 
<FOUND>.*         printf("%s\n", yytext);

Странность в конце состоит в том, чтобы иметь дело с входами, которые не заканчиваются правильно символом новой строки.Последний шаблон напечатает строку с символом новой строки (даже если его нет), а символ новой строки (если он есть) перезапустит начальное условие.

Для небольшого увеличения скорости вымог помнить предыдущее значение yyleng каждый раз, когда вы вызываете yymore(), так что yyleng - prev_yyleng будет длиной «этой части» токена.(Гибкий сканер знает это значение, но не предоставляет никакого интерфейса, чтобы вы могли его выяснить, что немного раздражает. Но это не имеет большого значения.) Затем вместо проверки достаточно ли всей строки до этой точки, чтобысделав сравнение возможным, вы можете проверить, была ли последнее найденное слово точно правильной длины, что будет реальным реже, что потребует меньше вызовов на strcmp.

В целом, хотя это не такхорошая стратегия.Вы, вероятно, обнаружите, что strstr быстрее, чем flex, и он только слегка оптимизирован по сравнению с тем, что возможно для повторного поиска той же цели.Лучше было бы реализовать или найти один из стандартных алгоритмов поиска:

...