Category:Amazing Hopper: Difference between revisions

no edit summary
No edit summary
 
(28 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 4,723 ⟶ 4,729:
#include <stdio.hh>
#include <math.hh>
 
#context-free obtenercuadradodepi
#define imprimeconunsalto {"\n"}print
Line 4,739 ⟶ 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,777 ⟶ 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,792 ⟶ 4,798:
 
#proto cálculo(_X_,_Y_)
#synon _cálculo _operación, _obtencióndelresultado
 
Line 4,799 ⟶ 4,805:
_operación (2,100.6)
_obtención del resultado ({M_PI}mulby(180), 0.25)
 
 
==== #IMPORT ====
Line 4,807 ⟶ 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,824 ⟶ 4,829:
 
#include prototipos.hh
 
main:
{0}return
 
.locals
muestra otro mensaje(m)
Line 4,867 ⟶ 4,872:
---- MENSAJE FINAL!!
 
==== #HL, #HIGH-LEVEL, #FX, #COMPUTE ====
 
Line 4,878 ⟶ 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,897 ⟶ 4,901:
#hl ( (i+30)*M_PI/180 ), mov(resultado)
o su equivalente:
#hl ( resultado = (i+30)*M_PI/180 )
Line 4,947 ⟶ 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,959 ⟶ 4,963:
x = y = log(x+y)^(log(x-y) )
 
p[2]=p[5]=p[7,1]=x=1000
Line 4,974 ⟶ 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,006 ⟶ 5,010:
 
Todas las estructuras de control en #HIGH-LEVEL permiten anidamiento.
 
 
EJEMPLOS:
Line 5,021 ⟶ 5,024:
IF:
 
#hl{
if ( (i==0) && (log(j*10)>2) )
Line 5,028 ⟶ 5,032:
 
DO:
 
i=10
#hl{
Line 5,060 ⟶ 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,073 ⟶ 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,108 ⟶ 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,135 ⟶ 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,147 ⟶ 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,163 ⟶ 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,180 ⟶ 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,199 ⟶ 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,205 ⟶ 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,239 ⟶ 5,236:
---v--- ------------v------------- -------------v------------
_Z_ %LOOP %ENDLOOP
 
 
 
Line 5,252 ⟶ 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,272 ⟶ 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,301 ⟶ 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,314 ⟶ 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,329 ⟶ 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,339 ⟶ 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,349 ⟶ 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