Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Temas - Miky Gonzalez

#1
Creo este tema para que aporten idea, una mejor solución o cualquier cosa que puedan aportar para mejorar esta pequeña idea.

En cuestión quiero crear una librería para simplificar el uso de sockets, en otra palabras, hacer las cosas más cómodamente.

La estructura general de la librería se compone de una estructura que almacena datos del socket; una estructura candidata posible podría ser algo como:

typedef int socket;

typedef struct libreria_socket {
socket socket_fd;
struct sockaddr_in host;
} socket;


La segunda cosa fundamental será la inicialización de esa estructura. Para ello necesitamos 2 funciones auxiliares que recibirán los parametros directamente desde una función principal iniciar_socket; la primera de ellas crear_socket, supongamos que AF (Adress Format) es INET (IP y puerto): AF_INET; la segunda de ellas podría tener 2 variantes: iniciar_sockaddr e iniciar_sockaddrany. La diferencia de estas es que en la estructura sockaddr_in, sin_addr atendería en todo el rango: 127.0.0.1/24.

Funciones secundarias, que bien podrían servir para formar parte de una función principal que automatice el proceso dependiendo de las necesidades del usuario final ó para tener el código más organizado, limpio, estético y hacer las cosas más sencillas. Estas son las funciones conectar_socket, bind_socket, escuchar_socket, aceptar_socket (esta según lo anterior también podría tener dos variantes: aceptar_socket y aceptar_socket_addrany), cerrar_socket.

Las funciones de lectura y escritura pueden usarse nativamente. Un pseudocódigo de cómo funcionaría la librería según las ideas que tengo ahora mismo:

socket socket_test;

iniciar_socket(&socket_test, 8080 /* puerto */, "127.0.0.1" /* direccion ip */);
conectar_socket(&socket_test);

char buffer[1024];

// Recibir datos
read(socket_test.socket_fd, buffer, 1024);

// Reenviar datos
write(socket_test.socket_fd, buffer, 1024);


De momento eso es todo. Aporten ideas, comentarios, soluciones, otra forma de hacerlo...

Saludos.
#2
Hoy recordando un tema que leí en éste mismo foro de Programación C/C++ acerca de la lectura de archivos y la interpretación de archivos de registros (LOGs) se me ha ocurrido programar un poco, una cosa ha derivado a la otra hasta que se me ha propuesto un problema acerca de la optimización del uso de arrays.

Es más rápido crear un array estático con los elementos suficientes (o más) del conjunto que queremos guardar. Por ejemplo, puedo crear un array de tipo char y tamaño 1024 para almacenar un texto de entrada y operar luego con él. Pero, ¿para qué reservar 1024 bytes si sólo usaré, por ejemplo, 8 bytes?. Entonces me puse a pensar en arrays dinámicos, en que por cada elemento valor añadido al conjunto llamaría a "realloc" para reservar el nuevo tamaño del conjunto, esto resulta muy lento. Una posible solución que se me ha ocurrido es reservar siguiendo como 2^n. Esto es:


  • Creo un array de tamaño 1
  • Inserto nuevo valor en array, para ello reservo 2^1 bytes
  • Inserto nuevo valor en array, para ello reservo 2^2 bytes, esto me permite añadir 1 elemento más sin necesidad de llamar a realloc (ya hay suficiente espacio para este elemento)
  • Si añado otro elemento más se reservan 2^3 bytes, esto es, tengo espacio para 4 elementos sin llamar a realloc

Con esto creo arrays dinámicos teniendo en cuenta la velocidad de proceso. La primera pregunta/duda/opininión me viene si hay una manera más optima teniendo en cuenta memoria/velocidad de procesamiento.

La siguiente preguntas es si existe una manera "organizada", tambien podria decirse como una manera adecuada, limpia, eficiente, de almacenar datos de todos los tipos reservando una N cantidad de memoria. Por ejemplo, si creo una estructura para el problema anterior para usar una "librería simple" de arrays dinámicos, la estructura usada para valores que contengan tipos enteros no me servirá para valores que contengan tipos char.

Existe alguna forma de hacer, en pseudocódigo:

Código (bash) [Seleccionar]
Almacenar 4 bits
# Con estos 4 bits puedo almacenar 4 tipos chars o un entero o un float...
Insertar entero...
O insertar char x 4...
O insertar float...

#3
Para el uso más cómodo de un programa en la creación de un simulador físico que requiere el uso de muchos vectores se me ha ocurrido crear una libreria para el manejo de los vectores. Comienzo definiendo la siguiente estructura:

typedef struct _vectf {
float *data;
int cap;
} vectf;


Entonces para la creación del vector uso:

vectf v;

Y creo una función que inicialice el vector (reservar memoria y ajustar elementos):

int init_vectorf(vectf *vectorf, int capacity) {
vectorf->data = malloc(capacity * sizeof(float));
if(!vectorf->data)
return 0;

vectorf->cap = sizeof(vectorf->data) / sizeof(vectorf->data[0]);
//vectorf->cap = capacity;
printf("sizeof(float) = %ld\n", sizeof(float));
printf("Inicializado vectorf de tamano: %d (%d elementos).", (int)sizeof(vectorf->data), sizeof(vectorf->data) / sizeof(vectorf->data[0]));

return 1;
}


En este paso se encuentra mi problema. Explicaré la idea del código para un mejor entendimiento:
1. Se reserva memoria para (n_elementos * tamaño_dato), esto es, si yo declaro:

init_vectorf(&vectorf, 3);

el cálculo sería: (3 * sizeof(float)), es decir, 3 elementos * 4 bytes = 12 bytes.

Cuando se hace la operación: vectorf->cap = sizeof(vectorf->data) / sizeof(vectorf->data[0]); la capacidad se establece a 3, como debería: memoria_total / tamaño_dato = 12 bytes / 4 bytes = 3 elementos.

El error viene que justamente despues al mostrarse la información de inicialización del vector escribe el siguiente mensaje en pantalla:

Código (bash) [Seleccionar]
mikygonzalez@public_gpg ~/ $ Inicializado vectorf de tamano: 8 (2 elementos).

¿Alguien puede explicar porqué no me devuelve tamaño 12, 3 elementos?. Seguramente sea un error con los punteros ó el tamaño de datos, pero no soy capaz de localizarlo.

Saludos,
MikyGonzalez
#4
Gilisoft Usb Lock es un programa que nos permite entre muchas otras cosas bloquear el acceso USB y páginas web.

Su utilización es sencilla y tiene la posibilidad de introducir una contraseña de acceso para modificar sus configuraciones. Esta contraseña esta cifrada, y nosotros a traves del editor de registro podemos saber la contraseña (cifrada). No hace falta saber el algoritmo de cifrado, ya que cualquier valor que introduzcamos en el campo de contraseña equivale a un valor cifrado. A esto se le llama cifrado por diccionario (por ejemplo: a = 0x85, b = 0x86...). En esta situación se puede producir un ataque fácilmente porque el algoritmo de cifrado no determina ni la posición del carácter ni la longitud de la cadena.

Despues de ver el código del programa, se determina el siguiente diccionario:


Si es una contraseña larga y no merece buscar cual es el texto descifrado, podríamos sustituir todo el contenido por: 9e 00, equivalente a la contraseña "a" ('a'-'\0').

Una alternativa para ordenador que tienen eliminado/prohibido el uso del editor de registro, se puede utilizar el comando reg para interactuar con el registro; un ejemplo de su uso: reg import cambiar_clave_gilisoft.reg.

Para el uso con sistemas de 64Bits, el código a importar en registro sería como sigue:

Código (dos) [Seleccionar]
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Gilisoft-usb-lock\configure]
"datP"=hex:9e,00


32 Bits:

Código (dos) [Seleccionar]
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Gilisoft-usb-lock\configure]
"datP"=hex:9e,00
#5
Programación C/C++ / [Ayuda-C] Algo falla...
12 Octubre 2013, 15:16 PM
Dado el siguiente código:

char lista_instrucciones[NUM_INSTR][10] = {
{"PRINT"},
{"SUM"},
{"EXIT"}
};

char *codigo = "PRINT BASURA!", *codigo2 = "EXIT TRASH";

void identificador_cadena(unsigned char *codigo) {
unsigned short int pos_buffer = 0;
char *buffer = (char *)malloc(1 * sizeof(char));

while(saber_letra(codigo[pos])) {
buffer[pos_buffer] = codigo[pos];
pos++;
pos_buffer++;
buffer = (char *)realloc(buffer, (pos_buffer + 1) * sizeof(char));
}

buffer[pos_buffer] = '\0';

// Reutilizar variable pos_buffer
for(pos_buffer = 0; pos_buffer < NUM_INSTR; pos_buffer++)
if(!strcmp(buffer, lista_instrucciones[pos_buffer]))
printf("Encontrado %s en %s\n", lista_instrucciones[pos_buffer], buffer);

free(buffer);
return;
}


Se espera que al pasar las variables codigo y codigo2 a la función identificador_cadena, esta imprima en pantalla:

Encontrado PRINT en PRINT
Encontrado EXIT en EXIT


Pero en su lugar, imprime:
Encontrado SUM en PRINT
Encontrado EXIT en PRINT
Encontrado PRINT en EXIT
Encontrado SUM en EXIT


¿Alguien podría determinar el error?, no entiendo porque esto sucede
#6
Solo por interés, les dejo un código proveniente de una fuente web que les dejo más abajo:

#include <stdio.h>

int m = 1711276033, N = 1, t[1 << 25] = { 2 }, a, *p, i, e = 39717691, s, c, U = 1;

void g(int d, int h) {
for(i = s; i < 1 << 24; i *= 2)
d = d * 1LL * d % m;
for(p = t; p < t + N; p += s)
for(i = s, c = 1; i; i--)
a = p[s] * (h ? c : 1LL) % m, p[s] = (m * 1U + *p - a) * (h ? 1LL : c) % m, *p = (a * 1U + *p) % m, p++, c = c * 1LL * d % m;
}

int main() {
while(e /= 2) {
N *= 2;
U = U * 1LL * (m + 1) / 2 % m;
for(s = N; s /= 2;)
g(40, 0);
for(p = t; p < t + N; p++)
*p = *p * 1LL ** p % m * U % m;
for(s = 1; s < N; s *= 2)
g(983983719, 1);
for(a = 0, p = t; p < t + N;)
a += *p << (e & 1), *p++ = a % 10, a /= 10;
}
while(!*--p);
for(t[0]--; p >= t;)
putchar(48 + *p--);

return 0;
}


[1] http://ijunkey.com/a-small-c-program-to-print-the-biggest-prime-number/
#7
Programación C/C++ / [Ayuda-C] Bucle infinito
10 Octubre 2013, 18:43 PM
Estaba programando en C un ensamblador para programas de mi máquina virtual (decidí continuar un proyecto). Tengo el siguiente código:

/*! Ejemplo de lector de archivo */

#include <stdio.h>
#include <stdlib.h>

/*! Declaración de variables locales */
enum {lex_PARI = '(', lex_PARD = ')', lex_LLAI = '{', lex_LLAD = '}'};
unsigned short int pos = 0x00;
unsigned int codigo_volumen;
unsigned char *codigo;
FILE *codigo_archivo;

void siguiente_lexema(unsigned char *codigo);

void buscar_caracter(char caracter) {
while((caracter != codigo[pos]) && (pos < codigo_volumen)) {
siguiente_lexema(codigo);
pos++;
}
if(pos == codigo_volumen)
printf("Se esperaba '%c'", caracter);
}

// modo == 0 (si cadena)
// modo == 1 (si entero)
void identificador(unsigned char *codigo, char modo) {

return;
}

int saber_letra(char caracter) {
return (((caracter >= 'A') && (caracter <= 'Z')) || ((caracter >= 'a') && (caracter <= 'z')));
}

int saber_numero(char caracter) {
return ((caracter >= '0') && (caracter <= '9'));
}

void siguiente_lexema(unsigned char *codigo) {
switch(codigo[pos]) {
case lex_PARI:
printf("Encontrado: %c\n", lex_PARI);
buscar_caracter(lex_PARD);
break;
case lex_LLAI:
printf("Encontrado: %c\n", lex_LLAI);
buscar_caracter(lex_LLAD);
break;
default:
if(saber_letra(codigo[pos]))
identificador(codigo, 0);
else if(saber_numero(codigo[pos]))
identificador(codigo, 1);
/*
* TODO: Mostrar error. Ignorar espacios, salto de línea y tabulador
*/
else
;
break;
}

return;
}

int main(int argc, char **argv) {
if(argc < 2) {
printf("Uso: %s <archivo>\n", argv[0]);
return 0;
}
codigo_archivo = fopen(argv[1], "r");
if(!codigo_archivo) {
printf("[ASM] Error al leer el archivo %s\n", argv[1]);
return 0;
}

/* Calcular tamaño (volumen) del código */
fseek(codigo_archivo, 0, SEEK_END);
codigo_volumen = ftell(codigo_archivo);
rewind(codigo_archivo);
if(!codigo_volumen) {
printf("[ASM] No hay instrucciones...\n");
fclose(codigo_archivo);
return 0;
}

/* Reservar el espacio necesario para almacenar
* el código en memoria. Si existe, copiarlo. */
codigo = (unsigned char *)malloc(codigo_volumen);
if(!fread(codigo, 1, codigo_volumen, codigo_archivo)) {
printf("[ASM] Error en lectura de archivo...\n");
fclose(codigo_archivo);
return 0;
} else fclose(codigo_archivo);

while(pos < codigo_volumen) {
siguiente_lexema(codigo);
pos++;
}

return 0;
}


El problema está en que dado un archivo:

Código (ini) [Seleccionar]
{
{
{
( {} )( } } }


Entra en un bucle infinito. He revisado muchas veces el código pero no veo ningún error de direcciones, punteros... ¿Alguien puede determinar a causa de que?
#8
Programación C/C++ / [C] Kernel - Contru...ctor
9 Octubre 2013, 19:26 PM
¡ADVERTENCIA!: Este tema contiene datos de otras páginas. Existe código ensamblador en el código.

Primero de todo, deberían revisar como funciona el ordenador para poder entender la práctica que aquí les pongo. No lo voy a explicar, hay muchos sitios donde se explica el funcionamiento interno de un ordenador.

El código fuente de mi Kernel se divide en varios archivos, para mantener el código ensamblador necesario apartado del código C. Empezaré por el primer archivo que debo crear:

Código (asm) [Seleccionar]
.section multiboot
// Cabezera multiboot
.align 4
.int 0x1badb002
.int 0x0
.int -0x1badb002

.section .text

// "init" es una función definida en init.c
.extern init

// _start debe ser global, para que el enlazador pueda encontrarla y
// usarla como punto de entrada.
.global _start
_start:
   // Inicializar la pila
   mov $kernel_stack, %esp

   // Llamar al código C
   call init

   // Parar CPU - retorno desde código C
   hlt

.section .bss
.space 8192
kernel_stack:


El próximo archivo que deberiamos crear sería el código C (init.c):

void init(void) {
   while(1) ;
}


Por último necesitamos un enlazador que nos permita enlazar correctamente el código C y el código ensamblador para poder usarlo en nuestro bootloader (yo usaré GRUB2):

Código (asm) [Seleccionar]
/*  En _start debe iniciar la ejecución */
ENTRY(_start)
SECTIONS {
   . = 0x100000;
   .text : {
       *(multiboot)
       *(.text)
   }
   .data ALIGN(4096) : {
       *(.data)
   }
   .rodata ALIGN(4096) : {
       *(.rodata)
   }
   .bss ALIGN(4096) : {
       *(.bss)
   }
}


Hasta ahora, compilando nuestro código y virtualizándolo (por ejemplo yo uso QEMU), nos saldrá la pantalla de como GRUB carga nuestro Kernel, pero... ¿cómo sabemos que lo cargo?.
La dirección de memoria de video (estándar - sin paginación) es la dirección 0x8B000. Sabiendo esto y que hay 25 columnas por 80 filas, y que se necesita un valor de color letra, podemos escribir un "Hola mundo" en pantalla:

char *video = (char *) 0xB8000; // Dirección memoria video
unsigned short int x = 0, y = 0; // Actual posición puntero

void putchar(char chr) {
   if((chr == '\n') || (x > 79)) {
       x = 0;
       y++;
   }
   if(chr == '\n')
       return;

   if(y > 24) {
       int i;
       for (i = 0; i < 2 * 24 * 80; i++)
           video[i] = video[i + 160];

       for (; i < 2 * 25 * 80; i++)
           video[i] = 0;
       y--;
   }

   video[2 * (y * 80 + x)] = chr;
   video[2 * (y * 80 + x) + 1] = 0x07; // Color "default"

   x++;
   return;
}


Con esto, desde nuestro código init, podríamos hacer:

int bucle_i;
char *str1 = "Hola Mundo!"; // 11 carácteres

for(bucle_i = 0; bucle_i < 11; bucle_i++)
   putchar(str1[bucle_i]);


Esto sería nuestra gran primitiva función printf de C. Podríamos crear una función strlen y usar de esta forma:
void printf(char *str) {
   int bucle_i = 0;

   for(; bucle_i < strlen(str); bucle_i++)
       putchar(str[bucle_i]);
}


Eso es todo, intentaré publicar avances y código de mi kernel.

[FUENTES]
#9
Adjunto el código fuente de una máquina simple que he estado haciendo, pero no tengo más tiempo para continuarla ni tampoco para terminar el ensamblador. Actualmente dispone de las siguientes funciones:




Set de instrucciones:
0x00haltdetiene el cpu
0x01litcargar en acumulador un valor inmediato
0x02loadcargar en acumulador valor de un registro
0x03storealmacenar valor acumulador en un registro
0x04incincrementar por 1 el acumulador
0x05decdecrementar por 1 el acumulador
0x06putlponer en memoria un valor inmediato
0x07putrponer en registro un valor de memoria
0x08getacargar en acumulador un valor de memoria
0x09getrcargar en registro un valor de memoria
0x0Acmplcomparar acumulador con valor inmediado. establece flag
0x0Bcmprcomparar acumulador con valor registro. establece flag
0x0Cjmpsaltar a direccion de codigo (inicio == 0x00)
0x0Djmplsaltar a direccion de codigo si flag == 1 ( < )
0x0Ejmpesaltar a direccion de codigo si flag == 2 ( = )
0x0Fjmpg    saltar a direccion de codigo si flag == 3 ( > )



Especificaciones técnicas:
El CPU consta de 4 registros de usuario, un registro flag y el registro acumulador. La máquina dispone de memoria a modo de pila (tengo otra versión con memoria dinámica, en vez de usar una pila); también se dispone de una memoria de sólo lectura para el código.




main.c:
/*!
Miky Gonzalez Virtual Machine
Contact: mikygonzalez95@gmail.com

Miky Gonzalez Virtual Machine por Miky Gonzalez se encuentra bajo una
Licencia Creative Commons Atribución-NoComercial-CompartirIgual 3.0
Unported. Más información:
http://creativecommons.org/licenses/by-nc-sa/3.0/deed.es
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include <inttypes.h>
//#include <time.h>

#include "pila.h"

/* MVM - Estructura de la MV */
typedef struct CPU {
short int registro[4];
short int acumulador;
unsigned int inst_pointer;
unsigned char *memoria_codigo;
unsigned char flag;
pila_ pila;
} cpu_t;

unsigned int crear_cpu(cpu_t *cpu, unsigned char *memoria_codigo) {
if(!memoria_codigo || !cpu) return 0;

//memset(cpu->registro, 0, sizeof(cpu->registro) / sizeof(*cpu->registro));
unsigned short int i = 0;
for(; i < 4; i++)
cpu->registro[i] = 0;
cpu->acumulador = 0;
cpu->inst_pointer = 0;
cpu->memoria_codigo = memoria_codigo;
cpu->flag = 0;
cpu->pila = NULL;

return 1;
}

void ejecutar_cpu(cpu_t *cpu) {
if(!cpu) {
printf("[MVM] Error al ejecutar CPU...\n");
return;
}
while(1) {
switch(cpu->memoria_codigo[cpu->inst_pointer]) {
case 0x00: /*! halt */
printf("halt\n");
return;
case 0x01: /*! lit */
cpu->acumulador = cpu->memoria_codigo[++cpu->inst_pointer];
printf("lit %d\n", cpu->memoria_codigo[cpu->inst_pointer]);
break;
case 0x02: /*! load */
if(cpu->memoria_codigo[++cpu->inst_pointer] > 0x03) {
printf("[CPU] Desbordamiento en numero de registro.\n");
return;
}
cpu->acumulador = cpu->registro[cpu->memoria_codigo[cpu->inst_pointer]];
printf("load r%d\n", cpu->memoria_codigo[cpu->inst_pointer]);
break;
case 0x03: /*! store */
if(cpu->memoria_codigo[++cpu->inst_pointer] > 0x03) {
printf("[CPU] Desbordamiento en numero de registro.\n");
return;
}
cpu->registro[cpu->memoria_codigo[cpu->inst_pointer]] = cpu->acumulador;
printf("store r%d\n", cpu->memoria_codigo[cpu->inst_pointer]);
break;
case 0x04: /*! inc */
cpu->acumulador++;
printf("inc\n");
break;
case 0x05: /*! dec */
cpu->acumulador--;
printf("dec\n");
break;
case 0x06: /*! pushl */
push(&cpu->pila, cpu->memoria_codigo[++cpu->inst_pointer]);
printf("pushl %d\n", cpu->memoria_codigo[cpu->inst_pointer]);
break;
case 0x07: /*! pushr */
if(cpu->memoria_codigo[++cpu->inst_pointer] > 0x03) {
printf("[CPU] Desbordamiento en numero de registro.\n");
return;
}
push(&cpu->pila, cpu->registro[cpu->memoria_codigo[cpu->inst_pointer]]);
printf("pushr r%d\n", cpu->memoria_codigo[cpu->inst_pointer]);
break;
case 0x08: /*! pop */
if(pila_vacia(&cpu->pila)) {
printf("[CPUSTACK] No hay elemento en pila.\n");
return;
}
pop(&cpu->pila);
printf("pop\n");
break;
case 0x09: /*! loadt */
if(pila_vacia(&cpu->pila)) {
printf("[CPUSTACK] No hay elemento en pila.\n");
return;
}
cpu->acumulador = pop(&cpu->pila);
printf("loadt\n");
break;
case 0x0A: /*! cmpl */
if(cpu->acumulador < cpu->memoria_codigo[++cpu->inst_pointer])
cpu->flag = 1;
else if(cpu->acumulador == cpu->memoria_codigo[cpu->inst_pointer])
cpu->flag = 2;
else if(cpu->acumulador > cpu->memoria_codigo[cpu->inst_pointer])
cpu->flag = 3;
printf("cmpl %d\n", cpu->memoria_codigo[cpu->inst_pointer]);
break;
case 0x0B: /*! cmpr */
if(cpu->acumulador < cpu->registro[cpu->memoria_codigo[++cpu->inst_pointer]])
cpu->flag = 1;
else if(cpu->acumulador == cpu->registro[cpu->memoria_codigo[cpu->inst_pointer]])
cpu->flag = 2;
else if(cpu->acumulador > cpu->registro[cpu->memoria_codigo[cpu->inst_pointer]])
cpu->flag = 3;
printf("cmpr r%d\n", cpu->memoria_codigo[cpu->inst_pointer]);
break;
case 0x0C: /*! jmp */
printf("jmp %d\n", cpu->memoria_codigo[++cpu->inst_pointer]);
cpu->inst_pointer = cpu->memoria_codigo[cpu->inst_pointer] - 1;
break;
case 0x0D: /*! jmpl */
printf("jmpl %d\n", cpu->memoria_codigo[++cpu->inst_pointer]);
if(cpu->flag == 1)
cpu->inst_pointer = cpu->memoria_codigo[cpu->inst_pointer] - 1;
break;
case 0x0E: /*! jmpe */
printf("jmpe %d\n", cpu->memoria_codigo[++cpu->inst_pointer]);
if(cpu->flag == 2)
cpu->inst_pointer = cpu->memoria_codigo[cpu->inst_pointer] - 1;
break;
case 0x0F: /*! jmpg */
printf("jmpg %d\n", cpu->memoria_codigo[++cpu->inst_pointer]);
if(cpu->flag == 3)
cpu->inst_pointer = cpu->memoria_codigo[cpu->inst_pointer] - 1;
break;
default:
printf("[CPU] Instruccion desconocida. Cerrando proceso CPU.\n");
return;
}
cpu->inst_pointer++;
printf("r0: %d\tr1: %d\tr2: %d\tr3: %d\tac: %d\n", cpu->registro[0], cpu->registro[1], cpu->registro[2], cpu->registro[3], cpu->acumulador);
contar_nodos(cpu->pila);
}
}

int main(int argc, char *argv[]) {
/* Inicializar datos y comprobar argumentos */
if(argc < 2) {
printf("Uso: %s <archivo>\n", argv[0]);
return 0;
}
FILE *codigo_archivo = fopen(argv[1], "rb");
if(!codigo_archivo) {
printf("[MVM] Fallo al abrir el archivo %s\n", argv[1]);
return 0;
}

/* Calcular tamaño (volumen) del código */
unsigned int codigo_volumen;
fseek(codigo_archivo, 0, SEEK_END);
codigo_volumen = ftell(codigo_archivo);
rewind(codigo_archivo);
if(!codigo_volumen) {
printf("[MVM] No hay instrucciones...\n");
fclose(codigo_archivo);
return 0;
}

/* Reservar el espacio necesario para almacenar
* el código en memoria. Si existe, copiarlo. */
unsigned char *codigo = (unsigned char *)malloc(codigo_volumen);
if(!fread(codigo, 1, codigo_volumen, codigo_archivo)) {
printf("[MVM] Error en lectura de archivo...\n");
fclose(codigo_archivo);
return 0;
} else fclose(codigo_archivo);

/* Crear CPU e inicializar los datos */
cpu_t cpu;
if(!crear_cpu(&cpu, codigo)) {
printf("[MVM] Error al crear CPU...\n");
return 0;
}

/* Ejecutar CPU hasta instrucción fin o error */
ejecutar_cpu(&cpu);
printf("r0: %d\tr1: %d\tr2: %d\tr3: %d\tac: %d\n", cpu.registro[0], cpu.registro[1], cpu.registro[2], cpu.registro[3], cpu.acumulador);
contar_nodos(cpu.pila);
eliminar_pila(&cpu.pila);
free(codigo);

getchar();
return 0;
}


pila.c:
/*!
Miky Gonzalez Virtual Machine
Contact: mikygonzalez95@gmail.com

Miky Gonzalez Virtual Machine por Miky Gonzalez se encuentra bajo una
Licencia Creative Commons Atribución-NoComercial-CompartirIgual 3.0
Unported. Más información:
http://creativecommons.org/licenses/by-nc-sa/3.0/deed.es
*/

/*! Implementación de una pila para memoria de datos MVM */

#include <stdio.h>
#include <stdlib.h>
#include "pila.h"

void push(pila_ *pila, int valor) {
nodo_ nodo = (nodo_)malloc(sizeof(nodo_t));

if(nodo != NULL) {
nodo->valor = valor;
nodo->nodo_siguiente = *pila;
*pila = nodo;
}
}

int pop(pila_ *pila) {
nodo_ nodo;
int valor = 0;

nodo = *pila;
valor = (*pila)->valor;
*pila = (*pila)->nodo_siguiente;

free(nodo);
return valor;
}

//#define pila_vacia(a) *a == NULL ? 1:0;
unsigned short int pila_vacia(pila_ *pila) {
return (*pila == NULL ? 1 : 0);
}

unsigned short int contar_nodos(nodo_ nodo) {
if(nodo == NULL) return 0;

unsigned short int nodos = 0;
while(nodo != NULL) {
nodos++;
printf("n%d: %d\t", nodos, nodo->valor);
nodo = nodo->nodo_siguiente;
}
printf("\n");

return nodos;
}

// #define eliminar_pila(a) {if(pila_vacia(a))return;while(!pila_vacia(a))pop(a);}
void eliminar_pila(pila_ *pila) {
if(pila_vacia(pila)) return;
while(!pila_vacia(pila)) pop(pila);
return;
}


pila.h:
/*!
Miky Gonzalez Virtual Machine
Contact: mikygonzalez95@gmail.com

Miky Gonzalez Virtual Machine por Miky Gonzalez se encuentra bajo una
Licencia Creative Commons Atribución-NoComercial-CompartirIgual 3.0
Unported. Más información:
http://creativecommons.org/licenses/by-nc-sa/3.0/deed.es
*/

#ifndef MVM_PILA
#define MVM_PILA

/* Estructura de nodos de pila */
typedef struct NODO {
int valor;
struct NODO *nodo_siguiente;
} nodo_t;

typedef nodo_t *nodo_;
typedef nodo_t *pila_;

void push(pila_ *pila, int valor);
int pop(pila_ *pila);
unsigned short int pila_vacia(pila_ *pila);
unsigned short int contar_nodos(nodo_ nodo);
void eliminar_pila(pila_ *pila);

#endif


Actualmente no dispongo de tiempo para terminar el ensamblador, así que tendrán que crear los ejecutables editandolos hexadecimalmente, hice un programa para facilitarme el trabajo de prueba:

#include <stdio.h>

int main(int argc, char **argv) {
char codigo[] = {0x00};
FILE *fd;
fd = fopen("test", "wb");
if(!fd) return 0;
fwrite(codigo, sizeof(char), sizeof(codigo), fd);
fclose(fd);
return 0;
}





Algunos ejemplos ya programados, con sus respectivos opcodes:

#========================================
# CALCULAR RESTA DE DOS NUMEROS
#========================================
# Usando 2 registros se pueden hacer
# funciones de resta de números.
# resultado: r0
#========================================

# Inicializacion de los datos

lit 25 # ac: 25
store r0 # r0: 25
lit 17 # ac: 17
store r1 # r1: 17
lit 0 # ac: 0

# Bucles

load r1 # ac: r1
dec # ac: ac--
store r1 # r1: ac
load r0 # ac: r0
dec # ac: ac--
store r0 # r0: ac

lit 1 # ac: 1
cmpr r1 # comparar ac & r1
jmpg 16 # ac > r1 --> jmp 16
jmp 6 # jmp 6

halt # stop

# 0x01 25 0x03 0x00 0x01 17 0x03 0x01 0x01 0x00 0x02 0x01 0x05
# 0x03 0x01 0x02 0x00 0x05 0x03 0x00 0x01 0x01 0x0B 0x01 0x0F 28
# 0x0C 10 0x00


#========================================
# CALCULAR SUMA DE DOS NUMEROS
#========================================
# Usando 2 registros se pueden hacer
# funciones de suma de números.
# resultado: r0
#========================================

# Inicializacion de los datos

lit 17 # ac: 17
store r0 # r0: 17
lit 25 # ac: 25
store r1 # r1: 25
lit 0 # ac: 0

# Bucles

load r1 # ac: r1
dec # ac: ac--
store r1 # r1: ac
load r0 # ac: r0
inc # ac: ac++
store r0 # r0: ac

lit 1 # ac: 1
cmpr r1 # comparar ac & r1
jmpg 16 # ac > r1 --> jmp 16
jmp 6 # jmp 6

halt # stop
# 0x01 25 0x03 0x00 0x01 17 0x03 0x01 0x01 0x00 0x02 0x01 0x05
# 0x03 0x01 0x02 0x00 0x04 0x03 0x00 0x01 0x01 0x0B 0x01 0x0F 28
# 0x0C 10 0x00


#========================================
# CALCULAR MULTIPLICACION DE DOS NUMEROS
#========================================
# Utilizando 3 registros (incluso menos) se
# pueden hacer funciones de multiplicación
# de números.
# resultado: r2.
#========================================

# Inicialización de los datos

lit 10 # ac: 10
store r0 # r0: 10
lit 3 # ac: 3
store r1 # r1: 3
lit 0 # ac: 0


# Bucles

load r1 # ac: r1
dec # ac: ac--
store r1 # r1: ac
cmpl 0 # comparar ac & 0
jmpe 23 # ac == 0 --> jmp 23

lit 10 # ac: 10
store r0 # r0: 10

load r2 # ac: r2
inc # ac: ac++
store r2 # r2: ac
load r0 # ac: r0
dec # ac: ac--
store r0 # r0: ac
lit 0 # ac: 0
cmpr r0 # comparar ac & r0
jmpl 13 # ac < r0 --> jmp 13
jmp 6 # jmp 6

lit 0 # ac: 0
store r1 # r1: 0

halt # stop
#0x01 0x0A 0x03 0x00 0x01 0x03 0x03 0x01 0x01 0x00  
#0x02 0x01 0x05 0x03 0x01 0x0A 0x00 0x0D 0x29 0x01
#0x0A 0x03 0x00 0x02 0x02 0x04 0x03 0x02 0x02 0x00
#0x05 0x03 0x00 0x01 0x00 0x0B 0x00 0x0D 23 0x0C 10
#0x01 0x00 0x03 0x01 0x00


Espero que este proyecto les guste, y si alguien puede continuarlo, espero que lo haga y tenga buenas ideas, tal vez aunque no puedo no seria malo proponerlas, nunca se sabe si volvere a continuar con la máquina virtual.

Saludos,
  Miky Gonzalez
#10
Mi problema es el siguiente: supongamos que sólo tengo una función que me permite cojer 1 solo caracter numérico (getch() - 48). ¿Cómo podría hacer para cojer mas de un caracter?.

Si no lo entiendo les pongo un ejemplo: yo tengo una variable tipo entero. Hago que se guarde el valor devuelto por getch() a mi variable tipo entero. Algo como:
Introduce un numero: 4
Numero introducido: 4

El problema viene cuando:
Introduce un numero: 42
Numero introducido: 4

Como es de obviar, el 2 se queda en el buffer. Cómo puedo hacer, suponiendo que sólo tengo la función getch que sólo lee un caracter, la lectura de enteros (hasta encontrar caracter 0xA ('\n'). Supongamos tambien que el valor devuelto por getch() es de tipo entero.
#11
Programación C/C++ / [Opiniones] Máquina virtual
17 Septiembre 2013, 22:45 PM
Especificaciones de la máquina virtual:

El CPU virtual consta de varios registros:
4 registros utilizables a modo usuario, el registro acumulador (*), puntero de instrucción, memoria de código y memoria de datos y un último registro de tamaño byte usado para establecer comparaciones.

La memoria de datos, los 4 registros de usuario y el registro acumulador son de tipo short int, esto quiere decir que pueden alcanzar valores desde 0x0000 hasta 0xFFFF, menos la memoria, que alcanza valores desde 0x1000 hasta 0x2000 (esto son 4kB).

La memoria de datos está programada para en un futuro poder utilizar varias en una misma CPU usadas como "módulos". Para utilizarla un ejemplo podría ser:
putl 1001 BB (guardar en posicion 1 valor 0xBB).
Es posible que en un futuro se junten las dos memorias (memoria de código y memoria de datos).




Set de instrucciones:
0x00haltdetiene el cpu
0x01litcargar en acumulador un valor inmediato
0x02loadcargar en acumulador valor de un registro
0x03storealmacenar valor acumulador en un registro
0x04incincrementar por 1 el acumulador
0x05decdecrementar por 1 el acumulador
0x06putlponer en memoria un valor inmediato
0x07putrponer en registro un valor de memoria
0x08getacargar en acumulador un valor de memoria
0x09getrcargar en registro un valor de memoria
0x0Acmplcomparar acumulador con valor inmediado. establece flag
0x0Bcmprcomparar acumulador con valor registro. establece flag
0x0Cjmpsaltar a direccion de codigo (inicio == 0x00)
0x0Djmplsaltar a direccion de codigo si flag == 1 ( < )
0x0Ejmpesaltar a direccion de codigo si flag == 2 ( = )
0x0Fjmpg    saltar a direccion de codigo si flag == 3 ( > )



Programas de ejemplos (con sus opcodes)

#========================================
# CALCULAR RESTA DE DOS NUMEROS
#========================================
# Usando 2 registros se pueden hacer
# funciones de resta de números.
# resultado: r0
#========================================

# Inicializacion de los datos

lit 25 # ac: 25
store r0 # r0: 25
lit 17 # ac: 17
store r1 # r1: 17
lit 0 # ac: 0

# Bucles

load r1 # ac: r1
dec # ac: ac--
store r1 # r1: ac
load r0 # ac: r0
dec # ac: ac--
store r0 # r0: ac

lit 1 # ac: 1
cmpr r1 # comparar ac & r1
jmpg 16 # ac > r1 --> jmp 16
jmp 6 # jmp 6

halt # stop


char codigo[] = {0x01, 25, 0x03, 0x00, 0x01,
  17, 0x03, 0x01, 0x01, 0x00,
  0x02, 0x01, 0x05, 0x03, 0x01,
  0x02, 0x00, 0x05, 0x03, 0x00,
  0x01, 0x01, 0x0B, 0x01, 0x0F,
  28, 0x0C, 10, 0x00};


#========================================
# CALCULAR SUMA DE DOS NUMEROS
#========================================
# Usando 2 registros se pueden hacer
# funciones de suma de números.
# resultado: r0
#========================================

# Inicializacion de los datos

lit 17 # ac: 17
store r0 # r0: 17
lit 25 # ac: 25
store r1 # r1: 25
lit 0 # ac: 0

# Bucles

load r1 # ac: r1
dec # ac: ac--
store r1 # r1: ac
load r0 # ac: r0
inc # ac: ac++
store r0 # r0: ac

lit 1 # ac: 1
cmpr r1 # comparar ac & r1
jmpg 16 # ac > r1 --> jmp 16
jmp 6 # jmp 6

halt # stop


char codigo[] = {0x01, 17, 0x03, 0x00, 0x01,
  25, 0x03, 0x01, 0x01, 0x00,
  0x02, 0x01, 0x05, 0x03, 0x01,
  0x02, 0x00, 0x04, 0x03, 0x00,
  0x01, 0x01, 0x0B, 0x01, 0x0F,
  28, 0x0C, 10, 0x00};


#========================================
# CALCULAR MULTIPLICACION DE DOS NUMEROS
#========================================
# Utilizando 3 registros (incluso menos) se
# pueden hacer funciones de multiplicación
# de números.
# resultado: r2.
#========================================

# Inicialización de los datos

lit 10 # ac: 10
store r0 # r0: 10
lit 3 # ac: 3
store r1 # r1: 3
lit 0 # ac: 0


# Bucles

load r1 # ac: r1
dec # ac: ac--
store r1 # r1: ac
cmpl 0 # comparar ac & 0
jmpe 23 # ac == 0 --> jmp 23

lit 10 # ac: 10
store r0 # r0: 10

load r2 # ac: r2
inc # ac: ac++
store r2 # r2: ac
load r0 # ac: r0
dec # ac: ac--
store r0 # r0: ac
lit 0 # ac: 0
cmpr r0 # comparar ac & r0
jmpl 13 # ac < r0 --> jmp 13
jmp 6 # jmp 6

lit 0 # ac: 0
store r1 # r1: 0

halt # stop


char codigo[] = {0x01, 0x0A, 0x03, 0x00, 0x01,
  0x03, 0x03, 0x01, 0x01, 0x00,  
  0x02, 0x01, 0x05, 0x03, 0x01, 0x0A, 0x00,
  0x0D, 0x29,
  0x01, 0x0A, 0x03, 0x00, 0x02, 0x02, 0x04,
  0x03, 0x02, 0x02, 0x00, 0x05, 0x03, 0x00,
  0x01, 0x00, 0x0B, 0x00, 0x0D, 23, 0x0C,
  10, 0x01, 0x00, 0x03, 0x01, 0x00};





Espero opiniones, críticas y sus comentarios
#12
Programación C/C++ / [Ayuda] Conversiones *char - int
17 Septiembre 2013, 17:43 PM
Supongamos que yo tengo la siguiente matriz:

char codigo[] = {0x00, 0xFF, 0x01, 0x03, 0x01, 0xFF, 0xFF, 0x00};

Con esta matriz se podrian hacer muchas cosas, desde interpretarla, hasta leer numeros. Mi pregunta:

En la posición 5 (recordar que empieza desde 0) y en la 6 hay 0xFF. Perfectamente podria poner en numero entero como 256, 256. Pero mi cuestion es: ¿Cómo puedo leer esos dos 0xFF, para que me queden como un 0xFFFF (tamaño de short int). Para que me entiendan, si hubiera: 0x4F, 0x33; quedaria: 0x4F33.

Se me ocurrieron varias opciones como: (0x4F << 2) &  0x33, pero ningun me funciona. ¿Podrían ayudarme?
#13
Llevo ya desarroyando una máquina virtual largo tiempo, pero no tengo mucho tiempo, estoy con otros proyectos más importantes. Las funciones actuales (no creo que implemente alguna función más, sólo características y ampliaciones):




0x00haltdetiene el cpu
0x01litcargar en acumulador un valor inmediato
0x02loadcargar en acumulador valor de un registro
0x03storealmacenar valor acumulador en un registro
0x04incincrementar por 1 el acumulador
0x05decdecrementar por 1 el acumulador
0x06pushlponer en pila un valor inmediato
0x07pushrponer en pila valor de un registro
0x08popeliminar 'cima de pila' (tos)
0x09loadtalmacenar valor retorno de pop en acumulador
0x0Acmplcomparar acumulador con valor inmediado. establece flag
0x0Bcmprcomparar acumulador con valor registro. establece flag
0x0Cjmpsaltar a direccion de codigo (inicio == 0x00)
0x0Djmplsaltar a direccion de codigo si flag == 1 ( < )
0x0Ejmpesaltar a direccion de codigo si flag == 2 ( = )
0x0Fjmpg    saltar a direccion de codigo si flag == 3 ( > )



No es un juego de instrucciones completo ni facil de usar, pero teoricamente cualquier otra operación se puede hacer con esas instrucciones, de echo, hice una operación de multiplicar dos números (30 * 3):

Código (asm) [Seleccionar]
#========================================
# CALCULAR MULTIPLICACION DE DOS NUMEROS
#========================================
# Utilizando tres registros se
# pueden hacer funciones de multiplicación
# de números.
#========================================

# Inicialización de los datos

lit 10 # ac: 10
store r0 # r0: 10
lit 3 # ac: 3
store r1 # r1: 3
lit 0 # ac: 0


# Bucles

load r1 # ac: r1
dec # ac: ac--
store r1 # r1: ac
cmpl 0 # comparar ac & 0
jmpe 23 # ac == 0 --> jmp 23

lit 10 # ac: 10
store r0 # r0: 10

load r2 # ac: r2
inc # ac: ac++
store r2 # r2: ac
load r0 # ac: r0
dec # ac: ac--
store r0 # r0: ac
lit 0 # ac: 0
cmpr r0 # comparar ac & r0
jmpl 13 # ac < r0 --> jmp 13
jmp 6 # jmp 6

lit 0 # ac: 0
store r1 # r1: 0

halt # stop


A la hora de ser compilado para la máquina virtual, queda una matriz como:
char codigo[] = {
0x01, 0x0A, 0x03, 0x00, 0x01,0x03, 0x03, 0x01, 0x01, 0x00,
0x02, 0x01, 0x05, 0x03, 0x01, 0x0A, 0x00, 0x0D, 0x29,
0x01, 0x0A, 0x03, 0x00, 0x02, 0x02, 0x04, 0x03, 0x02, 0x02,
0x00, 0x05, 0x03, 0x00, 0x01, 0x00, 0x0B, 0x00, 0x0D, 23,
0x0C, 10, 0x01, 0x00, 0x03, 0x01, 0x00};


Cuya alternativa en código C:
int num1, num2 = 3;
int mult = 0;

for (; num2 > 0; num2--) {
for(num1 = 10; num1 > 0; num1--) {
mult++;
}
}





Pueden si quieres crear sus propios algoritmos y postearlos en este mensaje, me ayudaría mucho, estoy intentando implementar "funciones externas", un archivo que incluya funciones para simplificar el trabajo. Esto es una multiplicación simple, seguramente se puede hacer optimizable y/o más corta, cualquier código que quieran crear utilizando esas funciones me ayudaria para probar la máquina virtual.

En aproximadamente 2 semanas espero publicar el código fuente completo... no me gusta sacar 100 versiones para una aplicacion!

Saludos
#14
Supongamos por un momento que debes hacer un programa que calcule, lo más exactamente posible, una media, o cálculos, que de seguro, tendrán decimales. Sólo hay una pega, no puedes usar el tipo float bajo ningún concepto.

Lo mejor para este ejercicio sería crear un archivo de cabezera que incluya estructura para crear tu propio tipo float basandote en tipos enteros. Hacer eso es muy facil:


typedef struct _real {
       int entero;
       unsigned long int decimal;
} real_t;


Pero se deben crear tambien unas funciones que nos permita actuar con sencillez, como si de un tipo entero se tratase. Puedes empezar por estas funciones:


real_t declarar_real(int entero, unsigned long int decimal) {
   real_t real;    

   real.entero = entero;
   real.decimal = decimal;

   return real;
}

#define mostrar_real(a) printf("%d.%u", a.entero, a.decimal)


Lo que se pide en este ejercicio, para quienes quieran hacerlo para practicar sus conocimientos:
Crear funciones de suma y resta de numeros tipo real, al igual que funciones de multiplicación y división.
Si has echo lo anterior, prueba a modificar la estructura para que admita un número ilimitado de decimales (podrías hacerlo con una matriz dinámica).
#15
Me gustaría que me diesen alguna opinión acerca de las implementaciones actuales y en el apartado 'para hacer' las ideas que tengo. La máquina virtual está programada y es rápida. Usa memoria dinámica para el uso de registros y la pila. Pronto intentaré implementar para el uso de API y añadir funcionalidades propias sin modificar código interno.

Expecificaciones del lenguaje:
Se trata de un microlenguaje de programación ensamblador orientado al uso de pila, registros y operaciones aritméticas. Esta diseñado con el mero propósito de aprender.

Dispone de 8 registros (r0-r7)(tipo entero), elegidos así porque me parece un número de registros adecuado. No admite cadenas de caracteres ni números reales. Es un lenguaje semicompilado, es decir, sus intrucciones son transmitidas a opcodes que son emulados por una máquina virtual (actualmente, la
máquina virtual ya está en una buena fase de desarrollo).

Algunas especificaciones técnicas del lenguaje:
   · Debe respetarse el orden de parámetros
   · Los registros son numerados desde 0 a 7, indicando que es un registro con la letra 'r' precediendo al número.
   · Para definir el inicio del programa debera utilizarse la etiqueta %main% precedida de las intrucciones.
   · Para definir el fin del programa debera utilizarse la etiqueta %end main%
   · Para definir una funcion común (no implementado) deberá utilizarse la etiqueta %nombredefuncion,parametro1,param...% finalizando esta con %end nombredefuncion%
   · Pueden incluirse comentarios en el código con ' y '= ='.
   · Cada línea tendrá como máximo una función
   · Pueden definirse 'cotas' de código para hacer el código más pequeño, compartiendo biblioteca que pueden ser incluidas en el código con %include archivo.mvm%. Se dispondrá de version estándar  de algunas implementaciones para agilizar el uso y ampliar las funciones con el uso de API.

Función 'setr' - Establece el valor a un registro:
   setr [r0-r7] num1      ' Uso normal

Función 'add' - Función con la capacidad de sumar 2 enteros y guardar la operación en el registro indicado:
   add [r0-r7] num1,num2   ' Uso normal
   
Función 'addr' - Suma 2 enteros, uno de ellos dado por el valor de un registro. Con las funciones add y addr pueden hacerse todas las operaciones de suma desde sumar dos registros hasta sumar registro con datos de la pila:
   addr [r0-r7] rX,rX      ' Uso normal
   
Función 'neg' - Niega el valor de un registro dado:
   neg [r0-r7]            ' Uso normal
   
El equivalente a la función 'sub' se puede utilizar conjuntamente con 'addr' y 'neg':
   '= Queremos restar r1 - r0 y guardar valor en r3 ='
   neg r0
   addr r3 r1 r0
   
Función 'mult' - Multiplica 2 enteros y guarda la operación en el registro dado:
   mult [r0-r7] num1,num2   ' Uso normal
   
Función 'multr' - Multiplica el valor de 2 registros y guarda la  operación en el registro dado:
   multr [r0-r7] rX,rX      ' Uso normal
   
Función 'push' - Pone el valor de un registro en pila:
   push [r0-r7]         ' Uso normal
   
Función 'pop' - Elimina el tos:
   pop                  ' Uso normal

Función 'inrp' - Intercambia el valor de un registro y del tos:
   inrp [r0-r7]         ' Uso normal

El equivalente a 'inrr' (intercambiar dos registros, mov), puede hacerse con funciones ya descritas:
   '= Queremos intercambiar r0 y r1. Vamos a suponer que todos los
   registros tienen valores que deben ser guardados. ='
   push r0
   inrp r1
   inrp r0
   pop

Otra utilidad que tiene las funciones anteriores, no se necesita de función 'clonr' (clonar valor de un registro en otro), ya que, esta podria hacerse de muchas otras maneras con inrp o addr.

Función 'cmp' - Comparar si el valor de un registro y un valor proporcionado son iguales, mayor, menor (con respecto al registro):
   cmp [r0-r7]   num1      ' Uso normal

Función 'cmpr' - Comparar si el valor de dos registros son iguales, mayor, o menor (con respecto al primer registro):
   cmpr [r0-r7] [r0-r7]   ' Uso normal

Para hacer:
Cambiar la forma de analizar las funciones, para evitar usar funciones clonadas para operar con registros (add, addr, mult, multr...); Así, se podrá operar con los registros de una forma más fácil y comoda.
Añadir funciones condicionales, uso de cadenas, operaciones con cadenas.
Ampliar numero de funciones aritméticas (shl, shr, xor, div, mod...).
#16
Buenas a todos, inicio un nuevo POST para pedirles ayuda sobre la programación de un analizador léxico-sintáctico. No entiendo los códigos que vi por ahí, o si los entiendo, son demasiados complejos para implementarlos y hacer una adaptación.

Les pondré un ejemplo si no entienden lo que quiero conseguir. Supongamos un fichero de texto como el que sigue:

var
    int a, b, c;
    string d, e, f;
begin
    print("hola")
end


El desglosamiento del programa podría seguir un arbol como:

Declarar variables
   |-a como entero
   |-b como entero
   |-c como entero
   |-d como cadena
   |-e como cadena
   |-f como cadena
Iniciar ejecucion
   |- llamar funcion print con argumento hola como cadena
Fin ejecucion


Y que eso me genere unos ciertos opcodes, (no es necesario que el programa genere el arbol anterior), por ejemplo podria ser:
0x00 a (declarar int a), 0x00 b (declarar int b) ... 0x01 d (declarar string d) ... 0x02 "hola" (llamar funcion print con argumento hola).

No se como implementar esto en C. ¿Alguien puede ayudarme?

Saludos,
   Miky Gonzalez
#17
Supongamos por un momento el siguiente código:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include <inttypes.h>

/* MVM - Estructura de la MV */
typedef struct CPU {
unsigned int inst_pointer;
unsigned char *memoria;
} cpu_t;

cpu_t *crear_cpu(unsigned char *memoria) {
if(!memoria) return NULL;
cpu_t *cpu_init = malloc(sizeof(*cpu_init));
cpu_init->inst_pointer = 0;
       cpu_init->memoria = memoria;

return cpu_init;
}

void borrar_cpu(cpu_t *cpu) {
if(!cpu) return;
//void *datos = (void *)((uintptr_t)cpu);
//free(datos);
free(cpu);
}

int main(int argc, char *argv[]) {
/* Inicializar datos y comprobar argumentos */
if(argc < 2) {
printf("Uso: %s <archivo>\n", argv[0]);
return 0;
}
unsigned int codigo_volumen = 100;
/* Reservar el espacio necesario para almacenar
* el código en memoria. Si existe, copiarlo. */
unsigned char *codigo = (unsigned char *)malloc(codigo_volumen);
if(!fread(codigo, 1, codigo_volumen, ARCHIVO)) {
fclose(codigo_archivo);
return 0;
} else fclose(codigo_archivo);

cpu_t *cpu = crear_cpu(codigo);
if(!cpu) return 0;

borrar_cpu(cpu);
free(codigo);

return 0;
}


Faltan muchas parte del código, pero está lo esencial para mi cuestión. Explico un poco el funcionamiento:
Es una máquina virtual (¿dificil de saber?, no creo xD), en la que leo un archivo, calculo el tamaño, creo memoria dinamica para almacenar el contenido del archivo con malloc y fwrite respectivamente. Creo una variable con tipo estructura de la CPU de la MV, llamo a la funcion que me crea la CPU y le asigna el puntero. Despues libero la memoria del codigo (supuestamenta) y la de la CPU creada con la funcion crear_cpu, a través de la función borrar_cpu.
Creo que estoy utilizando mal, o los punteros, o el uso de free(). No se porqué, ni dónde, ni cómo hacerlo bien. El programa funciona correctamente, pero creo que hay fugas de memoria. ¿Podrían solventar mi problema?.
#18
Voy a ir directo: tengo una función en C que me provoca un fallo de segmentación. He revisado y creo que los punteros están bien colocados y no devería de acceder a recursos de memoria no-accesibles.
void eliminar_espacios(char *contenido_linea) {
char *cadena_temporal = (char *)malloc(255);

while(*contenido_linea) {
if((*contenido_linea != 32) && (*contenido_linea != '\t')) {
contenido_linea++;
} else {
*cadena_temporal = *contenido_linea;
cadena_temporal++;
}
}

return (void)contenido_linea;
}


Elimina los espacios de una cadena.

Saludos!
#19
Hace aproximadamente un par de semánas (estamos hablando de principio de marzo) publiqué el código fuente de una máquina virtual con un par de funciones.
Actualicé la máquina y tiene un juego de instrucciones como sigue:

halt    Detener la máquina virtual
setr    Establecer un valor inmediato en un registro
push    Almacena en la pila el valor de un registro
pop    Elimina el TOS (primer elemento de pila)
move    Intercambia los valores entre el TOS y un registro
sum    Suma el valor de un registro y otro, el valor se almacena en el primer registro
div    Divide el valor de un registro y otro, el valor se almacena en el primer registro
mod    Divide el valor de un registro y otro, el valor del resto de división se almacena en el primer registro
mult    Multiplica el valor de un registro y otro, el valor se almacena en el primer registro
not    Niega un elemento
xor    Operación OR condicional con dos registros. El valor se almacena en el primer registro
shl    Mueve los bits de un registro hacia la izquierda un numero de veces como marque el segundo registro.
shr    Mueve los bits de un registro hacia la derecha un numero de veces como marque el segundo registro.
ife    Si los dos registros especificados son iguales, ejecuta la siguiente accion. En caso contrario la salta.
goto    Establece el 'ip' al valor inmediato dado.

El código fuente puede obtenerse de aquí

Unos ejemplos tambien pueden obtener desde aquí (con los opcodes correspondientes)

Un saludo, espero que les sirve de alguna utilidad. Un ejemplo de su uso podría ser por ejemplo para utilizar en algoritmo de cifrado, es mucho más difícil saber de donde sale un dato si este se está ejecutando virtualmente.

Puede obtener más información en: artículo
#20
Haber, no sabía como poner esto hexactamente, así que pense en un nombre:

Hexadecimal Dumper And To C Convertor

Creo que no hace falta explicar mucho, es un dumpeador hexadecimal para convertir cualquier archivo a variable del tipo char en C. En otras palabras, convierte:

#include <stdio.h>

double factorial(short int numero) {
    int pred = 0;
    double tmp = numero;
    for (pred = --numero; pred > 1; --pred)
        tmp *= pred;
    return tmp;
}

int main(void) {
    double factor87 = factorial(87);
    printf("Factorial de 87: %.20lg", factor87);
    getchar();   
    return 0;
}


En esto:

char hexdump2c[] = {
0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x74, 0x64, 0x69, 0x6f, 0x2e, 0x68, 0x3e,
0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x69,
0x61, 0x6c, 0x28, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72,
0x6f, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x65, 0x64,
0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x20,
0x74, 0x6d, 0x70, 0x20, 0x3d, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x70, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x2d, 0x2d, 0x6e, 0x75, 0x6d,
0x65, 0x72, 0x6f, 0x3b, 0x20, 0x70, 0x72, 0x65, 0x64, 0x20, 0x3e, 0x20, 0x31, 0x3b, 0x20, 0x2d, 0x2d, 0x70,
0x72, 0x65, 0x64, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x20,
0x2a, 0x3d, 0x20, 0x70, 0x72, 0x65, 0x64, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
0x72, 0x6e, 0x20, 0x74, 0x6d, 0x70, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x69, 0x6e, 0x74, 0x20,
0x6d, 0x61, 0x69, 0x6e, 0x28, 0x76, 0x6f, 0x69, 0x64, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x38, 0x37, 0x20, 0x3d, 0x20,
0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x28, 0x38, 0x37, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x61,
0x6c, 0x20, 0x64, 0x65, 0x20, 0x38, 0x37, 0x3a, 0x20, 0x25, 0x2e, 0x32, 0x30, 0x6c, 0x67, 0x22, 0x2c, 0x20,
0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x38, 0x37, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x65,
0x74, 0x63, 0x68, 0x61, 0x72, 0x28, 0x29, 0x3b, 0x20, 0x20, 0x20, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a};


El código fuente del programa es: /* Simple dumpeador de archivos a hexadecimal y guardar en C
* http://mikygonzalez.16mb.com
*/

#include <stdio.h>

#define TAM_HEXCODE 18

/*! Función principal hexdump */
void hexdump(FILE *archivo_fd) {
unsigned short int bucle_i;
char caracter_actual = '\0';
fseek(archivo_fd, 0, SEEK_SET);

while(!feof(archivo_fd)) {
for(bucle_i = 0; bucle_i < TAM_HEXCODE; bucle_i++) {
caracter_actual = fgetc(archivo_fd);
if(caracter_actual == EOF)
return (void) 0;
printf("0x%.2x, ", caracter_actual);
}
printf("\n");
}
}

int main(int argc, char *argv[]) {
FILE *archivo_fd;

if(argc < 2)
return 1;
if(!(archivo_fd = fopen(argv[1], "rb")))
return 1;

printf("char hexdump2c[] = {\n");
hexdump(archivo_fd);
printf("\b\b};\n");

return 0;
}


También pueden encontrarse este y otros programas en: http://pastes.mikygonzalez.16mb.com/?ad2cea935c65385a#c0bI9LQ9BD6f8snTLpklw/LgzXRnOEs6lJHJWqbbb9c= o en mi pagina personal (en la firma).

Saludos
#21
Estoy haciendo un manual de la creación de una máquina virtual, no creo que tenga que decir que en C... por algo estamos en el foro: "Programación C/C++"  ::). A continuación pongo el código fuente totalmente creado por mí basandomes en diversa información:
/*
* Miky Gonzalez Virtual Machine - Segunda revisión
* Compilar con: gcc -o vm vm.c -O2
* Para más información y futuras versiones visita:
* http://mikygonzalez.16mb.com/
*/

#include <stdio.h>
#include <stdlib.h>

#define MAXIMOS_NODOS 100

typedef struct _nodo {
int reg_pila;
struct _nodo *siguiente_nodo;
} nodo;

typedef nodo *__nodo;
typedef nodo *__pila;

typedef struct _cpu {
int reg[16];
unsigned short int reg_temp[5];
unsigned short int estado;
unsigned int instruction_pointer;
__pila pila_cpu;
} cpu;

/*! FUNCIONES DE LA PILA */
void push(__pila *pila, int num) {
__nodo nodo_push;

nodo_push = (__nodo) malloc(sizeof(nodo));
if(nodo_push != NULL) {
    nodo_push->reg_pila = num;
    nodo_push->siguiente_nodo = *pila;
    *pila = nodo_push;
   }
}

int pop(__pila *pila) {
__nodo nodo_pop;
int valor_nodo_pop = 0;

nodo_pop = *pila;
valor_nodo_pop = (*pila)->reg_pila;
*pila = (*pila)->siguiente_nodo;
free(nodo_pop);

return valor_nodo_pop;
}

unsigned int contar_nodos(__nodo nodo_pila) {
unsigned int valor_temporal = 0;

if(nodo_pila == NULL)
return valor_temporal;
while(nodo_pila != NULL) {
nodo_pila = nodo_pila->siguiente_nodo;
valor_temporal++;
}

return valor_temporal;
}

/*! FUNCIONES DEL CPU */
void iniciar_datos(cpu* CPU) {
unsigned short int bucle_i;

for(bucle_i = 0; bucle_i < 16; bucle_i++)
CPU->reg[bucle_i] = 0;

CPU->estado = 1;
CPU->instruction_pointer = 0;
CPU->pila_cpu = NULL;
}

void mostrar_datos(cpu* CPU) {
unsigned short int bucle_i;

for(bucle_i = 0; bucle_i < 16; bucle_i++)
printf("REG %d == %d\n", bucle_i, CPU->reg[bucle_i]);

printf("CPU ejecutandose: %s", CPU->estado ? "Si\n" : "No\n");
printf("Instruction Pointer: %d\n", CPU->instruction_pointer);
}

void preparar_cpu(cpu* CPU, unsigned short int instruccion) {
CPU->reg_temp[0] = (instruccion & 0xF000) >> 12;
CPU->reg_temp[1] = (instruccion & 0xF00) >> 8;
CPU->reg_temp[2] = (instruccion & 0xF0) >> 4;
CPU->reg_temp[3] = (instruccion & 0xF);
CPU->reg_temp[4] = (instruccion & 0xFF);
}

void ejecutar_cpu(unsigned int programa[], cpu* CPU) {
int valor_temporal = 0;

while(CPU->estado) {
preparar_cpu(CPU, programa[CPU->instruction_pointer]);
switch(CPU->reg_temp[0]) {
case 0: /*! halt */
CPU->estado = 0;
break;
case 1: /*! setr */
// Comprobar si los datos estan dentro de los registros accesibles
if(0x0 > CPU->reg_temp[1] > 0xF) {
printf("Error: setr espera un registro valido\n");
CPU->estado = 0;
break;
}
CPU->reg[CPU->reg_temp[1]] = CPU->reg_temp[4];
break;
case 2: /*! push */
// Comprobar si los datos estan dentro de los registros accesibles
if(0x0 > CPU->reg_temp[1] > 0xF) {
printf("Error: push espera un registro valido\n");
CPU->estado = 0;
break;
}
// Comprobar elementos maximos de la pila
if(contar_nodos(CPU->pila_cpu) == MAXIMOS_NODOS) {
printf("Error: desbordamiento de pila. MAX: %d\n", MAXIMOS_NODOS);
CPU->estado = 0;
break;
}
push(&CPU->pila_cpu, CPU->reg[CPU->reg_temp[1]]);
break;
case 3: /*! pop */
// Comprobar existe almenos un elemento en pila_cpu
if(CPU->pila_cpu == NULL) {
printf("Error: pop espera un elemento en pila\n");
CPU->estado = 0;
break;
}
pop(&CPU->pila_cpu);
break;
case 4: /*! move */
// Comprobar existe almenos un elemento en pila_cpu
if(CPU->pila_cpu == NULL) {
printf("Error: move espera un elemento en pila\n");
CPU->estado = 0;
break;
}
// Comprobar si los datos estan dentro de los registros accesibles
if(0x0 > CPU->reg_temp[1] > 0xF) {
printf("Error: move espera un registro valido\n");
CPU->estado = 0;
break;
}
valor_temporal = CPU->reg[CPU->reg_temp[1]];
CPU->reg[CPU->reg_temp[1]] = CPU->pila_cpu->reg_pila;
CPU->pila_cpu->reg_pila = valor_temporal;
break;
default:
printf("Instruccion %d no implementada...\n", CPU->reg_temp[0]);
break;
}
valor_temporal = 0;
CPU->instruction_pointer++;
}
}

/*! INICIO DE MG-VM */
int main(int argc, char *argv[]) {
cpu CPU;
unsigned int programa[] = {
0x1010, // setr 0 10
0x2000, // push 0
0x4100, // move 1
0x2100, // push 1
0x3000, // pop
0x3000, // pop
0x0000  // halt
};

iniciar_datos(&CPU);
mostrar_datos(&CPU);

ejecutar_cpu(programa, &CPU);
mostrar_datos(&CPU);

return 0;
}


Si encuentran una manera mejor de hacer las cosas, o más optimizada, porfavor, puedes comentar que propones. Cualquier sugerencia o queja son bienvenidas.
La máquina virtual sólo cuenta con funciones de manejo de la pila y registros. No tiene funciones artiméticas, en la próxima versión entrarán las demás funciones aritméticas. En total tengo un máximo de 16 funciones.

Un saludo, espero que les agrade el código. Intenté escribirlo para que pudiera entenderlo bien, aún siendo principiante en programación.

Para obtener más información del tutorial ó próximas revisiones del código: http://mikygonzalez.16mb.com/
#22
Hola a todo el mundo!. Estoy programando... una cosilla... en C, pero tengo un problema; Explico:
Yo tengo un ejecutable, suponiendo con este codigo:
unsigned char string[255] = {0xef, 0xbe, 0xad, 0xde} // 0xdeadbeed
Y ahora tengo otro ejecutable con el siguiente codigo:
while (1) {
     if (read(archivo_fd, (void *) &numero_magico, 4) <= 3) break;
     if (numero_magico == 0xdeadbeef) goto ir_a_seccion;
     lseek(archivo_fd, 3, SEEK_CUR);
     printf("Numero magico (actual): %lx\n", numero_magico);
 }


El problema está, antes de nada, el código de antes está en crear un archivo ejecutable y con otro ejecutable abrir el archivo y buscar el contenido de numero magico (0xdeadbeef) para sustituir de ahí en adelante por una cadena. El problema se encuentra en que no me encuentra el número mágico... alguien podría ayudar. Gracias
#23
Buenas, haber, hacer si un caracter se repite en una cadena (ver cuantas veces sale) se hacer, pero como hacer por ejemplo, que compare todos los caracteres de una cadena y ver si alguno se repite. Me explico:
Como puedo hacer para que dada una cadena: char string[5] = "Hola"; aqui no se repite ningun caracter pero si digo: "Hoola", saber que se repite un caracter.
No el buscar si el caracter 'o' se repite en la cadena; Si no si algun caracter dentro de la cadena se repite dentro de la misma cadena. ¿?
#24
Buenas, tengo el siguiente codigo:
char caracteres[39] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}, prueba[] = "HOLA MUNDO";
Como puedo hacer por ejemplo que al hacer: strcpy(caracteres, prueba); Se ajuste el tamaño de caracteres a 11 (caracteres[11]) para ahorrar la memoria de esas posiciones que ya no usare. Al hacer el strcpy me queda: char caracteres[39] = {'H', 'O', 'L', 'A', ' ', 'M', 'U', 'N', 'D', 'O', '\n', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} Como puedo eliminar lo anterior y ajustar el valor de caracteres[39] a caracteres[11] (se incluye el final de cadena).
#25
Hola, tengo un pequeño problema que no soluciono:
Tengo (por ejemplo) la siguiente funcion: funcion main(int argc, char **argv).
Y tengo por ejemplo: si (argv[1] == "argumento1"); se escribio un argumento.
Pero como puedo hacer para buscar por ejemplo si se ha contenido en la lista de argumentos el argumento -e por ejemplo para especificar algo, es decir podria hacer: prog.exe a -e; u otro ejemplo prog.exe -e a.
Es decir que sepa si se ha especificado el argumento buscandolo.. intente con strcmp pero nose como hacer para buscar en todos los posibles argumentos que haya puesto
#26
Estoy haciendo un codigo que llevaba bien hasta que me estanque en esto:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void uso(char *);
int main(int argc, char **argv) {
unsigned short int tmp[5] = {0, 0, 0, 0, 0};
char caracteres[39] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z'};
if (argc > 4 || argc < 3) uso(argv[0]);
if (argv[1] == NULL) { printf("ERR ARG:1: Se debe especificar nombre de archivo\n"); uso(argv[0]); }
if (atoi(argv[2]) == 0) { printf("ERR ARG:2: Debe especificarse un numero (longitud de cadena)\n"); uso(argv[0]); }
FILE *file;
    file = fopen(argv[1], "w");
    if (file == NULL) { printf("ERR ARG:1: Ocurrio un problema al abrir/crear el archivo\n"); uso(argv[0]); }
    // GENERADOR DEL DICCIONARIO
for (tmp[0] = 1; tmp[0] <= atoi(argv[2]); tmp[0]++) {
for (tmp[4] = tmp[0]; tmp[4] >= 0; tmp[4]--) {
for (tmp[1] = strlen(caracteres); tmp[1] >= 1; tmp[1]--) {
printf("%c", caracteres[tmp[1]-1]);
if (tmp[0] == 1) printf("\n");
fputc(caracteres[tmp[1]-1], file);
if (tmp[0] == 1) fputc('\n', file);
}
for (tmp[2] = tmp[4]; tmp[2] > 1; tmp[2]--) {
for (tmp[1] = strlen(caracteres); tmp[1] >= 1; tmp[1]--) {
printf("%c", caracteres[tmp[1]-1]);
fputc(caracteres[tmp[1]-1], file);
} printf("\n");
}
}
}
    fclose(file);
    return 0;
}
void uso(char *name) {
printf("Uso: %s archivo longitud [caracteres]\n", name); exit(0);
}


En la sección generador del diccionario solo hace bien la primera parte, me he liado mucho porque llevo como 40 minutos y no logro una solucion lo que quiero que haga:
z
..
a
zz
..
aa
..
zzz
..
aaa

Todas las combinaciones posibles dadas desde los parametros. El codigo creo que todo esta bien menos el algoritmo de generacion del diccionario. ¿Alguna solucion?. Gracias por leer.
#27
Hola, buenas... soy Mike Gonzalez. Estoy haciendo una calculadora por consola, mas bien el modulo de calcular y despues hare la GUI en VB6.
Tengo una funcion hecha que me permite calcular el factorial de un numero:

unsigned long int factorial(short int numero) {
   int pred = 0;
   unsigned long int tmp = numero;
   for (pred = --numero; pred > 1; --pred)
       tmp *= pred;
   return tmp;
}


Las declaraciones son unsigned porque se supone que asi gano mas memoria de calculo (en el almacenamiento de variables). Mi pregunta es que solo me permite calcular hasta el factorial de 25 (a partir de ahi da resultados negativos :S).
Alguna solucion de mejorar el codigo y/o permitirme calcular numeros mas elevados (las calculadoras normales llegan al 69).

Gracias de antemano.