Está en la página 1de 24

INSTITUTO POLITÉCNICO NACIONAL

Escuela Superior de Computo

Práctica no. 3 Análisis sintáctico


mediante YACC (yet another
compiler-compiler).

Compiladores

Autores:

Hernández Vergara, Eduardo

Rojas Cruz, José Ángel

Profesora:

Pescador Rojas, Miram

Noviembre de 2022
Índice

1. Introdución 2
1.1. Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2. Introducción teórica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1. Compiladores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.2. Modelo de análisis y síntesis de la compilación . . . . . . . . . . . . . . . 2
1.2.3. Análisis léxico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3. Yacc (Yet Another Compiler-Compiler) . . . . . . . . . . . . . . . . . . . . . . . 3
1.4. Especicaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5. Requerimientos de entrega de práctica . . . . . . . . . . . . . . . . . . . . . . . 4

2. Desarrollo Experimental 5
2.1. Programas a analizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.1. Palindromo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.2. Reconocimiento de grámatica . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.3. Binario a decimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2. Programas a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.1. Numero par . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.2. Binario a Hexadecimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.3. Números Capícuos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3. Código 13
3.1. Código a analizar (geeksforgeeks) . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2. Código Realizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

4. Conclusiones 22
4.1. Conclusiones Eduardo Hernández Vergara . . . . . . . . . . . . . . . . . . . . . 22
4.2. Conclusiones José Ángel Rojas Cruz . . . . . . . . . . . . . . . . . . . . . . . . 22

5. Referencias 23

1
1. Introdución

1.1. Objetivo
El alumno utilizará la biblioteca YACC (yet another compiler-compiler) para el proceso de
análisis sintáctico de un compilador.

1.2. Introducción teórica


1.2.1. Compiladores

A grandes rasgos, un compilador es un programa que lee un programa escrito en un lenguaje,


lenguaje fuente, y lo traduce a un programa equivalente en otro lenguaje, el lenguaje objeto.
Como parte importante de este proceso de traducción, el compilador informa a su usuario de
la presencia de errores en el programa fuente.

Figura 2: Un compilador

1.2.2. Modelo de análisis y síntesis de la compilación

En la compilación hay 2 partes: análisis y síntesis. La parte del analisis divide al programa
fuente en sus elementos componentes y crea una representación intermedia del programa fuente.
La parte de la síntesis construye el programa objeto deseado a partir de la representación
intermedia. Durante el análisis, se determinan las operaciones que implica el programa fuente
y se registran en una estructura jerárquica llamada árbol.

1.2.3. Análisis léxico

En un compilador, el análisis lineal se llama análisis léxico o exploración . Por ejemplo, en el


análisis léxico los caracteres de la proposición de asignacion
posición := inicial + velocidad * 60
Se agruparían en los componentes léxicos siguientes:

2
1. El identicador posición.
2. El símbolo de asignación :=.
3. El identicador inicial
4. El signo de suma
5. El identicador velocidad
6. El signo de multiplicacion
7. El número 60

Los espacios en blanco que separan los caracteres de estos componentes léxicos normalmente
se eliminan durante el análisis léxico.

1.3. Yacc (Yet Another Compiler-Compiler)


Yacc es un programa para generar analizadores sintácticos. Las siglas del nombre signican
Yet Another Compiler-Compiler, es decir, 'Otro generador de compiladores más'. Genera un
analizador sintáctico (la parte de un compilador que comprueba que la estructura del código
fuente se ajusta a la especicación sintáctica del lenguaje) basado en una gramática analítica
escrita en una notación similar a la BNF. Yacc genera el código para el analizador sintáctico
en el Lenguaje de programación C.
Fue desarrollado por Stephen C. Johnson en AT&T para el sistema operativo Unix. Después
se escribieron programas compatibles, por ejemplo Berkeley Yacc, GNU bison, MKS yacc y
Abraxas yacc (una versión actualizada de la versión original de AT&T que también es soft-
ware libre como parte del proyecto de OpenSolaris de Sun). Cada una ofrece mejoras leves y
características adicionales sobre el Yacc original, pero el concepto ha seguido siendo igual. Yacc
también se ha reescrito para otros lenguajes, incluyendo Ratfor, EFL, ML, Ada, Java, y Limbo.
Puesto que el analizador sintáctico generado por Yacc requiere un analizador léxico, se utiliza
a menudo conjuntamente con un generador de analizador léxico, en la mayoría de los casos lex o
Flex, alternativa del software libre. El estándar de IEEE POSIX P1003.2 dene la funcionalidad
y los requisitos a Lex y Yacc.

1.4. Especicaciones
Ingresar al siguiente enlace para conocer el uso y aplicación de la biblioteca YACC en lenguaje
C.
https://www.geeksforgeeks.org/introduction-to-yacc/?ref=rp

1. Analice los siguientes ejemplos:


a ) Lex program to check whether given string is Palindrome or Not: https://www.geeksforgeeks.org/
program-to-check-whether-given-string-is-palindrome-or-not/?ref=rp

3
b ) YACC program to recognize string with grammar (anbn >= 0): https://www.geeksforgeeks.org/y
program-to-recognize-string-with-grammar-anbn-n0/?ref=rp
c ) YACC program for Binary to Decimal Conversion: https://www.geeksforgeeks.org/yacc-

program-for-binary-to-decimal-conversion/?ref=rp
2. Programe lo siguiente:
a ) Reconocer cadenas binarias y aceptar aquellas que contengan un número par de 0's
o 1's
b ) Programar la conversión de binario a hexadecimal

c ) Buscar todos los números capicúas existentes entre el 0 y el 1000.

1.5. Requerimientos de entrega de práctica


La práctica será desarrollada en equipos de máximo 4 personas.
Se debe entregar un reporte que incluya lo siguiente:
ˆ Portada con los nombres de los integrantes del equipo(comenzando con apellidos)y
el grupo
Se entrega código fuente documentado con la implementación.
Deberá realizar una explicación de su programa en el laboratorio de clases.
La entrega es para el próximo viernes 30 de noviembre de 2022 a través de la plataforma
Teams.Solo lo envía uno de los integrantes del equipo.
Por cada día de retraso se descontará 10 % sobre la calicación nal de la práctica.

4
2. Desarrollo Experimental

2.1. Programas a analizar


En esta sección pondremos el código que se nos pidio analizar y lo explicaremos en la seccion
codigo, en esta seccion mostraremos los resultados:

2.1.1. Palindromo

En este código tenemos que ingresar una cadena y decir si es palindromo o no.

Figura 3: La ejecucion del programa de los palindromos

5
2.1.2. Reconocimiento de grámatica

En este código tenemos que ingresar una cadena y tenemos que encontrar que la cadena dada
cumpla con la gramatica de
an bn |n ≥ 0
.

Figura 4: La ejecucion del programa de las gramaticas a y b

6
2.1.3. Binario a decimal

En este código por medio de las reglas de produccion hacemos una conversión de una cadena
binaria a un número entero decimal:

Figura 5: La ejecucion del programa de la conversion de binario a decimal

7
2.2. Programas a realizar
En esta sección pondremos el código que se nos realizar:

2.2.1. Numero par

En este código tenemos que ingresar una cadena binaria y decir si la cadena tiene numero
par de ceros o numero par de unos, en caso de que sea verdadero se imprime en pantalla.

Figura 6: Obtenemos si una cadena tiene ceros pares o unos pares

8
2.2.2. Binario a Hexadecimal

En este código por medio de las reglas de produccion hacemos una conversión de una cadena
binaria a una cadena Hexadecimal:

Figura 7: La ejecucion del programa de la conversion de binario a hexadecimal

9
2.2.3. Números Capícuos

En este código realizamos una comparacion de n numeros capicuos y los almacenamos en un


archivo de texto:

Figura 8: Corremos el shell para poder correr el programa 1000 veces

10
Figura 9: Mostramos los capicuos Pt1

11
Figura 10: Mostramos los capicuos Pt2

12
3. Código

3.1. Código a analizar (geeksforgeeks)


Listing 1: Código Palindromos analizador léxico (lex)

1 %{
2 /* Definition section aqui ponemos las librerias que vamos a incluir
para que funcione nuestro c \ ' odigo , en este caso es la
3 entrada y salida de datos estandar y la libreria estandar , asi como
una libreria que se obtiene al compilar el archivo yacc
4 */
5 # include < stdio .h >
6 # include < stdlib .h >
7 # include " y . tab . h "
8 %}
9
10 /* %option noyywrap */
11
12 /* Rule Section Aqui definimos nuesto lenguaje , algo asi como el rejex
estandar */
13 %%
14
15 [a - zA - Z ]+ { yylval . f = yytext ; return STR ;}
16 [ -+() */] { return yytext [0];}
17 [ \ t ];
18 \ n { return 0; }
19 %%
20 // Aqui se pone la funcion yywrap para que jale
21 int yywrap ()
22 {
23 return -1;
24 }

Listing 2: Código Palindromos analizador sintactico (yacc)

1 %{
2 /* Definition section aqui ponemos las librerias que vamos a incluir
para que funcione nuestro c \ ' odigo y los prototipos asi como
inicializamos algunas variables */
3 # include < stdio .h >
4 # include < string .h >
5 # include < stdlib .h >
6 extern int yylex () ;
7
8 void yyerror ( char * msg ) ;
9 int flag ;
10
11 int i ;
12 int k =0;
13 %}
14 // Realizamos una union de chars para los strings
15 %union {
16 char * f ;
17 }
18 // Obtenemos el token STR del archivo lex
19 %token <f > STR
20 // Es el tipo E , para esto sirve la union de arriba

13
21 %type <f > E
22
23 /* Rule Section aqui es donde vamos a realizar las reglas de producci \ ' on
en este caso tenemos que una de nuestras de produccion es c \ ' odigo en
C */
24 %%
25
26 S : E {
27 flag = 0;
28 k = strlen ( $1 ) - 1;
29 for ( i = 0; i <= k /2; i ++) {
30 if ( $1 [ i ] != $1 [k - i ]) flag = 1;
31 }
32 if ( flag == 1) printf ( " Not palindrome \ n " ) ;
33 else printf ( " palindrome \ n " ) ;
34 printf ( " %s \ n " , $1 ) ;
35 }; // Aqui termina la regla de producci \ ' on que en este c \ ' odigo en C lo
que hace b \ ' asicamente ah \ ' i es recorrer un caracter de izquierda a
derecha
36 // y de derecha a izquierda y los compara , si son iguales simplemente
obtendriamos el palindromo , sino no es palindromo
37
38 E : STR { $$ = $1 ;}
39 // Esta regla de produccion obtiene el valor por el yyparcer
40 ;
41
42 %%
43 // Aqui nos devuelve si hay un error
44 void yyerror ( char * msg )
45 {
46 fprintf ( stderr , " %s \ n " , msg ) ;
47 exit (1) ;
48 }
49
50 // driver code aqui simplemente llamamos a la funci \ ' on yyparse
51 int main ()
52 {
53 yyparse () ;
54 return 0;
55 }

Listing 3: Código Reglas de produccion análisis léxico (lex)

1 %{
2 /* Definition section donde solamente incluimos la generada por el yacc */
3 # include " y . tab . h "
4 %}
5
6 /* Rule Section definimos nuestro lenguaje , donde tenemos q obtener a y b
*/
7 %%
8 [ aA ] { return A ;}
9 [ bB ] { return B ;}
10 \ n { return NL ;}
11 . { return yytext [0];}
12 %%
13 // El yywrap para que funcione
14 int yywrap ()
15 {
16 return 1;

14
17 }

Listing 4: Código Reglas de produccion análisis sintáctico (yacc)

1 %{
2 /* Definition section donde incluimos la libreria de datos estandar y la
de entrada salida */
3 # include < stdio .h >
4 # include < stdlib .h >
5 %}
6 // obtenemos nuestros tokens del lex , estos son A , B , NL
7 %token A B NL
8
9 /* Rule Section en estas reglas de produccion podemos ver que ahora no es
c \ ' odigo c tal cual por lo que */
10 %%
11 // Primero stmt puede tiene que ser S y NL o sea que tiene que irse a S
dar un salto de linea e imprimir valid string
12 stmt : S NL { printf ( " valid string \ n " ) ;
13 exit (0) ; }
14 ;
15 // Despues S tiene que ser A = A o a , B = B o b , y tiene que llamarse a si
mismo las veces que sea necesario por eso se llama S , o sea por eso
16 // Esta A S B , tambien acepta cadenas vacias
17 S: A S B |
18 ;
19 %%
20 // Es para los errores
21 int yyerror ( char * msg )
22 {
23 printf ( " invalid string \ n " ) ;
24 exit (0) ;
25 }
26
27 // driver code donde simplemente imprimimos una cadena y mandamos a llamar
al yyparse
28 main ()
29 {
30 printf ( " enter the string \ n " ) ;
31 yyparse () ;
32 }

Listing 5: Código Binario a Decimal (lex)

1 %{
2 /* Definition section donde importamos las librerias necesarias para el
desarrollo del proyecto */
3 # include < stdio .h >
4 # include < stdlib .h >
5 # include " y . tab . h "
6 extern int yylval ;
7 %}
8
9 /* Rule Section aqui tenemos lo que seria nuestros valores de nuestro
lenguaje */
10 %%
11 0 { yylval =0; return ZERO ;}
12 1 { yylval =1; return ONE ;}
13

15
14 [ \ t ] {;}
15 \ n return 0;
16 . return yytext [0];
17 %%
18
19 // El yywrap owo
20 int yywrap ()
21 {
22 return 1;
23 }

Listing 6: Código Binario a Decimal (yacc)

1 %{
2 /* Definition section donde ponemos prototipos y librerias */
3 # include < stdio .h >
4 # include < stdlib .h >
5 void yyerror ( char * s ) ;
6 %}
7 // Obtenemos nuestros tokens
8 %token ZERO ONE
9
10 /* Rule Section , estas reglas de produccion nos dicen si un numero es cero
o uno , ademas de que hace operaciones para convertir en binario
11 de manera q sea ' recursivo ', ya que primero se llama L a si mismo y
despues decide si simplemente obtener el valor del char pues , o
12 obtiene valor *2+ valor anterior , siendo que sea por ejemplo : 0011; B : ONE
, y despues se hace L : B , para tener el 1 y ahora seria nuestro
valor $2 , despues vuelve a ser llamado y ahora B : ONE , L : L B
es 2*1+1. y asi b \ ' asicamente ah \ ' i
13 */
14 %%
15 N : L { printf ( " \ n %d \ n " , $$ ) ;}
16 L : L B { $$ = $1 *2+ $2 ;}
17 | B { $$ = $1 ;}
18 B : ZERO { $$ = $1 ;}
19 | ONE { $$ = $1 ;};
20 %%
21
22 // driver code es llamado el yyparse de manera que solo se ejecute mientras
no se complete el programa .
23 int main ()
24 {
25 while ( yyparse () ) ;
26 }
27
28 yyerror ( char * s )
29 {
30 fprintf ( stdout , " \ n %s " , s ) ;
31 }

3.2. Código Realizado


Listing 7: Código numero par de ceros o unos (lex)

1 %{
2 // Realmente no hay mucho que explicar que no se haya explicado antes

16
3 /* Definition section */
4 # include < stdio .h >
5 # include < stdlib .h >
6 # include " y . tab . h "
7 %}
8
9 /* Rule Section */
10 %%
11
12 [0 -1]+ { yylval . f = yytext ; return STR ;}
13 [ \ t ];
14 \ n { return 0; }
15
16 %%
17
18
19 int yywrap ()
20 {
21 return 1;
22 }

Listing 8: Código numero par de ceros o unos (yacc)

1 %{
2 // Aqui lo unico que explicar es el c \ ' odigo en las reglas de producci \ '
on
3 /* Definition section */
4 # include < stdio .h >
5 # include < string .h >
6 # include < stdlib .h >
7 extern int yylex () ;
8
9 void yyerror ( char * msg ) ;
10 int flagC = 0 , flagU = 0;
11
12 int i ;
13 int k =0;
14 %}
15
16 %union {
17 char * f ;
18 }
19
20 %token <f > STR
21 %type <f > E
22
23 /* Rule Section */
24 %%
25 // Aqui obtenemos una cadena la recorremos y con ayuda de 2 contadores
obtenemos el numero total de ceros y de unos que hay , despues
simplemente se manda una estructura
26 // de control llamada if para comparar valores y decimos que si el modulo
2 de cualquiera de los 2 es cero se acepta la cadena
27 S : E {
28 k = strlen ( $1 ) - 1;
29 for ( i = 0; i <= k ; i ++) {
30 if ( $1 [ i ] == '0 ') flagC ++;
31 else flagU ++;
32 }
33 if (( flagC %2 ==0) || ( flagU %2 == 0) ) printf ( " Cadena Aceptada \ n " ) ;

17
34 else printf ( " No aceptada \ n " ) ;
35 printf ( " %s \ n " , $1 ) ;
36 }
37 ;
38
39 E : STR { $$ = $1 ;}
40 ;
41
42 %%
43
44 void yyerror ( char * msg )
45 {
46 fprintf ( stderr , " %s \ n " , msg ) ;
47 exit (1) ;
48 }
49
50 // driver code
51 int main ()
52 {
53 printf ( " Seleccione la cadena \ n " ) ;
54 yyparse () ;
55 printf ( " Fin del programa \ n " ) ;
56 return 0;
57 }

Listing 9: Código Binario a Hexadecimal (lex)

1 %{
2 /* Definition section donde importamos las librerias necesarias para el
desarrollo del proyecto */
3 # include < stdio .h >
4 # include < stdlib .h >
5 # include " y . tab . h "
6 extern int yylval ;
7 %}
8
9 /* Rule Section aqui tenemos lo que seria nuestros valores de nuestro
lenguaje */
10 %%
11 0 { yylval =0; return ZERO ;}
12 1 { yylval =1; return ONE ;}
13
14 [ \ t ] {;}
15 \ n return 0;
16 . return yytext [0];
17 %%
18
19 // El yywrap owo
20 int yywrap ()
21 {
22 return 1;
23 }

Listing 10: Código Binario a Hexadecimal (yacc)

1 %{
2 /* Definition section donde ponemos prototipos y librerias */
3 # include < stdio .h >
4 # include < stdlib .h >

18
5 void yyerror ( char * s ) ;
6 %}
7 // Obtenemos nuestros tokens
8 %token ZERO ONE
9
10 /* Rule Section , estas reglas de producci \ ' on son las mismas que las de
binario a decimal la unica diferencia es que imprimimos el tipo de
dato a Hexadecimal
11 */
12 %%
13 N : L { printf ( " \ n %X \ n " , $$ ) ;}
14 L : L B { $$ = $1 *2+ $2 ;}
15 | B { $$ = $1 ;}
16 B : ZERO { $$ = $1 ;}
17 | ONE { $$ = $1 ;};
18 %%
19
20 // driver code es llamado el yyparse de manera que solo se ejecute mientras
no se complete el programa .
21 int main ()
22 {
23 while ( yyparse () ) ;
24 }
25
26 yyerror ( char * s )
27 {
28 fprintf ( stdout , " \ n %s " , s ) ;
29 }

Listing 11: Código para números capicuos (lex)

1 %{
2 // Es el mismo que el de los palindromos solo que ahora es 0 -9 en vez de a
- zA - Z
3 /* Definition section */
4 # include < stdio .h >
5 # include < stdlib .h >
6 # include " y . tab . h "
7 %}
8
9 /* %option noyywrap */
10
11 /* Rule Section */
12 %%
13
14 [0 -9]+ { yylval . f = yytext ; return STR ;}
15 [ -+() */] { return yytext [0];}
16 [ \ t ];
17 \ n { return 0; }
18
19 %%
20
21 int yywrap ()
22 {
23 return -1;
24 }

Listing 12: Código para números capicuos (yacc)

1 %{

19
2 /* Definition section */
3 # include < stdio .h >
4 # include < string .h >
5 # include < stdlib .h >
6 extern int yylex () ;
7
8 void yyerror ( char * msg ) ;
9 int flag = 1;
10
11 int i ;
12 int n = 0 , k = 0;
13 %}
14
15 %union {
16 char * f ;
17 }
18
19 %token <f > STR
20 %type <f > E
21
22 /* Rule Section */
23 %%
24
25 S : E {
26 n = strlen ( $1 ) ;
27 k = n - 1;
28 for ( i = 0; i < n /2; i ++) {
29 if ( $1 [ i ] != $1 [k - i ])
30 flag = 0;
31 }
32 if ( flag )
33 printf ( " %s Es capicua \ n " , $1 ) ;
34 }
35 ;
36
37 E : STR { $$ = $1 ;}
38 ;
39
40 %%
41
42 void yyerror ( char * msg )
43 {
44 fprintf ( stderr , " %s \ n " , msg ) ;
45 exit (1) ;
46 }
47
48 // driver code
49 int main ()
50 {
51 // printf (" Seleccione el numero maximo que desea que sea el maximo de la
cadena : \ n ") ;
52 yyparse () ;
53 // printf (" Fin del programa \ n ") ;
54 return 0;
55 }

Listing 13: capicuos shell

1 # !/ bin / bash
2 # Primero borramos si es que hay un archivo para no sobreescribir

20
3 rm num_capicua . txt
4 # Despues enviamos el texto a un archivo num_capicua
5 echo " En numeros de uno al 1000 , estos son los numeros capicua : " >
num_capicua . txt
6 # corremos el programa 1000 veces y los resultados se almacenan en el
archivo num_capicua . txt
7 for i in {0..1000}
8 do
9 ./ capicua <<< $i >> num_capicua . txt
10 done

21
4. Conclusiones

4.1. Conclusiones Eduardo Hernández Vergara


En esta práctica pudimos ver de mejor manera lo que sería la importancia del análisis sin-
tactico, adémas de que a diferencia de la práctica anterior donde usabamos un lenguaje de
programación cualquiera, aqui usamos Yacc para poder hacer el analisis sintactico, ademas
lo complementamos con ex o lex, que nos sirve como analizador léxico para poder realizar
correctamente nuestro análisis.

4.2. Conclusiones José Ángel Rojas Cruz


Los compiladores permiten que a partir de un cierto lenguaje de programación seamos capaces
de ejecutar ordenes y comandos dentro de un dispositivo, esto a travez de un proceso donde
cada parte del programa escrito por el usuario es convertido en instrucciones que la maquina
puede procesar.

22
5. Referencias

Referencias

[1] Aho, A. (2008). Compiladores principios, técnicas y herramientas . Pearson Education In-
ternational.

23

También podría gustarte