Especificación
Extracción de Requisitos
De entre todos los requisitos enumerados en la descripción del Lenguaje, se extraen a continuación los correspondientes al analizador sintáctico.
Aspectos generales:
- La sección
DATA
deberá aparecer obligatoriamente antes de la secciónCODE
y cada una de ellas solo puede aparecer una vez. - Tanto las sentencias como las definiciones terminan con un punto y coma
;
.
Sección de Datos:
- En la sección
DATA
se realizan las definiciones de variables (no puede haber definiciones en la secciónCODE
). - No es obligatorio que se definan variables pero, en cualquier caso, tiene que aparecer la palabra reservada
DATA
. - Las variables solo pueden ser de tipo int (2 bytes) o float (4 bytes). Nótese que de este requisito sólo es relevante para esta fase el hecho de que hay dos tipos, pero no su tamaño.
- En cada definición sólo puede haber una variable (por ejemplo, no se permite
int a,b;
)
Sección de Código:
- En la sección
CODE
aparecerán las sentencias del programa (no puede haber sentencias en la secciónDATA
). - Un programa puede no tener ninguna sentencia pero, en cualquier caso, es obligatorio que aparezca la palabra reservada
CODE
. - En la sección
CODE
puede haber dos tipos de sentencias: escritura (print
) y asignación. - Las expresiones podrán estar formadas por literales enteros, literales reales y variables, pudiendo combinarse todos ellos mediante operadores aritméticos (
+
,-
,*
y/
). Los operadores tendrán la prioridad y asociatividad habitual. - Se podrán agrupar expresiones mediante paréntesis.
Estos requisitos se pueden observar en el programa de ejemplo:
DATA
float price;
int width;
int height;
float total;
CODE
price = 9.95;
total = (price - 3.0) * 1.18;
print total;
width = 10; height = 20;
print 0 - width * height / 2;
Especificación con Gramática Libre de Contexto
A continuación hay que modelar los requisitos anteriores de manera formal con un metalenguaje. En este tutorial se usará como metalenguaje las gramáticas libres de contexto (GLC). Los requisitos extraídos anteriormente, expresados en una GLC mediante BNF, son:
program ⟶ 'DATA' varDefinitions* 'CODE' statements*
varDefinition ⟶ type IDENT ';'
type ⟶ 'float' | 'int'
statement ⟶ 'print' expression ';'
| expression '=' expression ';'
expression ⟶
expression '+' expression
| expression '-' expression
| expression '*' expression
| expression '/' expression
| '(' expression ')'
| IDENT
| INT_LITERAL
| FLOAT_LITERAL
A la hora de construir una gramática es muy recomendable que, a la hora de crear cada regla, se plantee ésta como una y sólo una de las tres construcciones básicas:
- Secuencias. Indican el orden el que deben aparecer los símbolos de la estructura.
- Listas. Indican que la estructura se forma repitiendo otra estructura.
- Composiciones. En una composición se definen las formas atómicas (básicas) de la estructura para luego formar estructuras mayores que se apoyan en las primeras.
La gramática anterior se ha construido siguiendo estas pautas:
- Se ha definido programa como una secuencia que indica que lo primero son las variables y luego las sentencias. Otros ejemplos de la construcción secuencia son los no-terminales variable, tipo y sentencia, que indican respectivamente cómo se define una variable y cómo se ordenan una escritura y una asignación.
- Los no-terminales variables y sentencias se han definido mediante listas (en este caso mediante el patrón de cero o más elementos sin separadores).
- Por último, expression es una composición en la que se definen sus casos atómicos (identificadores y literales) y luego se define cómo se forman otras expresiones mayores en función de las anteriores.
La especificación anterior puede hacerse también en EBNF, simplificando así alguna de las reglas (concretamente las listas):
program ⟶ 'DATA' varDefinition* 'CODE' statement*
varDefinition ⟶ type IDENT ';'
type ⟶ 'float' | 'int'
statement ⟶ 'print' expression ';'
| expression '=' expression ';'
expression ⟶
expression ('+' | '-') expression
| expression ('*' | '/') expression
| '(' expression ')'
| IDENT
| INT_LITERAL
| FLOAT_LITERAL
Para acabar, nótese que los requisitos sintácticos expresados en el metalenguaje no solo son más precisos, sino que además son mucho más concisos; solo hay que comparar lo que ocupan los requisitos en BNF/EBNF y lo que ocupaban en lenguaje natural en el apartado anterior.
Aclaración sobre la Asignación
Nótese cómo se ha definido la asignación en la solución anterior:
statement ⟶ expression '=' expression ';'
En realidad, en este lenguaje tan sencillo, hubiera sido más correcto definir la asignación de la siguiente manera, ya que lo único que puede aparecer a la izquierda de una asignación es una variable:
statement ⟶ ‘IDENT’ '=' expression ';'
El motivo por el que se ha puesto una expresión a la izquierda de la asignación en lugar de una variable es meramente didáctico. Aunque en este lenguaje no hace falta, así es como habrá que hacerlo a poco que el lenguaje se amplíe, ya que, a la izquierda de una asignación, además de una variable, pueden aparecer accesos a arrays, estructuras, etc. Se muestra así cómo sería una versión más real de la representación de una asignación, lo cual permitirá en posteriores capítulos explicar aspectos adicionales.