#c #bison #flex-lexer
#c #bison #flex-lexer
Вопрос:
У меня есть эта программа, но она не работает, кто может мне помочь? Когда я ввожу 2 3 и ввожу, файл .exe внезапно закрывается. Я понятия не имею, что не так, но мне нужно решить это в ближайшее время, надеюсь, вы сможете мне помочь. Вот lexico.l:
/* Ejemplo para una pequeña calculadora que permite trabajar
con las funciones trigonometricas como el seno y el coseno */
#include <stdio.h>
#include <stdlib.h>
#include "sintactico.tab.h"
int nlines=0;
%}
DIGITO [0-9]
ID [a-zA-Z][a-zA-Z0-9_]*
%%
{DIGITO} ("."{DIGITO} )? {//printf("Encontrado TKN_NUM: %fn",atof(yytext));
yylval.real=atof(yytext);
return(TKN_NUM);}
"=" {//printf("Encontrado TKN_ASIGN: %sn",yytext);
return(TKN_ASIGN);}
"(" {//printf("Encontrado TKN_PAA: %sn",yytext);
return(TKN_PAA);}
")" {//printf("Encontrado TKN_PAC: %sn",yytext);
return(TKN_PAC);}
"cos" {//printf("Encontrado TKN_COS: %sn",yytext);
return(TKN_COS);}
"sen" {//printf("Encontrado TKN_SEN: %sn",yytext);
return(TKN_SEN);}
{ID} {//printf("Encontrado TKN_ID: %sn",yytext);
return(TKN_ID);}
"n" {nlines ;}
.
%%
И файл sintactico.y:
%{
/* Ejemplo para una pequeña calculadora que permite trabajar
con funciones trigonometricas como el seno y el coseno */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
extern int yylex(void);
extern char *yytext;
extern int nlines;
extern FILE *yyin;
void yyerror(char *s);
%}
%union
{
float real;
}
%start Calculadora
%token <real> TKN_NUM
%token TKN_ASIGN
%token TKN_PAA
%token TKN_PAC
%token TKN_COS
%token TKN_SEN
%token <real> TKN_ID
%type Calculadora
%type <real> Expresion
%left TKN_MAS TKN_MENOS
%left TKN_MULT TKN_DIV
%%
Calculadora : TKN_ID { printf("El valor de %s es: ", yytext);}
Expresion : TKN_NUM {$$=$1;}|
TKN_PAA Expresion TKN_PAC {$$=$2;}|
TKN_COS TKN_PAA Expresion TKN_PAC {$$=cos($3);}|
TKN_SEN TKN_PAA Expresion TKN_PAC {$$=sin($3);};
%%
void yyerror(char *s)
{
printf("Error %s",s);
}
int main(int argc,char **argv)
{
if (argc>1)
yyin=fopen(argv[1],"rt");
else
yyin=stdin;
yyparse();
printf("FIN del Analisis. Entrada CORRECTAn");
printf("Numero lineas analizadas: %dn", nlines);
return 0;
}
Что с ним не так? Я новичок в этом Flex и Bison, и мне трудно понять ошибки.
Комментарии:
1. Он напечатал количество строк?
2. Нет, приложение просто закрывается.
3. @Megasaw: Я настоятельно рекомендую вам прочитать примеры в руководстве Bison, которые подробно объяснены, чтобы вы могли видеть, что происходит. (К сожалению, только на английском, но я думаю, что это не слишком сложно.) Примеры превращаются в полноценный калькулятор с функциями и переменными, но они начинаются просто, и стоит потратить время на выполнение последовательности. Это избавит вас от многих проблем в долгосрочной перспективе.
Ответ №1:
Похоже, вы хотите использовать имена переменных, тогда вам нужно прочитать строковое значение в лексере и использовать его в файле bison.
Ваш%union может выглядеть следующим образом:
%union
{
char* str;
float real;
}
Аналогично, ваш TNK_ID должен быть:
%token <str> TKN_ID
И ваш адаптированный lexico.l может выглядеть примерно так:
{DIGITO} ("."{DIGITO} )? { yylval.real=atof(yytext); return(TKN_NUM); }
= { return TKN_ASIGN; }
( { return TKN_PAA; }
) { return TKN_PAC; }
cos { return TKN_COS; }
sen { return TKN_SEN; }
{ID} { yylval.str = strdup(yytext); return TKN_ID; }
{ return TKN_MAS; }
- { return TKN_MENOS; }
n { nlines ; return 'n'; }
.
Обратите внимание также, что теперь есть определения для и -, а также n . Имя переменной хранится в yylval.str.
Calculadora скорее будет выглядеть так:
Calculadora: { $$ = 0; }
| Calculadora Expresion 'n' { printf("%fn", $2); }
| Calculadora 'n'
;
А для Expresion
обработки идентификаторов следует добавить присваивания, а также операции плюс и минус, например
Expresion: TKN_NUM { $$=$1; }
| TKN_ID { $$ = get_symbol($1)->value; }
| TKN_ID TKN_ASIGN Expresion { put_symbol($1, $3); $$ = $3; }
| Expresion TKN_MENOS Expresion { $$ = $1 - $3; }
| Expresion TKN_MAS Expresion { $$ = $1 $3; }
| TKN_PAA Expresion TKN_PAC { $$ = $2; }
| TKN_COS TKN_PAA Expresion TKN_PAC { $$ = cos($3); }
| TKN_SEN TKN_PAA Expresion TKN_PAC { $$ = sin($3); }
;
Поскольку кажется, что вы хотите присвоить значения именам переменных, вам нужна своего рода таблица символов. Вы могли бы предоставить реализацию void put_symbol(char *name, float value)
и struct symbol_entry *get_symbol(char *name)
. Запись символа может быть определена как:
struct symbol_entry {
char name[50];
float value;
};
Тест
Быстрый тест — за одной строкой ввода следует однострочный вывод калькулятора:
5 3
8.000000
a = 5 3
8.000000
a = 0.5
0.500000
a
0.500000
b = cos(a)
0.877583
c = b a
1.377583
c
1.377583
Это то, что вы ищете?
Ответ №2:
Когда я ввожу 2 3 и ввожу, файл .exe внезапно закрывается.
Здесь происходит несколько вещей:
-
«2 3» не является допустимым вводом в вашу программу. Начальный символ вашей грамматики
Calculadora
— , и единственный продукт для этого состоит из одногоTKN_ID
токена. Первый токен, который ваш лексер вернет для данного ввода, будетTKN_NUM
соответствовать2
. В результате появится ошибка синтаксического анализа,yyparse()
которая вернется, и программа вскоре завершится. -
При запуске вашей программы Windows закрывает окно, в котором она запускается, как только программа завершается. Вы должны быть в состоянии избежать этого, открыв командное окно и запустив свою программу через командную строку.
Также обратите внимание, что:
- Даже если ваш начальный символ был
Expresion
, «2 3» все равно не будет допустимым вводом. aTKN_NUM
все равно будет первым токеном.TKN_NUM
, но в грамматике нет правила, согласно которому оно может применяться к двум последовательнымTKN_NUM
токенам.
Комментарии:
1. Даже если я введу cos(2), программа внезапно завершится: ( и я не знаю, как это исправить, я новичок в этом, и эта программа сводит меня с ума.
2. @megasaw, «cos (2)» также не является допустимым вводом для вашей программы. Опять же, ваш начальный символ равен
Calculadora
, и единственная последовательность токенов, которая может ему соответствовать, равна единицеTKN_ID
.3. Итак, я должен изменить #start Calculadora на #Start Expresion ?
4. @megasaw, если вы измените начальный символ на
Expresion
then, я бы ожидал, что ввод «cos (2)» будет принят. Однако грамматика не предоставляет возможности для анализа дополнительных входных данных, поэтому я ожидаюyyparse()
вернуться, возвращая вас к моей точке зрения (2).5. Кроме того, ничто
Expresion
не выводит значение выражения. ЭтоCalculadora
есть, но телоCalculadora
не соответствуетExpresion
.