Как что-то сделать, когда во входном файле достигнут EOF?

Я пытаюсь отслеживать сигнатуры всех функций, чтобы проверить - когда весь входной файл был просканирован - все ли они были определены, и в противном случае сообщить об ошибке. Для этого я хочу, чтобы сканер возвращал синтаксическому анализатору токен END_OF_FILE, чтобы вызвать мою процедуру проверки, но я получаю ошибку «токен не определен», хотя я определил его как токен в анализаторе.

Любое предложение?


person M-elman    schedule 10.03.2017    source источник


Ответы (1)


Отправка собственного токена конца файла очень редко бывает хорошей идеей, и если вы решили это сделать, вам нужно проявить большую осторожность.

К счастью, в этом почти никогда не бывает необходимости.

Если вы хотите выполнить код непосредственно перед концом синтаксического анализа, вы можете сделать это в начале производства:

start: program { /* Code to execute at the end of the parse */ }
     ;

Если вы используете bison, есть предостережение: код будет выполняться после завершения синтаксического анализа, независимо от того, завершился он успешно или нет. В частности, возможно, что во входном потоке все еще есть неиспользованный токен. [Примечание 1]

Во многих случаях это не проблема. Ошибка будет обнаружена немедленно (если действие не вызывает YYACCEPT), и выполнение дополнительных проверок, даже если синтаксический анализ завершится неудачно, обычно не является проблемой. В некоторых приложениях вам может даже потребоваться такое поведение; например, если вы анализируете выражение, встроенное в более крупный текст, и не хотите настаивать на том, чтобы анализируемый контекст расширялся до конца текста.

Но если вам действительно нужно знать, завершен ли синтаксический анализ, достаточно проверить, что значение yychar равно YYEOF (см. руководство по bison для получения дополнительной информации.) Таким образом, вы можете заменить предыдущее на:

start: program { if (yychar == YYEOF) {
                    /* Code to execute at the end of the parse */
                 }
                 else {
                    /* There is definitely an error. Probably do nothing. */
                 }
               }

Если вы собираетесь отправить свой собственный токен конца файла, вам необходимо убедиться, что вы по-прежнему поддерживаете контракт между синтаксическим анализатором и лексическим сканером, а именно:

  • сканер указывает конец ввода, возвращая 0 в качестве значения токена; а также
  • парсер не запрашивает другой токен после получения 0.

Хотя лексический сканер иногда может обрабатывать нарушения второго условия, это неопределенное поведение, и при определенных обстоятельствах сгенерированный сканер будет отказываться или выполнять другие нежелательные действия. А поскольку синтаксический анализатор не поймет, что ваш пользовательский токен конца файла указывает на конец ввода, он продолжит запрашивать дополнительные токены после его получения.

Это означает, что вам действительно нужно отправить и свой токен, и правильный токен END, что означает выполнение примерно следующего:

%% 
   /* This code is inserted at the top of yylex */
   static int eof_reached = 0; /* Note: not reentrant */
   if (eof_reached) return END;
 /* ... */
<<EOF>> { eof_reached = 1; return MY_END_OF_FILE; }

Это будет работать, но, как написано, сканер можно использовать только один раз, поскольку нет возможности сбросить логическое значение eof_reached. Вы можете сделать его глобальным или создать повторно входящий сканер и добавить его в раздел дополнительных данных объекта контекста сканера. Это полезные методы для поддержания состояния сканера между вызовами yylex, но в этом конкретном случае я не думаю, что с их помощью можно что-то получить, потому что, как упоминалось выше, на самом деле почти никогда не должно быть необходимости отправлять настраиваемый конец ввода. токен.


Что касается конкретной проблемы, с которой вы столкнулись:

Без более подробной информации невозможно ответить на:

Я получаю неопределенную ошибку токена,

От чего? Бизон? Flex? компилятор? Что именно говорится в сообщении? К какой строке вашего кода идет речь? (И вы точно назвали конец файла токеном END_OF_FILE?)

Примечания

  1. Из-за того, как токен конца ввода обрабатывается в исходном yacc, этого не произойдет с исходным yacc или byacc и их производными. Генераторы синтаксического анализатора с той же обработкой конца ввода, что и исходный yacc, обычно не будут выполнять действие, связанное с началом производства, если уже не встретился токен конца ввода.
person rici    schedule 10.03.2017