actividades unidad2 automatas ii

79
TECNOLÓGICO NACIONAL DE MÉXICO INSTITUTO TECNOLOGICO DE ACAPULCO “Educación Tecnológica con compromiso social” Ingeniería en Sistemas Computacionales Carrera Lenguajes y autómatas II Asignatura Actividades de aprendizaje Unidad 2Generación de código intermedio Competencia específica a desarrollar Aplicar las herramientas para desarrollar una máquina virtual que ejecute código intermedio a partir del código fuente de un lenguaje prototipo. Profesor: Silvestre Bedolla Solano. Integrantes del equipo 7 Alumnos: Jimenez Gonzalez Alam Emmanuel 10320978 Hidalgo Sánchez Teresita 11320155 1

Upload: alejandro-magno-santana

Post on 11-Jul-2016

237 views

Category:

Documents


12 download

DESCRIPTION

unidad 2 de la materia automatas 2 de la carrera ing. en sistemas computacionales

TRANSCRIPT

Page 1: ACTIVIDADES UNIDAD2 AUTOMATAS II

TECNOLÓGICO NACIONAL DE MÉXICOINSTITUTO TECNOLOGICO DE ACAPULCO

“Educación Tecnológica con compromiso social”

Ingeniería en Sistemas ComputacionalesCarrera

Lenguajes y autómatas IIAsignatura

Actividades de aprendizajeUnidad 2Generación de código intermedio

Competencia específica a desarrollarAplicar las herramientas para desarrollar una máquina virtual que ejecute código

intermedio a partir del código fuente de un lenguaje prototipo.

Profesor: Silvestre Bedolla Solano.

Integrantes del equipo 7

Alumnos:

Jimenez Gonzalez Alam Emmanuel 10320978Hidalgo Sánchez Teresita Berenice 11320155Arancibia García Ángel Andrés 10320918

Acapulco, Guerrero, 6 de Diciembre del 2015

1

Page 2: ACTIVIDADES UNIDAD2 AUTOMATAS II

Contenido

Introducción....................................................................................................................................3

Actividad 1: Reporte de la aplicación de los tipos de notación para la conversión de expresiones: Infija, prefija y posfija, como resultado de su ejecución en un programa diseñado en C#.............................................................................................................................6

Actividad 2: Reporte de la aplicación del manejo de tipos en las expresiones y el uso de operadores...................................................................................................................................13

Actividad 3: Código intermedio de la estructura de un lenguaje de programación de alto nivel...............................................................................................................................................14

Actividad 4: Lenguaje prototipo aplicando las acciones construidas a la gramática.........27

Actividad 5: Tres programas tipo, usando la gramática definida de su lenguaje de programación...............................................................................................................................37

Actividad 6: Reporte del avance por equipo del proyecto final consistente en desarrollar software de base: traductor, intérprete o compilador.............................................................46

Conclusión....................................................................................................................................63

Bibliografías.................................................................................................................................64

2

Page 3: ACTIVIDADES UNIDAD2 AUTOMATAS II

Introducción

Generación de código intermedio

• El objetivo del código intermedio es reducir el número de programas necesarios para construir traductores, y permitir más fácilmente la transportabilidad de unas máquinas a otras.

• Después de los análisis sintáctico y semántico, algunos compiladores generan una representación intermedia explicita del programa fuente. Esta representación intermedia debe tener dos propiedades importantes; debe ser fácil de producir y fácil de traducir al programa objeto.

Lenguajes intermedios

Un lenguaje intermedio es el lenguaje de una máquina abstracta diseñada para ayudar en el análisis de los programas de computadora. el término viene de su uso en los compiladores, donde un compilador primero traduce el código fuente de un programa, en una forma más apropiada para las transformaciones de mejora del código (forma usualmente llamada bytecode), como un paso intermedio antes de generar el archivo objeto o el código máquina para una máquina específica.

Características destacadas:

Su principal ventaja es la portabilidad, pues el mismo código puede ser ejecutado en diferentes plataformas y arquitecturas.

Esta ventaja la tiene también los lenguajes interpretados, aunque generalmente con mejor rendimiento. Por esto, muchos lenguajes interpretados se compilan a bytecode y después son ejecutados por un intérprete de bytecode.

en java generalmente se transmite el bytecode a la máquina receptora y esta se encarga de utilizar un compilador just-in-time para traducirlo a código máquina antes de su ejecución.

Tipos de lenguaje intermedio

Hay tres tipos de lenguaje intermedio los cuales son:

Tipo 1

Es una representación más abstracta y uniforme que un lenguaje máquina concreto. Su misión es descomponer las expresiones complejas en binarias y las sentencias complejas en sentencias simples.

3

Page 4: ACTIVIDADES UNIDAD2 AUTOMATAS II

Ventajas:

• permite una fase de análisis (análisis semántico) independiente de la máquina.

*bytecode: código intermedio entre el código fuente y el código máquina. suele tratárselo como un fichero binario que contiene un programa ejecutable similar a un módulo objeto.

• Se pueden realizar optimizaciones sobre el código intermedio (las complejas rutinas de optimización son independientes de la máquina.

Desventajas:

• perdida de eficiencia (no permite una compilación de una sola pasada).

• introduce en el compilador una nueva fase de traducción.

Tipo 2

Tipo de lenguajes intermedios:

• Árbol sintáctico.

• Árbol sintáctico abstracto (todos los nodos del árbol representan símbolos terminales, los nodos hijos son operandos y los nodos internos son operadores).

• Grafo dirigido a cíclico (gda).

• Notación posfija.

Tipo 3

• Tripelatas

Ejemplo:

d = a + b * c [1] (*, b, c) [2] (+, a, [1]) [3] (=, d, [2]) <operador>,<operando_1>, <operando_2>

4

Page 5: ACTIVIDADES UNIDAD2 AUTOMATAS II

• Cuartetos

Ejemplo:

d = a + b * c (*, b, c, temp1) (+, a, temp1, temp2) (=, temp2, ², d)

• Los lenguajes intermedios nos sirven para representar la producción final de nuestro lenguaje fuente.

• existen muchos lenguajes intermedios, la mayoría de ellos son una representación más simplificada del código original para facilitar la traducción hacia el código final.

• Por ejemplo al compilar un programa en c en windows o dos, se produce un código objeto con extensión .obj para que posteriormente el enlazador cree finalmente el código executable .exe

• En sistemas basados en unix, también ocurre algo similar generándose un archivo .o y el executablea.out

• Otros lenguajes intermedios famosos son los generados para la máquina virtual de java el bytecode; y para la máquina virtual de .net el misl para luego ejecutarse en tiempo de ejecución jit (just in time).

Actividad 1: Reporte de la aplicación de los tipos de notación para la conversión de expresiones: Infija, prefija y posfija, como resultado de su ejecución en un programa diseñado en C#.

5

Page 6: ACTIVIDADES UNIDAD2 AUTOMATAS II

Expresiones infijas, prefija, posfija

• PreFija:

La Expresión o Notación PreFija nos indica que el operador va antes de los operandos sus características principales son:

-Los operandos conservan el mismo orden que la notación infija equivalente.

-No requiere de paréntesis para indicar el orden de precedencia de operadores ya que el es una operación.

-Se evalúa de izquierda a derecha hasta que encontrémosle primer operador seguido inmediatamente de un par de operandos.

-Se evalúa la expresión binaria y el resultado se cambia como un nuevo operando. Se repite este hasta que nos quede un solo resultado.

Notación prefija: El orden es operador, primer operando, segundo operando

• InFija:

La Expresión o Notación InFija es la forma más común que utilizamos para escribir expresiones matemáticas, estas notaciones se refiere a que el operador esta entre los operandos. La notación infija puede estar completamente patentizada o puede basarse en un esquema de precedencia de operadores así como el uso de paréntesis para invalidar los arreglos al expresar el orden de evaluación de una expresión:

3*4=12

3*4+2=14

3*(4+2)=18

Notación infija: La notación habitual. El orden es primer operando, operador, segundo operando.

• PosFija:

Como su nombre lo indica se refiere a que el operador ocupa la posición después de los operandos sus características principales son:

-El orden de los operandos se conserva igual que la expresión infija equivalente no utiliza paréntesis ya que no es una operación ambigua.

6

Page 7: ACTIVIDADES UNIDAD2 AUTOMATAS II

-La operación posfija no es exactamente lo inverso a la operación prefija equivalente:

(A+B)*C AB+C*

Notación postfija: El orden es primer operando, segundo operando, operador.

Ejemplo:

Si deseamos representar las expresiones (2+(3*4)) = x y ((2+3)*4)= x en las tres notaciones mencionadas, el resultado sería:

(2+(3*4)) = x ((2+3)*4) = x

Notación prefija = + 2 * 3 4 x = * + 2 3 4 x

Notación infija 2+3*4 = x (2+3)*4 = x

Notación posfija 2 3 4 * + x = 2 3 + 4 * x =

Desarrollo

Código

Conversión de expresiones infija a posfija

#include <stdio.h>

bool isOperator(char c){if (c=='+' || c=='-' || c=='*' || c=='/' || c=='^' || c=='(' || c==')')return true;return false;}int precedencia (char x, char y){int prec1, prec2;

switch(x){case '+':prec1=1;break;

case '-':

7

Page 8: ACTIVIDADES UNIDAD2 AUTOMATAS II

prec1=2;break;

case '*':prec1=3;break;

case '/':prec1=4;break;

case '^':prec1=5;}

switch(y){case '+':prec2=1;break;

case '-':prec2=2;break;

case '*':prec2=3;break;

case '/':prec2=4;break;

case '^':prec2=5;}

return prec1-prec2;}

int main(){char *inf = new char[401];char *post = new char[401];

8

Page 9: ACTIVIDADES UNIDAD2 AUTOMATAS II

char *pila = new char[200];int ptr=0;

int n, j=0;

scanf("%d", &n);

while(n>0){scanf("%s", inf);

for(int i=0; inf[i]!='\0'; i++){if (!isOperator(inf[i])){post[j]=inf[i];j++;}else if (inf[i]=='('){pila[++ptr]='(';}else if (inf[i]==')'){while(pila[ptr]!='(' && ptr>0){post[j]=pila[ptr--];j++;}if (pila[ptr]=='(')ptr--;}else{while(precedencia(inf[i], pila[ptr]) < 0 && pila[ptr]!='(' && ptr>0){post[j]=pila[ptr--];j++;}pila[++ptr]=inf[i];}

}while(ptr>0)

9

Page 10: ACTIVIDADES UNIDAD2 AUTOMATAS II

{post[j]=pila[ptr--];j++;}post[j]='\0';printf("%s\n", post);j=0;ptr=0;n--;}return 0;}}

Pantallazos

Ejemplo: conversión de expresiones infijas a posfija

Entrada de expresiones infijas:

3 números de elementos que se desean consultar

(a+(b*c))

((a+b)*(z+x))

((a+t)*((b+(a+c))^(c+d)))

Salida de expresiones posfijas:

abc*+

ab+zx+*

at+bac++cd+^*

10

Page 11: ACTIVIDADES UNIDAD2 AUTOMATAS II

Conclusiones

Para concluir tenemos que las pilas las listas enlazadas, todos sus métodos y las diferentes expresiones son una de las herramientas utilizadas para programar y procesar de una manera automatizada todos los sistemas que usamos día tras día en relación a técnicas o métodos para agilizar operaciones. Estas herramientas son uno de los instrumentos más usados en la programación para estructurar y organizar información.

Bibliografía

http://www.monografias.com/trabajos44/pilas-listas-expresiones/pilas-listas-expresiones2.shtml#ixzz3nXiPGmfk

http://www.lawebdelprogramador.com/foros/Dev-C/724318-Transformar-notacion-i

11

Page 12: ACTIVIDADES UNIDAD2 AUTOMATAS II

Actividad 2: Reporte de la aplicación del manejo de tipos en las expresiones y el uso de operadores.

Introducción

Expresiones

Una expresión es una combinación de operadores y operando. Los datos u operando pueden ser constantes, variables y llamadas a funciones. Además, dentro de una expresión pueden encontrarse subexpresiones encerradas entre paréntesis. Por ejemplo, la siguiente expresión matemática:

( 3) cos( ) 2

x + b − ⋅ αCuando se ejecuta una sentencia de código que contiene una expresión, ésta se evalúa. Al evaluarse la expresión toma un valor que depende del valor asignado previamente a las variables, las constantes y los operadores y funciones utilizadas y la secuencia de la ejecución de las operaciones correspondientes. Este valor resultante de la evaluación de la expresión será de un determinado tipo de dato. Por ejemplo, de un tipo numérico entero (integer, shortint…), de un tipo real o de un tipo lógico o booleano.

Operadores

En el código fuente de un programa un operador es un carácter o una secuencia de caracteres. Por ejemplo: +, *, div o shr. Los operadores definen las operaciones que van a realizarse con los datos u operando. En TurboPascal existen distintos tipos de operadores. Por un lado, pueden clasificarse, dependiendo del número de operando, en unarios o unitarios (un operando) y binarios (dos operandos). Por otro lado, pueden clasificarse, dependiendo del tipo de operando y de su resultado, en operadores aritméticos, de cadenas de caracteres, de relación, lógicos o booleanos, de bit y de conjuntos. Algunos operadores están sobrecargados, lo que significa que la operación que representan depende del número o tipos de operando sobre los que actúa. De esta forma, por ejemplo el operador + puede hacer referencia a la suma de valores numéricos, a la concatenación de caracteres o a la unión de conjuntos dependiendo del tipo de sus operando.

Desarrollo

12

Page 13: ACTIVIDADES UNIDAD2 AUTOMATAS II

Operador de asignación

El operador de asignación se representa por la secuencia de caracteres:=. Permite asignar a una variable el valor de una expresión. Por ejemplo:

var x,y,z: real;Beginx:=12.5;y:=-5.7;z:=2*x+3*y;

Operadores aritméticos

Los operadores aritméticos operan sobre valores de tipo entero o real. Los operadores aritméticos se resumen en la Tabla 12. En el caso del operador unitario de cambio de signo, el resultado es del mismo tipo que el del operando; en el caso de los tres primeros operadores binarios (suma, resta y producto) si ambos operandos son enteros el resultado es entero, si alguno es real el resultado es real. Con el fin de mantener la coherencia durante la operación, para un operador binario, operandos con distinto tipo se convierten a un mismo tipo común antes de la operación. El tipo común es el tipo de dato predefinido de TurboPascal con el menor intervalo de representación que incluye los valores de ambos operandos. Un concepto equivalente sería el de mínimo común múltiplo.

Por ejemplo, el tipo común de dos tipos byte e integer es el tipo integer. El tipo común de dos tipos integer y word es un longint. El tipo común de dos tipos integer y real es un real. La operación se lleva a cabo dentro del intervalo de representación y con la precisión de este tipo común y el resultado es también de este tipo común.

Operadores de relación

Los operadores de relación son operadores binarios en los que los operandos son ordinales, reales o de cadena. Los dos primeros operadores sirven también para

13

Page 14: ACTIVIDADES UNIDAD2 AUTOMATAS II

operandos de tipo record y punteros. Todos ellos dan lugar a resultados de tipo booleano. Losoperadores de relación se resumen en la Tabla 13.

No hay que confundir el operador lógico igualdad =, con el operador de asignación:=, que asigna valores a variables o funciones. La expresión a=b compara los valores almacenados en la variables a y b y devuelve true o false según el resultado, mientras que la sentencia a:=b; asigna a la variable a el valor almacenado en la variable b.

Operadores lógicos o booleanos

Los operadores lógicos o booleanos realizan operaciones con operandos de tipo lógico o booleano y tiene como resultado un dato también del mismo tipo. Los operadores booleanos definidos en TurboPascal se resumen en la Tabla:

14

Page 15: ACTIVIDADES UNIDAD2 AUTOMATAS II

Niveles de prioridad de los operadores

Una expresión puede contener distintos tipo de operadores mientras cada operador trabaje con operandos del tipo adecuado. La pregunta que surge a continuación es: ¿qué operación de las que se pueda encontrar en una expresión se realiza antes que las demás? Los niveles de prioridad entre operadores en una misma expresión se resumen en la Tabla 16.

Las secuencias de operadores de igual prioridad normalmente se evalúan de izquierdaa derecha dentro de una expresión, aunque, en algunos casos, el compilador puede reordenar los operandos durante el proceso de compilación para generar código objeto óptimo para su posterior ejecución. En muchas ocasiones se recomienda el uso de los paréntesis para hacer que las expresiones sean más claras y fáciles de entender. En la Tabla 17 se muestran algunos ejemplos de expresiones y de los correspondientes resultados al ser evaluadas.

Las reglas de evaluación de expresiones pueden resumirse en las siguientes:

a) Un operando situado entre dos operadores de diferente prioridad se liga al operador de mayor prioridad.

b) Un operando situado entre dos operadores de igual prioridad se liga al operador de la izquierda.

c) Las expresiones entre paréntesis se evalúan primeramente para ser tratadas como operandos simples.

15

Page 16: ACTIVIDADES UNIDAD2 AUTOMATAS II

Conclusión

En este tema se presentan los siguientes elementos de la programación: las expresiones y los operadores. Se define el concepto de expresión y se continúa con el estudio de los distintos tipos de operadores: aritmético, de relación, boléanos y de bit. En el apartado final se analizan las reglas de prioridad de los operadores que se siguen en la evaluación de expresiones de todo tipo. Una expresión es una combinación de operadores y operandos. Los datos u operandos pueden ser constantes, variables y llamadas a funciones. Además, dentro de una expresión pueden encontrarse subexpresiones encerradas entre paréntesis.

Bibliografías

García-Beltrán, A., Martínez, R. y Jaén, J.A. Métodos Informáticos en TurboPascal, Ed.Bellisco, 2ª edición, Madrid, 2002

Joyanes, L. Fundamentos de programación, Algoritmos y Estructuras de Datos, McGrawHill, Segunda edición, 1996

Duntemann, J. La Biblia de TurboPascal, Anaya Multimedia, Madrid, 1991

16

Page 17: ACTIVIDADES UNIDAD2 AUTOMATAS II

Actividad 3: Código intermedio de la estructura de un lenguaje de programación de alto nivel.

Código intermedio

Existen códigos intermedios de diversos tipos que varían en cuanto a su sencillez, lo próximos que están a las maquinas reales y lo fácil que es trabajar con ellos. Nosotros nos centraremos en un tipo de código que se parece bastante al lenguaje ensamblador. Existen otros tipos de código intermedio que representan los programas como árboles o grafos. También existen representaciones mixtas que combinan grafos o árboles y representaciones lineales.

El formato que usaremos para las operaciones binarias es similar al del ensamblador MIPS:

Op dst, op1, op2, donde:

* op es un operador.

*dst es el registro destino de la operación.

*op1 y op2 son los operandos. Si op termina en i, el segundo operando es un valor inmediato

(Entero o real).

En caso de que el operador sea unario, la forma de la instrucción es op dst, op1. Para acceder

A memoria utilizaremos instrucciones de acceso a memoria usando un registro base y un desplazamiento. Para leer de memoria utilizamos lw dst, desp (base) donde dst es el registro destino, desp es un entero que representa el desplazamiento y base es el registro base. Si queremos acceder a una dirección absoluta, utilizamos $zero como registro base, aprovechando que este registro siempre contiene el valor 0. Para escribir en memoria utilizamos sw fnt, desp (base) donde fnt es el registro fuente y el resto tiene el mismo significado que antes.

17

Page 18: ACTIVIDADES UNIDAD2 AUTOMATAS II

Por ejemplo, la sentencia a:= b*(-c), donde a es una variable local en la dirección 1 respecto al registro $fp y b y c son variables globales en las direcciones 1000 y 1001, se puede traducir como:

Lw $r1, 1000($zero)

lw $r2, 1001($zero)

multi $r3, $r2, -1

mult $r4, $r1, $r3

sw $r4, 1($fp)

Uno de los objetivos que suele perseguirse es reducir al mínimo el número de registros utilizados.

En nuestro caso, podemos emplear dos:

lw $r1, 1000($zero)

lw $r2, 1001($zero)

multi $r2, $r2, -1

mult $r1, $r1, $r2

sw $r1, 1($fp)

Si las variables estuvieran en los registros $r1, $r2 y $r3, podríamos incluso no utilizar ningún registro auxiliar:

multi $r1, $r3, -1

mult $r1, $r2, $r1

18

Page 19: ACTIVIDADES UNIDAD2 AUTOMATAS II

También tendremos instrucciones para controlar el flujo de ejecución, para gestionar entrada salida, etc. A lo largo del tema iremos viendo esas instrucciones según las vayamos necesitando.

Generación de código para expresiones.

Empezaremos por generar código para las expresiones. Asumiremos que para gestionar el código disponemos de una función auxiliar, emite. Esta función recibe una cadena que representa una línea de código intermedio y hace lo necesario para que termine en el programa final; por ejemplo, puede escribirla en un fichero, almacenarla en una lista para pasarla a otro modulo, etc.

Expresiones aritméticas

Comenzamos el estudio por las expresiones aritméticas. Lo que tendremos que hacer es crear por cada tipo de nodo un método, genera Código, que genere el código para calcular la expresión y lo emita. Ese código dejar ‘a el resultado en un registro, cuyo nombre devolver ‘a genera Código como resultado.

Para reservar estos registros temporales, utilizaremos una función, reservaRegistro. En principio bastara con que esta función devuelva un registro distinto cada vez que se la llame. Cada nodo generara el código de la siguiente manera:

• Por cada uno de sus operandos, llamara al método correspondiente para que se evalúe la sub expresión.

• Si es necesario, reservara un registro para guardar su resultado.

• Emitirá las instrucciones necesarias para realizar el cálculo a partir de los operandos.

Con este esquema, la generación del código para una suma será:

Objeto Nodo Suma:

. . .

19

Page 20: ACTIVIDADES UNIDAD2 AUTOMATAS II

Método generaCódigo ()

izda:= i.generaCódigo ();

dcha:= d.generaCódigo ();

r =reserva Registro ();

emite (add r, izda, dcha);

devuelve r;

fin genera Código

. . .

fin Nodo Suma

En el caso de los operadores unarios, bastara con reservar un registro y hacer la correspondiente operación.

Ejercicio 1

[Escribe el método de generación de código para el operador unario de cambio de signo.]

La generación de código para constantes se limita a almacenar el valor en un registro:

Objeto Nodo Constante:

. . .

Método generaCódigo ()

r :=reserva Registro ();

emite (addi r, $zero, valor);

devuelve r;

20

Page 21: ACTIVIDADES UNIDAD2 AUTOMATAS II

fin generaCódigo

. . .

fin Nodo Constante

Para las variables, tendremos que distinguir según si son locales o globales y acceder a la dirección correspondiente. Las variables globales tendrán una dirección absoluta a la que accederemos utilizando el registro $zero como base y las variables locales y parámetros de las funciones tendrán una dirección relativa al registro $fp (frame pointer):

Objeto NodoAccesoVariable:

. . .

Método generaCódigo()

r :=reserva Registro();

if eslocal entonces

emite(lw r, dir($fp) );

si no

emite(lw r, dir($zero) );

fin si

devuelve r;

fin generaCódigo

. . .

fin NodoVariableGlobal

21

Page 22: ACTIVIDADES UNIDAD2 AUTOMATAS II

Observa que asumimos que las variables están en memoria y no permanentemente en registros. Esto no es óptimo, pero nos permite presentar un método de generación razonablemente sencillo.

Por ejemplo, vamos a traducir la expresión (a+2)*(b+c). Si suponemos que las variables están en las direcciones 1000, 1001 y 1002, respectivamente, el código que se generara es:

lw $r1, 1000($zero)

addi $r2, $zero, 2

add $r3, $r1, $r2

lw $r4, 1001($zero)

lw $r5, 1002($zero)

add $r6, $r4, $r5

mult $r7, $r3, $r6

Es bueno intentar reducir el número de registros utilizados. Por ejemplo, al llamar a una función, hay que guardar en la trama de activación todos los registros activos en ese punto. Por eso, será bueno intentar “reutilizar” los registros y tener el mínimo número de ellos ocupados. Si vamos a tener una fase de optimización, no hace falta ocuparse ahora de esta cuestión. Si no tenemos un optimizador, podemos utilizar una estrategia sencilla que reduce bastante el número de registros empleados. La idea es tener también una función liberaRegistro que marca un registro como disponible para una nueva llamada de reservaRegistro. Para implementarlas, podemos tener una lista de registros activos y otra de registros libres. La llamada a reservaRegistro devuelve un elemento de la lista de registros libres, si no está vacía, o crea un nuevo registro si lo está. La llamada a liberaRegistro mueve el registro a la lista de registros libres. La lista de registros activos se emplea, por ejemplo, para saber que registros hay que guardar en las llamadas a función.

22

Page 23: ACTIVIDADES UNIDAD2 AUTOMATAS II

Siguiendo esta idea, el no do de la suma sería:

Objeto NodoSuma:

. . .

Método generaCódigo()

izda:= i.generaCódigo();

dcha:= d.generaCódigo();

emite(add r, izda, dcha);

liberaRegistro(dcha);

devuelve izda;

fin generaCódigo

. . .

fin NodoSuma

Para (a+2)*(b+c) se generaría:

lw $r1, 1000($zero)

addi $r2, $zero, 2

add $r1, $r1, $r2

lw $r2, 1001($zero)

lw $r3, 1002($zero)

add $r2, $r2, $r3

mult $r1, $r1, $r2

En el caso de los unarios, directamente reutilizaremos el registro correspondiente al operando.

23

Page 24: ACTIVIDADES UNIDAD2 AUTOMATAS II

Actividad 4: Lenguaje prototipo aplicando las acciones construidas a la gramática.

La sintaxis de un lenguaje de programación describe la forma correcta en la cual las sentencias, expresiones y unidades de programa se deben escribir, mientras que la semántica denota el significado de esas sentencias, expresiones y unidades de programa. Por ejemplo la sintaxis de una sentencia Pascal if then es:

if <condición> then <sentencia>

La semántica de esta sentencia es que si el valor actual de la condición es verdadero, se ejecutará <sentencia>.

Describir sintaxis es más fácil que describir semántica, ya que existen notaciones aceptadas universalmente para la descripción de sintaxis y no así de semánticas.

En la definición de un lenguaje de programación la sintaxis usualmente se expresa en BNF (Backus- Naur Form) y la semántica está expresada en lenguaje natural (español, inglés, etc.).

BNF es un ejemplo de un metalenguaje, es decir, un lenguaje usado para definir otros lenguajes. Algol 60 fue el primer lenguaje que utilizó BNF para su descripción sintáctica.

Una gramática consiste de un conjunto de no-terminales, terminales y una serie de reglas de producción. Un no-terminal está definido en una regla de producción, mientras que un terminal es un símbolo del lenguaje que se está definiendo. En una regla de producción el no-terminal (que aparece en la parte izquierda) está definido en términos de una secuencia de no-terminales y terminales (que se encuentran en la parte derecha)

Ejemplo:

24

Page 25: ACTIVIDADES UNIDAD2 AUTOMATAS II

<dígito>::= 0|1|2|3|4|5|6|7|8|9

<letra>::= a|b|c……………|x|y|z

<identificador>::=<letra>|<identificador><dígito>|<identificador><letra>

En BNF, un no-terminal se escribe entre <>, el símbolo ::= significa “se define como” y el símbolo “|” significa “o”.

Estas reglas definen <dígitos> como uno de los símbolos 0, 1 al 9; <letra> como una letra minúscula e <identificador> se define como una única letra, un identificador seguido de una letra o un identificador seguido de un dígito.

Así, el identificador “ab1” puede ser derivado de <identificador>como sigue:

<identificador>

<identificador><dígito>

<identificador><letra>><dígito>

<letra><letra><dígito> a <letra><dígito> a b <dígito>

a b 1

En cada etapa, el no-terminal de más a la izquierda es reemplazado por la parte derecha de una de sus reglas de producción, la secuencia de terminales y no-terminales producidos en cada etapa en una derivación se conoce como formas sentenciales. La forma sentencia final (que ya no contiene símbolos no-terminales) se conoce como una sentencia.

La estructura de una derivación se muestra mejor en un árbol de derivación. El árbol de derivación que muestra cómo ab1 de <identificador> es:

<identificador>|<identificador> <dígito>| |

25

Page 26: ACTIVIDADES UNIDAD2 AUTOMATAS II

<identificador><letra> 1| |<letra>b| a

Un lenguaje de programación completo se define comenzando con un símbolo no- terminal tal como <programa>, conocido como start symbol (símbolo inicial) y desde el cual todos los posibles programas pueden ser derivados. En la práctica, los árboles de derivación se crean de dos formas posibles. En un esquema top-down, la sentencia requerida se deriva del símbolo inicial tal cual como hicimos en el ejemplo (ab1). En un esquema bottom-up, el punto de partida es la sentencia requerida, la cual es reducida al símbolo inicial reemplazando las partes derechas por sus correspondientes partes izquierdas de las reglas de producción. Ambos esquemas se utilizan en la fase de análisis sintáctico de muchos compiladores.

Una gramática que define un lenguaje de programación tiene un número finito de reglas de producción, pero como las reglas de producción contienen recursión, es posible generar infinitos programas posibles.

Ejemplo:

<ident>::=<ident><dígito>

Cuando se incluye recursión en las reglas de producción hay que tener cuidado. Hay que asegurarse que la recursión termine. Una regla de producción tal como la anterior se dice que es recursiva a izquierda. Existen definiciones similares pero recursivas a derecha.

Ejemplo: Gramática para una sentencia de asignación

<asig>::= <id>:=<exp>

<id>::= A| B| C |D (también podría ser la definición de identificador anterior)

<exp>::= <exp> + <exp>

| <exp> * <exp>

| <id>

26

Page 27: ACTIVIDADES UNIDAD2 AUTOMATAS II

¿Qué pasa con esta gramática? ¿Es correcta? Veamos el árbol de derivación de la siguiente sentencia.

A:= B + C * D

Árbol 1

<asig>

|<id> := <exp>| |A <exp> + <exp>| |<id> <exp> * <exp>| | |B <id> <id>| |C D

Árbol 2

<asig>|<id> := <exp>| |A <exp> * <exp>| |<exp> + <exp> <id>| | |<id> <id> D| |B C

En general la ambigüedad sintáctica de las estructuras de un lenguaje es un problema, debido a que los compiladores basan la semántica de esas estructuras en su estructura sintáctica. Si una estructura del lenguaje tiene más de un árbol de

27

Page 28: ACTIVIDADES UNIDAD2 AUTOMATAS II

derivación, entonces, el significado de la estructura no podría determinarse unívocamente.

¿Cómo desambiguamos la gramática anterior?

<asig>::= <id> := <exp>

<id>::= A| B| C| D

<exp>::= <exp> + <término> | <término>

<término>::= <término> * <factor> | <factor>

En general puede ser una declaración o un conjunto separados por “;”. Y una declaración puede ser un identificador o un conjunto separados por “,”:

<declaración>::= var <lista-de-dcls>

<lista-de-dcls>::= <unaDeclaración> | <unaDeclaración>; <lista –de-dcls>

<unaDeclaración>::= <lista-de-ident> : <tipo>

<lista-de-ident>::= <ident> |<ident>, <lista-de-ident>

<ident>::= Se definió en la teoría!!!

<tipo>::= ………..no hacerlo, en este caso para acá

Las anteriores son sólo reglas de producción de la gramática. La gramática se compone además de reglas de:

Dónde:

G={ N, T, P, S}

28

Page 29: ACTIVIDADES UNIDAD2 AUTOMATAS II

T = {var, “,” , “;” , : , etc……}

N = { <declaración>, <lista –de-dcls>, <unaDeclaración>, <lista-de-ident>,

<tipo>, <ident>}

P = { <declaración>::= var <lista-de-dcls>

<lista-de-dcls>::= <unaDeclaración> | <unaDeclaración>; <lista-de-dcls>

<unaDeclaración>::= <lista-de-ident> : <tipo>

<lista-de-ident>::= <ident> |<ident>, <lista-de-ident>

<ident>::= Se definió en la teoría!!!

<tipo>::= ………..no hacerlo, en este caso para acá

}

S = {<declaración>}

Prototipo de gramatica

abstract class Comm {

public Object visita(Visitor v);

}

class While extends Comm { public Expr e;

public Comm c;

29

Page 30: ACTIVIDADES UNIDAD2 AUTOMATAS II

public Object visita(Visitor v) { return v.visitaWhile(this);

}

}

class If extends Comm { public Expr e;

public Comm c1, c2;

public Object visita(Visitor v) { return v.visitaIf (this);

}

}

class Seq extends Comm { public Comm c1, c2;

public Object visita(Visitor v) { return v.visitaSeq(this);

}

}

class Assign extends Comm { public String name;

public Expr e;

public Object visita(Visitor v) { return v.visitaAssign(this);

}

}

class Skip extends Comm { Object visita(Visitor v) {

30

Page 31: ACTIVIDADES UNIDAD2 AUTOMATAS II

return v.visitaSkip(this);

}

}

En el caso de las expresiones, se realiza el mismo esquema.

abstract class Expr {

public abstract Object visita(Visitor v);

}

class BinOp extends Expr { public Operator op; public Expr e1,e2;

public Object visita(Visitor v) { return v.visitaBinOp(this);

}

}

class Var extends Expr { public String name;

public Object visita(Visitor v) { return v.visitaVar(this);

}

}

class Const extends Expr { public int n;

public Object visita(Visitor v) { return v.visitaConst(this);

31

Page 32: ACTIVIDADES UNIDAD2 AUTOMATAS II

}

}

Se define una clase abstracta Visitor cuyas subclases representarán posibles recorridos. La clase incluye métodos del tipo Object visitaX(X n) para cada tipo de nodo X del árbol sintáctico.

abstract class Visitor { Object visitaWhile(While w); Object visitaIf(If i); Object visitaSeq(Seq s);

Object visitaAssign(Assign a); Object visitaSkip(Skip s); Object visitaBinOp(BinOp b); Object visitaVar(Var v); Object visitaConst(Const c);

}

A continuación se define como un posible recorrido del árbol sintáctico y por tanto, una subclase de Visitor.

class Interp extends Visitor {

// Aquí se pueden definir los elementos del contexto (Tabla, Memoria, etc.) Object visitaWhile(While w) {

for (;;) {

BValue v = (BValue) w.e.visita(this); if (!v.b) break;

w.c.visita(this);

}

}

Object visitaIf(If i){

BValue v = (BValue) i.e.visita(this); if (!v.b) i.c1.visita(this);

else i.c2.visita(this);

}

32

Page 33: ACTIVIDADES UNIDAD2 AUTOMATAS II

Object visitaSeq(Seq s){ s.c1.visita(this); s.c2.visita(this);

}

Object visitaAssign(Assign a) { Value v = (Value) a.e.visita(this); update(a.name,v);

}

Object visitaSkip(Skip s) {

}

Object visitaBinOp(BinOp b) {

Value v1 = (Value) b.e1.visita(this); Value v2 = (Value) b.e2.visita(this); return (b.op.apply(v1,v2));

}

Object visitaVar(Var v){ return lookup(v.name);

}

Object visitaConst(Const c) { return c.n;

}

// Función de ejecución de órdenes Object exec(Comm c) {

c.visita(this);

}

}

33

Page 34: ACTIVIDADES UNIDAD2 AUTOMATAS II

Actividad 5: Tres programas tipo, usando la gramática definida de su lenguaje de programación.

Programación basada en prototipos es un estilo de programación orientada a objetos en el cual los objetos no son creados mediante la instanciación de clases sino mediante la clonación de otros objetos o mediante la escritura de código por parte del programador. De esta forma los objetos ya existentes pueden servir de prototipos para los que el programador necesite crear.

El original (y el más canónico) ejemplo de lenguaje prototipado es el lenguaje Self, desarrollado por David Ungar y Randall Smith.

Sin embargo el paradigma sin clases está comenzando a popularizarse y ya ha sido implementado en lenguajes de programación como JavaScript, Cecil, NewtonScript, IO,MOO, REBOL, Squeak.

Analógicamente.

Un ejemplo de instancia en un lenguaje de programación visual, sería tomar o arrastrar un objeto de la barra de herramientas o de la lista de librerías y colocarlo en el escritorio o escenario de trabajo (estamos creando una instancia de ese objeto, una copia). Si arrastramos 10 botones al entorno visual de trabajo, estamos creando una instancia del botón original, si a cada botón le cambiamos el nombre, tendremos 10 botones que heredan las mismas propiedades y métodos del objeto original. Tenemos como resultado que con un solo botón hicimos 10 y nuestro archivo pesara como si tuviese uno solo.

De esta forma, partiendo de lo que conforma a un objeto original (propiedades y métodos) se reutilizan sus funciones creando una instancia del mismo en distintas partes del programa donde se necesite. Si el objeto original cambia o le es agregado algún nuevo atributo, las instancias lo heredaran puesto que son una copia del objeto original.

Comparación del modelo basado en clases

En lenguajes basados en clases los objetos pueden ser de dos tipos generales, las clases y las instancias. Las clases definen la disposición y la funcionalidad básicas de los objetos, y las instancias son objetos "utilizables" basados en los patrones de una clase particular. En este modelo, las clases actúan como colecciones de comportamiento (métodos) y estructuras que son iguales para todas las instancias, mientras que las instancias llevan los datos de los objetos. La

34

Page 35: ACTIVIDADES UNIDAD2 AUTOMATAS II

distinción del papel se basa así sobre todo en una distinción entre la estructura y el comportamiento en un lado, y el estado en el otro.

Los entusiastas de la programación basada en prototipos a menudo argumentan que los lenguajes basados en clases animan un modelo del desarrollo que se centra primero en la taxonomía y las relaciones entre las clases. En cambio, la programación basada en prototipos intenta animar al programador que se centre en el comportamiento de un cierto sistema de ejemplos y después de clasificar estos objetos en objetos arquetipos que se utilizan más adelante en una manera similar a las clases. Como tal, muchos sistemas basados en prototipos animan la alteración de prototipos durante tiempo de ejecución, mientras que solamente muy pocos sistemas orientados a objeto, basados en clase (como el primer sistema orientado a los objetos dinámicos, Smalltalk) permiten que las clases sean alteradas durante la ejecución de un programa.

Mientras que la amplia mayoría de sistemas basados en prototipos se refieren a lenguajes de programación interpretados y de tipos de datos dinámicos, es importante precisar que los sistemas de tipos de datos estáticos son técnicamente factibles. El lenguaje de programación de Omega que es basado en prototipos es un ejemplo de tal sistema, aunque según el Web site de Omega, Omega no es exclusivamente de tipos de datos estáticos, pero su "compilador puede elegir utilizar el tipo de dato estático donde es posible esto y puede mejorar la eficacia del programa.”

Gramáticas formales

Las gramáticas de todos los lenguajes humanos conocidos tienen una cosa en común: están organizadas por frases. Digamos a “grosso modo” que una frase es una unidad de lenguaje. A su vez una frase para que sea sintácticamente correcta debe estar formada por sujeto y predicado; el predicado debe incluir un verbo; si el verbo es transitivo debe llevar un objeto directo, etc….. Tratamos de expresarlo con símbolos:

<frase>::= <sujeto><predicado><sujeto>::= juan / antonio / maría / pepa

<predicado>::= <verbo transitivo><objeto directo>

<predicado>::= <verbo intransitivo>

<verbo transitivo>::= ama / lava / peina / adora

<objeto directo>::= paula / antonio / sultán

<verbo intransitivo>::= corre / salta / camina

Si partimos de <frase> y seguimos estas ‘reglas’ podemos obtener

35

Page 36: ACTIVIDADES UNIDAD2 AUTOMATAS II

<frase> → <sujeto><predicado> → maría<predicado> →

→ maría<verbo transitivo><objeto directo> →

→ maría ama <objeto directo> → maría ama a sultán.

Hemos construido una frase utilizando sólo las reglas anteriores. Decimos que ‘maría ama a sultán’ es una frase de la gramática. De modo análogo

<frase> → <sujeto><predicado> → juan<predicado> →→ juan<verbo intransitivo> → juan camina

Así ‘juan camina’ es otra frase de nuestra gramática. Queremos hacer una definición formal de gramática, para ello vamos a tratar de abstraer lo principal de lo que en el lenguaje normal llamamos gramática. Observamos que hay dos tipos de componentes: los que escribimos entre corchetes <>y las que no. Llamaremos a esos dos tipos de objetos no terminales y terminales, respectivamente. Obsérvese que una verdadera frase está escrita sólo con terminales y los no terminales se usan sólo en pasos intermedios, para construir con sintaxis correcta. Lo fundamental de la gramática son las ‘reglas’ que nos van a permitir formar frases correctas. Sólo las frases que formemos de acuerdo a esas reglas serán frases correctas del lenguaje de nuestra gramática.

Las gramáticas son mecanismos generadores de lenguajes, es decir, nos dicen cómo podemos obtener o construir palabras de un determinado lenguaje.

Una gramática es una cuádrupla G = (VN, VT, S, P) donde:

VT : Es el alfabeto de símbolos terminales.

V N: Es el alfabeto de símbolos no terminales o variables, de forma que debe ser VN ∩ VT =∅ y denotamos con V al alfabeto total de la gramática, esto es, V = VN∪ VT.

S: Es el símbolo inicial y se cumple que S ∈ VN.

P: Es un conjunto finito de reglas de producción.

A veces se utiliza una notación especial para describir gramáticas llamada notación BNF (Backus-Naus-Form ). En la notación BNF los símbolos no terminales o variables son encerrados entre ángulos y utilizaremos el símbolo ::= para las producciones, en lugar de →. Por ejemplo, la producción S → aSa se representa en BNF como S ::= a S a. Tenemos también la notación BNF- extendida que incluye además los símbolos [] y {} para indicar elementos opcionales y repeticiones, respectivamente.

36

Page 37: ACTIVIDADES UNIDAD2 AUTOMATAS II

Tenemos un lenguaje de programación cuyas dos primeras reglas de producción para definir su sintaxis son:

Esto viene a decir que un programa se compone de una cabecera opcional, seguido de la palabra clave “begin”, a continuación una lista de sentencias (debe haber al menos una sentencia) y finaliza con la palabra clave “end”. Podemos transformar las producciones anteriores para especificarlas, según la notación que nosotros hemos introducido (estándar)

Programa 1:

Programa que acepta expresiones, para realizar este programa se utiliza la siguiente gramática.

E –> E+T | T

T –> T*R | R

R –> R-W | W

W –> W/F | F

E –> (E) | 0…9

Código:

#include<iostream>

#include<stdio.h>

#include<stdlib.h>

#include<ctype.h>

using namespace std;

char entrada[50];

char *ca=entrada; /*caracter actual*/

37

Page 38: ACTIVIDADES UNIDAD2 AUTOMATAS II

//declaracion de funcionees

void E();

void Eprima();

void T();

void Tprima();

void R();

void Rprima();

void W();

void Wprima();

void F();

void Aceptado();

int main(){

cout<<"ingrese la expresion: ";

gets(entrada);

E();

cout<<"\nLa expresion si es valida\n"<<endl;

system("pause");

}

void E()// *E –> TE’

{

T();

Eprima();

}

38

Page 39: ACTIVIDADES UNIDAD2 AUTOMATAS II

void Eprima() // E’ –> +TE’|vacío

{

if(*ca=='+')

{

Aceptado();

ca++;

T();

Eprima();

}

//vacío

}

void T() // T –> RT’

{

R();

Tprima();

}

void Tprima() // T’ –> *RT’|vacío

{

if(*ca=='*')

{

Aceptado();

ca++;

R();

39

Page 40: ACTIVIDADES UNIDAD2 AUTOMATAS II

Tprima();

}

//vacío

}

void R() // R –> WR’

{

W();

Rprima();

}

void Rprima() // R’ –> -WR’|vacío

{

if(*ca=='-')

{

Aceptado();

ca++;

W();

Rprima();

}

//vacío

}

void W() // W –> FW’

{

F();

Wprima();

40

Page 41: ACTIVIDADES UNIDAD2 AUTOMATAS II

}

void Wprima() // W’ –> /FW’|vacío

{

if(*ca=='/')

{

Aceptado();

ca++;

F();

Wprima();

}

//vacío

}

void F() // F –> (E)|0…9

{

if(isdigit(*ca))

{

Aceptado();

ca++;

}

else if (*ca=='(')

{

Aceptado();

ca++;

E();

41

Page 42: ACTIVIDADES UNIDAD2 AUTOMATAS II

if (*ca==')')

{

Aceptado();

ca++;

}

else

{

cout<<"se espera parentesis derecho u operador :"<<endl;

system("pause");

exit(0);

}

}

else

{

cout<<"se espera digito o paréntesis izquierdo:"<<endl;

system("pause");

exit(0);

}

}

void Aceptado() //esta función avisa que el caracter actual es aceptado

{

cout<<" caracter ' "<<*ca<<" ' aceptado"<<endl;

}

42

Page 43: ACTIVIDADES UNIDAD2 AUTOMATAS II

Programa 2:

#include<iostream>

#include<stdio.h>

#include<ctype.h>

#include<stdlib.h>

#include<string>

#define TAM_BUFFER 100

using namespace std;

classLexico

{

char *nombreFichero;

FILE* entrada;

int n1;

int traza;

char buffer[TAM_BUFFER];

int pBuffer;

43

Page 44: ACTIVIDADES UNIDAD2 AUTOMATAS II

public:

Lexico(char *unNombreFichero, int una_traza=0);

~Lexico(void);

char siguienteToken(void);

void devuelveToken(char toke);

int lineaActual(void){return n1;};

int existeTraza(void){if(traza)return 1; else return 0;}

};

Lexico::Lexico(char *unNombreFichero, int una_traza)

{

entrada=fopen(unNombreFichero, "rt");

if((entrada==NULL))

{

cout<<"No se puede abrir el archivo"<<endl;

system("pause");

exit(-2);

}

if(una_traza) traza=1;

else traza = 0;

n1=1;

pBuffer=0;

}

Lexico::~Lexico()

{

fclose(entrada);

44

Page 45: ACTIVIDADES UNIDAD2 AUTOMATAS II

}

char Lexico::siguienteToken(void)

{

char car;

while((car=((pBuffer>0) ? buffer[-pBuffer]:getc(entrada)))!=EOF)

{

if(car==' ') continue;

if(car=='\n'){++n1; continue;}

break;

}

if(traza) cout<<"ANALIZADOR LEXICO: Lee el token : "<<car<<endl;

switch(car)

{

case'M':

case'R':

case'W':

case'=':

case'(':

case')':

case';':

case'}':

case'{':

case'.':

case'+':

case'*':

45

Page 46: ACTIVIDADES UNIDAD2 AUTOMATAS II

case'-':

case'/':

case'%':

return(car);

}

if(islower(car))return(car);

else if(isdigit(car)) return(car);

else

{

cout<<"Error Lexico: Token Desconocido"<<endl; system("pause");

exit(-4);

}

return(car);

}

void Lexico::devuelveToken(char token)

{

if(pBuffer>TAM_BUFFER)

{

cout<<"ERROR: Desbordamiento del buffer del analizador lexico"<<endl; system("pause");

exit(-5); } else { buffer[pBuffer++]=token; if(existeTraza()) cout<<"ANALIZADOR LEXICO: Recibe en buffer el token"<<token<<endl; system("pause"); } }

46

Page 47: ACTIVIDADES UNIDAD2 AUTOMATAS II

int main()

{

int traza;

char token;

Lexicoobj("ejemplo_minidev.txt",1);

if(obj.existeTraza()) cout<<"INICIO DE ANALISIS"<<endl;

while((token=obj.siguienteToken() )!='}') cout<<token<<endl;

system("pause");

return 0;

}

Programa 3:

void inapre(){ system("cls"); int cy=0,rt=0,p=0,uui=0;

47

Page 48: ACTIVIDADES UNIDAD2 AUTOMATAS II

for(int g=0;g<=n;g++){

if(Frase[g] == ')' || Frase[g] == '+' || Frase[g] == '-' ||Frase[g] == '/' ||Frase[g] == '*'||Frase[g] == '('||Frase[g] == '^'){{

//cout<<endl<<prioridad(Frase[g])<<" "<<prioridad(pi[cy-1])<<endl<<endl; //cout<<Frase[g]<<" "<<pi[cy-1]<<endl; if( (Frase[g] != pi[cy-1]) && ( prioridad(Frase[g]) == prioridad(pi[cy-1]) ) && cy != 0 && Frase[g] != '(' && Frase[g] != ')'&& pi[cy-1] != '(' && pi[cy-1] != ')'){ pref[rt] = pi[cy-1]; cout<<pref[rt]<<" prio"<<endl; cout<<pi<<" SP "<<endl; rt++; pi[cy-1] = Frase[g]; cy--; }

if(Frase[g] == ')' ){ for(int jj=p+1;jj<cy;jj++){ pref[rt] = pi[jj]; cout<<pref[rt]<<" SS "<<endl; rt++; } for(int hrh = p;hrh<=cy;hrh++){ pi[hrh] = ' '; } cy = p; }

if(Frase[g] == '('){ p = cy; } if(Frase[g] != ')'){ pi[cy] = Frase[g]; cout<<pi<<" S "<<endl; cy++; }

}

48

Page 49: ACTIVIDADES UNIDAD2 AUTOMATAS II

}else if(Frase[g] == '9' ||Frase[g] == '8' ||Frase[g] == '1' ||Frase[g] == '2' ||Frase[g] == '3' ||Frase[g] == '4' ||Frase[g] == '6' || Frase[g] == '5' || Frase[g] == '7'){ pref[rt] = Frase[g]; cout<<pref[rt]<<" N "<<endl; rt++;

}else if(g==n){ int t=cy-1; if(pi[0] == ')'){t=1;} for(t;t>=0;t--){ pref[rt] = pi[t]; cout<<pref[rt]<<" F"<<endl; rt++; } } cout<<endl<<pref<<endl<<endl; }// TERMINO DE FOR

cout<<pref<<endl; /* strcpy(Volt,pref); cout<<Volt<<"frase1"<<endl; uui = n-1; for(int xx=0;xx<n;xx++,uui--){ cout<<xx<<" "<<uui<<endl; pref[xx] = Volt[uui]; cout<<endl<<Volt[xx]<<" "<<Frase[uui]; } cout<<endl<<pref<<"frase2"<<endl; cout<<Volt<<"volt"<<endl;

cout<<pref<<endl;*/ system("pause"); }//TERMINO DE INAPRE

Conversión de infijo a postfijo y de infijo a prefijo:

49

Page 50: ACTIVIDADES UNIDAD2 AUTOMATAS II

Introducción de sentencia.

Infijo a postfijo:

50

Page 51: ACTIVIDADES UNIDAD2 AUTOMATAS II

Infijo a prefijo:

Actividad 6: Reporte del avance por equipo del proyecto final consistente en desarrollar software de base: traductor, intérprete o compilador.

51

Page 52: ACTIVIDADES UNIDAD2 AUTOMATAS II

void CodInterIf(){//Codigo intermedio system("cls"); char fu[100]; int guu=0; int qww=0; int cyu=0; char ins[100]; for(int jn=0;jn<=n;jn++){

if(Frase[jn] == '(' && Frase[jn+1] == ')'){ cout<<"Debe ingresar una condicion"<<endl;}else{//FIN IF 1 if(Frase[jn] == 'I' && Frase[jn+1] == 'f' && Frase[jn+2] == '('){//IF 2

for(int gu = (jn+3) ; Frase[gu] != ')' ; gu++,guu++){ fu[guu] = Frase[gu];}

cyu++;} //FIN IF 2

}//FIN ELSE if(Frase[jn] == ')' ){//FIN IF3 for(int qw = (jn+2) ; Frase[qw] != '}' ;qw++,qww++){//FORins[qww] = Frase[qw]; }//FIN FOR

}//FIN IF 3

}//FIN FOR

cout<<Frase<<endl; if(cyu>0){ for(int mm=0;mm<guu;mm++){ cout<<fu[mm]; } cout<<endl;cout<<"Salta Si falso Etiqueta1"<<endl;for(int mm=0;mm<qww;mm++){ cout<<ins[mm]; } cout<<endl; cout<<"Etiqueta1:"<<endl;

52

Page 53: ACTIVIDADES UNIDAD2 AUTOMATAS II

cout<<"END"<<endl;

} system("pause"); } //Fin codigo intermedio

void CodInterFor(){//Codigo intermedio For system("cls"); int cyf=0; int pc=0; int qw2=0,qw1=0; char pcl[10]; char ins1[10]; for(int jn=0;jn<=n;jn++){if(Frase[jn] == '(' && Frase[jn+1] == ')'){ cout<<"Debe ingresar una condicion"<<endl; }else{//FIN IF 1 if(Frase[jn] == 'F' && Frase[jn+1] == 'o' && Frase[jn+2] == 'r' && Frase[jn+3] == '('){//IF 2

cyf++; }

} //FIN IF 2

if(Frase[jn] == ';'){ pc++; } if(pc == 1 && Frase[jn] == ';'){ for(int qw = jn+1; Frase[qw] != ';' ;qw++,qw2++){ pcl[qw2] = Frase[qw];} }

if(Frase[jn] == ')' ){//FIN IF3for(int qw = (jn+2) ; Frase[qw] != '}' ;qw++,qw1++){//FORins1[qw1] = Frase[qw]; }//FIN FOR

}//FIN IF 3

}//FIN FOR

cout<<Frase<<endl;

53

Page 54: ACTIVIDADES UNIDAD2 AUTOMATAS II

if(cyf > 0 && pc == 2){

cout<<"Etiqueta1:"<<endl; for(int mm=0;mm<qw2;mm++){ cout<<pcl[mm]; } cout<<endl;cout<<"Salta Si falso Etiqueta2"<<endl;for(int mm=0;mm<qw1;mm++){ cout<<ins1[mm]; } cout<<endl;cout<<"Salta Etiqueta1"<<endl; cout<<"Etiqueta2:"<<endl;cout<<"END"<<endl;

} system("pause");}//Fin codigo intermedio for

Ventajas: dentro de las ventajas de la generación de código intermedio se encuentran que: permite abstraer la máquina, separar operaciones de alto nivel de su implementación a bajo nivel, permite la reutilización de los front-ends y back-ends; y permite optimizaciones generales.

Desventajas: implica una pasada más para el compilador (no se puede utilizar el modelo de una pasada), dificulta llevar a cabo optimizaciones específicas de la arquitectura destino; y suele ser ortogonal a la máquina destino, la traducción a una arquitectura específica será más larga e ineficiente.

Tipos de código intermedio.

54

Page 55: ACTIVIDADES UNIDAD2 AUTOMATAS II

AST (AbstractSyntaxTrees): forma condensada de árboles de análisis, con sólo nodos semánticos y sin nodos para símbolos terminales (se supone que el programa es sintácticamente correcto).

DAG (DirectedAcyclicGraphs): árboles sintácticos concisos.

TAC (Three-AddressCode): secuencia de instrucciones de la forma: operando, operador, operando, requieren varias instrucciones y permite la reorganización de código, manejo de ensamblador, utiliza direcciones de memoria y nemotécnicos, pueden ser instrucciones de 2, 3 o 4 por cada operación.

Se genera una condición donde este nos indica los identificadores, palabras reservadas y operadores que este analiza este es posible, una vez que realiza la identificación de tokens este procede a generar lo que es el código intermedio, este lo hace posible tomando en cuenta una función donde desglosa su árbol sintáctico.

55

Page 56: ACTIVIDADES UNIDAD2 AUTOMATAS II

56

Page 57: ACTIVIDADES UNIDAD2 AUTOMATAS II

Como se observa en la siguiente imagen además de generar una operación y mostrarnos los tokens de dicha operación este nos genera el código intermedio y a su vez nos muestra el ejemplo de nuestra operación en lo que seria el lenguaje ensamblador, para ello necesitamos lo que es la generación de código intermedio y análisis léxico y sintáctico, para poder llevar a cabo la Graficación de nuestro árbol sintáctico.

57

Page 58: ACTIVIDADES UNIDAD2 AUTOMATAS II

Anexo

Para llevar a cabo la función del analizador tomamos en cuenta los que son los caracteres del código asccii esto más que nada es para tener un control de los token’s y así mismo poder identificarlos más fácilmente cuando se realice su compilación o ejecución. El siguiente código realiza el trabajo de la imagen anterior, identifica cada token y este los va almacenando de manera que los compare con nuestro alfabeto.

Public Sub analizar()

token = "" Dim estadios As Integer = 0 Dim numtoken As Integer Dim arr() As String = RichTextBox1.Text.Split(ChrW(10))

Dim nn, mm As Integer For nn = 0 To arr.Length - 1 For mm = 0 To Len(arr(nn)) - 1

Dim c, d As String

c = Asc(arr(nn).Chars(mm))

If (estadios = 0) Then estadios = estado(c)

End If

Try d = Asc(arr(nn).Chars(mm + 1)) Catch d = -4

End Try

sig = d

Select Case estadios

Case 1 token = token + arr(nn).Chars(mm) If (sig > 64 And sig < 92) Or (sig > 96 And sig < 123) Or (sig < 58 And sig > 47) Then

58

Page 59: ACTIVIDADES UNIDAD2 AUTOMATAS II

estadios = 1 Else estadios = 0 numtoken = 1 End If

Case 2 token = token + arr(nn).Chars(mm) If (sig < 58 And sig > 47) Then estadios = 2ElseIf (sig = 46) Then

estadios = 3 Else estadios = 0numtoken = 2 End If

Case 3 token = token + arr(nn).Chars(mm) If (sig < 58 And sig > 47) Then estadios = 4 Else estadios = -1 End If Case 4 token = token + arr(nn).Chars(mm) If (sig < 58 And sig > 47) Then estadios = 4 Else estadios = 0 numtoken = 3 End If

Case 100 estadios = -2

Case -1 token = token + arr(nn).Chars(mm) numtoken = 10 estadios = 0

Case 300 token = token + arr(nn).Chars(mm) numtoken = 20 estadios = 0 Case 400

59

Page 60: ACTIVIDADES UNIDAD2 AUTOMATAS II

token = token + arr(nn).Chars(mm) numtoken = 40 estadios = 0 Case 500 token = token + arr(nn).Chars(mm) numtoken = 50 estadios = 0 Case 501 token = token + arr(nn).Chars(mm) numtoken = 60 estadios = 0 Case 502 token = token + arr(nn).Chars(mm) numtoken = 70 estadios = 0 Case 503 token = token + arr(nn).Chars(mm) numtoken = 80 estadios = 0 Case 504 token = token + arr(nn).Chars(mm) numtoken = 90 estadios = 0

End Select

If estadios = 0 Then numerotoken.Add(numtoken) lexema.Add(token)token = ""

ElseIf estadios = -2 Then estadios = 0

ElseIf estadios = -1 Then numerotoken.Add(10) lexema.Add(token) token = ""

ElseIf (sig = -3) Then If estadios <> 0 Then numerotoken.Add(-1)

60

Page 61: ACTIVIDADES UNIDAD2 AUTOMATAS II

lexema.Add(token)

End If End If

Next

Next

For ii = 0 To numerotoken.Count - 1

If (numerotoken(ii) = 1) Then If lexema(ii) = palabras_reservadas(1) Or lexema(ii) = palabras_reservadas(2) Or lexema(ii) = palabras_reservadas(3) _ Or lexema(ii) = palabras_reservadas(4) Or lexema(ii) = palabras_reservadas(5) Or lexema(ii) = palabras_reservadas(6) _ Or lexema(ii) = palabras_reservadas(7) Or lexema(ii) = palabras_reservadas(8) Or lexema(ii) = palabras_reservadas(9) _ Or lexema(ii) = palabras_reservadas(10) Or lexema(ii) = palabras_reservadas(11) Or lexema(ii) = palabras_reservadas(12) _ Or lexema(ii) = palabras_reservadas(13) Or lexema(ii) = palabras_reservadas(14) Or lexema(ii) = palabras_reservadas(15) _ Or lexema(ii) = palabras_reservadas(16) Or lexema(ii) = palabras_reservadas(17) Or lexema(ii) = palabras_reservadas(18) _ Or lexema(ii) = palabras_reservadas(19) Or lexema(ii) = palabras_reservadas(20) Or lexema(ii) = palabras_reservadas(21) _ Or lexema(ii) = palabras_reservadas(22) Or lexema(ii) = palabras_reservadas(23) Or lexema(ii) = palabras_reservadas(24) _ Or lexema(ii) = palabras_reservadas(25) Or lexema(ii) = palabras_reservadas(26) Or lexema(ii) = palabras_reservadas(27) _ Or lexema(ii) = palabras_reservadas(28) Or lexema(ii) = palabras_reservadas(29) Or lexema(ii) = palabras_reservadas(30) Then reserva(cont1) = lexema(ii) cont1 = cont1 + 1

ListBox2.Items.Add("Palabra Reservada:" & " " & lexema(ii))Else reserva(cont1) = lexema(ii) cont1 = cont1 + 1 ListBox2.Items.Add("identificador" & " " & lexema(ii)) End If

ElseIf (numerotoken(ii) = 10) And (lexema(ii) <> ChrW(10)) And (lexema(ii) <> ChrW(13)) Then

61

Page 62: ACTIVIDADES UNIDAD2 AUTOMATAS II

ListBox2.Items.Add("Operador Matematico" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 40) And (lexema(ii) <> ChrW(10)) And (lexema(ii) <> ChrW(13)) ThenListBox2.Items.Add("Operador Comparativo" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 90) Then If lexema(ii) = "(" Then parenta(cont2) = lexema(ii) cont2 = cont2 + 1 cont5 = cont5 + 1 End If If cont5 = 0 Then If lexema(ii) = ")" Then parenta(cont2) = lexema(ii)

End If Else If lexema(ii) = ")" Then parentc(cont3) = lexema(ii) cont3 = cont3 + 1

End If

End IfListBox2.Items.Add("Comp. De Operacion:" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 80) Then ListBox2.Items.Add("Operador Exponencial" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 60) Then ListBox2.Items.Add("Operador Booleano" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 70) Then ListBox2.Items.Add("Corte" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 50) Then ListBox2.Items.Add("Comentario" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 20) And (lexema(ii) <> ChrW(10)) And (lexema(ii) <> ChrW(13)) Then ListBox1.Items.Add("Error" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 3) Then num(cont4) = lexema(ii) cont4 = cont4 + 1 cont6 = 1 'ListBox2.Items.Add("Decimal" & " " & lexema(ii))

ElseIf (numerotoken(ii) = 2) Then

62

Page 63: ACTIVIDADES UNIDAD2 AUTOMATAS II

If cont6 = 0 Then num(cont4) = lexema(ii) cont4 = cont4 + 1 cont6 = 0

End If 'ListBox2.Items.Add("Entero" & " " & lexema(ii))

End If

Next

'For i = 0 To cont1'If reserva(i) = palabras_reservadas(2) Or reserva(i) = palabras_reservadas(3) Or reserva(i) = palabras_reservadas(4) _ ' Or reserva(i) = palabras_reservadas(5) Or reserva(i) = palabras_reservadas(6) Or reserva(i) = palabras_reservadas(11) _' And parenta(i) = caracteres(1) And parentc(i) = caracteres(2) Then 'ListBox2.Items.Add("Funcion" & " " & reserva(i) & parenta(i) & num(i) & parentc(i)) 'Else 'ListBox1.Items.Add("Error" & " " & reserva(i) & parenta(i) & num(i) & parentc(i))'End If 'Next

End Sub

63

Page 64: ACTIVIDADES UNIDAD2 AUTOMATAS II

Conclusion

Esta fase del compilador no es en realidad una parte separada del compilador, la mayoría de los compiladores generan código como parte del proceso de análisis sintáctico, esto es debido a que requieren del árbol de sintaxis y si este no va a ser construido físicamente, entonces deberá acompañar al analizador sintáctico al barrer el árbol implícito. En lugar de generar código ensamblador directamente, los compiladores generan un código intermedio que es más parecido al código ensamblador, las operaciones por ejemplo nunca se hacen con más de dos operandos. Al no generarse código ensamblador el cual es dependiente de la computadora específica, sino código intermedio, se puede reutilizar la parte del compilador que genera código intermedio en otro compilador para una computadora con diferente procesador cambiando solamente el generador de código ensamblador al cual llamamos back-end, la desventaja obviamente es la

lentitud que esto conlleva.

La tarea de síntesis suele comenzar generando un código intermedio. El código intermedio no es el lenguaje de programación de ninguna máquina real, sino que corresponde a una máquina abstracta, que se debe de definir lo más general posible, de forma que sea posible traducir este código intermedio a cualquier máquina real. El objetivo del código intermedio es reducir el número de programas necesarios para construir traductores, y permitir más fácilmente la transportabilidad de unas máquinas a otras. Supóngase que se tienen n lenguajes, y se desea construir traductores entre ellos. Sería necesario construir n*(n-1) traductores.

Sin embargo si se construye un lenguaje intermedio, tan sólo son necesarios 2*n traductores.

Así por ejemplo un fabricante de compiladores puede construir un compilador para diferentes máquinas objeto con tan sólo cambiar las dos últimas fases de la tarea de síntesis.

64

Page 65: ACTIVIDADES UNIDAD2 AUTOMATAS II

ReferenciasGarcía-Beltrán, A. M. (s.f.). Métodos Informáticos . Mc Graw Hill.

J., D. (1991). La Biblia de TurboPascal. Madrid.: Anaya Multimedia.

Jaume. (22 de Enero de 2010.). Ingeniera Informática, Procesadores de Lenguaje. Obtenido de Ingeniera Informática, Procesadores de Lenguaje.: Generación de Código.

Joyanes. (1996). Fundamentos de programación, Algoritmos y Estructuras de Datos, Segunda edición. McGrawHill.

lawebdelprogramador. (s.f.). Transformar-notacion-infija-a-postfija. Obtenido de • http://www.lawebdelprogramador.com/foros/Dev-C/724318-Transformar-notacion-infija-a-postfija.html

pilas-listas-expresiones. (s.f.). monografias. Obtenido de http://www.monografias.com/trabajos44/pilas-listas-expresiones/pilas-listas-expresiones2.shtml#ixzz3nXiPGmfk

TurboPascal. (s.f.). Obtenido de Ed. Bellisco, 2ª edición, Madrid, 2002

65