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