Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 9107
  • Last Modified:

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);
}
0
luna621
Asked:
luna621
  • 10
  • 2
1 Solution
 
fridomCommented:
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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
 
fridomCommented:
You have to include the math library in the link you have to add
the -lm switch.

Regards
Friedrich
0
 
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

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 10
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now