Story Transcript
Sintaxis y Semántica del Lenguaje
Gramáticas La tarea de proveer una descripción bien concisa y entendible de un lenguaje de programación es difícil pero esencial para el éxito de un lenguaje. Uno de los problemas en describir un lenguaje es la diversidad de gente que debe comprender esas descripciones. Las personas que implementan obviamente deben ser capaces de determinar cómo se forman las expresiones, sentencias y unidades de programas y también el orden de ejecución de los mismos. La dificultad del trabajo que tiene esta gente (los implementadores) está determinado en parte por la claridad y complejidad de las descripciones del lenguaje. La sintaxis de un lenguaje de programación describe la forma correcta en la cual las sentencias, expresiones y unidades de programa se deben escribir, mientras que la semántica denota el significado de esas sentencias, expresiones y unidades de programa. Por ejemplo la sintaxis de una sentencia Pascal if then es: if then La semántica de esta sentencia es que si el valor actual de la condición es verdadero, se ejecutará . Describir sintaxis es más fácil que describir semántica, ya que existen notaciones aceptadas universalmente para la descripción de sintaxis y no así de semánticas. En la definición de un lenguaje de programación la sintaxis usualmente se expresa en BNF (Backus- Naur Form) y la semántica está expresada en lenguaje natural (español, inglés, etc). BNF es un ejemplo de un metalenguaje, es decir, un lenguaje usado para definir otros lenguajes. Algol 60 fue el primer lenguaje que utilizó BNF para su descripción sintáctica. Una gramática consiste de un conjunto de no-terminales, terminales y una serie de reglas de producción. Un no-terminal está definido en una regla de producción, mientras que un terminal es un símbolo del lenguaje que se está definiendo. En una regla de producción el no-terminal (que aparece en la parte izquierda) está definido en términos de una secuencia de no-terminales y terminales (que se encuentran en la parte derecha ) Ejemplo: ::= 0|1|2|3|4|5|6|7|8|9 ::= a|b|c……………|x|y|z ::=|| En BNF, un no-terminal se escribe entre < >, el símbolo ::= significa “se define como” y el símbolo “|” significa “o”. Estas reglas definen como uno de los símbolos 0, 1 al 9; como una letra minúscula e se define como una única letra, un identificador seguido de una letra o un identificador seguido de un dígito. Así, el identificador “ab1” puede ser derivado de como sigue:
1
Sintaxis y Semántica del Lenguaje
> a a b a b 1 En cada etapa, el no-terminal de más a la izquierda es reemplazado por la parte derecha de una de sus reglas de producción, la secuencia de terminales y no-terminales producidos en cada etapa en una derivación se conoce como formas sentenciales. La forma sentencia final (que ya no contiene símbolos no-terminales) se conoce como una sentencia. La estructura de una derivación se muestra mejor en un árbol de derivación . El árbol de derivación que muestra cómo ab1 de es: | | | 1 | | b | a Un lenguaje de programación completo se define comenzando con un símbolo noterminal tal como , conocido como start symbol (símbolo inicial) y desde el cual todos los posibles programas pueden ser derivados. En la práctica, los árboles de derivación se crean de dos formas posibles. En un esquema top-down, la sentencia requerida se deriva del símbolo inicial tal cual como hicimos en el ejemplo (ab1). En un esquema bottom-up, el punto de partida es la sentencia requerida, la cual es reducida al símbolo inicial reemplazando las partes derechas por sus correspondientes partes izquierdas de las reglas de producción. Ambos esquemas se utilizan en la fase de análisis sintáctico de muchos compiladores. Una gramática que define un lenguaje de programación tiene un número finito de reglas de producción, pero como las reglas de producción contienen recursión, es posible generar infinitos programas posibles. Ejemplo: ::= Cuando se incluye recursión en las reglas de producción hay que tener cuidado. Hay que asegurarse que la recursión termine. Una regla de producción tal como la anterior se dice que es recursiva a izquierda. Existen definiciones similares pero recursivas a derecha.
2
Sintaxis y Semántica del Lenguaje Ambigüedad Un problema surge cuando se definen gramáticas ambiguas. Esto es, una gramática que permite diferentes interpretaciones para la misma sentencia. Ejemplo: Veamos la siguiente definición para la sentencia condicional if ::= if then | if then else ::= | begin end La siguiente sentencia condicional tiene dos diferentes árboles de derivación: if then if then else árbol 1 ! if then | | if then else árbol 2 | if then else | | if then Como hay dos interpretaciones, la gramática es ambigua. Una solución podría ser que la sentencia anterior se escriba: if then begin if then else end ó if then begin if then end else Dependiendo de la interpretación que se desee. Otra solución sería agregando un cierre del if (ya sea con un ; o con un endif) 3
Sintaxis y Semántica del Lenguaje
Ejemplo: Gramática para una sentencia de asignación ::= := ::= A| B| C |D (también podría ser la definición de identificador anterior) ::= + | * | ¿Qué pasa con esta gramática? ¿Es correcta? Veamos el árbol de derivación de la siguiente sentencia. A:= B + C * D árbol 1 | := | | A + | | * | | | B | | C D árbol 2 | := | | A * | | + | | | D | | B C En general la ambiguedad sintáctica de las estructuras de un lenguaje es un problema, debido a que los compiladores basan la semántica de esas estructuras en su estructura sintáctica. Si una estructura del lenguaje tiene más de un árbol de derivación, entonces, el significado de la estructura no podría determinarse unívocamente. ¿Cómo desambiguamos la gramática anterior? ::= := ::= A| B| C| D ::= + | ::= * | 4
Sintaxis y Semántica del Lenguaje
Ejercicio: Hacer el árbol de derivación para la expresión anterior para ver que es único. Pensar: ¿Cómo se modificaría esta gramática para incluir paréntesis en las expresiones? Otras notaciones: Existen otras formas de describir gramáticas (otras notaciones). Por ejemplo, la siguiente sentencia: ::= + Se escribiría: expà exp ‘+’ término Además, existe otra forma más gráfica de representar gramáticas que son diagramas sintácticos. Son utilizados por los lenguajes Pascal y Ada. La simbología es la siguiente: No-terminales
terminales Ejemplo: El diagrama sintáctico para una expresión sería:
exp término término
+
término factor factor
*
/ factor
identificador
5
Sintaxis y Semántica del Lenguaje
Ejercicio: Escribir una gramática para verificar la declaración de variables de un programa Pascal. Resolución: Básicamente la sentencia es: var a:integer; b,c:real; d:alumno; en gral puede ser una declaración o un conjunto separados por “;”. Y una declaración puede ser un identificador o un conjunto separados por “,”: ::= var ::= | ; ::= : ::= |, ::= Se definió en la teoría!!! ::= ………..no hacerlo, en este caso para acá Las anteriores son sólo reglas de producción de la gramática. La gramática se compone además de reglas de: G={ N, T, P, S} donde: T = {var, “,” , “;” , : , etc……} N = { , , , , , } P = { ::= var ::= | ; ::= : ::= |, ::= Se definió en la teoría!!! ::= ………..no hacerlo, en este caso para acá } S = {}
6