lunes, 12 de junio de 2017

Encapsulamiento

//el encapsulamiento se define como la forma de aislar o de accesar a estas
//propiedades tanto como atributos y metodos dentro de nuestra clase

#include <iostream>
using namespace std;

class Auto{

private: //solamente se va a utilizar dentro de nuestra clase
    string Color;
   
private:
float Precio;

public: //los de tipo publico pueden utilizarce fuera de la clase
void SetColor(string _Color) //contiene un parametro en este caso SetColor
//set lo utilizamos para establecer y en la parte de obtener lo utilizamos como get
{
Color= _Color; //se va a enviar lo que contenga nuestro metodo SetColor
}

string GetColor() //metodo para recibir nuestra darto de el color del auto (metodo tipo cadena)
{
return Color; //retorna o recibe nuestra variable color
}

public:
void SetPrecio(float _Precio)
{
Precio = _Precio;
}

float GetPrecio()
{
return Precio;
}

};

int main()
{
Auto  miAuto;

miAuto.SetColor("A R C O I R I S"); //se manda a llamar y se agrega el dato del parametro
miAuto.SetPrecio(10000);


cout<<endl;
cout<< miAuto.GetColor(); //mostrando el metodo miAuto y lo que contiene lo va a mostrar
cout<<endl;
cout<< miAuto.GetPrecio();
cout<<endl;
}



martes, 6 de junio de 2017

Estructuras if-else, while, for y switch

#include <iostream>
using namespace std;
int main()
{
char opcion;
cout <<"Introduzca una letra a,b:"<<endl;
    cin >> opcion;
    switch (opcion)
    {
case 'a':
int numero, cont, suma;
bool encontrado;
encontrado = false;
numero = 101;
while (!encontrado)
{
suma = 1; //EL VALOR DE LA SUMA INICIAL ES 1
for (cont = 2; cont < numero; cont++) //EL CICLO FOR SE VA A INICIAR EN DOS Y SE IRA INCREMENTANDO DE DOS EN DOS HASTA ENCONTRAR EL NUMERO
{
if (numero % cont == 0)
{
suma = suma + cont;
// SI EL CONTADOR ENCONTRADO ES IGUAL A CERO ENTONCES LA SUMA SERA IGUAL A LA SUMA(1) MAS EL CONTADOR
}
}
if (suma == numero)
                {
                encontrado = true;
                }else
                {
                numero++;
                }
}
    cout << "El primero numero perfecto mayor que 100 = " << numero << endl;
    system("pause");
break;
case 'b':
cout << "Gracias por entrar al programa" << endl;
break;
    }
}
//*Un número es perfecto cuando la suma de sus divisores excepto él mismo
//es igual al propio número. Por ejemplo 6 es perfecto ya que sus divisores son 1, 2 ,3 y suman 6/




martes, 9 de mayo de 2017

Ejemplo de Herencia

En este programa lo que se hace es heredar los atributos de la clase padre que en este caso seria la clase persona, todos los atributos públicos serán heredados a la clase hija que es la clase Alumno la cual va a utilizar los datos de la clase padre para que al final se impriman todos los datos juntos que son los datos dela persona como nombre, edad,código de alumno y la nota final de cada alumno que se este dando de alta en el programa.

//Herencia en POO

#include<iostream>
#include<stdlib.h>
using namespace std;

class Persona{

     private: //atributos
     string nombre;
     int edad;
     public: //metodos de esta clase persona
     Persona(string,int); //constructor
     void mostrarPersona();
};

class Alumno : public Persona{ //esta clase es hija de la clase persona, el public se refiere a que puedes acceder a todo lo publico de esta clase
      private: //atributos
      string codigoAlumno;
      float notaFinal;
      public: //metodos
      Alumno(string,int,string,float); //constructor de la clase Alumno
      void mostrarAlumno();
};


//constructor de la clase Persona(clase padre)
Persona::Persona(string _nombre,int _edad){
nombre = _nombre;
edad = _edad;
}

Alumno::Alumno(string _nombre,int _edad,string _codigoAlumno,float _notaFinal) : Persona(_nombre,_edad){ //definiendo constructor
     codigoAlumno = _codigoAlumno;
     notaFinal = _notaFinal;
   
}

void Persona::mostrarPersona(){
cout<<"Nombre: " <<nombre<<endl;
cout<<"Edad: " <<edad<<endl;

}

void Alumno::mostrarAlumno(){
mostrarPersona();
cout<<"Codigo Alumno: " <<codigoAlumno<<endl;
cout<<"Nota Final: " <<notaFinal<<endl;
}

int main (){
Alumno alumno1("Cristian",25,"12345678",9.5);

alumno1.mostrarAlumno();


system("pause");
return 0;
}



Atributos heredados y sintetizados.

Atributos heredados y sintetizados.

Atributos heredados:

Todos los atributos que se calculan según el principio de composicionalidad generalizado (usando al menos un atributo del contexto) se llaman atributos heredados.

Es la capacidad de compartir atributos y métodos entre clases. Es la propiedad que permite definir nuevas clases usando como base clases ya existentes. La nueva clase (clase derivada) hereda los atributos y comportamiento que son específicos de ella. La herencia es una herramienta poderosa que proporciona un marco adecuado para producir software fiable, comprensible, de bajo costo, adaptable y reutilizable. La herencia o relación es-un es la relación que existe entre dos clases, en la que una clase denominada derivada o subclase se crea a partir de otra ya existente, denominada clase base o superclase.

  • 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 heredado

Ejemplo con atributos heredados.
Números en base X: Para interpretar un número hay que saber interpretar sus dígitos y además conocer la base Ej. AF3 = 2803)10 porque A=10, F=15, 3=3 y la base es 16 Ej. AF3 = 13503)10 porque A=10, F=15, 3=3 y la base es:




Atributos sintetizados:

Todos los atributos que se calculan según el principio de composicionalidad se llaman atributos sintetizados Ej. Los atributos anteriores lex y valor.
Las gramáticas de atributos que únicamente poseen atributos sintetizados se llaman gramáticas s-atribuidas. La evaluación en una gramática s-atribuida se puede hacer con un recorrido en postorden de los árboles sintácticos atribuidos.


Los atributos sintetizados son como valores de salida de las categorías sintácticas (suben hacia la raíz –el programa-), mientras que los atributos heredados son como valores de entrada (bajan hacia las hojas –las expresiones, etc.-). 

martes, 4 de abril de 2017

Código Intermedio.

Generación de código intermedio.

Ventajas:
– Permite abstraer la máquina, separar operaciones de alto nivel de su implementación a bajo nivel.
– Permite la reutilización de los front-ends y backends.
– Permite optimizaciones generales.

Desventajas:
– Implica un recorrido más para el compilador (no se puede utilizar el modelo de un recorrido, conceptual mente simple).
– Dificulta llevar a cabo optimizaciones específicas de la arquitectura destino.
– Suele ser ortogonal a la máquina destino, la traducción a una arquitectura específica será más larga e ineficiente.

Tipos de Código Intermedio.


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



Por ejemplo:
a = b + c * d;
El generador de código intermedio, tratar de dividir esta expresión en sub-expresiones y, a continuación, generar el código correspondiente.
r1 = c * d;
r2 = b + r1; 
r3 = r2 + r1;
a = r3
R que se utilizan como registros en el programa de destino.
Un código de dirección tiene un máximo de tres direcciones para calcular la expresión. Un código de dirección puede estar representado en dos formas : cuádruples y triples.
DAG: (Directed Acyclic Graphs): árboles sintácticos concisos.
– Ahorran espacio
– Resaltan operaciones duplicadas en el código
– Difíciles de construir

TAC (Three-AddressCode): secuencia de instrucciones de la forma:

– operador: aritmético / lógico
– operandos/resultado:
constantes, nombres, temporales.
• Se corresponde con instrucciones del tipo:
• Las operaciones más complejas requieren varias instrucciones:
• Este ‘desenrollado’ facilita la optimización y generación de código final.


Cuadruplica

Cada instrucción cuadruplica exposición se divide en cuatro campos: operador, arg1, arg2, y resultado. El ejemplo anterior se representa a continuación cuadruplica en formato:
Op.Arg1Arg2Resultado
*cdr1
+br1r2
+r2r1r3
=r3a

Triples

Cada instrucción en triples presentación tiene tres campos : op, arg1, arg2.Los resultados de las respectivas sub-expresiones son indicados por la posición de expresión. Similitud con Triples representan DAG y árbol de sintaxis. Son equivalentes a DAG al tiempo que representan las expresiones.
OpArg1Arg2
*cd
+b(0)
+(1)(0)
=(2)
Triples ante el problema de optimización código un inmovilismo mientras que, en la medida en que los resultados son posicionales y cambiar el orden o la posición de una expresión puede causar problemas.

Indirectos Triples


Esta representación es una mejora sobre representación triples. Se usa punteros en lugar de su posición para almacenar los resultados. Esto permite a los optimizadores libremente volver a colocar la sub-expresión para producir un código optimizado.

Declaraciones

Una variable o procedimiento tiene que ser declarado antes de que se pueda utilizar. Declaración implica asignación de espacio en la memoria y la entrada de tipo y nombre de la tabla de símbolos. Un programa puede ser codificada y diseñado siguiendo la estructura de la máquina destino en mente, pero es posible que no siempre se pueda convertir con precisión un código fuente para su idioma de destino.
Tomando el conjunto del programa, como una colección de procedimientos y sub-procedimientos, es posible declarar que todos los nombres locales en el procedimiento. Asignación de memoria se realiza de manera consecutiva y nombres son asignados a la memoria en la secuencia en la que se declara en el programa. Podemos utilizar el desplazamiento variable y ponerlo a cero {offset = 0} que denotan la dirección base.
La fuente lenguaje de programación y la arquitectura del equipo de destino puede variar en la forma los nombres se almacenan, por lo tanto se utiliza direccionamiento relativo. Mientras que el primer nombre se asigna memoria a partir de la posición de memoria 0 {offset= 0}, el siguiente nombre declaró después, debe ser asignada la memoria junto a la primera.
Ejemplo:
Tomamos el ejemplo de lenguaje de programación C en una variable de tipo entero se le asigna 2 bytes de memoria y una variable de tipo float se asigna 4 bytes de memoria.
int a;
float b;
Allocation process:
{offset = 0}
   int a;
   id.type = int
   id.width = 2
offset = offset + id.width 
{offset = 2}
   float b;
   id.type = float
   id.width = 4
offset = offset + id.width 
{offset = 6}
Para entrar en este detalle en una tabla de símbolos, un procedimientoentrar puede ser utilizado. Este método puede tener la siguiente estructura:
enter(name, type, offset)
Este procedimiento debe crear una entrada en la tabla de símbolos, de nombre de la variable, en su tipo y el tipo dedesplazamiento de dirección relativa en su área de datos.


martes, 28 de marzo de 2017

Analizador sintactico

import java.io.*;
import java.lang.*;
import java.util.UUID;

public class automata_finito {

public static void main(String[] args) throws IOException {

BufferedReader a=new BufferedReader(new InputStreamReader (System.in));

String Usuario,contrasena;
int Password;

//UUID (Unique Universal Identifier)

System.out.println(UUID.randomUUID().toString().toUpperCase().substring(0, 12));


System.out.println("Usuario:");
Usuario= a.readLine();
System.out.println("Password:");
Password= Integer.parseInt(a.readLine());

if (Usuario.equals("Cristian") && Password == 12345){

System.out.println(" ¡Bienvenido Cristian!");
}
else {

System.out.println(" El Usuario y/o Password son incorrectos");
}

}

}

Este programa lo que hace es validar las contraseñas nuevas que se entan generando a partir de un RANDOM, el cual va a integrar caracteres como el alfabeto de la A-Z combinado con numeros de el 0-9.
El proceso de entrada solo es valido si la contraseña ingresada esta escrita correcta de manera correcta en como se esta imprimiendo.



ejemplo 2: (Analizador sintáctico)

package lenguaje_formal;

import java.io.*;
import java.lang.*;

public class Lenguaje_formal {

    public static void main(String[] args) throws IOException  {

        BufferedReader a=new BufferedReader(new InputStreamReader (System.in));
        int opcion;
        int variableentera;
        String variabletexto;
     
        System.out.println("ELIGE EL TIPO DE PALABRA RESERVADA QUE DESEAS UTILIZAR");
        System.out.println("1.-ENTERO");
        System.out.println("2.-TEXTO");
     
        opcion=Integer.parseInt (a.readLine());
        switch(opcion){
         
            case 1:
                System.out.println("Para usar tipo entero solo puedes usar numeros entre el 0 y el 9");
                System.out.println("Introduce la variable que quieras usar:");
                variableentera = Integer.parseInt(a.readLine());
             
if (variableentera == 0 || variableentera == 1 || variableentera == 2 || variableentera == 3 || variableentera ==4 || variableentera == 5
        || variableentera == 6 || variableentera == 7 || variableentera == 8 || variableentera == 9)
                {
                    System.out.println("Este tipo de caracter es permitido");
                }
                else{
                    System.out.println("Este parametro no esta permitido");
                }
                break;
             
            case 2:
                System.out.println("Para usar de tipo texto solo puedes utilizar vocales");
                System.out.println("Introduce la variable que quieras usar:");
                variabletexto = a.readLine();
             
                if (variabletexto.equals("a") || variabletexto.equals("e") || variabletexto.equals("i") || variabletexto.equals("o") || variabletexto.equals("u"))
                {
                    System.out.println("Este tipo de caracter es permitido");
                }
                else{
                    System.out.println("Este parametro no esta permitido");
                }
                 
                break;
             
            default:
                System.out.println("Esta no es una opcion valida");  
                break;
        }
    }
 
}

En este programa se va analizar la estructura con la cual ingresamos las palabras o los números, es decir que solo puede ingresarse cierto numero de caracteres entre letras o números de acuerdo a la opción deseada.

Si se elige la opción de números solo podrás ingresar números enteros positivos del 0 al 9, si ingresamos algún otro numero diferente a los permitidos se mandara una alerta de que el numero que estamos ingresando no es valido en este programa.

En el caso de elegir la opción de texto, podremos ingresar letras básicas como son vocales: a,e,i,o,u. Si ingresamos alguna otra letra diferente a estas definidas se enviara un mensaje el cual es: Este parámetro no esta permitido y tendrás que entrar de nuevo al programa.





lunes, 27 de marzo de 2017

Construcción de analizadores sintácticos.

3.1 Analizadores sintácticos.

Es la fase del analizador que se encarga de chequear el texto de entrada en base a una gramática dada. Y en caso de que el programa de entrada sea válido, suministra el árbol sintáctico que lo reconoce. En teoría, se supone que la salida del analizador sintáctico es alguna representación del árbol sintáctico que reconoce la secuencia de tokens suministrada por el analizador léxico. 

En la práctica, el analizador sintáctico también hace: 

• Acceder a la tabla de símbolos (para hacer parte del trabajo del analizador semántico). 
• Chequeo de tipos ( del analizador semántico). 
• Generar código intermedio. 
• Generar errores cuando se producen. 

En definitiva, realiza casi todas las operaciones de la compilación. Este método de trabajo da lugar a los métodos de compilación dirigidos por sintaxis.
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:
  • Analizador 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.
  • Analizador 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í y un ejemplo es el Yacc.

Características

El análisis sintáctico descendente (ASD) intenta encontrar entre las producciones de la gramática la derivación por la izquierda del símbolo inicial para una cadena de entrada.
Parte del axioma de la gramática.
Procesa la entrada de izquierda a derecha.Escoge reglas gramaticales.
Bueno primeramente para trabajar el análisis sintáctico descendente se debe realizar primeramente algunas operaciones para que la gramática sea LL1 las cuales son:
– ELIMINAR AMBIGUEDAD: Para eliminar la ambigüedad se debe reescribir la gramática.
– ELIMINAR RECURSIVIDAD POR LA IZQUIERDA: Una gramática es recursiva por la izquierda si tiene un nodo Terminal a tal que existe una derivación A->Aα para alguna cadena . Es decir por simple observación podemos identificar.
Ventajas:

  • genera código intermedio
  • reconoce si una o varias cadenas de caracteres forman parte de un determinado lenguaje.
  • lenguajes libres de contexto.
  • pueden clasificarse dependiendo de la forma en como se construyen los nodos del árbol de derivación sintáctico: ascendentes y descendentes
Desventajas:

  • genera errores cuando se producen 
  • numerosos patrones de funcionamiento en ellos
Aplicabilidad:
El uso más común de los analizadores sintácticos es como parte de la fase de análisis de los compiladores. De modo que tienen que analizar el código fuente del lenguaje. Los lenguajes de programación tienden a basarse en gramáticas libres de contexto, debido a que se pueden escribir analizadores rápidos y eficientes para estas.
Las gramáticas libres de contexto tienen una expresividad limitada y sólo pueden expresar un conjunto limitado de lenguajes. Informalmente la razón de esto es que la memoria de un lenguaje de este tipo es limitada, la gramatica no puede recordar la presencia de una construcción en una entrada arbitrariamente larga y esto es necesario en un lenguaje en el que por ejemplo una variable debe ser declarada antes de que pueda ser referenciada. Las gramáticas más complejas no pueden ser analizadas de forma eficiente. Por estas razones es común crear un analizador permisivo para una gramática libre de contexto que acepta un super conjunto del lenguaje (acepta algunas construcciones inválidas), después del análisis inicial las construcciones incorrectas pueden ser filtradas.

3.1.2 
Eliminación de recursión izquierda en las gramáticas, arboles de sintaxis.
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.

Recursión por la izquierda inmediata simple  (Eliminación de la recursividad izquierda de las producciones)

En este caso la recursión por la izquierda se presenta solo en las reglas gramaticales

A → A α | β

Donde α y β son cadenas de terminales y no terminales y  β no comienza en A. Esta regla genera todas las cadenas de la forma β, β α, β α α…Todas las cadenas comienzan con una β, seguida por     (0 o mas α). Esta regla gramatical es equivalente a la expresión regular β αⁿ

Para eliminar  la recursión por la izquierda  volvemos a escribir estas reglas gramaticales divididas en dos: una para que primero genere β y otra que genere  las repeticiones de α utilizando recursión por la derecha en vez de recursión por la izquierda:

A → β A´
A´→ α A´|є

Ejemplo Considere de nueva cuenta la regla recursiva izquierda de la gramática de expresión simple:

exp → exp opsuma term | term

La forma de esta regla es  A → A α | β, con A= exp,  α=opsuma term y β=term. Al volverla a escribir para eliminar la recursividad por la izquierda obtenemos que

exp → term exp´
exp´→ opsuma term exp´ |є

Recursión por la izquierda inmediata general  (Eliminando la recursión directa por la izquierda de una producción general)

Este es el caso en que tenemos producciones de la forma

A → A α| A α|……|A α n | β | β |……… | βm

Donde ninguna β…… βm comienzan con una A. Después se sustituyen las producciones de A por:

A→ β A´| β  A´|…….| βm  A´
A´→ α A´| α A´|…….| α n A´|є

Ejemplo. Considere la regla gramatical

exp → exp + term | exp -  term | term

Eliminemos la recursión por la izquierda de la manera siguiente

exp → term exp´
exp → + term exp´ | - term exp´ |є

Recursión por la izquierda general (Eliminación de la recursividad izquierda de una gramática completa puede ser mas difícil debido a la recursividad izquierda indirecta).

Es indirectamente recursiva porque elimina por completo la recursividad izquierda


El algoritmo que aquí describimos  eliminara sistemáticamente la recursión por la izquierda general de una gramática. Siempre funciona si la gramática no tiene ciclos (donde un ciclo es una derivación de por lo menos un paso que comienza y finaliza con el mismo no terminal: 
A      A)


O producciones  є (producciones de la forma A → є)

Algoritmo

Entrada La gramática G sin ciclos ni producciones є
Salida Una gramática equivalente sin recursión por la izquierda

1.- Ordénense los no terminales en un orden A, A,……..,An
2.- PARA i =: 1 hasta n HACER
       COMIENZA {PARA i}
      PARA  j=: 1 hasta i-1 HACER
Reemplace cada producción de la forma  Ai → Ajβ por las producciones:

Ai → αβ| αβ|……| αk β

Donde:

Aj→ α| α|……| αk

Son todas las producciones de Aj actuales

Eliminar  la recursividad inmediata por la izquierda entre las producciones de Ai

Ejemplo: Dada la gramática

S→ Aa | b
A→ Ac|Sd|є

Se ordenan los no terminales S, A. No hay recursión directa por la izquierda entre las producciones de S, de modo que no ocurre  nada durante el paso 2 para el caso i=1. Para i=2, se sustituyen las producciones de S en A→ Sd para obtener las siguientes producciones de A.

A → Ac|Aad | bd  |є

Eliminando la recursión directa por la izquierda entre las producciones de A, se obtiene la siguiente gramática

S → Aa | b
A→bdA´ | A´
A´→c A´|ad A´| є

La eliminación de la recursión por la izquierda no cambia el lenguaje que se esta reconociendo, pero modifica la gramática y, en consecuencia, también los arboles de derivación.