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.
%{
/* 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*/
#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();
#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();
}
%{
/* 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*/
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"
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:
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