mpScript 1.01

Manual de usuario
(C) Angel Ortega 1997/1998

Sintaxis

El lenguaje mpScript está orientado al manejo de ficheros de texto. Puede aparecer embebido en otro programa (como en el editor de textos MedPro 2.1), ejecutado por el intérprete mpScript mps o compilado en su propio fichero ejecutable. Su principal característica es que los documentos son manejados como desde dentro de un editor de textos, incorporando comandos de movimiento del cursor, edición, operaciones de bloques y un mecanismo simple para el control de flujo.

Para la descripción de la sintaxis del lenguaje, veamos el siguiente ejemplo de código fuente mpScript:


<mpScript>
;
; Primer programa mpScript:
; Hace una copia del fichero prueba.txt como prueba2.txt
;

onerror(fallo)

load(t,"prueba.txt")            ; carga el texto y lo nombra t 
save(t,"prueba2.txt")           ; graba t con un nuevo nombre
exit()

:fallo
echo("Imposible cargar 'prueba.txt'")
</mpScript>

En este sencillo programa se presentan varias de las características propias de mpScript. Como se ve, el programa está delimitado por las marcas <mpScript> y </mpScript>, de inicio y final, respectivamente. La primera es imprescindible e identifica el fichero de texto como un fichero mpScript; la segunda es opcional, asumiéndose el final del fichero como final del programa si dicha marca no se encuentra. Asímismo, se muestra que se pueden introducir comentarios mediante el carácter ; (punto y coma), tanto en una línea por sí solos como a continuación de una línea con código.

La primera línea de código, onerror(fallo), implementa una de las principales características de mpScript: la captura de errores. Cuando se trabaja con textos, numerosas operaciones causan error, entendiéndose como tal la imposibilidad de efectuarse una operación, como intentar mover el cursor más abajo de la última línea, no encontrar una cadena en una búsqueda o no poder abrir un nuevo texto. Estos errores generan una bifurcación en el flujo normal del programa: en este caso, se ordena saltar a la etiqueta fallo si alguno de los comandos ejecutados no se puede completar. El programa continúa desde ahí y se desactiva la captura de errores hasta la siguiente llamada a onerror(). Si se ocasiona un error no capturado, la ejecución se interrumpe y se informa al usuario de la imposibilidad de continuar. Como se puede ver, las etiquetas se insertan precediendo el nombre con un carácter : (dos puntos) y deben ir al comienzo de la línea, sin espacios ni tabuladores previos (al contrario que el resto de los comandos, que pueden indentarse sin problemas).

Este mecanismo de captura de errores, combinado con la instrucción de salto incondicional goto(etiqueta), permite una sencilla implementación de bucles y toma de decisiones.

Otros dos de los comandos mostrados, load() y save(), introducen el concepto de textos. Los textos son ficheros de texto cargados en memoria, donde pueden ser manipulados mediante comandos que simulan operaciones efectuadas con un editor de texto, como mover el cursor hacia alguna de las direcciones, escribir en la posición del cursor, cortar y pegar bloques, etc. El comando load() presentado carga el fichero 'prueba.txt' y lo nombra t. Este nombre (pueden utilizarse nombres de texto de hasta 15 caracteres) identificará al texto hasta que sea cerrado y se utilizará en todos los comandos de movimiento y edición que le afecten. Es posible abrir hasta 8 textos simultáneos. Como era de esperar, el comando save() guarda en disco el texto t con el nombre 'prueba2.txt'.

Los otros comandos en este programa son exit(), que provoca la terminación del mpScript, y echo(mensaje), que muestra una cadena de información al usuario. La forma en que es presentada dicha cadena depende de la implementación: si se trata de mpScript interpretado o compilado, el mensaje se imprimirá en la pantalla en una línea, mientras que si es mpScript embebido en MedPro 2.1, el mensaje se mostrará en la línea de estado (aunque debido a que ahí también se muestra el código de salida del programa ejecutado, es probable que el mensaje no llegue a poderse leer).

Este pequeño programa no ha trabajado mucho. Veamos otro que hace algo más:


<mpScript>
;
; Segundo programa mpScript:
; Abre un fichero y le añade la línea /* mpScript rules! */ al
; principio de cada línea
;

onerror(errorcarga)
load(t,"prueba2.txt")

onerror(final)

:bucle
        movebol(t)                       ; principio de la línea 
        write(t,"/* mpScript rules! */") ; escribe la línea
        movedown(t)                      ; baja una línea
        goto(bucle)

:final

save(t,"prueba3.txt")
exit()

:errorcarga
echo("Imposible cargar 'prueba2.txt'")

</mpScript>

Aquí se puede observar el uso de dos comandos onerror() diferentes: el primero, onerror(errorcarga), permite controlar si el fichero no se ha podido encontrar, y el segundo, onerror(final), permite forzar la salida del bucle en caso de que el texto se acabe.

Los nuevos comandos, movebol(), write() y movedown(), efectúan cambios en la posición del cursor y en el propio texto. El primero mueve el cursor al principio de la línea en curso, el segundo escribe la cadena enviada como argumento en la posición del cursor y el tercero mueve el cursor una línea hacia abajo. De estas tres, las dos últimas generan error, aunque es bastante improbable que sea write() (implicaría no haber podido escribir en el texto debido a una falta de memoria o algún otro error más extraño). Si el cursor se encuentra en la última línea, movedown() fallará porque no hay más líneas en el texto y el programa continuará en la etiqueta final, donde se graba en disco y se termina.

El siguiente ejemplo muestra otra de las características fundamentales de mpScript, el uso del portapapeles:


<mpScript>
;
; Tercer programa mpScript:
; Ejemplos de operaciones básicas con el portapapeles 
;

; Abre prueba3.txt como t1 y crea t2
open(t1,"prueba3.txt")
create(t2)

; Escribe un texto inicial en t2
write(t2,"Contenido de prueba3.txt:\n")
write(t2,"-------------------------\n")

; Copia todo el contenido de t1
mark(t1)
moveeof(t1)             ; Va al final del fichero
mark(t1)
copymark(t1)

; Lo pega sobre t2
pastemark(t2)

; Y lo guarda
save(t2,"prueba4.txt")

</mpScript>

En este ejemplo se ilustran varios conceptos nuevos: la posibilidad de tener abiertos simultáneamente más de un texto (con nombres t1 y t2), la posibilidad de introducir en las cadenas de texto caracteres especiales con sintaxis de lenguaje C (los \n introducidos en los comandos write()) y los comandos de manejo del portapapeles mark(), copymark() y pastemark(), que respectivamente marcan el inicio (o el final) del bloque, lo copian a y lo pegan desde el portapapeles hasta el texto indicado. Debe tenerse en cuenta que, aunque el motor mpScript esté embebido en un entorno que disponga de portapapeles (como el editor de texto MedPro 2.1), estas operaciones se efectúan sobre un área especial privada que nada tiene que ver con el exterior.

Pero lejos de ser un mero espacio temporal para las operaciones de bloques, el portapapeles en mpScript tiene otro propósito aún más importante: el de servir de 'variable' para ciertas operaciones. Veamos el siguiente ejemplo:


<mpScript>
;
; Cuarto programa mpScript:
; El portapapeles utilizado como variable
;

; Crea un texto, escribe en él un nombre de fichero, 
; lo marca y lo envía al portapapeles
create(t)
write(t,"prueba4.txt")
markline(t)             ; marca la línea completa
copymark(t)             ; copia al portapapeles
close(t)                ; cierra el texto

; Carga el texto
loadmark(t2)

; Pide un nombre de fichero
input("Nombre de fichero a cargar:")
loadmark(t3)

</mpScript>

De nuevo aparecen varios conceptos nuevos. En el principio del programa, se crea un texto en el que se escribe el nombre de un fichero, que es marcado y enviado al portapapeles. A continuación, se ejecuta el comando loadmark(t2), que carga sobre t2 el fichero de texto cuyo nombre está en el portapapeles. Esto, que puede parecer inicialmente una retorcida variante de load(), permite efectuar largas secuencias de operaciones sobre un conjunto de ficheros, cuyos nombres se pueden ir obteniendo de otro texto, que actúa como almacenamiento temporal. Un ejemplo quizá más claro se puede ver en la línea siguiente, con el comando input(). Este comando (cuya presentación en pantalla varía según la implementación de mpScript sea interpretada o embebida en otro entorno) solicita al usuario que introduzca un texto, mostrando el mensaje "Nombre de fichero a cargar:". El texto tecleado por el usuario (de una sola línea) se escribirá en el portapapeles, de donde loadmark() lo tomará como nombre de fichero a cargar.

Este nuevo ejemplo obtiene la segunda palabra de cada línea de cada texto de una lista y ordena todas sobre otro fichero:


<mpScript>
;
; Quinto programa mpScript:
; Obtiene el segundo campo de cada línea de un
; grupo de ficheros y los ordena todos
;

; Crea el texto que contendrá la lista
create(lista)

; Escribe la lista de ficheros
write(lista,"fichero.001\n")
write(lista,"fichero.002\n")
write(lista,"fichero.003\n")
write(lista,"fichero.004\n")
write(lista,"fichero.005\n")
write(lista,"fichero.006\n")
write(lista,"fichero.fin\n")

; Vuelve arriba
movebof(lista)

; Crea el texto que contendrá los campos
create(campos)

; bucle de ficheros
:ficheros
        ; si hay error aquí, no hay más ficheros 
        onerror(nomasfich)

        ; obtiene un fichero
        markline(lista)
        copymark(lista)
        movedown(lista)
        loadmark(t)

        ; bucle de líneas

        onerror(nomaslin)
:lineas

                ; avanza una palabra a la derecha, marca,
                ; sigue hasta la siguiente, marca y copia al 
                ; portapapeles
                movewordright(t)
                mark(t)
                movewordright(t)
                mark(t)
                copymark(t)

                ; guarda la palabra en campos
                ; y añade nueva línea
                pastemark(campos)
                write(campos,"\n")

                ; avanza hasta la siguiente
                ; línea
                movedown(t)
                movebol(t)

                goto(lineas)
:nomaslin

        ; cierra t
        close(t)

        goto(ficheros)
:nomasfich

; ya está relleno el texto campos:
; ordenarlo

; marca el texto completo
markall(campos)

; 'corta' (copia y borra) todo campos
cutmark(campos)

; ejecuta el comando del DOS "sort"
exec("sort")

; copia el resultado de "sort"
pastemark(campos)

save(campos,"campos.ord")

</mpScript>

En este ejemplo se aplican todas las técnicas vistas hasta ahora. Se recorren dos textos (uno con los nombres de los ficheros y otro en el que se almacenan cada uno de ellos) en dos bucles anidados. Se hace un uso intensivo del portapapeles, tanto para operaciones habituales de copiar y pegar bloques (para recoger la segunda palabra de cada línea de los ficheros) como para ir recopilando la lista de ficheros a procesar. Finalmente, se invoca el comando exec(), que ejecuta un comando del DOS (en este caso el filtro sort), enviándole por su entrada standard el contenido del portapapeles y recogiendo la salida standard en el mismo, que se pega en el texto definitivo para guardarlo en disco.

Como se ve, mpScript es un lenguaje sencillo que muestra toda su potencia aplicado al mantenimiento de ficheros de texto.

Referencia de comandos

Esta sección contiene una descripción de todos los comandos de mpScript, clasificados por grupos. Los comandos marcados con el símbolo [*] generan, en caso de no poder completarse, un error capturable por el comando onerror().

Manejo de textos

create(texto) [*]
Crea un texto y le asigna el nombre texto.

load(texto,"fichero") [*]
Carga el fichero de texto y le asigna el nombre texto.

save(texto,"fichero")
saveas(texto,"fichero")
Guarda texto en disco con el nombre "fichero". save y saveas son sinónimos.

close(texto)
Cierra texto. Deja de ser válido.

text(texto,"identificativo")
Sólo para mpScript embebido. Asigna el nombre texto a un texto ya cargado en el entorno (en el caso de MedPro, el texto en una ventana). El identificativo entre comillas debe corresponderse exactamente con el nombre del fichero en la ventana. Las operaciones efectuadas en el texto se reflejarán cuando el programa mpScript en curso termine.

loadmark(texto) [*]
Carga con el nombre texto el fichero cuyo nombre está en el portapapeles.

savemark(texto)
Salva texto con el nombre de fichero que está en el portapapeles.

Movimiento del cursor

moveup(texto) [*]
Mueve el cursor una línea hacia arriba.

movedown(texto) [*]
Mueve el cursor una línea hacia abajo.

moveleft(texto) [*]
Mueve el cursor un carácter a la izquierda. Si el cursor estaba en la primera columna, se posiciona en el último carácter de la línea anterior, si la hubiera.

moveright(texto) [*]
Mueve el cursor un carácter a la derecha. Si el cursor estaba en el final de la línea, se posiciona en el principio de la siguiente, si la hubiera.

movewordleft(texto) [*]
Mueve el cursor una palabra a la izquierda.

movewordright(texto) [*]
Mueve el cursor una palabra a la derecha.

movebol(texto)
Mueve el cursor al principio de la línea en curso.

moveeol(texto)
Mueve el cursor al final de la línea en curso.

movebof(texto)
Mueve el cursor al principio del texto.

moveeof(texto)
Mueve el cursor al final del texto.

seek(texto,"cadena") [*]
Busca la cadena. Si se encuentra, el cursor se posiciona en el carácter siguiente a la cadena encontrada.

Edición de textos

write(texto,"cadena") [*]
Escribe la cadena en la posición del cursor. La cadena es como las del lenguaje C (con \n para el fin de línea, \t para el tabulador, \\ para el carácter \, etc.).

delete(texto) [*]
Borra un carácter.

deleteline(texto) [*]
Borra la línea en curso.

replace(texto,"origen","destino") [*]
Reemplaza la cadena origen por destino.

replaceall(texto,"origen","destino")
Reemplaza todas las ocurrencias de la cadena origen por destino.

Operaciones de bloques

mark(texto)
Marca el comienzo o el final de un bloque.

unmark(texto)
Desmarca el bloque.

copymark(texto)
Copia el bloque marcado al portapapeles.

cutmark(texto)
Copia el bloque al portapapeles y lo borra.

pastemark(texto)
Pega el contenido del portapapeles en la posición del cursor.

clearmark(texto)
Borra el bloque.

markline(texto)
Marca la línea en curso, sin incluir el fin de línea.

markall(texto)
Marca el texto entero.

Control de flujo

onerror(etiqueta)
Establece etiqueta como la dirección de salto en caso de producirse un error.

goto(etiqueta)
Fuerza un salto incondicional a etiqueta.

exit()
Termina el programa.

test(texto,offset,"cadena") [*]
testnot(texto,offset,"cadena") [*]
Comprueba si cadena está en la posición offset de texto, y en caso de ser así, efectúa un salto a la dirección capturada por onerror(). Si offset es 0, se comprueba que la cadena esté en cualquier parte de la línea. Debe tenerse en cuenta que el salto se genera si la cadena se encuentra, al contrario de lo que podía parecer inicialmente. si el comando es testnot(), el salto se efectúa si la cadena no es encontrada.

if(texto) [*]
ifnot(texto) [*]
Comprueba si la cadena texto es lo que hay en el portapapeles. Si es así, se efectúa un salto a la dirección capturada por onerror(). Si el comando es ifnot(), el salto se efectúa si la cadena no es la misma.

Otros

set(variable,valor)
Asigna valor a variable, que puede ser cualquiera de las siguientes:

iso_8859_1
Activa (con el valor 1) o desactiva (con 0) el uso del juego de caracteres ISO-8859-1 al cargar o grabar textos.

savetabs
Activa (con el valor 1) o desactiva (con 0) la grabación de tabuladores en lugar de espacios.

autoindent
Activa (con 1) o desactiva (con 0) la indentación automática.

tabsize
Define el número de espacios que genera la inserción de un tabulador.

wordwrap
Define la columna en la que se hace un word wrap, o se desactiva mediante el valor 0.

exec("comando del DOS")
Ejecuta comando del DOS, enviando a su entrada estándar el contenido del portapapeles y recogiendo su salida estándar en el portapapeles.

input("prompt")
Pide al usuario la introducción de una cadena de texto, que queda en el portapapeles.

parameter(número) [*]
Introduce en el portapapeles el parámetro nº número (comenzando desde 1). Los parámetros pueden ser enviados desde la línea de comandos del sistema operativo (no puede usarse desde mpScript embebido).

echo("cadena")
Imprime en pantalla cadena.

echomark()
Imprime en pantalla la primera línea del portapapeles.

message("cadena")
Muestra en pantalla cadena, esperando a que el usuario pulse una tecla.

Errores

Esta es una lista de los mensajes de error de mpScript:

Histórico de versiones

1.01
Los comandos if() e ifnot() han cambiado: quedan sustituídos por test() y testnot() para comparación de cadenas y se convierten en comprobadores del contenido del portapapeles (para poder evaluar parámetros y cosas así). Nuevo comando message().

1.0
Versión inicial.

(C) Angel Ortega 24/02/1998 (19/11/1997)