Gramática 1 : <program> ::= begin <dcl train> ; <stm train> end 2 : <dcl train> ::= <declaration> 3 : | <declaration> ; <dcl train> 4 : <stm train> ::= <statement> 5 : | <statement> ; <stm train> 6 : <declaration> ::= <mode> <idlist> 7 : <mode> ::= bool 8 : | int 9 : | ref <mode> 10 : <idlist> ::= <id> 11 : | <id> , <idlist> 12 : <statement> ::= <asgt stm> 13 : | <cond stm> 14 : | <loop stm> 15 : | <transput stm> 16 : <asgt stm> ::= <id> := <exp> 17 : <cond stm> ::= if <exp> then <stm train> fi 18 : | if <exp> then <stm train> else <stm train> fi 19 : <loop stm> ::= while <exp> do <stm train> end 19A: | repeat <stm train> until <exp> 20 : <transput stm> ::= input <id> 21 : | output <exp> 22 : <exp> ::= <factor> 23 : | <exp> + <factor> 24 : | <exp> - <factor> 25 : <factor> ::= <primary> 26 : | <factor> * <primary> 27 : <primary> ::= <id> 28 : | <constant> 29 : | ( <exp> ) 30 : | ( <compare> ) 31 : <compare> ::= <exp> = <exp> 32 : | <exp> <= <exp> 33 : | <exp> > <exp> 34 : <constant> ::= <bool constant> 35 : | <int constant> 36 : <bool constant>::= true 37 : | false 38 : <int constant> ::= <number> 39 : <number> ::= <digit> 40 : | <number> <digit> 41 : <id> ::= <letter> 42 : | <id> <letter> 43 : <digit> ::= 0 | 1 | ... | 9 53 : <letter> ::= A | B | ... | Z
begin
int X, Y, Z;
input X;
Y := 1;
Z := 1;
if (1<=X) then
while (Z<=X) do
Y := Y*Z;
Z := Z+1
end
fi;
output Y
end
Este programa lee un valor entero positivo y calcula e imprime su factorial. El programa declara las variables enteras X, Y, Z. Toda variable ASPLE debe recibir un valor, por asignación o "input", antes de poder usarse en una expresión. Una variable declarada
int A
es una referencia a un entero, y contrasta con otra declarada
ref int B
que llega al entero a través de un puntero. Diremos que el "modo primitivo" de B es entero. Ejecutar la asignación:
B := A
asigna a B un puntero a A, que a su vez se refiere directamente a un valor entero. Ejecutar la asignación:
A := 7
no cambia el valor de B, que sigue siendo un puntero a A, pero sí cambia el valor de A, al que B se refiere indirectamente. Para obtener el valor al que se refiere B (el valor primitivo de B), hay que "desreferenciar" dos veces.
Para evaluar una expresión como A+B, los dos identificadores se desreferencian las veces necesarias hasta llegar a su valor primitivo, que es el que se opera. + y * entre enteros representa la suma y el producto, entre booleanos representa OR y AND. = y <= operan sólo entre enteros y dan un resultado booleano. Una expresión entre paréntesis siempre da como resultado un valor primitivo.
En una asignación, el modo del identificador de la izquierda debe ser compatible con el de la expresión de la derecha. Para ser compatible, han de cumplirse dos condiciones:
Por ejemplo, dadas las declaraciones:
int A;
bool B;
ref int C;
ref ref int D;
son válidas las asignaciones:
A := 16; nl=1, nr=0
C := D; nl=2, nr=3
No son válidas las asignaciones:
A := B; viola la primera condición
C := 20; nl=2, nr=0
D := A; nl=3, nr=1
El proceso de la asignación es como sigue:
Quedan abiertas las siguientes cuestiones (cada compilador puede resolverlas como se desee):