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