📄 cexp.c
字号:
if (wide_flag) { width = MAX_WCHAR_TYPE_SIZE;#ifdef MULTIBYTE_CHARS max_chars = MB_CUR_MAX;#else max_chars = 1;#endif } else max_chars = MAX_LONG_TYPE_SIZE / width; token_buffer = (char *) alloca (max_chars + 1); while (1) { c = *lexptr++; if (c == '\'' || c == EOF) break; if (c == '\\') { c = parse_escape (&lexptr, mask); } num_chars++; /* Merge character into result; ignore excess chars. */ if (num_chars <= max_chars) { if (width < HOST_BITS_PER_WIDE_INT) result = (result << width) | c; else result = c; token_buffer[num_chars - 1] = c; } } token_buffer[num_chars] = 0; if (c != '\'') error ("malformatted character constant"); else if (num_chars == 0) error ("empty character constant"); else if (num_chars > max_chars) { num_chars = max_chars; error ("character constant too long"); } else if (num_chars != 1 && ! traditional) warning ("multi-character character constant"); /* If char type is signed, sign-extend the constant. */ if (! wide_flag) { int num_bits = num_chars * width; if (lookup ((U_CHAR *) "__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__") - 1, -1) || ((result >> (num_bits - 1)) & 1) == 0) yylval.integer.value = result & (~ (unsigned HOST_WIDE_INT) 0 >> (HOST_BITS_PER_WIDE_INT - num_bits)); else yylval.integer.value = result | ~(~ (unsigned HOST_WIDE_INT) 0 >> (HOST_BITS_PER_WIDE_INT - num_bits)); } else {#ifdef MULTIBYTE_CHARS /* Set the initial shift state and convert the next sequence. */ result = 0; /* In all locales L'\0' is zero and mbtowc will return zero, so don't use it. */ if (num_chars > 1 || (num_chars == 1 && token_buffer[0] != '\0')) { wchar_t wc; (void) mbtowc (NULL_PTR, NULL_PTR, 0); if (mbtowc (& wc, token_buffer, num_chars) == num_chars) result = wc; else pedwarn ("Ignoring invalid multibyte character"); }#endif yylval.integer.value = result; } } /* This is always a signed type. */ yylval.integer.signedp = SIGNED; return CHAR; /* some of these chars are invalid in constant expressions; maybe do something about them later */ case '/': case '+': case '-': case '*': case '%': case '|': case '&': case '^': case '~': case '!': case '@': case '<': case '>': case '[': case ']': case '.': case '?': case ':': case '=': case '{': case '}': case ',': case '#': if (keyword_parsing) break; case '(': case ')': lexptr++; return c; case '"': mask = MAX_CHAR_TYPE_MASK; string_constant: if (keyword_parsing) { char *start_ptr = lexptr; lexptr++; while (1) { c = *lexptr++; if (c == '\\') c = parse_escape (&lexptr, mask); else if (c == '"') break; } yylval.name.address = tokstart; yylval.name.length = lexptr - start_ptr; return NAME; } yyerror ("string constants not allowed in #if expressions"); return ERROR; } if (c >= '0' && c <= '9' && !keyword_parsing) { /* It's a number */ for (namelen = 1; ; namelen++) { int d = tokstart[namelen]; if (! ((is_idchar[d] || d == '.') || ((d == '-' || d == '+') && (c == 'e' || c == 'E' || ((c == 'p' || c == 'P') && ! c89)) && ! traditional))) break; c = d; } return parse_number (namelen); } /* It is a name. See how long it is. */ if (keyword_parsing) { for (namelen = 0;; namelen++) { if (is_space[tokstart[namelen]]) break; if (tokstart[namelen] == '(' || tokstart[namelen] == ')') break; if (tokstart[namelen] == '"' || tokstart[namelen] == '\'') break; } } else { if (!is_idstart[c]) { yyerror ("Invalid token in expression"); return ERROR; } for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) ; } lexptr += namelen; yylval.name.address = tokstart; yylval.name.length = namelen; return NAME;}/* Parse a C escape sequence. STRING_PTR points to a variable containing a pointer to the string to parse. That pointer is updated past the characters we use. The value of the escape sequence is returned. RESULT_MASK is used to mask out the result; an error is reported if bits are lost thereby. A negative value means the sequence \ newline was seen, which is supposed to be equivalent to nothing at all. If \ is followed by a null character, we return a negative value and leave the string pointer pointing at the null character. If \ is followed by 000, we return 0 and leave the string pointer after the zeros. A value of 0 does not mean end of string. */HOST_WIDE_INTparse_escape (string_ptr, result_mask) char **string_ptr; HOST_WIDE_INT result_mask;{ register int c = *(*string_ptr)++; switch (c) { case 'a': return TARGET_BELL; case 'b': return TARGET_BS; case 'e': case 'E': if (pedantic) pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c); return 033; case 'f': return TARGET_FF; case 'n': return TARGET_NEWLINE; case 'r': return TARGET_CR; case 't': return TARGET_TAB; case 'v': return TARGET_VT; case '\n': return -2; case 0: (*string_ptr)--; return 0; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { register HOST_WIDE_INT i = c - '0'; register int count = 0; while (++count < 3) { c = *(*string_ptr)++; if (c >= '0' && c <= '7') i = (i << 3) + c - '0'; else { (*string_ptr)--; break; } } if (i != (i & result_mask)) { i &= result_mask; pedwarn ("octal escape sequence out of range"); } return i; } case 'x': { register unsigned HOST_WIDE_INT i = 0, overflow = 0; register int digits_found = 0, digit; for (;;) { c = *(*string_ptr)++; if (c >= '0' && c <= '9') digit = c - '0'; else if (c >= 'a' && c <= 'f') digit = c - 'a' + 10; else if (c >= 'A' && c <= 'F') digit = c - 'A' + 10; else { (*string_ptr)--; break; } overflow |= i ^ (i << 4 >> 4); i = (i << 4) + digit; digits_found = 1; } if (!digits_found) yyerror ("\\x used with no following hex digits"); if (overflow | (i != (i & result_mask))) { i &= result_mask; pedwarn ("hex escape sequence out of range"); } return i; } default: return c; }}static voidyyerror (s) char *s;{ error ("%s", s); skip_evaluation = 0; longjmp (parse_return_error, 1);}static voidinteger_overflow (){ if (!skip_evaluation && pedantic) pedwarn ("integer overflow in preprocessor expression");}static HOST_WIDE_INTleft_shift (a, b) struct constant *a; unsigned HOST_WIDE_INT b;{ /* It's unclear from the C standard whether shifts can overflow. The following code ignores overflow; perhaps a C standard interpretation ruling is needed. */ if (b >= HOST_BITS_PER_WIDE_INT) return 0; else return (unsigned HOST_WIDE_INT) a->value << b;}static HOST_WIDE_INTright_shift (a, b) struct constant *a; unsigned HOST_WIDE_INT b;{ if (b >= HOST_BITS_PER_WIDE_INT) return a->signedp ? a->value >> (HOST_BITS_PER_WIDE_INT - 1) : 0; else if (a->signedp) return a->value >> b; else return (unsigned HOST_WIDE_INT) a->value >> b;}/* This page contains the entry point to this file. *//* Parse STRING as an expression, and complain if this fails to use up all of the contents of STRING. *//* STRING may contain '\0' bytes; it is terminated by the first '\n' outside a string constant, so that we can diagnose '\0' properly. *//* We do not support C comments. They should be removed before this function is called. */HOST_WIDE_INTparse_c_expression (string) char *string;{ lexptr = string; /* if there is some sort of scanning error, just return 0 and assume the parsing routine has printed an error message somewhere. there is surely a better thing to do than this. */ if (setjmp (parse_return_error)) return 0; if (yyparse () != 0) abort (); if (*lexptr != '\n') error ("Junk after end of expression."); return expression_value; /* set by yyparse () */}#ifdef TEST_EXP_READER#if YYDEBUGextern int yydebug;#endifint pedantic;int traditional;int main PROTO((int, char **));static void initialize_random_junk PROTO((void));/* Main program for testing purposes. */intmain (argc, argv) int argc; char **argv;{ int n, c; char buf[1024]; pedantic = 1 < argc; traditional = 2 < argc;#if YYDEBUG yydebug = 3 < argc;#endif initialize_random_junk (); for (;;) { printf ("enter expression: "); n = 0; while ((buf[n] = c = getchar ()) != '\n' && c != EOF) n++; if (c == EOF) break; printf ("parser returned %ld\n", (long) parse_c_expression (buf)); } return 0;}/* table to tell if char can be part of a C identifier. */unsigned char is_idchar[256];/* table to tell if char can be first char of a c identifier. */unsigned char is_idstart[256];/* table to tell if c is horizontal or vertical space. */unsigned char is_space[256];/* * initialize random junk in the hash table and maybe other places */static voidinitialize_random_junk (){ register int i; /* * Set up is_idchar and is_idstart tables. These should be * faster than saying (is_alpha (c) || c == '_'), etc. * Must do set up these things before calling any routines tthat * refer to them. */ for (i = 'a'; i <= 'z'; i++) { ++is_idchar[i - 'a' + 'A']; ++is_idchar[i]; ++is_idstart[i - 'a' + 'A']; ++is_idstart[i]; } for (i = '0'; i <= '9'; i++) ++is_idchar[i]; ++is_idchar['_']; ++is_idstart['_']; ++is_idchar['$']; ++is_idstart['$']; ++is_space[' ']; ++is_space['\t']; ++is_space['\v']; ++is_space['\f']; ++is_space['\n']; ++is_space['\r'];}voiderror (PRINTF_ALIST (msg)) PRINTF_DCL (msg){ va_list args; VA_START (args, msg); fprintf (stderr, "error: "); vfprintf (stderr, msg, args); fprintf (stderr, "\n"); va_end (args);}voidpedwarn (PRINTF_ALIST (msg)) PRINTF_DCL (msg){ va_list args; VA_START (args, msg); fprintf (stderr, "pedwarn: "); vfprintf (stderr, msg, args); fprintf (stderr, "\n"); va_end (args);}voidwarning (PRINTF_ALIST (msg)) PRINTF_DCL (msg){ va_list args; VA_START (args, msg); fprintf (stderr, "warning: "); vfprintf (stderr, msg, args); fprintf (stderr, "\n"); va_end (args);}intcheck_assertion (name, sym_length, tokens_specified, tokens) U_CHAR *name; int sym_length; int tokens_specified; struct arglist *tokens;{ return 0;}struct hashnode *lookup (name, len, hash) U_CHAR *name; int len; int hash;{ return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1);}GENERIC_PTRxmalloc (size) size_t size;{ return (GENERIC_PTR) malloc (size);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -