diff options
Diffstat (limited to 'char.c')
| -rw-r--r-- | char.c | 131 |
1 files changed, 131 insertions, 0 deletions
@@ -0,0 +1,131 @@ +#include <string.h> +#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; +} |
