Почему моя программа в flex и bison не работает? Калькулятор функций sin и cos

#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 внезапно закрывается.

Здесь происходит несколько вещей:

  1. «2 3» не является допустимым вводом в вашу программу. Начальный символ вашей грамматики Calculadora — , и единственный продукт для этого состоит из одного TKN_ID токена. Первый токен, который ваш лексер вернет для данного ввода, будет TKN_NUM соответствовать 2 . В результате появится ошибка синтаксического анализа, yyparse() которая вернется, и программа вскоре завершится.

  2. При запуске вашей программы Windows закрывает окно, в котором она запускается, как только программа завершается. Вы должны быть в состоянии избежать этого, открыв командное окно и запустив свою программу через командную строку.

Также обратите внимание, что:

  1. Даже если ваш начальный символ был Expresion , «2 3» все равно не будет допустимым вводом. a TKN_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 .