]>
Commit | Line | Data |
---|---|---|
f2b63869 CH |
1 | /* Parse C expressions for CCCP. |
2 | Copyright (C) 1987, 1992 Free Software Foundation. | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify it | |
5 | under the terms of the GNU General Public License as published by the | |
6 | Free Software Foundation; either version 2, or (at your option) any | |
7 | later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
17 | ||
18 | In other words, you are welcome to use, share and improve this program. | |
19 | You are forbidden to forbid anyone else to use, share and improve | |
20 | what you give them. Help stamp out software-hoarding! | |
21 | ||
960e4c1c | 22 | Adapted from expread.y of GDB by Paul Rubin, July 1986. */ |
f2b63869 CH |
23 | |
24 | /* Parse a C expression from text in a string */ | |
25 | ||
26 | %{ | |
27 | #include "config.h" | |
28 | #include <setjmp.h> | |
29 | /* #define YYDEBUG 1 */ | |
30 | ||
31 | #ifdef MULTIBYTE_CHARS | |
32 | #include <stdlib.h> | |
33 | #include <locale.h> | |
34 | #endif | |
35 | ||
5e0004ae RS |
36 | #include <stdio.h> |
37 | ||
f2b63869 CH |
38 | typedef unsigned char U_CHAR; |
39 | ||
40 | /* This is used for communicating lists of keywords with cccp.c. */ | |
41 | struct arglist { | |
42 | struct arglist *next; | |
43 | U_CHAR *name; | |
44 | int length; | |
45 | int argno; | |
46 | }; | |
47 | ||
d6927cc9 TW |
48 | /* Define a generic NULL if one hasn't already been defined. */ |
49 | ||
f2b63869 CH |
50 | #ifndef NULL |
51 | #define NULL 0 | |
52 | #endif | |
53 | ||
d6927cc9 TW |
54 | #ifndef GENERIC_PTR |
55 | #if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) | |
56 | #define GENERIC_PTR void * | |
57 | #else | |
58 | #define GENERIC_PTR char * | |
59 | #endif | |
60 | #endif | |
61 | ||
f2b63869 | 62 | #ifndef NULL_PTR |
d6927cc9 | 63 | #define NULL_PTR ((GENERIC_PTR)0) |
f2b63869 CH |
64 | #endif |
65 | ||
66 | int yylex (); | |
67 | void yyerror (); | |
68 | int expression_value; | |
69 | ||
70 | static jmp_buf parse_return_error; | |
71 | ||
72 | /* Nonzero means count most punctuation as part of a name. */ | |
73 | static int keyword_parsing = 0; | |
74 | ||
75 | /* some external tables of character types */ | |
76 | extern unsigned char is_idstart[], is_idchar[], is_hor_space[]; | |
77 | ||
58c8c593 RK |
78 | extern char *xmalloc (); |
79 | ||
f2b63869 CH |
80 | /* Flag for -pedantic. */ |
81 | extern int pedantic; | |
82 | ||
83 | /* Flag for -traditional. */ | |
84 | extern int traditional; | |
85 | ||
86 | #ifndef CHAR_TYPE_SIZE | |
87 | #define CHAR_TYPE_SIZE BITS_PER_UNIT | |
88 | #endif | |
89 | ||
90 | #ifndef INT_TYPE_SIZE | |
91 | #define INT_TYPE_SIZE BITS_PER_WORD | |
92 | #endif | |
93 | ||
94 | #ifndef LONG_TYPE_SIZE | |
95 | #define LONG_TYPE_SIZE BITS_PER_WORD | |
96 | #endif | |
97 | ||
98 | #ifndef WCHAR_TYPE_SIZE | |
99 | #define WCHAR_TYPE_SIZE INT_TYPE_SIZE | |
100 | #endif | |
4cf8de9f RS |
101 | |
102 | /* Yield nonzero if adding two numbers with A's and B's signs can yield a | |
103 | number with SUM's sign, where A, B, and SUM are all C integers. */ | |
104 | #define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0) | |
105 | ||
106 | static void integer_overflow (); | |
107 | static long left_shift (); | |
108 | static long right_shift (); | |
f2b63869 CH |
109 | %} |
110 | ||
111 | %union { | |
112 | struct constant {long value; int unsignedp;} integer; | |
113 | struct name {U_CHAR *address; int length;} name; | |
114 | struct arglist *keywords; | |
115 | int voidval; | |
116 | char *sval; | |
117 | } | |
118 | ||
119 | %type <integer> exp exp1 start | |
120 | %type <keywords> keywords | |
121 | %token <integer> INT CHAR | |
122 | %token <name> NAME | |
123 | %token <integer> ERROR | |
124 | ||
125 | %right '?' ':' | |
126 | %left ',' | |
127 | %left OR | |
128 | %left AND | |
129 | %left '|' | |
130 | %left '^' | |
131 | %left '&' | |
132 | %left EQUAL NOTEQUAL | |
133 | %left '<' '>' LEQ GEQ | |
134 | %left LSH RSH | |
135 | %left '+' '-' | |
136 | %left '*' '/' '%' | |
137 | %right UNARY | |
138 | ||
139 | /* %expect 40 */ | |
140 | \f | |
141 | %% | |
142 | ||
143 | start : exp1 | |
144 | { expression_value = $1.value; } | |
145 | ; | |
146 | ||
147 | /* Expressions, including the comma operator. */ | |
148 | exp1 : exp | |
149 | | exp1 ',' exp | |
150 | { if (pedantic) | |
151 | pedwarn ("comma operator in operand of `#if'"); | |
152 | $$ = $3; } | |
153 | ; | |
154 | ||
155 | /* Expressions, not including the comma operator. */ | |
156 | exp : '-' exp %prec UNARY | |
157 | { $$.value = - $2.value; | |
4cf8de9f RS |
158 | if (($$.value & $2.value) < 0 && ! $2.unsignedp) |
159 | integer_overflow (); | |
f2b63869 CH |
160 | $$.unsignedp = $2.unsignedp; } |
161 | | '!' exp %prec UNARY | |
162 | { $$.value = ! $2.value; | |
163 | $$.unsignedp = 0; } | |
164 | | '+' exp %prec UNARY | |
165 | { $$ = $2; } | |
166 | | '~' exp %prec UNARY | |
167 | { $$.value = ~ $2.value; | |
168 | $$.unsignedp = $2.unsignedp; } | |
169 | | '#' NAME | |
170 | { $$.value = check_assertion ($2.address, $2.length, | |
171 | 0, NULL_PTR); | |
172 | $$.unsignedp = 0; } | |
173 | | '#' NAME | |
174 | { keyword_parsing = 1; } | |
175 | '(' keywords ')' | |
176 | { $$.value = check_assertion ($2.address, $2.length, | |
177 | 1, $5); | |
178 | keyword_parsing = 0; | |
179 | $$.unsignedp = 0; } | |
180 | | '(' exp1 ')' | |
181 | { $$ = $2; } | |
182 | ; | |
183 | ||
184 | /* Binary operators in order of decreasing precedence. */ | |
185 | exp : exp '*' exp | |
186 | { $$.unsignedp = $1.unsignedp || $3.unsignedp; | |
187 | if ($$.unsignedp) | |
4cf8de9f | 188 | $$.value = (unsigned long) $1.value * $3.value; |
f2b63869 | 189 | else |
4cf8de9f RS |
190 | { |
191 | $$.value = $1.value * $3.value; | |
192 | if ($1.value | |
193 | && ($$.value / $1.value != $3.value | |
194 | || ($$.value & $1.value & $3.value) < 0)) | |
195 | integer_overflow (); | |
196 | } } | |
f2b63869 CH |
197 | | exp '/' exp |
198 | { if ($3.value == 0) | |
199 | { | |
200 | error ("division by zero in #if"); | |
201 | $3.value = 1; | |
202 | } | |
203 | $$.unsignedp = $1.unsignedp || $3.unsignedp; | |
204 | if ($$.unsignedp) | |
4cf8de9f | 205 | $$.value = (unsigned long) $1.value / $3.value; |
f2b63869 | 206 | else |
4cf8de9f RS |
207 | { |
208 | $$.value = $1.value / $3.value; | |
209 | if (($$.value & $1.value & $3.value) < 0) | |
210 | integer_overflow (); | |
211 | } } | |
f2b63869 CH |
212 | | exp '%' exp |
213 | { if ($3.value == 0) | |
214 | { | |
215 | error ("division by zero in #if"); | |
216 | $3.value = 1; | |
217 | } | |
218 | $$.unsignedp = $1.unsignedp || $3.unsignedp; | |
219 | if ($$.unsignedp) | |
4cf8de9f | 220 | $$.value = (unsigned long) $1.value % $3.value; |
f2b63869 CH |
221 | else |
222 | $$.value = $1.value % $3.value; } | |
223 | | exp '+' exp | |
224 | { $$.value = $1.value + $3.value; | |
4cf8de9f RS |
225 | $$.unsignedp = $1.unsignedp || $3.unsignedp; |
226 | if (! $$.unsignedp | |
227 | && ! possible_sum_sign ($1.value, $3.value, | |
228 | $$.value)) | |
229 | integer_overflow (); } | |
f2b63869 CH |
230 | | exp '-' exp |
231 | { $$.value = $1.value - $3.value; | |
4cf8de9f RS |
232 | $$.unsignedp = $1.unsignedp || $3.unsignedp; |
233 | if (! $$.unsignedp | |
234 | && ! possible_sum_sign ($$.value, $3.value, | |
235 | $1.value)) | |
236 | integer_overflow (); } | |
f2b63869 CH |
237 | | exp LSH exp |
238 | { $$.unsignedp = $1.unsignedp; | |
4cf8de9f RS |
239 | if ($3.value < 0 && ! $3.unsignedp) |
240 | $$.value = right_shift (&$1, -$3.value); | |
f2b63869 | 241 | else |
4cf8de9f | 242 | $$.value = left_shift (&$1, $3.value); } |
f2b63869 CH |
243 | | exp RSH exp |
244 | { $$.unsignedp = $1.unsignedp; | |
4cf8de9f RS |
245 | if ($3.value < 0 && ! $3.unsignedp) |
246 | $$.value = left_shift (&$1, -$3.value); | |
f2b63869 | 247 | else |
4cf8de9f | 248 | $$.value = right_shift (&$1, $3.value); } |
f2b63869 CH |
249 | | exp EQUAL exp |
250 | { $$.value = ($1.value == $3.value); | |
251 | $$.unsignedp = 0; } | |
252 | | exp NOTEQUAL exp | |
253 | { $$.value = ($1.value != $3.value); | |
254 | $$.unsignedp = 0; } | |
255 | | exp LEQ exp | |
256 | { $$.unsignedp = 0; | |
257 | if ($1.unsignedp || $3.unsignedp) | |
4cf8de9f | 258 | $$.value = (unsigned long) $1.value <= $3.value; |
f2b63869 CH |
259 | else |
260 | $$.value = $1.value <= $3.value; } | |
261 | | exp GEQ exp | |
262 | { $$.unsignedp = 0; | |
263 | if ($1.unsignedp || $3.unsignedp) | |
4cf8de9f | 264 | $$.value = (unsigned long) $1.value >= $3.value; |
f2b63869 CH |
265 | else |
266 | $$.value = $1.value >= $3.value; } | |
267 | | exp '<' exp | |
268 | { $$.unsignedp = 0; | |
269 | if ($1.unsignedp || $3.unsignedp) | |
4cf8de9f | 270 | $$.value = (unsigned long) $1.value < $3.value; |
f2b63869 CH |
271 | else |
272 | $$.value = $1.value < $3.value; } | |
273 | | exp '>' exp | |
274 | { $$.unsignedp = 0; | |
275 | if ($1.unsignedp || $3.unsignedp) | |
4cf8de9f | 276 | $$.value = (unsigned long) $1.value > $3.value; |
f2b63869 CH |
277 | else |
278 | $$.value = $1.value > $3.value; } | |
279 | | exp '&' exp | |
280 | { $$.value = $1.value & $3.value; | |
281 | $$.unsignedp = $1.unsignedp || $3.unsignedp; } | |
282 | | exp '^' exp | |
283 | { $$.value = $1.value ^ $3.value; | |
284 | $$.unsignedp = $1.unsignedp || $3.unsignedp; } | |
285 | | exp '|' exp | |
286 | { $$.value = $1.value | $3.value; | |
287 | $$.unsignedp = $1.unsignedp || $3.unsignedp; } | |
288 | | exp AND exp | |
289 | { $$.value = ($1.value && $3.value); | |
290 | $$.unsignedp = 0; } | |
291 | | exp OR exp | |
292 | { $$.value = ($1.value || $3.value); | |
293 | $$.unsignedp = 0; } | |
294 | | exp '?' exp ':' exp | |
295 | { $$.value = $1.value ? $3.value : $5.value; | |
296 | $$.unsignedp = $3.unsignedp || $5.unsignedp; } | |
297 | | INT | |
298 | { $$ = yylval.integer; } | |
299 | | CHAR | |
300 | { $$ = yylval.integer; } | |
301 | | NAME | |
302 | { $$.value = 0; | |
303 | $$.unsignedp = 0; } | |
304 | ; | |
305 | ||
306 | keywords : | |
307 | { $$ = 0; } | |
308 | | '(' keywords ')' keywords | |
309 | { struct arglist *temp; | |
310 | $$ = (struct arglist *) xmalloc (sizeof (struct arglist)); | |
311 | $$->next = $2; | |
312 | $$->name = (U_CHAR *) "("; | |
313 | $$->length = 1; | |
314 | temp = $$; | |
315 | while (temp != 0 && temp->next != 0) | |
316 | temp = temp->next; | |
317 | temp->next = (struct arglist *) xmalloc (sizeof (struct arglist)); | |
318 | temp->next->next = $4; | |
319 | temp->next->name = (U_CHAR *) ")"; | |
320 | temp->next->length = 1; } | |
321 | | NAME keywords | |
322 | { $$ = (struct arglist *) xmalloc (sizeof (struct arglist)); | |
323 | $$->name = $1.address; | |
324 | $$->length = $1.length; | |
325 | $$->next = $2; } | |
326 | ; | |
327 | %% | |
328 | \f | |
329 | /* During parsing of a C expression, the pointer to the next character | |
330 | is in this variable. */ | |
331 | ||
332 | static char *lexptr; | |
333 | ||
334 | /* Take care of parsing a number (anything that starts with a digit). | |
335 | Set yylval and return the token type; update lexptr. | |
336 | LEN is the number of characters in it. */ | |
337 | ||
338 | /* maybe needs to actually deal with floating point numbers */ | |
339 | ||
340 | int | |
341 | parse_number (olen) | |
342 | int olen; | |
343 | { | |
344 | register char *p = lexptr; | |
f2b63869 | 345 | register int c; |
ce73f2a5 | 346 | register unsigned long n = 0, nd, ULONG_MAX_over_base; |
f2b63869 CH |
347 | register int base = 10; |
348 | register int len = olen; | |
ce73f2a5 | 349 | register int overflow = 0; |
3292923d | 350 | register int digit, largest_digit = 0; |
ce73f2a5 | 351 | int spec_long = 0; |
f2b63869 CH |
352 | |
353 | for (c = 0; c < len; c++) | |
354 | if (p[c] == '.') { | |
355 | /* It's a float since it contains a point. */ | |
356 | yyerror ("floating point numbers not allowed in #if expressions"); | |
357 | return ERROR; | |
358 | } | |
359 | ||
360 | yylval.integer.unsignedp = 0; | |
361 | ||
362 | if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) { | |
363 | p += 2; | |
364 | base = 16; | |
365 | len -= 2; | |
366 | } | |
367 | else if (*p == '0') | |
368 | base = 8; | |
369 | ||
ce73f2a5 RS |
370 | ULONG_MAX_over_base = (unsigned long) -1 / base; |
371 | ||
372 | for (; len > 0; len--) { | |
f2b63869 | 373 | c = *p++; |
3292923d RS |
374 | |
375 | if (c >= '0' && c <= '9') | |
376 | digit = c - '0'; | |
377 | else if (base == 16 && c >= 'a' && c <= 'f') | |
378 | digit = c - 'a' + 10; | |
379 | else if (base == 16 && c >= 'A' && c <= 'F') | |
380 | digit = c - 'A' + 10; | |
381 | else { | |
f2b63869 CH |
382 | /* `l' means long, and `u' means unsigned. */ |
383 | while (1) { | |
384 | if (c == 'l' || c == 'L') | |
ce73f2a5 RS |
385 | { |
386 | if (spec_long) | |
387 | yyerror ("two `l's in integer constant"); | |
388 | spec_long = 1; | |
389 | } | |
f2b63869 | 390 | else if (c == 'u' || c == 'U') |
ce73f2a5 RS |
391 | { |
392 | if (yylval.integer.unsignedp) | |
393 | yyerror ("two `u's in integer constant"); | |
394 | yylval.integer.unsignedp = 1; | |
395 | } | |
f2b63869 CH |
396 | else |
397 | break; | |
398 | ||
ce73f2a5 | 399 | if (--len == 0) |
f2b63869 CH |
400 | break; |
401 | c = *p++; | |
f2b63869 CH |
402 | } |
403 | /* Don't look for any more digits after the suffixes. */ | |
404 | break; | |
405 | } | |
3292923d RS |
406 | if (largest_digit < digit) |
407 | largest_digit = digit; | |
408 | nd = n * base + digit; | |
409 | overflow |= ULONG_MAX_over_base < n | nd < n; | |
410 | n = nd; | |
f2b63869 CH |
411 | } |
412 | ||
413 | if (len != 0) { | |
414 | yyerror ("Invalid number in #if expression"); | |
415 | return ERROR; | |
416 | } | |
417 | ||
3292923d RS |
418 | if (base <= largest_digit) |
419 | warning ("integer constant contains digits beyond the radix"); | |
420 | ||
ce73f2a5 RS |
421 | if (overflow) |
422 | warning ("integer constant out of range"); | |
423 | ||
f2b63869 | 424 | /* If too big to be signed, consider it unsigned. */ |
ce73f2a5 RS |
425 | if ((long) n < 0 && ! yylval.integer.unsignedp) |
426 | { | |
427 | if (base == 10) | |
428 | warning ("integer constant is so large that it is unsigned"); | |
429 | yylval.integer.unsignedp = 1; | |
430 | } | |
f2b63869 CH |
431 | |
432 | lexptr = p; | |
433 | yylval.integer.value = n; | |
434 | return INT; | |
435 | } | |
436 | ||
437 | struct token { | |
438 | char *operator; | |
439 | int token; | |
440 | }; | |
441 | ||
442 | static struct token tokentab2[] = { | |
443 | {"&&", AND}, | |
444 | {"||", OR}, | |
445 | {"<<", LSH}, | |
446 | {">>", RSH}, | |
447 | {"==", EQUAL}, | |
448 | {"!=", NOTEQUAL}, | |
449 | {"<=", LEQ}, | |
450 | {">=", GEQ}, | |
451 | {"++", ERROR}, | |
452 | {"--", ERROR}, | |
453 | {NULL, ERROR} | |
454 | }; | |
455 | ||
456 | /* Read one token, getting characters through lexptr. */ | |
457 | ||
458 | int | |
459 | yylex () | |
460 | { | |
461 | register int c; | |
462 | register int namelen; | |
0671ee41 | 463 | register unsigned char *tokstart; |
f2b63869 CH |
464 | register struct token *toktab; |
465 | int wide_flag; | |
466 | ||
467 | retry: | |
468 | ||
0671ee41 | 469 | tokstart = (unsigned char *) lexptr; |
f2b63869 CH |
470 | c = *tokstart; |
471 | /* See if it is a special token of length 2. */ | |
472 | if (! keyword_parsing) | |
473 | for (toktab = tokentab2; toktab->operator != NULL; toktab++) | |
474 | if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) { | |
475 | lexptr += 2; | |
476 | if (toktab->token == ERROR) | |
477 | { | |
478 | char *buf = (char *) alloca (40); | |
479 | sprintf (buf, "`%s' not allowed in operand of `#if'", toktab->operator); | |
480 | yyerror (buf); | |
481 | } | |
482 | return toktab->token; | |
483 | } | |
484 | ||
485 | switch (c) { | |
486 | case 0: | |
487 | return 0; | |
488 | ||
489 | case ' ': | |
490 | case '\t': | |
491 | case '\r': | |
492 | case '\n': | |
493 | lexptr++; | |
494 | goto retry; | |
495 | ||
496 | case 'L': | |
497 | /* Capital L may start a wide-string or wide-character constant. */ | |
498 | if (lexptr[1] == '\'') | |
499 | { | |
500 | lexptr++; | |
501 | wide_flag = 1; | |
502 | goto char_constant; | |
503 | } | |
504 | if (lexptr[1] == '"') | |
505 | { | |
506 | lexptr++; | |
507 | wide_flag = 1; | |
508 | goto string_constant; | |
509 | } | |
510 | break; | |
511 | ||
512 | case '\'': | |
513 | wide_flag = 0; | |
514 | char_constant: | |
515 | lexptr++; | |
516 | if (keyword_parsing) { | |
517 | char *start_ptr = lexptr - 1; | |
518 | while (1) { | |
519 | c = *lexptr++; | |
520 | if (c == '\\') | |
521 | c = parse_escape (&lexptr); | |
522 | else if (c == '\'') | |
523 | break; | |
524 | } | |
0671ee41 | 525 | yylval.name.address = tokstart; |
f2b63869 CH |
526 | yylval.name.length = lexptr - start_ptr; |
527 | return NAME; | |
528 | } | |
529 | ||
530 | /* This code for reading a character constant | |
531 | handles multicharacter constants and wide characters. | |
532 | It is mostly copied from c-lex.c. */ | |
533 | { | |
534 | register int result = 0; | |
535 | register num_chars = 0; | |
536 | unsigned width = CHAR_TYPE_SIZE; | |
537 | int max_chars; | |
538 | char *token_buffer; | |
539 | ||
540 | if (wide_flag) | |
541 | { | |
542 | width = WCHAR_TYPE_SIZE; | |
543 | #ifdef MULTIBYTE_CHARS | |
544 | max_chars = MB_CUR_MAX; | |
545 | #else | |
546 | max_chars = 1; | |
547 | #endif | |
548 | } | |
549 | else | |
550 | max_chars = LONG_TYPE_SIZE / width; | |
551 | ||
552 | token_buffer = (char *) alloca (max_chars + 1); | |
553 | ||
554 | while (1) | |
555 | { | |
556 | c = *lexptr++; | |
557 | ||
558 | if (c == '\'' || c == EOF) | |
559 | break; | |
560 | ||
561 | if (c == '\\') | |
562 | { | |
563 | c = parse_escape (&lexptr); | |
564 | if (width < HOST_BITS_PER_INT | |
565 | && (unsigned) c >= (1 << width)) | |
566 | pedwarn ("escape sequence out of range for character"); | |
567 | } | |
568 | ||
569 | num_chars++; | |
570 | ||
571 | /* Merge character into result; ignore excess chars. */ | |
572 | if (num_chars < max_chars + 1) | |
573 | { | |
574 | if (width < HOST_BITS_PER_INT) | |
575 | result = (result << width) | (c & ((1 << width) - 1)); | |
576 | else | |
577 | result = c; | |
578 | token_buffer[num_chars - 1] = c; | |
579 | } | |
580 | } | |
581 | ||
582 | token_buffer[num_chars] = 0; | |
583 | ||
584 | if (c != '\'') | |
585 | error ("malformatted character constant"); | |
586 | else if (num_chars == 0) | |
587 | error ("empty character constant"); | |
588 | else if (num_chars > max_chars) | |
589 | { | |
590 | num_chars = max_chars; | |
591 | error ("character constant too long"); | |
592 | } | |
593 | else if (num_chars != 1 && ! traditional) | |
594 | warning ("multi-character character constant"); | |
595 | ||
596 | /* If char type is signed, sign-extend the constant. */ | |
597 | if (! wide_flag) | |
598 | { | |
599 | int num_bits = num_chars * width; | |
600 | ||
601 | if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1) | |
602 | || ((result >> (num_bits - 1)) & 1) == 0) | |
603 | yylval.integer.value | |
4cf8de9f | 604 | = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits)); |
f2b63869 CH |
605 | else |
606 | yylval.integer.value | |
4cf8de9f | 607 | = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits)); |
f2b63869 CH |
608 | } |
609 | else | |
610 | { | |
611 | #ifdef MULTIBYTE_CHARS | |
612 | /* Set the initial shift state and convert the next sequence. */ | |
613 | result = 0; | |
614 | /* In all locales L'\0' is zero and mbtowc will return zero, | |
615 | so don't use it. */ | |
616 | if (num_chars > 1 | |
617 | || (num_chars == 1 && token_buffer[0] != '\0')) | |
618 | { | |
619 | wchar_t wc; | |
620 | (void) mbtowc (NULL_PTR, NULL_PTR, 0); | |
621 | if (mbtowc (& wc, token_buffer, num_chars) == num_chars) | |
622 | result = wc; | |
623 | else | |
624 | warning ("Ignoring invalid multibyte character"); | |
625 | } | |
626 | #endif | |
627 | yylval.integer.value = result; | |
628 | } | |
629 | } | |
630 | ||
631 | /* This is always a signed type. */ | |
632 | yylval.integer.unsignedp = 0; | |
633 | ||
634 | return CHAR; | |
635 | ||
636 | /* some of these chars are invalid in constant expressions; | |
637 | maybe do something about them later */ | |
638 | case '/': | |
639 | case '+': | |
640 | case '-': | |
641 | case '*': | |
642 | case '%': | |
643 | case '|': | |
644 | case '&': | |
645 | case '^': | |
646 | case '~': | |
647 | case '!': | |
648 | case '@': | |
649 | case '<': | |
650 | case '>': | |
651 | case '[': | |
652 | case ']': | |
653 | case '.': | |
654 | case '?': | |
655 | case ':': | |
656 | case '=': | |
657 | case '{': | |
658 | case '}': | |
659 | case ',': | |
660 | case '#': | |
661 | if (keyword_parsing) | |
662 | break; | |
663 | case '(': | |
664 | case ')': | |
665 | lexptr++; | |
666 | return c; | |
667 | ||
668 | case '"': | |
669 | string_constant: | |
670 | if (keyword_parsing) { | |
671 | char *start_ptr = lexptr; | |
672 | lexptr++; | |
673 | while (1) { | |
674 | c = *lexptr++; | |
675 | if (c == '\\') | |
676 | c = parse_escape (&lexptr); | |
677 | else if (c == '"') | |
678 | break; | |
679 | } | |
0671ee41 | 680 | yylval.name.address = tokstart; |
f2b63869 CH |
681 | yylval.name.length = lexptr - start_ptr; |
682 | return NAME; | |
683 | } | |
684 | yyerror ("string constants not allowed in #if expressions"); | |
685 | return ERROR; | |
686 | } | |
687 | ||
688 | if (c >= '0' && c <= '9' && !keyword_parsing) { | |
689 | /* It's a number */ | |
690 | for (namelen = 0; | |
691 | c = tokstart[namelen], is_idchar[c] || c == '.'; | |
692 | namelen++) | |
693 | ; | |
694 | return parse_number (namelen); | |
695 | } | |
696 | ||
697 | /* It is a name. See how long it is. */ | |
698 | ||
699 | if (keyword_parsing) { | |
700 | for (namelen = 0;; namelen++) { | |
701 | if (is_hor_space[tokstart[namelen]]) | |
702 | break; | |
703 | if (tokstart[namelen] == '(' || tokstart[namelen] == ')') | |
704 | break; | |
705 | if (tokstart[namelen] == '"' || tokstart[namelen] == '\'') | |
706 | break; | |
707 | } | |
708 | } else { | |
709 | if (!is_idstart[c]) { | |
710 | yyerror ("Invalid token in expression"); | |
711 | return ERROR; | |
712 | } | |
713 | ||
714 | for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) | |
715 | ; | |
716 | } | |
717 | ||
718 | lexptr += namelen; | |
0671ee41 | 719 | yylval.name.address = tokstart; |
f2b63869 CH |
720 | yylval.name.length = namelen; |
721 | return NAME; | |
722 | } | |
723 | ||
724 | ||
725 | /* Parse a C escape sequence. STRING_PTR points to a variable | |
726 | containing a pointer to the string to parse. That pointer | |
727 | is updated past the characters we use. The value of the | |
728 | escape sequence is returned. | |
729 | ||
730 | A negative value means the sequence \ newline was seen, | |
731 | which is supposed to be equivalent to nothing at all. | |
732 | ||
733 | If \ is followed by a null character, we return a negative | |
734 | value and leave the string pointer pointing at the null character. | |
735 | ||
736 | If \ is followed by 000, we return 0 and leave the string pointer | |
737 | after the zeros. A value of 0 does not mean end of string. */ | |
738 | ||
739 | int | |
740 | parse_escape (string_ptr) | |
741 | char **string_ptr; | |
742 | { | |
743 | register int c = *(*string_ptr)++; | |
744 | switch (c) | |
745 | { | |
746 | case 'a': | |
747 | return TARGET_BELL; | |
748 | case 'b': | |
749 | return TARGET_BS; | |
750 | case 'e': | |
751 | return 033; | |
752 | case 'f': | |
753 | return TARGET_FF; | |
754 | case 'n': | |
755 | return TARGET_NEWLINE; | |
756 | case 'r': | |
757 | return TARGET_CR; | |
758 | case 't': | |
759 | return TARGET_TAB; | |
760 | case 'v': | |
761 | return TARGET_VT; | |
762 | case '\n': | |
763 | return -2; | |
764 | case 0: | |
765 | (*string_ptr)--; | |
766 | return 0; | |
767 | case '^': | |
768 | c = *(*string_ptr)++; | |
769 | if (c == '\\') | |
770 | c = parse_escape (string_ptr); | |
771 | if (c == '?') | |
772 | return 0177; | |
773 | return (c & 0200) | (c & 037); | |
774 | ||
775 | case '0': | |
776 | case '1': | |
777 | case '2': | |
778 | case '3': | |
779 | case '4': | |
780 | case '5': | |
781 | case '6': | |
782 | case '7': | |
783 | { | |
784 | register int i = c - '0'; | |
785 | register int count = 0; | |
786 | while (++count < 3) | |
787 | { | |
788 | c = *(*string_ptr)++; | |
789 | if (c >= '0' && c <= '7') | |
790 | i = (i << 3) + c - '0'; | |
791 | else | |
792 | { | |
793 | (*string_ptr)--; | |
794 | break; | |
795 | } | |
796 | } | |
797 | if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0) | |
798 | { | |
799 | i &= (1 << CHAR_TYPE_SIZE) - 1; | |
800 | warning ("octal character constant does not fit in a byte"); | |
801 | } | |
802 | return i; | |
803 | } | |
804 | case 'x': | |
805 | { | |
f46ffce4 | 806 | register unsigned i = 0, overflow = 0, digits_found = 0, digit; |
f2b63869 CH |
807 | for (;;) |
808 | { | |
809 | c = *(*string_ptr)++; | |
810 | if (c >= '0' && c <= '9') | |
f46ffce4 | 811 | digit = c - '0'; |
f2b63869 | 812 | else if (c >= 'a' && c <= 'f') |
f46ffce4 | 813 | digit = c - 'a' + 10; |
f2b63869 | 814 | else if (c >= 'A' && c <= 'F') |
f46ffce4 | 815 | digit = c - 'A' + 10; |
f2b63869 CH |
816 | else |
817 | { | |
818 | (*string_ptr)--; | |
819 | break; | |
820 | } | |
f46ffce4 RS |
821 | overflow |= i ^ (i << 4 >> 4); |
822 | i = (i << 4) + digit; | |
823 | digits_found = 1; | |
f2b63869 | 824 | } |
f46ffce4 RS |
825 | if (!digits_found) |
826 | yyerror ("\\x used with no following hex digits"); | |
827 | if (overflow | (i & ~((1 << BITS_PER_UNIT) - 1))) | |
f2b63869 CH |
828 | { |
829 | i &= (1 << BITS_PER_UNIT) - 1; | |
830 | warning ("hex character constant does not fit in a byte"); | |
831 | } | |
832 | return i; | |
833 | } | |
834 | default: | |
835 | return c; | |
836 | } | |
837 | } | |
838 | ||
839 | void | |
840 | yyerror (s) | |
841 | char *s; | |
842 | { | |
843 | error (s); | |
844 | longjmp (parse_return_error, 1); | |
845 | } | |
4cf8de9f RS |
846 | |
847 | static void | |
848 | integer_overflow () | |
849 | { | |
2f6f8824 RS |
850 | if (pedantic) |
851 | pedwarn ("integer overflow in preprocessor expression"); | |
4cf8de9f RS |
852 | } |
853 | ||
854 | static long | |
855 | left_shift (a, b) | |
856 | struct constant *a; | |
857 | unsigned long b; | |
858 | { | |
859 | if (b >= HOST_BITS_PER_LONG) | |
860 | { | |
861 | if (! a->unsignedp && a->value != 0) | |
862 | integer_overflow (); | |
863 | return 0; | |
864 | } | |
865 | else if (a->unsignedp) | |
866 | return (unsigned long) a->value << b; | |
867 | else | |
868 | { | |
869 | long l = a->value << b; | |
870 | if (l >> b != a->value) | |
871 | integer_overflow (); | |
872 | return l; | |
873 | } | |
874 | } | |
875 | ||
876 | static long | |
877 | right_shift (a, b) | |
878 | struct constant *a; | |
879 | unsigned long b; | |
880 | { | |
881 | if (b >= HOST_BITS_PER_LONG) | |
882 | return a->unsignedp ? 0 : a->value >> (HOST_BITS_PER_LONG - 1); | |
883 | else if (a->unsignedp) | |
884 | return (unsigned long) a->value >> b; | |
885 | else | |
886 | return a->value >> b; | |
887 | } | |
f2b63869 CH |
888 | \f |
889 | /* This page contains the entry point to this file. */ | |
890 | ||
891 | /* Parse STRING as an expression, and complain if this fails | |
892 | to use up all of the contents of STRING. */ | |
893 | /* We do not support C comments. They should be removed before | |
894 | this function is called. */ | |
895 | ||
896 | int | |
897 | parse_c_expression (string) | |
898 | char *string; | |
899 | { | |
900 | lexptr = string; | |
901 | ||
902 | if (lexptr == 0 || *lexptr == 0) { | |
903 | error ("empty #if expression"); | |
904 | return 0; /* don't include the #if group */ | |
905 | } | |
906 | ||
907 | /* if there is some sort of scanning error, just return 0 and assume | |
908 | the parsing routine has printed an error message somewhere. | |
909 | there is surely a better thing to do than this. */ | |
910 | if (setjmp (parse_return_error)) | |
911 | return 0; | |
912 | ||
913 | if (yyparse ()) | |
914 | return 0; /* actually this is never reached | |
915 | the way things stand. */ | |
916 | if (*lexptr) | |
917 | error ("Junk after end of expression."); | |
918 | ||
919 | return expression_value; /* set by yyparse () */ | |
920 | } | |
921 | \f | |
922 | #ifdef TEST_EXP_READER | |
923 | extern int yydebug; | |
924 | ||
925 | /* Main program for testing purposes. */ | |
926 | int | |
927 | main () | |
928 | { | |
929 | int n, c; | |
930 | char buf[1024]; | |
931 | ||
932 | /* | |
933 | yydebug = 1; | |
934 | */ | |
935 | initialize_random_junk (); | |
936 | ||
937 | for (;;) { | |
938 | printf ("enter expression: "); | |
939 | n = 0; | |
940 | while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF) | |
941 | n++; | |
942 | if (buf[n] == EOF) | |
943 | break; | |
944 | buf[n] = '\0'; | |
945 | printf ("parser returned %d\n", parse_c_expression (buf)); | |
946 | } | |
947 | ||
948 | return 0; | |
949 | } | |
950 | ||
951 | /* table to tell if char can be part of a C identifier. */ | |
952 | unsigned char is_idchar[256]; | |
953 | /* table to tell if char can be first char of a c identifier. */ | |
954 | unsigned char is_idstart[256]; | |
955 | /* table to tell if c is horizontal space. isspace () thinks that | |
956 | newline is space; this is not a good idea for this program. */ | |
957 | char is_hor_space[256]; | |
958 | ||
959 | /* | |
960 | * initialize random junk in the hash table and maybe other places | |
961 | */ | |
962 | initialize_random_junk () | |
963 | { | |
964 | register int i; | |
965 | ||
966 | /* | |
967 | * Set up is_idchar and is_idstart tables. These should be | |
968 | * faster than saying (is_alpha (c) || c == '_'), etc. | |
969 | * Must do set up these things before calling any routines tthat | |
970 | * refer to them. | |
971 | */ | |
972 | for (i = 'a'; i <= 'z'; i++) { | |
973 | ++is_idchar[i - 'a' + 'A']; | |
974 | ++is_idchar[i]; | |
975 | ++is_idstart[i - 'a' + 'A']; | |
976 | ++is_idstart[i]; | |
977 | } | |
978 | for (i = '0'; i <= '9'; i++) | |
979 | ++is_idchar[i]; | |
980 | ++is_idchar['_']; | |
981 | ++is_idstart['_']; | |
982 | #if DOLLARS_IN_IDENTIFIERS | |
983 | ++is_idchar['$']; | |
984 | ++is_idstart['$']; | |
985 | #endif | |
986 | ||
987 | /* horizontal space table */ | |
988 | ++is_hor_space[' ']; | |
989 | ++is_hor_space['\t']; | |
990 | } | |
991 | ||
992 | error (msg) | |
993 | { | |
994 | printf ("error: %s\n", msg); | |
995 | } | |
996 | ||
997 | warning (msg) | |
998 | { | |
999 | printf ("warning: %s\n", msg); | |
1000 | } | |
1001 | ||
1002 | struct hashnode * | |
1003 | lookup (name, len, hash) | |
1004 | char *name; | |
1005 | int len; | |
1006 | int hash; | |
1007 | { | |
1008 | return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1); | |
1009 | } | |
1010 | #endif |