Professional Documents
Culture Documents
(F) Lex & Bison/Yacc: Language Tools For C/C++ CS 550 Programming Languages
(F) Lex & Bison/Yacc: Language Tools For C/C++ CS 550 Programming Languages
(F) Lex & Bison/Yacc: Language Tools For C/C++ CS 550 Programming Languages
Alexander Gutierrez
Lex and Flex Overview
2
Yacc and Bison Overview
3
Which to use?
4
Lex/Flex on tux.cs.drexel.edu
5
Yacc/Bison on tux.cs.drexel.edu
● On tux, invoking yacc calls a script that runs bison in yacc-compatibility mode
● Why is there a yacc-compatibility mode for bison if they are basically the
same?
To account for some POSIX differences and minor quirks that we don’t really
care about
6
The Bigger Picture
● We can use Flex and Bison to (relatively) easily implement our own
programming language
● To do this, we need to make the instruction manuals for Flex and Bison
● For Flex, we need to determine what tokens our language consists of and
how each token can be described using a regular expression
● For Bison, we need to create a (LALR) grammar that takes these tokens and
turns it into machine code
● Both Flex and Bison will produce a piece of C/C++ code which we can
compile using an appropriate C/C++ compiler
7
Balanced Parentheses Example
8
paren.l
%{
#include "paren.tab.h"
%}
%%
\( { return LEFTPAREN; }
\) { return RIGHTPAREN; }
.|\n { return 0; }
%%
9
paren.y
%{
#include <string.h>
#include <stdio.h>
%}
%%
S0: S1 S0 { printf("S0 => S1 S0\n"); }
| S1 { printf("S0 => S1\n"); }
;
● All we need are these two files, paren.l and paren.y, in our directory:
$ ls
paren.l paren.y
$ bison -d paren.y
$ flex paren.l
$ gcc paren.tab.c lex.yy.c -ly -lfl
11
Running Bison
● The reason we use bison first is to produce information about tokens that it accepts,
which we can feed to flex to create our lexical analyzer
$ bison -d paren.y
● The ‘-d’ option for bison creates header files which enable us to feed this information to
flex
#include "paren.tab.h"
$ ls
paren.l paren.tab.c paren.tab.h paren.y
12
Running Flex
$ flex paren.l
$ ls
lex.yy.c paren.l paren.tab.c paren.tab.h paren.y
13
Compiling the compiler
● Here, we are using gcc to compile the code using the bison (yacc) and flex
libraries.
● The order of the options are actually important in order to make the resulting
compiler work.
● As usual with the GNU C/C++ compilers, the result is an executable named
a.out by default
14
Using Our New Language
● We can test to make sure it works by running the executable and giving it
input.
$ ./a.out
(())
S1 => ()
S2 => S1
S1 => (S2)
S0 => S1
● In other words, the function of this interpreter is to display its own parsing via
its grammar rules.
15
Using Our New Language (cont.)
$ ./a.out
(()()(
S1 => ()
S1 => ()
syntax error
● In this case, I gave it a malformed program. The input was not in the
recognized language due to imbalanced parentheses and therefore gave a
syntax error.
16
Summary
17
Reference
18