Проблема с printf в Bison Rule

Я пробовал что-то подобное в моем файле Bison...

ReturnS: RETURN expression {printf(";")}

... но точка с запятой печатается ПОСЛЕ следующей лексемы после этого правила, а не сразу после выражения. Это правило было введено, так как мы должны преобразовать входной файл в с-образную форму, а исходный язык не требует точки с запятой после выражения в операторе возврата, но C требует, поэтому я подумал, что добавлю его. вручную на вывод с помощью printf. Похоже, это не работает, так как добавляется точка с запятой, но по какой-то причине она добавляется после анализа следующего токена (вне правила ReturnS), а не сразу, когда правило выражения возвращается к ReturnS.

Это правило также приводит к тому же результату:

loop_for: FOR var_name COLONEQUALS expression TO {printf("%s<=", $<chartype>2);} expression STEP {printf("%s+=", $<chartype>2);} expression {printf(")\n");} Code ENDFOR

Помимо того, что первые два printf работают неправильно (я отправлю еще один вопрос по этому поводу), последний printf фактически вызывается ПОСЛЕ того, как первый токен/литерал правила «Code» был проанализирован, что приводит к чему-то вроде этого:

for (i=0; i<=5; i+=1
a)
=a+1;

вместо

for (i=0; i<=5; i+=1)
a=a+1;

Любые идеи, что я делаю неправильно?


person Lefteris Aslanoglou    schedule 21.08.2010    source источник


Ответы (2)


Вероятно, потому что грамматика должна смотреть вперед на один токен, чтобы принять решение о сокращении по показанному вами правилу.

Действие выполняется, когда правило сокращается, и очень типично, что грамматика должна прочитать еще одну лексему, прежде чем она узнает, что она может/должна сократить предыдущее правило.

Например, если выражение может состоять из неопределенной последовательности добавленных терминов, оно должно читаться после последнего термина, чтобы знать, что нет другого «+», чтобы продолжить выражение.


После знакомства с грамматикой Yacc/Bison и анализатором Lex/Flex некоторые проблемы стали очевидны, а с другими пришлось немного разобраться.

  • То, что лексический анализатор выполнял большую часть печати, означало, что грамматика не контролировала должным образом то, что и когда появляется. Анализатор делал слишком много.
  • Анализатор также выполнял недостаточно работы — заставить грамматику обрабатывать строки и числа по одному символу за раз можно, но это излишне тяжелая работа.
  • Обработка комментариев сложна, если их нужно сохранить. В обычном компиляторе C лексический анализатор отбрасывает комментарии; в этом случае комментарии должны были быть сохранены. Правило, обрабатывающее это, было перенесено из грамматики (где оно вызывало конфликты сдвига/уменьшения и сокращения/уменьшения из-за пустых строк, совпадающих с комментариями) в лексический анализатор. Это не всегда может быть оптимальным, но в этом контексте, похоже, работает нормально.
  • Лексическому анализатору нужно было убедиться, что он возвращает подходящее значение для yylval, когда это необходимо.
  • Грамматика должна распространять подходящие значения в $$, чтобы гарантировать, что правила содержат необходимую информацию. Ключевые слова по большей части не нуждались в значении; такие вещи, как имена переменных и числа.
  • Грамматика должна была сделать печать в соответствующих местах.

Возвращаемый прототип решения имел серьезную утечку памяти, потому что он широко использовал strdup() и вообще не использовал free(). Убедиться, что утечки устранены — возможно, с помощью массива символов, а не указателя символов для YYSTYPE — остается на усмотрение оператора.

person Jonathan Leffler    schedule 21.08.2010
comment
Я понимаю. Спасибо за ответ. Не знаю, как это исправить, но теперь, по крайней мере, я знаю, где искать. - person Lefteris Aslanoglou; 22.08.2010
comment
Я пытался, но не могу исправить это. Любые идеи о том, что нужно сделать, чтобы решить эту проблему? - person Lefteris Aslanoglou; 22.08.2010
comment
@Leftos: пришлите мне код по электронной почте - см. мой профиль. Я посмотрю, что я могу сделать из этого. - person Jonathan Leffler; 22.08.2010

Комментарии — не лучшее место для предоставления примеров кода, поэтому я собираюсь предоставить пример кода, который работает после того, как Джонатан (ответил выше) немного поработал над моим кодом. Все должное принадлежит ему, это не мое.

Джонатан предположил, что вместо того, чтобы FLEX печатал любые распознанные части и позволял BISON выполнять форматирование, FLEX ничего не печатал и возвращал только BISON, который затем должен сам обрабатывать всю печать.

Итак, вместо чего-то подобного...


ФЛЕКС

"FOR"   {printf("for ("); return FOR;}
"TO"    {printf("; "); return TO;}
"STEP"  {printf("; "); return STEP;}
"ENDFOR"    {printf("\n"); printf("}\n"); return ENDFOR;}
[a-zA-Z]+   {printf("%s",yytext); yylval.strV = yytext; return CHARACTERS;}
":="    {printf("="); lisnew=0; return COLONEQUALS;}

БИЗОН

loop_for:   FOR var_name {strcpy(myvar, $<strV>2);} COLONEQUALS expression TO {printf("%s<=", myvar);} expression STEP {printf("%s+=", myvar);} expression {printf(")\n");} Code ENDFOR

... он предложил это:


ФЛЕКС

[a-zA-Z][a-zA-Z0-9]*    { yylval = strdup(yytext); return VARNAME;}
[1-9][0-9]*|0           { yylval = strdup(yytext); return NUMBER; }

БИЗОН

loop_for:   FOR var_name COLONEQUALS NUMBER TO NUMBER STEP NUMBER
    { printf("for (%s = %s; %s <= %s; %s += %s)\n", $2, $4, $2, $6, $2, $8); }
var_name:   VARNAME
person Lefteris Aslanoglou    schedule 26.08.2010
comment
Джонатан, если вы хотите добавить приведенные выше примеры к своему ответу, я с радостью удалю свой ответ. - person Lefteris Aslanoglou; 26.08.2010
comment
Кроме того, если кому-то интересно узнать о $x в printf и о том, как они работают, см. также SO 3539498. правило" title="использование x для получения строки из правила"> stackoverflow.com/questions/3539498/ - person Lefteris Aslanoglou; 26.08.2010