#ifndef _WIN32 #include #else #include #endif #include #include #include #include #include #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 { 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 { 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 { 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 { 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 { 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 { 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 { printf("%s\n", ARG); continue; } if (!strcmp(NAME, "print")) // arg { printf("%s", ARG); continue; } // Modules if (!strcmp(NAME, "args")) // arg { 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 { 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 { 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 { 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