Это действительно не очень хороший вариант использования для 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, и он только слегка оптимизирован по сравнению с тем, что возможно для повторного поиска той же цели.Лучше было бы реализовать или найти один из стандартных алгоритмов поиска: