• C

lex and yacc floating point calculator

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);
}
luna621Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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

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

instead of yacc

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
PaulCaswellCommented:
Hi luna621,

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

Paul
0
luna621Author Commented:
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
Simple Misconfiguration =Network Vulnerability

In this technical webinar, AlgoSec will present several examples of common misconfigurations; including a basic device change, business application connectivity changes, and data center migrations. Learn best practices to protect your business from attack.

luna621Author Commented:
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
luna621Author Commented:
Also, how would I get something like this input to work?

>  23e5
0
luna621Author Commented:
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
luna621Author Commented:
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
fridomCEO/ProgrammerCommented:
You have to include the math library in the link you have to add
the -lm switch.

Regards
Friedrich
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
luna621Author Commented:
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
luna621Author Commented:
-------------------------------------------------------------------------
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
luna621Author Commented:
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
answer = 5.000000
syntax error

Enter an arithmetic expression
5 - 3
answer = 2.000000


0
luna621Author Commented:
Nevermind.  I fixed it:

digit   [0-9]
ndigit  (\-)?{digit}+
float      {digit}+(\.){digit}+
exponent ({digit}+|{float}+)(E|e){ndigit}+
0
luna621Author Commented:
Thank you for the information everyone.  Points time.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.