285 lines
5.7 KiB
C
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;
|
|
}
|