76 if (no_lineno)
77 pos.line = 123456;
78
79 pos.noexpand = 0;
80 return pos;
81 }
82
83 const char *show_special(int val)
84 {
85 static char buffer[4];
86
87 buffer[0] = val;
88 buffer[1] = 0;
89 if (val >= SPECIAL_BASE)
90 strcpy(buffer, (char *) combinations[val - SPECIAL_BASE]);
91 return buffer;
92 }
93
94 const char *show_ident(const struct ident *ident)
95 {
96 static char buffer[256];
97 if (!ident)
98 return "<noident>";
99 sprintf(buffer, "%.*s", ident->len, ident->name);
100 return buffer;
101 }
102
103 static char *charstr(char *ptr, unsigned char c, unsigned char escape, unsigned char next)
104 {
105 if (isprint(c)) {
106 if (c == escape || c == '\\')
107 *ptr++ = '\\';
108 *ptr++ = c;
109 return ptr;
110 }
111 *ptr++ = '\\';
112 switch (c) {
113 case '\n':
114 *ptr++ = 'n';
115 return ptr;
116 case '\t':
117 *ptr++ = 't';
118 return ptr;
119 }
120 if (!isdigit(next))
121 return ptr + sprintf(ptr, "%o", c);
122
123 return ptr + sprintf(ptr, "%03o", c);
124 }
125
126 const char *show_string(const struct string *string)
127 {
128 static char buffer[4 * MAX_STRING + 3];
129 char *ptr;
130 int i;
131
132 if (!string->length)
133 return "<bad_string>";
134 ptr = buffer;
135 *ptr++ = '"';
136 for (i = 0; i < string->length-1; i++) {
137 const char *p = string->data + i;
138 ptr = charstr(ptr, p[0], '"', p[1]);
139 }
140 *ptr++ = '"';
141 *ptr = '\0';
142 return buffer;
143 }
144
145 static const char *show_char(const char *s, size_t len, char prefix, char delim)
146 {
147 static char buffer[MAX_STRING + 4];
148 char *p = buffer;
149 if (prefix)
150 *p++ = prefix;
151 *p++ = delim;
152 memcpy(p, s, len);
432 int c = stream->buffer[offset++];
433 static const char special[256] = {
434 ['\t'] = 1, ['\r'] = 1, ['\n'] = 1, ['\\'] = 1
435 };
436 if (!special[c]) {
437 stream->offset = offset;
438 stream->pos++;
439 return c;
440 }
441 }
442 return nextchar_slow(stream);
443 }
444
445 struct token eof_token_entry;
446
447 static struct token *mark_eof(stream_t *stream)
448 {
449 struct token *end;
450
451 end = alloc_token(stream);
452 token_type(end) = TOKEN_STREAMEND;
453 end->pos.newline = 1;
454
455 eof_token_entry.next = &eof_token_entry;
456 eof_token_entry.pos.newline = 1;
457
458 end->next = &eof_token_entry;
459 *stream->tokenlist = end;
460 stream->tokenlist = NULL;
461 return end;
462 }
463
464 static void add_token(stream_t *stream)
465 {
466 struct token *token = stream->token;
467
468 stream->token = NULL;
469 token->next = NULL;
470 *stream->tokenlist = token;
471 stream->tokenlist = &token->next;
472 }
473
474 static void drop_token(stream_t *stream)
475 {
476 stream->newline |= stream->token->pos.newline;
477 stream->whitespace |= stream->token->pos.whitespace;
478 stream->token = NULL;
479 }
480
481 enum {
482 Letter = 1,
483 Digit = 2,
484 Hex = 4,
485 Exp = 8,
486 Dot = 16,
487 ValidSecond = 32,
488 Quote = 64,
489 };
490
491 static const long cclass[257] = {
492 ['0' + 1 ... '7' + 1] = Digit | Hex, /* \<octal> */
493 ['8' + 1 ... '9' + 1] = Digit | Hex,
494 ['A' + 1 ... 'D' + 1] = Letter | Hex,
495 ['E' + 1] = Letter | Hex | Exp, /* E<exp> */
496 ['F' + 1] = Letter | Hex,
497 ['G' + 1 ... 'O' + 1] = Letter,
498 ['P' + 1] = Letter | Exp, /* P<exp> */
499 ['Q' + 1 ... 'Z' + 1] = Letter,
500 ['a' + 1 ... 'b' + 1] = Letter | Hex, /* \a, \b */
501 ['c' + 1 ... 'd' + 1] = Letter | Hex,
502 ['e' + 1] = Letter | Hex | Exp,/* \e, e<exp> */
503 ['f' + 1] = Letter | Hex, /* \f */
504 ['g' + 1 ... 'm' + 1] = Letter,
505 ['n' + 1] = Letter, /* \n */
506 ['o' + 1] = Letter,
507 ['p' + 1] = Letter | Exp, /* p<exp> */
508 ['q' + 1] = Letter,
509 ['r' + 1] = Letter, /* \r */
510 ['s' + 1] = Letter,
511 ['t' + 1] = Letter, /* \t */
512 ['u' + 1] = Letter,
513 ['v' + 1] = Letter, /* \v */
514 ['w' + 1] = Letter,
515 ['x' + 1] = Letter, /* \x<hex> */
516 ['y' + 1 ... 'z' + 1] = Letter,
517 ['_' + 1] = Letter,
518 ['.' + 1] = Dot | ValidSecond,
519 ['=' + 1] = ValidSecond,
520 ['+' + 1] = ValidSecond,
521 ['-' + 1] = ValidSecond,
522 ['>' + 1] = ValidSecond,
523 ['<' + 1] = ValidSecond,
524 ['&' + 1] = ValidSecond,
525 ['|' + 1] = ValidSecond,
526 ['#' + 1] = ValidSecond,
527 ['\'' + 1] = Quote,
528 ['"' + 1] = Quote,
529 };
530
531 /*
532 * pp-number:
533 * digit
534 * . digit
535 * pp-number digit
536 * pp-number identifier-nodigit
537 * pp-number e sign
538 * pp-number E sign
539 * pp-number p sign
540 * pp-number P sign
541 * pp-number .
542 */
543 static int get_one_number(int c, int next, stream_t *stream)
544 {
545 struct token *token;
546 static char buffer[4095];
547 char *p = buffer, *buf, *buffer_end = buffer + sizeof (buffer);
548 int len;
549
550 *p++ = c;
551 for (;;) {
552 long class = cclass[next + 1];
553 if (!(class & (Dot | Digit | Letter)))
554 break;
555 if (p != buffer_end)
556 *p++ = next;
557 next = nextchar(stream);
558 if (class & Exp) {
559 if (next == '-' || next == '+') {
560 if (p != buffer_end)
561 *p++ = next;
562 next = nextchar(stream);
563 }
564 }
565 }
566
567 if (p == buffer_end) {
568 sparse_error(stream_pos(stream), "number token exceeds %td characters",
569 buffer_end - buffer);
570 // Pretend we saw just "1".
571 buffer[0] = '1';
572 p = buffer + 1;
573 }
574
575 *p++ = 0;
576 len = p - buffer;
577 buf = __alloc_bytes(len);
578 memcpy(buf, buffer, len);
579
580 token = stream->token;
581 token_type(token) = TOKEN_NUMBER;
582 token->number = buf;
583 add_token(stream);
584
585 return next;
586 }
587
588 static int eat_string(int next, stream_t *stream, enum token_type type)
589 {
590 static char buffer[MAX_STRING];
591 struct string *string;
592 struct token *token = stream->token;
593 int len = 0;
594 int escape;
595 int want_hex = 0;
596 char delim = type < TOKEN_STRING ? '\'' : '"';
597
598 for (escape = 0; escape || next != delim; next = nextchar(stream)) {
599 if (len < MAX_STRING)
600 buffer[len] = next;
601 len++;
602 if (next == '\n') {
603 warning(stream_pos(stream),
604 "Newline in string or character constant");
605 if (delim == '\'') /* assume it's lost ' */
606 break;
607 }
608 if (next == EOF) {
609 warning(stream_pos(stream),
610 "End of file in middle of string");
611 return next;
612 }
613 if (!escape) {
614 if (want_hex && !(cclass[next + 1] & Hex))
615 warning(stream_pos(stream),
616 "\\x used with no following hex digits");
617 want_hex = 0;
618 escape = next == '\\';
619 } else {
620 escape = 0;
621 want_hex = next == 'x';
622 }
623 }
624 if (want_hex)
625 warning(stream_pos(stream),
|
76 if (no_lineno)
77 pos.line = 123456;
78
79 pos.noexpand = 0;
80 return pos;
81 }
82
83 const char *show_special(int val)
84 {
85 static char buffer[4];
86
87 buffer[0] = val;
88 buffer[1] = 0;
89 if (val >= SPECIAL_BASE)
90 strcpy(buffer, (char *) combinations[val - SPECIAL_BASE]);
91 return buffer;
92 }
93
94 const char *show_ident(const struct ident *ident)
95 {
96 static char buff[4][256];
97 static int n;
98 char *buffer;
99
100 if (!ident)
101 return "<noident>";
102 buffer = buff[3 & ++n];
103 sprintf(buffer, "%.*s", ident->len, ident->name);
104 return buffer;
105 }
106
107 static char *charstr(char *ptr, unsigned char c, unsigned char escape, unsigned char next)
108 {
109 if (isprint(c)) {
110 if (c == escape || c == '\\')
111 *ptr++ = '\\';
112 *ptr++ = c;
113 return ptr;
114 }
115 *ptr++ = '\\';
116 switch (c) {
117 case '\n':
118 *ptr++ = 'n';
119 return ptr;
120 case '\t':
121 *ptr++ = 't';
122 return ptr;
123 }
124 if (!isdigit(next))
125 return ptr + sprintf(ptr, "%o", c);
126
127 return ptr + sprintf(ptr, "%03o", c);
128 }
129
130 const char *show_string(const struct string *string)
131 {
132 static char buffer[4 * MAX_STRING + 3];
133 char *ptr;
134 int i;
135
136 if (!string || !string->length)
137 return "<bad_string>";
138 ptr = buffer;
139 *ptr++ = '"';
140 for (i = 0; i < string->length-1; i++) {
141 const char *p = string->data + i;
142 ptr = charstr(ptr, p[0], '"', p[1]);
143 }
144 *ptr++ = '"';
145 *ptr = '\0';
146 return buffer;
147 }
148
149 static const char *show_char(const char *s, size_t len, char prefix, char delim)
150 {
151 static char buffer[MAX_STRING + 4];
152 char *p = buffer;
153 if (prefix)
154 *p++ = prefix;
155 *p++ = delim;
156 memcpy(p, s, len);
436 int c = stream->buffer[offset++];
437 static const char special[256] = {
438 ['\t'] = 1, ['\r'] = 1, ['\n'] = 1, ['\\'] = 1
439 };
440 if (!special[c]) {
441 stream->offset = offset;
442 stream->pos++;
443 return c;
444 }
445 }
446 return nextchar_slow(stream);
447 }
448
449 struct token eof_token_entry;
450
451 static struct token *mark_eof(stream_t *stream)
452 {
453 struct token *end;
454
455 end = alloc_token(stream);
456 eof_token_entry.pos = end->pos;
457 token_type(end) = TOKEN_STREAMEND;
458 end->pos.newline = 1;
459
460 eof_token_entry.next = &eof_token_entry;
461 eof_token_entry.pos.newline = 1;
462
463 end->next = &eof_token_entry;
464 *stream->tokenlist = end;
465 stream->tokenlist = NULL;
466 return end;
467 }
468
469 static void add_token(stream_t *stream)
470 {
471 struct token *token = stream->token;
472
473 stream->token = NULL;
474 token->next = NULL;
475 *stream->tokenlist = token;
476 stream->tokenlist = &token->next;
477 }
478
479 static void drop_token(stream_t *stream)
480 {
481 stream->newline |= stream->token->pos.newline;
482 stream->whitespace |= stream->token->pos.whitespace;
483 stream->token = NULL;
484 }
485
486 enum {
487 Letter = 1,
488 Digit = 2,
489 Hex = 4,
490 Exp = 8,
491 Dot = 16,
492 ValidSecond = 32,
493 Quote = 64,
494 };
495
496 static const char cclass[257] = {
497 ['0' + 1 ... '9' + 1] = Digit | Hex,
498 ['A' + 1 ... 'D' + 1] = Letter | Hex,
499 ['E' + 1] = Letter | Hex | Exp, /* E<exp> */
500 ['F' + 1] = Letter | Hex,
501 ['G' + 1 ... 'O' + 1] = Letter,
502 ['P' + 1] = Letter | Exp, /* P<exp> */
503 ['Q' + 1 ... 'Z' + 1] = Letter,
504 ['a' + 1 ... 'd' + 1] = Letter | Hex,
505 ['e' + 1] = Letter | Hex | Exp, /* e<exp> */
506 ['f' + 1] = Letter | Hex,
507 ['g' + 1 ... 'o' + 1] = Letter,
508 ['p' + 1] = Letter | Exp, /* p<exp> */
509 ['q' + 1 ... 'z' + 1] = Letter,
510 ['_' + 1] = Letter,
511 ['.' + 1] = Dot | ValidSecond,
512 ['=' + 1] = ValidSecond,
513 ['+' + 1] = ValidSecond,
514 ['-' + 1] = ValidSecond,
515 ['>' + 1] = ValidSecond,
516 ['<' + 1] = ValidSecond,
517 ['&' + 1] = ValidSecond,
518 ['|' + 1] = ValidSecond,
519 ['#' + 1] = ValidSecond,
520 ['\'' + 1] = Quote,
521 ['"' + 1] = Quote,
522 };
523
524 /*
525 * pp-number:
526 * digit
527 * . digit
528 * pp-number digit
529 * pp-number identifier-nodigit
530 * pp-number e sign
531 * pp-number E sign
532 * pp-number p sign
533 * pp-number P sign
534 * pp-number .
535 */
536 static int get_one_number(int c, int next, stream_t *stream)
537 {
538 struct token *token;
539 static char buffer[4095];
540 char *p = buffer, *buffer_end = buffer + sizeof (buffer);
541
542 *p++ = c;
543 for (;;) {
544 long class = cclass[next + 1];
545 if (!(class & (Dot | Digit | Letter)))
546 break;
547 if (p != buffer_end)
548 *p++ = next;
549 next = nextchar(stream);
550 if (class & Exp) {
551 if (next == '-' || next == '+') {
552 if (p != buffer_end)
553 *p++ = next;
554 next = nextchar(stream);
555 }
556 }
557 }
558
559 if (p == buffer_end) {
560 sparse_error(stream_pos(stream), "number token exceeds %td characters",
561 buffer_end - buffer);
562 // Pretend we saw just "1".
563 buffer[0] = '1';
564 p = buffer + 1;
565 }
566
567 *p++ = 0;
568 token = stream->token;
569 token_type(token) = TOKEN_NUMBER;
570 token->number = xmemdup(buffer, p - buffer);
571 add_token(stream);
572
573 return next;
574 }
575
576 static int eat_string(int next, stream_t *stream, enum token_type type)
577 {
578 static char buffer[MAX_STRING];
579 struct string *string;
580 struct token *token = stream->token;
581 int len = 0;
582 int escape;
583 int want_hex = 0;
584 char delim = type < TOKEN_STRING ? '\'' : '"';
585
586 for (escape = 0; escape || next != delim; next = nextchar(stream)) {
587 if (len < MAX_STRING)
588 buffer[len] = next;
589 len++;
590 if (next == '\n') {
591 warning(stream_pos(stream),
592 "missing terminating %c character", delim);
593 /* assume delimiter is lost */
594 break;
595 }
596 if (next == EOF) {
597 warning(stream_pos(stream),
598 "End of file in middle of string");
599 return next;
600 }
601 if (!escape) {
602 if (want_hex && !(cclass[next + 1] & Hex))
603 warning(stream_pos(stream),
604 "\\x used with no following hex digits");
605 want_hex = 0;
606 escape = next == '\\';
607 } else {
608 escape = 0;
609 want_hex = next == 'x';
610 }
611 }
612 if (want_hex)
613 warning(stream_pos(stream),
|