Из Книги Дракона, 2-е издание, раздел 3.5.3 «Разрешение конфликтов в Lex»:
We have alluded to the two rules that Lex uses to decide on the proper lexeme
to select, when several prefixes of the input match one or more patterns:
1. Always prefer a longer prefix to a shorter prefix.
2. If the longest possible prefix matches two or more patterns, prefer the
pattern listed first in the Lex program.
Приведенное выше правило также применимо к Flex.Вот что говорится в руководстве Flex (Глава 7: Как сопоставляются входные данные.)
When the generated scanner is run, it analyzes its input looking for strings
which match any of its patterns. If it finds more than one match, it takes the
one matching the most text (for trailing context rules, this includes the length
of the trailing part, even though it will then be returned to the input). If it
finds two or more matches of the same length, the rule listed first in the flex
input file is chosen.
Если я правильно понял, ваш лексер рассматривает такие ключевые слова, как Endif
, как идентификатор,поэтому он будет рассматриваться как часть выражения впоследствии.Если это ваша проблема, просто поместите правила ключевых слов поверх вашей спецификации , например, такие: (предположим, что каждое слово в верхнем регистре является предопределенным перечислением, соответствующим токену)
"If" { return IF; }
"Then" { return THEN; }
"Endif" { return ENDIF; }
"While" { return WHILE; }
"Do" { return DO; }
"EndWhile" { return ENDWHILE; }
\"(\\.|[^\\"])*\" { return STRING; }
[a-zA-Z_][a-zA-Z0-9_]* { return IDENTIFIER; }
Тогда ключевые слова всегда будут совпадать перед идентификатором в соответствии с правилом № 2.
РЕДАКТИРОВАТЬ:
Спасибо за ваш комментарийКол.Я забыл добавить правило для строки. Но я не думаю, что мое решение неверно. Например, если будет применяться идентификатор с именем If_this_is_an_identifier
, правило 1 , таким образом, правило идентификатора вступит в силу (так как оно соответствуетсамая длинная строка).Я написал простой тестовый пример и не нашел проблем в своем решении.Вот мой файл lex.l:
%{
#include <iostream>
using namespace std;
%}
ID [a-zA-Z_][a-zA-Z0-9_]*
%option noyywrap
%%
"If" { cout << "IF: " << yytext << endl; }
"Then" { cout << "THEN: " << yytext << endl; }
"Endif" { cout << "ENDIF: " << yytext << endl; }
"While" { cout << "WHILE: " << yytext << endl; }
"Do" { cout << "DO: " << yytext << endl; }
"EndWhile" { cout << "ENDWHILE: " << yytext << endl; }
\"(\\.|[^\\"])*\" { cout << "STRING: " << yytext << endl; }
{ID} { cout << "IDENTIFIER: " << yytext << endl; }
. { cout << "Ignore token: " << yytext << endl; }
%%
int main(int argc, char* argv[]) {
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yylex();
}
Я проверил свое решение с помощью следующего контрольного примера:
If If_this_is_an_identifier > 0 Then read(b); Endif
c := "If I were...";
While While_this_is_also_an_identifier > 5 Do d := d + 1 Endwhile
, и он дает мне следующий вывод (другой вывод, не относящийся купомянутая вами проблема игнорируется.)
IF: If
IDENTIFIER: If_this_is_an_identifier
......
STRING: "If I were..."
......
WHILE: While
IDENTIFIER: While_this_is_also_an_identifier
Программа lex.l модифицирована на основе примера из flex manual : (который использует тот же метод для сопоставления ключевого слова с идентификаторами)
Также взгляните на грамматику ANSI C, спецификацию Lex .
Я также использовал этот подход в своем личном проекте, и поэтомуПока я не нашел никаких проблем.