Если грамматика Bison компилируется правильно, но при запуске делает не то,
чего вы хотите, помочь вам выяснить, почему это происходит, может средство
трассировки анализатора yydebug
.
Чтобы включить компиляцию возможностей трассировки, вы должны определить
макрос YYDEBUG
как ненулевое значение при компиляции анализатора. Вы
можете использовать параметр компилятора `-DYYDEBUG=1' или поместить
`#define YYDEBUG 1' в секцию объявлений C файла грамматики
(см. раздел 4.1.1 Секция объявлений C). Вместо этого можно использовать
параметр `-t' при запуске Bison (см. раздел 10. Вызов Bison) или
объявление %debug
(см. раздел 4.7.8 Обзор объявлений Bison).
Мы полагаем, что вы всегда будете определять YYDEBUG
, так что отладка
всегда будет возможна.
Средство трассировки выводит собщения, используя макровызовы вида
YYFPRINTF (stderr, формат, аргументы
, где формат и
аргументы -- обычные формат и аргументы функции printf
.
Если вы определяете YYDEBUG
как ненулевое значение, но не определяете
YYFPRINTF
, автоматически включается <stdio.h>
и YYFPRINTF
определяется как fprintf
.
После того, как вы скомпилировали программу с использованием средств
трассировки, чтобы потребовать выполнения трассировки, нужно поместить
ненулевое значение в переменную yydebug
. Вы можете сделать это,
заставив это делать код на C (возможно, в функции main
), или изменить
это значение отладчиком C.
Каждый шаг, предпринимаемый анализатором, когда yydebug
не равно нулю,
даёт одну или две строки информации о трассировке, выдаваемой на stderr
.
Сообщения трассировки говорят о следующем:
yylex
: лексема какого вида прочитана.
Для осмысления этой информации полезно обратиться к файлу листинга, выдаваемому параметром Bison `-v' (см. раздел 10. Вызов Bison). Этот файл показывает смысл каждого состояния в терминах позиций в различных правилах, а также, что будет происходить в каждом состоянии при каждой возможной входной лексеме. Читая последовательные сообщения трассировки, вы можете видеть, что анализатор функционирует в соответствии с его спецификацией в файле листинга. В конце концов вы дойдёте до места, где происходит что-либо нежелательное, и увидите, какие части грамматики несут за это ответственность.
Файл анализатора -- это программа на C, и вы можете использовать отладчики C, но объяснить, что она делает непросто. Функция анализатора -- это интерпретатор машины с конечным числом состояний, и за пределами действий она выполняет один и тот же код снова и снова. В каком месте грамматики она работает, показывают только значения переменных.
Отладочная информация обычно содержит тип каждой прочитанной лексемы, но не
её семантическое значение. Вы можете также определить макрос YYPRINT
,
чтобы предоставить способ вывода значения. Если вы определяете YYPRINT
,
он должен принимать три аргумента. Анализатор будет передавать ему стандартный
поток ввода/вывода, числовой код типа лексемы и значение лексемы (из
yylval
).
Приведём пример YYPRINT
, подходящего для многофункционального
калькулятора (см. раздел 3.5.1 Объявления mfcalc
):
#define YYPRINT(file, type, value) yyprint (file, type, value)
static void
yyprint (FILE *file, int type, YYSTYPE value)
{
if (type == VAR)
fprintf (file, " %s", value.tptr->name);
else if (type == NUM)
fprintf (file, " %d", value.val);
}