Está en la página 1de 29

Introducción a la Lingüística Computacional

Prólogo

El presente documento es una recopilación de información de distintas bibliografías


y una presentación orientada a un mejor entendimiento de la Teoría de los Lenguajes
Formales para estudiantes de Ingeniería en Computación.
Podrá observar que, si lee la bibliografía recomendada para la Cátedra de
Compiladores e Intérpretes, en todas existe una explicación sobre cómo la Teoría de los
Lenguajes Formales, pero ninguna cuenta la historia completa de cómo nace, y a todas les
falta algo. Las que usan un enfoque lingüístico para explicar el tema les falta el enlace con
la lingüística computacional, y viceversa, las que usan un enfoque matemático les falta la
orientación lingüística que dio origen a su nacimiento. Este documento intenta ser una
solución a ese problema.
Ing. Domingo E. Becker, responsable de la Cátedra de Compiladores e Intérpretes,
Carrera “Ingeniería en Computación”, Universidad Católica de Santiago del Estero, Junio
de 2008.

Introducción a las Gramáticas Generativas

Los conceptos aquí presentados se manejaban antes de que Chomsky presentara su


trabajo sobre lingüística computacional.

Lo que Chomsky hizo fue encontrar la explicación matemática del mecanismo del
lenguaje, partiendo de estudios de lingüística que se habían realizado hasta ese momento.

Hasta el día de la edición de este trabajo, no se presentaron objeciones valederas a


los estudios realizados por Chomsky, aunque, a primera vista, pareciera ser que la Teoría
de los Lenguajes Formales va por otro camino distinto al que tomó Chomsky.

Este capítulo está basado principalmente en Nique [1985]. Christian Nique es de


nacionalidad francesa. Aunque en Francia había una Escuela que seguía caminos distintos
en la investigación a los que seguía la Escuela Americana, donde estaba Chomsky, fueron
los estudios de éste último los que predominaron e hicieron historia, y los lingüistas
franceses y alemanes los que más lo usaron en un principio.

Al finalizar la lectura de este capítulo, el lector estará en mejores condiciones de


iniciar el estudio de la Teoría de los Lenguajes Formales, tratada en el capítulo 2 de este
trabajo.

1 de 29
Un Mecanismo Finito para Generar un Número Infinito de Oraciones

No sólo el hablante posee implícitamente el mecanismo del lenguaje, sino que


además es "en todo momento capaz de emitir espontáneamente, o de percibir o
comprender, un número indefinido de oraciones que, en su mayor parte, no ha
pronunciado nunca ni oído antes". Esto equivale a decir que, cuando se habla , se hace
algo más que reproducir esquemas de oraciones que se escuchó antes, sino que también se
crean oraciones nuevas. Entonces el mecanismo del lenguaje es un mecanismo creador.

La repetición de oraciones es excepcional, y responde a características y costumbres


de algunos hablantes, por lo que (la repetición) no tiene ninguna relación con la utilización
del lenguaje. No se habla repitiendo lo que se ha oído, sino mediante un acto de creación
cada vez, y esta característica es entonces la principal en el uso del lenguaje.

Existen dos clases de creatividad que es preciso no confundir. La primera, que se


llama creatividad por cambio de reglas, consiste fundamentalmente en cambiar ciertas partes
del mecanismo lenguaje. Es lo que hace variar la pronunciación de ciertas palabras, que
crea otras nuevas, que acaba por admitir como gramatical lo que no era en un principio,
nada más que una desviación en relación a las reglas. El segundo tipo es completamente
diferente. Se le llama creatividad gobernada por las reglas. Es la que permite al hablante, por
aplicación de las reglas de la gramática, crear una infinidad de oraciones. Esto no es
posible más que por la misma naturaleza de las reglas del lenguaje, que poseen una
propiedad muy particular, llamada en matemáticas recursividad, es decir, la posibilidad
de reproducirse hasta el infinito.

Se denomina competencia (Chomsky [1965]) al conocimiento que el emisor-


receptor tiene de su lengua. La actuación se define como la utilización real en situaciones
concretas de la competencia. A la competencia se la considera como un mecanismo finito, es
decir, formado por un número limitado de reglas y capaz de generar un número infinito
de oraciones.

La gramática, que no es otra cosa que la explicación de la competencia, deberá


responder a la misma definición para ser válida. Por eso deberá disponer de reglas
estrictas, formuladas con una extremada precisión, y que podrán traducir esta propiedad
de la competencia: la de ser un mecanismo finito para generar un número infinito de
oraciones.

Teoría General y Gramáticas Particulares

Normalmente se reserva el término gramática para el estudio de las lenguas


particulares, y el de teoría general para el estudio de las particularidades en común que
tienen todos los lenguajes, las diferencias entre ellos, y entonces, las condiciones sobre la
forma que debe tener la gramática de cada lengua.

Se ve así la importancia de la teoría general (TG en adelante) para la elaboración de

2 de 29
las gramáticas particulares: éstas deben tener en cuenta la TG para ser adecuadas.

Se denomina corpus a un conjunto de oraciones de un lenguaje. Para el estudio de


lenguas que ya no existen, se trata de conseguir un corpus representativo de la misma.

La TG puede ser concebida de tres maneras diferentes incluyentes entre sí, y en


cada una de ellas tendrá tareas distintas:

1. La TG puede proporcionar un conjunto de instrucciones, un mecanismo, que


permita al lingüista construir la mejor gramática de una lengua, a partir de un
corpus dado. El mecanismo sería de alguna manera "un procedimiento de
descubrimiento" de la gramática adecuada para cada lengua. Gráficamente:

Dato: Corpus
T.G.

La Teoría General como un mecanismo para construir gramática.

2. La TG puede proporcionar un método que, dados un corpus y una gramática,


permita decir si la gramática es o no adecuada. Sería en este caso "un procedimiento
de decisión".

Corpus
Datos: T.G.
Gramática

La Teoría General como un mecanismo de validación de gramáticas.

3. La TG puede, por último, ante dos gramáticas (o más) y un corpus, decir cuál de las
dos es la más adecuada. Se le llama entonces "procedimiento de evaluación de las
gramáticas".

3 de 29
Corpus
Datos: Gramática 1 Respuesta: la mejor
T.G. gramática es...
Gramática 2

La Teoría General como un mecanismo de selección de gramáticas.

La primera es la más exigente, pero no la más difícil, viene a pedir a la teoría que
diga qué forma debe tener la gramática de cada lengua. Esta pregunta es difícil de
responder, por lo tanto no se está en condiciones de construir un procedimiento general de
descubrimiento de las gramáticas. Pero lo que si se puede, es usar ciertos criterios para
construir una gramática para un corpus dado.

La segunda es un poco menos exigente, puesto que sólo se trata de verificar si las
oraciones del corpus pueden ser generadas por la gramática, en otras palabras, que se las
pueda analizar sintácticamente por medio de la gramática.

La tercera es la más comprometida puesto que la selección se realiza en base a


criterios formados con la experiencia del lingüista, y los criterios a usar pueden ser varios,
todos ellos con fundamentos válidos.

La Teoría General de la que se habló, recibió el nombre de Teoría de los Lenguajes


Formales, los lingüistas la conocen también como Lingüística Computacional. Los temas
tratados por esta teoría son mucho más profundos que los tratados en este capítulo.

Gramaticalidad e Interpretabilidad

La Gramaticalidad es otro concepto importante. Para tener una visión más clara de lo
que es la gramaticalidad, es preciso oponerla a la interpretabilidad.

Sea la oración siguiente:

El padre del primo del tío del abuelo del vecino de la hermana mayor de la segunda mujer del
escribano vino ayer a verme.

Sin duda, esta oración es ininterpretable cuando se accede a ella por primera vez,
pero es gramaticalmente correcta, y obedece a una de las reglas que subyacen en la
competencia de la que se ha hablado anteriormente.

Es posible encontrarse frente a cuatro tipos de oraciones que son:

1. Gramaticales e interpretables. Ejemplo:


A Pedro le gusta el chocolate.

4 de 29
2. Gramaticales e ininterpretables. Ejemplo:
Pedro, cuyo amigo cuyo hermano bebe está borracho ha comido chocolate.

3. Agramaticales e interpretables. Ejemplo:


Mamá, da buen chocolate bebé.

4. Agramaticales e ininterpretables. Ejemplo:


Chocolate la había ser lo canta árbol.

Si se analiza sin mayor precisión la oración del ejemplo 2:

Pablo ha comido el chocolate

cuyo amigo está borracho

cuyo hermano bebe

se observará que la oración está gramaticalmente bien formada.

En realidad, parece ser que la noción de interpretabilidad debería integrarse en el


estudio de la actuación, ya que depende de factores como la limitación de la atención,
comprensión, memoria, etc.

Una teoría de la competencia, por el contrario, es una teoría del mecanismo del
lenguaje, y debe, pues, dar cuenta de las oraciones gramaticales y excluir las
agramaticales. La noción de gramaticalidad no puede ni debe confundirse con la aparición
en un corpus, ni con la probabilidad estadística de aparición, ya que un buen número de
oraciones que se pronuncian no son totalmente gramaticales, y las que son gramaticales en
algunos casos nunca se pronuncian.

En este sentido, la teoría de la competencia, es decir, la gramática generativa, aparece un


poco como gramática normativa. Pero no lo es del mismo modo que lo eran las gramáticas
tradicionales. No trata de preservar el "hermoso" lenguaje, y no se erige en el defensor de
un pretendido "lenguaje correcto". Toma el lenguaje tal cual es, diferente según los
individuos, según las clases sociales, según las situaciones, y trata sólo de dar cuenta de su
funcionamiento. Pero no dicta ninguna regla del tipo: "No hay que decir ... sino hay que
decir ...". Constata lo que se dice, lo que no se dice, o que no se dice ya tal o cual oración.
No se pronuncia nunca sobre las nociones de "buen o mal lenguaje", "estilo pesado",
"torpeza", etc. Le basta decir cuáles son las oraciones gramaticales y cuáles las
agramaticales, para dar cuenta de la estructura de las primeras y excluir las segundas.

5 de 29
La Gramática Generativa

Noción de Gramática Generativa

Apoyándose únicamente sobre las reflexiones precedentes, es posible considerar la


gramática como una teoría que da cuenta de las oraciones gramaticales, y sólo de las
gramaticales. Pero esta definición por si sola no es satisfactoria. La definición más correcta
es:

Una gramática es un modelo de la competencia, es decir, que debe hacer explícita


la gramática implícita que poseen los sujetos hablantes.

El término modelo es muy importante. La gramática, de alguna manera, es una


máquina, un mecanismo que nos permite generar oraciones. Esquemáticamente:

Entrada Constitución Salida


(instrucciones o reglas) de Oraciones (oraciones realizadas)

La gramática como mecanismo para generar oraciones.

Este esquema muestra en qué sentido la gramática ha podido ser calificada de


generativa. Permite generar el conjunto infinito de oraciones de la lengua. Pero no hay que
confundirla con una máquina que permita la emisión real de las oraciones.

Además, se hace la observación de que la gramática es "neutra" tanto frente al


emisor como al receptor. Es una teoría de la estructura y del funcionamiento del código
lingüístico, y no dice nada respecto al mecanismo físico-psicológico que permite hablar y
comprender.

La gramática generativa es tan sólo la explicitación del sistema de reglas que


subyace a la competencia, y la competencia es común al hablante y al oyente. En realidad,
el estudio de la emisión y de la recepción cae dentro de una teoría de la actuación.

De hecho, la gramática generativa no es una gramática en el sentido en el que


habitualmente se da a esta palabra. Sin duda se ocupa también de la estructura de la
lengua, pero si se distingue de las otras gramáticas no es sólo por el punto de vista que ha
elegido, sino sobre todo por el fin que se ha impuesto. Las gramáticas tradicionales y
estructurales eran modelos taxonómicos de la lengua, mientras que las generativas son un
modelo explicativo. Desea no sólo formar un inventario de los elementos lingüísticos, sino
también explicar su funcionamiento, la regularidad de cada lengua, las características
comunes universales del lenguaje, y dar cuenta del fenómeno de la creatividad. En este
sentido, las gramáticas taxonómicas son a la vez anteriores y necesarias para la gramática

6 de 29
generativa: las primeras describen los hechos lingüísticos que la segunda explica.

Al construir una gramática generativa, es decir, al dar cuenta de la competencia, se


debe partir de un hablante-oyente ideal que pertenezca a una comunidad lingüística
completamente homogénea, que conozca perfectamente su lengua y que, cuando aplique
ese conocimiento en una actuación real, no esté influenciado por condiciones
gramaticalmente irrelevantes como la limitación de memoria, distracciones de interés o
atención, o errores. Es una teoría de la actuación la que deberá considerar estos diversos
fenómenos.

Sincronía / Diacronía

Por el mismo fin que se impone, la gramática generativa no puede estudiar la


lengua más que en un cierto momento de su historia.

Los términos lingüística sincrónica y lingüística diacrónica fueron introducidos por


Saussure [1916] para distinguir los estudios que tienen por objeto un cierto estado de la
lengua de aquellos que se interesan por su evolución, respectivamente.

La gramática generativa no puede ser más que sincrónica, en el mismo sentido en


que la competencia no puede estar situada más que en un momento determinado en el
tiempo y en la evolución de la lengua.

Análisis en Constituyentes Inmediatos

Se desarrollará un ejemplo simple para explicar cómo construir una gramática


generativa. Lo que se está por hacer es descubrir los aspectos más importantes de la teoría
general antes mencionada. A tal efecto, se debe olvidar por un momento de la TG y
concentras la atención en la tarea que ésta puede realizar: dado un corpus, obtener la
gramática adecuada para el lenguaje al que pertenece el corpus.

Se tiene un corpus cuyos componentes son oraciones que tienen la misma


estructura gramatical, según una gramática tradicional. Las oraciones pertenecen al
lenguaje utilizado en la escritura de este documento (Castellano). El corpus es el siguiente:

El caballo salta el alambrado.


El gato toma la leche.
El perro come la carne.
El reloj marca la hora.
La niña saca la lengua.

Un corpus del Castellano.

Si tomamos la primera oración, lo primero que se observa es una oración correcta.

7 de 29
Esa oración tiene sujeto y predicado, que son los dos constituyentes inmediatos de la
oración.

Si se analiza el sujeto, se observa que tiene un núcleo y un modificador directo (MD); y


éstos son sus componentes inmediatos. Lo mismo ocurre con el predicado, que tiene un
verbo y un objeto directo (OD) como constituyentes. A su vez, el OD está formado por un
núcleo y un MD. Gráficamente:

El caballo salta el alambrado


El caballo salta el alambrado
El caballo salta el alambrado
El caballo salta el alambrado

Separación de la oración en constituyentes inmediatos.

o bien:

O
S P
MD N V OD
MD N V MD N

Análisis de la oración en constituyentes inmediatos.

El paso 1 toma la oración. El paso 2 separa la oración en sus componentes


inmediatos y así sucesivamente.

Se podría decir que del paso 4 sigue un quinto:

MD N V MD N
El caballo salta el alambrado

Ultimo paso del análisis en constituyentes inmediatos.

con el cual demostramos que el análisis en constituyentes inmediatos es válido.

Si al esquema realizado se lo grafica de otra forma, se tendría lo siguiente:

8 de 29
O

S P

MD N V OD

MD N

El caballo salta el alambrado

Análisis en componentes inmediatos (análisis sintáctico) de la oración del corpus.

Este esquema es similar al anterior, y difiere solamente en que se utilizan menos


líneas. Como se observará, el gráfico es más claro que el anterior. A este tipo de esquema
se lo conoce como árbol, y en lingüística computacional, como árbol de derivación o de
análisis sintáctico.

Para generar las oraciones, la gramática debe poseer un conjunto de instrucciones.


Estas se presentan bajo la forma de reglas que permiten rescribir un símbolo en una
secuencia de símbolos. El problema aquí ya no es la estructura de una oración particular,
sino el de la estructura de toda oración potencial.

En el corpus, las oraciones estaban formadas por sujetos (S) y predicados (P). Se
puede, entonces, formular una regla que diga más o menos lo siguiente: si se está en
presencia del símbolo O (oración), rescríbalo en S P (es decir, la concatenación de las
nociones sujeto y predicado). Esta regla tendrá la forma:

O ---> S P

Se leerá "O se rescribe en S P".

La regla dada indica cómo pasar del paso 1 al 2 en el análisis realizado arriba, es
decir, dice cuáles son los constituyentes de la noción O (oración). Se puede así escribir el
conjunto de reglas:

O ---> S P
S ---> MD N
P ---> V OD
OD ---> MD N

(Se debe tener en cuenta que en este ejemplo no se consideran aspectos semánticos y
morfológicos.)

9 de 29
Estas reglas no son suficientes para generar verdaderamente las oraciones. Hay que
añadirles otra serie de reglas llamadas reglas léxicas:

MD ---> el | la
N ---> caballo | alambrado | gato | leche | perro | carne | reloj |
hora | niña | lengua
V ---> salta | toma | come | marca | saca

Se leerá "MD se rescribe en el ó en la". El "ó" es en sentido excluyente. Las palabras


que aparecen en las reglas lexicales son todas aquellas que formaban alguna oración en el
corpus, no son palabras que no estaban en el corpus (es decir, no se las inventa).

Se debe observar que las reglas lexicales se rescriben en nociones (o símbolos) que
pertenecen al lenguaje. Dichas nociones o símbolos se denominan nociones terminales o
símbolos terminales. Las nociones o símbolos que en este ejemplo se escribieron con
mayúsculas, son utilizadas para describir al lenguaje que se está estudiando, y reciben el
nombre de metanociones o símbolos no terminales. Al lenguaje utilizado para describir un
lenguaje se lo denomina metalenguaje.

Aplicando sucesivamente las diferentes reglas obtenidas, se puede obtener lo que se


llama una derivación. Si para una oración dada se puede construir un árbol de derivación
que contenga sólo símbolos terminales en sus hojas, se dirá que la oración es
sintácticamente correcta (o gramaticalmente correcta), sin importar si es interpretable o no.

Para mostrar más específicamente por qué se dice que la gramática es generativa, se
partirá desde O, y se realizarán derivaciones sucesivas hasta llegar a obtener símbolos
terminales en las hojas del árbol de derivación. Una posibilidad sería la siguiente:

S P

MD N V OD

MD N

La niña toma la leche

Ejemplo de generación de una oración.

La oración obtenida es gramaticalmente correcta, y no figura en el corpus. Es en este


sentido en que se considera a la gramática como generativa, porque a partir de un número
finito de reglas se puede generar un número muy grandes (y a veces infinito) de oraciones.

10 de 29
Por supuesto que si se hubieran elegido otras reglas léxicas se habría llegado a una oración
como "El gato come el alambrado", lo cual no tiene sentido. La solución a este problema
puede ser agregar más reglas que no permitan tal combinación. Igualmente, la
concordancia en género y número del núcleo con el modificador directo se puede resolver
agregando reglas que restrinjan el uso de ellos.

Obsérvese que las reglas "S ---> N MD" y "OD ---> N MD" tienen la misma
secuencia de símbolos en la parte derecha de la flecha. Debido a que la gramática sólo
explica la estructura y no el significado, esas dos reglas se pueden resumir en una sola,
obteniéndose así una gramática mas pequeña.

Por último se puede decir que, si se tiene la descripción del lenguaje (corpus), es
probable que se pueda encontrar una gramática generativa que describa la estructura del
mismo. Lo de probable viene del hecho de que la teoría general no tiene un procedimiento
para escribir las reglas de la gramática, por lo que el lingüista debe usar mucho su
intuición.

La explicación del concepto de recursividad y del por qué es posible generar infinitas
oraciones con un número finito de reglas se da en la sección siguiente de este trabajo.

11 de 29
Introducción a la Teoría de los Lenguajes Formales

Introducción

Previo a la lectura de los capítulos que se encuentran en la Parte II se aconseja leer


el Capítulo 17 en la Parte V en donde se da una correcta introducción a las gramáticas
generativas y la lingüística matemática. Puede consultar además la bibliografía que trata la
teoría de compiladores.

En los puntos siguientes se hace una breve introducción a los conceptos


fundamentales usados por los 2 generadores y en los capítulos siguientes se explican
detalladamente cada uno de los algoritmos de análisis y de generación. Puede ser que el
lector que se esté iniciando en la teoría de los lenguajes formales necesite ver algunos
ejemplos; en este capítulo se minimiza la inclusión de ejemplos puesto que los conceptos
que introduce son muy básicos, por lo que se aconseja leer la bibliografía sobre
compiladores e intérpretes.

Lenguajes y Gramáticas

Alfabeto

Se denomina Alfabeto de un lenguaje a los caracteres que pueden formar parte de


las oraciones del mismo. Para el Castellano tenemos como Alfabeto a todas las letras y los
signos de puntuación. Se especifica como un conjunto de elementos.

Cadena o Tira de Caracteres

La noción más básica de la Teoría de los Lenguajes es la tira o cadena de caracteres,


que está formada por la concatenación de caracteres.

La cadena mínima o nula se denomina λ (lambda).

Lenguaje

Un lenguaje es, en general, un conjunto de cadenas de caracteres. A cada cadena de


caracteres la denominaremos oraciones. Está formado por los dos elementos siguientes

● Un diccionario, que indica los significados de las palabras.


● Un conjunto de reglas para describir las oraciones válidas del lenguaje. Este
conjunto de reglas forma la gramática del lenguaje.

12 de 29
Se denomina semántica al estudio del significado de las oraciones y frases de un
lenguaje, y su interpretación.

Se denomina sintaxis al estudio de la estructura del lenguaje. La sintaxis de las


oraciones del lenguaje (la estructura del lenguaje) se la explicita a través de reglas de
producciones.

Se denomina análisis sintáctico a la operación que se ejecuta para verificar la


gramaticalidad de una oración. Es un proceso de validación del texto fuente de entrada.
En cualquier situación donde se requiera validar la entrada de datos se puede usar el
análisis sintáctico.

Se denomina análisis semántico al proceso que se ejecuta para verificar la


coherencia en el significado de una oración.

Se denomina análisis lexicográfico a un caso especial de análisis sintáctico en donde


se usan técnicas especiales y más rápidas para tratar con la entrada de datos (texto fuente).
Lea también el punto 2.3.5.

Noción de Gramática

La noción de gramática que aquí se presenta es debida a Chomsky en el año 59.

Una gramática generativa transformacional está caracterizada por una cuádrupla


ordenada como la siguiente:

G=(N,T,R,O)

donde:
N: es el conjunto de símbolos no terminales usados para construir las reglas de la
gramática y no figuran en las oraciones del lenguaje. A veces se los denomina como no
terminales o metanociones.
T: es el conjunto de símbolos terminales . Cualquier oración del lenguaje debe ser una
cadena de símbolos de T, según la estructura que especifiquen las reglas. A veces pueden
ser llamados directamente terminales o nociones.
R: es el conjunto de las reglas de rescritura de la gramática. Tienen la forma cadena1 -->
Cadena2.
O: es el símbolo más importante del conjunto N, se denomina símbolo inicial, axioma,
símbolo distinguido o cabeza de lenguaje. Se usa para comenzar las derivaciones en el
análisis sintáctico de las oraciones.
Al lenguaje L generado por la gramática G está formado por todas las oraciones
tales que se puede encontrar a partir de O, por medio de aplicaciones sucesivas de las
reglas de la gramática. Se denota por
L(G) = { ε / O -*-> ε }

13 de 29
El conjunto de Reglas y la Clasificación de Chomsky

La clasificación publicada por Chomsky en el año 1959 introduce 4 tipos de


gramáticas a base de cambiar solamente el tipo de las reglas de derivación que se
encuentran en el conjunto R.

A las gramáticas del Tipo 0 y del Tipo 1 se las suele denominar gramáticas
generativas trasnformacionales. Lo de transformacional hace referencia al hecho de que
transforman una secuencia de caracteres en otra secuencia de caracteres en un solo paso.

Gramáticas de Tipo 0 o gramática con estructura de frase

Las reglas en este tipo de gramática tienen la forma:

α --->β donde α pertenece a (N U T)+ y β a (N U T)*

Por la definición dada, la regla que deriva en λ pertenece al lenguaje.

Este tipo engloba a todos los otros 3 tipos de gramática. Actualmente no se publicó
un trabajo en el que se haya presentado un analizador sintáctico que trabaje con una
gramática de éste tipo.

Se dice que la Máquina de Turing puede tratar este tipo de gramática. Las máquinas
de Turing son bidireccionales (pueden ir hacia adelante o hacia atrás en la examinación de
los caracteres de entrada).

Gramáticas de Tipo 1 o gramática sensible al contexto

Las reglas tienen la forma:

αA β ---> α γ β

donde A está en N y, α y β en (N U T) * y γ en (N U T)+

Se llama sensible al contexto por que cambia A por gamma sólo en el contexto
formado por alfa ... beta.

Aquí se puede observar que el problema de número que tenemos al trabajar con
lenguajes naturales (los que hablamos los humanos) puede ser tratado con gramáticas de
este tipo (por ejemplo, la concordancia del número del verbo con el del sujeto).

Se puede construir un autómata bidireccional para tratar esta gramática.


Gramáticas de Tipo 2 o gramáticas de contexto libre

14 de 29
La forma de las reglas es:

A --> α donde A está en N y α en (N U T)*

Se llama de contexto libre porque se puede cambiar A por α independientemente


del contexto en el que aparezca A.

Este tipo de gramáticas son las que se usan para los lenguajes de computación.
Cuando se utilice el término gramática en capítulos siguientes, se quiere decir gramáticas
de Tipo 2 o 3.

Para tratar estas gramáticas es necesario un autómata de pila.

Gramáticas de Tipo 3 o gramáticas regulares

Las reglas pueden tener una de las dos formas siguientes:

A ---> a B o bien
A ---> a

donde A y B son de N y a de T.

El no terminal B puede aparecer a la izquierda de a en la regla.

Tres años antes de la presentación de esta clasificación, Kleene estudió por primera
vez a las expresiones regulares. Resultó ser que las expresiones regulares es otra forma
muy compacta de escribir una gramática del Tipo 4.

El tratamiento de este tipo de gramáticas es a través de autómatas finitos.

Gramáticas de Contexto Libre

En esta sección estudiaremos conceptos fundamentales acerca de este tipo de


gramáticas, para pasar al capítulo siguiente en donde se utilizarán las operaciones
fundamentales con ellas, que serán usados más adelantes.
Recursividad

La recursividad es un mecanismo amplificador que permite definir formas


complicadas de un lenguaje con muy pocas reglas.

Veamos un ejemplo sencillo: sea el lenguaje cuyas oraciones son números enteros
según la siguiente descripción dada por extensión:

L = { números sin signos formados a partir de la combinación de los dígitos comprendidos


entre el 0 y el 9, por ejemplo el 457 }

15 de 29
Para construir las reglas de la gramática que den cuenta de la estructura de este
lenguaje se podrían dar las siguientes reglas:

N ---> D
N ---> D D
N ---> D D D
D ---> 0 | 1 | 2 | ... | 9

Se observa que la gramática construida no explica la estructura de los números de 4


o más dígitos. Aún más, si consideramos la posibilidad de que hay números con gran
cantidad de dígitos tendríamos una gramática con una gran cantidad de reglas, si es que
utilizamos esta forma de escribirla. Entonces, como solución aparece la recursividad, y a la
gramática la rescribiríamos de la siguiente manera:

N ---> N D
N ---> D
D ---> 0 | 1 | 2 | ... | 9

Arbol de Análisis Sintáctico

Es una representación gráfica del resultado obtenido al aplicar las reglas de la


gramática partiendo de O (el símbolo inicial) hasta llegar a la oración que se esté
analizando sintácticamente.

Al proceso de análisis sintáctico se lo menciona muchas veces como el proceso de


construir el árbol de análisis sintáctico de la oración.

Arbol sintáctico

Es una versión simplificada de un árbol de análisis sintáctico.

Los nodos de un árbol sintáctico son símbolos terminales y representan operaciones


entre ellos y el orden en que deben ser ejecutadas.

Un árbol sintáctico puede construirse a partir del análisis sintáctico del texto de
entrada.

La definición de árbol sintáctico dada aquí es la que sirve a los efectos de este
trabajo y puede no coincidir con alguna definición que se encuentre en la bibliografía
sobre compiladores. En términos de esta definición, cualquier árbol que se diga ser árbol
sintáctico y que tenga nodos con no terminales será considerado simplemente árbol.

En el capítulo 3 se utilizan árboles sintácticos para expresiones regulares.

16 de 29
Ambigüedad de una Gramática

Una gramática es ambigua si el lenguaje definido por la misma tiene alguna oración
que tenga más de un árbol de análisis sintáctico.

Se llama ambigua a la gramática y no al lenguaje que define, puesto que


frecuentemente es posible modificar la gramática para que deje de ser ambigua sin tocar
para nada el lenguaje implicado. Pero hay lenguajes para los que no existen más que
gramáticas ambiguas: a estos lenguajes se les llama "ambiguos intrínsecos".

La ambigüedad de una gramática es una propiedad indecidible, lo que significa que


no existe ningún algoritmo que acepte una gramática y determine con certeza y en un
tiempo finito si la gramática es ambigua o no.

Una gramática que es tratable con la técnica LR(k) o con la técnica LL(k) no es
ambigua, por lo que resulta un buen método de determinar la ambigüedad.

Gramáticas y el Análisis Sintáctico

La construcción de un analizador sintáctico consiste en el desarrollo de subrutinas


que revisen el código fuente de entrada y verificar que el mismo cumple con las reglas
gramaticales. Si cumple diremos que es gramaticalmente correcta, lo cual no significa que
sea entendible.

Existen varias técnicas de análisis sintácticos entre las que se destacan 2 grupos
principales: la técnica LR y la LL.

La técnica LR(k) (Left to right scanning - Rightmost parsing, examen de izquierda a


derecha - análisis a derechas), es un método de análisis ascendente, esto es, se parte de la
oración para llegar al símbolo inicial O. Ha sido presentado al público por primera vez por
Knuth [1965]. Reconocen la gran mayoría de los lenguajes de programación que se puedan
generar con gramáticas de contexto libre. En general su uso no tiene restricciones, pero la
construcción del analizador sintáctico es demasiado complicada por lo que se hace
necesario disponer de generadores de analizadores sintácticos para simplificar la tarea.

La técnica LL(k) (Left to right scanning - Leftmost parsing, examen de izquierda a


derecha - análisis a izquierdas) es un método descendente, esto es, parte desde el símbolo
inicial O para llegar a la oración. Las técnicas de análisis predictivos fueron estudiadas a
fondo por Knuth [1971]. El método es mucho más restrictivo que el LR, ya que el número
de gramáticas que se puede tratar es mucho menor. Gráficamente:

17 de 29
Comparación del número de gramáticas tratables con la técnica LR y el
número de gramáticas tratables con la técnica LL.

El generador de analizadores presentado en este trabajo genera analizadores que


trabajan con la técnica LR(1) Simple, a la que se le suele llamar SLR(1) o simplemente SLR.
El Análisis Lexicográfico

La función principal del análisis lexicográfico es la de convertir secuencias de


caracteres de entradas en símbolos léxicos.

Hay varias razones para dividir la fase de análisis de la traducción en análisis


lexicográfico y análisis sintáctico:

● Un diseño sencillo es la consideración más importante. El uso de un analizador


lexicográfico simplifica el analizador sintáctico. Imagine sino un analizador
sintáctico que incluya las convenciones de comentarios y espacios en blanco.
● Se mejora la eficiencia del compilador. Un analizador léxico independiente permite
construir un procesador especializado y potencialmente más eficiente para esta
función. Gran parte de tiempo del análisis se consume en leer el programa fuente y
separarlo en símbolos léxicos.
● Se mejora la transportabilidad del compilador. Las peculiaridades del alfabeto de
entrada y otras anomalías propias de los dispositivos de entrada pueden limitarse
al analizador lexicográfico.

La forma más simple de especificar símbolos léxicos y la que más se usa


actualmente es mediante el uso de expresiones regulares. La construcción de un
analizador lexicográfico a partir de estas expresiones regulares es una tarea complicada,
para lo cual es necesario disponer de un generador de analizadores lexicográficos.

Muchas veces se escuchará decir que la construcción manual del analizador


lexicográfico resulta en uno que funciona mucho más rápido que el que se obtendría a
través del uso de un generador. El generador que se presenta en este trabajo es un intento
de solución a este problema.

La inclusión de un analizador lexicográfico en el proyecto de construcción de un


traductor implica la construcción de otro analizador sintáctico, sólo que para una
gramática del Tipo 3 de la clasificación de Chomsky la cual es tratada con técnicas
distintas que las del Tipo 2. Las oraciones encontradas por ese analizador son pasadas al
analizador sintáctico del lenguaje fuente, y como consecuencia directa se tiene la
simplificación de la gramática del lenguaje fuente. Muchas veces este concepto es
confundido.

Esquemas de Traducción
Se define un esquema de traducción como un sistema formal del tipo:

18 de 29
EDT = { N, Te, Ts, R, O }

donde

N: es el conjunto finito de símbolos no terminales.

Te: es el conjunto finito de símbolos terminales del lenguaje de entrada o fuente.

Ts: es el conjunto finito de símbolos terminales del lenguaje de salida u objeto.

R: es el conjunto finito de reglas de traducción que poseen la estructura:


A ---> α , β

donde
A pertenece a N
α pertenece a ( N U Te)*
β pertenece a ( N U Ts)*

En cualquier caso se cumple que

N intersección (Te U Ts) = { }

O: es el símbolo inicial.

La estructura del lenguaje de salida se puede explicar con la gramática siguiente:

Gs = { N, Ts, P, O }

donde
N: es el conjunto de símbolos no terminales del lenguaje fuente. O es un elemento de este
conjunto.
Ts: es el mismo conjunto de símbolos terminales del esquema de traducción.
P: es el conjunto de reglas de la gramática, cuyos elementos son las reglas que:
P = { A ---> β / (A ---> α , β) era una regla de traducción del esquema }

Acciones Semánticas / Rutinas Semánticas

En la bibliografía utilizada se encontrarán definiciones distintas de lo que son las


acciones semánticas y las rutinas semánticas.

En Sanchis Llorca-Galán Pascual [1986], los términos acciones semánticas se aplican


a los autómatas finitos, y los términos rutinas semánticas a los analizadores sintácticos
(que en definitiva son también autómatas).

En Aho-Sethi-Ullman [1990], los términos acciones semánticas se aplican a los

19 de 29
analizadores sintácticos. Los términos rutinas semánticas no son utilizados en ese libro.

A los efectos de unificar conceptos, en este trabajo se tomarán como sinónimos a los
términos acciones semánticas y rutinas semánticas, fundamentado en que existe una
analogía entre un analizador sintáctico y un autómata finito.

La definición utilizada será la siguiente: se denomina acciones semánticas a los


fragmentos de oraciones de un lenguaje intercalados en la parte derecha de una regla de
una gramática libre de contexto.

En la definición dada en el punto anterior se habló de esquemas de traducción,


introduciendo un nuevo tipo de reglas en las que en la parte derecha se encuentran
cadenas de símbolos terminales del lenguaje objeto (o de salida). Se transcribe la forma
general de las reglas de traducción:

A ---> α , β

Aquí, β es la cadena de símbolos terminales del lenguaje objeto. Luego, se denomina


acciones semánticas a las acciones que se ejecutan para producir esa cadena de símbolos
terminales del lenguaje objeto.

En general, las acciones semánticas se escriben con fragmentos de oraciones de un


lenguaje distinto al fuente y al objeto. En este trabajo se utiliza el lenguaje C++ para
escribir acciones semánticas.

20 de 29
Un poco de Historia

Los descubrimientos y las investigaciones

Chomsky [1956] introdujo las gramáticas independientes del contexto como parte
de un estudio sobre lenguajes naturales. La utilización de este tipo de gramáticas para la
especificación de la sintaxis de los lenguajes de programación surgió independientemente.
El lingüista Panini diseñó una notación sintáctica equivalente para especificar las reglas de
la gramática del sánscrito de entre el 400 a.C. y el 200 a.C. (Ingerman [1967]).

En una carta de Knuth [1964], está contenida la propuesta de que BNF, que
comenzó como una abreviatura de Backus Normal Form (forma normal de Backus), se
leyera Backus-Naur Form (forma de Backus-Naur), para reconocer las contribuciones de
Naur como editor del informe de ALGOL 60 (Naur [1963]).

Las definiciones dirigidas por la sintaxis son una forma de definición inductiva, en
la cual la inducción se encuentra en la estructura sintáctica. Como tales, han sido muy
utilizadas en matemática. Su aplicación a los lenguajes de programación se introdujo con
el uso de una gramática para estructurar el informe de ALGOL 60. Poco tiempo después,
Irons [1961] construyó un compilador dirigido por la sintaxis.

El análisis sintáctico descendente recursivo se utiliza aproximadamente desde 1960.


Bauer [1976] atribuye el método a Lucas [1961]. Hoare [1962, pág. 128] describe un
compilador de ALGOL organizado como "un conjunto de procedimientos, cada uno de los
cuales puede procesar una de las unidades sintácticas del informe de ALGOL 60". Foster
[1968] analiza la eliminación de la recursividad por la izquierda de las producciones con
acciones semánticas que no afecten a los valores de los atributos.

McKarthy [1963] abogaba por que la traducción de un lenguaje se basara en una


sintaxis abstracta. En el mismo artículo, McKarthy [1963, pág. 24] dejaba "que el lector se
convenciera por sí mismo" de que una formulación recursiva por el final de la función
factorial es equivalente a un programa iterativo.

Las ventajas de dividir un compilador en una etapa inicial y otra final se analizaron
en un informe del comité de Strong y colaboradores [1958]. El informe acuño el término
UNCOL (del inglés universal computer oriented language, lenguaje orientado a un
computador universal) para un lenguaje intermedio universal. El concepto ha quedado
como un ideal.

Kernighan y Pike [1984] describen en detalle cómo construir un programa de


calculadora de escritorio a partir de un esquema de traducción dirigida por la sintaxis,
utilizando las herramientas para la construcción de compiladores disponibles en el sistema
operativo UNIX.

Las limitaciones impuestas a los aspectos léxicos de un lenguaje suelen estar

21 de 29
determinadas por el ambiente en que se creó el lenguaje. Cuando se diseñó FORTRAN en
1954, las tarjetas perforadas eran un medio común de entrada. En FORTRAN se ignoraron
los espacios en blanco debido en parte a que los perforistas, que preparaban las tarjetas a
partir de notas escritas a mano, tendían a equivocarse al contar los espacios en blanco
(Backus [1981]). La separación en ALGOL 58 de la representación en hardware a partir del
lenguaje de referencia fue un acuerdo alcanzado debido a que un miembro del comité de
diseño insistió: "No, nunca usaré un punto para el signo decimal". (Wegstein [1981]).

Knuth [1973] presenta otras técnicas para manejar la entrada con buffers. Feldman
[1979b] analiza las dificultades prácticas del reconocimiento de componentes léxicos en
FORTRAN 77.

Las expresiones regulares fueron estudiadas por primera vez por Kleene [1956], que
estaba interesado en describir los acontecimientos que se podían representar con el
modelo de autómata finito de actividad nerviosa de McCulloch y Pitts [1943]. La
minimización de los autómatas finitos fue estudiada por primera vez por Huffman [1954]
y Moore [1956]. La equivalencia entre autómatas determinísticos y no determinísticos en
cuanto a su capacidad para reconocer lenguajes fue mostrada por Rabin y Scott [1959].
McNaughton y Yamada [1960] describen un algoritmo para construir un AFD
directamente a partir de una expresión regular, que es el que se implementa en este
trabajo.

Pronto se comprendió que las herramientas para construir analizadores


lexicográficos a partir de especificaciones en forma de expresiones regulares serían útiles
en la implantación de compiladores. En Johnson y otros [1968] se analiza uno de estos
primeros sistemas. LEX, se debe a Lesk [1975], y se ha utilizado para construir
analizadores lexicográficos para muchos compiladores que trabajan bajo UNIX.

Las expresiones regulares y los autómatas finitos se han utilizado para muchas
aplicaciones, además de para la compilación. Muchos editores de texto usan expresiones
regulares para búsquedas dentro del texto. El sistema UNIX tiene tres programas de
búsqueda de propósito general basados en expresiones regulares: grep, egrep y fgrep. El
programa grep no permite unión o paréntesis para agrupar en sus expresiones regulares,
pero si una forma limitada de referencia hacia atrás como en SNOBOL. Actualmente, grep
se encuentra en casi todos los sistemas operativos de computadoras personales. También
se utilizan las expresiones regulares en lenguajes de consultas de bases de datos y en
lenguajes para procesamiento de archivos, como AWK (Aho, Kernighan y Weinberger
[1979]). Jarvis [1976] utilizó expresiones regulares para describir rasgos distintivos en
circuitos impresos.

El muy influyente informe de ALGOL 60 (Naur [1963]) utilizó la forma de Backus


Naur (BNF) para definir la sintaxis de un importante lenguaje de programación. Se
descubrió la equivalencia entre BNF y las gramáticas independientes del contexto, y la
teoría de los lenguajes formales fue objeto de una gran atención en la década de 1960.

Los métodos de análisis sintáctico se hicieron mucho más sistemáticos tras el

22 de 29
desarrollo de las gramáticas independientes del contexto. Se inventaron diversas técnicas
generales para analizar cualquier gramática independiente del contexto. Una de las
primeras es la técnica de programación dinámica descubierta independientemente por
Younger [1967] y Kasami [1965]. Como tesis doctoral, Earley [1970] también desarrolló un
algoritmo de análisis sintáctico universal para todas las gramáticas independientes del
contexto.

Se han empleado muchos métodos distintos de análisis sintáctico en los


compiladores. Los análisis sintácticos por descenso recursivo y predictivo son muy
utilizados en la práctica. Dada su flexibilidad, se utilizó el análisis sintáctico por descenso
recursivo en muchos de los primeros generadores de compiladores como META (Schorre
[1964]) y TMG (McClure [1965]). Pratt [1973] propone un método de análisis sintáctico
descendente por precedencia de operadores.

Las gramáticas LL fueron estudiadas por Lewis y Stearns [1968] y sus propiedades
se desarrollaron en Rosenkrantz y Stearns [1970]. Los analizadores sintácticos predictivos
fueron estudiados a fondo por Knuth [1971]. Lewis, Rosenkrantz y Stearns [1976]
describen el uso de los analizadores sintácticos predictivos en los compiladores. En
Tamagnini [1994] se presenta un generador de tablas para el análisis sintáctico LL(1). Los
algoritmos para convertir gramáticas a la forma LL(1) se introducen en Foster [1968],
Wood [1969], Stearns [1971] y Soisalon-Soininen y Ukkonen [1979].

Las gramáticas y los analizadores sintácticos LR fueron introducidos por primera


vez por Knuth [1965], quien describió la construcción de las tablas de análisis sintáctico LR
canónico. El método LR no resultó práctico hasta que Korenjak [1969] mostró que con él se
podrían producir analizadores sintácticos de tamaño razonable para gramáticas de los
lenguajes de programación. Cuando DeRemer [1969, 1971] inventó los métodos SLR y
LALR, que son más simples que el de Korenjak, la técnica LR se convirtió en el método
elegido para los generadores automáticos de analizadores sintácticos. Hoy en día, los
generadores de analizadores LR son habituales en los entornos de construcción de
compiladores.

La impresión de que el análisis sintáctico descendente permite una mayor


flexibilidad en la traducción resultó ser falsa, ya que Brosgol [1974] demostró que un
esquema de traducción basado en una gramática LL(1) se puede simular durante el
análisis sintáctico LR(1).

Gran parte de la investigación se dedicó a la construcción de analizadores


sintácticos LR. El uso de gramáticas ambiguas en el análisis sintáctico LR se debe a Aho,
Johnson y Ullman [1975] y a Earley [1975]. La eliminación de las reducciones por reglas
simples ha sido estudiada en Anderson, Eve y Horning [1973], Aho y Ullman [1973b],
Demers [1975], Backhouse [1976], Joliat [1976], Pager [1977], Soisalon-Soininen [1980] y
Tokuda [1981].

Watt [1977] utilizó no terminales marcadores para garantizar que los valores de los
atributos heredados aparezcan en una pila durante el análisis sintáctico ascendente. Las

23 de 29
posiciones en los lados derechos de las reglas donde se pueden insertar los no terminales
marcadores sin perder la propiedad LR(1) son estudiadas por Purdom y Brown [1980].

Aho y Johnson [1974] realizan un estudio general del análisis sintáctico LR y


analizan algunos de los algoritmos en que se basa el generador de analizadores sintácticos
YACC, incluido el uso de producciones de error para la recuperación de errores. Aho y
Ullman [1972 y 1973a] dan un tratamiento bastante completo del análisis sintáctico LR y
de sus fundamentos teóricos. La corrección de errores durante el análisis sintáctico es
estudiada por Conway y Maxwell [1963], Moulton y Muller [1967], Conway y Wilcox
[1973], Levy [1975], Tai [1978] y Röhrich [1980].

24 de 29
Bibliografía

Faltan agregar varios libros, pero las utilizadas hasta el momento son las siguientes, por
orden de importancia.

Bibliografía Principal

Alfred Aho - Ravi Sethi - Jeffrey Ullman [1990]. "Compiladores: Principios Técnicas y
Herramientas". Addison-Wesley Iberoamericana.
Sanchis Llorca - Galán Pascual [1986]. "Compiladores: Teoría y Construcción". Paraninfo.
Alfred Aho - Jeffrey Ullman [1977]. "Principles of Compiler Design". Addison-Wesley.
Manuales del Programador del Sistema Operativo XENIX. Microsoft Corp.
Bjarne Stroustrup [1992]. "The C++ Programming Language - 2nd Edition". Addison-
Wesley.
Manuales del Programador del Borland C++ 4.02 para Windows. Borland Intl. Inc.
Manuales del Programador del Borland C++ 2.0 para OS/2. Borland Intl. Inc.
Manuales del Programador del Borland C++ 4.5 para Windows. Borland Intl. Inc.
Manuales del Programador de Paradox 4.5 para Windows. Borland Intl. Inc.
Manuales del Programador de dBase V para Windows. Borland Intl. Inc.
"Reference Guide" del Borland Visual Solutions Pack Volume 1 para Windows. Capítulo
51: "SQL Primer", págs. 665 a 674. Borland Intl. Inc.
J. Tamagnini [1994]. "Un generador de analizadores sintácticos recursivos descendentes".
Tesis de Grado. Universidad Católica de Santiago del Estero.
Allen Holub [1990]. "Compiler Design in C". Prentice Hall.
Christian Nique [1985]. "Introducción metódica a la gramática generativa". Ediciones
Cátedra.
Bjarne Stroustrup [1994]. "The design and Evolution of C++". Addison Wesley. Págs. 337
a 381.

Bibliografía Secundaria (por orden alfabético)

A. V. Aho y S. C. Johnson [1974]. "LR Parsing". Computing Surveys 6:2, págs 99-124.
A. V. Aho, S. C. Johnson y J. D. Ullman [1977]. "Code generation for expressions with
common subexpressions". Journal ACM 14:1, págs. 146-160.
A. V. Aho, B. W. Kernighan y P. J. Weinberger [1979]. "AWK - a pattern scanning and

25 de 29
processing language". Software - Practice and Experience 9:4, págs. 267-280.
A. V. Aho y J. D. Ullman [1972]. "The Theory of Parsing, Translation and Compiling, Vol
I: Parsing". Prentice-Hall.
A. V. Aho y J. D. Ullman [1973a]. "The Theory of Parsing, Translation and Compiling, Vol
II: Compiling". Prentice-Hall.
A. V. Aho y J. D. Ullman [1973b]. "A technique for speeding up LR(k) parsers". SIAM J.
Computing 2:2, págs. 106-127.
T. Anderson, J. Eve y J. J. Horning [1973]. "Efficient LR(1) Parsers". Acta Informatica 2:1,
págs. 12-39.
R. C. Backhouse [1976]. "An alternative aproach to the improvement of LR parsers". Acta
Informatica 6:3, págs. 277-296.
J. W. Backus [1981]. "Transcript of presentation on the history of Fortran I, II and III". En
Wexelblat [1981], págs 45-66.
F. L. Bauer [1976]. "Historical remarks on compiler construction". en Bauer y Eichel [1976],
págs 603-621. Suplemento de Ershov. A. P. págs 622-626.
F. L. Bauer y J. Eichel [1976]. "Compiler Construction: An Advanced Course". 2da
Edición. Lecture Notes in Computer Science 21, Springer-Verlag, Berlín.
B. M. Brosgol [1974]. "Deterministic Translation Grammars". Tesis doctoral, TR 3-74.
Universidad de Harvard, Cambridge, Massachusetts.
Noam Chomsky [1956]. "Three models for the description of language". IRE Trans. on
Information Theory IT-2:3, págs. 113-124.
M. E. Conway y W. L. Maxwell [1963]. "CORC - the Cornell computing language". Comm.
ACM 6:6, págs. 317-321.
M. E. Conway y T. R. Wilcox [1973]. "Design and implementation of a diagnostic compiler
for PL/I". Comm. ACM 16:3, págs. 169-179.
A. J. Demers [1975]. "Elimination of single productions and merging of nonterminal
symbols in LR(1) grammars". Journal of Computer Languages 1:2, págs. 105-119.
F. DeRemer [1969]. "Practical Translators for LR(k) Languages". Tesis doctoral, M.I.T.,
Cambridge, Massachusetts.
F. DeRemer [1971]. "Simple LR(k) grammars". Comm. ACM 14:7, págs. 453-460.
J. Earley [1970]. "An efficient context-free parsing algorithm". Comm. ACM 13:2, págs. 94-
102.
J. Earley [1975]. "Ambiguity and precedence in syntax description". Acta Informática 4:2,
págs. 183-192.
S. I. Feldman [1979]. "Implementation of a portable Fortran 77 compiler using modern
tools". ACM SIGPLAN Notices 14:8, págs 255-265.
J. M. Foster [1968]. "A syntax improving program". Computer Journal 11:1, págs. 31-34.
C. A. R. Hoare [1962]. "Report on the Elliott ALGOL translator". Computer Journal 5:2,

26 de 29
págs. 127-129.
D. A. Huffman [1954]. "The synthesis of sequential machines". J. Franklin Inst. 257, págs.
3-4, 161, 190, 275-303.
P. Z. Ingerman [1967]. "Panini-Backus form suggested". Comm. ACM 10:3, pág. 137.
E. T. Irons [1961]. "A syntax directed compiler for ALGOL 60". Comm. ACM 4:1, págs 51-
55.
J. F. Jarvis [1976]. "Feature recognition in line drawings using regular expressions". Proc.
3rd Intl. Joint Conf. on Pattern Recognition, págs. 189-192.
W. L. Johnson, J. H. Porter, S. I. Ackley y D. T. Ross [1968]. "Automatic generation of
efficient lexical processors using finite state techniques".
M. L. Joliat [1976]. "A simple technique for partial elimination of unit productions from
LR(k) parser tables". IEEE Trans. on Computers C-25:7, págs. 763-764.
T. Kasami [1965]. "An efficient recognition and syntax analysis algorithm for context-free
languages". AFCRL-65-758, Air Force Cambridge Research Laboratory, Bedford,
Massachusetts.
B. W. Kernigan y R. Pike [1984]. "The UNIX Programming Environment". Prentice-Hall.
S. C. Kleene [1956]. "Representation of events in nerve nets". en Shannon y McCarthy
[1956], págs. 3-40.
D. E. Knuth [1964]. "Backus Normal Form vs. Backus Naur Form". Comm. ACM 7:12,
págs. 735 y 736.
D.E. Knuth[1965]. "On the translation of languages from left to right". Information and
Control 8:6, págs. 607-639.
D.E. Knuth [1971]. "Top-down syntax analysis". Acta Informatica 1:2, págs. 79-110.
D.E. Knuth [1973]. "The Art of Computer Programming: Vol 1 2nd Edition, Fundamental
Algorithms", Addison-Wesley.
A. J. Korenjak [1969]. "A practical method for constructing LR(k) processors". Comm
ACM 12:11, págs. 613-623.
M. E. Lesk [1975]. "Lex - a lexical analyzer generator". Computing Science Technical
Report 39, AT&T Bell Laboratories.
J. K. Levy [1975]. "Automatic correction of syntax errors in programming languages". Acta
Informatica 4, págs. 271-292.
P. M. Lewis II, D. J. Rosenkrantz y R. E. Stearns [1976]. "Compiler Design Theory".
Addison-Wesley.
P. M. Lewis II y R. E. Stearns [1968]. "Syntax-directed transduction". J. ACM 15:3, págs.
465-488.
P. Lucas [1961]. "The structure of formula translators". Elektronische Rechenanlagen 3,
págs 159-166.
J. McCarthy [1963]. "Towards a mathematical science of computation". Information

27 de 29
Processing 1962, págs 21-28.
R. M. McClure [1965]. "TMG - a syntax-directed compiler". Proc. 20th ACM National
Conf., págs. 262-274.
W. S. McCullough y W. Pitts [1943]. "A logical calculus of the ideas immanent in nervous
activity". Bulletin of Math. Biophysics 5, págs. 115-133.
R. McNaughton y H. Yamada [1960]. "Regular expressions and state graphs for
automata". IRE Trans. on Electronic Computers EC-9:1, págs. 38-47.
E. F. Moore [1956]. "Gedanken experiments in sequential machines". En Shannon y
McCarthy [1956], págs 129-153.
P. G. Moulton y M. E. Muller [1967]. "DITRAN - a compiler emphasizing diagnostics".
Comm. ACM 10:1, págs. 52-54.
P. Naur [1963]. "Revised report on the algorithmic language ALGOL 60". Comm. ACM 6:1,
págs. 1-17.
D. Pager [1977]. "Eliminating unit productions from LR(k) parsers". Acta Informatica 9,
págs. 249-268.
V. R. Pratt [1973]. "Top-down operator precedence". ACM Symposium on Principles of
Programming Languages, págs. 41-51.
P. Purdom y C. A. Brown [1980]. "Semantic routines and LR(k) parsers". Acta Informatica
14:4, págs. 299-315.
M. O. Rabin y D. Scott [1959]. "Finite automata and their decision problems". IBM Journal
of Research and Development 3:2, págs. 114-125.
J. Röhrich [1980]. "Methods for the automatic construction of error correcting parsers".
Acta Informatica 13:2, págs. 115-139.
D. J. Rosenkrantz y R. E. Stearns [1970]. "Properties of Deterministics top-down
grammars". Information and Control 17:3, págs. 226-256.
D. V. Schorre [1964]. "Meta-II: a syntax-oriented compiler writing language". Proc. 19th
ACM National Conf., DI., 3-1 - DI. 3-11.
C. Shannon y J. McCarthy [1956]. "Automata Studies". Princeton University Press.
E. Soisalon-Soininem [1980]. "On the space optimizing effect of eliminating single
productions from LR parsers". Acta Informatica 12, págs. 157-174.
E. Soisalon-Soininem y E. Ukkonen [1979]. "A method for transforming grammars into
LL(k) form". Acta Informatica 12, págs. 339-369.
R. E. Stearns [1971]. "Deterministic top-down parsing". Proc. 5th Annual Princeton Conf.
on Information Sciences and Systems, págs. 182-188.
J. Strong, J. H. Wegstein, A. Tritter, J. Olsztyn, O. Mock y T. Steel [1958]. "The problem
of programming communication with changing machines: a proposed solution". Comm.
ACM 1:8

28 de 29
(agosto), págs 12-18. Segunda parte 1:9 (setiembre), págs 9-15. Informe del Comité sobre
lenguas universales.
K. C. Tai [1978]. "Syntactic error correction in programming languages". IEEE Trans.
Software Engineering SE-4:5, págs. 414-425.
T. Tokuda [1981]. "Eliminating unit reductions from LR(k) parsers using minimum
contexts". Acta Informatica 15, págs. 447-470.
D. A. Watt [1977]. "The parsing problem for affix grammars". Acta Informatica 8, págs. 1-
20.
J. H. Wegstein [1981]. "Notes on ALGOL 60". en Wexelblat [1981], págs. 126-127.
R. L. Wexelblat [1981]. "History of Programming Languages". Academic Press. New
York.
D. Wood [1969]. "The Theory of left factored languages". Computer Journal 12:4, págs.
349-356.
D. H. Younger [1967]. "Recognition and parsing of context-free languages in time n3 ".
Information and Control 10:2, págs. 189-208.

29 de 29

También podría gustarte