# HG changeset patch # User David A. Holland # Date 1434092749 14400 # Node ID 0d5b9651b240be3708af7842a08167d59b5b1e52 # Parent e8f7ae63844f204c7d1b3108a00dce595863cad8# Parent 6119608a9817b516722adfb39ecf770482442d2a Merge Joerg's changes into upstream. (now that they've been thrashed out a bit, include CHANGES entries, etc.) diff -r e8f7ae63844f -r 0d5b9651b240 CHANGES --- a/CHANGES Fri Jun 12 03:04:48 2015 -0400 +++ b/CHANGES Fri Jun 12 03:05:49 2015 -0400 @@ -1,4 +1,8 @@ pending + - Fix output spacing behavior to match gcc when newlines appear in or + while looking for macro arguments. Partly from Joerg Sonnenberger. + - Implement __FILE__ and __LINE__ macros. Mostly from Joerg Sonnenberger. + - Implement #line. Partly from Joerg Sonnenberger. - Declare usage() with PF(). From wiz. release 0.4 (20130713) diff -r e8f7ae63844f -r 0d5b9651b240 directive.c --- a/directive.c Fri Jun 12 03:04:48 2015 -0400 +++ b/directive.c Fri Jun 12 03:05:49 2015 -0400 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "utils.h" #include "mode.h" @@ -415,11 +417,63 @@ void d_line(struct lineplace *lp, struct place *p2, char *line) { - (void)p2; - (void)line; + char *text; + size_t oldlen; + unsigned long val; + char *moretext; + size_t moretextlen; + char *filename; + + text = macroexpand(p2, line, strlen(line), true); + + oldlen = strlen(text); + uncomment(text); + /* trim to fit, so the malloc debugging won't complain */ + text = dorealloc(text, oldlen + 1, strlen(text) + 1); + + /* + * What we should have here: either 1234 "file.c", + * or just 1234. + */ - /* XXX */ - complain(&lp->current, "Sorry, no #line yet"); + errno = 0; + val = strtoul(text, &moretext, 10); + if (errno) { + complain(&lp->current, "No line number in #line directive"); + goto fail; + } +#if UINT_MAX < ULONG_MAX + if (val > UINT_MAX) { + complain(&lp->current, + "Line number in #line directive too large"); + goto fail; + } +#endif + moretext += strspn(moretext, ws); + moretextlen = strlen(moretext); + lp->current.column += (moretext - text); + + if (moretextlen > 2 && + moretext[0] == '"' && moretext[moretextlen-1] == '"') { + filename = dostrndup(moretext+1, moretextlen-2); + place_changefile(&lp->nextline, filename); + dostrfree(filename); + } + else if (moretextlen > 0) { + complain(&lp->current, + "Invalid file name in #line directive"); + goto fail; + } + + lp->nextline.line = val; + dostrfree(text); + return; + +fail: + complain(&lp->current, "Before macro expansion: #line %s", line); + complain(&lp->current, "After macro expansion: #line %s", text); + complain_fail(); + dostrfree(text); } //////////////////////////////////////////////////////////// @@ -584,7 +638,7 @@ } /* check if we have a directive line (# exactly in column 0) */ - if (line[0] == '#') { + if (len > 0 && line[0] == '#') { skip = 1 + strspn(line + 1, ws); assert(skip <= len); lp->current.column += skip; diff -r e8f7ae63844f -r 0d5b9651b240 directive.h diff -r e8f7ae63844f -r 0d5b9651b240 files.c --- a/files.c Fri Jun 12 03:04:48 2015 -0400 +++ b/files.c Fri Jun 12 03:05:49 2015 -0400 @@ -274,11 +274,8 @@ /* count how many commented-out newlines we swallowed */ places.nextline.line += countnls(buf, linestart, lineend); - /* if the line isn't empty, process it */ - if (lineend > linestart) { - directive_gotline(&places, - buf+linestart, lineend-linestart); - } + /* process the line (even if it's empty) */ + directive_gotline(&places, buf+linestart, lineend-linestart); linestart = nextlinestart; lineend = findeol(buf, linestart, bufend); diff -r e8f7ae63844f -r 0d5b9651b240 macro.c --- a/macro.c Fri Jun 12 03:04:48 2015 -0400 +++ b/macro.c Fri Jun 12 03:05:49 2015 -0400 @@ -28,6 +28,7 @@ */ #include +#include #include #include @@ -38,10 +39,10 @@ #include "output.h" struct expansionitem { - bool isstring; + enum { EI_STRING, EI_PARAM, EI_FILE, EI_LINE } itemtype; union { - char *string; - unsigned param; + char *string; /* EI_STRING */ + unsigned param; /* EI_PARAM */ }; }; DECLARRAY(expansionitem, static UNUSED); @@ -76,7 +77,7 @@ struct expansionitem *ei; ei = domalloc(sizeof(*ei)); - ei->isstring = true; + ei->itemtype = EI_STRING; ei->string = dostrdup(string); return ei; } @@ -88,7 +89,7 @@ struct expansionitem *ei; ei = domalloc(sizeof(*ei)); - ei->isstring = true; + ei->itemtype = EI_STRING; ei->string = dostrndup(string, len); return ei; } @@ -100,17 +101,45 @@ struct expansionitem *ei; ei = domalloc(sizeof(*ei)); - ei->isstring = false; + ei->itemtype = EI_PARAM; ei->param = param; return ei; } static +struct expansionitem * +expansionitem_create_file(void) +{ + struct expansionitem *ei; + + ei = domalloc(sizeof(*ei)); + ei->itemtype = EI_FILE; + return ei; +} + +static +struct expansionitem * +expansionitem_create_line(void) +{ + struct expansionitem *ei; + + ei = domalloc(sizeof(*ei)); + ei->itemtype = EI_LINE; + return ei; +} + +static void expansionitem_destroy(struct expansionitem *ei) { - if (ei->isstring) { + switch (ei->itemtype) { + case EI_STRING: dostrfree(ei->string); + break; + case EI_PARAM: + case EI_FILE: + case EI_LINE: + break; } dofree(ei, sizeof(*ei)); } @@ -120,17 +149,23 @@ expansionitem_eq(const struct expansionitem *ei1, const struct expansionitem *ei2) { - if (ei1->isstring != ei2->isstring) { + if (ei1->itemtype != ei2->itemtype) { return false; } - if (ei1->isstring) { + switch (ei1->itemtype) { + case EI_STRING: if (strcmp(ei1->string, ei2->string) != 0) { return false; } - } else { + break; + case EI_PARAM: if (ei1->param != ei2->param) { return false; } + break; + case EI_FILE: + case EI_LINE: + break; } return true; } @@ -587,6 +622,24 @@ } void +macro_define_magic(struct place *p, const char *macro) +{ + struct macro *m; + struct expansionitem *ei; + + m = macro_define_common_start(p, macro, p); + if (!strcmp(macro, "__FILE__")) { + ei = expansionitem_create_file(); + } + else { + assert(!strcmp(macro, "__LINE__")); + ei = expansionitem_create_line(); + } + expansionitemarray_add(&m->expansion, ei, NULL); + macro_define_common_end(m); +} + +void macro_undef(const char *macro) { struct macro *m; @@ -624,7 +677,7 @@ static struct expstate mainstate; static void doexpand(struct expstate *es, struct place *p, - char *buf, size_t len); + const char *buf, size_t len); static void @@ -705,7 +758,7 @@ static void -expand_newarg(struct expstate *es, char *buf, size_t len) +expand_newarg(struct expstate *es, const char *buf, size_t len) { char *text; @@ -715,7 +768,7 @@ static void -expand_appendarg(struct expstate *es, char *buf, size_t len) +expand_appendarg(struct expstate *es, const char *buf, size_t len) { unsigned num; char *text; @@ -742,6 +795,7 @@ char *arg; char *ret; unsigned numargs, numparams; + char numbuf[64]; numargs = stringarray_num(&es->args); numparams = stringarray_num(&es->curmacro->params); @@ -766,11 +820,20 @@ num = expansionitemarray_num(&es->curmacro->expansion); for (i=0; icurmacro->expansion, i); - if (ei->isstring) { + switch (ei->itemtype) { + case EI_STRING: len += strlen(ei->string); - } else { + break; + case EI_PARAM: arg = stringarray_get(&es->args, ei->param); len += strlen(arg); + break; + case EI_FILE: + len += strlen(place_getname(p)) + 2; + break; + case EI_LINE: + len += snprintf(numbuf, sizeof(numbuf), "%u", p->line); + break; } } @@ -778,11 +841,23 @@ *ret = '\0'; for (i=0; icurmacro->expansion, i); - if (ei->isstring) { + switch (ei->itemtype) { + case EI_STRING: strcat(ret, ei->string); - } else { + break; + case EI_PARAM: arg = stringarray_get(&es->args, ei->param); strcat(ret, arg); + break; + case EI_FILE: + strcat(ret, "\""); + strcat(ret, place_getname(p)); + strcat(ret, "\""); + break; + case EI_LINE: + snprintf(numbuf, sizeof(numbuf), "%u", p->line); + strcat(ret, numbuf); + break; } } @@ -846,7 +921,8 @@ static void -expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len) +expand_got_ws(struct expstate *es, struct place *p, + const char *buf, size_t len) { switch (es->state) { case ES_NORMAL: @@ -868,7 +944,8 @@ static void -expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len) +expand_got_word(struct expstate *es, struct place *p, + const char *buf, size_t len) { struct macro *m; @@ -917,7 +994,8 @@ static void -expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len) +expand_got_lparen(struct expstate *es, struct place *p, + const char *buf, size_t len) { switch (es->state) { case ES_NORMAL: @@ -940,7 +1018,8 @@ static void -expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len) +expand_got_rparen(struct expstate *es, struct place *p, + const char *buf, size_t len) { switch (es->state) { case ES_NORMAL: @@ -975,7 +1054,8 @@ static void -expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len) +expand_got_comma(struct expstate *es, struct place *p, + const char *buf, size_t len) { switch (es->state) { case ES_NORMAL: @@ -1003,7 +1083,8 @@ static void -expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len) +expand_got_other(struct expstate *es, struct place *p, + const char *buf, size_t len) { switch (es->state) { case ES_NORMAL: @@ -1055,7 +1136,7 @@ static void -doexpand(struct expstate *es, struct place *p, char *buf, size_t len) +doexpand(struct expstate *es, struct place *p, const char *buf, size_t len) { char *s; size_t x; @@ -1144,7 +1225,7 @@ } char * -macroexpand(struct place *p, char *buf, size_t len, bool honordefined) +macroexpand(struct place *p, const char *buf, size_t len, bool honordefined) { struct expstate es; char *ret; @@ -1166,10 +1247,30 @@ } void -macro_sendline(struct place *p, char *buf, size_t len) +macro_sendline(struct place *p, const char *buf, size_t len) { doexpand(&mainstate, p, buf, len); - output(p, "\n", 1); + switch (mainstate.state) { + case ES_NORMAL: + /* + * If we were sent a blank line, don't emit a newline + * for it. This matches the prior behavior of tradcpp. + */ + if (len > 0) { + output(p, "\n", 1); + } + break; + case ES_WANTLPAREN: + case ES_NOARG: + case ES_HAVEARG: + /* + * Apparently to match gcc's -traditional behavior we + * need to emit a space for each newline that appears + * while processing macro args. + */ + expand_got_ws(&mainstate, p, " ", 1); + break; + } } void diff -r e8f7ae63844f -r 0d5b9651b240 macro.h --- a/macro.h Fri Jun 12 03:04:48 2015 -0400 +++ b/macro.h Fri Jun 12 03:05:49 2015 -0400 @@ -40,10 +40,12 @@ void macro_define_params(struct place *, const char *macro, struct place *, const char *params, struct place *, const char *expansion); +void macro_define_magic(struct place *, const char *macro); void macro_undef(const char *macro); bool macro_isdefined(const char *macro); -char *macroexpand(struct place *, char *buf, size_t len, bool honordefined); +char *macroexpand(struct place *, const char *buf, size_t len, + bool honordefined); -void macro_sendline(struct place *, char *buf, size_t len); +void macro_sendline(struct place *, const char *buf, size_t len); void macro_sendeof(struct place *); diff -r e8f7ae63844f -r 0d5b9651b240 main.c --- a/main.c Fri Jun 12 03:04:48 2015 -0400 +++ b/main.c Fri Jun 12 03:05:49 2015 -0400 @@ -195,6 +195,16 @@ static void +apply_magic_macro(unsigned num, const char *name) +{ + struct place p; + + place_setbuiltin(&p, num); + macro_define_magic(&p, name); +} + +static +void apply_builtin_macro(unsigned num, const char *name, const char *val) { struct place p; @@ -209,6 +219,9 @@ { unsigned n = 1; + apply_magic_macro(n++, "__FILE__"); + apply_magic_macro(n++, "__LINE__"); + #ifdef CONFIG_OS apply_builtin_macro(n++, CONFIG_OS, "1"); #endif diff -r e8f7ae63844f -r 0d5b9651b240 place.c --- a/place.c Fri Jun 12 03:04:48 2015 -0400 +++ b/place.c Fri Jun 12 03:05:49 2015 -0400 @@ -53,7 +53,7 @@ static const char *myprogname; //////////////////////////////////////////////////////////// -// seenfiles +// placefiles static struct placefile * @@ -101,6 +101,58 @@ return place->file->dir; } +static +bool +place_eq(const struct place *a, const struct place *b) +{ + if (a->type != b->type) { + return false; + } + if (a->file != b->file) { + return false; + } + if (a->line != b->line || a->column != b->column) { + return false; + } + return true; +} + +static +struct placefile * +placefile_find(const struct place *incfrom, const char *name) +{ + unsigned i, num; + struct placefile *pf; + + num = placefilearray_num(&placefiles); + for (i=0; iincludedfrom) && + !strcmp(name, pf->name)) { + return pf; + } + } + return NULL; +} + +void +place_changefile(struct place *p, const char *name) +{ + struct placefile *pf; + + assert(p->type == P_FILE); + if (!strcmp(name, p->file->name)) { + return; + } + pf = placefile_find(&p->file->includedfrom, name); + if (pf == NULL) { + pf = placefile_create(&p->file->includedfrom, name, + p->file->fromsystemdir); + placefilearray_add(&placefiles, pf, NULL); + } + p->file = pf; +} + const struct placefile * place_addfile(const struct place *place, const char *file, bool issystem) { @@ -154,7 +206,6 @@ p->column = 1; } -static const char * place_getname(const struct place *p) { diff -r e8f7ae63844f -r 0d5b9651b240 place.h --- a/place.h Fri Jun 12 03:04:48 2015 -0400 +++ b/place.h Fri Jun 12 03:05:49 2015 -0400 @@ -53,8 +53,11 @@ void place_setcommandline(struct place *p, unsigned word, unsigned column); void place_setfilestart(struct place *p, const struct placefile *pf); +const char *place_getname(const struct place *); const char *place_getparsedir(const struct place *incplace); +void place_changefile(struct place *p, const char *name); + const struct placefile *place_addfile(const struct place *incplace, const char *name, bool fromsystemdir); diff -r e8f7ae63844f -r 0d5b9651b240 tests/Makefile --- a/tests/Makefile Fri Jun 12 03:04:48 2015 -0400 +++ b/tests/Makefile Fri Jun 12 03:05:49 2015 -0400 @@ -4,7 +4,7 @@ TESTS=\ t01 t02 t03 t04 t05 t06 t07 t08 t09 t10 t11 t12 t13 t14 t15 t16 \ t17 t18 t19 t20 t21 t22 t23 t24 t25 t26 t27 t28 t29 t30 t31 t32 \ - t33 t34 t35 t36 t37 + t33 t34 t35 t36 t37 t38 t39 all: run-tests .WAIT show-diffs diff -r e8f7ae63844f -r 0d5b9651b240 tests/t38.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t38.c Fri Jun 12 03:05:49 2015 -0400 @@ -0,0 +1,9 @@ +#define m() __FILE__:__LINE__ +__LINE__ +__FILE__ +__LINE__ +m() +#line 500 +m() +#line 600 "foo.c" +m() diff -r e8f7ae63844f -r 0d5b9651b240 tests/t38.good --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t38.good Fri Jun 12 03:05:49 2015 -0400 @@ -0,0 +1,6 @@ +2 +"t38.c" +4 +"t38.c":5 +"t38.c":500 +"foo.c":600 diff -r e8f7ae63844f -r 0d5b9651b240 tests/t39.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t39.c Fri Jun 12 03:05:49 2015 -0400 @@ -0,0 +1,21 @@ +#define m(a,b) a::b +=m(123, +456) + ------ +=m +(123, 456) + ------ +=m( +123, 456) + ------ +=m( +123, +456 +) + ------ +=m(123, + +456) + ------ +=m(123, + 456) diff -r e8f7ae63844f -r 0d5b9651b240 tests/t39.good --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t39.good Fri Jun 12 03:05:49 2015 -0400 @@ -0,0 +1,11 @@ +=123:: 456 + ------ +=123:: 456 + ------ += 123:: 456 + ------ += 123:: 456 + ------ +=123:: 456 + ------ +=123:: 456 diff -r e8f7ae63844f -r 0d5b9651b240 utils.c diff -r e8f7ae63844f -r 0d5b9651b240 utils.h