***Administración de la Memoria ***
La parte del sistema operativo que administra la memoria se llama administrador de la memoria. Para ello existen diferentes esquemas de administración de memoria desde los mas simples hasta los mas elaborados entre los cuales se ubican:
• Administración de la memoria sin intercambio o paginación.
Los sistemas de administración de memoria se pueden clasificar en dos tipos. Los que desplazan los procesos de la memoria principal al disco y viceversa durante la ejecución (intercambio y paginación) y aquellos que no.
• Monopogramación sin intercambio o paginación.
Es en forma secuencial pues solo se tiene un objeto en memoria en cada instante, el usuario carga toda la memoria con un programa, esto implica que cada proceso debe contener controladores de dispositivo para cada uno de los dispositivos E/S que utilice.
• Multiprogramación y uso de la memoria.
La multiprogramación facilita la programación de una aplicación al dividirla en dos o mas procesos. La mayoría de los procesos tardan cierto tiempo en la espera de datos de dispositivos E/S.
Un modelo para el uso y aprovechamiento de la CPU es el modelo probabilístico dado por la fórmula :
Uso de la CPU = 1 - pn
• Multiprogramación con particiones fijas
El objetivo en todo esto es tener mas de un proceso en memoria a la vez, solución posible sería dividir la memoria en n partes al inicio de una sesión de uso de la máquina, pero aún así se obtiene el desperdicio de particiones grandes con una tarea pequeña, la respuesta puede ser tener particiones pequeñas también.
Las tareas que van llegando se forman hasta que una partición adecuada está disponible, en cuyo momento la tarea se carga en esa partición y se ejecuta hasta terminar.
• Segmentación
La memoria virtual que hemos analizado hasta ahora es unidimensional, puesto que cada segmento constituye un espacio independiente de direcciones, los distintos segmentos pueden crecer o reducirse en forma independiente sin afectar a los demás.
Una memoria segmentada tiene otras ventajas como hacer mas sencilla la administración de las estructuras de datos que crecen o se reducen, si cada procedimiento ocupa un segmento independiente con la posición inicial cero el ligado independiente de los procesos compilados es mucho mas sencillo.
Bit que se activa si se hace referencia a la página en cuestión
Bit que se activa si se modifica la página
***Memoria Virtual***
La memoria virtual es una técnica que permite al software usar más memoria principal que la que realmente posee el ordenador. La mayoría de los ordenadores tienen cuatro tipos de memoria: registros en la CPU, la memoria caché (tanto dentro como fuera del CPU), la memoria física (generalmente en forma de RAM, donde la CPU puede escribir y leer directa y razonablemente rápido) y el disco duro que es mucho más lento, pero también más grande y barato.
Muchas aplicaciones requieren el acceso a más información (código y datos) que la que se puede mantener en memoria física. Esto es así sobre todo cuando el sistema operativo permite múltiples procesos y aplicaciones ejecutándose simultáneamente. Una solución al problema de necesitar mayor cantidad de memoria de la que se posee consiste en que las aplicaciones mantengan parte de su información en disco, moviéndola a la memoria principal cuando sea necesario. Hay varias formas de hacer esto. Una opción es que la aplicación misma sea responsable de decidir qué información será guardada en cada sitio (segmentación), y de traerla y llevarla. La desventaja de esto, además de la dificultad en el diseño e implementación del programa, es que es muy probable que los intereses sobre la memoria de dos o varios programas generen conflictos entre sí: cada programador podría realizar su diseño teniendo en cuenta que es el único programa ejecutándose en el sistema. La alternativa es usar memoria virtual, donde la combinación entre hardware especial y el sistema operativo hace uso de la memoria principal y la secundaria para hacer parecer que el ordenador tiene mucha más memoria principal (RAM) que la que realmente posee. Este método es invisible a los procesos. La cantidad de memoria máxima que se puede hacer ver que hay tiene que ver con las características del procesador. Por ejemplo, en un sistema de 32 bits, el máximo es 232, lo que da 4096 Megabytes (4 Gigabytes).
Todo esto hace el trabajo del programador de aplicaciones mucho más fácil, al poder ignorar completamente la necesidad de mover datos entre los distintos espacios de memoria.
Aunque la memoria virtual podría estar implementada por el software del sistema operativo, en la práctica casi siempre se usa una combinación de hardware y software, dado el esfuerzo extra que implicaría para el procesador.
Operación básica
Cuando se usa Memoria Virtual, o cuando una dirección es leída o escrita por la CPU, una parte del hardware dentro de la computadora traduce las direcciones de memoria generadas por el software (direcciones virtuales) en:
• la dirección real de memoria (la dirección de memoria física), o
• una indicación de que la dirección de memoria deseada no se encuentra en memoria principal (llamado excepción de memoria virtual)
En el primer caso, la referencia a la memoria es completada, como si la memoria virtual no hubiera estado involucrada: el software accede donde debía y sigue ejecutando normalmente. En el segundo caso, el sistema operativo es invocado para manejar la situación y permitir que el programa siga ejecutando o aborte según sea el caso. La memoria virtual es una técnica para proporcionar la simulación de un espacio de memoria mucho mayor que la memoria física de una máquina. Esta "ilusión" permite que los programas se ejecuten sin tener en cuenta el tamaño exacto de la memoria física.
La ilusión de la memoria virtual está soportada por el mecanismo de traducción de memoria, junto con una gran cantidad de almacenamiento rápido en disco duro. Así en cualquier momento el espacio de direcciones virtual hace un seguimiento de tal forma que una pequeña parte de él, está en memoria real y el resto almacenado en el disco, y puede ser referenciado fácilmente.
Debido a que sólo la parte de memoria virtual que está almacenada en la memoria principal, es accesible a la CPU, según un programa va ejecutándose, la proximidad de referencias a memoria cambia, necesitando que algunas partes de la memoria virtual se traigan a la memoria principal desde el disco, mientras que otras ya ejecutadas, se pueden volver a depositar en el disco (archivos de paginación).
La memoria virtual ha llegado a ser un componente esencial de la mayoría de los sistemas operativos actuales. Y como en un instante dado, en la memoria sólo se tienen unos pocos fragmentos de un proceso dado, se pueden mantener más procesos en la memoria. Es más, se ahorra tiempo, porque los fragmentos que no se usan no se cargan ni se descargan de la memoria. Sin embargo, el sistema operativo debe saber cómo gestionar este esquema.
La memoria virtual también simplifica la carga del programa para su ejecución llamada reubicación, este procedimiento permite que el mismo programa se ejecute en cualquier posición de la memoria física.
En un estado estable, prácticamente toda la memoria principal estará ocupada con fragmentos de procesos, por lo que el procesador y el S.O tendrán acceso directo a la mayor cantidad de procesos posibles, y cuando el S.O traiga a la memoria un fragmento, deberá expulsar otro. Si expulsa un fragmento justo antes de ser usado, tendrá que traer de nuevo el fragmento de manera casi inmediata. Demasiados intercambios de fragmentos conducen a lo que se conoce como hiperpaginación: donde el procesador consume más tiempo intercambiando fragmentos que ejecutando instrucciones de usuario. Para evitarlo el sistema operativo intenta adivinar, en función de la historia reciente, qué fragmentos se usarán con menor probabilidad en un futuro próximo (véase algoritmos de reemplazo de páginas).
Los argumentos anteriores se basan en el principio de cercanía de referencias o principio de localidad que afirma que las referencias a los datos y el programa dentro de un proceso tienden a agruparse. Por lo tanto, es válida la suposición de que, durante cortos períodos de tiempo, se necesitarán sólo unos pocos fragmentos de un proceso.
Una manera de confirmar el principio de cercanía es considerar el rendimiento de un proceso en un entorno de memoria virtual.
El principio de cercanía sugiere que los esquemas de memoria virtual pueden funcionar. Para que la memoria virtual sea práctica y efectiva, se necesitan dos ingredientes. Primero, tiene que existir un soporte de hardware y, en segundo lugar, el S.O debe incluir un software para gestionar el movimiento de páginas o segmentos entre memoria secundaria y memoria principal.
Justo después de obtener la dirección física y antes de consultar el dato en memoria principal se busca en memoria-cache, si esta entre los datos recientemente usados la búsqueda tendrá éxito, pero si falla, la memoria virtual consulta memoria principal , ó, en el peor de los casos se consulta de disco (swapping).
Detalles
La traducción de las direcciones virtuales a reales es implementada por una Unidad de Manejo de Memoria (MMU). El sistema operativo es el responsable de decidir qué partes de la memoria del programa es mantenida en memoria física. Además mantiene las tablas de traducción de direcciones (si se usa paginación la tabla se denomina tabla de paginación), que proveen las relaciones entre direcciones virtuales y físicas, para uso de la MMU. Finalmente, cuando una excepción de memoria virtual ocurre, el sistema operativo es responsable de ubicar un área de memoria física para guardar la información faltante, trayendo la información desde el disco, actualizando las tablas de traducción y finalmente continuando la ejecución del programa que dio la excepción de memoria virtual desde la instrucción que causó el fallo.
En la mayoría de las computadoras, las tablas de traducción de direcciones de memoria se encuentran en memoria física. Esto implica que una referencia a una dirección virtual de memoria necesitará una o dos referencias para encontrar la entrada en la tabla de traducción, y una más para completar el acceso a esa dirección.
Para acelerar el desempeño de este sistema, la mayoría de las Unidades Centrales de Proceso (CPU) incluyen una MMU en el mismo chip, y mantienen una tabla de las traducciones de dirrecciones virtuales a reales usadas recientemente, llamada Translation Lookaside Buffer (TLB). El uso de este buffer hace que no se requieran referencias de memoria adicionales, por lo que se ahorra tiempo al traducir.
En algunos procesadores, esto es realizado enteramente por el hardware. En otros, se necesita de la asistencia del sistema operativo: se levanta una excepción, y en ella el sistema operativo reemplaza una de las entradas del TLB con una entrada de la tabla de traducción, y la instrucción que hizo la referencia original a memoria es reejecutada.
El hardware que tiene soporte para memoria virtual, la mayoría de la veces también permite protección de memoria. La MMU puede tener la habilidad de variar su forma de operación de acuerdo al tipo de referencia a memoria (para leer, escribir, o ejecutar), así como el modo en que se encontraba el CPU en el momento de hacer la referencia a memoria. Esto permite al sistema operativo proteger su propio código y datos (como las tablas de traducción usadas para memoria virtual) de corromperse por una aplicación, y de proteger a las aplicaciones que podrían causar problemas entre sí.
Paginación y memoria virtual
La memoria virtual usualmente (pero no necesariamente) es implementada usando paginación. En paginación, los bits menos significativos de la dirección de memoria virtual son preservados y usados directamente como los bits de orden menos significativos de la dirección de memoria física. Los bits más significativos son usados como una clave en una o más tablas de traducción de direcciones (llamadas tablas de paginación), para encontrar la parte restante de la dirección física buscada
martes, 27 de abril de 2010
Administracion De Procesos
¿Qué es un proceso?
Un proceso es un programa en ejecución. Un proceso simple tiene un hilo de ejecución, por el momento dejemos esta última definición como un concepto, luego se verá en más detalle el concepto de hilo. Una vez definido que es un proceso nos podríamos preguntar cuál es la diferencia entre un programa y un proceso, y básicamente la diferencia es que un proceso es una actividad de cierto tipo que contiene un programa, entradas salidas y estados.
Los procesos pueden ser cooperantes o independientes, en el primer caso se entiende que los procesos interactúan entre sí y pertenecen a una misma aplicación. En el caso de procesos independientes en general se debe a que no interactúan y un proceso no requiere información de otros o bien porque son procesos que pertenecen a distintos usuarios.
Estados de los procesos
Un proceso puede estar en cualquiera de los siguientes tres estados: Listo, En ejecución y Bloqueado.
Los procesos en el estado listo son los que pueden pasar a estado de ejecución si el planificador los selecciona. Los procesos en el estado ejecución son los que se están ejecutando en el procesador en ese momento dado. Los procesos que se encuentran en estado bloqueado están esperando la respuesta de algún otro proceso para poder continuar con su ejecución. Por ejemplo operación de E/S.
Implantación de los procesos
La implementación del modelo de procesos se logra debido a que el sistema operativo almacena en una tabla denominada tabla de control de procesos información relativa a cada proceso que se esta ejecutando en el procesador. Cada línea de esta tabla representa a un proceso.
La información que se almacena es la siguiente:
1) Identificación del proceso.
2) Identificación del proceso padre.
3) Información sobre el usuario y grupo.
4) Estado del procesador.
5) Información de control de proceso
5.1) Información del planificador.
5.2) Segmentos de memoria asignados.
5.3) Recursos asignados.
Comunicación entre procesos
Las condiciones de competencia se dan cuando dos o más procesos intentan acceder a un mismo recurso.
Secciones críticas
Para solucionar las condiciones de competencia se implementó un modelo para prohibir que dos procesos accedan al mismo recurso. El modelo en cuestión se denomina exclusión mutua.
Exclusión mutua con espera ocupada
Las soluciones con espera ocupada funcionan de la siguiente manera, cuando un proceso intenta ingresar a su región crítica, verifica si esta permitida la entrada. Si no, el proceso se queda esperando hasta obtener el permiso.
Desactivación de interrupciones
El método más simple para evitar las condiciones de competencia es hacer que cada proceso desactive todas sus interrupciones antes de entrar a su sección crítica y las active una vez que salio de la misma. Este modelo como se puede observar, éste modelo tiene una gran problema y es que si se produce una falla mientras que el proceso esta en la región crítica no se puede salir de la misma y el sistema operativo no recuperaría el control.
Variables cerradura
En éste caso se genera una variable la cual puede tener dos valores o bien 0 (no hay ningún proceso en su sección crítica) o bien 1 (indicando que la sección crítica está ocupada) entonces cada proceso antes de ingresar a la sección crítica verifica el estado de la variable de cerradura y en caso de que la misma este en 0, le cambia el valor e ingresa a la misma y en caso de que la misma sea 1 el proceso se queda verificando el estado de la misma hasta que el mismo sea 0.
El problema aquí se presenta si dos procesos verifican al mismo tiempo que la variable cerradura esta en 0 e ingresan a la región crítica.
Alternancia estricta
El algoritmo de alternancia estricta no bloquea el ingreso a la región crítica cuando otro proceso se esta ejecutando. El problema de ésta solución es que cuando un proceso no esta en la sección crítica igualmente tiene bloqueado el acceso a la misma y por lo tanto no permite que otro proceso que requiera ingresar a la misma logre hacerlo.
Instrucción TSL
Esta solución requiere ayuda del hardware y es debido a que en general las computadoras diseñadas para tener más de un procesador tienen una instrucción TEST AND SET LOCK
Dormir y despertar
El modelo de espera acotada tienen el inconveniente que se desperdicia tiempo de procesador.
El problema del productor y el consumidor
El problema del productor y el consumidor describe el echo de que cuando hay dos o más procesos interactuando a través de un buffer común habiendo procesos que ponen información o datos y otros que los sacan se pueden llegar a dar condiciones en las cuales los procesos que ingresan los datos no puedan hacerlo debido a que el buffer ya se encuentra lleno y para el caso de los que sacan los datos del buffer intenten sacar datos cuando ya no hay nada que sacar. Para evitar estas condiciones se desarrollaron métodos de comunicación/sincronización entre procesos en los cuales se impide que esto suceda haciendo que el proceso productor "duerma" si el buffer está lleno y una vez que exista espacio el proceso "consumidor" despierte al productor para que siga generando o viceversa.
Planificación de procesos
La planificación es el proceso por el cual el sistema operativo selecciona que proceso ejecutar. La selección del proceso se basa en alguno de los algoritmos de planificación que se describen más abajo.
Expulsión
Es la característica por el cual el sistema operativo puede o no expulsar del estado de ejecución a un proceso dado. En este sentido entonces tenemos la planificación apropiativa en la cual el sistema operativo puede cortar en cualquier momento la ejecución de un proceso y la planificación no apropiativa en la cual una vez que el proceso esta en ejecución el sistema operativo no puede sacarlo de ese estado.
Objetivos de la planificación
Los objetivos de la planificación de proceso son:
• Equidad, todos los procesos deben poder ejecutarse
• Eficacia, mantener ocupada la CPU un 100% del tiempo
• Tiempo de respuesta, minimizar el tiempo de respuesta al usuario
• Tiempo de regreso, minimizar el tiempo que deben esperar los usuarios por lotes para obtener sus resultados
• Rendimiento, maximizar el número de tareas procesadas por hora.
Algoritmos de planificación
Los algoritmos de planificación son los que definen que política se va a seguir para que un proceso pase al estado de ejecución
.
Planificación Round-Robin
En este tipo de planificación cada proceso tiene asignado un quantum de tiempo para ejecutarse y en el caso de que no pueda terminar la ejecución en su quantum el proceso pasa de nuevo a la cola de procesos para ser ejecutado por otro quantum luego de recorrer la cola para asegurarse que todos los procesos reciban ese quantum de procesamiento.
Planificación por prioridad
En la planificación round-robin todos los procesos son tratados con la misma prioridad. Para el caso de este tipo de planificación a cada proceso se le asigna una prioridad y los mismos son ejecutados
Colas múltiples
Las colas múltiples están basadas en una pila que sirve como índice de una lista de procesos que se tienen que ejecutar.
Primero el trabajo más corto
Este tipo de algoritmo de planificación se usa para trabajos en batch o de procesamiento or lotes en los cuales se puede saber cual es el tiempo de duración de la ejecución de cada proceso y entonces se puede seleccionar primero el trabajo más corto. El problema que se presenta con éste algoritmo es que los grandes procesos podrían sufrir de inanición dado que cualquier proceso pequeño se "cuela" sobre uno de mayor tamaño y como resultado final se podría dar el caso que el proceso grande nunca obtenga procesamiento.
Planificación garantizada
En este modelo de planificación se tiene en cuenta la cantidad de usuarios en el sistema y se le asigna a cada uno el tiempo de ejecución de 1/n (siendo n la cantidad total de usuarios) de esa forma el planificador tiene que llevar cuenta del tiempo de ejecución de los procesos y balancear el tiempo que están utilizando el procesador para cumplir con la ecuación previa.
Procesos ligeros
Los procesos ligeros son programas en ejecución son básicamente procesos pero a diferencia de éstos últimos que solo tienen un hilo de ejecución los primeros tienen el hilo principal más hilos secundarios o hijos, en éste caso todos los procesos hijos comparten la información del hilo principal pero además puede cada hilo tener su información privada.
Dentro de la información propia tenemos:
• Contador de programa
• Pila
• Registros.
• Estado del proceso ligero.
• Dentro de la información compartida tenemos:
• Variables globales.
• Archivos abiertos
• Señales
• Semáforos.
• Contabilidad.
Señales
Las señales son el mecanismo de comunicación que se establece entre los procesos. Para comparar se puede decir que las señales son a los procesos lo que las interrupciones son al procesador. Cuando un proceso recibe una señal detiene su ejecución, bifurca a la rutina del tratamiento de la señal que esta en el mismo proceso y luego una vez finalizado sigue la ejecución en el punto que había bifurcado anteriormente.
Las señales se pueden originar en un proceso o bien en el sistema operativo. Las señales se pueden enviar entre procesos, solo los que tengan el mismo uid, o bien el sistema operativo puede enviarle una señal a un proceso, por ejemplo excepciones de ejecución.
Un proceso es un programa en ejecución. Un proceso simple tiene un hilo de ejecución, por el momento dejemos esta última definición como un concepto, luego se verá en más detalle el concepto de hilo. Una vez definido que es un proceso nos podríamos preguntar cuál es la diferencia entre un programa y un proceso, y básicamente la diferencia es que un proceso es una actividad de cierto tipo que contiene un programa, entradas salidas y estados.
Los procesos pueden ser cooperantes o independientes, en el primer caso se entiende que los procesos interactúan entre sí y pertenecen a una misma aplicación. En el caso de procesos independientes en general se debe a que no interactúan y un proceso no requiere información de otros o bien porque son procesos que pertenecen a distintos usuarios.
Estados de los procesos
Un proceso puede estar en cualquiera de los siguientes tres estados: Listo, En ejecución y Bloqueado.
Los procesos en el estado listo son los que pueden pasar a estado de ejecución si el planificador los selecciona. Los procesos en el estado ejecución son los que se están ejecutando en el procesador en ese momento dado. Los procesos que se encuentran en estado bloqueado están esperando la respuesta de algún otro proceso para poder continuar con su ejecución. Por ejemplo operación de E/S.
Implantación de los procesos
La implementación del modelo de procesos se logra debido a que el sistema operativo almacena en una tabla denominada tabla de control de procesos información relativa a cada proceso que se esta ejecutando en el procesador. Cada línea de esta tabla representa a un proceso.
La información que se almacena es la siguiente:
1) Identificación del proceso.
2) Identificación del proceso padre.
3) Información sobre el usuario y grupo.
4) Estado del procesador.
5) Información de control de proceso
5.1) Información del planificador.
5.2) Segmentos de memoria asignados.
5.3) Recursos asignados.
Comunicación entre procesos
Las condiciones de competencia se dan cuando dos o más procesos intentan acceder a un mismo recurso.
Secciones críticas
Para solucionar las condiciones de competencia se implementó un modelo para prohibir que dos procesos accedan al mismo recurso. El modelo en cuestión se denomina exclusión mutua.
Exclusión mutua con espera ocupada
Las soluciones con espera ocupada funcionan de la siguiente manera, cuando un proceso intenta ingresar a su región crítica, verifica si esta permitida la entrada. Si no, el proceso se queda esperando hasta obtener el permiso.
Desactivación de interrupciones
El método más simple para evitar las condiciones de competencia es hacer que cada proceso desactive todas sus interrupciones antes de entrar a su sección crítica y las active una vez que salio de la misma. Este modelo como se puede observar, éste modelo tiene una gran problema y es que si se produce una falla mientras que el proceso esta en la región crítica no se puede salir de la misma y el sistema operativo no recuperaría el control.
Variables cerradura
En éste caso se genera una variable la cual puede tener dos valores o bien 0 (no hay ningún proceso en su sección crítica) o bien 1 (indicando que la sección crítica está ocupada) entonces cada proceso antes de ingresar a la sección crítica verifica el estado de la variable de cerradura y en caso de que la misma este en 0, le cambia el valor e ingresa a la misma y en caso de que la misma sea 1 el proceso se queda verificando el estado de la misma hasta que el mismo sea 0.
El problema aquí se presenta si dos procesos verifican al mismo tiempo que la variable cerradura esta en 0 e ingresan a la región crítica.
Alternancia estricta
El algoritmo de alternancia estricta no bloquea el ingreso a la región crítica cuando otro proceso se esta ejecutando. El problema de ésta solución es que cuando un proceso no esta en la sección crítica igualmente tiene bloqueado el acceso a la misma y por lo tanto no permite que otro proceso que requiera ingresar a la misma logre hacerlo.
Instrucción TSL
Esta solución requiere ayuda del hardware y es debido a que en general las computadoras diseñadas para tener más de un procesador tienen una instrucción TEST AND SET LOCK
Dormir y despertar
El modelo de espera acotada tienen el inconveniente que se desperdicia tiempo de procesador.
El problema del productor y el consumidor
El problema del productor y el consumidor describe el echo de que cuando hay dos o más procesos interactuando a través de un buffer común habiendo procesos que ponen información o datos y otros que los sacan se pueden llegar a dar condiciones en las cuales los procesos que ingresan los datos no puedan hacerlo debido a que el buffer ya se encuentra lleno y para el caso de los que sacan los datos del buffer intenten sacar datos cuando ya no hay nada que sacar. Para evitar estas condiciones se desarrollaron métodos de comunicación/sincronización entre procesos en los cuales se impide que esto suceda haciendo que el proceso productor "duerma" si el buffer está lleno y una vez que exista espacio el proceso "consumidor" despierte al productor para que siga generando o viceversa.
Planificación de procesos
La planificación es el proceso por el cual el sistema operativo selecciona que proceso ejecutar. La selección del proceso se basa en alguno de los algoritmos de planificación que se describen más abajo.
Expulsión
Es la característica por el cual el sistema operativo puede o no expulsar del estado de ejecución a un proceso dado. En este sentido entonces tenemos la planificación apropiativa en la cual el sistema operativo puede cortar en cualquier momento la ejecución de un proceso y la planificación no apropiativa en la cual una vez que el proceso esta en ejecución el sistema operativo no puede sacarlo de ese estado.
Objetivos de la planificación
Los objetivos de la planificación de proceso son:
• Equidad, todos los procesos deben poder ejecutarse
• Eficacia, mantener ocupada la CPU un 100% del tiempo
• Tiempo de respuesta, minimizar el tiempo de respuesta al usuario
• Tiempo de regreso, minimizar el tiempo que deben esperar los usuarios por lotes para obtener sus resultados
• Rendimiento, maximizar el número de tareas procesadas por hora.
Algoritmos de planificación
Los algoritmos de planificación son los que definen que política se va a seguir para que un proceso pase al estado de ejecución
.
Planificación Round-Robin
En este tipo de planificación cada proceso tiene asignado un quantum de tiempo para ejecutarse y en el caso de que no pueda terminar la ejecución en su quantum el proceso pasa de nuevo a la cola de procesos para ser ejecutado por otro quantum luego de recorrer la cola para asegurarse que todos los procesos reciban ese quantum de procesamiento.
Planificación por prioridad
En la planificación round-robin todos los procesos son tratados con la misma prioridad. Para el caso de este tipo de planificación a cada proceso se le asigna una prioridad y los mismos son ejecutados
Colas múltiples
Las colas múltiples están basadas en una pila que sirve como índice de una lista de procesos que se tienen que ejecutar.
Primero el trabajo más corto
Este tipo de algoritmo de planificación se usa para trabajos en batch o de procesamiento or lotes en los cuales se puede saber cual es el tiempo de duración de la ejecución de cada proceso y entonces se puede seleccionar primero el trabajo más corto. El problema que se presenta con éste algoritmo es que los grandes procesos podrían sufrir de inanición dado que cualquier proceso pequeño se "cuela" sobre uno de mayor tamaño y como resultado final se podría dar el caso que el proceso grande nunca obtenga procesamiento.
Planificación garantizada
En este modelo de planificación se tiene en cuenta la cantidad de usuarios en el sistema y se le asigna a cada uno el tiempo de ejecución de 1/n (siendo n la cantidad total de usuarios) de esa forma el planificador tiene que llevar cuenta del tiempo de ejecución de los procesos y balancear el tiempo que están utilizando el procesador para cumplir con la ecuación previa.
Procesos ligeros
Los procesos ligeros son programas en ejecución son básicamente procesos pero a diferencia de éstos últimos que solo tienen un hilo de ejecución los primeros tienen el hilo principal más hilos secundarios o hijos, en éste caso todos los procesos hijos comparten la información del hilo principal pero además puede cada hilo tener su información privada.
Dentro de la información propia tenemos:
• Contador de programa
• Pila
• Registros.
• Estado del proceso ligero.
• Dentro de la información compartida tenemos:
• Variables globales.
• Archivos abiertos
• Señales
• Semáforos.
• Contabilidad.
Señales
Las señales son el mecanismo de comunicación que se establece entre los procesos. Para comparar se puede decir que las señales son a los procesos lo que las interrupciones son al procesador. Cuando un proceso recibe una señal detiene su ejecución, bifurca a la rutina del tratamiento de la señal que esta en el mismo proceso y luego una vez finalizado sigue la ejecución en el punto que había bifurcado anteriormente.
Las señales se pueden originar en un proceso o bien en el sistema operativo. Las señales se pueden enviar entre procesos, solo los que tengan el mismo uid, o bien el sistema operativo puede enviarle una señal a un proceso, por ejemplo excepciones de ejecución.
Sistemas Operativos
Un Sistema operativo (SO) es un software que actúa de interfaz entre los dispositivos de hardware y los programas usados por el usuario para manejar un computador. Es responsable de gestionar, coordinar las actividades y llevar a cabo el intercambio de los recursos y actúa como estación para las aplicaciones que se ejecutan en la máquina.
Uno de los más prominentes ejemplos de sistema operativo, es el núcleo Linux, el cual junto a las herramientas GNU, forman las llamadas distribuciones Linux.
Nótese que es un error común muy extendido denominar al conjunto completo de herramientas sistema operativo, pues este, es sólo el núcleo y no necesita de entorno operador para estar operativo y funcional. Este error de precisión, se debe a la modernización de la informática llevada a cabo a finales de los 80, cuando la filosofía de estructura básica de funcionamiento de los grandes computadores se rediseñó a fin de llevarla a los hogares y facilitar su uso, cambiando el concepto de computador multiusuario, (muchos usuarios al mismo tiempo) por un sistema monousuario (únicamente un usuario al mismo tiempo) más sencillo de gestionar. (Véase AmigaOS, beOS o MacOS como los pioneros de dicha modernización, cuando los Amiga, fueron bautizados con el sobrenombre de Video Toasters por su capacidad para la Edición de vídeo en entorno multitarea round robin, con gestión de miles de colores e interfaces intuitivos para diseño en 3D con programas como Imagine o Scala multimedia, entre muchos otros.)
Uno de los propósitos de un sistema operativo como programa estación principal, consiste en gestionar los recursos de localización y protección de acceso del hardware, hecho que alivia a los programadores de aplicaciones de tener que tratar con estos detalles. Se encuentran en la mayoría de los aparatos electrónicos que utilizan microprocesadores para funcionar. (teléfonos móviles, reproductores de DVD, computadoras, radios, etc.)
Parte de la infraestructura de la World Wide Web está compuesta por el Sistema Operativo de Internet, creado por Cisco Systems para gestionar equipos de interconexión como los conmutadores y los enrutadores.
***Tipos De Sistemas Operativos (Historia De Los Sistemas Operativos Windows) ***
Noviembre de 1985 - Windows 1.01 1.01 - Sin soporte. -
Noviembre de 1987 - Windows 2.03 2.03 - Sin soporte. -
Mayo de 1988 Windows - 2.10 2.10 - Sin soporte. -
Marzo de 1989 Windows - 2.11 2.11 - Sin soporte. -
Mayo de 1990 Windows 3.0 3.0 Sin soporte. -
Marzo de 1992 Windows 3.1x 3. -1 Sin soporte -Version de IE 5
Octubre de 1992 Windows For Workgroups 3.1 3.1 Sin soporte -Version de IE 5
Julio de 1993 Windows NT 3.1 NT 3.1 Sin soporte - Version de IE 5
Diciembre de 1993 Windows For Workgroups 3.11 3.11 Sin soporte- Version de IE 5
Enero de 1994 Windows 3.2 (publicado en chino simplificado) 3.2 Sin soporte - Version de IE 5
Septiembre de 1994 Windows NT 3.5 NT 3.5 Sin soporte -Version de IE 5
Mayo de 1995 Windows NT 3.51 NT 3.51 Sin soporte - Version de IE 5
Agosto de 1995 Windows 95 4.0.950 Sin soporte - Version de IE 5.5
Julio de 1996 Windows NT 4.0 NT 4.0.1381 Sin soporte- Version de IE 6
Junio de 1998 Windows 98 4.10.1998 Sin soporte - Version IE 6
Mayo de 1999 Windows 98 SE 4.10.2222 Sin soporte - Version de IE 6
Febrero de 2000 Windows 2000 NT 5.0.2195 Únicamente soporte extendido hasta el 13 de julio de 2010 para Service Pack 4 (versión RTM, SP1, SP2 Y SP3 sin soporte) - Version de IE 6
Septiembre de 2000 Windows Me 4.90.3000 Sin soporte - Version de IE 6
Octubre de 2001 Windows XP NT 5.1.2600 Únicamente soporte extendido hasta el 8 de abril de 2014 para Service Pack 3 y 13 de julio de 2010 para Service pack 2 (versión RTM y SP1 sin soporte) - Version De IE 8
Abril de 2003 Windows Server 2003 NT 5.2.3790 Soporte estándar vigente para Service pack 2 y versión R2 (versión RTM y SP1 sin soporte) - Version de IE 8
Abril de 2005 Windows XP Professional x64 Edition NT 5.2.3790 Únicamente soporte extendido hasta el 8 de abril de 2014 para Service pack 2 (versión RTM y SP1 sin soporte) - Version de IE 8
Julio de 2006 Windows Fundamentals for Legacy PC NT 5.1.2600 Soporte estándar vigente - Version de IE 8
Noviembre de 2006 (licencias por volumen)
Enero de 2007 (retail) Windows Vista NT 6.0.6002 Soporte estándar vigente para Service pack 1 o Service pack 2 (versión RTM sin soporte). Versión cambiada a NT 6.0.6001 con el Service Pack 1 (4 de febrero de 2008) y a NT 6.0.6002 con el Service Pack 2 (28 de abril de 2009) - Version de IE 8
Julio de 2007 Windows Home Server NT 5.2.4500 Soporte estándar vigente -Version deIE 8
Febrero de 2008 Windows Server 2008 NT 6.0.6002 Soporte estándar vigente. Versión cambiada a NT 6.0.6002 con el Service Pack 2 (28 de abril de 2009) - Version de IE 8
Octubre 2009[6] Windows 7 y Windows Server 2008 R2 NT 6.1.7600 Soporte estándar vigente - Version de IE8
2012 Windows 8 - Todo Por Confirmar
***Necesidad De Los Sistemas Operativos***
Se mencionaran los mas recientes de Windows:
Windows XP (cuyo nombre en clave inicial fue Whistler) es una versión de Microsoft Windows, línea de sistemas operativos desarrollado por Microsoft. Lanzado al mercado el 25 de octubre de 2001, actualmente es el sistema operativo más utilizado del planeta (con una cuota de mercado del 58,4%) y se considera que existen más de 400 millones de copias funcionando.[3] Las letras "XP" provienen de la palabra eXPeriencia (eXPerience en inglés).
Dispone de versiones para varios entornos informáticos, incluyendo PCs domésticos o de negocios, equipos portátiles, "netbooks", "tablet PC" y "media center". Sucesor de Windows 2000 junto con Windows ME, y antecesor de Windows Vista, es el primer sistema operativo de Microsoft orientado al consumidor que se construye con un núcleo y arquitectura de Windows NT disponible en versiones para plataformas de 32 y 64 bits.
A diferencia de versiones anteriores de Windows, al estar basado en la arquitectura de Windows NT proveniente del código de Windows 2000, presenta mejoras en la estabilidad y el rendimiento. Tiene una interfaz gráfica de usuario (GUI) perceptiblemente reajustada (denominada Luna), la cual incluye características rediseñadas, algunas de las cuales se asemejan ligeramente a otras GUI de otros sistemas operativos, cambio promovido para un uso más fácil que en las versiones anteriores. Se introdujeron nuevas capacidades de gestión de software para evitar el "DLL Hell" (infierno de las DLLs) que plagó las viejas versiones. Es también la primera versión de Windows que utiliza la activación del producto para reducir la piratería del software, una restricción que no sentó bien a algunos usuarios. Ha sido también criticado por las vulnerabilidades de seguridad, integración de Internet Explorer, la inclusión del reproductor Windows Media Player y aspectos de su interfaz.
Requisitos
Procesador: 800 MHz o más
Memoria: 256 MB RAM o superior
Vídeo: VGA /2 MB de video o más
Disco duro: 20 GB o superior
Windows Vista es una versión de Microsoft Windows, línea de sistemas operativos desarrollada por Microsoft. Esta versión se enfoca para ser utilizada en equipos de escritorio en hogares y oficinas, equipos portátiles, "tablet PC" y equipos "media center".
El proceso de desarrollo terminó el 8 de noviembre de 2006 y en los siguientes tres meses fue entregado a los fabricantes de hardware y software, clientes de negocios y canales de distribución. El 30 de enero de 2007 fue lanzado mundialmente y fue puesto a disposición para ser comprado y descargado desde el sitio web de Microsoft.
La aparición de Windows Vista viene más de 5 años después de la introducción de su predecesor, Windows XP, es decir el tiempo más largo entre dos versiones consecutivas de Microsoft Windows. La campaña de lanzamiento fue incluso más costosa que la de Windows 95, ocurrido el 25 de agosto de 1995, debido a que esta incluyó además otros productos como Microsoft Office 2007 y Exchange Server 2007.[cita requerida] Actualmente Windows Vista ya tiene un sucesor, llamado Windows 7.
Windows 7 es la versión más reciente de Microsoft Windows, línea de sistemas operativos producida por Microsoft Corporation. Esta versión está diseñada para uso en PC, incluyendo equipos de escritorio en hogares y oficinas, equipos portátiles, "tablet PC", "netbooks" y equipos "media center". El desarrollo de Windows 7 se completó el 22 de julio de 2009, siendo entonces confirmada su fecha de venta oficial para el 22 de octubre de 2009 junto a su equivalente para servidores Windows Server 2008 R2
A diferencia del gran salto arquitectónico y de características que sufrió su antecesor Windows Vista con respecto a Windows XP, Windows 7 fue concebido como una actualización incremental y focalizada de Vista y su núcleo NT 6.0, lo que permitió el mantener cierto grado de compatibilidad con aplicaciones y hardware en los que éste ya era compatible. Sin embargo, entre las metas de desarrollo para Windows 7 se dio importancia en mejorar su interfaz para volverla más accesible al usuario e incluir nuevas características que permitieran hacer tareas de una manera más fácil y rápida, al mismo tiempo en que se realizarían esfuerzos para lograr un sistema más ligero, estable y rápido.
Diversas presentaciones dadas por la compañía en el 2008 se enfocaron en demostrar capacidades multitáctiles, una interfaz rediseñada junto con una nueva barra de tareas y un sistema de redes domésticas fácil de usar denominado Grupo en el Hogar, además de grandes mejoras en el rendimiento general del equipo.
Requerimientos
Arquitectura 32 bits 64 bits
Procesador 1 GHz
Memoria RAM 1 GB de RAM 2 GB de RAM
Tarjeta gráfica Dispositivo de gráficos DirectX 9 con soporte de controladores WDDM 1.0 (para Windows Aero)
Disco duro 16 GB de espacio libre 20 GB de espacio libre
Unidad óptica DVD-R/RW
***Componentes De Un Sistema Operativo***
Gestión de procesos
Un proceso es simplemente, un programa en ejecución que necesita recursos para realizar su tarea: tiempo de CPU, memoria, archivos y dispositivos de E/S. El SO es el responsable de:
* Crear y destruir los procesos.
* Parar y reanudar los procesos.
* Ofrecer mecanismos para que se comuniquen y sincronicen.
La gestión de procesos podría ser similar al trabajo de oficina. Se puede tener una lista de tareas a realizar y a estas fijarles prioridades alta, media, baja por ejemplo. Debemos comenzar haciendo las tareas de prioridad alta primero y cuando se terminen seguir con las de prioridad media y después las de baja. Una vez realizada la tarea se tacha. Esto puede traer un problema que las tareas de baja prioridad pueden que nunca lleguen a ejecutarse. y permanezcan en la lista para siempre. Para solucionar esto, se puede asignar alta prioridad a las tareas más antiguas.
Gestión de la memoria principal
La Memoria (informática) es una gran tabla de palabras o bytes que se referencian cada una mediante una dirección única. Este almacén de datos de rápido accesos es compartido por la CPU y los dispositivos de E/S, es volátil y pierde su contenido en los fallos del sistema. El SO es el responsable de:
* Conocer qué partes de la memoria están utilizadas y por quién.
* Decidir qué procesos se cargarán en memoria cuando haya espacio disponible.
* Asignar y reclamar espacio de memoria cuando sea necesario.
Gestión del almacenamiento secundario
Un sistema de almacenamiento secundario es necesario, ya que la memoria principal (almacenamiento primario) es volátil y además muy pequeña para almacenar todos los programas y datos. También es necesario mantener los datos que no convenga mantener en la memoria principal. El SO se encarga de:
* Planificar los discos.
* Gestionar el espacio libre.
* Asignar el almacenamiento.
El sistema de E/S
Consiste en un sistema de almacenamiento temporal (caché), una interfaz de manejadores de dispositivos y otra para dispositivos concretos. El sistema operativo debe gestionar el almacenamiento temporal de E/S y servir las interrupciones de los dispositivos de E/S.
Sistema de archivos
Los archivos son colecciones de información relacionada, definidas por sus creadores. Éstos almacenan programas (en código fuente y objeto) y datos tales como imágenes, textos, información de bases de datos, etc. El SO es responsable de:
* Construir y eliminar archivos y directorios.
* Ofrecer funciones para manipular archivos y directorios.
* Establecer la correspondencia entre archivos y unidades de almacenamiento.
* Realizar copias de seguridad de archivos.
Existen diferentes Sistemas de Archivos, es decir, existen diferentes formas de organizar la información que se almacena en las memorias (normalmente discos) de los ordenadores. Por ejemplo, existen los sistemas de archivos FAT, FAT32, EXT2, NTFS, etc.
Desde el punto de vista del usuario estas diferencias pueden parecer insignificantes a primera vista, sin embargo, existen diferencias muy importantes. Por ejemplo, los sistemas de ficheros FAT32 y NTFS, que se utilizan fundamentalmente en sistemas operativos de Microsoft, tienen una gran diferencia para un usuario que utilice una base de datos con bastante información ya que el tamaño máximo de un fichero con un Sistema de Archivos FAT32 está limitado a 4 gigabytes, sin embargo, en un sistema NTFS el tamaño es considerablemente mayor.
Sistemas de protección
Mecanismo que controla el acceso de los programas o los usuarios a los recursos del sistema. El SO se encarga de:
* Distinguir entre uso autorizado y no autorizado.
* Especificar los controles de seguridad a realizar.
* Forzar el uso de estos mecanismos de protección.
Sistema de comunicaciones
Para mantener las comunicaciones con otros sistemas es necesario poder controlar el envío y recepción de información a través de las interfaces de red. También hay que crear y mantener puntos de comunicación que sirvan a las aplicaciones para enviar y recibir información, y crear y mantener conexiones virtuales entre aplicaciones que están ejecutándose localmente y otras que lo hacen remotamente.
Programas de sistema
Son aplicaciones de utilidad que se suministran con el SO pero no forman parte de él. Ofrecen un entorno útil para el desarrollo y ejecución de programas, siendo algunas de las tareas que realizan:
* Manipulación y modificación de archivos.
* Información del estado del sistema.
* Soporte a lenguajes de programación.
* Comunicaciones.
Interpretes
En ciencias de la computación, intérprete o interpretador es un programa informático capaz de analizar y ejecutar otros programas, escritos en un lenguaje de alto nivel. Los intérpretes se diferencian de los compiladores en que mientras estos traducen un programa desde su descripción en un lenguaje de programación al código de máquina del sistema, los primeros (los intérpretes) sólo realizan la traducción a medida que sea necesaria, típicamente, instrucción por instrucción, y normalmente no guardan el resultado de dicha traducción.
Usando un intérprete, un solo archivo fuente puede producir resultados iguales incluso en sistemas sumamente diferentes (ejemplo. una PC y un PlayStation 3). Usando un compilador, un solo archivo fuente puede producir resultados iguales solo si es compilado a distintos ejecutables específicos a cada sistema.
Los programas interpretados suelen ser más lentos que los compilados debido a la necesidad de traducir el programa mientras se ejecuta, pero a cambio son más flexibles como entornos de programación y depuración (lo que se traduce, por ejemplo, en una mayor facilidad para reemplazar partes enteras del programa o añadir módulos completamente nuevos), y permiten ofrecer al programa interpretado un entorno no dependiente de la máquina donde se ejecuta el intérprete, sino del propio intérprete (lo que se conoce comúnmente como máquina virtual).
Para mejorar el desempeño, algunas implementaciones de programación de lenguajes de programación pueden interpretar o compilar el código fuente original en una más compacta forma intermedia y después traducir eso al código de máquina (ej. Perl, Python, MATLAB, y Ruby). Algunos aceptan los archivos fuente guardados en esta representación intermedia (ej. Python, UCSD Pascal y Java).
Comparando su actuación con la de un ser humano, un compilador equivale a un traductor profesional que, a partir de un texto, prepara otro independiente traducido a otra lengua, mientras que un intérprete corresponde al intérprete humano, que traduce de viva voz las palabras que oye, sin dejar constancia por escrito.
En la actualidad, uno de los entornos más comunes de uso de los intérpretes informáticos es Internet, debido a la posibilidad que estos tienen de ejecutarse independientemente de la plataforma.
Interpretadores de bytecode
Artículo principal: Bytecode
Hay un espectro de posibilidades entre la interpretación y la compilación, dependiendo de la cantidad de análisis realizados antes de que el programa sea ejecutado. Por ejemplo, el Emacs Lisp es compilado a bytecode, que es una representación altamente comprimida y optimizada del código fuente del Lisp, pero no es código de máquina (y por lo tanto no está atado a cualquier hardware particular). Este código "compilado" es entonces interpretado por un interpretador de bytecode (que está escrito en C). En este caso, el código compilado es el código de máquina para una máquina virtual, que no está implementada en el hardware, sino en el interpretador de bytecode. El mismo acercamiento es utilizado con el código Forth usado en sistemas Open Firmware: el lenguaje fuente es compilado en "código F" (un bytecode), que entonces es interpretado por una máquina virtual.
***Eficiencia***
La desventaja principal de los interpretadores es que cuando se interpreta un programa, típicamente corre más lentamente que si hubiera sido compilado. La diferencia en velocidades puede ser minúscula o grande; a menudo un orden de magnitud y a veces más. Generalmente toma más tiempo correr un programa bajo un interpretador que correr el código compilado, pero puede tomar menos tiempo para interpretarlo que el tiempo total requerido para compilarlo y ejecutarlo. Esto es especialmente importante si se está haciendo y probando un código prototipo cuando un ciclo de editar, interpretar y depurar del interpretador, a menudo puede ser mucho más corto que el ciclo de editar, compilar, ejecutar y depurar del compilador.
La interpretación de código es más lenta que la ejecución de código compilado porque el interpretador debe analizar cada sentencia en el programa cada vez que es ejecutada y entonces realizar la acción deseada, mientras que el código compilado solo realiza la acción dentro de un determinado contexto fijo por la compilación. Este análisis en tiempo de ejecución se conoce como "sobrecarga interpretativa". En un interpretador, el acceso a las variables es también más lento porque el mapeo de identificadores hacia las localizaciones de almacenamiento debe hacerse repetidamente en tiempo de ejecución en vez de en el tiempo de compilación. Hay varios compromisos entre la velocidad de desarrollo al usar un interpretador y la velocidad de ejecución al usar un compilador. Algunos sistemas (ej., algunos LISPs) permiten al código interpretado y al compilado llamarse el uno al otro y compartir variables. Esto significa que una vez que una rutina ha sido probada y depurada bajo el interpretador puede ser compilada y por lo tanto beneficiarse de una ejecución más rápida mientras que otras rutinas están siendo desarrolladas. Muchos interpretadores no ejecutan el código fuente tal y como está sino que lo convierten en una forma interna más compacta. Por ejemplo, algunos interpretadores BASIC reemplazan palabras clave (keywords) con tokens de un simple byte que pueden ser usados para encontrar la instrucción en una tabla de saltos. Un interpretador puede bien usar el mismo analizador lexicográfico y el analizador sintáctico (parser) que el compilador y entonces interpretar el árbol de sintaxis abstracta resultante.
***Interpretadores de árbol de sintáxis abstracta***
En el espectro entre la interpretación y la compilación, otro acercamiento está transformando el código fuente en un árbol de sintaxis abstracta optimizado (AST), y después procediendo a ejecutar el programa siguiendo esta estructura arborescente. En este acercamiento cada sentencia necesita ser analizada (parsed) solo una vez. Como una ventaja sobre el bytecode, el AST mantiene la estructura y las relaciones globales del programa entre las sentencias (que se pierden en una representación de bytecode), y proporciona una representación más compacta.
Así, el AST se ha propuesto como un mejor formato intermedio para los compiladores justo a tiempo que el bytecode. También, permite realizar un mejor análisis durante tiempo de ejecución. Un interpretador Java basado en AST ha demostrado ser más rápido que un interpretador similar basado en bytecode, gracias a las más poderosas optimizaciones permitidas al tener la estructura completa del programa, así como tipos de datos de alto nivel, disponibles durante la ejecución.
***Compilación justo a tiempo***
Para desdibujar más la distinción entre los interpretadores, los interpretadores de bytecode y la compilación, está la compilación justo a tiempo (o JIT), una técnica en la cual la representación intermedia es compilada a código de máquina nativo en tiempo de ejecución. Esto confiere la eficiencia de ejecutar el código nativo, al costo de tiempo de inicio y de un uso creciente de la memoria cuando el bytecode o el AST es compilado por primera vez. La optimización adaptativa es una técnica complementaria en la cual el interpretador hace un análisis de desempeño del programa que está corriendo (profiling) y compila sus partes más frecuentemente ejecutadas a código nativo. Ambas técnicas tienen algunas décadas, apareciendo en lenguajes tales como Smalltalk en los años 1980.
En años recientes, la compilación justo a tiempo ha ganado la atención de la mayoría de los implementadores de lenguajes de programación, con Java, Python, y el Microsoft .NET Framework todos ahora incluyendo JITs.
***Interpretador de tarjeta perforada***
El término "interpretador" frecuentemente se refería a una pieza de equipo de registro de unidad que podía leer tarjetas perforadas e imprimir los caracteres en la tarjeta en una forma que podía ser leída por humanos. El interpretador Numérico del IBM 550 y el Interpretador Alfabético del IBM 557 son ejemplos típicos a partir de 1930 y 1954, respectivamente.
***Ejemplos***
Algunos ejemplos de lenguajes que son normalmente interpretados en vez de compilados son:
• Perl
• PHP
• Java
• Javascript
• Logo
• ASP (hasta la versión 3)
• Python
• C#
• J#
• ASP
Usando un intérprete, un solo archivo fuente puede producir resultados iguales incluso en sistemas sumamente diferentes (ejemplo. una PC y un PlayStation 3). Usando un compilador, un solo archivo fuente puede producir resultados iguales solo si es compilado a distintos ejecutables específicos a cada sistema.
Los programas interpretados suelen ser más lentos que los compilados debido a la necesidad de traducir el programa mientras se ejecuta, pero a cambio son más flexibles como entornos de programación y depuración (lo que se traduce, por ejemplo, en una mayor facilidad para reemplazar partes enteras del programa o añadir módulos completamente nuevos), y permiten ofrecer al programa interpretado un entorno no dependiente de la máquina donde se ejecuta el intérprete, sino del propio intérprete (lo que se conoce comúnmente como máquina virtual).
Para mejorar el desempeño, algunas implementaciones de programación de lenguajes de programación pueden interpretar o compilar el código fuente original en una más compacta forma intermedia y después traducir eso al código de máquina (ej. Perl, Python, MATLAB, y Ruby). Algunos aceptan los archivos fuente guardados en esta representación intermedia (ej. Python, UCSD Pascal y Java).
Comparando su actuación con la de un ser humano, un compilador equivale a un traductor profesional que, a partir de un texto, prepara otro independiente traducido a otra lengua, mientras que un intérprete corresponde al intérprete humano, que traduce de viva voz las palabras que oye, sin dejar constancia por escrito.
En la actualidad, uno de los entornos más comunes de uso de los intérpretes informáticos es Internet, debido a la posibilidad que estos tienen de ejecutarse independientemente de la plataforma.
Interpretadores de bytecode
Artículo principal: Bytecode
Hay un espectro de posibilidades entre la interpretación y la compilación, dependiendo de la cantidad de análisis realizados antes de que el programa sea ejecutado. Por ejemplo, el Emacs Lisp es compilado a bytecode, que es una representación altamente comprimida y optimizada del código fuente del Lisp, pero no es código de máquina (y por lo tanto no está atado a cualquier hardware particular). Este código "compilado" es entonces interpretado por un interpretador de bytecode (que está escrito en C). En este caso, el código compilado es el código de máquina para una máquina virtual, que no está implementada en el hardware, sino en el interpretador de bytecode. El mismo acercamiento es utilizado con el código Forth usado en sistemas Open Firmware: el lenguaje fuente es compilado en "código F" (un bytecode), que entonces es interpretado por una máquina virtual.
***Eficiencia***
La desventaja principal de los interpretadores es que cuando se interpreta un programa, típicamente corre más lentamente que si hubiera sido compilado. La diferencia en velocidades puede ser minúscula o grande; a menudo un orden de magnitud y a veces más. Generalmente toma más tiempo correr un programa bajo un interpretador que correr el código compilado, pero puede tomar menos tiempo para interpretarlo que el tiempo total requerido para compilarlo y ejecutarlo. Esto es especialmente importante si se está haciendo y probando un código prototipo cuando un ciclo de editar, interpretar y depurar del interpretador, a menudo puede ser mucho más corto que el ciclo de editar, compilar, ejecutar y depurar del compilador.
La interpretación de código es más lenta que la ejecución de código compilado porque el interpretador debe analizar cada sentencia en el programa cada vez que es ejecutada y entonces realizar la acción deseada, mientras que el código compilado solo realiza la acción dentro de un determinado contexto fijo por la compilación. Este análisis en tiempo de ejecución se conoce como "sobrecarga interpretativa". En un interpretador, el acceso a las variables es también más lento porque el mapeo de identificadores hacia las localizaciones de almacenamiento debe hacerse repetidamente en tiempo de ejecución en vez de en el tiempo de compilación. Hay varios compromisos entre la velocidad de desarrollo al usar un interpretador y la velocidad de ejecución al usar un compilador. Algunos sistemas (ej., algunos LISPs) permiten al código interpretado y al compilado llamarse el uno al otro y compartir variables. Esto significa que una vez que una rutina ha sido probada y depurada bajo el interpretador puede ser compilada y por lo tanto beneficiarse de una ejecución más rápida mientras que otras rutinas están siendo desarrolladas. Muchos interpretadores no ejecutan el código fuente tal y como está sino que lo convierten en una forma interna más compacta. Por ejemplo, algunos interpretadores BASIC reemplazan palabras clave (keywords) con tokens de un simple byte que pueden ser usados para encontrar la instrucción en una tabla de saltos. Un interpretador puede bien usar el mismo analizador lexicográfico y el analizador sintáctico (parser) que el compilador y entonces interpretar el árbol de sintaxis abstracta resultante.
***Interpretadores de árbol de sintáxis abstracta***
En el espectro entre la interpretación y la compilación, otro acercamiento está transformando el código fuente en un árbol de sintaxis abstracta optimizado (AST), y después procediendo a ejecutar el programa siguiendo esta estructura arborescente. En este acercamiento cada sentencia necesita ser analizada (parsed) solo una vez. Como una ventaja sobre el bytecode, el AST mantiene la estructura y las relaciones globales del programa entre las sentencias (que se pierden en una representación de bytecode), y proporciona una representación más compacta.
Así, el AST se ha propuesto como un mejor formato intermedio para los compiladores justo a tiempo que el bytecode. También, permite realizar un mejor análisis durante tiempo de ejecución. Un interpretador Java basado en AST ha demostrado ser más rápido que un interpretador similar basado en bytecode, gracias a las más poderosas optimizaciones permitidas al tener la estructura completa del programa, así como tipos de datos de alto nivel, disponibles durante la ejecución.
***Compilación justo a tiempo***
Para desdibujar más la distinción entre los interpretadores, los interpretadores de bytecode y la compilación, está la compilación justo a tiempo (o JIT), una técnica en la cual la representación intermedia es compilada a código de máquina nativo en tiempo de ejecución. Esto confiere la eficiencia de ejecutar el código nativo, al costo de tiempo de inicio y de un uso creciente de la memoria cuando el bytecode o el AST es compilado por primera vez. La optimización adaptativa es una técnica complementaria en la cual el interpretador hace un análisis de desempeño del programa que está corriendo (profiling) y compila sus partes más frecuentemente ejecutadas a código nativo. Ambas técnicas tienen algunas décadas, apareciendo en lenguajes tales como Smalltalk en los años 1980.
En años recientes, la compilación justo a tiempo ha ganado la atención de la mayoría de los implementadores de lenguajes de programación, con Java, Python, y el Microsoft .NET Framework todos ahora incluyendo JITs.
***Interpretador de tarjeta perforada***
El término "interpretador" frecuentemente se refería a una pieza de equipo de registro de unidad que podía leer tarjetas perforadas e imprimir los caracteres en la tarjeta en una forma que podía ser leída por humanos. El interpretador Numérico del IBM 550 y el Interpretador Alfabético del IBM 557 son ejemplos típicos a partir de 1930 y 1954, respectivamente.
***Ejemplos***
Algunos ejemplos de lenguajes que son normalmente interpretados en vez de compilados son:
• Perl
• PHP
• Java
• Javascript
• Logo
• ASP (hasta la versión 3)
• Python
• C#
• J#
• ASP
Compiladores
Compiladores
Un compilador es un programa informático que traduce un programa escrito en un lenguaje de programación a otro lenguaje de programación, generando un programa equivalente que la máquina será capaz de interpretar. Usualmente el segundo lenguaje es lenguaje de máquina, pero también puede ser simplemente texto. Este proceso de traducción se conoce como compilación.
Un compilador es un programa que permite traducir el código fuente de un programa en lenguaje de alto nivel, a otro lenguaje de nivel inferior (típicamente lenguaje de máquina). De esta manera un programador puede diseñar un programa en un lenguaje mucho más cercano a como piensa un ser humano, para luego compilarlo a un programa más manejable por una computadora.
***Partes de un compilador***
La construcción de un compilador involucra la división del proceso en una serie de fases que variará con su complejidad. Generalmente estas fases se agrupan en dos tareas: el análisis del programa fuente y la síntesis del programa objeto.
• Análisis: Se trata de la comprobación de la corrección del programa fuente, e incluye las fases correspondientes al Análisis Léxico (que consiste en la descomposición del programa fuente en componentes léxicos), Análisis Sintáctico (agrupación de los componentes léxicos en frases gramaticales ) y Análisis Semántico (comprobación de la validez semántica de las sentencias aceptadas en la fase de Análisis Sintáctico).
• Síntesis: Su objetivo es la generación de la salida expresada en el lenguaje objeto y suele estar formado por una o varias combinaciones de fases de Generación de Código (normalmente se trata de código intermedio o de código objeto) y de Optimización de Código (en las que se busca obtener un código lo más eficiente posible).
Alternativamente, las fases descritas para las tareas de análisis y síntesis se pueden agrupar en Front-end y Back-end:
• Front-end: es la parte que analiza el código fuente, comprueba su validez, genera el árbol de derivación y rellena los valores de la tabla de símbolos. Esta parte suele ser independiente de la plataforma o sistema para el cual se vaya a compilar, y está compuesta por las fases comprendidas entre el Análisis Léxico y la Generación de Código Intermedio.
• Back-end: es la parte que genera el código máquina, específico de una plataforma, a partir de los resultados de la fase de análisis, realizada por el Front End.
Esta división permite que el mismo Back End se utilice para generar el código máquina de varios lenguajes de programación distintos y que el mismo Front End que sirve para analizar el código fuente de un lenguaje de programación concreto sirva para generar código máquina en varias plataformas distintas. Suele incluir la generación y optimización del código dependiente de la máquina.
El código que genera el Back End normalmente no se puede ejecutar directamente, sino que necesita ser enlazado por un programa enlazador (linker)
**Tipos de compiladores***
Esta taxonomía de los tipos de compiladores no es excluyente, por lo que puede haber compiladores que se adscriban a varias categorías:
• Compiladores cruzados: generan código para un sistema distinto del que están funcionando.
• Compiladores optimizadores: realizan cambios en el código para mejorar su eficiencia, pero manteniendo la funcionalidad del programa original.
• Compiladores de una sola pasada: generan el código máquina a partir de una única lectura del código fuente.
• Compiladores de varias pasadas: necesitan leer el código fuente varias veces antes de poder producir el código máquina.
• Compiladores JIT (Just In Time): forman parte de un intérprete y compilan partes del código según se necesitan.
Pauta de creación de un compilador: En las primeras épocas de la informática, el software de los compiladores era considerado como uno de los más complejos existentes.
Los primeros compiladores se realizaron programándolos directamente en lenguaje máquina o en ensamblador. Una vez que se dispone de un compilador, se pueden escribir nuevas versiones el compilador (u otros compiladores distintos) en el lenguaje que compila ese compilador.
Actualmente existen herramientas que facilitan la tarea de escribir compiladores ó intérpretes informáticos. Estas herramientas permiten generar el esqueleto del analizador sintáctico a partir de una definición formal del lenguaje de partida, especificada normalmente mediante una gramática formal y barata, dejando únicamente al programador del compilador la tarea de programar las acciones semánticas asociadas.
***Proceso de compilación***
Es el proceso por el cual se traducen las instrucciones escritas en un determinado lenguaje de programación a lenguaje máquina. Además de un traductor, se pueden necesitar otros programas para crear un programa objeto ejecutable. Un programa fuente se puede dividir en módulos almacenados en archivos distintos. La tarea de reunir el programa fuente a menudo se confía a un programa distinto, llamado preprocesador. El preprocesador también puede expandir abreviaturas, llamadas a macros, a proposiciones del lenguaje fuente.
Normalmente la creación de un programa ejecutable (un típico.exe para Microsoft Windows o DOS) conlleva dos pasos. El primer paso se llama compilación (propiamente dicho) y traduce el código fuente escrito en un lenguaje de programación almacenado en un archivo a código en bajo nivel (normalmente en código objeto, no directamente a lenguaje máquina). El segundo paso se llama enlazado en el cual se enlaza el código de bajo nivel generado de todos los ficheros y subprogramas que se han mandado compilar y se añade el código de las funciones que hay en las bibliotecas del compilador para que el ejecutable pueda comunicarse directamente con el sistema operativo, traduciendo así finalmente el código objeto a código máquina, y generando un módulo ejecutable.
Estos dos pasos se pueden hacer por separado, almacenando el resultado de la fase de compilación en archivos objetos (un típico.obj para Microsoft Windows, DOS o para Unix); para enlazarlos en fases posteriores, o crear directamente el ejecutable; con lo que la fase de compilación se almacena sólo temporalmente. Un programa podría tener partes escritas en varios lenguajes (por ejemplo C, C++ y Asm), que se podrían compilar de forma independiente y luego enlazar juntas para formar un único módulo ejecutable.
***Etapas del proceso**
El proceso de traducción se compone internamente de varias etapas o fases, que realizan distintas operaciones lógicas. Es útil pensar en estas fases como en piezas separadas dentro del traductor, y pueden en realidad escribirse como operaciones codificadas separadamente aunque en la práctica a menudo se integren juntas.
Fase de análisis
Análisis léxico
Artículo principal: Analizador léxico
El análisis léxico constituye la primera fase, aquí se lee el programa fuente de izquierda a derecha y se agrupa en componentes léxicos (tokens), que son secuencias de caracteres que tienen un significado. Además, todos los espacios en blanco, líneas en blanco, comentarios y demás información innecesaria se elimina del programa fuente. También se comprueba que los símbolos del lenguaje (palabras clave, operadores,...) se han escrito correctamente.
Como la tarea que realiza el analizador léxico es un caso especial de coincidencia de patrones, se necesitan los métodos de especificación y reconocimiento de patrones, y éstos métodos son principalmente las expresiones regulares y los autómatas finitos. Sin embargo, un analizador léxico también es la parte del traductor que maneja la entrada del código fuente, y puesto que esta entrada a menudo involucra un importante gasto de tiempo, el analizador léxico debe funcionar de manera tan eficiente como sea posible.
Análisis sintáctico
Artículo principal: Analizador sintáctico
En esta fase los caracteres o componentes léxicos se agrupan jerárquicamente en frases gramaticales que el compilador utiliza para sintetizar la salida. Se comprueba si lo obtenido de la fase anterior es sintácticamente correcto (obedece a la gramática del lenguaje). Por lo general, las frases gramaticales del programa fuente se representan mediante un árbol de análisis sintáctico.
La estructura jerárquica de un programa normalmente se expresa utilizando reglas recursivas.
Por ejemplo, se pueden dar las siguientes reglas como parte de la definición de expresiones:
1. Cualquier identificador es una expresión.
2. Cualquier número es una expresión.
3. Si expresión1 y expresión2 son expresiones, entonces también lo son:
o expresión1 + expresión2
o expresión1 * expresión2
o ( expresión1 )
Las reglas 1 y 2 son reglas básicas (no recursivas), en tanto que la regla 3 define expresiones en función de operadores aplicados a otras expresiones.
La división entre análisis léxico y análisis sintáctico es algo arbitraria. Un factor para determinar la división es si una construcción del lenguaje fuente es inherentemente recursiva o no. Las construcciones léxicas no requieren recursión, mientras que las construcciones sintácticas suelen requerirla. No se requiere recursión para reconocer los identificadores, que suelen ser cadenas de letras y dígitos que comienzan con una letra. Normalmente, se reconocen los identificadores por el simple examen del flujo de entrada, esperando hasta encontrar un carácter que no sea ni letra ni dígito, y agrupando después todas las letras y dígitos encontrados hasta ese punto en un componente léxico llamado identificador. Por otra parte, esta clase de análisis no es suficientemente poderoso para analizar expresiones o proposiciones. Por ejemplo, no podemos emparejar de manera apropiada los paréntesis de las expresiones, o las palabras begin y end en proposiciones sin imponer alguna clase de estructura jerárquica o de anidamiento a la entrada.
Análisis semántico
La fase de análisis semántico revisa el programa fuente para tratar de encontrar errores semánticos y reúne la información sobre los tipos para la fase posterior de generación de código. En ella se utiliza la estructura jerárquica determinada por la fase de análisis sintáctico para identificar los operadores y operandos de expresiones y proposiciones.
Un componente importante del análisis semántico es la verificación de tipos. Aquí, el compilador verifica si cada operador tiene operandos permitidos por la especificación del lenguaje fuente. Por ejemplo, las definiciones de muchos lenguajes de programación requieren que el compilador indique un error cada vez que se use un número real como índice de una matriz. Sin embargo, la especificación del lenguaje puede imponer restricciones a los operandos, por ejemplo, cuando un operador aritmético binario se aplica a un número entero y a un número real. Revisa que los arreglos tengan definido el tamaño correcto.
Fase de síntesis
Consiste en generar el código objeto equivalente al programa fuente. Sólo se genera código objeto cuando el programa fuente está libre de errores de análisis, lo cual no quiere decir que el programa se ejecute correctamente, ya que un programa puede tener errores de concepto o expresiones mal calculadas. Por lo general el código objeto es código de máquina relocalizable o código ensamblador. Las posiciones de memoria se seleccionan para cada una de las variables usadas por el programa. Después, cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de máquina que ejecuta la misma tarea. Un aspecto decisivo es la asignación de variables a registros.
Generación de código intermedio
Después de los análisis sintáctico y semántico, algunos compiladores generan una representación intermedia explícita del programa fuente. Se puede considerar esta representación intermedia como un programa para una máquina abstracta. Esta representación intermedia debe tener dos propiedades importantes; debe ser fácil de producir y fácil de traducir al programa objeto.
La representación intermedia puede tener diversas formas. Existe una forma intermedia llamada "código de tres direcciones" que es como el lenguaje ensamblador de una máquina en la que cada posición de memoria puede actuar como un registro. El código de tres direcciones consiste en una secuencia de instrucciones, cada una de las cuales tiene como máximo tres operandos. Esta representación intermedia tiene varias propiedades:
• Primera.- Cada instrucción de tres direcciones tiene a lo sumo un operador, además de la asignación, por tanto, cuando se generan estas instrucciones, el traductor tiene que decidir el orden en que deben efectuarse las operaciones.
• Segunda.- El traductor debe generar un nombre temporal para guardar los valores calculados por cada instrucción.
• Tercera.- Algunas instrucciones de "tres direcciones" tienen menos de tres operandos, por ejemplo, la asignación.
Optimización de código
La fase de optimización de código consiste en mejorar el código intermedio, de modo que resulte un código máquina más rápido de ejecutar. Esta fase de la etapa de síntesis es posible sobre todo si el traductor es un compilador (difícilmente un interprete puede optimizar el código objeto). Hay mucha variación en la cantidad de optimización de código que ejecutan los distintos compiladores. En los que hacen mucha optimización, llamados "compiladores optimizadores", una parte significativa del tiempo del compilador se ocupa en esta fase. Sin embargo, hay optimizaciones sencillas que mejoran sensiblemente el tiempo de ejecución del programa objeto sin retardar demasiado la compilación.
Un compilador es un programa informático que traduce un programa escrito en un lenguaje de programación a otro lenguaje de programación, generando un programa equivalente que la máquina será capaz de interpretar. Usualmente el segundo lenguaje es lenguaje de máquina, pero también puede ser simplemente texto. Este proceso de traducción se conoce como compilación.
Un compilador es un programa que permite traducir el código fuente de un programa en lenguaje de alto nivel, a otro lenguaje de nivel inferior (típicamente lenguaje de máquina). De esta manera un programador puede diseñar un programa en un lenguaje mucho más cercano a como piensa un ser humano, para luego compilarlo a un programa más manejable por una computadora.
***Partes de un compilador***
La construcción de un compilador involucra la división del proceso en una serie de fases que variará con su complejidad. Generalmente estas fases se agrupan en dos tareas: el análisis del programa fuente y la síntesis del programa objeto.
• Análisis: Se trata de la comprobación de la corrección del programa fuente, e incluye las fases correspondientes al Análisis Léxico (que consiste en la descomposición del programa fuente en componentes léxicos), Análisis Sintáctico (agrupación de los componentes léxicos en frases gramaticales ) y Análisis Semántico (comprobación de la validez semántica de las sentencias aceptadas en la fase de Análisis Sintáctico).
• Síntesis: Su objetivo es la generación de la salida expresada en el lenguaje objeto y suele estar formado por una o varias combinaciones de fases de Generación de Código (normalmente se trata de código intermedio o de código objeto) y de Optimización de Código (en las que se busca obtener un código lo más eficiente posible).
Alternativamente, las fases descritas para las tareas de análisis y síntesis se pueden agrupar en Front-end y Back-end:
• Front-end: es la parte que analiza el código fuente, comprueba su validez, genera el árbol de derivación y rellena los valores de la tabla de símbolos. Esta parte suele ser independiente de la plataforma o sistema para el cual se vaya a compilar, y está compuesta por las fases comprendidas entre el Análisis Léxico y la Generación de Código Intermedio.
• Back-end: es la parte que genera el código máquina, específico de una plataforma, a partir de los resultados de la fase de análisis, realizada por el Front End.
Esta división permite que el mismo Back End se utilice para generar el código máquina de varios lenguajes de programación distintos y que el mismo Front End que sirve para analizar el código fuente de un lenguaje de programación concreto sirva para generar código máquina en varias plataformas distintas. Suele incluir la generación y optimización del código dependiente de la máquina.
El código que genera el Back End normalmente no se puede ejecutar directamente, sino que necesita ser enlazado por un programa enlazador (linker)
**Tipos de compiladores***
Esta taxonomía de los tipos de compiladores no es excluyente, por lo que puede haber compiladores que se adscriban a varias categorías:
• Compiladores cruzados: generan código para un sistema distinto del que están funcionando.
• Compiladores optimizadores: realizan cambios en el código para mejorar su eficiencia, pero manteniendo la funcionalidad del programa original.
• Compiladores de una sola pasada: generan el código máquina a partir de una única lectura del código fuente.
• Compiladores de varias pasadas: necesitan leer el código fuente varias veces antes de poder producir el código máquina.
• Compiladores JIT (Just In Time): forman parte de un intérprete y compilan partes del código según se necesitan.
Pauta de creación de un compilador: En las primeras épocas de la informática, el software de los compiladores era considerado como uno de los más complejos existentes.
Los primeros compiladores se realizaron programándolos directamente en lenguaje máquina o en ensamblador. Una vez que se dispone de un compilador, se pueden escribir nuevas versiones el compilador (u otros compiladores distintos) en el lenguaje que compila ese compilador.
Actualmente existen herramientas que facilitan la tarea de escribir compiladores ó intérpretes informáticos. Estas herramientas permiten generar el esqueleto del analizador sintáctico a partir de una definición formal del lenguaje de partida, especificada normalmente mediante una gramática formal y barata, dejando únicamente al programador del compilador la tarea de programar las acciones semánticas asociadas.
***Proceso de compilación***
Es el proceso por el cual se traducen las instrucciones escritas en un determinado lenguaje de programación a lenguaje máquina. Además de un traductor, se pueden necesitar otros programas para crear un programa objeto ejecutable. Un programa fuente se puede dividir en módulos almacenados en archivos distintos. La tarea de reunir el programa fuente a menudo se confía a un programa distinto, llamado preprocesador. El preprocesador también puede expandir abreviaturas, llamadas a macros, a proposiciones del lenguaje fuente.
Normalmente la creación de un programa ejecutable (un típico.exe para Microsoft Windows o DOS) conlleva dos pasos. El primer paso se llama compilación (propiamente dicho) y traduce el código fuente escrito en un lenguaje de programación almacenado en un archivo a código en bajo nivel (normalmente en código objeto, no directamente a lenguaje máquina). El segundo paso se llama enlazado en el cual se enlaza el código de bajo nivel generado de todos los ficheros y subprogramas que se han mandado compilar y se añade el código de las funciones que hay en las bibliotecas del compilador para que el ejecutable pueda comunicarse directamente con el sistema operativo, traduciendo así finalmente el código objeto a código máquina, y generando un módulo ejecutable.
Estos dos pasos se pueden hacer por separado, almacenando el resultado de la fase de compilación en archivos objetos (un típico.obj para Microsoft Windows, DOS o para Unix); para enlazarlos en fases posteriores, o crear directamente el ejecutable; con lo que la fase de compilación se almacena sólo temporalmente. Un programa podría tener partes escritas en varios lenguajes (por ejemplo C, C++ y Asm), que se podrían compilar de forma independiente y luego enlazar juntas para formar un único módulo ejecutable.
***Etapas del proceso**
El proceso de traducción se compone internamente de varias etapas o fases, que realizan distintas operaciones lógicas. Es útil pensar en estas fases como en piezas separadas dentro del traductor, y pueden en realidad escribirse como operaciones codificadas separadamente aunque en la práctica a menudo se integren juntas.
Fase de análisis
Análisis léxico
Artículo principal: Analizador léxico
El análisis léxico constituye la primera fase, aquí se lee el programa fuente de izquierda a derecha y se agrupa en componentes léxicos (tokens), que son secuencias de caracteres que tienen un significado. Además, todos los espacios en blanco, líneas en blanco, comentarios y demás información innecesaria se elimina del programa fuente. También se comprueba que los símbolos del lenguaje (palabras clave, operadores,...) se han escrito correctamente.
Como la tarea que realiza el analizador léxico es un caso especial de coincidencia de patrones, se necesitan los métodos de especificación y reconocimiento de patrones, y éstos métodos son principalmente las expresiones regulares y los autómatas finitos. Sin embargo, un analizador léxico también es la parte del traductor que maneja la entrada del código fuente, y puesto que esta entrada a menudo involucra un importante gasto de tiempo, el analizador léxico debe funcionar de manera tan eficiente como sea posible.
Análisis sintáctico
Artículo principal: Analizador sintáctico
En esta fase los caracteres o componentes léxicos se agrupan jerárquicamente en frases gramaticales que el compilador utiliza para sintetizar la salida. Se comprueba si lo obtenido de la fase anterior es sintácticamente correcto (obedece a la gramática del lenguaje). Por lo general, las frases gramaticales del programa fuente se representan mediante un árbol de análisis sintáctico.
La estructura jerárquica de un programa normalmente se expresa utilizando reglas recursivas.
Por ejemplo, se pueden dar las siguientes reglas como parte de la definición de expresiones:
1. Cualquier identificador es una expresión.
2. Cualquier número es una expresión.
3. Si expresión1 y expresión2 son expresiones, entonces también lo son:
o expresión1 + expresión2
o expresión1 * expresión2
o ( expresión1 )
Las reglas 1 y 2 son reglas básicas (no recursivas), en tanto que la regla 3 define expresiones en función de operadores aplicados a otras expresiones.
La división entre análisis léxico y análisis sintáctico es algo arbitraria. Un factor para determinar la división es si una construcción del lenguaje fuente es inherentemente recursiva o no. Las construcciones léxicas no requieren recursión, mientras que las construcciones sintácticas suelen requerirla. No se requiere recursión para reconocer los identificadores, que suelen ser cadenas de letras y dígitos que comienzan con una letra. Normalmente, se reconocen los identificadores por el simple examen del flujo de entrada, esperando hasta encontrar un carácter que no sea ni letra ni dígito, y agrupando después todas las letras y dígitos encontrados hasta ese punto en un componente léxico llamado identificador. Por otra parte, esta clase de análisis no es suficientemente poderoso para analizar expresiones o proposiciones. Por ejemplo, no podemos emparejar de manera apropiada los paréntesis de las expresiones, o las palabras begin y end en proposiciones sin imponer alguna clase de estructura jerárquica o de anidamiento a la entrada.
Análisis semántico
La fase de análisis semántico revisa el programa fuente para tratar de encontrar errores semánticos y reúne la información sobre los tipos para la fase posterior de generación de código. En ella se utiliza la estructura jerárquica determinada por la fase de análisis sintáctico para identificar los operadores y operandos de expresiones y proposiciones.
Un componente importante del análisis semántico es la verificación de tipos. Aquí, el compilador verifica si cada operador tiene operandos permitidos por la especificación del lenguaje fuente. Por ejemplo, las definiciones de muchos lenguajes de programación requieren que el compilador indique un error cada vez que se use un número real como índice de una matriz. Sin embargo, la especificación del lenguaje puede imponer restricciones a los operandos, por ejemplo, cuando un operador aritmético binario se aplica a un número entero y a un número real. Revisa que los arreglos tengan definido el tamaño correcto.
Fase de síntesis
Consiste en generar el código objeto equivalente al programa fuente. Sólo se genera código objeto cuando el programa fuente está libre de errores de análisis, lo cual no quiere decir que el programa se ejecute correctamente, ya que un programa puede tener errores de concepto o expresiones mal calculadas. Por lo general el código objeto es código de máquina relocalizable o código ensamblador. Las posiciones de memoria se seleccionan para cada una de las variables usadas por el programa. Después, cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de máquina que ejecuta la misma tarea. Un aspecto decisivo es la asignación de variables a registros.
Generación de código intermedio
Después de los análisis sintáctico y semántico, algunos compiladores generan una representación intermedia explícita del programa fuente. Se puede considerar esta representación intermedia como un programa para una máquina abstracta. Esta representación intermedia debe tener dos propiedades importantes; debe ser fácil de producir y fácil de traducir al programa objeto.
La representación intermedia puede tener diversas formas. Existe una forma intermedia llamada "código de tres direcciones" que es como el lenguaje ensamblador de una máquina en la que cada posición de memoria puede actuar como un registro. El código de tres direcciones consiste en una secuencia de instrucciones, cada una de las cuales tiene como máximo tres operandos. Esta representación intermedia tiene varias propiedades:
• Primera.- Cada instrucción de tres direcciones tiene a lo sumo un operador, además de la asignación, por tanto, cuando se generan estas instrucciones, el traductor tiene que decidir el orden en que deben efectuarse las operaciones.
• Segunda.- El traductor debe generar un nombre temporal para guardar los valores calculados por cada instrucción.
• Tercera.- Algunas instrucciones de "tres direcciones" tienen menos de tres operandos, por ejemplo, la asignación.
Optimización de código
La fase de optimización de código consiste en mejorar el código intermedio, de modo que resulte un código máquina más rápido de ejecutar. Esta fase de la etapa de síntesis es posible sobre todo si el traductor es un compilador (difícilmente un interprete puede optimizar el código objeto). Hay mucha variación en la cantidad de optimización de código que ejecutan los distintos compiladores. En los que hacen mucha optimización, llamados "compiladores optimizadores", una parte significativa del tiempo del compilador se ocupa en esta fase. Sin embargo, hay optimizaciones sencillas que mejoran sensiblemente el tiempo de ejecución del programa objeto sin retardar demasiado la compilación.
Lenguaje Ensamblador
***Lenguaje Ensamblador ***
Lenguaje de máquina del Intel 8088. El código de máquina se resalta en rojo, el equivalente en lenguaje assembler en magenta, y las direcciones de memoria donde se encuentra el código, en azul.
El lenguaje ensamblador es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de computadoras legible por un programador.
Fue usado principalmente en los inicios del desarrollo de software, cuando aún no se contaba con los potentes lenguajes de alto nivel. Actualmente se utiliza con frecuencia en ambientes académicos y de investigación, especialmente cuando se requiere la manipulación directa de hardware, se pretenden altos rendimientos o un uso de recursos controlado y reducido.
Muchos dispositivos programables (como los microcontroladores) aun cuentan con el ensamblador como la única manera de ser manipulados.
***Características***
• El código escrito en lenguaje ensamblador posee una cierta dificultad de ser entendido directamente por un ser humano ya que su estructura se acerca más bien al lenguaje máquina, es decir, lenguaje de bajo nivel.
• El lenguaje ensamblador es difícilmente portable, es decir, un código escrito para un microprocesador, suele necesitar ser modificado, muchas veces en su totalidad para poder ser usado en otra máquina distinta, aun con el mismo microprocesador.
• Los programas hechos en lenguaje ensamblador son generalmente más rápidos y consumen menos recursos del sistema (memoria RAM y ROM). Al programar cuidadosamente en lenguaje ensamblador se pueden crear programas que se ejecutan más rápidamente y ocupan menos espacio que con lenguajes de alto nivel.
• Con el lenguaje ensamblador se tiene un control muy preciso de las tareas realizadas por un microprocesador por lo que se pueden crear segmentos de código difíciles de programar en un lenguaje de alto nivel.
• También se puede controlar el tiempo en que tarda una rutina en ejecutarse, e impedir que se interumpa durante su ejecución.
Un ensamblador (assembler en inglés) es un programa que crea código objeto traduciendo instrucciones nemócodigos de un programa fuente escrito en ensamblador a códigos ejecutables e interpretando los nombres simbólicos para direcciones de memoria y otras entidades (ensamblado). El uso de referencias simbólicas es una característica básica del lenguaje ensamblador, evitando tediosos cálculos y direccionamiento manual después de cada modificación del programa. La mayoría de los ensambladores también incluyen facilidades para crear macros, a fin de generar series de instrucciones cortas que se ejecutan en tiempo real, que insertan el código de la macro, en dicha posición, en lugar de utilizar subrutinas.
Los ensambladores han estado disponibles desde la década de 1950. Los ensambladores modernos, especialmente para arquitecturas basadas en RISC que pueden ejecutar varias instrucciones simultáneamente, como por ejemplo MIPS, SPARC y PA-RISC optimizan las instrucciones para explotar al máximo la eficiencia de segmentación de la CPU.
En los compilador para lenguajes de alto nivel, son el último paso antes de generar el código ejecutable.
Los ensambladores avanzados ofrecen posibilidades de abstracción que incluyen:
• Control avanzado de estructuras.
• Procedimientos de alto nivel, declaración de funciones.
• Tipos de datos que incluyen estructuras, registros, uniones, clases y conjuntos.
• Sofisticado procesamiento de macros.
***Lenguaje ***
Un programa escrito en lenguaje ensamblador consiste en una serie de instrucciones que corresponden al flujo de órdenes ejecutables que pueden ser cargadas en la memoria de un sistema basado en microprocesador.
Por ejemplo, un procesador x86 puede ejecutar la siguiente instrucción binaria como se expresa en código de máquina:
• Binario: 10110000 01100001 (Hexadecimal: 0xb061)
La representación equivalente en lenguaje ensamblador es más fácil de recordar:
• MOV al, 061h
Esta instrucción significa:
• Asigna el valor hexadecimal 61 (97 decimal) al registro "al".
El mnemónico "mov" es un código de operación u "opcode", elegido por los diseñadores de la colección de instrucciones para abreviar "move" (mover, pero en el sentido de copiar valores de un sitio a otro). El opcode es seguido por una lista de argumentos o parámetros, completando una instrucción de ensamblador típica.
La transformación del lenguaje ensamblador en código máquina la realiza un programa Ensamblador, y la traducción inversa la puede efectuar un desensamblador. A diferencia de los lenguajes de alto nivel, aquí hay usualmente una correspondencia 1 a 1 entre las instrucciones simples del ensamblador y el lenguaje de máquina. Sin embargo, en algunos casos, un ensamblador puede proveer "pseudo instrucciones" que se expanden en un código de máquina más extenso a fin de proveer la funcionalidad necesaria. Por ejemplo, para un código máquina condicional como "si X mayor o igual que" , un ensamblador puede utilizar una pseudoinstrucción al grupo "haga si menor que" , y "si = 0" sobre el resultado de la condición anterior. Los Ensambladores más completos también proveen un rico lenguaje de macros que se utiliza para generar código más complejo y secuencias de datos.
El uso del ensamblador no resuelve definitivamente el problema de cómo programar un sistema basado en microprocesador de modo sencillo ya que para hacer un uso eficiente del mismo, hay que conocer a fondo el microprocesador, los registros de trabajo de que dispone, la estructura de la memoria, y muchas cosas más referentes a su estructura básica de funcionamiento.
Cada arquitectura de microprocesadores tiene su propio lenguaje de máquina, y en consecuencia su propio lenguaje ensamblador ya que este se encuentra muy ligado al la estructura del hardware para el cual se programa. Los microprocesadores difieren en el tipo y número de operaciones que soportan; también pueden tener diferente cantidad de registros, y distinta representación de los tipos de datos en memoria. Aunque la mayoría de los microprocesadores son capaces de cumplir esencialmente las mismas funciones, la forma en que lo hacen difiere y los respectivos lenguajes ensamblador reflejan tal diferencia.
Pueden existir múltiples conjuntos de mnemónicos o sintáxis de lenguaje ensamblador para un mismo conjunto de instrucciones, instanciados típicamente en diferentes programas en ensamblador. En estos casos, la alternativa más popular es la provista por los fabricantes, y usada en los manuales del programa.
***Código máquina ***
El código máquina, o lenguaje de máquina, está formado por instrucciones sencillas, que -dependiendo de la estructura del procesador- pueden especificar:
• Registros específicos para operaciones aritméticas, direccionamiento o control de funciones.
• Posiciones de memoria específicas (offset).
• Modos de direccionamiento usados para interpretar operandos.
Las operaciones más complejas se realizan combinando estas instrucciones sencillas, que pueden ser ejecutadas secuencialmente o mediante instrucciones de control de flujo.
Las operaciones disponibles en la mayoría de los conjuntos de instrucciones incluye:
• mover
o llenar un registro con un valor constante
o mover datos de una posición de memoria a un registro o viceversa
o escribir y leer datos de dispositivos
• computar
o sumar, restar, multiplicar o dividir los valores de dos registros, colocando el resultado en uno de ellos o en otro registro
o realizar operaciones binarias, incluyendo operaciones lógicas (AND/OR/XOR/NOT)
o comparar valores entre registros (mayor, menor, igual)
• afectar el flujo del programa
o saltar a otra posición en el programa y ejecutar instrucciones allí
o saltar si se cumplen ciertas condiciones (IF)
o saltar a otra posición, pero guardar el punto de salida para retornar (CALL, llamada a subrutinas)
Algunas computadoras incluyen instrucciones complejas dentro de sus capacidades. Una sola instrucción compleja hace lo mismo que en otras computadoras puede requerir una larga serie de instrucciones, por ejemplo:
• salvar varios registros en la pila de una sola vez
• mover grandes bloques de memoria
• operaciones aritméticas complejas o de punto flotante (seno, coseno, raíz cuadrada)
Mientras que una computadora reconoce la instrucción de máquina IA-32
10110000 01100001
para los programadores de microprocesadores x86 es mucho más fácil reconocer dicha instrucción empleando lenguaje ensamblador:
movb 0x61,%al
Lenguaje de máquina del Intel 8088. El código de máquina se resalta en rojo, el equivalente en lenguaje assembler en magenta, y las direcciones de memoria donde se encuentra el código, en azul.
El lenguaje ensamblador es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de computadoras legible por un programador.
Fue usado principalmente en los inicios del desarrollo de software, cuando aún no se contaba con los potentes lenguajes de alto nivel. Actualmente se utiliza con frecuencia en ambientes académicos y de investigación, especialmente cuando se requiere la manipulación directa de hardware, se pretenden altos rendimientos o un uso de recursos controlado y reducido.
Muchos dispositivos programables (como los microcontroladores) aun cuentan con el ensamblador como la única manera de ser manipulados.
***Características***
• El código escrito en lenguaje ensamblador posee una cierta dificultad de ser entendido directamente por un ser humano ya que su estructura se acerca más bien al lenguaje máquina, es decir, lenguaje de bajo nivel.
• El lenguaje ensamblador es difícilmente portable, es decir, un código escrito para un microprocesador, suele necesitar ser modificado, muchas veces en su totalidad para poder ser usado en otra máquina distinta, aun con el mismo microprocesador.
• Los programas hechos en lenguaje ensamblador son generalmente más rápidos y consumen menos recursos del sistema (memoria RAM y ROM). Al programar cuidadosamente en lenguaje ensamblador se pueden crear programas que se ejecutan más rápidamente y ocupan menos espacio que con lenguajes de alto nivel.
• Con el lenguaje ensamblador se tiene un control muy preciso de las tareas realizadas por un microprocesador por lo que se pueden crear segmentos de código difíciles de programar en un lenguaje de alto nivel.
• También se puede controlar el tiempo en que tarda una rutina en ejecutarse, e impedir que se interumpa durante su ejecución.
Un ensamblador (assembler en inglés) es un programa que crea código objeto traduciendo instrucciones nemócodigos de un programa fuente escrito en ensamblador a códigos ejecutables e interpretando los nombres simbólicos para direcciones de memoria y otras entidades (ensamblado). El uso de referencias simbólicas es una característica básica del lenguaje ensamblador, evitando tediosos cálculos y direccionamiento manual después de cada modificación del programa. La mayoría de los ensambladores también incluyen facilidades para crear macros, a fin de generar series de instrucciones cortas que se ejecutan en tiempo real, que insertan el código de la macro, en dicha posición, en lugar de utilizar subrutinas.
Los ensambladores han estado disponibles desde la década de 1950. Los ensambladores modernos, especialmente para arquitecturas basadas en RISC que pueden ejecutar varias instrucciones simultáneamente, como por ejemplo MIPS, SPARC y PA-RISC optimizan las instrucciones para explotar al máximo la eficiencia de segmentación de la CPU.
En los compilador para lenguajes de alto nivel, son el último paso antes de generar el código ejecutable.
Los ensambladores avanzados ofrecen posibilidades de abstracción que incluyen:
• Control avanzado de estructuras.
• Procedimientos de alto nivel, declaración de funciones.
• Tipos de datos que incluyen estructuras, registros, uniones, clases y conjuntos.
• Sofisticado procesamiento de macros.
***Lenguaje ***
Un programa escrito en lenguaje ensamblador consiste en una serie de instrucciones que corresponden al flujo de órdenes ejecutables que pueden ser cargadas en la memoria de un sistema basado en microprocesador.
Por ejemplo, un procesador x86 puede ejecutar la siguiente instrucción binaria como se expresa en código de máquina:
• Binario: 10110000 01100001 (Hexadecimal: 0xb061)
La representación equivalente en lenguaje ensamblador es más fácil de recordar:
• MOV al, 061h
Esta instrucción significa:
• Asigna el valor hexadecimal 61 (97 decimal) al registro "al".
El mnemónico "mov" es un código de operación u "opcode", elegido por los diseñadores de la colección de instrucciones para abreviar "move" (mover, pero en el sentido de copiar valores de un sitio a otro). El opcode es seguido por una lista de argumentos o parámetros, completando una instrucción de ensamblador típica.
La transformación del lenguaje ensamblador en código máquina la realiza un programa Ensamblador, y la traducción inversa la puede efectuar un desensamblador. A diferencia de los lenguajes de alto nivel, aquí hay usualmente una correspondencia 1 a 1 entre las instrucciones simples del ensamblador y el lenguaje de máquina. Sin embargo, en algunos casos, un ensamblador puede proveer "pseudo instrucciones" que se expanden en un código de máquina más extenso a fin de proveer la funcionalidad necesaria. Por ejemplo, para un código máquina condicional como "si X mayor o igual que" , un ensamblador puede utilizar una pseudoinstrucción al grupo "haga si menor que" , y "si = 0" sobre el resultado de la condición anterior. Los Ensambladores más completos también proveen un rico lenguaje de macros que se utiliza para generar código más complejo y secuencias de datos.
El uso del ensamblador no resuelve definitivamente el problema de cómo programar un sistema basado en microprocesador de modo sencillo ya que para hacer un uso eficiente del mismo, hay que conocer a fondo el microprocesador, los registros de trabajo de que dispone, la estructura de la memoria, y muchas cosas más referentes a su estructura básica de funcionamiento.
Cada arquitectura de microprocesadores tiene su propio lenguaje de máquina, y en consecuencia su propio lenguaje ensamblador ya que este se encuentra muy ligado al la estructura del hardware para el cual se programa. Los microprocesadores difieren en el tipo y número de operaciones que soportan; también pueden tener diferente cantidad de registros, y distinta representación de los tipos de datos en memoria. Aunque la mayoría de los microprocesadores son capaces de cumplir esencialmente las mismas funciones, la forma en que lo hacen difiere y los respectivos lenguajes ensamblador reflejan tal diferencia.
Pueden existir múltiples conjuntos de mnemónicos o sintáxis de lenguaje ensamblador para un mismo conjunto de instrucciones, instanciados típicamente en diferentes programas en ensamblador. En estos casos, la alternativa más popular es la provista por los fabricantes, y usada en los manuales del programa.
***Código máquina ***
El código máquina, o lenguaje de máquina, está formado por instrucciones sencillas, que -dependiendo de la estructura del procesador- pueden especificar:
• Registros específicos para operaciones aritméticas, direccionamiento o control de funciones.
• Posiciones de memoria específicas (offset).
• Modos de direccionamiento usados para interpretar operandos.
Las operaciones más complejas se realizan combinando estas instrucciones sencillas, que pueden ser ejecutadas secuencialmente o mediante instrucciones de control de flujo.
Las operaciones disponibles en la mayoría de los conjuntos de instrucciones incluye:
• mover
o llenar un registro con un valor constante
o mover datos de una posición de memoria a un registro o viceversa
o escribir y leer datos de dispositivos
• computar
o sumar, restar, multiplicar o dividir los valores de dos registros, colocando el resultado en uno de ellos o en otro registro
o realizar operaciones binarias, incluyendo operaciones lógicas (AND/OR/XOR/NOT)
o comparar valores entre registros (mayor, menor, igual)
• afectar el flujo del programa
o saltar a otra posición en el programa y ejecutar instrucciones allí
o saltar si se cumplen ciertas condiciones (IF)
o saltar a otra posición, pero guardar el punto de salida para retornar (CALL, llamada a subrutinas)
Algunas computadoras incluyen instrucciones complejas dentro de sus capacidades. Una sola instrucción compleja hace lo mismo que en otras computadoras puede requerir una larga serie de instrucciones, por ejemplo:
• salvar varios registros en la pila de una sola vez
• mover grandes bloques de memoria
• operaciones aritméticas complejas o de punto flotante (seno, coseno, raíz cuadrada)
Mientras que una computadora reconoce la instrucción de máquina IA-32
10110000 01100001
para los programadores de microprocesadores x86 es mucho más fácil reconocer dicha instrucción empleando lenguaje ensamblador:
movb 0x61,%al
Descripcion De Los Lenguajes De Programacion
***LENGUAJES DE MÁQUINA***
El lenguaje máquina de una computadora consta de cadenas de números binarios (ceros y unos) y es el único que "entienden" directamente los procesadores. Todas las instrucciones preparadas en cualquier lenguaje de máquina tienen por lo menos dos partes. La primera es el comando u operación, que dice a la computadora cuál es la función que va a realizar. Todas las computadoras tienen un código de operación para cada una de sus funciones. La segunda parte de la instrucción es el operando, que indica a la computadora dónde hallar o almacenar los datos y otras instrucciones que se van a manipular; el número de operandos de una instrucción varía en las distintas computadoras. En una computadora de operando único, el equivalente binario de "SUMAR 0814" podría hacer que se sume el valor que se encuentra en la localidad de almacenamiento o dirección 0814 al valor que se encuentra en la unidad aritmética lógica. En una máquina de dos operandos, la representación binaria de "SUMAR 0814 8672" podría hacer que se sume el valor que está en la localidad 8672 al valor que está en la dirección 0814. El formato de operando único es popular en las microcomputadoras más pequeñas; la estructura de dos operandos se encuentra en casi todas las demás máquinas.
Según los estándares actuales, las primeras computadoras eran poco tolerantes. Los programadores tenían que traducir las instrucciones de manera directa a la forma de lenguaje de máquina que comprendían las computadoras. Por ejemplo, un programador que escribiera la instrucción "SUMAR 0814" para una de las primeras máquinas IBM hubiera escrito:
000100000000000000000000000010111000
Además de recordar las docenas de códigos numéricos para los comandos del conjunto de instrucciones de la máquina, el programador tenía que conocer las posiciones donde se almacenan los datos y las instrucciones. La codificación inicial muchas veces requería meses, por lo que era costosa y era frecuente que originara errores. Revisar las instrucciones para localizar errores era casi tan tedioso como escribirlas por primera vez. Además, si era necesario modificar un programa posteriormente, la tarea podía llevarse meses.
***LENGUAJES DE ALTO NIVEL***
Los primeros programas ensambladores producían sólo una instrucción en lenguaje de máquina por cada instrucción del programa fuente. Para agilizar la codificación, se desarrollaron programas ensambladores que podían producir una cantidad variable de instrucciones en lenguaje de máquina por cada instrucción del programa fuente. Dicho de otra manera, una sola macroinstrucción podía producir varias líneas de código en lenguaje de máquina. Por ejemplo, el programador podría escribir "LEER ARCHIVO", y el programa traductor produciría una serie detallada de instrucciones al lenguaje de máquina previamente preparadas, con lo que se copiaría un registro del archivo que estuviera leyendo el dispositivo de entrada a la memoria principal. Así, el programador no se tenía que ocupar de escribir una instrucción por cada operación de máquina realizada.
El desarrollo de las técnicas nemotécnicas y las macroinstrucciones condujo, a su vez, al desarrollo de lenguajes de alto nivel que a menudo están orientados hacia una clase determinada de problemas de proceso. Por ejemplo, se han diseñado varios lenguajes para procesar problemas científico-matemático, asimismo han aparecido otros lenguajes que hacen hincapié en las aplicaciones de proceso de archivos.
A diferencia de los programas de ensamble, los programas en lenguaje de alto nivel se pueden utilizar con diferentes marcas de computadores sin tener que hacer modificaciones considerables. Esto permite reducir sustancialmente el costo de la reprogramación cuando se adquiere equipo nuevo. Otras ventajas de los lenguajes de alto nivel son:
• Son más fáciles de aprender que los lenguajes ensambladores.
• Se pueden escribir más rápidamente.
• Permiten tener mejor documentación.
• Son más fáciles de mantener.
• Un programador que sepa escribir programas en uno de estos lenguajes no está limitado a utilizar un solo tipo de máquina.
*** LENGUAJES INTERPRETADOS ***
Se puede también utilizar una alternativa diferente de los compiladores para traducir lenguajes de alto nivel. En vez de traducir el programa fuente y grabar en forma permanente el código objeto que se produce durante la corrida de compilación para utilizarlo en una corrida de producción futura, el programador sólo carga el programa fuente en la computadora junto con los datos que se van a procesar. A continuación, un programa intérprete, almacenado en el sistema operativo del disco, o incluido de manera permanente dentro de la máquina, convierte cada proposición del programa fuente en lenguaje de máquina conforme vaya siendo necesario durante el proceso de los datos. No se graba el código objeto para utilizarlo posteriormente.
La siguiente vez que se utilice una instrucción, se le debe interpretar otra vez y traducir a lenguaje máquina. Por ejemplo, durante el procesamiento repetitivo de los pasos de un ciclo, cada instrucción del ciclo tendrá que volver a ser interpretado cada vez que se ejecute el ciclo, lo cual hace que el programa sea más lento en tiempo de ejecución (porque se va revisando el código en tiempo de ejecución) pero más rápido en tiempo de diseño (porque no se tiene que estar compilando a cada momento el código completo). El intérprete elimina la necesidad de realizar una corrida de compilación después de cada modificación del programa cuando se quiere agregar funciones o corregir errores; pero es obvio que un programa objeto compilado con antelación deberá ejecutarse con mucha mayor rapidez que uno que se debe interpretar a cada paso durante una corrida de producción.
**LENGUAJES DE PROGRAMACIÓN DECLARATIVOS***
Se les conoce como lenguajes declarativos en ciencias computacionales a aquellos lenguajes de programación en los cuales se le indica a la computadora qué es lo que se desea obtener o qué es lo que se esta buscando, por ejemplo: Obtener los nombres de todos los empleados que tengan más de 32 años. Eso se puede lograr con un lenguaje declarativo como SQL.
La programación declarativa es una forma de programación que implica la descripción de un problema dado en lugar de proveer una solución para dicho problema, dejando la interpretación de los pasos específicos para llegar a dicha solución a un intérprete no especificado. La programación declarativa adopta, por lo tanto, un enfoque diferente al de la programación imperativa tradicional.
En otras palabras, la programación declarativa provee el "qué", pero deja el "cómo" liberado a la implementación particular del intérprete. Por lo tanto se puede ver que la programación declarativa tiene dos fases bien diferenciadas, la declaración y la interpretación.
Es importante señalar que a pesar de hacer referencia a intérprete, no hay que limitarse a "lenguajes interpretados" en el sentido habitual del término, sino que también se puede estar trabajando con "lenguajes compilados".
CARACTERÍSTICAS DE LOS LENGUAJES DE PROGRAMACIÓN DECLARATIVOS
• Los lenguajes declarativos están orientados a buscar la solución del problema, sin preocuparse por la forma de llegar a ello; es decir, el programador debe concentrarse en la lógica del algoritmo, más que en el control de la secuencia.
• Los programas están formados por un conjunto de definiciones o ecuaciones, las cuales describen lo que debe ser calculado, no en sí la forma de hacerlo.
• Las variables sólo pueden tener asignado un solo valor a lo largo de la ejecución del programa, lo cual implica que no puede existir asignación destructiva. Debido a esto, cobra especial importancia el uso del anidamiento y la recursividad.
• Las listas representan la estructura fundamental de datos.
• El orden de la ejecución no resulta importante debido a que no existen efectos colaterales; es decir, que al calcular un valor, resulta imposible afectar el cálculo de otros y con esto se puede afirmar que cualquier secuencia de ejecución deberá conducir al mismo resultado.
• Las expresiones o definiciones pueden ser usadas como valores y por lo tanto se pueden tratar como argumentos de otras definiciones.
• El control de la ejecución no es responsabilidad del programador.
***DESVENTAJAS DE LA PROGRAMACIÓN DECLARATIVA***
La principal desventaja de la programación declarativa es que no puede resolver cualquier problema dado, sino que está restringida al subconjunto de problemas para los que el intérprete o compilador fue diseñado.
Otra desventaja de la programación declarativa está relacionada con la eficiencia. Dado que es necesaria una fase de interpretación extra, en la cual se deben evaluar todas las consecuencias de todas las declaraciones realizadas, el proceso es relativamente más lento que en la programación imperativa, en que los cambios de estado del sistema están dados por instrucciones particulares y no por un conjunto de condiciones arbitrariamente grande.
***VENTAJAS DE LA PROGRAMACIÓN DECLARATIVA***
A pesar de lo anterior existen algunas ventajas en el uso de la programación declarativa. Entre las ventajas se destaca que la solución de un problema se puede realizar con un nivel de abstracción considerablemente alto, sin entrar en detalles de implementación irrelevantes, lo que hace a las soluciones más fácil de entender por las personas. La resolución de problemas complejos es resuelta por el intérprete a partir de la declaración de las condiciones dadas.
La programación declarativa es muy usada en la resolución de problemas relacionados con inteligencia artificial, bases de datos, configuración, y comunicación entre procesos; sin embargo, ningún leguaje declarativo se aproxima en popularidad a los lenguajes imperativos.
***EJEMPLOS DE LENGUAJES DECLARATIVOS***
Algunos lenguajes declarativos que se pueden mencionar son:
• PROLOG
• SQL
• HTML
• WSDL (Web Services Description Language)
• XML Stylesheet Language for Transformation
***PROGRAMACIÓN LÓGICA***
La idea fundamental de la programación lógica consiste en emplear la lógica como lenguaje de programación.
La lógica no es imperativa porque no sirve para indicar cómo resolver un problema (órdenes). La lógica es declarativa porque sirve para especificar qué problema resolver (condiciones).
En la programación lógica, se especifican las condiciones que satisfacen las soluciones, se deducen las soluciones a partir de las condiciones y el énfasis de todo está en qué problema resolver. El problema se describe especificando qué caracteriza a sus posibles soluciones.
La programación lógica, junto con la funcional, forma parte de lo que se conoce como programación declarativa. En los lenguajes tradicionales, la programación consiste en indicar cómo resolver un problema mediante sentencias; en la programación lógica, se trabaja de forma descriptiva, estableciendo relaciones entre entidades, indicando no cómo, sino qué hacer. Se establece entonces que la idea esencial de la programación lógica es: algoritmos = lógica + control. Es decir, un algoritmo se construye especificando conocimiento en un lenguaje formal (lógica de primer orden), y el problema se resuelve mediante un mecanismo de inferencia (control) que actúa sobre aquél.
Al hacer un recorrido por la programación lógica, aparece como uno de sus lenguajes más representativos, Prolog, que es un clásico de la inteligencia artificial y que se aplica de múltiples formas en el desarrollo de software comercial.
***PROGRAMACIÓN FUNCIONAL***
La programación funcional es un paradigma de programación declarativa basado en la utilización de funciones matemáticas. El objetivo de la programación funcional es conseguir lenguajes expresivos y matemáticamente elegantes, en los que no sea necesario bajar al nivel de la máquina para describir el proceso llevado a cabo por el programa.
Los programas escritos en un lenguaje funcional están constituidos únicamente por definiciones de funciones, entendiendo éstas no como subprogramas clásicos de un lenguaje imperativo (pues la programación funcional es declarativa), sino como funciones puramente matemáticas, en las que se verifican ciertas propiedades como la transparencia referencial (el significado de una expresión depende únicamente del significado de sus subexpresiones), y por tanto, la carencia total de efectos laterales.
Otras características propias de estos lenguajes son la no existencia de asignaciones de variables y la falta de construcciones estructuradas como la secuencia o la iteración (lo que obliga en la práctica a que todas las repeticiones de instrucciones se lleven a cabo por medio de funciones recursivas).
Existen dos grandes categorías de lenguajes funcionales: los funcionales puros y los híbridos. La diferencia entre ambos estriba en que los lenguajes funcionales híbridos son menos dogmáticos que los puros, al permitir conceptos tomados de los lenguajes imperativos, como las secuencias de instrucciones o la asignación de variables. En contraste, los lenguajes funcionales puros tienen una mayor potencia expresiva, conservando a la vez su transparencia referencial, algo que no se cumple siempre con un lenguaje híbrido.
El lenguaje máquina de una computadora consta de cadenas de números binarios (ceros y unos) y es el único que "entienden" directamente los procesadores. Todas las instrucciones preparadas en cualquier lenguaje de máquina tienen por lo menos dos partes. La primera es el comando u operación, que dice a la computadora cuál es la función que va a realizar. Todas las computadoras tienen un código de operación para cada una de sus funciones. La segunda parte de la instrucción es el operando, que indica a la computadora dónde hallar o almacenar los datos y otras instrucciones que se van a manipular; el número de operandos de una instrucción varía en las distintas computadoras. En una computadora de operando único, el equivalente binario de "SUMAR 0814" podría hacer que se sume el valor que se encuentra en la localidad de almacenamiento o dirección 0814 al valor que se encuentra en la unidad aritmética lógica. En una máquina de dos operandos, la representación binaria de "SUMAR 0814 8672" podría hacer que se sume el valor que está en la localidad 8672 al valor que está en la dirección 0814. El formato de operando único es popular en las microcomputadoras más pequeñas; la estructura de dos operandos se encuentra en casi todas las demás máquinas.
Según los estándares actuales, las primeras computadoras eran poco tolerantes. Los programadores tenían que traducir las instrucciones de manera directa a la forma de lenguaje de máquina que comprendían las computadoras. Por ejemplo, un programador que escribiera la instrucción "SUMAR 0814" para una de las primeras máquinas IBM hubiera escrito:
000100000000000000000000000010111000
Además de recordar las docenas de códigos numéricos para los comandos del conjunto de instrucciones de la máquina, el programador tenía que conocer las posiciones donde se almacenan los datos y las instrucciones. La codificación inicial muchas veces requería meses, por lo que era costosa y era frecuente que originara errores. Revisar las instrucciones para localizar errores era casi tan tedioso como escribirlas por primera vez. Además, si era necesario modificar un programa posteriormente, la tarea podía llevarse meses.
***LENGUAJES DE ALTO NIVEL***
Los primeros programas ensambladores producían sólo una instrucción en lenguaje de máquina por cada instrucción del programa fuente. Para agilizar la codificación, se desarrollaron programas ensambladores que podían producir una cantidad variable de instrucciones en lenguaje de máquina por cada instrucción del programa fuente. Dicho de otra manera, una sola macroinstrucción podía producir varias líneas de código en lenguaje de máquina. Por ejemplo, el programador podría escribir "LEER ARCHIVO", y el programa traductor produciría una serie detallada de instrucciones al lenguaje de máquina previamente preparadas, con lo que se copiaría un registro del archivo que estuviera leyendo el dispositivo de entrada a la memoria principal. Así, el programador no se tenía que ocupar de escribir una instrucción por cada operación de máquina realizada.
El desarrollo de las técnicas nemotécnicas y las macroinstrucciones condujo, a su vez, al desarrollo de lenguajes de alto nivel que a menudo están orientados hacia una clase determinada de problemas de proceso. Por ejemplo, se han diseñado varios lenguajes para procesar problemas científico-matemático, asimismo han aparecido otros lenguajes que hacen hincapié en las aplicaciones de proceso de archivos.
A diferencia de los programas de ensamble, los programas en lenguaje de alto nivel se pueden utilizar con diferentes marcas de computadores sin tener que hacer modificaciones considerables. Esto permite reducir sustancialmente el costo de la reprogramación cuando se adquiere equipo nuevo. Otras ventajas de los lenguajes de alto nivel son:
• Son más fáciles de aprender que los lenguajes ensambladores.
• Se pueden escribir más rápidamente.
• Permiten tener mejor documentación.
• Son más fáciles de mantener.
• Un programador que sepa escribir programas en uno de estos lenguajes no está limitado a utilizar un solo tipo de máquina.
*** LENGUAJES INTERPRETADOS ***
Se puede también utilizar una alternativa diferente de los compiladores para traducir lenguajes de alto nivel. En vez de traducir el programa fuente y grabar en forma permanente el código objeto que se produce durante la corrida de compilación para utilizarlo en una corrida de producción futura, el programador sólo carga el programa fuente en la computadora junto con los datos que se van a procesar. A continuación, un programa intérprete, almacenado en el sistema operativo del disco, o incluido de manera permanente dentro de la máquina, convierte cada proposición del programa fuente en lenguaje de máquina conforme vaya siendo necesario durante el proceso de los datos. No se graba el código objeto para utilizarlo posteriormente.
La siguiente vez que se utilice una instrucción, se le debe interpretar otra vez y traducir a lenguaje máquina. Por ejemplo, durante el procesamiento repetitivo de los pasos de un ciclo, cada instrucción del ciclo tendrá que volver a ser interpretado cada vez que se ejecute el ciclo, lo cual hace que el programa sea más lento en tiempo de ejecución (porque se va revisando el código en tiempo de ejecución) pero más rápido en tiempo de diseño (porque no se tiene que estar compilando a cada momento el código completo). El intérprete elimina la necesidad de realizar una corrida de compilación después de cada modificación del programa cuando se quiere agregar funciones o corregir errores; pero es obvio que un programa objeto compilado con antelación deberá ejecutarse con mucha mayor rapidez que uno que se debe interpretar a cada paso durante una corrida de producción.
**LENGUAJES DE PROGRAMACIÓN DECLARATIVOS***
Se les conoce como lenguajes declarativos en ciencias computacionales a aquellos lenguajes de programación en los cuales se le indica a la computadora qué es lo que se desea obtener o qué es lo que se esta buscando, por ejemplo: Obtener los nombres de todos los empleados que tengan más de 32 años. Eso se puede lograr con un lenguaje declarativo como SQL.
La programación declarativa es una forma de programación que implica la descripción de un problema dado en lugar de proveer una solución para dicho problema, dejando la interpretación de los pasos específicos para llegar a dicha solución a un intérprete no especificado. La programación declarativa adopta, por lo tanto, un enfoque diferente al de la programación imperativa tradicional.
En otras palabras, la programación declarativa provee el "qué", pero deja el "cómo" liberado a la implementación particular del intérprete. Por lo tanto se puede ver que la programación declarativa tiene dos fases bien diferenciadas, la declaración y la interpretación.
Es importante señalar que a pesar de hacer referencia a intérprete, no hay que limitarse a "lenguajes interpretados" en el sentido habitual del término, sino que también se puede estar trabajando con "lenguajes compilados".
CARACTERÍSTICAS DE LOS LENGUAJES DE PROGRAMACIÓN DECLARATIVOS
• Los lenguajes declarativos están orientados a buscar la solución del problema, sin preocuparse por la forma de llegar a ello; es decir, el programador debe concentrarse en la lógica del algoritmo, más que en el control de la secuencia.
• Los programas están formados por un conjunto de definiciones o ecuaciones, las cuales describen lo que debe ser calculado, no en sí la forma de hacerlo.
• Las variables sólo pueden tener asignado un solo valor a lo largo de la ejecución del programa, lo cual implica que no puede existir asignación destructiva. Debido a esto, cobra especial importancia el uso del anidamiento y la recursividad.
• Las listas representan la estructura fundamental de datos.
• El orden de la ejecución no resulta importante debido a que no existen efectos colaterales; es decir, que al calcular un valor, resulta imposible afectar el cálculo de otros y con esto se puede afirmar que cualquier secuencia de ejecución deberá conducir al mismo resultado.
• Las expresiones o definiciones pueden ser usadas como valores y por lo tanto se pueden tratar como argumentos de otras definiciones.
• El control de la ejecución no es responsabilidad del programador.
***DESVENTAJAS DE LA PROGRAMACIÓN DECLARATIVA***
La principal desventaja de la programación declarativa es que no puede resolver cualquier problema dado, sino que está restringida al subconjunto de problemas para los que el intérprete o compilador fue diseñado.
Otra desventaja de la programación declarativa está relacionada con la eficiencia. Dado que es necesaria una fase de interpretación extra, en la cual se deben evaluar todas las consecuencias de todas las declaraciones realizadas, el proceso es relativamente más lento que en la programación imperativa, en que los cambios de estado del sistema están dados por instrucciones particulares y no por un conjunto de condiciones arbitrariamente grande.
***VENTAJAS DE LA PROGRAMACIÓN DECLARATIVA***
A pesar de lo anterior existen algunas ventajas en el uso de la programación declarativa. Entre las ventajas se destaca que la solución de un problema se puede realizar con un nivel de abstracción considerablemente alto, sin entrar en detalles de implementación irrelevantes, lo que hace a las soluciones más fácil de entender por las personas. La resolución de problemas complejos es resuelta por el intérprete a partir de la declaración de las condiciones dadas.
La programación declarativa es muy usada en la resolución de problemas relacionados con inteligencia artificial, bases de datos, configuración, y comunicación entre procesos; sin embargo, ningún leguaje declarativo se aproxima en popularidad a los lenguajes imperativos.
***EJEMPLOS DE LENGUAJES DECLARATIVOS***
Algunos lenguajes declarativos que se pueden mencionar son:
• PROLOG
• SQL
• HTML
• WSDL (Web Services Description Language)
• XML Stylesheet Language for Transformation
***PROGRAMACIÓN LÓGICA***
La idea fundamental de la programación lógica consiste en emplear la lógica como lenguaje de programación.
La lógica no es imperativa porque no sirve para indicar cómo resolver un problema (órdenes). La lógica es declarativa porque sirve para especificar qué problema resolver (condiciones).
En la programación lógica, se especifican las condiciones que satisfacen las soluciones, se deducen las soluciones a partir de las condiciones y el énfasis de todo está en qué problema resolver. El problema se describe especificando qué caracteriza a sus posibles soluciones.
La programación lógica, junto con la funcional, forma parte de lo que se conoce como programación declarativa. En los lenguajes tradicionales, la programación consiste en indicar cómo resolver un problema mediante sentencias; en la programación lógica, se trabaja de forma descriptiva, estableciendo relaciones entre entidades, indicando no cómo, sino qué hacer. Se establece entonces que la idea esencial de la programación lógica es: algoritmos = lógica + control. Es decir, un algoritmo se construye especificando conocimiento en un lenguaje formal (lógica de primer orden), y el problema se resuelve mediante un mecanismo de inferencia (control) que actúa sobre aquél.
Al hacer un recorrido por la programación lógica, aparece como uno de sus lenguajes más representativos, Prolog, que es un clásico de la inteligencia artificial y que se aplica de múltiples formas en el desarrollo de software comercial.
***PROGRAMACIÓN FUNCIONAL***
La programación funcional es un paradigma de programación declarativa basado en la utilización de funciones matemáticas. El objetivo de la programación funcional es conseguir lenguajes expresivos y matemáticamente elegantes, en los que no sea necesario bajar al nivel de la máquina para describir el proceso llevado a cabo por el programa.
Los programas escritos en un lenguaje funcional están constituidos únicamente por definiciones de funciones, entendiendo éstas no como subprogramas clásicos de un lenguaje imperativo (pues la programación funcional es declarativa), sino como funciones puramente matemáticas, en las que se verifican ciertas propiedades como la transparencia referencial (el significado de una expresión depende únicamente del significado de sus subexpresiones), y por tanto, la carencia total de efectos laterales.
Otras características propias de estos lenguajes son la no existencia de asignaciones de variables y la falta de construcciones estructuradas como la secuencia o la iteración (lo que obliga en la práctica a que todas las repeticiones de instrucciones se lleven a cabo por medio de funciones recursivas).
Existen dos grandes categorías de lenguajes funcionales: los funcionales puros y los híbridos. La diferencia entre ambos estriba en que los lenguajes funcionales híbridos son menos dogmáticos que los puros, al permitir conceptos tomados de los lenguajes imperativos, como las secuencias de instrucciones o la asignación de variables. En contraste, los lenguajes funcionales puros tienen una mayor potencia expresiva, conservando a la vez su transparencia referencial, algo que no se cumple siempre con un lenguaje híbrido.
Suscribirse a:
Entradas (Atom)
