Если анализ не выполнен, yyparse
возвращает ненулевое значение. Это одинаково для парентерабельных и не реентерабельных парсеров. Поэтому вы должны всегда получить возвращаемое значение из yyparse
:
status = yy_parse(scanner);
Если вы выполняете восстановление после ошибок (то есть у вас есть одно или несколько error
произведений), тогда вам придется вести подсчет ошибок самостоятельно. Возвращение ошибки yyparse
происходит только в случае сбоя восстановления после ошибки (или при наличии ошибки выделения памяти).
yyerror
вызывается при обнаружении ошибки (до попытки восстановления ошибки). В примерах игрушек он обычно просто выводит аргумент stderr
. (В конфигурации по умолчанию аргумент «синтаксическая ошибка», но вы можете получить лучшие сообщения об ошибках с помощью %define parse.error verbose
.) В рабочем анализаторе с восстановлением ошибок yyerror
может ничего не делать, оставляя процедуру восстановления после ошибки для попытаться создать более значимое сообщение об ошибке. Или он может хранить сообщение об ошибке бизона где-нибудь для дальнейшего использования.
Нет большой проблемы с печатью на stderr
, поскольку вызов yyerror
выполняется синхронно в том же потоке, что и синтаксический анализатор (bison полностью не знает о потоках). Но некоторые приложения предпочитают помещать сообщения в некую структуру данных для последующей обработки. (Вы определенно захотите учесть это в многопоточном приложении.) Для облегчения этого, как вы можете видеть в моем коде, yyerror
вызывается с теми же дополнительными параметрами, что и yyparse
.
В примере кода эта функция не использовалась (поэтому аргумент scanner_t
называется unused
). Но поскольку flex позволяет расширять объект контекста сканера дополнительными данными , это было бы разумным местом для размещения сборщика ошибок, поэтому будет полезно, если yyerror
имеет к нему доступ. (Конечно, он также доступен в любом действии парсера, поскольку это параметр yyparse
.)
Возможно, сбивает с толку то, что я поместил определение yyerror
в файл сканера, а не в файл парсера. Поскольку это внешняя функция, не имеет значения, в какую единицу перевода она входит. Размещение ее в синтаксическом анализаторе, вероятно, то, что вы увидите в примерах, но также имеет смысл определить ее в единице перевода, которая вызывает синтаксический анализатор.
Положить его в сканер в лучшем случае эксцентрично c. Я сделал это исключительно для того, чтобы избежать проблем с циклической зависимостью, которые я подробно опишу в связанном ответе, поэтому я не буду повторять это здесь.
Круговая зависимость не будет проблемой ни в одном модуль перевода, отличный от кода, сгенерированного Bison. Если вы хотите использовать метод дополнительных данных, упомянутый выше, вам нужно попросить flex сгенерировать файл заголовка и убедиться, что вы #include этот заголовок в файле, где определено yyerror
.