Mercurial > ~dholland > hg > tradcpp > index.cgi
comparison 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 |
comparison
equal
deleted
inserted
replaced
48:0af03c5571e0 | 49:8a204d153398 |
---|---|
37 #include "place.h" | 37 #include "place.h" |
38 #include "files.h" | 38 #include "files.h" |
39 #include "directive.h" | 39 #include "directive.h" |
40 #include "macro.h" | 40 #include "macro.h" |
41 #include "eval.h" | 41 #include "eval.h" |
42 #include "output.h" | |
42 | 43 |
43 struct ifstate { | 44 struct ifstate { |
44 struct ifstate *prev; | 45 struct ifstate *prev; |
45 struct place startplace; | 46 struct place startplace; |
46 bool curtrue; | 47 bool curtrue; |
47 bool evertrue; | 48 bool evertrue; |
48 bool seenelse; | 49 bool seenelse; |
49 }; | 50 }; |
50 | 51 |
51 static struct ifstate *ifstate; | 52 static struct ifstate *ifstate; |
53 static bool in_multiline_comment; | |
52 | 54 |
53 //////////////////////////////////////////////////////////// | 55 //////////////////////////////////////////////////////////// |
54 // common parsing bits | 56 // common parsing bits |
55 | 57 |
56 static | 58 static |
406 skip = strcspn(line, ws); | 408 skip = strcspn(line, ws); |
407 complain(p, "Unknown directive #%.*s", (int)skip, line); | 409 complain(p, "Unknown directive #%.*s", (int)skip, line); |
408 complain_fail(); | 410 complain_fail(); |
409 } | 411 } |
410 | 412 |
413 /* | |
414 * If desired, warn about a nested comment. The comment begins at | |
415 * offset POS from the place P. | |
416 */ | |
417 static | |
418 void | |
419 warn_nestcomment(const struct place *p, size_t pos) | |
420 { | |
421 struct place p2; | |
422 | |
423 if (warns.nestcomment) { | |
424 p2 = *p; | |
425 p2.column += pos; | |
426 complain(p, "Warning: %c%c within comment", | |
427 '/', '*'); | |
428 if (mode.werror) { | |
429 complain_failed(); | |
430 } | |
431 } | |
432 } | |
433 | |
434 /* | |
435 * Check for comment delimiters in LINE. If a multi-line comment is | |
436 * continuing or ending, set ACOMM to its length. If a multi-line | |
437 * comment is starting, set BCOMM to its length. Set TEXT to the | |
438 * length of text that is not commented out, or that contains comments | |
439 * that both begin and end on this line. ACOMM + TEXT + BCOMM == LEN. | |
440 * | |
441 * Updates in_multiline_comment to the appropriate state for after | |
442 * this line is handled. | |
443 */ | |
444 static | |
445 size_t | |
446 directive_scancomments(const struct place *p, char *line, size_t len, | |
447 size_t *acomm, size_t *text, size_t *bcomm) | |
448 { | |
449 size_t pos; | |
450 size_t first_commentend; | |
451 size_t last_commentstart; | |
452 bool incomment; | |
453 | |
454 first_commentend = len; | |
455 last_commentstart = len; | |
456 incomment = in_multiline_comment; | |
457 for (pos = 0; pos+1 < len; pos++) { | |
458 if (line[pos] == '/' && line[pos+1] == '*') { | |
459 if (incomment) { | |
460 warn_nestcomment(p, pos); | |
461 } else { | |
462 incomment = true; | |
463 last_commentstart = pos; | |
464 } | |
465 } else if (line[pos] == '*' && line[pos+1] == '/') { | |
466 if (incomment) { | |
467 incomment = false; | |
468 if (first_commentend == len) { | |
469 first_commentend = pos; | |
470 } | |
471 last_commentstart = len; | |
472 } else { | |
473 /* stray end-comment; should we care? */ | |
474 } | |
475 } | |
476 } | |
477 | |
478 if (in_multiline_comment && first_commentend < last_commentstart) { | |
479 /* multiline comment ends */ | |
480 /* first_commentend points to the star, adjust */ | |
481 *acomm = first_commentend + 2; | |
482 *text = len - *acomm; | |
483 } else if (in_multiline_comment) { | |
484 /* comment did not end, so another one cannot have started */ | |
485 assert(last_commentstart == len); | |
486 *acomm = len; | |
487 *text = 0; | |
488 } else { | |
489 *acomm = 0; | |
490 *text = len; | |
491 } | |
492 | |
493 *bcomm = len - last_commentstart; | |
494 *text -= *bcomm; | |
495 | |
496 in_multiline_comment = incomment; | |
497 return len; | |
498 } | |
499 | |
411 void | 500 void |
412 directive_gotline(struct place *p, char *line, size_t len) | 501 directive_gotline(struct place *p, char *line, size_t len) |
413 { | 502 { |
503 size_t acomm; /* length of comment ending on this line */ | |
504 size_t text; /* length of non-multi-line-comment text */ | |
505 size_t bcomm; /* length of comment beginning on this line */ | |
414 size_t skip; | 506 size_t skip; |
415 | 507 |
508 directive_scancomments(p, line, len, &acomm, &text, &bcomm); | |
509 | |
510 if (acomm > 0) { | |
511 if (mode.output_retain_comments && ifstate->curtrue) { | |
512 /* | |
513 * Do not expand the comment; send it straight | |
514 * to the output. This will cause it to appear | |
515 * first if we're partway through collecting a | |
516 * macro argument. Too bad. This isn't a | |
517 * standard mode anyway. | |
518 */ | |
519 output(p, line, acomm); | |
520 } | |
521 p->column += acomm; | |
522 } | |
523 | |
416 /* check if we have a directive line */ | 524 /* check if we have a directive line */ |
417 skip = strspn(line, ws); | 525 skip = strspn(line + acomm, ws); |
418 if (line[skip] == '#') { | 526 if (acomm == 0 && line[skip] == '#') { |
419 skip = skip + 1 + strspn(line + skip + 1, ws); | 527 skip = skip + 1 + strspn(line + skip + 1, ws); |
528 assert(skip <= text); | |
420 p->column += skip; | 529 p->column += skip; |
421 directive_gotdirective(p, line+skip, len-skip); | 530 directive_gotdirective(p, line+skip, text-skip); |
531 p->column += text-skip; | |
422 } else if (ifstate->curtrue) { | 532 } else if (ifstate->curtrue) { |
423 macro_sendline(p, line, len); | 533 macro_sendline(p, line + acomm, text); |
424 } | 534 p->column += text; |
425 } | 535 } |
426 | 536 |
537 if (bcomm > 0) { | |
538 if (mode.output_retain_comments && ifstate->curtrue) { | |
539 output(p, line + acomm + text, bcomm); | |
540 } | |
541 p->column += bcomm; | |
542 } | |
543 } | |
427 | 544 |
428 void | 545 void |
429 directive_goteof(struct place *p) | 546 directive_goteof(struct place *p) |
430 { | 547 { |
431 while (ifstate->prev != NULL) { | 548 while (ifstate->prev != NULL) { |