import java.io.*;
import java.awt.Component;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
public class maquinaTuring {
public static int direccion(int dir)
{
int seleccion=-1;
boolean errorAsignacion = true;
while (errorAsignacion == true )
{
seleccion = JOptionPane.showOptionDialog(
null,
"Selecciona la opcion para el movimiento "+dir,
"Selector de opciones" ,
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null, // null para icono por defecto.
new Object[] { "Avanzar", "Retroseder"}, // null para YES, NO y CANCEL
"opcion 1");
if (seleccion != -1)
{
errorAsignacion = false;
}
else
{
errorAsignacion = true;
}
}
return seleccion;
}
public static void main (String [] args) throws IOException
{
boolean error = true;
//Llenado de la cintilla.
int cuantos=0;
String cadenaCintilla="";
while (error == true)
{
cuantos=Integer.parseInt(JOptionPane.showInputDialog("Cuantos números deseas que tenga la cintilla?"));
cadenaCintilla = JOptionPane.showInputDialog("Dame los datos de la cintilla?");
// System.out.println(cuantos + " " + cadenaCintilla.length());
if (cuantos == cadenaCintilla.length())
error = false;
else
{
error = true;
JOptionPane.showMessageDialog(null, "No colocó los datos correctos", "Datos Incorrectos", JOptionPane.ERROR_MESSAGE);
}
}
int[] cinta = new int[cuantos];
int[] resultado = new int[cuantos];
for (int i=0; i<cuantos; i++)
{
cinta[i] = Integer.parseInt(cadenaCintilla.substring(i,i+1));
}
int tipomov0 = -1;
tipomov0 = JOptionPane.showOptionDialog(null, "Selecciona la opcion para el movimiento ","Selector de opciones" ,JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,null, // null para icono por defecto.
new Object[] { "Avanza y modifica", "Modifica y avanza"}, // null para YES, NO y CANCEL
"opcion 1");
// movimiento 0
int movimiento0 = direccion(0);
System.out.println(movimiento0);
// salto que tendrá 0
int salto0=Integer.parseInt(JOptionPane.showInputDialog("Cuantos saltos desea que de la posición 0?"));
// valor que pondra cuando aparezca }0
int poner0 = Integer.parseInt(JOptionPane.showInputDialog("Que valor quieres poner cuando sea 0?"));
// movimiento 1
int tipomov1 = -1;
tipomov1 = JOptionPane.showOptionDialog(null, "Selecciona la opcion para el movimiento ","Selector de opciones" ,JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,null, // null para icono por defecto.
new Object[] { "Avanza y modifica", "Modifica y avanza"}, // null para YES, NO y CANCEL
"opcion 1");
int movimiento1 = direccion(1);
// salto que tendrá 1
int salto1=Integer.parseInt(JOptionPane.showInputDialog("Cuántos saltos desea que de la posicón 1?"));
// valor que pondra cuando salga 1
int poner1 = Integer.parseInt(JOptionPane.showInputDialog("Que valor quieres poner cuando sea 1?"));
System.out.println("Valores de la cintilla");
for (int i=0; i<cuantos; i++)
{
System.out.print(cinta[i] + " ");
}
String mensajeMov0="";
String mensajeMov1="";
System.out.println("\n");
System.out.println(" " + " movimiento" + " " + "salto" + " " + "colocar");
if (movimiento0==0)
mensajeMov0="DER";
else
mensajeMov0="IZQ";
if (movimiento1==0)
mensajeMov1="DER";
else
mensajeMov1="IZQ";
System.out.print("0 " + mensajeMov0 + " " + salto0 + " " + poner0 + "\n");
System.out.print("1 " + mensajeMov1 + " " + salto1 + " " + poner1 + "\n");
int indice = 0;
// System.out.println(cinta.length);
while (indice < cinta.length && indice >= 0)
{
for (int i=0; i<cinta.length; i++)
{
System.out.print(cinta[i] + " ");
}
switch (cinta[indice])
{
case 0:
{
if (tipomov0 == 0) {
if (movimiento0 == 0 )
indice = indice + salto0;
else
indice = indice - salto0;
if (indice >=0 && indice < cinta.length)
cinta[indice]=poner0;
}
else {
cinta[indice]=poner0;
if (movimiento0 == 0)
indice = indice + salto0;
else
indice = indice - salto0;
}
break;
}
case 1:
{
if (tipomov1 == 0 )
{
if (movimiento1 == 0)
indice = indice + salto1;
else
indice = indice - salto1;
if (indice >= 0 && indice < cinta.length )
cinta[indice]=poner1;
}
else
{
cinta[indice]=poner1;
if (movimiento1 == 0)
indice = indice + salto1;
else
indice = indice - salto1;
}
break;
}
}
}
if (indice < 0 )
// System.out.println("El programa fue ABORTADO");
JOptionPane.showMessageDialog(null, "El programa no término porque fue ABORTADO", "Programa ABORTADO", JOptionPane.ERROR_MESSAGE);
else
{
// System.out.println("Resultados Nuevos");
JOptionPane.showMessageDialog(null, "El programa ha FINALIZADO", "Nuevos Resultados", JOptionPane.PLAIN_MESSAGE);
String res = "";
for (int i=0; i<cuantos; i++)
{
System.out.print( cinta[i] + " ");
// System.out.print(cinta[i] + " ");
}
// JOptionPane.showMessageDialog(null, res, "Nuevos Resultados", JOptionPane.PLAIN_MESSAGE);
}
}
ISC :SOFIA
martes, 6 de junio de 2017
lunes, 29 de mayo de 2017
Tabla de Símbolos
DEFINICIÓN DE LAS TABLA DE SÍMBOLOS.
Una tabla de símbolos es una estructura de datos usada en el proceso de traducción de un lenguaje de programación (por un compilador o un intérprete), dónde cada símbolo en el código fuente de un programa está asociado con información tal como la ubicación, el tipo de datos y el ámbito de cada variable, constante o procedimiento.
Esta estructura de datos contiene una entrada o registro para cada identificador. Cada registro incluye los campos para los atributos del identificador. El administrador de la tabla de símbolos se encarga de manejar los accesos a la tabla de símbolos, en cada una de las etapas de compilación de un programa.
Se examina la tabla de símbolos cada vez que se encuentra un nombre en el texto fuente. Si dicho nombre ya existiese, se realizan cambios sobre la tabla existente. Un mecanismo de tabla de símbolos debe permitir añadir entradas nuevas y encontrar entradas existentes de manera eficaz.
La tabla de símbolos se construye durante el proceso de análisis. La información en la tabla de símbolos se utiliza tanto en el análisis (para especificar restricciones contextuales) como en la síntesis/traducción (para interpretar/traducir el significado de los tokens).
La información se reúne en las fases de análisis del compilador y la emplea la fase de síntesis para generar el código objeto. Por ejemplo, durante el análisis léxico, la cadena de caracteres, o lexema, que forma un identificador se guarda en una entrada de la tabla de símbolos. Las fases posteriores del compilador pueden añadir a esta entrada información, como el tipo del identificador, su uso (por ejemplo, procedimiento, variable o etiqueta) y su posición en la memoria. La fase de generación de código usaría después esta información para generar el código apropiado para almacenar y acceder a esta variable.
ESTRUCTURA
Cada entrada de la tabla de símbolos corresponde a al declaración de un nombre. El formato de las entradas no tiene que ser uniforme porque la información de un nombre depende del uso de dicho nombre. Cada entrada en principio puede considerarse:
( Nombre, descriptor )
LEXEMA ATRIBUTOS
LEXEMA ATRIBUTOS
· LEXEMA: distintas políticas de almacenamiento.
· ATRIBUTOS: cuanta información contiene dicho campo depende del objeto que denota el lexema.
· ATRIBUTOS: cuanta información contiene dicho campo depende del objeto que denota el lexema.
La estructura inicial de la tabla de símbolos suele constar de dos partes:
· PARTE FIJA: formada por las palabras clave del lenguaje (suelen ser de uso reservado y del orden de unas decenas de palabras en un lenguaje programación típico)
· PARTE VARIABLE: definida por el programador: con el significado de los identificadores utilizados en cada frase (programa).
· PARTE VARIABLE: definida por el programador: con el significado de los identificadores utilizados en cada frase (programa).
La información se introduce en la tabla de símbolos a la vez. Las palabras claves se introducen al inicio, o bien también podrían iniciarse en una tabla separada. El analizador léxico busca secuencia de letras y dígitos en la tabla de símbolos para determinar si se ha encontrado una palabra clave reservada o un nombre, este es el motivo por el que las palabras reservadas deben estar en la tabla de símbolos antes de que comience el análisis.
Si se da el caso que el analizador léxico reconoce las palabras clave reservadas, entonces no necesitan aparecer en la tabla de símbolos puede tratarse como una estructura transitoria o volátil, que sea utilizada únicamente en el proceso de traducción de un lenguaje de programación, para luego ser descartada, o integrada en la salida del proceso de compilación para una explotación posterior, como puede ser por ejemplo, durante una sesión de depuración, o como recurso para obtener un informe de diagnóstico durante o después la ejecución de un programa.
La construcción de la tabla de símbolos debe seguirse de una correcta especificación de la misma. Como la definición de la parte dinámica de la tabla de símbolos está basada en las restricciones del lenguaje de programación, la especificación de la construcción de la tabla de símbolos está dirigida por la sintaxis de este sub-lenguaje de declaración y utiliza las mismas técnicas utilizadas para especificar y construir otros elementos del procesador de lenguaje (La construcción de la tabla de símbolos es una tarea del módulo de análisis sintáctico en la que coopera inicialmente el módulo de análisis léxico).
ANALIZADOR LÉXICO
El ANALIZADOR LÉXICO
Un programa fuente es una serie de símbolos (letras, símbolos, caracteres especiales: +, *, !)Con estos símbolos se representan las construcciones del lenguaje tales como variables, etiquetas, palabras reservadas, constantes, etc. Es necesario que el compilador o traductor identifique los distintos significados de estas construcciones, que los creadores de lenguajes dan en la definición del lenguaje.
El programa fuente se trata inicialmente con el analizador léxico (en inglés scanner), con el propósito de agrupar el texto en grupos de caracteres con significado propio llamados tokens o componentes léxicos, tales como variables, identificadores, palabras reservadas y operadores.
Por razones de eficiencia a cada token se le asocia un atributo (o más de uno) que se representa internamente por un código numérico o por un tipo enumerado.
Por ejemplo considerar la siguiente sentencia es C/C++:
Por ejemplo considerar la siguiente sentencia es C/C++:
if sueldo == 1000 sueldo * 0.25;
Conceptos Analizador Léxico
Token
Es el nombre que se le da a cada patrón definido, éste nombre debe usarse en todos los procesos del análisis en todos los lexemas encontrados.Patrón
Es una representación lógica de una serie de agrupaciones de caracteres con características comunes.Lexema
Es cada una de las combinaciones de caracteres que encajan en la definición de un patrón o token.Atributo
Características propias de cada token, por tanto se les denomina atributos del token.Gramática
Se define como un ente formal para especificar de una manera finita el conjunto de cadenas de símbolos que constituyen un lenguaje.Alfabeto
Conjunto finito de símbolos no vacío que conforman una gramática, se representan por Σ (sigma).Símbolo
Entidad abstracta que no se va a definir pues se deja como axioma. Normalmente son letras de alfabetos, números o caracteres especiales como +, -, *, /, etc. No necesariamente serán uno solo, ya que un símbolo puede ser una combinación como palabras reservadas de un lenguaje de programación then, end, beging, else, while, etc.Expresión Regular
Representan patrones de cadenas de caracteres. Se conocen más como metalenguajes que sirven para describir los lenguajes regulares.Diagrama de Transición
Es el conjunto de secuencias de entrada que representan gráficamente los símbolos validos por la gramática, es una representación de los universales autómatas que aparecen en la matemática y otras ciencias.Tabla de Transiciones
Es la manera más cercana de representar los autómatas, consta de filas que representan los estados y las columnas que representan los símbolos de entrada. Adicionalmente se agregan dos columnas para representar los tokens y para indicar retrocesos.Cadena
Se define como una secuencia de símbolos de un lenguaje determinado. Por ejemplo 0001, abcd, a+4*b, 11000, etc. Una cadena siempre tiene una longitud que esta denotada por la cantidad de símbolos independientes que la conforman.
|abcde| →5
|000111| →6
Cuando la cadena es vacía se representa como |λ|→0.
|000111| →6
Cuando la cadena es vacía se representa como |λ|→0.
Lenguaje
Un lenguaje es un conjunto de palabras que se puede representar con un determinado alfabeto.Autómata
Es una construcción lógica que recibe como entrada una cadena de símbolos y produce una salida indicando si la salida es una cadena que pertenece a un determinado lenguaje.lunes, 8 de mayo de 2017
DIFERENCIA ENTRE ATRIBUTOS HEREDADOS Y ATRIBUTOS SINTETIZADOS
Atributos Sintetizados
Se puede decir que un atributo es sintetizado si su valor en un nodo del árbol de análisis
sintáctico se determina a partir de los valores de atributos de los hijos de ese nodo (como decir de abajo
hacia arriba). Se pueden calcular mediante un solo recorrido ascendente del árbol de análisis sintáctico, lo
que es muy deseable.
- Los atributos sintetizados se utilizan ampliamente.
- Si una definición dirigida por sintaxis tiene únicamente atributos sintetizados se dice que es S-atribuida.
- El árbol de análisis sintáctico de una gramática S-atribuida puede decorarse mediante un recorrido en post orden.
- Los atributos sintetizados se utilizan ampliamente.
- Si una definición dirigida por sintaxis tiene únicamente atributos sintetizados se dice que es S-atribuida.
- El árbol de análisis sintáctico de una gramática S-atribuida puede decorarse mediante un recorrido en post orden.
Atributos Heredados
- Sirven para expresar la dependencia que hay entre una construcción del lenguaje de programación y su contexto.
- Siempre es posible reescribir una definición dirigida por sintaxis para que sea S-atribuida.
- En ocasiones es más natural utilizar atributos heredados
- Sirven para expresar la dependencia que hay entre una construcción del lenguaje de programación y su contexto.
- Siempre es posible reescribir una definición dirigida por sintaxis para que sea S-atribuida.
- En ocasiones es más natural utilizar atributos heredados
lunes, 3 de abril de 2017
ANALIZADOR LEXICO CODIGO DEV C++
#include <stdio.h>
#include <conio.h>
#include <string.h>
int contar_vocales(char *);
int main(){
char cad[300];
int longi;
float porc;
printf("Ingrese el texto a contar vocales : ");
gets(cad);
longi = strlen(cad);
printf("La cantidad de Vocales: %d",contar_vocales(cad));
printf("\nCantidad de caracteres: %d",longi);
getch();
}
//-- Funcion:
int contar_vocales(char *cad){
int cont=0;
char *aux=cad;
while(*aux){
if(*aux=='a'||*aux=='e'||*aux=='i'||*aux=='o'||*aux=='u')
cont++;
aux++;
}//función
return cont;
}//contar_vocales
#include <conio.h>
#include <string.h>
int contar_vocales(char *);
int main(){
char cad[300];
int longi;
float porc;
printf("Ingrese el texto a contar vocales : ");
gets(cad);
longi = strlen(cad);
printf("La cantidad de Vocales: %d",contar_vocales(cad));
printf("\nCantidad de caracteres: %d",longi);
getch();
}
//-- Funcion:
int contar_vocales(char *cad){
int cont=0;
char *aux=cad;
while(*aux){
if(*aux=='a'||*aux=='e'||*aux=='i'||*aux=='o'||*aux=='u')
cont++;
aux++;
}//función
return cont;
}//contar_vocales
martes, 28 de marzo de 2017
Eliminación de la Recursividad Izquierda
Eliminación de la Recursividad Izquierda
1. Se agrupan todas las producciones de A en la
forma:
A→ A α
1|A α
2| … |A α
m| β
1 |β
2| … | β
n
,
donde ninguna βi comienza con una A.
2. Se sustituyen las producciones de A por:
A→
β
1A’| β
2A’|…|β
nA’
• A’→
α
1A’|α
2A’|…|α
mA’| ε
Una gramática es recursiva por la izquierda si tiene un no terminal A tal que existe una derivación A Aα para alguna cadena α. Los métodos de análisis sintáctico descendente no pueden manejar gramáticas recursivas por la izquierda, así que se necesita una transformación que elimine la recursión por la izquierda.
Ejemplo: Eliminar la recursividad a izquierdas
de:
E → E+T
E → T
T → F
F → (E)
F → id
T → T*F
•Se identifica si cada una de las producciones que
tienen la forma:
A→ A α| β
•La producción E → E+T ,
tiene recursividad
izquierda, por lo que:
E → E+T | T
A→ A α| β
Se igualan los símbolos según la formula:
A = E
α = + T
β = T
Se utilizan las reglas de remplazo
A→ β1A’| β2A’|…|βnA’
A’→ α1A’|α2A’|…|αmA’|
ε
E → TE’
E’ → +TE’|ε
6
A las producciónes T → T*F | F, también se le
aplica el mismo proceso :
A = T
α = *F
β = F
• Se utilizan las reglas de remplazo
A→ β1A’| β2A’|…|βnA’
A’→ α1A’|α2A’|…|αmA’|
ε
T→ FT’
T’→ *FT’ | ε
Se hace necesario eliminar las producciones del tipo A→ λ para dejar una gramática bien formada.
E → TE’
E’ → +TE’
E→ T
E’→ +T
T→ FT’
T→ F
T’→ *FT’
T’→ *F
F→ (E)
F→ id
Se hace necesario también eliminar las reglas de redenominación.
E → TE’
E’ → +TE’
E→ (E)
E→ id
E’→ +T
T→ FT’
T→ (E)
T→ id
T’→ *FT’
T’→ *F
F→ (T)
F→ id
Finalmente la gramática no recursiva por izquierda
es:
E → TE’
E’ → +TE’
E→ (E)
E→ id
E→ +T
T→ FT’
T→ (E)
T→ id
T’→ *FT’
T’→ *F
F→ (T)
F→ id
ANALIZADOR SINTÁCTICO
Análisis Sintáctico
·
La principal tarea del analizador sintáctico no es comprobar que la
sintaxis del programa fuente sea correcta.
·
El analizador sintáctico (A.S.) comprueba que el orden en que el
analizador léxico le va entregando los tokens es válido. Si esto es así
significará que la sucesión de símbolos que representan dichos tokens puede ser
generada por la gramática correspondiente al lenguaje del código fuente.
·
La forma más habitual de representar la sintaxis de un programa es el
árbol de análisis sintáctico, y lo que hacen los analizadores sintácticos es
construir una derivación por la izquierda o por la derecha del programa fuente,
que en realidad son dos recorridos determinados del árbol de análisis
sintáctico
Sus funciones son :
·
Aceptar lo que es válido sintácticamente y rechazar lo que no lo es.
·
Hacer explícito el orden jerárquico que tienen los operadores en el
lenguaje de que se trate. Por ejemplo, la cadena A/B*C es interpretada como
(A/B)*C en FORTRAN y comoA/(B*C) en APL.
·
Guiar el proceso de traducción (traducción dirigida por la sintaxis).
Clasificación :
La tarea esencial de un analizador es determinar
si una determinada entrada puede ser derivada desde el símbolo inicial, usando
las reglas de una gramática formal, y como hacer esto, existen esencialmente
dos formas:
· ANÁLISIS SINTÁCTICO DESCENDENTE (Top-Down-Parser):
Un analizador puede empezar con el símbolo inicial
e intentar transformarlo en la entrada, intuitivamente esto sería ir dividiendo
la entrada progresivamente en partes cada vez más pequeñas, de esta forma
funcionan los analizadores LL, un ejemplo es el javaCC.
· ANÁLISIS SINTÁCTICO ASCENDENTE (Bottom-Up-Parser):
Un analizador puede empezar con la entrada e
intentar llegar hasta el símbolo inicial, intuitivamente el analizador intenta
encontrar los símbolos más pequeños y progresivamente construir la jerarquía de
símbolos hasta el inicial, los analizadores LR funcionan así
Para una pequeña clase de gramáticas se puede construir con facilidad a mano eficientes analizadores sintácticos ascendentes.Estas gramáticas, por precedencia de operadores, tienen la propiedad de que ningún lado derecho de la producción es є ni tiene 2 terminales adyacentes.
Una gramática con esta última propiedad de denomina gramática de operadores.
ANALIZADORES
SINTÁCTICOS IZQUIERDA-DERECHA
Es una técnica eficiente de análisis sintáctico ascendente que se puede utilizar para analizar una amplia clase de gramáticas independientes de contexto, denominada Análisis sintáctico LR(k)
L es por el examen de la entrada de izquierda a derecha (left to right)
R por construir una derivación por la derecha (right most derivation) en orden inverso.
K por el número de símbolos de entrada de examen por anticipado utilizados para tomar decisiones del análisis sintáctico.
Cuando se omite, se asume que k es 1.
Este análisis es atractivo por varias razones:
• Reconocen prácticamente todas las construcciones de los lenguajes de programación para los que se pueden escribir gramáticas independientes del contexto.
• Puede detectar un error sintáctico tan pronto como sea posible hacerlo en un examen de izquierda a derecha de la entrada.
APLICABILIDAD
Un analizador sintáctico es
un Autómata de pila que reconoce la estructura de una cadena de componentes
léxicos.
CÓMO FUNCIONA (TEORÍA EN LA QUE SE BASA)
El analizador sintáctico, que se utilizara en esta práctica, será de
tipo LL1 o SLR. Se pueden aplicar también técnicas mixtas, analizando, por
ejemplo, las sentencias aritméticas con un analizador de lenguajes de
precedencia y el resto del programa con LL1 o SLR. Si se utilizan herramientas
de generación automática (compiladores de compiladores como yacc y bison) el
lenguaje será del tipo LARL.
LL1:
Definición:
Se agrupan todas las clausuras con idéntica parte izquierda. Es decir
todas las clausuras del tipo:
A -> B C D
A -> E F G
......
A ->X Y Z
Si no existen dos clausuras con idéntica parte izquierda que pueden
empezar con un mismo símbolo terminal, y no existe recursividad a la izquierda,
el lenguaje es LL1.
Nota:
1. No
es necesario que la clausura empiece con símbolos terminales diferentes. Lo
único que es necesario comprobar es si puede o no empezar con un símbolo
terminal.
2. Para
cualquier lenguaje independiente del contexto se puede definir la función
FIRST(a), definida para todas las formas sentenciales, cuyo valor es un
conjunto de los símbolos terminales con los que puede empezar a. Si al en el
conjunto se incluye también la sentencia vacía l. Si l está en FIRST(a),
entonces la clausura A->a puede también empezar con todos los símbolos
terminales que pueden seguir a A, denominado FOLLOW(A). FOLLOW puede incluir
también el símbolo de End-Of-File $. El cálculo de la función FOLLOW(A) es
también esencial para el analizador SLR.
3.Para
los lenguajes LL1 es posible construir un autómata finito a pila, con un solo
estado que analice el lenguaje. Las decisiones del autómata se toman sólo a
partir del último elemento de la pila y el símbolo de entrada.
En general, un analizador sintáctico es un autómata a pila.
El
analizador sintáctico:
*Inicializa
el compilador y AS en particular.
*Para
cada símbolo de entrada llama al analizador morfológico y el AM proporciona el
siguiente símbolo de entrada.
*Analizando
el símbolo, la pila y el estado del autómata, el AS produce las estructuras
necesarias para la siguiente etapa y en el caso de compilación dirigida por la
sintaxis .
*invoca llamadas directas al analizador semántico y al generador de
código.
*Escribe
mensajes de errores y trata de limitar el efecto de estos errores.
Elección de algoritmos. Consideración de las diferencias, ventajas y
desventajas.
Existen por lo menos cuatro maneras de hacer el
analizador morfológico:
A. utilizando
herramientas especializadas yacc/bison,
B. utilizando
analizador del tipo SLR.
C. utilizando
analizador LL1 con llamadas a funciones.
D. utilizando
analizador LL1 con tabla.
Suscribirse a:
Entradas (Atom)