scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 0ecbf7a103fa60948be1dfb8cd41691272bb909d
parent c50c0b5735d98f2503f99c215efae6c88c7a46c1
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue,  5 Jul 2016 08:38:51 +0200

Merge remote-tracking branch 'origin/master'

Diffstat:
Mcc1/cc1.h | 6++++--
Mcc1/cpp.c | 58+++++++++++++++++++++++++++-------------------------------
Mcc1/lex.c | 62+++++++++++++++++++++++++++++---------------------------------
Mcc1/main.c | 19++++++++++++++++++-
Mdriver/posix/Makefile | 2+-
Mdriver/posix/scc.c | 148++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Minc/arg.h | 90++++++++++++++++++++++++++++++++++++++++----------------------------------------
7 files changed, 226 insertions(+), 159 deletions(-)

diff --git a/cc1/cc1.h b/cc1/cc1.h @@ -382,8 +382,10 @@ extern int moreinput(void); extern void expect(unsigned tok); extern void discard(void); extern int addinput(char *fname); +extern void allocinput(char *fname, FILE *fp, char *line); +extern void delinput(void); extern void setsafe(int type); -extern void ilex(char *fname); +extern void ilex(void); #define accept(t) ((yytoken == (t)) ? next() : 0) /* code.c */ @@ -418,7 +420,7 @@ extern int cpp(void); extern int expand(char *begin, Symbol *sym); extern void incdir(char *dir); extern void outcpp(void); -extern Symbol *defmacro(char *s); +extern void defdefine(char *macro, char *val); extern void undefmacro(char *s); /* diff --git a/cc1/cpp.c b/cc1/cpp.c @@ -13,6 +13,7 @@ static char *argp, *macroname; static unsigned arglen; +static unsigned ncmdlines; static Symbol *symline, *symfile; static unsigned char ifstatus[NR_COND]; static int ninclude; @@ -21,30 +22,20 @@ static char **dirinclude; unsigned cppctx; int disexpand; -Symbol * -defmacro(char *s) +void +defdefine(char *macro, char *val) { - char *p, *q; - Symbol *sym; - char def[] = "=1"; - - if ((p = strchr(s, '=')) == NULL) - p = def; - *p++='\0'; - q = xmalloc(strlen(p) + 4); - sprintf(q, "-1#%s", p); + char *def, *fmt = "#define %s %s"; - sym = lookup(NS_CPP, s); - if (sym->flags & SDECLARED) { - warn("'%s' redefined"); - free(sym->u.s); - } else { - install(NS_CPP, sym); - sym->flags |= SDECLARED|SSTRING; - } + if (!val) + val = ""; + def = xmalloc(strlen(fmt) + strlen(macro) + strlen(val)); - sym->u.s = q; - return sym; + sprintf(def, fmt, macro, val); + allocinput("command-line", NULL, def); + input->nline = ++ncmdlines; + cpp(); + delinput(); } void @@ -56,7 +47,7 @@ undefmacro(char *s) void icpp(void) { - static char sdate[17], stime[14]; + static char sdate[14], stime[11]; struct tm *tm; time_t t; static char **bp, *list[] = { @@ -81,20 +72,25 @@ icpp(void) {NULL, 0, 0} }; + keywords(keys, NS_CPPCLAUSES); + t = time(NULL); tm = localtime(&t); - strftime(sdate, sizeof(sdate), "-1#\"%b %d %Y\"", tm); - strftime(stime, sizeof(stime), "-1#\"%H:%M:%S\"", tm); - defmacro("__DATE__")->u.s = sdate; - defmacro("__TIME__")->u.s = stime; + strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm); + strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm); + defdefine("__DATE__", sdate); + defdefine("__TIME__", stime); + defdefine("__STDC_VERSION__", "199409L"); + defdefine("__LINE__", NULL); + defdefine("__FILE__", NULL); - defmacro("__STDC_VERSION__")->u.s = "-1#199409L"; - symline = defmacro("__LINE__"); - symfile = defmacro("__FILE__"); + symline = lookup(NS_CPP, "__LINE__"); + symfile = lookup(NS_CPP, "__FILE__"); for (bp = list; *bp; ++bp) - defmacro(*bp)->u.s = "-1#1"; - keywords(keys, NS_CPPCLAUSES); + defdefine(*bp, NULL); + + ncmdlines = 0; } static void diff --git a/cc1/lex.c b/cc1/lex.c @@ -22,23 +22,25 @@ int namespace = NS_IDEN; static int safe, eof; Input *input; -static void -allocinput(char *fname, FILE *fp) +void +allocinput(char *fname, FILE *fp, char *line) { - Input *ip; + Input *ip = xmalloc(sizeof(Input)); - ip = xmalloc(sizeof(Input)); - ip->fname = xstrdup(fname); - ip->p = ip->begin = ip->line = xmalloc(INPUTSIZ); - ip->p[0] = '\0'; + if (!line) { + line = xmalloc(INPUTSIZ); + line[0] = '\0'; + } + ip->p = ip->begin = ip->line = line; ip->nline = 0; + ip->fname = xstrdup(fname); ip->next = input; ip->fp = fp; input = ip; } void -ilex(char *fname) +ilex(void) { static struct keyword keys[] = { {"auto", SCLASS, AUTO}, @@ -78,18 +80,6 @@ ilex(char *fname) {"while", WHILE, WHILE}, {NULL, 0, 0}, }; - FILE *fp; - - if (!fname) { - fp = stdin; - fname = "<stdin>"; - } else { - if ((fp = fopen(fname, "r")) == NULL) { - die("error: failed to open input file '%s': %s", - fname, strerror(errno)); - } - } - allocinput(fname, fp); keywords(keys, NS_KEYWORD); } @@ -98,21 +88,29 @@ addinput(char *fname) { FILE *fp; - if ((fp = fopen(fname, "r")) == NULL) - return 0; - allocinput(fname, fp); + if (fname) { + if ((fp = fopen(fname, "r")) == NULL) + return 0; + } else { + fp = stdin; + fname = "<stdin>"; + } + allocinput(fname, fp, NULL); return 1; } -static void +void delinput(void) { Input *ip = input; - if (!ip->next) - eof = 1; - if (fclose(ip->fp)) - die("error: failed to read from input file '%s'", ip->fname); + if (ip->fp) { + if (fclose(ip->fp)) + die("error: failed to read from input file '%s'", + ip->fname); + if (!ip->next) + eof = 1; + } if (eof) return; input = ip->next; @@ -130,14 +128,12 @@ newline(void) static int readchar(void) { + FILE *fp = input->fp; int c; - FILE *fp; -repeat: - if (eof) + if (eof || !fp) return 0; - fp = input->fp; - +repeat: switch (c = getc(fp)) { case EOF: c = '\0'; diff --git a/cc1/main.c b/cc1/main.c @@ -29,6 +29,19 @@ clean(void) } static void +defmacro(char *macro) +{ + char *p = strchr(macro, '='); + + if (p) + *p++ = '\0'; + else + p = "1"; + + defdefine(macro, p); +} + +static void usage(void) { die(!strcmp(name, "cpp") ? @@ -46,6 +59,7 @@ main(int argc, char *argv[]) atexit(clean); icpp(); + ilex(); /* if run as cpp, only run the preprocessor */ name = (cp = strrchr(*argv, '/')) ? cp + 1 : *argv; @@ -88,7 +102,10 @@ main(int argc, char *argv[]) for (i = 0; i < uflags.n; ++i) undefmacro(uflags.s[i]); - ilex(*argv); + if (!addinput(*argv)) { + die("error: failed to open input file '%s': %s", + *argv, strerror(errno)); + } if (onlycpp) { outcpp(); } else { diff --git a/driver/posix/Makefile b/driver/posix/Makefile @@ -7,7 +7,7 @@ OBJS = scc.o all: scc -$(OBJS): ../../inc/cc.h +$(OBJS): ../../inc/cc.h ../../inc/arg.h ../../lib/libcc.a: cd ../../lib && $(MAKE) -e diff --git a/driver/posix/scc.c b/driver/posix/scc.c @@ -1,5 +1,6 @@ /* See LICENSE file for copyright and license details. */ #define _POSIX_SOURCE +#define _XOPEN_SOURCE 500 #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> @@ -48,7 +49,9 @@ static struct tool { }; char *argv0; -static char *arch, *outfile; +static char *arch, *objfile, *outfile; +static char *tmpdir; +static size_t tmpdirln; static struct items objtmp, objout; static int Eflag, Sflag, cflag, kflag, sflag; @@ -134,30 +137,35 @@ inittool(int tool) } static char * -outfilename(char *path, char *ext) +outfname(char *path, char *type) { - char *new, *name, *dot; - size_t newsz, nameln; - int n; - - if (!(name = strrchr(path, '/'))) - name = path; - else - ++name; - - nameln = strlen(name); - - if (!(dot = strrchr(name, '.'))) - dot = &name[nameln]; - - nameln = nameln - strlen(dot); - newsz = nameln + strlen(ext) + 1 + 1; + char *new, sep, *p; + size_t newsz, pathln; + int tmpfd, n; + + if (path) { + sep = '.'; + if (p = strrchr(path, '/')) + path = p + 1; + pathln = strlen(path); + if (p = strrchr(path, '.')) + pathln -= strlen(p); + } else { + sep = '/'; + type = "scc-XXXXXX"; + path = tmpdir; + pathln = tmpdirln; + } + newsz = pathln + 1 + strlen(type) + 1; new = xmalloc(newsz); - - n = snprintf(new, newsz, "%.*s.%s", nameln, name, ext); + n = snprintf(new, newsz, "%.*s%c%s", pathln, path, sep, type); if (n < 0 || n >= newsz) die("scc: wrong output filename"); + if ((tmpfd = mkstemp(new)) < 0 && errno != EINVAL) + die("scc: could not create output file '%s': %s", + new, strerror(errno)); + close(tmpfd); return new; } @@ -172,27 +180,27 @@ settool(int tool, char *infile, int nexttool) switch (tool) { case TEEIR: - t->outfile = outfilename(infile, "ir"); + t->outfile = outfname(infile, "ir"); addarg(tool, t->outfile); break; case TEEQBE: - t->outfile = outfilename(infile, "qbe"); + t->outfile = outfname(infile, "qbe"); addarg(tool, t->outfile); break; case TEEAS: - t->outfile = outfilename(infile, "as"); + t->outfile = outfname(infile, "as"); addarg(tool, t->outfile); break; case AS: - t->outfile = outfile ? outfile : outfilename(infile, "o"); + if (cflag && outfile) { + objfile = outfile; + } else { + objfile = (cflag || kflag) ? infile : NULL; + objfile = outfname(objfile, "o"); + } + t->outfile = xstrdup(objfile); addarg(tool, t->outfile); break; - case LD: - for (i = 0; i < objtmp.n; ++i) - addarg(tool, xstrdup(objtmp.s[i])); - for (i = 0; i < objout.n; ++i) - addarg(tool, xstrdup(objout.s[i])); - break; case STRIP: if (cflag || kflag) { for (i = 0; i < objout.n; ++i) @@ -298,16 +306,20 @@ validatetools(void) t->pid = 0; } } + if (failed < LAST_TOOL) { + unlink(objfile); + free(objfile); + objfile = NULL; + return 0; + } - return failed == LAST_TOOL; + return 1; } -static void -build(char *file) +static int +buildfile(char *file, int tool) { - int tool = toolfor(file), nexttool; - struct items *objs = (tool == LD || cflag || kflag) ? - &objout : &objtmp; + int nexttool; for (; tool < LAST_TOOL; tool = nexttool) { switch (tool) { @@ -346,8 +358,39 @@ build(char *file) spawn(settool(inittool(tool), file, nexttool)); } - if (validatetools()) - newitem(objs, outfilename(file, "o")); + return validatetools(); +} + +static void +build(struct items *chain, int link) +{ + int i, tool; + + if (link) + inittool(LD); + + for (i = 0; i < chain->n; ++i) { + if (!strcmp(chain->s[i], "-l")) { + if (link) { + addarg(LD, xstrdup(chain->s[i++])); + addarg(LD, xstrdup(chain->s[i])); + } else { + ++i; + } + continue; + } + tool = toolfor(chain->s[i]); + if (tool == LD) { + if (link) + addarg(LD, xstrdup(chain->s[i])); + continue; + } + if (buildfile(chain->s[i], tool)) { + if (link) + addarg(LD, xstrdup(objfile)); + newitem((!link || kflag) ? &objout : &objtmp, objfile); + } + } } static void @@ -367,6 +410,9 @@ usage(void) int main(int argc, char *argv[]) { + struct items linkchain = { .n = 0, }; + int link; + atexit(terminate); arch = getenv("ARCH"); @@ -406,8 +452,8 @@ main(int argc, char *argv[]) kflag = 1; break; case 'l': - addarg(LD, "-l"); - addarg(LD, EARGF(usage())); + newitem(&linkchain, "-l"); + newitem(&linkchain, EARGF(usage())); break; case 'm': arch = EARGF(usage()); @@ -427,19 +473,29 @@ main(int argc, char *argv[]) break; default: usage(); + } ARGOPERAND { +operand: + newitem(&linkchain, ARGOP()); } ARGEND - if (Eflag && (Sflag || kflag) || argc > 1 && cflag && outfile || !argc) + for (; *argv; --argc, ++argv) + goto operand; + + if (Eflag && (Sflag || kflag) || linkchain.n == 0 || + linkchain.n > 1 && cflag && outfile) usage(); - for (; *argv; ++argv) - build(*argv); + if (!(tmpdir = getenv("TMPDIR")) || !tmpdir[0]) + tmpdir = "."; + tmpdirln = strlen(tmpdir); + + build(&linkchain, (link = !(Eflag || Sflag || cflag))); - if (Eflag || Sflag) + if (!(link || cflag)) return failure; - if (!cflag && !failure) { - spawn(settool(inittool(LD), NULL, LAST_TOOL)); + if (link && !failure) { + spawn(settool(LD, NULL, LAST_TOOL)); validatetools(); } diff --git a/inc/arg.h b/inc/arg.h @@ -9,57 +9,57 @@ extern char *argv0; /* use main(int argc, char *argv[]) */ -#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ - argv[0] && argv[0][0] == '-'\ - && argv[0][1];\ - argc--, argv++) {\ - char argc_;\ - char **argv_;\ - int brk_;\ - if (argv[0][1] == '-' && argv[0][2] == '\0') {\ - argv++;\ - argc--;\ - break;\ - }\ - for (brk_ = 0, argv[0]++, argv_ = argv;\ - argv[0][0] && !brk_;\ - argv[0]++) {\ - if (argv_ != argv)\ - break;\ - argc_ = argv[0][0];\ - switch (argc_) +#define ARGBEGIN \ +for (argv0 = *argv, argv++, argc--;\ + argv[0];\ + argc--, argv++) {\ + if (argv[0][0] == '-') {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) -/* Handles obsolete -NUM syntax */ -#define ARGNUM case '0':\ - case '1':\ - case '2':\ - case '3':\ - case '4':\ - case '5':\ - case '6':\ - case '7':\ - case '8':\ - case '9' +#define ARGOPERAND \ + }\ + } else if (argv[0][0] != '\0') {\ + { -#define ARGEND }\ - } +#define ARGEND \ + }\ + }\ +} -#define ARGC() argc_ +#define ARGC() argc_ -#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) +#define ARGOP() argv[0] -#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ - ((x), abort(), (char *)0) :\ - (brk_ = 1, (argv[0][1] != '\0')?\ - (&argv[0][1]) :\ - (argc--, argv++, argv[0]))) +#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) -#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ - (char *)0 :\ - (brk_ = 1, (argv[0][1] != '\0')?\ - (&argv[0][1]) :\ - (argc--, argv++, argv[0]))) +#define EARGF(x) \ +((argv[0][1] == '\0' && argv[1] == NULL) ?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0') ?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) -#define LNGARG() &argv[0][0] +#define ARGF() \ +((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define LNGARG() &argv[0][0] #endif