INTERFACING LEX WITH YACC. One of the main uses of LEX is as a companion to the YACC parser-generator.
%{
#include <ctype.h>
#include <stdio.h>
void yyerror(const char *str)
{
fprintf(stderr,"error: %s\n",str);
}
int yywrap()
{
return 1;
}
main()
{
yyparse();
}
%}
%token TOK_NUMBER TOK_PLUS TOK_TIMES TOK_MINUS TOK_DIVIDE TOK_LP TOK_RP
%%
line : line expr '\n' {printf("%d\n", $2); }
| /* empty word */
;
expr : expr TOK_PLUS term {$$ = $1 + $3; }
| term {$$ = $1; }
term : factor TOK_TIMES term {$$ = $1 * $3; }
| factor {$$ = $1; }
factor : TOK_LP expr TOK_RP {$$ = $2; }
| TOK_NUMBER {$$ = $1; }
;
%%
The file calculator.l specifies how the above tokens are detected
%{
#include "y.tab.h"
extern int yylval;
#include <stdlib.h>
%}
PLUS [\+]
MINUS [\-]
TIMES [\*]
DIVIDE [/]
DIGIT [0-9]
NUMBER [0-9]+
WS [ \t]*
LP "("
RP ")"
RET [\n]
%%
{WS} {
/* eat up white space */
}
{NUMBER} {
yylval = atoi( yytext );
return TOK_NUMBER;
}
{PLUS} {
return TOK_PLUS;
}
{TIMES} {
return TOK_TIMES;
}
{MINUS} {
return TOK_MINUS;
}
{DIVIDE} {
return TOK_DIVIDE;
}
{LP} {
return TOK_LP;
}
{RP} {
return TOK_RP;
}
. {
}
{RET} {
return yytext[0];
}
The corresponding calculator is built and run as follows:
[moreno@iguanodon yacc]$ yacc -d src/calculator.y yacc: 16 shift/reduce conflicts [moreno@iguanodon yacc]$ flex src/calculator.l [moreno@iguanodon yacc]$ gcc lex.yy.c y.tab.c -ll -o calculator [moreno@iguanodon yacc]$ ./calculator 1 + 3 4 2 * 4 8 (2 + 3) * 6 30 (2 + 3) * (4 + 5) 45
ABOUT THE SEPARATION OF THE LEXER FROM THE PARSER.