summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-06-09 02:22:33 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-06-09 02:22:33 +0200
commit924558d3c9d8363d80136cb7599bd98b19c93f48 (patch)
tree19b5aae7a340e4c0c23a404dac489a24fe3dd988
parent9e9027cc63e63e80dc8fcb82f2f2c3b60acf95f7 (diff)
downloadbxgen-924558d3c9d8363d80136cb7599bd98b19c93f48.zip
Add semantic tree example
-rw-r--r--.gitignore2
-rwxr-xr-xbinary_code_generation.c136
2 files changed, 117 insertions, 21 deletions
diff --git a/.gitignore b/.gitignore
index 8b13789..145f5d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-
+test_*
diff --git a/binary_code_generation.c b/binary_code_generation.c
index 0f0d374..3735b2c 100755
--- a/binary_code_generation.c
+++ b/binary_code_generation.c
@@ -9,7 +9,7 @@ exit $?
//
// Binary code generation compiler backend
//
-// Traits
+// Qualities
//
// - Single source file
// - Simple and flexible API
@@ -27,6 +27,8 @@ exit $?
// - Sea of Nodes
// - Optimization layers
// - Multithreading
+// - COFF, PE, OMF, Mach-O
+// - i386, RISC-V, ARM
//
// ================================================================
//
@@ -66,6 +68,23 @@ enum {
// For indices
UNDEFINED = -1,
+ // Formats
+ //
+
+ FORMAT_ELF = 1,
+ FORMAT_COFF,
+ FORMAT_PE,
+ FORMAT_OMF,
+ FORMAT_MATCH_O,
+
+ // Architecture
+ //
+
+ ARCH_RISC_V = 64,
+ ARCH_I386,
+ ARCH_X86_64,
+ ARCH_ARM,
+
// Sea of Nodes flow type
//
@@ -99,15 +118,15 @@ enum {
// (see `entity_t::tail`), except for `MAX_ENTITY_COUNT`.
//
- MAX_LITERAL_SIZE = 512,
+ MAX_LITERAL_SIZE = 400,
MAX_NAME_SIZE = 128,
- MAX_PROC_COUNT = 126,
- MAX_NODE_COUNT = 110,
+ MAX_PROC_COUNT = 80,
+ MAX_NODE_COUNT = 60,
MAX_ENTITY_COUNT = 16384,
};
-// A semantic node is an operation with
-// possible references to other nodes.
+// A semantic node is an operation with optional data
+// and possible references to other nodes.
//
typedef struct {
@@ -136,6 +155,7 @@ typedef struct {
typedef struct {
i16 type;
+ i64 entry_point;
i64 proc_count;
i64 procs[MAX_PROC_COUNT];
} unit_t;
@@ -206,6 +226,22 @@ void node_destroy(entity_pool_t *pool, i64 node) {
pool_entity_remove(pool, node, TYPE_NODE);
}
+i64 node_op_i64(entity_pool_t *pool, i64 value) {
+ return node_init(pool, (node_t) {
+ .op = OP_I64,
+ .flow = FLOW_DATA,
+ .lit_int = value,
+ });
+}
+
+i64 node_op_ret(entity_pool_t *pool, i64 node_return_value) {
+ return node_init(pool, (node_t) {
+ .op = OP_RET,
+ .flow = FLOW_CONTROL,
+ .ref_node = node_return_value,
+ });
+}
+
i64 proc_init(entity_pool_t *pool) {
return pool_entity_add(pool, (entity_t) {
.type = TYPE_PROC,
@@ -217,7 +253,7 @@ void proc_destroy(entity_pool_t *pool, i64 proc) {
pool_entity_remove(pool, proc, TYPE_PROC);
}
-void proc_set_name(entity_pool_t *pool, i64 proc, i64 name_size, c8 *name) {
+void proc_set_name(entity_pool_t *pool, i64 proc, i64 name_size, c8 const *name) {
assert(pool != NULL);
assert(pool->entities[proc].is_enabled);
assert(pool->entities[proc].type == TYPE_PROC);
@@ -261,6 +297,9 @@ i64 unit_init(entity_pool_t *pool) {
return pool_entity_add(pool, (entity_t) {
.type = TYPE_UNIT,
.tail = UNDEFINED,
+ .unit = (unit_t) {
+ .entry_point = UNDEFINED,
+ }
});
}
@@ -293,28 +332,75 @@ void unit_proc_remove(entity_pool_t *pool, i64 unit, i64 proc) {
pool->entities[unit].unit.procs[proc] = UNDEFINED;
}
+void unit_set_entry_point(entity_pool_t *pool, i64 unit, i64 entry_point_proc) {
+ assert(pool != NULL);
+ assert(pool->entities[unit].is_enabled);
+ assert(pool->entities[unit].type == TYPE_UNIT);
+ assert(pool->entities[entry_point_proc].type == TYPE_PROC);
+
+ pool->entities[unit].unit.entry_point = entry_point_proc;
+}
+
+void unit_write(entity_pool_t *pool, i64 unit, i16 target, FILE *out) {
+ assert(pool != NULL);
+ assert(pool->entities[unit].is_enabled);
+ assert(pool->entities[unit].unit.entry_point != UNDEFINED);
+ assert(out != NULL);
+ assert(target == (FORMAT_ELF | ARCH_X86_64));
+
+ // TODO
+ printf("[TODO] Writing ELF x86_64 executable...");
+}
+
+// ================================================================
+//
+// Helpers
+//
+// ================================================================
+
// Global state
//
static entity_pool_t g_pool = { 0 };
-// Helper functions
+// Handy procedures
//
-i64 op_i64(i64 value) {
- return node_init(&g_pool, (node_t) {
- .op = OP_I64,
- .flow = FLOW_DATA,
- .lit_int = value,
- });
+i64 n_i64(i64 value) {
+ return node_op_i64(&g_pool, value);
}
-i64 op_ret(i64 node_return_value) {
- return node_init(&g_pool, (node_t) {
- .op = OP_RET,
- .flow = FLOW_CONTROL,
- .ref_node = node_return_value,
- });
+i64 n_ret(i64 node_return_value) {
+ return node_op_ret(&g_pool, node_return_value);
+}
+
+i64 p_new(c8 const *name) {
+ i64 p = proc_init(&g_pool);
+ proc_set_name(&g_pool, p, strlen(name), name);
+ return p;
+}
+
+void p_add(i64 proc, i64 node) {
+ proc_node_add(&g_pool, proc, node);
+}
+
+i64 u_new() {
+ return unit_init(&g_pool);
+}
+
+void u_add(i64 unit, i64 proc) {
+ unit_proc_add(&g_pool, unit, proc);
+}
+
+void u_entry_point(i64 unit, i64 proc) {
+ unit_set_entry_point(&g_pool, unit, proc);
+}
+
+void u_elf_x86_64(i64 unit, c8 const *output_file_name) {
+ FILE *f = fopen(output_file_name, "wb");
+ assert(f != NULL);
+ unit_write(&g_pool, unit, FORMAT_ELF | ARCH_X86_64, f);
+ fclose(f);
}
// ================================================================
@@ -328,6 +414,16 @@ int main(int argc, char **argv) {
printf("proc - %d bytes\n", (i32) sizeof(proc_t));
printf("unit - %d bytes\n", (i32) sizeof(unit_t));
+ i64 main = p_new("main");
+ i64 n0 = n_i64(42);
+ p_add(main, n0);
+ p_add(main, n_ret(n0));
+
+ i64 u = u_new();
+ u_add(u, main);
+ u_entry_point(u, main);
+ u_elf_x86_64(u, "test_foo");
+
printf("\nBye!\n");
return 0;
}