📄 cexp.y
字号:
sprintf (buf, "`%s' not allowed in operand of `#if'", toktab->operator); yyerror (buf); } return toktab->token; } switch (c) { case 0: return 0; case ' ': case '\t': case '\r': case '\n': lexptr++; goto retry; case 'L': /* Capital L may start a wide-string or wide-character constant. */ if (lexptr[1] == '\'') { lexptr++; wide_flag = 1; goto char_constant; } if (lexptr[1] == '"') { lexptr++; wide_flag = 1; goto string_constant; } break; case '\'': wide_flag = 0; char_constant: lexptr++; if (keyword_parsing) { char *start_ptr = lexptr - 1; while (1) { c = *lexptr++; if (c == '\\') c = parse_escape (&lexptr); else if (c == '\'') break; } yylval.name.address = tokstart; yylval.name.length = lexptr - start_ptr; return NAME; } /* This code for reading a character constant handles multicharacter constants and wide characters. It is mostly copied from c-lex.c. */ { register int result = 0; register num_chars = 0; unsigned width = MAX_CHAR_TYPE_SIZE; int max_chars; char *token_buffer; 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); if (width < HOST_BITS_PER_INT && (unsigned) c >= (1 << width)) pedwarn ("escape sequence out of range for character"); } num_chars++; /* Merge character into result; ignore excess chars. */ if (num_chars < max_chars + 1) { if (width < HOST_BITS_PER_INT) result = (result << width) | (c & ((1 << width) - 1)); 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 ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1) || ((result >> (num_bits - 1)) & 1) == 0) yylval.integer.value = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits)); else yylval.integer.value = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - 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 warning ("Ignoring invalid multibyte character"); }#endif yylval.integer.value = result; } } /* This is always a signed type. */ yylval.integer.unsignedp = 0; 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 '"': string_constant: if (keyword_parsing) { char *start_ptr = lexptr; lexptr++; while (1) { c = *lexptr++; if (c == '\\') c = parse_escape (&lexptr); 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 = 0; c = tokstart[namelen], is_idchar[c] || c == '.'; namelen++) ; return parse_number (namelen); } /* It is a name. See how long it is. */ if (keyword_parsing) { for (namelen = 0;; namelen++) { if (is_hor_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. 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. */intparse_escape (string_ptr) char **string_ptr;{ 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 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 & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0) { i &= (1 << MAX_CHAR_TYPE_SIZE) - 1; warning ("octal character constant does not fit in a byte"); } return i; } case 'x': { register unsigned i = 0, overflow = 0, 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 & ~((1 << BITS_PER_UNIT) - 1))) { i &= (1 << BITS_PER_UNIT) - 1; warning ("hex character constant does not fit in a byte"); } return i; } default: return c; }}voidyyerror (s) char *s;{ error (s); skip_evaluation = 0; longjmp (parse_return_error, 1);}static voidinteger_overflow (){ if (!skip_evaluation && pedantic) pedwarn ("integer overflow in preprocessor expression");}static longleft_shift (a, b) struct constant *a; unsigned long 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_LONG) return 0; else if (a->unsignedp) return (unsigned long) a->value << b; else return a->value << b;}static longright_shift (a, b) struct constant *a; unsigned long b;{ if (b >= HOST_BITS_PER_LONG) return a->unsignedp ? 0 : a->value >> (HOST_BITS_PER_LONG - 1); else if (a->unsignedp) return (unsigned long) a->value >> b; else return 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. *//* 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 (lexptr == 0 || *lexptr == 0) { error ("empty #if expression"); return 0; /* don't include the #if group */ } /* 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 ()) return 0; /* actually this is never reached the way things stand. */ if (*lexptr) error ("Junk after end of expression."); return expression_value; /* set by yyparse () */}#ifdef TEST_EXP_READERextern int yydebug;/* Main program for testing purposes. */intmain (){ int n, c; char buf[1024];/* yydebug = 1;*/ initialize_random_junk (); for (;;) { printf ("enter expression: "); n = 0; while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF) n++; if (buf[n] == EOF) break; buf[n] = '\0'; printf ("parser returned %ld\n", 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 space. isspace () thinks that newline is space; this is not a good idea for this program. */char is_hor_space[256];/* * initialize random junk in the hash table and maybe other places */initialize_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['_'];#if DOLLARS_IN_IDENTIFIERS ++is_idchar['$']; ++is_idstart['$'];#endif /* horizontal space table */ ++is_hor_space[' ']; ++is_hor_space['\t'];}error (msg){ printf ("error: %s\n", msg);}warning (msg){ printf ("warning: %s\n", msg);}struct hashnode *lookup (name, len, hash) char *name; int len; int hash;{ return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -