Код, сгенерированный flex, не будет выводиться на консоль

#flex-lexer #lex

Вопрос:

Я экспериментирую с flex, чтобы попытаться лучше понять, как это работает. У меня есть это в файле lex (.l) :

 %option noyywrap

%%
"a"   printf("Found an "a"");

%%

int main()
{
   printf("This is working");
   return 0;
}
 

Игнорирование единственного правила на данный момент (если только это каким-то образом не является причиной) Я хочу знать, почему оператор printf в функции main() ничего не делает. Покопавшись в сгенерированном файле lex.yy.c, я подозреваю, что строка

 yyout = stdout;
 

возможно, это причина, хотя я не могу сказать, почему (и я ничего не смог найти, когда искал, почему flex делает это)

Я надеюсь понять не только то, что это означает с точки зрения кода на C, но и почему flex делает это. Похоже, что он либо подавляет, либо перенаправляет вывод (возможно, в код yacc?). Я был бы признателен за любые объяснения или ссылки на некоторую информацию.

(Если только это не просто мой код C, который каким-то образом нарушен)

Комментарии:

1. Если вы не позвоните yylex , лексер не повлияет на работу вашей программы 🙂

2. @rici проверьте мой комментарий к приведенному ниже ответу (такая глупая ошибка) оператор печати в основной функции отлично работает без вызова yylex. Не могли бы вы уточнить, что не сработает, если я этого не сделаю?

3. Основная проблема, с которой сталкиваются люди, заключается в том, что строка, напечатанная без новой строки, фактически выводится только позже, когда вы выводите новую строку (или закрываете stdout). Это может ввести вас в заблуждение, заставив думать, что ошибка (например, ошибка segfault) произошла намного раньше, чем это было на самом деле, потому что резкое завершение останавливает программу до сброса stdout, и вы никогда не увидите результат. Таким образом, вывод отладки и ведение журнала всегда должны завершаться новой строкой и/или направляться в небуферизованный поток вывода.

4. yylex действительно не имеет к этому никакого отношения. Если ты не позвонишь, значит, этого не было.

Ответ №1:

Если вы используете puts вместо printf этого, то для вас автоматически будет добавлена новая строка. Нет смысла использовать printf для печати постоянную строку, которая не включает форматированные преобразования.

Вы, конечно, могли бы сделать это сами, изменив его на

 printf("This is workingn")
 

или:

 printf("%sn", "This is working.");
 

Или даже лучше:

 fprintf(stderr, "%sn", "This is working.");
 

(См. ниже.)

Если вы не выведете новую строку, ваш вывод, вероятно, просто останется в буфере stdio (хотя он должен быть сброшен, когда stdout закрыт). Кроме того, некоторые IDE ведут себя плохо, когда последний бит вывода не заканчивается новой строкой. (Проглатывание символов-распространенный симптом.) В целом, лучше всего следовать следующим рекомендациям.

В общем:

  • Вы всегда должны заканчивать напечатанные строки новыми строками.
  • Вы должны знать о последствиях stdout буферизации строк, которая заключается в том, что в обычных случаях не завершение вывода stdout означает, что он не будет представлен сразу.
  • И вы должны привыкнуть использовать stderr вместо stdout того, чтобы регистрировать сообщения, даже если они, строго говоря, не являются ошибками, оставляя stdout для обработанного вывода вашей программы (в случае, если вы хотите передать вывод в другую утилиту). В отличие stdout от , stderr обычно (по умолчанию) не буферизован, поэтому вывод отображается немедленно. (Но вы все равно должны поставить новую строку в конце, а не оставлять курсор болтающимся в середине строки.)

    fputs кстати, автоматически новая строка не пишется. Но это все равно лучше, чем fprintf в случае буквальных строк.

Комментарии:

1. О нет. Я сам себе не верю. Я назвал выходной файл «тест». когда я попытался запустить его, я на самом деле выполнял команду unix «тест». Невероятно. Я переименовал его и попытался запустить снова, и все сработало.

2. @Хайден. Ах, да, это была еще одна возможность. Но мой ответ остается в силе. 🙂 Это хорошее время для выработки хороших привычек.

3. Надеюсь, это нормально, чтобы спросить (так как это не связано с исходным вопросом), но я также пытался проверить правило, которое я написал, но оно ничего не напечатает, когда я передам текстовый файл, содержащий некоторые «а», в программу. Разве не так работают программы lex? И да, я добавил новую строку в конце 🙂

4. @hayden: Да, сканер должен распечатать сообщение. Убедитесь, что вы действительно передали ему текст, который, как вам кажется, вы сделали, и убедитесь, что ваше сообщение для входа в систему заканчивается новой строкой: -) Кроме того, правило по умолчанию также приводит к тому, что любые нераспознанные символы будут передаваться в yyout (или stdout, если yyout равен НУЛЮ). О, и вам действительно нужно позвонить в yylex (), чтобы сканер что-то сделал.

5. итак, программа (тестовая программа), по-видимому, работает в «интерактивном» режиме, она позволяет мне вводить текст и выводить строку при обнаружении буквы «а». Но я попытался передать текстовый файл (input_test.txt), содержащий «aaa» и новую строку. Выполнение команды «./тестовая программа input_test.txt» просто войдите в этот интерактивный режим. Еще одна глупая ошибка?