Vous êtes sur la page 1sur 9

Lex et Yacc, exemples introductifs

D. Michelucci

LEX

1.1

Fichier makefile

exemple1 : exemple1 . l e x
f l e x oexemple1 . c exemple1 . l e x
g c c o exemple1 exemple1 . c l f l l c
exemple1 < exemple1 . i n p u t

#
#
#
#
#
#

l e x example1 . l
c c l e x . yy . c o example1 l l
NOTE: I f you a r e u s i n g f l e x
you may have to change l l
in t h e c o m p i l a t i o n s c r i p t s .
even when you i n v o k e f l e x

, i n s t e a d of l e x ,
to l f l
RedHat 6 . x and SuSE need t h i s ,
as l e x !

exemple2 : exemple2 . l e x
f l e x oexemple2 . c exemple2 . l e x
g c c o exemple2 exemple2 . c l f l l c
exemple2 < exemple2 . i n p u t
exemple3 : exemple3 . l e x
f l e x oexemple3 . c exemple3 . l e x
g c c o exemple3 exemple3 . c l f l l c
exemple3 < exemple3 . i n p u t
p1 : p1 . l e x
f l e x op1 . c p1 . l e x
g c c o p1 p1 . c l f l l c
p2 : p2 . l e x
f l e x op2 . c p2 . l e x
g c c o p2 p2 . c l f l l c
p2 < p3 . i n p u t
p3 : p3 . l e x
f l e x op3 . c p3 . l e x
g c c o p3 p3 . c l f l l c
p3 p3 . i n p u t

1.2

Fichier exemple1.lex

%{
#include <stdio.h>
%}
%%
stop
start
%%

printf("Stop command received\n");


printf("Start command received\n");

1.3

Fichier exemple1.input

stop stop s t a r t s t a r t

1.4

Fichier exemple2.lex

%{
#include <stdio.h>
%}
%%
[0123456789]+
[a-zA-Z][a-zA-Z0-9]*
%%

1.5

printf("NUMBER:%s\n", yytext);
printf("WORD:%s\n", yytext);

Fichier exemple3.lex

Exemple de fichier en entree :


logging {
category lame-servers { null; };
category cname { null; };
};
zone "." {
type hint;
file "/etc/bind/db.root";
};
La sortie correspondante :
WORD OBRACE
WORD FILENAME OBRACE WORD SEMICOLON EBRACE SEMICOLON
WORD WORD OBRACE WORD SEMICOLON EBRACE SEMICOLON
EBRACE SEMICOLON
WORD QUOTE FILENAME QUOTE OBRACE
WORD WORD SEMICOLON
WORD QUOTE FILENAME QUOTE SEMICOLON
EBRACE SEMICOLON
Le fichier exemple3.lex correspondant :
%{
#include <stdio.h>
%}
%%
[a-zA-Z][a-zA-Z0-9]*
[a-zA-Z0-9\/.-]+
\"
\{
\}
;
\n
[ \t]+
%%

1.6

printf("WORD ");
printf("FILENAME ");
printf("QUOTE ");
printf("OBRACE ");
printf("EBRACE ");
printf("SEMICOLON ");
printf("\n");
/* ignore whitespace */;

p2.lex

%{
#define _UINT

#define _SINT
2
#define _REAL
3
#define _KEYWORD
4
#define _ID
5
int lines=0;
%}
uint ([1-9][0-9]*)
real ([0-9]?\.[0-9]+)
id
([_a-zA-Z][_0-9a-zA-Z]*)
ws
([ \t]+)
%%
{ws}
{; }
\n
{ lines++;}
int |
for |
do |
if |
then |
else
{ return _KEYWORD;}
{uint}
{ return _UINT; }
[+-]{uint}
{ return _SINT; }
{id}
{ return _ID; }
{real}
{ return _REAL; }
.
{ printf("Error: Undefined string found! (%s)\n",yytext);
exit(1); }
%%
int yywrap(void){
return 1;
}
int main(int argc, char *argv[]) {
int res;
if(argc>2) {
printf("Syntax: %s [infile]\n",argv[0]);
exit(1);
}
if(argc==2)
if((yyin=fopen(argv[1],"r"))==NULL) {
printf("Cannot open input file %s.\n",argv[1]);
exit(1);
}
/* otherwise yyin = stdin */
while(res=yylex()){
switch(res){
case _UINT: printf("<unsigned int>"); break;
case _SINT: printf("<signed int>"); break;
case _REAL: printf("<real>"); break;
case _KEYWORD: printf("<keyword>"); break;
case _ID: printf("<ID>");
}
printf("[%s]\n",yytext);
}
printf(" %d lines processed.\n",lines);
fclose(yyin);
return 0;
}

1.7

p3.lex illustre yywrap, les


etats

%{
#define _UINT

#define _SINT
2
#define _REAL
3
#define _KEYWORD
4
#define _ID
5
int lines=0;
int filesno=0;
char **filename=NULL;
%}
/* the state COMMENT is exclusive */
%x COMMENT
uint ([1-9][0-9]*)
real ([0-9]?\.[0-9]+)
id
([_a-zA-Z][_0-9a-zA-Z]*)
ws
([ \t]+)
%%
{ws}
{; }
"/*"
{ BEGIN(COMMENT); /* enter comment eating mode */ }
<COMMENT>"*/"
{ BEGIN (INITIAL); /* exit comment eating mode */ }
<INITIAL,COMMENT>\n { lines++; /* INITIAL is defined as 0 */ }
<COMMENT>.
{ ; /* eat comments */ }
int |
for |
do |
if |
then |
else
{ return _KEYWORD;}
{uint}
{ return _UINT; }
[+-]{uint}
{ return _SINT; }
{id}
{ return _ID; }
{real}
{ return _REAL; }
.
{ printf("Error: Undefined string found!(%s)\n",yytext);
exit(1); }
%%
int yywrap(void){
static int i=1;
if(filesno<=0) return 1;
/* no other input file */
if((yyin=fopen(filename[i],"r"))==NULL) {
printf("Cannot open input file %s.\n",filename[i]);
exit(1);
}
i++;
filesno--;
return 0;
}
int main(int argc, char *argv[]) {
int res;
if(argc == 1) {
printf("Syntax: %s infile1 [infile2 ...]\n",argv[0]);
exit(1);
}
filesno=argc-1;
/* number of input files */
filename=argv;
/* names of input files */
yywrap();
/* opens the input first file */
while(res=yylex()){
switch(res){
case _UINT: printf("<unsigned int>"); break;
case _SINT: printf("<signed int>"); break;
case _REAL: printf("<real>"); break;

case _KEYWORD: printf("<keyword>"); break;


case _ID: printf("<ID>");
}
printf("[%s]\n",yytext);
}
printf(" %d lines processed.\n",lines);
fclose(yyin);
return 0;
}

2
2.1

Yacc : calculatrice en notation polonaise


makefile

ok : p o l i s h . y
#l e x c a l c u l . l e x
y a c c p o l i s h . y o p o l i s h . cpp
g++ o p o l i s h p o l i s h . cpp
l f l l c

2.2

Fichier yacc : polish.y

/* Reverse polish notation calculator. */


%{
#define YYSTYPE double
#include <math.h>
#include <stdio.h>
int yylex();
int yyerror( char *);
%}
%token NUM
%% /* Grammar rules and actions follow */
input : /* empty */
| input line
;
line : \n
| exp \n { printf ("\t%.10g\n", $1); }
;
exp : NUM
{ $$ = $1;
}
| exp exp +
{ $$ = $1 + $2;
}
| exp exp -
{ $$ = $1 - $2;
}
| exp exp *
{ $$ = $1 * $2;
}
| exp exp /
{ $$ = $1 / $2;
}
/* Exponentiation */
| exp exp ^
{ $$ = pow ($1, $2); }
/* Unary minus
*/
| exp n
{ $$ = -$1;
}
;
%%
/* Lexical analyzer returns a double floating point
number on the stack and the token NUM, or the ASCII
character read if not a number. Skips all blanks
and tabs, returns 0 for EOF. */
#include <ctype.h>
int yylex ()
{ int c;
/* skip white space */
while ((c = getchar ()) == || c == \t)
;
/* process numbers
*/
if (c == . || isdigit (c))
{

ungetc (c, stdin);


scanf ("%lf", &yylval);
return NUM;
}
/* return end-of-file */
if (c == EOF)
return 0;
/* return single chars */
return c;
}
main ()
/* The Main function to make this stand-alone
{
yyparse ();
}
#include <stdio.h>
int yyerror (char *s) /* Called by yyparse on error */
{
printf ("%s\n", s);
}

*/

Exemple dentree :
$ polish
2 1 +
3
2 3 5 * +
17

3
3.1

Calculatrice
makefile

ok : c a l c u l s c a n n e r t o u p p e r p r e p r o c e s s e r c o u r s l e x y a c c . p d f c o u r s l e x y a c c 2 . p d f
c a l c u l : c a l c u l . l e x c a l c u l . y a c c c a l c u l . cpp
lex calcul . lex
yacc c a l c u l . yacc
g++ o c a l c u l c a l c u l . cpp
l f l l c
clean :
rm f y . tab . c l e x . yy . c
scanner : scanner . lex
l e x o s c a n n e r . c s c a n n e r . l e x
g c c o s c a n n e r s c a n n e r . c l f l l c
toupper : toupper . l e x
l e x o t o u p p e r . c t o u p p e r . l e x
g c c o t o u p p e r t o u p p e r . c l f l l c
preprocesser : preprocesser . lex
l e x o p r e p r o c e s s e r . c p r e p r o c e s s e r . l e x
g c c o p r e p r o c e s s e r p r e p r o c e s s e r . c l f l l c
c o u r s l e x y a c c . pdf : c o u r s l e x y a c c . tex
latex cours lex yacc
dvipdf cours lex yacc
c o u r s l e x y a c c 2 . pdf : c o u r s l e x y a c c 2 . tex
latex cours lex yacc2
dvipdf cours lex yacc2

3.2

Fichier decla.h
6

#i f n d e f DECLA INCLUDED
#d e f i n e DECLA INCLUDED
#d e f i n e MAXNOMS 50
#d e f i n e MAXLENGTH 20
s t r u c t Table
{
c h a r tabNom [MAXNOMS] [MAXLENGTH] ;
i n t tabVal [MAXNOMS] ;
i n t i n i t i a l i z e d [MAXNOMS] ;
i n t tabNb ;
};
e x t e r n Table t a b l e ;
void i n i t t a b l e ( ) ;
i n t g e t v a r ( c h a r nom ) ;
i n t new var ( c h a r nom ) ;
v o i d i n i t i a l i z e ( i n t i n d i c e v a r , i n t value ) ;
int get val ( int indicevar ) ;
int yylex ( ) ; ;
int yyparse ( ) ; ;
i n t yyerror ( char s ) ;
#e n d i f

3.3

Fichier calcul.cpp

#include <s t d i o . h>


#include < s t d l i b . h>
#include <a s s e r t . h>
#include <s t r i n g . h>
#include d e c l a . h
/ t h e f i l e y . tab . c i s g e n e r a t e d with : y a c c c a l c u l . y a c c /
#include y . tab . c
Table t a b l e ;
void i n i t t a b l e ()
{
t a b l e . tabNb =0;
f o r ( i n t i =0; i <MAXNOMS; i ++)
{ table . i n i t i a l i z e d [ i ]=0;
t a b l e . tabVal [ i ]= 0 ; }
}
i n t g e t v a r ( c h a r nom )
{
f o r ( i n t i =1; i <=t a b l e . tabNb ; i ++)
i f ( ! strcmp ( t a b l e . tabNom [ i ] , nom ) ) r e t u r n i ;
return 0;
}
i n t new var ( c h a r nom )
{
t a b l e . tabNb ++ ;
a s s e r t ( t a b l e . tabNb < MAXNOMS ) ;
s t r c p y ( t a b l e . tabNom [ t a b l e . tabNb ] , nom ) ;
t a b l e . tabVal [ t a b l e . tabNb ] = 0 ;
t a b l e . i n i t i a l i z e d [ t a b l e . tabNb ] = 0 ;
r e t u r n t a b l e . tabNb ;
}
void i n i t i a l i z e ( i n t indvar , i n t valeur )
{

i f ( i n d v a r <=0 | | i n d v a r>=MAXNOMS)
{
p r i n t f ( i n i t i a l i z e bug : i n d v a r=%d\n , i n d v a r ) ;
}
t a b l e . tabVal [ i n d v a r ] = v a l e u r ;
table . i n i t i a l i z e d [ indvar ] = 1;
}
int g e t v a l ( int indvar )
{
i f ( i n d v a r <0 | | i n d v a r>=MAXNOMS)
{
p r i n t f ( g e t v a l bug : i n d v a r=%d\n , i n d v a r ) ;
}
i f ( t a b l e . i n i t i a l i z e d [ i n d v a r ]==0)
{
p r i n t f ( a c c e s a une v a r i a b l e non i n i t i a l i s e e : %s \n ,
t a b l e . tabNom [ i n d v a r ] ) ; }
r e t u r n t a b l e . tabVal [ i n d v a r ] ;
}

main ( )
{
init table ();
yyparse ( ) ;
}

3.4

Fichier calcul.lex

%{
#include d e c l a . h
%}
c h i f f r e [0 9]
l e t t r e [ azAZ ]
%%
quitter
{ r e t u r n QUIT ; }
;
|\ t |\n
s e t { r e t u r n DEF ; }
{ l e t t r e }({ l e t t r e }|{ c h i f f r e }) { i n t var ;
v a r=g e t v a r ( y y t e x t ) ;
i f ( ! v a r ) v a r=new var ( y y t e x t ) ;
y y l v a l = var ;
r e t u r n VAR; }
[0 9]+
{ y y l v a l = a t o i ( y y t e x t ) ; r e t u r n INT ; }
\
{ r e t u r n MOINS ; }
\/
{ r e t u r n DIV ; }
=
{ r e t u r n EGAL ; }
+
{ r e t u r n PLUS ; }

{ r e t u r n TIMES ; }
\
{ r e t u r n PUISS ; }
(
{ r e t u r n LPAREN ; }
)
{ r e t u r n RPAREN ; }
;
{ r e t u r n PV ; }
.
{ r e t u r n ERREUR ; }

3.5
%t o k e n
%t o k e n
%t o k e n
%t o k e n
%t o k e n

Fichier calcul.yacc
INT
FLOAT
PLUS TIMES
LPAREN RPAREN
QUIT ERREUR

%t o k e n
%t o k e n
%t o k e n
%t o k e n

DIV MOINS
PV
PUISS
VAR DEF EGAL

%l e f t MOINS
%l e f t PLUS / + b a s s e p r e c e d e n c e /
%l e f t DIV
%l e f t TIMES / moyenne p r e c e d e n c e /
%n o n a s s o c UMINUS
%r i g h t PUISS
%s t a r t top / p o i n t d e n t r e e /
%%
top : e x p r PV
{ $$ = $1 ; p r i n t f ( = %d \n , $$ ) ; } top
| DEF VAR EGAL e x p r PV
{
$$ = $4 ;
i n i t i a l i z e ( $2 , $4 ) ;
p r i n t f ( = %d \n , $$ ) ;
}
top
| e r r o r { p r i n t f ( s y n t a x e r r o r \n ) ; } top
| QUIT { r e t u r n 0 ; }
;
expr :
|
|
|
|
|
|
|
|

INT
{
VAR
{
LPAREN e x p r RPAREN
{
e x p r PLUS e x p r
{
MOINS e x p r %p r e c UMINUS
e x p r MOINS e x p r
{
e x p r DIV e x p r
{
e x p r TIMES e x p r
{
e x p r PUISS e x p r
{

$$= $1 ; }
$$= g e t v a l ( $1 ) ; }
$$=$2 ; }
$$=$1 + $3 ; }
{ $$= $2 ; }
$$=$1 $3 ; }
$$=$1 / $3 ; }
$$=$1 $3 ; }
i n t i ; i n t i n t e r m =1;
f o r ( i =0; i <$3 ; i ++)
i n t e r m = i n t e r m $1 ;
$$=i n t e r m ; }

;
%%
#include l e x . yy . c
i n t yyerror ( char s )
{
p r i n t f ( %s \n , s ) ;
return 0;
}
$ calcul
set a=1+2*3;
= 7
set b= a^3^2;
= 40353607
2+3*2^10;
= 3074
2^10;
= 1024