lama_byterun/byterun/byterun.c

342 lines
6.8 KiB
C
Raw Normal View History

2021-09-28 03:02:05 +03:00
/* Lama SM Bytecode interpreter */
2025-02-27 20:59:10 +01:00
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "../runtime/runtime.h"
2021-09-28 03:02:05 +03:00
void *__start_custom_data;
void *__stop_custom_data;
2021-09-28 09:58:10 +03:00
/* The unpacked representation of bytecode file */
2025-02-27 20:59:10 +01:00
typedef struct
{
char *string_ptr; /* A pointer to the beginning of the string table */
int *public_ptr; /* A pointer to the beginning of publics table */
char *code_ptr; /* A pointer to the bytecode itself */
int *global_ptr; /* A pointer to the global area */
int stringtab_size; /* The size (in bytes) of the string table */
int global_area_size; /* The size (in words) of global area */
int public_symbols_number; /* The number of public symbols */
char buffer[0];
2021-09-28 03:02:05 +03:00
} bytefile;
2021-09-28 09:58:10 +03:00
/* Gets a string from a string table by an index */
2025-02-27 20:59:10 +01:00
char *get_string(bytefile *f, int pos)
{
2021-09-28 03:02:05 +03:00
return &f->string_ptr[pos];
}
2021-09-28 09:58:10 +03:00
/* Gets a name for a public symbol */
2025-02-27 20:59:10 +01:00
char *get_public_name(bytefile *f, int i)
{
return get_string(f, f->public_ptr[i * 2]);
2021-09-28 03:02:05 +03:00
}
2021-09-28 09:58:10 +03:00
/* Gets an offset for a publie symbol */
2025-02-27 20:59:10 +01:00
int get_public_offset(bytefile *f, int i)
{
return f->public_ptr[i * 2 + 1];
2021-09-28 03:02:05 +03:00
}
2021-09-28 09:58:10 +03:00
/* Reads a binary bytecode file by name and unpacks it */
2025-02-27 20:59:10 +01:00
bytefile *read_file(char *fname)
{
FILE *f = fopen(fname, "rb");
2021-09-28 03:02:05 +03:00
long size;
bytefile *file;
2025-02-27 20:59:10 +01:00
if (f == 0)
{
failure("%s\n", strerror(errno));
2021-09-28 03:02:05 +03:00
}
2025-02-27 20:59:10 +01:00
if (fseek(f, 0, SEEK_END) == -1)
{
failure("%s\n", strerror(errno));
2021-09-28 03:02:05 +03:00
}
2025-02-27 20:59:10 +01:00
file = (bytefile *)malloc(sizeof(int) * 4 + (size = ftell(f)));
2021-09-28 03:02:05 +03:00
2025-02-27 20:59:10 +01:00
if (file == 0)
{
failure("*** FAILURE: unable to allocate memory.\n");
2021-09-28 03:02:05 +03:00
}
2025-02-27 20:59:10 +01:00
rewind(f);
2021-09-28 03:02:05 +03:00
2025-02-27 20:59:10 +01:00
if (size != fread(&file->stringtab_size, 1, size, f))
{
failure("%s\n", strerror(errno));
2021-09-28 03:02:05 +03:00
}
2025-02-27 20:59:10 +01:00
fclose(f);
2025-02-27 20:59:10 +01:00
file->string_ptr = &file->buffer[file->public_symbols_number * 2 * sizeof(int)];
file->public_ptr = (int *)file->buffer;
file->code_ptr = &file->string_ptr[file->stringtab_size];
file->global_ptr = (int *)malloc(file->global_area_size * sizeof(int));
2021-09-28 03:02:05 +03:00
return file;
}
2021-09-28 10:39:02 +03:00
/* Disassembles the bytecode pool */
2025-02-27 20:59:10 +01:00
void disassemble(FILE *f, bytefile *bf)
{
2025-02-27 20:59:10 +01:00
#define INT (ip += sizeof(int), *(int *)(ip - sizeof(int)))
#define BYTE *ip++
#define STRING get_string(bf, INT)
#define FAIL failure("ERROR: invalid opcode %d-%d\n", h, l)
2025-02-27 20:59:10 +01:00
char *ip = bf->code_ptr;
char *ops[] = {"+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"};
2021-09-28 03:02:05 +03:00
char *pats[] = {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"};
2025-02-27 20:59:10 +01:00
char *lds[] = {"LD", "LDA", "ST"};
do
{
2021-09-28 03:02:05 +03:00
char x = BYTE,
h = (x & 0xF0) >> 4,
l = x & 0x0F;
2025-02-27 20:59:10 +01:00
fprintf(f, "0x%.8x:\t", ip - bf->code_ptr - 1);
2025-02-27 20:59:10 +01:00
switch (h)
{
2021-09-28 03:02:05 +03:00
case 15:
goto stop;
2021-09-28 03:02:05 +03:00
/* BINOP */
case 0:
2025-02-27 20:59:10 +01:00
fprintf(f, "BINOP\t%s", ops[l - 1]);
2021-09-28 03:02:05 +03:00
break;
2021-09-28 03:02:05 +03:00
case 1:
2025-02-27 20:59:10 +01:00
switch (l)
{
case 0:
fprintf(f, "CONST\t%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 1:
fprintf(f, "STRING\t%s", STRING);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 2:
fprintf(f, "SEXP\t%s ", STRING);
fprintf(f, "%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 3:
fprintf(f, "STI");
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 4:
fprintf(f, "STA");
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 5:
fprintf(f, "JMP\t0x%.8x", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 6:
fprintf(f, "END");
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 7:
fprintf(f, "RET");
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 8:
fprintf(f, "DROP");
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 9:
fprintf(f, "DUP");
2021-09-28 03:02:05 +03:00
break;
2021-09-28 03:02:05 +03:00
case 10:
2025-02-27 20:59:10 +01:00
fprintf(f, "SWAP");
2021-09-28 03:02:05 +03:00
break;
2021-10-03 17:10:21 +03:00
case 11:
2025-02-27 20:59:10 +01:00
fprintf(f, "ELEM");
2021-10-03 17:10:21 +03:00
break;
2021-09-28 03:02:05 +03:00
default:
FAIL;
}
break;
2021-09-28 03:02:05 +03:00
case 2:
case 3:
case 4:
2025-02-27 20:59:10 +01:00
fprintf(f, "%s\t", lds[h - 2]);
switch (l)
{
case 0:
fprintf(f, "G(%d)", INT);
break;
case 1:
fprintf(f, "L(%d)", INT);
break;
case 2:
fprintf(f, "A(%d)", INT);
break;
case 3:
fprintf(f, "C(%d)", INT);
break;
default:
FAIL;
2021-09-28 03:02:05 +03:00
}
break;
2021-09-28 03:02:05 +03:00
case 5:
2025-02-27 20:59:10 +01:00
switch (l)
{
case 0:
fprintf(f, "CJMPz\t0x%.8x", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 1:
fprintf(f, "CJMPnz\t0x%.8x", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 2:
fprintf(f, "BEGIN\t%d ", INT);
fprintf(f, "%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 3:
fprintf(f, "CBEGIN\t%d ", INT);
fprintf(f, "%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 4:
fprintf(f, "CLOSURE\t0x%.8x", INT);
{
int n = INT;
for (int i = 0; i < n; i++)
{
switch (BYTE)
{
case 0:
fprintf(f, "G(%d)", INT);
break;
case 1:
fprintf(f, "L(%d)", INT);
break;
case 2:
fprintf(f, "A(%d)", INT);
break;
case 3:
fprintf(f, "C(%d)", INT);
break;
default:
FAIL;
}
}
2021-09-28 03:02:05 +03:00
};
break;
2025-02-27 20:59:10 +01:00
case 5:
fprintf(f, "CALLC\t%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 6:
fprintf(f, "CALL\t0x%.8x ", INT);
fprintf(f, "%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 7:
fprintf(f, "TAG\t%s ", STRING);
fprintf(f, "%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 8:
fprintf(f, "ARRAY\t%d", INT);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 9:
fprintf(f, "FAIL\t%d", INT);
fprintf(f, "%d", INT);
2021-09-28 03:02:05 +03:00
break;
2021-09-28 03:02:05 +03:00
case 10:
2025-02-27 20:59:10 +01:00
fprintf(f, "LINE\t%d", INT);
2021-09-28 03:02:05 +03:00
break;
default:
FAIL;
}
break;
2021-09-28 03:02:05 +03:00
case 6:
2025-02-27 20:59:10 +01:00
fprintf(f, "PATT\t%s", pats[l]);
2021-09-28 03:02:05 +03:00
break;
2025-02-27 20:59:10 +01:00
case 7:
{
switch (l)
{
2021-10-03 17:10:21 +03:00
case 0:
2025-02-27 20:59:10 +01:00
fprintf(f, "CALL\tLread");
2021-10-03 17:10:21 +03:00
break;
2021-10-03 17:10:21 +03:00
case 1:
2025-02-27 20:59:10 +01:00
fprintf(f, "CALL\tLwrite");
2021-10-03 17:10:21 +03:00
break;
case 2:
2025-02-27 20:59:10 +01:00
fprintf(f, "CALL\tLlength");
2021-10-03 17:10:21 +03:00
break;
case 3:
2025-02-27 20:59:10 +01:00
fprintf(f, "CALL\tLstring");
2021-10-03 17:10:21 +03:00
break;
case 4:
2025-02-27 20:59:10 +01:00
fprintf(f, "CALL\tBarray\t%d", INT);
2021-10-03 17:10:21 +03:00
break;
default:
FAIL;
}
}
break;
2021-09-28 03:02:05 +03:00
default:
FAIL;
}
2025-02-27 20:59:10 +01:00
fprintf(f, "\n");
} while (1);
stop:
fprintf(f, "<end>\n");
2021-09-28 03:02:05 +03:00
}
2021-09-28 09:58:10 +03:00
/* Dumps the contents of the file */
2025-02-27 20:59:10 +01:00
void dump_file(FILE *f, bytefile *bf)
{
2021-09-28 03:02:05 +03:00
int i;
2025-02-27 20:59:10 +01:00
fprintf(f, "String table size : %d\n", bf->stringtab_size);
fprintf(f, "Global area size : %d\n", bf->global_area_size);
fprintf(f, "Number of public symbols: %d\n", bf->public_symbols_number);
fprintf(f, "Public symbols :\n");
2021-09-28 03:02:05 +03:00
2025-02-27 20:59:10 +01:00
for (i = 0; i < bf->public_symbols_number; i++)
fprintf(f, " 0x%.8x: %s\n", get_public_offset(bf, i), get_public_name(bf, i));
2021-09-28 03:02:05 +03:00
2025-02-27 20:59:10 +01:00
fprintf(f, "Code:\n");
disassemble(f, bf);
2021-09-28 03:02:05 +03:00
}
2025-02-27 20:59:10 +01:00
int main(int argc, char *argv[])
{
bytefile *f = read_file(argv[1]);
dump_file(stdout, f);
2021-09-28 03:02:05 +03:00
return 0;
}