Assembler/src/main.c
2023-09-07 18:41:46 +02:00

205 lines
5.9 KiB
C
Executable file

/*
This code is part of the EIPA Platform
This code is the entry point of the EIPA Assembler and calls the needed functions to create the EIPA Image
It also is responsible for Argument Parsing
*/
#include <argp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../header/argp_commons.h"
#include "../header/common.h"
#include "../header/error_analyzer.h"
#include "../header/image_saver.h"
#include "../header/instruction_table.h"
#include "../header/labels.h"
#include "../header/lexer.h"
#include "../header/target_code_generator.h"
const char *argp_program_version =
VER_MAJOR "." VER_MINOR "." VER_PATCH " || " TAG;
const char *argp_program_bug_address = EIPA_BUG_ADRESS;
// Here, the argumets get stored by the parser, so acess them from here
struct cmd_arguments
{
char *input_file;
char *output_file;
unsigned short int print_tokens;
unsigned short int print_target_code;
};
// Parses the command line options & arguments
static error_t parser_function(int key, char *arg, struct argp_state *state)
{
struct cmd_arguments *save_arguments = state->input;
switch (key)
{
case 'o':
save_arguments->output_file = arg;
break;
case 't':
save_arguments->print_tokens = 1;
break;
case 'b':
save_arguments->print_target_code = 1;
break;
case ARGP_KEY_ARG:
// If we got more than one non-option argument
if (state->arg_num >= 1)
{
argp_usage(state);
}
save_arguments->input_file = arg;
break;
case ARGP_KEY_END:
// If we didn't receive 1 Argument yet
if (state->arg_num < 1)
{
argp_usage(state);
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
// This array stores structs containing information about the cli options
static struct argp_option argp_options[] =
{
{.name = "output",
.key = 'o',
.arg = "FILE",
.flags = 0,
.doc = "Output file",
.group = 0},
{.name = "print_tokens",
.key = 't',
.arg = 0,
.flags = 0,
.doc = "Print the tokens generated by the Lexer to stdout",
.group = 0},
{.name = "print_target_code",
.key = 'b',
.arg = 0,
.flags = 0,
.doc = "Print the (Binary) target code generated to stdout",
.group = 0},
{0}
};
// Contains the neccesary stuff for argp
static struct argp argument_parser =
{
.options = argp_options,
.parser = parser_function,
.args_doc = ARGUMENT_DOC,
.doc = LONG_DOC};
int main(int argc, char **argv)
{
// Parse CLI Arguments
// set defaults
struct cmd_arguments arguments;
arguments.output_file = DEFAULT_OUT_FILE;
arguments.input_file = "";
arguments.print_target_code = 0;
arguments.print_tokens = 0;
if (argp_parse(&argument_parser, argc, argv, 0, 0, &arguments) != 0)
{
printf("Error: Failed to parse CLI Arguments - Error code\n");
return EXIT_FAILURE;
}
// Tokenize the EIPA Assembly
FILE *assembly_file;
assembly_file = fopen(arguments.input_file, "r");
if (assembly_file == NULL)
{
printf("Error: Couldn't open input file\n");
return EXIT_FAILURE;
}
char(*label_tokens)[MAX_TOKEN_SIZE] = calloc(MAX_MEMORY, sizeof(*label_tokens));
if (label_tokens == NULL)
{
printf("Error: Could not allocate memory for the label_tokens array\n");
return EXIT_FAILURE;
}
lexer(assembly_file, label_tokens);
fclose(assembly_file);
// Part I of processing labels
shash_hashtable_t label_table;
shash_init_hashtable(&label_table, LABEL_TABLE_SIZE);
build_label_table(label_tokens, &label_table);
printf("Built label table\n");
char(*no_label_definition_tokens)[MAX_TOKEN_SIZE] = calloc(MAX_MEMORY, sizeof(*no_label_definition_tokens));
if (no_label_definition_tokens == NULL)
{
printf("Error: Could not allocate memory for the no_label_defintion_tokens array\n");
return EXIT_FAILURE;
}
remove_label_definition_tokens(label_tokens, no_label_definition_tokens);
printf("Removed label defintions\n");
free(label_tokens);
// Check if the EIPA Assembly contains errors with the no_label_definition_tokens array
shash_hashtable_t instruction_informations = create_instruction_information_hastable();
printf("Found %d errors\n", check_token_errors(no_label_definition_tokens, instruction_informations, label_table));
// Part II of processing labels
char(*tokens)[MAX_TOKEN_SIZE] = calloc(MAX_MEMORY, sizeof(*tokens));
if (tokens == NULL)
{
printf("Error: Could not allocate memory for the tokens array\n");
return EXIT_FAILURE;
}
replace_labels_with_adresses(no_label_definition_tokens, tokens, label_table, instruction_informations);
printf("Removed labels\n");
free(no_label_definition_tokens);
// Generate the target code
__uint32_t *target_code = calloc(MAX_MEMORY, sizeof(target_code));
if (target_code == NULL)
{
printf("Error: Could not allocate memory for the target code\n");
return EXIT_FAILURE;
}
int error = gen_target_code(tokens, target_code);
if (error != 0)
{
printf("Error: Could not generate target code - Error %s\n", strerror(error));
return EXIT_FAILURE;
}
// Save the target code to a file
if (save_img(arguments.output_file, target_code) != 0)
{
printf("Couldn't save the output file\n");
exit(EXIT_FAILURE);
}
// If the requested, we print the tokens and/or the target code
if (arguments.print_tokens)
print_tokens(tokens);
if (arguments.print_target_code)
print_target_code(target_code);
// Cleanup
destroy_instruction_information_hashtable(&instruction_informations);
shash_destroy_hashtable(&label_table);
return EXIT_SUCCESS;
}