Solved

# lex and yacc floating point calculator

Posted on 2006-04-26
8,174 Views
I'm used to compiling (1) a lex definition file and (2) a yacc definition file as follows:

1. lex mylexfile.l
2. yacc -d -l myfile.y
3. gcc y.tab.c lex.yy.c -ly -ll
4. ./a.out

I found this example, and I'm trying to understand it.  What is this BISON business?  Is there a way to separate them into one lex (mylexfile.l) and one yacc file (myfile.y)?  Any help appreciated.
---------------------------------------

/* Infix notation calculator--calc */

%{
#define YYSTYPE double
#define alloca malloc
#include <math.h>
%}

/* BISON Declarations */
%token NUM
%left '-' '+'
%left '*' '/'
%left NEG     /* negation--unary minus */
%right '^'     /* exponentiation        */

/* Grammar follows */
%%
input:    /* empty string */
| input line
;

line:     '\n'
| exp '\n'  { printf("\t%.10g\n", \$1); }
;

exp:      NUM                    { \$\$ = \$1;         }
| exp '+' exp             { \$\$ = \$1 + \$3;    }
| exp '-' exp              { \$\$ = \$1 - \$3;    }
| exp '*' exp             { \$\$ = \$1 * \$3;    }
| exp '/' exp              { \$\$ = \$1 / \$3;    }
| '-' exp  %prec NEG  { \$\$ = -\$2;        }
| exp '^' exp             { \$\$ = pow (\$1, \$3); }
| '(' exp ')'                { \$\$ = \$2;         }
;
%%

/* Lexical analyzer returns a double floating point
number on the stack and the token NUM, or the ASCII
character read if not a number.  Skips all blanks
and tabs, returns 0 for EOF. */

#include <ctype.h>

yylex ()
{
int c;

/* skip white space  */
while ((c = getchar ()) == ' ' || c == '\t')
;

/* process numbers   */
if (c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", &yylval);
return NUM;
}

/* return end-of-file  */
if (c == EOF)
return 0;

/* return single chars */
return c;
}

main ()
{
yyparse ();
}

#include <stdio.h>

yyerror (s)  /* Called by yyparse on error */
char *s;
{
printf ("%s\n", s);
}
0
Question by:luna621

LVL 24

Expert Comment

bison is a yacc implementation from GNU.
http://www.gnu.org/software/bison/

so you shoul get aways with using it like this:
bison ...

The C code looks as if it has a considerable age, maybe it would be a good idea to update it a bit.

Regards
Friedrich
0

LVL 16

Expert Comment

Hi luna621,

Welcome back!! :-) Long time no see! How're you doing?

Paul
0

Author Comment

Hi Paul!!

I've been busy with the kids (it was Spring break), now summer school is coming up.  No chance to relax, and program!!  I'm still getting a workout with the Assembly.  My next self project is making a very simple arcade-type game.  Hopefully that goes well.  If not, you'll be hearing from me in the Assembly section. :-)

I was working on the above late last night, so I might not have been functioning right.  I need to take another look at it with the suggestions.  Great to see you again!
0

Author Comment

Okay, I came up with something that seems to work for ints only.  I tried to convert to float, but I am getting errors.  Example:

3+4
=1075576832

That's not right!!  It worked (even parenthesis and precedence) when I did it with integers.  But once I changed it over to float, it's pulling strange numbers.

CODE:
-----------------------------------
yacc file
-----------------------------------

%{
#include <stdio.h>
#define YYSTYPE float
%}

%token NUMBER
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS
%%
statement : expression      {printf("=%d\n",\$1);}
;
expression: expression '+' expression      { \$\$ = \$1 + \$3; }
| expression '-' expression       { \$\$ = \$1 - \$3; }
| expression '*' expression       { \$\$ = \$1 * \$3; }
| expression '/' expression       { if ( \$3 == 0 )
yyerror("Cannot divide by zero!");
else
\$\$ = \$1 / \$3;
}
| '-' expression %prec UMINUS { \$\$ = -\$2; }
| '(' expression ')'             { \$\$ = \$2; }
| NUMBER                     { \$\$ = \$1; }
;
%%

-----------------------------------
lex file
-----------------------------------

%{
#include "y.tab.h"  /*  Created by yacc */
extern int yylval;
%}

%%
[0-9]+            {yylval = atoi(yytext); return NUMBER;}
[  \t]            ;                  /*  Ignore white space */
\n            { return 0; }            /* logical EOF */
.            { return yytext[0]; }      /* catch-all return single char */
%%
0

Author Comment

Also, how would I get something like this input to work?

>  23e5
0

Author Comment

Okay, changed my code a bit.  Now I'm getting this compiling error:

> lex lexfloat.l
> yacc -d -l float.y
> gcc y.tab.c lex.yy.c -ly -ll

y.tab.c:36: error: conflicting types for `yylex'
y.tab.c:6: error: previous declaration of `yylex'

-------------------------------------------
lex file
-------------------------------------------

%{
#include "y.tab.h"  /*  Created by yacc */
#include <stdlib.h>
typedef float YYSTYPE;
extern YYSTYPE yylval;
%}

%%
[0-9]+          {yylval = atof(yytext); return NUMBER;}
[  \t]          ;                       /*  Ignore white space */
\n              { return 0; }           /* logical EOF */
.               { return yytext[0]; }   /* catch-all return single char */
%%

-------------------------------------------
yacc file
-------------------------------------------

%{
#include <math.h>
#include <stdio.h>

#define YYSTYPE float

float yylex(void);
void yyerror(const char *errMsg);
%}

/* yacc declarations */
%token NUMBER
%left '-' '+'
%left '*' '/'
%left NEG       /* negation--unary minus */
%right '^'      /* exponentiation   */

/* Grammar follows */
%%
input
: /* empty */
| input line
;

line
: '\n'
| exp '\n'            { printf ("\t%.10g\n", \$1); }
;

exp
: NUMBER
| exp '+' exp         { \$\$= \$1 + \$3; }
| exp '-' exp         { \$\$= \$1 - \$3; }
| exp '*' exp         { \$\$= \$1 * \$3; }
| exp '/' exp         { \$\$= \$1 / \$3; }
| '-' exp  %prec NEG  { \$\$= -\$2; }
| exp '^' exp         { \$\$= pow (\$1, \$3); }
| '(' exp ')'         { \$\$= \$2; }
;
%%
0

Author Comment

Okay, got rid of those errors because I needed to leave the types as int.  But, now I get this error:

Undefined                       first referenced
symbol                             in file
pow                                 /var/tmp//ccg6LBHz.o
ld: fatal: Symbol referencing errors. No output written to a.out
collect2: ld returned 1 exit status

It's referring to this line:

| exp '^' exp         { \$\$= pow (\$1, \$3); }

Any ideas?  I included:

#include <math.h>
#include <stdio.h>

Do I need something else??
0

LVL 24

Accepted Solution

You have to include the math library in the link you have to add
the -lm switch.

Regards
Friedrich
0

Author Comment

Okay, I started from scratch again.  I get syntax errors when I try to do something like:     23.5e-1
I know I have to fix something in my lex file.  Any ideas?

-------------------------------------------------------------------------
LEX FILE:
-------------------------------------------------------------------------

#include "y.tab.h"
#include <math.h>
#include <stdlib.h>  /* for atof */

typedef double YYSTYPE;

extern YYSTYPE yylval;
extern int unary_fl;

%}

digit   [0-9]
float      {digit}(\.){digit}
negdigit  (\-)?{digit}
exponent ({digit}|{float})(E|e){negdigit}

%%

{digit}+              { yylval = atof(yytext);
return number; }
{negdigit}+           { yylval = atof(yytext);
return number; }
{float}+              { yylval = atof(yytext);
return number; }
{exponent}+           { yylval = atof(yytext);
return number; }
(" "|\t)*             ;

\n                    { return(0); }  /* provide code for EOF on Enter */

.                     { return yytext[0]; }
0

Author Comment

-------------------------------------------------------------------------
YACC FILE:
-------------------------------------------------------------------------

#include <stdio.h>  /* for printf */
#include <math.h>
#define YYSTYPE double

int yyparse(void);
int yylex(void);
void yyerror(char *mes);

int unary_fl = 1;

%}

%token number
%left '+' '-'
%left '*' '/'
%right UPLUS
%right UMINUS

%%

program : expression                {printf("\nAnswer = %f\n", \$\$);}
;

expression : expression '+' term  {\$\$ = \$1 + \$3;}
| expression '-' term  {\$\$ = \$1 - \$3;}
| '+' term   %prec UPLUS   {\$\$ = + \$2;}
| '-' term   %prec UMINUS  {\$\$ = - \$2;}
| term
;

term : term '*' factor  {\$\$ = \$1 * \$3;}
| term '/' factor  {\$\$ = \$1 / \$3;}
| factor
;

factor : '(' expression ')'   {\$\$ = \$2;}
| number
;

%%

void main()
{
printf("\nEnter an arithmetic expression:\n\n");
yyparse();
}

void yyerror(char *mes) {printf("%s\n", mes);}
0

Author Comment

Just noticed that the errors are only on the negative or minus.  If there are no spaces, I get a syntax error:

Enter an arithmetic expression
5-2
syntax error

Enter an arithmetic expression
5 - 3

0

Author Comment

Nevermind.  I fixed it:

digit   [0-9]
ndigit  (\-)?{digit}+
float      {digit}+(\.){digit}+
exponent ({digit}+|{float}+)(E|e){ndigit}+
0

Author Comment

Thank you for the information everyone.  Points time.
0

## Featured Post

### Suggested Solutions

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.