labashki/src/execute.c

673 lines
16 KiB
C

#ifndef _WIN32
#include <dlfcn.h>
#else
#include <windows.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "config.h"
#include "execute.h"
#include "stack.h"
#define NAME stack->program[stack->program_counter].name
#define DATA stack->program[stack->program_counter].data
#define ARG stack->program[stack->program_counter].arg
typedef enum
{
MPUSH = '>',
MDROP = '$',
MDUP = ':',
MSWAP = '\\',
MINC = '+',
MDEC = '-',
PDRAIN = '/', // Haha drain gang
PPIPE = '|'
} OP;
static void prefix_operator(Stack *stack, char op)
{
if (NAME[0] != '@' && (NAME[1] == '\0' || NAME[1] == '\n'))
{
printf("%c\n", op);
kms(stack, "Invalid usage of prefix operators");
}
switch (op)
{
case PDRAIN:
NAME++;
stack_push(stack, DATA);
DATA = 0;
break;
case PPIPE:
NAME++;
DATA = stack_pop(stack);
break;
}
}
static void expression(Stack *stack, char *code)
{
uint16_t ax, ax2;
for (uint16_t i = 0; code[i] != '\0'; i++)
{
switch (code[i])
{
case MPUSH:
stack_push(stack, 0);
break;
case MDROP:
stack_pop(stack);
break;
case MDUP:
stack_push(stack, stack_peek(stack));
break;
case MSWAP:
ax = stack_pop(stack);
ax2 = stack_pop(stack);
stack_push(stack, ax);
stack_push(stack, ax2);
break;
case MINC:
ax = stack_pop(stack);
stack_push(stack, ax + 1);
break;
case MDEC:
ax = stack_pop(stack);
stack_push(stack, ax - 1);
break;
default:
printf("INVALID EXPRESSION: UNKNOWN OPERATOR '%c'\n", code[i]);
kms(stack, "INVALID EXPRESSION");
break;
}
}
}
static void find_labels(Stack *stack)
{
for (; stack->program_counter < stack->program_size; stack->program_counter++)
{
if (NAME[0] == '@')
{
if (DATA > MAX_LABELS)
{
printf("INVALID LABEL: %i\n", DATA);
kms(stack, "INVALID LABEL");
}
if (stack->labels[DATA] != -1)
{
printf("LABEL ALREADY DEFINED: %i\n", DATA);
kms(stack, "LABEL ALREADY DEFINED");
}
if (DATA == 0)
{
stack->labels[0] = stack->program_counter;
continue;
}
stack->labels[DATA] = stack->program_counter;
}
}
if (stack->labels[0] != -1)
stack->program_counter = stack->labels[0];
else
stack->program_counter = 0;
}
void execute(Stack *stack, Stack *originstack, char *modname)
{
find_labels(stack);
for (; stack->program_counter < stack->program_size; stack->program_counter++)
{
#ifdef DEBUG
fprintf(stderr, "Inst: %s, IP: %d, Stack top: %d, Module: %s\n", NAME, stack->program_counter,
stack_peek(stack), modname);
#endif
prefix_operator(stack, NAME[0]);
if (NAME[0] == '#' || NAME[0] == '$')
NAME++;
if (NAME[0] == '@')
continue;
// Stack operations
if (!strcmp(NAME, "push")) // arg <uint16>
{
stack_push(stack, DATA);
continue;
}
if (!strcmp(NAME, "pop"))
{
stack_pop(stack);
continue;
}
if (!strcmp(NAME, "dup"))
{
stack_push(stack, stack_peek(stack));
continue;
}
if (!strcmp(NAME, "swap"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, a);
stack_push(stack, b);
continue;
}
if (!strcmp(NAME, "pick"))
{
uint16_t arg = stack_pop(stack);
if (arg >= stack->pointer)
kms(stack, "ATTEMPTED TO PICK BELOW STACK");
stack_push(stack, stack->memory[stack->pointer - arg - 1]);
continue;
}
if (!strcmp(NAME, "string"))
{
for (char *i = ARG; *i != '\0'; i++)
stack_push(stack, *i);
stack_push(stack, strlen(ARG));
continue;
}
// Math
if (!strcmp(NAME, "add"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, b + a);
continue;
}
if (!strcmp(NAME, "sub"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, b - a);
continue;
}
if (!strcmp(NAME, "mul"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, b * a);
continue;
}
if (!strcmp(NAME, "div"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, b / a);
continue;
}
if (!strcmp(NAME, "mod"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, b % a);
continue;
}
// Logic
if (!strcmp(NAME, "and"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, a && b);
continue;
}
if (!strcmp(NAME, "or"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, a || b);
continue;
}
if (!strcmp(NAME, "xor"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, !a != !b);
continue;
}
if (!strcmp(NAME, "nand"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, !(a && b));
continue;
}
if (!strcmp(NAME, "not"))
{
stack_push(stack, !stack_pop(stack));
continue;
}
// Bitwise
if (!strcmp(NAME, "band"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, a & b);
continue;
}
if (!strcmp(NAME, "bor"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, a | b);
continue;
}
if (!strcmp(NAME, "bxor"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, a ^ b);
continue;
}
if (!strcmp(NAME, "bnand"))
{
uint16_t a = stack_pop(stack);
uint16_t b = stack_pop(stack);
stack_push(stack, ~(a & b));
continue;
}
if (!strcmp(NAME, "bnot"))
{
stack_push(stack, ~stack_pop(stack));
continue;
}
// Flow control
if (!strcmp(NAME, "jmp")) // arg <uint16>
{
if (stack->labels[DATA] == -1)
{
printf("UNKNOWN LABEL: %i\n", DATA);
kms(stack, "UNKNOWN LABEL");
}
stack->program_counter = stack->labels[DATA];
continue;
}
if (!strcmp(NAME, "jnz")) // arg <uint16>
{
if (stack->labels[DATA] == -1)
{
printf("UNKNOWN LABEL: %i\n", DATA);
kms(stack, "UNKNOWN LABEL");
}
if (stack_pop(stack) != 0)
stack->program_counter = stack->labels[DATA];
continue;
}
if (!strcmp(NAME, "jz")) // arg <uint16>
{
if (stack->labels[DATA] == -1)
{
printf("UNKNOWN LABEL: %i\n", DATA);
kms(stack, "UNKNOWN LABEL");
}
if (stack_pop(stack) == 0)
stack->program_counter = stack->labels[DATA];
continue;
}
if (!strcmp(NAME, "kjnz")) // arg <uint16>
{
if (stack->labels[DATA] == -1)
{
printf("UNKNOWN LABEL: %i\n", DATA);
kms(stack, "UNKNOWN LABEL");
}
if (stack_peek(stack) != 0)
stack->program_counter = stack->labels[DATA];
continue;
}
if (!strcmp(NAME, "kjz")) // arg <uint16>
{
if (stack->labels[DATA] == -1)
{
printf("UNKNOWN LABEL: %i\n", DATA);
kms(stack, "UNKNOWN LABEL");
}
if (stack_peek(stack) == 0)
stack->program_counter = stack->labels[DATA];
continue;
}
// I/O
if (!strcmp(NAME, "putc"))
{
putchar(stack_pop(stack));
continue;
}
if (!strcmp(NAME, "getc"))
{
stack_push(stack, getchar());
continue;
}
if (!strcmp(NAME, "scan"))
{
uint16_t num;
scanf("%hu", &num);
stack_push(stack, num);
continue;
}
if (!strcmp(NAME, "meow"))
{
printf("%i\n", stack_pop(stack));
continue;
}
if (!strcmp(NAME, "println")) // arg <string>
{
printf("%s\n", ARG);
continue;
}
if (!strcmp(NAME, "print")) // arg <string>
{
printf("%s", ARG);
continue;
}
// Modules
if (!strcmp(NAME, "args")) // arg <uint16>
{
if (!originstack)
kms(stack, "ATTEMPTED TO USE ARGS IN THE MAIN MODULE");
if (DATA > STACK_SIZE)
kms(stack, "ATTEMPTED TO POP MORE THAN STACK_SIZE ARGUMENTS");
if (DATA == 0)
DATA = stack_pop(originstack);
uint16_t ddata = DATA;
while (ddata != 0)
{
stack_push(stack, stack_pop(originstack));
ddata--;
}
continue;
}
if (!strcmp(NAME, "exec")) // arg <const>
{
if (!strcmp(ARG, modname))
{
printf("MODULE %s: CAN'T EXECUTE ITSELF\n", ARG);
kms(stack, "CAN'T EXECUTE ITSELF");
}
FILE *file = fopen(ARG, "r");
if (!file)
{
printf("ERROR OPENING MODULE: %s\n", ARG);
kms(stack, "ERROR OPENING MODULE");
}
DATA = DATA ? DATA : STACK_SIZE;
Stack *tempstack = program_init(DATA);
parse_and_process(tempstack, file);
fclose(file);
execute(tempstack, stack, ARG);
for (int i = 0; i < tempstack->pointer; i++)
stack_push(stack, tempstack->memory[i]);
free(tempstack);
continue;
}
if (!strcmp(NAME, "call"))
{
unsigned short len = stack_pop(stack);
char *string = calloc(len, sizeof(char));
for (int i = len - 1; i != -1; i--)
string[i] = stack_pop(stack);
if (!strcmp(string, modname))
{
printf("MODULE %s: CAN'T EXECUTE ITSELF\n", string);
kms(stack, "CAN'T EXECUTE ITSELF");
}
FILE *file = fopen(string, "r");
if (!file)
{
printf("ERROR OPENING MODULE: %s\n", string);
kms(stack, "ERROR OPENING MODULE");
}
DATA = DATA ? DATA : STACK_SIZE;
Stack *tempstack = program_init(DATA);
parse_and_process(tempstack, file);
fclose(file);
execute(tempstack, stack, string);
for (int i = 0; i < tempstack->pointer; i++)
stack_push(stack, tempstack->memory[i]);
free(tempstack);
free(string);
continue;
}
// Native
#ifndef _WIN32
if (!strcmp(NAME, "native"))
{
char *modulename = malloc(strlen(ARG) + 6 * sizeof(char));
strcpy(modulename, "./");
strcat(modulename, ARG);
strcat(modulename, ".so");
void *module = dlopen(modulename, RTLD_NOW);
if (!module)
kms(stack, "UNABLE TO OPEN DYNAMIC LIBRARY");
void (*labashka)(unsigned short (*pop)(void), void (*push)(unsigned short), size_t (*len)(void),
size_t max_size);
labashka = (void (*)(unsigned short (*pop)(void), void (*push)(unsigned short), size_t (*len)(void),
size_t max_size))dlsym(module, "labashka");
stack_init_callback(stack);
labashka(stack_pop_callback, stack_push_callback, stack_len_callback, stack->stacksize);
dlclose(module);
free(modulename);
continue;
}
#else
if (!strcmp(NAME, "native"))
{
char *modulename = malloc(strlen(ARG) + 7 * sizeof(char));
strcpy(modulename, "./");
strcat(modulename, ARG);
strcat(modulename, ".dll");
void *module = LoadLibrary(TEXT(modulename));
if (!module)
kms(stack, "UNABLE TO OPEN DYNAMIC LIBRARY");
int (*labashka)(unsigned short (*pop)(void), void (*push)(unsigned short), size_t (*len)(void),
size_t max_size);
labashka = (int (*)(unsigned short (*pop)(void), void (*push)(unsigned short), size_t (*len)(void),
size_t max_size))GetProcAddress(module, "labashka");
stack_init_callback(stack);
labashka(stack_pop_callback, stack_push_callback, stack_len_callback, stack->stacksize);
FreeLibrary(module);
free(modulename);
continue;
}
#endif
// Self-modifying
if (!strcmp(NAME, "insert")) // arg <const>
{
if (ARG[0] == '#' || ARG[0] == '$')
kms(stack, "ATTEMPTED TO INSERT A HASH/STRING-INSTRUCTION");
if (ARG[0] == '\n')
kms(stack, "ATTEMPTED TO INSERT AN EMPTY CONSTANT");
if (ARG[0] == '@' && ARG[1] == ' ')
kms(stack, "ATTEMPTED TO INSERT A LABEL");
stack->program[stack->program_size++] = (Instruction){ARG, "\n", DATA};
continue;
}
// Special
if (!strcmp(NAME, "dump"))
{
for (int i = 0; i < stack->pointer; i++)
printf("%d: %d\n", i, stack->memory[i]);
continue;
}
if (!strcmp(NAME, "size"))
{
stack_push(stack, stack->pointer);
continue;
}
if (!strcmp(NAME, "maxsize"))
{
stack_push(stack, stack->stacksize);
continue;
}
if (!strcmp(NAME, "expr")) // arg <const>
{
expression(stack, ARG);
continue;
}
if (!strcmp(NAME, "field"))
{
continue;
}
if (!strcmp(NAME, "quit"))
{
break;
}
if (!strcmp(NAME, "exit"))
{
exit(stack_pop(stack));
}
// Platform-specific
#ifdef __unix__
if (!strcmp(NAME, "_unix_random"))
{
srand(getc(fopen("/dev/urandom", "r")));
stack_push(stack, rand() % stack_pop(stack));
continue;
}
#endif
// LBR-SPECIFIC
printf("UNKNOWN INSTRUCTION: %s\n", NAME);
kms(stack, "UNKNOWN INSTRUCTION");
}
}
#undef NAME
#undef ARG
#undef DATA