aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2026-09-06 00:52:48 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2026-09-06 02:29:44 +0200
commitf382f410b367d7ce83725c7b8b56f7672cee0b13 (patch)
tree2bad0529b566914dddf5723988089dc8a94b2a25
parent61217a063ee120e427bbba470c7a2c6d5eb45900 (diff)
downloadprc-f382f410b367d7ce83725c7b8b56f7672cee0b13.tar.gz
Add prc front-end
-rw-r--r--src/prc/CMakeLists.txt12
-rw-r--r--src/prc/main.c358
2 files changed, 370 insertions, 0 deletions
diff --git a/src/prc/CMakeLists.txt b/src/prc/CMakeLists.txt
new file mode 100644
index 0000000..e685a15
--- /dev/null
+++ b/src/prc/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_executable(${PROJECT_NAME}
+ main.c
+)
+
+target_compile_definitions(${PROJECT_NAME} PRIVATE
+ PREFIX="${CMAKE_INSTALL_PREFIX}")
+target_compile_options(${PROJECT_NAME} PRIVATE -g -Wall -pedantic)
+set_target_properties(${PROJECT_NAME} PROPERTIES C_STANDARD 99 C_EXTENSIONS OFF)
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ target_compile_options(${PROJECT_NAME} PRIVATE -Og)
+endif()
+install(TARGETS ${PROJECT_NAME})
diff --git a/src/prc/main.c b/src/prc/main.c
new file mode 100644
index 0000000..a3b9511
--- /dev/null
+++ b/src/prc/main.c
@@ -0,0 +1,358 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct input
+{
+ const char **v;
+ size_t n;
+};
+
+struct rwinput
+{
+ const char **v;
+ size_t n;
+};
+
+struct dstr
+{
+ char *s;
+};
+
+struct state
+{
+ struct input sources, incs, libs, ldirs;
+ struct rwinput objs;
+ const char *prefix, *name, *out;
+ const struct arg *arg;
+ int componly;
+};
+
+struct arg
+{
+ const char *s;
+ int (*f)(struct state *, const char *);
+
+ enum
+ {
+ NOVAL,
+ SPACEVAL = 1,
+ EQVAL = 1 << 1,
+ JOINVAL = 1 << 2
+ } v;
+};
+
+static int comp(struct state *s, const char *val)
+{
+ s->componly = 1;
+ return 0;
+}
+
+static int ldflag(struct state *s, const char *val)
+{
+ fprintf(stderr, "%s: TODO, val=%s\n", __func__, val);
+ return -1;
+}
+
+static int optim(struct state *s, const char *val)
+{
+ return 0;
+}
+
+static int out(struct state *s, const char *val)
+{
+ s->out = val;
+ return 0;
+}
+
+static int addinput(struct state *s, struct input *i, const char *val)
+{
+ size_t n = i->n + 1;
+ const char **v = realloc(i->v, n * sizeof *v);
+
+ if (!v)
+ {
+ perror("realloc(3)");
+ return -1;
+ }
+
+ v[i->n++] = val;
+ i->v = v;
+ s->arg = NULL;
+ return 0;
+}
+
+static int inc(struct state *s, const char *val)
+{
+ return addinput(s, &s->incs, val);
+}
+
+static int lib(struct state *s, const char *val)
+{
+ return addinput(s, &s->libs, val);
+}
+
+static int ldir(struct state *s, const char *val)
+{
+ return addinput(s, &s->ldirs, val);
+}
+
+static int opt(struct state *s, const struct arg *a, const char *arg)
+{
+ const struct arg *prev = s->arg;
+ const char *v = arg + strlen(a->s);
+
+ if (prev && prev->v)
+ {
+ fprintf(stderr, "%s: option '%s' requires a value\n", s->name, prev->s);
+ return -1;
+ }
+ else if (*v)
+ {
+ if (!(a->v & JOINVAL))
+ {
+ fprintf(stderr, "%s: unrecognized command-line option '%s'\n",
+ s->name, arg);
+ return -1;
+ }
+ }
+ else if (a->v & SPACEVAL)
+ {
+ s->arg = a;
+ return 0;
+ }
+ else
+ v = NULL;
+
+ return a->f(s, v);
+}
+
+static int addfile(struct state *s, const char *arg)
+{
+ return addinput(s, &s->sources, arg);
+}
+
+static int arg(struct state *s, const char *arg, int rem)
+{
+ static const struct arg args[] =
+ {
+ {"-c", comp},
+ {"-O", optim, JOINVAL},
+ {"-Wl,", ldflag, JOINVAL},
+ {"-o", out, SPACEVAL | JOINVAL},
+ {"-I", inc, SPACEVAL | JOINVAL},
+ {"-l", lib, SPACEVAL | JOINVAL},
+ {"-L", ldir, SPACEVAL | JOINVAL}
+ };
+
+ const struct arg *prev = s->arg;
+
+ for (size_t i = 0; i < sizeof args / sizeof *args; i++)
+ {
+ const struct arg *a = &args[i];
+
+ if (!strncmp(arg, a->s, strlen(a->s)))
+ return opt(s, a, arg);
+ }
+
+ if (prev)
+ {
+ if (*arg != '-')
+ return prev->f(s, arg);
+ }
+ else
+ return addfile(s, arg);
+
+ return 0;
+}
+
+static void print_input(const struct input *in)
+{
+ fprintf(stderr, ": [");
+
+ for (size_t i = 0; i < in->n; i++)
+ {
+ fprintf(stderr, "%s", in->v[i]);
+
+ if (i + 1 < in->n)
+ fprintf(stderr, ", ");
+ }
+
+ fprintf(stderr, "]\n");
+}
+
+static int append(struct dstr *d, const char *fmt, ...)
+{
+ int ret = 1, n;
+ char *s;
+ va_list ap;
+ size_t len = d->s ? strlen(d->s) : 0;
+
+ va_start(ap, fmt);
+
+ if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0)
+ {
+ fprintf(stderr, "vsnprintf(3) failed\n");
+ goto end;
+ }
+ else if (!(s = realloc(d->s, len + n + 1)))
+ {
+ perror("realloc(3)");
+ goto end;
+ }
+
+ va_end(ap);
+ va_start(ap, fmt);
+ vsprintf(s + len, fmt, ap);
+ d->s = s;
+ ret = 0;
+
+end:
+ va_end(ap);
+ return ret;
+}
+
+static void free_dstr(struct dstr *d)
+{
+ free(d->s);
+}
+
+static int as(struct state *s, const char *src)
+{
+ int ret = -1;
+ struct dstr d = {0};
+
+ if (append(&d, "as %s"))
+ goto end;
+
+ ret = 0;
+
+end:
+ free_dstr(&d);
+ return ret;
+}
+
+static int qbe(struct state *s, const char *src)
+{
+ fprintf(stderr, "%s: TODO\n", __func__);
+ return -1;
+}
+
+static int prc1(struct state *s, const char *src)
+{
+ int ret = -1;
+ struct dstr d = {0};
+ const struct input *incs = &s->incs;
+
+ if (append(&d, "%s/libexec/prc1 %s", s->prefix, src))
+ goto end;
+
+ for (size_t i = 0; i < incs->n; i++)
+ if (append(&d, " -I %s", incs->v[i]))
+ return -1;
+
+ ret = 0;
+
+end:
+ free_dstr(&d);
+ return ret;
+}
+
+static int runtool(struct state *s, const char *src)
+{
+ static const struct t
+ {
+ const char *suffix;
+ int (*f)(struct state *, const char *);
+ } tb[] =
+ {
+ {"o", as},
+ {"obj", as},
+ {"qbe", qbe},
+ };
+
+ const char *sep = strchr(src, '.');
+
+ if (sep)
+ for (size_t i = 0; i < sizeof tb / sizeof *tb; i++)
+ {
+ const char *ext = sep + 1;
+ const struct t *t = &tb[i];
+
+ if (!strcmp(ext, t->suffix))
+ return t->f(s, src);
+ }
+
+ return prc1(s, src);
+}
+
+static int reconcile(struct state *s)
+{
+ fprintf(stderr, "sources");
+ print_input(&s->sources);
+ fprintf(stderr, "incs");
+ print_input(&s->incs);
+ fprintf(stderr, "ldirs");
+ print_input(&s->ldirs);
+ fprintf(stderr, "libs");
+ print_input(&s->libs);
+ fprintf(stderr, "out: %s\n", s->out);
+
+ for (size_t i = 0; i < s->sources.n; i++)
+ if (runtool(s, s->sources.v[i]))
+ return -1;
+
+ return 0;
+}
+
+static void free_input(struct input *i)
+{
+ free(i->v);
+}
+
+static void free_state(struct state *s)
+{
+ free_input(&s->sources);
+ free_input(&s->incs);
+ free_input(&s->libs);
+ free_input(&s->ldirs);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+ struct state s =
+ {
+ .name = *argv,
+ .out = "a.out",
+ .prefix = getenv("PREFIX")
+ };
+
+ if (argc == 1)
+ {
+ fprintf(stderr, "%s [options ...] file...\n", *argv);
+ goto end;
+ }
+ else if (!s.prefix)
+ s.prefix = PREFIX;
+
+ for (int i = 1; i < argc; i++)
+ if (arg(&s, argv[i], argc - i))
+ goto end;
+
+ if (s.arg)
+ {
+ fprintf(stderr, "%s: command-line argument '%s' requires an argument\n",
+ s.name, s.arg->s);
+ goto end;
+ }
+ else if (reconcile(&s))
+ goto end;
+
+ ret = EXIT_SUCCESS;
+end:
+ free_state(&s);
+ return ret;
+}