fix: file structure, building to build/
This commit is contained in:
32
src/api.c
Normal file
32
src/api.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "api.h"
|
||||
#include "interpreter_states.h"
|
||||
|
||||
#ifdef _WIN32 //windows only apis
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void api_put() {
|
||||
int mode = state->STACK[state->STACK_IDX--]; // 1 for char, 2 for num
|
||||
if (mode != 1 && mode != 2) return;
|
||||
|
||||
if (mode == 1) {
|
||||
char c = state->STACK[state->STACK_IDX--];
|
||||
if (c == '\0') c = ' ';
|
||||
|
||||
printf("%c", c); //using printf and not write because of the buffer
|
||||
}
|
||||
else {
|
||||
printf("%d", state->STACK[state->STACK_IDX--]);
|
||||
}
|
||||
}
|
||||
|
||||
void api_getasynckeystate() {
|
||||
#ifdef _WIN32
|
||||
eax = GetAsyncKeyState(state->STACK[STACK_IDX--]);
|
||||
#else
|
||||
state->STACK_IDX--;
|
||||
state->registers->eax = 1;
|
||||
#endif
|
||||
}
|
||||
12
src/api.h
Normal file
12
src/api.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "instructions.h"
|
||||
|
||||
void api_put();
|
||||
void api_getasynckeystate();
|
||||
|
||||
static const command_t api_map[] = {
|
||||
{.command = "put", .fptr = api_put},
|
||||
{.command = "GetAsyncKeyState", .fptr = api_getasynckeystate},
|
||||
|
||||
{.command = NULL, .fptr = NULL}
|
||||
};
|
||||
50
src/file_utils.c
Normal file
50
src/file_utils.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "interpreter_states.h"
|
||||
|
||||
#define MAX_LINE 1024
|
||||
|
||||
size_t line_count = 0;
|
||||
int read_script(const char *filename, char ***buf, size_t *lines) {
|
||||
FILE *script = fopen(filename, "r");
|
||||
if (script == NULL) {
|
||||
fprintf(stderr, "Could not open %s.\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char line[MAX_LINE];
|
||||
while (fgets(line, sizeof(line), script) != NULL) {
|
||||
size_t length = strlen(line);
|
||||
if (line[length - 1] == '\n') {
|
||||
line[length - 1] = '\0';
|
||||
}
|
||||
char *line_copy = strdup(line);
|
||||
char **temp = realloc(*buf, (line_count + 1) * sizeof(char*));
|
||||
if (temp == NULL) {
|
||||
fprintf(stderr, "Error allocating memory.\n");
|
||||
return 1;
|
||||
}
|
||||
*buf = temp;
|
||||
(*buf)[line_count++] = line_copy;
|
||||
}
|
||||
if (line_count == 0) {
|
||||
fprintf(stderr, "%s is an empty file.\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*lines = line_count;
|
||||
fclose(script);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_script(char **buf) {
|
||||
if (!buf)
|
||||
return;
|
||||
for (size_t i = 0; i < line_count; ++i)
|
||||
if (buf[i])
|
||||
free(buf[i]);
|
||||
free(buf);
|
||||
free_state();
|
||||
}
|
||||
5
src/file_utils.h
Normal file
5
src/file_utils.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
|
||||
int read_script(const char *filename, char ***buf, size_t *lines);
|
||||
void free_script(char **buf);
|
||||
284
src/instructions.c
Normal file
284
src/instructions.c
Normal file
@@ -0,0 +1,284 @@
|
||||
#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;
|
||||
}
|
||||
61
src/instructions.h
Normal file
61
src/instructions.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include "interpreter_states.h"
|
||||
|
||||
typedef struct command_s {
|
||||
char *command;
|
||||
void (*fptr)();
|
||||
} command_t;
|
||||
|
||||
bool is_reg(char* arg);
|
||||
bool check_args(s_arguments *args, int num_in_first, int num_args);
|
||||
int* get_reg(char* arg);
|
||||
|
||||
void add();
|
||||
void sub();
|
||||
void mul();
|
||||
void _div();
|
||||
void mov();
|
||||
void cmp();
|
||||
void je();
|
||||
void jne();
|
||||
void jb();
|
||||
void jnb();
|
||||
void ja();
|
||||
void jna();
|
||||
void jmp();
|
||||
void ret();
|
||||
void pop();
|
||||
void push();
|
||||
void call();
|
||||
void _and();
|
||||
void _xor();
|
||||
void end();
|
||||
|
||||
static const command_t command_map[] = {
|
||||
{.command = "add", .fptr = add},
|
||||
{.command = "sub", .fptr = sub},
|
||||
{.command = "mul", .fptr = mul},
|
||||
{.command = "div", .fptr = _div},
|
||||
{.command = "mov", .fptr = mov},
|
||||
{.command = "cmp", .fptr = cmp},
|
||||
{.command = "je", .fptr = je},
|
||||
{.command = "jne", .fptr = jne},
|
||||
{.command = "jb", .fptr = jb},
|
||||
{.command = "jnb", .fptr = jnb},
|
||||
{.command = "ja", .fptr = ja},
|
||||
{.command = "jna", .fptr = jna},
|
||||
{.command = "jmp", .fptr = jmp},
|
||||
{.command = "ret", .fptr = ret},
|
||||
{.command = "pop", .fptr = pop},
|
||||
{.command = "push", .fptr = push},
|
||||
{.command = "call", .fptr = call},
|
||||
{.command = "and", .fptr = _and},
|
||||
{.command = "xor", .fptr = _xor},
|
||||
{.command = "end", .fptr = end},
|
||||
|
||||
{.command = NULL, .fptr = NULL}
|
||||
};
|
||||
|
||||
const command_t *find_command(const command_t *commands, char *func);
|
||||
143
src/interpreter_states.c
Normal file
143
src/interpreter_states.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "interpreter_states.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
s_state *state = NULL;
|
||||
int init_state() {
|
||||
state = malloc(sizeof(s_state));
|
||||
if (state == NULL)
|
||||
return 1;
|
||||
memset(state, 0, sizeof(s_state));
|
||||
state->registers = malloc(sizeof(s_registers));
|
||||
if (state->registers == NULL) {
|
||||
free(state);
|
||||
return 1;
|
||||
}
|
||||
memset(state->registers, 0, sizeof(s_registers));
|
||||
state->args = malloc(sizeof(s_arguments));
|
||||
if (state->args == NULL) {
|
||||
free(state);
|
||||
free(state->registers);
|
||||
return 1;
|
||||
}
|
||||
state->args->arg1 = malloc(sizeof(char) * MAX_ARG_SIZE);
|
||||
state->args->arg2 = malloc(sizeof(char) * MAX_ARG_SIZE);
|
||||
if (state->args->arg1 == NULL || state->args->arg2 == NULL) {
|
||||
free(state);
|
||||
free(state->registers);
|
||||
return 1;
|
||||
}
|
||||
memset(state->args->arg1, 0, sizeof(char) * MAX_ARG_SIZE);
|
||||
memset(state->args->arg2, 0, sizeof(char) * MAX_ARG_SIZE);
|
||||
state->labels_values = malloc(sizeof(int) * MAX_LABELS);
|
||||
if (state->labels_values == NULL) {
|
||||
free(state);
|
||||
free(state->registers);
|
||||
free(state->args->arg1);
|
||||
free(state->args->arg2);
|
||||
return 1;
|
||||
}
|
||||
memset(state->labels_values, 0, sizeof(int) * MAX_LABELS);
|
||||
memset(state->RET_STACK, -1, sizeof(int) * STACK_SIZE);
|
||||
memset(state->STACK, 0, sizeof(int) * STACK_SIZE);
|
||||
state->RET_STACK_IDX = -1;
|
||||
state->STACK_IDX = -1;
|
||||
state->last_stack_code = STACK_OK;
|
||||
state->last_check_args_code = OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_state() {
|
||||
for (int i = 0; i < state->num_labels; i++) {
|
||||
if (state->labels[i])
|
||||
free(state->labels[i]);
|
||||
}
|
||||
free(state->labels);
|
||||
free(state->labels_values);
|
||||
free(state->registers);
|
||||
free(state->args->arg1);
|
||||
free(state->args->arg2);
|
||||
free(state->args);
|
||||
|
||||
free(state);
|
||||
}
|
||||
|
||||
void set_exit_state(int exit_state) {
|
||||
state->should_exit = exit_state;
|
||||
}
|
||||
|
||||
int get_exit_state() {
|
||||
return state->should_exit;
|
||||
}
|
||||
|
||||
LABEL_ERR add_label(char *label, int line) {
|
||||
if (label == NULL)
|
||||
return LABEL_INVALID;
|
||||
if (state->num_labels == MAX_LABELS)
|
||||
return LABEL_MAX;
|
||||
|
||||
for (int i = 0; i < state->num_labels; i++)
|
||||
if (strcmp(label, state->labels[i]) == 0)
|
||||
return LABEL_ALREADY_EXISTS;
|
||||
|
||||
char *line_copy = strdup(label);
|
||||
if (line_copy == NULL) {
|
||||
fprintf(fstream, "Error allocating memory.\n");
|
||||
return LABEL_ERROR;
|
||||
}
|
||||
char **temp = realloc(state->labels, (state->num_labels + 1) * sizeof(char*));
|
||||
if (temp == NULL) {
|
||||
fprintf(fstream, "Error allocating memory.\n");
|
||||
return LABEL_ERROR;
|
||||
}
|
||||
state->labels = temp;
|
||||
state->labels_values[state->num_labels] = line;
|
||||
state->labels[state->num_labels++] = line_copy;
|
||||
return LABEL_OK;
|
||||
}
|
||||
|
||||
char *extract_arg(char *ptr, int a) {
|
||||
char *arg = 0;
|
||||
char *ptr2 = strstr(ptr, ";");
|
||||
if (ptr2)
|
||||
ptr2[0] = '\0';
|
||||
if (a == 0) {
|
||||
arg = strtok(ptr, ",");
|
||||
} else {
|
||||
arg = strtok(NULL, ",");
|
||||
}
|
||||
if (arg == NULL)
|
||||
return NULL;
|
||||
if (arg[0] == ' ')
|
||||
arg++;
|
||||
ptr2 = strstr(arg, " ");
|
||||
if (ptr2)
|
||||
ptr2[0] = '\0';
|
||||
return arg;
|
||||
}
|
||||
|
||||
int parse_arguments(char *line) {
|
||||
strcpy(state->args->arg1, "");
|
||||
strcpy(state->args->arg2, "");
|
||||
|
||||
char *line_cpy = strdup(line);
|
||||
char *ptr = strstr(line_cpy, " ");
|
||||
char *arg = 0;
|
||||
if (!ptr) {
|
||||
free(line_cpy);
|
||||
return 0;
|
||||
}
|
||||
if ((arg = extract_arg(ptr, 0)) == NULL) {
|
||||
free(line_cpy);
|
||||
return 0;
|
||||
}
|
||||
strcpy(state->args->arg1, arg);
|
||||
if ((arg = extract_arg(ptr, 1)) == NULL) {
|
||||
free(line_cpy);
|
||||
return 0;
|
||||
}
|
||||
strcpy(state->args->arg2, arg);
|
||||
free(line_cpy);
|
||||
return 0;
|
||||
}
|
||||
71
src/interpreter_states.h
Normal file
71
src/interpreter_states.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAX_LABELS 256
|
||||
#define MAX_ARG_SIZE 25
|
||||
#define STACK_SIZE 50
|
||||
|
||||
extern FILE *fstream;
|
||||
|
||||
typedef enum cmp_return_codes {
|
||||
CMP_ERROR = -1, //unused
|
||||
CMP_EQUAL,
|
||||
CMP_BELOW,
|
||||
CMP_ABOVE,
|
||||
} cmp_return_codes;
|
||||
|
||||
typedef enum check_args_codes {
|
||||
ARG1_WRONG,
|
||||
ARG2_WRONG,
|
||||
WRONG_NUMBER,
|
||||
OK
|
||||
} check_args_codes ;
|
||||
|
||||
typedef enum stack_codes {
|
||||
OVERFLOW,
|
||||
UNDERFLOW,
|
||||
STACK_OK
|
||||
} stack_codes;
|
||||
|
||||
typedef struct t_arguments {
|
||||
char* arg1;
|
||||
char* arg2;
|
||||
} s_arguments;
|
||||
|
||||
typedef struct t_registers {
|
||||
int a1, a2, a3, a4, a5, a6, a7, a8, a9, eax;
|
||||
} s_registers;
|
||||
|
||||
typedef struct t_state {
|
||||
int curr_line;
|
||||
int num_labels;
|
||||
char **labels;
|
||||
int *labels_values;
|
||||
s_arguments *args;
|
||||
s_registers *registers;
|
||||
int should_exit;
|
||||
int RET_STACK[STACK_SIZE];
|
||||
int RET_STACK_IDX;
|
||||
int STACK_IDX;
|
||||
int STACK[STACK_SIZE];
|
||||
int last_jmp_code;
|
||||
stack_codes last_stack_code;
|
||||
cmp_return_codes last_cmp_code;
|
||||
check_args_codes last_check_args_code;
|
||||
} s_state;
|
||||
extern s_state *state;
|
||||
|
||||
typedef enum E_LABEL_ERR {
|
||||
LABEL_OK,
|
||||
LABEL_ALREADY_EXISTS,
|
||||
LABEL_INVALID,
|
||||
LABEL_MAX,
|
||||
LABEL_ERROR
|
||||
} LABEL_ERR;
|
||||
|
||||
int init_state();
|
||||
void free_state();
|
||||
void set_exit_state(int exit_state);
|
||||
int get_exit_state();
|
||||
LABEL_ERR add_label(char *label, int line);
|
||||
int parse_arguments(char *args);
|
||||
114
src/pasm.c
Normal file
114
src/pasm.c
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "file_utils.h"
|
||||
#include "interpreter_states.h"
|
||||
#include "instructions.h"
|
||||
|
||||
FILE *fstream = NULL;
|
||||
void show_error(size_t line, char *line_) {
|
||||
int wrote = fprintf(fstream, "%ld| ", line + 1);
|
||||
fprintf(fstream, "%s\n", line_);
|
||||
fprintf(fstream, "%*s\n", wrote + 1, "^");
|
||||
fprintf(fstream, "%*s\n", wrote + 1, "|");
|
||||
for (int i = 0; i < wrote; i++)
|
||||
fprintf(fstream, " ");
|
||||
}
|
||||
|
||||
void show_states() {
|
||||
printf("\n\n--------PASM STATE--------\n");
|
||||
printf("a1: %-3d | ", state->registers->a1);
|
||||
printf("a2: %-3d | ", state->registers->a2);
|
||||
printf("a3: %-3d\n", state->registers->a3);
|
||||
printf("a4: %-3d | ", state->registers->a4);
|
||||
printf("a5: %-3d | ", state->registers->a5);
|
||||
printf("a6: %-3d\n", state->registers->a6);
|
||||
printf("a7: %-3d | ", state->registers->a7);
|
||||
printf("a8: %-3d | ", state->registers->a8);
|
||||
printf("a9: %-3d\n", state->registers->a9);
|
||||
printf("eax: %-3d\n", state->registers->eax);
|
||||
}
|
||||
|
||||
int check_errors(char *line) {
|
||||
if (state->last_check_args_code != OK) {
|
||||
show_error(state->curr_line, line);
|
||||
|
||||
switch ((int)state->last_check_args_code) {
|
||||
case WRONG_NUMBER :
|
||||
fprintf(fstream, "wrong number of arguments on line %d\n", state->curr_line + 1);
|
||||
break;
|
||||
case ARG1_WRONG :
|
||||
fprintf(fstream, "arg1 is invalid on line %d\n", state->curr_line + 1);
|
||||
break;
|
||||
case ARG2_WRONG :
|
||||
fprintf(fstream, "arg2 is invalid on line %d\n", state->curr_line + 1);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (state->last_jmp_code) {
|
||||
show_error(state->curr_line, line);
|
||||
fprintf(fstream, "%s is not a valid label/api", state->args->arg1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (state->last_stack_code != STACK_OK) {
|
||||
show_error(state->curr_line, line);
|
||||
fprintf(fstream, "stack %s on line %d",
|
||||
state->last_stack_code == OVERFLOW ? "overflow" : "underflow", state->curr_line + 1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pasm_run_script(const char *filename, char **file, size_t lines, FILE *_fstream) {
|
||||
fstream = _fstream;
|
||||
|
||||
if (filename && read_script(filename, &file, &lines) == 1)
|
||||
return 1;
|
||||
if (init_state() == 1) {
|
||||
fprintf(fstream, "Failed to initialize the interpreter.\n");
|
||||
free_script(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int found_main = 0;
|
||||
for (state->curr_line = 0; state->curr_line < (int)lines && get_exit_state() == 0 ; ++state->curr_line) {
|
||||
char *line = strdup(file[state->curr_line]);
|
||||
if (line[0] == ';' || line[0] == '\0') {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
const command_t *com = find_command(command_map, strtok(line, " "));
|
||||
if (com == NULL || com->fptr == NULL) {
|
||||
if (file[state->curr_line][strlen(line) - 1] != ':') {
|
||||
show_error(state->curr_line, file[state->curr_line]);
|
||||
fprintf(fstream, "%s \"%s\"\n", "unknown expression", strtok(file[state->curr_line], " "));
|
||||
set_exit_state(-1);
|
||||
free(line);
|
||||
break;
|
||||
}
|
||||
add_label(line, state->curr_line);
|
||||
if (!found_main && strcmp(line, "main:") == 0)
|
||||
found_main = 1;
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
parse_arguments(file[state->curr_line]);
|
||||
if (found_main)
|
||||
com->fptr();
|
||||
if (check_errors(file[state->curr_line])) {
|
||||
set_exit_state(-1);
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
|
||||
int ret_code = get_exit_state();
|
||||
#ifdef DEBUG
|
||||
show_states();
|
||||
#endif
|
||||
free_script(file);
|
||||
return ret_code;
|
||||
}
|
||||
Reference in New Issue
Block a user