Está en la página 1de 48

Introduccin

Las primeras computadoras electrnicas fueron contracciones monstruas, llenando varios cuartos, consumiendo tanta electricidad como buena-cantidad de factora, y costando millones de 1940s dlares (pero con el poder informtico de una calculadora de mano). Los programadores que usaron estas maquinas creyeron que el tiempo de las computadoras eran ms valiosas que las de ellos. Ellos programaban en lenguaje de maquinas. El lenguaje de las maquinas es la secuencia de bits que directamente controla al procesador, causando que aada, compare, mueva datos de un lado a otro, y as sucesivamente en tiempos apropiados. Especificar programas a este nivel es una tarea enormemente tediosa. El siguiente programa calcula el ms importante y comn divisor (CGD) de dos enteros, usando el algoritmo de Euclides. Est escrito en el lenguaje de las maquinas, expresado aqu como hexadecimal (base 16) nmeros, por el conjunto de instrucciones de el x86(Pentium).

Cuando las personas comenzaron a escribir programas ms grandes, pronto se hizo obvio que una notacin menos propensa a errores era requerida. Los lenguajes de ensamblaje fueron inventados para permitir a las operaciones se expresen con abreviaciones nemotcnicas. Nuestro programa GCD luce as en lenguaje de ensamblaje x86:

El lenguaje de ensamblaje fueron originalmente diseados con una correspondencia uno a uno entre nemotcnica y instrucciones de lenguaje de maquinas, como se mostro en el ejemplo. 1 Traducir del lenguaje nemotcnico a el lenguaje de las maquinas se volvi el trabajo de un programa de sistemas conocido como assembler (ensamblador). Assemblers (ensambladores) fueron eventualmente aumentados con facilidades elaboradas macro expansivas para permitir a los programadores definir abreviaciones parameterizadas para secuencias comunes de instrucciones. La correspondencia entre el lenguaje de ensamblaje y el lenguaje de las maquinas permaneci obvia y clara, sin embargo. Programacin contino siendo un negocio centrado en maquinas: cada diferente tipo de computadora tena que ser programada en su propio lenguaje de ensamblaje, y los programadores pensaron en trminos de instrucciones que las maquinas efectivamente ejecutaran. Cuando las computadoras evolucionaron, y mientras diseos competitivos se desarrollaban, se volvi cada vez ms frustrante tener que escribir programas para cada nueva mquina. Tambin se volvi cada vez ms difcil para los seres humanos mantener la trayectoria de la riqueza de los detalles en grandes programas de ensamblaje. Las personas comenzaron a desear una maquina de lenguaje independiente, particularmente una en la cual los clculos numricos (el tipo ms comn de programa en esos das) poda ser expresado en algo parecido a frmula matemtica. Estos deseos nos llevaron a mediados de los aos 50s a el desarrollo del dialecto original de Fortran, el primer, as podra llamrsele, lenguaje de programacin de de alto nivel. Otros programas de alto nivel le siguieron, notablemente Lisp and Algol. Traducir de un lenguaje de alto nivel a uno de ensamblaje o de lenguaje de maquinas es el trabajo de sistema de programa conocido como Compiler (compilador).2 .Compiler (compiladores) son sustancialmente ms complicados que el de ensamblaje porque correspondencia uno a uno entre la fuente y el objetivo de las operaciones no existen ms cuando la fuente es un lenguaje de alto nivel. Fortran era lento en darse cuenta al principio, porque programadores humanos con algo de esfuerzo, podan casi siempre escribir programas en lenguaje de ensamblaje que podran correr mucho ms rpido de lo que el compilador podra producir. Con el tiempo, sin embargo, la brecha en el desempeo se ha reducido, y eventualmente revertido. Incrementos en complejidad de equipos hardware (debido a la canalizacin, unidades multifuncionales, etc.) y continuas mejoras en tecnologa compiladora nos ha llevado a una situacin en la cual el estado de la tcnica compiladora generara usualmente mejores cdigos de los que un ser humano lo hara. Incluso en casos en que seres humanos pueden hacerlo mejor, incremento en la velocidad de computadoras y tamaos de programas lo han hecho cada vez mas importante economizar en esfuerzo programacin, no solo en la construccin original de programas, sino en subsecuentes mantenimientos de programas-mejoras y correccin. La mano de obra cuesta ahora y superan en gran medida el costo de los equipos de computacin.
1 Las 22 lneas de cdigo de ensamblaje en el ejemplo estn codificados en nmeros variados de bytes en lenguaje
de mquina. Las 3 instrucciones cmp (comparar), por ejemplo, todas tienen la misma estructura de operando, y estn codificadas en la secuencia de 2-byte (39c3). Los 4 instrucciones mov (mover) tienen diferente operando y longitud, y empiezan con 89 o 8b. La sintaxis escogida es el del juego de compilador GNU gcc, en los que los resultados son sobrescritos en el ultimo operando, no el primero. 2 Los lenguajes de alto nivel pueden tambin ser interpretados directamente, sin el paso de traducir. Retomaremos esto en la seccin 1.4. Son la forma principal como Python y Javascript son implementados.

El arte del lenguaje de diseo


Hoy hay miles de lenguajes de programacin de alto nivel, y nuevos por venir. Los seres humanos usan el lenguaje de ensamblaje solo para aplicaciones de propsito especial. En una clase de pregrado, no es raro encontrar usuarios de puntuaciones de diferentes lenguajes. Porque son estos tantos? Hay varias posibles respuestas a esto: Evolucin. La ciencia de la computacin es una disciplina joven; estamos constantemente encontrando mejores formas de hacer las cosas. A finales de los aos 60s y 70s se vio una revolucin en programacin estructurada, en la que el ir a la base de control fluido de lenguaje de programacin como el de Fortran, Cobol, y Basic .3. dio paso a un control de fluidos oracionales, mecanismo de control de seleccin de oraciones, y similares construcciones de alto nivel. A finales de los aos 80s la estructura de bloque anidada de lenguajes como el de Algol, Pascal, y Ada comenzaron a dar paso a una estructura objetiva orientada a un lenguaje de programacin que permite realizar tareas de computacin mediante la interaccin con un entorno de objetos virtuales llamado smalltalk, C++, Eiffel, y similares. Propsitos especiales. Muchos lenguajes fueron diseados para un problema de dominio especfico. Los diferentes dialectos Lisp son buenos para manipular datos simblicos y estructura de datos complejos. Icon y Awk son buenos para manipular cadenas de caracteres. C es bueno para sistemas de programacin de bajo nivel. Prolog es bueno para razonar sobre relaciones lgicas entre datos. Cada uno de estos lenguajes puede ser usado con xito para una gama ms amplia de tareas, pero el nfasis es claramente en la especialidad. Preferencia personal. A diferentes personas les gustan diferentes cosas. Gran parte de la mentalidad localista de programacin es simplemente un asunto de gusto. Algunas personas aman la brevedad de C; algunos la odian. Algunas personas encuentran natural pensar recursivamente; otros prefieren iteracin. Algunas personas les gusta trabajar con pointers; otros prefieren la implcita eliminacin de referencias de Lisp, Clu, Java, and ML. La fuerza y variedad de preferencia personal hace poco probable que cualquier persona alguna vez desarrolle un lenguaje de programacin universalmente aceptable. Por supuesto, algunos lenguajes son ms exitosos que otros. De los muchos que han sido diseados, solo unas pocas docenas son ampliamente usadas. Qu hace a un lenguaje exitoso? De nuevo hay varias respuestas a esta pregunta: Poder expresivo. Uno comnmente oye argumentos que un lenguaje es ms poderoso que otro, aunque en un sentido matemtico formal ellos son todos---- reestructuracin completa---cada una puede ser usada, si torpemente, para implementar algoritmos arbitrarios. A pesar de todo, las caractersticas del lenguaje claramente tienen un impacto enorme en la habilidad de los programadores para escribir cdigos claros, concisos, y mantenibles, especialmente para muy grandes sistemas. No hay punto de comparacin, por ejemplo, entre versiones tempranas de Basic por un lado, y Common Lisp o Ada por el otro. Los factores que contribuyen para las facilidades de poder de abstraccin en particular--son de mayor enfoque en este libro

Los nombres de estos lenguajes son a veces escritos enteramente en letras maysculas y a veces en minsculas y maysculas.

Por el bien de la inconsistencia, yo adopto la convencin en este libro de usar maysculas y minsculas para lenguajes cuyos nombres son pronunciados como palabras (ejemplo, Fortran, Basic, Cobol), y maysculas para los que son pronunciados como series de letras (ejemplo, APL, PL/I, ML).

Facilidad de uso para el principiante. Mientras es fcil entender Basic, uno no puede negar su xito. Parte de ese xito es debido a que a su muy baja curva de aprendizaje. Logo es popular entre educadores de nivel elemental por una razn similar: incluso alguien de 5 aos puede aprenderlo. Pascal fue enseado por muchos aos en cursos de lenguaje de programacin introductorio porque, al menos en comparacin con otros lenguajes serios es compacto y fcil de aprender. En aos recientes java se ha jugado un papel similar. Aunque sustancialmente ms complejo que Pascal, es mucho ms simple que, digamos, C++. Facilidad de implementacin. Adems de su baja curva de aprendizaje, Basic es exitoso porque puede ser implementado fcilmente en diminutas maquinas, con sus limitados recursos. Forth tiene un pequeo pero dedicado seguimiento por razones similares. Podra decirse que el factor singular mas importante en este xito de Pascal fueron sus diseos, Niklaus Wirth , desarrollo una simple, portable implementacin del lenguaje, y darlo gratis a universidades en todo el mundo (mire ejemplo 1.15).4. Los diseadores de Java dieron pasos similares para hacer su lenguaje disponible gratuitamente para casi todos los que la quieran. Estandarizacin. Casi cada lenguaje ampliamente usado tiene un estndar internacional o (en el caso de varios lenguajes de secuencia de comandos) una sola implementacin canonca; y en el ltimo caso la implementacin canonca es casi invariablemente escrita en un lenguaje que tiene un estndar. Estandarizacin ---de ambos---el lenguaje y un amplio conjunto de de bibliotecas----es la nica verdaderamente modo efectivo de asegurar la portabilidad de cdigo a travs de la plataformas. El relativo estndar empobrecido para Pascal, que est perdiendo varias caractersticas consideradas esencial por muchos programadores (compilacin separada, cadenas, inicializacin inactiva - esttica, de acceso aleatorio I/O), es al menos parcialmente responsable por la cada en desgracia del lenguaje en los aos 80s. Muchas de estas caractersticas fueron implementadas de diferentes modos por diferentes proveedores. Cdigo abierto. La mayora de los lenguajes de programacin hoy en da tienen al menos un interpretador o compilador de cdigo abierto, pero algunos lenguajes ---C en particular---son mucho ms de cerca asociados que otros con distribucin gratuita, revisin de pares, comunidad de apoyo de computacin. C fue originalmente desarrollado temprano en los aos 70s por Dennis Ritchie y Ken Thompson en laboratorios Bell .5. , conjuntamente con el diseo de el original sistema operativo portable Unix. Con el tiempo Unix evoluciono en el sistema operativo mas portable de todo el mundo----el OS de preferencia para ciencia de computacin acadmica--- y C estuvo cercanamente asociado con l. Con la estandarizacin de C, el lenguaje se ha vuelto disponible en enormes variedades de plataformas adicionales. Linux, liderando el sistema operativo de cdigo abierto, es escrito en C. Como en octubre 2008, C y sus descendientes cuentan con 66% de sus proyectos alojados en el almacn sourceforge.net.

4 Niklaus Wirth (1934-), profesor de informtica jubilado de ETH en Zrich, Suiza, es responsable por grandes
lneas de influencia en lenguajes, incluyendo Euler, Algol W, Pascal, Modula, Modula-2, y Oberon, Entre otras cosas, sus lenguajes introdujeron la nocin de enumeraciones, sub-rangos, tipos conjunto, y unifico los conceptos de records (estructuras) y variantes (uniones). l recibi el ACM Turing Award, el ms alto honor en computacin, en 1984. 5 Ken Thompson (1943-)dirigi al equipo que desarrollo Unix. l tambin diseo el lenguaje de rpogramacion B, el retoo de BCPL y el padre de C. Dennis Ritchie (1941-) fue la fuerza principal detrs del desarrollo de C mismo. Thompson y Ritchie juntos formaron el ncleo de un grupo increblemente productivo e influyente.

Compiladores excelentes. Fortran debe mucho de su xito a compiladores extremadamente buenos. En parte esto es una asunto de accidente histrico. Fortran ha vivido ms que cualquier otra cosa, y las compaas han invertido enormes sumas de dinero y tiempo haciendo compiladores que generen cdigos rpidamente. Tambin es asunto del diseo de lenguaje, sin embargo: Los dialectos de Fortran antes de Fortran 90 carecen de recursividad y punteros, caractersticas que en gran medida complican la tarea de generar cdigos rpidos (al menos para programas que pueden ser escritos con una moda razonable sin ellos! ) En un rasgo similar, algunos lenguajes (e.g., Common Lisp) son exitosos en parte porque tienen compiladores y herramientas de apoyo que hacen extraordinariamente un buen trabajo de ayudar al programador gestionando grandes proyectos. Economa, Patrocinio, y inercia. Finalmente, hay factores otros con merito tcnico que en gran medida influyen en el xito. El respaldo de un poderoso patrocinador es uno. PL/I, al menos para una primera aproximacin, debe su vida a IBM. Cobol y, ms recientemente, Ada debe su vida al departamento de defensa de los estados unidos: Ada contiene una riqueza de excelentes caractersticas e ideas, pero la verdadera completa complejidad de implementacin hubiese probablemente matado por ello si no fuera por el respaldo de DoD. Similarmente, C#, a pesar de sus meritos tcnicos, probablemente no hubiese recibido la atencin que tiene sin el respaldo de Microsoft. En el otro extremo del ciclo vital, algunos lenguajes perduran ampliamente usados mucho tiempo despus mejores alternativas estn disponibles porque una enorme base de programas instalados y experiencia de programadores, que costaran demasiado reemplazar.

Diseo & implementacin


Introduccin A travs de los libros, barras laterales como esta resaltaran la interaccin de lenguaje de diseos e implementacin. Entre otras cosas, nosotros consideraremos los siguientes. Casos (como esos mencionados en esta seccin) en la cual la facilidad o dificultad de la implementacin afecto significativamente el xito del lenguaje. Las caractersticas del lenguaje que muchos diseadores ahora creen fueron errores, al menos en parte debido a dificultades en la implementacin. Potencialmente caractersticas tiles omitidas por algunos lenguajes por preocupacin que podra ser demasiado difcil o lento para implementar. Las caractersticas del lenguaje introducidas al menos en parte para facilitar implementaciones eficientes o elegantes. Casos en que la arquitectura de una maquina hace caractersticas razonables irracionalmente costosas. Varias otras desventajas y ventajas en que la implementacin juega un papel significante Una completa lista de barras laterales aparecen en el apndice B.

Claramente ni factor singular determina si un lenguaje es bueno. A medida que vayamos estudiando el lenguaje de programacin, necesitaremos considerar cuestiones desde varios puntos de vista. En particular, necesitaremos considerar puntos de vista de ambos el programador y el implementador de lenguaje. A veces estos puntos de vista estarn en harmona, como en el deseo para la velocidad de ejecucin. A menudo, sin embargo, habrn conflictos y ventajas y desventajas, como el recurso conceptual de una caracterstica que es balanceada contra el costo de implementacin. La ventaja y desventaja se vuelve particularmente pantanosa cuando la implementacin impone costos no solo en programas que usan la caracterstica, sino tambin en programas que no. Los lenguajes de programacin evolucionaron como modos de decirle a la computadora que hacer. Para programadores, sin embargo, un lenguaje es ms aptamente definido como modos de expresar algoritmos. Justamente como los lenguajes naturales que constrien exposicin y discurso, as que los lenguajes de programacin constrien lo que puede o no fcilmente ser expresado, y tienen ambas influencia profunda y sutil sobre lo que el programador pueda pensar. Donald Knuth ha sugerido que la programacin sea considerada como el arte de decirle a otro ser humano lo que uno quiere que la computadora haga [Knu84].6 .Esta definicin quizs acua el mejor tipo de compromiso. Ello reconoce que ambos claridad conceptual y eficiente implementacin son preocupaciones fundamentales. Este libro intenta capturar este espritu de compromiso, considerando simultneamente los aspectos conceptuales e implementacin de cada uno de los tpicos cubiertos.

El espectro de lenguaje de programacin


Los muchos existentes lenguajes pueden ser clasificados en familias basadas en sus modelos de computacin. Figura1.1. muestra un conjunto comn de familias. La divisin de nivel superior distingue entre los lenguajes declarativos, en los cuales el enfoque est en que la computadora har, y los lenguajes imperativos, en los cuales el enfoque se basa en como la computadora debera hacerlo. Los lenguajes declarativos son en cierto sentido alto nivel; estn ms en concertacin con el punto de vista del programador, y menos con el punto de vista del implementador. El lenguaje imperativo predomina, sin embargo, principalmente por razones de desempeo. Hay una tensin en el diseo de lenguajes declarativos entre el deseo de alejarse de los detalles de implementacin irrelevante, y la necesidad de mantenerse lo suficientemente cerca de los detalles para al menos controlar el esquema de un algoritmo. El diseo de algoritmos eficientes, despus de todo, es de lo que trata en su mayora la ciencia de la computacin. No est an claro a que extensin, y en que problemas de dominio, podemos esperar compiladores
6 Donald E Knuth (1938-), profesor jubilado en la universidad de Stanford y una de las principales figuras en diseo y anlisis de algoritmos, es tambin ampliamente conocido como el inventor del sistema de composicin tipogrfica TEX (con lo que este libro fue producido) y de la metodologa de programacin alfabetizada con la que TEX fue construida. Sus varios volmenes The Art of Computing Programming tiene el lugar de honor en la estantera de la mayora de profesionales cientficos de informtica. l recibi el ACM Turing Award en 1974.

Declarativo Funcional Flujo de datos (Dataflow) Lgica, base constreida Plantilla base Imperativo Lisp/Scheme, Ml, Haskell Id, Val Prolog, spreadsheets XSLT

Von Neumann Secuencia de comandos (scripting) Orientador-objetivo

C,Ada,Fortran Perl, Python, PHP Smalltalk, Eiffel, Java

Figura I.I Clasificacin de lenguajes de programacin. Note que las categoras son confusas y abiertas a debate. En particular, es posible para un lenguaje funcional ser orientador-objetivo, y muchos autores no consideran programacin funcional como declarativo. Descubrir algoritmos adecuados para problemas establecidos en un alto nivel de abstraccin. En cualquier dominio en el cual el compilador no puede encontrar un algoritmo adecuado, el programador necesita ser capaz de especificar uno explcitamente. Dentro de las familias declarativas e imperativas, hay muchas subclases importantes. Lenguajes funcionales que emplean un modelo computacional basado en definicin recursiva de funciones. Ellos toman su inspiracin de la lambda calculus, un modelo computacional formal desarrollado por Alonzo Church en los aos 30s. En esencia, un programa es considerado una funcin de salidas y entradas, definido en trminos de funciones ms simples a travs de un proceso de refinamiento. Lenguajes en esta categora incluyen Lisp, ML, and Haskell. Dataflow (flujo de datos) modelos de lenguaje de clculo como el flujo de informacin (tokens) entre los primitivos nodos funcionales. Ellos proveen un modelo inherentemente paralelo: los nodos son provocados por la llegada de (inputs) flujos de informacin (tokens), y pueden ser operados al mismo

tiempo. Id y Val son ejemplos de lenguajes de flujo de informacin. Sisal, un descendiente de Val, es mas a menudo descrito como un lenguaje funcional. Lgico- o lenguajes base-constreida toman su inspiracin desde la lgica de predicados. Estos modelan el clculo como un intento de encontrar valores que satisfagan ciertas relaciones especficas, usando dirigida a la meta de bsqueda a travs de una lista de reglas lgicas. Prolog es el lenguaje lgico mejor conocido. El trmino es a veces tambin aplicado al lenguaje de base de datos SQL, El XSLT lenguaje de secuencia de datos, y aspectos programables de hojas de clculos (spreedsheats) como Excel y sus predecesores.

Los lenguajes Von Newman son los ms familiares y exitosos. Ellos incluyen Fortran, Ada 83, C, y todos los otros en los cuales los medios bsicos de clculo son las modificaciones de las variables.7. Mientras los lenguajes funcionales son basados en expresiones que tienen valores, los lenguajes de Von Newmann son basados en oraciones (asignaciones en particular) que influencian clculos subsecuentes va el efecto secundario de cambiar el valor de la memoria.

7 John von Newmann (1903-1957) era un matemtico y pionero en computacin que ayudo a desarrollar el concepto de programa de almacenamiento en computacin, que subyace en la mayora de equipos de computacin. En un programa de almacenamiento, ambos programas y datos son representados como bits en la memoria, que el procesador repetidamente extrae, interpreta y actualiza.

Secuencia de comandos (scripting) son un subconjunto del lenguaje de Neumann. Son distinguidos por su nfasis en pegando componentes que estaban originalmente desarrollados como programas independientes. Varios lenguajes de secuencias de comando fueron originalmente desarrollados para propsitos especficos: csh y bash, por ejemplo, son los lenguajes de entrada de trabajo de control programas (shell); Awk fueron destinados par generacin de reportes; PHP y Javascript fueron creados con la intencin para la generacin de pginas web con contenido dinmico (con ejecucin en el server y el cliente, respectivamente). Otros lenguajes, incluyendo Perl, Python, Ruby, y Tcl, fueron ms deliberadamente para fines generales. La mayora pone nfasis en la creacin de prototipos, con una bias a travs de la facilidad de expresin sobre la velocidad de ejecucin. Lenguajes objeto-orientado rastrea sus rutas para simulacin 67. La mayora estn cercanamente relacionados al lenguaje de Von Newmann, pero tienen un modelo mucho ms estructurado y distribuido de ambos memoria y calculo. En lugar de describir el clculo como la operacin de un procesador monoltico en una memoria monoltica, lenguajes objeto-orientado lo describen como interacciones entre objetos semiindependientes, cada cual tiene ambos su estado interno propio y subrutinas para gestionar ese estado. Smalltalk es el ms puro de los lenguajes objeto orientados; C++ y Java son los ms ampliamente usados. Es tambin posible elaborar orientado a objetos lenguajes funcionales (el ms conocido de estos es el CLOS [Kee89] extensin de Common Lisp), pero ellos tienden a tener un sabor imperativo. Uno puede que sospeche que lenguajes concurrentes (paralelos) tambin formen una clase separada (de hecho este libro dedica un captulo a este tema) pero la distincin entre programas concurrentes y ejecucin secuencial es la mayor parte de las veces independiente de la clasificacin antes mencionada. Los programas concurrentes son en la actualidad escritos usando paquetes especiales de bibliotecas o compiladores conjuntamente con lenguaje secuencial como Fortran o C. Unos pocos lenguajes usados ampliamente, incluyendo Java, C#, y Ada, tienen caractersticas explcitamente concurrentes. Investigadores estn investigando concurrencia en cada uno de las clases de lenguajes mencionados aqu. Como simple ejemplo de contraste entre clases de lenguajes, considere el problema divisor ms comn (GCD) introducido al principio de este captulo. La eleccin entre, digamos, Von Newmann, funcional, o lgica programacin para este problema influencia no solo en la apariencia del

cdigo, sino como el programador piensa. La versin de algoritmo de von Newmann sobre el algoritmo es muy imperativa: Para calcular el gcd de a y b, chequear para ver si a y b son iguales. Si es as, grabe uno de ellos y detngase. De otro modo, remplace el ms grande por su diferencia y repita. C cdigo para este algoritmo aparece en la parte de arriba de la figura 1.2.

Figura 1.2. El GCD algoritmo en C (arriba), esquema (medio), y Prolog (parte inferior) En un lenguaje funcional, el nfasis est en la relacin matemtica de salidas a entradas: El gcd de a y b es definido ser (1) a cuando a y b son iguales, (2) el gcd de b y a b cuando a>b, y (3) el gcd de a y b a cuando b>a. Para calcular el gcd de un par dado de nmeros, expanda y simplifique esta definicin hasta que se termine. Una versin de esquema de este algoritmo aparece en el medio de la figura 1.2. El teclado Lambda introduce una definicin de funcin; (a b) es su lista de argumento. La construccin de cond es esencialmente un multipunto si..luego.adems. La diferencia de a y b est escrito (- a b).

En lenguaje lgico, el programador especifica un conjunto de axiomas y prueba reglas que permiten al sistema encontrar valores deseados: La proposicin gcd (a,b,g) es cierto si (1) a, b, y g son todos iguales; (2) a es mayor que b y existe un numero c tal c es a-b y gcd (c,b,g) es cierto ; o (3) a es menor que b y existe un numero c tal c es b-a y gcd (c,a,g) es cierto. Para calcular el gcd de un par de nmeros dados, busque por un numero g (y varios nmeros c) por lo que estas reglas permiten a uno probar que gcd (a, b, g) es cierto. Una versin Prolog de este algoritmo aparece en la parte inferior e la figura 1.2. Ello podra ser ms fcil de entender si uno lee si (if) para: - y and para comas. Debe enfatizarse que las distinciones entre clases de lenguaje no son bien definidas. La divisin entre los lenguajes objeto-orientado de von Newmann, por ejemplo, es a menudo muy confusa, y la mayora de los lenguajes funcionales y lgicos incluyen algunas caractersticas imperativas. Las descripciones arriba mencionadas estn dirigidas a capturar el sabor general de las clases, sin dar definiciones formales. Lenguajes imperativos- von Newmann y objeto orientado-reciben la mayora de atencin en este libro. Muchas cuestiones transcienden la lnea de la familia, sin embargo, y el lector interesado descubrir que mucho de lo que est en los captulos de este libro es aplicable a modelos alternativos computacionales. Capitulo 10 al 13 contienen material adicional sobre lenguajes funcionales, lgicos, concurrentes, y secuencia de comandos (scripting).

Porque estudiar lenguajes de programacin?


Los lenguajes de programacin son centrales para las ciencias de la computacin, y para un currculo. Como muchos dueos de carro, los estudiantes que se han familiarizado con uno o ms lenguajes de alto nivel estn generalmente curiosos por aprender sobre otros lenguajes, y para saber que est sucediendo debajo del cap. Aprender sobre lenguajes es interesante, Tambin prctico. Por algo, un buen entendimiento de diseo de lenguaje e implementacin puede ayudar a uno a escoger el lenguaje ms adecuado para cada tarea dada. La mayora de lenguajes son mejores para algunas cosas que otros. Pocos programadores son probablemente escojan fortran debido a su simblica computacin o procesamiento en cadenas, pero otras series de posibilidades no estn tan as de claro. Debiera uno

escoger C, C++, o C# para sistema de programacin? PHP o Ruby para una aplicacin base web? Ada o C para sistemas integrados? Visual Basic o Java para un usuario de interfaz grafica? Este libro debe ayudarlo a equiparse para tomar esas decisiones. Similarmente, este libro debe hacer ms fcil de aprender nuevos lenguajes. Muchos lenguajes estn cercanamente relacionados. Java y C# son ms fciles de aprender si ya se conoce C++; Common Lisp si ya se conoce Scheme; Haskell si ya se conoce ML. Mas importante, hay conceptos bsicos que son la base de todos los lenguajes de programacin. La mayora de estos conceptos son el tema de los captulos en este libro: tipos, control (interaccin, seleccin, recursividad, no determinismo, concurrencia), abstraccin, y designacin. Pensando en trminos de estos conceptos hace fcil asimilar la sintaxis (forma) y semntica (significado) de nuevos lenguajes, comparado con el recogerlo con una aspiradora. La situacin es anloga a como sucede en los lenguajes naturales: un buen conocimiento de formas gramaticales hacen ms fcil aprender un idioma extranjero. Cualquier lenguaje que se aprenda, entendiendo las decisiones que conllevaron a su diseo e implementacin nos ayudara a usarlo mejor. Este libro debera ayudarle con las siguientes. Entender caractersticas obscuras. El programador tpico C++ raramente usa uniones, mltiple legado, variado numero de argumentos, o el.* operador. (si no sabes lo que son , no te preocupes!) A medida que se valla simplificando la asimilacin nuevos lenguajes, un entendimiento de conceptos bsicos hacen ms fcil de entender estas caractersticas cuando busques los detalles en el manual. Escoger entre formas alternativas de expresar las cosas, basado en el conocimiento de costos de implementacin. In C++, por ejemplo, programadores puede que necesiten evadir variable temporales innecesarias, y usar constructores de copia cuando sea posible, para minimizar el costo de inicializacin. En Java puede que desee utilizar objetos ejecutantes ms que una serie de creaciones. Con ciertos compiladores deficientes, puede que tengo que adoptar modismos especiales de programacin para obtener los cdigos ms rpido: punteros para formacin de recorrido en C; con oraciones para factorizar direcciones comunes de clculos en Pascal o Modula-3; x*x en vez de x**2 en Basic. En cualquier lenguaje, necesitan ser capaces de evaluar las ventajas y desventajas entre implementaciones alternativas de abstraccionespor ejemplo entre clculo y tabla de bsqueda para funciones como cardinalidad bit set, la que puede ser implementada de cualquier manera. Hacer buen uso de depuradores, ensambladores, enlazadores, y herramientas relacionadas. En general, el programador de lenguaje de alto nivel no debera necesitar molestarse con detalles de implementacin. Hay veces, sin embargo, cuando un entendimiento de esos detalles resultan ser extremadamente tiles. El error tenaz o inusual problema de construccin de sistema es a veces ms fcil de manejar si uno est dispuesto a escoger los bits.

Simule caractersticas tiles en lenguajes que lo carecen. Ciertas caractersticas muy tiles se estn perdiendo en lenguajes antiguos, pero pueden ser estimulados siguiendo un deliberado (si no ejecutados) estilo de programacin. En los dialectos antiguos de Fortran, por ejemplo, programadores familiarizados con construcciones de moderno control pueden usar comentarios y auto disciplina para escribir cdigos bien estructurados. Similarmente, en lenguajes con facilidades de abstraccin deficientes, comentarios y nombres convencionales pueden ayudar a imitar estructura modular, y los patrones de diseo extremadamente tiles de Clu, C#, Python, y Ruby (que estudiaremos en seccin 6.5.3) pueden ser imitados con subrutinas y variables estticas. En Fortran 77 y otros lenguajes que carecen de recursividad, un programa iterativo puede ser derivado va transformaciones mano mecnica, comenzando con pseudocdigos recursivos. En lenguajes sin constantes nombradas o tipos de enumeracin, variables que son inicializadas una vez y nunca cambiaron posteriormente pueden hacer el cifrado mucho ms legible y fcil de mantener. Hacer un mejor uso de la tecnologa lingstica dondequiera que aparezca. La mayora de programadores nunca disearan o implementaran un lenguaje convencional de programacin, pero la mayora necesitara tecnologa lingstica para otras tareas de programacin. La computadora personal tpica contiene archivos en docenas de estructura de formatos, abarcando contenido web, procesador de palabras, hojas de clculo, presentaciones, grficos-msica-video y base de datos raster y vectoriales, y una amplia variedad de otros dominios de aplicacin. Cada uno de estos formatos de estructuras tiene una sintaxis y semntica formal, que las herramientas deben entender. El cdigo para analizar, generar, optimizar, y de otro modo manipular datos estructurados pueden por lo tanto ser encontrados en casi cualquier programa sofisticado, y todos estos cdigos estn basados en tecnologa lingstica. Los programadores con una fuerte comprensin de esta tecnologa estarn en una mejor posicin para escribir herramientas sustentadas y bien estructuradas. En una misma lnea, la mayora de herramientas pueden ser personalizadas, por medio de cuando sean necesarias: configuracin de archivos, argumentos en lnea de comandos, comandos de entrada, o lenguajes construidos en extensin (considerados al detalle en el captulo 13). Mi directorio de inicio tiene ms de 250 (de preferencia) archivos de configuraciones separadas. Mi configuracin personal de archivos para el editor de texto emacs contiene ms de 1200 lneas de cdigo Lisp. El usuario de casi cualquier programa sofisticado hoy en da necesitara hacer buen uso de lenguajes de configuracin o extensin. Los diseadores tal programa necesitara adoptar o /y adaptar algunos lenguajes de extensin existentes, o inventar su propia notacin. Los programadores con una alta comprensin de lenguaje terico estarn en una mejor posicin de disear elegante y bien estructurada notacin que satisfaga las necesidades de usuarios actuales y facilidades por desarrollar en el futuro.

Finalmente, este libro debera ayudar a prepararlo para estudios ms avanzados en lenguaje de diseo o implementacin, a los que debe estar tan inclinado. Tambin lo equipara para comprender las interacciones de lenguajes con sistemas operativos y arquitecturas, a los que debera dirigir su inters.

Chequear comprensin
1. Cul es la diferencia entre lenguaje de maquinas y lenguaje de ensamblaje? 2. De qu forma (s) son una mejora los lenguajes de alto nivel en los lenguajes de ensamblaje? 3. Por qu hay tantos lenguajes de programacin? 4. Qu hace a un lenguaje de programacin exitoso? 5. Nombre tres lenguajes en las siguientes categoras: Von Newmann, funcional, objeto-orientado. Nombre dos lenguajes lgicos. Nombre dos lenguajes concurrentes ampliamente usados. 6. Qu distingue lenguajes declarativos de lenguajes imperativos? 7. Qu organizacin lidera el desarrollo de Ada? 8. Cul es el lenguaje de programacin generalmente considerado el primero de alto nivel? 9. Cul fue el primer lenguaje funcional? 10. Por qu los lenguajes concurrentes no fueron puestos en la lista como categora en la figura 1.1?

Compilacin e interpretacin
En el ms alto nivel de abstraccin, la compilacin y ejecucin de un programa en lenguaje de alto nivel luce algo parecido a esto:

El compilador traduce la fuente del programa de alto nivel a un equivalente programa objetivo (tpicamente en lenguaje de maquina), y luego se va. En un punto tardo arbitrario, el usuario le dice al operador de sistema que d inicio al programa objetivo. El compilador es lugar de control durante la compilacin; el programa objetivo es el lugar de control durante su propia ejecucin. El compilador es en s misma es un programa lenguaje de mquina, presumidamente creado compilando otros programs de alto nivel. Cuando es escrito en un archivo en formato entendido por el sistema operativo, el lenguaje de maquinas es comnmente conocido como el cdigo objeto. Un estilo alternativo de implementacin para lenguajes de alto nivel es conocido como interpretacin.

A diferencia de un compilador, un interpretador se mantiene para la ejecucin de la aplicacin, De hecho, el interpretador es el lugar de control durante la ejecucin. En efecto, el interpretador implementa una maquina virtual cuyo lenguaje de mquina es el lenguaje de programacin de ms alto nivel. El interpretador lee las oraciones en ese lenguaje en ms o menos una a la vez, ejecutndolos a medida que se va a lo largo. En general, la interpretacin nos dirige a una mayor flexibilidad y mejor diagnsticos (mensajes de error) que de compilacin. Porque el cdigo fuente est siendo ejecutado directamente, el interpretador puede incluir un excelente depurador de nivel fuente. Puede tambin hacer frente a lenguajes en los cuales las caractersticas fundamentales del programa, como los tamaos y tipos de variables, o incluso cuyos nombres se refieren a que variables, puede depender del dato de entrada. Algunas caractersticas de los lenguajes son casi imposibles de implementar sin interpretacin: en Lisp y prolog, por ejemplo, un programa puede escribir piezas nuevas de s misma y ejecutarlas cuando sea necesario. (Varios lenguajes de secuencias de comando, incluyen Perl, Tcl, Python, y Ruby, tambin provee esta capacidad) Demorar las decisiones sobre implementacin de programas hasta el tiempo de ejecucin es conocido como late binding ; discutiremos esto en mayor medida en la seccin 3.1. Compilacin, por contraste, generalmente nos conduce a un mejor desempeo. En general, una decisin tomada en el momento de compilar es una decisin que no necesita ser tomada en tiempo de ejecucin. Por ejemplo, si el compilador puede

garantizar esa variable x siempre este situado en la localizacin 49378, puede generar que las instrucciones del lenguaje de mquina que acceda a esta localizacin cada vez que el programa fuente se refiera a x. En contraste un interpretador puede que necesite buscar la x en la tabla cada vez que acceda, para encontrar su localizacin. Desde la (versin final de un) programa es compilado solo una vez, pero generalmente ejecutado muchas veces, guardar puede ser sustancial, particularmente si el interpretador est haciendo trabajo innecesario en cada iteracin de un bucle. Mientras que la diferencia conceptual entre compilacin e interpretacin es clara, la mayora de implementaciones de lenguajes incluyen una mezcla de ambos. Estos tpicamente lucen as:

Generalmente decimos que un lenguaje es interpretado cuando el traductor inicial es simple. Si el traductor es complicado, decimos que el lenguaje es compilado . La distincin puede ser confusa porque simple y complicado son trminos subjetivos, y porque es posible para un compilador (traductores complicados) para producir cdigos que son luego ejecutados por una maquina virtual complicada (interpretador); esto es precisamente lo que sucede por defecto en Java. Decimos aun que un lenguaje es compilado si el traductor lo analiza a fondo (en lugar de efectuar algo de transformacin mecnica), y si el programa intermedio no tiene un fuerte parecido a la fuente. Estas dos caractersticas anlisis completo y transformacin no trivial--son las seas de identidad de la compilacin. En prctica uno ve un amplio espectro de estrategias de implementacin: La mayora de lenguajes interpretados emplean un traductor principal (un pre procesador) que remueve comentarios y espacios en blanco, y agrupa caracteres juntos en Tokens como teclados, identificadores, nmeros, y smbolos. El traductor puede que expanda abreviaciones en el estilo de un macro ensamblador. Finalmente, puede que identifique estructuras de alto nivel sintctico, como los bucles y subrutinas. La meta es producir una forma intermedia que refleje la estructura de la fuente, pero que pueda ser interpretada ms eficientemente.

Diseo & Implementacin


Lenguajes compilados e interpretados
Ciertos lenguajes (ejemplo. Smaltalk y Python) son a veces referidos como lenguajes interpretados porque la mayora de sus chequeos por errores semnticos deben ser hechos durante el tiempo de ejecucin. Otros ciertos lenguajes (ejemplo., Fortran y C) son a veces referidos como lenguajes compilados porque casi todos sus chequeos de error de semntica pueden ser hechos inactivamente. Esta terminologa no es estrictamente correcta: interpretadores para C y fortran pueden ser construidos rpidamente, y un compilador puede generar cdigo para desempear aun los chequeos ms dinmicos semnticos extensivos. Es decir, el diseo de lenguaje tiene un efecto profundo en compilacin.

En algunas implementaciones muy tempranas de Basic, el manual realmente sugera remover los comentarios del programa para mejorar su desempeo. Estas implementaciones eran puras interpretaciones; estas releeran (y luego ignoraran) los comentarios cada vez que ejecutaran una parte dada del programa. No tenan traductor inicial. La implementacin tpica de Fortran se acerca a la compilacin pura. El compilador traduce la fuente de Fortran en lenguaje de mquina. Usualmente, sin embargo, cuenta con la existencia de una biblioteca de subrutinas que no son parte del programa original. Ejemplos incluyen funciones matemticas (sin, cons, log, etc ) y I/O. El compilador confa en un programa separado, conocido como un linker, para unir las rutinas apropiadas de la biblioteca en el programa final:

En cierto sentido, uno puede que piense de la biblioteca de rutinas como extensiones para el conjunto de instrucciones del hardware. El compilador puede entonces pensrsele como un generador de cdigo para una maquina virtual que incluye las capacidades de ambos hardware y el de biblioteca (library). En un sentido ms literal, uno puede encontrar interpretacin en las rutinas de Fortran para salida dimensionada. Fortran permite el uso de oraciones format que controlen la alineacin de salida en columnas, el nmero de dgitos significativos y el tipo de notacin cientfica para nmeros con puntos flotantes, inclusin/ supresin ceros inciales, etc. Los programas pueden calcular sus propios formatos cuando sea necesario. Las rutinas de salida de las bibliotecas incluyen interpretador de formato.

Un interpretador similar puede ser encontrado en la rutina printf de C y sus descendientes. Muchos compiladores generan lenguaje de ensamblaje en vez de lenguaje de mquina. Esta convencin facilita depuracin, desde que el lenguaje de ensamblaje es ms fcil de leer para las personas, y asla al compilador de cambios en el formato de los archivos de lenguaje de mquina que pueden ser mandados por nuevas liberaciones del sistema operativo (solo el ensamblador debe ser cambiado, y es compartido por varios compiladores).

Compiladores para C (y para muchos otros lenguajes ejecutados bajo Unix) comienzan con un preprocesador que remueve comentarios y expande macros. El preprocesador puede tambin ser instruido para borrar porciones del cdigo en s, proporcionando una facilidad condicional de compilacin que permita varias versiones de un programa para ser construido de la misma fuente.

Las implementaciones C++ basadas en un primitivo compilador AT&T realmente generaba un programa intermedio en C, en vez de en lenguaje de ensamblaje. Este compilador C++ fue de hecho un verdadero compilador: desempeo un anlisis completo de la semntica y sintaxis del programa fuente C++, y con muy pocas excepciones gener todos los mensajes de error que un programador vera antes de ejecutar el programa. De hecho, programadores eran generalmente inconscientes de que el compilador C era usado detrs de cmaras. El compilador C++ no apelaba al compilador C a menos que hubiese generado cdigo C que pasara a travs de un segundo round de compilacin sin producir ni un mensaje de error.

Ocasionalmente oiramos que el compilador C++ se refiere a un preprocesador, presumiblemente porque genero una salida de alto nivel que fue sucesivamente compilado. Yo considero esto como un uso indebido del trmino: compiladores intentan entender su fuente; preprocesadores no. Los preprocesadores desempean transformaciones basadas en simples patrones emparejados, y puede que produzcan una salida que genere errores de mensaje cuando se ejecute a travs de subsecuente etapas de traduccin. Muchos compiladores son auto-alojadores: estn escritos en el lenguaje que compilancompiladores de Ada en Ada, compiladores de C en C. Esto saca a flote una pregunta obvia: En primer lugar como compilar uno un compilador? La repuesta esta en usar una tcnica conocida como Bootstrapping, un trmino derivado de la adrede, ridcula nocin de alzarlo a uno del suelo jalando sin ayuda de nadie. En pocas palabras, uno comienza con una implementacin simple ---a menudo un interpretadory lo usa para construir progresivamente versiones ms sofisticadas. Podemos ilustrar la idea con un ejemplo histrico. Varios compiladores Pascal primitivos fueron construidos alrededor de un conjunto de herramientas distribuidas por Niklaus Wirth. Estos incluyeron los siguientes. Un compilador Pascal, escrito en Pascal, que generara salida en P-code, una pila de lenguaje basado similar al de byte code de los compiladores modernos de java. El mismo compilador, pero traducido en P-code

Un interpretador P-code, escrito en pascal

Para hacer que Pascal funcione en una maquina local, el usuario del conjunto de herramientas necesitaron solo traducir el interpretador P-code (a mano) a algn tipo disponible de lenguaje local. Esta traduccin no fue una tarea difcil; el interpretador era pequeo. Al ejecutar la versin del compilador P-code en el tope del interpretador P-code, uno poda entonces compilar los programas de Pascal en P-code, el que podra a su vez ser ejecutado en el interpretador. Para obtener una implementacin ms rpida, uno poda modificar la versin del compilador de Pascal para generar localmente una variedad disponible de lenguaje de ensamblaje o mquina, en vez de generar P-code (algn tanto una tarea ms difcil). Este compilador poda entonces ser arrancado (bootstrapped)-ejecutado por s mismo- para entregar una versin de cdigo de maquina del compilador.

Para un ejemplo ms moderno, suponga que estamos construyendo uno de los primeros compiladores de Java. Si tuviramos ya un compilador C, debemos comenzar por escribir, en un simple subconjunto de C, un compilador para un igualmente subconjunto de Java. Una vez que el compilador este funcionando, podramos traducir a mano el cdigo C a nuestro subconjunto de Java y ejecutar el compilador a travs de s mismo. Podramos entonces repetidamente extender el compilador para aceptar un mayor subconjunto de de Java, ejecutarlo otra vez, y usar el lenguaje extendido para implementar un subconjunto aun mas grande.

Diseo & Implementacin


EL xito prematuro de Pascal
La implementacin basada en P-code de Pascal, y su uso de ejecucin (bootstrapping), son en gran medida responsables por el xito remarcable de el lenguaje en crculos acadmicos en los aos 1970s. Ni una plataforma de hardware o sistema operativo de esa era dominaba por el diseo del modo como el x86, Linux and Windows lo hacen hoy en da. La caja de herramientas de Wirth hizo posible obtener una implementacin de Pascal y ejecutarla en casi todas las plataformas en una semana o ms o menos. Fue una de los primeros grandes xitos en portabilidad de sistema.

8 A travs de este libro usaremos el trmino x86 para referirnos a la arquitectura de conjuntos de instruccin del Intel 8086 y sus descendientes, incluyendo los varios Pentium procesadores. Intel llama esta arquitectura el IA-32, pero x86 es un trmino ms genrico que abarca las ofertas de competidores como ADM tambin.

A veces encontraremos compiladores para lenguajes (ejem, Lisp, Prolog, Smalltalk, etc) Que permitan un montn de late binding (Demorar las decisiones sobre implementacin de programas hasta el tiempo de ejecucin), y son tradicionalmente interpretados. Estos compiladores deben estar preparados, en el caso general, para generar cdigo que desempeen gran parte del trabajo de un interpretador, o que llame a una biblioteca que haga ese trabajo. En casos especiales e importantes, sin embargo, el compilador puede generar cdigo que haga supuestos razonables sobre decisiones que no sern finalizadas hasta la hora de ejecucin. Si estos supuestos resultan validos el cdigo ejecutara muy rpido. Y si no son correctos, un chequeo dinmico descubrir la inconsistencia, y revertir al interpretador. En algunos casos el sistema de programacin puede que demore la compilacin hasta el ltimo momento. Un ejemplo ocurre en implementacin de Lisp o Prolog que evocan el compilador cuando sea necesario, para traducir nueva fuente creada a lenguaje de maquinas, o para optimizar el cdigo para una salida de conjunto particular. Otro ejemplo ocurre en implementaciones de Java. La definicin del lenguaje de Java define una forma intermedia independiente de maquina conocida como Byte Code. Byte Code es un formato estndar para la distribucin de programas Java; permite a los programas transferir fcilmente en el internet, y luego ejecutar en cualquier plataforma. Las primeras implementaciones de Java fueron basadas en interpretadores byte-code, pero ms reciente (ms rpido) las implementaciones emplearon un justo-a-tiempo compilador que tradujera byte-code a lenguaje de maquina inmediatamente antes de cada ejecucin del programa. C#, similarmente, fue hecho para traduccin justo-a-tiempo. El compilador principal C# produce .NET Lenguaje comn intermedio (CIL), que es luego traducido a lenguaje de maquina inmediatamente antes de la ejecucin. CIL es un lenguaje deliberadamente independiente, as que puede ser usado para cdigo producido por una variedad de compiladores front-end (estado inicial de un proceso). En algunas maquinas (particularmente esas diseadas antes de a mediados de los 1980s), el conjunto de instrucciones de nivel de ensamblaje no es realmente implementado en hardware, pero de hecho corre en un interpretador. El interpretador est escrito en instrucciones de bajo-nivel llamado microcode (o firmware), que est almacenado en una lectora de solo memoria y ejecutada por el hardware. Microcode y microprogramacin son considerados ms adelante en la seccin 5.4.1. Mientras algunos de estos ejemplos nos aclaran la mente, un compilador no necesariamente traduce de un lenguaje de alto nivel a uno de lenguaje de mquina. No es raro para compiladores, especialmente prototipos, generar C como resultado (output). Yendo un poco ms lejos, formateadores de texto como TEX y el Troff son realmente compiladores, traduciendo descripciones de documento de alto nivel a comandos para impresoras laser o foto compositor. (Muchas impresoras lser

incorporan interpretadores para el comentario del lenguaje de pgina de descripcin) Procesadores de lenguaje de Consulta para base de datos de sistemas son tambin compiladores, traduciendo lenguajes como SQL a operaciones primitivas en archivos. Hay inclusive compiladores que traducen especificaciones de nivel- lgico de circuito a mascaras fotogrficas para chips de computadora. Aunque el enfoque en este libro es en lenguajes de programacin imperativa, el trmino compilacin se aplica siempre que traduzcamos automticamente de un lenguaje no trivial a otro, con un anlisis completo del significado del sistema de entrada de informacin (input).

Ambientes de programacin
Compiladores e interpretadores no existen en aislamiento. Los programadores son asistidos en su trabajo por un husped de otras herramientas. Ensambladores, depuradores, preprocesadores, y vinculadores que fueron mencionados antes. Editores le son familiares a cada programador. Pueden ser aumentados con facilidades de cruce referencial que permiten al programador encontrar el punto en el cual un objeto es definido, dado un punto en el que este es usado. Impresoras bonitas ayudan a reforzar convenciones de formateo. Style checkers (chequeadores de estilos) refuerzan convenciones semnticas o sintticas que pueden ser ms estrictas que esas reforzadas por el compilador (vea exploracin 1.12). Las herramientas de configuracin de mantenimiento sigue los pasos de las dependencias entre (las muchas versiones de) separadamente mdulos compilados en un sistema mayor de software. Las herramientas de Perusal existen solo para texto pero tambin para lenguajes intermedios que pueden ser almacenados en cdigo binario. Los perfiladores y otras herramientas con desempeo de anlisis a menudo trabajan conjuntamente con depuradores para ayudar a identificar las piezas de un programa que consume la mayora de su tiempo de computacin. En entornos de antigua programacin, las herramientas pueden ser ejecutadas individualmente, al explicito pedido del usuario. Si un programa que se est ejecutando se detiene anormalmente con un mensaje de bus error (direccin invlida, por ejemplo, el usuario puede que prefiera invocar un depurador para examinar el core el archivo volcado por el sistema operativo. l o ella intentaran identificar el error del programa (bug) estableciendo puntos de interrupcin, permitiendo rastrear y etc, e iniciar el programa otra vez bajo el control del depurador. Una vez que el error es encontrado, el usuario invocara el editor para hacer un cambio apropiado. Ella o el luego recompilaran el programa modificado, posiblemente con la ayuda de un gestor de configuracin. Entornos ms recientes proveen herramientas mucho mas integradas. Cuando un error de direccin invalida ocurre en un entorno integrado de desarrollo (IDE), una nueva ventana posiblemente aparezca en la pantalla del usuario, con la lnea de cdigo de

fuente en el que el error aparece resaltado. Puntos de interrupcin y rastreo pueden ser establecidos en esta ventana sin explcitamente invocar un depurador. Cambios en la fuente pueden ser hechos sin invocar un editor. Si el usuario pide reiniciar el programa despus de haber hechos los cambios, una nueva versin puede que sea construida sin llamar al compilador o gestin de configuracin. El editor para un IDE puede incorporar conocimiento sobre sintaxis de lenguaje, proporcionando plantillas para todas las estructuras de control estndar, y verificando la sintaxis como est escrito.

Diseo e implementacin
Poderosos Entornos de desarrollo
Entornos de desarrollos sofisticados pueden ser como una hoja de doble filo. La calidad del entorno comn de Lisp podra decirse ha contribuido a su generalizada aceptacin. Por otro lado, la particularidad del entorno grafico para Smalltalk (con su insistencia en su tipo de fuente especifica, estilos de ventana, etc.) ha hecho difcil presentar el lenguaje a sistemas accedidos a travs de un interfaz textual, o para sistemas grficos con una apariencia diferente.

Internamente, El IDE es posible que mantenga no solo la fuente de un programa y cdigo de objeto, sino tambin una estructura de sintaxis. Cuando la fuente es editada la estructura ser actualizada automticamente ----a menudo incrementadamente (sin re-analizar grandes pociones de fuente). En algunos casos, los cambios estructurales al programa podrn ser implementados primero en la estructura de sintaxis, y luego automticamente reflejada en la fuente. IDEs son fundamentales para Smalltalk--- es casi imposible separar el lenguaje de su entorno grafico y ha sido rutinariamente usado por Common Lisp desde los aos 1980. En aos ms recientes, los entornos integrados han en su mayora desplazado herramientas en lnea de comando por muchos lenguajes y sistemas. Cdigos abiertos populares IDEs incluyen Eclipse y NetBeans. Sistemas comerciales incluyen Visual Studio de Microsoft y Xcode de Apple. La mayor parte de la apariencia de integracin puede ser lograda dentro de editores sofisticados como emacs.

Revisa tu entendimiento

11.-Explica la diferencia entre interpretacin y compilacin. Cules son las ventajas y desventajas comparativas de estos dos enfoques? 12.- Java es interpretada o compilada (o ambos)? Cmo lo sabes? 13.- Cul es la diferencia entre un compilador y preprocesador? 14.- Cul era la forma intermedia empleada por el compilador original ATT&T C++? 15.- Qu es el P-code? 16.- Qu es bootstrapping? 17.- Qu es un compilador justo-a- tiempo (just in-time)? 18.- Nombre dos lenguajes en los cuales un programa puede escribir nuevas piezas de s mismo cuando sea necesario 19.- Brevemente describa tres compiladores no convencionales---compiladores cuyo propsito no es preparar un programa de alto nivel para ejecucin en un microprocesador. 20.- haga una lista de seis tipos de herramientas que comnmente apoye el trabajo de un compilador cuyo propsito dentro de un mayor entorno de programacin. 21.- Explique como un IDE se diferencia de una coleccin de herramientas de comando en lnea.

Resumen de compilacin
Los compiladores son entre otros las clases ms bien estudiadas de programas de computadora. Lo consideraremos repetidamente en todo el resto del libro, y en el captulo 2, 4, 14, y 16 en particular. El remanente de esta seccin proporciona un resumen introductorio.

Figura 1.3 Fases de compilacin. Las fases son enlistadas en la derecha y las formas en las que la informacin es pasada entre fases enlistadas en la izquierda. La tabla de smbolos sirve en toda la compilacin como un almacn para informacin sobre identificadores.

En un compilador tpico, la compilacin procede a travs de una serie de fases bien definidas, expuestas en la figura 1.3. Cada fase descubre informacin de uso para fases posteriores, o transforma el programa en una forma que es ms til para las fases subsecuentes. Las primeras fases (a travs de anlisis semntico) sirven para descifrar el significado de la fuente del programa. Son a veces llamados front-end (estado inicial de un proceso) del compilador. Las ltimas fases sirven para construir un programa equivalente objetivo. A veces son llamados back-end (estado final de un proceso) del compilador. Muchas fases de compiladores pueden ser creadas automticamente de una descripcin formal de la fuente y/o lenguajes objetivos. Oiremos que las compilaciones son descritas como una serie de fases pasos. Un paso es una fase o conjunto de fases que es serializado con respecto el resto de compilacin: no comienza hasta que fases previas sean completadas, y termina antes de que cualquier fase subsecuente comience. Si se desea, una fase puede ser escrita como un programa separado, leyendo su input (sistema de entrada de informacin) desde un archivo y escribiendo su output (el resultado del

input) en un archivo. Los compiladores son comnmente divididos en fases de modo que el estado inicial del proceso pueda ser compartido por compiladores por ms de una maquina (lenguaje objetivo), y par que el estado final del proceso puedan ser compartidos con compiladores por ms de un lenguaje fuente. En algunas implementaciones el estado inicial del proceso y el final puede ser separado por un estado medio que es responsable por el lenguaje y mejoramiento del cdigo de maquina independiente. Antes del dramtico incremento del tamao de memorias de mediados y finales de los aos 1980s, compiladores fueron solo a veces divididos en fases para minimizar el uso de memoria: como cada fase completada, el texto poda volver a usar su cdigo de espacio.

Anlisis de lxico y sintaxis


Considere el mayor problema de divisor comn (GCD) introducido al principio de este captulo, y expuesto como una funcin en la figura 1.2 (pgina 13). Haciendo hiptesis sobre rutinas triviales I/O y presentar la funcin como un programa autnomo, el cdigo debe lucir como se muestra a continuacin en C.

Explorar y analizar sirve para reconocer la estructura del programa, sin mencin de su significado. El escner lee los caracteres (i,n,t, , m,a,i,n, (, ) , etc.) y los agrupa en Tokens, que son las unidades ms pequeas y significativas del programa. En nuestro ejemplo, los Tokens son

La exploracin o escaneo es conocido como anlisis lxico. El propsito principal del escner es simplificar la tarea del anlisis, reduciendo el tamao del sistema de entrada de informacin (hay mucho ms caracteres que tokens) removiendo caracteres extraos como espacio en blanco. El escner tpicamente remueve comentarios y etiquetas tokens con lneas y columnas de nmeros, para hacer ms fcil generar diagnsticos adecuados en fases posteriores. Se puede disear un analizador para tomar caracteres en vez de tokens como sistema de entrada de informacin dispensando con el escner--pero el resultado sera torpe y lento. El escner organiza los tokens en una estructura de anlisis que representa construcciones de alto nivel (oraciones, expresiones, subrutinas, etc.) en trminos de sus componentes. Cada construccin es un nodo en la estructura; sus constituyentes son como sus hijos. La raz de la estructura es simplemente programa; las partes, de izquierda a derecha, son los Tokens recibidos desde el escner. Tomado como un todo, la estructura nos muestra como los tokens encajan juntos para hacer valido un programa. La estructura confa en un conjunto de reglas potencialmente recursivas conocidas como un contexto libre de gramtica. Cada regla tiene una flecha () con el nombre de construccin en la izquierda y una posible expansin a la derecha. 9 En C, por ejemplo, un while loop (controlador de oraciones) consiste en la palabra clave, while, seguida por una proposicin lgica (boolean) entre parntesis y una oracin.

9 tericos tambin estudian contextos gramaticales sensitivos, en los cuales las expansiones permitidas de una construccin (las reglas aplicables) dependen en el contexto en la que la construccin aparece (ejemplo, en construcciones a la izquierda y derecha). Contexto sensitivo es importante para lenguajes naturales como el ingls, pero es casi nunca usado en diseo de lenguajes de programacin.

La oracin, a su vez, es a menudo una lista cerrada en corchetes:

Donde

Aqu representa la cadena vaca; indica que el block-item-list-opt puede ser simplemente borrado. Muchas ms reglas gramaticales son necesarias, por supuesto, para explicar la estructura completa de un programa. Un contexto libre de gramtica se dice que define la sintaxis del lenguaje; parsing es por consiguiente conocido como anlisis de sintaxis. Hay bastantes posibilidades gramaticales para C (un nmero indefinido, de hecho) el fragmento presentado arriba fue tomado del ejemplo gramtico contenido en la definicin oficial del lenguaje [Int99]. Una estructura de anlisis completa para nuestro programa GCD (basado en una gramtica completa no mostrada aqu) aparece en la figura 1.4 Mientras el tamao de la estructura puede parecer de enormes proporciones, sus detalles no son particularmente importantes en este punto en el texto. Lo que es relevante es que (1) cada punto de ramificacin individual representa la aplicacin de un sola regla gramatical, y (2) la resultante complejidad es ms una reflexin de la gramtica que de el programa de sistema de entrada de informacin (input). La mayor parte de sus tallos del (a) el uso de tales construcciones artificiales como block-

item-list_opt para generar listas de extensiones, y (b) el uso de expresiones asignadas igualmente artificiales, expresiones aditivas, expresiones multiplicadoras, y etc., para capturar el precedente y la sociabilidad en expresiones aritmticas. Veremos en la siguiente subdivisin que la mayor parte de esta complejidad puede ser descartada una vez que el anlisis de sintaxis se complete. En el proceso de escaneo y anlisis de sintaxis, el compilador verifica para ver que todos los tokens del programa estn bien formulados, y que la secuencia de tokens conforme para la sintaxis definida por la gramtica libre de contexto. (Ejemplo, 123abc o $@ foo in C) debera causar que el escner produzca un mensaje de error. Cualquier secuencia invalida de token sintcticamente (ejemplo, A=X Y Z in C) nos llevara a un mensaje de error de el analizador.

Anlisis semntico y cdigo de generacin intermedio


El anlisis semntico es un descubrimiento de significado en un programa. La fase de anlisis semntico de compilacin reconoce cuando mltiples ocurrencias de la misma identificadora se refieren al mismo programa, y asegura que los usos sean consistentes. En la mayora de lenguajes el analizador de semntica rastrea el tipo de ambos identificadores y expresiones, ambas para verificar uso consistente y guiar la generacin de cdigo en fases posteriores. Para asistir en su trabajo, el analizador de semntica tpicamente construye y mantiene una tabla de smbolos estructura de datos que traza un mapa de cada identificador a la informacin conocida por ella. Entre otras cosas, esta informacin incluye el tipo de identificador, estructura interna (si alguna), y alcance (la porcin del programa en que esta es vlido). Usando la tabla de smbolos, el analizador de semntica refuerza una gran variedad de reglas que no son capturadas por la estructura jerrquica del contexto libre de gramtica y el analizador de estructura. En C, por ejemplo, verifica para tener seguridad que Cada identificador este declarado antes de que sea usado Ningn identificador es usado en un contexto inapropiado (llamando un entero como una subrutina, aadiendo una cadena a un entero, haciendo referencia a un campo de tipo errneo de estructura)

Invocaciones de subrutinas proporcionan el nmero y tipo correctos de argumentos Etiquetas en los brazos de un conmutador de oraciones son constantes distintas. Cualquier funcin con un tipo vacio de no retorno regresa un valor explcitamente. En varios compiladores, el trabajo del analizador de semntica toma la forma de acciones de rutinas semntica invocado por el analizador cuando se da cuenta que ha llegado a un punto en particular dentro de una regla de gramtica. Por supuesto, no todas las reglas semnticas pueden ser revisadas en tiempo de compilacin. Esos que pueden esta referidos como semntica esttica del lenguaje. Esos que deben ser revisados en el tiempo de ejecucin son referidos como semntica dinmica del lenguaje. C tiene muy poco en lo que se refiere a estructuras dinmicas (sus diseos optaron por desempeo en vez de seguridad). Ejemplos de reglas que otros lenguajes refuerzan en el tiempo de ejecucin incluyen las siguientes. Variables nunca son usados en una expresin a menos que hayan sido dados un valor. 10 Punteros nunca son diferenciados a menos que se refieran a un objeto valido Subndices de expresiones matrices yacen dentro de los lmites de la matriz Operaciones aritmticas no se desbordan

10 como veremos en la seccin 6.1.3., Java y C# realmente refuerzan inicializacin en tiempo de compilacin, pero solo adoptando un conjunto conservativo de reglas para asignaciones definidas, programas prohibidos para los cuales lo correcto es difcil o imposible de verificar en tiempo de compilacin.

Traduccin-unidad Funcin-definicin Declarador

Puntero-opt

Declaracin-especificadores

Tipo-especificador

Inicializador

Directo-declarador

Oracin Expresin-oracin Oracin-iteracin Mientras (expresin)


Componente-expresin

Sufijo-expresin

Igualdad-expresin
Relacional-expresin
Bloque-tem-lista-opt

Argumento-expresin-lista

Cambio-expresin Asignacin-expresin

Multiplicativo-expresin Aditivo-expresin

Figura 1.4 Analizador de estructura para el programa GCD. El smbolo

representa la cadena vaca. Las lneas de puntos indican una cadena de reemplazos uno-a-uno, omitido para guardar espacio; nmeros adyacentes indican el nmero de nodos omitidos. Mientras los detalles de la estructura son irrelevantes para el presente capitulo, la cantidad completa del detalle es: viene de tener que encajar (las ms simple) fuente de cdigo en la estructura jerrquica de un contexto libre de gramtica.

Figura 1.5 estructura de sintaxis y tabla de smbolos para el programa GCD. Note que en
contraste con la figura 1.4: la estructura sintctica retiene solo la estructura esencial del programa, omitiendo detalles que solo eran necesarios para guiar el anlisis de algoritmo.

Cuando no puede reforzar las reglas estticamente, un compilador a menudo produce cdigo para desempear revisin apropiada en el tiempo de ejecucin, abortando el programa o generando una excepcin si una de las estructuras falla. (Las excepciones sern discutidas en la seccin 8.5.) Algunas reglas, desafortunadamente, podran ser inaceptablemente costosas o imposibles de reforzar, y la implementacin de lenguaje podra simplemente fallar revisndolos. En Ada, un programa que rompe tal regla se dice que es errnea; en C su comportamiento se dice que es indefinido. Una estructura de anlisis es a veces conocida como una estructura de sintaxis concreta, porque ello demuestra, completa y concretamente, como una secuencia particular de tokens pueden ser derivados bajo las reglas de un contexto libre de gramtica. Una vez que sepamos que una secuencia de token es vlida, sin embargo, la mayor parte de la informacin en la estructura de anlisis es irrelevante para posteriores fases de compilacin. En el proceso de revisin de reglas estticas semnticas, el analizador semntico tpicamente

transforma la estructura de anlisis en una estructura de anlisis abstracta ( de otro modo conocido como AST, o simplemente estructura sintctica ) removiendo la mayora de los nodos artificiales en el interior de la estructura. El analizador semntico tambin anota los nodos restantes con informacin til , como los punteros de los identificadores a sus tablas de acceso simblico. Las anotaciones adjuntas a un nodo particular son conocidas como sus atributos. Una estructura sintctica para nuestro programa GCD es representado en la figura 1.5. En varios compiladores, la anotada estructura sintctica constituye la forma intermedia que es movida de un estado inicial de proceso a uno final. En otros compiladores, el anlisis semntico termina con una traversal de la estructura que genera otra forma intermedia. Una forma comn consiste en un controlador de grafico flotante cuyos nodos parecen fragmentos de lenguaje de ensamblaje para una simple idealizada maquina. Consideraremos esta opcin posteriormente en el captulo 14, donde un controlador de grafico flotante para nuestro programa GCD aparece en la figura 14.3. En un conjunto de compiladores relacionados, los estados inciales de un proceso para varios lenguajes y los estados finales de un proceso para varias maquinas compartiran una forma intermedia comn.

Cdigo de generacin objetiva


El fase de generacin de cdigo de un compilador traduce la forma intermedia a el lenguaje objetivo. Dada la informacin contenida en la estructura sintctica, generando cdigo correcto es usualmente no una tarea difcil (generar un bien cdigo es ms difcil, como veremos en la seccin 1.6.4). Para generar lenguaje de ensamblaje o maquina , el generador de cdigo atraviesa la tabla de smbolos para asignar localizaciones a las variables, y luego atravesar la representacin intermedia de el programa, generando cargas y almacenamientos para referencias de variables, intercaladas con operaciones aritmticas apropiadas, pruebas, y ramificaciones. Cdigo sencillo para nuestro ejemplo GCD aparece en la figura 1.6, en lenguaje x86 de ensamblaje. Fue generado automticamente por un compilador simple y pedaggico.

El lenguaje de ensamblaje nemotcnico podra parecer un poco crptico, pero los comentarios en cada lnea (no generadas por el compilador) debera hacer correspondencia entre las figuras 1.5 y 1.6 generalmente aparente. unos pocos sugerencias : esp, ebp, eax, ebx, y edi son registros (localizaciones de almacenamiento especial, limitado en nmeros que pueden ser accesados muy rpidamente) .-8(%ebp) se refiere localizacin de memoria de 8 bytes antes de

la localizacin cuya direccin est en registro ebp; en este programa, ebp sirve como una forma de base en la que podemos encontrar variables i e j. el argumento a una subrutina llamada instruccin es pasada empujando a la pila, para lo cual esp es la cima de la pila de puntero. El valor de retorno regresa en registro eax. Operaciones aritmticas sobrescriben su segundo argumento con el resultado de la operacin. 11 A menudo el generador de cdigo guardara la tabla de smbolo para un uso posterior por un depurador simblico, incluyendo en l una inejecutable parte del objetivo de cdigo.

Mejoras en el cdigo
La mejora en el cdigo a menudo se refiere a esta como optimizacin, aunque la verdad rara vez hace algo ptimo en un sentido absoluto. Es una fase opcional de compilacin cuya meta es transformar el programa en una nueva versin de que calcule el mismo resultado ms eficientemente- ms rpidamente o usando menos memoria o ambos.

11

Como anotado en pie de pgina 1, estos son convenciones de ensamblador GNU; Microsoft e Intel

ensambladores especifican argumentos en el orden contrario.

Figura 1.6 Sencillo x86 lenguaje de ensamblaje para el programa GCD

Algunas mejoras son las maquinas independientes. Pueden actuar como transformaciones en la forma intermedia. Otras mejora requieren de un entendimiento del objetivo de la maquina(o de todo lo que ejecutara el programa en el lenguaje objetivo). Estas deben actuar como transformaciones en el programa objetivo. En consecuencia las mejoras en el cdigo a menudo aparecen como dos fases adicionales de compilacin, una inmediatamente despus de el anlisis semntico y generacin de de cdigo intermedio, y los otros inmediatamente despus de la generacin de cdigo objetivo.

Aplicacin de un buen mejorador de cdigo al cdigo en la figura 1.6 produce el cdigo mostrado en el ejemplo 1.2 (pgina 5) Comparando los dos programas, podemos ver que la versin mejorada bastante corta. Conspicuamente ausente estn la mayora de las cargas y almacenamientos. El mejorador de cdigo maquina independiente es capaz de verificar que i y j pueden ser mantenidas en los registros en toda la ejecucin del bucle principal. (Este no hubiera sido el caso si, por ejemplo, el bucle contuviera un llamado a subrutina que re-use esos registros, o que intentara modificar i o j) el mejorador de cdigo maquina especifico es entonces capaz de asignar i y j para los registros actuales de el objetivo de la maquina. Para modernas arquitecturas de microprocesadores, particularmente esas con un llamado implementaciones superescalar (unas donde unidades funcionales separadas pueden ejecutar instrucciones simultneamente), compiladores pueden usualmente generar mejor cdigo que los programadores de lenguaje de ensamblaje.

Revisa tu entendimiento
22. Haga una lista de las fases de compilacin principales, y describa el trabajo desempeado por cada uno. 23. describa como un programa es pasado de un escner (scanner) a un analizador gramatical (parse); del analizador (parse) al analizador semntico y de este al generador de cdigo intermedio. 24. Qu diferencia el front- en d de un compilador de un bacck-end? 25 Cul es la diferencia entre una fase y un paso de compilacin? Bajo qu circunstancias tiene sentido para un compilador tener mltiples pasos? 26 cul es el propsito de la tabla de smbolos del compilador? 27 cul es la diferencia entre semntica esttica y dinmica? 28 En maquinas modernas, los programadores de lenguaje de ensamblaje aun tienden a escribir mejor cdigo de lo que un compilador puede? Porque o porque no?

Resumen y observaciones finales


En este captulo introducimos el estudio del lenguaje de diseo de programacin e implementacin. Consideramos porque hay tantos lenguajes, que los hace exitosos o no, como deben ser categorizados para estudio, y que beneficios es probable que el lector gane de este estudio. Notamos que el lenguaje de diseo e implementacin est ntimamente relacionado el uno del otro. Obviamente una implementacin debe ajustarse a las reglas del lenguaje. Al mismo tiempo, un diseador de lenguaje debe

considerar cun difcil o fcil ser implementar varias caractersticas, y que tipo de rendimiento probablemente resulte para programas que usen esas caractersticas. Las implementaciones de lenguaje son comnmente diferenciadas en esas basadas en interpretacin y compilacin. Notamos, sin embargo, que la diferencia entre estos dos enfoques es confuso y que la mayora de implementaciones incluyen un poco de cada uno. Como regla general, podemos decir que un lenguaje es compilado si la ejecucin es precedida por un paso de traduccin que (1) totalmente analice ambos estructura (sintaxis) y significado (semntica) del programa, y (2) produce un programa equivalente en una forma significativamente diferente. La mayor parte del material de aplicacin en este libro pertenece a la compilacin. Compiladores son generalmente estructurados como una serie de fases. Las pocas primeras fases escaneo, anlisis gramatical (parsing) y anlisis de semntica---sirvieron para analizar la fuente del programa. Colectivamente estas fases son conocidas como los compiladores front-end. Y las ltimas fasesgeneracin de cdigo intermedio, mejoras en cdigo, generacin de cdigo objetivo---son conocidos como back-end. Sirven para construir un programa objetivo preferiblemente uno rpidocuya semntica encajan con los de la fuente.

Capitulo 3, 6, 7,8, y 9 forman el ncleo de este libro. Cubren temas fundamentales de lenguaje de diseo, ambos desde el punto de vista del programador y el implementador de lenguaje. Para respaldar la discusin de implementaciones, capitulo 2 y 4 describen compiladores front-ends ms al detalle de lo que ha sido posible en esta introduccin. Capitulo 5 proporciona una vista de los que es arquitectura a nivel ensamblador. Captulos 14 hasta el 16 discuten lo que son los compiladores back-ends, incluyendo ensambladores y vinculadores, sistemas de tiempo de ejecucin, y tcnicas de mejoramiento de cdigo. Ejemplos veremos ms de este lenguaje en el captulo 10 hasta el 13. Apndice A hace una lista de los lenguajes de programacin aqu mencionados, juntos con un grafico genealgico referencias bibliogrficas. Apndice B contiene una lista de barras laterales de Diseo e implementacin; Apndice C contiene una lista de ejemplos enumerados.

Ejercicios
Los errores en un programa de computadora pueden ser clasificados de acuerdo a cuando estos son detectados y, si son detectados en el momento de compilacin, que parte del compilador los detecta. Usando tu lenguaje imperativo favorito, de un ejemplo de los siguientes: (a) (b) (c) (d) Un error lxico, detectado por el escner Un error en sintaxis, detectado por el analizador gramatical (parser) Un error semntico esttico, detectado por anlisis semntico Un error semntico dinmico, detectado por cdigo generado por el compilador (e) Un error que el compilador no puede ni atrapar ni generar cdigo para atrapar (esto debe ser una violacin a la definicin de lenguaje, no solo un error de programa ) 1.2 Consideremos otra vez el conjunto de herramienta Pascal distribuido por Niklaus Wirth (ejemplo 1.15). Despus de construir exitosamente una versin de lenguaje de maquina del compilador pascal, uno puede en principio descartar el interpretador Pcode y la versin P-code del compilador. Porque escogeramos no hacer eso? 1.3 Los lenguajes imperativos como el de Fortran y C son tpicamente compilados, mientras que los lenguajes de secuencias de comandos (scripting), en los que muchas cuestiones no pueden ser establecidas hasta el tiempo de ejecucin, son tpicamente interpretados. Es interpretacin lo que uno tiene que hacer simplemente cuando la compilacin es inviable, o hay verdaderamente algunas ventajas para interpretar un lenguaje, aun as cuando un compilador est disponible? 1.4 El programa GCD del ejemplo 1.20 puede ser tambin escrito

Este programa calcula el mismo resultado? Si no, Puedes arreglarlo? Bajo que circunstancias esperaras uno o el otro que sea ms rpido?

1.5 En tu implementacin local de C, cual es el lmite de tamao de enteros? Qu sucede en el evento de desbordamiento aritmtico? Cules son las implicaciones de lmites de tamao en la portabilidad de programas de una maquina/compilador a otra? Como las respuestas a estas preguntas difieren en java? En el caso de Ada? O para Pascal y Scheme? (necesitara encontrar un manual.) 1.6 El Unix hace que la utilidad permita al programador especificar dependencias entre las piezas compiladas separadamente de un programa. Si el archivo A depende de el archivo B y el B es modificado, hacemos deducciones de que A debe ser recompilado, en caso de que cualquiera de los cambios en B afecten el cdigo producido para A. Cun preciso es este tipo de dependencia de gestin? Bajo qu circunstancias nos guiara a hacer trabajo innecesario? Bajo qu circunstancias fallara en recompilar lo que necesite ser compilado? 1.7 Por qu es difcil decir porque un programa bien? Cmo le haces para encontrar errores en tu cdigo? Qu clase de errores son revelados en la prueba? Y qu tipos de errores no? (para mas nociones formales de correccin de programas vea las notas bibliogrficas al final del captulo 4)

Exploraciones
1.8 (a) Cul fue el primer lenguaje de programacin que aprendi? Si lo escogiste, porque lo hiciste? Se fue escogido para ti por otros, porque crees que lo escogieron? que partes del lenguaje encontraste ms difcil de aprender? (b) Con el lenguaje con el que ests mas familiarizado (no ser el primero que aprendas o aprenders), haz una lista de tres cosas que tu desees hayan sido diseados diferente. Porque crees que fueron diseados de ese modo? Cmo lo arreglaras si tuvieras la oportunidad de hacerlo? Habra alguna consecuencia negativa, por ejemplo en trminos de complejidad de compilador o rapidez de ejecucin del programa? 1.9 Jntate con un compaero cuya principal experiencia es en programacin de uno diferente al de la categora presentada en figura 1.1 (si es que tu experiencia es mayor en C, por ejemplo, podras buscar a alguien con experiencia en Lisp) Compara anotaciones. Cules son los ms fciles y difciles aspectos de programar, en cada una de sus respectivas experiencias? Escojan un solo problema (ejemplo, clasificando, o identificacin de componentes conectados en un grafico) y resulvelo usando cada uno de sus lenguajes favoritos. Qu solucin es ms elegante (haga dos de su preferencia)? Cual es ms rpido porque?

1.10 (a) Si tienes acceso a un sistema Unix, compila un programa simple con la S bandera de lnea de comando. Aade comentarios al archivo de lenguaje de ensamblaje resultante para explicar el propsito de cada instruccin. (b) Ahora usa la bandera de comando de lnea o para generar un archivo reubicable. Usando herramientas locales apropiadas (busque en particular por for nm, objdump, o un depurador simblico como gdb o dbx), identifique el lenguaje de maquina correspondiente para cada lnea de ensamblaje. (c) Usando nm, objdump, o una herramienta similar, identifique los smbolos en su archivo objetivo. Ahora arranque el compilador para la finalizacin, para producir un archivo ejecutable. Finalmente, corra nm u objdump nuevamente para ver que ha sucedido a los smbolos en parte (b). De donde aparecieron----como el vinculador los resolvi? (d) Arranque el compilador para finalizar una vez ms, usando la bandera de comando -v. debera ver ahora mensajes que describen varios subprogramas que fueron invocados durante el proceso de compilacin (cada compilador usa una letra diferente para esta opcin; revise la pagina man). Los subprogramas pueden incluir un preprocesador, separar pases del compilador en si (a menudo dos), probablemente un ensamblador, y el vinculador. Si es posible, corra estos subprogramas usted mismo, individualmente. Cules de ellos producen los archivos descritos en sub-preguntas previas? Explique el propsito de varios comandos de lnea con los que los subprogramas fueron invocados. 1.11 Escriba un programa que se comprometa un error de semntica dinmica (ejemplo, divisin por cero, acceso final de una matriz, eliminar la referencia de un puntero nulo). Qu sucede cuando arranca el programa? El compilador te da opciones para controlar lo que pasa? Idee un experimento para evaluar el costo de las estructuras de semntica en el tiempo de ejecucin. Si es posible, intente este ejercicio con ms de un lenguaje o compilador. 1.12 C tiene una reputacin por ser un lenguaje de alto nivel relativamente inseguro. En particular, permite al programador mezclar operando de diferentes tamaos y tipos en mucho ms modos que sus primos cercanos. La utilidad Unix Lint puede ser usado para buscar construcciones potencialmente inseguras en programas C. En efecto, muchas de estas reglas que son reforzadas por el compilador en otros lenguajes son opcional en C, y son reforzadas (si se desea) por un programa separado. Qu piensas de este enfoque? Es una buena idea? Porque o porque no? 1.13 Usando un motor de bsqueda de internet o una revista de servicios indexados, lea sobre la historia de java y C#, incluyendo el conflicto entre Sun y Microsoft sobre

estandarizaciones de Java. Algunos han clamado que C# es, al menos en parte, un intento de Microsoft para matar a Java. Defiende o refuta esta afirmacin.

Notas bibliogrficas
Los captulos compilador orientados de este libro intentan trasmitir un sentido de lo que el compilador hace, ms que explicar cmo construir uno. Un mayor grado nivel de detalle puede ser encontrado en otros textos. Opciones principales incluyen trabajo de Aho et al. [ALSU07] y el de Cooper y Torczon[CT04]. Otro excelente, aunque menos actual textos incluyen los de Grune et al. [GBJL01], Appel[App97], y Fischer y LeBlanc[FL88]. Textos populares de diseo de lenguaje de programacin incluyen los de Louden[Lou03], Sebesta[Seb08], y Sethi[Set96]. Algo de la mejor informacin puede ser encontrada en los procedimientos de las conferencias auspiciadas por la Asociacin de maquinaria de computacin en 1978, 1993, y 2007 [Wex78, Ass93, Ass07]. Otra referencia excelente es el texto de Horowitz de 1987 [Hor87]. Una gama ms amplia de material histrico puede ser encontrada en la trimestral IEEE Anales sobre la historia de la computacin. Dada la importancia del gusto personal en diseo de lenguaje de programacin, es inevitable que algunas comparaciones de diseos de lenguajes deberan ser marcadas por opiniones slidamente redactadas. Ejemplos incluyen los escritos de Dijkstra[Dij82], Hoare[Hoa81], Kernighan[Ker81], y Wirth [Wir85a]. La mayor parte de desarrollo de software tiene lugar en entornos de programacin integrada. Precursor que influencian estos entornos son el entorno Genera Common Lisp de Symbolic Corp. [WMWM87] y Smalltalk[Gol84], Interlisp[Tm81], Cedar[SZBH86] entornos en el Xerox Palo Alto Research Center.

También podría gustarte