forked from OSchip/llvm-project
Bug #:
Submitted by: Reviewed by: Moved numeric literal support from SemaExpr.cpp to LiteralSupport.[h,cpp] in Lex. This will allow it to be used by both Sema and Preprocessor (and should be the last major refactoring of this sub-system).. Over time, it will be reused by anyone implementing an actions module (i.e. any subclass of llvm::clang::Action. Minor changes to IntegerLiteral in Expr.h. More to come... llvm-svn: 39351
This commit is contained in:
parent
cf30755a41
commit
09ef474197
|
@ -16,6 +16,7 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
|
@ -24,7 +25,7 @@
|
|||
using namespace llvm;
|
||||
using namespace clang;
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
|
||||
/// not valid.
|
||||
|
@ -285,68 +286,6 @@ Sema::ExprResult Sema::ParseSimplePrimaryExpr(SourceLocation Loc,
|
|||
}
|
||||
}
|
||||
|
||||
/// SkipHexDigits - Read and skip over any hex digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
static const char *SkipHexDigits(const char *ptr, const char *end) {
|
||||
while (ptr != end && isxdigit(*ptr))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// SkipOctalDigits - Read and skip over any octal digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
static const char *SkipOctalDigits(const char *ptr, const char *end) {
|
||||
while (ptr != end && ((*ptr >= '0') && (*ptr <= '7')))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// SkipDigits - Read and skip over any digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
static const char *SkipDigits(const char *ptr, const char *end) {
|
||||
while (ptr != end && isdigit(*ptr))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// integer-constant: [C99 6.4.4.1]
|
||||
/// decimal-constant integer-suffix
|
||||
/// octal-constant integer-suffix
|
||||
/// hexadecimal-constant integer-suffix
|
||||
/// decimal-constant:
|
||||
/// nonzero-digit
|
||||
/// decimal-constant digit
|
||||
/// octal-constant:
|
||||
/// 0
|
||||
/// octal-constant octal-digit
|
||||
/// hexadecimal-constant:
|
||||
/// hexadecimal-prefix hexadecimal-digit
|
||||
/// hexadecimal-constant hexadecimal-digit
|
||||
/// hexadecimal-prefix: one of
|
||||
/// 0x 0X
|
||||
/// integer-suffix:
|
||||
/// unsigned-suffix [long-suffix]
|
||||
/// unsigned-suffix [long-long-suffix]
|
||||
/// long-suffix [unsigned-suffix]
|
||||
/// long-long-suffix [unsigned-sufix]
|
||||
/// nonzero-digit:
|
||||
/// 1 2 3 4 5 6 7 8 9
|
||||
/// octal-digit:
|
||||
/// 0 1 2 3 4 5 6 7
|
||||
/// hexadecimal-digit:
|
||||
/// 0 1 2 3 4 5 6 7 8 9
|
||||
/// a b c d e f
|
||||
/// A B C D E F
|
||||
/// unsigned-suffix: one of
|
||||
/// u U
|
||||
/// long-suffix: one of
|
||||
/// l L
|
||||
/// long-long-suffix: one of
|
||||
/// ll LL
|
||||
///
|
||||
/// floating-constant: [C99 6.4.4.2]
|
||||
/// TODO: add rules...
|
||||
///
|
||||
Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) {
|
||||
SmallString<512> IntegerBuffer;
|
||||
IntegerBuffer.resize(Tok.getLength());
|
||||
|
@ -360,148 +299,37 @@ Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) {
|
|||
// a pointer to a *constant* buffer (avoiding a copy).
|
||||
|
||||
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
|
||||
ExprResult Res;
|
||||
|
||||
// This is an optimization for single digits (which are very common).
|
||||
if (ActualLength == 1) {
|
||||
return ExprResult(new IntegerLiteral());
|
||||
}
|
||||
const char *ThisTokEnd = ThisTokBegin+ActualLength;
|
||||
const char *s = ThisTokBegin;
|
||||
unsigned int radix;
|
||||
bool saw_exponent = false, saw_period = false;
|
||||
Expr *literal_expr = 0;
|
||||
|
||||
if (*s == '0') { // parse radix
|
||||
s++;
|
||||
if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
|
||||
s++;
|
||||
radix = 16;
|
||||
s = SkipHexDigits(s, ThisTokEnd);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipHexDigits(s, ThisTokEnd);
|
||||
}
|
||||
// A binary exponent can appear with or with a '.'. If dotted, the
|
||||
// binary exponent is required.
|
||||
if (*s == 'p' || *s == 'P') {
|
||||
s++;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s, ThisTokEnd);
|
||||
if (first_non_digit == s) {
|
||||
Diag(Tok, diag::err_exponent_has_no_digits);
|
||||
return ExprResult(true);
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
} else if (saw_period) {
|
||||
Diag(Tok, diag::err_hexconstant_requires_exponent);
|
||||
return ExprResult(true);
|
||||
}
|
||||
} else {
|
||||
// For now, the radix is set to 8. If we discover that we have a
|
||||
// floating point constant, the radix will change to 10. Octal floating
|
||||
// point constants are not permitted (only decimal and hexadecimal).
|
||||
radix = 8;
|
||||
s = SkipOctalDigits(s, ThisTokEnd);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s, ThisTokEnd);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s, ThisTokEnd);
|
||||
if (first_non_digit == s) {
|
||||
Diag(Tok, diag::err_exponent_has_no_digits);
|
||||
return ExprResult(true);
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // the first digit is non-zero
|
||||
radix = 10;
|
||||
s = SkipDigits(s, ThisTokEnd);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s, ThisTokEnd);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s, ThisTokEnd);
|
||||
if (first_non_digit == s) {
|
||||
Diag(Tok, diag::err_exponent_has_no_digits);
|
||||
return ExprResult(true);
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *suffix_start = s;
|
||||
|
||||
if (saw_period || saw_exponent) {
|
||||
bool saw_float_suffix = false, saw_long_suffix = false;
|
||||
if (ActualLength == 1)
|
||||
return ExprResult(new IntegerLiteral(atoi(ThisTokBegin)));
|
||||
|
||||
if (s < ThisTokEnd) { // parse size suffix (float, long double)
|
||||
if (*s == 'f' || *s == 'F') {
|
||||
saw_float_suffix = true;
|
||||
s++;
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
saw_long_suffix = true;
|
||||
s++;
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(Tok, diag::err_invalid_suffix_float_constant,
|
||||
std::string(suffix_start, ThisTokEnd));
|
||||
return ExprResult(true);
|
||||
}
|
||||
}
|
||||
literal_expr = new FloatingLiteral();
|
||||
} else {
|
||||
bool saw_unsigned = false, saw_long = false, saw_longlong = false;
|
||||
|
||||
// if there is no suffix, this loop won't be executed (s == ThisTokEnd)
|
||||
while (s < ThisTokEnd) {
|
||||
// parse int suffix - they can appear in any order ("ul", "lu", "llu").
|
||||
if (*s == 'u' || *s == 'U') {
|
||||
if (saw_unsigned) break; // only allowed to have one
|
||||
saw_unsigned = true;
|
||||
s++;
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
if (saw_long || saw_longlong) break; // only allowed to have one
|
||||
s++;
|
||||
if (s < ThisTokEnd && (*s == *(s-1))) {
|
||||
saw_longlong = true; // l's need to be adjacent and same case.
|
||||
s++;
|
||||
} else {
|
||||
saw_long = true;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(Tok, diag::err_invalid_suffix_integer_constant,
|
||||
std::string(suffix_start, ThisTokEnd));
|
||||
return ExprResult(true);
|
||||
}
|
||||
literal_expr = new IntegerLiteral();
|
||||
NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
||||
Tok.getLocation(), PP, Context.Target);
|
||||
if (Literal.hadError) {
|
||||
return ExprResult(true);
|
||||
}
|
||||
Expr *literal_expr;
|
||||
|
||||
if (Literal.isIntegerLiteral()) {
|
||||
TypeRef t;
|
||||
if (Literal.hasSuffix()) {
|
||||
if (Literal.isLong)
|
||||
t = Literal.isUnsigned ? Context.UnsignedLongTy : Context.LongTy;
|
||||
else if (Literal.isLongLong)
|
||||
t = Literal.isUnsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
|
||||
else
|
||||
t = Context.UnsignedIntTy;
|
||||
} else {
|
||||
t = Context.IntTy; // implicit type is "int"
|
||||
}
|
||||
intmax_t val;
|
||||
if (Literal.GetValue(val)) {
|
||||
literal_expr = new IntegerLiteral(val, t);
|
||||
}
|
||||
} else if (Literal.isFloatingLiteral()) {
|
||||
// TODO: add floating point processing...
|
||||
}
|
||||
return ExprResult(literal_expr);
|
||||
}
|
||||
|
||||
Action::ExprResult Sema::ParseParenExpr(SourceLocation L, SourceLocation R,
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
//===--- LiteralSupport.cpp - Code to parse and process literals-*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Steve Naroff and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the NumericLiteralParser interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace clang;
|
||||
|
||||
/// integer-constant: [C99 6.4.4.1]
|
||||
/// decimal-constant integer-suffix
|
||||
/// octal-constant integer-suffix
|
||||
/// hexadecimal-constant integer-suffix
|
||||
/// decimal-constant:
|
||||
/// nonzero-digit
|
||||
/// decimal-constant digit
|
||||
/// octal-constant:
|
||||
/// 0
|
||||
/// octal-constant octal-digit
|
||||
/// hexadecimal-constant:
|
||||
/// hexadecimal-prefix hexadecimal-digit
|
||||
/// hexadecimal-constant hexadecimal-digit
|
||||
/// hexadecimal-prefix: one of
|
||||
/// 0x 0X
|
||||
/// integer-suffix:
|
||||
/// unsigned-suffix [long-suffix]
|
||||
/// unsigned-suffix [long-long-suffix]
|
||||
/// long-suffix [unsigned-suffix]
|
||||
/// long-long-suffix [unsigned-sufix]
|
||||
/// nonzero-digit:
|
||||
/// 1 2 3 4 5 6 7 8 9
|
||||
/// octal-digit:
|
||||
/// 0 1 2 3 4 5 6 7
|
||||
/// hexadecimal-digit:
|
||||
/// 0 1 2 3 4 5 6 7 8 9
|
||||
/// a b c d e f
|
||||
/// A B C D E F
|
||||
/// unsigned-suffix: one of
|
||||
/// u U
|
||||
/// long-suffix: one of
|
||||
/// l L
|
||||
/// long-long-suffix: one of
|
||||
/// ll LL
|
||||
///
|
||||
/// floating-constant: [C99 6.4.4.2]
|
||||
/// TODO: add rules...
|
||||
///
|
||||
|
||||
NumericLiteralParser::
|
||||
NumericLiteralParser(const char *begin, const char *end,
|
||||
SourceLocation TokLoc, Preprocessor &pp, TargetInfo &t) :
|
||||
PP(pp), Target(t), ThisTokBegin(begin), ThisTokEnd(end)
|
||||
{
|
||||
s = DigitsBegin = begin;
|
||||
saw_exponent = false;
|
||||
saw_period = false;
|
||||
saw_float_suffix = false;
|
||||
isLong = false;
|
||||
isUnsigned = false;
|
||||
isLongLong = false;
|
||||
hadError = false;
|
||||
|
||||
if (*s == '0') { // parse radix
|
||||
s++;
|
||||
if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
|
||||
s++;
|
||||
radix = 16;
|
||||
DigitsBegin = s;
|
||||
s = SkipHexDigits(s);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipHexDigits(s);
|
||||
}
|
||||
// A binary exponent can appear with or with a '.'. If dotted, the
|
||||
// binary exponent is required.
|
||||
if (*s == 'p' || *s == 'P') {
|
||||
s++;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s);
|
||||
if (first_non_digit == s) {
|
||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
||||
return;
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
} else if (saw_period) {
|
||||
Diag(TokLoc, diag::err_hexconstant_requires_exponent);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// For now, the radix is set to 8. If we discover that we have a
|
||||
// floating point constant, the radix will change to 10. Octal floating
|
||||
// point constants are not permitted (only decimal and hexadecimal).
|
||||
radix = 8;
|
||||
DigitsBegin = s;
|
||||
s = SkipOctalDigits(s);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s);
|
||||
if (first_non_digit == s) {
|
||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
||||
return;
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // the first digit is non-zero
|
||||
radix = 10;
|
||||
s = SkipDigits(s);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s);
|
||||
if (first_non_digit == s) {
|
||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
||||
return;
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SuffixBegin = s;
|
||||
|
||||
if (saw_period || saw_exponent) {
|
||||
if (s < ThisTokEnd) { // parse size suffix (float, long double)
|
||||
if (*s == 'f' || *s == 'F') {
|
||||
saw_float_suffix = true;
|
||||
s++;
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
isLong = true;
|
||||
s++;
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(TokLoc, diag::err_invalid_suffix_float_constant,
|
||||
std::string(SuffixBegin, ThisTokEnd));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (s < ThisTokEnd) {
|
||||
// parse int suffix - they can appear in any order ("ul", "lu", "llu").
|
||||
if (*s == 'u' || *s == 'U') {
|
||||
s++;
|
||||
isUnsigned = true; // unsigned
|
||||
|
||||
if ((s < ThisTokEnd) && (*s == 'l' || *s == 'L')) {
|
||||
s++;
|
||||
// handle "long long" type - l's need to be adjacent and same case.
|
||||
if ((s < ThisTokEnd) && (*s == *(s-1))) {
|
||||
isLongLong = true; // unsigned long long
|
||||
s++;
|
||||
} else {
|
||||
isLong = true; // unsigned long
|
||||
}
|
||||
}
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
s++;
|
||||
// handle "long long" types - l's need to be adjacent and same case.
|
||||
if ((s < ThisTokEnd) && (*s == *(s-1))) {
|
||||
s++;
|
||||
if ((s < ThisTokEnd) && (*s == 'u' || *s == 'U')) {
|
||||
isUnsigned = true; // unsigned long long
|
||||
s++;
|
||||
} else {
|
||||
isLongLong = true; // long long
|
||||
}
|
||||
} else { // handle "long" types
|
||||
if ((s < ThisTokEnd) && (*s == 'u' || *s == 'U')) {
|
||||
isUnsigned = true; // unsigned long
|
||||
s++;
|
||||
} else {
|
||||
isLong = true; // long
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(TokLoc, diag::err_invalid_suffix_integer_constant,
|
||||
std::string(SuffixBegin, ThisTokEnd));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NumericLiteralParser::GetValue(intmax_t &val) {
|
||||
intmax_t cutoff = INTMAX_MAX;
|
||||
int cutlim = cutoff % radix;
|
||||
char c;
|
||||
|
||||
val = 0;
|
||||
cutoff /= radix;
|
||||
s = DigitsBegin;
|
||||
while (s < SuffixBegin) {
|
||||
c = *s++;
|
||||
if (c >= '0' && c <= '9')
|
||||
c -= '0';
|
||||
else if (c >= 'A' && c <= 'F') // 10...15
|
||||
c -= 'A' - 10;
|
||||
else if (c >= 'a' && c <= 'f') // 10...15
|
||||
c -= 'a' - 10;
|
||||
|
||||
if (val > cutoff || (val == cutoff && c > cutlim)) {
|
||||
return false; // Overflow!
|
||||
} else {
|
||||
val *= radix;
|
||||
val += c;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
|
@ -24,7 +25,7 @@
|
|||
using namespace llvm;
|
||||
using namespace clang;
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
|
||||
/// not valid.
|
||||
|
@ -285,68 +286,6 @@ Sema::ExprResult Sema::ParseSimplePrimaryExpr(SourceLocation Loc,
|
|||
}
|
||||
}
|
||||
|
||||
/// SkipHexDigits - Read and skip over any hex digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
static const char *SkipHexDigits(const char *ptr, const char *end) {
|
||||
while (ptr != end && isxdigit(*ptr))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// SkipOctalDigits - Read and skip over any octal digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
static const char *SkipOctalDigits(const char *ptr, const char *end) {
|
||||
while (ptr != end && ((*ptr >= '0') && (*ptr <= '7')))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// SkipDigits - Read and skip over any digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
static const char *SkipDigits(const char *ptr, const char *end) {
|
||||
while (ptr != end && isdigit(*ptr))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// integer-constant: [C99 6.4.4.1]
|
||||
/// decimal-constant integer-suffix
|
||||
/// octal-constant integer-suffix
|
||||
/// hexadecimal-constant integer-suffix
|
||||
/// decimal-constant:
|
||||
/// nonzero-digit
|
||||
/// decimal-constant digit
|
||||
/// octal-constant:
|
||||
/// 0
|
||||
/// octal-constant octal-digit
|
||||
/// hexadecimal-constant:
|
||||
/// hexadecimal-prefix hexadecimal-digit
|
||||
/// hexadecimal-constant hexadecimal-digit
|
||||
/// hexadecimal-prefix: one of
|
||||
/// 0x 0X
|
||||
/// integer-suffix:
|
||||
/// unsigned-suffix [long-suffix]
|
||||
/// unsigned-suffix [long-long-suffix]
|
||||
/// long-suffix [unsigned-suffix]
|
||||
/// long-long-suffix [unsigned-sufix]
|
||||
/// nonzero-digit:
|
||||
/// 1 2 3 4 5 6 7 8 9
|
||||
/// octal-digit:
|
||||
/// 0 1 2 3 4 5 6 7
|
||||
/// hexadecimal-digit:
|
||||
/// 0 1 2 3 4 5 6 7 8 9
|
||||
/// a b c d e f
|
||||
/// A B C D E F
|
||||
/// unsigned-suffix: one of
|
||||
/// u U
|
||||
/// long-suffix: one of
|
||||
/// l L
|
||||
/// long-long-suffix: one of
|
||||
/// ll LL
|
||||
///
|
||||
/// floating-constant: [C99 6.4.4.2]
|
||||
/// TODO: add rules...
|
||||
///
|
||||
Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) {
|
||||
SmallString<512> IntegerBuffer;
|
||||
IntegerBuffer.resize(Tok.getLength());
|
||||
|
@ -360,148 +299,37 @@ Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) {
|
|||
// a pointer to a *constant* buffer (avoiding a copy).
|
||||
|
||||
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
|
||||
ExprResult Res;
|
||||
|
||||
// This is an optimization for single digits (which are very common).
|
||||
if (ActualLength == 1) {
|
||||
return ExprResult(new IntegerLiteral());
|
||||
}
|
||||
const char *ThisTokEnd = ThisTokBegin+ActualLength;
|
||||
const char *s = ThisTokBegin;
|
||||
unsigned int radix;
|
||||
bool saw_exponent = false, saw_period = false;
|
||||
Expr *literal_expr = 0;
|
||||
|
||||
if (*s == '0') { // parse radix
|
||||
s++;
|
||||
if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
|
||||
s++;
|
||||
radix = 16;
|
||||
s = SkipHexDigits(s, ThisTokEnd);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipHexDigits(s, ThisTokEnd);
|
||||
}
|
||||
// A binary exponent can appear with or with a '.'. If dotted, the
|
||||
// binary exponent is required.
|
||||
if (*s == 'p' || *s == 'P') {
|
||||
s++;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s, ThisTokEnd);
|
||||
if (first_non_digit == s) {
|
||||
Diag(Tok, diag::err_exponent_has_no_digits);
|
||||
return ExprResult(true);
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
} else if (saw_period) {
|
||||
Diag(Tok, diag::err_hexconstant_requires_exponent);
|
||||
return ExprResult(true);
|
||||
}
|
||||
} else {
|
||||
// For now, the radix is set to 8. If we discover that we have a
|
||||
// floating point constant, the radix will change to 10. Octal floating
|
||||
// point constants are not permitted (only decimal and hexadecimal).
|
||||
radix = 8;
|
||||
s = SkipOctalDigits(s, ThisTokEnd);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s, ThisTokEnd);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s, ThisTokEnd);
|
||||
if (first_non_digit == s) {
|
||||
Diag(Tok, diag::err_exponent_has_no_digits);
|
||||
return ExprResult(true);
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // the first digit is non-zero
|
||||
radix = 10;
|
||||
s = SkipDigits(s, ThisTokEnd);
|
||||
if (s == ThisTokEnd) {
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s, ThisTokEnd);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s, ThisTokEnd);
|
||||
if (first_non_digit == s) {
|
||||
Diag(Tok, diag::err_exponent_has_no_digits);
|
||||
return ExprResult(true);
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *suffix_start = s;
|
||||
|
||||
if (saw_period || saw_exponent) {
|
||||
bool saw_float_suffix = false, saw_long_suffix = false;
|
||||
if (ActualLength == 1)
|
||||
return ExprResult(new IntegerLiteral(atoi(ThisTokBegin)));
|
||||
|
||||
if (s < ThisTokEnd) { // parse size suffix (float, long double)
|
||||
if (*s == 'f' || *s == 'F') {
|
||||
saw_float_suffix = true;
|
||||
s++;
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
saw_long_suffix = true;
|
||||
s++;
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(Tok, diag::err_invalid_suffix_float_constant,
|
||||
std::string(suffix_start, ThisTokEnd));
|
||||
return ExprResult(true);
|
||||
}
|
||||
}
|
||||
literal_expr = new FloatingLiteral();
|
||||
} else {
|
||||
bool saw_unsigned = false, saw_long = false, saw_longlong = false;
|
||||
|
||||
// if there is no suffix, this loop won't be executed (s == ThisTokEnd)
|
||||
while (s < ThisTokEnd) {
|
||||
// parse int suffix - they can appear in any order ("ul", "lu", "llu").
|
||||
if (*s == 'u' || *s == 'U') {
|
||||
if (saw_unsigned) break; // only allowed to have one
|
||||
saw_unsigned = true;
|
||||
s++;
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
if (saw_long || saw_longlong) break; // only allowed to have one
|
||||
s++;
|
||||
if (s < ThisTokEnd && (*s == *(s-1))) {
|
||||
saw_longlong = true; // l's need to be adjacent and same case.
|
||||
s++;
|
||||
} else {
|
||||
saw_long = true;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(Tok, diag::err_invalid_suffix_integer_constant,
|
||||
std::string(suffix_start, ThisTokEnd));
|
||||
return ExprResult(true);
|
||||
}
|
||||
literal_expr = new IntegerLiteral();
|
||||
NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
||||
Tok.getLocation(), PP, Context.Target);
|
||||
if (Literal.hadError) {
|
||||
return ExprResult(true);
|
||||
}
|
||||
Expr *literal_expr;
|
||||
|
||||
if (Literal.isIntegerLiteral()) {
|
||||
TypeRef t;
|
||||
if (Literal.hasSuffix()) {
|
||||
if (Literal.isLong)
|
||||
t = Literal.isUnsigned ? Context.UnsignedLongTy : Context.LongTy;
|
||||
else if (Literal.isLongLong)
|
||||
t = Literal.isUnsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
|
||||
else
|
||||
t = Context.UnsignedIntTy;
|
||||
} else {
|
||||
t = Context.IntTy; // implicit type is "int"
|
||||
}
|
||||
intmax_t val;
|
||||
if (Literal.GetValue(val)) {
|
||||
literal_expr = new IntegerLiteral(val, t);
|
||||
}
|
||||
} else if (Literal.isFloatingLiteral()) {
|
||||
// TODO: add floating point processing...
|
||||
}
|
||||
return ExprResult(literal_expr);
|
||||
}
|
||||
|
||||
Action::ExprResult Sema::ParseParenExpr(SourceLocation L, SourceLocation R,
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; };
|
||||
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
|
||||
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
|
||||
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
|
||||
DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06B73D0A8307640050E87E /* LangOptions.h */; };
|
||||
DE06BECB0A854E4B0050E87E /* Scope.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06BECA0A854E4B0050E87E /* Scope.h */; };
|
||||
|
@ -145,6 +147,7 @@
|
|||
DED67AEE0B6DB92A00AAD4A3 /* X86Builtins.def in CopyFiles */,
|
||||
DED67AF00B6DB92F00AAD4A3 /* PPCBuiltins.def in CopyFiles */,
|
||||
1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */,
|
||||
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
|
@ -152,6 +155,8 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = "<group>"; };
|
||||
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
|
||||
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
|
||||
8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
|
||||
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; };
|
||||
|
@ -415,6 +420,7 @@
|
|||
DED7D73F0A524295003AD0FB /* Pragma.h */,
|
||||
DED7D7400A524295003AD0FB /* Preprocessor.h */,
|
||||
DED7D9170A52518C003AD0FB /* ScratchBuffer.h */,
|
||||
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */,
|
||||
);
|
||||
name = Lex;
|
||||
path = clang/Lex;
|
||||
|
@ -436,6 +442,7 @@
|
|||
DED7D78C0A5242E6003AD0FB /* Lex */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */,
|
||||
DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */,
|
||||
DED7D79D0A5242E6003AD0FB /* IdentifierTable.cpp */,
|
||||
DED7D79E0A5242E6003AD0FB /* Lexer.cpp */,
|
||||
|
@ -534,6 +541,7 @@
|
|||
DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */,
|
||||
DE1737A90B0847BC0080B521 /* SemaType.cpp in Sources */,
|
||||
DED677C90B6C854100AAD4A3 /* Builtins.cpp in Sources */,
|
||||
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -60,9 +60,30 @@ public:
|
|||
static bool classof(const DeclRefExpr *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
// FIXME: The "type" will eventually be moved to Stmt.
|
||||
class IntegerLiteral : public Expr {
|
||||
TypeRef Type; // IntTy, LongTy, LongLongTy
|
||||
// UnsignedIntTy, UnsignedLongTy, UnsignedLongLongTy
|
||||
intmax_t Value;
|
||||
public:
|
||||
IntegerLiteral() : Expr(IntegerLiteralClass) {}
|
||||
// FIXME: To satisfy some of the current adhoc usage...
|
||||
IntegerLiteral() : Expr(IntegerLiteralClass),
|
||||
Type(0), Value(0) {
|
||||
}
|
||||
// constructor for the single digit case
|
||||
IntegerLiteral(intmax_t value) : Expr(IntegerLiteralClass),
|
||||
Type(0), Value(value) {
|
||||
}
|
||||
IntegerLiteral(intmax_t value, TypeRef type)
|
||||
: Expr(IntegerLiteralClass), Type(type), Value(value) {
|
||||
#if 0
|
||||
std::cout << "Value=" << Value;
|
||||
std::cout << " Type= ";
|
||||
std::cout << static_cast<BuiltinType *>(type.getTypePtr())->getName();
|
||||
std::cout << "\n";
|
||||
#endif
|
||||
}
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IntegerLiteralClass;
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
//===--- LiteralSupport.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Steve Naroff and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the NumericLiteralParser interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LITERALSUPPORT_H
|
||||
#define LLVM_CLANG_LITERALSUPPORT_H
|
||||
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace clang {
|
||||
|
||||
class Diagnostic;
|
||||
class Preprocessor;
|
||||
class TargetInfo;
|
||||
|
||||
struct NumericLiteralParser {
|
||||
NumericLiteralParser(const char *begin, const char *end,
|
||||
SourceLocation Loc, Preprocessor &PP, TargetInfo &T);
|
||||
private:
|
||||
Preprocessor &PP; // needed for diagnostics
|
||||
TargetInfo &Target; // needed to compute the size
|
||||
|
||||
const char *const ThisTokBegin;
|
||||
const char *const ThisTokEnd;
|
||||
const char *DigitsBegin, *SuffixBegin; // markers
|
||||
const char *s; // cursor
|
||||
|
||||
unsigned int radix;
|
||||
|
||||
bool saw_exponent, saw_period;
|
||||
bool saw_float_suffix;
|
||||
|
||||
public:
|
||||
bool hadError;
|
||||
bool isUnsigned;
|
||||
bool isLong;
|
||||
bool isLongLong;
|
||||
|
||||
bool isIntegerLiteral() {
|
||||
return !saw_period && !saw_exponent ? true : false;
|
||||
}
|
||||
bool isFloatingLiteral() {
|
||||
return saw_period || saw_exponent ? true : false;
|
||||
}
|
||||
bool hasSuffix() {
|
||||
return SuffixBegin != ThisTokEnd;
|
||||
}
|
||||
/// getValue - Convert the string into a number. At this point, we know
|
||||
/// the digit characters are valid (0...9, a...f, A...F). We don't know
|
||||
/// how many bits are needed to store the number. We return true if the
|
||||
/// value fit into intmax_t (typically 64-bit's), false otherwise. This
|
||||
/// API will likely be replaced by sizing hooks and APInt. Nevertheless,
|
||||
/// this provides basic conversion support for now.
|
||||
bool GetValue(intmax_t &val);
|
||||
|
||||
private:
|
||||
void Diag(SourceLocation Loc, unsigned DiagID,
|
||||
const std::string &M = std::string()) {
|
||||
PP.Diag(Loc, DiagID, M);
|
||||
hadError = true;
|
||||
}
|
||||
|
||||
/// SkipHexDigits - Read and skip over any hex digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
const char *SkipHexDigits(const char *ptr) {
|
||||
while (ptr != ThisTokEnd && isxdigit(*ptr))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// SkipOctalDigits - Read and skip over any octal digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
const char *SkipOctalDigits(const char *ptr) {
|
||||
while (ptr != ThisTokEnd && ((*ptr >= '0') && (*ptr <= '7')))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// SkipDigits - Read and skip over any digits, up to End.
|
||||
/// Return a pointer to the first non-hex digit or End.
|
||||
const char *SkipDigits(const char *ptr) {
|
||||
while (ptr != ThisTokEnd && isdigit(*ptr))
|
||||
ptr++;
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue