Tutorial de Lex & Yacc
Genreración de Parsers de Gramaticas Libres de Contexto.

Regístrate y participa en el foro: http://flex.chocoforum.com
www.medina-web.com

Índice :

Juntos Lex & Yacc

A continuacion se presenta un ejemplo mas complejo con explicación y algunas corridas del mismo.

Ejemplo 2

Descripción

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:
OpsDescripción
^ , | , & XOR , OR y AND bit por bit. (funcionan igual que en C)
+ , - Suma y Resta.
* , / , % Multiplicacion, Divición y Módulo.
eq , ne , gt , lt , ge , le Comparadores entre cadenas, 'igual que', 'diferente de', 'mayor que', 'menor que', 'mayor o igual que' y 'menor o igual que' respectivamente entre cadenas, estos operadores son analogos a las funciones de comparacion entre cadenas de la libreria "string.h" de C.
|| , && , > , < , == , != , >= , <= Comparadores y operadores logicos, OR , AND, 'mayor que', 'menor que', 'igual que', 'diferente de', 'mayor o igual que' y 'menor o igual que' respectivamente.
! Descripción
- Descripción
~ Descripción
Cuando se usan operadores numericos entre cadenas o mixtos, el valor tomado para las cadenas es la longitud de la misma, si se usan numeros con operadores de cadenas se genera un error de sintaxis.

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 lexer

Cuando 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 Parser

Se 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
Cualquier persona es libre de imprimir y reproducir este documento siempre y cuando esta nota permanezca en el documento.