Conceptos De Compilador
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Conceptos De Compilador

on

  • 834 views

 

Statistics

Views

Total Views
834
Views on SlideShare
834
Embed Views
0

Actions

Likes
1
Downloads
19
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft Word

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Conceptos De Compilador Document Transcript

  • 1. Conceptos de compilador.<br />Un compilador es un programa informático que traduce un programa escrito es un lenguaje de programación a otro lenguaje de programación genera un programa equivalente que la maquina será capaz de interpretar. <br />Un compilador es un programa que permite traducir el código fuente de un programa de lenguaje de alto nivel a otro lenguaje de nivel inferior es típicamente lenguaje de maquina un programador puede diseñar un programa de lenguaje más cercano al ser humano para luego compilar al programa de la computadora. <br />Un traductor es cualquier programa que toma como entrada un texto escrito en un lenguaje, llamado fuente y da como salida otro texto en un lenguaje, denominado objeto.<br />Compilador: Es un lenguaje fuente sea un lenguaje de programación de alto nivel y el objeto sea un lenguaje de bajo nivel ensamblador o código de máquina, a dicho traductor se le denomina compilador. Un ensamblador es un compilador cuyo lenguaje fuente es el lenguaje ensamblador. <br />Históricamente, con la escasez de memoria de los primeros ordenadores, se puso de moda el uso de intérpretes frente a los compiladores, pues el programa fuente sin traducir y el intérprete juntos daban una ocupación de memoria menor que la resultante de los compiladores.<br /> Por ello los primeros ordenadores personales iban siempre acompañados de un intérprete de BASIC La mejor información sobre los errores por parte del compilador así como una mayor velocidad de ejecución del código resultante hizo que poco a poco se impusieran los compiladores.<br />El proceso de compilador: Es el proceso por el cual se traducen las instrucciones escritas en un determinado lenguaje de programación o lenguaje de máquina. Un traductor se puede necesitar otros programas para crear un programa objeto ejecutable. Es una tarea de reunir programas fuente a menudo se confía un programas distintos y se llama preprocesador. <br />Los preprocesadores también puede que se expande abreviaturas, y se llaman marcos que son proposiciones de lenguaje fuentes. La creación de un programa ejecutable es un típico de EXE para Microsoft Windows o DOS que conlleva los pasos.<br />Se llama compilación propiamente dicha y traducida los códigos fuentes escritos en un lenguaje de programación que al almacenado en un archivo a código en bajo nivel en código normalmente y directamente a un lenguaje de máquina. <br />Se llama enlazado en el cual se enlaza al códigos de bajo nivel generado de todos los ficheros y subprogramas que se han mandado compilar y se añade el código y las funciones que hay en las bibliotecas de compiladores para que ejecute y se puedan comunicarse con el sistema operativo que traduce así finalmente los códigos objeto a código de máquina.<br />Etapas de procesos.<br />El proceso de traducción se compone internamente en varias etapas o frases, que realizan distintas operaciones lógicas. Etapas o frases que realizan distintas operaciones lógicas. Estas etapas fases como en piezas separadas dentro del traductor y pueden que en realidad escribirse como operaciones codificadas y separadamente en la práctica a menudo. <br />Tipos de compiladores.<br />Un compilador cruzado: Es un compilador capaz de crear código ejecutable para otra plataforma distinta a aquélla en la que él se ejecuta. Esta herramienta es útil cuando quiere compilarse código para una plataforma a la que no se tiene acceso, o cuando es incómodo o imposible compilar en dicha plataforma como en el caso de los sistemas embebidos. Un ejemplo de un compilador con estas posibilidades es el NASM, que puede ensamblar, entre otro formato, ELF para sistemas UNIX y COM para DOS.<br /> Uso de los compiladores cruzados: El uso fundamental de un compilador cruzado es compilar para un entorno diferente en el que se ejecuta el compilador. Esto es muy utilizado en las siguientes situaciones:<br />Sistemas empotrados, dónde los recursos son extremadamente limitados. <br />Compilación para múltiples máquinas.<br />Un compilador cruzado cross compiler es aquel que genera código para una plataforma diferente a aquella en la que se ejecuta. <br />Por ejemplo, supongamos que queremos desarrollar aplicaciones para un teléfono móvil, una PDA o una consola de videojuegos. Normalmente será más cómodo realizar el desarrollo en un PC y luego volcar el código objeto en el dispositivo de destino. En estas situaciones, el compilador que usaremos en el PC es un caso de compilador cruzado. <br />El sistema operativo Nachos se ejecuta sobre una máquina virtual basada en el procesador MIPS. Los programas de usuario deben estar escritos en código máquina del MIPS. Afortunadamente, no necesitas escribir los programas de usuario en código máquina o en ensamblador, sino que lo puedes hacer en lenguaje C. El compilador cruzado que viene con la instalación de Nachos es capaz de traducir de C a código del MIPS. <br />El compilador cruzado que distribuimos con el Nachos es una versión del popular compilador GCC. Funciona sobre prácticamente cualquier versión de Linux. Si quieres trabajar en tu propio ordenador, necesitas instalar este compilador. <br /> 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. <br />Fue usado ampliamente en el pasado para el desarrollo de software, pero actualmente sólo se utiliza en contadas ocasiones, especialmente cuando se requiere la manipulación directa del hardware o se pretenden rendimientos inusuales de los equipos. Un ensamblador crea código objeto traduciendo instrucciones mnemónicas a códigos operativos, e interpretando los nombres simbólicos para direcciones de memoria y otras entidades. <br /> El uso de referencias simbólicas es una característica básica de los ensambladores, 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, en lugar de utilizar subrutinas. <br />Los ensambladores son por lo general más fáciles de programar que los compiladores de lenguajes de alto nivel, y han estado disponibles desde la década de 1950. Los ensambladores modernos, especialmente para arquitecturas basadas en RISC, como por ejemplo MIPS, SPARC y PA-RISC optimizan las instrucciones para explotar al máximo la eficiencia de segmentación del CPU. <br />Los ensambladores de alto nivel ofrecen posibilidades de abstracción que incluyen: <br />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. <br />Un programa escrito en lenguaje Assembly consiste en una serie de instrucciones que corresponden al flujo de órdenes ejecutables que pueden ser cargadas en la memoria de una computadora.<br />Auto compilador: Es aquél que está escrito en el mismo lenguaje que se pretende compilar. Supongamos, por ejemplo, que queremos desarrollar la versión 2.0 de un compilador Pascal. Dicho compilador generará un código mucho más rápido y eficiente que el que generaba la versión anterior 1.0. <br />Sin embargo, son ya muchas las máquinas IBM 370, Serie 1, PDP 11 que disponen del antiguo compilador, o que al menos tienen otro compilador Pascal. La mejor opción consiste en escribir el nuevo compilador en Pascal, ya que así podrá el compilador ser compilado en las distintas máquinas por los compiladores Pascal ya existentes.<br />Meta compilador: Es un traductor que tiene como entrada la definición de un lenguaje y como salida el compilador para dicho lenguaje2.<br />Descompilador: Es el que traduce código máquina a lenguaje de alto nivel. Los descompiladores más usuales son los desensambladores, que traducen un programa en lenguaje máquina a otro en ensamblador.<br />Los compiladores son programas que se encargan de traducir programas escritos por el programador en lenguaje de alto nivel a un lenguaje de bajo nivel que es comprensible por la maquina y que de esta manera, permite que pueda ejecutar por la computadora y transforma el código fuente a un lenguaje de máquina y código objeto.<br />Para poder entender cómo realizar su tarea es muy conveniente conocer las diversas frases que cumplan un compilador para lograr la traducción. Las primeras tres fases son análisis léxicos, sintáctico y las frases en las que se leen los caracteres del códigos fuentes, también se analizan se comprueban si son validos y se van reagrupando en secuencias lógicas y frases y gramaticales.<br /> Esta primera partes es la que se conoce como Front End, y las últimas tres frases de las síntesis generación de códigos intermedios que optimización de códigos y generación de códigos que a partir del análisis anterior se genera la traducción para convertirlo en código o lenguaje de maquina la segunda parte se denomina Back End. <br />Permanente el manejados de errores que se encarga de analizar en cada una de las frases posibles de errores que pueden haber durante los procesos de la traducción. <br />Ventajas de compilar frente a interpretar:<br />Se compila una vez, se ejecuta n veces. <br />En bucles, la compilación genera código equivalente al bucle, pero interpretándolo se traduce tantas veces una línea como veces se repite el bucle. <br />El compilador tiene una visión global del programa, por lo que la información de mensajes de error es más detallada. <br />Ventajas del intérprete frente al compilador: <br />Un intérprete necesita menos memoria que un compilador. En principio eran más abundantes dado que los ordenadores tenían poca memoria. <br />Permiten una mayor interactividad con el código en tiempo de desarrollo.<br />Funciones de un compilador<br />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, Hay miles de lenguajes fuente, desde los lenguajes de programación tradicionales, como FORTRAN o Pascal, hasta los lenguajes especializados que han surgido virtualmente en todas las áreas de aplicación de la informática. <br />Los lenguajes objeto son igualmente variados; un lenguaje objeto puede ser otro lenguaje de programación o el lenguaje de máquina de cualquier computador entre un microprocesador y un supercomputador.<br />Partes en las que trabaja un compilador<br />Conceptualmente un compilador opera en fases. Cada una de las cuales transforma el programa fuente de una representación en otra. En la práctica se pueden agrupar fases y las representaciones intermedias entres las fases agrupadas no necesitan ser construidas explícitamente<br />Las tres primeras fases, que forman la mayor parte de la porción de análisis de un compilador se analizan en la sección IX. Otras dos actividades, la administración de la tabla se símbolos y el manejo de errores, se muestran en interacción con las seis fases de análisis léxico, análisis sintáctico, análisis semántico, generación de código intermedio, optimación de código y generación de código.<br />Administrador de la tabla de símbolos.<br />Una función esencial de un compilador es registrar los identificadores utilizados en el programa fuente y reunir información sobre los distintos atributos de cada identificador. Una tabla de símbolos es una estructura de datos que contiene un registro por cada identificador, con los campos para los atributos del identificador. <br />La estructura de datos permite encontrar rápidamente el registro de cada identificador y almacenar o consultar rápidamente datos en un registro cuando el analizador léxico detecta un identificador en el programa fuente, el identificador se introduce en la tabla de símbolos. Sin embargo, normalmente los atributos de un identificador no se pueden determinar durante el análisis léxico. <br />Las fases restantes introducen información sobre los identificadores en la tabla de símbolos y después la utilizan de varias formas. Por ejemplo, cuando se está haciendo el análisis semántico y la generación de código intermedio, se necesita saber cuáles son los tipos de los identificadores, para poder comprobar si el programa fuente los usa de una forma válida y así poder generar las operaciones apropiadas con ellos.<br /> El generador de código, por lo general, introduce y utiliza información detallada sobre la memoria asignada a los identificadores.<br />Características de un compilador.<br />Los programas compiladores se traducen las instrucciones en un lenguaje de alto nivel a instrucciones que las computadoras pueden interpretar y ejecutar cada lenguaje de programación se requieren compiladores separados.<br /> Los compiladores son programas de traducción insertadas en la memoria por los sistemas operativos para convertir programas de computadoras en pulsaciones electrónicas ejecutables de lenguaje de maquinas. <br />Características de compiladores generalmente un compilador se divide en dos partes:Front End: Analiza el código fuente, comprueba su validez, genera el árbol de derivación y rellena los valores de la tabla de símbolos. Parte que suele ser independiente de la plataforma o sistema operativo para el que funcionará. <br />Back End: parte en donde se genera el código máquina exclusivo para una plataforma a partir de lo analizado en el Front End.<br />Por lo general el resultado del Back End no puede ser ejecutado directamente, se necesita pasar por un proceso de enlazado Linker. Existen varios tipos de compiladores: Compiladores cruzados, Compiladores optimizadores, Compiladores de una sola pasada, Compiladores de varias pasadas, Compiladores JIT Just In Time.<br />Los compiladores pueden ser de:<br />una sola pasada: examina el código fuente una vez, generando el código o programa objeto. <br />pasadas múltiples: requieren pasos intermedios para producir un código en otro lenguaje, y una pasada final para producir y optimizar el código producido durante los pasos anteriores. <br />Optimación: lee un código fuente, lo analiza y descubre errores potenciales sin ejecutar el programa. <br />Compiladores incrementales: generan un código objeto instrucción por instrucción una vez en hacerlo para todo el programa cuando el usuario teclea cada orden individual.<br />Ensamblador: el lenguaje fuente es lenguaje ensamblador y posee una estructura sencilla. <br />Compilador cruzado: se genera código en lenguaje objeto para una máquina diferente de la que se está utilizando para compilar. Es perfectamente normal construir un compilador de Pascal que genere código para MS-DOS y que el compilador funcione en Linux y se haya escrito en C++. <br />Compilador con montador: compilador que compila distintos módulos de forma independiente y después es capaz de enlazarlos. <br />Auto compilador: compilador que está escrito en el mismo lenguaje que va a compilar. Evidentemente, no se puede ejecutar la primera vez. Sirve para hacer ampliaciones al lenguaje, mejorar el código generado, etc. <br />Meta compilador: es sinónimo de compilador de compiladores y se refiere a un programa que recibe como entrada las especificaciones del lenguaje para el que se desea obtener un compilador y genera como salida el compilador para ese lenguaje. El desarrollo de los meta compiladores se encuentra con la dificultad de unir la generación de código con la parte de análisis. <br />Descompilador: es un programa que acepta como entrada código máquina y lo traduce a un lenguaje de alto nivel, realizando el proceso inverso a la compilación.<br />Compiladores en sí que se entiendan.<br />Compiladores que se entiendan se manejan todo igual o quizás confundís el Front End con lo que en realidad es el compilador es la interfaz visual que se encarga de reconocer sintaxis, colorearte las palabras del lenguaje, y hacer que compilar sea tan fácil como hacer click en un botón. <br />El compilador es binario y ejecutable que pasándole como parámetros los archivos que quiere compilar te los transforma en un .EXE o binario de Linux o ejecutable de Mac o etc. <br />Ejemplo:gcc text.c -o TestEso te compila el text.c y te los transforma en un ejecutable. <br />El Free Pascal como el Borland C menor al 5 y el Turbo Pascal. Viene con un IDE por defecto que es esa cosa horrible con onda DOS.<br />Si te bajas el GCC o el Borland C 5.5. Ambos vienen sin IDE es decir interfaz visual. Tendrías que bajaste algún IDE que use alguno de estos compiladores. Por ejemplo Free C, Eclipse C++, Visual C, etc. Un lenguaje de programación permite al usuario crear programas que serán entendidos por el ordenador directa o indirectamente con el objetivo de realizar alguna tarea. <br />Ensamblador anexan todo lo que hicimos.<br />;Programa cadenas.ens<br />;;Lectura de dos cadenas, concatenar y dar la vuelta<br />;El programa pide al usuario que introduzca dos cadenas cualesquiera<br />;A continuacion, las concatena, y muestra el resultado en pantalla al<br />;derecho y al reves<br />;leer cadena1<br />wrstr /mens1<br />instr /cadena1<br />;leer cadena2<br />wrstr /mens2<br />instr /cadena2<br />;concatenar<br />move #cadena1,.r1<br />move #cadena2,.r2<br />move #resu1,.r0<br />move #resu2,.r3<br />cad1:cmp [.r1],#0<br />bz $cad2<br />move [.r1],[.r0]<br />inc .r0<br />inc .r1<br />br $cad1<br />cad2:cmp [.r2],#0<br />bz $fin<br />move [.r2],[.r0]<br />inc .r0<br />inc .r2<br />br $cad2<br />fin:move #0,[.r0]<br />;mostrar al derecho<br />wrstr /derecho<br />wrstr /resu1<br />wrstr /eol<br />;mostrar al reves<br />cmp .r0,#resu1<br />bz $fin2<br />rev:dec .r0<br />cmp [.r0],#0<br />bz $fin2<br />move [.r0],[.r3]<br />inc .r3<br />br $rev<br />fin2:move #0,[.r3]<br />wrstr /reves<br />wrstr /resu2<br />wrstr /eol<br />halt<br />;cadenas<br />mens1:data "Introduzca la primera cadena: "<br />mens2:data "Introduzca la segunda cadena: "<br />derecho:data "Cadena al derecho: "<br />reves:data "Cadena al reves: "<br />eol:data "n"<br />cadena1:res 500<br />cadena2:res 500<br />resu1:res 1000<br />resu2:res 1000<br />end<br />Programa fact.ens<br />;El programa pide un entero, y a continuacion calcula el factorial y<br />;lo muestra en pantalla.<br />;Es necesario que la pila este configurada hacia direcciones decrecientes,<br />;si no el ejemplo no funcionara correctamente.<br />; coloco el puntero de pila en la cima de la memoria<br />move #32767,.sp<br />; Escribo un mensaje y solicito un numero<br />wrstr /UN_NUMERO<br />inint .r1<br />; preparo el argumento de la funcion y la llamo<br />push .r1<br />call /SUB_FACT<br />; recupero el valor y lo trato segun lo que devolvio<br />pop .r2<br />cmp .r2,#0<br />bn /ERROR<br />wrstr /EL_FACT_ES<br />wrint .r2<br />halt<br />ERROR:cmp .r2, #COD_NEGATIVO<br />bz /ERROR1<br />wrstr /NUMERO_GRANDE<br />halt<br />ERROR1: wrstr /NUMERO_NO_VALIDO<br />halt<br />; almacenamiento de la cadenas de caracteres con su referencias<br />UN_NUMERO: data "nUn numero: "<br />NUMERO_NO_VALIDO: data "nNumero no valido"<br />NUMERO_GRANDE: data "nNumero demasiado grande"<br />EL_FACT_ES:data "nEl factorial es "<br />COD_NEGATIVO:equ -1<br />COD_OVERFLOW:equ -2<br />; ************************************************************************<br />; Rutina SUB_FACT<br />;<br />; Calcula el factorial de un numero que le viene en la pila<br />;<br />;<br />; ************************************************************************<br />; salvo los registros en el marco de pila<br />SUB_FACT:push .iy<br />push .r1<br />push .r2<br />; coloco el marco de pila<br />move .sp, .iy<br />; recojo el argumento<br />move #5[.iy],.r1<br />cmp .r1,#0<br />bp /SIGUE1<br />; es negativo devuelvo un codigo de error de numero negativo.<br />move #COD_NEGATIVO,.r2<br />br /VOLVER<br /> ; valor no negativo<br />SIGUE1:bp /SIGUE2<br />move #1,.r2<br />br /VOLVER<br /> ; valor positivo en R1<br />SIGUE2:move #1,.r2<br />SIGUEMUL:mul .r2, .r1<br />bv /OVERFLOW<br />move .a, .r2<br />dec .r1<br />cmp .r1, #0<br />bz /VOLVER<br />br /SIGUEMUL<br />; se produjo overflow, devuelvo codigo de error de OVERFLOW<br />OVERFLOW:move #COD_OVERFLOW,.r2<br />; retorno el valor en la misma posicion del argumento<br />VOLVER:move .r2, #5[.iy]<br />; restauro los valores y retorno<br />pop .r2<br />pop .r1<br />pop .iy<br />ret<br />Programa matriz.ens<br />;Muestra un menu que ofrece opciones para manejar una matriz 5x5<br />;1.Introducir un valor<br />;2.Consultar un valor<br />;3.Mostrar el contenido de la matriz<br />;4.Salir<br />nFilas: equ 6 ; número de filas de la matriz<br />nColumnas: equ 5 ; número de columnas de la matriz<br />nOpciones: equ 5 ; núm. de opciones<br />opcAlmacenar: equ 1<br />opcObtener: equ 2<br />opcMostrar: equ 3<br />opcSalir: equ 4<br /> move #0x7fff,.sp ; inicializar la pila<br />bucleGeneral:call /funcMenu <br /> move .r1, .r5 ; guardar la opcion en r5<br /> cmp .r5, #opcSalir ; comprobar que es la opcion de salir<br /> bz /fin<br /> cmp .r5, #opcMostrar ; comprobar que es la opcion de mostrar<br /> bz /opcion3<br /> call /solicitarPosicion ; solicitar par de posicion en la matriz<br /> cmp .r5 , #opcAlmacenar ; comprobar si es opcion 1 o 2<br /> bnz /opcion2<br />opcion1: wrstr /sPedirValor ; solicitar un valor<br /> inint .r3 <br /> call /ponerValor ; colocar valor en la memoria<br /> br /bucleGeneral <br />opcion2:call /dameValor ; solicitar valor de la matriz<br /> wrstr /sDecirValor ; sacar valor por pantalla<br /> wrint .r3<br /> br /bucleGeneral<br />opcion3:call /mostrarMatriz ; llamar a procedimiento de mostrar matriz<br /> wrchar #13<br /> br /bucleGeneral<br />fin: halt<br />longAlmacenMatriz: equ 6*5<br />dMatriz: res 30<br />sRetCarro: data "n"<br />sAlmacenar: data "n1 .- Amacenar valor"<br />sObtener: data "n2 .- Obtener valor"<br />sMostrar: data "n3 .- Escribir Matriz"<br />sSalir: data "n4 .- Salir" <br />sPedirOpcion: data "n Dame opcion:"<br />sPedirFila: data "n Dame número de fila: "<br />sPedirColumna: data "n Dame número de columna: "<br />sDecirValor: data "n El valor es "<br />sPedirValor: data "n Valor a almacenar: "<br />funcMenu: wrstr /sRetCarro <br /> wrstr /sAlmacenar<br /> wrstr /sObtener<br /> wrstr /sMostrar<br /> wrstr /sSalir<br /> wrstr /sPedirOpcion<br />menuDeNuevo:inchar .r1 ; lee la opcion<br /> sub .r1, #48 ; resta el valor ascii del '0'<br /> cmp .a,#1 ; comprueba límite inferior <br /> bn /menuDeNuevo ; si no valido repetir lectura<br /> cmp .a, #nOpciones ; comprueba límite superior<br /> bp /menuDeNuevo ; si no valido repetir lectura <br /> move .a, .r1 ; colocar salida en .r1<br /> ret<br />solicitarPosicion: wrstr /sPedirFila ; mensaje de solicitud<br /> inint .r1<br /> cmp .r1, #1 ; comprueba límite inferior<br /> bn /solicitarPosicion ; si no valido repetir<br /> cmp .r1, #nFilas ; comprueba límite superior<br /> bp /solicitarPosicion ; si no valido repetir<br />otraColumna:wrstr /sPedirColumna ; mensaje de solicitud<br /> inint .r2<br /> cmp .r2, #1 ; comprueba límite inferior<br /> bn /otraColumna ; si no valido repetir<br /> cmp .r2, #nColumnas ; comprueba límite superior<br /> bp /otraColumna ; si no valido repetir<br /> ret<br />dameValor:dec .r2<br /> dec .r1<br /> mul .r1, #nColumnas<br /> add .a, .r2<br /> add .a, #dMatriz<br /> move .a, .ix<br /> move #0[.ix],.r3<br /> ret<br />ponerValor:dec .r2<br /> dec .r1<br /> mul .r1, #nColumnas<br /> add .a, .r2<br /> add .a, #dMatriz<br /> move .a, .ix<br /> move .r3, #0[.ix]<br /> ret <br />mostrarMatriz:move #nFilas,.r1<br /> move #dMatriz,.ix<br /> wrstr /sRetCarro<br />otraFila:move #0,.r2<br />sigueFila: wrint #0[.ix]<br /> inc .r2<br /> inc .ix<br /> wrchar #32<br /> cmp .r2, #nColumnas<br /> bnz /sigueFila<br /> wrstr /sRetCarro<br /> dec .r1<br /> bnz /otraFila<br /> ret<br />Programa matriz.ens<br />Muestra un menu que ofrece opciones para manejar una matriz 5x5<br />1. Introducir un valor<br />2. Consultar un valor<br />3. Mostrar el contenido de la matriz<br />4. Salir<br />nFilas: equ 6 ; número de filas de la matriz<br />nColumnas: equ 5 ; número de columnas de la matriz<br />nOpciones: equ 5 ; núm. de opciones<br />opcAlmacenar: equ 1<br />opcObtener: equ 2<br />opcMostrar: equ 3<br />opcSalir: equ 4<br /> move #0x7fff,.sp ; inicializar la pila<br />bucleGeneral:call /funcMenu <br /> move .r1, .r5 ; guardar la opcion en r5<br /> cmp .r5, #opcSalir ; comprobar que es la opcion de salir<br /> bz /fin<br /> cmp .r5, #opcMostrar ; comprobar que es la opcion de mostrar<br /> bz /opcion3<br /> call /solicitarPosicion ; solicitar par de posicion en la matriz<br /> cmp .r5 , #opcAlmacenar ; comprobar si es opcion 1 o 2<br /> bnz /opcion2<br />opcion1: wrstr /sPedirValor ; solicitar un valor<br /> inint .r3 <br /> call /ponerValor ; colocar valor en la memoria<br /> br /bucleGeneral <br />opcion2:call /dameValor ; solicitar valor de la matriz<br /> wrstr /sDecirValor ; sacar valor por pantalla<br /> wrint .r3<br /> br /bucleGeneral<br />opcion3:call /mostrarMatriz ; llamar a procedimiento de mostrar matriz<br /> wrchar #13<br /> br /bucleGeneral<br />fin: halt<br />longAlmacenMatriz: equ 6*5<br />dMatriz: res 30<br />sRetCarro: data "n"<br />sAlmacenar: data "n1 .- Amacenar valor"<br />sObtener: data "n2 .- Obtener valor"<br />sMostrar: data "n3 .- Escribir Matriz"<br />sSalir: data "n4 .- Salir" <br />sPedirOpcion: data "n Dame opcion:"<br />sPedirFila: data "n Dame número de fila: "<br />sPedirColumna: data "n Dame número de columna: "<br />sDecirValor: data "n El valor es "<br />sPedirValor: data "n Valor a almacenar: "<br />funcMenu: wrstr /sRetCarro <br /> wrstr /sAlmacenar<br /> wrstr /sObtener<br /> wrstr /sMostrar<br /> wrstr /sSalir<br /> wrstr /sPedirOpcion<br />menuDeNuevo:inchar .r1 ; lee la opcion<br /> sub .r1, #48 ; resta el valor ascii del '0'<br /> cmp .a,#1 ; comprueba límite inferior <br /> bn /menuDeNuevo ; si no valido repetir lectura<br /> cmp .a, #nOpciones ; comprueba límite superior<br /> bp /menuDeNuevo ; si no valido repetir lectura <br /> move .a, .r1 ; colocar salida en .r1<br /> ret<br />solicitarPosicion: wrstr /sPedirFila ; mensaje de solicitud<br /> inint .r1<br /> cmp .r1, #1 ; comprueba límite inferior<br /> bn /solicitarPosicion ; si no valido repetir<br /> cmp .r1, #nFilas ; comprueba límite superior<br /> bp /solicitarPosicion ; si no valido repetir<br />otraColumna:wrstr /sPedirColumna ; mensaje de solicitud<br /> inint .r2<br /> cmp .r2, #1 ; comprueba límite inferior<br /> bn /otraColumna ; si no valido repetir<br /> cmp .r2, #nColumnas ; comprueba límite superior<br /> bp /otraColumna ; si no valido repetir<br /> ret<br />dameValor:dec .r2<br /> dec .r1<br /> mul .r1, #nColumnas<br /> add .a, .r2<br /> add .a, #dMatriz<br /> move .a, .ix<br /> move #0[.ix],.r3<br /> ret<br />ponerValor:dec .r2<br /> dec .r1<br /> mul .r1, #nColumnas<br /> add .a, .r2<br /> add .a, #dMatriz<br /> move .a, .ix<br /> move .r3, #0[.ix]<br /> ret <br />mostrarMatriz:move #nFilas,.r1<br /> move #dMatriz,.ix<br /> wrstr /sRetCarro<br />otraFila:move #0,.r2<br />sigueFila: wrint #0[.ix]<br /> inc .r2<br /> inc .ix<br /> wrchar #32<br /> cmp .r2, #nColumnas<br /> bnz /sigueFila<br /> wrstr /sRetCarro<br /> dec .r1<br /> bnz /otraFila<br /> ret<br />operaciones.ens<br />En r0 se guarda la direccion de la funcion de operacion<br />en r1 se guarda el primer operando<br />en r2 se guarda el segundo operando<br />en a se guarda el resultado de la operacion<br />en r3 se guarda la opcion elegida por el usuario<br />INICIO:<br />; Muestra las operaciones por la consola<br />wrstr /menu1<br />wrstr /menu2<br />wrstr /menu3<br />wrstr /menu4<br />wrstr /menu5<br />wrstr /menu6<br />wrstr /menu7<br />wrstr /menu8<br />wrstr /menu0<br />; Lectura de la operacion<br />wrstr /cad1<br />inint .r3<br />; Se calcula la direccion de la funcion correspondiente<br />cmp .r3,#0<br />bz /SALIR<br />cmp .r3,#1<br />bz $OP1<br />cmp .r3,#2<br />bz $OP2<br />cmp .r3,#3<br />bz $OP3<br />cmp .r3,#4<br />bz $OP4<br />cmp .r3,#5<br />bz $OP5<br />cmp .r3,#6<br />bz $OP6<br />cmp .r3,#7<br />bz $OP7<br />cmp .r3,#8<br />bz $OP8<br />br $OPERROR<br />OPERANDOS :<br />;primer operando - se guarda en la variable OPERANDO1<br />wrstr /cad2<br />inint /OPERANDO1<br />;segundo operando - se guarda en la variable OPERANDO2<br />wrstr /cad3<br />inint /OPERANDO2<br />;se ponen los parametros en la pila<br />push /RESULTADO<br />push /OPERANDO1<br />push /OPERANDO2<br />;se llama a la funcion operar<br />call /OPERAR<br />;se recuperan los valores de retorno de la funcion<br />pop /OPERANDO2<br />pop /OPERANDO1<br />pop /RESULTADO<br />;se muestra el resultado<br />wrstr /cad4<br />wrint /RESULTADO<br />wrstr /saltolin<br />ACARREO :bnc $DESBORDAMIENTO<br />wrstr /cad7<br />DESBORDAMIENTO :bnv $ACABAR<br />wrstr /cad6<br />;vuelta a empezar<br />ACABAR :br /INICIO<br />;direcciones de las funciones<br />OP1 : move #SUMA,.r0<br />br /OPERANDOS<br />OP2 :move #RESTA,.r0<br />br /OPERANDOS<br />OP3 : move #PRODUCTO,.r0<br />br /OPERANDOS<br />OP4 : move #DIVISION,.r0<br />br /OPERANDOS<br />OP5 :move #MODULO,.r0<br />br /OPERANDOS<br />OP6 :move #Y,.r0<br />br /OPERANDOS<br />OP7 :move #O,.r0<br />br /OPERANDOS<br />OP8 :move #OEX,.r0<br />br /OPERANDOS<br />OPERROR :move #ERROR,.r0<br />br /OPERANDOS<br />;Funciones (paso de parametros por registros)<br />SUMA :add .r1,.r2<br />ret<br />RESTA :sub .r1,.r2<br />ret<br />PRODUCTO :mul .r1,.r2<br />ret<br />DIVISION :div .r1,.r2<br />ret<br />MODULO :mod .r1,.r2<br />ret<br />Y :and .r1,.r2<br />ret<br />O :or .r1,.r2<br />ret<br />OEX :xor .r1,.r2<br />ret<br />ERROR :wrstr /cad5<br />ret<br />SALIR :halt<br />;funcion operar(paso de parametros por pila)<br />OPERAR :move .sp,.ix<br />move #3[.ix],.r1 ;se recupera el primer argumento<br />move #2[.ix],.r2 ;se recupera el segundo argumento<br />call [.r0] ;se llama a la operacion pertinente<br />move .a,#4[.ix] ;se devuelve el resultado<br />ret<br />;cadenas de texto<br />cad1 :data "Introduzca la operacion: "<br />cad2 :data "Introduzca el primer operando: "<br />cad3 :data "Introduzca el segundo operando: "<br />cad4 :data "El resultado de la operacion es: "<br />cad5 :data "La operacion introducida no es correcta.n"<br />cad6 :data "La operacion produjo desbordamiento.n"<br />cad7 :data "La operacion produjo acarreo.n"<br />menu1 :data "1.Suman"<br />menu2 :data "2.Restan"<br />menu3 :data "3.Producton"<br />menu4 :data "4.Divisionn"<br />menu5 :data "5.Modulon"<br />menu6 :data "6.Andn"<br />menu7 :data "7.Orn"<br />menu8 :data "8.Xorn"<br />menu0 :data "0.Salirn"<br />saltolin :data "n"<br />;variables<br />OPERANDO1 :res 1<br />OPERANDO2 : res 1<br />RESULTADO :res 1<br />end<br />Los arboles que hay árboles como se identifican.<br />Los arboles Inorden: Izquierda-Raíz-Derecha. <br />GEAIBMCLDFKJH.<br />IE <br />M<br />CGA<br />JB<br />D<br />HKLF<br /> Los arboles Postorden: izquierda-Derecha-Raíz. <br />A<br />GE<br />JDH<br />LC<br />KF<br />GLos arboles Pre orden: Raíz-izquierda-Derecha. <br />AE <br />HCI<br />FDMB<br />J<br />Los arboles Inorden.<br />DIABEGLDCFMKHJ.<br />A<br />GI<br />LEB<br />H<br />F<br />JKCM<br />Los arboles Postorden: <br />BLD<br />I <br />MAGE<br />J <br />FCKH<br />ILos arboles Pre orden:<br />AB<br />EJ<br />DLGM<br />FC<br />HK<br />Gramática BNF definición.<br />La BNF es un metalenguaje muy utilizado para definir la estructura sintáctica de un lenguaje de programación. Con la aparición de la notación BNF desarrollada en primer lugar por Backus en 1960 cuando trabajaba en un borrador del ALGOL 60, modificada en 1963 por Naur y formalizada por Knuth en 1964 se tiene una guía para el desarrollo del análisis sintáctico. <br />En 1959, Sheridan describe un método de FORTRAN que introducía paréntesis adicionales alrededor de los operando para ser capaz de analizar las expresiones. Más adelante, Floyd introduce la técnica de la precedencia de operador y el uso de las funciones de precedencia. A mitad de la década de los 60, Knuth define las gramáticas LR y describe la construcción de una tabla canónica de LR. <br />Por otra parte, el uso por primera vez descendente recursivo tuvo lugar en el año 1961. En el año 1968 se estudian y definen las gramáticas LL así como los parsers predictivos. También se estudia la eliminación de la recursión a la izquierda de producciones que contienen acciones semánticas sin afectar a los valores de los atributos. <br /> Los métodos SLR y LALR de LR. Debido a su sencillez y a su capacidad de análisis para una gran variedad de lenguajes, la técnica de LR va a ser la elegida para los generadores automáticos de parsers. A mediados de los 70, Johnson crea el generador de analizadores sintácticos YACC para funcionar bajo un entorno UNIX. Junto al análisis sintáctico, también se fue desarrollando el análisis semántico.<br />La gramática Bnf es el acrónico de Backus Naur Form, y fue utilizada para describir el algol 60 Backus 59 Naur 63. Algunas definiciones para el correcto de la notación de Bnf.<br />Terminal: Es un símbolo terminal cuando tiene entidad propia y se describe por sí mismo es decir no requiere una explicación. <br />No terminal: Es un símbolo es no terminal cuando requiere una explicación mediante una regla o producción. En Bnf han de ir encerrado entre los paréntesis angulares.<br />Meta símbolos: son aquellos símbolos de la notación utilizada dos para distinguir los elementos y propiedades de una regla. <br />En la notación Bnf se utilizan una serie de reglas o producciones cuyos objetivos es la descripción de unidades sintácticas o símbolos no terminales. <br />Una regla BNF: <br />V   <br />Especifica que un solo símbolo no terminal v N puede ser substituido por N T sin importar el contexto donde aparezca v. Estas producciones se conocen como independientes del contexto. De acuerdo con N. Chomsky, una gramática y un lenguaje correspondiente son independientes del contexto si y solo si pueden definirse con un conjunto de producciones independientes del contexto. <br />Las gramáticas independientes del contexto son muy importantes en la teoría de los lenguajes de programación, ya que los lenguajes que definen tienen, en general, una estructura muy sencilla. Las técnicas de análisis sintáctico suelen basarse en gramáticas independientes del contexto. <br />Una gramática representa la definición formal de la sintaxis de un lenguaje. Consta de un conjunto de reglas que especifican las secuencias de símbolos ítems de léxico que forman estructuras sintácticas en el lenguaje definido.<br />Un metalenguaje es una gramática formal destinada a la descripción de un lenguaje. Existen tres metalenguajes comúnmente utilizados. BNF se identifica como Backus-Naur-Form.<br />Notación desarrollada por los especialistas Backus y Naur para definir lenguaje Algol60<br />Ejemplo de BNF para lenguaje Pascal:<br /><Sentencia for>:= for <variable>:= <intervalo> do <sentencia><br /><Intervalo>:= <valor inicial> to <valor final> | <valor inicial> downto <valor final><br /><Sentencia for>:= for <variable>:= <valor inicial> <hasta> <valor final>do <sentencia><br /><hasta>::= to | downto<br /><variable> := <identificador><br /><Identificador>:= <letra> {<letra>|<dígito>} o<br /><letra>:= A | B... | Z | a | b... | z<br /><dígito>:= 0 | 1 | 2... | 9<br /><valor inicial>:= <expresión><br /><valor final>:= <expresión><br />Alternativamente se pueden usar reglas BNF en forma recursiva.<br /><Alfanum>:= <letra> | <dígito><br /><secuencia>:= <alfanum> | <alfanum> <secuencia><br /><identificador>:= <letra> | <letra> <secuencia><br />Los símbolos <, >, |, {,}:=, no son parte del lenguaje definido, sino parte del mecanismo de descripción y reciben el nombre de meta símbolos. El símbolo:= significa se define como. Las secuencias encerradas entre < > constituyen símbolos no terminales o meta variables y las secuencias restantes subrayadas y otras símbolos terminales.<br />La máquina de Turing.<br />Es un modelo computacional que realiza una lectura y escritura de manera automática sobre una entrada llamada cinta, generando una salida en esta misma. Este modelo está formado por un alfabeto de entrada y uno de salida, un símbolo especialmente llamado blanco que un conjunto de estados finitos y un conjunto de transiciones entre dichos estados. <br />Su funcionamiento se basa en una función de transición, que recibe un estado inicial y una cadena de caracteres de la cinta, la cual puede ser infinita pertenecientes al alfabeto de entrada. <br />La máquina puede ir leyendo una celda de la cinta en cada paso, también es borrando el símbolo en el que se encuentra posicionado su cabezal y escribiendo un nuevo símbolo perteneciente al alfabeto de salida, para luego desplazar el cabezal a la izquierda o a la derecha. <br />Esto se repite según se indique en la función de transición, para finalmente detenerse en un estado final o de aceptación, representando así la salida.<br />Mediante este modelo teórico y el análisis de la complejidad de los algoritmos, fue posible la categorización de problemas computacionales de acuerdo a su comportamiento, apareciendo así, el conjunto de problemas denominados P y NP, cuyas soluciones pueden encontrarse en tiempo polinómico por máquinas de Turing deterministas y no deterministas, respectivamente.<br />Definición formal:<br />Una máquina de Turing con una sola cinta puede definirse como una 7 tupla. <br /> Donde:[]<br />es un conjunto finito de estados. <br />es un conjunto finito de símbolos distinto del espacio en blanco, denominado alfabeto de máquina o de entrada. <br />es un conjunto finito de símbolos de cinta, denominado alfabeto de cinta. <br />es el estado inicial. <br />es un símbolo denominado blanco, y es el único símbolo que se puede repetir un número infinito de veces. <br />es el conjunto de estados finales de aceptación. <br /> es una función parcial denominada función de transición, donde es un movimiento a la izquierda y es el movimiento a la derecha. <br />Existen en la literatura un abundante número de definiciones alternativas, pero todas ellas tienen el mismo poder computacional, por ejemplo se puede añadir el símbolo como símbolo de no movimiento en un paso de cómputo.<br />El Funcionamiento<br />La máquina de Turing consta de un cabezal lector y escritor y una cinta infinita en la que el cabezal lee el contenido, borra el contenido anterior y escribe un nuevo valor. Las operaciones que se pueden realizar en esta máquina se limitan. <br />Avanzar el cabezal lector y escritor hacia la derecha. <br />Visualización de una máquina de Turing, en la que se ve el cabezal y la cinta que se lee.<br />Avanzar el cabezal lector y escritor hacia la izquierda. <br />El cómputo es determinado a partir de una tabla de estados de la forma: Estado, valor y nuevo estado, nuevo valor, dirección. <br />Esta tabla toma como parámetros el estado actual de la máquina y el carácter leído de la cinta, dando la dirección para mover el cabezal, el nuevo estado de la máquina y el valor a escribir en la cinta. La memoria es la cinta de la máquina que se divide en espacios de trabajo denominados celdas, donde se pueden escribir y leer símbolos. Inicialmente todas las celdas contienen un símbolo especial denominado blanco. <br />La máquina de Turing puede considerarse como un autómata capaz de reconocer lenguajes formales. <br />En ese sentido, es capaz de reconocer los lenguajes recursivamente e numerables, Su potencia es, por tanto, superior a otros tipos de autómatas, como el autómata finito, o el autómata con pila, o igual a otros modelos con la misma potencia computacional.<br />Representación como diagrama de estados.<br />Las maquinas de Turing pueden representarse mediante grafos particulares, también llamados diagramas de estados finitos, de la siguiente manera. <br />Esta máquina de Turing está definida sobre el alfabeto a, b, c, posee el conjunto de estados q0, q1, q2, q3, q4, q5, q6, con las transiciones que se pueden ver. Su estado inicial es q0 y el estado final es q2, el lenguaje de salida X, Y, Z, B siendo B el símbolo denominado blanco. Esta máquina reconoce la expresión regular de la forma anbncn con n > = 0.<br />Los estados se representan como vértices, etiquetados con su nombre en el interior. <br />Una transición desde un estado a otro, se representa mediante una arista dirigida que une a estos vértices, y esta rotulada por símbolo que lee el cabezal y símbolo que escribirá el cabezal, movimiento del cabezal. <br />El estado inicial se caracteriza por tener una arista que llega a él y que no proviene de ningún otro vértice. <br />El o los estados finales se representan mediante vértices que están encerrados a su vez por otra circunferencia. <br />Modificaciones equivalentes.<br />Una razón para aceptar la máquina de Turing como un modelo general de cómputo es que el modelo que hemos definido anteriormente es equivalente a muchas versiones modificadas que en principio pareciera incrementar el poder computacional. <br />Máquina de Turing determinista y no determinista.<br />La entrada de una máquina de Turing viene determinada por el estado actual y el símbolo leído, un par estado, símbolo, siendo el cambio de estado, la escritura de un nuevo símbolo y el movimiento del cabezal, las acciones a tomar en función de una entrada. <br />Símbolo posible exista a lo sumo una posibilidad de ejecución, se dirá que es una máquina de Turing determinista, mientras que en el caso de que exista al menos un par estado, símbolo con más de una posible combinación de actuaciones se dirá que se trata de una máquina de Turing no determinista. <br />La capacidad de cómputo de ambas versiones es equivalente; se puede demostrar que dada una máquina de Turing no determinista existe otra máquina de Turing determinista equivalente, en el sentido de que reconoce el mismo lenguaje, y viceversa. <br />Es decir, el no determinismo permitirá reducir la complejidad de la solución de los problemas, permitiendo resolver, por ejemplo, problemas de complejidad exponencial en un tiempo polinómico.<br />Codificación de una máquina de Turing<br />Toda máquina de Turing puede codificarse como una secuencia binaria finita, es decir una secuencia finita de ceros y unos. Para simplificar la codificación, suponemos que toda MT tiene un único estado inicial denotado por, y un único estado final denotado. Tendremos que para una MT M de la forma. <br /> donde s1 representa el símbolo blanco 0, Δ o b según se desee denotar, es alfabeto de entrada y son los símbolos auxiliares utilizados por M cada MT utiliza su propia colección finito de símbolos auxiliares. <br />Máquina universal de Turing. <br />Una máquina de Turing computa una determinada función parcial de carácter definido, definida sobre las secuencias de posibles cadenas de símbolos de su alfabeto. Posiblemente, la idea germinal del concepto de sistema operativo, un programa que puede, a su vez, ejecutar, en el sentido de controlar otros programas, demostrando su existencia, y abriendo camino para su construcción real. <br />Con esta codificación de tablas como cadenas, se abre la posibilidad de que unas máquinas de Turing se comporten como otras máquinas de Turing. Sin embargo, muchas de sus posibilidades son indecidibles, pues no admiten una solución algorítmica. <br />Máquina de Turing cuántica<br />En 1985, Deutsch presentó el diseño de la primera Máquina cuántica basada en una máquina de Turing. Con este fin enunció una nueva variante la tesis de Church Turing dando lugar al denominado principio de Church Turing Deutsch. <br /> <br />Está compuesta por los tres elementos clásicos:<br />una cinta de memoria infinita en donde cada elemento es un qubit, <br />un procesador finito y <br />un cabezal. <br />La cinta de memoria es similar a la de una máquina de Turing tradicional. La única diferencia es que cada elemento de la cinta de la máquina cuántica es un qubit. El alfabeto de esta nueva máquina está formado por el espacio de valores del qubit. La posición del cabezal se representa con una variable entera.<br />El análisis sintáctico, como se utilizan puede ser descendente y ascendente.<br />Un analizador sintáctico es una de las partes de un compilador que transforma su entrada en un árbol de derivación. El análisis sintáctico convierte el texto de entrada en otras estructuras comúnmente árboles, que son más útiles para el posterior análisis y capturan la jerarquía implícita de la entrada. <br />Un analizador léxico crea tokens de una secuencia de caracteres de entrada y son estos tokens los que son procesados por el analizador sintáctico para construir la estructura de datos, por ejemplo un árbol de análisis o árboles de sintaxis abstracta los lenguajes habitualmente reconocidos por los analizadores sintácticos son los lenguajes libres de contexto. <br />Cabe notar que existe una justificación formal que establece que los lenguajes libres de contexto son aquellos reconocibles por un autómata de pila, de modo que todo analizador sintáctico que reconozca un lenguaje libre de contexto es equivalente en capacidad computacional a un autómata de pila. <br />Los analizadores sintácticos fueron extensivamente estudiados durante los años 70 del siglo XX, detectándose numerosos patrones de funcionamiento en ellos, cosa que permitió la creación de programas generadores de analizadores sintácticos a partir de una especificación de la sintaxis del lenguaje en forma Backus-Naur.<br />Análisis sintáctico descendente:<br />Un analizador puede empezar con el símbolo inicial e intentar transformarlo en la entrada, intuitivamente esto sería ir dividiendo la entrada progresivamente en partes cada vez más pequeñas. <br />El análisis sintáctico descendente es una técnica de análisis sintáctico que intenta comprobar si una cadena X pertenece al lenguaje definido por una gramática L y G aplicando los siguientes criterios.<br />Partir del axioma de la gramática.<br />Escoger reglas gramaticales estratégicamente.<br />Hacer derivaciones por la izquierda.<br />Obtener el árbol de análisis sintáctico o error.<br />Análisis sintáctico descendente<br />Explicaremos este método con un ejemplo, usando la siguiente gramática simple, G1 T1, N1, P1, S1 que define los enteros no negativos ENN<br />T1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}<br />N1 = {DIGITO, ENN}<br />P1 = {ENN DIGITO | ENN DIGITO}<br />DIGITO 0|1|2|3|4|5|6|7|8|9|<br />S1 = {ENN}<br />Queremos analizar la frase 123. Un principio solo conocemos la raíz del árbol y la frase que debe analizarse.<br />Árbol semántico frase<br />ENN 1 2 3<br />En el primer paso encontramos la producción ENN DIGITO y obtenemos el inicio del árbol de análisis sintáctico.<br />En el siguiente paso hallamos de nuevo a la misma producción.<br />Después encontramos la producción ENN DIGITO, que expande el árbol sintáctico a lo siguiente:<br />Encontramos ahora la producción DIGITO 1, que establece la conexión con el primer elemento de la frase dada.<br />La producción DIGITO 2 establece la conexión con el segundo elemento de la frase:<br />Por último el árbol de análisis sintáctico queda completo con la producción DIGITO 3.<br />Podemos ver que el árbol crece de arriba abajo a medida que se lee la frase de entrada de izquierda a derecha. Por consiguiente, este método se denomina análisis sintáctico descendente.<br />Análisis sintáctico ascendente.<br />Un analizador puede empezar con la entrada e intentar llegar hasta el símbolo inicial, intuitivamente el analizador intenta encontrar los símbolos más pequeños y progresivamente construir la jerarquía de símbolos hasta el inicial. <br />Objetivo de un análisis ascendente.<br />El objetivo de un análisis ascendente consiste en construir el árbol sintáctico desde abajo hacia arriba, esto es, desde los tokens hacia el axioma inicial, lo cual disminuye el número de reglas mal aplicadas con respecto al caso descendente si hablamos del caso con retroceso o amplía el número de gramáticas susceptibles de ser analizadas si hablamos del caso LL.<br />Operaciones en un analizador ascendente.<br />Un analizador sintáctico va construyendo el árbol, se enfrenta a una configuración distinta se denomina configuración y debe tomar una decisión sobre el siguiente paso u operación a realizar. <br />Básicamente se dispone de cuatro operaciones diferentes, y cada tipo de analizador ascendente se distingue de los demás en base a la inteligencia sobre cuándo aplicar cada una de dichas operaciones análisis ascendente consiste en partir de una configuración inicial e ir aplicando operaciones, cada una de las cuales permite pasar de una configuración origen a otro destino.<br />Las operaciones disponibles son las siguientes: <br />1. ACEPTAR: se acepta la cadena: β ≡ EOF y α ≡ S. axioma inicial. <br />2. RECHAZAR: la cadena de entrada no es válida. <br />3. REDUCIR: consiste en aplicar una regla de producción hacia atrás a algunos elementos situados en el extremo derecho de α. <br />4. DESPLAZAR: consiste únicamente en quitar el terminal más a la izquierda de β y ponerlo a la derecha de α. <br />Clasificación <br />Analizador sintáctico ascendente con retroceso. <br />Analizador sintáctico ascendente LR. <br />Análisis ascendente con retroceso.<br />Que ocurría con el caso descendente, este tipo de análisis intenta probar todas las posibles operaciones reducciones y desplazamientos mediante un método de fuerza bruta, hasta llegar al árbol sintáctico, o bien agotar todas las opciones, en cuyo caso la cadena se rechaza. <br />En el análisis con retroceso no se permiten las reglas, puesto que estas se podrán aplicar de forma indefinida. <br />Análisis ascendente sin retroceso.<br />El análisis ascendente sin retroceso busca una derivación derecha de la cadena de entrada de forma determinista. <br />Este se sustenta en su aplicación a las gramáticas LR K. <br />La L viene de la lectura de la cadena de entrada de izquierda a derecha. <br />La R de producir un árbol de derivación derecho. <br />La k indica el número de símbolos que es necesario leer a la entrada para tomar la decisión de qué producción emplear. <br />Un Parser del tipo short reduce puede verse como un autómata de pila determinista extendido que realiza el análisis de abajo hacia arriba. <br />Dada una cadena de entrada w, simula una derivación más a la derecha. <br />Diferencias entre el descendente y el ascendente <br />En el análisis sintáctico descendente: se construye el árbol sintáctico arriba hacia abajo y se utiliza más reglas. <br />En el análisis sintáctico ascendente: se construye el árbol sintáctico de abajo hacia arriba, lo cual disminuye el número de reglas mal aplicadas con respecto al caso descendente.<br />Análisis sintáctico ascendente.<br />Ejemplifiquemos el análisis sintáctico ascendente usando otra vez la gramática G1 y la frase 123. De nuevo, solo sabemos cuál es la raíz del árbol de análisis sintáctico y la frase que debemos de analizar. En el primer paso se encuentran la reducción 1 DIGITO y se obtiene el inicio del árbol sintáctico.<br />En el segundo paso se encuentra la reducción del DIGITO ENN y se obtiene el segundo árbol sintáctico El tercer paso reduce el segundo elemento de la frase usando la reducción 2 DIGITO. Entonces se aplica la reducción DIGITO ENN para continuar con el árbol de análisis sintáctico:<br />En el paso siguiente se reduce a un digito el último elemento de la frase: 3 DIGITO<br />Para concluir se completa el árbol de análisis sintáctico con la reducción ENN DIGITO ENN: A partir de este ejemplo podemos ver que comenzamos con las hojas del árbol sintáctico y asciende hacia la raíz. . Por ello, este método se denomina análisis sintáctico ascendente.<br />El análisis léxicos.<br />El analizador léxico, también conocido como scanner, lee los caracteres uno a uno desde la entrada y va formando grupos de caracteres con alguna relación entre sí tokens, que constituirán la entrada para la siguiente etapa del compilador. Cada token representa una secuencia de caracteres que son tratados como una única entidad. <br />Hay dos tipos de tokens: tiras específicas, el punto y coma, la asignación, los operadores aritméticos o lógicos, etc.; tiras no específicas, como identificadores, constantes o etiquetas. Se considera que un token tiene dos partes componentes: el tipo de token y su valor. Las tiras específicas sólo tienen tipo lo que representan, mientras que las tiras no específicas tienen tipo y valor.<br />Comenzaremos con la parte más sencilla del compilador: el analizador léxico. Habitualmente el término análisis léxico se refiere al tratamiento de la entrada que produce como salida la lista de tokens. Un token hace alusión a las unidades más simples que tiene significado. <br />Habitualmente un token o lexema queda descrito por una expresión regular. Léxico viene del griego lexis, que significa palabra. Una herramienta eficaz para encontrar en qué lugar de la cadena se produce un emparejamiento. <br />El análisis léxico, el problema es encontrar la subcadena a partir de la última posición en la que se produjo un emparejamiento y que es aceptada por una de las expresiones regulares que definen los lexemas del lenguaje dado.<br />En un compilador, el análisis lineal se llama análisis lineal o exploración. Por análisis lineal entendemos la cadena de caracteres que constituye el programa fuente se lee de izquierda a derecha y se agrupan en componentes léxicos, que son secuencias de caracteres que tiene un significado colectivo en análisis léxico los caracteres de las siguientes proposiciones de asignación. <br />Los espacios en blanco separan los caracteres de estos componentes léxicos normalmente se eliminan durante el análisis léxico. Una expresión regular denota un conjunto de secuencias de símbolos válidas que se construyen en base al alfabeto de un lenguaje.<br />El Analizador Léxico es la etapa del compilador que va a permitir saber si es un lenguaje de formato libre. Frecuentemente va unido al analizador sintáctico en la misma pasada, funcionando entonces como una subrutina de este último. Ya que es el que va leyendo los caracteres del programa, ignorará aquellos elementos innecesarios para la siguiente fase, como los tabuladores, comentarios, espacios en blanco.<br />Funcionamiento de un analizador léxico.<br />El analizador léxico es la primera fase de un compilador. Su función principal es leer los caracteres de entrada y producir como salida una secuencia de tokens que el parser luego utiliza en su análisis sintáctico. El analizador léxico lee una secuencia de caracteres del código fuente del programa hasta identificar un token, el cual es retornado como respuesta al pedido del analizador sintáctico.<br />El analizador léxico opera bajo petición del analizador sintáctico devolviendo un componente léxico conforme el analizador sintáctico lo va necesitando para avanzar en la gramática. Los componentes léxicos son los símbolos terminales de la gramática. Suele implementarse como una subrutina del analizador sintáctico. <br />Cuando recibe la orden el siguiente componente léxico, el analizador léxico lee los caracteres de entrada hasta idéntica el siguiente componente léxico. Analizador léxico analizador sintáctico programa fuente léxico componente<br />Especificación de un Analizador Léxico. <br /> Analizador Léxico para un lenguaje determinado, es necesario diseñar su especificación. Para ello hay que identificar primeramente la colección de tokens que compone el lenguaje. Cada token debe estar especificado mediante algún esquema generador o un esquema reconocedor, preferiblemente expresiones regulares. <br />Funciones el análisis léxico.<br />Otras funciones secundarias:<br />Manejo del chero de entrada del programa fuente: abrirlo, leer sus caracteres, cerrarlo y gestionar posibles errores de lectura.<br />Eliminar comentarios, espacios en blanco, tabuladores y saltos de línea o caracteres no validos para formar un token. <br />Inclusión de ficheros: # include ...<br />La expansión de macros y funciones inline: # define ...<br />Contabilizar el número de líneas y columnas para emitir mensajes de error.<br />Reconocimiento y ejecución de las directivas de compilación.<br />Ventajas de separar el análisis léxico y el análisis sintáctico:<br />Facilita transportabilidad del traductor (por ejemplo, si decidimos en un momento dado cambiar las palabras reservadas Begin y End de inicio y de bloque, por f y g, solo hay que cambiar este modulo.<br />Se simplifica el diseño: el analizador es un objeto con el que se interactúa mediante ciertos métodos.<br />La opción g <br />Como lo usamos en un contexto escalar, la opción g itera sobre la cadena, devolviendo cierto cada vez que casa, y falso cuando deja de casar. Se puede averiguar la posición del emparejamiento utilizando la función. <br />La opción c. <br />La opción c afecta a las operaciones de emparejamiento con g en un contexto escalar. Normalmente, cuando una búsqueda global escalar tiene lugar y no ocurre casamiento, la posición de comienzo de búsqueda es restablecida al comienzo de la cadena. La opción c hace que la posición inicial de emparejamiento permanezca donde la dejó el último emparejamiento con éxito y no se vaya al comienzo. Al combinar esto con el ancla G, la cual casa con el final del último emparejamiento, obtenemos que la combinación. <br />La opción i: La última opción i permite ignorar los tipos de letra mayúsculos o minúsculos. <br />Código del Analizador Léxico. <br />Este es el código completo de la subrutina scanner que se encarga del análisis léxico:<br />1 package Lexical::Analysis;<br /> 2 sub scanner {<br /> 3 local $_ = Shift;<br /> 4 {# Con el redo del final hacemos un bucle "infinito"<br /> 5 if (m {Gs* (d+)}gc) {<br /> 6 push @tokens, 'NUM', $1;<br /> 7 } <br /> 8 elsif (m {Gs*intb}igc) {<br /> 9 push @tokens, 'INT', 'INT';<br />10 } <br />11 elsif (m {Gs*stringb}igc) {<br />12 push @tokens, 'STRING', 'STRING';<br />13 } <br />14 elsif (m {Gs*pb}igc) {<br />15 push @tokens, 'P', 'P'; # P para imprimir<br />16 } <br />17 elsif (m {Gs* ([a-z_]w*)b} igc) {<br />18 push @tokens, 'ID', $1;<br />19 } <br />20 elsif (m {Gs*"([^"]*)"} igc) {<br />21 push @tokens, 'STR', $1;<br />22 } <br />23 elsif (m {Gs* ([+*() = ;,])} GC) {<br />24 push @tokens, 'PUN', $1;<br />25 }<br />26 elsif (m {Gs*(S)}gc) {# Hay un carácter "no blanco"<br />27 Error: fatal "Carácter invalido: $1n";<br />28 }<br />29 else {<br />30 last;<br />31 }<br />32 redo;<br />33 }<br />34 }<br /> <br />Buffers de entrada.<br />buffer de entrada resulta útil cuando es necesario un pre-análisis en la entrada para identificar los componentes léxicos después se introducen algunas técnicas básicas para encontrar la velocidad del analizador léxico, como es el uso de centinelas que sirven para marcar el final de buffer, hay tres métodos generales de implantar un léxico:<br />Utilizar un generador de analizadores léxicos, como el compilador LEX para producir el analizador léxico a partir de una especificación basada en expresiones regulares, en este caso el generador proporciona rutinas para leer la entrada y manejarla con buffers.<br />Escribir el analizador léxico en un lenguaje convencional de programación de sistemas utilizando las posibilidades de entrada y salida de este lenguaje para leer la entrada.<br /> Escribir el analizador léxico en lenguaje ensamblador y manejar explícitamente la lectura de la entrada<br />Área del almacenamiento primario destinada a contener datos durante transferencia de entrada salida. <br />Si se utiliza la pareja de buffers, cada vez que se mueva el apuntador delantero se debe comprobar si se ha salido de una mitad del buffer, si así ocurriera se deberá cargar la segunda mitad. <br /> <br />Se pueden reducir estas dos pruebas a una si se amplía cada mitad del buffer para admitir un carácter centinela EOF al final.<br />Se mantienen dos apuntadores al buffer de entrada:<br /> Apuntador delantero examina hacia delante hasta encontrar una concordancia con un patrón. Una vez determinado el siguiente lexema, el apuntador delantero se coloca en el carácter de su extremo derecho.<br /> <br /> Apuntador de lexema se queda al inicio del lexema y lo procesa. <br />Técnica de Pareja de buffers <br />Se divide en dos mitades de tamaño N un bloque del disco 1024 o 4096 Dos punteros: comienzo lexema y delantero.<br /> Al principio los dos igual y avanzo delantero hasta encontrar concordancia con patrón un token.<br />      Delantero se coloca en su carácter derecho.<br />     Comienzo lexema y delantero delimitan lexema.<br />    Procesa lexema (devuelvo token y coloco comienzo lexema en delantero primer carácter del siguiente<br />      Cando termina una mitad, recarga la otra y continua hasta encontrar token.<br />Un buffer de entrada resulta útil cuando es entrada para identificar los componentes léxicos después se introducen algunas técnicas básicas para encontrar la velocidad del analizador léxico, como es el uso de centinelas que sirven para marcar el final de buffer, hay tres métodos generales de implantar un léxico:<br />Escribir el analizador léxico en un lenguaje convencional de programación de sistemas utilizando las posibilidades de entrada y salida de este lenguaje para leer la entrada.<br /> Escribir el analizador léxico en lenguaje ensamblador y manejar explícitamente la lectura de la entrada.<br /> Utilizar un generador de analizadores léxicos, como el compilador LEX para producir el analizador léxico a partir de una especificación basada en expresiones regulares, en este caso el generador proporciona rutinas para leer la entrada y manejarla con buffers.<br />Puede estar dividido en:<br />Texto lenguaje fuenteTraductorTexto lenguaje objetoPrograma objetoCompiladorManejo de erroresManejo de tabla de símbolosPrograma fuenteBuffer = espacio en memoriaPrograma fuenteMensajes de errorPrograma fuenteAnalizador léxicoAnalizador sintácticoAnálisis semánticoGeneración de código intermedioOptimización de códigoGenerador de códigoPrograma objetoManejo de tabla de símbolosAnalizador léxicoAnalizador sintácticoTabla de símbolosComponente léxicoObtén el siguiente componente léxico<br />Los buffers se utilizan a menudo, conjuntamente con E/S de hardware, tal como unidades de disco, enviar o recibir datos a/o desde una red, o reproducción de sonido en un altavoz. Una línea a una montaña rusa en un parque de atracciones comparte muchas similitudes. Las personas que viajan en la montaña llegan, a menudo, a un ritmo desconocido y variable, pero la montaña rusa será capaz de cargar personas de golpe tal como llegan se van montando. La zona de la cola actúa como un buffer: un espacio temporal donde los que deseen viajar deben esperar a que el viaje esté disponible. Los buffers utilizan generalmente un método FIFO primero en entrar, primero en salir, es decir, la salida de datos se produce en el orden en que llegaron.<br />Se utiliza un buffer dividido en dos mitades de caracteres cada una como se indica en la figura:<br />Texto lenguaje fuente<br />Traductor<br />Texto lenguaje objeto<br />Programa objeto<br />Compilador<br />Programa fuente<br />Mensajes de error<br />Programa fuente<br />Analizador léxico<br />Analizador sintáctico<br />Análisis semántico<br />Generación de código intermedio<br />Optimización de código<br />Generador de código<br />Programa objeto<br />Manejo de errores<br />Manejo de tabla de símbolos<br />Analizador léxico<br />Analizador sintáctico<br />Tabla de símbolos<br />Componente léxico<br />Obtén el siguiente componente léxico<br />Programa fuente<br />Buffer = espacio en memoria<br />Expresiones de maquina finita.<br />Máquinas de estado finito.<br />Una máquina de estado finito o autómata finito es aquella que tiene un número finito de estados así como se puede introducir una serie de monedas a una máquina recaudadora, también se puede dar a cualquier autómata una serie de caracteres de su alfabeto de entrada. <br />Una serie finita de caracteres se llama cadena de caracteres. Se dice que el autómata acepta una cadena de caracteres si, cuando empieza en su estado inicial y recibe esta serie de entradas, la maquina llega a un estado de aceptación. <br />El conjunto de estados, el alfabeto de entrada y el conjunto de cadenas de caracteres aceptados por el autómata determinista la imagen. <br />El conjunto de estados es empezar, no, a, b, c, d. Los estados de aceptación son b y d. El alfabeto de entrada es O, 1, ya que los bordes que salen de cada vértice tienen la etiqueta O la etiqueta 1. Una serie que conduce al estado b solamente puede tener ceros. <br />Se puede demostrar por inducción sobre el número de ceros que una serie de ceros conduce a un estado a si tiene un número impar de ceros y a un estado b si tiene un número par de ceros. <br />Que es una máquina procesadora de información, las señales de entrada son la presión sobre el acelerador y la posición angular del volante, y las señales de salida corresponden a la velocidad y dirección del vehículo. En una máquina vendedora, también una procesadora de información las señales de entrada son las monedas depositadas y la selección de la mercancía, las señales de salida son la mercancía y, posiblemente, el cambio.<br />MÁQUINAS DE ESTADO FINITO<br />Ahora introducimos un modelo abstracto de una máquina de estado finito, la cual está especificada por:<br />1. Un conjunto finito de estados S= {s0, s1, s2,. . .}.<br />2. Un elemento especial del conjunto S, s0, es conocido como estado inicial.<br />3. Un conjunto finito de caracteres de entrada I = {i1, i2...}<br />4. Un conjunto finito de caracteres de salida O = {o1, 02. . .}.<br />5. Una función f de S x / a S, conocida como función de transición.<br />6. Una función g de S a O, conocida como función de salida.<br />Una máquina de estado finito se encuentra en uno de sus estados. Al llegar un carácter de entrada, la máquina pasará a otro estado de acuerdo con la función de transición. Además, en cada estado la máquina produce un carácter de salida de acuerdo con la función de salida. Al principio, la máquina se encuentra en su estado inicial. <br />MÁQUINAS DE ESTADO FINITO COMO MODELOS DE SISTEMAS FÍSICOS: <br />Una máquina de estado finito puede ser útil para modelar un sistema físico. Anteriormente vimos cómo una máquina vendedora puede ser modelada como una máquina finita. Consideremos el problema de diseñar un contador módulo 3 que reciba de números 0, 1 Y 2 como entrada, y produzca una sucesión de números 0, 1 Y 2 como salida de manera que en cualquier instante la salida sea igual al módulo 3 de la suma de los dígitos de la sucesión de entrada. La máquina de la figura siguiente generará la sucesión de salida como:<br />Entrada<br />Estado O 1 2 Salida<br />=>A A B C O<br />B C A 1<br />C A B 2.<br />Observe que A es un estado correspondiente a la situación en que el módulo 3 de la suma de todos los dígitos de entrada es 0; B es un estado que corresponde a la situación en que el módulo 3 de la suma de todos los dígitos de entrada es 1, Y C es un estado que corresponde a la situación en que el módulo 3 de la suma de todos los dígitos de entrada es 2.<br />Los grafos son artefactos matemáticas que permiten expresar de una forma visualmente muy sencilla y efectiva las relaciones que se dan entre elementos de muy diversa índole. <br />Un grafo esta formado por dos conjuntos: <br /> Un conjunto V de puntos llamados vértices. <br /> Un conjunto de pares de vértices que se llaman aristas o arcos y que indican que vértices están relacionados. <br />De manera sencilla podemos decir que un grafo es un conjunto de vértices con enlaces entre ellos denominado aristas o arcos. <br />Un grafo simple es cuando entre dos vértices hay un solo arco, si hay más de un arco se llama multígrafo. <br />Un grafo es dirigido si los arcos se pueden recorrer en una dirección concreta y no en la contraria. <br />El grado de un vértice comprende el número de aristas que inciden en el vértice. <br /> <br />Los arboles son partes semánticos.<br />Árboles semánticos: <br />Un árbol semántico es una secuencia de secuencias de expresiones del tipo, donde es una fórmula del lenguaje y n es un índice numérico siendo 0, tal que se constituye a partir de una expresión 1 según ciertas reglas. A esta secuencia la llamaremos árbol, o más esquemáticamente.<br />Las reglas de construcción se basan en la definición de conjunto modelo, de modo que puede concebirse como una secuencia de enunciados metalingüísticos acerca de un conjuntos y modelo que nos permite obtener un S modelo que Satisfaga.<br />Comprobación estática<br />Comprobación de tipos:<br /> La aplicación de los operadores y operandos deben ser compatibles<br />Comprobaciones del flujo del control<br />Las proposiciones que hacen que se abandone el flujo del control de una construcción debe transferirse a otro punto. <br />Comprobaciones de unicidad<br />Hay situaciones en los que un objeto solo puede definirse una vez exclusivamente. Las etiquetas de una sentencia case no deben repetirse, declaraciones de objetos,..<br />Comprobaciones relacionadas con nombre<br />El mismo nombre debe aparecer dos o más veces. En Ada el nombre que aparece en un bloque puede aparecer al principio y final, el compilador debe comprobar que se utiliza el mismo él ambos sitios.<br />Además de comprobar que un programa cumple con las reglas de la gramática, hay que comprobar que lo que se quiere hacer tiene sentido fase también modifica la tabla de símbolos y suele estar mezclada con la generación de código intermedio<br /> Las gramáticas independientes del contexto G2 no son suficientes para realizar el análisis semántico<br />Por ejemplo, no hay forma de comprobar si una variable ha sido definida ya, o si existe una determinada etiqueta<br />Es necesario definir un tipo de gramática más rica como las gramáticas de atributo<br />Las gramáticas de atributo son gramáticas G2 a las que se añaden atributos y reglas de evaluación de atributos funciones reglas semánticas. <br />Un Árbol semántico es una técnica similar a las tablas de verdad que puede simplificar la evaluación de algunas fórmulas <br />Inicialmente, se forma el conjunto LP de letras proposicionales de la fórmula. Se construye un nodo inicial del árbol que se tomará como nodo actual y se aplica el siguiente procedimiento<br />1.- Se intenta evaluar la fórmula en el nodo actual.<br />2.- Si es posible asignar a F un valor { } V F se etiqueta el nodo con dicho valor y se finaliza el tratamiento del nodo actual.<br />En caso. Contrario: Se Selecciona la primera letra proposicional p del conjunto LP<br />Se Borra p de LP.<br />Se Construyen dos ramas, una correspondiente a p Interpretado con valor V<br />Identificada como p y la otra correspondiente a p con valor F identificada como. <br />Repetir el procedimiento por cada uno de los dos nuevos nodos. Al final del desarrollo del árbol, cada rama ACTIVA es un modelo para el juicio; si el juicio de salida era V., entonces una rama ACTIVA es un modelo para la formula, mientras si era F. es un modelo para la formula. Si no hay ramas ACTIVAS, el juicio de salida es insatisfactible; por ejemplo, si se trataba de un juicio del tipo V. entonces es insatisfactible, o sea es una Tautología.<br />Fase de compilación y como este estructurado.<br />Fases de Compilación de un Programa<br />La compilación consiste en la traducción de un programa fuente escrito en un lenguaje de alto nivel  a un programa objeto y luego  se debe utilizar un programa llamado montador o enlazador con linker. <br />El proceso de montaje conduce a un programa en lenguaje máquina directamente ejecutable.<br />Intérprete: toma el programa fuente, lo traduce y a continuación lo ejecuta un ejemplo de lenguaje interpretado es Java. <br />Compilador: es un programa que se encargan de convertir las instrucciones escritas en un lenguaje de programación en instrucciones escritas en lenguaje máquina 0´s y 1´s que la computadora. <br />Fases de Proceso de un compilador: <br />Analizador Léxico: Realiza un análisis del archivo. La cadena de entrada se lee e izquierda a derecha y se va agrupando en componentes léxicos, que son secuencias de caracteres con un significado colectivo. <br /> Analizador Sintáctico: Realiza un análisis jerárquico agrupado de los componentes léxicos en frases gramaticales que el compilador utiliza.<br /> Analizador Semántico: Busca errores semánticos, reúne información sobre los tipos; identifica operadores en base al árbol sintáctico producido en el análisis anterior operación entre tipos de datos incompatibles, rangos permitidos existencia de variables.<br /> Generador de código intermedio: Algunos compiladores generan una representación explicita del programa fuente este código es independiente de la maquina y a veces se usa en un conjunto con interpretes, en lenguajes independientes de la plataforma. <br />Optimización: Esta fase trata de mejorar el código intermedio, o las estructuras que generaran el código definitivo de modo de que resulte un código de maquina más rápido de ejecutar para guardarlos valores calculados por cada instrucción.<br /> Generador de código. Esta fase final de un compilador. Genera el código objeto, que por lo general consiste en un código de maquina re localizable o código ensamblador. <br />Agrupación lógica de un  compilador: Es la fase de análisis, depende del lenguaje fuente y son independientes de las maquinas controla la corrección del programa fuente, manejando errores encada etapa.<br />Las fases de compilación<br />La primera fase consiste en escribir el código fuente en lenguaje C o C++ archivos con extensión .c y .h en C y .cpp y .hpp en C++. Luego se efectúa la compilación, por ejemplo con gcc en C o g++ en C++. La compilación se desarrolla en tres grandes fases. <br />El preprocesador<br />El compilador comienza por aplicar cada instrucción pasada al preprocesador todas las líneas que comienzan con #, entre estas las # define. Estas instrucciones son en realidad muy simples ya que únicamente copian o eliminan secciones de código sin compilarlas. Es en esta fase que las #define que se encuentran en un archivo fuente c o .cpp o en un header .h o .hpp son reemplazadas por código CC+. Al final de esta etapa, no habrán instrucciones comenzando por #.<br />Las fases de resolución de un problema con computadora son:<br />Análisis del problemaDiseño del algoritmoCodificación Compilación y ejecuciónVerificaciónDepuraciónMantenimientoDocumentación<br />Fase de edición: Esta fase consiste en escribir dentro de un fichero, llamado programa fuente, el programa anterior, utilizando para ello un editor.<br />Fase de compilación: Esta fase consiste en traducir el programa fuente a lenguaje máquina, obteniéndose el programa objeto, utilizando para ello un compilador o intérprete, que informa sobre los errores sintácticos cometidos.<br />Fase de montaje: Esta fase consiste en enlazar los distintos programas objetos que pueden componer una aplicación, así como las rutinas necesarias del sistema, obteniéndose el programa ejecutable, utilizando para ello un montador. <br />Fase de prueba de ejecución: Esta fase consiste en ejecutar el programa utilizando un juego de datos de entrada lo suficientemente amplio y diverso para poder asegurar que el programa funciona de forma adecuada, proporcionando los resultados correctos.<br />Fase de explotación y mantenimiento: Esta fase consiste en el uso cotidiano del programa por parte de los usuarios del mismo, así como en la comprobación periódica de su buen funcionamiento y en la realización de las modificaciones necesarias para que se mantenga actualizado.<br /> <br />Errores: Durante todas las fases comentadas pueden cometerse errores, que se pueden clasificar como sigue:<br />Errores de compilación: Sintácticos cometidos al escribir el programa en un lenguaje de programación determinado. Este lenguaje impone unas reglas sintácticas que deben ser cumplidas, ya que en caso contrario aparece este tipo de error.<br />Errores de ejecución: Los errores causados por la ejecución de una operación no permitida, como dividir por cero, exceder un rango de valores, cuando ocurren, se suele decir que el programa ha sido abortado por el sistema.<br />Errores de lógica: son los errores en los resultados, por ejemplo se espera un listado ordenado y aparece desordenado. Como en el caso anterior, para detectarlos debe probarse el programa en su totalidad y verificar que los resultados son correctos.<br />Errores de especificación: son los errores causados por unas especificaciones incorrectas, debidas a un malentendido entre el programador y quien plantea el problema. <br />Fases de la compilación<br />La compilación es el proceso de la traducción de programas fuente a programas objeto.<br />El programa objeto obtenido de la compilación no ha sido traducido normalmente a código máquina sino a ensamblador. Para conseguir el programa máquina real se debe utilizar un programa llamado montador o enlazador linker. <br />El proceso de ejecución de un Programa en C++ tiene los siguientes pasos:<br />Escritura del programa fuente con un editor programa que permite a una computadora actuar de modo similar a una máquina de escribir electrónica y guardarlo en un dispositivo de almacenamiento un disco. <br />Introducir el programa fuente en memoria. <br />Compilar el programa con el compilador C++. <br />Verificar y corregir errores de compilación listado de errores. <br />Obtención del programa objeto. <br />El montador obtiene el programa ejecutable. <br />Se ejecuta el programa y si no existen errores, se tendrá la salida del mismo. <br />Conclusión.<br />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. <br />Los compiladores son, pues, programas de traducción insertados en la memoria por el sistema operativo el compilador es un programa que se encarga de traducir los programas escritos por el programador en lenguaje de alto nivel entendible por el ser humano a un lenguaje de bajo nivel que es el comprensible La máquina de Turing puede considerarse como un autómata capaz de reconocer lenguajes formales. <br />Reconocer los lenguajes recursivamente e numerables, de su potencia es, por tanto, superior a otros tipos de autómatas, como el autómata finito, o el autómata con pila, o igual a otros modelos con la misma potencia computacional. <br />Este modelo está formado por un alfabeto de entrada y uno de salida, un símbolo especialmente llamado blanco que un conjunto de estados finitos y un conjunto de transiciones entre dichos estados. Su funcionamiento se basa en una función de transición la entrada de una máquina de Turing viene determinada por el estado actual y el símbolo leído, un par estado, símbolo, siendo el cambio de estado, la escritura de un nuevo símbolo y el movimiento del cabezal, las acciones a tomar en función de una entrada. <br />Una máquina de Turing computa una determinada función parcial de carácter definido, definida sobre las secuencias de posibles cadenas de símbolos de su alfabeto. Un analizador sintáctico es una de las partes de un compilador que transforma su entrada en un árbol de derivación. El análisis sintáctico convierte el texto de entrada en otras estructuras comúnmente árboles, que son más útiles para el posterior análisis. <br />Una máquina de estado finito o autómata finito es aquella que tiene un número finito de estados así como se puede introducir una serie de monedas a una máquina recaudadora, también se puede dar a cualquier autómata una serie de caracteres de su alfabeto de entrada. <br />En una máquina vendedora, también una procesadora de información las señales de entrada son las monedas depositadas y la selección de la mercancía, las señales de salida son la mercancía y, posiblemente, el cambio.<br />La compilación consiste en la traducción de un programa fuente escrito en un lenguaje de alto nivel  a un programa objeto y luego  se debe utilizar un programa llamado montador o enlazador con linker. El proceso de montaje conduce a un programa en lenguaje máquina. <br />Un árbol semántico es una secuencia de secuencias de expresiones del tipo, donde es una fórmula del lenguaje y n es un índice numérico siendo 0, tal que se constituye a partir de una expresión 1 según ciertas reglas. Esta fase consiste en escribir dentro de un fichero, llamado programa fuente, el programa anterior, utilizando para ello un editor.<br />Esta fase consiste en traducir el programa fuente a lenguaje máquina, obteniéndose el programa objeto, utilizando para Esta fase consiste en ejecutar el programa utilizando un juego de datos de entrada lo suficientemente amplio y diverso para poder asegurar que el programa funciona de forma adecuada, proporcionando los resultados correctos. <br />La compilación es el proceso de la traducción de programas fuente a programas objeto el programa objeto obtenido de la compilación no ha sido traducido normalmente a código máquina sino a ensamblador. Para conseguir el programa máquina real se debe utilizar un programa llamado montador o enlazador linker. <br />Los grafos son artefactos matemáticas que permiten expresar de una forma visualmente muy sencilla y efectiva las relaciones que se dan entre elementos. <br />Una máquina de estado finito se encuentra en uno de sus estados. Al llegar un carácter de entrada, la máquina pasará a otro estado de acuerdo con la función de transición. Además, en cada estado la máquina produce un carácter de salida de acuerdo con la función de salida. Al principio, la máquina se encuentra en su estado inicial. <br />