#include "../debug.h" #include "cmd.h" #include #include #include #include #include #include #include #include #include enum { ARG_SOURCE_FILE, OPT_OUT_FILE, ARG_OUT_FILE, }; static int assemble_file(const char *in_path, const char *out_path) { enum ivy_status status = IVY_OK; struct ivy_file *src = NULL; status = ivy_file_open(in_path, &src); if (!src) { b_err("cannot open source file '%s'", in_path); b_i("reason: %s", ivy_status_to_string(status)); return -1; } FILE *out = fopen(out_path, "w+b"); if (!out) { b_err("cannot open output file '%s'", out_path); b_i("reason: %s", strerror(errno)); return -1; } struct ivy_assembler *as = NULL; 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)); ivy_file_close(src); fclose(out); return -1; } struct ivy_asm_lexer *lex; 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); ivy_asm_parser_set_assembler(parser, as); while (true) { struct ivy_asm_token *tok = ivy_asm_lexer_read(lex); status = ivy_asm_lexer_get_status(lex); if (status == IVY_ERR_EOF) { break; } if (status != IVY_OK) { 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; } static b_string *get_source_filename(const char *src_path) { 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; } char s[] = {src_path[i], 0}; b_string_append_cstr(name, s); } 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); if (!path) { printf("no output path specified.\n"); return -1; } FILE *out = fopen(path, "wb"); struct ivy_assembler *as; enum ivy_status status = ivy_assembler_create(out, &as); if (status != IVY_OK) { b_err("failed to initialise assembler"); b_i("reason: ", ivy_status_to_string(status)); fclose(out); 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, }; ivy_assembler_begin_scope(as, IVY_ASM_SCOPE_CLASS, attrib); ivy_assembler_end_scope(as); attrib[IVY_ASM_ATTRIB_IDENT] = 64; ivy_assembler_begin_scope(as, IVY_ASM_SCOPE_CLASS, attrib); ivy_assembler_end_scope(as); ivy_assembler_finish(as); fclose(out); #endif return 0; } B_COMMAND(CMD_ASSEMBLE, CMD_ROOT) { B_COMMAND_NAME("assemble"); B_COMMAND_SHORT_NAME('A'); B_COMMAND_DESC( "assemble one or more Ivy assembly source files into Ivy " "object files."); B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); B_COMMAND_FUNCTION(assemble); B_COMMAND_ARG(ARG_SOURCE_FILE) { B_ARG_NAME("source file"); B_ARG_DESC("the .iasm assembly file to compile."); B_ARG_NR_VALUES(1); } B_COMMAND_OPTION(OPT_OUT_FILE) { B_OPTION_SHORT_NAME('o'); B_OPTION_LONG_NAME("out"); B_OPTION_DESC("the path to write the output binary file to."); B_OPTION_ARG(ARG_OUT_FILE) { B_ARG_NAME("path"); B_ARG_NR_VALUES(1); } } B_COMMAND_HELP_OPTION(); }