Files
harbour-core/harbour/doc/es/pcode.txt
2002-01-22 22:23:33 +00:00

141 lines
4.3 KiB
Plaintext

/*
* Las siguientes partes son derechos adquiridos de sus autores individuales.
* www - http://www.harbour-project.org
*
* Copyright 2001 Antonio Linares
* Documentación en Inglés
*
* Copyright 2001 Alejandro de Gárate <alex_degarate@hotmail.com>
* Traducción al Español de pcode.txt
*
* Vea doc/license.txt por los términos de la licencia.
*
*/
El OBJ de Clipper y el modelo pcode (GNU|Open|Clipper project)
==============================================================
Consideremos el siguiente ejemplo de Clipper, test.prg:
function Main()
? "Hola mundo!"
return nil
Una vez que esto se compila dentro de un OBJ, qué es lo que hay dentro
de él ?
En efecto, lo que nosostros tenemos es un equivalente a la siguiente
aplicación de lenguaje C:
SYMBOL symbols[] = { ... };
void MAIN( void )
{
BYTE pcode[] = { ... };
VirtualMachine( pcode, symbols );
}
Básicamente, el código fuente de test.prg ha sido convertido en una
secuencia de bytes pcode contenidos en el array pcode[] = {...}
Todo lo que nuestra función MAIN hace es invocar, en tiempo de ejecución
a la función de VirtualMachine() que procesará aquellos bytes de pcodes.
Vamos a revisar la estructura de pcodes de test.prg con más detalle:
0000 (2A) LINE 0 2A 00 00
0003 (2A) LINE 3 2A 03 00
0006 (13) SYMF [QOUT] 13 02 00
0009 (01) PUSHC "Hello world!" 01 ...
0018 (27) DO(1) 27 01 00
001B (2A) LINE 5 2A 05 00
001E (7B) UNDEF 7B
001F (79) SAVE_RET 79
0020 (1E) JMP 0023 1E 00 00
0023 (60) ENDPROC 60
Nosotros podemos definir un archivo hbpcode.h para leer mejor aquellos
pcode:
----------------------
hbpcode.h
#define LINE 0x2A
#define SYMF 0x13
#define PUSHC 0x01
#define DO 0x27
#define UNDEF 0x7B
...
----------------------
Así finalmente esto quedaría como:
BYTE pcode[] =
{ LINE, 0, 0,
LINE, 3, 0,
SYMF, 2, 0,
PUSHC, 'H', 'o', 'l', 'a', ' ', 'm', 'u', 'n', 'd', 'o', '!', '0',
DO, 1, 0,
LINE, 5, 0,
UNDEF,
SAVE_RET,
JMP, 0, 0,
ENDPROC };
Y qué es SYMBOL symbols[] ?
Cliper crea una tabla de símbolos en el archivo OBJ que luego será usada
para crear una tabla dinámica de símbolos compartida por la aplicación
entera. cada uno de esos símbolos tiene la siguiente estructura:
typedef struct
{
char * szName; // Clipper de hecho mantiene un array aquí (11 bytes)
BYTE bScope;
LPVOID pVoid;
} SYMBOL;
#define PUBLIC 0 // el alcance de la función !
SYMBOL symbols[] = { { "MAIN", PUBLIC, MAIN },
{ "QQOUT", PUBLIC, QQOUT } };
Recordemos que el nombre de una función (MAIN, QQOUT) es la dirección de
la función, así nuestra tabla de símbolos estará lista para usarla para
saltar y ejecutar cualquier función enlazada (linkeada).
De hecho, el pcode SYMF 2, 0 en nuestro ejemplo, instruirá a la función
VirtualMachine(), para usar el 2do símbolo que es QQOUT.
Vamos a leer el pcode:
LINE 0, 0 => Nosotros estamos ubicados en la línea 0
LINE 3, 0 => Nosotros estamos ubicados en la línea 3
SYMF 2, 0 => Vamos a llamar a QQOUT desde nuestra tabla de símbolos
PUSHC ... => Esta cadena va a ser usada como un parámetro
DO 1, 0 => ok, saltemos a QQOUT y recordemos que le dimos 1 parámetro
LINE 5, 0 => Estamos de vuelta desde QQOUT y estamos ubicados en línea 5
UNDEF => Nosotros vamos a retornar este valor (NIL)
SAVE_RET => Ok, retornemoslo
JMP 0 => No saltamos dondequiera, continuamos con el próximo pcode
ENDPROC => Es el fin. hemos completado la ejecución de esta función
Todas estas funciones serán evaluadas desde nuestra función
VirtualMachine(), (Clipper la llama _plankton() ). Todas las funciones
terminan usando ENDPROC, así cuando VirtualMachine() encuentra ENDPROC
sabe que ha alcanzado el final de una función pcode.
Ahora que nosotros entendemos claramente el modelo básico, nosotros
estamos en condiciones de comenzar a implementar "reglas de producción"
en nuestra sintaxis yacc (harbour.y) para generar el archivo de salida
específico (test.c) con la estructura de arriba (ó nosotros podemos
fácilmente generar el archivo OBJ para él).
Continuará...
Antonio Linares