Sunday, September 16, 2012

Best Tutorial on Flex and Bison

http://aquamentus.com/flex_bison.html
Chris verBurg 2011-12-08

I had just finished all the tutorials and manged to make it work with mingw64 and gnuwin32, latest version as 16 Sep 1963. Malaysia day.

This is the easiest way of writing your own assemblers and compilers. These languages can be incorporated into application software since the output is just C or C++ source codes.

The only problem compiling was the missing yywrap library. Fixing it by including its source into the flex source file solved the problem. Take out the -lfa option in flex.

The make file for windows environment didn't work so had to resort to batch programming.

File: build_snazzle.bat

bison -d snazzle.y
flex snazzle.l
g++ snazzle.tab.c lex.yy.c  -o snazzle.exe
snazzle
pause
del lex.yy.c snazzle.tab.c snazzle.tab.h

Flex source File: snazzle.l

/* File snazzle.l
w w w . a q u a m e n t u s . c o m Chris verBurg 2011-12-08 */

/* Note that flex cannot take // as comment line here */

%{
#include <iostream>
#include "snazzle.tab.h"
using namespace std;
#define YY_DECL extern "C" int yylex()
int line_num = 1;
%}
%%
[ \t] ;
sNaZZle        { return SNAZZLE; }
type           { return TYPE; }
end            { return END; }
[0-9]+\.[0-9]+ { yylval.fval = atof(yytext); return FLOAT; }
[0-9]+         { yylval.ival = atoi(yytext); return INT; }
[a-zA-Z0-9]+   {
    // we have to copy because we can't rely on yytext not changing underneath us:
    yylval.sval = strdup(yytext);
    return STRING;
}
\n             { ++line_num; return ENDL;}
.              ;
%%

// Not in the original file. It is taken from gnu flex sources. Othman Ahmad
int     yywrap (void)
{
    return 1;
}

Bison source File: snazzle.y

// File snazzle.y  from w w w . a q u a m e n t u s . c o m Chris verBurg 2011-12-08
%{
#include <cstdio>
#include <iostream>
using namespace std;

//Included in the original file, but will cause errors if included. Othman Ahmad
//#include "y.tab.h"  // to get the token types that we return

// stuff from flex that bison needs to know about:
extern "C" int yylex();
extern "C" int yyparse();
extern "C" FILE *yyin;
extern int line_num;

void yyerror(const char *s);
%}

// Bison fundamentally works by asking flex to get the next token, which it
// returns as an object of type "yystype".  But tokens could be of any
// arbitrary data type!  So we deal with that in Bison by defining a C union
// holding each of the types of tokens that Flex could return, and have Bison
// use that union instead of "int" for the definition of "yystype":
%union {
    int ival;
    float fval;
    char *sval;
}

// define the constant-string tokens:
%token SNAZZLE TYPE
%token END ENDL

// define the "terminal symbol" token types I'm going to use (in CAPS
// by convention), and associate each with a field of the union:
%token <ival> INT
%token <fval> FLOAT
%token <sval> STRING

%%

// the first rule defined is the highest-level rule, which in our
// case is just the concept of a whole "snazzle file":
snazzle:
    header template body_section footer { cout << "done with a snazzle file!" << endl; }
    ;
header:
    SNAZZLE FLOAT ENDLS{ cout << "reading a snazzle file version " << $2 << endl; }
    ;
template:
    typelines
    ;
typelines:
    typelines typeline
    | typeline
    ;
typeline:
    TYPE STRING ENDLS{ cout << "new defined snazzle type: " << $2 << endl; }
    ;
body_section:
    body_lines
    ;
body_lines:
    body_lines body_line
    | body_line
    ;
body_line:
    INT INT INT INT STRING ENDLS{ cout << "new snazzle: " << $1 << $2 << $3 << $4 << $5 << endl; }
    ;
footer:
    END ENDLS
    ;
ENDLS:
    ENDLS ENDL
    | ENDL
    ;
%%

main() {
    // open a file handle to a particular file:
    FILE *myfile = fopen("in.snazzle", "r");
    // make sure it's valid:
    if (!myfile) {
        cout << "I can't open a.snazzle.file!" << endl;
        return -1;
    }
    // set flex to read from it instead of defaulting to STDIN:
    yyin = myfile;

    // parse through the input until there is no more:
    do {
        yyparse();
    } while (!feof(yyin));
   
}

void yyerror(const char *s) {
    cout << "EEK, parse error on line " << line_num << "! Message: " << s << endl;
    // might as well halt now:
    exit(-1);
}

File for testing: in.snazzle

sNaZZle 1.3
type foo
type bar
type bas
0 0 10 5 foo
20 10 30 20 foo
type oops
7 8 12 13 bas
78 124 100 256 bar
end



No comments:

Post a Comment