# HG changeset patch # User David A. Holland # Date 1364706283 14400 # Node ID 8a204d1533980e8c4aae983a87fb5eb5cc73d513 # Parent 0af03c5571e0b93ff919a039aa4b7e1025ba93b8 Intercept multiline comments earlier. Leave same-line comments alone. Fixes all of the pathological comment behavior we've noticed so far. diff -r 0af03c5571e0 -r 8a204d153398 directive.c --- a/directive.c Sat Mar 30 23:29:08 2013 -0400 +++ b/directive.c Sun Mar 31 01:04:43 2013 -0400 @@ -39,6 +39,7 @@ #include "directive.h" #include "macro.h" #include "eval.h" +#include "output.h" struct ifstate { struct ifstate *prev; @@ -49,6 +50,7 @@ }; static struct ifstate *ifstate; +static bool in_multiline_comment; //////////////////////////////////////////////////////////// // common parsing bits @@ -408,23 +410,138 @@ complain_fail(); } +/* + * If desired, warn about a nested comment. The comment begins at + * offset POS from the place P. + */ +static +void +warn_nestcomment(const struct place *p, size_t pos) +{ + struct place p2; + + if (warns.nestcomment) { + p2 = *p; + p2.column += pos; + complain(p, "Warning: %c%c within comment", + '/', '*'); + if (mode.werror) { + complain_failed(); + } + } +} + +/* + * Check for comment delimiters in LINE. If a multi-line comment is + * continuing or ending, set ACOMM to its length. If a multi-line + * comment is starting, set BCOMM to its length. Set TEXT to the + * length of text that is not commented out, or that contains comments + * that both begin and end on this line. ACOMM + TEXT + BCOMM == LEN. + * + * Updates in_multiline_comment to the appropriate state for after + * this line is handled. + */ +static +size_t +directive_scancomments(const struct place *p, char *line, size_t len, + size_t *acomm, size_t *text, size_t *bcomm) +{ + size_t pos; + size_t first_commentend; + size_t last_commentstart; + bool incomment; + + first_commentend = len; + last_commentstart = len; + incomment = in_multiline_comment; + for (pos = 0; pos+1 < len; pos++) { + if (line[pos] == '/' && line[pos+1] == '*') { + if (incomment) { + warn_nestcomment(p, pos); + } else { + incomment = true; + last_commentstart = pos; + } + } else if (line[pos] == '*' && line[pos+1] == '/') { + if (incomment) { + incomment = false; + if (first_commentend == len) { + first_commentend = pos; + } + last_commentstart = len; + } else { + /* stray end-comment; should we care? */ + } + } + } + + if (in_multiline_comment && first_commentend < last_commentstart) { + /* multiline comment ends */ + /* first_commentend points to the star, adjust */ + *acomm = first_commentend + 2; + *text = len - *acomm; + } else if (in_multiline_comment) { + /* comment did not end, so another one cannot have started */ + assert(last_commentstart == len); + *acomm = len; + *text = 0; + } else { + *acomm = 0; + *text = len; + } + + *bcomm = len - last_commentstart; + *text -= *bcomm; + + in_multiline_comment = incomment; + return len; +} + void directive_gotline(struct place *p, char *line, size_t len) { + size_t acomm; /* length of comment ending on this line */ + size_t text; /* length of non-multi-line-comment text */ + size_t bcomm; /* length of comment beginning on this line */ size_t skip; + directive_scancomments(p, line, len, &acomm, &text, &bcomm); + + if (acomm > 0) { + if (mode.output_retain_comments && ifstate->curtrue) { + /* + * Do not expand the comment; send it straight + * to the output. This will cause it to appear + * first if we're partway through collecting a + * macro argument. Too bad. This isn't a + * standard mode anyway. + */ + output(p, line, acomm); + } + p->column += acomm; + } + /* check if we have a directive line */ - skip = strspn(line, ws); - if (line[skip] == '#') { + skip = strspn(line + acomm, ws); + if (acomm == 0 && line[skip] == '#') { skip = skip + 1 + strspn(line + skip + 1, ws); + assert(skip <= text); p->column += skip; - directive_gotdirective(p, line+skip, len-skip); + directive_gotdirective(p, line+skip, text-skip); + p->column += text-skip; } else if (ifstate->curtrue) { - macro_sendline(p, line, len); + macro_sendline(p, line + acomm, text); + p->column += text; + } + + if (bcomm > 0) { + if (mode.output_retain_comments && ifstate->curtrue) { + output(p, line + acomm + text, bcomm); + } + p->column += bcomm; } } - void directive_goteof(struct place *p) { diff -r 0af03c5571e0 -r 8a204d153398 tests/Makefile --- a/tests/Makefile Sat Mar 30 23:29:08 2013 -0400 +++ b/tests/Makefile Sun Mar 31 01:04:43 2013 -0400 @@ -1,6 +1,6 @@ TRADCPP=../obj/tradcpp # XXX -TESTS=t01 t02 t03 t04 t05 t06 t07 t08 t09 t10 t11 t12 +TESTS=t01 t02 t03 t04 t05 t06 t07 t08 t09 t10 t11 t12 t13 t14 t15 all: run-tests .WAIT show-diffs diff -r 0af03c5571e0 -r 8a204d153398 tests/t07.good --- a/tests/t07.good Sat Mar 30 23:29:08 2013 -0400 +++ b/tests/t07.good Sun Mar 31 01:04:43 2013 -0400 @@ -1,1 +1,3 @@ + + diff -r 0af03c5571e0 -r 8a204d153398 tests/t09.good --- a/tests/t09.good Sat Mar 30 23:29:08 2013 -0400 +++ b/tests/t09.good Sun Mar 31 01:04:43 2013 -0400 @@ -1,1 +1,3 @@ - fnord + + + diff -r 0af03c5571e0 -r 8a204d153398 tests/t13.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t13.c Sun Mar 31 01:04:43 2013 -0400 @@ -0,0 +1,4 @@ +/* +#define FOO BAR +*/ +FOO diff -r 0af03c5571e0 -r 8a204d153398 tests/t13.good --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t13.good Sun Mar 31 01:04:43 2013 -0400 @@ -0,0 +1,4 @@ + + + +FOO diff -r 0af03c5571e0 -r 8a204d153398 tests/t14.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t14.c Sun Mar 31 01:04:43 2013 -0400 @@ -0,0 +1,4 @@ +/* +#define FOO BAR */ +FOO +FOO diff -r 0af03c5571e0 -r 8a204d153398 tests/t14.good --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t14.good Sun Mar 31 01:04:43 2013 -0400 @@ -0,0 +1,4 @@ + + +FOO +FOO diff -r 0af03c5571e0 -r 8a204d153398 tests/t15.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t15.c Sun Mar 31 01:04:43 2013 -0400 @@ -0,0 +1,3 @@ +#define FOO /* BAR */ BAZ +FOO +FOO diff -r 0af03c5571e0 -r 8a204d153398 tests/t15.good --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/t15.good Sun Mar 31 01:04:43 2013 -0400 @@ -0,0 +1,2 @@ + BAZ + BAZ