Сгенерированная lex (flex) программа не анализирует весь ввод

У меня есть относительно простой файл lex/flex, и я запускаю его с флагом отладки flex, чтобы убедиться, что он правильно токенизируется. К сожалению, я всегда сталкиваюсь с одной из двух проблем: либо программа, которую генерирует flex, останавливается, просто молча сдается после пары токенов, либо правило, которое я использую для распознавания символов и строк, не вызывается, а правило по умолчанию вместо этого вызывается.

Может ли кто-нибудь указать мне в правильном направлении? Я прикрепил свой гибкий файл и пример ввода/вывода.

Изменить: я обнаружил, что сгенерированный лексер останавливается после определенного правила: «cdr». Это более подробно, но и гораздо более запутанно. Я разместил сокращенный модифицированный файл lex.

/* lex file*/
%option noyywrap
%option nodefault

%{
       enum tokens{
                CDR,
                CHARACTER,
                SET
        };
%}

%%

"cdr"                                               { return CDR; }
"set"                                               { return SET; }

[ \t\r\n]                                           /*Nothing*/
[a-zA-Z0-9\\!@#$%^&*()\-_+=~`:;"'?<>,\.]      { return CHARACTER; }

%%

Пример ввода:

set c cdra + cdr b + () ;

Полный вывод после запуска ввода через сгенерированный парсер:

--(end of buffer or a NUL)
--accepting rule at line 16 ("set")
--accepting rule at line 18 (" ")
--accepting rule at line 19 ("c")
--accepting rule at line 18 (" ")
--accepting rule at line 15 ("cdr")

Есть предположения? Сгенерированная программа сдается после половины ввода! (для справки, я делаю ввод, перенаправляя содержимое файла в сгенерированную программу).


person Zxaos    schedule 14.02.2010    source источник


Ответы (2)


При создании автономного лексера (то есть не с токенами, определенными в bison/yacc), вы обычно пишете перечисление в начале файла, определяющего ваши токены. Однако основной цикл программы lex, включая основной цикл, сгенерированный по умолчанию, выглядит примерно так:

while( token = yylex() ){
    ...

Это нормально, пока ваш лексер не соответствует правилу, которое появляется первым в перечислении - в данном конкретном случае CDR. Поскольку перечисления по умолчанию начинаются с нуля, это приводит к завершению цикла while. Перенумерация вашего перечисления - решит проблему.

enum tokens{
            CDR = 1,
            CHARACTER,
            SET
    };

Краткая версия: при определении токенов вручную для лексера начинайте с 1, а не с 0.

person Zxaos    schedule 14.02.2010

Это правило

[-+]?([0-9*\.?[0-9]+|[0-9]+\.)([Ee][-+]?[0-9]+)? 
          |

кажется, отсутствует закрывающая скобка сразу после первых 0-9, я добавил | ниже, где я думаю, что это должно быть. Я даже не мог предположить, как флекс отреагирует на это.

Правило, которое я обычно использую для имен символов, это [a-zA-Z$_], это похоже на ваши строки без кавычек, за исключением того, что я обычно разрешаю числа внутри символов, если символ не начинается с цифры.

[a-zA-Z$_]([a-zA-Z$_]|[0-9])*

Символы - это просто короткий символ. Я не думаю, что для этого нужно иметь собственное правило, но если оно есть, вам нужно убедиться, что для правила строки требуется как минимум 2 символа.

[a-zA-Z$_]([a-zA-Z$_]|[0-9])+
person John Knoeller    schedule 14.02.2010
comment
Исправлены несоответствующие квадратные скобки, но не повезло. Однако мне удалось воспроизвести проблему с более коротким набором правил. - person Zxaos; 14.02.2010
comment
Чтобы ответить, как отреагирует Лекс, он просто не выполнит правило и остановится. Поскольку скобки никогда не совпадают, действительное правило никогда не указывается. (9 * будет просто воздействовать на 9 и не слишком сильно повредит программе) - person Stegosaurus; 23.05.2016