1 - Análisis-Semántico

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 72

TECNOLGICO NACIONAL DE MXICO

INSTITUTO TECNOLGICO DE ACAPULCO

Educacin Tecnolgica con Compromiso Social

Carrera:
Ingeniera en Sistemas Computacionales

Asignatura:
Lenguajes y Autmatas II

Reporte de actividades de aprendizaje y prcticas

Unidad 2: Generacin de cdigo intermedio..

Competencia especfica a desarrollar

Disea mediante el uso de reglas semnticas dirigidas por sintaxis,


un analizador semntico para un compilador.

Profesor: Silvestre Bedolla Solano

Integrantes del equipo: 1

Nombre del alumno: Nmero de control

Peralta Arechiga Samuel 1332


Fajardo Barreiro Eduardo 1332
Rodriguez Aparicio Karina Mitzel 13320964
Bautista santos Alejandro 13320828

Acapulco, Guerrero, Mx., 26 de Septiembre del 2016.

ndice

Contenido
Introduccin.......................................................................................3
Actividad 1.........................................................................................4
Detectar Errores Semnticos...................................................................4
Ejemplos De La Actividad Uno...............................................................7
Actividad 2.......................................................................................23
Disear Y Seleccionar Informacin Sobre La Construccin De Un Analizador
Semntico........................................................................................23
Ejemplos De La Actividad Dos.............................................................28
Actividad 3.......................................................................................46
Reconocer El Manejo De Tipos En Las Expresiones Y El Uso De Operadores.......46
Actividad 4.......................................................................................54
Establecer Las Reglas Para La Conversin De Tipos (Casting) En Expresiones....54
Conversiones Implcitas....................................................................56
Conversiones Explcitas....................................................................56
Excepciones De Las Conversiones De Tipos En Tiempo De Ejecucin............58
Actividad 5.......................................................................................59
Agregar Acciones Semnticas A La Estructura De La Gramtica......................59
Actividad 6.......................................................................................70
Manipular La Tabla De Conversin De Smbolos Y De Errores Y Direcciones.......70
Actividad 7.......................................................................................65
Integrar Equipos De Trabajo Para La Construccin De Un Analizador Semntico.. 65
Actividad 8.......................................................................................81
Propuesta De Proyecto Para El Analizador Lxico Y Sintctico........................81
Conclusiones....................................................................................82
Bibliografa....................................................................................83

Actividad 1.
Aplicar los tipos de notacin para la conversin de expresiones: Infija, prefija y posfija.

2.3 Esquema de generacin


Los esquemas de generacin son las estrategias o acciones que se
debern realizarse y tomarse en cuenta en el momento de generar cdigo
intermedio.

2
Los esquemas de generacin dependen de cada lenguaje. Tomaremos
algunos esquemas de generacin del lenguaje C.

Variables y constantes
Las variables y constantes deben separarse de tal manera que queden
las expresiones una por una de manera simple.
Por ejemplo int a,b,c; se descompone a int a; int b; intc;
respectivamente.

Expresiones
En esta funcin recibe una cadena que representa una lnea de cdigo
intermedio y toma las medidas oportunas para que ese cdigo se utilice.
Estas medidas pueden ser escribir la lnea en un fichero adecuado,
almacenar la instruccin en una lista que despus se pasar a otros
mdulos, o cualquier otra que necesitemos en nuestro compilador.
Expresiones aritmticas
Son aquella donde los operadores que intervienen en ella son numricos, el
resultado es un nmero y los operadores son aritmticos. Los operadores
aritmticos ms comnmente utilizados son: +, - , * , / y %.
Comenzamos el estudio por las expresiones aritmticas. Lo que tendremos
que hacer es crear por cada tipo de nodo un mtodo que genere el cdigo
para calcular la expresin y lo emita. Ese cdigo dejar el resultado en un
registro, cuyo nombre devolver el mtodo como resultado.
Para reservar estos registros temporales, utilizaremos una funcin, reserva.
En principio bastar a con que esta funcin devuelva un registro distinto
cada vez que se la llame.
Cada nodo generar el cdigo de la siguiente manera:
Por cada uno de sus operandos, llamara al mtodo correspondiente
para que se evale la sub expresin. Si es necesario, reservara un
registro para guardar su resultado.
Emitir las instrucciones necesarias para realizar el clculo a partir
de los operandos.

Instrucciones de asignacin
La sintaxis general de la instruccin de asignacin es:

nombre_de_la_variable = valor

El valor a la derecha del signo igual puede ser una constante, otra variable

3
o una expresin que combine constantes y variables, pero siempre la
variable y su valor deben ser del mismo tipo de dato.

Ejemplos:

edad% = 5

area! = 12.3

nombre$ = Pedro

Instrucciones de asignacin compuesta

Las instrucciones de asignacin compuesta realizan primero una operacin


en una expresin antes de asignarla a un elemento de programacin. En el
siguiente ejemplo se muestra uno de estos operadores, +=, que incrementa
el valor de la variable del lado izquierdo del operador con el valor de la
expresin de la derecha.

Una instruccin de asignacin asigna el valor de una expresin a una


variable. En general, si la variable que se va a asignar es una propiedad, la
propiedad debe ser de lectura y escritura o de slo escritura; en caso
contrario, se produce un error de compilacin. Si la variable es una variable
de slo lectura, la asignacin debe producirse en un constructor Shared o
un constructor de instancia apropiado para el tipo de la variable; en caso
contrario, se producir un error de compilacin.

Instrucciones de control
Esta forma de programacin slo permite resolver problemas sencillos.
Para resolver problemas ms complejos, nos puede interesar que
dependiendo de los valores de los datos, se ejecuten unas instrucciones u
otras.
Las instrucciones condicionales nos van a permitir representar ste tipo de
comportamiento. Sentencias IF y SWITCH. En otros casos, nos
encontraremos con la necesidad de repetir una instruccin o instrucciones
un nmero determinado de veces. En stos casos utilizaremos
instrucciones de control iterativas o repetitivas (ciclos). Sentencias WHILE,
DO-WHILE y FOR.

Funciones
Las funciones pueden reducir a en lnea, lo que se hace que expandir el cdigo
original de la funcin.
Las funciones se descomponen simplificando los parmetros de manera individual
al igual que el valor de retorno.

Actividad 1

4
package infixpostfix4;

import java.util.Scanner;
import java.util.Stack;

public class InfixPostfix4 {


public static void main(String[] args) {

//Entrada de datos
System.out.println("*Escribe una expresin algebraica: ");
Scanner leer = new Scanner(System.in);

//Depurar la expresion algebraica


String expr = depurar(leer.nextLine());
String[] arrayInfix = expr.split(" ");

//Declaracin de las pilas


Stack < String > E = new Stack < String > (); //Pila entrada
Stack < String > P = new Stack < String > (); //Pila temporal
para operadores
Stack < String > S = new Stack < String > (); //Pila salida

//Aadir la array a la Pila de entrada (E)


for (int i = arrayInfix.length - 1; i >= 0; i--) {
E.push(arrayInfix[i]);
}

try {
//Algoritmo Infijo a Postfijo
while (!E.isEmpty()) {
switch (pref(E.peek())){
case 1:
P.push(E.pop());
break;
case 3:
case 4:
while(pref(P.peek()) >= pref(E.peek())) {
S.push(P.pop());
}
P.push(E.pop());
break;
case 2:
while(!P.peek().equals("(")) {
S.push(P.pop());
}
P.pop();
E.pop();
break;

5
default:
S.push(E.pop());
}
}

//Eliminacion de `impurezas en la expresiones algebraicas


String infix = expr.replace(" ", "");
String postfix = S.toString().replaceAll("[\\]\\[,]", "");

//Mostrar resultados:
System.out.println("Expresion Infija: " + infix);
System.out.println("Expresion Postfija: " + postfix);

}catch(Exception ex){
System.out.println("Error en la expresin algebraica");
System.err.println(ex);
}
}

//Depurar expresin algebraica


private static String depurar(String s) {
s = s.replaceAll("\\s+", ""); //Elimina espacios en blanco
s = "(" + s + ")";
String simbols = "+-*/()";
String str = "";

//Deja espacios entre operadores


for (int i = 0; i < s.length(); i++) {
if (simbols.contains("" + s.charAt(i))) {
str += " " + s.charAt(i) + " ";
}else str += s.charAt(i);
}
return str.replaceAll("\\s+", " ").trim();
}

//Jerarquia de los operadores


private static int pref(String op) {
int prf = 99;
if (op.equals("^")) prf = 5;
if (op.equals("*") || op.equals("/")) prf = 4;
if (op.equals("+") || op.equals("-")) prf = 3;
if (op.equals(")")) prf = 2;
if (op.equals("(")) prf = 1;
return prf;
}
}

6
Actividad 2.

Disear y seleccionar informacin sobre la construccin de un


analizador semntico.

Atributos y Gramticas con Atributos

7
Informalmente, se llamar atributos de un smbolo de la gramtica a toda
informacin aadida en el rbol de derivacin por el analizador semntico,
asociada a los smbolos de los nodos anotados. Un componente importante de
las gramticas de atributos es el algoritmo de clculo de los valores.

Ejemplos de atributos:

o Tipo de una variable


o Valor de una expresin
o Ubicacin en memoria de una variable
o Cdigo objeto de un procedimiento
o Nmero de dgitos significativos en un nmero

Una gramtica de atributos es una gramtica independiente del contexto en la cual


a sus smbolos terminales y no terminales se les dota de unos atributos y a sus
producciones de unas funciones de evaluacin que hacen que dichos atributos se
propaguen a travs de la gramtica. Su fin es conocer un determinado valor de un
atributo en cualquier parte del rbol de derivacin y tomar la decisin oportuna.

Un atributo es una propiedad asociada a una estructura sintctica. Si una


estructura sintctica representada por el smbolo gramatical X tiene asociado un
atributo a lo representaremos por X.a (Nombre smbolo. Nombre atributo)

Ejemplo:

numero -> numero digito | digito

a) numero-> digito

numero.valor = digito.valor

b) numero -> numero digito numero1.valor = numero2.valor * 10 +


digito.valor

Las funciones semnticas relacionan los valores de los atributos definidos sobre la
gramtica atribuida y van asociadas a producciones de la gramtica atribuida.

Definicin formal

Una gramtica de atributos est formada por una tripleta GA = {GIC, A, F}

G gramtica independiente del contexto

8
A atributos asociados a los smbolos terminales y no terminales

F funcin de evaluacin, funcin asociada a produccin que determina como


obtener unos atributos en funcin de otros dentro de la misma produccin

a es un atributo asociado al smbolo no terminal A y obtiene su valor en funcin de


los atributos: a asociado a X1, b asociado a X2 ,y z asociado a Xm ( es un
atributo obtenido en funcin de la parte derecha de la produccin)

a es un atributo asociado al smbolo X1 y obtiene su valor en funcin de los


atributos: a asociado a A, b asociado a X2 (es un atributo obtenido en funcin de
elementos de la parte derecha e izquierda de la produccin)
A.a=f (y1.b, B.a) , X1.a=f (y1.b, B.a) Atributos incorrectos no se obtienen dentro
de la produccin.

Algoritmos para Clculo de Atributos

Al igual que existen herramientas que construyen analizadores sintcticos a partir


de gramticas libres de contexto, tambin existen herramientas automticas que
generan evaluadores de gramticas atribuidas o, en la mayor parte de los casos,
definiciones dirigidas por sintaxis. En muchas ocasiones, las herramientas de

9
desarrollo de procesadores de lenguaje ofrecen la posibilidad de especificar, de un
modo imperativo en lugar de declarativo, las reglas semnticas de las definiciones
dirigidas por sintaxis (gramticas atribuidas). Esta notacin es la que se conoce
como esquema de traduccin (dirigida por sintaxis): una gramtica libre de
contexto en la que se asocian atributos con los smbolos gramaticales y se
insertan rutinas semnticas dentro de las partes derecha de las producciones
[Aho90]. Las rutinas semnticas son, a su vez, fragmentos de cdigo que el
desarrollador del compilador escribe normalmente entre llaves {} dejando
explcito el momento en el que la herramienta ha de ejecutar la misma, durante su
proceso de anlisis.

La principal diferencia entre las herramientas que emplean gramticas atribuidas y


aqullas que ofrecen esquemas de traduccin es que en las segundas el
desarrollador especifica el momento en el que se ha de ejecutar el cdigo. Sin
embargo, en las gramticas atribuidas y definiciones dirigidas por sintaxis, el
proceso de evaluacin de los atributos debe ser resuelto por la propia herramienta.
La evaluacin de una gramtica atribuida, conlleva procesos como la creacin y
ordenamiento topolgico de un grafo de dependencias, o la limitacin a priori de
las caractersticas de la gramtica

La mayora de las herramientas que generan analizadores sintcticos ofrecen la


posibilidad de aadir rutinas semnticas, definiendo as un esquema de
traduccin. Herramientas como yacc/bison [Johnson75], ANTLR [ANTLR] o
JavaCC [JavaCC] permiten entremezclar rutinas semnticas con las producciones
de las gramticas libres de contexto.

Puesto que los esquemas de traduccin ejecutan las rutinas semnticas de un


modo imperativo, el modo en el que se deriven las distintas producciones de la
gramtica variar el orden de ejecucin de las rutinas. De este modo, el diferenciar
si un esquema de traduccin emplea un anlisis descendente o ascendente es
fundamental para la ubicacin de sus rutinas semnticas. En los generadores de
analizadores sintcticos descendentes que incorporan esquemas de traduccin
(por ejemplo JavaCC o ANTLR), las rutinas semnticas pueden aparecer en
cualquier parte de la parte derecha de la produccin. Una rutina semntica al
comienzo de la parte derecha de una produccin ser ejecutada cuando el
analizador tome la decisin de derivar por dicha produccin. Una rutina situada en
el medio de la parte derecha de una produccin se ejecutar una vez haya
derivado todos los smbolos de la parte derecha, ubicados a su izquierda. Como
se aprecia en el prrafo anterior, las limitaciones de los esquemas de traduccin
basados en analizadores descendentes son los mismos que los identificados para
la evaluacin descendente de gramticas L-atribuidas en una nica pasada (
5.2). Adicionalmente a estas limitaciones, hay que aadir que la ubicacin de las
rutinas semnticas, dentro de la parte derecha de cada produccin, sea en los
sitios oportunos. Las restricciones para ubicar las rutinas son [Aho90]:

Un atributo heredado para un smbolo en el lado derecho de una produccin se


debe calcular antes que dicho smbolo.

10
Una rutina semntica no debe utilizar atributos sintetizados de un smbolo
gramatical que est a la derecha de ella.
Un atributo sintetizado para el no terminal de la izquierda slo se puede calcular
posteriormente a los atributos de los que depende. La rutina semntica que
calcula estos atributos se suele colocar al final del lado derecho de la produccin.

La Tabla de Smbolos

Un compilador utiliza una tabla de smbolos para llevar un registro de la


informacin sobre el mbito y el enlace de los nombres. Se examina la tabla de
smbolos cada vez que se encuentra un nombre en el texto fuente. Si se descubre
un nombre nuevo o nueva informacin sobre un nombre ya existente, se producen
cambios en la tabla.

Un mecanismo de tabla de smbolos debe permitir aadir entradas nuevas y


encontrar las entradas existentes eficientemente. Los dos mecanismos para tablas
de smbolos presentadas en esta seccin son listas lioeal.es y tablas de
dispersin. Cada esquema se evala basndose en el tiempo necesario para
aadir n entradas y realizar e consultas. Una lista lineal es lo ms fcil de
implantar, pero su rendimiento es pobre cuando e y n s vuelven ms grandes.
Los esquemas de dispersin proporcionan un mayor rendimiento con un esfuerzo
algo mayor de programacin y gasto de espacio. Ambos mecanismos pueden
adaptarse rpidamente para funcionar con la regla del anidamiento ms cercano.

Es til que un compilador pueda aumentar dinmicamente, la tabla de smbolos


durante la compilacin. Si la tabla de smbolos tiene tamao fijo al escribir el
compilador, entonces el tamao debe ser lo suficientemente grande como para
albergar cualquier programa fuente. Es muy probable que dicho tamao sea
demasiado grande para la mayora de los programas e inadecuado para algunos.

Entradas de la tabla de smbolos

Cada entrada de la tabla de smbolos corresponde a la declaracin de un nombre.


El formato de las entradas no tiene que ser uniforme porque la informacin de un
nombre depende del uso de dicho nombre. Cada entrada se puede implantar
como un registro que conste de una secuencia de palabras consecutivas de
memoria. Para mantener uniformes los registros de la tabla de smbolos, es
conveniente guardar una parte de la informacin de un nombre fuera de la entrada
de la tabla, almacenando en el registro slo un apuntador a esta informacin.

No toda la informacin se introduce en la tabla de smbolos a la vez. Las palabras


clave se introducen, si acaso, al inicio.

El analizador lxico busca secuencias de letras y dgitos en la tabla de


smbolos para determinar si se ha encontrado una palabra clave reservada o un

11
nombre. Con este enfoque, las palabras clave deben estar en la tabla de smbolos
antes de que comience el anlisis lxico. En ocasiones, si el analizador lxico
reconoce las palabras clave reservadas, entonces no necesitan aparecer en la
tabla de smbolos. Si el lenguaje no convierte en reservadas las palabras clave,
entonces es indispensable que las palabras clave se introduzcan en la tabla de
smbolos advirtiendo su posible uso como palabras clave.

Caracteres dentro de un nombre

Existe una distincin entre el componente lxico id para un identificador o nombre,


el lexema formado por la cadena de caracteres que componen el nombre, y los
atributos del nombre. Las cadenas de caracteres pueden ser difciles de manejar,
as que los compiladores utilizan a menudo alguna representacin de longitud fija
del nombre en lugar del lexema. El lexema es necesario cuando se establece por
primera vez una entrada a la tabla de smbolos y cuando se busca un lexema
encontrado en los datos de entrada para determinar si es un nombre que ya ha
aparecido. Una representacin habitual de un nombre es un apuntador a una
entrada en la tabla de smbolos para l.

Si hay un lmite superior pequeo para la longitud de un nombre, entonces los


caracteres del nombre pueden almacenarse en la entrada de la tabla de smbolos,
como se muestra en la figura 2(a). Si no hay lmite para la longitud de un nombre,
o si rara vez se alcanza el lmite, se puede utilizar el esquema indirecto de la figura
2(b). En lugar de asignar la cantidad mxima de espacio para guardar un lexema
en cada entrada de la tabla, se puede utilizar el espacio ms eficientemente si slo
hay espacio para un apuntador en cada entrada de la tabla.

Ejemplos de la actividad dos


package tokens;
import java.util.*;

12
/**
*
* @author Invitado
*/
public class Tokens {
static String linea = "38+2*3";
//usando delimitadores y regresandolos como tokens
static StringTokenizer tokens3 = new StringTokenizer(linea, "+-*/=", true);
static final int NUMERO=0;
static final int OPERADOR=1;
static String lexema="";

public static int lexico()


{
if (tokens3.hasMoreTokens())
lexema=tokens3.nextToken().trim();
else
lexema="";
if (lexema.equals("+")|| lexema.equals("-")||lexema.equals("*")||
lexema.equals("/"))
return OPERADOR;
else
return NUMERO;
}

public static void main(String args[])


{

13
/* // separacion de tokens con StringTokenizer usando el espacio por defecto
como separador de tokens
StringTokenizer tokens = new StringTokenizer(linea);
while(tokens.hasMoreTokens())
System.out.println(tokens.nextToken());

System.out.println();
//usando delimitadores
StringTokenizer tokens2 = new StringTokenizer(linea, "+=");
while(tokens2.hasMoreTokens())
System.out.println(tokens2.nextToken().trim());
System.out.println();
*/

int token=lexico();
do
{
System.out.println(token+" "+lexema);
token=lexico();
}
while (!lexema.equals(""));

}
}

14
Figura E.1 Pantallazo de Cdigo fuente

Figura E.2 Resultados del programa ejecutado muestra los tokens utilizados en
este mismo cdigo.

Ejemplo 2
15
Cdigo Fuente:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package tabla.de.tokens;
import java.util.*;
/**
*
* @author Invitado
*/
public class TablaDeTokens {

public static class ElementoTs // elemento de la tabla de simbolos,


{
String lexema; //aqui debemos poner todos los atributos que
queremos usar en el compilador
int longitudBytes;
public ElementoTs(String l) // constructor que recibe lexema
{
this.lexema=l;
}
public void setLexema(String l) // a partir de aqui ponemos todos los
"getters" y los "setters"
{
this.lexema=l;
}
public String getLexema()

16
{
return this.lexema;
}

public static final int p=23; // el tamao del arreglo de hash (un nmero primo)

public static int h(String x) // la funcion de hash


{ int suma=0;
for (int i=0; i<x.length(); i++)
suma+=x.charAt(i);
return suma%p;
}
public static class Atributos
{
String tipo;
int longitudBytes;
}
public static void main(String args[])
{

LinkedList<ElementoTs>[] listaLigada = (LinkedList<ElementoTs>[]) new


LinkedList[p]; // el arreglo de hash de tamao p, es un arreglo de listas ligadas

for(int i=0; i<listaLigada.length; i++)


listaLigada[i] = new LinkedList<ElementoTs>(); /* inicializamos el arreglo de
listas ligadas*/

17
// creamos 2 datos de prueba
ElementoTs a=new ElementoTs("ident01");
ElementoTs b=new ElementoTs("ident02");

// Ingresamos datos (lexemas) usando el metodo de hash


listaLigada[h(a.getLexema())].add(a);
System.out.println("Agrego en lista "+h(a.getLexema()) );
listaLigada[h(b.getLexema())].add(b);
System.out.println("Agrego en lista "+h(b.getLexema()) );

// Ahora una busqueda


String lexema01="ident02"; // lexema a buscar
int buscar=h(lexema01); // calculamos funcion de hash (lo pongo aqui, aparte,
para ser claro)
for (ElementoTs elemento : listaLigada[buscar] ) // solo buscamos en la lista
ligada de todos los lexemas que tengan la misma funcion de hash
if (elemento.getLexema().equals(lexema01)) System.out.println("Lo encontro:
" + elemento.getLexema()+" estaba en la lista "+buscar);
// Ahora la tabla de smbolos usando la clase Hashtable
Hashtable<String, Atributos> ts = new Hashtable<String, Atributos>();
Atributos s = new Atributos();
s.tipo = "int";
s.longitudBytes=4;
ts.put ("var1", s);
s = new Atributos();
s.tipo = "float";
s.longitudBytes=32;
ts.put ("xVar", s);

18
Atributos axVar = ts.get("xVar");
System.out.println("xVar es "+axVar.tipo+" "+axVar.longitudBytes);
}
}

Figura E.3 Cdigo Fuente

Figura E.4 Resultado del programa que busca y analiza Tokens en su cdigo
fuente.

Ejemplo 3
Cdigo Fuente:

19
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;

namespace analizador_lexico
{
publicpartialclassForm1 : Form
{
public Form1()
{
InitializeComponent();
}
RegexLexer csLexer = newRegexLexer();
bool load;
List<string> palabrasReservadas;

privatevoid Form1_Load(object sender, EventArgs e)


{
using (StreamReader sr = newStreamReader(@"C:\Users\Raul\Documents\Visual Studio
2015\Projects\analizador lexico\analizador lexico\RegexLexer.cs"))
{
//tbxCode.Text = sr.ReadToEnd();

csLexer.AddTokenRule(@"\s+", "ESPACIO", true);


csLexer.AddTokenRule(@"\b[_a-zA-Z][\w]*\b", "IDENTIFICADOR");
csLexer.AddTokenRule("\".*?\"", "CADENA");
csLexer.AddTokenRule(@"'\\.'|'[^\\]'", "CARACTER");
csLexer.AddTokenRule("/[^\r\n]*", "COMENTARIO1");
csLexer.AddTokenRule(@"\d*\.?\d+", "NUMERO");
csLexer.AddTokenRule(@"[\(\)\{\}\[\];,]", "DELIMITADOR");
csLexer.AddTokenRule(@"[\.=\+\-/*%]", "OPERADOR");
csLexer.AddTokenRule(@">|<|==|>=|<=|!", "COMPARADOR");
csLexer.AddTokenRule(@">=|=<|===|=!", "ERROR");

palabrasReservadas = newList<string>() { "abstract", "as", "async", "await",


"checked", "const", "continue", "default", "delegate", "base", "break", "case",
"do", "else", "enum", "event", "explicit", "extern", "false", "finally",
"fixed", "for", "foreach", "goto", "if", "implicit", "in", "interface",
"internal", "is", "lock", "new", "null", "operator","catch",
"out", "override", "params", "private", "protected", "public", "readonly",
"ref", "return", "sealed", "sizeof", "stackalloc", "static",
"switch", "this", "throw", "true", "try", "typeof", "namespace",
"unchecked", "unsafe", "virtual", "void", "while", "float", "int", "long", "object",
"get", "set", "new", "partial", "yield", "add", "remove", "value", "alias", "ascending",
"descending", "from", "group", "into", "orderby", "select", "where",
"join", "equals", "using","bool", "byte", "char", "decimal", "double", "dynamic",
"sbyte", "short", "string", "uint", "ulong", "ushort", "var", "class", "struct" };

csLexer.Compile(RegexOptions.Compiled | RegexOptions.Singleline |
RegexOptions.ExplicitCapture);

20
load = true;
AnalizeCode();
tbxCode.Focus();
}
}
privatevoid AnalizeCode()
{
dataGridView1.Rows.Clear();
//lvToken.Items.Clear();
int n = 0, e = 0;
foreach (var tk1 in csLexer.GetTokens(tbxCode.Text))
{
if (tk1.Name == "ERROR") e++;

if (tk1.Name == "IDENTIFICADOR")
if (palabrasReservadas.Contains(tk1.Lexema))
tk1.Name = "RESERVADO";
dataGridView1.Rows.Add(tk1.Name,tk1.Lexema,tk1.Linea,tk1.Columna,tk1.Index);
//string cadena = tk1.Name + " " +tk1.Lexema;
//lvToken.Items.Add(cadena);
n++;
}
this.Text = string.Format("Analizador Lexico - {0} tokens {1} errores", n, e);
}//fin del metodo analizecode

privatevoid CodeChanged(object sender, EventArgs e)


{
if (load)
AnalizeCode();
}
}
}
En esta parte es donde definimos las variables que guardaran la informacin que
son los tokens, lexemas, lneas e ndice.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace analizador_lexico
{
classToken
{
public Token(string name, string lexema, int index, int linea, int columna)
{
Name = name;
Lexema = lexema;
Index = index;
Linea = linea;
Columna = columna;
}

publicstring Name { get; set; }


publicstring Lexema { get; privateset; }

publicint Index { get; privateset; }

21
publicint Linea { get; privateset; }
publicint Columna { get; privateset; }

publicint Lenght { get { return Lexema.Length; } }


}
}
Y por ltimo esta parte es donde extrae las reglas y palabras reservadas y las
analizara y se compilara del texto que introduzca en la caja de texto.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace analizador_lexico
{
classRegexLexer
{
Regex rex;
StringBuilder patron;
bool requiereCompilar;
List<string> TNames;
int[] GNumbers;

public RegexLexer()
{
requiereCompilar = true;
TNames = newList<string>();
}

///<summary>
/// Agrega una nueva regla para reconocer token
///</summary>
//"/[*].*?[*]/", "COMENTARIO2"
///<param name="pattern">patrn en el que debe encajar</param>
///<param name="token_name">id nico para este patrn</param>
///<param name="ignore">true para no devolver este token</param>
publicvoid AddTokenRule(string pattern, string token_name, bool ignore = false)
{
if (string.IsNullOrWhiteSpace(token_name))
thrownewArgumentException(string.Format("{0} no es un nombre vlido.", token_name));

if (string.IsNullOrEmpty(pattern))
thrownewArgumentException(string.Format("El patrn {0} no es vlido.", pattern));

if (patron == null)
patron = newStringBuilder(string.Format("(?<{0}>{1})", token_name, pattern));
else
patron.Append(string.Format("|(?<{0}>{1})", token_name, pattern));

if (!ignore)
TNames.Add(token_name);

requiereCompilar = true;
}

22
///<summary>
/// Reinicia el Lexer
///</summary>
publicvoid Reset()
{
rex = null;
patron = null;
requiereCompilar = true;
TNames.Clear();
GNumbers = null;
}

///<summary>
/// Analisa una entrada en busca de tokens validos y errores
///</summary>
///<param name="text">entrada a analizar</param>
publicIEnumerable<Token> GetTokens(string text)
{
if (requiereCompilar) thrownewException("Compilacin Requerida, llame al mtodo
Compile(options).");

Match match = rex.Match(text);

if (!match.Success) yieldbreak;

int line = 1, start = 0, index = 0;

while (match.Success)
{
if (match.Index > index)
{
string token = text.Substring(index, match.Index - index);

yieldreturnnewToken("ERROR", token, index, line, (index - start) + 1);

line += CountNewLines(token, index, ref start);


}

for (int i = 0; i < GNumbers.Length; i++)


{
if (match.Groups[GNumbers[i]].Success)
{
string name = rex.GroupNameFromNumber(GNumbers[i]);

yieldreturnnewToken(name, match.Value, match.Index, line, (match.Index - start) + 1);

break;
}
}

line += CountNewLines(match.Value, match.Index, ref start);


index = match.Index + match.Length;
match = match.NextMatch();
}

if (text.Length > index)


{
yieldreturnnewToken("ERROR", text.Substring(index), index, line, (index - start) + 1);

23
}
}

///<summary>
/// Crea el AFN con los patrones establecidos
///</summary>
publicvoid Compile(RegexOptions options)
{
if (patron == null) thrownewException("Agrege uno o ms patrones, llame al mtodo
AddTokenRule(pattern, token_name).");

if (requiereCompilar)
{
try
{
rex = newRegex(patron.ToString(), options);

GNumbers = newint[TNames.Count];
string[] gn = rex.GetGroupNames();

for (int i = 0, idx = 0; i < gn.Length; i++)


{
if (TNames.Contains(gn[i]))
{
GNumbers[idx++] = rex.GroupNumberFromName(gn[i]);
}
}

requiereCompilar = false;
}
catch (Exception ex) { throw ex; }
}
}

///<summary>
/// Cuenta la cantidad de lineas presentes en un token, establece el inicio de linea.
///</summary>
privateint CountNewLines(string token, int index, refint line_start)
{
int line = 0;
for (int i = 0; i < token.Length; i++)
if (token[i] == '\n')
{
line++;
line_start = index + i + 1;
}
return line;
}
}
}

24
Actividad 3.

25
Reconocer el manejo de tipos en las expresiones y el uso de operadores.

Un operador es un elemento de programa que se aplica a uno o varios operandos


en una expresin o instruccin. Los operadores que requieren un operando, como
el operador de incremento se conocen como operadores unarios. Los operadores
que requieren dos operandos, como los operadores aritmticos (+,-,*, /) se
conocen como operadores binarios. Un operador, el operador condicional (?:),
utiliza tres operandos y es el nico operador ternario de C++ [1]. Existen 6 tipos
de operadores segn su funcin, que son aritmticos, relacionales, de asignacin,
lgicos, de direccin y de manejo de Bits.

OPERADORES DE ASIGNACIN
Este tipo de operadores permiten la asignacin de un valor especfico a una
variable. En C++ se encuentran disponibles los siguientes operadores:

Todos ellos son operadores binarios, de los cuales, = es el nico de asignacin


simple, los dems son operadores de asignacin compuestos, puesto que estn
conformados por ms de un smbolo, por ejemplo += se compone del operador
+ y el operador = . Los seis primeros aceptan operandos de distinto tipo,
mientras que los cinco ltimos: <<=, >>=, &=, ^= y |=, implican manejo de bits, por
lo que sus operandos deben ser numero int en sus distintas variantes. El
funcionamiento de estos operadores se encuentra descrito en la seccin de
operadores de bits. La parte izquierda (que tiene que ser una variable no
constante) adquiere el valor sealado en la expresin de la derecha, pero se
mantiene el tipo original de la variable de la parte izquierda. En caso necesario se

26
realiza una conversin de tipo (con prdida de precisin en su caso) del izquierdo
al derecho. Es necesario resaltar que el operador C++ de asignacin simple (=) se
distingue de otros lenguajes como Pascal que utilizan el smbolo := para este
operador. Observe tambin que la asignacin simple (=) utiliza un smbolo distinto
del operador relacional de igualdad (==) [2]. Adems, en los operadores
compuesto no debe haber espacios de la forma + = y que el igual siempre va a la
derecha del resto de operandos.

OPERADORES ARITMTICOS
Los operadores aritmticos se usan para realizar clculos y operaciones con
nmeros reales y punteros. Bsicamente permiten hacer cualquier operacin
aritmtica que se necesite. Los operadores ms comunes son:

Una caracterstica importante del lenguaje C es que todos los elementos


anteriormente enumerados distinguen entre maysculas y minsculas.
Constantes:
Las constantes que se pueden usar en C se clasifican en:
enteras
reales
de carcter

Cadena de caracteres: Son secuencias de caracteres simples encerradas entre .


A las cadenas de caracteres el compilador les aade un carcter nulo, aparece
despus de las cadenas y se representan `\0', y los almacena como una matriz de
carcter.

Ej.: HOLA\0! `H', `O', `L', `A', `\0! donde \0 es el carcter de terminacin

27
Identificadores:
Son los nombre dados a variables, funciones, etiquetas u otros objetos definidos
por el programador. Un identificador est formado por letras (maysculas o
minsculas), nmeros y carcter de subrayado, con la condicin de que le primer
carcter no sea un nmero.

Ej.:
Precio_Venta Verdadero
Precio Venta Falso
1Num Falso
_123 Verdadero
De un identificador, slo son significativos los primeros 32 caracteres.
Palabras reservadas:
Son palabras especiales que no se pueden usar para nombrar otros elementos del
lenguaje.
NOTA: C hace distincin entre maysculas y minsculas

Ej.: int, float (no se pueden usar)

Comentarios:
El compilador reconoce como comentario cualquier grupo de caracteres situados
entre \* *\ aunque estn en diferentes lneas. Se pueden definir comentarios en
una sola lnea mediante //

Ej.: //Esto es un comentario


En este caso, no es necesario poner indicador de lnea.

Operadores, expresiones, sentencias:


Un operador es un smbolo que indica alguna operacin sobre uno o varios
objetos del lenguaje a los que se denominan operandos.

28
Atendiendo al nmero de operandos sobre los que acta un operador, estos se
clasifican en:

unitarios: cuando actan sobre un solo operando


binarios: 2 operandos
ternarios: 3 operandos

Atendiendo al tipo de operacin que realizan, se clasifican en:

aritmticos
relacionales
lgicos
de tratamiento de bits
especiales

Los operadores, junto con los operandos, forman expresiones. En una expresin,
los operandos pueden ser constantes, variables o llamadas a funciones que
devuelvan valores. Una expresin se convierte en una sentencia cuando va
seguida de un ;. Cuando un grupo de sentencias se encierran entre llaves, { },
forman un bloque sintcticamente equivalente a una sentencia.

Resto de divisin entera

El valor devuelto por el operador de divisin (/) depende del tipo de operandos. Si
stos son enteros, devuelve la parte entera del cociente. Si alguno de ellos es real,
devuelve el resultado como nmero real.

El operador de resto de divisin entera (%) equivale a mod

Ej.: X/Y siendo int x, y; el resultado es 4.

X=9

29
Y=2

Los operadores + + y - - aumentan o disminuyen respectivamente en una unidad


el operando sobre el que actan.

Ej.: C++ es lo mismo que C! C + 1

C - - es lo mismo que C! C - 1

Si el operador est antes de la variable, la operacin de incremento o decremento


se realiza antes de usar el valor de la variable.

Si el operador est despus, primero se usa el valor de la variable y despus se


realiza la operacin de incremento o decremento.

- Los operadores relacionales se usan para expresar condiciones y describir una


relacin entre dos valores.

BINARIOS
>, <, >=, <=, ==!=, Mayor que, Menor que, Mayor o igual que, Menor o igual que,
Igual que, Diferente que.

If (a==b) printf (Son iguales);

Si el contenido de la variable a es igual al de b, muestra en pantalla la frase Son


iguales

El resultado de una expresin relacional solo puede ser verdadero o falso, lo que
en C se identifica con los valores "0 y 0 respectivamente. La expresin a==b se
evaluar como 0 si a y b son diferentes y como distinto de 0 si son iguales.

30
Actan sobre expresiones booleanas, es decir, sobre valores V o F generados por
expresiones como las del caso anterior. Son los siguientes:

UNARIOS
!, NOT, BINARIOS, &&, AND, ||, OR,
Ej.:
X=20 x==y ! F(0)
Y=4 x=y! V
Z=5 x== (y*z)! V

- Operadores de tratamiento de bits: C incorpora ciertas operaciones sobre bits,


propias del lenguaje ensamblador, como desplazamientos o manipulacin
individual de bits. Los operadores que realizan estas operaciones son los
siguientes:
~
not
BINARIOS
&
and
|
or
^
or exclusivo
>>
desplazamiento a la derecha
<<
desplazamiento a la izquierda

Los operadores and, or y not, se rigen por la misma tabla de verdad que
gobierna los operadores lgicos equivalentes. La diferencia entre unos y otros

31
consiste en que estos tres actan a nivel de bits individuales y no sobre valores
completos (&&, ||, !). As, las variables a y b almacenan respectivamente los
valores a ! 0xA1B2

B ! 0xF0F0

Las siguientes expresiones se evalan de la forma:


a&&b ! 1(V)
a||b !1 (V)
!a ! 0 (F)
a&b ! 0xA0B0
a|b ! 0xF1B2
~a ! 0x5E4D

Los operadores &, |, ~, 0 y not, son idnticos respectivamente a las instrucciones


del lenguaje ensamblador and, or y not. Por lo tanto, el operador and (&) permite
poner ciertos bits a 0 dejando el resto inalterado, y el operador not (~), cambia los
bit 1 por 0 y viceversa. El operador or exclusivo (^) es idntico a ^XOR del
lenguaje ensamblador.

Ej:

a ! 0xA1B2
b ! 0x1234
a^b ! 0xB386
Los operadores de desplazamiento (>>, <<) derecha, izquierda, mueven todos los
bits de una variable a la derecha o a la izquierda, respectivamente, un nmero de
posiciones determinado. Su formato general es:
variable<<n
variable>>n
Ej.:

32
a=b<<4! almacena en a el contenido de b despus de realizar un
desplazamiento de b de 4 bits a la izquierda.

Al igual que en el lenguaje ensamblador, C distingue entre desplazamientos


aritmticos y lgicos.
El desplazamiento aritmtico lo hacen sobre datos enteros y mantienen el signo.
El desplazamiento lgico se realiza sobre datos declarados como sin signo
(unsigned) y simplemente aade 0s. Son de tipo int.

Ejemplo:
Sea a una variable declarada como entera (con signo) que almacena el valor
hexadecimal A1B2, con lo que a! 0xA1B2

a=a<<4 produce a! 0x1B20


a=a>>4 produce a! 0x0A1B

- Operadores de asignacin: Las asignaciones se realizan mediante el operador =.


El uso de este operador tiene ciertos aspectos que lo distinguen de otros
lenguajes. Son los siguientes:

En primer lugar, se puede emplear cualquier nmero de veces en una expresin,


por ejemplo, a=b=c=3; x=3; y=x+(z=6);

El operador de asignacin combina con los siguientes operadores: *, /, %, +, -, <<,


>>, &, \, ^, para operaciones acumulativas.

Ejemplo

m*=5 equivale a m=m*5

33
m+=5 equivale a m=m+5

m+=y-3 equivale a m=m+y-3

m-=(y=5) equivale a m=m-(y=5)

m>>=(2*x+1)equivale a m=m>>(2*x+1)

INSTRUCCIONES DE E/S

- DE SALIDA:

La instruccin de salida por excelencia es PRINTF. Nos permite mostrar por


pantalla desde una constante, ya sea una cadena, nmero, hasta una variable de
cualquier tipo. STDIO.H es la librera que contiene printf. Estndar input/output. El
formato de printf es el siguiente:

printf(cadena de control, lista de variables);

Ejemplo:

printf(se ha cometido un error);

Si queremos mostrar el valor de una variable por pantalla, hacemos lo siguiente:

printf(El valor de la variable es: %d, var);

Lo que imprimira por pantalla sera,

34
El valor de la variable es: 3

Printf(Los valores de las variables son: %d, %d, var1, var2);

Los valores de las variables son: 3, 5

TIPOS DE IDENTIFICADORES

%D, %I ! toda variable definida como int. Los nmeros enteros.

%C ! con ella mostramos una variable de tipo char.

%S ! nos permite representar una cadena de caracteres (un array de char (varias
letras)).

%E ! Nos permite representar coma flotante de forma exponencial. Un nmero de


forma exponencial.

%F ! nmero en coma flotante con notacin decimal. Un float.

%U ! un nmero entero sin signo

%P ! nos permite mostrar el valor de un puntero (que almacena una direccin de


memoria)
%LD

%LI ! muestran enteros largos (long int). Si un entero tiene 2 byte, un entero largo
tiene 4 byte.
%LT ! representamos un double.
%2.2f 25.38261

35
escala (2) y precisin (2)
%.2f si no me importa el nmero de parte entera que saque.
Esto se llama flash

CDIGOS DE CONTROL Y CONSTANTES DE BARRA


BARRA INVERTIDA

\n ! a partir de este cdigo se produce en la pantalla un salto de lnea. \n\n\n (3


saltos de lnea). La posicin es importante. Siempre tiene que estar dentro de la
cadena de control.

\t ! se produce una tabulacin. Cinco caracteres de desplazamiento por defecto. \t\t


( dos desplazamientos.

\a ! Alerta. Cuando se pone, emite un beep, un sonido. Un aviso.

\r ! para indicar un retorno de carro, que es un cdigo ASCII 13. Cuando por
ejemplo, pulsa intro. Cuando se pone \n, es un \r y un salto de lnea.

Si queremos que aparezca algo entrecomillado ponemos:

\ \

- DE ENTRADA:

SCANF tambin est en STDIO.H. Nos sirve para introducir datos por el teclado,
cualquier tipo de variable. Su formato es:

scanf(cadena de control, lista de variables);

36
Dentro de esta cadena, lo nico que nos admite son los identificadores (%d, %i,
etc), que son los mismos que en printf.

scanf(%d, &variable);
donde & es direccin de (variable). Si no se pone esto, no lo hace; toma variable
como direccin y no lo ejecuta correctamente.
scanf/%d, cadena);
cadena 20 ! aqu no se pone &, por que el nombre del array de caracteres es un
puntero a la posicin del array (esto es para introducirlo de golpe).
Si queremos meter carcter a carcter a carcter, ponemos scanf(%d, cadena)
Slo en estas situaciones es la excepcin; por regla general siempre &.
Para introducir ms de una variable en un scanf:
scanf(%d %d %d %d, var1, var2, var3, var4);
Pero es preferible hacer varios scanf, 1 por variable. Se pueden introducir
diferentes identificadores. Hay algunas veces que en el buffer del teclado se
quedan 2 retornos de carro almacenados, esto implica que se salten algunas
lneas. Para solucionarlo ponemos:
fflush(stdin); siempre encima de scanf.
Una excepcin a esto es cuando queremos leer ms de un carcter del teclado,
teclas especiales (intro, sangra, etc.)
Si ponemos scanf(3d, &var), estamos limitando la introduccin a tres dgitos.
El lenguaje ensamblador, o assembler (en ingls assembly language y la
abreviacin asm), es un lenguaje de programacin de bajo nivel. Consiste en un
conjunto de mnemnicos que representan instrucciones bsicas para los
computadores, microprocesadores, microcontroladores y otros circuitos integrados
programables. Implementa una representacin simblica de los cdigos de
mquina binarios y otras constantes necesarias para programar una arquitectura
de processador y constituye la representacin ms directa del cdigo mquina
especfico para cada arquitectura legible por un programador. Cada arquitectura
de processador tiene su propio lenguaje ensamblador que usualmente es definida
por el fabricante de hardware, y est basada en los mnemnicos que simbolizan
los pasos de procesamiento (las instrucciones), los registros del procesador, las
posiciones de memoria y otras caractersticas del lenguaje. Un lenguaje
ensamblador es por lo tanto especfico de cierta arquitectura de computador fsica
(o virtual). Esto est en contraste con la mayora de los lenguajes de programacin
de alto nivel, que idealmente son porttiles.

37
Un programa utilitario llamado ensamblador es usado para traducir sentencias del
lenguaje ensamblador al cdigo de mquina del computador objetivo. El
ensamblador realiza una traduccin ms o menos isomorfa (un mapeo de uno a
uno) desde las sentencias mnemnicas a las instrucciones y datos de mquina.
Esto est en contraste con los lenguajes de alto nivel, en los cuales una sola
declaracin generalmente da lugar a muchas instrucciones de mquina.
Muchos sofisticados ensambladores ofrecen mecanismos adicionales para facilitar
el desarrollo del programa, controlar el proceso de ensamblaje, y la ayuda de
depuracin. Particularmente, la mayora de los ensambladores modernos incluyen
una facilidad de macro (descrita ms abajo), y se llaman macro ensambladores.
Fue usado principalmente en los inicios del desarrollo de software, cuando an no
se contaba con potentes lenguajes de alto nivel y los recursos eran limitados.
Actualmente se utiliza con frecuencia en ambientes acadmicos y de
investigacin, especialmente cuando se requiere la manipulacin directa de
hardware, alto rendimiento, o un uso de recursos controlado y reducido. Tambin
es utilizado en el desarrollo de controladores de dispositivo (en ingls, device
drivers) y en el desarrollo de sistemas operativos, debido a la necesidad del
acceso directo a las instrucciones de la mquina. Muchos dispositivos
programables (como los microcontroladores) an cuentan con el ensamblador
como la nica manera de ser manipulados.
Ejemplo 1

Pantalla de programa de ejemplo 1

38
Codigo del programa, se insertan las libreras correspondientes, se inicializan las
variables y se muestran en pantalla con la instruccion cout.

39
Actividad 4.
Establecer las reglas para la conversin de tipos (casting) en expresiones.

En la evaluacin se quiere obtener un valor real, hay que hacer


un casting (o conversin de tipo). Su sintaxis es:

( <tipo_de_dato> ) <expresin>;

De esta forma, se consigue cambiar el tipo de dato del valor resultante de evaluar
la <expresin> a un <tipo_de_dato> deseado.

Ejemplo: Para cambiar el tipo de dato de los valores resultantes de las siguientes
expresiones:

5 (valor entero)

v (valor entero)

5.0 (valor real)

v/h

5/h

5.0 / 2

5 / 2.

5.4 / 2.0

se puede escribir:

( float ) 5

( float ) v

( int ) 5.0

( float ) v / h

( float ) 5 / h

( int ) 5.0 / 2

40
5 / ( int ) 2.

( int ) ( 5.4 / 2.0 )

de tal forma que, los resultados de evaluar las expresiones anteriores son:

5.000000 (valor real)

6.000000 (valor real)

5 (valor entero)

2.000000 (actan en orden los operadores: "( <tipo> )" y (/))

1.666667 (actan en orden los operadores: "( <tipo> )" y (/))

2 (actan en orden los operadores: "( <tipo> )" y (/))

2 (actan en orden los operadores: "( <tipo> )" y (/))

2 (actan en orden los operadores: (/) y "( <tipo> )")

Conversiones implcitas: no se requiere una sintaxis especial porque la


conversin se realiza con seguridad de tipos y no se perdern datos. Entre
los ejemplos se incluyen las conversiones de tipos enteros de menor a
mayor y las conversiones de clases derivadas en clases base.
Conversiones explcitas (conversiones de tipos): las conversiones
explcitas requieren un operador de conversin. La conversin se requiere
cuando es posible que se pierda informacin en el proceso o cuando esta
puede no realizarse correctamente por otras razones. Entre los ejemplos
habituales se incluye la conversin en un tipo con menor precisin o un
intervalo menor, y la conversin de una instancia de clase base en una
clase derivada.
Conversiones definidas por el usuario: las conversiones definidas por el
usuario se realizan a travs de mtodos especiales que puede definir para
habilitar las conversiones explcitas e implcitas entre tipos personalizados
que no tienen una relacin de clase base-clase derivada.
Conversiones con clases auxiliares: para realizar conversiones entre
tipos no compatibles, como los enteros y los objetosSystem.DateTime, o
bien cadenas hexadecimales y matrices de bytes, puede utilizar la
clase System.BitConverter, la claseSystem.Convert y los mtodos Parse de
los tipos numricos integrados, como Int32.Parse.

41
Conversiones implcitas
En los tipos numricos integrados, puede realizarse una conversin implcita
cuando el valor que se va a almacenar puede ajustarse a la variable sin necesidad
de truncamiento o redondeo. Por ejemplo, una variable de tipo long (entero de 8
bytes) puede almacenar cualquier valor que pueda almacenar a su vez un
elemento int (4 bytes en un equipo de 32 bits). En el ejemplo siguiente, el
compilador convierte implcitamente el valor de la derecha en un tipo long antes
de asignarlo a bigNum.
C#
// Implicit conversion. num long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;

En los tipos de referencia, siempre existe una conversin implcita desde una
clase a cualquiera de sus interfaces o clases base, directas o indirectas. No se
requiere una sintaxis especial, ya que una clase derivada siempre contiene todos
los miembros de una clase base.
Derived d = new Derived ();
Base b = d; // Always OK.

Conversiones explcitas
Sin embargo, si no se puede realizar una conversin sin riesgo de perder
informacin, el compilador requiere que se realice una conversin explcita,
denominada conversin de tipo. Una conversin de tipo es una manera de
informar al compilador de forma explcita de que pretende realizar la conversin y
que est al tanto de que puede producirse una prdida de datos. Para realizar
una conversin de tipo, especifique entre parntesis el tipo al que se va a aplicar
dicha conversin delante del valor o la variable que se va a convertir. El programa
siguiente convierte un tipo double a un tipo int. El programa no se compilar sin el
operador de conversin de tipo.

C#
class Test
{
static void Main()
{
double x = 1234.7;
int a;
// Cast double to int.
a = (int)x;
System.Console.WriteLine(a);
}
}
// Output: 1234

42
En los tipos de referencia, se requiere una conversin explcita si debe convertir
de un tipo base a un tipo derivado:

C#
// Create a new derived type.
Giraffe g = new Giraffe();

// Implicit conversion to base type is safe.


Animal a = g;

// Explicit conversion is required to cast back


// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe) a;

Una operacin de conversin entre tipos de referencia no cambia el tipo en tiempo


de ejecucin del objeto subyacente; solo cambia el tipo del valor que se utiliza
como referencia para ese objeto.

Excepciones de las conversiones de tipos en tiempo de ejecucin

En algunas conversiones de tipos de referencia, el compilador no puede


determinar si ser vlida una conversin de tipo. Es posible que una operacin de
conversin de tipo que se compila correctamente provoque un error en tiempo de
ejecucin. Como se muestra en el ejemplo siguiente, una conversin de tipo que
origine un error en tiempo de ejecucin har que se produzca una
excepcin InvalidCastException.

using System;

class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Reptile : Animal { }
class Mammal : Animal { }

class UnSafeCast
{

43
static void Main()
{
Test(new Mammal());

// Keep the console window open in debug mode.


System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}

static void Test(Animal a)


{
// Cause InvalidCastException at run time
// because Mammal is not convertible to Reptile.
Reptile r = (Reptile)a;
}

44
Actividad 5.
Agregar acciones semnticas a la estructura de la gramtica.

Un esquema de traduccin es una gramtica independiente del contexto en la cual


se han insertado fragmentos de cdigo en las partes derechas de sus reglas de
produccin. Los fragmentos de cdigo as insertados se denominan acciones
semnticas. Dichos fragmentos actan, calculan y modifican los atributos
asociados con los nodos del rbol sintctico. El orden en que se evalan los
fragmentos es el de un recorrido primero-profundo del rbol de anlisis sintctico.

Obsrvese que, en general, para poder aplicar un esquema de traduccin hay que
construir el rbol sintctico y despus aplicar las acciones empotradas en las
reglas en el orden de recorrido primero-profundo. Por supuesto, si la gramtica es
ambigua una frase podra tener dos rboles y la ejecucin de las acciones para
ellos podra dar lugar a diferentes resultados. Si se quiere evitar la multiplicidad de
resultados (interpretaciones semnticas) es necesario precisar de que rbol
sintctico concreto se esta hablando.

La accin se ejecutar despus de todas las acciones asociadas con el


recorrido del subrbol de y antes que todas las acciones asociadas con el

recorrido del subrbol .

El siguiente esquema de traduccin recibe como entrada una expresin en infijo y


produce como salida su traduccin a postfijo para expresiones aritmticas con slo
restas de nmeros:

Las apariciones de variables sintcticas en una regla de produccin se indexan


como se ve en el ejemplo, para distinguir de que nodo del rbol de anlisis

45
estamos hablando. Cuando hablemos del atributo de un nodo utilizaremos una
indexacin tipo hash. Aqu VAL es un atributo de los nodos de tipo
denotando su valor numrico y para accederlo escribiremos $NUM{VAL}.
Anlogamente $expr{TRA} denota el atributo ``traduccin'' de los nodos de

tipo .

En este ejemplo, el cmputo del atributo $expr{TRA} depende de los atributos en


los nodos hijos, o lo que es lo mismo, depende de los atributos de los smbolos en
la parte derecha de la regla de produccin. Esto ocurre a menudo y motiva la
siguiente definicin:

Un atributo tal que su valor en un nodo puede ser computado en trminos de los
atributos de los hijos del nodo se dice que es un atributo sintetizado.

Un ejemplo de atributo heredado es el tipo de las variables en las declaraciones:

Un atributo heredado es aquel cuyo valor se computa a partir de los valores de sus
hermanos y de su padre.

Escriba un esquema de traduccin que convierta expresiones en infijo con los


operadores +-*/() y nmeros en expresiones en postfijo. Explique el significado de
los atributos elegidos.

Ejemplos de la actividad dos

package tokens;
import java.util.*;
/**
*
* @author Invitado

46
*/
public class Tokens {
static String linea = "38+2*3";
//usando delimitadores y regresandolos como tokens
static StringTokenizer tokens3 = new StringTokenizer(linea, "+-*/=", true);
static final int NUMERO=0;
static final int OPERADOR=1;
static String lexema="";

public static int lexico()


{
if (tokens3.hasMoreTokens())
lexema=tokens3.nextToken().trim();
else
lexema="";
if (lexema.equals("+")|| lexema.equals("-")||lexema.equals("*")||
lexema.equals("/"))
return OPERADOR;
else
return NUMERO;
}

public static void main(String args[])


{

/* // separacion de tokens con StringTokenizer usando el espacio por defecto


como separador de tokens
StringTokenizer tokens = new StringTokenizer(linea);

47
while(tokens.hasMoreTokens())
System.out.println(tokens.nextToken());

System.out.println();
//usando delimitadores
StringTokenizer tokens2 = new StringTokenizer(linea, "+=");
while(tokens2.hasMoreTokens())
System.out.println(tokens2.nextToken().trim());
System.out.println();
*/
int token=lexico();
do
{
System.out.println(token+" "+lexema);
token=lexico();
}
while (!lexema.equals(""));
}
}

Resultados del programa ejecutado muestra los tokens utilizados en este mismo
cdigo.

48
Ejemplo 2:

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package tabla.de.tokens;
import java.util.*;
/**
*
* @author Invitado
*/
public class TablaDeTokens {

public static class ElementoTs // elemento de la tabla de simbolos,


{
String lexema; //aqui debemos poner todos los atributos que
queremos usar en el compilador
int longitudBytes;
public ElementoTs(String l) // constructor que recibe lexema
{
this.lexema=l;
}
public void setLexema(String l) // a partir de aqui ponemos todos los
"getters" y los "setters"
{
this.lexema=l;

49
}
public String getLexema()
{
return this.lexema;
}

public static final int p=23; // el tamao del arreglo de hash (un nmero primo)

public static int h(String x) // la funcion de hash


{ int suma=0;
for (int i=0; i<x.length(); i++)
suma+=x.charAt(i);
return suma%p;
}
public static class Atributos
{
String tipo;
int longitudBytes;
}
public static void main(String args[])
{

LinkedList<ElementoTs>[] listaLigada = (LinkedList<ElementoTs>[]) new


LinkedList[p]; // el arreglo de hash de tamao p, es un arreglo de listas ligadas

for(int i=0; i<listaLigada.length; i++)

50
listaLigada[i] = new LinkedList<ElementoTs>(); /* inicializamos el arreglo de
listas ligadas*/

// creamos 2 datos de prueba


ElementoTs a=new ElementoTs("ident01");
ElementoTs b=new ElementoTs("ident02");

// Ingresamos datos (lexemas) usando el metodo de hash


listaLigada[h(a.getLexema())].add(a);
System.out.println("Agrego en lista "+h(a.getLexema()) );
listaLigada[h(b.getLexema())].add(b);
System.out.println("Agrego en lista "+h(b.getLexema()) );

// Ahora una busqueda


String lexema01="ident02"; // lexema a buscar
int buscar=h(lexema01); // calculamos funcion de hash (lo pongo aqui, aparte,
para ser claro)
for (ElementoTs elemento : listaLigada[buscar] ) // solo buscamos en la lista
ligada de todos los lexemas que tengan la misma funcion de hash
if (elemento.getLexema().equals(lexema01)) System.out.println("Lo encontro:
" + elemento.getLexema()+" estaba en la lista "+buscar);
// Ahora la tabla de smbolos usando la clase Hashtable
Hashtable<String, Atributos> ts = new Hashtable<String, Atributos>();
Atributos s = new Atributos();
s.tipo = "int";
s.longitudBytes=4;
ts.put ("var1", s);
s = new Atributos();
s.tipo = "float";
s.longitudBytes=32;

51
ts.put ("xVar", s);

Atributos axVar = ts.get("xVar");


System.out.println("xVar es "+axVar.tipo+" "+axVar.longitudBytes);
}
}

Ejecucin de una accin semntica del programa que busca y analiza Tokens en
su cdigo fuente

Ejemplo 3:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace analizador_lexico
{
classRegexLexer
{
Regex rex;
StringBuilder patron;
bool requiereCompilar;
List<string> TNames;
int[] GNumbers;

public RegexLexer()
{

52
requiereCompilar = true;
TNames = newList<string>();
}

///<summary>
/// Agrega una nueva regla para reconocer token
///</summary>
//"/[*].*?[*]/", "COMENTARIO2"
///<param name="pattern">patrn en el que debe encajar</param>
///<param name="token_name">id nico para este patrn</param>
///<param name="ignore">true para no devolver este token</param>
publicvoid AddTokenRule(string pattern, string token_name, bool ignore = false)
{
if (string.IsNullOrWhiteSpace(token_name))
thrownewArgumentException(string.Format("{0} no es un nombre vlido.", token_name));

if (string.IsNullOrEmpty(pattern))
thrownewArgumentException(string.Format("El patrn {0} no es vlido.", pattern));

if (patron == null)
patron = newStringBuilder(string.Format("(?<{0}>{1})", token_name, pattern));
else
patron.Append(string.Format("|(?<{0}>{1})", token_name, pattern));

if (!ignore)
TNames.Add(token_name);

requiereCompilar = true;
}

///<summary>
/// Reinicia el Lexer
///</summary>
publicvoid Reset()
{
rex = null;
patron = null;
requiereCompilar = true;
TNames.Clear();
GNumbers = null;
}

///<summary>
/// Analisa una entrada en busca de tokens validos y errores
///</summary>
///<param name="text">entrada a analizar</param>
publicIEnumerable<Token> GetTokens(string text)
{
if (requiereCompilar) thrownewException("Compilacin Requerida, llame al mtodo
Compile(options).");

Match match = rex.Match(text);

if (!match.Success) yieldbreak;

int line = 1, start = 0, index = 0;

while (match.Success)

53
{
if (match.Index > index)
{
string token = text.Substring(index, match.Index - index);

yieldreturnnewToken("ERROR", token, index, line, (index - start) + 1);

line += CountNewLines(token, index, ref start);


}

for (int i = 0; i < GNumbers.Length; i++)


{
if (match.Groups[GNumbers[i]].Success)
{
string name = rex.GroupNameFromNumber(GNumbers[i]);

yieldreturnnewToken(name, match.Value, match.Index, line, (match.Index - start) + 1);

break;
}
}

line += CountNewLines(match.Value, match.Index, ref start);


index = match.Index + match.Length;
match = match.NextMatch();
}

if (text.Length > index)


{
yieldreturnnewToken("ERROR", text.Substring(index), index, line, (index - start) + 1);
}
}

///<summary>
/// Crea el AFN con los patrones establecidos
///</summary>
publicvoid Compile(RegexOptions options)
{
if (patron == null) thrownewException("Agrege uno o ms patrones, llame al mtodo
AddTokenRule(pattern, token_name).");

if (requiereCompilar)
{
try
{
rex = newRegex(patron.ToString(), options);

GNumbers = newint[TNames.Count];
string[] gn = rex.GetGroupNames();

for (int i = 0, idx = 0; i < gn.Length; i++)


{
if (TNames.Contains(gn[i]))
{
GNumbers[idx++] = rex.GroupNumberFromName(gn[i]);
}
}

54
requiereCompilar = false;
}
catch (Exception ex) { throw ex; }
}
}

///<summary>
/// Cuenta la cantidad de lineas presentes en un token, establece el inicio de linea.
///</summary>
privateint CountNewLines(string token, int index, refint line_start)
{
int line = 0;
for (int i = 0; i < token.Length; i++)
if (token[i] == '\n')
{
line++;
line_start = index + i + 1;
}
return line;
}
}
}

Se muestra el compilador donde introducimos un cdigo y nos muestra los tokens


y lexemas. Observamos que en la parte superior Compilador el nmero de token
- el nmero de error. Podemos observar que nos marca un error y es debido a que
declaramos una variable pero empezando con un nmero

55
Actividad 6.
Manipular la tabla de conversin de smbolos y de errores y direcciones.

Se le llama tabla de nombres o tabla de identificadores y tiene dos funciones


principales:
- Efectuar chequeos semnticos.
- Generacin de cdigo.
Permanece slo en tiempo de compilacin, no de ejecucin, excepto en aquellos
casos en que se compila con opciones de depuracin.

La tabla almacena la informacin que en cada momento se necesita sobre las


variables del programa, informacin tal como: nombre, tipo, direccin de
localizacin, tamao, etc.

La gestin de la tabla de smbolos es muy importante, ya que consume gran parte


del tiempo
de compilacin. De ah que su eficiencia sea crtica. Aunque tambin sirve para
guarda informacin referente a los tipos creados por el usuario, tipos enumerados
y, en general, a cualquier identificador creado por el usuario, nos vamos a centrar
principalmente en las variables de usuario. Respecto a cada una de ellas podemos
guardar:

Almacenamiento del nombre.


Se puede hacer con o sin lmite. Si lo hacemos con lmite, emplearemos una
longitud fija para cada variable, lo cual aumenta la velocidad de creacin, pero
limita la longitud en unos casos, y desperdicia espacio en la mayora. Otro mtodo
es habilitar la memoria que necesitemos en cada caso para guardar el nombre. En
C esto es fcil con los char *. Si hacemos el compilador en MODULA-2, por
ejemplo, habra que usar el tipo ADDRESS.

El tipo tambin se almacena en la tabla, como veremos en un apartado dedicado


a ello.

Direccin de memoria en que se guardar.


Esta direccin es necesaria, porque las instrucciones que referencian a una
variable deben saber dnde encontrar el valor de esa variable en tiempo de
ejecucin, tambin cuando se trata de variables globales. En lenguajes que no
permiten recursividad, las direcciones se van asignando secuencialmente a
medida que se hacen las declaraciones. En lenguajes con estructuras de bloques,
la direccin se da con respecto al comienzo del bloque de datos de ese bloque,
(funcin o procedimiento) en concreto.

El nmero de dimensiones de una variable array, o el de parmetros de una


funcin o procedimiento junto con el tipo de cada uno de ellos es til para el

56
chequeo semntico. Aunque esta informacin puede extraerse de la estructura de
tipos, para un control ms eficiente, se puede indicar explcitamente.

Tambin podemos guardar informacin de los nmeros de lnea en los que se ha


usado
un identificador, y de la lnea en que se declar.

Consideraciones sobre la Tabla de Smbolos.

La tabla de smbolos puede iniciarse con cierta informacin til, tal


como:

- Constantes: PI, E, etc.


- Funciones de librera: EXP, LOG, etc.
- Palabras reservadas.

Esto facilita el trabajo al lexicogrfico, que tras reconocer un identificador lo busca


en la tabla de smbolos, y si es palabra reservada devuelve un token asociado.
Bien estructurado puede ser una alternativa ms eficiente al lex tal y como lo
hemos visto (hash perfecto).

Conforme van apareciendo nuevas declaraciones de identificadores, el analizador


lxico, o el analizador sintctico segn la estrategia que sigamos, insertar nuevas
entradas en la
tabla de smbolos, evitando siempre la existencia de entradas repetidas.

El analizador semntico efecta las comprobaciones sensibles al contexto gracias


a la tabla
de smbolos, y el generador de cdigo intermedio usa las direcciones de memoria
asociada a cada identificador en la tabla de smbolos, al igual que el generador de
cdigo. El cdigo no necesita hacer uso del optimizador.

57
Vamos a hacer un intrprete. Recordar que en un intrprete la entrada es un
programa y la salida es la ejecucin de ese programa.

Suponemos que queremos hacer las siguientes operaciones:


a=7*3
b=3*a

En la segunda instruccin necesitamos saber cunto vale a; es decir el valor de


a debe estar guardado en algn sitio. Para ello utilizaremos una lista de pares:

de forma que cuando nos encontremos con la instruccin a = 7 * 3, miremos en la


tabla, si no est a en la tabla, creamos un nodo para introducirla.

A continuacin, nos encontramos con b = 3 * a. Qu es a? Busco en la tabla de


smbolos
y vemos que el valor de a es 21.
b = 3 * a Ahora buscamos b en la tabla de smbolos y como no est lo creamos.

58
Si ejecutramos ahora la instruccin: a = a + b
Tendramos a a y b en la tabla de smbolos con lo cual solo tendramos que
modificar el valor de a.

Como hemos dicho una tabla de smbolos es una estructura que almacena
informacin relativa a los identificadores de usuario. Pero, Qu informacin
exactamente?, segn el propsito que tengamos. En nuestro caso el propsito es
hacer un intrprete y nos interesa mantener informacin, entre otras cosas, del
valor de cada variable.

Ejemplo 1:

package tablasimbolos;
import java.util.*;

public class TablaSimbolos


{

public static class ElementoTs // elemento de la tabla de simbolos,


{
String lexema; //aqui debemos poner todos los atributos que
queremos usar en el compilador
int longitudBytes;
public ElementoTs(String l) // constructor que recibe lexema
{
this.lexema=l;
}
public void setLexema(String l) // a partir de aqui ponemos todos los
"getters" y los "setters"
{
this.lexema=l;
}
public String getLexema()
{
return this.lexema;
}

public static final int p=23; // el tamao del arreglo de hash (un nmero primo)

59
public static int h(String x) // la funcion de hash
{ int suma=0;
for (int i=0; i<x.length(); i++)
suma+=x.charAt(i);
return suma%p;
}
public static void main(String args[])
{

Scanner Entrada= new Scanner (System.in);


boolean bandera=false;
String lexema;

LinkedList<ElementoTs>[] listaLigada = (LinkedList<ElementoTs>[]) new


LinkedList[p]; // el arreglo de hash de tamao p, es un arreglo de listas ligadas

for(int i=0; i<listaLigada.length; i++)


listaLigada[i] = new LinkedList<ElementoTs>(); /* inicializamos el arreglo de
listas ligadas*/

// creamos 2 datos de prueba


ElementoTs a=new ElementoTs("ident01");
ElementoTs b=new ElementoTs("ident02");

System.out.println("Dame una lexena");


lexema=Entrada.nextLine();

// Ingresamos datos (lexemas) usando el metodo de hash


listaLigada[h(a.getLexema())].add(a);
System.out.println("Agrego en lista "+h(a.getLexema()) );
listaLigada[h(b.getLexema())].add(b);
System.out.println("Agrego en lista "+h(b.getLexema()) );

// Ahora una busqueda


String lexema01=lexema; // lexema a buscar
int buscar=h(lexema01); // calculamos funcion de hash (lo pongo aqui, aparte,
para ser claro)
for (ElementoTs elemento : listaLigada[buscar] ) // solo buscamos en la lista
ligada de todos los lexemas que tengan la misma funcion de hash
if (elemento.getLexema().equals(lexema01))
{

60
System.out.println("Lo encontro: " + elemento.getLexema()+" estaba en la
lista "+buscar);
bandera=true;
}

if(bandera == false)
{
System.out.print("No Se Encontro elemento: ");
System.out.println(lexema01);
bandera=true;
}

En este ejemplo se muestra como el ejemplo 1 pide una lexema y esta es


procesada e indica que est en la lista de lexemas aceptadas.

Ejemplo 2:

package tablasimbolos;
import java.util.*;

public class TablaSimbolos


{

public static class ElementoTs // elemento de la tabla de simbolos,


{
String lexema; //aqui debemos poner todos los atributos que
queremos usar en el compilador
int longitudBytes;
public ElementoTs(String l) // constructor que recibe lexema
{
this.lexema=l;
}
public void setLexema(String l) // a partir de aqui ponemos todos los
"getters" y los "setters"

61
{
this.lexema=l;
}
public String getLexema()
{
return this.lexema;
}

public static final int p=23; // el tamao del arreglo de hash (un nmero primo)

public static int h(String x) // la funcion de hash


{ int suma=0;
for (int i=0; i<x.length(); i++)
suma+=x.charAt(i);
return suma%p;
}
public static void main(String args[])
{

Scanner Entrada= new Scanner (System.in);


boolean bandera=false;
String lexema;

LinkedList<ElementoTs>[] listaLigada = (LinkedList<ElementoTs>[]) new


LinkedList[p]; // el arreglo de hash de tamao p, es un arreglo de listas ligadas

for(int i=0; i<listaLigada.length; i++)


listaLigada[i] = new LinkedList<ElementoTs>(); /* inicializamos el arreglo de
listas ligadas*/

// creamos 2 datos de prueba


ElementoTs a=new ElementoTs("ident01");
ElementoTs b=new ElementoTs("ident02");

System.out.println("Dame una lexena");


lexema=Entrada.nextLine();

// Ingresamos datos (lexemas) usando el metodo de hash


listaLigada[h(a.getLexema())].add(a);
// System.out.println("Agrego en lista "+h(a.getLexema()) );
listaLigada[h(b.getLexema())].add(b);
// System.out.println("Agrego en lista "+h(b.getLexema()) );
62
// Ahora una busqueda
String lexema01=lexema; // lexema a buscar
int buscar=h(lexema01); // calculamos funcion de hash (lo pongo aqui, aparte,
para ser claro)
for (ElementoTs elemento : listaLigada[buscar] ) // solo buscamos en la lista
ligada de todos los lexemas que tengan la misma funcion de hash
if (elemento.getLexema().equals(lexema01))
{
System.out.println("Lo encontro: " + elemento.getLexema()+" estaba en la
lista "+buscar);
bandera=true;
}

if(bandera == false)
{
System.out.print("No Se Encontro elemento: ");
System.out.println(lexema01);
bandera=true;
}

En este ejemplo se muestra como el ejemplo 1 pide una lexema y esta es


procesada e indica que no est en la lista de lexemas aceptadas.

Ejemplo 3:

package tablasimbolos;
import java.util.*;

public class TablaSimbolos


{

public static class ElementoTs // elemento de la tabla de simbolos,


{

63
String lexema; //aqui debemos poner todos los atributos que
queremos usar en el compilador
int longitudBytes;
public ElementoTs(String l) // constructor que recibe lexema
{
this.lexema=l;
}
public void setLexema(String l) // a partir de aqui ponemos todos los
"getters" y los "setters"
{
this.lexema=l;
}
public String getLexema()
{
return this.lexema;
}

public static final int p=23; // el tamao del arreglo de hash (un nmero primo)

public static int h(String x) // la funcion de hash


{ int suma=0;
for (int i=0; i<x.length(); i++)
suma+=x.charAt(i);
return suma%p;
}
public static void main(String args[])
{

Scanner Entrada= new Scanner (System.in);


boolean bandera=false;
String lexema;

LinkedList<ElementoTs>[] listaLigada = (LinkedList<ElementoTs>[]) new


LinkedList[p]; // el arreglo de hash de tamao p, es un arreglo de listas ligadas

for(int i=0; i<listaLigada.length; i++)


listaLigada[i] = new LinkedList<ElementoTs>(); /* inicializamos el arreglo de
listas ligadas*/

// creamos 2 datos de prueba


ElementoTs a=new ElementoTs("ident01");
ElementoTs b=new ElementoTs("ident02");

// System.out.println("Dame una lexena");

64
// lexema=Entrada.nextLine();

// Ingresamos datos (lexemas) usando el metodo de hash


listaLigada[h(a.getLexema())].add(a);
System.out.println("Agrego en lista "+h(a.getLexema()) );
listaLigada[h(b.getLexema())].add(b);
System.out.println("Agrego en lista "+h(b.getLexema()) );

// Ahora una busqueda


String lexema01="ident02"; // lexema a buscar
int buscar=h(lexema01); // calculamos funcion de hash (lo pongo aqui, aparte,
para ser claro)
for (ElementoTs elemento : listaLigada[buscar] ) // solo buscamos en la lista
ligada de todos los lexemas que tengan la misma funcion de hash
if (elemento.getLexema().equals(lexema01))
{
System.out.println("Lo encontro: " + elemento.getLexema()+" estaba en la
lista "+buscar);
bandera=true;
}
/*
if(bandera == false)
{
System.out.print("No Se Encontro elemento: ");
System.out.println(lexema01);
bandera=true;
}
*/

Se muestra un determinado lexema cargada por defecto y su procesamiento


indica la lista donde se encontr.

65
Actividad 7.
Integrar equipos de trabajo para la construccin de un analizador
semntico.

Se realizar la construccin de un analizador semntico, para lo cual se utilizar


un equipo integrado por 6 personas.
Para realizar este trabajo utilizaremos el mtodo de la investigacin Cientfica el
cual consiste en:
La serie de pasos que conducen a la bsqueda de conocimientos mediante la
aplicacin de mtodos y tcnicas. Son las investigaciones que pretenden darnos
una visin general de tipo aproximativo respecto a una determinada realidad. Este
tipo de investigacin se realiza especialmente cuando el tema elegido ha sido
poco explorado y reconocido, y cuando an, sobre l es difcil formular hiptesis
precisas o de cierta generalidad. Suelen surgir tambin cuando aparece un nuevo
fenmeno, que precisamente por su novedad, no admite todava una descripcin
sistemtica, o cuando los recursos que dispone el investigador resultan
insuficientes como para emprender un trabajo ms profundo.
De esta forma y organizndonos, asignando a cada uno del equipo, llevar a cabo
el proyecto y terminarlo con una resolucin optima y que satisfaga las necesidades
que se buscan.

66
Actividad 8.
Propuesta de proyecto para el analizador lxico y sintctico.

Reglas del compilador:


Crear un primer compilador que slo reconozca una orden muy simple,
avise en caso de error.

Ampliar nuevamente para que fuerce a una estructura de programa


concreta (El programa deber comenzar por using System;, el cuerpo
deber estar entre class Program { y } y las ordenes debern terminar en
punto y coma.

Aadir la posibilidad de declarar y usar variables.

Aadir variables de ms de un tipo (numricas, carcter).


El proyecto a realizar del equipo 1, de la materia lenguajes y autmatas
II, es el realizar un compilador, el cual tomara una serie de comandos o
alfabetos para realizar una funcin ya pre establecido y lograr nuestro
objetivo, el cual es que se logre sin ningn inconveniente.
Este proyecto se realizar para que de una forma fcil y sencilla se lean
las cadenas de los alfabetos y llevar a cabo la compilacin de estos.
Nos inspiramos en la necesidad de realizar un compilador de alfabetos y
realizar lo que nosotros le hallamos puesto,
Para poder lograr nuestro objetivo primero se har una investigacin
profunda de que es o de que trata un compilador y como ayuda en
nuestra materia.
Nos dividiremos el trabajo para avanzar de forma apresurada y con
resultados ptimos que se medirn de acuerdo a valores que nosotros le
pondremos, para saber el avance del proyecto.

Objetivos:

_Estudiar el funcionamiento de los compiladores.

_Disear un compilador e implementarlo.

Intrpretes y Compiladores:

El presente proyecto como su nombre lo indica pretende estudiar a los Interpretes


y Compiladores. Sin embargo, estas palabras " Interpretes y Compiladores ",
dicen mucho y a la vez no dicen nada. Todos nosotros alguna vez estuvimos en
contacto con ellos, y en algn momento nos preguntamos cmo funcionan. Pero

67
muy pocos nos sentamos a tratar de entender su mecnica, su funcionamiento y
ver los conceptos que estn ocultos detrs de ellos.

Digo ocultos porque es de mi conocimiento, que estos conceptos son tales, que
no se me hubieran ocurrido que forman parte de la teora que engloba a los
Interpretes y Compiladores. Los principios y tcnicas de escritura de Interpretes y
Compiladores comprende los conceptos de: los lenguajes de programacin, la
arquitectura de computadores, la teora de lenguajes, los algoritmos, la ingeniera
de Software, como as tambin tener pleno conocimiento de las distintas
plataformas existentes, de las tcnicas de programacin ( lineales, estructuradas,
orientadas a objetos, a eventos y paralelas ), y de los distintos Hardware, tanto
desde el punto de vista de un programador como al nivel en que interactan sus
componentes internos, para poder obtener de ellos la mayores prestaciones
posibles. Adems, el tener conocimiento de lo que es una maquina abstracta, su
relacin con la gramtica y muchos otros conceptos.

Hay que destacar que el estudio terico que aqu se realizara, es una importante
base para la investigacin y desarrollo de aplicaciones en las cuales el anlisis de
patrones este muy vinculadas con ellas, como por ejemplo Bases de Datos,
Desarrollo de herramientas Orientadas a Objetos, Graficadores, Procesadores de
Texto, Formatos de Archivos, Traductores, Analizadores Lxicos, Analizadores
Sintcticos, por supuesto Interpretes y Compiladores y muchas otras
aplicaciones. Adems, haciendo uso de los conceptos de la Teora General de
Sistemas y los de una maquina abstracta, en particular las denominada Autmatas
Traductores, se puede llegar a la implementacin de un sistema como un
autmata, que ante la lectura de patrones (entrada de datos) reacciona con una
traduccin (salida de datos). Es por todo esto y por una curiosidad propia que he
decido realizar este proyecto.

Planificacin de Actividades:

Objetivos:

Primera etapa:

_Estudiar el concepto de Gramticas Regular.

_Estudiar el funcionamiento de un Autmata Finito.

68
_Observar la dualidad y correspondencia entre una Gramticas Regular y un
Autmata Finito.

_Desarrollar los algoritmos de un Autmata Finito.

_Estudiar el concepto de un Analizador Lxico.

Segunda etapa:

_Estudiar los conceptos de Gramticas de Contexto Libre.

_Estudiar el funcionamiento de un Autmata a Pila.

_Observar la dualidad y correspondencia entre una Gramticas de Contexto Libre


y un Autmata a Pila.

_Desarrollar los algoritmos de un Autmata a Pila.

_Estudiar el concepto de un Analizador Sintctico.

Tercera etapa:

_Estudiar el concepto y el funcionamiento de un Analizador Semntico.

_Estudiar el concepto y el funcionamiento de un Generador de Cdigo Intermedio.

_Desarrollar los algoritmos para la implementacin de un Analizador Semntico y


un Generador de Cdigo.

Cuarta etapa:

_Estudiar el concepto y el funcionamiento de un Optimizador de Cdigo


Intermedio.

_Estudiar el concepto y el funcionamiento de un Generador de Cdigo.

_Desarrollar los algoritmos para la implementacin de un Optimizador de Cdigo


intermedio y un Generador de Cdigo.

_Desarrollar los algoritmos para la implementacin de un Intrprete.

69
Quinta etapa:

_Estudiar el concepto y el funcionamiento de un Compilador.

_Estudiar el concepto y el funcionamiento de un Compilador en el anlisis de un


proyecto como un Traductor Interactivo.

_Desarrollar los algoritmos para la implementacin de un Compilador.

_Desarrollar los algoritmos para la implementacin de un entorno integrado EDI de


un compilador.

70
Conclusiones

En conclusin con estas actividades dimos la introduccin a Autmatas,


conocimos sus conceptos principales los cuales son alfabeto, cadenas y lenguaje
donde explica cmo se conforma cada uno de estos, para la creacin de un
compilador primero tendremos que crear ciertas fases del compilador ya que cada
una de estas tiene una determina tarea y se tiene que ejecutar correctamente, es
decir, que no haya un error y prosiga con la siguiente fase hasta llegar a la ltima
fase para completar una compilacin correcta. Y con la propuesta del proyecto, se
observ las caractersticas y reglas que se deben cumplir. Como resultado de las
actividades realizadas es posible concluir que en el rea de la programacin las
expresiones regulares son un mtodo por medio del cual se pueden realizar
bsquedas dentro de cadenas de caracteres. Sin importar la amplitud de la
bsqueda requerida de un patrn definido de caracteres, las expresiones
regulares proporcionan una solucin prctica al problema. Para poder crear ER es
necesario conocer la estructura de las mismas.

71
Bibliografa
Ceballos, F. J. (2007). Enciclopdia de Microsoft Visual C#. 2da Edicion. Espaa:
Ra-MA.
Hopcroft, J. E. (2007). Teoria de automatas, Lenguajes y Computacion . Madrid,
Espaa: PERSON .
http://www.gramaticas.net/2012/05/ejemplos-de-analisis-semantico.html
http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/autocontenido/autoc
on/45__errores_semnticos.html
http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/autocontenido/autoc
on/311_manejo_de_los_errores_sintcticos.html
CRISTIAN GUILLERMO GARCA. (2012). Operadores. 2014, de Universidad
Distrital francisco Jos de Caldas Sitio web: http://profesores.fi-
b.unam.mx/carlos/lcpi/p09/OPERADORES%20EN%20%20C++.pdf
Jess Vegas. (2012). Identificadores, Operadores y Expresiones. 2015, de Dpto.
Informtica Universidad de Valladolid Sitio web:
http://www.infor.uva.es/~jvegas/cursos/prog/tema3.html

Vicente Benjumea y Manuel Roldn. (2016). Fundamentos de Programacin con


el Lenguaje de Programacin C++. 2016, de UNIVERSIDAD DE MLAGA Dpto.
Lenguajes y CC. Computacin E.T.S.I. Informtica Sitio web:
http://www.lcc.uma.es/~vicente/docencia/cppdoc/programacion_cxx.pdf
Wilder Urbaez. (2005). Constantes, variables y expresiones. 2016, de desarrollo
web Sitio web: http://www.desarrolloweb.com/articulos/2164.php

72

También podría gustarte