PRACTICA 1

Esta práctica quiere conseguir:

ANALISIS LEXICO: LEX

Programa en lenguaje C -------------------------------------------------------------> Genera código de 3 direcciones

ANALISIS SINTACTICO: YACC



 

El estudio realizado se centra sobre las reglas del fichero pl95.y.

 

FICHERO DE ESPECIFICACIONES EN LEX: PL95.L


 

%{

/* SECCION DE DECLARACIONES */

#include "y.tab.h"

%}

%%


/* SECCION DE REGLAS: Cada regla se compone de 2 partes: un patrón y una acción separadas por un espacio en blanco. El lexer que genera Lex ejecutará la acción cuando reconozca el patrón de entre lo que toma de la entrada. */

 

{" { return '{';}

"}" { return '}';}

if { return IF; }

; { return ';'; }

"(" { return '('; }

")" { return ')'; }

else { return ELSE ;}

while { return WHILE;}

do { return DO;}

for { return FOR;}

"+" { return '+';}

- { return '-';}

"*" { return '*';}

"/" { return '/';}

"++" { return MASMAS;}

= { return ASIG;}

== { return IG;}

"<" { return '<';}

!= { return DIS;}

">" { return '>';}

&& { return AND;}

"||" { return OR;}

! { return NOT;}

"," { return ',';}

[\ \t] ;

0 ;

[1-9][0-9]* { strcpy(yylval.cod,yytext); return NUM;}

[a-zA-Z][a-zA-Z0-9]* { strcpy(yylval.cod,yytext); return IDENT; }

. { printf("caracter incorrecto");}

 


%%



/* SECCION DE RUTINAS DE USUARIO: Aquí se escribe cualquier código legal en C. El programa Lex copiará esta parte al final de fichero que genera. */



/* No hay ninguna rutina*/




FICHERO CON RUTINAS PARA PL95.Y: FUNC.H



 

#define TD_SUM 9

#define TD_RES 10

#define TD_MUL 11

#define TD_DIV 12

#define TD_IFM 13

#define TD_IFI 14

#define TD_GO 15

#define TD_LA 16

#define TD_MENU 17

#define TD_ASIG 19



int gc();

char *nuevatemp();

char *nuevaetiq();






FICHERO CON RUTINAS PARA PL95.Y: FUNC.C



 

#include "func.h"



int yyparse();



/* GC: Generador de código de tres direcciones. */



 

int gc(op,arg1,arg2,resul)

int op;

char arg1[32],arg2[32],resul[32];

{

switch (op)

{

case TD_SUM : printf("%s=%s+%s;\n",resul,arg1,arg2); break;

case TD_RES : printf("%s=%s-%s;\n",resul,arg1,arg2); break;

case TD_MUL : printf("%s=%s*%s;\n",resul,arg1,arg2); break;

case TD_DIV : printf("%s=%s/%s;\n",resul,arg1,arg2); break;

case TD_MENU: printf("%s=-%s;\n",resul,arg1); break;

case TD_ASIG : printf("%s=%s;\n",resul,arg1); break;

case TD_IFM : printf("if (%s < %s) goto %s;\n",arg1,arg2,resul); break;

case TD_IFI : printf("if (%s == %s) goto %s;\n",arg1,arg2,resul); break;

case TD_GO : printf("goto %s;\n",resul); break;

case TD_LA : printf("%s:\n",resul); break;

}

}



/* NUEVATEMP: Devuelve el nombre de una nueva variable temporal. */



 

char *nuevatemp()

{

static char salida[32];

static int indice=0;



++indice;

sprintf(salida,"temp%d",indice);

return salida;

}



/* NUEVAETIQUETA: Devuelve el nombre de una nueva etiqueta. */



 

char *nuevaetiq()

{

static char salida[32];

static int indice=0;



++indice;

sprintf(salida,"label%d",indice);

return salida;

}



/* MAIN: Se encarga de llamar a la rutina yyparse() hasta que se agota el fichero de entrada . */



 

main()

{

yyparse();

}


FICHERO DE ESPECIFICACIONES EN YACC: PL95.Y



%{

/* SECCION DE DECLARACIONES. */



 

#include "func.h"

 


%}



 

%union{

char cod[32];

struct {

char ini[32];

char fin[32];

} doblecod;

struct {

char ini[32];

char fin[32];

char sen[32];

char ex[32];

} cuatcod;

}

 

 

%type <cod> expr

%token PYC ELSE

%token <cod> NUM IDENT

%token <doblecod> IF WHILE DO

%token <cuatcod> FOR

%left ','

%right ASIG

%left <doblecod> OR

%left <doblecod> AND

%left <doblecod> NOT

%left IG DIS

%left '<' '>'

%left '+' '-'

%left '*' '/'

%right MASMAS

%right MENOSUNA

 


%%

/* SECCION DE REGLAS: Aquí se declara la gramática, sus reglas. */



/* Un programa consta de una lista de sentencias */



Prog: Lista_sent



;



Lista_sent: /*VACIO*/



| Lista_sent sent



;



sent: expr ';'



| IF '(' expr ')'

{

strcpy($1.ini,nuevaetiq());

strcpy($1.fin,nuevaetiq());

gc(TD_IFI,$3,"0",$1.ini);

}

sent {

gc(TD_GO,"","",$1.fin);

gc(TD_LA,"","",$1.ini);

}

parteelse

{

gc(TD_LA,"","",$1.fin);

}



| WHILE '('

{

strcpy($1.ini,nuevaetiq());

strcpy($1.fin,nuevaetiq());

gc(TD_LA,"","",$1.ini);

}

expr ')' {gc(TD_IFI,$4,"0",$1.fin);}

sent

{

gc(TD_GO,"","",$1.ini);

gc(TD_LA,"","",$1.fin);

}



| DO { strcpy($1.ini,nuevaetiq());

strcpy($1.fin,nuevaetiq());

gc(TD_LA,"","",$1.ini);

}

sent WHILE expr ';' {

gc(TD_IFI,$5,"0",$1.fin);

gc(TD_GO,"","",$1.ini);

gc(TD_LA,"","",$1.fin);

}



| FOR '(' expr ';' {

strcpy($1.ini,nuevaetiq());

strcpy($1.fin,nuevaetiq());

strcpy($1.sen,nuevaetiq());

strcpy($1.ex,nuevaetiq());

gc(TD_LA,"","",$1.ini);

}

expr ';' { gc(TD_IFI,$6,"0",$1.fin);

gc(TD_GO,"","",$1.sen);

gc(TD_LA,"","",$1.ex);

}

expr ')' { gc(TD_GO,"","",$1.ini);

gc(TD_LA,"","",$1.sen);

}

sent { gc(TD_GO,"","",$1.ex);

gc(TD_LA,"","",$1.fin);

}



| '{' Lista_sent '}'



;



parteelse: /*vacio*/



| ELSE sent



expr: NUM { strcpy($$,$1); }



| IDENT { strcpy($$,$1); }



| IDENT ASIG expr

{

gc(TD_ASIG,$3,"",$1);

strcpy($$,$1);

}



| expr '+' expr

{

strcpy($$,nuevatemp());

gc(TD_SUM,$1,$3,$$);

}



| expr '-' expr

{

strcpy($$,nuevatemp());

gc(TD_RES,$1,$3,$$);

}



| expr '*' expr

{

strcpy($$,nuevatemp());

gc(TD_MUL,$1,$3,$$);

}

| expr '/' expr

{

strcpy($$,nuevatemp());

gc(TD_DIV,$1,$3,$$);

}



| '-' expr %prec MENOSUNA

{

strcpy($$,nuevatemp());

gc(TD_MENU,$2,"",$$);

}



| MASMAS IDENT { gc(TD_SUM,$2,"1",$2);}



| IDENT MASMAS

{

strcpy($$,nuevatemp());

gc(TD_ASIG,$1,"",$$);

gc(TD_SUM,$1,"1",$1);

}



| expr '<' expr {

char fin[32];

strcpy($$,nuevatemp());

gc(TD_ASIG,"1","",$$);

strcpy(fin,nuevaetiq());

gc(TD_IFM,$1,$3,fin);

gc(TD_ASIG,"0","",$$);

gc(TD_LA,"","",fin);

}



| expr '>' expr {

char fin[32];

strcpy($$,nuevatemp());

gc(TD_ASIG,"1","",$$);

strcpy(fin,nuevaetiq());

gc(TD_IFM,$3,$1,fin);

gc(TD_ASIG,"0","",$$);

gc(TD_LA,"","",fin);

}



| expr IG expr {

char fin[32];

strcpy($$,nuevatemp());

gc(TD_ASIG,"1","",$$);

strcpy(fin,nuevaetiq());

gc(TD_IFI,$1,$3,fin);

gc(TD_ASIG,"0","",$$);

gc(TD_LA,"","",fin);

}



| expr DIS expr {

char fin[32];

strcpy($$,nuevatemp());

gc(TD_ASIG,"0","",$$);

strcpy(fin,nuevaetiq());

gc(TD_IFI,$1,$3,fin);

gc(TD_ASIG,"1","",$$);

gc(TD_LA,"","",fin);

}



| expr AND {

strcpy($2.ini,nuevatemp());

strcpy($2.fin,nuevaetiq());

gc(TD_ASIG,"0","",$2.ini);

gc(TD_IFI,$1,"0",$2.fin);

}

expr {

gc(TD_IFI,$4,"0",$2.fin);

gc(TD_ASIG,"1","",$2.ini);

gc(TD_LA,"","",$2.fin);

strcpy($$,$2.ini);

}



| expr OR {

strcpy($2.ini,nuevatemp());

strcpy($2.fin,nuevaetiq());

gc(TD_ASIG,"1","",$2.ini);-6++

gc(TD_IFI,$1,"1",$2.fin);

}

expr {

gc(TD_IFI,$4,"1",$2.fin);

gc(TD_ASIG,"0","",$2.ini);

gc(TD_LA,"","",$2.fin);

strcpy($$,$2.ini);

}



| NOT expr {

char fin[32];

strcpy($$,nuevatemp());

strcpy(fin,nuevaetiq());

gc(TD_ASIG,"1","",$$);

gc(TD_IFI,$2,"0",fin);

gc(TD_ASIG,$2,"0","",$$);

gc(TD_LA,"","",fin);

}



| '(' expr ')' { strcpy($$,$2); }



| expr ',' expr { strcpy($$,$3); }



;



%%


 

/* SECCION DE RUTINAS DE USUARIO. */


 

/*No hay rutinas*/


EXPLICACION DE LA CODIFICACION DE LAS ACCIONES

reglas de PL96.Y:



 

 

expr: NUM { strcpy($$,$1); } ® El no terminal expr devolverá

el valor que el token NUM tiene.

Hemos pasado la información de la

acción al símbolo de la regla.

| IDENT { strcpy($$,$1); } ® El no terminal expr tiene ahora

asociado el valor que el token IDENT tiene.

| IDENT ASIG expr ® Se reduce expr

{

gc(TD_ASIG,$3,"",$1); ® Ident = expr

strcpy($$,$1); ® En expr se copia el nombre del

} IDENT.



expr: expr IG expr {

char fin[32];

strcpy($$,nuevatemp()); ® Crea una temporal asociada al no

terminal expr. Por ejemplo "t1"

gc(TD_ASIG,"1","",$$); ® t1= 1

strcpy(fin,nuevaetiq()); ® Crea una nueva etiqueta que la mete

en la cadena "fin"

gc(TD_IFI,$1,$3,fin); ® if $1== $3 goto fin

gc(TD_ASIG,"0","",$$); ® t1 =0

gc(TD_LA,"","",fin); ® fin

}



expr: NOT expr {

char fin[32];

strcpy($$,nuevatemp()); ® Crea una temporal. "t1"

strcpy(fin,nuevaetiq()); ® Crea una etiqueta y la copia en la

cadena "fin"

gc(TD_ASIG,"1","",$$); ® t1 =1

gc(TD_IFI,$2,"0",fin); ® if $2 == 0 goto fin

gc(TD_ASIG,"0","",$$); ® t1=0

gc(TD_LA,"","",fin); ® fin

}



/* Solo es necesario que una de las dos expresiones sea cierta*/



expr: expr1 OR {

strcpy($2.ini,nuevatemp()); ® Copiará en la cadena $2.ini una

nueva temporal. Pej: "t1"

strcpy($2.fin,nuevaetiq()); ® Copiará en la cadena $2.fin una

nueva etiqueta. Pej: "l1"

gc(TD_ASIG,"1","",$2.ini); ® t1 = 1

gc(TD_IFI,$1,"1",$2.fin); ® if expr1== 1 goto l1

}

expr2 {

gc(TD_IFI,$4,"1",$2.fin); ® if expr2 == 1 goto l1

gc(TD_ASIG,"0","",$2.ini); ® t1 = 0

gc(TD_LA,"","",$2.fin); ® l1

strcpy($$,$2.ini); ® Al no terminal expr se le pasa

} la temporal "t1"

 



 

EJEMPLO:


 

 

k=5 ® expr: IDENT ASIG expr1 ® k= 5 (y copiamos en la cadena expr la "k")

DO ® l1:

a= k-1; ® t1 = k -1

WHILE k>0; ® t2 = 1

if 0 < k goto fin

t2 = 0

fin:

® if t2 = = 0 goto l2

® goto l1

® l2:


FICHERO MAKEFILE:


 

 

YACC = yacc -d

LEX = lex

CC = cc



OBJS = y.tab.o lex.yy.o func.o



p: $(OBJS)

$(CC) -g $(OBJS) -o p -ll -ly



y.tab.c y.tab.h: p.y func.h

$(YACC) p.y

lex.yy.c: p.l y.tab.h

$(LEX) p.l

 

.c.o:

$(CC) -c -g $*.c



touch:

touch p.l p.y func.c

< atras  incio

Hosted by www.Geocities.ws

1