📄 c-lex.c
字号:
/* Effectively do c = skip_white_space (c) but do it faster in the usual cases. */ while (1) switch (c) { case ' ': case '\t': case '\f': case '\v': case '\b': c = GETC(); break; case '\r': /* Call skip_white_space so we can warn if appropriate. */ case '\n': case '/': case '\\': c = skip_white_space (c); default: goto found_nonwhite; } found_nonwhite: token_buffer[0] = c; token_buffer[1] = 0;/* yylloc.first_line = lineno; */ switch (c) { case EOF: end_of_file = 1; token_buffer[0] = 0; value = ENDFILE; break; case 'L': /* Capital L may start a wide-string or wide-character constant. */ { register int c = GETC(); if (c == '\'') { wide_flag = 1; goto char_constant; } if (c == '"') { wide_flag = 1; goto string_constant; } UNGETC (c); } goto letter; case '@': if (!doing_objc_thang) { value = c; break; } else { /* '@' may start a constant string object. */ register int c = GETC (); if (c == '"') { objc_flag = 1; goto string_constant; } UNGETC (c); /* Fall through to treat '@' as the start of an identifier. */ } case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '_': case '$': letter: p = token_buffer; while (isalnum (c) || c == '_' || c == '$' || c == '@') { /* Make sure this char really belongs in an identifier. */ if (c == '@' && ! doing_objc_thang) break; if (c == '$') { if (! dollars_in_ident) error ("`$' in identifier"); else if (pedantic) pedwarn ("`$' in identifier"); } if (p >= token_buffer + maxtoken) p = extend_token_buffer (p); *p++ = c; c = GETC(); } *p = 0;#if USE_CPPLIB UNGETC (c);#else nextchar = c;#endif value = IDENTIFIER; yylval.itype = 0; /* Try to recognize a keyword. Uses minimum-perfect hash function */ { register struct resword *ptr; if (ptr = is_reserved_word (token_buffer, p - token_buffer)) { if (ptr->rid) yylval.ttype = ridpointers[(int) ptr->rid]; value = (int) ptr->token; /* Only return OBJECTNAME if it is a typedef. */ if (doing_objc_thang && value == OBJECTNAME) { lastiddecl = lookup_name(yylval.ttype); if (lastiddecl == NULL_TREE || TREE_CODE (lastiddecl) != TYPE_DECL) value = IDENTIFIER; } /* Even if we decided to recognize asm, still perhaps warn. */ if (pedantic && (value == ASM_KEYWORD || value == TYPEOF || ptr->rid == RID_INLINE) && token_buffer[0] != '_') pedwarn ("ANSI does not permit the keyword `%s'", token_buffer); } } /* If we did not find a keyword, look for an identifier (or a typename). */ if (value == IDENTIFIER) { if (token_buffer[0] == '@') error("invalid identifier `%s'", token_buffer); yylval.ttype = get_identifier (token_buffer); lastiddecl = lookup_name (yylval.ttype); if (lastiddecl != 0 && TREE_CODE (lastiddecl) == TYPE_DECL) value = TYPENAME; /* A user-invisible read-only initialized variable should be replaced by its value. We handle only strings since that's the only case used in C. */ else if (lastiddecl != 0 && TREE_CODE (lastiddecl) == VAR_DECL && DECL_IGNORED_P (lastiddecl) && TREE_READONLY (lastiddecl) && DECL_INITIAL (lastiddecl) != 0 && TREE_CODE (DECL_INITIAL (lastiddecl)) == STRING_CST) { tree stringval = DECL_INITIAL (lastiddecl); /* Copy the string value so that we won't clobber anything if we put something in the TREE_CHAIN of this one. */ yylval.ttype = build_string (TREE_STRING_LENGTH (stringval), TREE_STRING_POINTER (stringval)); value = STRING; } else if (doing_objc_thang) { tree objc_interface_decl = is_class_name (yylval.ttype); if (objc_interface_decl) { value = CLASSNAME; yylval.ttype = objc_interface_decl; } } } break; case '0': case '1': { int next_c; /* Check first for common special case: single-digit 0 or 1. */ next_c = GETC (); UNGETC (next_c); /* Always undo this lookahead. */ if (!isalnum (next_c) && next_c != '.') { token_buffer[0] = (char)c, token_buffer[1] = '\0'; yylval.ttype = (c == '0') ? integer_zero_node : integer_one_node; value = CONSTANT; break; } /*FALLTHRU*/ } case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': { int base = 10; int count = 0; int largest_digit = 0; int numdigits = 0; /* for multi-precision arithmetic, we actually store only HOST_BITS_PER_CHAR bits in each part. The number of parts is chosen so as to be sufficient to hold the enough bits to fit into the two HOST_WIDE_INTs that contain the integer value (this is always at least as many bits as are in a target `long long' value, but may be wider). */#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2) int parts[TOTAL_PARTS]; int overflow = 0; enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS} floatflag = NOT_FLOAT; for (count = 0; count < TOTAL_PARTS; count++) parts[count] = 0; p = token_buffer; *p++ = c; if (c == '0') { *p++ = (c = GETC()); if ((c == 'x') || (c == 'X')) { base = 16; *p++ = (c = GETC()); } /* Leading 0 forces octal unless the 0 is the only digit. */ else if (c >= '0' && c <= '9') { base = 8; numdigits++; } else numdigits++; } /* Read all the digits-and-decimal-points. */ while (c == '.' || (isalnum (c) && c != 'l' && c != 'L' && c != 'u' && c != 'U' && c != 'i' && c != 'I' && c != 'j' && c != 'J' && (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F'))))) { if (c == '.') { if (base == 16) error ("floating constant may not be in radix 16"); if (floatflag == TOO_MANY_POINTS) /* We have already emitted an error. Don't need another. */ ; else if (floatflag == AFTER_POINT) { error ("malformed floating constant"); floatflag = TOO_MANY_POINTS; /* Avoid another error from atof by forcing all characters from here on to be ignored. */ p[-1] = '\0'; } else floatflag = AFTER_POINT; base = 10; *p++ = c = GETC(); /* Accept '.' as the start of a floating-point number only when it is followed by a digit. Otherwise, unread the following non-digit and use the '.' as a structural token. */ if (p == token_buffer + 2 && !isdigit (c)) { if (c == '.') { c = GETC(); if (c == '.') { *p++ = c; *p = 0; return ELLIPSIS; } error ("parse error at `..'"); } UNGETC (c); token_buffer[1] = 0; value = '.'; goto done; } } else { /* It is not a decimal point. It should be a digit (perhaps a hex digit). */ if (isdigit (c)) { c = c - '0'; } else if (base <= 10) { if (c == 'e' || c == 'E') { base = 10; floatflag = AFTER_POINT; break; /* start of exponent */ } error ("nondigits in number and not hexadecimal"); c = 0; } else if (c >= 'a') { c = c - 'a' + 10; } else { c = c - 'A' + 10; } if (c >= largest_digit) largest_digit = c; numdigits++; for (count = 0; count < TOTAL_PARTS; count++) { parts[count] *= base; if (count) { parts[count] += (parts[count-1] >> HOST_BITS_PER_CHAR); parts[count-1] &= (1 << HOST_BITS_PER_CHAR) - 1; } else parts[0] += c; } /* If the extra highest-order part ever gets anything in it, the number is certainly too big. */ if (parts[TOTAL_PARTS - 1] != 0) overflow = 1; if (p >= token_buffer + maxtoken - 3) p = extend_token_buffer (p); *p++ = (c = GETC()); } } if (numdigits == 0) error ("numeric constant with no digits"); if (largest_digit >= base) error ("numeric constant contains digits beyond the radix"); /* Remove terminating char from the token buffer and delimit the string */ *--p = 0; if (floatflag != NOT_FLOAT) { tree type = double_type_node; int exceeds_double = 0; int imag = 0; REAL_VALUE_TYPE value; jmp_buf handler; /* Read explicit exponent if any, and put it in tokenbuf. */ if ((c == 'e') || (c == 'E')) { if (p >= token_buffer + maxtoken - 3) p = extend_token_buffer (p); *p++ = c; c = GETC(); if ((c == '+') || (c == '-')) { *p++ = c; c = GETC(); } if (! isdigit (c)) error ("floating constant exponent has no digits"); while (isdigit (c)) { if (p >= token_buffer + maxtoken - 3) p = extend_token_buffer (p); *p++ = c; c = GETC(); } } *p = 0; errno = 0; /* Convert string to a double, checking for overflow. */ if (setjmp (handler)) { error ("floating constant out of range"); value = dconst0; } else { int fflag = 0, lflag = 0; /* Copy token_buffer now, while it has just the number and not the suffixes; once we add `f' or `i', REAL_VALUE_ATOF may not work any more. */ char *copy = (char *) alloca (p - token_buffer + 1); bcopy (token_buffer, copy, p - token_buffer + 1); set_float_handler (handler); while (1) { int lose = 0; /* Read the suffixes to choose a data type. */ switch (c) { case 'f': case 'F': if (fflag) error ("more than one `f' in numeric constant"); fflag = 1; break; case 'l': case 'L': if (lflag) error ("more than one `l' in numeric constant"); lflag = 1; break; case 'i': case 'I': if (imag) error ("more than one `i' or `j' in numeric constant"); else if (pedantic) pedwarn ("ANSI C forbids imaginary numeric constants"); imag = 1; break; default: lose = 1; } if (lose) break; if (p >= token_buffer + maxtoken - 3) p = extend_token_buffer (p); *p++ = c; *p = 0; c = GETC(); } /* The second argument, machine_mode, of REAL_VALUE_ATOF tells the desired precision of the binary result of decimal-to-binary conversion. */ if (fflag) { if (lflag) error ("both `f' and `l' in floating constant"); type = float_type_node; value = REAL_VALUE_ATOF (copy, TYPE_MODE (type)); /* A diagnostic is required here by some ANSI C testsuites. This is not pedwarn, become some people don't want an error for this. */ if (REAL_VALUE_ISINF (value) && pedantic) warning ("floating point number exceeds range of `float'"); } else if (lflag) { type = long_double_type_node; value = REAL_VALUE_ATOF (copy, TYPE_MODE (type)); if (REAL_VALUE_ISINF (value) && pedantic) warning ("floating point number exceeds range of `long double'"); } else { value = REAL_VALUE_ATOF (copy, TYPE_MODE (type)); if (REAL_VALUE_ISINF (value) && pedantic) warning ("floating point number exceeds range of `double'"); } set_float_handler (NULL_PTR); }#ifdef ERANGE if (errno == ERANGE && !flag_traditional && pedantic) { /* ERANGE is also reported for underflow, so test the value to distinguish overflow from that. */ if (REAL_VALUES_LESS (dconst1, value) || REAL_VALUES_LESS (value, dconstm1)) { warning ("floating point number exceeds range of `double'"); exceeds_double = 1; } }#endif /* If the result is not a number, assume it must have been due to some error message above, so silently convert it to a zero. */ if (REAL_VALUE_ISNAN (value)) value = dconst0; /* Create a node with determined type and value. */ if (imag) yylval.ttype = build_complex (NULL_TREE, convert (type, integer_zero_node), build_real (type, value)); else yylval.ttype = build_real (type, value); } else { tree traditional_type, ansi_type, type; HOST_WIDE_INT high, low; int spec_unsigned = 0; int spec_long = 0; int spec_long_long = 0; int spec_imag = 0; int bytes, warn, i; while (1) { if (c == 'u' || c == 'U') { if (spec_unsigned) error ("two `u's in integer constant"); spec_unsigned = 1; } else if (c == 'l' || c == 'L') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -