Files
pasm/instructions.c
ALittlePatate a97fde9f86 first commit of the recode
70% of the code was re-writter from scratch
2024-01-18 16:01:04 +01:00

285 lines
5.7 KiB
C

#include "instructions.h"
#include "interpreter_states.h"
#include "api.h"
#include <string.h>
#include <stdlib.h>
bool is_reg(char* arg) {
return (strcmp(arg, "eax") == 0) || (((arg[0] == 'a' &&
('0' <= arg[1] && arg[1] <= '9'))) && strlen(arg) == 2);
}
bool is_num(char* arg) {
return (atoi(arg) != 0 || (arg[0] == '0' && strlen(arg) == 1));
}
bool check_args(s_arguments *args, int num_in_first, int num_args) {
int arg_num = strcmp(args->arg2, "") != 0;
arg_num += strcmp(args->arg1, "") != 0;
if (arg_num != num_args) {
state->last_check_args_code = WRONG_NUMBER;
return false;
}
if (!(((num_in_first && is_num(args->arg1)) || (is_reg(args->arg1))))) {
state->last_check_args_code = ARG1_WRONG;
return false;
}
if ((!is_num(args->arg2) && !is_reg(args->arg2))) {
state->last_check_args_code = ARG2_WRONG;
return false;
}
return true;
}
int* get_reg(char* reg_char) {
switch (reg_char[1]) {
case '1' :
return &state->registers->a1;
case '2' :
return &state->registers->a2;
case '3' :
return &state->registers->a3;
case '4' :
return &state->registers->a4;
case '5' :
return &state->registers->a5;
case '6' :
return &state->registers->a6;
case '7' :
return &state->registers->a7;
case '8' :
return &state->registers->a8;
case '9' :
return &state->registers->a9;
case 'a' : //eax
return &state->registers->eax;
default :
return NULL; //should never happen
}
}
int get_value(char* arg) {
int ret = 0;
if (is_reg(arg)) {
ret = *get_reg(arg);
}
else {
ret = atoi(arg);
}
return ret;
}
const command_t *find_command(const command_t *commands, char *func)
{
if (func == NULL)
return NULL;
for (int index = 0; commands[index].fptr != NULL; index += 1) {
if (strcmp(func, commands[index].command) == 0) {
return &commands[index];
}
}
return NULL;
}
void cmp() {
if (!check_args(state->args, 1, 2)) {
state->last_cmp_code = CMP_ERROR;
return;
}
int a1_ = get_value(state->args->arg1);
int a2_ = get_value(state->args->arg2);
if (a1_ == a2_) state->last_cmp_code = CMP_EQUAL;
else if (a1_ > a2_) state->last_cmp_code = CMP_ABOVE;
else if (a2_ > a1_) state->last_cmp_code = CMP_BELOW;
return;
}
int check_ret_stack() {
if (state->RET_STACK_IDX > STACK_SIZE) {
state->last_stack_code = OVERFLOW;
return 0;
}
if (state->RET_STACK_IDX < 0) {
state->last_stack_code = UNDERFLOW;
return 0;
}
return 1;
}
void ret() {
if (!check_ret_stack()) return;
if (state->RET_STACK[state->RET_STACK_IDX] == -1) {
state->should_exit = 1;
return;
}
state->curr_line = state->RET_STACK[state->RET_STACK_IDX--];
}
void jmp() {
if (state->RET_STACK_IDX != -1 && !check_ret_stack()) return;
if (strcmp(state->args->arg1, "return") == 0) {
ret();
return;
}
state->registers->eax = 0;
for (int i = 0; i < state->num_labels; i++) {
if (state->labels[i] == NULL) break;
if (strlen(state->labels[i]) - 1 != strlen(state->args->arg1))
continue;
if (strncmp(state->args->arg1, state->labels[i], strlen(state->labels[i]) - 1) == 0) {
state->RET_STACK[++state->RET_STACK_IDX] = state->curr_line;
state->curr_line = state->labels_values[i];
return;
}
}
state->last_jmp_code = 1;
return;
}
void jna() {
if (state->last_cmp_code != CMP_ABOVE) jmp();
}
void ja() {
if (state->last_cmp_code == CMP_ABOVE) jmp();
}
void jnb() {
if (state->last_cmp_code != CMP_BELOW) jmp();
}
void jb() {
if (state->last_cmp_code == CMP_BELOW) jmp();
}
void jne() {
if (state->last_cmp_code != CMP_EQUAL) jmp();
}
void je() {
if (state->last_cmp_code == CMP_EQUAL) jmp();
}
void sub() {
if (!check_args(state->args, 0, 2)) {
return;
}
*get_reg(state->args->arg1) -= get_value(state->args->arg2);
}
void add() {
if (!check_args(state->args, 0, 2)) {
return;
}
*get_reg(state->args->arg1) += get_value(state->args->arg2);
}
void mul() {
if (!check_args(state->args, 0, 2)) {
return;
}
*get_reg(state->args->arg1) *= get_value(state->args->arg2);
}
void _div() {
if (!check_args(state->args, 0, 2)) {
return;
}
*get_reg(state->args->arg1) /= get_value(state->args->arg2);
}
void mov() {
if (!check_args(state->args, 0, 2)) {
return;
}
*get_reg(state->args->arg1) = get_value(state->args->arg2);
}
void call() {
const command_t* com = find_command(api_map, state->args->arg1);
if (com != NULL) {
com->fptr();
}
else {
state->last_jmp_code = 1;
}
}
void push() {
if (state->STACK_IDX == STACK_SIZE) { //stack overflow
state->last_stack_code = OVERFLOW;
return;
}
int value = get_value(state->args->arg1);
if (value == 0) {
if (state->args->arg1[0] == '\\') {
switch (state->args->arg1[1]) {
case 'n':
value = (int)'\n';
break;
case 't':
value = (int)'\t';
break;
case 'r':
value = (int)'\r';
break;
default:
break;
}
}
else {
value = (int)state->args->arg1[0];
}
}
state->STACK[++state->STACK_IDX] = value;
}
void pop() {
if (!is_reg(state->args->arg1)) {
state->last_check_args_code = ARG1_WRONG;
return;
}
if (state->STACK_IDX == -1) { //stack underflow
state->last_stack_code = UNDERFLOW;
return;
}
*get_reg(state->args->arg1) = state->STACK[state->STACK_IDX--];
}
void _and() {
if (!check_args(state->args, 1, 2)) {
return;
}
state->registers->eax = get_value(state->args->arg1) & get_value(state->args->arg2);
}
void _xor() {
if (!check_args(state->args, 1, 2)) {
return;
}
state->registers->eax = get_value(state->args->arg1) ^ get_value(state->args->arg2);
}
void end() {
state->should_exit = 1;
}