ref: 6f2fe6bc22f5baeec9feb049cc434fb32e64c8ed
dir: /6/main.c/
#include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <inttypes.h> #include <ctype.h> #include <string.h> #include <assert.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/wait.h> #include "util.h" #include "parse.h" #include "mi.h" #include "asm.h" #include "../config.h" /* FIXME: move into one place...? */ Node *file; char debugopt[128]; int writeasm; int extracheck = 1; int p9asm; char *outfile; char *objdir; char **incpaths; char *localincpath; size_t nincpaths; Asmsyntax asmsyntax; static void usage(char *prog) { printf("%s [-?|-h] [-o outfile] [-O dir] [-d[dbgopts]] inputs\n", prog); printf("\t-?|-h\tPrint this help\n"); printf("\t-o\tOutput to outfile\n"); printf("\t-O dir\tOutput to dir\n"); printf("\t-S\tGenerate assembly source alongside object code\n"); printf("\t-c\tEnable additional (possibly flaky) checking\n"); printf("\t-I path\tAdd 'path' to use search path\n"); printf("\t-d\tPrint debug dumps. Recognized options: f r p i\n"); printf("\t-G\tGenerate asm in gas syntax\n"); printf("\t-9\tGenerate asm in plan 9 syntax\n"); printf("\t-d opts: additional debug logging. Options are listed below:\n"); printf("\t\tf: log folded trees\n"); printf("\t\tl: log lowered pre-cfg trees\n"); printf("\t\tT: log tree immediately\n"); printf("\t\tr: log register allocation activity\n"); printf("\t\ti: log instruction selection activity\n"); printf("\t\tu: log type unifications\n"); } static void swapout(char* buf, size_t sz, char* suf) { char* psuffix; psuffix = strrchr(outfile, '.'); if (psuffix != NULL) swapsuffix(buf, sz, outfile, psuffix, suf); else bprintf(buf, sz, "%s%s", outfile, suf); } static void assemble(char *asmsrc, char *path) { char *asmcmd[] = Asmcmd; char objfile[1024]; char *psuffix; char **p, **cmd; size_t ncmd, i; int pid, status; if (outfile != NULL) strncpy(objfile, outfile, 1024); else { psuffix = strrchr(path, '+'); i = 0; if (objdir) i = bprintf(objfile, sizeof objfile, "%s/", objdir); if (psuffix != NULL) swapsuffix(objfile + i, sizeof objfile - i, path, psuffix, Objsuffix); else swapsuffix(objfile + i, sizeof objfile - i, path, ".myr", Objsuffix); } cmd = NULL; ncmd = 0; for (p = asmcmd; *p != NULL; p++) lappend(&cmd, &ncmd, *p); lappend(&cmd, &ncmd, objfile); lappend(&cmd, &ncmd, asmsrc); lappend(&cmd, &ncmd, NULL); pid = fork(); if (pid == -1) { die("couldn't fork"); } else if (pid == 0) { if (execvp(cmd[0], cmd) == -1) die("Couldn't exec assembler\n"); } else { waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) die("Couldn't run assembler"); } /* We don't want to keep the asm source around, but it's useful for deubgging without mapping to line numbers. */ if (asmsyntax != Plan9 && !writeasm) unlink(asmsrc); } static char * dirname(char *path) { char *p; p = strrchr(path, '/'); if (p) return strdupn(path, p - path); else return xstrdup("."); } static char * gentempfile(char *buf, size_t bufsz, char *path, char *suffix) { char *tmpdir; char *base; struct timeval tv; tmpdir = getenv("TMPDIR"); if (!tmpdir) tmpdir = "/tmp"; base = strrchr(path, '/'); if (base) base++; else base = path; gettimeofday(&tv, NULL); bprintf(buf, bufsz, "%s/tmp%lx%lx-%s%s", tmpdir, (long)tv.tv_sec, (long)tv.tv_usec, base, suffix); return buf; } static int hasmain(Node *file) { Node *n, *name; name = mknsname(Zloc, NULL, "main"); n = getdcl(file->file.globls, name); if (!n) return 0; n = n->decl.name; if (n->name.ns) return 0; return 1; } static void genuse(char *path) { FILE *f; char buf[1024]; char *psuffix; size_t i; if (outfile != NULL) swapout(buf, 1024, ".use"); else { psuffix = strrchr(path, '+'); i = 0; if (objdir) i = bprintf(buf, sizeof buf, "%s/", objdir); if (psuffix != NULL) swapsuffix(buf + i, sizeof buf - i, path, psuffix, ".use"); else swapsuffix(buf + i, sizeof buf - i, path, ".myr", ".use"); } f = fopen(buf, "w"); if (!f) { fprintf(stderr, "Could not open path %s\n", buf); exit(1); } writeuse(f, file); fclose(f); } int main(int argc, char **argv) { char buf[1024]; Stab *globls; Optctx ctx; size_t i; outfile = NULL; optinit(&ctx, "cd:?hSo:I:9G:O:", argv, argc); asmsyntax = Defaultasm; while (!optdone(&ctx)) { switch (optnext(&ctx)) { case 'O': objdir = ctx.optarg; break; case 'o': outfile = ctx.optarg; break; case 'S': writeasm = 1; break; case '?': case 'h': usage(argv[0]); exit(0); break; case 'c': extracheck = 1; break; case 'd': while (ctx.optarg && *ctx.optarg) debugopt[*ctx.optarg++ & 0x7f]++; break; case '9': asmsyntax = Plan9; break; case 'G': if (!strcmp(ctx.optarg, "e")) asmsyntax = Gnugaself; else if (!strcmp(ctx.optarg, "m")) asmsyntax = Gnugasmacho; else die("unknown gnu syntax flavor"); break; case 'I': lappend(&incpaths, &nincpaths, ctx.optarg); break; default: usage(argv[0]); exit(0); break; } } /* Sysinit is arbitrary code defined by the configure script */ Sysinit; lappend(&incpaths, &nincpaths, Instroot "/lib/myr"); if (ctx.nargs == 0) { fprintf(stderr, "No input files given\n"); exit(1); } else if (ctx.nargs > 1) outfile = NULL; for (i = 0; i < ctx.nargs; i++) { if (outfile) localincpath = dirname(outfile); else localincpath = dirname(ctx.args[i]); globls = mkstab(0); tyinit(globls); tokinit(ctx.args[i]); file = mkfile(ctx.args[i]); file->file.globls = globls; yyparse(); /* before we do anything to the parse */ if (debugopt['T']) dump(file, stdout); infer(file); if (hasmain(file)) geninit(file); tagexports(file, 0); /* after all type inference */ if (debugopt['t']) dump(file, stdout); if (writeasm) { if (outfile != NULL) swapout(buf, sizeof buf, ".s"); else swapsuffix(buf, sizeof buf, ctx.args[i], ".myr", ".s"); } else { gentempfile(buf, sizeof buf, ctx.args[i], ".s"); } genuse(ctx.args[i]); gen(file, buf); assemble(buf, ctx.args[i]); free(localincpath); } return 0; }