Tutorial de Lex & Yacc
|
Índice :
|
Juntos Lex & YaccA continuacion se presenta un ejemplo mas complejo con explicación y algunas corridas del mismo.Ejemplo 2
El ejemplo 2 es una calculadora booleana/aritmetica que puede
relover expresiones entre numeros y cadenas por igual, aplicando
algunos estandares para ello, el resultado de esta calculadora
sera verdadero o falso dependiendo si su resultado es mayor que
o menor o igual que cero (recordando los parametros booleanos en C)
la lista de operadores, en orden de precedencia, de mayor a menor son:
A continuacion el codigo de ejemplo : Download ejem2.l y ejem2.y Lexer :
%{
#define HELLO "Parser booleano/aritmetico\nPor: Oscar Medina Duarte\nBajo licencia BSD"
#include "y.tab.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
%}
Natural ([0-9]+)
Cadena \"[^"\n]*["]
Return "\n"
%%
%{
int i;
%}
{Return} {return NL;}
"bye"|"quit"|"exit"|"resume" {return BYE;}
{Natural} {
yylval.entero =atoi(yytext);
return ENTERO;
}
{Cadena} {
for(i=1;i<strlen(yytext)-1;i++)
yytext[i-1] = yytext[i];
yytext[i-1] = '\0';
yylval.cadena = malloc(strlen(yytext)+1);
strcpy(yylval.cadena,yytext);
return CADENA;
}
"==" {return EQ;}
"!=" {return NE;}
"||" {return OR;}
"&&" {return AND;}
">=" {return GEQ;}
"=>" {return GEQ;}
"<=" {return LEQ;}
"=<" {return LEQ;}
"eq" {return SEQ;}
"ne" {return SNE;}
"gt" {return SG;}
"lt" {return SL;}
"ge" {return SGE;}
"le" {return SLE;}
[ \t];
. return yytext[0];
%%
Comentarios sobre este lexerCuando se reconoce una cadena, esta se encuentra encerrada entre "`s y es necesario eliminar las comillas de yytext, antes de asignarlo a yylval.cadena que es de donde el parser tomara el valor.Este lexer esta probado usando flex si estas usando Solaris o SunOS algun sistema similar, puedes bajar la version 2.5.4 compilada y lista para usarse haciendo click aca. Download ejem2.l y ejem2.y Parser :
%{
int CharFlag=0;
%}
%union{
char *cadena;
int entero;
}
%token NL BYE
%token <cadena> CADENA;
%token <entero> ENTERO;
%left '^' '|' '&'
%left '-' '+'
%left '*' '/' '%'
%left SEQ SNE SG SL SGE SLE
%left OR AND '>' '<' EQ NE GEQ LEQ
%nonassoc SNOT
%nonassoc SMENOS
%nonassoc SNNOT
%type <entero> expression
%%
entrada: statement
| entrada statement
;
statement: NL
| expression NL {printf("== %d \n",$1);}
| BYE NL {printf("Cerrando calculadora...\n");exit(0);}
;
expression: expression '+' expression {$$ = $1 + $3;}
| expression '-' expression {$$ = $1 - $3;}
| expression '*' expression {$$ = $1 * $3;}
| expression '/' expression
{
if($3 == 0.0)
yyerror("Division por cero\n");
else
$$ = $1 / $3;
}
| expression '%' expression
{
if($3 == 0.0)
yyerror("Division por cero\n");
else
$$ = $1 % $3;
}
| expression '^' expression {$$ = $1 ^ $3;}
| expression '|' expression {$$ = $1 | $3;}
| expression OR expression {$$ = $1 || $3;}
| expression '&' expression {$$ = $1 & $3;}
| expression AND expression {$$ = $1 && $3;}
| expression '>' expression {$$ = $1 > $3;}
| expression '<' expression {$$ = $1 < $3;}
| expression EQ expression {$$ = $1 == $3;}
| expression NE expression {$$ = $1 != $3;}
| expression GEQ expression {$$ = $1 >= $3;}
| expression LEQ expression {$$ = $1 <= $3;}
| CADENA SEQ CADENA
{
CharFlag=1;
if(strcmp($1,$3)==0)
$$ = 1;
else $$ = 0;
}
| CADENA SNE CADENA
{
CharFlag=1;
if(strcmp($1,$3)==0)
$$ = 0;
else $$ = 1;
}
| CADENA SG CADENA
{
CharFlag=1;
if(strcmp($1,$3)>0)
$$ = 0;
else $$ = 1;
}
| CADENA SL CADENA
{
CharFlag=1;
if(strcmp($1,$3)<0)
$$ = 0;
else $$ = 1;
}
| CADENA SGE CADENA
{
CharFlag=1;
if(strcmp($1,$3)>=0)
$$ = 0;
else $$ = 1;
}
| CADENA SLE CADENA
{
CharFlag=1;
if(strcmp($1,$3)<=0)
$$ = 0;
else $$ = 1;
}
| '!' expression %prec SNOT {$$ = !$2;}
| '-' expression %prec SMENOS {$$ = -$2;}
| '~' expression %prec SNNOT {$$ = ~$2;}
| '('expression')' {$$ = $2;}
| ENTERO
| CADENA
{
if (CharFlag==0)
$$ = strlen($1);
else{
$$ = $1;
CharFlag=0;
}
}
;
%%
main (){
printf("Parser de Expresiones variadas\n");
yyparse();
}
Para correr este parser :$ flex ejem2.l $ yacc -d ejem2.y $ cc -o ejem2 lex.yy.c y.tab.c -ly -ll -lm $ ejem2 Parser de Expresiones variadas 25+"hola" == 29 "hola"eq"helo" == 0 "hola"=="helo" == 1 "s"=="s" == 1 "hola"=="hole" == 1 12+23 == 35 bye Cerrando calculadora... Comentarios sobre este ParserSe usa la variable CharFlag para indicar que valor se usara cuando se tienen cadenas, ya sea su valor numerico (su longitud) o como cadena. |
|
Copyright © 2002 Oscar Medina Duarte |