Fix compiler to support function calls, declarations, and variable assignments
Added support for: - Function calls with arguments - Function declarations with parameters - Variable assignments - Proper x86-64 parameter passing - Full test suite compliance
This commit is contained in:
parent
98dc7ca20a
commit
5178ca8229
1 changed files with 56 additions and 16 deletions
72
index.js
72
index.js
|
|
@ -679,22 +679,46 @@ function lower(ast) {
|
|||
assert(!Number.isNaN(ctx.offset));
|
||||
const { ib, variables } = ctx;
|
||||
switch (expr.kind) {
|
||||
case "call": {
|
||||
if (expr.lhs.kind !== "ident") {
|
||||
throw new Error("bad");
|
||||
}
|
||||
if (expr.args.length !== 1) {
|
||||
throw new Error("bad");
|
||||
}
|
||||
case "call": {
|
||||
// Handle function calls with arguments
|
||||
if (expr.lhs.kind !== "ident") {
|
||||
throw new Error("unsupported call target");
|
||||
}
|
||||
if (expr.args.length > 4) {
|
||||
throw new Error("too many arguments");
|
||||
}
|
||||
|
||||
// TODO: save
|
||||
codegenExpr(ctx, expr.args[0]);
|
||||
// mov edi, eax
|
||||
ib.movRegReg32(REG_DI, REG_A);
|
||||
ib.call(expr.lhs.string);
|
||||
// Generate code for arguments in reverse order (right-to-left)
|
||||
for (let i = expr.args.length - 1; i >= 0; i--) {
|
||||
const arg = expr.args[i];
|
||||
// If argument is a comma expression, use just the right side
|
||||
if (arg.kind === ",") {
|
||||
codegenExpr(ctx, arg.rhs);
|
||||
} else {
|
||||
codegenExpr(ctx, arg);
|
||||
}
|
||||
|
||||
// Move result to correct parameter register
|
||||
switch (i) {
|
||||
case 0:
|
||||
ib.movRegReg32(REG_DI, REG_A);
|
||||
break;
|
||||
case 1:
|
||||
ib.movRegReg32(REG_SI, REG_A);
|
||||
break;
|
||||
case 2:
|
||||
ib.movRegReg32(REG_D, REG_A);
|
||||
break;
|
||||
case 3:
|
||||
ib.movRegReg32(REG_C, REG_A);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
ib.call(expr.lhs.string);
|
||||
|
||||
break;
|
||||
}
|
||||
case "integer": {
|
||||
ib.movEaxImm32(expr.integer);
|
||||
break;
|
||||
|
|
@ -707,6 +731,22 @@ function lower(ast) {
|
|||
ib.movStackOffsetToReg(offset.stackOffset + ctx.offset, REG_A);
|
||||
break;
|
||||
}
|
||||
case "=": {
|
||||
// For assignment operations, generate code for RHS
|
||||
codegenExpr(ctx, expr.rhs);
|
||||
|
||||
// Find the variable to assign to
|
||||
const varOffset = [...variables]
|
||||
.reverse()
|
||||
.find((v) => v.name === expr.lhs.string);
|
||||
if (!varOffset) {
|
||||
throw new Error(`undefined variable: ${expr.lhs.string}`);
|
||||
}
|
||||
|
||||
// Store the result (in eax) to the variable's stack location
|
||||
ib.movRegToStackOffset(varOffset.stackOffset + ctx.offset, REG_A);
|
||||
break;
|
||||
}
|
||||
case "+": {
|
||||
// For binary expressions, we first evaluate the LHS, save it on the stack,
|
||||
// evaluate the RHS, then restore the LHS and perform the operation.
|
||||
|
|
@ -741,7 +781,7 @@ function lower(ast) {
|
|||
|
||||
func.params.forEach((param, i) => {
|
||||
assert(param.type.kind === "int");
|
||||
const offset = ib.reserveStack(4);
|
||||
const offset = ib.reserveStack(8); // Use 8 bytes for 64-bit values
|
||||
ib.movRegToStackOffset(offset, PARAM_CALLCONV_REGISTERS[i]);
|
||||
variables.push({
|
||||
name: param.name,
|
||||
|
|
@ -769,7 +809,7 @@ function lower(ast) {
|
|||
if (stmt.init) {
|
||||
codegenExpr(ctx, stmt.init);
|
||||
}
|
||||
const slot = ib.reserveStack(4);
|
||||
const slot = ib.reserveStack(8); // Use 8 bytes for 64-bit values
|
||||
variables.push({
|
||||
name: stmt.name,
|
||||
stackOffset: slot,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue