1 #include <string.h> 2 #include "target.h" 3 #include "lib.h" 4 #include "allocate.h" 5 #include "token.h" 6 #include "expression.h" 7 #include "char.h" 8 9 static const char *parse_escape(const char *p, unsigned *val, const char *end, int bits, struct position pos) 10 { 11 unsigned c = *p++; 12 unsigned d; 13 if (c != '\\') { 14 *val = c; 15 return p; 16 } 17 18 c = *p++; 19 switch (c) { 20 case 'a': c = '\a'; break; 21 case 'b': c = '\b'; break; 22 case 't': c = '\t'; break; 23 case 'n': c = '\n'; break; 24 case 'v': c = '\v'; break; 25 case 'f': c = '\f'; break; 26 case 'r': c = '\r'; break; 27 case 'e': c = '\e'; break; 28 case 'x': { 29 unsigned mask = -(1U << (bits - 4)); 30 for (c = 0; p < end; c = (c << 4) + d) { 31 d = hexval(*p); 32 if (d > 16) 33 break; 34 p++; 35 if (c & mask) { 36 warning(pos, 37 "hex escape sequence out of range"); 38 mask = 0; 39 } 40 } 41 break; 42 } 43 case '0'...'7': { 44 if (p + 2 < end) 45 end = p + 2; 46 c -= '0'; 47 while (p < end && (d = *p - '0') < 8) { 48 c = (c << 3) + d; 49 p++; 50 } 51 if ((c & 0400) && bits < 9) 52 warning(pos, 53 "octal escape sequence out of range"); 54 break; 55 } 56 default: /* everything else is left as is */ 57 warning(pos, "unknown escape sequence: '\\%c'", c); 58 break; 59 case '\\': 60 case '\'': 61 case '"': 62 case '?': 63 break; /* those are legal, so no warnings */ 64 } 65 *val = c & ~((~0U << (bits - 1)) << 1); 66 return p; 67 } 68 69 void get_char_constant(struct token *token, unsigned long long *val) 70 { 71 const char *p = token->embedded, *end; 72 unsigned v; 73 int type = token_type(token); 74 switch (type) { 75 case TOKEN_CHAR: 76 case TOKEN_WIDE_CHAR: 77 p = token->string->data; 78 end = p + token->string->length - 1; 79 break; 80 case TOKEN_CHAR_EMBEDDED_0 ... TOKEN_CHAR_EMBEDDED_3: 81 end = p + type - TOKEN_CHAR; 82 break; 83 default: 84 end = p + type - TOKEN_WIDE_CHAR; 85 } 86 p = parse_escape(p, &v, end, 87 type < TOKEN_WIDE_CHAR ? bits_in_char : wchar_ctype->bit_size, token->pos); 88 if (p != end) 89 warning(token->pos, 90 "multi-character character constant"); 91 *val = v; 92 } 93 94 struct token *get_string_constant(struct token *token, struct expression *expr) 95 { 96 struct string *string = token->string; 97 struct token *next = token->next, *done = NULL; 98 int stringtype = token_type(token); 99 int is_wide = stringtype == TOKEN_WIDE_STRING; 100 static char buffer[MAX_STRING]; 101 int len = 0; 102 int bits; 103 int esc_count = 0; 104 105 while (!done) { 106 switch (token_type(next)) { 107 case TOKEN_WIDE_STRING: 108 is_wide = 1; 109 case TOKEN_STRING: 110 next = next->next; 111 break; 112 default: 113 done = next; 114 } 115 } 116 bits = is_wide ? wchar_ctype->bit_size: bits_in_char; 117 while (token != done) { 118 unsigned v; 119 const char *p = token->string->data; 120 const char *end = p + token->string->length - 1; 121 while (p < end) { 122 if (*p == '\\') 123 esc_count++; 124 p = parse_escape(p, &v, end, bits, token->pos); 125 if (len < MAX_STRING) 126 buffer[len] = v; 127 len++; 128 } 129 token = token->next; 130 } 131 if (len > MAX_STRING) { 132 warning(token->pos, "trying to concatenate %d-character string (%d bytes max)", len, MAX_STRING); 133 len = MAX_STRING; 134 } 135 136 if (esc_count || len >= string->length) { 137 if (string->immutable || len >= string->length) /* can't cannibalize */ 138 string = __alloc_string(len+1); 139 string->length = len+1; 140 memcpy(string->data, buffer, len); 141 string->data[len] = '\0'; 142 } 143 expr->string = string; 144 expr->wide = is_wide; 145 return token; 146 } 147