Наиболее важной вещью в сгенерированном бизоном заголовке являются значения enum, которые используются для идентификации типов токенов (которые являются значениями, возвращаемыми парсеру лексическими действиями).
Заголовок также объявляет семантический тип YYSTYPE
и переменную yylval
(которая имеет этот тип), используемую для передачи семантического значения каждого токена анализатору.(По крайней мере, для токенов, которые имеют семантические значения.) Аналогично, если анализатор использует информацию о местоположении, заголовок определяет тип местоположения YYLTYPE
и переменную yylloc
этого типа.
Поскольку зависимости заголовкане может быть циклическим, синтаксический анализатор не имеет никакой зависимости заголовка от сканера.Именно по этой причине ваш входной файл бизонов должен включать объявление yylex
.
Это хорошо для классического интерфейса между анализатором и сканером, который использует глобальные переменные для связи.И это также более или менее работает с реентерабельным («чистым») синтаксическим анализатором, в котором семантическое значение (и местоположение, если используется) передаются через аргументы yylex
, хотя тот факт, что объявление yylex
не является автоматическим, больше раздражает.
Там, где он начинает ломаться, это когда сканер также возвращается.В этом случае анализатор должен вызвать сканер с непрозрачным контекстным объектом сканера типа yyscan_t
.yyscan_t
«принадлежит» сканеру, поэтому его можно определить только в заголовке для сканера.Но, как отмечалось выше, это приведет к круговой цепочке зависимостей.Это обнаруживает слабость в традиционной модели: синтаксический анализатор является клиентом сканера, поэтому тот факт, что сканер зависит от синтаксического анализатора для определения основных структур данных, является инверсией зависимостей.
Это очень реальная проблема, потому чтооткрытый интерфейс для сканера с повторным входом включает функции, прототипы которых требуют специфические для синтаксического анализатора типы данных (YYSTYPE
и YYLTYPE
), в то время как прототипу синтаксического анализатора почти наверняка потребуется принять объект контекста сканера в качестве аргумента, поэтому он не может бытьобъявляется без специфического для сканера типа данных yyscan_t
.
Обычным решением этой проблемы является нарушение инкапсуляции, отметив, что yyscan_t
- это просто void*
, поэтому его можно объявить таковым в анализаторетем самым избегая необходимости синтаксического анализатора для #include
заголовка сканера (если он не требует доступа к каким-либо другим открытым методам, объявленным в этом заголовке).
Менее уродливое решение, на мой взгляд,чтобы избежать этой конкретной конфигурации в целом.Bison позволяет запрашивать реентерабельный «синтаксический анализатор», который можно использовать вместе с реентерабельным сканером без каких-либо перечисленных выше сложностей.
В модели push-синтаксического анализатора сканер является функцией верхнего уровня, вызываемой для анализафайл, и сканер вызывает синтаксический анализатор каждый раз, когда он идентифицирует токен.Зависимости заголовка больше не являются круговыми, потому что синтаксическому анализатору не нужно ничего знать об объекте контекста сканера или, в этом отношении, о прототипе yylex()
.Сканер теперь является клиентом синтаксического анализатора и, таким образом, имеет естественную зависимость заголовка от синтаксического анализатора, поэтому тот факт, что синтаксический анализатор определяет перечисления маркеров, а также семантические типы и типы данных местоположения, больше не является исключительным.
А также упрощениеВ зависимости от заголовка между двумя компонентами, синтаксический анализатор часто упрощает поток управления внутри самого сканера.Во многих случаях использование одного шаблона сканера приведет к идентификации нескольких токенов.В традиционной модели сканер должен хранить очередь токенов, освобождая их по одному за раз при вызове анализатором.Но в модели «push» действие сканера может просто вызывать анализатор несколько раз, по одному разу для каждого идентифицированного токена.Эта модель была популяризирована генератором парсеров Lemon (часть sqlite3) и впоследствии реализована другими генераторами парсеров, включая bison.