Category:Amazing Hopper: Difference between revisions

no edit summary
No edit summary
 
(45 intermediate revisions by the same user not shown)
Line 1:
{{stub}}{{language|Amazing Hopper}}
 
___ _____ ___ __ __ ___ ___ ___ ___
Line 9:
 
HOPPER (Amazing Grace!), es un prototipo de máquina virtual, inspirado en las ideas de Grace Murray Hopper, pero llevadas un paso más allá. Su sintaxis corresponde a un "pseudo-ensamblador", y pretende ser una "gramática profunda", es decir, una gramática que permita sostener a otras gramáticas, definidas en el nivel del programador final, denominado "nivel de abstracción superior".
 
Cosiga una versión actualizada en el sitio Web:
 
https://github.com/DanielStuardo/Amazing-Hopper
 
Como prototipo, HOPPER es un programa cuya naturaleza responde a la investigación: ese es el motivo de su diseño y desarrollo.
Line 51 ⟶ 55:
== INSPIRACION ==
 
HOPPER es una aplicación práctica de una investigación realizada por el autor, sobre "gramáticas profundas" (al estilo "Wittgenstein", no teniendo nada que ver con el concepto elaborado por "Chomsky"), un soporte para la definición de cualquier forma o estilo de programación, ya sean lenguajes formales, como lenguajes naturales. Se trata, por lo tanto, de un prototipo que demuestra los resultados actuales de dicha investigación, y podría ser modificado en el futuro, gracias al avance de la misma.
 
En la década de los años 50 del siglo XX, Grace Murray Hopper, científica computacional estadounidense, buscaba la manera de escribir lenguajes de programación más cercanos al ser humano. En aquella época, los programadores debían programar en ensamblador. Los resultados de su esfuerzo, se traducen en un prototipo llamado FLOW-MATIC, y en el lenguaje COBOL, este último en uso en la actualidad.
Line 218 ⟶ 222:
El stack almacena datos que serán los argumentos de las instrucciones HOPPER.
 
{DATO} ==> mete DATO al stack.
 
donde DATO puede ser:
 
1) Una constante numérica, de cadena, un parámetro.
2) Un array.
 
2) Un array.
 
OBSERVACION. Pueden apilarse muchos datos en el stack, aunque el número de posiciones del stack es limitado (10), este puede ser cambiado con la cláusula .STACK. Ejemplo:
Line 320 ⟶ 323:
Un control "!" mantiene un solo dato en el stack, partiendo desde el HEAD. Dos controles, "!!", mantienen los datos en la posición HEAD y HEAD+1 del stack. En general, El control "!(n)", mantiene "n" datos en el stack. Ejemplo:
 
// imprime todo el stack, pero lo mantiene gracias a "!!!"
{"Mensaje de Hopper: ",2000.9,"\n"}!!!print
 
// imprime otra vez el stack, pero esta vez lo consume.
{"\n"}print
 
Line 341 ⟶ 344:
(Sobre el uso de variables, ver las secciones que hablan de ellas, a continuación)
 
** MOVER un dato del stack a una variable:
{100},mov(v)
==> ahora, el stack está vacío, y v=100
 
** COPIAR un dato del stack a una variable:
{"mensaje"},cpy(s)
==> ahora, el stack continúa con "mensaje", pero s="mensaje"
Line 364 ⟶ 367:
genera la siguiente línea preprocesada:
 
postfix,{"mensaje"},len,{100},mul,postfix,n=0,mov(n)
 
Line 370 ⟶ 373:
#compute{
n:=( len("mensaje")*100 )
}
genera la siguiente línea:
{"mensaje"},len,{100},mul,r=0,cpy(r)
 
NOTA: si va a usar ":=", la expresión a asignar debe ser colocada entre paréntesis.
 
Line 381 ⟶ 384:
HOPPER puede apilar una matriz o vector (un array), de dos maneras:
 
1) copiando el puntero a la matriz (forma usual).
2) copiando la matriz completa.
 
2) copiando la matriz completa.
 
Para copiar la matriz completa, se debe usar el control "@" antes de la variable.
Line 396 ⟶ 398:
1.61907 1.90591
1.3727 1.84048
 
94.807 17.5982 ==> esto es "n" original, por 100 = t.
61.9072 90.5911
37.2703 84.048
 
En cambio, si no se usa el control "@", solo copia el puntero.
n=0, {2,3}rand array(n) // crea un array aleatorio de 3 filas y 2 columnas en "n"
Line 411 ⟶ 413:
1.8034 1.84302
1.93367 1.23961
 
157.044 147.523 ==> esto es "n" incrementado, por 100 = t.
180.34 184.302
Line 424 ⟶ 426:
 
OBSERVACION 3. No se permiten instrucciones combinadas dentro de "{}". Observe que "++n" está fuera de "{}".
 
 
== CUESTIONES SINTACTICAS TRIVIALES ==
=== COMENTARIOS ===
 
HOPPER soporta comentarios de línea "//" y comentarios de bloque "/**/".:
// este es un comentario de línea
 
// este otro también
y comentarios de bloque:
/* este es un comentario de bloque
que puede ser empleado en cualquier
parte */
/* este otro también lo es */
 
=== SEPARADOR DE STRING ===
Line 517 ⟶ 525:
Es posible detectar y generar datos NAN, con las siguientes instrucciones:
 
1) detectar nan: nan?
2) detectar inf: inf?
3) generar array de nan: nanarray
 
También se pueden generar valores NAN y -INF con operaciones aritméticas 0/0 y n/0.
 
 
=== CODIGOS DE ESCAPE ===
Line 528 ⟶ 535:
HOPPER usa los siguientes códigos de escape en el despliegue con PRINT:
 
* - \n Salto de línea
* - \t Tabulación de 8 espacios.
* - \" despliega la comilla dentro de un string.
* - \XX códigos de escape de colores del terminal. Esto será descrito más adelante.
 
Por ejemplo:
Line 542 ⟶ 549:
"Todos son buenas personas"
Será desplegado en una sola línea.
 
 
=== SEPARACION DE LINEAS ===
Line 576 ⟶ 582:
HOPPER maneja tres tipos de datos:
 
*) números (internamente: int, long y double)
*) cadenas
*) booleanos (0 y 1)
 
==== NUMEROS ====
 
Los números pueden ser, internamente, de tipo int, long y double, según las operaciones efectuadas, dado que esos son los tipos empleados en la versión 3.0 de Harbour. HOPPER usa la estructura de datos interna de Harbour para manejar los tipos numéricos. En el futuro, si HOPPER abandona su calidad de prototipo, usará su propia estructura de datos, y allí se usarán tipos más extremos, como long long double, y excesos como ese.
Line 598 ⟶ 604:
10 = 0xAh = 0x1010b = 0x12o
 
====CADENAS====
 
Las cadenas son tratadas internamente como arreglos de caracteres, aunque todo eso queda oculto a los ojos del programador. HOPPER puede hacer y deshacer con cadenas de caracteres, gracias a funciones prestadas por Harbour, y a funciones de factura propia. En tal sentido, no me equivoco al afirmar que el mejor tratamiento de cadenas, lo tiene Harbour. Echadle un vistazo a ese proyecto.
 
====BOOLEANOS====
 
Los valores booleanos no se pueden calcular como números, salvo que se los convierta a números.
Cualquier variable puede ser evaluada lógicamente por las instrucciones lógicas, y convertida a tipo booleano, de acuerdo al siguiente criterio:
 
*) cadenas:
Si tiene caracteres = 1 (true)
Si está vacía = 0 (false)
 
*) números:
Si es distinto de 0 = 1 (true)
Si es 0 = 0 (false)
 
Se pueden declarar variables de tipo simple como TRUE o FALSE, con las instrucciones:
 
true(v) ==> asigna 1-lógico a "v"
false(v) ==> asigna 0-lógico a "v"
Line 626 ⟶ 632:
 
OBSERVACION. Las instrucciones TRUE y FALSE no trabaja con matrices, por el momento.
 
 
=== VARIABLES ===
Line 637 ⟶ 642:
{"Valor global A = ",a,", B = ",b,"\n"}print
{0}return
 
.locals
label:
Line 655 ⟶ 660:
...
a={}, {1,2,3,4,5,6} add row(a)
 
 
=== LIMPIAR VARIABLES ===
Line 756 ⟶ 760:
x-- ==> apila "x" en el stack, y luego, decrementa.
 
Sea "M" matriz, y contiene "10,0,5,-3,1":
++M ==> "11,1,6,-2,2"
--M ==> "9,-1,4,-4,0"
Line 770 ⟶ 774:
n++, print ==> imprime 10
{n} print ==> ahora, imprime 11
 
 
=== OPERADORES MATEMATICOS ===
Line 863 ⟶ 866:
 
[ #include <archivo.hh> | [path/]archivo.hh ]
[ #import archivo-libreria
[ #define DEFNAME cuerpo-de-define [\
[ #define DEFNAME[(argumentos)] cuerpo-de-define [\
continuación ] ]
continuación ] ]
[ #defn DEFNAME cuerpo-de-define-con-TAGS-macro-programación [\
[ #defn DEFNAME[(argumentos)] cuerpo-de-define-con-TAGS-macro-programación [\
continuación ] ]
continuación ] ]
[ #proto NOMBRE_PSEUDO_FUNCION[(arguentos)] ]
[ #context | #context-free <lista-de-contextos> ]
Line 878 ⟶ 882:
[ <label>:
instrucciones-HOPPER ]
[ #define DEFNAME[(argumentos)] cuerpo-de-define [\
continuación ] ]
[ #defn DEFNAME[(argumentos)] cuerpo-de-define-con-TAGS-macro-programación [\
continuación ] ]
{<valor-retorno>}return
[.locals]
Line 889 ⟶ 893:
back ]
 
OBSERVACIONES. los comandos de macro-procesamiento #DEFINE y #DEFN pueden ser usados en cualquier parte del programa, pero solo serán visibles desde el momento en que son declarados en adelante.
 
== ETIQUETAS, CONTEXTOS Y PSEUDOFUNCIONES ==
Line 913 ⟶ 917:
jsub(obtener mensaje), print // imprime el mensaje del stack
...
 
obtener mensaje:
{"Hola mundo!\n"} // mete mensaje en el stack.
back
 
La invocación puede suceder hacia arriba. Ejemplo:
 
obtener mensaje:
{"Hola mundo!\n"} // mete mensaje en el stack.
back
:
Line 931 ⟶ 935:
print
...
 
mensaje:
{"Es un record Guiness!!!\n"}
back
OBSERVACION. GOSUB requiere un valor, de cualquier tipo simple. Si unano instrucciónhay XX?nada devuelveen un array de valores deel verdadstack, GOSUB arrojará un error.
 
=== PSEUDOFUNCIONES ===
Line 1,005 ⟶ 1,009:
 
Un contexto de este tipo permite definir una llamada especial a un contexto, con sinónimos para dicha llamada. Existen dos tipos de contextos de alto nivel: #CONTEXT y #CONTEXT-FREE. #CONTEXT define una llamada que se invoca consultando el stack por un valor de verdad TRUE: si es FALSE, no hay invocación. Por otro lado, #CONTEXT-FREE define una llamada simple.
#CONTEXT, internamente, usa lalas instruccióninstrucciones KEEP,GOSUB.
#CONTEXT-FREE, internamente, usa la instrucción JSUB.
 
Line 1,058 ⟶ 1,062:
 
8. Se puede adaptar un analizador de voz para codificar contextos de alto nivel.
 
 
== CODIGO DE ALTO NIVEL ==
Line 1,226 ⟶ 1,229:
caso de un array, apila el puntero
de dicho array.
 
{@A} Apila una copia del array A en
el stack. El contenido del stack
Line 1,235 ⟶ 1,238:
el stack por el Garbage Collector.
Usese con cuidado.
 
{[&n]} Apila una copia del parámetro "n"
en el stack.
 
clearstack Marca los elementos desreferenciados del
stack, para que el Garbage Collector los
Line 1,272 ⟶ 1,275:
CADA UNA DE LAS INSTANCIAS CREADAS, SI
SE USAN MATRICES PESADAS.
 
emptystack? Devuelve TRUE si el stack de trabajo isemptystack
está vacío.
 
sizestack Devuelve el número de posiciones
usadas del stack.
 
kill Elimina el último elemento apilado
en el stack (el top).
 
keep | ! Evita que el elemento ubicado en el
head del stack sea consumido por una
Line 1,288 ⟶ 1,291:
elementos del head del stack
luego de consumidos.
 
dup Duplica el último elemento del stack.
 
.stack n Define un tamaño de "n" posiciones
en el stack.
 
{A}cpy(C) Copia el contenido del top del stack,
a la variable C, sin extraer el dato.
 
{A}mov(C) Mueve el contenido del top del stack,
a la variable C, extrayendo dicho dato.
Line 1,457 ⟶ 1,460:
==== SALTOS CON RETORNO ====
 
{A}gosub(ETIQUETA) Salta a ETIQUETA si A es TRUE (1), yo tiene
retornauna concadena BACK.no vacía, o un número distinto
de cero, o un array. Si el stack está vacío,
GOSUB arrojará error.
Retorna con BACK.
jsub(ETIQUETA) Salto incondicional a ETIQUETA, y retorna
con BACK.
Line 1,786 ⟶ 1,792:
{A,B}hypot Calcula la hipotenusa, con la hypot(A,B)
fórmula pitagórica C=sqrt(A^2+B^2).
 
{...}mulall Multiplica todos los datos que se mulall(A,B,...)
encuentren en el stack. Los datos
Line 1,794 ⟶ 1,800:
encuentren en el stack. Los datos
deben ser numéricos.
 
=== FUNCIONES MATEMATICAS ===
 
Line 1,815 ⟶ 1,821:
{A}sqrt Devuelve la raíz cuadrada de A sqrt(A)
 
{A}cbrt Devuelve la raíz cúbica de A cbrt(A)
{A}int Castea A a entero largo int(A)
 
{A}floor Función piso de A floor(A)
Line 1,852 ⟶ 1,858:
{A,B}min Devuelve el mínimo entre A y B. min(A,B)
Misma descripción que MAX.
 
{A,B}mulmat Devuelve la multiplicación mulmat(A,B)
matricial entre A y B.
Line 2,239 ⟶ 2,245:
== TOKENS ==
 
HOPPER DESCRIPCION
-----------------------------------------------------------------------------------
{A}toksep Establece un separador de token, el cual será usado por $, $$,
totaltoken y print using token.
Ejemplo:
{","}toksep
Por defecto, el separador de token es espacio en blanco.
 
gettoksep Obtiene el separador de token activo, y lo deja en el stack.
 
{A}gettoken(B)
{A}$(B) Obtiene el token A de la cadena B.
Ejemplo:
s="María tenía un corderito blanco"
{4}$(s) ==> corderito
{4}get token(s) ==> corderito
{A,B}modtoken(C)
{A,B}$$(C) Modifica el token B de la cadena C, con la cadena A.
Ejemplo:
s="María tenía un corderito blanco"
{"lorito",4}$$(s) ==> María tenía un lorito blanco
{"lorito",4}mod token(s) ==> María tenía un lorito blanco
 
totaltoken(C) Devuelve la totalidad de tokens existentes en la cadena C.
Ejemplo:
s="María tenía un corderito blanco"
{" "}toksep
total token(s) ==> 5
 
 
== TERMINAL Y SISTEMA ==
=== FUNCIONES DE TERMINAL ===
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
echo Imprime todo el stack en pantalla echo()
Ejemplo:
{"Valor: ",200,"otro",100.9}echo
==> Valor: 200otro100.9
 
print Imprime todo el stack en pantalla print()
{"Valor: ",200,"otro",100.9}print
==> Valor: 200otro100.9
printusingtoken Imprime todo el stack, usando el printusingtoken()
separador de token definido en
toksep. Ejemplo:
{";"}toksep
{"Valor: ",200,"otro",100.9}printusingtokenprint using token
==> Valor: 200;otro;100.9
show Imprime el stack, sin consumirlo. show()
 
escape imprime una secuencia de escape.
El primer caracter debe ser "[".
Internamente, se añade el caracter
de escape "\033".
Ejemplo:
{"[?25l"}, escape
==> esconde el cursor.
 
puts(A) Imprime A en pantalla.
{}puts imprime el TOP del stack.
{}puts imprime el TOP del stack.
 
{X,Y}goxy Posiciona el cursor en la posición
{X,Y}goxy Posiciona el cursor en la fila X, columna Y, en pantalla.posición
fila X, columna Y, en pantalla.
 
{X}gox Posiciona el cursor en la fila X.
{X}gox Posiciona el cursor en la fila X.
 
{Y}goy Posiciona el cursor en la columna Y.
{Y}goy Posiciona el cursor en la columna Y.
 
strtoutf8 Convierte el string a codificación UTF8.
strtoutf8 Convierte el string a codificación UTF8.
 
utf8tostr Convierte el string a codificación ANSI.
utf8tostr Convierte el string a codificación ANSI.
 
NOTA: STRTOUTF8 y UTF8TOSTR no están definidas
para trabajar conNOTA: matrices.STRTOUTF8 Paray eso,UTF8TOSTR puedeno están definidas
hacer uso depara latrabajar macrocon ITERATOR,matrices. yPara trabajareso, puede
sobre cada elementohacer uso de unala macro ITERATOR, y matriz.trabajar
sobre cada elemento de una matriz.
 
=== CODIGOS DE ESCAPE ===
Line 2,325 ⟶ 2,331:
Los siguientes códigos de escape se introducen dentro de una cadena de caracteres.
 
\n Inserta un salto de línea en la cadena.
Ejemplo:
{"\nValor: ",v,"\n"}print
\t Inserta una tabulación en la cadena.
 
\" Despliega el caracter comilla en la
cadena. Ejemplo:
{"Mensaje \"especial\""}print
==> Mensaje "especial"
 
\e
\033 Inserta un código de escape (27).
 
=== CONSTANTES TERMINAL ===
Line 2,356 ⟶ 2,362:
CODIGO CODIGO
HOPPER TERMINAL DESCRIPCION
------------------------------------------------------------------
\BGLGR \e[47m Activa color background ligth grey
\BGDGR \e[100m Activa color background dark grey
Line 2,373 ⟶ 2,379:
\BGM \e[45m Activa color background magenta
\BGC \e[46m Activa color background cyan
 
\CUR \e[3m Activa atributo CURSIVA
\ENF \e[1m Activa atributo ENFATIZADO
Line 2,379 ⟶ 2,385:
\BLK \e[5m Activa atributo BLINK
\INV \e[7m Activa atributo INVERT
 
\DGR \e[90m Activa color dark grey
\LGR \e[37m Activa color ligth grey
Line 2,396 ⟶ 2,402:
\M \e[35m Activa color magenta
\C \e[36m Activa color cyan
 
\OFF \e[0m Desactiva todos los atributos y colores.
 
Line 2,407 ⟶ 2,413:
=== FUNCIONES DE LLAMADA A SISTEMA ===
 
{}execv Ejecuta una cadena de comando, sin
esperar un resultado.
Ejemplo:
{"ls -lstar"},execv,print
==> Muestra el directorio actual.
 
{}exec Ejecuta una cadena de comando, y
guarda el resultado en el stack.
Ejemplo:
{"ls -lstar"},exec, mov(v)
==> guarda la lista de directorio
actual en "v".
V=`línea-comando` Ejecuta la línea-comando y guarda el
resultado en la variable "v".
Ejemplo:
v = `ls -lstar`
 
OBSERVACION. Una llamada a sistema puede incluir la constante macro E_EXECNULL, con la cual, la llamada se realizará en paralelo a la ejecución del programa. Ejemplo:
 
Line 2,435 ⟶ 2,441:
=== FUNCIONES DE VARIABLES DE SISTEMA ===
 
{V}getenv Obtiene el valor de la variable de getenv(V)
sistema "V". Ejemplo:
{"PATH"}getenv
==> /usr/local/sbin:/usr/local/bin:...
 
{A,V}setenv Establece, localmente, una variable setenv(A,V)
de sistema "V" con valor "A".
Ejemplo:
{"100","CODIGO"}setenv
 
{V}unsetenv Elimina la variable de entorno "V". unsetenv(V)
 
{A}env? Devuelve TRUE si A es una variable isenv(A)
de entorno. Ejemplo:
{"PATH"}env?
==> 1 (TRUE)
 
== INTERVALOS Y RANGOS DE ARRAYS ==
Line 2,458 ⟶ 2,464:
No obstante, se puede acceder a una sintaxis más estándar, para algunas de las operaciones, dentro de #HIGH-LEVEL.
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
 
[a,b,c] Establece un intervalo a operar en
las matrices y vectores. Acepta
hasta 3 dimensiones, y se pueden
definir, de izquierda a derecha,
filas, columnas y páginas.
Las instrucciones que usan estos
intervalos son:
GET, PUT, = (asignación).
Para acceder a una porción de
un array, por ejemplo, de 2D,
se suele hacer esto:
 
[2:3,4:end]get(array),plus'10',
put(array)
lo que obtiene una sub-matriz de
"array", de 2 filas y 7 columnas,
suponiendo que array tiene 10;
luego, suma 10 a sus elementos,
y vuelve a ponerlo en el array
original.
En #HIGH-LEVEL, esto se humaniza:
#hl{
array[2:3,4:end] = array[2:3,4:end]+10
}
o bien:
#hl{
array[2:3,4:end] += 10
}
aunque #HIGH-LEVEL es más sencillo
de usar, es más costoso que la
versión ensamblada de HOPPER.
Ejemplos de intervalos:
[10] fija la posición 10
de un vector cualquiera;
también, fija la coor-
denada 10 de una
matriz 3D.
[10:15] fija un intervalo que va
desde la posición 10
hasta la 15, dentro
de cualquier vector
que la use.
[2,4:10] fija coordenadas para
cualquier matriz 2D,
fila 2, columnas 4 a
la 10.
[5:end,5] fija coordenadas para
cualquier matriz 2D,
filas 5 hasta el final,
columna 5.
[3:4,2,2:5] fija coordenadas para
una matriz 3D, filas
3 y 4, columna 2,
páginas 2 a la 5.
 
++i,--j,[1:i,j]
fija coordenadas para
una matriz 2D, con uso
de variables que deben
ser modificadas fuera de
[].
 
Nota: SE ACEPTAN variables dentro de
los [].
ACEPTA INTERVALOS. Ejemplo:
[1:2:end] trabaja sobre las posiciones
impares del array.
[1:end, 2:(f+1):end]
fija el trabajo sobre todas
las filas, pero las columnas
desde la 2 hasta el final, a
intervalos (f+1).
Nota: una operación aritmética ACEPTAdentro INTERVALOS. Ejemplo:de
un intervalo, debe escribirse con
[1:2:end] trabaja sobre las posiciones paréntesis.
impares del array.
ACEPTA operaciones aritméticas
dentro de [1:end]; sin embargo, 2:(f+1):end]no
acepta el uso de fija el trabajo sobrefunciones todaso
las filas, pero las columnasmacro-funciones.
desde la 2 hasta el final, a
{N}loc1, loc1(N) Establece la posición N de un vector
intervalos (f+1).
cualquiera. Ejemplo:
Nota: una operación aritmética{10}loc1, dentro deget(array)
un intervaloloc1(10), debe escribirse conget(array)
hacen lo mismo. La diferencia, paréntesis.es que
con el primero se pueden realizar
ACEPTA operaciones aritméticas:
dentro de []; sin embargo{10}plus'i', noloc1.
o acepta el uso de funciones obien
#hl( 10+i ), macro-funciones.loc1
 
pero, con LOC1(N), no puede hacerse.
{N}loc1, loc1(N) Establece la posición N de un vector
cualquiera. Ejemplo:N, en este caso, es un numero o una
{10}loc1, get(array)variable.
loc1(10), get(array)
hacen lo mismo. La diferencia, es que
con el primero se pueden realizar
operaciones aritméticas:
{10}plus'i',loc1.
o bien
#hl( 10+i ), loc1
 
pero, con LOC1(N), no puede hacerse.
N, en este caso, es un numero o una
variable.
Por otro lado,
loc1(10)
es similar a:
[10]
Nota: También se establece el número
de página, en una matriz 3D.
{F,C}loc2 Establece coordenadas para un elemento
de una matriz 2D cualquiera, en fila F
columna C.
{N}offset1 Establece la posición final de un
intervalo para un vector, iniciado
con LOC1.
Ejemplo:
{3}loc1,{6}offset1
es similar a:
[3:6]
y
{3}loc1,{0}offset1
es igual a:
[3]
{F,C}offset2 Establece el desplazamiento en filas F
y columnas C, para un intervalo usado en
una matriz 2D cualesquiera.
Si no se quiere desplazar alguna
coordenada, use 0.
Ejemplo:
{3,2}loc2,{end,4}offset2
es similar a:
[3:end,2:4]
{N}interval1,
{F,C}interval2
{F,C,P}interval3 Establecen intervalos para las marcas
definidos por LOC1,LOC2, y OFFSET1 y
OFFSET2.
Se pueden usar junto a la forma simple:
[1:10],{2}interval1
declara el siguiente rango de posiciones,
internamente:
1,3,5,7,9
El caso es el mismo para INTERVAL2 e
INTERVAL3.
 
clearmark Elimina las marcas definidas por LOC1, LOC2,
OFFSET1 y OFFSET2.
Esto es útil, cuando se desea asignar un
valor constante a una matriz.
La asignación "=", por ejemplo, a=0
Asignará "0" a la matriz "a"; pero, si
existen marcas, asignará "0" a las
posiciones definidas por las funciones
anteriores.
clearinterval Esto es necesario para borrar los intervalos
definidos con INTERVAL1, INTERVAL2 e
INTERVAL3.
clrmarksall Activa/desactiva la ejecución de CLEARMARK y
CLEARINTERVAL internamente, luego de la
ejecución de un GET o un PUT.
 
{M}cartesian Genera una matriz o vector con las posiciones
cuyo valor es TRUE (o equivalente), de un
vector o matriz.
Las funciones lógicas vistas en OPERADORES
MATEMATICOS Y LOGICOS, segmento OPERACIONES
LOGICAS MATRICIALES, devuelven vectores o
matrices booleanas, cuando se comparan
esta clase de datos, y pueden ser usadas
junto con CARTESIAN. No obstante, cualquier
valor distinto de vacío (matrices de cadena),
distinto de cero (matrices numéricas), o
con 1's lógicos (matrices booleanas), será
tomado por CARTESIAN para obtener una
posición.
Ejemplo:
Sea "t" una matriz:
{t}gthan(5), ==> devuelve una matriz
del tamaño de "t",
Line 2,666 ⟶ 2,672:
2,4
2,5...
 
range(R) Toma la matriz cartesiana R obtenida de la
instrucción CARTESIAN, y establece rangos
de operación sobre matrices. No deja nada
en el stack.
Estos rangos se denominan:
RANGOS CARTESIANOS
GET, PUT, y asignación "=" son afectadas
por estos rangos especiales.
Sirve para modificar elementos determinados
dentro de una matriz, que no obedecen a los
rangos vistos con las funciones anteriores.
Ejemplo:
{t}gthan(5), cartesian,mov(r)
range(r),get(t),mulby(100), put(t),
{t} println
Elabora un rango cartesiano con las posiciones
mayores que 5, obtiene esos elementos de la
forma de un vector (GET), los multiplica por 100,
y luego, los colocan nuevamente dentro de la
matriz original, con PUT.
Después, imprime la matriz modificada.
 
clearrange Elimina el rango cartesiano.
 
 
== ESTADISTICA ==
Line 2,698 ⟶ 2,703:
La instrucción STATS es del tipo NAVAJA SUIZA: a través de ella es posible acceder a numerosos cálculos estadísticos básicos, con los cuales se pueden relizar operaciones más complejas, por combinación de ellos.
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
{V}stats(CODIGO) Ejecuta una serie de cálculos no existe
{V}statistic(CODIGO) estadísticos simples, según el
{V}statistic(CODIGO) estadísticos simples, según el
CODIGO dado.
CODIGO dado.
 
Los códigos están definidos en HOPPER.H.
Line 2,711 ⟶ 2,717:
Ejemplo:
{V}stats(SUMMATORY)
 
MEAN Calcula el promedio de los valores de la matriz.
Ejemplo:
Line 2,720 ⟶ 2,726:
Ejemplo:
{V}stats(SUMM+MEAN) ==> { suma, promedio }
 
BINCLASS Genera clases, según un bin (intervalos de clase). Devuelve
un array 2D con los valores de los intervalos calculados, y
Line 2,727 ⟶ 2,733:
{25,V}stats(BINCLASS) ==> {ini,fin,ocurrencia}
Genera una "tabla" con 25 bines.
 
STURGCLASS Genera intervalos de clase con método de Sturges.
Ejemplo:
{V}stats(STURGCLASS)
 
CLASS Genera una estadística para cada elemento (ocurrencia) de los
valores de la matriz.
Ejemplo:
{V}stats(CLASS) ==> {Elemento, ocurrencia}
 
SUMMCOL Suma columnas de una matriz 2D, y devuelve un array 1D con el
total para cada columna.
 
SUMMROW Suma filas de una matriz 2D, y devuelve un array 1D con el
total para cada fila.
 
OBSERVACION. SUMMCOL y SUMMROW solo trabajan sobre matrices 2D. Para calcular dicha
suma sobre matrices 3D, es necesario obtener cada página con GETPAGE, y los resultados
Line 2,751 ⟶ 2,757:
La intrucción SETS es una instrucción tipo NAVAJA SUIZA, con la cual se pueden realizar las operaciones básicas de CONJUNTOS.
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
{C}sets(CODIGO) Ejecuta una serie de cálculos sobre un conjunto C, según un
código (ver lista de códigos).
Un conjunto se define como una colección ordenada de elementos
únicos. Para ordenar los elementos, se usa:
{V}array(SORT)
La definición para SORT se encuentra en HOPPER.H.
 
Los códigos están definidos en HOPPER.H.
Line 2,773 ⟶ 2,778:
{V},sets(UNIQUE)
==> {0,1,2,3,4,8,9,10}
 
UNION Efectúa la UNION de dos matrices procesadas previamente por
UNIQUE.
Ejemplo:
{A,B}sets(UNION)
 
INTERSEC Efectúa la INTERSECCION de dos matrices procesadas previamente
por UNIQUE.
Ejemplo:
{A,B}sets(INTERSEC)
 
DIFF Efectúa la DIFERENCIA de dos matrices procesadas previamente
por UNIQUE.
Line 2,789 ⟶ 2,794:
A: 1 2 3 5 6 7 8 9 10
B: 1 4 6 7 8 9 10
 
{A,B}sets(DIFF) ==> {2,3,5}
Line 2,795 ⟶ 2,800:
Ejemplo:
{B,A}sets(DIFF) ==> {4}
 
SIMDIFF Efectúa la DIFERENCIA SIMETRICA de dos matrices procesadas
previamente por UNIQUE.
Line 2,801 ⟶ 2,806:
A: 1 2 3 5 6 7 8 9 10
B: 1 4 6 7 8 9 10
 
{A,B}sets(SIMDIFF) ==> {2,3,4,5}
OBSERVACION. {A,B}sets(SIMDIFF) es igual a {B,A}sets(SIMDIFF)
 
 
== MANEJO DE BITS Y CAMBIO DE BASE ==
Line 2,811 ⟶ 2,815:
La instrucción BIT es una función tipo NAVAJA SUIZA, que encierra numerosas herramientas para el manejo de bits.
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
{N}bit(CODIGO) Ejecuta una serie de cálculos de bits sobre N números enteros
de 16 bits (ver lista de códigos).
Si CODIGO es menor que 100, hace referencia a la posición del
bit.
Ejemplo (con macro FOR/NEXT):
num=4003
for(i=32, {i}is greater than (0),--i)
{num},bit(i), print
next
==> 00000000000000000000111110100011
 
{N}hex Convierte un número decimal a una cadena hexadecimal.
{200}hex ==> C8
 
{N}bin Convierte un número decimal a una cadena binaria.
{200}bin ==> 11001000
 
setbin(n) Establece un número "n" de dígitos binarios para la salida
de BIN.
setbin(15)
{200}bin ==> 000000011001000
 
{N}oct Convierte un número decimal a una cadena octal.
{200}oct ==> 310
 
 
Los códigos están definidos en HOPPER.H.
Line 2,846 ⟶ 2,849:
BITAND AND binario. Ejemplo:
{0xfffh,0x99h},bit(BITAND) ==> 153 (99h)
 
BITOR OR binario. Ejemplo:
{0xfffh,0x99h},bit(BITOR) ==> 4095 (FFFh)
 
BITXOR XOR (OR exclusivo) binario.
Ejemplo:
{0xfffh,0x80h},bit(BITXOR) ==> 3967 (F7Fh)
 
BITNOT NOT binario. Ejemplo:
{0xfffh},bit(BITNOT) ==> 4294963200 (FFFFF000h)
 
BITCLR Deja el bit indicado en 0 (lo apaga). El valor del TOP
es el entero a procesar; el resto, son las posiciones
Line 2,863 ⟶ 2,866:
num=0xfffh
{7,5,4,3,num},bit(BITCLR) ==> 4003 (111110100011)
 
BITSET Enciende el bit indicado. El valor del TOP es el entero
a procesar; el resto, son las posiciones de bits,
Line 2,870 ⟶ 2,873:
num=4003
{7,5,4,3,num},bit(BITSET) ==> 4095 (111111111111)
 
MIRRBYTE Invierte los bits de un entero. LOWBYTE y HIGHBYTE definen
los bits a reflejar (si solo el byte más bajo, o todo).
Line 2,877 ⟶ 2,880:
{LOWBYTE,num},bit(MIRRBYTE) ==> 0000100010001111 = 2191
{HIGHBYTE,num},bit(MIRRBYTE) ==> 1000111100010000 = 36624
 
BITROT Rota bits hacia la izquierda. El bit de más hacia la
izquierda (del byte más bajo o del más alto), pasa a ser
Line 2,883 ⟶ 2,886:
BITROT distingue LOWBYTE y HIGHBYTE.
Ejemplo 1 (LOWBYTE):
 
num = 2289 // (0000100011110001)
i=1
Line 2,889 ⟶ 2,892:
{LOWBYTE,i,num},bit(BITROT),bin,P_NL,print
++i,{5,i} jle(loop lowbyte)
 
Salida:
Line 2,897 ⟶ 2,900:
0000100000011111
0000100000111110
 
Ejemplo 2 (HIGHBYTE):
 
num = 2289 // (0000100011110001)
i=1
Line 2,905 ⟶ 2,908:
{HIGHBYTE,i,num},bit(BITROT),bin,P_NL,print
++i,{5,i} jle(loop highbyte)
 
Salida:
Line 2,923 ⟶ 2,926:
{5,num},bit(SHIFTR) ==> 0000001100100010 = 802
{5,num},bit(SHIFTL) ==> 1000100011000000 = 821440
 
HEXTODEC
OCTTODEC
Line 2,938 ⟶ 2,941:
HEXTODEC:1011754
OCTTODEC:15483
 
LOWBYTE Macro que señala el byte más bajo, usado en BITROT y MIRRBYTE.
HIGHBYTE Macro que señala el byte más alto, usado en BITROT y MIRRBYTE.
 
 
== ATRAPAMIENTO DE ERRORES ==
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
swtrap(DIR) Instrucción detrás de la macro TRY.
Almacena la dirección de salto DIR al
punto del programa donde un error
será atrapado.
 
gettry(E) Instrucción detrás de CATCH. Obtiene
el código numérico del error, y lo
Line 2,961 ⟶ 2,962:
su posterior proceso.
Su uso normal es:
 
{"Has pasado el límite"},throw(1000)
La macro, definida en stdio.hh, tiene
un uso más normal:
 
raise(1000,"Has pasado el límite")
 
popcatch Elimina la dirección almacenada por
SWTRAP, desde el stack interno de
Line 2,974 ⟶ 2,975:
Está detrás de FINISH, y mejor use
esta macro.
 
OBSERVACIONES: Estas instrucciones no deben ser usadas. En su lugar, use las macros dispuestas en stdio.hh, donde se establece el uso más estándar. Ejemplo:
try
Line 2,987 ⟶ 2,988:
{0,v}eq?, assert("Son iguales!")
 
== PARSER XML/HTML ==
 
HOPPER DESCRIPCION
-----------------------------------------------------------------------------------
{A,B,C,D}parser(M) Construye un registro XML/HTML, y lo agrega a M, donde:
A = nombre del campo
B = atributos
C = contenido del campo
D = código de parser (ver lista de códigos).
M = cadena con registros anidados XML.
Si no hay atributos, debe escribir "" en su lugar.
Si no hay contenido, debe escribir "" en su lugar.
El nombre del campo, y el código de parser, son
obligatorios. Obviamente, la cadena con registros
anidados también son obligatorios.
 
Ejemplo:
 
msg=""
{"nombre","","Este tag esta con datos",NORMALTAG}, parser(msg)
Line 3,016 ⟶ 3,017:
{"code_secret","tag=AB450C M=\"MORE\"","INFO-C",NORMALTAG},parser(msg)
{"only_tag","","",ONLYTAG},parser(msg)
Genera:
<nombre>Este tag esta con datos</nombre>
Line 3,024 ⟶ 3,025:
<code_secret tag=AB450C M="MORE">INFO-C</code_secret>
<only_tag/>
Para dejar el grupo de registros anterior dentro de otro registro, escribir:
forma=""
{"forma","code=100001",msg,NORMALTAG},parser(forma)
Genera:
<forma code=100001>
Line 3,039 ⟶ 3,040:
<only_tag/>
</forma>
 
{A}unparser(M) Descompone la cadena M, obteniendo el campo indicado
por A. Si el campo no existe, devuelve un error que
puede ser atrapado por las macros TRY/CATCH.
El campo A puede estar en cualquier parte de la
cadena M. Si existe más de un campo con el mismo
nombre, será extraída la primera ocurrencia.
Si A contiene atributos, UNPARSER devuelve:
1) un array con los valores de los atributos.
2) el contenido.
Si A no contiene atributos, solo devuelve el contenido.
Si A no contiene atributoscontenidos, solo devuelve eluna cadena contenidonula.
Si se sabe que A no contiene contenidosatributos, devuelve unasolo cadenaes nula.
necesaria una variable para el contenido.
Si se sabe que A no contiene atributos, solo es
necesaria una variable para el contenido.
 
Ejemplo:
content=""
Line 3,084 ⟶ 3,085:
<mem_copy length=1000/>
</forma>
 
Los códigos están definidos en HOPPER.H.
Line 3,100:
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
{F}statsfile Devuelve al stack la siguiente statsfile(F)
información:
Line 3,134:
del stack en una variable de cadena, separados por
el separador de token definido por TOKSEP.
 
{T,F}open(FD) Abre un archivo identificado por F, usando un modo de
apertura T, y crea el identificador de archivo FD.
Line 3,157:
OPEN_DREAD 48 // RED: inhabilita que otro lea
OPEN_SHARED 64 // RED: comparte lectura y escritura
 
{T,F}create(FD) Crea un archivo identificado por F, usando un modo de
creación T, y asigna el identificador FD.
Line 3,169:
Nota: los modos de creación se encuentran en stdio.hh.
La lista es la siguiente:
 
CREATE_NORMAL 0
CREATE_READONLY 1
CREATE_HIDDEN 2
CREATE_SYSTEM 4
 
close(FD) Cierra un archivo abierto con OPEN, o creado con CREATE.
Ejemplo:
close(fd)
 
eof(FD) Devuelve TRUE si el handler FD ha llegado al final del
archivo.
Line 3,197:
proviene del proceso de recolección de los datos del archivo,
que realizan tanto SEARCH como STATFILE.
 
{T,P}seek(FD) Establece el puntero de posición del archivo apuntado por FD.
La nueva posición, medida en bytes, es obtenida desplazando
Line 3,218:
Se mueve a la posición 100 del archivo, contando desde el
principio de dicho archivo.
 
{SEEK_END,0},seek(fd), mov(nFinalPos)
Line 3,234:
SEEK_CUR 1
SEEK_END 2
{max-long}readline(FD)
Lee una línea desde el archivo apuntado por FD,
Line 3,253:
al inicio de la línea siguiente de la leída, o al
fin de archivo.
 
{S}writeline(FD) Guarda una cadena en el archivo apuntado por FD.
Si ocurre un error, la instrucción ERROR?
Line 3,262:
{"Esta línea será guardada"},write line(fw)
close(fw)
 
{B}readstring(FD) Lee un número de B bytes desde un archivo apuntado
por FD, y lo deja en stack como una cadena.
Line 3,273:
Nota: esta instrucción se combina fuertemente con
la instrucción SEEK.
 
{S}writestring(FD) Guarda una cadena S en el archivo apuntado por FD.
Ejemplo:
{OPEN_WRITE,"texto.txt"} open(fd)
{"MENSAJE PARA LA TIERRA\n"} write string(fd)
 
Nota: esta instrucción se combina fuertemente con
la instrucción SEEK.
 
{F}loadstring(S) Lee el archivo F y lo guarda en la cadena S.
Ejemplo:
s = ""
{"texto.txt"},load string(s)
 
{F}savestring(S) Guarda la cadena S en el archivo F.
Ejemplo:
s = "Mensaje a guardar"
{"texto.txt"} save string(s)
 
[L]getline(S)
{L}getline(S) Obtiene la línea L desde la cadena S. Se considera
Line 3,305:
++i
{c,i},jle(loop)
 
countlines(S) Cuenta el total de líneas de la cadena S, y
guarda el resultado en el stack.
 
{B,F}search(S) Busca una cadena, o una expresión regular (B) en el
archivo F, elabora una matriz con las posiciones
Line 3,331:
busqueda, añada la opción "-e" dentro de la cadena
del patrón. Grep.
 
Para un ejemplo completo, ver el archivo de ejemplo
GREP.COM del directorio SRC.
Line 3,362:
lado, se ubican los accesos al stack; por otro, las
instrucciones.
 
fileerror Devuelve una cadena con el mensaje de error de
la operación de archivo fallida.
 
== PILAS, COLAS Y RECURSIVIDAD ==
Line 3,373 ⟶ 3,372:
Ejemplo de uso de PILAS:
 
#include <hopper.h>
main:
stack={} // se define un array vacío
{100}push(stack) // mete el primer dato: 100
Line 3,388 ⟶ 3,387:
Ejemplo de uso de COLAS:
 
#include <stdio.hh>
main:
stack={} // se define un array vacío
{100}push(stack) // mete el primer dato: 100
Line 3,403 ⟶ 3,402:
Ejemplo de RECURSIVIDAD:
 
#include <stdio.hh>
#proto factorial(_v_) /* simula "funciones", expandiendo
la llamada "_factorial()", y la
declaración "factorial()" */
main:
arg=100
{"Factorial de ",arg," = "}print
_factorial(arg) // esto expande a "{arg}jsub(factorial)"
println
{0}return
.locals
factorial(n) // esto expande a "factorial:,n=0,mov(n)"
if ( {n} lethan '1' )
{1}
Line 3,421 ⟶ 3,420:
{n}, _factorial( {n}minus'1' ), mul
end if
back
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
{D}push(S) Mete un dato D en el stack S. El
dato puede ser una constante, un
registro-variable, o una matriz.
 
{D}pushall(S) mete todo lo que encuentre en el
stack, en el array S, en el orden
Line 3,435 ⟶ 3,434:
ADDROW cuando se quiere crear un
único vector.
 
pop(S) Extrae un dato desde el stack,
en modo PILA (desde el último,
hasta el primero).
El dato extraído queda en el stack.
 
qpop(S) Extrae un dato desde el principio
del stack S, o sea, en modo COLA.
El dato extraído queda en el stack.
 
head(S) Devuelve, sin extraer, el dato
ubicado al inicio del stack, es
decir, el primero ingresado.
 
tail(S) Devuelve, sin extraer, el dato
ubicado en la cima del stack, es
Line 3,455 ⟶ 3,454:
empty(S) Devuelve TRUE si el stack S está
vacío.
 
ipush(V)
ipop(V) "internal push", e "internal pop".
Line 3,493 ⟶ 3,492:
{"M=\n",m,"\nY=",y,"\n"} print
back
 
itop(V) "internal top". Obtiene el dato que está en
el "top" de la pila interna. No extrae el dato.
Line 3,502 ⟶ 3,501:
de pseudofunciones, dado que es allí donde se
usa la pila interna.
 
IMPORTANTE: la pila interna tiene un máximo no configurable
de 1.024 posiciones. Es, en realidad, un array
Line 3,508 ⟶ 3,507:
medida de ser ejecutado un IPOP, sin alterar
el tamaño de la pila.
 
== ARRAYS ==
Line 3,541 ⟶ 3,539:
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
{datos}addrow(A) Añade lo que encuentre en el stack,
como una fila en el array A, declarado
Line 3,579 ⟶ 3,577:
inicio .STACK n, donde "n" es el tamaño
que se reservará para el stack.
 
{F,[C[,P]]}newarray(A)
Crea un array A con las dimensiones
Line 3,591 ⟶ 3,589:
las que serán rellenadas luego con el
valor "10".
 
{F,[C[,P]],dato-relleno}fillarray(A)
Crea un array A con un valor dado, sea
Line 3,603 ⟶ 3,601:
columnas, y rellena cada posición con
la cadena "cadena".
 
{F,[C[,P]]}nanarray(A)
Crea un array de valores NaN (not a
Line 3,610 ⟶ 3,608:
donde queremos estar seguros de qué
elementos del array son alterados.
 
{F,[C[,P]]}randarray(A)
Crea un array de números aleatorios,
Line 3,617 ⟶ 3,615:
A=0
{10,5}rand array(A)
 
{F,[C[,P]]}zerosarray(A)
Crea u array con ceros.
 
{F,[C[,P]]}onesarray(A)
Crea un array con unos.
 
{F,[C[,P]]}eyesarray(A)
Crea una matriz identidad. Solo se aceptan
Line 3,650 ⟶ 3,648:
obtiene una matriz de 2 filas (filas 2 y 3),
y todas las columnas de la matriz A original.
 
La porción obtenida de la matriz, quedará en
el stack.
Line 3,656 ⟶ 3,654:
Sobre esta porción, se pueden efectuar las
operaciones que desee.
 
put(A) Guarda lo que encuentre en el stack, en la
matriz A, de acuerdo a las marcas de intervalos
Line 3,681 ⟶ 3,679:
a[2:3,1:end] *= 10 + tasa
}
 
{lista-filas}getrow(A)
Creará una nueva matriz con las filas definidas
Line 3,696 ⟶ 3,694:
Esta operación no tiene reversa, como GET/PUT.
{lista-columnas}getcol(A)
{lista-columnas}getcolumn(A)
Line 3,710 ⟶ 3,708:
Esto creará una matriz con la columna 3 repetida, y
la guardará en TMP.
 
Esta operación no tiene reversa, como GET/PUT.
Line 3,716 ⟶ 3,714:
obtener sub-matrices con intervalos de la matriz
original.
 
{D}catrow(A) Concatena todos los vectores dentro del stack, al array
A, como nuevas filas.
Line 3,734 ⟶ 3,732:
{"T=\n",t}println
{0}return
 
Nota: como se puede apreciar, se pueden repetir los
vectores que serán concatenados. Asimismo, es posible
Line 3,741 ⟶ 3,739:
"{0}reshape(s)" convierte "s" en un vector simple,
porque ADDROW crea un vector columna de tamaño (1,5).
{D}catcol(A),
{D}catcolumn(A) Concatena todos los vectores dentro del stack, al array
Line 3,750 ⟶ 3,748:
que número de filas de A.
Ejemplo:
 
#include <stdio.hh>
#include <array.hh>
Line 3,761 ⟶ 3,759:
{"T=\n",t}println
{0}return
 
[P]getpage(A)
[P]putpage(A) GETPAGE obtiene una página de la matriz 3D A, y la
Line 3,788 ⟶ 3,786:
INTERVALOS en sus operaciones. Ver INTERVALOS Y RANGOS
para más información.
size(A) Devuelve un array con la metadata del arreglo A. Dicho
array es guardado en el stack.
Line 3,799 ⟶ 3,797:
y tiene 4 filas y 7 columnas, SIZE(A) devolverá:
{2,4,7}
 
empty(A)
{A}isempty Devuelven TRUE si el array A está vacío. La instrucción
Line 3,828 ⟶ 3,826:
// SIZE de ARRAY = 1,5
{0}return
 
{A}packstring(S) Empaqueta, o convierte, el array A en una cadena S,
y concatena los elementos según el token definido en
Line 3,856 ⟶ 3,854:
sobre el array, y luego, empaquetar.
PACKSTRING no puede empaquetar elementos array.
 
 
=== FUNCIONES UTILES PARA MANEJO DE ARRAYS ===
Line 3,875 ⟶ 3,872:
{0}reshape(A)
significa que A será un vector simple.
 
{A}compact Compacta un array n-dimensional en compact(A)
un array unidimensional, eliminando
Line 3,896 ⟶ 3,893:
pueden facilitar las cosas: sus nombres
son COMPACTSTRING y COMPACTNUMERIC.
 
{inicio,final,num-elementos}sequencespaced(V)
{inicio,final,num-elementos}seqsp(V)
Line 3,910 ⟶ 3,907:
{"Secuencia = \n",x}println
{0}return
 
Imprime:
1 0.944444 0.888889 0.833333 0.777778 0.722222 0.666667 0.611111 0.555556 0.5
{inicio,incremento,num-elementos}sequence(V)
Line 3,928 ⟶ 3,925:
{"Secuencia = \n",x}println
{0}return
 
Imprime:
1,1.5,2,2.5,3,3.5,4,4.5,5,5.5
 
{I,F}clamp(V) Limita un escalar o matriz V a un intervalo definido
por dos valores, I-nicial, y F-inal.
Si I <= V <= F, retorna V al stack.
Si V < I, retorna I.
Si V > F, retorna F.
Para el caso en que V es una matriz, retorna dichos
valores para cada posición de ésta.
Ejemplo:
#include <stdio.hh>
main:
v=5, jsub(evalúa clamp)
v=-1, jsub(evalúa clamp)
Line 3,949 ⟶ 3,946:
v=8, jsub(evalúa clamp)
v=1, jsub(evalúa clamp)
{0}return
.locals
evalúa clamp:
{1,10} clamp(v),
{"Valor devuelto: ",v,"\n"}print
back
Imprime:
Line 3,963 ⟶ 3,960:
Valor devuelto: 8
Valor devuelto: 1
 
 
=== ARCHIVOS DE MATRICES ===
Line 3,997 ⟶ 3,993:
print("SIZE="),size(matriz),println
return(0)
 
Imprimirá:
TIPO=<string>
Line 4,005 ⟶ 4,001:
tipo MULTITIPO, porque posee tanto datos
numéricos, como alfanuméricos.
 
Se pueden cargar segmentos del archivo
señalando marcas de intervalos con [],
Line 4,013 ⟶ 4,009:
Ejemplo: a continuación, solo se cargará un
segmento del archivo.
 
#include <stdio.hh>
main:
Line 4,027 ⟶ 4,023:
print("SIZE="),size(matriz),println
return(0)
 
Imprimirá:
MATRIZ=
Line 4,036 ⟶ 4,032:
a,b,c,d,e,f,g,h,i,j
1,2,3,4,5,6,7,8,9,10
 
TIPO=<number>
SIZE=2,6,10
Line 4,043 ⟶ 4,039:
Ejemplo:
{matriz,"datos.txt"} save
 
{max-long}readrow(FD)
Lee una línea del archivo abierto con el
Line 4,088 ⟶ 4,084:
Posicion final de linea leida: 241
fila 6,1,2,3,4,5,6,7,8,9,10
 
{A}writerow(FD) Escribe los elementos de una fila del array A
en el archivo identificado por FD. El array
Line 4,095 ⟶ 4,091:
fila del array "a", y la guarda en el archivo
apuntado por "fw2:
 
#include <stdio.hh>
main:
Line 4,129 ⟶ 4,125:
Ejemplo:
{x} array(SORT)
 
SCAN Buscará por un elemento, en el array indicado, desde
el principio hasta el final.
Ejemplo:
{5,x}, array(SCAN)
buscará el número "5" en el array "x", y si existe,
dejará la posición de la primera ocurrecia en el stack.
Line 4,148 ⟶ 4,144:
Idem al ejemplo 2, pero solo buscará dentro de las
siguientes 100 posiciones del array.
 
SCAN2D Buscará un elemento, en el array indicado, desde el
principio hasta el final.
Line 4,157 ⟶ 4,153:
y dejará en el stack la posición fila encontrada, o
bien, "-1" si no fue encontrado.
REVSCAN Buscará por un elemento, en el array indicado, desde
el final hasta el principio del array.
Line 4,165 ⟶ 4,161:
Nota: Todas las opciones de SCAN, se pueden usar con
REVSCAN.
INSERT Insertará un elemento, o un array, en la posición
indicada dentro del array objetivo.
Line 4,182 ⟶ 4,178:
se añadirán tantas posiciones en "x", comenzando desde
la posición 10, como elementos tenga "vCosas".
 
DELETE Borra una posición desde el array objetivo, compactando
dicho array.
Line 4,189 ⟶ 4,185:
Borrará el elemento de la posición "2" del array "x".
ZAPRANGE Borra un grupo de elementos desde el array objetivo.
Ejemplo:
Line 4,196 ⟶ 4,192:
Borrará las posiciones desde la "5" hasta la "10", del
array "x".
 
CONCAT Concatena dos arrays.
Ejemplo:
Line 4,212 ⟶ 4,208:
Si el tamaño original de "x" es 10, se añaden 10 nuevas
posiciones al final de dicho array.
 
 
== MENSAJERIA SYSTEM V ==
Line 4,230 ⟶ 4,225:
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
kbfree Elimina el buffer con la última iskbfree
tecla presionada.
 
{C}keyput Pone la tecla C (representada keyput(C)
como un código ASCII) en el buffer
del teclado.
Dicha tecla podrá ser consumida
por KBHIT?, KBESC?, KBCTRLC? y
LASTKEY().
Ejemplo:
{65}keyput, tecla presionada=0
lastkey(tecla presionada)
{tecla presionada}print
==> A
 
lastkey(T) Guarda la última tecla presionada no existe
en la variable T. Dicha tecla
puede ser obtenida, incluso, con
PAUSE.
 
kbhit? Devuelve TRUE si se presionó una iskbhit
tecla.
 
kbesc? Devuelve TRUE si se presionó la iskbesc
tecla ESC.
 
kbctrlc? Devuelve TRUE si se presionó la iskbctrlc
combinación CTRL-C.
 
 
== INSTRUCCIONES MISCELANEAS ==
 
HOPPER DESCRIPCION ALTO NIVEL
-----------------------------------------------------------------------------------
totalarg Devuelve el número total de argumentos
pasados al programa, desde la línea de
comandos.
Si no se pasa ninguno, totalarg=1, que
corresponde al nombre del programa.
Véase las macros del archivo stdio.hh
para más información.
 
++ incremento de registro-variable.
Si es numérica, aumenta 1 a la variable.
Observación:
++v no es lo mismo que v++:
++v incrementa "v" en 1.
v++ mete "v" en el stack, y luego, lo
incrementa.
Nota: no puede ser usada dentro del
tag #high-level.
Sobrecarga:
++v y v++ eliminan el primer caracter de
v, si este es una cadena.
Ver OPERADORES SUBORDINADOS para más
información sobre "+=", que permite
eliminar más de un carcater.
 
-- decremento de registro-variable.
Si es numérica, disminuye 1 a la variable.
Observación:
--v no es lo mismo que v--:
--v decrementa "v" en 1.
v-- mete "v" en el stack, y luego, lo
decrementa.
Nota: no puede ser usada dentro del
tag #high-level.
Sobrecarga:
--v y v-- eliminan el último caracter de
v, si este es una cadena.
Ver OPERADORES SUBORDINADOS para más
información sobre "-=", que permite
elimiar más de un caracter.
 
postfix Fuerza el cálculo en modo NOTACION POLACA.
Esta cláusula se usa antes y después de
una operación aritmética, o concatenación
de cadenas con CAT.
De manera natural, las instrucciones de
HOPPER sacan los operandos desde el tope
del stack, hacia atrás, contradiciendo
el modo de operar de la notación polaca.
Ejemplo:
{2,5}sub ==> 5-2 = 3 normal
postfix,{2,5}sub,postfix
==> 2-5 = -3
Ver CALCULO POSFIJO para más información.
Nota: Por defecto, POSTFIX se incluye
dentro de las operaciones de #HIGH-LEVEL.
 
back Esta instrucción retorna a la instrucción
siguiente de una llamada JSUB o GOSUB.
No se usa con JMP ni derivados: si lo
intenta, obtendrá un error.
Normalmente se usa dentro de los bloques
de código ubicados luego de .LOCALS, aunque
puede usarlo en el módulo principal: en
tal caso, HOPPER le dará un WARNING por
usar BACK sin haber detectado .LOCALS,
pero no se preocupe. Para desactivar los
WARNINGS, use la opción "-w".
getstrerror Cuando usa TRY/CATCH (macros para SWTRAP
y GETTRY), se captura el código numérico
del error. GETSTRERROR obtiene la
cadena descriptiva de dicho error.
Es útil cuando se usa en combinación con
RAISE (macro de THROW).
Puede ser usado dentro de #HIGH-LEVEL.
Ver stdio.hh para más información sobre
las macros.
 
true Como INSTRUCCION, mete un valor TRUE en
el stack. Como función, asigna un valor
TRUE al registro-variable entre paréntesis.
Ejemplo:
true,println ==> imprime 1
true(v) ==> v contiene 1 booleano.
Ver CONVERSION DE TIPOS para más información
acerca de los valores considerados como
booleanos por HOPPER.
false Hace lo mismo que TRUE, pero con valores
booleanos falsos.
Ver CONVERSION DE TIPOS para más información
acerca de los valores considerados como
booleanos por HOPPER.
pause Realiza una PAUSA en la ejecución. La tecla
presionada para liberar la pausa, es
almacenada internamente, y se puede obtener
con la instrucción LASTKEY(v), donde "v"
contendrá el valor numérico de dicha tecla.
clear Ver LIMPIAR VARIABLES.
dowith Es una instrucción que guarda internamente
un valor numérico, o un valor de cadena,
para ser evaluado por las instrucciones
JCASE.
Nota: no es una estructura; por lo tanto,
no se permite anidaciones.
Ver stdio.hh para más información sobre
las macros que usan esta instrucción.
NOTA: NO USE ESTA FUNCION: SERA REESCRITA
EN EL FUTURO.
jcase evalúa el contenido del stack Vercontra CONVERSION DE TIPOS para más informaciónel
acerca devalor losalmacenado valorespor consideradosDOWITH. comoSi coinciden,
booleanos porpondrá HOPPER.TRUE en el stack, el que puede ser
evaluado por DO{}.
 
false Hace lo mismo que TRUE, pero conVer valoresstdio.hh para más información sobre
booleanos falsoslas macros que usan esta instrucción.
Ver CONVERSION DE TIPOS para más información
acerca deNOTA: losNO valoresUSE consideradosESTA comoFUNCION: SERA REESCRITA
booleanos porEN HOPPEREL FUTURO.
{A,B}typechar? Devuelve TRUE si A es del tipo B typechar(A,B)
pause Realiza una PAUSA en la ejecución. La tecla
presionada para liberar la pausa, es
almacenada internamente, y se puede obtener
con la instrucción LASTKEY(v), donde "v"
contendrá el valor numérico de dicha tecla.
 
clear Ver LIMPIAR VARIABLES.
 
dowith Es una instrucción que guarda internamente
un valor numérico, o un valor de cadena,
para ser evaluado por las instrucciones
JCASE.
Nota: no es una estructura; por lo tanto,
no se permite anidaciones.
Ver stdio.hh para más información sobre
las macros que usan esta instrucción.
NOTA: NO USE ESTA FUNCION: SERA REESCRITA
EN EL FUTURO.
jcase evalúa el contenido del stack contra el
valor almacenado por DOWITH. Si coinciden,
pondrá TRUE en el stack, el que puede ser
evaluado por DO{}.
Ver stdio.hh para más información sobre
las macros que usan esta instrucción.
NOTA: NO USE ESTA FUNCION: SERA REESCRITA
EN EL FUTURO.
 
{A,B}typechar? Devuelve TRUE si A es del tipo B typechar(A,B)
B es una cadena.
B puede ser cualquiera de los
Line 4,416 ⟶ 4,410:
"upper" (A-Z)
"xdigit" (0 to 9, A to F, a to f)
 
{A}type Obtiene el tipo de A. type(A)
Los tipos de arrays, cuando puede
ser evaluado con precisión, están
Line 4,428 ⟶ 4,422:
 
OBSERVACION. En un array, TYPE comprueba el primer elemento de la matriz. En una matriz multitipo, TYPE puede inducir a un error de percepción ideológicamente falso.
 
 
== PREPROCESAMIENTO Y METALENGUAJE ==
Line 4,454 ⟶ 4,447:
break, break infinity, breaking, etc.
declarar las macros con nombres complejos al principio, y dejar la palabra átomo al final. Por ejemplo, la lista anterior debería ser declarada en este orden:
break infinity, breaking, break.
Line 4,464 ⟶ 4,457:
3) Trate de no declarar macros con nombres que pertenecen a los nombres de las funciones de Hopper.
 
4) Ponga atención al punto 1.
4)
 
5) Puede usar una macro #PROTO, una declaración de pseudofunción, dentro de los tags #HIGH-LEVEL, pero no puede usar ningún otro tipo de macros.
 
 
=== DIRECTIVAS PRINCIPALES ===
Line 4,475 ⟶ 4,467:
Dentro de las directivas del preprocesador, podemos encontrar:
 
- #!/usr/bin/hopper
- #!/usr/bin/bhopper
- #include
- #define
- #defn
- #prototype, #proto
- #context
- #context-free
- #synonimous, #synon
- #import
- #high-level, #compute, #hl, #fx
 
==== DIRECTIVAS INLINE DEFN ====
Line 4,495 ⟶ 4,487:
Las directivas inline son las siguientes:
 
- \
- *
- ;
- #VOID
- #RAND
- #RNDV
- #ATOM
- #ATOMF
- #CMPLX
- #IF / #ELSE / #EIF
 
 
Line 4,513 ⟶ 4,505:
Las directivas que permiten simular estructuras de control, son las siguientes:
 
- #LOOP / #ENDLOOP
- ##ENDLOOP
- #CATCH / #ENDCATCH
- ##CODEIF
- #ENDIF
- #ENDIIF
- %LOOP
- %ENDLOOP
- %%LOOP
- %%ENDLOOP
- %CODEIF
- %ENDIF
- %ENDIIF
- %%CODEIF
- &()
- %&
- %%&
 
La siguiente es una descripción de las directivas inline usadas por el preprocesador de HOPPER. Se pueden encontrar en todos los archivos de cabecera ".HH" o ".H", y sus efectos se pueden hallar compilando un programa con la opción "-p", y consultando el archivo resultante ".PPO".
 
== DETALLE DE DIRECTIVAS DE PREPROCESAMIENTO ==
Line 4,542 ⟶ 4,534:
Por ejemplo, sea el siguiente programa, llamado "holamundo.com":
 
#!/usr/bin/hopper
 
main:
{"hola mundo!\n"} return
 
Para que el "bang line" funcione, debe cambiar los permisos del programa, como sigue:
Line 4,553 ⟶ 4,545:
Luego, ejecute con normalidad:
 
$ ./holamundo.com
 
Lo único que hace "bang line", es omitir "hopper"; pero, debe colocar las opciones de todas maneras.
 
 
BANG LINE EN UN PROGRAMA BINARIO.
Line 4,573 ⟶ 4,564:
 
./holamundo
 
 
==== #INCLUDE ====
Line 4,639 ⟶ 4,629:
#proto NOMBRE_MACRO( <argumentos> )
La directiva #PROTO hace referencia a un bloque de código BLOCK:/BACK, usualmente declarado después de la cláusula .LOCALS, por lo que no requiere de código a expandir, como sí lo necesitan #DEFINE y #DEFN.
Una macro #PROTO se debe usar, dentro de MAIN:, anteponiendo un guión subrayado "_", como se muestra a continuación:
 
Line 4,646 ⟶ 4,636:
El bloque de código referenciado, se declara como si se tratase de una función:
 
#proto NOMBRE_MACRO( argumentos )
 
Internamente, HOPPER toma la llamada a la macro-función, y la expande como sigue:
Line 4,686 ⟶ 4,676:
back
 
Con la directiva #PROTO, se pueden simular funciones, y estas pueden ser RECURSIVAS. Esto se logra gracias a que, luego de detectarse una "pseudofunción" luego de la cláusula .LOCALS, cualquier llamada con JSUB, de manera interna, es "rodeada" con instrucciones IPUSH, antes, e IPOP después de JSUB, lo que almacenará las variables declaradas dentro del bloque de la pseudofunción en un stack interno de datos.
Con la directiva #PROTO, se pueden simular funciones.
 
 
==== #CONTEXT ====
Line 4,701 ⟶ 4,690:
Ejemplo:
 
#include <stdiohopper.hhh>
#include <math.hh>
 
#context dividir por la raíz de 2
#define imprimeconunsalto {"\n"}print
Line 4,720 ⟶ 4,708:
El ejemplo anterior se expande a lo siguiente:
 
main:
{10,5}mul; gosub(dividirporlaraízde2)
emptystack?do{{"No puedo continuar por falta de datos "},throw(1000)},{"\n"}print
{0}return
.locals
dividirporlaraízde2:
{2},sqrt;postfix;div;postfix
back
 
Primero, multiplica 10 y 5; luego, se activa GOSUB (la declaración de #CONTEXT), porque en el stack hay un dato distinto de cero o vacío, y va al bloque en cuestión para realizar el cálculo. Al retornar, imprime el resultado.
 
Nota: si el resultado de la operación hubiese sido "0", GOSUB no se activa, e imprime "0".
 
 
==== #CONTEXT-FREE ====
Line 4,742 ⟶ 4,729:
#include <stdio.hh>
#include <math.hh>
 
#context-free obtenercuadradodepi
#define imprimeconunsalto {"\n"}print
Line 4,758 ⟶ 4,745:
El código anterior expande a:
 
main:
emptystack?,not,do{{"No puedo continuar por datos en el stack "},throw(1000)}jsub(obtenercuadradodepi),{"\n"}print
{0}return
.locals
obtenercuadradodepi:
{3.14159265358979323846}powby'2'
back
 
 
==== #SYNONYMOUS, #SYNON ====
Line 4,796 ⟶ 4,782:
Lo anterior expande a:
 
main:
emptystack?,not,do{{"No puedo continuar por datos en el stack "},throw(1000)}jsub(obtenercuadradodepi),{"\n"}print
emptystack?,not,do{{"No puedo continuar por datos en el stack "},throw(1000)},jsub(obtenercuadradodepi);emptystack?,do{{"No puedo continuar por falta de datos "},throw(1001)},{"\n"}print
puedo continuar por falta de datos "},throw(1001)},{"\n"}print
{0}return
{0}return
.locals
.locals
obtenercuadradodepi:
obtenercuadradodepi:
{3.14159265358979323846}powby'2'
{3.14159265358979323846}powby'2'
back
back
 
CONSIDERACIONES CON #PROTO.
Line 4,811 ⟶ 4,798:
 
#proto cálculo(_X_,_Y_)
#synon _cálculo _operación, _obtencióndelresultado
 
Line 4,818 ⟶ 4,805:
_operación (2,100.6)
_obtención del resultado ({M_PI}mulby(180), 0.25)
 
 
==== #IMPORT ====
Line 4,826 ⟶ 4,812:
 
hopper script.com -l -o <directorio-libreria>
 
El archivo generado tendrá el nombre del archivo original (incluyendo su extensión), más la extensión ".lib", y será una versión preprocesada del archivo-librería original, donde se excluyen todas las líneas anteriores a .LOCALS, inclusive.
 
Line 4,843 ⟶ 4,829:
 
#include prototipos.hh
 
main:
{0}return
 
.locals
muestra otro mensaje(m)
Line 4,886 ⟶ 4,872:
---- MENSAJE FINAL!!
 
==== #HL, #HIGH-LEVEL, #FX, #COMPUTE ====
 
Line 4,897 ⟶ 4,882:
Por ejemplo: enunciar el Teorema de Pitágoras, no es lo mismo que calcularlo. Cuando lo calculamos, seguimos un procedimiento semejante a éste:
 
"obtén el cuadrado del cateto mayor, y el cuadrado del cateto menor; luego, súmalos, y calcula su raíz cuadrada"
 
y eso es lo que hace HOPPER:
 
"{cateto mayor}pow by '2',{cateto menor}pow by'2',add,sqrt"
 
Esto es una ventaja, hasta cierto punto; es, también, la idea detrás del Proyecto Hopper: programar, en primera instancia, siguiendo una lógica más cercana a la "natural", pensando en una, no muy lejana, "programación hablada".
Line 4,916 ⟶ 4,901:
#hl ( (i+30)*M_PI/180 ), mov(resultado)
o su equivalente:
#hl ( resultado = (i+30)*M_PI/180 )
Line 4,966 ⟶ 4,951:
 
++i,--j,{i}mul by'j',plus '[i:end,j]get(a)', put(x)
 
¿Por qué se escribe solo una vez "[i:end,j]"? Porque basta con una declaración, para que quede disponible al resto del programa. De ahí que es necesario CLEARMARK.
 
Line 4,978 ⟶ 4,963:
x = y = log(x+y)^(log(x-y) )
 
p[2]=p[5]=p[7,1]=x=1000
Line 4,993 ⟶ 4,978:
r=(x:=(2+1))*2^(x-1)
}
 
Se calcula "2+1", se deja el resultado en "x", pero también se deja disponible para el resto del cálculo.
 
Line 5,025 ⟶ 5,010:
 
Todas las estructuras de control en #HIGH-LEVEL permiten anidamiento.
 
 
EJEMPLOS:
Line 5,040 ⟶ 5,024:
IF:
 
#hl{
if ( (i==0) && (log(j*10)>2) )
Line 5,047 ⟶ 5,032:
 
DO:
 
i=10
#hl{
Line 5,079 ⟶ 5,065:
 
Donde sí es muy práctico usar #HIGH-LEVEL, es en las expresiones lógicas, debido a que expanden a código HOPPER sin pérdida de optimización.
 
 
== DIRECTIVAS INLINE PARA #DEFN ==
 
 
=== DIRECTIVA "\" ===
 
No es una directiva propiamente tal, dado que puede ser usada a lo largo de todo el programa; no obstante, se incluye aquí por razones de apoyo a la definición de directivas.
Line 5,092 ⟶ 5,077:
Ejemplo:
 
#defn uniformrand(_MU_,_FVAR_,*) #RAND,_V_#RNDV=0,{*}randarray(_V_#RNDV),\
{_V_#RNDV}mulby(2),minus(1),mulby(_FVAR_),\
plus(1),mulby(_MU_),clear(_V_#RNDV)
 
Dentro del código principal de programación, se puede esar para aquellas macros que se anidan, por ejemplo:
 
#include <stdiohopper.hhh>
main:
true(i)
iif(false,{"Es verdad\n"},\
iif(true,{"Es verdad por 2 intento\n"},{"Es falso"})), println
return exit(0)
 
En el ejemplo, la macro IIF, ubicada dentro de STDIO.HH, anidada, extiende la programación; en este caso, es muy útil "\".
 
 
=== DIRECTIVA "*" ===
 
Es un comodín, que será reemplazado por cualquier cosa que encuentre en el argumento. Este comodín es FINAL, es decir, debe colocarse como último argumento de la macro.
Line 5,127 ⟶ 5,112:
 
 
=== DIRECTIVA ";" ===
 
El semicolon es útil para forzar que el preprocesador de macros de HOPPER lea una expresión, como un único argumento. Dicho caracter puede ser usado en el código de programa, en la invocación de macros.
Line 5,154 ⟶ 5,139:
Este número reemplazará todas las instancias de #RNDV dentro de la actual expansión. Se coloca al principio del desarrollo de la macro, y desaparece en la expansión. Ejemplo:
 
#defn uniformrand(_MU_,_FVAR_,*) #RAND,_V_#RNDV=0,{*}randarray(_V_#RNDV),\
{_V_#RNDV}mulby(2),minus(1),mulby(_FVAR_),\
plus(1),mulby(_MU_),clear(_V_#RNDV)
 
En el ejemplo, se crea un número pseudo-aleatorio, y éste reemplaza a todas las instancias #RNDV, creándose variables intermedias. Por ejemplo, si #RAND libera 28973, todas las instancias _V_#RNDV se convierten en _V_28973.
Line 5,166 ⟶ 5,151:
Ejemplo:
 
#defn rnd #RAND, {#RNDV}divby(1000000)
 
Esta macro generará un número aleatorio entre 0 y 1, igual que la instrucción RAND:
Line 5,182 ⟶ 5,167:
La macro ADDTO espera que exista un valor en el stack. Si el argumento _X_ es un número o una variable, reemplazará a #ATOM y lo colocará entre "{}", o sea, declarará un PUSH de ese dato; si es una expresión compleja (una operación), reemplazará #CMPLX, pero omitirá el uso de "{}". Es decir:
 
{100},add to (5) ==> expande: {100}{5};add
{100},add to ({x}minus(1)) ==> expande: {100}{x}minus(1);add
 
{100},add to ({x}minus(1)) ==> expande: {100}{x}minus(1);add
 
RESTRICCION. Cada combinación #ATOM#CMPLX reemplaza a un solo argumento de la macro, en la posición señalada. Por ejemplo:
Line 5,199 ⟶ 5,183:
Permite al preprocesador de HOPPER la toma de decisiones dentro de una macro particular. Ejemplo:
 
/* sobrecarga de instrucciones aritmeticas naturales: MINUS */
#defn minusMINUS(_X_) #IF minus(#ATOMF) #ELSE #CMPLX;postfix;sub;postfix #EIF
 
MINUS es más rápido que SUB, pero solo admite una constante o una variable. La macro, sobrecargano puede sobrecargar al operador real, dándolepor lalo posibilidadque dese elegirhace elnecesario tipo de operaciónescribirla, segúnen laeste naturalezacaso, delcon argumentomayúscula.
 
{5}minus(x) ==> expande a: {5}minus(x)
{5}minusMINUS({x}mul by'10') ==> expande a: {5}{x}mul by'10';postfix;sub;postfix
 
Recordar que POSTFIX activa/desactiva el cálculo en notación polaca. Para el ejemplo, calculará 5 - x*10; sin POSTFIX, HOPPER calcularía x*10-5, y no cumpliría con el sentido de la operación MINUS.
 
 
$$END Directivas inline para #defn
$$BEGIN Directivas de estructuras
 
 
=== #LOOP / #ENDLOOP, %LOOP / %ENDLOOP ===
Line 5,218 ⟶ 5,197:
Sirven para definir estructuras de CICLO. Con estas directivas, es posible simular estructuras de control WHILE, familia de FOR, REPEAT/UNTIL, y cualquiera que pueda imaginar.
 
La directiva #LOOP devuelve una etiqueta aleatoria para usarla como declaración de un bloque. Dicha etiqueta es colocada en un stack, el que será consultado por %LOOP para "cerrar" la estructura. Asimismo, #ENDLOOP devuelve otra etiqueta aleatoria, que señala el fin de la estructura, y la coloca en el stack de estructuras. Dicha etiqueta será consultada por %ENDLOOP.
 
El stack de etiquetas permite la anudación de estructuras.
Line 5,224 ⟶ 5,203:
Ejemplo:
 
#defn while(*) &( ) #LOOP:,*,jnt(#ENDLOOP)
#defn for(_X_,_Y_,_Z_) &(_Z_) _X_, #LOOP:, _Y_, jnt(#ENDLOOP)
 
#defn wend %&, jmp(%LOOP), %ENDLOOP:
#synon wend next
 
%LOOP y %ENDLOOP sacan la etiqueta del stack de estructuras.
 
Las directivas %LOOP y %ENDLOOP sacan la etiqueta del stack de estructuras.
 
=== DIRECTIVAS &(), %& ===
Line 5,258 ⟶ 5,236:
---v--- ------------v------------- -------------v------------
_Z_ %LOOP %ENDLOOP
 
 
 
Line 5,271 ⟶ 5,248:
Ejemplo:
 
#defn continue %%&, jmp(%%LOOP)
#defn break jmp(%%ENDLOOP)
 
Si en el ejemplo del ciclo FOR anterior, existiese un CONTINUE, éste expandiría así:
Line 5,291 ⟶ 5,268:
Ejemplo:
 
#defn foreachline(_Y_,_X_,_V_) #RAND, ##ENDLOOP\
&(++_V_;{_V_#RNDV,_V_},jgt(%%ENDLOOP)),\
_Y_="", _V_=1, _V_#RNDV=0, {"\n"}toksep,\
totaltoken(_X_), cpy( _V_#RNDV ), \
jz(%%ENDLOOP), #LOOP:,{_V_},$(_X_),mov(_Y_)
 
Ejemplo:
#include <stdio.hh>
main:
s="Juanito juega a la pelota\nMaría tenía un corderito\nPablito clavó un clavito"
v="",indice=0
for each line(v, s, indice)
prnlutf8(v)
next
return(0)
Line 5,320 ⟶ 5,297:
Ejemplo (stdio.hh):
 
#defn try swtrap( #CATCH )
#defn raise(_ERR_,_M_) {_M_}, throw(_ERR_)
#defn catch(_X_) jmp(#ENDCATCH), %CATCH:,\
clearstack,_X_=0,gettry(_X_)
#defn finish %ENDCATCH:, popcatch
 
Las directivas #CATCH y #ENDCATCH son almacenadas en el stack de estructuras, por lo que también permiten anidamiento.
 
 
Line 5,333 ⟶ 5,310:
Estas directivas se diseñaron para simular estructuras de BIFURCACION, aunque no necesariamente se remiten a IF/ELSE. Con ellas, es posible dar vida a la estructura IF/ELSEIF/ELSE/ENDIF, y a otras, como se mostrará a continuación.
 
Ejemplo (stdio.hh y hopper.h):
 
#defn elseif(*) jmp(%%CODEIF), %ENDIF:, *, jnt(#ENDIF)
#defn if(*) ##CODEIF, *, jnt(#ENDIF)
#defn else jmp(%%CODEIF), %ENDIF:, true,jnt(#ENDIF)
#defn endif %CODEIF:, %ENDIF:
 
NOTA: se coloca ELSEIF antes de IF, porque el preprocesador se confunde si están al revés.
 
La directiva ##CODEIF crea una etiqueta aleatoria, y la guarda en el stack de bifurcación. #ENDIF creará una única etiqueta aleatoria, que será consumida por ELSEIF o por ELSE, asegurando el funcionamiento de la estructura. ELSEIF o ELSE, consumen la etiqueta (%ENDIF), y a continuación, crean una nueva con #ENDIF.
 
La lógica de "%%" es la misma vista en las directivas anteriores.
Line 5,348 ⟶ 5,325:
Un ejemplo de una bifurcación natural, se muestra a continuación, donde se espera que exista un dato en el stack, y que sea TRUE o similar:
 
#defn segúnloanteriorhazesto ##CODEIF,jnt(#ENDIF)
#defn hastaaquí %CODEIF:,%ENDIF:
 
 
Line 5,358 ⟶ 5,335:
Ejemplo (hopper.h):
 
#defn iif(_X_,_Y_,_Z_) #ATOMF#CMPLX, jnt(#ENDIIF),\
#ATOMF#CMPLX, jmp(#ENDIF),\
%ENDIIF:, #ATOMF#CMPLX, %ENDIF:
 
La macro IIF requiere de #ENDIF, que la usa para reservar una etiqueta de salto, si la expresión _X_ es TRUE.
Line 5,368 ⟶ 5,345:
Ejemplo:
 
#include <hopper.h>
main:
false(i)
iif(i, {"Es verdad\n"},\
iif(true,{"Es verdad por 2do intento\n"},{"Es falso"}))
println
return exit(0)
 
imprimirá: "Es verdad por 2do intento"
543

edits