c-lex.c
来自「C语言C-lex词法分析头文件」· C语言 代码 · 共 2,046 行 · 第 1/4 页
C
2,046 行
};
struct try_type type_sequence[] =
{
{ &integer_type_node, 0, 0, 0},
{ &unsigned_type_node, 1, 0, 0},
{ &long_integer_type_node, 0, 1, 0},
{ &long_unsigned_type_node, 1, 1, 0},
{ &long_long_integer_type_node, 0, 1, 1},
{ &long_long_unsigned_type_node, 1, 1, 1}
};
#endif /* 0 */
int
yylex ()
{
register int c;
register char *p;
register int value;
int wide_flag = 0;
if (nextchar >= 0)
c = nextchar, nextchar = -1;
else
c = getc (finput);
/* 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 (finput);
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 '$':
if (dollars_in_ident)
goto letter;
return '$';
case 'L':
/* Capital L may start a wide-string or wide-character constant. */
{
register int c = getc (finput);
if (c == '\'')
{
wide_flag = 1;
goto char_constant;
}
if (c == '"')
{
wide_flag = 1;
goto string_constant;
}
ungetc (c, finput);
}
goto letter;
case '@':
if (!doing_objc_thang)
{
value = c;
break;
}
p = token_buffer;
*p++ = '@';
c = getc (finput);
while (isalnum (c) || c == '_')
{
if (p >= token_buffer + maxtoken)
p = extend_token_buffer (p);
*p++ = c;
c = getc (finput);
}
*p = 0;
nextchar = c;
value = recognize_objc_keyword (token_buffer + 1);
if (value != 0)
break;
error ("invalid Objective C keyword `%s'", token_buffer);
/* Cause a syntax error--1 is not a valid token type. */
value = 1;
break;
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 '_':
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 == '$' && ! dollars_in_ident)
break;
if (p >= token_buffer + maxtoken)
p = extend_token_buffer (p);
*p++ = c;
c = getc (finput);
}
*p = 0;
nextchar = c;
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;
/* 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)
{
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)
{
yylval.ttype = DECL_INITIAL (lastiddecl);
value = STRING;
}
else if (doing_objc_thang)
{
tree objc_interface_decl = lookup_interface (yylval.ttype);
if (objc_interface_decl)
{
value = CLASSNAME;
yylval.ttype = objc_interface_decl;
}
}
}
break;
case '0': case '1': 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 total_parts = TOTAL_PARTS;
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 (finput));
if ((c == 'x') || (c == 'X'))
{
base = 16;
*p++ = (c = getc (finput));
}
/* 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 == AFTER_POINT)
{
error ("malformed floating constant");
floatflag = TOO_MANY_POINTS;
}
else
floatflag = AFTER_POINT;
base = 10;
*p++ = c = getc (finput);
/* 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 (finput);
if (c == '.')
{
*p++ = c;
*p = 0;
return ELLIPSIS;
}
error ("parse error at `..'");
}
ungetc (c, finput);
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 (finput));
}
}
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)
{
#ifdef ADI
/*
* On the 21k we want to make floating point constants and
* not double constants. This will make the code more efficent.
*/
extern int flag_no_nonansi_builtin;
tree type = (!flag_no_nonansi_builtin
? float_type_node
: double_type_node);
#else
tree type = double_type_node;
#endif
int garbage_chars = 0, 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 (finput);
if ((c == '+') || (c == '-'))
{
*p++ = c;
c = getc (finput);
}
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 (finput);
}
}
*p = 0;
errno = 0;
/* Convert string to a double, checking for overflow. */
if (setjmp (handler))
{
error ("floating constant out of range");
value = dconst0;
}
else
{
set_float_handler (handler);
value = REAL_VALUE_ATOF (token_buffer);
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))
{
pedwarn ("floating point number exceeds range of `double'");
exceeds_double = 1;
}
}
#endif
/* Read the suffixes to choose a data type. */
switch (c)
{
case 'f': case 'F':
type = float_type_node;
value = REAL_VALUE_TRUNCATE (TYPE_MODE (type), value);
if (REAL_VALUE_ISINF (value) && ! exceeds_double && pedantic)
pedwarn ("floating point number exceeds range of `float'");
garbage_chars = -1;
break;
case 'l': case 'L':
type = long_double_type_node;
garbage_chars = -1;
break;
case 'i': case 'I':
if (imag)
error ("more than one `i' or `j' in numeric constant");
imag = 1;
garbage_chars = -1;
}
/* Note: garbage_chars is -1 if first char is *not* garbage. */
while (isalnum (c) || c == '.' || c == '_'
|| (!flag_traditional && (c == '+' || c == '-')
&& (p[-1] == 'e' || p[-1] == 'E') ))
{
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
c = getc (finput);
garbage_chars++;
}
if (garbage_chars > 0)
error ("garbage at end of number");
/* Create a node with determined type and value. */
if (imag)
yylval.ttype = build_complex (convert (type, integer_zero_node),
build_real (type, value));
else
yylval.ttype = build_real (type, value);
ungetc (c, finput);
*p = 0;
}
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')
{
if (spec_long)
{
if (spec_long_long)
error ("three `l's in integer constant");
else if (pedantic)
pedwarn ("ANSI C forbids long long integer constants");
spec_long_long = 1;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?