Un. I. Introducción a la programación de sistemas 1.1 Qué es la programación de sistemas? La programación de sistemas comprende el desarrollo de aquellos programas de computadora que tienen una fuerte interacción con el hardware de la computadora y su sistema operativo. Los programas de sistemas tienen que ver con organización y direcciones de memoria, registros del procesador, ciclos de reloj, Entrada / Salida, conjuntos de instrucciones, dispositivos periféricos, etc. Ejemplos de programas de sistemas: El sistema operativo (S.O) Traductores de lenguaje (compiladores, ensambladores, interpretes, etc.) Cargadores ( loaders ) Ligadores (linkers). El diseño y construcción de los compiladores requiere del conocimiento y aplicación de multiples disciplinas, tales como: teoria de la comunicación y lenguajes, arquitectura de computadoras, ingeniería de software, programación de computadoras, entre otras. 1.2 Herramientas desarrolladas con la teoría de programación de sistemas El mecanismo más básico de operar una computadora es entrando un comando y esperar una acción o resultado como respuesta. Aunque hoy en día se usan interfaces de usuario más amigables como uso de ratón, tabletas
gráficas, pantallas sensibles al tacto, etc. casi todas las acciones se convierten en comandos que son ejecutados como si se hubieran tecleado directamente. Podemos ver la aplicación de la programación de sistemas en herramientas tales como: Procesadores de comandos ( shell ) Procesadores de palabras Correctores gramaticales Editores sensibles al contexto Procesadores de lenguaje como SQL, HTML o XML Procesadores de archivos de inicialización (.INI ) 1.3 Lenguajes 1.3.1 Proceso de la comunicación
Los lenguajes de más alto nivel no ofrecen necesariamente mayores capacidades de programación, pero si ofrecen una interacción programador/computadora más avanzada. Cuanto más alto es el nivel del lenguaje, más sencillo es comprenderlo y utilizarlo. El único lenguaje que hoy en día la computadora es capaz de entender de forma nativa es en código binario. Aun no existe una computadora cuyo lenguaje nativo sea un lenguaje humano, tal como el español. Para reducir la complejidad y costo de programar al nivel físico de la computadora (unos y ceros) se emplea un enfoque de máquina multinivel. 1.3.2 Lenguajes Naturales Son los que cotidianamente los seres humanos utilizan para comunicarse, expresar ideas, etc. Tiene una fuerte caracterización para las costumbres, geografía y entorno entre otros. Ejemplo: Ingles, francés, Español. En un futuro quizás sea posible desarrollar un lenguaje de programación basado 100% en lenguaje natural. 1.3.3 Lenguajes Artificiales Son aquellos que intentan resolver situaciones de ambigüedad o de múltiple interpretación, que se da en los lenguajes naturales. Ejemplo: la palabra Salte en lenguaje natural debe ser interpretada como salir o saltar? También llamados Lenguajes formales tales como Lenguajes Matemáticos como en una expresión matemática. Ejemplo: ½ x 2 dx Estos lenguajes artificiales son subconjuntos de un lenguaje natural utilizado con un fin determinado; ejemplo, para la programación de computadoras.
Lenguaje de Programación: Son un tipo de lenguaje artificial que se usan como herramientas para trabajar con una computadora. Son notaciones para escribir programas a través de los cuales podemos comunicarnos con el hardware y dar así las órdenes adecuadas para la realización de un determinado proceso. Podemos diferenciar entre tres grupos principales de lenguajes de programación: 1. Lenguaje Maquina. 2. Lenguaje Ensamblador. 3. Lenguaje de Alto Nivel. Lenguaje Maquina: Es el único que entiende la computadora, utiliza al alfabeto binario (0,1) denominados bits. Lenguaje Ensamblador: Cada instrucción equivale a una instrucción del lenguaje maquina. Se utilizan palabras Menemo Técnicas en lugar de cadenas de bits. Al igual que el lenguaje maquina hay un lenguaje ensamblador para cada modelo de computadora. Lenguaje de Alto Nivel: Ofrece un nivel de abstracción que permite la especificación de datos, funciones o procesos y su control en forma independiente de la maquina. 1.4 Traductores y su estructura Un traductor es un programa que convierte un programa fuente a un objeto o programa objeto. El programa fuente puede estar en algún lenguaje de
programación dado. El programa objeto esta en el otro lenguaje de programación. 1.4.1 Traductores - Ensambladores - Interpretes - Compiladores - Preprocesadores Cuando se empezaron a utilizar símbolos nemotécnicos, se escribieron programas para traducir automáticamente los programas escritos en lenguaje ensamblador a lenguaje máquina. A estos programas traductores se les llamo ensambladores. La entrada para un ensamblador es un programa fuente escrito en lenguaje ensamblador. La salida es un programa objeto, escrito en lenguaje de máquina. El programa objeto incluye también la información necesaria para que el cargador pueda preparar el programa objeto para su ejecución. Para evitar confusiones, de aquí en adelante llamaremos lenguaje ensamblador al conjunto de nemotécnicos y a las reglas para su manejo. Al programa que traduce un programa objeto a partir de un programa escrito en lenguaje ensamblador lo llamaremos ensamblador.
Es como un compilador, solo que la salida es una ejecución. El programa de entrada se reconoce y ejecuta a la vez. No se produce un resultado físico (código máquina) sino lógico (una ejecución). Hay lenguajes que sólo pueden ser interpretados, como p.ej. SNOBOL (StriNg Oriented SimBOlyc Language), LISP (LISt Processing), algunas versiones de BASIC (Beginner s All-purpose Symbolic Instruction Code), etc. Su principal ventaja es que permiten una fácil depuración. Entre los inconvenientes podemos citar, en primer lugar, la lentitud de ejecución, ya que al ejecutar a la vez que se traduce no puede aplicarse un alto grado de optimización. Además de que la traducción optimiza el programa acercándolo a la máquina, los lenguajes interpretados tienen la característica de que permiten construir programas que se pueden modificar a sí mismos. Hoy en día, un compilador es un traductor que facilita la comunicación entre el programador y la máquina, por medio de un proceso de transformación. Un compilador es un programa que lee las líneas escritas en un lenguaje de programación (como Pascal) y las traduce a otro que pueda ejecutar la computadora. Los programas compilados se ejecutan más rápido que los interpretados, debido a que han sido completamente traducidos a lenguaje de máquina y no necesitan compartir memoria con el intérprete.
A grandes rasgos un compilador es un programa que lee un programa escrito es un lenguaje, el lenguaje fuente, y lo traduce a un programa equivalente en otro lenguaje, el lenguaje objeto. Como parte importante de este proceso de traducción, el compilador informa a su usuario de la presencia de errores en el programa fuente. El programa compilador traduce las instrucciones en un lenguaje de alto nivel a instrucciones que la computadora puede interpretar y ejecutar. Para cada lenguaje de programación se requiere un compilador separado. El compilador traduce todo el programa antes de ejecutarlo. Los compiladores son, pues, programas de traducción insertados en la memoria por el sistema operativo para convertir programas de cómputo en pulsaciones electrónicas ejecutables (lenguaje de máquina).
1.4.2 Contexto de la compilación.
1.4.3 Estructura de un compilador. La estructura de un compilador, está dividida en cuatro grandes módulos, cada uno independiente del otro, se podría decir que un compilador está formado por cuatros módulos más a su vez. El primero de ellos es el preprocesador, es el encargado de transformar el código fuente de entrada original en el código fuente puro. El segundo modulo es el de compilación que recibe el código fuente puro, este es él modulo principal de un compilador, pues si ocurriera algún error en esta etapa el compilador no podría avanzar. En esta etapa se somete al código fuente puro de entrada a un análisis léxico gráfico, a un análisis sintáctico, a un análisis semántico, que construyen la tabla de símbolos, se genera un código intermedio al cual se optimiza para así poder producir un código de salida generalmente en algún lenguaje ensamblador. El tercer modulo es el llamado modulo de ensamblado, este modulo no es ni más ni menos que otro compilador pues recibe un código fuente de entrada escrito en ensamblador, y produce otro código de salida, llamado código binario no enlazado. El cuarto y último modulo es el encargado de realizar el enlazado del código de fuente de entrada (código maquina re localizable) con las librerías que necesita, como así también de proveer al código de las rutinas necesarias para poder ejecutarse y cargarse a la hora de llamarlo para su ejecución, modifica las direcciones re localizables y ubica los datos en las posiciones apropiadas de la memoria.
1.5 Generadores de código para compiladores (compilador de compilador). Analizando en detalle el proceso de compilación, se divide en dos grandes fases, una de Análisis y la otra de Síntesis. Fase de Análisis: En el llamado análisis lexicográfico o léxico, el compilador revisa y controla que las "palabras" estén bien escritas y pertenezcan a algún tipo de token (cadena) definido dentro del lenguaje, como por ejemplo que sea algún tipo de palabra reservada, o si es el nombre de una variable que este escrita de acuerdo a las pautas de definición del lenguaje.
En el análisis sintáctico como su nombre lo indica se encarga de revisar que los tokens estén ubicados y agrupados de acuerdo a la definición del lenguaje. Dicho de otra manera, que los tokens pertenezcan a frases gramaticales validas, que el compilador utiliza para sintetizar la salida. El análisis semántico se encarga de revisar que cada agrupación o conjunto de token tenga sentido, y no sea un absurdo. En esta etapa se reúne la información sobre los tipos para la fase posterior, en esta etapa se utiliza la estructura jerárquica de la etapa anterior y así poder determinar los operadores, y operandos de expresiones y preposiciones. Fase de Síntesis: Etapa de generación de código intermedio, aunque algunos compiladores no la tienen, es bueno saber de su existencia, en esta etapa se lleva el código del programa fuente a un código interno para poder trabajar más fácilmente sobre él. En la etapa de optimización de código, se busca obtener el código más corto y rápido posible, utilizando distintos algoritmos de optimización. Etapa de generación de código, se lleva el código intermedio final a código maquina o código objeto, que por lo general consiste en un código maquina re localizable o código ensamblador. La tabla de símbolos no es una etapa del proceso de compilación, sino que una tarea, una función que debe realizar el proceso de compilación. En ella se almacenan los identificadores que aparecen en el código fuente puro, como así también los atributos de los mismos, su tipo, su ámbito y en el caso de los procedimientos el número de argumentos el tipo del mismo etc.