c-lex.c
来自「C语言C-lex词法分析头文件」· C语言 代码 · 共 2,046 行 · 第 1/4 页
C
2,046 行
spec_long = 1;
}
else if (c == 'i' || c == 'j' || c == 'I' || c == 'J')
{
if (spec_imag)
error ("more than one `i' or `j' in numeric constant");
spec_imag = 1;
}
else
{
if (isalnum (c) || c == '.' || c == '_'
|| (!flag_traditional && (c == '+' || c == '-')
&& (p[-1] == 'e' || p[-1] == 'E')))
{
error ("garbage at end of number");
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);
}
}
break;
}
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
c = getc (finput);
}
ungetc (c, finput);
/* If the constant is not long long and it won't fit in an
unsigned long, or if the constant is long long and won't fit
in an unsigned long long, then warn that the constant is out
of range. */
/* ??? This assumes that long long and long integer types are
a multiple of 8 bits. This better than the original code
though which assumed that long was exactly 32 bits and long
long was exactly 64 bits. */
if (spec_long_long)
bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
else
bytes = TYPE_PRECISION (long_integer_type_node) / 8;
warn = overflow;
for (i = bytes; i < TOTAL_PARTS; i++)
if (parts[i])
warn = 1;
if (warn)
pedwarn ("integer constant out of range");
/* This is simplified by the fact that our constant
is always positive. */
high = low = 0;
for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++)
{
high |= ((HOST_WIDE_INT) parts[i + (HOST_BITS_PER_WIDE_INT
/ HOST_BITS_PER_CHAR)]
<< (i * HOST_BITS_PER_CHAR));
low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
}
yylval.ttype = build_int_2 (low, high);
TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node;
/* If warn_traditional, calculate both the ANSI type and the
traditional type, then see if they disagree.
Otherwise, calculate only the type for the dialect in use. */
if (warn_traditional || flag_traditional)
{
/* Calculate the traditional type. */
/* Traditionally, any constant is signed;
but if unsigned is specified explicitly, obey that.
Use the smallest size with the right number of bits,
except for one special case with decimal constants. */
if (! spec_long && base != 10
&& int_fits_type_p (yylval.ttype, unsigned_type_node))
traditional_type = (spec_unsigned ? unsigned_type_node
: integer_type_node);
/* A decimal constant must be long
if it does not fit in type int.
I think this is independent of whether
the constant is signed. */
else if (! spec_long && base == 10
&& int_fits_type_p (yylval.ttype, integer_type_node))
traditional_type = (spec_unsigned ? unsigned_type_node
: integer_type_node);
else if (! spec_long_long)
traditional_type = (spec_unsigned ? long_unsigned_type_node
: long_integer_type_node);
else
traditional_type = (spec_unsigned
? long_long_unsigned_type_node
: long_long_integer_type_node);
}
if (warn_traditional || ! flag_traditional)
{
/* Calculate the ANSI type. */
if (! spec_long && ! spec_unsigned
&& int_fits_type_p (yylval.ttype, integer_type_node))
ansi_type = integer_type_node;
else if (! spec_long && (base != 10 || spec_unsigned)
&& int_fits_type_p (yylval.ttype, unsigned_type_node))
ansi_type = unsigned_type_node;
else if (! spec_unsigned && !spec_long_long
&& int_fits_type_p (yylval.ttype, long_integer_type_node))
ansi_type = long_integer_type_node;
else if (! spec_long_long)
ansi_type = long_unsigned_type_node;
else if (! spec_unsigned
/* Verify value does not overflow into sign bit. */
&& TREE_INT_CST_HIGH (yylval.ttype) >= 0
&& int_fits_type_p (yylval.ttype,
long_long_integer_type_node))
ansi_type = long_long_integer_type_node;
else
ansi_type = long_long_unsigned_type_node;
}
type = flag_traditional ? traditional_type : ansi_type;
if (warn_traditional && traditional_type != ansi_type)
{
if (TYPE_PRECISION (traditional_type)
!= TYPE_PRECISION (ansi_type))
warning ("width of integer constant changes with -traditional");
else if (TREE_UNSIGNED (traditional_type)
!= TREE_UNSIGNED (ansi_type))
warning ("integer constant is unsigned in ANSI C, signed with -traditional");
else
warning ("width of integer constant may change on other systems with -traditional");
}
if (!flag_traditional && !int_fits_type_p (yylval.ttype, type)
&& !warn)
pedwarn ("integer constant out of range");
if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
warning ("decimal constant is so large that it is unsigned");
if (spec_imag)
{
if (TYPE_PRECISION (type)
<= TYPE_PRECISION (integer_type_node))
yylval.ttype
= build_complex (integer_zero_node,
convert (integer_type_node, yylval.ttype));
else
error ("complex integer constant is too wide for `complex int'");
}
else if (flag_traditional && !int_fits_type_p (yylval.ttype, type))
/* The traditional constant 0x80000000 is signed
but doesn't fit in the range of int.
This will change it to -0x80000000, which does fit. */
{
TREE_TYPE (yylval.ttype) = unsigned_type (type);
yylval.ttype = convert (type, yylval.ttype);
}
else
TREE_TYPE (yylval.ttype) = type;
*p = 0;
}
value = CONSTANT; break;
}
case '\'':
char_constant:
{
register int result = 0;
register int num_chars = 0;
unsigned width = TYPE_PRECISION (char_type_node);
int max_chars;
if (wide_flag)
{
width = WCHAR_TYPE_SIZE;
#ifdef MULTIBYTE_CHARS
max_chars = MB_CUR_MAX;
#else
max_chars = 1;
#endif
}
else
max_chars = TYPE_PRECISION (integer_type_node) / width;
while (1)
{
tryagain:
c = getc (finput);
if (c == '\'' || c == EOF)
break;
if (c == '\\')
{
int ignore = 0;
c = readescape (&ignore);
if (ignore)
goto tryagain;
#ifndef ADI
if (width < HOST_BITS_PER_INT
&& (unsigned) c >= (1 << width))
pedwarn ("escape sequence out of range for character");
#endif
}
else if (c == '\n')
{
if (pedantic)
pedwarn ("ANSI C forbids newline in character constant");
lineno++;
}
num_chars++;
if (num_chars > maxtoken - 4)
extend_token_buffer (token_buffer);
token_buffer[num_chars] = c;
/* 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] = '\'';
token_buffer[num_chars + 2] = 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 && ! flag_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 (TREE_UNSIGNED (char_type_node)
|| ((result >> (num_bits - 1)) & 1) == 0)
yylval.ttype
= build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
>> (HOST_BITS_PER_WIDE_INT - num_bits)),
0);
else
yylval.ttype
= build_int_2 (result | ~((unsigned HOST_WIDE_INT) ~0
>> (HOST_BITS_PER_WIDE_INT - num_bits)),
-1);
TREE_TYPE (yylval.ttype) = integer_type_node;
}
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[1] != '\0'))
{
wchar_t wc;
(void) mbtowc (NULL_PTR, NULL_PTR, 0);
if (mbtowc (& wc, token_buffer + 1, num_chars) == num_chars)
result = wc;
else
warning ("Ignoring invalid multibyte character");
}
#endif
yylval.ttype = build_int_2 (result, 0);
TREE_TYPE (yylval.ttype) = wchar_type_node;
}
value = CONSTANT;
break;
}
case '"':
string_constant:
{
c = getc (finput);
p = token_buffer + 1;
while (c != '"' && c >= 0)
{
/* ignore_escape_flag is set for reading the filename in #line. */
if (!ignore_escape_flag && c == '\\')
{
int ignore = 0;
c = readescape (&ignore);
if (ignore)
goto skipnewline;
#ifndef ADI
if (!wide_flag
&& TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
&& c >= (1 << TYPE_PRECISION (char_type_node)))
pedwarn ("escape sequence out of range for character");
#endif
}
else if (c == '\n')
{
if (pedantic)
pedwarn ("ANSI C forbids newline in string constant");
lineno++;
}
if (p == token_buffer + maxtoken)
p = extend_token_buffer (p);
*p++ = c;
skipnewline:
c = getc (finput);
}
*p = 0;
/* We have read the entire constant.
Construct a STRING_CST for the result. */
if (wide_flag)
{
/* If this is a L"..." wide-string, convert the multibyte string
to a wide character string. */
char *widep = (char *) alloca ((p - token_buffer) * WCHAR_BYTES);
int len;
#ifdef MULTIBYTE_CHARS
len = mbstowcs ((wchar_t *) widep, token_buffer + 1, p - token_buffer);
if ((unsigned) len >= (p - token_buffer))
{
warning ("Ignoring invalid multibyte string");
len = 0;
}
bzero (widep + (len * WCHAR_BYTES), WCHAR_BYTES);
#else
{
union { long l; char c[sizeof (long)]; } u;
int big_endian;
char *wp, *cp;
/* Determine whether host is little or big endian. */
u.l = 1;
big_endian = u.c[sizeof (long) - 1];
wp = widep + (big_endian ? WCHAR_BYTES - 1 : 0);
bzero (widep, (p - token_buffer) * WCHAR_BYTES);
for (cp = token_buffer + 1; cp < p; cp++)
*wp = *cp, wp += WCHAR_BYTES;
len = p - token_buffer - 1;
}
#endif
yylval.ttype = build_string ((len + 1) * WCHAR_BYTES, widep);
TREE_TYPE (yylval.ttype) = wchar_array_type_node;
}
else
{
yylval.ttype = build_string (p - token_buffer, token_buffer + 1);
TREE_TYPE (yylval.ttype) = char_array_type_node;
}
*p++ = '"';
*p = 0;
value = STRING; break;
}
case '+':
case '-':
case '&':
case '|':
case '<':
case '>':
case '*':
case '/':
case '%':
case '^':
case '!':
case '=':
{
register int c1;
combine:
switch (c)
{
case '+':
yylval.code = PLUS_EXPR; break;
case '-':
yylval.code = MINUS_EXPR; break;
case '&':
yylval.code = BIT_AND_EXPR; break;
case '|':
yylval.code = BIT_IOR_EXPR; break;
case '*':
yylval.code = MULT_EXPR; break;
case '/':
yylval.code = TRUNC_DIV_EXPR; break;
case '%':
yylval.code = TRUNC_MOD_EXPR; break;
case '^':
yylval.code = BIT_XOR_EXPR; break;
case LSHIFT:
yylval.code = LSHIFT_EXPR; break;
case RSHIFT:
yylval.code = RSHIFT_EXPR; break;
case '<':
yylval.code = LT_EXPR; break;
case '>':
yylval.code = GT_EXPR; break;
}
token_buffer[1] = c1 = getc (finput);
token_buffer[2] = 0;
if (c1 == '=')
{
switch (c)
{
case '<':
value = ARITHCOMPARE; yylval.code = LE_EXPR; goto done;
case '>':
value = ARITHCOMPARE; yylval.code = GE_EXPR; goto done;
case '!':
value = EQCOMPARE; yylval.code = NE_EXPR; goto done;
case '=':
value = EQCOMPARE; yylval.code = EQ_EXPR; goto done;
}
value = ASSIGN; goto done;
}
else if (c == c1)
switch (c)
{
case '+':
value = PLUSPLUS; goto done;
case '-':
value = MINUSMINUS; goto done;
case '&':
value = ANDAND; goto done;
case '|':
value = OROR; goto done;
case '<':
c = LSHIFT;
goto combine;
case '>':
c = RSHIFT;
goto combine;
}
else if ((c == '-') && (c1 == '>'))
{ value = POINTSAT; goto done; }
ungetc (c1, finput);
token_buffer[1] = 0;
if ((c == '<') || (c == '>'))
value = ARITHCOMPARE;
else value = c;
goto done;
}
case 0:
/* Don't make yyparse think this is eof. */
value = 1;
break;
default:
value = c;
}
done:
/* yylloc.last_line = lineno; */
return value;
}
/* Sets the value of the 'yydebug' variable to VALUE.
This is a function so we don't have to have YYDEBUG defined
in order to build the compiler. */
void
set_yydebug (value)
int value;
{
#if YYDEBUG != 0
yydebug = value;
#else
warning ("YYDEBUG not defined.");
#endif
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?