Está en la página 1de 49

Guía de Programación

User RPL
Por: Mario de Lama y
José M. Alarcón Aguín
malar@arrakis.es
http://users.servicios.retecal.es/mdelama/
Guía de programación User RPL

Tabla de contenidos.

Tabla de contenidos..........................................................................................................................3
1. Introducción..................................................................................................................................5
2. Cómo crear, guardar y editar un programa.......................................................................6
3. Las variables globales y locales..........................................................................................8
3.1. Manejo en la pila:..................................................................................................................8
3.2. Variables globales:................................................................................................................8
3.3. Variables locales:...................................................................................................................9
3.4. Variables locales compiladas:...............................................................................................9
4. Tipos de tests en la hp48.....................................................................................................12
4.1. Las Banderas (Flags)...........................................................................................................12
4.2. Las funciones de comparación............................................................................................12
4.3. Las funciones lógicas..........................................................................................................14
4.3.1. Argumentos reales........................................................................................................14
4.3.2. Algebraicos:.............................................................................................................14
4.3.3. Cadenas....................................................................................................................15
4.3.4. Binarios....................................................................................................................16
4.4. Comandos TYPE y VTYPE................................................................................................16
5. Estructuras condicionales...................................................................................................18
5.1. Estructura IF ... THEN ... END...........................................................................................18
5.2. Estructura IF ... THEN ... ELSE ... END.............................................................................19
5.3. Estructura CASE ... THEN ... END.....................................................................................19
5.4. Estructura IFERR …THEN ... END...................................................................................20
5.5. Estructura IFERR ...THEN ... ELSE ...END.......................................................................20
5.6. Comando IFT.......................................................................................................................21
5.7. Comando IFTE....................................................................................................................21
6. Estructuras iterativas............................................................................................................22
6.1. Estructuras Definidas:........................................................................................................22
6.1.1. Estructura START ... NEXT...............................................................................22
6.1.2. Estructura START ... STEP................................................................................22
6.1.3. Estructura FOR ... NEXT.....................................................................................23
6.1.4. Estructura FOR ... STEP...............................................................................................24
6.2. Estructuras Indefinidas:.......................................................................................................24
6.2.1. Estructura DO ... UNTIL ... END.................................................................................24
6.2.1.1. Como salir de un bucle definido cuando lo deseemos.........................................25
6.2.2. Estructura WHILE ... REPEAT ... END......................................................................25
6.2.2.1. Bucles animados....................................................................................................26
7. Nombres prohibidos de variables. Cómo ocultar variables y directorios.
Directorios temporales.............................................................................................................28
8. Depuración de errores en programas...............................................................................32
9. Menús de usuario, GROB, WAIT y KEY......................................................................33
10. La entrada de datos en los programas ..........................................................................38

3
Guía de programación User RPL

10.1. Toma de datos desde la pila...............................................................................................38


10.2. PROMPT...........................................................................................................................38
10.3. CLLCD DISP FREEZE HALT.........................................................................................39
10.4. INPUT...............................................................................................................................40
10.5. INFORM............................................................................................................................41
10.6. CHOOSE...........................................................................................................................44
11. La RECURSIVIDAD en Programación.......................................................................46
11.1. Recursividad......................................................................................................................46

4
Guía de programación User RPL

1. Introducción.

Hay diversos tipos de lenguajes de programación para la hp4x, el que ahora abordamos es el de
más alto nivel. Esto quiere decir que es el más amigable y él más lento ya que los comandos de
este lenguaje realizan comprobaciones para ver si los argumentos sobre los que se aplica son
correctos. Además del User RPL existen el System RPL y el ML (Machine Languaje) entre otros.
El de más bajo nivel es el ML y por ello es el más rápido y engorroso. Asumo mi ignorancia y
confieso que no tengo ni idea de él, sólo sé que trabaja directamente sobre el procesador de la HP
y poco más. En general suele bastar con programar en User, si el algoritmo es bueno la rapidez
también; cuando se necesite que una rutina sea rápida podemos implementarla en System y va
que chuta. Si el algoritmo es malo ya puedes programar en código máquina que te va a dar igual.

A partir de ahora todo lo que se diga se refiere al lenguaje User RPL salvo que se diga lo
contrario.

5
Guía de programación User RPL

2. Cómo crear, guardar y editar un programa.

Para empezar por el principio hay que decir que un programa es todo aquello que en la
calculadora empieza por \<< y termina en \>>

Todos los caracteres precedidos por la barra "\" son caracteres de la HP que o tienen
equivalente en el PC y se traducen así. Puedes ver la tabla de equivalencias en la Pág. 27-17
del manual de la HP48 G o en la 663 del de la HP48 S.

Por ejemplo \<< 2 DUP * \>> es un programa que al ejecutarse multiplica 2 por 2 y pone 4 en el
nivel 1: de la pila. Como es un rollo hacer un programa cada vez que queremos multiplicar 2 por
2, lo mejor es que lo hagamos a mano. Si la cosa se complica y necesitamos a menudo elevar 2 al
cuadrado y el resultado multiplicarlo por el logaritmo neperiano de una variable "X" ya nos va
interesando hacer un programilla que en este caso será \<< LN 2 DUP ^ * \>>. Si colocamos la
variable "X" en el nivel 1: de la pila y a continuación escribimos y ejecutamos el programa
anterior vemos que en primer lugar se obtiene el logaritmo de "X", a continuación el programa
coloca un 2 en el nivel 1: de la pila colocando el logaritmo en el nivel 2: para seguidamente
duplicar con DUP el nivel 1:. Ahora tenemos en la pila lo siguiente

4:
3: LN "X"
2: 2
1: 2

El siguiente comando del programa "^" nos eleva el objeto del nivel 2: a la potencia expresada en
el nivel 1: (A partir de ahora expresaré siempre los niveles con su índice seguido de dos puntos
sin citar expresamente que se trata de un nivel de la pila). Tendremos ahora:

4:
3:
2: LN "X"
1: 4

Finalmente se multiplica 2: por 1: obteniendo en 1: el ansiadísimo resultado. Si cada vez que


deseáramos hacer esta cuenta tuviésemos que escribir el programa nos iba a salir cara la HP y
sería mejor pasarnos a la CASIO. Previsoramente se ha creado un método para guardar el
programa y ejecutarlo cada vez que lo deseemos sin necesidad de teclearlo de nuevo. Lo primero
que hemos de hacer es escribir el programa comenzando por el símbolo \<< para lo que
presionamos la tecla malva de desplazamiento a la izquierda y a continuación la tecla "-". La
calculadora nos crea el símbolo de inicio y de fin así que sólo tenemos que escribir el código
presionando ENTER al final tras lo que obtenemos el programa en 1:. Ahora debemos guardarlo
en una variable para ello escribimos el nombre que deseemos entre comillas simples (el símbolo
que aparece en la 3ª fila 1ª columna de las teclas) presionando a continuación STO (a la derecha
de la tecla anterior). Los nombres tienen que ser los permitidos por la calculadora, puedes ver las
restricciones en la Pág. 5-6 de la Guía de Usuario. Si ahora vamos al menú VAR (presionando la
tecla de la 2ª fila 4ª columna) vemos que nos aparecen las tres o cuatro primeras letras del
nombre de nuestro programa en el menú. Para ejecutarlo pondremos el valor de la variable "X"
en 1: presionando a continuación la tecla de menú correspondiente. Así de sencillo.

6
Guía de programación User RPL

Presionar ENTER mientras escribimos el programa significa compilar el código, esto es,
traducirlo para que lo entienda la calculadora (presionar ON significa tirar todo lo escrito hasta
ahora, cuidado que no hay pregunta de confirmación, el trabajo se pierde). Hay dos formas de
ejecutar los programas: Compilar el código o interpretarlo. Un compilador traduce la totalidad del
programa a código binario que es el único que entienden todos estos artilugios electrónicos, de
esta forma cuando queramos ejecutarlo va más rápido ya que las instrucciones no deben
traducirse. Por contra un intérprete tiene que traducir instrucción tras instrucción cada vez que
ejecutamos el programa. Es fácil saber que hay un compilador interno asociado a ENTER ya que
si metemos la pata en algo al escribir el programa la calculadora nos avisa con un pitido durante
la compilación deteniéndose esta con el cursor en una posición cercana al error. Naturalmente no
puede avisarnos de todos los errores así que hay que tener cuidado al escribir.

Si queremos editar el programa para mejorarlo o modificarlo sólo tenemos que colocar su código
en 1: (presionando la tecla verde de desplazamiento a la derecha y luego la tecla del menú VAR
en el que está nuestro programa) y dar al cursor con la flecha hacia abajo. Modificamos lo que
queremos y presionamos ENTER de nuevo. Otra forma algo más engorrosa, bajo mi punto de
vista, es poner el nombre del programa en 1: (escribiéndolo entre ' ' o presionando ' y a
continuación la tecla de la variable del programa) y ejecutando EDIT a continuación (tecla
desplazada a la izquierda a la derecha de ENTER).

7
Guía de programación User RPL

3. Las variables globales y locales.

Cuando se ejecutan los programas tenemos diversas alternativas para guardar y manipular los
argumentos que precisan los comandos:

3.1. Manejo en la pila:

Es la alternativa más rápida de todas, aceleramos de forma significativa la ejecución del


programa. Debemos dejar los datos en el nivel apropiado y tomarlos de allí cuando se precisen.
Tiene el gran inconveniente de que los programas se hacen muy difíciles de leer y a la vuelta de
unas horas nos es difícil recordar que hay en cada momento en la pila. Además el programa suele
ocupar algo más ya que para manipular los datos debemos utilizar más comandos (los que
aparecen en la Pág. 3-11 de la Guía de Usuario) que cuando usamos variables.

3.2. Variables globales:

Son las que aparecen en el menú VAR de la calculadora, el propio programa es una variable en el
momento en que lo guardamos en este menú con STO. Para crear estas variables desde un
programa ponemos en 2: el objeto a guardar y en 1: el nombre deseado, a continuación
ejecutamos STO. Para borrarlas ponemos el nombre en 1: y ejecutamos PURGE, esto conlleva
añadir un tiempo significativo a la ejecución del programa. Tienen los inconvenientes de ser más
lentas que las locales y que debemos eliminarlas tras haberlas creado, si queremos recuperar la
memoria que ocupan. Normalmente cuando termina el programa ya no valen de nada y sólo
ocupan espacio y aumentan el menú VAR. Si no las borra el programa obligaremos al usuario a
borrarlas él mismo si quiere recuperar su menú VAR original. Un ejemplo sencillo sería:
En 1: debemos tener al iniciar el programa un objeto que no de error al aplicarle el comando LN

\<<
'X' @ Colocamos el nombre de la variable global en 1:
STO @ Almacenamos el contenido de 2: en la variable X
2 @ Colocamos un 2 en la pila
DUP @ Lo duplicamos
^ @ Elevamos 2: a la potencia indicada en 1:
X @ Recuperamos la variable X en 1:
LN @ Hallamos su logaritmo
* @ Multiplicamos 2: por 1:
'X' @ Colocamos el nombre de la variable en la pila
PURGE @ Borramos la variable
\>>

Vemos que para recuperar el contenido de una variable sólo tenemos que poner en la pila su
nombre sin delimitadores. Otra versión de este programa sería:

\<<
'X' @ Colocamos el nombre de la variable global en 1:
STO @ Almacenamos el contenido de 2: en la variable X
2 @ Colocamos un 2 en la pila
SQ @ Lo elevamos al cuadrado

8
Guía de programación User RPL

X @ Recuperamos la variable X en 1:
LN @ Hallamos su logaritmo
* @ Multiplicamos 2: por 1:
'X' @ Colocamos el nombre de la variable en la pila
PURGE @ Borramos la variable
\>>

3.3. Variables locales:

Son más rápidas que las globales y no nos tenemos que preocupar de destruirlas al final del
programa ya que desaparecen cuando este termina. Se gestionan igual que las globales salvo a la
hora de crearlas, he aquí el ejemplo anterior adaptado a estas:

\<<
\-> @ Inicio de la creación de variables locales
X @ Nombre de la variable local
\<< @ Almacenamos el contenido de 2: en la variable X
2 @ Colocamos un 2 en la pila
SQ @ Lo elevamos al cuadrado
X @ Recuperamos la variable X en 1:
LN @ Hallamos su logaritmo
* @ Multiplicamos 2: por 1:
\>> @ Desaparece la variable X
\>>

Otra versión sería:

\<<
\-> @ Inicio de la creación de variables locales
X @ Nombre de la variable local
'LN(X)*SQ(2)' @ Ejecutamos la expresión algebraica
\>>

Vemos que a continuación del comando \ -> puede haber un programa o un algebraico, cuando
este termina las variables desaparecen y no se pueden utilizar en el resto del programa (si lo hay).

3.4. Variables locales compiladas:

Son las mismas variables locales pero con una diferencia: La programación estructurada requiere
de diversas subrutinas que no son más que programas que son ejecutados desde otros programas.
Estas subrutinas pueden necesitar para ejecutarse de ciertas variables que están definidas en el
programa principal, estas variables sólo pueden ser ejecutadas por las subrutinas si son
compiladas. Por ejemplo, guardemos el programa anterior en la variable 'LOGA':

\<<
\-> @ Inicio de la creación de variables locales
X @ Nombre de la variable local
'LN(X)*SQ(2)' @ Ejecutamos la expresión algebraica
\>>

9
Guía de programación User RPL

Ponemos 'LOGA' en 1: y presionamos STO. Esta va a ser nuestra subrutina llamada por el
siguiente programa:

\<<
\-> @ Inicio de la creación de variables locales
X @ Nombre de la variable local
\<< @ Almacenamos el contenido de 2: en la variable X
X @ Recuperamos la variable
SIN @ Hallamos el seno de X
X @ Volvemos a recuperar la variable
LOGA @ Llamamos a la subrutina
\>> @ Desaparece la variable X
- @ Restamos al seno el resultado de LOGA
\>>

Una vez que el programa llega a LOGA, como es una variable, ejecuta lo que contiene. Es lo
mismo que cuando recupera el valor de X. Si sólo deseamos poner en la pila el contenido de una
variable debemos ejecutar el siguiente procedimiento: Poner su nombre en la pila entre comillas
simples ('LOGA' en este caso) y ejecutar RCL. De esta manera obtendríamos en la pila: \<< \-> X
'LN(X)*SQ(2)' \>>, para ejecutarlo deberemos programar a continuación el comando EVAL.
Siguiendo con el programa, vemos que LOGA utiliza la misma variable X que el programa que lo
llama ¿Para qué crear una nueva variable entonces? es más fácil usar una variable compilada de
la siguiente forma:
Guardamos en LOGA el algebraico siguiente:

'LN(\<-X)*SQ(2)'

Escribimos la subrutina principal:

\<<
\-> @ Inicio de la creación de variables locales
\<-X @ Nombre de la variable local compilada
\<< @ Almacenamos el contenido de 2: en la variable \<-X
\<-X @ Recuperamos la variable
SIN @ Hallamos el seno de \<-X
LOGA @ Llamamos a la subrutina
\->NUM @ Evaluamos el algebraico
\>> @ Desaparece la variable \<-X
- @ Restamos al seno el resultado de LOGA
\>>

Como podemos ver el primer carácter de las variables compiladas ha de ser "\<-". En el primer
ejemplo, el programa principal deja en la pila la variable X antes de llamar a la subrutina LOGA.
Esto es necesario ya que LOGA necesita que en 1: haya un argumento para guardarlo en su
propia variable X . Ambas son distintas a pesar de llevar el mismo nombre (la calculadora las
guarda en diferentes posiciones de memoria), sin embargo la variable compilada \<-X es la
misma para ambos programas y no es necesario que el principal deje nada en la pila a la
subrutina. Para convencernos de que efectivamente desaparece \<-X podemos probar con el
siguiente programa:

10
Guía de programación User RPL

\<<
\-> @ Inicio de la creación de variables locales
\<-X @ Nombre de la variable local compilada
\<< @ Almacenamos el contenido de 2: en la variable \<-X
\<-X @ Recuperamos la variable
SIN @ Hallamos el seno de \<-X
LOGA @ Llamamos a la subrutina
\>> @ Desaparece la variable \<-X
\->NUM @ Intentamos evaluar el algebraico
- @ No llega a ejecutarse
\>>

Este programa nos produce un error: "\->NUM Error: Undefined Local Name" ya que la
variable \<-X no existe.

11
Guía de programación User RPL

4. Tipos de tests en la hp48.

Hay cuatro tipos de test en la HP48:

4.1. Las Banderas (Flags).

Son registros en los que se guarda un estado: activado o desactivado. Hay dos clases de flags: de
sistema y de usuario. Hay 64 de cada uno de ellos. Los de sistema podemos encontrarlos en el
apéndice D de la Guía de Usuario y tienen la característica de nombrarse con números negativos
(-1, -2, ...., -64), con ellos determinamos la forma en que la máquina se comporta en
determinadas circunstancias. Los de usuario se nombran con positivos (1, 2, ..., 64) y nos sirven
para señalizar en nuestros programas opciones que ofrecemos al usuario. Cuando comprobamos
el estado de estos registros obtenemos 0 cuando están desactivados o 1 cuando están activados.
Las funciones relacionadas con estos indicadores son:

1. SF Activa el flag señalado en 1: (bien sea de sistema o de usuario).


2. CF Desactiva flags
3. FS? Comprueba el estado del flag y devuelve verdadero (1) si está conectado o falso (0) si no
lo está.
4. FC? Comprueba el estado del flag y devuelve verdadero (1) si está desconectado o falso (0)
en caso contrario.
5. FS?C Tiene dos partes, primero comprueba el estado del flag devolviendo verdadero si está
activado o falso si no lo está, a continuación lo desactiva.
6. FC?C Igualmente comprueba el estado, devolviendo verdadero o falso dependiendo de si está
desactivado o activado. Seguidamente lo desactiva.
7. STOF Puede tener dos tipos de argumentos, si le damos un entero binario fijará el estado de
los flags del sistema, si damos una lista con dos binarios fijará los flags del sistema y los de
usuario. Estos enteros binarios están formados por una sucesión de guarismos que representan
el estado de cada flag por un 0 o un 1.
8. RCLF Pone en la pila una lista con dos enteros binarios, el primero contiene el estado de los
flags de sistema y el segundo el de los de usuario.
9. RESET Fija los flags de sistema a sus valores por defecto.

En la serie G se puede dar una lista de flags como argumento para las seis primeras funciones, en
la S sólo pueden darse enteros.

4.2. Las funciones de comparación.

Son:
> (Menor que)Ejemplos:

Arg. 1 Arg. 2 Función Resultado Comentario


8 9 < 1
9 8 < 0
5 'A' < Obtenemos '5 < A' si el flag -3 está

12
Guía de programación User RPL

desactivado, en otro caso se evalúa el


algebraico

> (Mayor que)Ejemplos:

Arg. 1 Arg. 2 Función Resultado Comentario


"B" "A"<TD>>< TD> 1  
5 6<TD>>< TD> 0  
El código del carácter "A" es
"A" "a"   0 el 65 mientras que el del "a"
es el 97

\<= (Menor o igual que)Ejemplos:

Arg. 1 Arg. 2 Función Resultado Comentario


8 8 \<=
1  
9 8 \<=
0  
"A" "a" \<=
1  

\>= (Mayor o igual que)Ejemplos:

Arg. 1 Arg. 2 Función Resultado Comentario


8 8 \>= 1  
9 8 \>= 1  
"A" "a" \>= 0  

= = (Igual que)Ejemplos:

Arg. 1 Arg. 2 Función Resultado Comentario


8 8 = = 1  
"1" 1 = = 0  
Obtenemos 'A = = A' si el flag -3 está
'A' 'A' = =   desactivado, en otro caso se evalúa el
algebraico

\=/ (Distinto a)Ejemplos:

Arg. 1 Arg. 2 Función Resultado Comentario


8 8 \=/ 0  
"1" 1 \=/ 1  
Obtenemos 'A \=/ A' si el flag -3 está
'A' 'A' \=/   desactivado, en otro caso se evalúa el
algebraico

13
Guía de programación User RPL

SAME (Idénticamente igual a)Ejemplos:

Arg. 1 Arg. 2 Función Resultado Comentario


1 1 SAME 1  
'A' 1 SAME 0  
"1" 1 SAME 0  

LININ Comprueba si una expresión es función lineal de una variable.Ejemplos:

Arg.1 Arg. 2 Función Resultado Comentario


Si representamos esta función
'X*Y^3' 'X' LININ 1
respecto de X obtenemos una recta
Si representamos esta función
'X^2*Y^3' 'X' LININ 0
respecto de X obtenemos una parábola

4.3. Las funciones lógicas.

Las funciones lógicas toman uno o dos argumentos de la pila (cualquier real distinto de cero es
tomado como uno (verdadero), sólo el cero es considerado como falso).Las funciones son:
 AND: Devuelve verdadero (1) si ambos argumentos son verdaderos
 OR: Verdadero si al menos uno es verdadero
 XOR: Verdadero si uno y sólo uno es verdadero
 NOT: Siempre devuelve el inverso lógico
El resultado que devuelven depende del tipo de los argumentos:

4.3.1. Argumentos reales.

AND OR
Arg. 1 Arg. 2 Función Resultado Arg. 1 Arg. 2 Función Resultado
1 1 AND 1 1 1 OR 1
1 0 AND 0 1 0 OR 1
0 1 AND 0 0 1 OR 1
0 0 AND 0 0 0 OR 0

XOR NOT
Arg. 1 Arg. 2 Función Resultado Arg. Función Resultado
1 1 XOR 0 1 NOT 0
1 0 XOR 1 1.34 NOT 0
0 1 XOR 1 0 NOT 1
0 0 XOR 0

4.3.2. Algebraicos:

Arg. 1 Arg. 2 Función Resultado Comentario


'A' 'B' AND   Obtenemos 'A (función) B' si el flag -3
OR está desactivado, en otro caso se evalúa
XOR el algebraico obrando entonces según el
NOT tipo de datos contenidos en las

14
Guía de programación User RPL

variables A y B

4.3.3. Cadenas.

Cada carácter de las cadenas se convierte al código de carácter correspondiente (por ejemplo, el
de "A" es el 65, ver la función NUM) y este código al binario correspondiente, a continuación se
efectúa la comparación lógica entre las cadenas (aplicamos la función AND OR XOR NOT
correspondiente) y realizamos el proceso anterior al contrario para volver a obtener la cadena
resultado.

Todos los siguientes ejemplos han sido efectuados con 7 como longitud de palabra (ver las
funciones STWS y RCWS en la guía de usuario).

AND
Carácter Código Binario
Arg. 1 "A" 65 #1000001b
Arg. 2 "B" 66 #1000010b
Función AND AND
Resultado "@" 64 #1000000b

"A" = código de carácter 65, "B" = código de carácter 66, si transformamos estos números a
binarios obtenemos: 65 = #1000001b, 66 = #1000010b. Ahora se ejecuta AND obteniendo
#1000000b que es el decimal 64 y que a su vez es el código de carácter de "@"

OR XOR
Carácte
Código Binario Carácter Código Binario
r
Arg. 1 "A" 65 #1000001b Arg. 1 "A" 65 #1000001b
Arg. 2 "B" 66 #1000010b Arg. 2 "B" 66 #1000010b
Función OR OR Función XOR XOR
carácter
Resultado "C" 67 #1000011b Resultado 3 #0000011b
3

Esta función tiene la "virtud" de que si la ejecutamos dos veces nos devuelve el carácter original,
esto es, "A" "B" XOR nos devuelve el carácter 3 y si volvemos a hacer: carácter 3 "B" XOR
obtendremos de nuevo "A". Esto es lo único que necesitamos para hacer un programa que cifre
un archivo que es lo que hizo Simone Rapisarda en 1991 con su programa CODER (Goodie Disk
5), reproduzco aquí su código y forma de uso

CODIFICAR

4: 4:
3: 3:
2: "Cadena a codificar" 2:
1: "Clave" 1: "Cadena codificada"
CODER ### ### ### ### ### CODER ### ### ### ### ###

15
Guía de programación User RPL

DESCODIFICAR

4: 4:
3: 3:
2: "Cadena a des codificar" 2:
1: "Clave" 1: "Cadena descodificada"
CODER ### ### ### ### ### CODER ### ### ### ### ###

CÓDIGO

\<<
\->STR SWAP @ Asegura que ambos argumentos sean cadenas
\->STR @ convirtiéndolas si no lo son
DUP SIZE @ Halla la longitud de la cadena a codificar.
ROT @ Coloca la pila de la forma:
@ 3: Cadena a cifrar, 2: su longitud, 1: clave
WHILE @ Se inicia el bucle Mientras ...Repite... End
DUP2 @ Duplica los niveles 1: y 2:
SIZE @ Calcula la longitud de la cadena clave.
> @ Comprueba si la longitud de la cadena a cifrar
@ es aún mayor que la de la clave
REPEAT @ Si aún es mayor se ejecuta lo siguiente
DUP + @ Dobla la longitud de la cadena clave sumándola a si misma.
END @ Si la cadena de la clave ya es mayor o igual que
@ la cadena a cifrar salimos del bucle
1 ROT SUB @ Asegura que ambas cadenas tengan igual longitud
@ obteniendo de la cadena clave justo los primeros
@ n elementos, siendo n la longitud de la cadena a cifrar
XOR @ Codifica o descodifica.
\>>

NOT
  Carácter Código Binario
Arg. "A" 65 #1000001b
Función NOT   NOT
Resultado "3/4" 190 #0111110b

4.3.4. Binarios.

Ya lo hemos visto en el ejemplo anterior

4.4. Comandos TYPE y VTYPE.

La función TYPE nos da el número del tipo de objeto que hay en 1:

16
Guía de programación User RPL

Estos códigos son:

Objeto Nº tipo Objeto Nº tipo


Número real 0 Nombre XLIB 14
Número complejo 1 Directorio 15
Cadenas 2 Librería 16
Función real 3 Backup 17
Funciones
Función compleja 4 18
incorporadas
Lista 5 Comandos incorporados 19
Nombre global 6 Binarios System RPL 20
Nombre local 7 Reales largos 21
Programa 8 Complejos largos 22
Algebraico 9 Matriz enlazada 23
Enteros binarios 10 Carácter 24
Gráfico 11 Code 25
Etiquetas 12 Library data 26
Unidades 13 External 26-31

VTYPE toma de 1: un nombre de variable y devuelve un número que representa el tipo de


variable almacenada en ella. Si no existe la variable devuelve -1

17
Guía de programación User RPL

5. Estructuras condicionales.

Hay cinco tipos de estructuras condicionales y dos comandos:

5.1. Estructura IF ... THEN ... END

Podríamos traducirla como SI ... ENTONCES ... FIN, de forma que explicaríamos su sintaxis:
SI el resultado de un test es verdadero ENTONCES ejecuta este código FIN
Los test no sólo pueden ser tales sino cualquier algebraico u operación que devuelva un resultado
a la pila. Sea cual sea el test se entiende que el resultado es verdadero si en 1: hay un número
distinto de 0. El test puede ejecutarse antes de IF:
\<<
1 3 < IF THEN CLLCD
"Si: 1 es menor que 3"
1 DISP 7 FREEZE END
\>>

Programa tonto como el que más que siempre haría que nos apareciera la frase "Si: 1 es menor
que 3" en la línea 1 de la pantalla. Aunque sólo sea por legibilidad es mejor esta forma:

\<<
IF '1 <3' THEN CLLCD
"Si: 1 es menor que 3"
1 DISP 7 FREEZE END
\>>

Si nos fijamos un poco veremos que en realidad IF es una etiqueta que posee esta estructura para
mejorar su legibilidad, pero quien hace el trabajo es THEN que evalúa lo que hay en 1: y si el
resultado es distinto de 0 ejecuta la cláusula que le sigue. Por ejemplo:

\<<
IF 'A * 3' THEN CLLCD
"Depende de A"
1 DISP 7 FREEZE END
\>>

THEN toma el algebraico 'A * 3' de la pila y lo evalúa. Si la variable 'A' es un número distinto de
0 aparece el mensaje en la primera línea de la pantalla. Si es 0 no aparece nada. Si no existe esta
variable THEN producirá un error: " * Error: Undefined Name". Si 'A' contiene un tipo de dato
que produce un error al evaluarse 'A*3', se producirá dicho error y el programa terminará.
Finalmente si 'A' contiene otro algebraico o programa este se evalúa y lo que se obtiene se
multiplica por 3, este resultado es el que toma THEN (si no es un número real se produce el error:
"THEN Error: Bad Argument Type").
Finalmente comentar que tanto si el resultado del test es cierto como si es falso, el programa
continúa después de END.

18
Guía de programación User RPL

5.2. Estructura IF ... THEN ... ELSE ... END.

Podríamos traducirla como SI ... ENTONCES ... SINO ... FIN, o dicho de otra forma:
SI el resultado del test es verdadero ENTONCES ejecuta este código SINO ejecuta este otro FIN

El funcionamiento de esta estructura es similar a la anterior con la diferencia de que si el test es


falso se ejecuta el código que hay tras ELSE. Ejemplo:

\<<
IF 'A <3'
THEN CLLCD
"A es menor que 3"
1 DISP 7 FREEZE
ELSE CLLCD
"A es mayor o igual que 3"
1 DISP 7 FREEZE
END
\>>

Si al evaluar 'A' obtenemos un número mayor o igual a 3 en pantalla aparece "A es mayor o igual
que 3"

5.3. Estructura CASE ... THEN ... END.

La estructura CASE ... THEN ... END es un poco más compleja y se utiliza cuando hay más de
dos opciones. Se evalúan tantos test como deseemos de forma que el primero que devuelve un
resultado verdadero hace que se ejecute el código asociado a él y termina la evaluación de CASE.
Traducido sería:

EN CASO DE
que este test devuelva verdadero ENTONCES haz esto y termina FIN
que este test devuelva verdadero ENTONCES haz esto y termina FIN
que este test devuelva verdadero ENTONCES haz esto y termina FIN
cláusula por defecto FIN
Un ejemplo:

\<<
\-> nivel1
\<<
CASE nivel1 TYPE 0 ==
THEN CLLCD "Es un real"
1 DISP 7 FREEZE
END
nivel1 TYPE 1 ==
THEN CLLCD
"Es un complejo"
1 DISP 7 FREEZE
END
nivel1 TYPE 2 ==
THEN CLLCD "Es una
cadena de caracteres"

19
Guía de programación User RPL

1 DISP 7 FREEZE
END
nivel1 TYPE 3 ==
THEN CLLCD
"Es una función real"
1 DISP 7 FREEZE
END
CLLCD "Esto es un
aburrimiento" 1 DISP 7 FREEZE
END
\>>
\>>

Este programa toma un objeto de la pila y nos devuelve una cadena de caracteres indicadora de su
tipo. Como tenemos que evaluar repetidamente el comando TYPE sobre un mismo objeto es
mejor guardarlo en la variable local 'nivel1' de forma que podamos acceder a su contenido
cuando lo deseemos. Si nos hemos aburrido de poner cadenas con el tipo podemos crear una
cláusula por defecto (en este caso la línea: CLLCD "Esto es un aburrimiento" 1 DISP 7 FREEZE)
de forma que si ninguno de los anteriores test ha devuelto verdadero sea este código el que se
ejecute. Si ponemos el número 7,64 en la pila y ejecutamos el programa se ejecutaría: CLLCD
"Es un real" 1 DISP 7 FREEZE y el programa continuaría a continuación del último END.

5.4. Estructura IFERR …THEN ... END.

Es una estructura de captura de errores que traducida sería:


SI SE PRODUCE UN ERROR en este código ENTONCES ejecuta esto FIN
Podemos ver como funciona en este ejemplo:

\<<
IFERR
IF 'A * 3'
THEN CLLCD "Depende de A" 1 DISP 7 FREEZE
END
THEN CLLCD "Has hecho algo mal" 1 DISP 7 FREEZE
END
\>>

Si la variable 'A' no existe o contiene un objeto que produce un error al ser evaluado por THEN el
programa no se interrumpe sino que salta a la cláusula THEN de IFERR y se ejecuta esta:
CLLCD "Has hecho algo mal" 1 DISP 7 FREEZE . En caso de que no se produzca ningún error
esta cláusula no se ejecuta.

5.5. Estructura IFERR ...THEN ... ELSE ...END

Sería la estructura anterior a la que se le dota de ELSE. Funciona de la misma forma que
IFERR... THEN... END salvo que si no se produce ningún error entre IFERR y THEN se ejecuta
el código que sigue a ELSE. El comando IFT es una versión compacta de IF ...THEN ... END. En
2: debe estar la cláusula test y en 1: el objeto a ser evaluado. Este comando evalúa el nivel 2: y
comprueba el resultado. Si es falso borra el contenido de 1:, si es verdadero lo evalúa. Ejemplo:

20
Guía de programación User RPL

\<<
'A*3'
\<<
"A es distinto de cero"
\>>
IFT
\>>

5.6. Comando IFT

Evalúa el algebraico 'A*3', si este devuelve un número distinto de cero evalúa el programa \<<
"A es distinto de cero" \>> apareciendo esta cadena en 1:
El mismo resultado se habría obtenido si el programa fuera:

\<<
A 3 *
"A es distinto de cero"
IFT
\>>

5.7. Comando IFTE

Es la versión compacta de IF ... THEN .... ELSE ... END. Ejemplo

\<<
A 3 *
"A es distinto de cero"
"A es cero"
IFTE
\>>

En 1: aparecerá la frase correcta en función del contenido de 'A'

21
Guía de programación User RPL

6. Estructuras iterativas.

Antes de nada comentar que podemos escribir estas estructuras presionando muy pocas teclas:
primero PRG y BRCH. A continuación la tecla deseada pero con desplazamiento izquierdo
(primero tecla morada) para las estructuras NEXT o derecho (primero tecla verde) para las STEP.
Las estructuras iterativas, o bucles, se encargan de repetir un determinado código de programa
una serie de veces. Hay dos tipos: Definidos e indefinidos.

6.1. Estructuras Definidas:

Los bucles definidos llevan asociados una variable contador en la que se especifica el número de
veces que ha de repetirse el código. Hay dos tipos de bucles definidos, cada uno de ellos tiene dos
variantes dependiendo de si el contador se incrementa de uno en uno o de forma definida por el
programador.

6.1.1. Estructura START ... NEXT

La estructura START ... NEXT se traduce como INICIO ... SIGUIENTE, su sintaxis sería:
'inicio' 'fin' START código a repetir NEXT.
En el nivel 2: de la pila pondremos el valor inicial del contador y en 1: el valor final. A
continuación se ejecuta el código tras lo que NEXT incrementa en uno el contador interno que
crea el sistema operativo de la calculadora y comprueba su valor. Si es menor o igual que 'fin' se
ejecuta de nuevo el código, si es mayor no se repite y el programa continúa. El bucle se repetirá
'fin - inicio + 1' veces.

\<<
"H" "O" "L" "A"
1 3
START
+
NEXT
"A" "M" "I" "G" "O" "/" "A"
1 6
START
+
NEXT
\>>

Este ejemplo nos deja en 2: la cadena "HOLA" y en 1: "AMIGO/A"

6.1.2. Estructura START ... STEP.

La estructura START ... STEP se podría traducir como INICIO ... INCREMENTO, su sintaxis
sería: 'inicio' 'fin' START código a repetir 'incremento' STEP

22
Guía de programación User RPL

Esta estructura sólo se diferencia de la anterior en que se puede especificar un incremento distinto
de 1, que era el único que podíamos tener con la anterior.

El incremento puede ser positivo o negativo (nunca cero ya que el bucle sería infinito), si usamos
un algebraico o un nombre de variable como argumento de STEP se evalúa y su resultado es con
el que STEP incrementa el contador. En caso de que el incremento sea negativo 'inicio' debe ser
mayor que 'fin' deteniéndose el bucle cuando el contador es menor que el valor de 'fin'

\<<
"H" "O" "L" "A"
1 0.2
START
+ -0.3
STEP
"A" "M" "I" "G" "O" "/" "A"
0 1.12
START
+ '1-0.7'
STEP
\>>

El resultado es el mismo que en el caso anterior.

6.1.3. Estructura FOR ... NEXT.

FOR ... NEXT tiene la siguiente sintaxis: 'inicio' 'fin' FOR 'contador' código a repetir NEXT .
Este bucle tiene la ventaja de que utilizamos una variable local como contador, esto nos permite
acceder a él y recuperarlo en la pila o modificarlo. FOR toma el valor inicial y final del contador
y además crea la variable local con el nombre que le suministramos delante. NEXT incrementa
en 1 el contador y a continuación comprueba su valor volviendo a ejecutar la cláusula si es menor
o igual que 'fin'. La variable local se destruye al terminar el bucle.

Es, sin duda alguna, el más utilizado de todos los bucles lo cual no quiere decir que sea el único a
utilizar ya que si no tenemos necesidad de acceder al contador es mejor utilizar las estructuras
START que son más simples y rápidas al no tener que crear la variable local.

\<<
\-> z
\<<
FOR n
z n ^
NEXT
\>>
\>>

En la pila debe haber 3 números. El código "\-> z" guarda el valor de 1: en la variable local 'z'
dejando en la pila el nivel 2: con el valor de 'inicio' y 1: con 'fin' para que los tome FOR. El bucle
calcula distintas potencias de 'z' dependiendo de los valores 'inicio' y 'fin'

23
Guía de programación User RPL

6.1.4. Estructura FOR ... STEP.

FOR ... STEP tiene la siguiente sintaxis:


'inicio' 'fin' FOR 'contador' código a repetir 'incremento' STEP
Es la misma estructura anterior con la posibilidad de poder especificar el incremento deseado.
Este puede ser también positivo o negativo y tiene todas las demás características que hemos
visto en START ... STEP.

\<<
48 57
FOR x
x CHR STR\-> SQ 2
STEP
\>>

Este ejemplo calcula el cuadrado de 0, 2, 4, 6 y 8

6.2. Estructuras Indefinidas:

Los bucles indefinidos se repiten hasta que una condición establecida se cumple o deja de
cumplirse.

6.2.1. Estructura DO ... UNTIL ... END.

Podríamos traducir DO ... UNTIL ... END como HAZ ... HASTA que esta cláusula sea cierta
FIN, su sintaxis sería: DO código a repetir UNTIL condicional END

En primer lugar se ejecuta el código que hay entre DO y UNTIL tras lo que se inicia la condición
o test. Estos test no sólo pueden ser tales sino cualquier algebraico u operación que devuelva un
resultado a la pila. Sea cual sea el test se entiende que el resultado es verdadero si en 1: hay un
número distinto de 0. END evalúa cualquier algebraico o un nombre de variable que le demos
como argumento.
Si el resultado del test es falso el bucle vuelve a ejecutarse, si es verdadero el programa continúa.

Esta estructura se utiliza cuando no sepamos las veces que ha de ejecutarse un código pero si
sabemos que ha de realizarse, al menos, una vez.

\<<
IF DEPTH 0 \=/
THEN
0 \-> pila
\<<
DO 'pila' STO
UNTIL DEPTH 0 ==
pila TYPE 8 == OR
END
IF pila TYPE 8 ==
THEN pila "Es un programa"
ELSE "No hay programas"

24
Guía de programación User RPL

END
\>>
END
\>>

El ejemplo anterior comprueba en primer lugar si hay algún objeto en la pila, si no lo hay
termina. Si lo hay, primero crea una variable local (pila) y a continuación empieza una estructura
DO ... UNTIL que guarda en la variable local el contenido de 1: para seguidamente comprobar si
queda algo en la pila o bien la variable contiene un programa. Si se cumple cualquiera de las dos
condiciones el bucle termina, en caso contrario sigue ejecutándose hasta hacerlo. Finalmente
comprobamos si en la variable hay un programa colocando una cadena en la pila que nos lo
indique.

6.2.1.1. Como salir de un bucle definido cuando lo deseemos.

Este programa se puede hacer también con un bucle definido pero lo complicaríamos mucho ya
que no hay forma de salir de ellos sino es produciendo un error que capturemos fuera del bucle:

\<<
IF DEPTH 0 \=/
THEN
0 \-> pila
<<
IFERR DEPTH 1 SWAP
START
'pila' STO
IF 'pila' VTYPE 8 ==
THEN "" DOERR
END
NEXT
THEN
pila "Es un programa"
ELSE
"No hay programas"
END
\>>
END
\>>

6.2.2. Estructura WHILE ... REPEAT ... END

Podríamos traducir WHILE ... REPEAT ... END como MIENTRAS esta cláusula sea cierta
REPITE ... FIN, su sintaxis sería: WHILE condicional REPEAT código a repetir END
En esta ocasión el test lo valora REPEAT: si el resultado es verdadero ejecuta el código, en caso
contrario el programa continúa tras END. Vemos, por tanto, que el código puede no ejecutarse
nunca mientras en la anterior cláusula siempre se ejecutaba una vez por lo menos. Otra notable
diferencia es que ahora se ejecuta el código si el resultado del test es verdadero.

\<<
IF DEPTH 0 \=/
THEN

25
Guía de programación User RPL

\-> pila
\<<
WHILE
DEPTH 0 \=/ pila TYPE 8 \=/ AND
REPEAT
'pila' STO
END
IF pila TYPE 8 ==
THEN
pila "Es un programa"
ELSE
"No hay programas"
END
\>>
END
\>>

Vemos que el resultado de este programa es el mismo del anterior. ¿Cuál usar entonces? El que
nos parezca más fácil en cada momento. El test de este último es más rebuscado que el del
anterior y en general el programa es más confuso. En este caso yo elegiría la estructura DO ...
UNTIL.

6.2.2.1. Bucles animados.

Podemos incluir un bucle dentro de otro, a esto se le llama anidar bucles. Podemos anidar tantos
como queramos teniendo una serie de precauciones:
1. Cada bucle anidado ha de estar enteramente dentro del otro.
2. Cada bucle ha de tener su propio nombre de contador.
3. Es mejor no usar nombres de contador como 'i', 'e', ... que pueden ser interpretados en
ciertas circunstancias como números. Esta precaución se extiende a todos los nombres de
variables.
\<<
IF DUP TYPE 3 = = OVER SIZE SIZE 1 > AND
THEN
DUP SIZE EVAL \-> n
\<<
1 SWAP
FOR fila
1 n
FOR columna
DUP fila columna 2 \->LIST GET
IF columna 1 ==
THEN 2 *
ELSE 2 /
END
fila columna 2 \->LIST SWAP PUT
NEXT
NEXT
\>>
END
\>>

26
Guía de programación User RPL

Este ejemplo nos permite multiplicar la primera columna de cualquier matriz por 2, y dividir las
demás columnas por 2.

27
Guía de programación User RPL

7. Nombres prohibidos de variables. Cómo ocultar variables y


directorios. Directorios temporales.

En la calculadora se pueden ocultar las variables y los directorios. ¿Qué quiero decir con ocultar?
Supón que tienes un directorio que se llama TRABAJO, las variables y/o subdirectorios que hay
en él las vemos en el menú VAR y podemos recuperarlos en la pila, ejecutarlos, ordenarlos, etc.
Pues podemos hacer que esas variables permanezcan en el directorio TRABAJO pero que al dar
VAR no nos aparezcan en el menú, de esta forma podremos seguir trabajando con ellas pero sólo
si sabemos que están allí y su nombre. Por ejemplo, si tenemos una variable llamada AGENDA
-que nos ejecuta un programa para gestionar números de teléfonos y direcciones- y la ocultamos,
sólo nosotros que sabemos cuál es su nombre y que está ahí podremos poner AGENDA en el
nivel 1: y dando a ENTER correr dicho programa.

No tenemos más que crear una variable de nombre nulo (null-name variable) y a partir de ella
todas las que haya hacia la derecha en el menú VAR quedarán ocultas. Para crear variables sólo
tenemos que guardar un objeto (mediante STO) en un nombre de variable (cualquier combinación
de caracteres entre comillas simples, salvo los prohibidos en la página 5-6 de la guía de usuario)
La variable de nombre nulo es la que resulta de guardar un objeto entre dos comillas simples sin
nada entre ellas (''). Puede ser cualquier objeto, incluido un directorio. Sólo hay un inconveniente,
que no podemos introducir las dos comillas simples en la pila y presionar ENTER ya que el
sistema operativo de la máquina nos lo impide, en la pila no aparece nada. Hay una forma de
solventar esto: Con el lenguaje System RPL.

Para el que no sepa qué lenguaje es éste, baste decir que es de más bajo nivel que el normal de la
calculadora, el User RPL, y por ello más rápido y peligroso. A nada que te equivoques puedes
borrar toda la memoria de usuario de la calculadora: ¿Os suena "Try to Recover Memory?" ?.
Pues id con cuidado al experimentar con lo que sigue, lo mejor sería hacer un backup de la
memoria para poder recuperar todo lo que tengáis ahora en ella.

La orden de System que crea un nombre de variable a partir de un string cualquiera (incluidos "",
"3", "]", etc.) es "$>ID", si tenéis el suficiente conocimiento de System como para saber compilar
esta orden, hacedlo y obtendréis un bonito External que os creará un nombre de variable a partir
de cualquier cadena que tengáis en 1: (también de la cadena nula: ""). Si no sabes cómo
compilarla no te preocupes ya que podemos obtener el mismo resultado llamando a la dirección
de memoria ROM en la que está guardado este comando poniendo para ello una cadena en el
nivel 1 y a continuación introduciendo #5B15h SYSEVAL. Este comando (SYSEVAL
seguramente viene de System Eval) sólo viene reseñado en la Guía de Usuario dentro del índice
de operaciones (Pág. G-49) y nos remite al misterioso libro AUR, en el que tampoco nos aclara
mucho ya que sólo nos dice que sirve para evaluar objetos sin nombre del sistema operativo
especificados por su dirección de memoria. Todos los comandos de la calculadora podemos
evaluarlos si ponemos en la pila su dirección de memoria y ejecutamos SYSEVAL. Esto es muy
peligroso ya que podemos borrar la memoria a la mínima. Por ejemplo, si en 1: tenemos un
número real en vez de una cadena de caracteres y ejecutamos la anterior orden (#5B15h
SYSEVAL) borraremos la memoria con toda seguridad, probadlo si deseáis ver como
desaparecen esos bonitos programas que tanto os ha costado hacer ;->

28
Guía de programación User RPL

Naturalmente que podéis hacer un programa de forma que no tengáis que teclear la dirección de
memoria y SYSEVAL cada vez que deseéis crear una variable de nombre prohibido. Nos
quedaría así: << #5B15h SYSEVAL >>. Podéis transformarlo en un misterioso << External >>
usándolo como argumento del programa pack de Joe Horn (Goodie Disk #2). Para acabar de
quedar como un experto puedes usar strip de Simone Rapisarda (en el GD#6) y tendrás sólo el
External sin los delimitadores. En total habrás reducido el tamaño de los 25,5 by de << #5B15h
SYSEVAL >> a los 2,5 by del último External y no sólo eso sino que este último tarda cerca de
un 42% menos de tiempo en ejecutarse.

Ahora ya podemos esconder cualquier variable, cread un directorio y dentro de él cread la


variable 'A' con un 7 en ella, a continuación tenéis que poner un cero en la pila (o lo que deseéis
guardar en la variable de nombre nulo) y la cadena nula en 1:. Ejecutad #5B15h SYSEVAL y
veréis que os aparecen las dos comillas simples. En la pila debéis tener:

4:
3:
2: 0
1: ''

Sólo queda dar a STO y veréis como el menú VAR queda vacío. La variable 'A' ha desaparecido
pero si tecleamos A ENTER en la pila nos aparece 7. También podemos hacer:

4:
3:
2: "Hola"
1: 'A'

Y dar STO a continuación. Si ahora evaluamos 'A' nos saldrá su nuevo contenido "Hola" en

1:
Para hacer que las variables ocultas aparezcan de nuevo tenemos que borrar esta variable. Para
ello pondremos su nombre en la pila con "" #5B15h SYSEVAL y daremos a PURGE.

Ya tenemos de nuevo la variable 'A' en el menú de VAR.


Para rizar el rizo podemos crear un directorio de nombre nulo en vez de una variable. Además de
escondernos todas las variables del directorio podremos acceder a él (poniendo su nombre en la
pila y dando EVAL a continuación) y guardar lo que deseemos como si fuese otro directorio más.

Hay un sólo directorio donde no podemos crear variables ocultas por este método: El directorio
HOME. Haced la prueba: Dentro de HOME teclead "" #5B15h SYSEVAL EVAL y veréis que
aparecemos en un directorio oculto que tiene tres variables: 'Alarms' (lista con todas las alarmas),
'UserKeys' (lista con todas las asignaciones de teclas de usuario) y 'UserKeys.CRC' (un número
que es el CRC de control de la anterior lista). Mucho cuidado, no las borréis o juguéis con ellas
ya que podéis borrar la memoria muy fácilmente. También podéis guardar cosas en este
directorio, pero os aconsejo mucha prudencia. Para regresar al directorio HOME basta con dar
UPDIR o HOME.

29
Guía de programación User RPL

Puesto que hay que tener tanto cuidado con los SYSEVAL os doy compilado prohivar.zip. Este
programilla transformará cualquier cadena de caracteres de 1: en el nombre de variable
correspondiente. Si en 1: no hay una cadena dará el mensaje "Bad Argument Type". El código en
System es:

::
CK&DISPATCH1 * Chequea que el argumento del nivel 1
str * sea una cadena de caracteres.
$>ID * La convierte en nombre de variable.
;

También puedes llegar a él sabiendo las direcciones de memoria de estos comandos y teniendo
los programas pack y strip , de los que ya hemos hablado antes. Para ello crea el programa:

\<<
# 18FB2h SYSEVAL
# 0400Dh SYSEVAL
# 05B15h SYSEVAL
\<<

Ahora pásale pack y strip. Llegarás al mismo resultado que si lo hubieras compilado, verás que
tiene el mismo tamaño que prohivar y si los pones en la pila a ambos y ejecutas el test SAME
obtendrás que efectivamente son iguales. Ten mucho cuidado en teclear las direcciones de
memoria correctas.

Si quieres ver una aplicación práctica de esto puedes bajarte editor.zip. Es un editor-visor de
textos y gráficos. Cuando lo pases a la calculadora verás que es un directorio con una sola
variable DAME, sin embargo hay un montón de variables ocultas (no borres la variable sin
nombre, directorio en este caso, ya que el programa lo utiliza y no funcionaría). Ocurre una cosa
curiosa: Si recuperas con RCL el contenido de DAME en la pila verás que no aparece nada
¿Cómo es que funciona si está vacía?. La primera persona que me diga cómo lo he hecho que me
lo comente y le pondré en la web al lado de este texto. Si no puedes dar con la solución mándame
un e-mail a mdelama@teleline.es y te lo resolveré.
Hay otra utilidad para este programa: Si deseas borrar un directorio rápidamente sólo tienes que
esconder todas las variables que hay en él y a continuación poner su nombre en la pila y dar
PURGE. A 'casi' todos los efectos el directorio está vacío y podemos eliminarlo con este
comando. En esto se basa el programa fpgdir del GD #5:

\<<
IF DUP TYPE 6 ==
THEN
IF DUP VTYPE -1 ==
THEN DROP
ELSE
IF DUP VTYPE 15 ==
THEN DUP EVAL 0 # 15777h SYSEVAL DUP PURGE STO UPDIR PURGE
ELSE 515 DOERR
END
END
ELSE 514 DOERR
END

30
Guía de programación User RPL

\>>

Puedes ver que aquí se utiliza la dirección # 15777h para crear el nombre nulo. Esta se
corresponde con el comando NULLID de System RPL y crea directamente el nombre nulo en la
pila. Podéis usar este para esconder variables y el otro para crear nombres prohibidos de
variables.

A pesar de lo que en un principio se creía, dentro de HOME hay una forma de esconder variables
que no es yendo al directorio oculto. Hasta ahora si intentábamos crear un directorio oculto en
HOME con << 0 "" #5B15h SYSEVAL STO >> nos encontrábamos con el mensaje "Directory
Not Allowed" pero en el GD #8 Joe Horn nos presentó el programa htrim de Simone Rapisarda.
Sólo funciona en HOME y acepta como argumentos una lista o el entero 0. Si le damos una lista
con nombres de variables las ordena y oculta todas las variables que hay en HOME y que no
aparecen en dicha lista. Si la lista está vacía esconde todas las variables y si damos un cero como
argumento descubre todas las variables ocultas.

Finalmente os voy a contar cómo crear directorios temporales que podéis utilizar para lo que os
resulte oportuno en vuestros programas. Usaremos para ello el programa de Rick Grevelle tdir del
GD #5. Los argumentos son: Una cadena en 2: y una lista tal como las usadas con el comando
TMENU (Guía de Usuario Pág.. 30-5) en 1: Las uniremos en una sola con 2 \->LIST y a
continuación ejecutamos TDIR. Podéis ver que os aparece un menú cuya única variable es un
directorio con el nombre que hemos puesto. Pulsando la tecla correspondiente entramos en él y
tenemos acceso a sus variables. Espero que os sirva de algo.

31
Guía de programación User RPL

8. Depuración de errores en programas.

Es imposible hacer un programa y que nos salga bien a la primera de cambio. Siempre tendremos
unos cuantos errores que nos fastidiarán la cosa y no es eso lo peor si no que ¿Dónde están esos
errores? Tardamos más en seguir el código y buscarlos que luego en rectificarlos.

Para ayudarnos en la tarea de la depuración de programas tenemos una potente herramienta en la


calculadora, viene explicada en la Pág.. 29-9 de la guía de usuario. Sólo tenéis que poner el
código del programa a revisar en 1:, no lo editéis sólo ponedlo en la pila con RCL o dando a la
tecla desplazada a la derecha (tecla verde) del menú donde esté la variable. Ahora debéis de ir al
menú PRG NXT RUN (o al PRG CRTL en los que tengáis la S o SX) y presionar DBUG. El
programa desaparece de 1: y aparece el anunciador HALT en la línea de estado, esto significa que
está cargado en la memoria y si presionamos NEXT podemos ver (también en la línea de estado)
la acción que está preparada para ejecutarse. Si presionamos SST se ejecutará. Continuando de
esta manera podremos ver paso a paso cómo actúan las instrucciones hasta dar con el error.
Siempre podemos manipular la pila para presentar al programa otros argumentos a los requeridos
en cada momento, de esta manera podremos juzgar si de esa otra forma el error no se produciría,
también podremos ejecutar otros comandos para ver si de esa forma el programa mejoraría y en
fin cualquier otra cosa que se nos ocurra.

Si presionamos SST\|v (la tecla del menú SST con la flecha hacia abajo) podemos introducirnos
en el código de una subrutina, dicho de otra forma, si nuestro programa constara de un primer
programa guardado en una variable y este llama a otro segundo programa guardado en otra
variable, pondríamos en 1: el código del primero y tras dar DBUG iríamos depurándolo hasta
llegar a la parte donde está la llamada al segundo (su nombre). Si damos SST este programa se
ejecutará de una sola vez, como si fuera otro comando más. Si presionamos SST\|v entramos en
el código de esta subrutina y podemos seguir presionando SST hasta que se termine y
continuemos de nuevo en el programa que lo ha llamado.

Tenemos en el menú el comando HALT que es muy conveniente para insertar en el código del
programa cuando estemos seguros de que el error se produce a partir de un determinado punto.
En dicho punto colocamos nuestro HALT y corremos el programa como es habitual (sin
DEBUG), llegado a HALT el programa se detiene y aparece HALT en la línea de estado. Sólo
tenemos que ir al menú RUN e ir depurándolo según se ha comentado antes. Nos ahorramos
ejecutar todo el código hasta HALT con SST y si el programa es largo es de agradecer.
Además de esta utilidad, HALT es también necesario cuando usamos la cláusula IFERR y
queremos depurar el programa. Si no ponemos HALT después de IFERR no podremos depurar el
código que hay entre IFERR ... END. El sistema operativo de la calculadora lo ejecutará como si
fuese un sólo comando.

Finalmente nos encontramos (en el menú RUN) con el comando KILL que sirve para terminar un
programa. Si lo estamos depurando y ya no queremos seguir porque hemos encontrado el error (o
porque la tía Rita a terminado las rosquillas y estamos de catadores) sólo hemos de presionar
KILL y el programa termina. También podemos introducirlo en el código del programa para
terminar el programa cuando lo deseemos.

32
Guía de programación User RPL

9. Menús de usuario, GROB, WAIT y KEY.

En el capítulo 30 de la Guía de usuario de la hp48 vienen un par de páginas dedicadas a los


menús de usuario. Seguramente esto valga para la mayoría de la gente pero para otros es una
información escasa, sobre todo si lo que deseas es programar. La mayor omisión de dicho
capítulo es la referente a los menús gráficos. Si, has oído bien, en la hp puedes introducir un
gráfico como etiqueta de menú de forma que al presionar sobre la tecla correspondiente se ejecute
un programa. No estás obligado a poner una cadena de caracteres.
Ya sabes que al comando MENU puedes darle dos usos según los argumentos que le presentes.

Si en 1: pones un número como mm.pp y ejecutas MENU habrás llamado a la página "pp" del
menú "mm" (puedes ver la lista de números de menús en el apéndice C de la Guía). Si por
ejemplo ejecutas 3 (o 3.01) MENU te aparece el menú que obtienes pulsando la tecla MTH, si
hubieras puesto 3.02 (no 3.2) te aparece el mismo menú que si presionas MTH y a continuación
NEXT. El comando RCLMENU te pone en 1: el número que corresponde al menú actual, esto es
útil si deseas salvar el entorno antes de comenzar a ejecutar un programa y restaurarlo al
terminar. Puedes ver un ejemplo en el capitulo la entrada de datos en los programas.

También puedes hacer aparecer una línea de menús personalizada en la pantalla de la hp. Si no
sabes cómo te recomiendo que primero estudies un poco el citado capítulo 30 de la Guía de
usuario. Este menú personalizado, al igual que los que trae consigo la HP, obedece a la pulsación
de la correspondiente tecla blanca bajo la pantalla (de la A a la F), y si presionas NEXT te
aparece la continuación del menú (cuando hay más de 6 etiquetas). La estructura de la lista a dar
a MENU es:

{ etiqueta_1 { acción1 left_shift_acción1 right_shift_acción1 } ... etiqueta_N { acciónN


left_shift_acciónN right_shift_acciónN } }

Donde "etiqueta_i" es la cadena de caracteres que aparece en el menú de pantalla y las distintas
acciones son las que se ejecutan al presionar esa tecla con los modos de desplazamiento posibles.
La etiqueta no tiene por que ser un string, puedes sustituirla con un GROB (gráfico) de 21
columnas por 7 filas ya que este es el tamaño de las etiquetas (la primera fila se suele usar para
poner la barra que distingue a los directorios de las variables). En realidad la calculadora lo que
hace es transformar la cadena que le suministras en un grob y luego ponerlo en la pantalla, si
colocas un grob en vez de un string le facilitas la tarea.

Hago un inciso para recordar los fundamentos de las bases numéricas. Si nos dan un número de 4
dígitos MLKJ en alguna de las siguientes bases, este nos expresa:

BASE GUARISMOS USADOS M L K J


Binaria 0 1 2^3 x M + 2^2 x L + 2^1 x K + 2^0 x J
Octal 0 1 2 3 4 5 6 7 8^3 x M + 8^2 x L + 8^1 x K + 8^0 x J
decimal 0 1 2 3 4 5 6 7 8 9 10^3 x M + 10^2 x L + 10^1 x K + 10^0 x J
0 1 2 3 4 5 6 7 8
hexadecimal 16^3 x M + 16^2 x L + 16^1 x K + 16^0 x J
9 A B C D E F

33
Guía de programación User RPL

Si alguna vez has transformado un grob en cadena de caracteres, o si lo has puesto en la pila y le
has dado al cursor que indica hacia abajo entrando en el modo edición, puedes ver su estructura
que es:

"GROB "No Columnas" "No Filas" Gráfico"

En "No Columnas" y "No Filas" se expresa el ancho y alto del gráfico en píxeles (puntos de
pantalla). En "Gráfico" se da la información acerca del gráfico en una secuencia de
hexadecimales. ¿Cómo se codifica esa secuencia? Cada número hexadecimal se corresponde con
cuatro números binarios que son los que indican si el pixel que representan, con su valor 1 ó 0,
está encendido o apagado. Por tanto, cada hexadecimal representa a cuatro píxeles, pero hay una
salvedad, el hexadecimal #Eh (en binario #1110d) representa al grob 0111 (simétrico al 1110),
quiere esto decir que los cuatro píxeles han de leerse de derecha a izquierda por lo que los bites
más significativos se corresponden con los píxeles de más a la derecha. El orden que se sigue
para representar el gráfico es de izquierda a derecha y de arriba a abajo, el primer hexadecimal
representará entonces a los cuatro píxeles de la esquina superior izquierda. Como las filas de los
gráficos no tienen porque tener un número de píxeles divisibles por 4, al final de cada línea nos
quedarán 1, 2, 3 ó 4 píxeles. En el último caso no habrá ningún problema, ponemos el
hexadecimal correspondiente y vale. Pero si nos quedan, por ejemplo, 3 píxeles estos se
representarán por los 3 bits menos significativos, los de la izquierda y el restante lo ignorará el
sistema operativo de la calculadora cuando vaya a representar el gráfico, por ejemplo el grob 110
queda representado por el #3h (que en binario sería #0011d).

Como vale más una imagen que mil palabras vamos a obtener la codificación del siguiente grob:

Si lo separamos en filas y aplicamos la regla anterior tendremos:

34
Guía de programación User RPL

Si ponemos todos los hexadecimales seguidos obtendremos el grob:

GROB 21 8 0C78100FF5200284200BA110010900029400044200083100.

Un poco de historia: La revista Forum HP nació en Barcelona en Diciembre de 1992 y murió en


Diciembre de 1993. La dirigió Carles Crespo y entre sus colaboradores se encontraban Enrique
de la Torre, Julián Garrido, Daniel C. Bachero, Marcos Ortega y también colaboré algo yo. Se
distribuía por correo (entonces sólo usaban Internet los pocos que podían pagar una conexión y la
factura del teléfono). Tiempos gloriosos :) Esto viene a cuenta de que en uno de los números,
Daniel C. Bachero puso en esta revista un artículo en el que daba el código de un programa para
hacer estos iconos para los menús sin necesidad de hacer la bestialidad que he puesto antes ni
tener que dibujarlos en pequeñito en la pantalla. El archivo MENUS tiene el código fuente de ese
programa junto a unos cuantos ejemplos que hice en su día y que puse en el archivo
ETIQUETAS. si los quieres ver, pasa ETIQUETAS a la hp y con sólo presionar sobre ella verás

35
Guía de programación User RPL

como aparecen los menús gráficos (entre ellos está el Chaplin del ejemplo). Puedes hacer cuantos
desees con el programa ICONO.
ETIQUETAS no es más que:

\<<{
GROB 21 8 00E0000051000842000444000EFF10004000EFFFF0CFFF30
GROB 21 8 0EFF00054410800020EFFFF04111508FFF3001401083E830
GROB 21 8 0208008F0E3040114020A08020A080104001000000000000
GROB 21 8 00FF10080130049970CFFFF1CFB7F1EFFFF1EFFFF10E0C10
GROB 21 8 0C1800031C008C1A00831A00803800815810822820010010
GROB 21 8 0C78100FF5200284200BA110010900029400044200083100
GROB 21 8 02590084F5200DE61042D94081F13042E8400D061084F520
GROB 21 8 C10081E300E1FF08F1FFFFF1FFFFF1DD08F12200E1C10081
GROB 21 8 000000CFFF7000462000462000231000990000990000EF10
GROB 21 8 0000008008F0A20CF1E30C81FFFF81FFFF81000CF10008F0
GROB 21 8 0CC7000EDF000FBF300FBF100FBF000FB7008F7B00080100
GROB 21 8 0C300042400021B000294100CFFF300144400228300C1000
GROB 21 8 CC18302E7C701FFD709FFF70EFFF3087FF608FEFF00FDFF1
GROB 21 8 006C10007220F333604C8C90819C90836360030220000C10
} TMENU
\>>

Veréis que al final no hago presentar el menú con MENU si no con TMENU. Este comando lo
usamos cuando no queremos que el menú se guarde en la variable de sistema CST. Si hubiese
usado MENU, se me crea esa variable y cada vez que presione la tecla dura CST me aparecerá
ese menú. Sin embargo, al usar TMENU no se crea esa variable y tendríamos que poner de nuevo
la lista en la pila y presionar TMENU cada vez. Esto, que en principio parece un engorro, es
bueno para que nuestros programas no dejen llenos los menús de variables con CST.

Si deseas mostrar un menú durante la ejecución de un programa has de parar su ejecución con
PROMPT o HALT. Es lo normal ya que desearás que el programa se detenga para que el usuario
pueda darte los datos. Si deseas que se detenga con WAIT tienes dos posibilidades, ejecutar 0
WAIT ó -1 WAIT. Con la primera logras que el programa se detenga y WAIT te devuelve el
código de la tecla pulsada (mira en el capítulo 30 estos códigos) y continúa el programa. -1
WAIT hace lo mismo pero además fuerza al sistema a que muestre el menú especificado con
anterioridad. Hacer la prueba es muy fácil, sólo debes poner la línea -1 WAIT y 0 WAIT al final
del programa etiqueta, verás como sólo se muestra el menú en el primer caso.

Hay otra forma de 'detener' el proceso del programa. Es mediante el uso de KEY. Este comando
nos devuelve constantemente un 0 (falso) a la pila hasta que presionamos una tecla, en ese
momento devuelve un 1 (verdadero) y el código de la tecla presionada. Por ello KEY debe ser
usado en un bucle indefinido y en realidad no detiene al programa:

\<<
1 DO
1 +
UNTIL
KEY
END
IF DUP 51 \=/
THEN DROP2

36
Guía de programación User RPL

ELSE DROP
END
\>>

Este programilla va sumando 1 al primer 1 que ponemos hasta que presionamos una tecla, si es
ENTER (código 51) el programa deja el total en la pila, en caso contrario lo borra. Si el programa
es el siguiente veréis que no se muestra el menú hasta finalizar el programa, estamos en el mismo
caso que con 0 WAIT.
\<<{
GROB 21 8 00E0000051000842000444000EFF10004000EFFFF0CFFF30
GROB 21 8 0EFF00054410800020EFFFF04111508FFF3001401083E830
GROB 21 8 0208008F0E3040114020A08020A080104001000000000000
GROB 21 8 00FF10080130049970CFFFF1CFB7F1EFFFF1EFFFF10E0C10
GROB 21 8 0C1800031C008C1A00831A00803800815810822820010010
GROB 21 8 0C78100FF5200284200BA110010900029400044200083100
GROB 21 8 02590084F5200DE61042D94081F13042E8400D061084F520
GROB 21 8 C10081E300E1FF08F1FFFFF1FFFFF1DD08F12200E1C10081
GROB 21 8 000000CFFF7000462000462000231000990000990000EF10
GROB 21 8 0000008008F0A20CF1E30C81FFFF81FFFF81000CF10008F0
GROB 21 8 0CC7000EDF000FBF300FBF100FBF000FB7008F7B00080100
GROB 21 8 0C300042400021B000294100CFFF300144400228300C1000
GROB 21 8 CC18302E7C701FFD709FFF70EFFF3087FF608FEFF00FDFF1
GROB 21 8 006C10007220F333604C8C90819C90836360030220000C10
} TMENU
1 DO
1 +
UNTIL
KEY
END
IF DUP 51 \=/
THEN DROP2
ELSE DROP
END
\>>

37
Guía de programación User RPL

10. La entrada de datos en los programas .

Hay numerosas formas de solicitar al usuario los datos requeridos por un programa. La serie G
tienen ventajas sobre la S ya que posee dos herramientas más. Las siguientes son las formas más
usuales ya que si nos vamos al lenguaje System RPL encontraríamos otras maneras, incluso hay
muchos programas que nos ofrecen herramientas para lograr este mismo fin. También se puede
señalar que con un poco de imaginación podemos usar lo que sigue para dar formato a las salidas,
esto es, para presentar las soluciones de nuestros programas. Pero eso sería motivo de otro
artículo, vamos a comenzar por las entradas.

10.1. Toma de datos desde la pila.

Es la forma más evidente. Hay numerosos programas que requieren que todos los argumentos
estén en la pila antes de ejecutarse, en caso de que no estén se producirá el error "Too Few
Arguments" y el programa terminará.

Ventajas: El tamaño del programa se reduce ya que no es necesario hacer ninguna elaborada
toma de datos, valdrá simplemente con guardar el contenido de la pila en variables o trabajar
directamente en la pila.

Inconvenientes: El usuario ha de recordar cuántos datos, de que tipo y en qué orden hay que
suministrar al programa, si todos los programas fueran así lo llevábamos claro.

10.2. PROMPT.

Este comando es bastante fácil de utilizar. Requiere que en el nivel 1 de la pila haya una cadena
la cual será mostrada en el área de estado de la pantalla sin los delimitadores " ", deteniendo a
continuación la ejecución del programa para permitir que el usuario introduzca los datos. Tras
ello hemos de presionar la tecla CONT para que el programa continúe.
Ejemplo:
\<<
"Dame el ancho y alto"
PROMPT * "A" \->TAG
\>>

Este programa calcula el área de un rectángulo y le pone la etiqueta A:

Ventajas: Apenas ocupa espacio en el programa y presenta un texto recordando qué datos hay
que dar.

Inconvenientes: El usuario sigue teniendo que recordar algunas cosas como el tipo orden de los
datos.

38
Guía de programación User RPL

10.3. CLLCD DISP FREEZE HALT.

El uso conjunto de estos comandos nos permite una entrada más elaborada.
Ejemplo:

\<<
RCLMENU \->menu
\<<
{{"ANCHO"
\<< 'AN' STO
\>>
}{"ALTO"
\<<'AL' STO
\>>
}{}{"CONT"
\<< CONT
\>> }}
TMENU CLLCD
"Pon en la pila los \10
datos y presiona la \10
tecla de menú adecuada"
3 DISP 3 FREEZE HALT AL
AN * "A" \->TAG { AL AN }
PURGE menu MENU
\>>
\>>

\10 simboliza el retorno de carro/nueva línea que corresponde al carácter 10. Todos los caracteres
precedidos por la barra "\" son caracteres de la HP que no tienen equivalente en el PC y se traducen así.
Puedes ver la tabla de equivalencias en la pág. 27-17 del manual de la HP48 G o en la 663 del de la HP48
S.

Es otra versión del programa anterior, vemos que el código aumenta pero también lo hace la
claridad para el usuario. Es mejor crear un menú para que éste lo tenga más fácil, eso es lo que
hacemos al principio con TMENU (también podía haberse creado en el ejemplo de PROMPT), a
continuación detenemos el programa presentando un mensaje. El usuario pone en la pila los datos
y presiona las teclas de menú apropiadas que los guardan en las variables AL y AN, a
continuación presionando la tecla de menú CONT el programa continúa calculando el área y
poniendo el resultado etiquetado en la pila. Finalmente borramos las variables utilizadas y
volvemos al menú inicial guardado en la variable local 'menu'. Es una norma de educación que el
programa deje la calculadora tal como la encontró.

Figura 1 Figura 2 Figura 3

39
Guía de programación User RPL

CLLCD se encarga de borrar el área de estado y la pila. Vemos en la Fig. 1 como queda la
pantalla al utilizarse este comando, de no hacerlo esta quedaría como en la Fig. 2. Por otro lado,
DISP coloca la cadena del nivel 2 de la pila en la línea de pantalla indicada en el nivel 1, las
líneas se encontrarán entre 1 y 7. FREEZE congela la imagen de pantalla dependiendo de si se le
da como parámetro: 1 (área de estado), 2 (pila y línea de comandos), 4 (área de menús). La suma
de 1 y 2 daría lugar al "congelamiento" del área de estado y la pila (pasaríamos un 3 como
parámetro de FREEZE), etc. Los números mayores de 7 o menores de 0 son equivalentes al 7.

Ventajas: Hay una gran claridad para el usuario que no debe recordar más que el tipo de los
datos.

Inconvenientes: El código aumenta mucho lo que hace aumentar el tamaño del programa.

10.4. INPUT.

Este comando es más complicado pero a cambio ofrece bastante claridad. Al ejecutarse limpia el
área de la pila presentando una cadena indicadora en su parte superior. En la línea de comandos
aparece la llamada cadena de línea de comandos, también aparece el cursor y se activa el modo
de entrada al programa (en la esquina superior derecha aparece PRG). En ese momento se pueden
introducir los datos para a continuación presionar ENTER lo que devuelve al nivel uno de la pila
una cadena resultado y el programa continúa.

Ejemplo:
<<
"Dame los datos"
{ ":Largo:\10:Ancho:"
{ 1 0 } V } INPUT
OBJ\-> * "A" \->TAG
>> Fig. 4

Vemos en la Fig. 4 que la pantalla de entrada de datos que crea este programa es muy clara.

Estudiemos con más detenimiento los parámetros de INPUT:


En el nivel 2 de la pila ha de estar la cadena indicadora (que puede estar vacía: "").
En el 1 ha de haber una cadena (la cadena de la línea de comandos) o una lista. Esta lista puede
contener uno o más de los siguientes parámetros y en cualquier orden:
La cadena de la línea de comandos

Un número real o una lista con dos números reales especificando la posición del cursor en la línea
de comandos: Si sólo ponemos un número real, nos indica la posición en la que aparecerá el
cursor en la cadena de la línea de comandos, si es un 0 el cursor aparece al final de esta, si es
negativo el cursor será el de reemplazo y si es positivo el de inserción. Si ponemos una lista, el
primer número nos indica la fila de la línea de comandos en la que aparecerá el cursor (puede ser
positivo o negativo indicando lo mismo que en el caso anterior) y el segundo la posición del
cursor en esta; si es 0, aparece al final.

40
Guía de programación User RPL

Uno o más de los parámetros ALG, V ó \Ga. ALG activa el modo algebraico/programa (ver pág.
2.10 de la Guía de Usuario en la serie G o pág. 81 en la serie S). V verifica si la cadena resultado
contiene uno o más objetos válidos; en caso de no ser así muestra el mensaje Invalid Sintax y
vuelve a pedir los datos. \Ga activa el teclado alfabético.
Todos los siguientes son ejemplos válidos:

"Dame los datos" "" INPUT (Fig. 5)


"" { ":Lado:" 0 } INPUT (Fig. 6)
"Dame los datos" { ":Largo:\10:Ancho:" { 1 0 } V } INPUT (Fig. 7)
"Dame los datos" { V ":Largo:\10:Ancho:" { -2 0 } \Ga } INPUT (Fig. 8)

Fig. 5 Fig. 6 Fig. 7 Fig. 8

Si os fijáis, la cadena de la línea de comandos va entre los delimitadores de etiqueta ( :: ). De esta


forma al deshacer con OBJ\-> la cadena que nos devuelve INPUT, en la pila nos quedan objetos
etiquetados (Fig. 9), en caso de no hacerlo así nos quedaría la Fig. 10. Si deseáis que sólo os
queden los datos y nada más que los datos, poned la cadena de la línea de comandos entre
símbolos de comentario: Con { "@ Largo @(@ Ancho @" } obtendréis la Fig. 11.

Fig. 9 Fig. 10 Fig. 11

Ventajas: Se consigue un potente método de toma de datos con muy poco código.

Inconvenientes: Aunque se pueden introducir más de 4 líneas en la cadena de la línea de


comandos, sólo aparecen en la pantalla las 4 primeras, para ir a las demás hay que dar al cursor \|
v hasta llegar a ellas. El usuario normalmente cree que sólo están las primeras ya que no hay
ninguna señal que indique lo contrario. Además, en el caso de que haya 4 o más líneas, la cadena
indicadora desaparece al ser sobre escrita por la primera línea de la cadena de la línea de
comandos. Más que inconvenientes podemos decir que son defectos.

10.5. INFORM.

Esta es una de las nuevas herramientas de la serie G (es una caja de diálogo o formulario de
entrada). Nos presenta una pantalla en la que vienen las etiquetas de los datos a introducir y
podemos, con los cursores, desplazarnos de una a otra para introducirlos, editarlos, etc.
Ejemplo:

El símbolo @ (arroba) inicia un comentario en el lenguaje User RPL, lo que se escribe


tras él en la misma línea no se compila y no sólo eso sino que si tras guardar el programa

41
Guía de programación User RPL

se vuelve a editar, los comentarios han desaparecido. La calculadora compila el programa


al guardarlo en una variable, en ese momento deshecha todo lo que haya en una línea tras
las arrobas.

<<
WHILE @ Iniciamos una cláusula WHILE REPEAT
"AREA DE UN RECTANGULO" @ Título de la caja
{{"NOMBRE" "" 2}{ }
{"LARGO" "LADO INFERIOR" 0}
{"ALTO" "" 0}} @ Definición de los campos
{ 2 0 } @ Formato de los campos
{"Rectángulo" NOVAL NOVAL} @ Valores de RESET
{ NOVAL 4 2 } @ Valores iniciales
INFORM @ Muestra la caja de diálogo y el menú (con
NEXT obtenemos el siguiente)
REPEAT @ Vemos si se ha dado OK (hay un 1 en el nivel
1) o CANCEL (hay un 0)
IFERR @ En caso de que haya sido OK, iniciamos la
cláusula de captura de errores
LIST\-> DROP * "área" @ Deshacemos la lista que INFORM ha devuelto y
hacemos L * H
IF 3 PICK NOVAL \=/ @ Si el campo NOMBRE (que estará en el nivel 3
de la pila) no está vacío
THEN " de " + ROT + @ formamos la cadena "Area de NOMBRE" para el
mensaje solución.
ELSE ROT DROP @ Si NOMBRE=NOVAL, borramos el nivel 3. La
cadena será sólo "área"
END "\10" + SWAP + MSGBOX @ Añadimos un retorno de carro y la solución a
la cadena y la mostramos
THEN @ Si al hacer L * H, son L=NOVAL o H=NOVAL, se
produce un error
"Tienes que darme
el largo y el alto"
MSGBOX 3 DROPN @ Mostramos un mensaje y borramos la pila
END @ Finaliza la captura de errores
END @ Finaliza la cláusula WHILE REPEAT
\>>

La pantalla del programa tras introducir el nombre "CAJA" corresponde a la Fig. 12, la solución
va en la Fig. 13. Si hacemos "Reset all", tendremos la Fig. 14. Si tras ejecutar RESET damos OK
obtendremos la Fig. 15 ya que se producirá un error al multiplicar el ancho (NOVAL) por el alto
(también NOVAL). Si intentamos introducir en un campo un dato que no sea del tipo expresado
en la definición de campos (ejemplo: un real (TYPE= 0) en el campo NOMBRE que sólo admite
cadenas (TYPE= 2)), obtendremos la Fig. 16.

Fig. 12 Fig. 13 Fig. 14

42
Guía de programación User RPL

Fig. 15 Fig. 16

Los argumentos de INFORM son:


El título de la caja ha de ser una cadena que estará en el nivel 5 de la pila.
La definición de los campos será una lista en el nivel 4 que puede tener dos formatos:

Una cadena, que corresponderá a la etiqueta del campo


Una lista tal como { "etiqueta" "cadena de ayuda" tipo1 tipo2 ....}. La cadena de ayuda aparecerá
encima del menú (ver Figs. 12 y 13) y tipo1, tipo2, etc. son los tipos de datos válidos en ese
campo. En caso de que el usuario introduzca un dato de otro tipo a los especificados, se genera
una pantalla como la de la Fig. 16. Si en la lista se introduce algún parámetro de tipo, han de
introducirse obligatoriamente "etiqueta" y "cadena de ayuda" (ambas pueden estar vacías), sino
INFORM producirá el error "INFORM Error: Bad Argument Type".

La lista de definición de los campos puede ser mixta, esto es, puede tener campos con sólo la
etiqueta y otros que sean listas. Si deseamos que haya algún campo vacío, pondremos una lista
vacía en su lugar (como por ejemplo el segundo campo de nuestro ejemplo). La lista de
definición puede contener cualquier número de campos pero sólo se presentarán en pantalla (y se
devolverán a la pila) los que entren en pantalla dentro de las primeras cuatro filas a partir del
título .

En el nivel 3 de la pila ha de estar la información del formato con que los campos se presentan en
pantalla. Esta información puede ser:
Un entero representando el número de columnas en que se han de presentar (puede ser cualquier
entero mayor de 0 pero el número máximo de columnas que aparecerán será 10).
Una lista cuyo primer entero es el número de columnas (por defecto 1) y el segundo es el número
de espacios que habrá entre la etiqueta del campo y el dato introducido (por defecto 3). Si la lista
está vacía se entenderá que es { 1 3 }. Si sólo tiene un entero se entenderá que es el número de
columnas. Si en vez de una lista ponemos un entero también se entiende que son las columnas y
el resultado sería el que obtendríamos con una lista cuyo primer número fuera ese y el segundo
un 3.

En el nivel 2 de la pila ha de haber una lista con los valores que han de tomar los campos al
presionar la tecla de menú RESET. Puede estar vacía o contener tantos elementos como campos.
Si deseamos que el valor de RESET de un campo en particular esté vacío, hemos de poner
NOVAL en el lugar correspondiente a ese campo.
En el nivel 1 habrá otra lista con el valor inicial de los campos. También puede estar vacía o tener
tantos elementos como campos. NOVAL tiene la misma función de antes: El campo estará vacío.

Ventajas: INFORM nos ofrece un formulario de introducción de datos muy claro y potente,
tanto que durante la ejecución actúen del programa podemos pasar a la pila, con ALC, hacer lo

43
Guía de programación User RPL

que deseemos y continuar con el programa. Todo sin escribir una sola línea de código. Podemos
restringir el tipo de datos y ofrecer mensajes de error, también sin necesidad de escribir código.
Podemos ofrecer una ayuda específica para cada campo (cosa imposible con INPUT). En general
podemos decir que sin apenas código, ofrecemos al usuario una gran claridad y flexibilidad.

Inconvenientes: Al usarlo es lento, algunas veces desesperantemente lento.

10.6. CHOOSE.

Esta caja de selección es también una de las nuevas funciones de la serie G y hace más vistosa la
interfase de usuario.

Ejemplo:

\<<
WHILE @ Iniciamos una cláusula WHILE REPEAT
"CALCULO DE AREAS" @ Título de la caja de selección
{Círculo {"Triángulo" 2}
{"Rectángulo" 3} @ Lista con las posibilidades de selección
{"Pentágono regular" 4}
{"Hexágono regular" 5}}
1 @ Posición preseleccionada
COSE @ Se muestra la caja de selección y el menú (OK
o el CANCL, OK)
REPEAT @ Vemos si se ha dado OK (hay un 1 en el nivel
1) o CANCEL (hay un 0)
\-> n @ Guardamos en la variable local 'n' lo que
CHOOSE deja en la pila
\<<
CASE n 2 == @ Si 'n' es un 2
THEN TRIAN @ Ejecutamos el programa TRIAN que nos pide
datos y hace el cálculo
END n 3 == @ del área del triángulo.
THEN RECTAN @ Si hemos seleccionado la tercera opción, se
ejecuta RECTAN
END n 4 ==
THEN PENTA @ La cuarta corresponde al programa PENTA
END n 5 ==
THEN HEXA @ La quinta al HEXA
END n EVAL @ Si no era ninguna de las anteriores, en 'n'
estará almacenado 'Círculo',
END @ que es a la vez el nombre del programa y de
una selección
\>> @ Para ejecutarlo, hemos de ponerlo en la
pila
y ejecutar EVAL.
END @ Termina la cláusula WHILE REPEAT
>>

La pantalla generada por este programa corresponde a la Fig. 17

44
Guía de programación User RPL

Fig. 17 Fig. 18 Fig. 19 Fig. 20

Los argumentos de CHOOSE son tres:


Una cadena con el título en el nivel 3, si está vacía no aparece ningún encabezamiento.
En el nivel 2 una lista con las posibilidades de selección, sus elementos puede tener dos formatos:

El objeto a ser presentado (cualquiera).


Una lista con el objeto a ser presentado y el objeto que CHOOSE devuelve a la pila si este es el
seleccionado.

El último parámetro de CHOOSE es un entero en el nivel 1 de la pila que señala la opción


seleccionada por defecto; si es 0 la caja sólo puede usarse para visualizar los objetos (Fig. 18):
Tiene prácticamente el mismo cometido que MSGBOX.

Si seleccionamos un objeto que en la lista del nivel 2 no aparece como una lista (en nuestro
ejemplo 'Círculo') y presionamos OK, en el nivel 2 aparece dicho objeto (Fig. 19) y el programa
continúa (la Fig. 19 no se vería, es un proceso interno del programa ). Si la selección hubiera sido
'Triángulo', la pantalla sería la de la Fig. 20 (es otra figura aclaratoria que tampoco se vería). Si
presionamos CANCL sólo aparece un 0 en el nivel 1 de la pila y entonces REPEAT no ejecutaría
el bucle.

Ventajas: Es una forma vistosa de permitir al usuario elegir entre una serie de posibilidades.
Presenta una flecha para indicar que hay más de cuatro posibilidades.

Inconvenientes: Las cajas de selección no dejan de ejercer la misma función que los menús de
usuario pero con más código y menos posibilidades ya que desperdiciamos la pantalla. Los
gráficos los muestra como: "Graphic 21 x ....", no hay ninguna forma de que los presente como
tales gráficos. Para mi gusto ofrecen poca flexibilidad, eso si, quedan muy bonitas.

Los usuarios de la serie S pueden encontrar un sustituto a CHOOSE con FCHOOSE (Librería
de1985.5 by, es de Matthew Willis, en el Goodie Disk 10). También corre en la serie G. Los
parámetros son los mismos unicamente hay que poner FCHOOSE en el lugar de CHOOSE y
obtendríamos la Fig. 21. Tiene un bug: La flecha indicadora se mueve con los cursores de forma
que de la última opción pasamos a la primera presionando el cursor \|v, igualmente, de la primera
opción se pasa a la última presionando \|^ pero en este caso se "come" la primera columna de
píxeles de cada opción, según se muestra en la Fig. 22.

Fig. 21 Fig. 22

45
Guía de programación User RPL

Además de FCHOOSE la librería tiene el comando TITLE cuyo único parámetro es una cadena
que muestra en el área de estado. La presentación es la misma que el título de FCHOOSE, de
forma que \<< "CALCULO DE AREAS" TITLE 1 FREEZE \>> mostraría el mismo título de la
Fig. 21.

46
Guía de programación User RPL

11. La RECURSIVIDAD en Programación.

En esta ocasión veremos el concepto de la recursividad en la programación y especialmente en


como podemos usarla en nuestros programas de HP-4x para sacar provecho de sus importantes
ventajas.

11.1. Recursividad.

Para empezar veamos qué se entiende por el concepto de Recursividad : Se trata un método
de resolución de problemas que se basa en la descomposición de un problema grande en una
sucesión más o menos larga de problemas pequeños similares entre si que una vez combinados
nos ofrecen la solución total del problema original.

Un programa o sub-programa recursivo se llama a si mismo constantemente cada vez desde una
situación más sencilla (o igual ala anterior) de manera que se llega a un problema final trivial y el
proceso se detiene. Como dice Gary Cornell: "para un programador con experiencia el pensar
de forma recursiva representa la única alternativa a determinados problemas, produciendo a
menudo, soluciones especialmente elegantes y por lo tanto programas elegantes".

La recursividad se utiliza con preferencia frente a otros métodos de programación en multitud de


situaciones, como por ejemplo en resolución de problemas que conllevan el resolver muchos
pasos idénticos en sucesión, cada uno de cuyos estadios depende del anterior en alguna forma
(como por ejemplo el cálculo de un factorial que luego veremos). También es típico el uso de
algoritmos recursivos cuando se tiene que recrear la estructura de directorios de una unidad (o de
la memoria de la HP) o se debe hacer una búsqueda selectiva por un estructura de datos
complicada como pueden ser algunas jerarquías....
La recursividad en un programa la podemos aplicar de manera directa (es decir un programa se
llama a si mismo sucesivas veces de manera recursiva), o de manera indirecta (un programa
llama a otro y éste último llama al primero y así sucesivamente). Además en la HP podemos
definir mediante el uso de variables locales compiladas un subprograma dentro de uno principal
mayor, de manera que se llame a si mismo sin salir del principal... Tranquilo/a ahora veremos un
ejemplo de esto último.

Antes de comenzar a ver algún ejemplo, debo advertir que la recursividad es un concepto
complicado aunque a simple vista pueda parecer lo contrario, y se debe tener un cuidado especial
y una "visión de futuro" importantes cuando se plantea la resolución de un problema mediante la
recursividad, ya que podemos entrar en un proceso infinito de llamadas de un proceso a si mismo
de manera que al final nos quedemos sin memoria de usuario ( o más técnicamente "sin memoria
de pila") y se nos cuelgue el sistema en el mejor de los casos. Lo que hay que hacer es asegurarse
siempre que en cualquier situación que se nos plantee en mayor o menos tiempo deberemos
asegurar que se va a llegar a un problema trivial y la situación recursiva se va a detener.

Para comenzar vamos a ver dos maneras de resolver el mismo problema: la tradicional y la
recursiva.

47
Guía de programación User RPL

El problema que planteo es hallar el factorial de un número cualquiera. No me voy a plantear


nada más que ilustrar el concepto de recursión, y por lo tanto no entro en disquisiciones acerca de
la manera de pedir datos (ver el texto de Mario al respecto en esta página) ni en la comprobación
de errores o validez de argumentos (que sean números naturales, etc..).

La forma tradicional de resolver este problema sería el uso de un bucle que sin más fuese
multiplicando los números entre el dado y 1 disminuyendo en la unidad el número dentro del
bucle. Este programa tendría un aspecto tal que así:

\<<
DUP 1 - 1 FOR I
I *
-1 STEP
\>>

Primero duplicamos el número en la pila para tener un argumento para la primera multiplicación
que realicemos y después establecemos los límites del bucle de manera que dentro de este
multipliquemos los números hasta el 1 por lo que haya en la pila (que será el resultado de las
anteriores operaciones). De hecho aún se puede mejorar el programa haciendo que el bucle llegue
sólo hasta el 2 y no hasta el 1 puesto que la última multiplicación por 1 es innecesaria y aumenta
el tiempo de proceso.

Lo cierto es que este programa es extremadamente sencillo y en este caso no estará justificada el
uso de la recursión, pues el programa no quedará tan claro (la recursión siempre es difícil de ver
como trabaja). De todas formas en este planteamiento que yo califiqué de "tradicional" un
programador experimentado puede ver fácilmente que ya se contempla el concepto de
recursividad. Bien es cierto que no se llama a otro programa varias veces, pero como en la HP
dejamos siempre argumentos en la pila, aquí el operador * del producto actúa casi como si fuese
un programa que llamamos de manera recursiva. Creo que me he explicado ¿No?..

Ahora veamos como se haría de manera recursiva, que aunque quede más complicado nos
permitirá ver como se utiliza esta técnica. Para ello veamos el siguiente listado:
Primero escribimos un pequeñísimo programa que se encarga de poner el primer argumento en la
pila y de llamar acto seguido al recursivo "Factorial" que será el realmente encargado de hacer las
operaciones

\<<
DUP Factorial
\>>

Ahora el encargado realmente de operar es "Factorial" :

\<<
1 -
IF DUP 1 > THEN
DUP Factorial END
*
\>>

48
Guía de programación User RPL

que lo único que hace es restar uno al número que se le pasa como argumento y se llama a si
mismo si no hemos llegado a 1 en esta resta. Después, cuando las subsiguientes instancias de si
mismo terminan y devuelven el control al programa que las llamó (es decir nos ponemos en cada
instancia justo después del END) se multiplican los números que hay en la pila sucesivamente,
puesto que es la única operación que queda. Dicho de manera más llana: Son instancias del
mismo programa que se contienen unas a otras y que no dejan continuar la ejecución de su
"padre" hasta que ella misma y todas sus hijas no hayan terminado de ejecutarse...

En fin, aunque este ejemplo no es probablemente el más apropiado (de hecho la versión recursiva
va más lenta que la tradicional) si ha servido para mostrar en poco espacio y con una tarea
sencilla el concepto de recursión, que es lo que se buscaba.
Puesto que se pueden resolver problemas mucho más complicados que este con la Recursividad
propongo al lector/ra el siguiente desafío:

Dado el nombre de una variable de la HP, hacer un programa que la busque por toda la memoria
(por todos los directorios y subdirectorios) de manera que devuelva una lista con todos los
lugares donde se ha localizado la variable. Yo lo he hecho con recursión embebida dentro del
propio programa en una subrutina local (posibilidad que comento al principio de este texto) y no
se me ocurre otra manera de hacerlo.

De todas maneras si a alguien se le ocurre otra forma de hacerlo sin utilizar la recursión aunque
ni siquiera vaya más rápido que el mío, me gustaría que me lo hiciese saber.

Este texto es propiedad intelectual de Mario de Lama y José M. Alarcón Aguín y no puede ser
utilizado ni modificado sin su permiso expreso.

Mario de Lama   malar@arrakis.es


http://users.servicios.retecal.es/mdelama/

49

También podría gustarte