0
votes

I'm not very experienced in bison and flex and i need some help.

i have some errors in my .y file.

syntax wise its fine and it compiles when i "bison -d" it but when i try to compile with gcc it gives me some errors that im not sure how to solve(total noob here):

https://i.stack.imgur.com/fUeR7.png

the .lex file:

%{
#include "meals.tab.h"
#include <string.h> 

extern void exit(int);
int line = 1;

#define VEGETABLE 1
#define FRUIT 2
#define BREAD 3
#define MEAT 4
#define CAKE 5
#define CHOCOLATE_ICE_CREAM 6
#define VANILLA_ICE_CREAM 7
#define BEGIN_MEAL 100
#define END_MEAL 101

%}

%option noyywrap

%%

"<meal>"    {return BEGIN_MEAL;}
"</meal>"   {return END_MEAL;}

"broccoli"      {return VEGETABLE;}
"lettuce"       {return VEGETABLE;}
"tomato"        {return VEGETABLE;}
"cucumber"  {return VEGETABLE;}
"orange"        {return FRUIT;}
"apple"     {return FRUIT;}
"strawberry"    {return FRUIT;}
"watermelon"    {return FRUIT;}
"chicken"       {return MEAT;}
"beef"      {return MEAT;}
"bread"     {return BREAD;}
"cake"      {return CAKE}
"chocolate ice cream"   {return CHOCOLATE_ICE_CREAM ;}
"vanilla ice cream"     {return VANILLA_ICE_CREAM ;}

","     /* skip comma */
[\t ]+      /* skip white space */
\n         { line++; }
.   { fprintf (stderr, "line %d: unrecognized token %c\n",
                               line, yytext[0]);  
                exit(1);
            }


%%

the .y file:

%code {

#include <stdio.h>

extern int yylex (void);
void yyerror (const char *s);

struct diet
}

%code requires {
    struct diet {
        int veg_fruit, dessert, calories, isDesertFine, isVeggieFine;
    };
}
%union {
    struct diet _diet;
}

%token BEGIN_MEAL END_MEAL VEGETABLE FRUIT MEAT BREAD CAKE CHOCOLATE_ICE_CREAM VANILLA_ICE_CREAM 
%type <_diet> list_of_meals meal list_of_servings serving

%error-verbose

%%

day: list_of_meals{
                    if(($1.calories <= 18) && ($1.isDesertFine == 0) && ($1.isVeggieFine == 0))
                    printf ("everything is OK\n");
                    else if($1.calories <= 18 && $1.isDesertFine == 0)
                    printf ("Not enough veggies/fruits\n");
                    else if($1.calories <= 18 && $1.isVeggieFine == 0)
                    printf ("Too many desserts\n");
                    else if($1.isDesertFine == 0 && $1.isVeggieFine == 0)
                    printf ("Too many calories: total is $1.calories\n");
                    else if($1.calories <= 18){
                    printf ("Too many desserts\n");
                    printf ("Not enough veggies/fruits\n");
                    }
                    else if($1.isDesertFine == 0){
                    printf ("Too many calories: total is $1.calories\n");
                    printf ("Not enough veggies/fruits\n");
                    }
                    else if($1.isVeggieFine == 0){
                    printf ("Too many desserts\n");
                    printf ("Too many calories: total is $1.calories\n");
                    }
                    else{
                    printf ("Too many calories: total is $1.calories\n");
                    printf ("Too many desserts\n");
                    printf ("Not enough veggies/fruits\n");
                    }
                    };

list_of_meals: list_of_meals meal {$$.calories = $1.calories + $2.calories;
                                    $$.isDesertFine = $1.isDesertFine + $2.isDesertFine;
                                    $$.isVeggieFine = $1.isVeggieFine + $2.isVeggieFine;};

list_of_meals:  /*empty*/ {$$.calories = -1;
                                $$.veg_fruit = -1;
                                $$.dessert = -1;
                                $$.isVeggieFine = 1;
                                };
meal: BEGIN_MEAL list_of_servings END_MEAL {if($2.calories > 18)
                                            printf ("Meal : too many calories\n");
                                            if($2.veg_fruit < 2){
                                            printf ("Meal : not enough veggies/fruit\n");
                                            $$.isVeggieFine = 1;
                                            }else{ $$.isVeggieFine = 0;}
                                            if($2.dessert > 1){
                                            printf ("Meal : too many desserts\n");
                                            $$.isDesertFine = 1;
                                            }else{ $$.isDesertFine = 0;}

                                            $$.calories = $2.calories;
                                            };

list_of_servings: list_of_servings ',' serving {$$.calories = $1.calories + $3.calories;
                                                $$.veg_fruit = $1.veg_fruit + $3.veg_fruit;
                                                $$.dessert = $1.dessert + $3.dessert;};

list_of_servings: serving {$$.calories = $1.calories;
                            $$.veg_fruit = $1.veg_fruit;
                            $$.dessert = $1.dessert;};

serving:  VEGETABLE {$$.calories = 1; $$.veg_fruit = 1;}
        | FRUIT {$$.calories = 2; $$.veg_fruit = 1;}
        | MEAT {$$.calories = 3;}
        | BREAD {$$.calories = 4;}
        | CAKE{$$.calories = 5; $$.dessert = 1;}
        | CHOCOLATE_ICE_CREAM{$$.calories = 6; $$.dessert = 1;}
        | VANILLA_ICE_CREAM {$$.calories = 7; $$.dessert = 1;}
        ;

%%

#include <stdio.h>
#include <stdlib.h>

main (int argc, char **argv)
{
  extern FILE *yyin;
  if (argc != 2) {
     fprintf (stderr, "Usage: %s <input-file-name>\n", argv[0]);
     return 1;
  }
  yyin = fopen (argv [1], "r");
  if (yyin == NULL) {
       fprintf (stderr, "failed to open %s\n", argv[1]);
       return 2;
  }

  yyparse ();

  fclose (yyin);
  return 0;
}

void yyerror (const char *s)
{
  extern int line;
  fprintf (stderr, "line %d: %s\n", line, s);
}

Thanks!

1
Please don't include text as images. It makes it hard to read and impossible to quote in answers. Instead, copy and paste the text (or the relevant part of it) into your question.rici

1 Answers

2
votes

The problem is the C syntax error in the first %code section in your bison file:

struct diet

That's missing a semicolon, and will create a variety of unpredictable compile errors when eventually passed to a C compiler.

However, the declaration is unnecessary, and should simply be removed.

There are also some issues with your flex file:

  1. Don't do this:

    #define VEGETABLE 1
    #define FRUIT 2
    ...
    

    The correct token definitions are in the header file created by bison, which you have already included. The values you provide are incorrect and will cause parsing to fail.

  2. Don't do this either:

    extern void exit(int);
    

    exit is declared in the standard header stdlib.h; you should include that header file instead of second-guessing its contents:

    #include <stdlib.h> 
    #include <string.h> 
    #include "meals.tab.h"
    

    Note that it is conventional to include system headers before including your own headers (such as the one generated by bison).

  3. Finally, I strongly recommend that you remove your own attempt to track line numbers in line, and instead just let flex do it:

    %option yylineno
    

    will cause flex to insert efficient code to maintain the current line number in the variable yylineno. Furthermore, it will maintain the line number correctly, since it understands all the corner cases. (Unless you sidestep flex processing by using input() to directly read from yyin.)