2024-11-19 22:09:54 +00:00
|
|
|
#include "../debug.h"
|
2024-11-01 21:41:44 +00:00
|
|
|
#include "cmd.h"
|
|
|
|
|
|
|
|
|
|
#include <blue/cmd.h>
|
2025-11-06 10:39:08 +00:00
|
|
|
#include <blue/ds/string.h>
|
2025-05-08 20:32:22 +01:00
|
|
|
#include <blue/term.h>
|
2024-11-19 22:09:54 +00:00
|
|
|
#include <errno.h>
|
2025-05-08 20:32:22 +01:00
|
|
|
#include <ivy/asm/assembler.h>
|
2024-11-19 22:09:54 +00:00
|
|
|
#include <ivy/asm/lex.h>
|
2024-12-13 12:26:32 +00:00
|
|
|
#include <ivy/asm/parse.h>
|
2025-05-08 20:32:22 +01:00
|
|
|
#include <ivy/file.h>
|
2024-11-19 22:09:54 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
ARG_SOURCE_FILE,
|
2024-12-10 22:27:34 +00:00
|
|
|
OPT_OUT_FILE,
|
|
|
|
|
ARG_OUT_FILE,
|
2024-11-19 22:09:54 +00:00
|
|
|
};
|
|
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
static int assemble_file(const char *in_path, const char *out_path)
|
2024-11-19 22:09:54 +00:00
|
|
|
{
|
2025-05-08 20:32:22 +01:00
|
|
|
enum ivy_status status = IVY_OK;
|
|
|
|
|
|
|
|
|
|
struct ivy_file *src = NULL;
|
|
|
|
|
status = ivy_file_open(in_path, &src);
|
|
|
|
|
if (!src) {
|
2024-12-13 12:26:32 +00:00
|
|
|
b_err("cannot open source file '%s'", in_path);
|
2025-05-08 20:32:22 +01:00
|
|
|
b_i("reason: %s", ivy_status_to_string(status));
|
2024-12-13 12:26:32 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 16:29:09 +01:00
|
|
|
FILE *out = fopen(out_path, "w+b");
|
2024-12-13 12:26:32 +00:00
|
|
|
if (!out) {
|
|
|
|
|
b_err("cannot open output file '%s'", out_path);
|
2024-11-19 22:09:54 +00:00
|
|
|
b_i("reason: %s", strerror(errno));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
struct ivy_assembler *as = NULL;
|
2025-05-08 20:32:22 +01:00
|
|
|
status = ivy_assembler_create(out, &as);
|
2024-12-13 12:26:32 +00:00
|
|
|
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
b_err("failed to initialise Ivy assembler");
|
|
|
|
|
b_i("reason: %s", ivy_status_to_string(status));
|
|
|
|
|
|
2025-05-08 20:32:22 +01:00
|
|
|
ivy_file_close(src);
|
2024-12-13 12:26:32 +00:00
|
|
|
fclose(out);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-19 22:09:54 +00:00
|
|
|
struct ivy_asm_lexer *lex;
|
2024-12-13 12:26:32 +00:00
|
|
|
status = ivy_asm_lexer_create(&lex);
|
|
|
|
|
if (status != IVY_OK) {
|
2024-11-19 22:09:54 +00:00
|
|
|
b_err("failed to initialise Ivy assembly lexer");
|
2024-12-13 12:26:32 +00:00
|
|
|
b_i("reason: %s", ivy_status_to_string(status));
|
2025-05-08 20:32:22 +01:00
|
|
|
|
2024-11-19 22:09:54 +00:00
|
|
|
ivy_file_close(src);
|
2024-12-13 12:26:32 +00:00
|
|
|
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);
|
|
|
|
|
|
2024-11-19 22:09:54 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ivy_asm_lexer_set_source(lex, &src->f_base);
|
2024-12-13 12:26:32 +00:00
|
|
|
ivy_asm_parser_set_assembler(parser, as);
|
2024-11-19 22:09:54 +00:00
|
|
|
|
|
|
|
|
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) {
|
2024-12-13 12:26:32 +00:00
|
|
|
b_err("failed to parse '%s'", in_path);
|
2024-11-19 22:09:54 +00:00
|
|
|
b_i("reason: lex error (%s)",
|
|
|
|
|
ivy_status_to_string(ivy_asm_lexer_get_status(lex)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_asm_lex_token(tok);
|
2024-12-13 12:26:32 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2024-11-19 22:09:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int r = (status == IVY_OK || status == IVY_ERR_EOF) ? 0 : -1;
|
2025-05-08 20:32:22 +01:00
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
ivy_asm_parser_destroy(parser);
|
|
|
|
|
ivy_assembler_finish(as);
|
2024-11-19 22:09:54 +00:00
|
|
|
ivy_file_close(src);
|
2024-12-13 12:26:32 +00:00
|
|
|
fclose(out);
|
2024-11-19 22:09:54 +00:00
|
|
|
ivy_asm_lexer_destroy(lex);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
static b_string *get_source_filename(const char *src_path)
|
2024-11-19 22:09:54 +00:00
|
|
|
{
|
2024-12-13 12:26:32 +00:00
|
|
|
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);
|
2024-11-19 22:09:54 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-08 20:32:22 +01:00
|
|
|
char s[] = {src_path[i], 0};
|
2024-12-13 12:26:32 +00:00
|
|
|
b_string_append_cstr(name, s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b_string_get_size(name, B_STRLEN_NORMAL) == 0) {
|
2025-11-06 10:39:08 +00:00
|
|
|
b_string_unref(name);
|
2024-12-13 12:26:32 +00:00
|
|
|
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;
|
2024-11-19 22:09:54 +00:00
|
|
|
}
|
2025-05-08 20:32:22 +01:00
|
|
|
|
|
|
|
|
char s[] = {src_filename[i], 0};
|
2024-12-13 12:26:32 +00:00
|
|
|
b_string_append_cstr(name, s);
|
2024-11-19 22:09:54 +00:00
|
|
|
}
|
2024-12-10 22:27:34 +00:00
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
if (b_string_get_size(name, B_STRLEN_NORMAL) == 0) {
|
|
|
|
|
b_string_append_cstr(name, "out");
|
|
|
|
|
}
|
2025-05-08 20:32:22 +01:00
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
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;
|
|
|
|
|
|
2025-05-08 20:32:22 +01:00
|
|
|
b_arglist_get_string(
|
|
|
|
|
args, B_COMMAND_INVALID_ID, ARG_SOURCE_FILE, 0, &in_path);
|
2024-12-13 12:26:32 +00:00
|
|
|
if (!in_path) {
|
|
|
|
|
b_err("no source file specified.");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2025-05-08 20:32:22 +01:00
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
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);
|
|
|
|
|
|
2025-11-06 10:39:08 +00:00
|
|
|
b_string_unref(in_name);
|
|
|
|
|
b_string_unref(out_name);
|
2024-12-13 12:26:32 +00:00
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
#if 0
|
2024-12-10 22:27:34 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-13 12:26:32 +00:00
|
|
|
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);
|
|
|
|
|
|
2024-12-10 22:27:34 +00:00
|
|
|
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);
|
2024-12-13 12:26:32 +00:00
|
|
|
#endif
|
2024-11-19 22:09:54 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2024-11-01 21:41:44 +00:00
|
|
|
|
|
|
|
|
B_COMMAND(CMD_ASSEMBLE, CMD_ROOT)
|
|
|
|
|
{
|
|
|
|
|
B_COMMAND_NAME("assemble");
|
|
|
|
|
B_COMMAND_SHORT_NAME('A');
|
|
|
|
|
B_COMMAND_DESC(
|
2025-05-08 20:32:22 +01:00
|
|
|
"assemble one or more Ivy assembly source files into Ivy "
|
|
|
|
|
"object files.");
|
2024-11-01 21:41:44 +00:00
|
|
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
2024-11-19 22:09:54 +00:00
|
|
|
B_COMMAND_FUNCTION(assemble);
|
|
|
|
|
|
|
|
|
|
B_COMMAND_ARG(ARG_SOURCE_FILE)
|
|
|
|
|
{
|
|
|
|
|
B_ARG_NAME("source file");
|
2024-12-13 12:26:32 +00:00
|
|
|
B_ARG_DESC("the .iasm assembly file to compile.");
|
|
|
|
|
B_ARG_NR_VALUES(1);
|
2024-11-19 22:09:54 +00:00
|
|
|
}
|
2024-11-01 21:41:44 +00:00
|
|
|
|
2024-12-10 22:27:34 +00:00
|
|
|
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.");
|
2025-05-08 20:32:22 +01:00
|
|
|
B_OPTION_ARG(ARG_OUT_FILE)
|
|
|
|
|
{
|
2024-12-10 22:27:34 +00:00
|
|
|
B_ARG_NAME("path");
|
|
|
|
|
B_ARG_NR_VALUES(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 21:41:44 +00:00
|
|
|
B_COMMAND_HELP_OPTION();
|
|
|
|
|
}
|