180 lines
5.6 KiB
Plaintext
180 lines
5.6 KiB
Plaintext
|
|
/*
|
|
* Las siguientes partes son derechos adquiridos de sus autores individuales.
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* Copyright 2001 Ryszard Glab <rglab@imid.med.pl>
|
|
* Documentación en Inglés de codeblock.txt
|
|
*
|
|
* Copyright 2001 Alejandro de Gárate <alex_degarate@hotmail.com>
|
|
* Traducción al Español de codeblock.txt
|
|
*
|
|
* Vea doc/license.txt por los términos de la licencia.
|
|
*
|
|
*/
|
|
|
|
Implementación de Harbour de codeblocks (bloques de código)
|
|
===========================================================
|
|
|
|
Compilación de un codeblock
|
|
Durante el tiempo de Compilación, el codeblock es almacenado en la
|
|
siguiente forma:
|
|
- la cabecera
|
|
- la ristra de bytes de pcodes
|
|
|
|
La cabecera almacena información acerca de variables locales
|
|
referenciadas.
|
|
+0: el byte pcode para _PUSHBLOCK
|
|
+1: el número de bytes que definen a un codeblock
|
|
+3: el número de parámetros codeblock (declarados entre || en el codeblock)
|
|
+5: número de variables locales usadas declaradas en el procedimiento /
|
|
función donde el codeblock es creado.
|
|
+7: La lista de las posiciones de variables locales de los procedimientos /
|
|
funciones, en la pila eval del procedimiento / función. Cada variable
|
|
local usada en un codeblock usa 2 bytes en esta lista. Cuando son
|
|
usados codeblocks anidados, entonces esta lista es creada solamente
|
|
en el codeblock más externo.
|
|
+x: La ristra de bytes pcode, siguiendo a la cabecera.
|
|
+y: El byte pcode para _ENDBLOCK
|
|
|
|
|
|
Creación de un codeblock
|
|
========================
|
|
Cuando el opcode HB_P_PUSHBLOCK es ejecutado entonces la estructura
|
|
HB_ITEM es creada y puesta en la pila de evaluación. El tipo de item
|
|
es IT_BLOCK.
|
|
El valor de este item es un puntero a la estructura HB_CODEBLOCK.
|
|
Adicionalmente este item almacena la base de las variables estáticas
|
|
definidas para el procedimiento/función actual. - esto es usado durante
|
|
la evaluación de un codeblock cuando la evaluación es llamada desde
|
|
código desde otro módulo PRG. También el número de parámetros esperados
|
|
es almacenado.
|
|
|
|
La estructura HB_CODEBLOCK almacena un puntero a la ristra (stream)
|
|
de pcodes que es ejecutada durante la evaluación de un codeblock.
|
|
Este almacena también el puntero a la tabla con referencia a variables
|
|
locales. Valores de todas las variables locales definidas en un
|
|
procedimiento y usadas en un codeblock son reemplazadas con una
|
|
referencia a un valor almacenado en un pool de variables de memoria
|
|
global. Esto permite el correcto acceso a variables locales aisladas
|
|
en un codeblock devuelto desde ésta función (sea directamente en una
|
|
sentencia RETURN ó indirectamente por asignarlo éste a una variable
|
|
estática ó MEMVAR).
|
|
Este reemplazo automático e incondicional es requerido porque no hay
|
|
un método seguro de encontrar si un codeblock será accedido desde
|
|
fuera de una función dónde éste es creado.
|
|
|
|
Cuando son usados codeblocks anidados, solamente el codeblock más
|
|
externo crea la tabla - todo codeblock interno usa esta tabla.
|
|
Esto permite compartir la tabla entre codeblocks anidados - , la
|
|
tabla es borrada si no hay más referencias a ella.
|
|
Esto es causado por el hecho que un codeblock interno puede ser
|
|
creado durante la evaluación del codeblock exterior cuando las
|
|
variables locales no existen como en este ejemplo:
|
|
|
|
PROCEDURE MAIN()
|
|
PRIVATE foo, bar
|
|
|
|
Test()
|
|
EVAL( foo )
|
|
EVAL( bar )
|
|
|
|
RETURN
|
|
|
|
PROCEDURE Test()
|
|
LOCAL a:='FOO', b:='BAR'
|
|
|
|
foo ={ || a + ( bar:=EVAL( {|| b} ) ) }
|
|
|
|
RETURN
|
|
|
|
|
|
Evaluación de un codeblock
|
|
==========================
|
|
Los parámetros pasados a un codeblock son puestos en la pila de
|
|
evaluación antes de la evaluación del codeblock. Ellos son accedidos
|
|
exactamente igual que cualquier parámetro de función. Cuando un
|
|
parámetro de codeblock es referenciado, entonces su posición en
|
|
la pila de evaluación es usada.
|
|
Cuando una variable local de un procedimiento es referenciada
|
|
entonces el índice dentro de la tabla de posiciones de variables
|
|
locales (copiada de la cabecera) es usada. El valor negativo es
|
|
usado como un índice para distinguirlo de la referencia a un
|
|
parámetro del codeblock.
|
|
|
|
|
|
Incompatibilidad con Clipper
|
|
============================
|
|
|
|
1) Variables locales aisladas pasadas por referencia
|
|
-------------------------------------------------
|
|
Hay una pequeña diferencia entre el manejo de las variables pasadas
|
|
por referencia en un codeblock.
|
|
El siguiente código lo explica (gracias a David G. Holm)
|
|
|
|
Function Main()
|
|
Local nTest
|
|
Local bBlock1 := MakeBlock()
|
|
Local bBlock2 := {|| DoThing( @nTest ), qout("From Main: ", nTest ) }
|
|
|
|
eval( bBlock1 )
|
|
eval( bBlock2 )
|
|
|
|
Return( NIL )
|
|
|
|
Function MakeBlock()
|
|
Local nTest
|
|
Return( {|| DoThing( @nTest ), qout("From MakeBlock: ", nTest ) } )
|
|
|
|
|
|
Function DoThing( n )
|
|
n := 42
|
|
Return( NIL )
|
|
|
|
|
|
En Clipper esto produce:
|
|
Desde MakeBlock = NIL
|
|
Desde Main = 42
|
|
|
|
En Harbour esta produce: (esta es la salida correcta, en mi opinión )
|
|
Desde MakeBlock = 42
|
|
Desde Main = 42
|
|
|
|
|
|
2) Alcance de variables sin declarar
|
|
---------------------------------
|
|
Considere el siguiente código:
|
|
|
|
PROCEDURE MAIN()
|
|
LOCAL cb
|
|
cb :=Detach()
|
|
? EVAL( cb, 10 )
|
|
|
|
RETURN
|
|
|
|
FUNCTION Detach()
|
|
LOCAL b:={|x| x+a}
|
|
LOCAL a:=0
|
|
RETURN b
|
|
|
|
En Clipper la variable 'a' en un codeblock tiene alcance *local* ,
|
|
sin embargo en Harbour la variable 'a' tiene un alcance *privado*.
|
|
Como resultado de ello, en Clipper este código imprimirá 10 y en
|
|
Harbour este producirá "error de argumento" en la operación '+'.
|
|
Esto será cierto cuando la variable 'a' sea declarada como PRIVATE.
|
|
|
|
PROCEDURE MAIN()
|
|
LOCAL cb
|
|
PRIVATE a
|
|
cb := Detach()
|
|
? EVAL( cb, 10 )
|
|
RETURN
|
|
|
|
El código de arriba también produce 10 en Clipper (aún si es
|
|
compilado con el switch -a ó -v).
|
|
|
|
|
|
|
|
|
|
|