diff options
| author | hachem <im@hachem.wtf> | 2026-08-30 22:42:20 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-08-30 22:42:20 +0200 |
| commit | 81799f3e41ad9cab305930b7743a752003ff16ec (patch) | |
| tree | 20fd67914ac143ab97a00392abcf5817ba11db22 /src | |
| parent | 294777178f9203283364f3e672569becb4dd1e7c (diff) | |
feat: sized memory stores bia ^
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen/nasm.c | 86 | ||||
| -rw-r--r-- | src/lexer/lexer.c | 8 | ||||
| -rw-r--r-- | src/lexer/lexer.h | 4 | ||||
| -rw-r--r-- | src/parser/ast.h | 10 | ||||
| -rw-r--r-- | src/parser/parser.c | 14 |
5 files changed, 120 insertions, 2 deletions
diff --git a/src/codegen/nasm.c b/src/codegen/nasm.c index 1062d7a..323adfc 100644 --- a/src/codegen/nasm.c +++ b/src/codegen/nasm.c @@ -193,6 +193,71 @@ static void emit_expr_into(struct Emitter* emitter, const char* dst, struct Expr fprintf(emitter->out, "\n"); } +static const char* store_size_keyword(enum StoreSize size) +{ + switch (size) + { + case STORE_SIZE_BYTE: return "byte "; + case STORE_SIZE_WORD: return "word "; + case STORE_SIZE_DWORD: return "dword "; + case STORE_SIZE_QWORD: return "qword "; + default: return ""; + } +} + +// maps a full 64-bit register to its byte/word/dword sub-register for a sized +// store, so `^byte rsi = rdx` writes `dl` rather than the whole register. +// returns NULL when the token is not a full register, or no resizing applies. +static const char* sized_register(struct Token reg, enum StoreSize size) +{ + if (size == STORE_SIZE_NONE || size == STORE_SIZE_QWORD) + return NULL; + + static const struct RegisterSizes + { + const char* quad; + const char* dword; + const char* word; + const char* byte; + } registers[] = + { + { "rax", "eax", "ax", "al" }, + { "rbx", "ebx", "bx", "bl" }, + { "rcx", "ecx", "cx", "cl" }, + { "rdx", "edx", "dx", "dl" }, + { "rsi", "esi", "si", "sil" }, + { "rdi", "edi", "di", "dil" }, + { "rbp", "ebp", "bp", "bpl" }, + { "rsp", "esp", "sp", "spl" }, + { "r8", "r8d", "r8w", "r8b" }, + { "r9", "r9d", "r9w", "r9b" }, + { "r10", "r10d", "r10w", "r10b" }, + { "r11", "r11d", "r11w", "r11b" }, + { "r12", "r12d", "r12w", "r12b" }, + { "r13", "r13d", "r13w", "r13b" }, + { "r14", "r14d", "r14w", "r14b" }, + { "r15", "r15d", "r15w", "r15b" }, + }; + + for (size_t i = 0; i < sizeof(registers) / sizeof(registers[0]); i += 1) + { + const struct RegisterSizes* entry = ®isters[i]; + size_t length = strlen(entry->quad); + if (reg.length != length || memcmp(reg.start, entry->quad, length) != 0) + continue; + + switch (size) + { + case STORE_SIZE_DWORD: return entry->dword; + case STORE_SIZE_WORD: return entry->word; + case STORE_SIZE_BYTE: return entry->byte; + default: return NULL; + } + } + + return NULL; +} + static void emit_assign(struct Emitter* emitter, struct AssignStatement* assign) { if (assign->op.type == TOKEN_SLASH_EQUAL) @@ -227,11 +292,28 @@ static void emit_assign(struct Emitter* emitter, struct AssignStatement* assign) } if (assign->target_deref) - fprintf(emitter->out, "\t%s [%.*s], ", mnemonic, (int)target.length, target.start); + { + fprintf(emitter->out, "\t%s %s[%.*s], ", mnemonic, + store_size_keyword(assign->store_size), (int)target.length, target.start); + + const char* sized = NULL; + if (assign->value->kind == EXPR_PRIMARY) + { + struct Token value = resolve_token(emitter, assign->value->primary.token); + sized = sized_register(value, assign->store_size); + if (sized != NULL) + fprintf(emitter->out, "%s", sized); + } + + if (sized == NULL) + emit_operand(emitter, assign->value); + } else + { fprintf(emitter->out, "\t%s %.*s, ", mnemonic, (int)target.length, target.start); + emit_operand(emitter, assign->value); + } - emit_operand(emitter, assign->value); fprintf(emitter->out, "\n"); } diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 97a91b1..da45741 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -31,6 +31,10 @@ static enum TokenType identifier_type(const char* start, size_t length) { "if", 2, TOKEN_IF }, { "goto", 4, TOKEN_GOTO }, { "syscall", 7, TOKEN_SYSCALL }, + { "byte", 4, TOKEN_BYTE }, + { "word", 4, TOKEN_WORD }, + { "dword", 5, TOKEN_DWORD }, + { "qword", 5, TOKEN_QWORD }, }; for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i += 1) @@ -224,6 +228,10 @@ const char* token_type_name(enum TokenType type) case TOKEN_IF: return "if"; case TOKEN_GOTO: return "goto"; case TOKEN_SYSCALL: return "syscall"; + case TOKEN_BYTE: return "byte"; + case TOKEN_WORD: return "word"; + case TOKEN_DWORD: return "dword"; + case TOKEN_QWORD: return "qword"; case TOKEN_EQUAL: return "equal"; case TOKEN_PLUS: return "plus"; case TOKEN_MINUS: return "minus"; diff --git a/src/lexer/lexer.h b/src/lexer/lexer.h index 56c1feb..441fe10 100644 --- a/src/lexer/lexer.h +++ b/src/lexer/lexer.h @@ -18,6 +18,10 @@ enum TokenType TOKEN_IF, TOKEN_GOTO, TOKEN_SYSCALL, + TOKEN_BYTE, + TOKEN_WORD, + TOKEN_DWORD, + TOKEN_QWORD, TOKEN_EQUAL, TOKEN_PLUS, diff --git a/src/parser/ast.h b/src/parser/ast.h index 8281085..6071c4a 100644 --- a/src/parser/ast.h +++ b/src/parser/ast.h @@ -59,6 +59,15 @@ struct Expr }; }; +enum StoreSize +{ + STORE_SIZE_NONE, + STORE_SIZE_BYTE, + STORE_SIZE_WORD, + STORE_SIZE_DWORD, + STORE_SIZE_QWORD, +}; + enum StatementKind { STATEMENT_ASSIGN, @@ -73,6 +82,7 @@ enum StatementKind struct AssignStatement { bool target_deref; + enum StoreSize store_size; struct Token target; struct Token op; struct Expr* value; diff --git a/src/parser/parser.c b/src/parser/parser.c index d2a7285..ca14023 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -344,6 +344,19 @@ static bool parse_statement(struct Parser* parser, struct Statement* out) bool deref = match_token(parser, TOKEN_CARET); + enum StoreSize store_size = STORE_SIZE_NONE; + if (deref) + { + if (match_token(parser, TOKEN_BYTE)) + store_size = STORE_SIZE_BYTE; + else if (match_token(parser, TOKEN_WORD)) + store_size = STORE_SIZE_WORD; + else if (match_token(parser, TOKEN_DWORD)) + store_size = STORE_SIZE_DWORD; + else if (match_token(parser, TOKEN_QWORD)) + store_size = STORE_SIZE_QWORD; + } + if (!consume(parser, TOKEN_IDENTIFIER, "expected a statement")) return false; struct Token name = parser->previous; @@ -373,6 +386,7 @@ static bool parse_statement(struct Parser* parser, struct Statement* out) out->kind = STATEMENT_ASSIGN; out->assign.target_deref = deref; + out->assign.store_size = store_size; out->assign.target = name; out->assign.op = op; out->assign.value = value; |
