0
votes

I am very new to Flex and bison, I am doing an application to compare number. If a > b it will return 0 and a < b will return 1 However, I got a problem when it come to &, |, == Here is an example of my output:

>> a = 5

5

>> b = 8

8

>> a < b & a < b

1

>> syntax error

I don't know how I can fix this problem. Here is some complain of the compiler:

[tpham14@linux5 ~/331] make -f mymake calc
bison -d -o y.tab.c -v calc.y
calc.y: warning: 16 shift/reduce conflicts [-Wconflicts-sr]
calc.y: warning: 6 reduce/reduce conflicts [-Wconflicts-rr]
cc    -c -o y.tab.o y.tab.c
cc    -c -o lex.yy.o lex.yy.c
cc -o calc y.tab.o lex.yy.o

Here is my calc.y file:

%{
#include "calc.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

/************************************************************************
* Defines a yacc grammar for a simple calculator using infix
* notation.  WHen executed, the calculator enters a loop in
* which it prints the prompt >>, reads a toplevel expression
* terminated by a newline, and prints its value.  Operators
* include +, -, *, and = (assignment). Note that all
* expressions return values, even assignment.  Parentheses
* can be used to override operator precedence and
* associativity rules. Based on zcalc by [email protected]
************************************************************************/
int yylex();
int yyparse();

%}

/*
  Th union directive specifies the collection of tpes our grammar
  deals with -- just doubles and pointers to symbol table entries.
*/

%union {
  double dval;
  struct symtab *symp;
  }

/*
  Declare the token types and any associated value types.  We made
  EQ a token in calc.l because otherwise '=' and '==' would clash.
*/
%token <symp> NAME
%token <dval> NUMBER
%token EQ
%token GT
%token LT
%token OR
%token AND
%token NOT
%token IF
%token ELSE
/* The folowing declarations specify the precidence and associativity
   of our operators. The operators -, +, * and / to be left
   associative, * and EQ to be right associative and UMINUS to be
   non-associative (since it is a unary operator). The '=' operator
   has the lowest precedence and UMINUS the highest.
*/

%right '='      /*lowest precedence*/
%right EQ GT LT
%left '-' '+'
%left '*' '/'
%left '&'
%nonassoc OR AND NOT
%nonassoc IF
%nonassoc ELSE
%nonassoc UMINUS     /* highest precedence */


/*
  Declare the type of expression to be a dval (double).
*/

%type <dval> expr
%type <dval> smallexprs
%%

/*
  Here are our grammar rules.  a session is a sequence of lines.  A
  toplevel is just an expr (print its value followed by two
  newlines and the prompt >>) or a '? (print help) or a '.' (exit).
  An expr can be a number, name, the sum of two exprs, ...
 */

session: /* empty */
         |session toplevel '\n'

;

toplevel:  expr                 { printf("%g\n\n>> ", $1); }
          | /*empty*/

                       | '?'                 { printHelp(); printf("\n>> "); }
          | '.'                 { printf("Exiting 331 calc\n"); exit(1); }


expr:   smallexprs                              { $$ = $1; }
       | NAME                                   { $$ = $1->value; }
       | NAME '=' expr                          { $1->value = $3; $$ = $3; }
       | IF   expr expr expr                    { if($2 == 1) $$ = $3; else $$ = $4; }
       | smallexprs AND smallexprs              { $$ = $1 && $3; }
       | smallexprs OR smallexprs               { $$ = $1 || $3; }
       | smallexprs EQ smallexprs               { $$ = $1 == $3; }
       | expr GT expr                           { $$ = $1 > $3; }
       | expr LT expr                           { $$ = $1 < $3; }
       | expr '+' expr                          { $$ = $1 + $3; }
       | expr '-' expr                          { $$ = $1 - $3; }
       | expr '*' expr                          { $$ = $1 * $3; }
       | expr '/' expr                          { $$ = $1 / $3; }

smallexprs: NUMBER                                      { $$ = $1; }
       | IF   smallexprs smallexprs smallexprs          { if($2 == 1) $$ = $3; else $$ = $4; }
       | smallexprs EQ smallexprs                       { $$ = $1 == $3; }
       | smallexprs GT smallexprs                       { $$ = $1 > $3; }
       | smallexprs LT smallexprs                       { $$ = $1 < $3; }
       | smallexprs '+' smallexprs                      { $$ = $1 + $3; }
       | smallexprs '-' smallexprs                      { $$ = $1 - $3; }
       | smallexprs '*' smallexprs                      { $$ = $1 * $3; }
       | smallexprs '/' smallexprs                      { $$ = $1 / $3; }
       | '~'  smallexprs %prec UMINUS                   { $$ = -$2; }
       | '('  smallexprs  ')'                           { $$ = $2; }


%%

struct   symtab *
symlook(s)
char *s;
{
   char *p;
   struct symtab *sp;

   /*  given the name of a symbol, scan the symbol table and
      either return the entry with matching name or add it
      to the next free cell in the symbol table. */

   for(sp = symtab; sp < &symtab[SYMBOLTABLESIZE]; sp++) {

     /* If the symbol table entry has a name and its equal
to the one we are looking for, return this entry */
     if (sp->name && !strcmp(sp->name, s))
       return sp;

         /* If the name is empty then this entry is free, so the
            symbol must not be in the table and we can add it here
            and return this entry. */
         if (!sp->name) {
           sp->name = strdup(s);
           return sp;
           }
       }

       /* We searched the entire symbol table and neither found
          the symbol or an unused entry.  So the table must be
          full.  Sigh. */
       yyerror("The symbol table is full, sorry...\n");
       exit(1);
    }



    void printHelp()
    { /* print calculator help and return */
      printf("Enter an expression in infix notation followed by a newline.\n");
      printf("Operators include +, -, * and =.  Defined functions include\n");
      printf("sqrt, exp and log.  You can assign a variable using the =\n");
      printf("operator. Type . to exit.  Syntax errors will terminate the\n");
      printf("program, so be careful.\n");
    }


    /* If error prints error and Do not accept to signify bad syntax in
       program */

    void yyerror(char *msg) /* yacc error function */
    {
      printf("%s \n" , msg);
    }

    int yywrap(){return 1;}

    int main()
    { /* print herald and call parser */
      printf("331 Calculator\n(type ? for help and . to exit)\n\n>> ");
      yyparse();
      return 0;
    }

Below will be my calc.l file:

%{
#include "y.tab.h"
#include "calc.h"
#include <math.h>

/************************************************************************
A lexical scanner to recognize numbers, symbols and the EQ
operator.  When a NUMBER is found, its value is set is set to the
appropriate float.  When a NAME is found, an entry in symbol table is
created (with initial value 0.0) and the token's value is a pointer to
this entry.  If a '==' sequence is seen, it is returned as a token
EQ.  Spaces and tabs are ignored. Any other characters, including
a newline, are passed on as their own tokens. Based on the zcalc
calculator by [email protected]
************************************************************************/

%}

D     [0-9]
A     [a-zA-Z]
AD    [a-zA-Z0-9]

%%

({D}+|({D}*\.{D}+)([eE][-+]?{D}+)?) {yylval.dval = atof(yytext); return NUMBER;}

if                                 {return IF;}
or                                 {return OR;}
and                                {return AND;}
not                                {return NOT;}



{A}{AD}*                             {struct symtab *sp = symlook(yytext); yylval.symp = sp; return NAME;}

"=="                                 {return EQ;}
">"                                  {return GT;}
"<"                                  {return LT;}
[ \t]  ;

\n    |
.     return yytext[0];

%%

Below is my calc.h file:

#define SYMBOLTABLESIZE 30

/* An entry in the symbol table has a name, a pointer to a function,
   and a numeric value. */

struct symtab {
  char *name;
  double (*funcptr)();
  double value;
} symtab[SYMBOLTABLESIZE];

struct symtab *symlook();

void printHelp();
void yyerror();
1
I don't see & being defined as the token AND anywhere. I see and and I asume that is the character string and, but I don't see &.Paul Ogilvie
I wonder if you need smallexprsPaul Ogilvie
Sorry, I probably don't know what I'm doing. I must put something like in calc.l "&" {return AND;} Like that?EthanP
And my be add token in calc.y?EthanP
smallexprs EQ smallexprs is defined twice. Once in expr and once in smallexprs. Some other rules too. This causes the shift/reduce conflicts.Paul Ogilvie

1 Answers

1
votes

syntax error no rule matching or containing &

&& token defined in your lex specification as 'and', you should check with

 a < b and a < b

or change lex specification as

  &&     { return AND;}
  ||     { return OR;}
  !      { return NOT;}

after GT shift, Reduce by Px as smallexprs Follow contains GT similarly for LT,+,-,*. (6 shift/reduce conflicts)

 expr:   smallexprs                  --- Px
 smallexprs: smallexprs .GT smallexprs  ---Sy



expr: smallexprs EQ smallexprs .
smallexprs: smallexprs EQ smallexprs .

reduce/reduce conflicts on Follow of expr and smallexprs (6 Reduce/Reduce conflicts)