Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad


Compiladores e interpretes teoria y practica, Apuntes de Ingeniería Infórmatica

Libro de Compiladores e interpretes buena explicación parte teórica y practica

Tipo: Apuntes

2015/2016

Subido el 03/10/2016

lorena_salas
lorena_salas 🇻🇪

4.8

(5)

1 documento

1 / 375

Toggle sidebar

Esta página no es visible en la vista previa

¡No te pierdas las partes importantes!

bg1
Compiladores e interpretes:
teoría y práctica
Manuel Alfonseca Moreno
Marina de la Cruz Echeandía
Alfonso Ortega de la Puente
Estrella Pulido Cañabate
www.pearsoneducacion.com
Compiladores e Intérpretes: Teoría y Práctica, es un texto dirigido a
Escuelas y Facultades de Informática, en cuya titulación existe esta asignatura
bajo el nombre usual de Procesadores de Lenguaje. El libro describe con
detalle y ejemplos las distintas fases del proceso de compilación o
interpretación y los algoritmos que se pueden utilizar para implementarlas.
Cada capítulo se acompaña con ejercicios, cuya solución aparece en
www.librosite.net/pulido, donde también se incluye el código completo de
un compilador para un lenguaje sencillo, así como los pasos que hay que dar
para construirlo.
ISBN 978-84-205-5031-2
Otro libro de interés:
Alfred V. Aho, Ravi Sethi y
Jeffrey Ullman:
Compiladores: Principios, técnicas
y herramientas. México,
Pearson Addison Wesley, 1990.
ISBN: 968-4443-33-1
Incluye:
LibroSite es una página web
asociada al libro, con una
gran variedad de recursos y
material adicional tanto para
los profesores como para
estudiantes. Apoyos a la
docencia, ejercicios de
autocontrol, enlaces
relacionados, material de
investigación, etc., hacen de
LibroSite el complemento
académico perfecto para este
libro.
Compiladores e interpretes
Alfonseca
de la Cruz
Ortega
Pulido
www.librosite.net/pulido
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a
pf4b
pf4c
pf4d
pf4e
pf4f
pf50
pf51
pf52
pf53
pf54
pf55
pf56
pf57
pf58
pf59
pf5a
pf5b
pf5c
pf5d
pf5e
pf5f
pf60
pf61
pf62
pf63
pf64

Vista previa parcial del texto

¡Descarga Compiladores e interpretes teoria y practica y más Apuntes en PDF de Ingeniería Infórmatica solo en Docsity!

Compiladores e interpretes:

teoría y práctica

Manuel Alfonseca Moreno

Marina de la Cruz Echeandía

Alfonso Ortega de la Puente

Estrella Pulido Cañabate

www.librosite.net/pulido

Compiladores

e intérpretes:

teoría y práctica

Manuel Alfonseca Moreno
Marina de la Cruz Echeandía
Alfonso Ortega de la Puente
Estrella Pulido Cañabate

Departamento de Ingeniería Informática Universidad Autónoma de Madrid

Madrid • México • Santafé de Bogotá • Buenos Aires • Caracas • Lima Montevideo • San Juan • San José • Santiago • Sâo Paulo • Reading, Massachusetts • Harlow, England

2.1. Complejidad temporal de los algoritmos

5.4.1. Algunas observaciones sobre la información semántica

 - Contenido 
  • Capítulo 1. Lenguajes, gramáticas y procesadores
    • 1.1. Gödel y Turing
    • 1.2. Autómatas
    • 1.3. Lenguajes y gramáticas
    • 1.4. Máquinas abstractas y lenguajes formales
    • 1.5. Alfabetos, símbolos y palabras
    • 1.6. Operaciones con palabras
      • 1.6.1. Concatenación de dos palabras
      • 1.6.2. Monoide libre
      • 1.6.3. Potencia de una palabra
      • 1.6.4. Reflexión de una palabra
    • 1.7. Lenguajes
      • 1.7.1. Unión de lenguajes
      • 1.7.2. Concatenación de lenguajes
      • 1.7.3. Binoide libre
      • 1.7.4. Potencia de un lenguaje
      • 1.7.5. Clausura positiva de un lenguaje
      • 1.7.6. Iteración, cierre o clausura de un lenguaje
      • 1.7.7. Reflexión de lenguajes
      • 1.7.8. Otras operaciones
    • 1.8. Ejercicios
    • 1.9. Conceptos básicos sobre gramáticas
      • 1.9.1. Notación de Backus
      • 1.9.2. Derivación directa
      • 1.9.3. Derivación
      • 1.9.4. Relación de Thue
      • 1.9.5. Formas sentenciales y sentencias - 1.9.6. Lenguaje asociado a una gramática - 1.9.7. Frases y asideros - 1.9.8. Recursividad - 1.9.9. Ejercicios
    • 1.10. Tipos de gramáticas - 1.10.1. Gramáticas de tipo - 1.10.2. Gramáticas de tipo - 1.10.3. Gramáticas de tipo - 1.10.4. Gramáticas de tipo - 1.10.5. Gramáticas equivalentes - 1.10.6. Ejercicios
    • 1.11. Árboles de derivación - 1.11.1. Subárbol - 1.11.2. Ambigüedad - 1.11.3. Ejercicios
    • 1.12. Gramáticas limpias y bien formadas - 1.12.1. Reglas innecesarias - 1.12.2. Símbolos inaccesibles - 1.12.3. Reglas superfluas - 1.12.4. Eliminación de símbolos no generativos - 1.12.5. Eliminación de reglas no generativas - 1.12.6. Eliminación de reglas de redenominación - 1.12.7. Ejemplo - 1.12.8. Ejercicio
    • 1.13. Lenguajes naturales y artificiales - 1.13.1. Lenguajes de programación de computadoras - 1.13.2. Procesadores de lenguaje - 1.13.3. Partes de un procesador de lenguaje - 1.13.4. Nota sobre sintaxis y semántica
    • 1.14. Resumen
    • 1.15. Bibliografía
  • Capítulo 2. Tabla de símbolos - de búsqueda - 2.1.1. Búsqueda lineal - 2.1.2. Búsqueda binaria - 2.1.3. Búsqueda con árboles binarios ordenados - 2.1.4. Búsqueda con árboles AVL - 2.1.5. Resumen de rendimientos
    • 2.2. El tipo de datos diccionario - 2.2.1. Estructura de datos y operaciones - 2.2.2. Implementación con vectores ordenados - 2.2.3. Implementación con árboles binarios ordenados - 2.2.4. Implementación con AVL
    • 2.3. Implementación del tipo de dato diccionario con tablas hash - 2.3.1. Conclusiones sobre rendimiento - 2.3.2. Conceptos relacionados con tablas hash - 2.3.3. Funciones hash - 2.3.4. Factor de carga - 2.3.5. Solución de las colisiones - 2.3.6. Hash con direccionamiento abierto - 2.3.7. Hash con encadenamiento
    • 2.4. Tablas de símbolos para lenguajes con estructuras de bloques - 2.4.1. Conceptos - 2.4.2. Uso de una tabla por ámbito - 2.4.3. Evaluación de estas técnicas - 2.4.4. Uso de una sola tabla para todos los ámbitos
      • en las tablas de símbolos 2.5. Información adicional sobre los identificadores
    • 2.6. Resumen
    • 2.7. Ejercicios y otro material práctico
    • 2.8. Bibliografía
  • Capítulo 3. Análisis morfológico
    • 3.1. Introducción
    • 3.2. Expresiones regulares
      • expresión regular 3.3. Autómata Finito No Determinista (AFND) para una
    • 3.4. Autómata Finito Determinista (AFD) equivalente a un AFND
    • 3.5. Autómata finito mínimo equivalente a uno dado
    • 3.6. Implementación de autómatas finitos deterministas
    • 3.7. Otras tareas del analizador morfológico
    • 3.8. Errores morfológicos
      • la herramienta lex 3.9. Generación automática de analizadores morfológicos:
        • 3.9.1. Expresiones regulares en lex
        • 3.9.2. El fichero de especificación lex
        • 3.9.3. ¿Cómo funciona yylex()?
        • 3.9.4. Condiciones de inicio
    • 3.10. Resumen
    • 3.11. Ejercicios
    • 3.12. Bibliografía
  • Capítulo 4. Análisis sintáctico
    • 4.1. Conjuntos importantes en una gramática
    • 4.2. Análisis sintáctico descendente - 4.2.1. Análisis descendente con vuelta atrás - 4.2.2. Análisis descendente selectivo - de Greibach 4.2.3. Análisis LL(1) mediante el uso de la forma normal
      • 4.2.4. Análisis LL(1) mediante el uso de tablas de análisis
    • 4.3. Análisis sintáctico ascendente
      • 4.3.1. Introducción a las técnicas del análisis ascendente
      • 4.3.2. Algoritmo general para el análisis ascendente
      • 4.3.3. Análisis LR(0)
      • 4.3.4. De LR(0) a SLR(1)
      • 4.3.5. Análisis SLR(1)
      • 4.3.6. Más allá de SLR(1)
      • 4.3.7. Análisis LR(1)
      • 4.3.8. LALR(1)
    • 4.4. Gramáticas de precedencia simple
      • 4.4.1. Notas sobre la teoría de relaciones
      • 4.4.2. Relaciones y matrices booleanas
        • de la gramática 4.4.3. Relaciones y conjuntos importantes
      • 4.4.4. Relaciones de precedencia
      • 4.4.5. Gramática de precedencia simple
      • 4.4.6. Construcción de las relaciones
      • 4.4.7. Algoritmo de análisis
      • 4.4.8. Funciones de precedencia
    • 4.5. Resumen
    • 4.6. Ejercicios
  • Capítulo 5. Análisis semántico
    • 5.1. Introducción al análisis semántico - programación de alto nivel 5.1.1. Introducción a la semántica de los lenguajes de
      • 5.1.2. Objetivos del analizador semántico
      • 5.1.3. Análisis semántico y generación de código
      • 5.1.4. Análisis semántico en compiladores de un solo paso
        • de un paso 5.1.5. Análisis semántico en compiladores de más
    • 5.2. Gramáticas de atributos - y ejemplos de introducción 5.2.1. Descripción informal de las gramáticas de atributos
      • 5.2.2. Descripción formal de las gramáticas de atributos
        • su cálculo 5.2.3. Propagación de atributos y tipos de atributos según
      • 5.2.4. Algunas extensiones
      • 5.2.5. Nociones de programación con gramáticas de atributos
    • 5.3. Incorporación del analizador semántico al sintáctico - semánticos? 5.3.1. ¿Dónde se guardan los valores de los atributos
      • 5.3.2. Orden de recorrido del árbol de análisis
      • 5.3.3. Tipos interesantes de gramáticas de atributos - de dos o más pasos 5.3.4. Técnica general del análisis semántico en compiladores - semánticos en los compiladores de sólo un paso 5.3.5. Evaluación de los atributos por los analizadores
      • lenguajes de programación 5.4. Gramáticas de atributos para el análisis semántico de los - programación de alto nivel necesaria para el análisis de los lenguajes de
        • 5.4.2. Declaración de identificadores
        • 5.4.3. Expresiones aritméticas
        • 5.4.4. Asignación de valor a los identificadores
        • 5.4.5. Instrucciones condicionales
        • 5.4.6. Instrucciones iterativas (bucles)
        • 5.4.7. Procedimientos
      • semánticos 5.5. Algunas herramientas para la generación de analizadores
        • 5.5.1. Estructura del fichero fuente de yacc
        • 5.5.2. Sección de definiciones
        • 5.5.3. Sección de reglas
        • 5.5.4. Sección de funciones de usuario
        • 5.5.5. Conexión entre yacc y lex
    • 5.6. Resumen
    • 5.7. Bibliografía
    • 5.8. Ejercicios
  • Capítulo 6. Generación de código
    • 6.1. Generación directa de código ensamblador en un solo paso - 6.1.1. Gestión de los registros de la máquina - 6.1.2. Expresiones - 6.1.3. Punteros - 6.1.4. Asignación - 6.1.5. Entrada y salida de datos - 6.1.6. Instrucciones condicionales - 6.1.7. Bucles - 6.1.8. Funciones
    • 6.2. Código intermedio - 6.2.1. Notación sufija - 6.2.2. Cuádruplas
    • 6.3. Resumen
    • 6.4. Ejercicios
  • Capítulo 7. Optimización de código
    • 7.1. Tipos de optimizaciones - 7.1.1. Optimizaciones dependientes de la máquina
      • 7.1.2. Optimizaciones independientes de la máquina
    • 7.2. Instrucciones especiales
    • 7.3. Reordenación de código
    • 7.4. Ejecución en tiempo de compilación
      • 7.4.1. Algoritmo para la ejecución en tiempo de compilación
    • 7.5. Eliminación de redundancias
      • 7.5.1. Algoritmo para la eliminación de redundancias
    • 7.6. Reordenación de operaciones - aritméticas 7.6.1. Orden canónico entre los operandos de las expresiones
      • 7.6.2. Aumento del uso de operaciones monádicas
      • 7.6.3. Reducción del número de variables intermedias
    • 7.7. Optimización de bucles - reducción de fuerza 7.7.1. Algoritmo para la optimización de bucles mediante - por reducción de fuerza 7.7.2. Algunas observaciones sobre la optimización de bucles
    • 7.8. Optimización de regiones - regiones 7.8.1. Algoritmo de planificación de optimizaciones utilizando
    • 7.9. Identificación y eliminación de las asignaciones muertas
    • 7.10. Resumen
    • 7.11. Ejercicios
  • Capítulo 8. Intérpretes
    • 8.1. Lenguajes interpretativos
    • 8.2 Comparación entre compiladores e intérpretes
      • 8.2.1. Ventajas de los intérpretes
      • 8.2.2. Desventajas de los intérpretes
    • 8.3. Aplicaciones de los intérpretes
    • 8.4. Estructura de un intérprete - de código 8.4.1. Diferencias entre un ejecutor y un generador
      • 8.4.2. Distintos tipos de tabla de símbolos en un intérprete
    • 8.5. Resumen
    • 8.6. Bibliografía
  • Capítulo 9. Tratamiento de errores
    • 9.1. Detección de todos los errores verdaderos
    • 9.2. Detección incorrecta de errores falsos
    • 9.3. Generación de mensajes de error innecesarios
    • 9.4. Corrección automática de errores
    • 9.5. Recuperación de errores en un intérprete
    • 9.6. Resumen
  • Capítulo 10. Gestión de la memoria
    • 10.1. Gestión de la memoria en un compilador
    • 10.2. Gestión de la memoria en un intérprete
      • 10.2.1. Algoritmos de recolección automática de basura
    • 10.3. Resumen
  • Índice analítico

capaz de obtener su solución. Por ello se considera a Turing el padre de la teoría de la com- putabilidad. El teorema de Turing es, en el fondo, equivalente al teorema de Gödel. Si el segundo de- muestra que no todos los teoremas pueden demostrarse, el primero dice que no todos los proble- mas pueden resolverse. Además, la demostración de ambos teoremas es muy parecida. Uno de esos problemas que no se puede resolver es el denominadol problema de la parada de la máqui- na de Turing. Puede demostrarse que la suposición de que es posible predecir, dada la descrip- ción de una máquina de Turing y la entrada que recibe, si llegará a pararse o si continuará procesando información indefinidamente, lleva a una contradicción. Esta forma de demostración, muy utilizada en las ciencias matemáticas, se llama reducción al absurdo.

Autómatas

El segundo eslabón en la cadena vino de un campo completamente diferente: la ingeniería eléc- trica. En 1938, otro artículo famoso [2] del matemático norteamericano Claude Elwood Shannon (1916-2001), quien más tarde sería más conocido por su teoría matemática de la comunicación, vino a establecer las bases para la aplicación de la lógica matemática a los circuitos combinato- rios y secuenciales, construidos al principio con relés y luego con dispositivos electrónicos de va- cío y de estado sólido. A lo largo de las décadas siguientes, las ideas de Shannon se convirtieron en la teoría de las máquinas secuenciales y de los autómatas finitos.

Los autómatas son sistemas capaces de transmitir información. En sentido amplio, todo siste- ma que acepta señales de su entorno y, como resultado, cambia de estado y transmite otras seña- les al medio, puede considerarse como un autómata. Con esta definición, cualquier máquina, una central telefónica, una computadora, e incluso los seres vivos, los seres humanos y las socieda- des se comportarían como autómatas. Este concepto de autómata es demasiado general para su estudio teórico, por lo que se hace necesario introducir limitaciones en su definición.

Desde su nacimiento, la teoría de autómatas encontró aplicación en campos muy diversos, pero que tienen en común el manejo de conceptos como el control , la acción , la memoria. A me- nudo, los objetos que se controlan, o se recuerdan, son símbolos, palabras o frases de algún tipo.

Estos son algunos de los campos en los que ha encontrado aplicación la Teoría de Autómatas:

  • Teoría de la comunicación.
  • Teoría del control.
  • Lógica de los circuitos secuenciales.
  • Computadoras.
  • Redes conmutadoras y codificadoras.
  • Reconocimiento de patrones.
  • Fisiología del sistema nervioso.
  • Estructura y análisis de los lenguajes de programación para computadoras.
  • Traducción automática de lenguajes.
  • Teoría algebraica de lenguajes.

1.

2 Compiladores e intérpretes: teoría y práctica

Se sabe que un autómata (o una máquina secuencial) recibe información de su entorno ( en- trada o estímulo ), la transforma y genera nueva información, que puede transmitirse al entorno ( salida o respuesta ). Puede darse el caso de que la información que devuelve el autómata sea muy reducida: podría ser una señal binaria (como el encendido o apagado de una lámpara), que indi- ca si la entrada recibida por el autómata es aceptada o rechazada por éste. Tendríamos, en este caso, un autómata aceptador.

Lenguajes y gramáticas

El tercer eslabón del proceso surgió de un campo que tradicionalmente no había recibido con- sideración de científico: la lingüística, la teoría de los lenguajes y las gramáticas. En la déca- da de 1950, el lingüista norteamericano Avram Noam Chomsky (1928-) revolucionó su campo de actividad con la teoría de las gramáticas transformacionales [3, 4], que estableció las ba- ses de la lingüística matemática y proporcionó una herramienta que, aunque Chomsky la des- arrolló para aplicarla a los lenguajes naturales, facilitó considerablemente el estudio y la formalización de los lenguajes de computadora, que comenzaban a aparecer precisamente en aquella época. El estudio de los lenguajes se divide en el análisis de la estructura de las frases (gramática) y de su significado (semántica). A su vez, la gramática puede analizar las formas que toman las pa- labras (morfología), su combinación para formar frases correctas (sintaxis) y las propiedades del lenguaje hablado (fonética). Por el momento, tan sólo esta última no se aplica a los lenguajes de computadora.

Aunque desde el punto de vista teórico la distinción entre sintaxis y semántica es un poco ar- tificial, tiene una enorme trascendencia desde el punto de vista práctico, especialmente para el di- seño y construcción de compiladores, objeto de este libro.

Máquinas abstractas y lenguajes formales

La teoría de lenguajes formales resultó tener una relación sorprendente con la teoría de máqui- nas abstractas. Los mismos fenómenos aparecen independientemente en ambas disciplinas y es posible establecer correspondencias entre ellas (lo que los matemáticos llamarían un isomor- fismo ). Chomsky clasificó las gramáticas y los lenguajes formales de acuerdo con una jerarquía de cuatro grados, cada uno de los cuales contiene a todos los siguientes. El más general se llama gra- máticas del tipo 0 de Chomsky. A estas gramáticas no se les impone restricción alguna. En con- secuencia, el conjunto de los lenguajes que representan coincide con el de todos los lenguajes posibles.

El segundo grado es el de las gramáticas del tipo 1 , que introducen algunas limitaciones en la estructura de las frases, aunque se permite que el valor sintáctico de las palabras dependa de su

1.

1.

Capítulo 1. Lenguajes, gramáticas y procesadores 3

Alfabetos, símbolos y palabras

Se llama alfabeto a un conjunto finito, no vacío. Los elementos de un alfabeto se llaman símbo- los. Un alfabeto se define por enumeración de los símbolos que contiene. Por ejemplo:

Σ 1 = {A,B,C,D,E,...,Z} Σ 2 = {0,1} Σ 3 = {0,1,2,3,4,5,6,7,8,9,.} Σ 4 = {/,}

Se llama palabra , formada con los símbolos de un alfabeto, a una secuencia finita de los sím- bolos de ese alfabeto. Se utilizarán letras minúsculas como x o y para representar las palabras de un alfabeto: x = JUAN (palabra sobre Σ 1 ) y = 1234 (palabra sobre Σ 3 ) Se llama longitud de una palabra al número de letras que la componen. La longitud de la pa- labra x se representa con la notación |x|. La palabra cuya longitud es cero se llama palabra va- cía y se representa con la letra griega lambda (λ). Evidentemente, cualquiera que sea el alfabeto considerado, siempre puede formarse con sus símbolos la palabra vacía.

El conjunto de todas las palabras que se pueden formar con las letras de un alfabeto se llama lenguaje universal de Σ. De momento se utilizará la notación W(Σ) para representarlo. Es evidente que W(Σ) es un conjunto infinito. Incluso en el peor caso, si el alfabeto sólo tiene una letra (por ejemplo, Σ = {a}), las palabras que podremos formar son:

W(Σ) = {λ, a, aa, aaa, ...}

Es obvio que este conjunto tiene infinitos elementos. Obsérvese que la palabra vacía pertene- ce a los lenguajes universales de todos los alfabetos posibles.

Operaciones con palabras

Esta sección define algunas operaciones sobre el conjunto W(Σ) de todas las palabras que se pue- den construir con las letras de un alfabeto Σ = {a 1 , a 2 , a 3 , ...}.

1.6.1. Concatenación de dos palabras

Sean dos palabras x e y tales que x ∈ W(Σ), y ∈ W(Σ). Suponiendo que x tiene i letras, e y tiene j letras:

x = a 1 a 2 ...a (^) i y = b 1 b 2 ...b (^) j

1.

1.

Capítulo 1. Lenguajes, gramáticas y procesadores 5

Donde todas las letras a (^) p, b (^) q son símbolos del alfabeto Σ. Se llama concatenación de las palabras x e y (y se representa xy) a otra palabra z, que se obtiene poniendo las letras de y a continuación de las letras de x: z = xy = a 1 ...a (^) i b 1 ...b (^) j La concatenación se representa a veces también x.y. Esta operación tiene las siguientes pro- piedades:

  1. Operación cerrada: la concatenación de dos palabras de W(Σ) es una palabra de W(Σ). x ∈ W(Σ) ∧ y ∈ W(Σ) ⇒ xy ∈ W(Σ)
  2. Propiedad asociativa:

x(yz) = (xy)z Por cumplir las dos propiedades anteriores, la operación de concatenación de las palabras de un alfabeto es un semigrupo.

  1. Existencia de elemento neutro. La palabra vacía (λ) es el elemento neutro de la concate- nación de palabras, tanto por la derecha, como por la izquierda. En efecto, sea x una pa- labra cualquiera. Se cumple que: λx = xλ = x

Por cumplir las tres propiedades anteriores, la operación de concatenación de las palabras de un alfabeto es un monoide (semigrupo con elemento neutro).

  1. La concatenación de palabras no tiene la propiedad conmutativa, como demuestra un con- traejemplo. Sean las palabras x=abc, y=ad. Se verifica que

xy=abcad yx=adabc

Es evidente que xy no es igual a yx. Sea z = xy. Se dice que x es cabeza de z y que y es cola de z. Además, x es cabeza propia de z si y no es la palabra vacía. De igual manera, y es cola propia de z si x no es la palabra vacía.

Se observará que la función longitud de una palabra tiene, respecto a la concatenación, propie- dades semejantes a las de la función logaritmo respecto a la multiplicación de números reales: |xy| = |x| + |y|

1.6.2. Monoide libre

Sea un alfabeto Σ. Cada una de sus letras puede considerarse como una palabra de longitud igual a 1, perteneciente a W(Σ). Aplicando a estas palabras elementales la operación concatenación, puede formarse cualquier palabra de W(Σ) excepto λ, la palabra vacía. Se dice entonces que Σ es un conjunto de generadores de W(Σ)-{λ}. Este conjunto, junto con la operación concatenación, es un semigrupo, pero no un monoide (pues carece de elemento neutro). Se dice que W(Σ)-{λ}

6 Compiladores e intérpretes: teoría y práctica