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 9static 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 69void 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 if (end == p) { 80 sparse_error(token->pos, "empty character constant"); 81 *val = 0; 82 return; 83 } 84 break; 85 case TOKEN_CHAR_EMBEDDED_0 ... TOKEN_CHAR_EMBEDDED_3: 86 end = p + type - TOKEN_CHAR; 87 break; 88 default: 89 end = p + type - TOKEN_WIDE_CHAR; 90 } 91 p = parse_escape(p, &v, end, 92 type < TOKEN_WIDE_CHAR ? bits_in_char : wchar_ctype->bit_size, token->pos); 93 if (p != end) 94 warning(token->pos, 95 "multi-character character constant"); 96 *val = v; 97} 98 99struct token *get_string_constant(struct token *token, struct expression *expr) 100{ 101 struct string *string = token->string; 102 struct token *next = token->next, *done = NULL; 103 int stringtype = token_type(token); 104 int is_wide = stringtype == TOKEN_WIDE_STRING; 105 static char buffer[MAX_STRING]; 106 int len = 0; 107 int bits; 108 int esc_count = 0; 109 110 while (!done) { 111 switch (token_type(next)) { 112 case TOKEN_WIDE_STRING: 113 is_wide = 1; 114 case TOKEN_STRING: 115 next = next->next; 116 break; 117 default: 118 done = next; 119 } 120 } 121 bits = is_wide ? wchar_ctype->bit_size: bits_in_char; 122 while (token != done) { 123 unsigned v; 124 const char *p = token->string->data; 125 const char *end = p + token->string->length - 1; 126 while (p < end) { 127 if (*p == '\\') 128 esc_count++; 129 p = parse_escape(p, &v, end, bits, token->pos); 130 if (len < MAX_STRING) 131 buffer[len] = v; 132 len++; 133 } 134 token = token->next; 135 } 136 if (len > MAX_STRING) { 137 warning(token->pos, "trying to concatenate %d-character string (%d bytes max)", len, MAX_STRING); 138 len = MAX_STRING; 139 } 140 141 if (esc_count || len >= string->length) { 142 if (string->immutable || len >= string->length) /* can't cannibalize */ 143 string = __alloc_string(len+1); 144 string->length = len+1; 145 memcpy(string->data, buffer, len); 146 string->data[len] = '\0'; 147 } 148 expr->string = string; 149 expr->wide = is_wide; 150 return token; 151} 152