rutile/compiler/codegen.c
2025-01-12 18:20:42 -03:00

101 lines
2.2 KiB
C

#define _POSIX_C_SOURCE 200809L
#include <unistd.h>
#include <spawn.h>
#include <sys/wait.h>
#include "codegen.h"
#include "cgC.h"
#include "messages.h"
#include "libs/stb_ds.h"
/* (Std)In --> process --> (Std)Out */
void
spawn_with_iofp(const char *path, char *const *argv,
pid_t *pid, FILE **in, FILE **out)
{
int irp[2], asmp[2];
posix_spawn_file_actions_t fileacts;
posix_spawn_file_actions_init(&fileacts);
if (in != nil) {
/* the "in" pipe */
if (pipe(irp) < 0)
fatal(nil, nil, "could not open pipe");
posix_spawn_file_actions_addclose(&fileacts, irp[1]);
posix_spawn_file_actions_adddup2(&fileacts, irp[0], STDIN_FILENO);
}
if (out != nil) {
/* the "out" pipe */
if (pipe(asmp) < 0)
fatal(nil, nil, "could not open pipe");
posix_spawn_file_actions_addclose(&fileacts, asmp[0]);
posix_spawn_file_actions_adddup2(&fileacts, asmp[1], STDOUT_FILENO);
}
if (posix_spawn(pid, path, &fileacts, nil, argv, nil) != 0)
fatal(nil, nil, "posix_spawn failed");
posix_spawn_file_actions_destroy(&fileacts);
if (in != nil) {
close(irp[0]);
if ((*in = fdopen(irp[1], "wb")) == nil)
fatal(nil, nil, "fdopen fail");
}
if (out != nil) {
close(asmp[1]);
if ((*out = fdopen(asmp[0], "rb")) == nil)
fatal(nil, nil, "fdopen fail");
}
}
void
process_wait(pid_t pid)
{
int pstat;
waitpid(pid, &pstat, 0);
if (!WIFEXITED(pstat))
fatal(nil, nil, "qbe crashed");
/* did not crash, read return status */
int exitc;
if ((exitc = WEXITSTATUS(pstat)) != 0)
fatal(nil, nil, "qbe exited with non-zero status %d", exitc);
}
CodegenCtx *
codegen_new(Compiler *cm, enum CodegenBackends backend)
{
CodegenCtx *ctx = calloc(1, sizeof(*ctx));
ctx->ext_pid = ctx->ld_pid = -1;
ctx->backend = backend;
ctx->cctx = cm;
sh_new_arena(ctx->strings);
shdefault(ctx->strings, -1);
return ctx;
}
void
codegen_destroy(CodegenCtx *cgctx)
{
if (cgctx->ext_pid != -1)
process_wait(cgctx->ext_pid);
if (cgctx->ld_pid != -1)
process_wait(cgctx->ld_pid);
shfree(cgctx->strings);
free(cgctx);
}
void
codegen(CodegenCtx *cgctx, Ast *program)
{
switch (cgctx->backend) {
case CgBackendC:
cgC(&(CodegenC){.cgctx = cgctx, .indent = 2}, program);
break;
case CgBackendLibGccJit:
fatal(nil, nil, "libgccjit backend not implemented yet");
break;
}
}