Простая калькуляторная программа на lex и yacc не выдает вывод
Я пытаюсь написать очень простую калькуляторную программу, использующую lex и yacc, но застреваю при выводе на печать. Файлы:
calc.l:
%{
#include "y.tab.h"
extern int yylval;
%}
%%
[0-9]+ {yylval = atoi(yytext); return NUMBER;}
[ \t] ;
\n return 0;
. return yytext[0];
%%
calc.y:
%{
#include <stdio.h>
void yyerror(char const *s) {
fprintf(stderr, "%s\n", s);
}
%}
%token NAME NUMBER
%%
statement: NAME '=' expression
| expression {printf(" =%d\n", $1);}
;
expression: expression '+' NUMBER {$$ = $1 + $3;}
| expression '-' NUMBER {$$ = $1 - $3;}
| NUMBER {$$ = $1;}
;
Команды, которые я использовал:
flex calc.l
bison calc.y -d
gcc lex.yy.c calc.tab.c -lfl
./a.out
После запуска последней команды, хотя программа принимает ввод с клавиатуры, но ничего не печатает, она просто завершается. Я не получил никакого предупреждения или ошибки при компиляции, но это не дает никакого вывода. Пожалуйста помоги.
1 ответ
У вас нет определения main
так что основная функция в -lfl
будет использоваться. Эта библиотека для гибких программ, и ее main
функция будет вызывать yylex
- лексический сканер - пока не вернется 0.
Вам нужно вызвать парсер. Кроме того, вам нужно вызывать его повторно, потому что ваш лексический сканер возвращает 0, указывая конец ввода, каждый раз, когда он читает символ новой строки.
Таким образом, вы можете использовать что-то вроде этого:
int main(void) {
do {
yyparse();
} while (!feof(stdin));
return 0;
}
Однако это выявит некоторые другие проблемы. Самое неприятное, что ваша грамматика не примет пустой ввод, поэтому пустая строка вызовет синтаксическую ошибку. Это обязательно произойдет в конце ввода, потому что EOF вызовет yylex
немедленно вернуть 0, что неотличимо от пустой строки.
Кроме того, любая ошибка, обнаруженная во время синтаксического анализа, приведет к немедленному прекращению синтаксического анализа, в результате чего оставшаяся часть входной строки будет непрочитанной.
В целом, сканеру лучше возвращать токен новой строки (или \n
) для символов новой строки.
Кроме main
функция, которая вам не нужна, единственное в -lfl
это определение по умолчанию yywrap
, Вы можете просто определить эту функцию самостоятельно (нужно только вернуть 1), или вы можете избежать необходимости в функции, добавив
%option noyywrap
в ваш гибкий файл. На самом деле, я обычно рекомендую
%option noyyrap noinput nounput
что позволит избежать предупреждений компилятора (которые вы не видели, потому что вы не предоставили -Wall
когда вы скомпилировали программу, что вы должны сделать.)
Еще одного предупреждения компилятора можно избежать, добавив объявление yylex
в ваш входной файл бизонов до определения yyerror
:
int yylex(void);
В заключение, yylval
объявлен в y.tab.h
так что нет необходимости extern int yylval;
в вашем гибком файле. В этом случае это не повредит, но если вы измените тип семантического значения, что вы, вероятно, в конечном итоге захотите сделать, эту строку также нужно будет изменить. Лучше просто устранить это.