[LinuxFocus-icon]
Hogar  |  Mapa  |  Indice  |  Busqueda

Noticias | Arca | Enlaces | Sobre LF
[an error occurred while processing this directive]
convert to palmConvert to GutenPalm
or to PalmDoc

[Photo of the Author]
por Emre Demiralp
<emre(at)kardelen.fe.itu.edu.tr>

Sobre el autor:

Soy estudiante en del Istanbul American Robert College, y al mismo tiempo uno de los administradores del sistema de ordenadores de la facultad de Ciencias y Letras de la Universidad Técnica de Estambul. El sistema operativo predominante es LINUX. Intereses: PovRay y PostScript, animación, diseño de CD's, programación, holografia. Soy usuario de Linux desde 1994.



Taducido al español por:
Alberto Pardo <apardoyo(at)yahoo.es>

Contenidos:

 

Postscript III:Manejo de datos en PostScript: Arrays, Variables, Bucles y definiciones de Macros

[Ilustration]

Resumen:

Quien sabe demasiado, se equivoca demasiado.
-Proverbio turco-.

El autor continua la descripción del manejo de datos en lenguaje PostScript. La definición de arrays, operaciones con arrays, definición de variables, bucles y definiciones de macros se presentan el el presente artículo con suficiente detalle. Además de ilustrarlo con ejemplos y preguntas que se contestarán en el proximo artículo.



 

Introducción

Este es el tercero de una serie de artículos sobre PostScript. Continuaremos con las operanciones con la pila de PostScript. Se recalcará sobre la definición de los arrays, operadiones con arrays, definiciones de variables, definiciones de loops y macros. Se explicaran los aspectos más importantes de estos puntos, ilustrandiose con algun ejemplo. Se ampliarán los conceptos de las operaciones don la pila en un futuro artículo

 

Arrays y operadores de Array

En anteriores artículos de esta serie, se comento la estructura de los operadores de stack y de las operaciones con las que podemos las extructuras de las pilas. Recordamos que todo lo que guardamos en la pila eran enteros, exceptuando unos elementos especiales que se usan como puntos de refenrencia en las pilas. Estos elementos los llamabamos -marktype- y los operadores: cleartomark y counttomark, Y serán utilizados para limpiar o contar los elementos desde el principio hasta el final de la pila.Tambien se puede crear otro tipo de extructura que puede incluir muchos elementos. Este tipo de estructura se le denomina array y es posible operar con sus elementos usando los operadores de array del lenguaje PosScript. Vamos a ilustrar estos conceptos con un ejemplo de ordenar los operadores de un array.

[  :Esto crea un elemento marktype en el stack. A menos que no se acompañe de ] funciona igual que un comando mark. Todos los elementos que entren en el operando stack despues de este operador considerados elementos individuales aunque esten marcados con un punto de referencia despues de ellos en el operando stack. A continuación se explica la relación entre [ y mark

GS>[ pstack
-marktype
GS<1>2 3 mark pstack
-marktype-
3
2-marktype-
GS<4>

]  :Este es el acompañante del operador anterior [. El stack debe contener un elemento marktype o tipo marca antes de que se de ese elemento. De hecho, se el considera como una marcar que indica el final del array y completa la construcción del array. Todo final necesita un principio, PostScript tiene su compañero, la marca de inicio ] . Si [ se piederde, PostScript devuelve un mensaje de error y no se ejecuta la operación. Si el elemento registra el operando stack despues de [ entonces se crea un array vacio y se almacena una sola entidad o elemento en el array ( el elemento marktype se convierte en parte del array, aquí aparece como un elemento diferente) tal como se muetra a continuación:

GS>[ pstack
-marktype-
GS<1>] pstack
[]
GS<1>

Despues de todo esto, el stack contiene un único elemento, un array vacio. Para crear un Array con datos, se realiza con [ y ] junto con los elementos al mismo tiempo en una única entrada de datos. Tal como se muestra a continuación:

GS>[ 1 2 3 ] pstack
[1 2 3]
GS<1>

El array se considera como una única entidad.

Se puede crear un array que este vacio pero que pueda contener un número determinado de elementos. Para ello será necerario el uso de null que significa nada.

GS>[ null null ] pstack
[null null]
GS<1>

array:Este comando necesita un parámetro entero. Si el parámetro es n el comando es n array. Esto permite crear un array conteniendo exactamente n null elementos. Hace lo mismo que crear un array con los simbolos de inicio y fin. Por ejemplo, 3 array, es lo mismo que [ null null null ]. Busca su parámetro como primer elemento del operando stack. Si se da antes del comando, entoces entra el operando stack y se convierte en el primer elemento que toma el comando. Si no se introduce el parámetro, entonces el primer elemento del operando stack determina lo que pasará. Si el valor es entero, su valor se utilizará por el comando, en otro caso aparece un mensaje de error debido a incompatibilidades.

length:Evalua el número de elementos de un array. Los elmentos null tambien se cuentan. Este operador necesita un parámetro que debe estar situado como primer elemento del array.Y desaparece cuando finaliza la ejecución de la operación. Para que no haya problemas este parámetro se ha de asignar antes de ejecutar la operación. Veamos un ejemplo

GS>[ 1 2 3 4 5 ] length pstack
5
GS<1>

Si no damos el paramentro para el operador length entonces el comando usara el primer elemento del operando stack, se sustituira por el número de elementos que haya en el array

GS<1>pstack
[1 2 3 6 7]
GS<1>length pstack
5
GS<1>

aparecerá un mensaje de error, si el primer elemento del operando stack no es un array.

get:Necesita dos parámetros. El primero ha de ser un array y el segundo un entero. Toma un elemento especificado del array. La posición viene determinada por el segundo parámetro: el entero. La posición viene indehe position of the element to be gotten is the second parameter of the operator. The positions are indexxada con números naturales, empezando por cero. De hecho esta regla se aplica a todos los parámetros del operando. El comando usa estos parámetros y despues son borrados. Su tipo ha de ser compatible con los valores dados. No se recalcará sobre este punto nunca más. Veamos un emjemplo de get .

GS[1 6 3 0 9] 0 get pstack
1
GS<1>

put:Necesita tres parametros.Son respctivamente: array, índice y el elemento a insertar en el array. Se ejecuta de la siguiente manera: Toma el array, busca la localización con el índice, y sustituye el elemento que hay por el tercer parámetro. El array resultante, no se almacena en el operador stack. Por consiguiente, definiremos un array variable (o en terminologia Postcript, una llave), mediante el uso del operador put. De esta manera, el array se asigna al stack. Veamos un ejemplo:

GS>[1 2 3] 0 8 put
GS>

De echo, no ha ocurrido nada y no aparece ningún mensaje de error. Put se ha ejecutado correctamente, pero no se ha guardado el array en el stack. Para ello se ha de hacer un paso más:

GS>/ar [ 1 2 3 ] def
GS>ar 0 8 put
GS>ar pstack
[8 2 3]
GS<1>

Primero se define el array variable o llave. Su nombre es ar. El segundo paso consiste en cambiar el primer elemento (con indice 0) por 8 usando el operador put. Después con ar pstack se inserta el valor del array variable ar en el opertador stack y se visualiza su contenido. Ya se mencionará como se define la variable más adelante,en este artículo. Los comentarios sobre diccionarios y el diccionario Stack se realizarán en posteriores artículos de esta serie.

getinterval:Crea un subarray a partir de un array. Necesita tres parametros.Respectivamente son : el array, de donde se crea el sukbarray, el índice que especifica el primer elemento del subarray, y un entero que indica el número de elementos del subarray. Cuando se ejecuta, toma el número de elementos (indicado por el tercer parametro)del array (el primer parámetro) empezando por la posición indicada por el índice (segundo parámetro)y copia el resultado en un nuevo array. El nuevo array se inserta en el operando stack. Por ejemplo,

GS>[1 2 3 4 5 6 7 8 9] 2 3 getinterval pstack
[3 4 5]
GS<1>

putinterval:Reemplaza un subarray de un array dado por otro array. Se necesitan tres parametros : Primero, el array de donde se extrae el subarray; segundo, el integer que indica la posición del subarray a cambiar; y tercero, el array que subtituirá al subarray. Este comando es similar a put. Veamos un ejemplo:

GS>/ar [1 2 3 4 5 6 7 8 9] def
GS>ar 3 [0 0 0] putinterval
GS>ar pstack
[1 2 3 0 0 0 7 8 9]
GS<1>

aload:Toma el array como parámetro y copia sus elementos como entidades simples en el stack. Veamos un ejemplo:

[1 2 3] aload pstack
[1 2 3]
3
2
1
GS<4>

astore:Reemplaza todos los elementos de un array dado como segundo parémero con una secuencia de elementos cuyos número es igual a la longitud del array del operador stack. El resultado es un nuevo array con los elementos sustituidos.

GS>1 2 3 [null null null] astore pstack
[1 2 3]
GS<1>

copy: Copia el primer parámetro del array en el primer subarray dado como segundo parámetro. El resultado es el array copiado, no el segundo subarray. Veamos un ejemplo:

GS>[1 2 3] [4 5 6 7 8] copy pstack
[1 2 3]
GS<1>/ar [4 5 6 7 8] def
GS<1>[1 2 3] ar copy
GS<2>ar pstack
[1 2 3 7 8]
[1 2 3]
[1 2 3]
GS<3>

Los elementos del array no han de ser enteros. Puede ser arrays de carácteres o cadenas de carácteres. Se puede anidar estructuras de arrays. Esto permite utilizar operaciones sobre matrices y definiciones de macros sobre matrices. Esto permite trabajar con secuencias multidimensionales.

 

Claves y Variables

Como cualquier otro lenguaje de programación se puede definir variables. Esto permite manenjar cantidades sin tener en cuenta su situación en la memoria. Se puede guardar un dato en memoria y acceder mediante una dirección o clave. La primera aproximación es el uso de punteros como en C.... Si no quieres utilizar direcciones, ya tienes suficiente con el uso de claves. En este caso es el interprete del lenguaje quien se encarga del acceso a memoria y otras operaciones. Así puedes definir un nombre y asignarle un valor. La manera que tiene de trabajar PostScript es mediante diccionarios que contienen los nombres y sus definiciones relacionadas. Así un diccionario se compone en parejas : la llave ó key y el valor ó value. Por ejemplo, add es un nombre(key)que hace la suma(value). PostScript conoce el significado de add por que esta guardado en el dictionario cuyo ic systemdict. Si se introduce 1 2 add pstack se muestra el resultado 3 debido a que PostScriptbecause PostScript mira lso tres nombres y ejecuta la instrucción. Priemro encuentra 1 y 2 y entonces add. Los primeros objetos son enteros, así que se guardan en la memoria. El tercer elemento es una cadena de carácteres,así que debe ser un nombre (key) o no. PostScript busca en su diccionario o diccionarios dicho nombre. Si lo encuentra, ejecuta la instrucción. Desde que existe add en el diccionario, systemdict hay una acción (value) para este nombre (key). Toma los dos primeros elementos del stack, realiza la suma y el resultado lo pone como primer elemento del stack. La parte que queda de la orden es la cadena pstack que esta en el diccionario y significa " presenta el contenido del stack en la salida standard ". Por otro lado se puede tomar la siguiente linea del interprete como un error : 1 2 dad pstack. En este caso el interprete puede presentar un mensaje de error debido a que no es una llave o nombre, dad definida en el diccionario de PostScript.

No estamos limitados a las definiciones del diccionario del sistema de PostScript. Se puede definir nuestros propios procedimientos o comandos del usuario. Si lo que se definen son identificadores, entonces los podemos llamar variable aunque no es su uso en la terminologia PostScript. Nuestro proposito es realizar llamadas desde otros lenguajes de programación conocidos. Para realizar una definición de varible se debe declarar /x value def donde value es un objeto de Postcript del tipo integer, array, string ... Podemos considerar, por ejemplo, el caso de /x 12 def en la línea del prompt. Cuando esta hecho, el interprete de PostScript toma tres objetos, /x, 12 and def. Los objetos que empiezan con el caracter "/" los reconoce como llaves o nombres. Se pueden insertar en el stack sin comprobar si existenen en algún diccionario. El comando def esta definido en el diccionario del sistema de PostScript de tal manera que necesita dos parametros: El primero se define como una llave o nombre, y el segundo es el valor que se le asigna al nombre. Por lo tanto, PostScript crea el par key-value después de este comando, /x 12 def, lo publica y lo coloca en el siguiente diccionario current dictionary.Este elemento es el primero del diccionario, del que más adelante haremos mención. Despues de este punto, x se reconocerá por Postcript como 12 durante el resto de la sesión.

En principio cualquier cadena de caracteres que empiece con "/" se puede utilixar como llave. De todas maneras es mejor utilizar letras y números. Evitar el uso de caráteres especiales del tipo : "/" , puntos, etc... Ya que PostScript los puede interporetar como modificadores, dando lugar a respuestas inesperadas. La limitación del número de caracteres viene determinado por el interprete que se este utilizando. De hecho, no es practico utilizar nombres formados por 100 caracteres, aunque el interprete lo permite. PostScript distingue entre mayusculas y minusculas, lo que aumenta su versatilididad. Hay que ser cuidadoso y no definir nombres que esten en el diicionario de Postcript ya que el nuevo nombre sustituirá al del diccionario. Po ejemplo, si se define /add 13 def entonces add se confvierte en una constante y perdemos esta orden en lo que queda de sesión.

 

Bucles

PostScript permite crear instrucciones repetitivas, denominadas bucles. Esto permite repetir el mismo tipo de ejecuciones. A continuación presentamos una instrucción que permite esto:

repeat:Necesita dos parámetros.El primero es del tipo integer he indica el número de repeticiones que se han de hacer y el segundo es un procedimiento que consiste en un bloque acciones. In PostScript la definición de bloque se realiza con los limitadores { y }. Las instrucciones o comandos se han de poner entre estos limitadores. La sintaxis es de la forma n { ... } repeat. Al ejecutar esta instrucción, PostScript toma el primer operando y lo coloca en el stack. Se ejecuta todas las instrucciones incluidas en el bloque { ... } . Y por último se busca la orden repeat en el diccionario del sistema y se ejecuta el bloque n veces. Veamos un ejemplo.

GS>3 {1} repeat
1
1
1
GS<3>

Tres valores enteros , 1 se insertan en el stack. De hecho, este procedimiento es muy simple. Se trata de entrar 1. Veamos un ejemplo un poco más complicado.

GS>1 5 {1 add} repeat pstack
6
GS<1>

En este ejemplo, primero 1 se entra en el operando stack y se ejecuta la instrucción {1 add} 5 veces sobre el stack. Esta ejecución en 5 veces sigue de la siguiente manera. Se ejecuta en el primer paso 1 add . add necesita dos parametros, el segundo de los cuales se da en el procedimiento. El primer parametro (o operand) en terminologia PostScript se toma del stack. Ademas se ejevuta el primer paso de la repetición, 1 1 add . El único elemnto del stack se elimina tras la ejecución y el resultado, que es 2, se inserta como primer elemento. En el segundo paso continua con 2 1 add y se obtiene un nuevo resultado 3. Esto nos lleva al tercer paso 3 1 add. Así con los siguientes: 4 1 add y 5 1 add. Al final solo tenemos un elemento en el stack 6.

for:Este comando utiliza una variable de control del tipo entero para la ejecución del proceso que se ha de repetir. La variable de control empieza desde un valor dado y se va incrementando despues de cada ejecución del proceso. Este proceso continua hasta sobrepasar un limite preestablecido. Este comando necesita cuatro variables, las primeras tres son respectivamente Initial, Increment, and Limit. Estos tres parametros son del tipo entero o decimal. El cuarto parametro es el procedimineto, que puede ser una instruccioón o un bloque de instrucciones indicados por los siguientes simbolos { y }. La sintaxis del comando es Initial Increment Limit Procedure for. Cuando se ejecuta, PostScript crea un contador temporal varible (control variable en terminologia PostScript ) y lo inicializa al valor Initial. Este valor se inserta en el stack. Que puede o no ser utilizado por Procedure como operando. Si se usa se elimina del stack, en caso contrario permanece en él. Despues de que la variable contador se actiova a Initial se ejecuta Procedure. A continuación se incrementa la variable contador con el valor de Increment. El bucle continmua hasta que el valor del contador excede del valor Limit. Lo que se esta indicando es que se ha sobrepasado el intervalo entre Initial y Limit. Si Increment es positivo, la ejecución de for se completa cueando la varable cotador sobrepasa a Limit. El otro caso, la ejecución de for para cuando la variable contador es menor que el Limit. Hay que asegurarse que la variable Initial debe ser menor que Limit cuando Increment es positivo y viceversa. Veamos un ejemplo para ser más explicitos.

GS>1 -0.5 -1 {} for pstack
-1.0
-0.5
0.0
0.5
1.0
GS<5>clear 0 1 1 23 {add} for pstack
276
GS<1>

El primer comando es del tipo null y no hace nada. Todos los valore pasan al stack y permanecen allí hasta que se utilicen. El segundo, la siguiente orden incluye un procedimiento add que necesita dos operandos. El primer elemento corresponde al primer elemento del stack y el segundo corresponde al valor del contador del bucle, se inserta en el stack en este paso. El segundo comando evalua la suma de los 23 primeros numeros positivos enteros. Se necesita un valor inicial para poder realizar la suma. Por eso temnemos el 0 antes de la orden. No forma parte de la orden for.

forall:Este comando ejecuta un procediemiento por cada elemento de un array dado. Para ello enumera cada elemento empezando desde 0. Utiliza una variable temporal para controlar el bucle. La variable temporal empieza desde 0, incrementadose de 1 en 1 hasta llegar al final del array. El bucle es parecido al comando for. La diferencia esta, en que se emplean elementos de un array en lugar de una variable para contar. Este comando necesita dos operandos. El primero es el array con los elementos que se van a utilizar y el segundo es el procedimiento. La sintaxis completa es is Array Procedure forall . Veamos a continuación un ejemplo, cuyo objetivo es obtener la suma de un array dado y poner los elementos en otro array.

GS>0 [11 23 45 -89 26 12 0 -34] {add} forall pstack
-6
GS<1>[1 22 -12 0] {} forall pstack
0
-12
22
1
-6
GS<5>

loop:El procedimiento busca el comando que ha de ejecutar y lo hace indefenidamente. El bucle se rompe externamente, por ejemplo con Ctrl-C . Se puede mejorar el programa permitiendo que en determinadas condiciones el bucle se pare. La sintaxis del comando es Procedureloop.

 

Procedimientos o Definiciones de Macros

En PostScript, Procedure (procedimiento) or Macro significa un conjunto ordenado de objetos. Estos deben ser agrupados con limitadores { and }. Se pueden crear utilizando la definición /Macro1 {1 add 2 mul} def. Una vez hecho /Macro y su valor {1 add 2 mul} se añade al diccionario colocandose como primer elemento, como par key-value. Al aparecer el objeto Macro1 en el promt de interprete, se ejecuta lo que tiene esta macro. Lo que se defina en la macro, puede ser simple o complidaca. En futuros artículos ampliaremos el tema de las macros.

 

Ejercicios

Cuando empezamos esta sere de artículos dimos algunos ejercicios para el lector. En este artículo encontraras las soluciones.

  • 1)  Escribir un procedimiento que tome un valor entero y realice la suma de los cuadrados desde 1 hasta ese valor inclusive.

  • 2)  Escribir un procedimiento que tome dos enteros y calcule los cubos de los enteros comprendidos entre estos dos enteros inclusives. Se debe crear un array donde poner los resultados.

  • 3)  Escribir un procedimiento que calcule la media aritmetica de los elementos de un array. Se debe obtener también la raíz cuadrada de la suma de los cuadrados de los elementos del array.

  • 4)  Assume that the PostScript does not have exp procedure and write a procedure which takes two numerical values as operands and considers the first operand as base and the second operand as the exponent. The procedure will evaluate the exponent-th power of the base. The operands must be maintained in the operand stack after the operation.

  • 5)  The mathematical object, matrix, can be considered as the array of arrays. An N row square matrix can be represented by an N-element array whose elements are again N-element arrays. Call this type array of arrays "Square Matrix". Write a procedure which takes a square matrix operand and evaluates its trace (the sum of the diagonal elements). The result and the original square matrix must be maintained after the operation.

  • 6)  Se escribe un procedimiento que utiliza un operador de matrices cuadradas y evalua su transpuesta.(las filas se intercambian por las columnas).

  • 7)  Se escribe un procedimiento que apartir de dos matrices cuadradas y se obtiene la suma de ambas. La matriz cuadrada original y el resultado se deben guardar despues de la operación.

  • 8)  Escribir un procedimiento que tome dos matrices cuadradas y realice el producto entre ellas. El resultado y las matrices originales han de conservarse despues de la operación.


  • Contactar con el equipo de LinuFocus
    © Emre Demiralp, FDL
    LinuxFocus.org

    Pinchar aquí para informar de algún problema o enviar comentarios a LinuxFocus
    Información sobre la traducción:
    en --> -- : Emre Demiralp <emre(at)kardelen.fe.itu.edu.tr>
    en --> es: Alberto Pardo <apardoyo(at)yahoo.es>

    2002-02-21, generated by lfparser version 2.21