From 4b4deba3fdc29cd4a78dc506d76db49fefa00cb6 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 14 Nov 2017 23:21:39 +0000 Subject: [PATCH] cc: add a frontend Not yet tested! --- Applications/SmallC/frontend.c | 526 +++++++++++++++++++++++++++++++++ 1 file changed, 526 insertions(+) create mode 100644 Applications/SmallC/frontend.c diff --git a/Applications/SmallC/frontend.c b/Applications/SmallC/frontend.c new file mode 100644 index 00000000..af93575a --- /dev/null +++ b/Applications/SmallC/frontend.c @@ -0,0 +1,526 @@ +/* + * It's easiest to think of what cc does as a sequence of four + * conversions. Each conversion produces the inputs to the next step + * and the number of types is reduced. If the step is the final + * step for the conversion then the file is generated with the expected + * name but if it will be consumed by a later stage it is a temporary + * scratch file. + * + * Stage 1: (-c -o overrides object name) + * + * Ending Action + * $1.S preprocessor - may make $1.s + * $1.s nothing + * $1.c preprocessor, may make $1.% or /dev/tty + * $1.o nothing + * $1.a nothing (library) + * + * Stage 2: (not -E) + * + * Ending Action + * $1.s nothing + * $1.% cc, opt - make $1.s + * $1.o nothing + * $1.a nothing (library) + * + * Stage 3: (not -E or -S) + * + * Ending Action + * $1.s assembler - makes $1.o + * $1.o nothing + * $1.a nothing (library) + * + * Stage 4: (run if no -c -E -S) + * + * ld [each .o|.a in order] [each -l lib in order] -lc + * (with -b -o $1 etc) + * + * TODO: + * + * Platform specifics + * Search library paths for libraries (or pass to ld and make ld do it) + * Turn on temp removal once confident + * Split I/D + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CMD_AS "/bin/as" +#define CMD_CC "/usr/lib/cc" +#define CMD_COPT "/usr/lib/copt" +#define COPT_FILE "/usr/lib/cc-copt" +#define CMD_LD "/bin/ld" +#define CMD_CPP "/usr/lib/cpp" +#define CRT0 "/usr/lib/crt0.o" + +struct obj { + struct obj *next; + char *name; + uint8_t type; +#define TYPE_S 1 +#define TYPE_C 2 +#define TYPE_s 3 +#define TYPE_C_pp 4 +#define TYPE_O 5 +#define TYPE_A 6 + uint8_t used; +}; + +struct objhead { + struct obj *head; + struct obj *tail; +}; + +struct objhead objlist; +struct objhead liblist; +struct objhead inclist; +struct objhead deflist; +struct objhead libpathlist; + +int keep_temp; +int last_phase = 4; +int only_one_input; +char *target; +int strip; +int c_files; +int standalone; + +#define MAXARG 64 + +int arginfd, argoutfd; +char *arglist[MAXARG]; +char **argptr; +char *rmlist[MAXARG]; +char **rmptr = rmlist; + +static void remove_temporaries(void) +{ + char **p = rmlist; + while (p < rmptr) { + if (keep_temp == 0) + printf("remove %s\n", *p); + free(*p++); + } + rmptr = rmlist; +} + +static void fatal(void) +{ + remove_temporaries(); + exit(1); +} + +static void memory(void) +{ + fprintf(stderr, "cc: out of memory.\n"); + fatal(); +} + +static void append_obj(struct objhead *h, char *p, uint8_t type) +{ + struct obj *o = malloc(sizeof(struct obj)); + if (o == NULL) + memory(); + o->name = p; + o->next = NULL; + o->used = 0; + o->type = type; + if (h->tail) + h->tail->next = o; + else { + h->tail = o; + h->head = o; + } +} + +static char *pathmod(char *p, char *f, char *t, int rmif) +{ + char *x = strrchr(p, '.'); + if (x == NULL) { + fprintf(stderr, "cc: no extension on '%s'.\n", p); + fatal(); + } + if (strcmp(x, f)) { + fprintf(stderr, "cc: internal got '%s' expected '%s'.\n", + p, t); + fatal(); + } + strcpy(x, t); + if (rmif != last_phase) { + *rmptr = strdup(p); + if (*rmptr++ == NULL) + memory(); + } + return p; +} + +static void add_argument(char *p) +{ + if (argptr == &arglist[MAXARG]) { + fprintf(stderr, "cc: too many arguments to command.\n"); + fatal(); + } + *argptr++ = p; +} + +static void add_argument_list(char *header, struct objhead *h) +{ + struct obj *i = h->head; + while (i) { + if (header) + add_argument(header); + add_argument(i->name); + i->used = 1; + i = i->next; + } +} + +static void run_command(void) +{ + pid_t pid, p; + int status; + + fflush(stdout); + + pid = fork(); + if (pid == -1) { + perror("fork"); + fatal(); + } + if (pid == 0) { + if (arginfd != -1) { + dup2(arginfd, 0); + close(arginfd); + } + if (argoutfd != -1) { + dup2(argoutfd, 1); + close(argoutfd); + } + execv(arglist[0], arglist); + perror("execv"); + exit(255); + } + if (arginfd) + close(arginfd); + if (argoutfd) + close(argoutfd); + while ((p = waitpid(pid, &status, 0)) != pid) { + if (p == -1) { + perror("waitpid"); + fatal(); + } + } + if (WIFSIGNALED(status) || WEXITSTATUS(status)) + fatal(); +} + +static void redirect_in(const char *p) +{ + arginfd = open(p, O_RDONLY); + if (arginfd == -1) { + perror(p); + fatal(); + } +} + +static void redirect_out(const char *p) +{ + argoutfd = open(p, O_WRONLY | O_CREAT, 0666); + if (argoutfd == -1) { + perror(p); + fatal(); + } +} + +static void build_arglist(char *p) +{ + arginfd = -1; + argoutfd = -1; + argptr = arglist; + add_argument(p); +} + +void convert_s_to_o(char *path) +{ + build_arglist(CMD_AS); + add_argument(path); + run_command(); + pathmod(path, ".s", ".o", 3); /* 3 ?? check */ +} + +void convert_c_to_s(char *path) +{ + char *tmp; + build_arglist(CMD_CC); + redirect_in(path); + tmp = strdup(pathmod(path, ".%", ".@", 0)); + if (tmp == NULL) + memory(); + redirect_out(tmp); + run_command(); + build_arglist(CMD_COPT); + add_argument(COPT_FILE); + redirect_in(tmp); + redirect_out(pathmod(path, ".%", ".s", 2)); + free(tmp); +} + +void convert_S_to_s(char *path) +{ + build_arglist(CMD_CPP); + redirect_in(path); + redirect_out(pathmod(path, ".S", ".s", 1)); + run_command(); +} + +void preprocess_c(char *path) +{ + build_arglist(CMD_CPP); + + add_argument_list("-I", &inclist); + add_argument_list("-D", &deflist); + add_argument(path); + /* Weird one .. -E goes to stdout */ + if (last_phase != 1) + redirect_out(pathmod(path, ".c", ".%", -1)); + run_command(); +} + +void link_phase(void) +{ + build_arglist(CMD_LD); + add_argument("-b"); + if (strip) + add_argument("-s"); + add_argument("-o"); + add_argument(target); + if (!standalone) + add_argument(CRT0); + add_argument_list(NULL, &objlist); + add_argument_list(NULL, &liblist); +} + +void sequence(struct obj *i) +{ + printf("Processing %s %d\n", i->name, i->type); + if (i->type == TYPE_S) { + convert_S_to_s(i->name); + i->type = TYPE_s; + i->used = 1; + } + if (i->type == TYPE_C) { + preprocess_c(i->name); + i->type = TYPE_C_pp; + i->used = 1; + } + if (last_phase == 1) + return; + printf("Processing %s %d\n", i->name, i->type); + if (i->type == TYPE_C_pp) { + convert_c_to_s(i->name); + i->type = TYPE_s; + i->used = 1; + } + if (last_phase == 2) + return; + printf("Processing %s %d\n", i->name, i->type); + if (i->type == TYPE_s) { + convert_s_to_o(i->name); + i->type = TYPE_O; + i->used = 1; + } +} + +void processing_loop(void) +{ + struct obj *i = objlist.head; + while (i) { + sequence(i); + remove_temporaries(); + i = i->next; + } + if (last_phase == 3) + return; + link_phase(); +} + +void unused_files(void) +{ + struct obj *i = objlist.head; + while (i) { + if (!i->used) + fprintf(stderr, "cc: warning file %s unused.\n", + i->name); + i = i->next; + } +} + +void usage(void) +{ + fprintf(stderr, "usage...\n"); + fatal(); +} + +char **add_macro(char **p) +{ + if ((*p)[2]) + append_obj(&deflist, *p + 2, 0); + else + append_obj(&deflist, *++p, 0); + return p; +} + +char **add_library(char **p) +{ + if ((*p)[2]) + append_obj(&liblist, *p + 2, TYPE_A); + else + append_obj(&liblist, *++p, TYPE_A); + return p; +} + +char **add_library_path(char **p) +{ + if ((*p)[2]) + append_obj(&libpathlist, *p + 2, 0); + else + append_obj(&libpathlist, *++p, 0); + return p; +} + + +char **add_includes(char **p) +{ + if ((*p)[2]) + append_obj(&inclist, *p + 2, 0); + else + append_obj(&inclist, *++p, 0); + return p; +} + + +void dunno(const char *p) +{ + fprintf(stderr, "cc: don't know what to do with '%s'.\n", p); + fatal(); +} + +void add_file(char *p) +{ + char *x = strrchr(p, '.'); + if (x == NULL) + dunno(p); + switch (x[1]) { + case 'a': + append_obj(&objlist, p, TYPE_A); + break; + case 's': + append_obj(&objlist, p, TYPE_s); + break; + case 'S': + append_obj(&objlist, p, TYPE_S); + break; + case 'c': + append_obj(&objlist, p, TYPE_C); + c_files++; + break; + case 'o': + append_obj(&objlist, p, TYPE_O); + break; + default: + dunno(p); + } +} + +void one_input(void) +{ + fprintf(stderr, "cc: too many files for -E\n"); + fatal(); +} + +void uniopt(char *p) +{ + if (p[2]) + usage(); +} + +int main(int argc, char *argv[]) +{ + char **p = argv; + signal(SIGCHLD, SIG_DFL); + + while (*++p) { + /* filename or option ? */ + if (**p != '-') { + add_file(*p); + continue; + } + switch ((*p)[1]) { + /* Don't link */ + case 'c': + uniopt(*p); + last_phase = 3; + break; + /* Don't assemble */ + case 'S': + uniopt(*p); + last_phase = 2; + break; + /* Only pre-process */ + case 'E': + uniopt(*p); + last_phase = 1; + only_one_input = 1; + break; + case 'l': + p = add_library(p); + break; + case 'I': + p = add_includes(p); + break; + case 'L': + p = add_library_path(p); + break; + case 'D': + p = add_macro(p); + break; + case 'i': +/* split_id();*/ + uniopt(*p); + break; + case 'o': + if (target != NULL) { + fprintf(stderr, + "-o can only be used once.\n"); + fatal(); + } + if ((*p)[2]) + target = *p + 2; + else + target = *++p; + break; + case 'X': + uniopt(*p); + keep_temp = 1; + break; + default: + usage(); + } + } + + if (target == NULL) + target = "a.out"; + if (only_one_input && c_files > 1) + one_input(); + processing_loop(); + unused_files(); + return 0; +} -- 2.34.1