diff --git a/frontend/cmd/assemble.c b/frontend/cmd/assemble.c index c52bf5a..4283510 100644 --- a/frontend/cmd/assemble.c +++ b/frontend/cmd/assemble.c @@ -3,9 +3,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -15,26 +17,63 @@ enum { ARG_OUT_FILE, }; -#if 0 -static int assemble_file(const char *path) +static int assemble_file(const char *in_path, const char *out_path) { - FILE *fp = fopen(path, "r"); - if (!fp) { - b_err("cannot open source file '%s'", path); + FILE *in = fopen(in_path, "r"); + if (!in) { + b_err("cannot open source file '%s'", in_path); b_i("reason: %s", strerror(errno)); return -1; } - struct ivy_file *src = ivy_file_from_fp(fp); + FILE *out = fopen(out_path, "wb"); + if (!out) { + b_err("cannot open output file '%s'", out_path); + b_i("reason: %s", strerror(errno)); + return -1; + } + + struct ivy_assembler *as = NULL; + enum ivy_status status = ivy_assembler_create(out, &as); + + if (status != IVY_OK) { + b_err("failed to initialise Ivy assembler"); + b_i("reason: %s", ivy_status_to_string(status)); + + fclose(in); + fclose(out); + return -1; + } + + struct ivy_file *src = ivy_file_from_fp(in); struct ivy_asm_lexer *lex; - if (ivy_asm_lexer_create(&lex) != IVY_OK) { + status = ivy_asm_lexer_create(&lex); + if (status != IVY_OK) { b_err("failed to initialise Ivy assembly lexer"); + b_i("reason: %s", ivy_status_to_string(status)); + ivy_file_close(src); + fclose(out); + ivy_assembler_finish(as); + return -1; + } + + struct ivy_asm_parser *parser; + status = ivy_asm_parser_create(&parser); + if (status != IVY_OK) { + b_err("failed to initialise Ivy assembly parser"); + b_i("reason: %s", ivy_status_to_string(status)); + + ivy_asm_lexer_destroy(lex); + ivy_file_close(src); + fclose(out); + ivy_assembler_finish(as); + return -1; } ivy_asm_lexer_set_source(lex, &src->f_base); - enum ivy_status status = IVY_OK; + ivy_asm_parser_set_assembler(parser, as); while (true) { struct ivy_asm_token *tok = ivy_asm_lexer_read(lex); @@ -44,41 +83,109 @@ static int assemble_file(const char *path) } if (status != IVY_OK) { - b_err("failed to parse '%s'", path); + b_err("failed to parse '%s'", in_path); b_i("reason: lex error (%s)", ivy_status_to_string(ivy_asm_lexer_get_status(lex))); break; } print_asm_lex_token(tok); + status = ivy_asm_parser_push_token(parser, tok); + + if (status != IVY_OK) { + b_err("failed to parse '%s'", in_path); + b_i("reason: parse error (%s)", + ivy_status_to_string(status)); + break; + } } int r = (status == IVY_OK || status == IVY_ERR_EOF) ? 0 : -1; + + ivy_asm_parser_destroy(parser); + ivy_assembler_finish(as); ivy_file_close(src); + fclose(out); ivy_asm_lexer_destroy(lex); return r; } -#endif -static int assemble(const b_command *cmd, const b_arglist *args, const b_array *_) +static b_string *get_source_filename(const char *src_path) { -#if 0 - b_arglist_iterator it; - b_arglist_foreach_filtered(&it, args, B_COMMAND_INVALID_ID, ARG_SOURCE_FILE) - { - b_arglist_value *path = it.value; - if (path->val_type != B_COMMAND_ARG_STRING) { + b_string *name = b_string_create(); + + for (unsigned int i = 0; src_path[i]; i++) { + if (src_path[i] == '/' || src_path[i] == '\\') { + b_string_clear(name); continue; } - printf("%s\n", path->val_str); - int r = assemble_file(path->val_str); - if (r != 0) { - return r; - } + char s[] = { src_path[i], 0 }; + b_string_append_cstr(name, s); } -#endif + if (b_string_get_size(name, B_STRLEN_NORMAL) == 0) { + b_string_release(name); + name = NULL; + } + + return name; +} + +static b_string *generate_object_filename(const char *src_filename) +{ + b_string *name = b_string_create(); + + for (unsigned int i = 0; src_filename[i]; i++) { + if (src_filename[i] == '.') { + break; + } + + char s[] = { src_filename[i], 0 }; + b_string_append_cstr(name, s); + } + + if (b_string_get_size(name, B_STRLEN_NORMAL) == 0) { + b_string_append_cstr(name, "out"); + } + + b_string_append_cstr(name, ".io"); + return name; +} + +static int assemble(const b_command *cmd, const b_arglist *args, const b_array *_) +{ + const char *in_path = NULL; + const char *out_path = NULL; + + b_string *in_name = NULL; + b_string *out_name = NULL; + + b_arglist_get_string(args, B_COMMAND_INVALID_ID, ARG_SOURCE_FILE, 0, &in_path); + if (!in_path) { + b_err("no source file specified."); + return -1; + } + + in_name = get_source_filename(in_path); + if (!in_path) { + b_err("source filepath is not a file."); + return -1; + } + + b_arglist_get_string(args, OPT_OUT_FILE, ARG_OUT_FILE, 0, &out_path); + if (!out_path) { + out_name = generate_object_filename(b_string_ptr(in_name)); + out_path = b_string_ptr(out_name); + } + + int r = assemble_file(in_path, out_path); + + b_string_release(in_name); + b_string_release(out_name); + + return r; +#if 0 const char *path = NULL; b_arglist_get_string(args, OPT_OUT_FILE, ARG_OUT_FILE, 0, &path); @@ -98,6 +205,10 @@ static int assemble(const b_command *cmd, const b_arglist *args, const b_array * return -1; } + ivy_assembler_begin_scope(as, IVY_ASM_SCOPE_CONSTPOOL, NULL); + ivy_assembler_put_pval(as, IVY_ASM_PVAL_STRING, 0, "Hello, world!"); + ivy_assembler_end_scope(as); + ivy_assembler_attrib_table attrib = { [IVY_ASM_ATTRIB_IDENT] = 32, }; @@ -111,7 +222,7 @@ static int assemble(const b_command *cmd, const b_arglist *args, const b_array * ivy_assembler_finish(as); fclose(out); - +#endif return 0; } @@ -127,8 +238,8 @@ B_COMMAND(CMD_ASSEMBLE, CMD_ROOT) B_COMMAND_ARG(ARG_SOURCE_FILE) { B_ARG_NAME("source file"); - B_ARG_DESC("the .iasm assembly files to compile."); - B_ARG_NR_VALUES(B_ARG_1_OR_MORE_VALUES); + B_ARG_DESC("the .iasm assembly file to compile."); + B_ARG_NR_VALUES(1); } B_COMMAND_OPTION(OPT_OUT_FILE)