aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-03-24 20:37:41 +0800
committerMistivia <i@mistivia.com>2025-03-24 20:37:41 +0800
commit4188f791787be19f32226b8ac0f213f61cdd4666 (patch)
tree54a38cbcaf67647c2e0e865f7f1dd537456817c1
parent4f7f0aa49844756dbf430f35600d7c88e1a6a730 (diff)
finish analyzer
-rw-r--r--src/as_analyzer.c38
-rw-r--r--src/as_analyzer.h9
-rw-r--r--src/as_op.c40
-rw-r--r--src/as_op.h3
-rw-r--r--src/as_tokenizer.c3
-rw-r--r--tests/test_as_analyzer.c42
6 files changed, 125 insertions, 10 deletions
diff --git a/src/as_analyzer.c b/src/as_analyzer.c
index dbc1bd2..a3e7ea4 100644
--- a/src/as_analyzer.c
+++ b/src/as_analyzer.c
@@ -3,11 +3,6 @@
#include <stddef.h>
#include <string.h>
-struct sym_table_entry {
- const char * name;
- size_t offset;
-};
-
const char * compose_section_label(allocator_t alct, const char * section, const char * name) {
size_t section_len = strlen(section);
size_t name_len = strlen(name);
@@ -36,18 +31,43 @@ void process_section_label(allocator_t alct, prog_t prog) {
}
size_t instr_size(instr_t instr) {
- // TODO
- return 0;
+ return op_size(instr->op);
+}
+
+struct sym_table new_sym_table(allocator_t alct) {
+ struct sym_table tbl;
+ tbl.cap = 16;
+ tbl.size = 0;
+ tbl.buf = allocate(alct, sizeof(struct sym_table_entry) * 16);
+ return tbl;
+}
+
+void sym_table_add(allocator_t alct, struct sym_table* tbl, const char* name, int pos) {
+ if (tbl->cap == tbl->size) {
+ void *old_buf = tbl->buf;
+ tbl->buf = allocate(alct, sizeof(struct sym_table_entry) * tbl->cap * 2);
+ memcpy(tbl->buf, old_buf, sizeof(struct sym_table_entry) * tbl->cap);
+ tbl->cap = tbl->cap * 2;
+ }
+ tbl->buf[tbl->size] = (struct sym_table_entry){.name = name, .offset = pos,};
+ tbl->size += 1;
}
struct sym_table analyze_prog(allocator_t alct, prog_t prog) {
process_section_label(alct, prog);
stmt_t * stmts = prog->stmts->stmts;
+ struct sym_table tbl = new_sym_table(alct);
+ size_t cur_pos = 0;
for (int i = 0; ; i++) {
if (stmts[i] == NULL) break;
+ stmt_t stmt = stmts[i];
+ if (stmt->label) {
+ sym_table_add(alct, &tbl, stmt->label->name, cur_pos);
+ }
+ if (stmt->instr) {
+ cur_pos += instr_size(stmt->instr);
+ }
}
- struct sym_table tbl;
- // TODO
return tbl;
}
diff --git a/src/as_analyzer.h b/src/as_analyzer.h
index 793d14a..988cca0 100644
--- a/src/as_analyzer.h
+++ b/src/as_analyzer.h
@@ -4,13 +4,20 @@
#include "as_parser.h"
#include "utils.h"
-struct sym_table_entry;
+struct sym_table_entry {
+ const char * name;
+ size_t offset;
+};
+
struct sym_table {
int size;
int cap;
struct sym_table_entry *buf;
};
+struct sym_table new_sym_table(allocator_t alct);
+void sym_table_add(allocator_t alct, struct sym_table* tbl, const char* name, int pos);
+
struct sym_table analyze_prog(allocator_t alct, prog_t prog);
#endif // FVM_AS_ANALYZER_H_
diff --git a/src/as_op.c b/src/as_op.c
index 8b5d887..67c91ff 100644
--- a/src/as_op.c
+++ b/src/as_op.c
@@ -92,6 +92,46 @@ struct op_table_entry op_table [] = {
{OP_END, NULL},
};
+int op_size(enum op op) {
+ if (op == OP_IMM) {
+ return 8 + 1;
+ }
+ if (op == OP_CALL
+ || op == OP_JMP
+ || op == OP_JNZ
+ || op == OP_JZ
+ || op == OP_SYSCALL) {
+ return 8 + 1 + 1;
+ }
+ if (op == OP_LDARG || op == OP_STARG) {
+ return 9 + 9 + 1 + 9 + 4;
+ }
+ if (op == OP_LDVAR || op == OP_STVAR) {
+ return 9 + 9 + 2 + 9 + 4;
+ }
+ return 1;
+}
+
+int is_ld_op(enum op op) {
+ if (op == OP_LD
+ || op == OP_LD8
+ || op == OP_LD16
+ || op == OP_LD32) {
+ return 1;
+ }
+ return 0;
+}
+
+int is_st_op(enum op op) {
+ if (op == OP_ST
+ || op == OP_ST8
+ || op == OP_ST16
+ || op == OP_ST32) {
+ return 1;
+ }
+ return 0;
+}
+
enum op str2op(const char* str) {
for (int i = 0; op_table[i].name != NULL; i++) {
if (strcmp(op_table[i].name, str) == 0) {
diff --git a/src/as_op.h b/src/as_op.h
index bded9e4..d02c29f 100644
--- a/src/as_op.h
+++ b/src/as_op.h
@@ -23,6 +23,9 @@ enum op {
enum op str2op(const char *str);
int isOp(const char *str);
+int op_size(enum op op);
+int is_ld_op(enum op);
+int is_st_op(enum op);
#endif
diff --git a/src/as_tokenizer.c b/src/as_tokenizer.c
index 54e0969..216ee8a 100644
--- a/src/as_tokenizer.c
+++ b/src/as_tokenizer.c
@@ -55,6 +55,9 @@ int is_start_of_identifier(int c) {
if (c == '_') {
return 1;
}
+ if (c == '.') {
+ return 1;
+ }
return 0;
}
diff --git a/tests/test_as_analyzer.c b/tests/test_as_analyzer.c
new file mode 100644
index 0000000..4c56131
--- /dev/null
+++ b/tests/test_as_analyzer.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "as_tokenizer.h"
+#include "as_parser.h"
+#include "as_analyzer.h"
+#include "utils.h"
+
+char *input_buffer =
+ "start:\n"
+ " imm 1\n"
+ "mid: add\n"
+ " call start\n"
+ " sub\n"
+ ".insec: add\n"
+ " div\n"
+ "end: eq\n";
+
+int main(int argc, char** argv) {
+ printf("[TEST] assembler analyzer\n");
+ // make a memory buffer to FILE*
+ FILE *fp = fmemopen(input_buffer, strlen(input_buffer), "r");
+ allocator_t alct = new_allocator();
+ token_stream_t ts = new_token_stream(alct, fp);
+ prog_t prog = parse_prog(alct, ts);
+ struct sym_table sym_table = analyze_prog(alct, prog);
+
+ assert(strcmp(sym_table.buf[0].name, "start") == 0);
+ assert(strcmp(sym_table.buf[1].name, "mid") == 0);
+ assert(strcmp(sym_table.buf[2].name, "mid.insec") == 0);
+ assert(strcmp(sym_table.buf[3].name, "end") == 0);
+
+ assert(sym_table.buf[0].offset == 0);
+ assert(sym_table.buf[1].offset == 9);
+ assert(sym_table.buf[2].offset == 21);
+ assert(sym_table.buf[3].offset == 23);
+
+ printf("[PASS] assembler analyzer\n");
+ delete_allocator(alct);
+ return 0;
+}