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