diff --git a/src/api.c b/src/api.c new file mode 100644 index 0000000..bfa6e39 --- /dev/null +++ b/src/api.c @@ -0,0 +1 @@ +#include "api.h" \ No newline at end of file diff --git a/src/api.h b/src/api.h new file mode 100644 index 0000000..45dcbb0 --- /dev/null +++ b/src/api.h @@ -0,0 +1,3 @@ +#pragma once + + diff --git a/src/get_instruction.c b/src/get_instruction.c index 2a86925..385573f 100644 --- a/src/get_instruction.c +++ b/src/get_instruction.c @@ -2,8 +2,9 @@ #include "main.h" #include #include +#include -const char* instructions_char[] = {"add", "sub", "mov", "cmp", "je", "jne", "jmp", "jb", "jbn", "ja", "jna", "ret", "pop", "push", "call"}; +const char* instructions_char[] = {"add", "sub", "mov", "cmp", "je", "jne", "jmp", "jb", "jbn", "ja", "jna", "ret", "pop", "push", "call", "and"}; INSTRUCTION get_instruction(char* line, int* args_start_pos, int line_number) { char ins[20]; //20 should be enough @@ -19,7 +20,17 @@ INSTRUCTION get_instruction(char* line, int* args_start_pos, int line_number) { ins[i] = '\0'; *args_start_pos = -1; - labels[num_labels] = ins; + for (int i = 0; i < MAX_LABEL; i++) { + if (labels[i] == NULL) break; + if (strcmp(ins, labels[i]) == 0) { + return LABEL; + } + } + + labels[num_labels] = (char*)calloc(1, strlen(ins) + 1); + if (labels[num_labels] != NULL) { + strcpy_s(labels[num_labels], strlen(ins) + 1, ins); + } labels_lines[num_labels] = line_number; ++num_labels; return LABEL; @@ -38,7 +49,7 @@ INSTRUCTION get_instruction(char* line, int* args_start_pos, int line_number) { return ERROR_INSTRUCTION; } -arguments get_args(char* line, int args_start_pos) { +void get_args(char* line, int args_start_pos) { char first_arg[256]; char second_arg[256]; @@ -47,11 +58,28 @@ arguments get_args(char* line, int args_start_pos) { for (int i = args_start_pos; i < (int)strlen(line); i++) { if (line[i] == '\n' || line[i] == '\0' || line[i] == ';') { second_arg[j] = '\0'; + args->arg2 = (char*)calloc(1, strlen(second_arg) + 1); + if (args->arg2 != NULL) { + strcpy_s(args->arg2, strlen(second_arg)+1, second_arg); + } + + if (write_to_first) { //only one arg + first_arg[j] = '\0'; + args->arg1 = (char*)calloc(1, strlen(first_arg) + 1); + if (args->arg1 != NULL) { + strcpy_s(args->arg1, strlen(first_arg)+1, first_arg); + } + } + break; } if (line[i] == ',') { first_arg[j] = '\0'; + args->arg1 = (char*)calloc(1, strlen(first_arg) + 1); + if (args->arg1 != NULL) { + strcpy_s(args->arg1, strlen(first_arg)+1, first_arg); + } write_to_first = 0; j = 0; continue; @@ -69,6 +97,5 @@ arguments get_args(char* line, int args_start_pos) { } } - arguments args = {first_arg, second_arg}; - return args; + return; } diff --git a/src/get_instruction.h b/src/get_instruction.h index 7d800c0..c9f4c60 100644 --- a/src/get_instruction.h +++ b/src/get_instruction.h @@ -1,10 +1,5 @@ #pragma once #include "instruction_set.h" -typedef struct arguments { - char* arg1; - char* arg2; -} arguments; - INSTRUCTION get_instruction(char* line, int* args_start_pos, int line_number); -arguments get_args(char* line, int args_start_pos); +void get_args(char* line, int args_start_pos); diff --git a/src/instruction_set.h b/src/instruction_set.h index 179f16d..1205a90 100644 --- a/src/instruction_set.h +++ b/src/instruction_set.h @@ -17,5 +17,6 @@ typedef enum INSTRUCTIONS { RET, POP, PUSH, - CALL + CALL, + AND } INSTRUCTION; diff --git a/src/instructions.c b/src/instructions.c index 918e131..ce63a56 100644 --- a/src/instructions.c +++ b/src/instructions.c @@ -1,22 +1,141 @@ #include "instructions.h" #include "main.h" #include +#include #include -bool check_args(arguments args, int expected_num) { - if (strcmp(args.arg1, "a1") == 0) { - printf("aa\n"); +bool is_reg(char* arg) { + return (strcmp(arg, "eax") == 0) || (((arg[0] == 'a' && '0' <= arg[1] <= '9')) && strlen(arg) == 2); +} + +bool is_num(char* arg) { + return (atoi(arg) != 0 || (arg[0] == '0' && strlen(arg) == 1)); +} + +bool check_args(int num_in_first) { + if (!(((num_in_first && is_num(args->arg1)) || (is_reg(args->arg1))))) { + last_check_args_code = ARG1_WRONG; + return false; + } + + if ((!is_num(args->arg2) && !is_reg(args->arg2))) { + last_check_args_code = ARG2_WRONG; + return false; } return true; } -void add(arguments args) { - if (!check_args(args, 2)) { - return; +int* get_reg(char* reg_char) { + switch (reg_char[1]) { + case '1' : + return &a1; + case '2' : + return &a2; + case '3' : + return &a3; + case '4' : + return &a4; + case '5' : + return &a5; + case '6' : + return &a6; + case '7' : + return &a7; + case '8' : + return &a8; + case '9' : + return &a9; + case 'a' : //eax + return &eax; + default : + return NULL; //should never happen } } -void mov(arguments args) { - +int get_value(char* arg) { + int ret = 0; + if (is_reg(arg)) { + ret = *get_reg(arg); + } + else { + ret = atoi(arg); + } + return ret; +} + +cmp_return_codes cmp() { + if (!check_args(1)) { + return CMP_ERROR; + } + + int a1_ = get_value(args->arg1); + int a2_ = get_value(args->arg2); + + if (a1_ == a2_) return CMP_EQUAL; + if (a1_ > a2_) return CMP_ABOVE; + if (a2_ > a1_) return CMP_BELOW; + + return CMP_EQUAL; //never hit but it makes the compiler happy +} + +void jmp() { + for (int i = 0; i < MAX_LABEL; i++) { + if (labels[i] == NULL) break; + if (strcmp(args->arg1, labels[i]) == 0) { + fseek(fptr, labels_lines[i], SEEK_SET); + return; + } + } + + last_jmp_code = 1; + return; +} + +bool jna() { + return last_cmp_code != CMP_ABOVE; +} + +bool ja() { + return last_cmp_code == CMP_ABOVE; +} + +bool jnb() { + return last_cmp_code != CMP_BELOW; +} + +bool jb() { + return last_cmp_code == CMP_BELOW; +} + +bool jne() { + return last_cmp_code != CMP_EQUAL; +} + +bool je() { + return last_cmp_code == CMP_EQUAL; +} + +void sub() { + if (!check_args(0)) { + return; + } + + *get_reg(args->arg1) -= get_value(args->arg2); +} + +void add() { + if (!check_args(0)) { + return; + } + + *get_reg(args->arg1) += get_value(args->arg2); +} + +void mov() { + if (!check_args(0)) { + return; + } + + *get_reg(args->arg1) = get_value(args->arg2); } \ No newline at end of file diff --git a/src/instructions.h b/src/instructions.h index b2c4495..15cc18a 100644 --- a/src/instructions.h +++ b/src/instructions.h @@ -3,32 +3,34 @@ #include typedef enum cmp_return_codes { - EQUAL, - BELOW, - ABOVE, + CMP_ERROR = -1, //unused + CMP_EQUAL, + CMP_BELOW, + CMP_ABOVE, } cmp_return_codes; typedef enum check_args_codes { + ARG1_WRONG, + ARG2_WRONG, WRONG_NUMBER, - NOT_VALID, OK } check_args_codes ; -static check_args_codes last_check_args_code = OK; +extern check_args_codes last_check_args_code; -bool check_args(arguments args, int expected_num); +bool check_args(int num_in_first); -void add(arguments args); -void sub(arguments args); -void mov(arguments args); -cmp_return_codes cmp(arguments args); -bool je(arguments args); -bool jne(arguments args); -bool jb(arguments args); -bool jnb(arguments args); -bool ja(arguments args); -bool jna(arguments args); -void jmp(arguments args); -void ret(arguments args); -void pop(arguments args); -void push(arguments args); -void call(arguments args); +void add(); +void sub(); +void mov(); +cmp_return_codes cmp(); +bool je(); +bool jne(); +bool jb(); +bool jnb(); +bool ja(); +bool jna(); +void jmp(); +void ret(); +void pop(); +void push(); +void call(); diff --git a/src/main.c b/src/main.c index 0c38c88..41d0efe 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ #include #include +#include #include "main.h" #include "get_instruction.h" #include "instructions.h" @@ -8,6 +9,16 @@ void show_help() { printf("usage : pasm.exe [filename]"); } +arguments* args = NULL; +int stack[9] = {0*9}; +int a1, a2, a3, a4, a5, a6, a7, a8, a9, eax = 0; +char* labels[256] = {0*256}; +int labels_lines[256] = {0*256}; +int num_labels = 0; +FILE* fptr = NULL; +last_jmp_code = 0; +cmp_return_codes last_cmp_code = CMP_EQUAL; +last_check_args_code = OK; //init error code int main(int argc, char** argv) { if (argc != 2) { printf("Bad arguments.\n"); @@ -20,7 +31,6 @@ int main(int argc, char** argv) { return 1; } - FILE* fptr; fopen_s(&fptr, argv[1], "r"); if (fptr == NULL) { printf("File %s does not exist.", argv[1]); @@ -28,39 +38,83 @@ int main(int argc, char** argv) { } memset(&stack, 0, sizeof(stack)); //init stack + args = (arguments*)calloc(1, sizeof(arguments)); + a1 = 69420; char line[256]; int line_number = 1; + size_t char_read = 0; while (fgets(line, sizeof(line), fptr)) { + char_read += strlen(line); + if (line[0] == ';' || line[0] == '\n') { ++line_number; continue; } int args_pos; - INSTRUCTION ins = get_instruction(line, &args_pos, line_number); - arguments args; - + INSTRUCTION ins = get_instruction(line, &args_pos, (int)char_read); if (args_pos != -1) { - args = get_args(line, args_pos); - + get_args(line, args_pos); } switch (ins) { case SUB : + sub(); break; case MOV : - //mov(args); + mov(); break; case ADD : - add(args); + add(); + break; + case CMP : + last_cmp_code = cmp(); + break; + case JE : + if (je()) { + jmp(); + } + break; + case JNE : + if (jne()) { + jmp(); + } + break; + case JB : + if (jb()) { + jmp(); + } + break; + case JNB : + if (jnb()) { + jmp(); + } + break; + case JA : + if (ja()) { + jmp(); + } + break; + case JNA : + if (jna()) { + jmp(); + } + break; + case JMP : + jmp(); + break; + case LABEL : break; case ERROR_INSTRUCTION: printf("%s ^\n |\ninvalid operand on line %d", line, line_number); + free(args->arg1); + free(args->arg2); + free(args); fclose(fptr); return 1; } - + if (last_check_args_code != OK) { printf("%s", line); printf("%*c ^\n", args_pos, ' '); @@ -69,17 +123,37 @@ int main(int argc, char** argv) { switch (last_check_args_code) { case WRONG_NUMBER : printf("%*c wrong number of arguments on line %d", args_pos, ' ', line_number); - case NOT_VALID : - printf("%*c invalid number/register on line %d", args_pos, ' ', line_number); + break; + case ARG1_WRONG : + printf("%*c arg1 is invalid on line %d", args_pos, ' ', line_number); + break; + case ARG2_WRONG : + printf("%*c arg2 is invalid on line %d", args_pos, ' ', line_number); + break; } - fclose(fptr); + free(args->arg1); + free(args->arg2); + free(args); + return 1; + } + + if (last_jmp_code) { + printf("%s", line); + printf("%*c ^\n", args_pos, ' '); + printf("%*c |\n", args_pos, ' '); + printf("%*c %s is not a valid label/api", args_pos, ' ', args->arg1); + + free(args->arg1); + free(args->arg2); + free(args); return 1; } ++line_number; } + free(args); fclose(fptr); return 0; diff --git a/src/main.h b/src/main.h index 968441a..d05bfe0 100644 --- a/src/main.h +++ b/src/main.h @@ -1,7 +1,20 @@ #pragma once +#include "instructions.h" +#include +#define MAX_LABEL 256 -static int stack[9]; -static int a1, a2, a3, a4, a5, a6, a7, a8, a9, eax; //registers -static char* labels[256]; //max 256 labels -static int labels_lines[256]; //line numbers for the labels -static int num_labels = 0; //number of labels already in use +extern int stack[9]; +extern int a1, a2, a3, a4, a5, a6, a7, a8, a9, eax; //registers +extern char* labels[MAX_LABEL]; //max 256 labels +extern int labels_lines[MAX_LABEL]; //line numbers for the labels +extern int num_labels; //number of labels already in use +extern cmp_return_codes last_cmp_code; +extern int last_jmp_code; //easier when global +extern FILE* fptr; //file pointer + +typedef struct arguments{ + char* arg1; + char* arg2; +} arguments; + +extern arguments *args; diff --git a/src/pasm.vcxproj b/src/pasm.vcxproj index a2e5a35..bc913ae 100644 --- a/src/pasm.vcxproj +++ b/src/pasm.vcxproj @@ -44,6 +44,7 @@ true v143 Unicode + true Application @@ -77,7 +78,7 @@ false - true + false false @@ -116,6 +117,10 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + Disabled + ProgramDatabase + stdcpp20 + stdc17 Console @@ -130,6 +135,8 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp20 + stdc17 Console @@ -139,11 +146,13 @@ + + diff --git a/src/pasm.vcxproj.filters b/src/pasm.vcxproj.filters index d0eec67..cbd3bda 100644 --- a/src/pasm.vcxproj.filters +++ b/src/pasm.vcxproj.filters @@ -23,6 +23,9 @@ instructions + + Fichiers sources + @@ -37,5 +40,8 @@ instructions + + Fichiers sources + \ No newline at end of file