Mercurial > ~dholland > hg > tradcpp > index.cgi
diff directive.c @ 49:8a204d153398
Intercept multiline comments earlier. Leave same-line comments alone.
Fixes all of the pathological comment behavior we've noticed so far.
author | David A. Holland |
---|---|
date | Sun, 31 Mar 2013 01:04:43 -0400 |
parents | 337110e7240a |
children | 90c6052410ce |
line wrap: on
line diff
--- 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) {