cbisonflex-lexeryacc

Combine flex and bison for file parsing


I have this program in flex/bison.

My two problems are this :

  1. I don't know how to make it work for file inputs because my university exercise need it work with files.

    I tried using iostream library from g++ compiler but i had many errors (I change of course printfs in cout etc)

  2. I can't make it work as a float, I used atof declared yytext as boolean also still got nothing.

flex.l :

%option noyywrap
%option yylineno

%{
    #include <stdlib.h>
    #include "bison.tab.h"
    #define YYDEBUG 1
%}

%%
create_table {return CREATE;}
[ ][a-z]+ {return MONO;}
([ ][a-z]+[ ][&])+ {return CREATELIST;}

create_record_data {return RECORD;}
([ ][a-z]+)([ ]#[0-9]{1,2}) {return RECORDNUMBER;}

[0-9]+(["."][0-9]+)? {yylval = atoi(yytext); return NUMBER;}
"+" {return PLUS;}
"-" {return MINUS;}
"*" {return MULT;}
"/" {return DIV;}
"\n" {printf("Line : %d \n",yylineno);  return END;}
"\t" {return TAB;}
"(" {return PARL;}
")" {return PARR;}

%%

bison.y :

%{
    #include <stdlib.h>
    #include <stdio.h>
%}

%token CREATE RECORD 
%token MONO CREATELIST RECORDNUMBER
%token NUMBER
%token PLUS MINUS MULT DIV PARL PARR
%token END TAB

%left PARL PARR
%left MULT DIV
%left PLUS MINUS

%start Input
%%

Input:
 | Input Line
;

Line:
 END
 | Expr END { printf("Result: %d \n", $1); }
 | Create_table END { printf("Create Table ! \n"); }
 | Create_record_data END { printf("Record Data Created ! \n"); }
;

Expr:
 NUMBER {$$ = $1;}
 | Expr PLUS Expr {$$=$1+$3;}
 | Expr MINUS Expr {$$=$1-$3;}
 | Expr MULT Expr {$$=$1*$3;}
 | Expr DIV Expr {$$=$1/$3;} 
 | PARL Expr PARR {$$=$2;}
 ; 

Create_table:
 CREATE MONO { printf("Create Table Single! \n"); } 
 | CREATE CREATELIST { printf("Create Table List ! \n"); }
 ;

Create_record_data:
 RECORD RECORDNUMBER Expr { printf("Record Created \n"); }
 ;

%%

int yyerror(char *s) {
  printf("%s \n", s);
}

int main() {
  if (yyparse()==0)
     fprintf(stderr, "Successful parsing.\n");
  else
     fprintf(stderr, "error found.\n");
}

Solution

  • In your main you can open a file or use stdin (this makes testing easier).

    Say if you want to optionally accept an input filename as your first argument, change your main to look like:

    extern FILE* yyin;
    int main(int argc,char **argv) {
      yyin = NULL;
      if (argc==2) yyin = fopen(argv[1],"r");
      if (!yyin) yyin = stdin;
      if (!yyparse()) {
        ...
    

    For your other issue of "using" the tokens.

    You can use the yytext to get the text that the scanner found that triggered the token, but you can't assign just assign this to a token. You have to use types.

    If you want to get the value from the scanner (and not worry about yytext in the grammar, then above your %token section, add this:

    %union
    {
      int intval;
      float floatval;
    }
    ...
    %token <intval> NUMBER
    

    Then, in your flex.l, you can assign to the union according to whatever type the token is:

    [0-9]+(["."][0-9]+)? {yylval.intval = atoi(yytext); return NUMBER;}
    

    Then, in your grammar, you can access the (int value in this case) using the $1 or $3 / etc. positional variable and get that atoi value.

    Last thing, is you declare grammar for Expr but it has no type.

    In the top section, below your tokens, you have to give non-terminals a type:

    %type <intval> Expr // if an Expr is just a number
    

    If you want to store more information in a Non-Terminal then you should probably make/use a struct, declare its type in the union, then you can set the type of the NT to your struct.

    The only way to assign $$ (the left side of the production rule) is for $$ to have a type. With the above, giving Expr an int and the numbers ints ...

    Expr : Expr PLUS Expr { $$ = $1 + $3; }
    

    should work