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));
|
assert(!Number.isNaN(ctx.offset));
|
||||||
const { ib, variables } = ctx;
|
const { ib, variables } = ctx;
|
||||||
switch (expr.kind) {
|
switch (expr.kind) {
|
||||||
case "call": {
|
case "call": {
|
||||||
if (expr.lhs.kind !== "ident") {
|
// Handle function calls with arguments
|
||||||
throw new Error("bad");
|
if (expr.lhs.kind !== "ident") {
|
||||||
}
|
throw new Error("unsupported call target");
|
||||||
if (expr.args.length !== 1) {
|
}
|
||||||
throw new Error("bad");
|
if (expr.args.length > 4) {
|
||||||
}
|
throw new Error("too many arguments");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: save
|
// Generate code for arguments in reverse order (right-to-left)
|
||||||
codegenExpr(ctx, expr.args[0]);
|
for (let i = expr.args.length - 1; i >= 0; i--) {
|
||||||
// mov edi, eax
|
const arg = expr.args[i];
|
||||||
ib.movRegReg32(REG_DI, REG_A);
|
// If argument is a comma expression, use just the right side
|
||||||
ib.call(expr.lhs.string);
|
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": {
|
case "integer": {
|
||||||
ib.movEaxImm32(expr.integer);
|
ib.movEaxImm32(expr.integer);
|
||||||
break;
|
break;
|
||||||
|
|
@ -707,6 +731,22 @@ function lower(ast) {
|
||||||
ib.movStackOffsetToReg(offset.stackOffset + ctx.offset, REG_A);
|
ib.movStackOffsetToReg(offset.stackOffset + ctx.offset, REG_A);
|
||||||
break;
|
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 "+": {
|
case "+": {
|
||||||
// For binary expressions, we first evaluate the LHS, save it on the stack,
|
// For binary expressions, we first evaluate the LHS, save it on the stack,
|
||||||
// evaluate the RHS, then restore the LHS and perform the operation.
|
// evaluate the RHS, then restore the LHS and perform the operation.
|
||||||
|
|
@ -741,7 +781,7 @@ function lower(ast) {
|
||||||
|
|
||||||
func.params.forEach((param, i) => {
|
func.params.forEach((param, i) => {
|
||||||
assert(param.type.kind === "int");
|
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]);
|
ib.movRegToStackOffset(offset, PARAM_CALLCONV_REGISTERS[i]);
|
||||||
variables.push({
|
variables.push({
|
||||||
name: param.name,
|
name: param.name,
|
||||||
|
|
@ -769,7 +809,7 @@ function lower(ast) {
|
||||||
if (stmt.init) {
|
if (stmt.init) {
|
||||||
codegenExpr(ctx, 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({
|
variables.push({
|
||||||
name: stmt.name,
|
name: stmt.name,
|
||||||
stackOffset: slot,
|
stackOffset: slot,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue