hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-10-12 11:41:05 +0200
committerhachem <im@hachem.wtf>2026-10-12 11:41:05 +0200
commit62636576bce8e8121a3d70f63547fae40a52f697 (patch)
tree077dfe4f04235cce63b7abb1b05bb539232ae74a /src
parentc0f000ea166a24781fcdbf23c080b203cd9b8ed7 (diff)
chore: refactor
Diffstat (limited to 'src')
-rw-r--r--src/ast.c1
-rw-r--r--src/ast.h5
-rw-r--r--src/codegen.c185
-rw-r--r--src/diag.c8
-rw-r--r--src/parser.c2
-rw-r--r--src/sema.c30
6 files changed, 60 insertions, 171 deletions
diff --git a/src/ast.c b/src/ast.c
index b613abe..4480b56 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -149,7 +149,6 @@ void free_program(struct Program* program)
program->proc_capacity = 0;
}
-// TODO: generalize this growable-array boilerplate once a third list appears
void add_const(struct Program* program, struct ConstDecl decl)
{
if (program->const_count == program->const_capacity)
diff --git a/src/ast.h b/src/ast.h
index 1db8b99..23fe438 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -177,9 +177,6 @@ struct StackStatement
struct Expr* size;
};
-// a bare instruction: a mnemonic and its operands emitted verbatim, the escape
-// hatch for anything outside the assignment / control-flow model (int, hlt,
-// lgdt, in/out, ...)
struct InstructionStatement
{
struct Token mnemonic;
@@ -188,8 +185,6 @@ struct InstructionStatement
size_t operand_capacity;
};
-// a branchless conditional move: `target = if_value if left cmp right else
-// else_value`. Lowers to csel on AArch64 and cmov on x86.
struct SelectStatement
{
struct Token target;
diff --git a/src/codegen.c b/src/codegen.c
index c0e67be..b111fb8 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -32,11 +32,11 @@ static const char* assign_mnemonic(enum TokenType op)
{
switch (op)
{
- case TOKEN_EQUAL: return "mov";
+ case TOKEN_EQUAL: return "mov";
case TOKEN_PLUS_EQUAL: return "add";
case TOKEN_MINUS_EQUAL: return "sub";
case TOKEN_STAR_EQUAL: return "imul";
- default: return NULL;
+ default: return NULL;
}
}
@@ -60,11 +60,9 @@ static bool is_float_register(struct Token token)
{
if (token.length < 4 || memcmp(token.start, "xmm", 3) != 0)
return false;
-
for (size_t i = 3; i < token.length; i += 1)
if (token.start[i] < '0' || token.start[i] > '9')
return false;
-
return true;
}
@@ -74,7 +72,6 @@ static size_t float_index(const struct FloatTable* floats, struct Token literal)
if (floats->items[i].length == literal.length
&& memcmp(floats->items[i].start, literal.start, literal.length) == 0)
return i;
-
return floats->count;
}
@@ -105,8 +102,6 @@ static struct Token text_token(const char* text)
return token;
}
-// with the logical_registers extension, r1..r14 name the general-purpose
-// registers; rsp/rbp and the instruction pointer keep their dedicated names.
static const char* logical_register_base(struct Token token)
{
static const char* registers[] = {
@@ -135,14 +130,12 @@ static const char* logical_register_base(struct Token token)
static struct Token resolve_register(struct Emitter* emitter, struct Token token)
{
struct Token resolved = resolve_token(emitter, token);
-
if (emitter->program->config.logical_registers)
{
const char* base = logical_register_base(resolved);
if (base != NULL)
return text_token(base);
}
-
return resolved;
}
@@ -320,8 +313,6 @@ static bool fold_member(struct Program* program, struct Expr* object, struct Tok
return false;
}
-// evaluates a compile-time constant expression: integer/char literals, other
-// constants, enum values and struct offsets, and + - * / over them
static bool fold_const(struct Program* program, struct Expr* expr, uint64_t* out)
{
switch (expr->kind)
@@ -379,8 +370,6 @@ static bool fold_const(struct Program* program, struct Expr* expr, uint64_t* out
return false;
}
-// an enum member folds to its 0-based index; a struct member folds to its byte
-// offset (or the total size for `.size`)
static bool emit_named_member(struct Emitter* emitter, struct Token object, struct Token member)
{
const struct EnumDecl* enumeration = find_enum(emitter->program, object);
@@ -429,7 +418,6 @@ static bool emit_operand(struct Emitter* emitter, struct Expr* expr)
}
case EXPR_MEMBER:
{
- // a register size suffix: r1.64 -> rax, r1.8 -> al
if (expr->member.member.type == TOKEN_INTEGER &&
expr->member.object->kind == EXPR_PRIMARY)
{
@@ -442,10 +430,8 @@ static bool emit_operand(struct Emitter* emitter, struct Expr* expr)
fprintf(emitter->out, "%.*s", (int)base.length, base.start);
return true;
}
-
- // enum value or struct offset
- if (expr->member.object->kind == EXPR_PRIMARY
- && emit_named_member(emitter, expr->member.object->primary.token, expr->member.member))
+ if (expr->member.object->kind == EXPR_PRIMARY &&
+ emit_named_member(emitter, expr->member.object->primary.token, expr->member.member))
return true;
if (!emit_operand(emitter, expr->member.object))
@@ -479,14 +465,9 @@ static bool is_gp_register(struct Token token)
for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i += 1)
if (token_matches(token, names[i]))
return true;
-
return false;
}
-// idiv can divide by a general-purpose register directly, but not by rax or rdx
-// (it overwrites both with the quotient and remainder) nor by an immediate (it
-// has no immediate form). Those divisors are copied into r11 first — already a
-// volatile register here, clobbered by syscall just like rcx.
static bool divisor_uses_scratch(struct Emitter* emitter, const struct Expr* divisor)
{
if (divisor->kind == EXPR_PRIMARY)
@@ -497,14 +478,9 @@ static bool divisor_uses_scratch(struct Emitter* emitter, const struct Expr* div
return true;
}
- // enum/struct members and unary minus fold to immediates; a binary or deref
- // divisor is left to the direct path (unsupported, as before)
return divisor->kind == EXPR_MEMBER || divisor->kind == EXPR_UNARY;
}
-// idiv divides rdx:rax by its operand, leaving the quotient in rax and the
-// remainder in rdx. The dividend arrives in dst; this loads it into rax, routes
-// an awkward divisor through r11, and runs idiv. It clobbers rax, rdx and r11.
static void emit_idiv(struct Emitter* emitter, const char* dst, struct Expr* divisor)
{
FILE* out = emitter->out;
@@ -519,9 +495,8 @@ static void emit_idiv(struct Emitter* emitter, const char* dst, struct Expr* div
return;
}
- // a divisor in rax must be saved before the dividend overwrites rax
- bool divisor_in_rax = divisor->kind == EXPR_PRIMARY
- && token_matches(resolve_register(emitter, divisor->primary.token), "rax");
+ bool divisor_in_rax = divisor->kind == EXPR_PRIMARY &&
+ token_matches(resolve_register(emitter, divisor->primary.token), "rax");
if (divisor_in_rax && strcmp(dst, "rax") != 0)
{
@@ -574,9 +549,6 @@ static void emit_divide(struct Emitter* emitter, struct AssignStatement* assign)
emit_division(emitter, dst, assign->value);
}
-// an expression can be evaluated into a register when it is a single term
-// (primary or member), or a left-associative chain of binary operators whose
-// right operands are plain operands (never a buffer or a nested binary)
static bool expr_supported(struct Emitter* emitter, struct Expr* expr)
{
switch (expr->kind)
@@ -610,9 +582,6 @@ static bool expr_supported(struct Emitter* emitter, struct Expr* expr)
return false;
}
-// dst = [address], extending narrower loads into the full register. Unsigned
-// loads zero-extend (movzx / a 32-bit mov); signed loads sign-extend (movsx,
-// or movsxd for a dword).
static void emit_load(struct Emitter* emitter, const char* dst, struct DerefExpr* deref)
{
FILE* out = emitter->out;
@@ -719,9 +688,6 @@ static const char* store_size_keyword(enum StoreSize size)
}
}
-// 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)
@@ -795,14 +761,10 @@ static bool value_is_float(struct Emitter* emitter, const struct Expr* expr)
return is_float_register(resolve_register(emitter, expr->primary.token));
}
-// floating point: xmm moves and arithmetic, conversions to/from general-purpose
-// registers, and float literals loaded from their .data slot
-static bool emit_float_assign(struct Emitter* emitter, struct AssignStatement* assign,
- struct Token target, bool target_float)
+static bool emit_float_assign(struct Emitter* emitter, struct AssignStatement* assign, struct Token target, bool target_float)
{
struct Expr* value = assign->value;
- // float store: ^ptr = xmm -> movsd [ptr], xmm
if (assign->target_deref)
{
if (assign->op.type != TOKEN_EQUAL || value->kind != EXPR_PRIMARY)
@@ -815,7 +777,6 @@ static bool emit_float_assign(struct Emitter* emitter, struct AssignStatement* a
return true;
}
- // float load: xmm = ^ptr -> movsd xmm, [ptr]
if (value->kind == EXPR_DEREF)
{
if (!target_float || assign->op.type != TOKEN_EQUAL)
@@ -896,7 +857,6 @@ static void emit_assign(struct Emitter* emitter, struct AssignStatement* assign)
return;
}
- // deref store or compound assignment: needs a plain operand, not a buffer or binary
const char* mnemonic = assign_mnemonic(assign->op.type);
bool value_is_buffer = assign->value->kind == EXPR_PRIMARY
&& is_buffer_name(emitter, assign->value->primary.token);
@@ -907,11 +867,11 @@ static void emit_assign(struct Emitter* emitter, struct AssignStatement* assign)
return;
}
- // adding or subtracting a constant zero (e.g. a struct field at offset 0) is a no-op
uint64_t folded;
- if (!assign->target_deref
- && (assign->op.type == TOKEN_PLUS_EQUAL || assign->op.type == TOKEN_MINUS_EQUAL)
- && fold_const(emitter->program, assign->value, &folded) && folded == 0)
+ if (!assign->target_deref &&
+ (assign->op.type == TOKEN_PLUS_EQUAL || assign->op.type == TOKEN_MINUS_EQUAL) &&
+ fold_const(emitter->program, assign->value, &folded) &&
+ folded == 0)
return;
if (assign->target_deref)
@@ -993,15 +953,12 @@ static void emit_call(struct Emitter* emitter, struct CallStatement* call)
}
static void emit_statement(struct Emitter* emitter, struct Statement* statement);
-
static void emit_block(struct Emitter* emitter, struct Statement* body, size_t count)
{
for (size_t i = 0; i < count; i += 1)
emit_statement(emitter, &body[i]);
}
-// ucomisd sets the flags like an unsigned compare, so float branches use the
-// unsigned jump family (ja/jae/jb/jbe) rather than the signed one
static const char* float_jump_if_false(enum TokenType comparison)
{
switch (comparison)
@@ -1028,10 +985,6 @@ static void emit_float_operand(struct Emitter* emitter, const struct Expr* expr)
fprintf(emitter->out, "%.*s", (int)token.length, token.start);
}
-// Emits the comparison for `left cmp right` and a jump to `target` taken when
-// the condition is false, so the code that follows runs when it is true. Both
-// if and while build on this. Returns false (after a TODO note) for a form that
-// isn't supported yet.
static bool emit_branch_test(struct Emitter* emitter, struct Expr* left,
struct Token comparison, struct Expr* right, const char* target)
{
@@ -1127,9 +1080,6 @@ static void emit_while(struct Emitter* emitter, struct WhileStatement* loop)
fprintf(emitter->out, "%s:\n", end);
}
-// renders a raw instruction's operand: registers, immediates, constants and
-// members reuse emit_operand; memory (^x -> [x], with an optional size) and
-// address math are handled here so operands like `^byte si` and `gdt + 2` work
static void emit_instruction_operand(struct Emitter* emitter, struct Expr* operand)
{
switch (operand->kind)
@@ -1162,7 +1112,6 @@ static void emit_instruction(struct Emitter* emitter, struct InstructionStatemen
fprintf(emitter->out, "\n");
}
-// the x86 condition-move suffix for a comparison, true or inverted
static const char* cmov_cc(enum TokenType comparison, bool when_true)
{
switch (comparison)
@@ -1177,23 +1126,21 @@ static const char* cmov_cc(enum TokenType comparison, bool when_true)
}
}
-// target = if_value if L cmp R else else_value, branchlessly via cmov. The
-// destination defaults to one source and conditionally takes the other, choosing
-// which to default so the target can alias either source safely.
static void emit_select(struct Emitter* emitter, struct SelectStatement* select)
{
FILE* out = emitter->out;
- if (select->if_value->kind != EXPR_PRIMARY || select->else_value->kind != EXPR_PRIMARY
- || cmov_cc(select->comparison.type, true) == NULL)
+ if (select->if_value->kind != EXPR_PRIMARY ||
+ select->else_value->kind != EXPR_PRIMARY ||
+ cmov_cc(select->comparison.type, true) == NULL)
{
fprintf(out, "\t; TODO: unsupported select\n");
return;
}
struct Token dst = resolve_register(emitter, select->target);
- struct Token a = resolve_register(emitter, select->if_value->primary.token);
- struct Token b = resolve_register(emitter, select->else_value->primary.token);
- bool dst_is_a = tokens_equal(dst, a);
+ struct Token a = resolve_register(emitter, select->if_value->primary.token);
+ struct Token b = resolve_register(emitter, select->else_value->primary.token);
+ bool dst_is_a = tokens_equal(dst, a);
if (!dst_is_a && !tokens_equal(dst, b))
fprintf(out, "\tmov %.*s, %.*s\n", (int)dst.length, dst.start, (int)b.length, b.start);
@@ -1204,11 +1151,9 @@ static void emit_select(struct Emitter* emitter, struct SelectStatement* select)
emit_operand(emitter, select->right);
fprintf(out, "\n");
- // if the destination already holds if_value, keep it when the condition is
- // false and move else_value in otherwise; otherwise the normal true form
struct Token source = dst_is_a ? b : a;
fprintf(out, "\tcmov%s %.*s, %.*s\n", cmov_cc(select->comparison.type, !dst_is_a),
- (int)dst.length, dst.start, (int)source.length, source.start);
+ (int)dst.length, dst.start, (int)source.length, source.start);
}
static void emit_statement(struct Emitter* emitter, struct Statement* statement)
@@ -1267,7 +1212,6 @@ static uint64_t proc_stack_size(struct Program* program, struct ProcDecl* proc)
if (total % 16 != 0)
total += 16 - (total % 16);
-
return total;
}
@@ -1346,17 +1290,16 @@ static struct FloatTable collect_floats(struct Program* program)
for (size_t i = 0; i < program->proc_count; i += 1)
for (size_t j = 0; j < program->procs[i].body_count; j += 1)
collect_floats_statement(&floats, &program->procs[i].body[j]);
-
return floats;
}
static void emit_proc_x86(struct Program* program, struct FloatTable* floats, struct ProcDecl* proc, bool is_entry, FILE* out)
{
struct Emitter emitter;
- emitter.program = program;
- emitter.proc = proc;
- emitter.floats = floats;
- emitter.out = out;
+ emitter.program = program;
+ emitter.proc = proc;
+ emitter.floats = floats;
+ emitter.out = out;
emitter.label_id = 0;
fprintf(out, "%.*s:\n", (int)proc->name.length, proc->name.start);
@@ -1380,19 +1323,12 @@ static void emit_proc_x86(struct Program* program, struct FloatTable* floats, st
}
}
-// ---------------------------------------------------------------------------
-// AArch64 target
-//
-// A separate instruction selector: the register model (logical rN -> xN-1, or
-// native x0.., w0.., sp, lr), 3-operand arithmetic, ldr/str memory, cmp + b.cond
-// control flow and svc #0 syscalls are all its own. Shares only the arch-neutral
-// helpers above (fold_const, resolve_token, the AST).
-// ---------------------------------------------------------------------------
-
static bool is_a64_register(struct Token token)
{
- // logical rN (mapped to xN-1)
- if (token.length >= 2 && token.start[0] == 'r' && token.start[1] >= '0' && token.start[1] <= '9')
+ if (token.length >= 2 &&
+ token.start[0] == 'r' &&
+ token.start[1] >= '0' &&
+ token.start[1] <= '9')
{
for (size_t i = 1; i < token.length; i += 1)
if (token.start[i] < '0' || token.start[i] > '9')
@@ -1400,14 +1336,18 @@ static bool is_a64_register(struct Token token)
return true;
}
- // native names x0..x30 / w0..w30
- if ((token.start[0] == 'x' || token.start[0] == 'w') && token.length >= 2
- && token.start[1] >= '0' && token.start[1] <= '9')
+ if ((token.start[0] == 'x' ||
+ token.start[0] == 'w') &&
+ token.length >= 2 &&
+ token.start[1] >= '0' &&
+ token.start[1] <= '9')
return true;
- return token_matches(token, "sp") || token_matches(token, "lr")
- || token_matches(token, "fp") || token_matches(token, "xzr")
- || token_matches(token, "wzr");
+ return token_matches(token, "sp") ||
+ token_matches(token, "lr") ||
+ token_matches(token, "fp") ||
+ token_matches(token, "xzr") ||
+ token_matches(token, "wzr");
}
static void emit_a64_reg(struct Emitter* emitter, struct Token token)
@@ -1424,8 +1364,6 @@ static void emit_a64_reg(struct Emitter* emitter, struct Token token)
fprintf(emitter->out, "%.*s", (int)r.length, r.start);
}
-// an operand in register or immediate position: a register maps through, and
-// anything that folds to a constant becomes an #immediate
static void emit_a64_operand(struct Emitter* emitter, struct Expr* expr)
{
if (expr->kind == EXPR_PRIMARY && is_a64_register(resolve_token(emitter, expr->primary.token)))
@@ -1459,7 +1397,6 @@ static const char* a64_binop(enum TokenType op)
}
}
-// branch taken when the comparison is false (to skip the guarded body)
static const char* a64_jump_if_false(enum TokenType comparison)
{
switch (comparison)
@@ -1475,7 +1412,6 @@ static const char* a64_jump_if_false(enum TokenType comparison)
}
static void emit_a64_statement(struct Emitter* emitter, struct Statement* statement);
-
static void emit_a64_block(struct Emitter* emitter, struct Statement* body, size_t count)
{
for (size_t i = 0; i < count; i += 1)
@@ -1486,7 +1422,6 @@ static void emit_a64_assign(struct Emitter* emitter, struct AssignStatement* ass
{
FILE* out = emitter->out;
- // store through a pointer: ^[size] p = value
if (assign->target_deref)
{
const char* store = assign->store_size == STORE_SIZE_BYTE ? "strb"
@@ -1501,7 +1436,6 @@ static void emit_a64_assign(struct Emitter* emitter, struct AssignStatement* ass
struct Expr* value = assign->value;
- // load through a pointer: dst = ^[size] p
if (assign->op.type == TOKEN_EQUAL && value->kind == EXPR_DEREF
&& value->deref.address->kind == EXPR_PRIMARY)
{
@@ -1515,7 +1449,6 @@ static void emit_a64_assign(struct Emitter* emitter, struct AssignStatement* ass
return;
}
- // three-operand arithmetic: dst = a op b
if (assign->op.type == TOKEN_EQUAL && value->kind == EXPR_BINARY)
{
const char* mnemonic = a64_binop(value->binary.op.type);
@@ -1534,7 +1467,6 @@ static void emit_a64_assign(struct Emitter* emitter, struct AssignStatement* ass
return;
}
- // compound assignment: dst op= value -> op dst, dst, value
if (assign->op.type != TOKEN_EQUAL)
{
const char* mnemonic = a64_binop(assign->op.type);
@@ -1553,7 +1485,6 @@ static void emit_a64_assign(struct Emitter* emitter, struct AssignStatement* ass
return;
}
- // plain move: dst = <register | immediate | symbol/address>
if (value->kind == EXPR_PRIMARY && is_a64_register(resolve_token(emitter, value->primary.token)))
{
fprintf(out, "\tmov ");
@@ -1573,7 +1504,6 @@ static void emit_a64_assign(struct Emitter* emitter, struct AssignStatement* ass
return;
}
- // a data label or other symbol: load its address/value through the pool
if (value->kind == EXPR_PRIMARY)
{
fprintf(out, "\tldr ");
@@ -1693,7 +1623,6 @@ static void emit_a64_instruction(struct Emitter* emitter, struct InstructionStat
fprintf(emitter->out, "\n");
}
-// the AArch64 condition code for a true comparison (used by csel)
static const char* a64_cond(enum TokenType comparison)
{
switch (comparison)
@@ -1708,8 +1637,6 @@ static const char* a64_cond(enum TokenType comparison)
}
}
-// target = if_value if L cmp R else else_value -> cmp; csel (one instruction,
-// no aliasing hazard)
static void emit_a64_select(struct Emitter* emitter, struct SelectStatement* select)
{
FILE* out = emitter->out;
@@ -1790,23 +1717,16 @@ static void emit_proc_aarch64(struct Program* program, struct FloatTable* floats
fprintf(out, "\tret\n");
}
-// Instruction selection lives behind the Arch seam: turning a procedure's
-// statements into a target's instructions (register model, mnemonics, stack
-// frames) is all an architecture decides. The Backend below is the orthogonal
-// axis — the assembler *syntax* (framing, data, labels) for a given arch.
struct Arch
{
- void (*emit_proc)(struct Program* program, struct FloatTable* floats,
- struct ProcDecl* proc, bool is_entry, FILE* out);
+ void (*emit_proc)(struct Program* program,
+ struct FloatTable* floats,
+ struct ProcDecl* proc,
+ bool is_entry, FILE* out);
};
-static const struct Arch x86_arch = {
- emit_proc_x86,
-};
-
-static const struct Arch aarch64_arch = {
- emit_proc_aarch64,
-};
+static const struct Arch x86_arch = { emit_proc_x86, };
+static const struct Arch aarch64_arch = { emit_proc_aarch64, };
struct Backend
{
@@ -1842,8 +1762,6 @@ static void nasm_data_section(FILE* out)
static void nasm_string_data(struct DataDecl decl, FILE* out)
{
- // the value lexeme keeps its quotes; NASM backtick strings interpret the
- // same escapes, so re-wrap the inner content
fprintf(out, "%.*s: db `%.*s`\n",
(int)decl.name.length, decl.name.start,
(int)(decl.value.length - 2), decl.value.start + 1);
@@ -1865,7 +1783,6 @@ static void nasm_global(struct Token name, FILE* out)
fprintf(out, "global %.*s\n", (int)name.length, name.start);
}
-// pad to 510 bytes and append the 0x55AA boot signature (little-endian dw)
static void nasm_boot_signature(FILE* out)
{
fprintf(out, "times 510-($-$$) db 0\n");
@@ -1894,9 +1811,7 @@ static void fasm_prologue(const struct Program* program, FILE* out)
fprintf(out, "use%u\n", config.bits);
}
else
- {
fprintf(out, "format ELF%s\n", config.bits == 64 ? "64" : "");
- }
}
static void fasm_constant(struct ConstDecl decl, FILE* out)
@@ -1911,8 +1826,6 @@ static void fasm_data_section(FILE* out)
fprintf(out, "section '.data' writeable\n");
}
-// fasm string literals are taken verbatim, so the escapes NASM would interpret
-// are expanded here into the byte values fasm expects (db "run", 10, "run").
static void fasm_string_data(struct DataDecl decl, FILE* out)
{
fprintf(out, "%.*s db ", (int)decl.name.length, decl.name.start);
@@ -2002,8 +1915,6 @@ static const struct Backend fasm_backend = {
fasm_boot_signature,
};
-// GNU as (the assembler for the ARM targets): different directives from the
-// Intel-syntax assemblers, but the same framing shape.
static void gas_prologue(const struct Program* program, FILE* out)
{
(void)program;
@@ -2024,8 +1935,6 @@ static void gas_data_section(FILE* out)
static void gas_string_data(struct DataDecl decl, FILE* out)
{
- // GNU as .ascii interprets the same C escapes NASM's backtick strings do,
- // so the inner content passes through unchanged (no trailing NUL, matching)
fprintf(out, "%.*s: .ascii \"%.*s\"\n",
(int)decl.name.length, decl.name.start,
(int)(decl.value.length - 2), decl.value.start + 1);
@@ -2051,7 +1960,6 @@ static void gas_global(struct Token name, FILE* out)
static void gas_boot_signature(FILE* out)
{
- // boot sectors are an x86/BIOS concept; not meaningful for the ARM targets
(void)out;
}
@@ -2066,22 +1974,18 @@ static const struct Backend gas_backend = {
gas_boot_signature,
};
-// the entry procedure drops its trailing `ret`. It is the [entry: NAME] proc if
-// given; otherwise a flat binary starts at its first proc.
static bool proc_is_entry(struct Program* program, size_t index)
{
struct Config config = program->config;
struct ProcDecl* proc = &program->procs[index];
if (config.has_entry)
- return proc->name.length == config.entry.length
- && memcmp(proc->name.start, config.entry.start, proc->name.length) == 0;
-
+ return proc->name.length == config.entry.length && memcmp(proc->name.start, config.entry.start, proc->name.length) == 0;
return config.format == OUTPUT_BIN && index == 0;
}
static void emit_data_block(struct Program* program, struct FloatTable* floats,
- const struct Backend* backend, FILE* out)
+ const struct Backend* backend, FILE* out)
{
for (size_t i = 0; i < program->data_count; i += 1)
backend->string_data(program->data_decls[i], out);
@@ -2105,7 +2009,6 @@ static void generate(struct Program* program, FILE* out, const struct Arch* arch
if (program->config.format == OUTPUT_BIN)
{
- // a flat binary executes from its origin, so code comes first, then data
for (size_t i = 0; i < program->proc_count; i += 1)
{
if (i > 0)
diff --git a/src/diag.c b/src/diag.c
index 6962046..cb1a057 100644
--- a/src/diag.c
+++ b/src/diag.c
@@ -30,10 +30,10 @@ void report_error(struct Source source, struct Token token, const char* message)
if (span == 0)
span = 1;
- const char* bold = colored() ? "\033[1m" : "";
+ const char* bold = colored() ? "\033[1m" : "";
const char* red = colored() ? "\033[31m" : "";
const char* blue = colored() ? "\033[34m" : "";
- const char* reset = colored() ? "\033[0m" : "";
+ const char* reset = colored() ? "\033[0m" : "";
int gutter = snprintf(NULL, 0, "%u", token.line);
@@ -55,9 +55,9 @@ void report_error(struct Source source, struct Token token, const char* message)
void report_error_message(const char* message)
{
- const char* bold = colored() ? "\033[1m" : "";
+ const char* bold = colored() ? "\033[1m" : "";
const char* red = colored() ? "\033[31m" : "";
- const char* reset = colored() ? "\033[0m" : "";
+ const char* reset = colored() ? "\033[0m" : "";
fprintf(stderr, "%s%serror:%s %s%s%s\n", bold, red, reset, bold, message, reset);
}
diff --git a/src/parser.c b/src/parser.c
index b0e049c..1815562 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -279,8 +279,6 @@ static struct Expr* parse_postfix(struct Parser* parser)
while (match_token(parser, TOKEN_DOT))
{
- // an identifier is a member (data.len); an integer is a register size
- // suffix (r1.64), meaningful with the logical_registers extension
if (!check(parser, TOKEN_IDENTIFIER) && !check(parser, TOKEN_INTEGER))
{
error_at(parser, parser->current, "expected a member name or size after '.'");
diff --git a/src/sema.c b/src/sema.c
index 01fe644..342fe44 100644
--- a/src/sema.c
+++ b/src/sema.c
@@ -180,14 +180,14 @@ static void ref_error(struct RefCheck* check, struct Token token, const char* fo
static bool is_arch_register(struct Token token)
{
static const char* names[] = {
- "rax", "eax", "ax", "al", "ah",
- "rbx", "ebx", "bx", "bl", "bh",
- "rcx", "ecx", "cx", "cl", "ch",
- "rdx", "edx", "dx", "dl", "dh",
- "rsi", "esi", "si", "sil",
- "rdi", "edi", "di", "dil",
- "rbp", "ebp", "bp", "bpl",
- "rsp", "esp", "sp", "spl",
+ "rax", "eax", "ax", "al", "ah",
+ "rbx", "ebx", "bx", "bl", "bh",
+ "rcx", "ecx", "cx", "cl", "ch",
+ "rdx", "edx", "dx", "dl", "dh",
+ "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",
@@ -411,8 +411,6 @@ static void check_target(struct RefCheck* check, struct Token target)
ref_error(check, target, "cannot assign to '%.*s': not a register", (int)target.length, target.start);
}
-// a stack size must be a compile-time constant: integer/char literals, other
-// constants, enum values, struct sizes/offsets, and arithmetic over them
static void check_stack_size(struct RefCheck* check, struct Expr* expr)
{
switch (expr->kind)
@@ -427,9 +425,9 @@ static void check_stack_size(struct RefCheck* check, struct Expr* expr)
case EXPR_MEMBER:
{
const struct Expr* object = expr->member.object;
- if (object->kind == EXPR_PRIMARY
- && (find_enum(check, object->primary.token) != NULL
- || find_struct(check, object->primary.token) != NULL))
+ if (object->kind == EXPR_PRIMARY &&
+ (find_enum(check, object->primary.token) != NULL ||
+ find_struct(check, object->primary.token) != NULL))
check_expr(check, expr);
else
ref_error(check, first_token(expr), "stack size must be a constant");
@@ -500,9 +498,7 @@ static void check_statement(struct RefCheck* check, struct Statement* statement)
case STATEMENT_SYSCALL:
break;
case STATEMENT_INSTRUCTION:
- // a raw instruction is an escape hatch; its operands may name asm
- // symbols or registers hdass does not model, so leave them to the
- // assembler rather than flagging them as undefined
+ // escape hatch
break;
case STATEMENT_SELECT:
check_target(check, statement->select.target);
@@ -533,7 +529,6 @@ static bool check_references(struct Source source, struct Program* program)
bool analyze_program(struct Source source, struct Program* program)
{
bool ok = true;
-
if (!check_duplicate_names(source, program))
ok = false;
if (!check_entry_point(source, program))
@@ -542,6 +537,5 @@ bool analyze_program(struct Source source, struct Program* program)
ok = false;
if (!check_references(source, program))
ok = false;
-
return ok;
}