Capítulo 1. Introducción
Raúl José Palma Mendoza
“El propósito primario de un lenguaje de
programación es ayudar al programador en la
práctica de su arte”
Charles Hoare
Introducción
 Las primeras computadoras eran artefactos
monstruosos: grandes, costosas y con el poder
de procesamiento de...
Introducción
 Ejemplo de un programa en lenguaje de
máquina para calcular el máximo común divisor
de dos enteros el proce...
Introducción
Introducción
 Los lenguajes ensambladores se diseñaron
originalmente para tener una correspondencia
uno a uno entre los m...
Introducción
 Era necesario escribir programas nuevos para
cada máquina nueva que aparecía.
 Las personas empezaron a de...
Introducción
 Traducir de un lenguaje de alto nivel a lenguaje
ensamblador o lenguaje de máquina es el
trabajo del compil...
Introducción
 Al inicio era más eficiente escribir directamente
en lenguaje de máquina que compilar, pero
ahora los compi...
1.1 El Arte del Diseño de Lenguajes
 Actualmente hay miles de lenguajes de alto
nivel, por razones como:
 Evolución. Las...
1.1 El Arte del Diseño de Lenguajes
Aunque hay miles ¿qué características
contribuyen a que un lenguaje sea ampliamente
us...
1.1 El Arte del Diseño de Lenguajes
 Estandarización. Casi todos los lenguajes
ampliamente usados tienen un estándar
inte...
1.1 El Arte del Diseño de Lenguajes
 Excelentes compiladores. Los compiladores de
Fortran son famosos por su eficiencia, ...
1.1 El Arte del Diseño de Lenguajes
 No hay un sólo factor que determine que un lenguaje
es bueno, hay que considerar el ...
1.2 El Abanico de los Lenguajes
 Podemos hacer varias clasificaciones y
someterlas a discusión en nuestro caso
tomaremos ...
1.2 El Abanico de los Lenguajes
 Imperativos
 von Neumann: C, Ada, Fortran, ...
 Scripting: Perl, Python, PHP, …
 Orie...
1.2 El Abanico de los Lenguajes
 Los lenguajes de flujo de datos modelan la
computación como un flujo de información a
tr...
1.2 El Abanico de los Lenguajes
 En ocasiones se clasifica dentro de los
lenguajes lógicos o basados en restricciones al
...
1.2 El Abanico de los Lenguajes
 Los lenguajes de scripting son un subconjunto
de los lenguajes de von Neumann hacen
énfa...
1.2 El Abanico de los Lenguajes
 De los lenguajes orientados a objetos el “más
puro” es Smalltalk, C++ y Java probablemen...
1.2 El Abanico de los Lenguajes
 Ahora veamos tres ejemplos para encontrar el
máximo común divisor (gcd) en tres lenguaje...
1.2 El Abanico de los Lenguajes
; Scheme
(define gcd
(lambda (a b)
(cond ((= a b) a)
((> a b) (gcd (- a b) b))
(else (gcd ...
1.2 El Abanico de los Lenguajes
% Prolog
gcd(A,B,G) :- A = B, G = A.
gcd(A,B,G) :- A > B, C is A-B, gcd(C,B,G).
gcd(A,B,G)...
1.3 ¿Por qué Estudiar Lenguajes de
Programación?
 Para saber seleccionar el lenguaje adecuado
recordando la frase de Char...
1.3 ¿Por qué Estudiar Lenguajes de
Programación?
 Algunos de los beneficios son:
 Entender características oscuras.
 Es...
1.4 Compiladores e Intérpretes
 Un compilador traduce un programa en código
fuente a un programa equivalente en un código...
1.4 Compiladores e Intérpretes
 Un compilador por sí mismo es un programa en
lenguaje de máquina, probablemente creado al...
1.4 Compiladores e Intérpretes
 A diferencia de un compilador, un intérprete
permanece ejecutando durante la ejecución de...
1.4 Compiladores e Intérpretes
 La interpretación generalmente conlleva a tener
mayor flexibilidad y mejores diagnósticos...
1.4 Compiladores e Intérpretes
 En la práctica ocurre que muchas
implementaciones de lenguajes incluyen una
mezcla de com...
1.4 Compiladores e Intérpretes
 Para el caso anterior, diríamos que el lenguaje es
interpretado si la traducción inicial ...
1.4 Compiladores e Intérpretes
Preprocesamiento:
 Ocurre como un paso previo en la mayoría de los
lenguajes interpretados...
1.4 Compiladores e Intérpretes
Ejemplo: compilación en Fortran, se asemeja a la
compilación “pura”.
1.4 Compiladores e Intérpretes
Ejemplo: ensamblado
posterior a la
compilación, este libera
al compilador de
cambios en el ...
1.4 Compiladores e Intérpretes
Ejemplo: el
preprocesador de C,
remueve comentarios y
expande macros,
además puede ser
inst...
1.4 Compiladores e Intérpretes
Ejemplo: traducción de
código fuente en C++ a
código fuente en C. Es
una compilación
comple...
1.4 Compiladores e Intérpretes
Bootstrapping
 Muchos compiladores están escritos en el
lenguaje que compilan, para lograr...
1.4 Compiladores e Intérpretes
Ejemplo:
 Si quisierámos empezar a construir el primer
compilador de Java y tuviésemos ya ...
1.4 Compiladores e Intérpretes
 Los compiladores no necesariamente traducen
de un código de alto nivel a un lenguaje de
m...
1.5 Ambientes de Programación
 Además de los compiladores e intépretes los
programadores son asistidos en sus tareas por
...
1.6 Un Vistazo al Proceso de
Compilación
1.6 Un Vistazo al Proceso de
Compilación
 Los primeros pasos hasta el análisis semántico
inclusive sirven para determinar...
1.6.1 Análisis Léxico y Sintáctico
 El análisis léxico también llamado escaneo y el
análisis sintáctico también llamado p...
1.6.1 Análisis Léxico y Sintáctico
 Usualmente el escáner remueve espacios en
blanco innecesarios, remueve comentarios y
...
1.6.1 Análisis Léxico y Sintáctico
Ejemplo: Dado el siguiente programa en C (gcd),
sus tokens muestran a continuación:
int...
1.6.1 Análisis Léxico y Sintáctico
int main ( )
{ int i =
getint ( ) ,
j = getint (
) ; while (
i != j )
1.6.1 Análisis Léxico y Sintáctico
{ if ( i
> j ) i
= i - j
; else j =
j - i ;
} putint ( i
) ; }
1.6.1 Análisis Léxico y Sintáctico
 El parseo crea un árbol de parseo que representa
contrucciones de mayor nivel que los...
1.6.1 Análisis Léxico y Sintáctico
 Decimos que la sintaxis del lenguaje está
definida por una gramática libre de context...
1.6.1 Análisis Léxico y Sintáctico
1.6.1 Análisis Léxico y Sintáctico
 En el proceso de escaneo y parseo el
compilador revisa que todos los tokens estén
bie...
1.6.2 Análisis Semántico y
Generación de Código Intermedio
 En el análsis semántico se descubre el
significado del progra...
1.6.2 Análisis Semático y Generación
de Código Intermedio
 Por ejemplo en C, el analizador semántico lleva
el control de:...
1.6.2 Análisis Semático y Generación
de Código Intermedio
 En muchos compiladores, el trabajo del
analizador semántico to...
1.6.2 Análisis Semántico y
Generación de Código Intermedio
 Un ejemplo de semántica dinámica común en
muchos lenguajes se...
1.6.2 Análisis Semántico y
Generación de Código Intermedio
 Un árbol de parseo se conoce a veces como un
árbol de sintaxi...
1.6.2 Análisis Semántico y
Generación de Código Intermedio
 El analizador semántico por lo general
transforma el árbol de...
1.6.2 Análisis Semántico y
Generación de Código Intermedio
Ejemplo de árbol sintáctico abstracto:
1.6.2 Análisis Semántico y
Generación de Código Intermedio
La tabla de símbolos para el árbol sería:
1.6.2 Análisis Semántico y
Generación de Código Intermedio
 En algunos compiladores el árbol sintáctico y la
tabla de sím...
1.6.3 Generación del Código Meta
 Para generar el código meta, el generador de
código usa la tabla de símbolos para asign...
1.6.4 Mejoras al Código
 Usualmente se les llama optimizaciones,
aunque en realidad en raras ocasiones se logra
obtener u...
Próxima SlideShare
Cargando en…5
×

introducción a lenguajes de programacion

456 visualizaciones

Publicado el

introducción a los lenguajes de programación, ing. Raúl Palma Universidad Nacional Autónoma de Honduras

Publicado en: Educación
0 comentarios
0 recomendaciones
Estadísticas
Notas
  • Sé el primero en comentar

  • Sé el primero en recomendar esto

Sin descargas
Visualizaciones
Visualizaciones totales
456
En SlideShare
0
De insertados
0
Número de insertados
5
Acciones
Compartido
0
Descargas
11
Comentarios
0
Recomendaciones
0
Insertados 0
No insertados

No hay notas en la diapositiva.

introducción a lenguajes de programacion

  1. 1. Capítulo 1. Introducción Raúl José Palma Mendoza
  2. 2. “El propósito primario de un lenguaje de programación es ayudar al programador en la práctica de su arte” Charles Hoare
  3. 3. Introducción  Las primeras computadoras eran artefactos monstruosos: grandes, costosas y con el poder de procesamiento de un calculadora.  Los programadores creían que el tiempo de éstas era más importante que el de ellos mismos.  Ellos programaban usando lenguaje de máquina.
  4. 4. Introducción  Ejemplo de un programa en lenguaje de máquina para calcular el máximo común divisor de dos enteros el procesador MIPS R4000:
  5. 5. Introducción
  6. 6. Introducción  Los lenguajes ensambladores se diseñaron originalmente para tener una correspondencia uno a uno entre los mnemónicos y las instrucciones de lenguaje de máquina.  Se le llamó “ensamblador” al software de sistema encargado de hacer la traducción.  Luego se les añadió capacidades de expasión de macros que permitían definir abreviaciones parametrizadas para secuencias de instrucciones comunes.
  7. 7. Introducción  Era necesario escribir programas nuevos para cada máquina nueva que aparecía.  Las personas empezaron a desear un lenguaje independiente de la máquina, en el cual los cálculos numéricos fuesen expresados de forma más similar a al lenguaje matemático.  Fua hasta mediados de los 50's que se desarrolló el dialecto original de Fortran, el primer lenguaje de programación de alto nivel.  Poco después aparecieron Lisp y Algol.
  8. 8. Introducción  Traducir de un lenguaje de alto nivel a lenguaje ensamblador o lenguaje de máquina es el trabajo del compilador.  Los compiladores son mucho más complejos que los ensambladores, pues ya no existe la relación uno a uno entre el lenguaje de alto nivel y el lenguaje de máquina.  Los lenguajes de alto nivel también se pueden interpretar, por ejemplo: Phyton y Javascript.
  9. 9. Introducción  Al inicio era más eficiente escribir directamente en lenguaje de máquina que compilar, pero ahora los compiladores han avazando tanto que en general producen código ensamblador más eficiente, que lo que puede producir un ser humano.
  10. 10. 1.1 El Arte del Diseño de Lenguajes  Actualmente hay miles de lenguajes de alto nivel, por razones como:  Evolución. Las ciencias de la computación son una disciplina joven en constante evolución.  Propósitos especiales. Hay varios lenguajes que se desarrollan para problemas específicos.  Preferencias personales. A las personas les gustan diferentes cosas: brevedad, recursividad, iteración, punteros, etc. todo esto hace improbable que algún día exista un lenguaje universal.
  11. 11. 1.1 El Arte del Diseño de Lenguajes Aunque hay miles ¿qué características contribuyen a que un lenguaje sea ampliamente usado?  Potencia expresiva. Escribir código claro, conciso y mantenible.  Facilidad de uso para el novato. Tener una curva de aprendizaje baja, ej.: Basic, Logo, Pascal.  Facilidad de implementación. Ej.: Basic, Pascal.
  12. 12. 1.1 El Arte del Diseño de Lenguajes  Estandarización. Casi todos los lenguajes ampliamente usados tienen un estándar internacional oficial. Pascal falló en eso al no estandarizar elementos como las cadenas y la compilación separada. Algol 60 también falló al no estandarizar una librería de entrada y salida.  Código Abierto. Muchos lenguajes ampliamente usados tienen un compilador o intérprete de código abierto en la actualidad. C se creó para implementar Unix y también actualmente se usa para Linux.
  13. 13. 1.1 El Arte del Diseño de Lenguajes  Excelentes compiladores. Los compiladores de Fortran son famosos por su eficiencia, otros lenguajes como Common Lisp tienen compiladores y herramientas que ayudan mucho al manejo de proyectos grandes.  Economía y Patrocinio. Muchos lenguajes permanecen debido al respaldo de fuertes empresas y a que reemplazarlos sería muy costos. Ej.: Ada debe su vida al DoD (U.S. Department of Defense), pues es complejo de implementar, C# debe su gran aceptación a Microsoft.
  14. 14. 1.1 El Arte del Diseño de Lenguajes  No hay un sólo factor que determine que un lenguaje es bueno, hay que considerar el punto de vista del implementador y del programador.  El primero está interesado en cómo decirle a la computadora qué hacer, y el segundo en cómo expresar sus algoritmos e ideas. Al inicio el primer punto de vista era dominante.  En 1984 Donald Knuth sugirió que la programación debería de ser reconocida como el arte de decirle a otro humano qué es lo que uno desea que la computadora haga. Declarando así que la claridad conceptual y la eficiencia de implementación son muy importantes.
  15. 15. 1.2 El Abanico de los Lenguajes  Podemos hacer varias clasificaciones y someterlas a discusión en nuestro caso tomaremos las siguiente:  Declarativos  Funcionales: Lisp/Scheme, ML, Haskell.  Flujo de Datos: Id, Val, SISAL.  Lógicos o basados en restricciones: Prolog, en ocasiones también se considera a SQL, a lenguajes basados en plantillas como XSLT y aspectos programables de las hojas de cálculo en esta categoría.
  16. 16. 1.2 El Abanico de los Lenguajes  Imperativos  von Neumann: C, Ada, Fortran, ...  Scripting: Perl, Python, PHP, …  Orientados a objetos: Smalltalk, Eiffel, Java, …  Los lenguajes funcionales utilizan modelo computacional basado en la definición recursiva de funciones, toman su inspiración en el cálculo lambda un modelo computacional formal desarrollado por Alonzo Church en los 1930's.
  17. 17. 1.2 El Abanico de los Lenguajes  Los lenguajes de flujo de datos modelan la computación como un flujo de información a través de nodos funcionales primitivos, este modelo es inherentemente paralelo, los nodos se activan al recibir datos (tokens) y pueden operar concurrentemente.  Los lenguajes lógicos o basados en restricciones toman su inspiración en la lógica de predicados, modelan la computación como un intento de encontrar valores que satisfagan ciertas relaciones especificadas, usando una búsqueda diriga por metas.
  18. 18. 1.2 El Abanico de los Lenguajes  En ocasiones se clasifica dentro de los lenguajes lógicos o basados en restricciones al lenguaje SQL, al lenguaje XSLT y a algunos aspectos programables de hojas de cálculo como Excel.  Los lenguajes de von Neumann son los más usados, modelan la computación como serie de cambios de estado o de modificaciones de variables. Están basados en enunciados secuenciales que influencian al siguiente usando efectos de lado.
  19. 19. 1.2 El Abanico de los Lenguajes  Los lenguajes de scripting son un subconjunto de los lenguajes de von Neumann hacen énfasis en pegar o conectar componentes hechos en diferentes lenguajes, no hacen énfasis en la eficiencia, sino en la brevedad de escritura, generalmente son interpretados.  Los lenguajes orientados a objetos en general están estrechamente relacionados con los lenguajes de von Neumann pero tienen un modelo de computación y de la memoria mucho más estructurado y distribuido.
  20. 20. 1.2 El Abanico de los Lenguajes  De los lenguajes orientados a objetos el “más puro” es Smalltalk, C++ y Java probablemente los más usados.  Podríamos pensar en que los lenguajes concurrentes son una clase independiente, pero lo ocurre es que la concurrencia se investiga e implementa en cada una de las clases mencionadas.
  21. 21. 1.2 El Abanico de los Lenguajes  Ahora veamos tres ejemplos para encontrar el máximo común divisor (gcd) en tres lenguajes distintos: int gcd(int a, int b) { // C while (a != b) { if (a > b) a = a - b; else b = b - a; } return a; }
  22. 22. 1.2 El Abanico de los Lenguajes ; Scheme (define gcd (lambda (a b) (cond ((= a b) a) ((> a b) (gcd (- a b) b)) (else (gcd (- b a) a)))))
  23. 23. 1.2 El Abanico de los Lenguajes % Prolog gcd(A,B,G) :- A = B, G = A. gcd(A,B,G) :- A > B, C is A-B, gcd(C,B,G). gcd(A,B,G) :- B > A, C is B-A, gcd(C,A,G).
  24. 24. 1.3 ¿Por qué Estudiar Lenguajes de Programación?  Para saber seleccionar el lenguaje adecuado recordando la frase de Charles Hoare.  Para aprender nuevos lenguajes fácilmente.  Para saberlos aprovechar mejor al conocerlos internamente.
  25. 25. 1.3 ¿Por qué Estudiar Lenguajes de Programación?  Algunos de los beneficios son:  Entender características oscuras.  Escoger correctamente entre formas alternativas de expresar las cosas.  Hacer buen uso de los depuradores, enlazadores, ensambladores.  Simular características útiles de un lenguaje en otro.  Hacer uso de la tecnología de lenguajes donde sea que aparezca.
  26. 26. 1.4 Compiladores e Intérpretes  Un compilador traduce un programa en código fuente a un programa equivalente en un código meta (usualmente en lenguaje de máquina). Y luego termina su ejecución:
  27. 27. 1.4 Compiladores e Intérpretes  Un compilador por sí mismo es un programa en lenguaje de máquina, probablemente creado al compilar otro lenguaje de alto nivel.  Cuando el lenguaje de máquina ha sido escrito en un formato de archivo entendible para el sistema operativo se le conoce como código objeto.
  28. 28. 1.4 Compiladores e Intérpretes  A diferencia de un compilador, un intérprete permanece ejecutando durante la ejecución del software, éste implementa una máquina virtual cuyo lenguaje de máquina es el lenguaje de programación de alto nivel que se está interpretando.
  29. 29. 1.4 Compiladores e Intérpretes  La interpretación generalmente conlleva a tener mayor flexibilidad y mejores diagnósticos de errores que la compilación, algunas características son casi imposibles de obtener sin interpretación, ej.: los programas que pueden añadir nuevas líneas de código a sí mismos durante la ejecución y ejecutárlas también.  En cambio la compilación generalmente lleva a una mayor eficiencia.
  30. 30. 1.4 Compiladores e Intérpretes  En la práctica ocurre que muchas implementaciones de lenguajes incluyen una mezcla de compilación e interpretación:
  31. 31. 1.4 Compiladores e Intérpretes  Para el caso anterior, diríamos que el lenguaje es interpretado si la traducción inicial es “sencilla” y si es compleja, si incluye un análisis completo y el programa intermedio no tiene parecido al programa fuente, entonces decimos que es compilado.  La discusión surge en lenguajes como Java que tiene una traducción inicial compleja y luego tiene una interpretación compleja. Aunque en las últimas versiones de Java se está dejando la interpretación por la “compilación justo a tiempo” (Just In Time).
  32. 32. 1.4 Compiladores e Intérpretes Preprocesamiento:  Ocurre como un paso previo en la mayoría de los lenguajes interpretados (ej.: Lisp), un preprocesador, remueve comentarios, espacios en blanco y agrupa caracteres en “tokens” como palabras clave, identificadores, números y símbolos, también podría expandir macros, e incluso indentificar estructuras sintácticas de alto nivel como ciclos y subrutinas, con el fin de obtener un código más eficiente para interpretar.
  33. 33. 1.4 Compiladores e Intérpretes Ejemplo: compilación en Fortran, se asemeja a la compilación “pura”.
  34. 34. 1.4 Compiladores e Intérpretes Ejemplo: ensamblado posterior a la compilación, este libera al compilador de cambios en el lenguaje de máquina, un mismo ensamblador puede ser usado por varios compiladores
  35. 35. 1.4 Compiladores e Intérpretes Ejemplo: el preprocesador de C, remueve comentarios y expande macros, además puede ser instruído para borrar partes del código, proveyendo un compilación condicional con el mismo código:
  36. 36. 1.4 Compiladores e Intérpretes Ejemplo: traducción de código fuente en C++ a código fuente en C. Es una compilación completa pues el compilador de C++ hace una análisis exhaustivo y provoca un cambio significativo (no directo) en el código.
  37. 37. 1.4 Compiladores e Intérpretes Bootstrapping  Muchos compiladores están escritos en el lenguaje que compilan, para lograr esto se usa una técnica conocida como “bootstrapping”, nombrada debido a la frase en inglés: “pull oneself up by one's bootstraps”.  Básicamente consiste en crear un pequeña implementación del lenguaje y usar esta para ir creando otras más complejas.
  38. 38. 1.4 Compiladores e Intérpretes Ejemplo:  Si quisierámos empezar a construir el primer compilador de Java y tuviésemos ya un compilador de C, podríamos iniciar escribiendo un pequeño compilador para un subconjunto de Java en C usando un pequeño subconjunto de C.  Luego podríamos desarrollar usando el subconjunto de Java y compilar el pequeño compilador de Java en el compilador que ya tenemos y después podríamos usar este compilador de Java escrito en Java para desarrollar y compilar un compilador que acepte un subconjunto mayor de Java y así sucesivamente.
  39. 39. 1.4 Compiladores e Intérpretes  Los compiladores no necesariamente traducen de un código de alto nivel a un lenguaje de máquina, existen compiladores que traducen una descripción de un documento de texto en comando para una impresora, una consulta SQL en operaciones primitivas sobre archivos, un diseño del ambiente de un edificio a un lenguaje entendible por un motor de 3D, etc.
  40. 40. 1.5 Ambientes de Programación  Además de los compiladores e intépretes los programadores son asistidos en sus tareas por otras herramientas como: ensambladores, depuradores, preporcesadores, enlazadores, editores de texto, entre otros.  Anteriormente estas herramientas se ejecutaban individualmente, pero en la actualidad estas se integran cada vez más en los conocidos Ambientes de Desarollo Integrado o IDE por sus siglas en inglés. Por ejemplo: Eclipse, Netbeans, Visual Studio.
  41. 41. 1.6 Un Vistazo al Proceso de Compilación
  42. 42. 1.6 Un Vistazo al Proceso de Compilación  Los primeros pasos hasta el análisis semántico inclusive sirven para determinar el significado del programa, se le conoce como el front end del compilador, la últimos pasos sirven para encontrar un programa equivalente en el código meta, se conocen como el back end del compilador.  Los compiladores están divididos en “pasos” que deben realizarse uno después del otro, esto permite que varios compiladores para distintos códigos fuente compartan el mismo back end y varios compiladores para distintos lenguajes de máquina compartan el mismo front end.
  43. 43. 1.6.1 Análisis Léxico y Sintáctico  El análisis léxico también llamado escaneo y el análisis sintáctico también llamado parseo, sirven para determinar la estructura del programa.  El escáner (analizador léxico) lee los caracteres del programa en código fuente y los agrupa en tokens, que son la unidad con sentido más pequeña que tienen los programas. La principal razón de hacer esto es simplificar el trabajo del parser (analizador sintáctico).
  44. 44. 1.6.1 Análisis Léxico y Sintáctico  Usualmente el escáner remueve espacios en blanco innecesarios, remueve comentarios y etiqueta los tokens con números de línea y de columna para poder hacer diagnósticos acertados en fases posteriores.
  45. 45. 1.6.1 Análisis Léxico y Sintáctico Ejemplo: Dado el siguiente programa en C (gcd), sus tokens muestran a continuación: int main() { int i = getint(), j = getint(); while (i != j) { if (i > j) i = i - j; else j = j - i; } putint(i); }
  46. 46. 1.6.1 Análisis Léxico y Sintáctico int main ( ) { int i = getint ( ) , j = getint ( ) ; while ( i != j )
  47. 47. 1.6.1 Análisis Léxico y Sintáctico { if ( i > j ) i = i - j ; else j = j - i ; } putint ( i ) ; }
  48. 48. 1.6.1 Análisis Léxico y Sintáctico  El parseo crea un árbol de parseo que representa contrucciones de mayor nivel que los tokens ( ej.: enunciados, expresiones, subrutinas, etc.) en términos de otras construcciones y/o tokens.  Cada construcción es un nodo en el árbol, los elementos que la conforman son sus hijos, la raíz del árbol es la construcción “programa”; las hojas siempre son tokens recibidos del escáner. Visto de forma completa el árbol muestra como los tokens forman un programa válido.  La estructura del árbol se basa en una serie de reglas potencialmente recursivas conocidas como una gramática libre de contexto.
  49. 49. 1.6.1 Análisis Léxico y Sintáctico  Decimos que la sintaxis del lenguaje está definida por una gramática libre de contexto, por ejemplo hay infinitas grámaticas libres de contexto para definir C, a continuación veremos un ejemplo de un árbol de parseo para la gramática de C oficial del estándar de 1999. La líneas punteadas representan una cadena de reemplazos uno a uno, el número contiguo a la línea representa el número de nodos omitidos, (esto se hace para ahorrar espacio).
  50. 50. 1.6.1 Análisis Léxico y Sintáctico
  51. 51. 1.6.1 Análisis Léxico y Sintáctico  En el proceso de escaneo y parseo el compilador revisa que todos los tokens estén bien formados y que su secuencia esté conforme a la sintaxis definida en la gramática libre de contexto, cualquier error deberá ser informado.
  52. 52. 1.6.2 Análisis Semántico y Generación de Código Intermedio  En el análsis semántico se descubre el significado del programa.  Se analiza si varias ocurrencias del mismo identificador corresponden al mismo elemento del programa.  En la mayoría de los lenguajes lleva un control de los tipos de los identificadores y de las expresiones.  Genera y mantiene una tabla de símbolos que relaciona cada identificador con la información que se va obteniendo de él.
  53. 53. 1.6.2 Análisis Semático y Generación de Código Intermedio  Por ejemplo en C, el analizador semántico lleva el control de:  Cada identificador sea declarado antes de ser usado.  Que cada identificador sea usando en un contexto apropiado, (ej.: llamar a un entero como subrutina, sumar una cadena a un real, etc.)  Que los llamados a subrutinas tengan el número y tipo correcto en los argumentos.  Que las etiquetas de las ramas de un switch sean distintas.  Etc.
  54. 54. 1.6.2 Análisis Semático y Generación de Código Intermedio  En muchos compiladores, el trabajo del analizador semántico toma la forma de rutinas de acción semántica, invocada por el parser cuando se da cuenta que ha llegado a un punto en particular dentro de una regla gramatical.  No todas las reglas semánticas se puede comprobar en tiempo de compilación:  Las que pueden comprobar se conocen como semática estática del lenguaje.  La que se deben comprobar en tiempo de ejecución se refieren como la semántica dinámica del lenguaje.
  55. 55. 1.6.2 Análisis Semántico y Generación de Código Intermedio  Un ejemplo de semántica dinámica común en muchos lenguajes sería:  Verificar que las variables no se usan en una expresión, a menos que se les ha dado un valor.  Verificar que los punteros no se desreferencian, a menos que se refieren a un objeto válido.  Verificar que el subíndice se encuentra dentro de los límites de la matriz.  Verificar que las operaciones aritméticas no provoquen un desbordamiento.
  56. 56. 1.6.2 Análisis Semántico y Generación de Código Intermedio  Un árbol de parseo se conoce a veces como un árbol de sintaxis concreto, porque demuestra por completo y en concreto, cómo una determinada secuencia de tokens se pueden derivar conforme a las reglas de la gramática libre de contexto. Sin embargo, una vez que sabemos que una secuencia de tokens es válido, mucha de la información en el árbol de análisis es irrelevante para las fases posteriores de la compilación.
  57. 57. 1.6.2 Análisis Semántico y Generación de Código Intermedio  El analizador semántico por lo general transforma el árbol de parseo en un árbol de sintaxis abstracta (también conocido como un AST, o simplemente un árbol sintáctico) mediante la eliminación de la mayor parte de los nodos “artificiales” en el interior del árbol. El analizador semántico también anota la información útil de los nodos restantes, como los punteros de los identificadores a sus entradas en la tabla de símbolos.
  58. 58. 1.6.2 Análisis Semántico y Generación de Código Intermedio Ejemplo de árbol sintáctico abstracto:
  59. 59. 1.6.2 Análisis Semántico y Generación de Código Intermedio La tabla de símbolos para el árbol sería:
  60. 60. 1.6.2 Análisis Semántico y Generación de Código Intermedio  En algunos compiladores el árbol sintáctico y la tabla de símbolos corresponden a la forma intermedia que se pasa del front end al back end.  En otros esta forma intermedia se obtiene a partir de un recorrido de dicho árbol para generar un grafo de control de flujo cuyos nodos se asemejan a fragmentos de un lenguaje ensamblador para una máquina idealizada.
  61. 61. 1.6.3 Generación del Código Meta  Para generar el código meta, el generador de código usa la tabla de símbolos para asignar lugares a las variables, y luego atraviesa la representación intermedia del programa, generando las cargas y almacenamientos para las referencias a variables, intercaladas con las operaciones aritméticas correspondientes, decisiones y ramificaciones  Usualmente el generador de código almacenará la tabla de símbolos para ser usada por un depurador simbólico, incluyéndola en el código meta.
  62. 62. 1.6.4 Mejoras al Código  Usualmente se les llama optimizaciones, aunque en realidad en raras ocasiones se logra obtener un resultado óptimo.  Es una fase opcional de la compilación que busca que el código sea más eficiente.  Puede haber optimizaciones independientes de la máquina que suelen hacerse sobre la representación intermedia.  Las optimizaciones dependientes de la máquina se hacen a través de transformaciones al código meta.

×