0

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
megasaw
  • 13
  • 4
  • Did it print the number of lines? – stark Sep 18 '20 at 19:22
  • No, the application just closes. – megasaw Sep 18 '20 at 19:38
  • 2
    @Megasaw: I strongly suggest you read the [Examples](https://www.gnu.org/software/bison/manual/bison.html#Examples) in the Bison manual, which are carefully explained so that you should be able to see what is going on. (Only in English, unfortunately, but I think it is not too complicated.) The examples build up to a full calculator with functions and variables, but they start simple and its worth taking the time to follow through the sequence. It will save you a lot of pain in the long run. – rici Sep 18 '20 at 20:59

2 Answers2

0

When I entry 2+3 and Enter, the .exe file suddenly closes.

Several things are going on here:

  1. "2+3" is not valid input to your program. Your grammar's start symbol is Calculadora, and the only production for that consists of one TKN_ID token. The first token your lexer will return for the given input will be a TKN_NUM corresponding to the 2. A parse error will result, yyparse() will return, and the program will soon terminate.

  2. The way you are launching your program, Windows closes the window in which it runs as soon as the program terminates. You should be able to avoid that by opening a command window, and launching your program within via the command line.

Note also that:

  1. Even if your start symbol were Expresion, "2+3" still would not be valid input. a TKN_NUM would still be the first token. The + would be matched only by the lexer's wildcard pattern, which has an empty action, so it will be printed but not produce a token. Then there will be another TKN_NUM, but the grammar has no rule that it can apply to two consecutive TKN_NUM tokens.
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Even if I put cos(2) the program terminates suddenly :( and I don't know how to fix it, I'm new with this and this program is driving me crazy. – megasaw Sep 18 '20 at 20:02
  • @megasaw, "cos(2)" is not valid input to your program, either. Again, your start symbol is `Calculadora`, and the only token sequence that can match that is one `TKN_ID`. – John Bollinger Sep 18 '20 at 20:08
  • So, I must change #start Calculadora by #Start Expresion? – megasaw Sep 18 '20 at 20:15
  • @megasaw, if you change the start symbol to `Expresion` then I would expect the input "cos(2)" to be accepted. However, the grammar provides no way to parse additional input beyond that, so I would expect `yyparse()` to return, bringing you right back to my point (2). – John Bollinger Sep 18 '20 at 20:25
  • 1
    Also, nothing in `Expresion` prints the value of the expression. That's in `Calculadora`, but the body of `Calculadora` doesn't match an `Expresion`. – rici Sep 18 '20 at 20:47
0

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?

Stephan Schlecht
  • 26,556
  • 1
  • 33
  • 47