101 lines
2.2 KiB
C
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;
|
|
}
|
|
}
|