Search code examples
cbisonflex-lexer

Why my program in flex and bison isn't working? Calculator of sin and cos functions


I have this program but it doesn't work, who can help me? When I entry 2+3 and Enter, the .exe file suddenly closes. I have no idea of what's wrong but I need to solve this soon, hope you can help me. Here's 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: %f\n",atof(yytext));
 yylval.real=atof(yytext);
return(TKN_NUM);}
"=" {//printf("Encontrado TKN_ASIGN: %s\n",yytext);
 return(TKN_ASIGN);}
"(" {//printf("Encontrado TKN_PAA: %s\n",yytext);
 return(TKN_PAA);}
")" {//printf("Encontrado TKN_PAC: %s\n",yytext);
 return(TKN_PAC);}
"cos" {//printf("Encontrado TKN_COS: %s\n",yytext);
 return(TKN_COS);}
"sen" {//printf("Encontrado TKN_SEN: %s\n",yytext);
 return(TKN_SEN);}
{ID} {//printf("Encontrado TKN_ID: %s\n",yytext);
 return(TKN_ID);}
"\n" {nlines++;}
.
%%

And sintactico.y file:

%{
/* 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 CORRECTA\n");
printf("Numero lineas analizadas: %d\n", nlines);
return 0;
}

What's wrong with it? I'm new with this Flex and Bison and it's hard to me to understand errors.


Solution

  • It looks like you want to use variable names, then you need to read in a string value in the lexer and use it the bison file.

    Your %union could look like this:

    %union
    {
        char* str;
        float real;
    }
    

    Likewise your TNK_ID should be:

    %token <str> TKN_ID
    

    And your adapted lexico.l could look something like this:

    {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'; }
    .
    

    Note also that there are now definitions for + and - as well as \n. The variable name is stored in yylval.str.

    Calculadora would rather look like this:

    Calculadora: { $$ = 0; }
        | Calculadora Expresion '\n' { printf("%f\n", $2); }
        | Calculadora '\n'
        ;
    

    And for Expresion the handling for IDs, assignments as well as plus and minus operation should be added, e.g.

    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); }
        ;
    

    Since it seems you want to assign values to variable names, you need a kind of symbol table. You could provide an implemention of void put_symbol(char *name, float value) and struct symbol_entry *get_symbol(char *name). A symbol entry could be defined as:

    struct symbol_entry {
        char name[50];
        float value;
    };
    

    Test

    A quick test - one line of entry is followed by one line output of the calculator:

    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
    

    Is that what you are looking for?