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) {