/* Parse C expressions for cpplib.
Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
- 2002, 2004, 2008, 2009 Free Software Foundation.
+ 2002, 2004, 2008, 2009, 2010 Free Software Foundation.
Contributed by Per Bothner, 1994.
This program is free software; you can redistribute it and/or modify it
static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,
enum cpp_ttype);
static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num);
-static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype,
+ source_location);
static cpp_num num_lshift (cpp_num, size_t, size_t);
static cpp_num num_rshift (cpp_num, size_t, size_t);
const uchar *limit;
unsigned int max_digit, result, radix;
enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
+ bool seen_digit;
/* If the lexer has done its job, length one can only be a single
digit. Fast-path this very common case. */
float_flag = NOT_FLOAT;
max_digit = 0;
radix = 10;
+ seen_digit = false;
/* First, interpret the radix. */
if (*str == '0')
if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
{
+ seen_digit = true;
c = hex_value (c);
if (c > max_digit)
max_digit = c;
return CPP_N_INVALID;
}
+ if (radix == 16 && !seen_digit)
+ SYNTAX_ERROR ("no digits in hexadecimal floating constant");
+
if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
cpp_error (pfile, CPP_DL_PEDWARN,
"use of C99 hexadecimal floating constant");
if (limit != str
&& CPP_WTRADITIONAL (pfile)
&& ! cpp_sys_macro_p (pfile))
- cpp_error (pfile, CPP_DL_WARNING,
- "traditional C rejects the \"%.*s\" suffix",
- (int) (limit - str), str);
+ cpp_warning (pfile, CPP_W_TRADITIONAL,
+ "traditional C rejects the \"%.*s\" suffix",
+ (int) (limit - str), str);
/* A suffix for double is a GCC extension via decimal float support.
If the suffix also specifies an imaginary value we'll catch that
if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
{
int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
- int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
+ int large = (result & CPP_N_WIDTH) == CPP_N_LARGE
+ && CPP_OPTION (pfile, warn_long_long);
- if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
- cpp_error (pfile, CPP_DL_WARNING,
- "traditional C rejects the \"%.*s\" suffix",
- (int) (limit - str), str);
+ if (u_or_i || large)
+ cpp_warning (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL,
+ "traditional C rejects the \"%.*s\" suffix",
+ (int) (limit - str), str);
}
if ((result & CPP_N_WIDTH) == CPP_N_LARGE
&& CPP_OPTION (pfile, warn_long_long))
- cpp_error (pfile,
- CPP_OPTION (pfile, c99) ? CPP_DL_WARNING : CPP_DL_PEDWARN,
- CPP_OPTION (pfile, cplusplus)
- ? "use of C++0x long long integer constant"
- : "use of C99 long long integer constant");
+ {
+ const char *message = CPP_OPTION (pfile, cplusplus)
+ ? N_("use of C++0x long long integer constant")
+ : N_("use of C99 long long integer constant");
+
+ if (CPP_OPTION (pfile, c99))
+ cpp_warning (pfile, CPP_W_LONG_LONG, message);
+ else
+ cpp_pedwarning (pfile, CPP_W_LONG_LONG, message);
+ }
result |= CPP_N_INTEGER;
}
if (token->type == CPP_NAME)
{
- node = token->val.node;
+ node = token->val.node.node;
if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
{
cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
break;
case CPP_NAME:
- if (token->val.node == pfile->spec_nodes.n_defined)
+ if (token->val.node.node == pfile->spec_nodes.n_defined)
return parse_defined (pfile);
else if (CPP_OPTION (pfile, cplusplus)
- && (token->val.node == pfile->spec_nodes.n_true
- || token->val.node == pfile->spec_nodes.n_false))
+ && (token->val.node.node == pfile->spec_nodes.n_true
+ || token->val.node.node == pfile->spec_nodes.n_false))
{
result.high = 0;
- result.low = (token->val.node == pfile->spec_nodes.n_true);
+ result.low = (token->val.node.node == pfile->spec_nodes.n_true);
}
else
{
result.high = 0;
result.low = 0;
if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
- cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined",
- NODE_NAME (token->val.node));
+ cpp_warning (pfile, CPP_W_UNDEF, "\"%s\" is not defined",
+ NODE_NAME (token->val.node.node));
}
break;
cpp_error (pfile, CPP_DL_PEDWARN,
"assertions are a GCC extension");
else if (CPP_OPTION (pfile, warn_deprecated))
- cpp_error (pfile, CPP_DL_WARNING,
- "assertions are a deprecated extension");
+ cpp_warning (pfile, CPP_W_DEPRECATED,
+ "assertions are a deprecated extension");
}
_cpp_test_assertion (pfile, &temp);
result.high = 0;
case CPP_DIV:
case CPP_MOD:
top[-1].value = num_div_op (pfile, top[-1].value,
- top->value, top->op);
+ top->value, top->op, top->loc);
top[-1].loc = top->loc;
break;
{
case CPP_UPLUS:
if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
- cpp_error (pfile, CPP_DL_WARNING,
- "traditional C rejects the unary plus operator");
+ cpp_warning (pfile, CPP_W_TRADITIONAL,
+ "traditional C rejects the unary plus operator");
num.overflow = false;
break;
return result;
}
-/* Divide two preprocessing numbers, returning the answer or the
- remainder depending upon OP. */
+/* Divide two preprocessing numbers, LHS and RHS, returning the answer
+ or the remainder depending upon OP. LOCATION is the source location
+ of this operator (for diagnostics). */
+
static cpp_num
-num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
+num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op,
+ source_location location)
{
cpp_num result, sub;
cpp_num_part mask;
else
{
if (!pfile->state.skip_eval)
- cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if");
+ cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0,
+ "division by zero in #if");
return lhs;
}