#include #include "target.h" #include "lib.h" #include "allocate.h" #include "token.h" #include "expression.h" static const char *parse_escape(const char *p, unsigned *val, const char *end, int bits, struct position pos) { unsigned c = *p++; unsigned d; if (c != '\\') { *val = c; return p; } c = *p++; switch (c) { case 'a': c = '\a'; break; case 'b': c = '\b'; break; case 't': c = '\t'; break; case 'n': c = '\n'; break; case 'v': c = '\v'; break; case 'f': c = '\f'; break; case 'r': c = '\r'; break; case 'e': c = '\e'; break; case 'x': { unsigned mask = -(1U << (bits - 4)); for (c = 0; p < end; c = (c << 4) + d) { d = hexval(*p++); if (d > 16) break; if (c & mask) { warning(pos, "hex escape sequence out of range"); mask = 0; } } break; } case '0'...'7': { if (p + 2 < end) end = p + 2; c -= '0'; while (p < end && (d = *p++ - '0') < 8) c = (c << 3) + d; if ((c & 0400) && bits < 9) warning(pos, "octal escape sequence out of range"); break; } default: /* everything else is left as is */ break; } *val = c & ~((~0U << (bits - 1)) << 1); return p; } void get_char_constant(struct token *token, unsigned long long *val) { const char *p = token->embedded, *end; unsigned v; int type = token_type(token); switch (type) { case TOKEN_CHAR: case TOKEN_WIDE_CHAR: p = token->string->data; end = p + token->string->length; break; case TOKEN_CHAR + 1 ... TOKEN_CHAR + 4: end = p + type - TOKEN_CHAR; break; default: end = p + type - TOKEN_WIDE_CHAR; } p = parse_escape(p, &v, end, type < TOKEN_WIDE_CHAR ? bits_in_char : 32, token->pos); if (p != end) warning(token->pos, "multi-character character constant"); *val = v; } struct token *get_string_constant(struct token *token, struct expression *expr) { struct string *string = token->string; struct token *next = token->next, *done = NULL; int stringtype = token_type(token); int is_wide = stringtype == TOKEN_WIDE_STRING; static char buffer[MAX_STRING]; int len = 0; int bits; while (!done) { switch (token_type(next)) { case TOKEN_WIDE_STRING: is_wide = 1; case TOKEN_STRING: next = next->next; break; default: done = next; } } bits = is_wide ? 32 : bits_in_char; while (token != done) { unsigned v; const char *p = token->string->data; const char *end = p + token->string->length - 1; while (p < end) { p = parse_escape(p, &v, end, bits, token->pos); if (len < MAX_STRING) buffer[len] = v; len++; } token = token->next; } if (len > MAX_STRING) { warning(token->pos, "trying to concatenate %d-character string (%d bytes max)", len, MAX_STRING); len = MAX_STRING; } if (len >= string->length) /* can't cannibalize */ string = __alloc_string(len+1); string->length = len+1; memcpy(string->data, buffer, len); string->data[len] = '\0'; expr->string = string; expr->wide = is_wide; return token; }