aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/char.c
diff options
Diffstat (limited to 'char.c')
-rw-r--r--char.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/char.c b/char.c
new file mode 100644
index 00000000..92674565
--- /dev/null
+++ b/char.c
@@ -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;
+}