Support C++11/14 features: nullptr, decltype, unicode literals, custom literals, alignof

This commit is contained in:
rdb 2015-10-12 23:28:53 +02:00
parent a43d6a45c1
commit b65ad853fe
18 changed files with 4139 additions and 3376 deletions

File diff suppressed because it is too large Load Diff

View File

@ -49,216 +49,234 @@ extern int cppyydebug;
REAL = 258,
INTEGER = 259,
CHAR_TOK = 260,
STRING = 261,
SIMPLE_STRING = 261,
SIMPLE_IDENTIFIER = 262,
IDENTIFIER = 263,
TYPENAME_IDENTIFIER = 264,
SCOPING = 265,
TYPEDEFNAME = 266,
ELLIPSIS = 267,
OROR = 268,
ANDAND = 269,
EQCOMPARE = 270,
NECOMPARE = 271,
LECOMPARE = 272,
GECOMPARE = 273,
LSHIFT = 274,
RSHIFT = 275,
POINTSAT_STAR = 276,
DOT_STAR = 277,
UNARY = 278,
UNARY_NOT = 279,
UNARY_NEGATE = 280,
UNARY_MINUS = 281,
UNARY_STAR = 282,
UNARY_REF = 283,
POINTSAT = 284,
SCOPE = 285,
PLUSPLUS = 286,
MINUSMINUS = 287,
TIMESEQUAL = 288,
DIVIDEEQUAL = 289,
MODEQUAL = 290,
PLUSEQUAL = 291,
MINUSEQUAL = 292,
OREQUAL = 293,
ANDEQUAL = 294,
XOREQUAL = 295,
LSHIFTEQUAL = 296,
RSHIFTEQUAL = 297,
KW_BEGIN_PUBLISH = 298,
KW_BLOCKING = 299,
KW_BOOL = 300,
KW_CATCH = 301,
KW_CHAR = 302,
KW_CHAR16_T = 303,
KW_CHAR32_T = 304,
KW_CLASS = 305,
KW_CONST = 306,
KW_DELETE = 307,
KW_DOUBLE = 308,
KW_DYNAMIC_CAST = 309,
KW_ELSE = 310,
KW_END_PUBLISH = 311,
KW_ENUM = 312,
KW_EXTENSION = 313,
KW_EXTERN = 314,
KW_EXPLICIT = 315,
KW_PUBLISHED = 316,
KW_FALSE = 317,
KW_FLOAT = 318,
KW_FRIEND = 319,
KW_FOR = 320,
KW_GOTO = 321,
KW_IF = 322,
KW_INLINE = 323,
KW_INT = 324,
KW_LONG = 325,
KW_LONGLONG = 326,
KW_MAKE_PROPERTY = 327,
KW_MAKE_SEQ = 328,
KW_MUTABLE = 329,
KW_NAMESPACE = 330,
KW_NEW = 331,
KW_NOEXCEPT = 332,
KW_OPERATOR = 333,
KW_PRIVATE = 334,
KW_PROTECTED = 335,
KW_PUBLIC = 336,
KW_REGISTER = 337,
KW_RETURN = 338,
KW_SHORT = 339,
KW_SIGNED = 340,
KW_SIZEOF = 341,
KW_STATIC = 342,
KW_STATIC_ASSERT = 343,
KW_STATIC_CAST = 344,
KW_STRUCT = 345,
KW_TEMPLATE = 346,
KW_THROW = 347,
KW_TRUE = 348,
KW_TRY = 349,
KW_TYPEDEF = 350,
KW_TYPENAME = 351,
KW_UNION = 352,
KW_UNSIGNED = 353,
KW_USING = 354,
KW_VIRTUAL = 355,
KW_VOID = 356,
KW_VOLATILE = 357,
KW_WCHAR_T = 358,
KW_WHILE = 359,
START_CPP = 360,
START_CONST_EXPR = 361,
START_TYPE = 362
STRING_LITERAL = 263,
CUSTOM_LITERAL = 264,
IDENTIFIER = 265,
TYPENAME_IDENTIFIER = 266,
SCOPING = 267,
TYPEDEFNAME = 268,
ELLIPSIS = 269,
OROR = 270,
ANDAND = 271,
EQCOMPARE = 272,
NECOMPARE = 273,
LECOMPARE = 274,
GECOMPARE = 275,
LSHIFT = 276,
RSHIFT = 277,
POINTSAT_STAR = 278,
DOT_STAR = 279,
UNARY = 280,
UNARY_NOT = 281,
UNARY_NEGATE = 282,
UNARY_MINUS = 283,
UNARY_STAR = 284,
UNARY_REF = 285,
POINTSAT = 286,
SCOPE = 287,
PLUSPLUS = 288,
MINUSMINUS = 289,
TIMESEQUAL = 290,
DIVIDEEQUAL = 291,
MODEQUAL = 292,
PLUSEQUAL = 293,
MINUSEQUAL = 294,
OREQUAL = 295,
ANDEQUAL = 296,
XOREQUAL = 297,
LSHIFTEQUAL = 298,
RSHIFTEQUAL = 299,
KW_ALIGNAS = 300,
KW_ALIGNOF = 301,
KW_AUTO = 302,
KW_BEGIN_PUBLISH = 303,
KW_BLOCKING = 304,
KW_BOOL = 305,
KW_CATCH = 306,
KW_CHAR = 307,
KW_CHAR16_T = 308,
KW_CHAR32_T = 309,
KW_CLASS = 310,
KW_CONST = 311,
KW_CONSTEXPR = 312,
KW_DECLTYPE = 313,
KW_DEFAULT = 314,
KW_DELETE = 315,
KW_DOUBLE = 316,
KW_DYNAMIC_CAST = 317,
KW_ELSE = 318,
KW_END_PUBLISH = 319,
KW_ENUM = 320,
KW_EXTENSION = 321,
KW_EXTERN = 322,
KW_EXPLICIT = 323,
KW_PUBLISHED = 324,
KW_FALSE = 325,
KW_FLOAT = 326,
KW_FRIEND = 327,
KW_FOR = 328,
KW_GOTO = 329,
KW_IF = 330,
KW_INLINE = 331,
KW_INT = 332,
KW_LONG = 333,
KW_LONGLONG = 334,
KW_MAKE_PROPERTY = 335,
KW_MAKE_SEQ = 336,
KW_MUTABLE = 337,
KW_NAMESPACE = 338,
KW_NEW = 339,
KW_NOEXCEPT = 340,
KW_NULLPTR = 341,
KW_OPERATOR = 342,
KW_PRIVATE = 343,
KW_PROTECTED = 344,
KW_PUBLIC = 345,
KW_REGISTER = 346,
KW_RETURN = 347,
KW_SHORT = 348,
KW_SIGNED = 349,
KW_SIZEOF = 350,
KW_STATIC = 351,
KW_STATIC_ASSERT = 352,
KW_STATIC_CAST = 353,
KW_STRUCT = 354,
KW_TEMPLATE = 355,
KW_THROW = 356,
KW_TRUE = 357,
KW_TRY = 358,
KW_TYPEDEF = 359,
KW_TYPENAME = 360,
KW_UNION = 361,
KW_UNSIGNED = 362,
KW_USING = 363,
KW_VIRTUAL = 364,
KW_VOID = 365,
KW_VOLATILE = 366,
KW_WCHAR_T = 367,
KW_WHILE = 368,
START_CPP = 369,
START_CONST_EXPR = 370,
START_TYPE = 371
};
#endif
/* Tokens. */
#define REAL 258
#define INTEGER 259
#define CHAR_TOK 260
#define STRING 261
#define SIMPLE_STRING 261
#define SIMPLE_IDENTIFIER 262
#define IDENTIFIER 263
#define TYPENAME_IDENTIFIER 264
#define SCOPING 265
#define TYPEDEFNAME 266
#define ELLIPSIS 267
#define OROR 268
#define ANDAND 269
#define EQCOMPARE 270
#define NECOMPARE 271
#define LECOMPARE 272
#define GECOMPARE 273
#define LSHIFT 274
#define RSHIFT 275
#define POINTSAT_STAR 276
#define DOT_STAR 277
#define UNARY 278
#define UNARY_NOT 279
#define UNARY_NEGATE 280
#define UNARY_MINUS 281
#define UNARY_STAR 282
#define UNARY_REF 283
#define POINTSAT 284
#define SCOPE 285
#define PLUSPLUS 286
#define MINUSMINUS 287
#define TIMESEQUAL 288
#define DIVIDEEQUAL 289
#define MODEQUAL 290
#define PLUSEQUAL 291
#define MINUSEQUAL 292
#define OREQUAL 293
#define ANDEQUAL 294
#define XOREQUAL 295
#define LSHIFTEQUAL 296
#define RSHIFTEQUAL 297
#define KW_BEGIN_PUBLISH 298
#define KW_BLOCKING 299
#define KW_BOOL 300
#define KW_CATCH 301
#define KW_CHAR 302
#define KW_CHAR16_T 303
#define KW_CHAR32_T 304
#define KW_CLASS 305
#define KW_CONST 306
#define KW_DELETE 307
#define KW_DOUBLE 308
#define KW_DYNAMIC_CAST 309
#define KW_ELSE 310
#define KW_END_PUBLISH 311
#define KW_ENUM 312
#define KW_EXTENSION 313
#define KW_EXTERN 314
#define KW_EXPLICIT 315
#define KW_PUBLISHED 316
#define KW_FALSE 317
#define KW_FLOAT 318
#define KW_FRIEND 319
#define KW_FOR 320
#define KW_GOTO 321
#define KW_IF 322
#define KW_INLINE 323
#define KW_INT 324
#define KW_LONG 325
#define KW_LONGLONG 326
#define KW_MAKE_PROPERTY 327
#define KW_MAKE_SEQ 328
#define KW_MUTABLE 329
#define KW_NAMESPACE 330
#define KW_NEW 331
#define KW_NOEXCEPT 332
#define KW_OPERATOR 333
#define KW_PRIVATE 334
#define KW_PROTECTED 335
#define KW_PUBLIC 336
#define KW_REGISTER 337
#define KW_RETURN 338
#define KW_SHORT 339
#define KW_SIGNED 340
#define KW_SIZEOF 341
#define KW_STATIC 342
#define KW_STATIC_ASSERT 343
#define KW_STATIC_CAST 344
#define KW_STRUCT 345
#define KW_TEMPLATE 346
#define KW_THROW 347
#define KW_TRUE 348
#define KW_TRY 349
#define KW_TYPEDEF 350
#define KW_TYPENAME 351
#define KW_UNION 352
#define KW_UNSIGNED 353
#define KW_USING 354
#define KW_VIRTUAL 355
#define KW_VOID 356
#define KW_VOLATILE 357
#define KW_WCHAR_T 358
#define KW_WHILE 359
#define START_CPP 360
#define START_CONST_EXPR 361
#define START_TYPE 362
#define STRING_LITERAL 263
#define CUSTOM_LITERAL 264
#define IDENTIFIER 265
#define TYPENAME_IDENTIFIER 266
#define SCOPING 267
#define TYPEDEFNAME 268
#define ELLIPSIS 269
#define OROR 270
#define ANDAND 271
#define EQCOMPARE 272
#define NECOMPARE 273
#define LECOMPARE 274
#define GECOMPARE 275
#define LSHIFT 276
#define RSHIFT 277
#define POINTSAT_STAR 278
#define DOT_STAR 279
#define UNARY 280
#define UNARY_NOT 281
#define UNARY_NEGATE 282
#define UNARY_MINUS 283
#define UNARY_STAR 284
#define UNARY_REF 285
#define POINTSAT 286
#define SCOPE 287
#define PLUSPLUS 288
#define MINUSMINUS 289
#define TIMESEQUAL 290
#define DIVIDEEQUAL 291
#define MODEQUAL 292
#define PLUSEQUAL 293
#define MINUSEQUAL 294
#define OREQUAL 295
#define ANDEQUAL 296
#define XOREQUAL 297
#define LSHIFTEQUAL 298
#define RSHIFTEQUAL 299
#define KW_ALIGNAS 300
#define KW_ALIGNOF 301
#define KW_AUTO 302
#define KW_BEGIN_PUBLISH 303
#define KW_BLOCKING 304
#define KW_BOOL 305
#define KW_CATCH 306
#define KW_CHAR 307
#define KW_CHAR16_T 308
#define KW_CHAR32_T 309
#define KW_CLASS 310
#define KW_CONST 311
#define KW_CONSTEXPR 312
#define KW_DECLTYPE 313
#define KW_DEFAULT 314
#define KW_DELETE 315
#define KW_DOUBLE 316
#define KW_DYNAMIC_CAST 317
#define KW_ELSE 318
#define KW_END_PUBLISH 319
#define KW_ENUM 320
#define KW_EXTENSION 321
#define KW_EXTERN 322
#define KW_EXPLICIT 323
#define KW_PUBLISHED 324
#define KW_FALSE 325
#define KW_FLOAT 326
#define KW_FRIEND 327
#define KW_FOR 328
#define KW_GOTO 329
#define KW_IF 330
#define KW_INLINE 331
#define KW_INT 332
#define KW_LONG 333
#define KW_LONGLONG 334
#define KW_MAKE_PROPERTY 335
#define KW_MAKE_SEQ 336
#define KW_MUTABLE 337
#define KW_NAMESPACE 338
#define KW_NEW 339
#define KW_NOEXCEPT 340
#define KW_NULLPTR 341
#define KW_OPERATOR 342
#define KW_PRIVATE 343
#define KW_PROTECTED 344
#define KW_PUBLIC 345
#define KW_REGISTER 346
#define KW_RETURN 347
#define KW_SHORT 348
#define KW_SIGNED 349
#define KW_SIZEOF 350
#define KW_STATIC 351
#define KW_STATIC_ASSERT 352
#define KW_STATIC_CAST 353
#define KW_STRUCT 354
#define KW_TEMPLATE 355
#define KW_THROW 356
#define KW_TRUE 357
#define KW_TRY 358
#define KW_TYPEDEF 359
#define KW_TYPENAME 360
#define KW_UNION 361
#define KW_UNSIGNED 362
#define KW_USING 363
#define KW_VIRTUAL 364
#define KW_VOID 365
#define KW_VOLATILE 366
#define KW_WCHAR_T 367
#define KW_WHILE 368
#define START_CPP 369
#define START_CONST_EXPR 370
#define START_TYPE 371

View File

@ -209,7 +209,8 @@ pop_struct() {
%token <u.real> REAL
%token <u.integer> INTEGER
%token <u.integer> CHAR_TOK
%token <str> STRING SIMPLE_IDENTIFIER
%token <str> SIMPLE_STRING SIMPLE_IDENTIFIER
%token <u.expr> STRING_LITERAL CUSTOM_LITERAL
%token <u.identifier> IDENTIFIER TYPENAME_IDENTIFIER SCOPING
%token <u.type> TYPEDEFNAME
@ -245,6 +246,9 @@ pop_struct() {
%token LSHIFTEQUAL
%token RSHIFTEQUAL
%token KW_ALIGNAS
%token KW_ALIGNOF
%token KW_AUTO
%token KW_BEGIN_PUBLISH
%token KW_BLOCKING
%token KW_BOOL
@ -254,6 +258,9 @@ pop_struct() {
%token KW_CHAR32_T
%token KW_CLASS
%token KW_CONST
%token KW_CONSTEXPR
%token KW_DECLTYPE
%token KW_DEFAULT
%token KW_DELETE
%token KW_DOUBLE
%token KW_DYNAMIC_CAST
@ -280,6 +287,7 @@ pop_struct() {
%token KW_NAMESPACE
%token KW_NEW
%token KW_NOEXCEPT
%token KW_NULLPTR
%token KW_OPERATOR
%token KW_PRIVATE
%token KW_PROTECTED
@ -348,7 +356,7 @@ pop_struct() {
%type <u.type> enum_element_type
/*%type <u.type> typedefname*/
%type <u.identifier> name
%type <str> string
%type <u.expr> string_literal
/* We need to treat KW_OPERATOR as a scopable keyword. */
%type <u.identifier> KW_OPERATOR
@ -526,13 +534,15 @@ declaration:
CPPMakeSeq *make_seq = new CPPMakeSeq($3->get_simple_name(), $5->get_simple_name(), $7->get_simple_name(), @1.file);
current_scope->add_declaration(make_seq, global_scope, current_lexer, @1);
}
| KW_STATIC_ASSERT '(' const_expr ',' string ')'
| KW_STATIC_ASSERT '(' const_expr ',' string_literal ')'
{
CPPExpression::Result result = $3->evaluate();
if (result._type == CPPExpression::RT_error) {
yywarning("static_assert requires a constant expression", @3);
} else if (!result.as_boolean()) {
yywarning("static_assert failed: " + $5, @3);
stringstream str;
str << *$5;
yywarning("static_assert failed: " + str.str(), @3);
}
}
| KW_STATIC_ASSERT '(' const_expr ')'
@ -571,7 +581,7 @@ storage_class:
{
$$ = $1 | (int)CPPInstance::SC_extern;
}
| storage_class KW_EXTERN string
| storage_class KW_EXTERN SIMPLE_STRING
{
$$ = $1 | (int)CPPInstance::SC_extern;
if ($3 == "C") {
@ -1266,6 +1276,21 @@ instance_identifier:
ident->_names.push_back("operator "+$2);
}
$$ = new CPPInstanceIdentifier(ident);
}
| KW_OPERATOR SIMPLE_STRING IDENTIFIER
{
// A C++11 literal operator.
if (!$2.empty()) {
yyerror("expected empty string", @2);
}
CPPIdentifier *ident = $1;
if (ident == NULL) {
ident = new CPPIdentifier("operator \"\" "+$3->get_simple_name(), @3);
} else {
ident->_names.push_back("operator \"\" "+$3->get_simple_name());
}
$$ = new CPPInstanceIdentifier(ident);
}
| KW_CONST instance_identifier %prec UNARY
@ -1691,6 +1716,15 @@ type:
}
$$ = et;
}
}
| KW_DECLTYPE '(' const_expr ')'
{
$$ = $3->determine_type();
if ($$ == (CPPType *)NULL) {
stringstream str;
str << *$3;
yyerror("could not determine type of " + str.str(), @3);
}
}
;
@ -1772,6 +1806,15 @@ type_decl:
}
$$ = et;
}
}
| KW_DECLTYPE '(' const_expr ')'
{
$$ = $3->determine_type();
if ($$ == (CPPType *)NULL) {
stringstream str;
str << *$3;
yyerror("could not determine type of " + str.str(), @3);
}
}
;
@ -2212,48 +2255,34 @@ code_block:
element:
REAL
{
}
| INTEGER
{
}
| STRING
{
}
| SIMPLE_STRING
| STRING_LITERAL
| CUSTOM_LITERAL
| CHAR_TOK
{
}
| IDENTIFIER
{
}
| TYPENAME_IDENTIFIER
{
}
| SCOPING
{
}
| SIMPLE_IDENTIFIER
{
}
| ELLIPSIS | OROR | ANDAND
| EQCOMPARE | NECOMPARE | LECOMPARE | GECOMPARE
| LSHIFT | RSHIFT | POINTSAT_STAR | DOT_STAR | POINTSAT
| SCOPE | PLUSPLUS | MINUSMINUS
| TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
| OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL
| KW_BOOL | KW_CATCH | KW_CHAR | KW_CHAR16_T | KW_CHAR32_T
| KW_WCHAR_T | KW_CLASS | KW_CONST
| KW_ALIGNAS | KW_ALIGNOF | KW_AUTO | KW_BOOL | KW_CATCH
| KW_CHAR | KW_CHAR16_T | KW_CHAR32_T
| KW_CLASS | KW_CONST | KW_CONSTEXPR | KW_DECLTYPE | KW_DEFAULT
| KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM
| KW_EXTERN | KW_EXPLICIT | KW_FALSE
| KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
| KW_IF | KW_INLINE | KW_INT
| KW_LONG | KW_MUTABLE | KW_NEW | KW_PRIVATE | KW_PROTECTED
| KW_IF | KW_INLINE | KW_INT | KW_LONG | KW_MUTABLE
| KW_NEW | KW_NULLPTR | KW_OPERATOR | KW_PRIVATE | KW_PROTECTED
| KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_RETURN
| KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_CAST
| KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF | KW_TYPENAME
| KW_UNION | KW_UNSIGNED | KW_VIRTUAL | KW_VOID | KW_VOLATILE
| KW_WHILE
| KW_OPERATOR
| KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_ASSERT
| KW_STATIC_CAST | KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY
| KW_TYPEDEF | KW_TYPENAME | KW_UNION | KW_UNSIGNED | KW_VIRTUAL
| KW_VOID | KW_VOLATILE | KW_WCHAR_T | KW_WHILE
{
}
| '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
@ -2314,6 +2343,10 @@ no_angle_bracket_const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
}
| '!' no_angle_bracket_const_expr %prec UNARY
{
@ -2325,15 +2358,7 @@ no_angle_bracket_const_expr:
}
| '-' no_angle_bracket_const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
$$ = new CPPExpression(UNARY_MINUS, $2);
}
| '*' no_angle_bracket_const_expr %prec UNARY
{
@ -2544,6 +2569,10 @@ const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
}
| KW_NEW predefined_type %prec UNARY
{
@ -2563,15 +2592,7 @@ const_expr:
}
| '-' const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
$$ = new CPPExpression(UNARY_MINUS, $2);
}
| '*' const_expr %prec UNARY
{
@ -2704,13 +2725,21 @@ const_operand:
{
$$ = new CPPExpression($1);
}
| string
| string_literal
{
$$ = new CPPExpression($1);
$$ = $1;
}
| CUSTOM_LITERAL
{
$$ = $1;
}
| IDENTIFIER
{
$$ = new CPPExpression($1, current_scope, global_scope, current_lexer);
}
| KW_NULLPTR
{
$$ = new CPPExpression(CPPExpression::get_nullptr());
}
;
@ -2741,6 +2770,10 @@ formal_const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
}
| KW_NEW predefined_type %prec UNARY
{
@ -2760,15 +2793,7 @@ formal_const_expr:
}
| '-' const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
$$ = new CPPExpression(UNARY_MINUS, $2);
}
| '&' const_expr %prec UNARY
{
@ -2897,9 +2922,17 @@ formal_const_operand:
{
$$ = new CPPExpression($1);
}
| string
| string_literal
{
$$ = new CPPExpression($1);
$$ = $1;
}
| CUSTOM_LITERAL
{
$$ = $1;
}
| KW_NULLPTR
{
$$ = new CPPExpression(CPPExpression::get_nullptr());
}
;
@ -2956,14 +2989,29 @@ name:
}
;
string:
STRING
string_literal:
SIMPLE_STRING
{
$$ = new CPPExpression($1);
}
| STRING_LITERAL
{
$$ = $1;
}
| string STRING
| string_literal SIMPLE_STRING
{
$$ = $1 + $2;
// The right string takes on the literal type of the left.
$$ = $1;
$$->_str += $2;
}
| string_literal STRING_LITERAL
{
// We have to check that the two literal types match up.
$$ = $1;
if ($2->_type != CPPExpression::T_string && $2->_type != $1->_type) {
yywarning("cannot concatenate two string literals of different types", @$);
}
$$->_str += $2->_str;
}
;

View File

@ -68,8 +68,8 @@ class cppyystype {
public:
string str;
union {
int integer;
double real;
unsigned long long integer;
long double real;
CPPScope *scope;
CPPDeclaration *decl;
CPPInstance *instance;

View File

@ -201,6 +201,19 @@ output(ostream &out) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(unsigned long long value) :
CPPDeclaration(CPPFile())
{
_type = T_integer;
_u._integer = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
@ -220,7 +233,7 @@ CPPExpression(int value) :
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(double value) :
CPPExpression(long double value) :
CPPDeclaration(CPPFile())
{
_type = T_real;
@ -397,6 +410,89 @@ sizeof_func(CPPType *type) {
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named alignof_func constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
alignof_func(CPPType *type) {
CPPExpression expr(0);
expr._type = T_alignof;
expr._u._typecast._to = type;
expr._u._typecast._op1 = NULL;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(unsigned long long value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = new CPPExpression(value);
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(long double value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = new CPPExpression(value);
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(CPPExpression *value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = value;
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named raw_literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
raw_literal(const string &raw, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_raw_literal;
expr._str = raw;
expr._u._literal._value = (CPPExpression *)NULL;
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::get_nullptr
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
const CPPExpression &CPPExpression::
get_nullptr() {
static CPPExpression expr(0);
expr._type = T_nullptr;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Destructor
// Access: Public
@ -416,13 +512,20 @@ evaluate() const {
Result r1, r2;
switch (_type) {
case T_nullptr:
return Result((void *)0);
case T_integer:
return Result(_u._integer);
return Result((int)_u._integer);
case T_real:
return Result(_u._real);
return Result((double)_u._real);
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return Result();
case T_variable:
@ -468,6 +571,17 @@ evaluate() const {
case T_sizeof:
return Result();
case T_alignof:
if (_u._typecast._to != NULL) {
// Check if the type is defined with an alignas. TODO: this should
// probably be moved to a virtual getter on CPPType.
CPPExtensionType *etype = _u._typecast._to->as_extension_type();
if (etype != NULL && etype->_alignment != NULL) {
return etype->_alignment->evaluate();
}
}
return Result();
case T_binary_operation:
assert(_u._op._op2 != NULL);
r2 = _u._op._op2->evaluate();
@ -652,6 +766,10 @@ evaluate() const {
abort();
}
case T_literal:
case T_raw_literal:
return Result();
default:
cerr << "**invalid operand**\n";
abort();
@ -671,25 +789,51 @@ determine_type() const {
CPPType *t1 = (CPPType *)NULL;
CPPType *t2 = (CPPType *)NULL;
CPPType *int_type =
static CPPType *nullptr_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_nullptr));
static CPPType *int_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int));
CPPType *bool_type =
static CPPType *unsigned_long_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_unsigned |
CPPSimpleType::F_long));
static CPPType *bool_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool));
CPPType *float_type =
static CPPType *float_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double));
CPPType *char_type =
static CPPType *char_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char));
CPPType *const_char_type =
CPPType::new_type(new CPPConstType(char_type));
static CPPType *wchar_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
CPPType *char_star_type =
CPPType::new_type(new CPPPointerType(const_char_type));
static CPPType *char16_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t));
static CPPType *char32_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t));
static CPPType *char_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char_type))));
static CPPType *wchar_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(wchar_type))));
static CPPType *char16_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char16_type))));
static CPPType *char32_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char32_type))));
switch (_type) {
case T_nullptr:
return nullptr_type;
case T_integer:
return int_type;
@ -697,7 +841,19 @@ determine_type() const {
return float_type;
case T_string:
return char_star_type;
return char_str_type;
case T_wstring:
return wchar_str_type;
case T_u8string:
return char_str_type;
case T_u16string:
return char16_str_type;
case T_u32string:
return char32_str_type;
case T_variable:
return _u._variable->_type;
@ -725,7 +881,11 @@ determine_type() const {
return CPPType::new_type(new CPPPointerType(_u._typecast._to));
case T_sizeof:
return int_type;
case T_alignof:
// Note: this should actually be size_t, but that is defined as a
// typedef in parser-inc. We could try to resolve it, but that's
// hacky. Eh, it's probably not worth the effort to get this right.
return unsigned_long_type;
case T_binary_operation:
case T_trinary_operation:
@ -819,6 +979,18 @@ determine_type() const {
abort();
}
case T_literal:
case T_raw_literal:
if (_u._literal._operator != NULL) {
CPPType *type = _u._literal._operator->_type;
CPPFunctionType *ftype = type->as_function_type();
if (ftype != (CPPFunctionType *)NULL) {
return ftype->_return_type;
}
}
return NULL;
default:
cerr << "**invalid operand**\n";
abort();
@ -842,9 +1014,14 @@ is_fully_specified() const {
}
switch (_type) {
case T_nullptr:
case T_integer:
case T_real:
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return false;
case T_variable:
@ -865,6 +1042,7 @@ is_fully_specified() const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to->is_fully_specified();
case T_trinary_operation:
@ -882,6 +1060,13 @@ is_fully_specified() const {
case T_unary_operation:
return _u._op._op1->is_fully_specified();
case T_literal:
return _u._literal._value->is_fully_specified() &&
_u._literal._operator->is_fully_specified();
case T_raw_literal:
return _u._literal._value->is_fully_specified();
default:
return true;
}
@ -972,6 +1157,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
rep->_u._typecast._to =
_u._typecast._to->substitute_decl(subst, current_scope, global_scope)
->as_type();
@ -1042,6 +1228,7 @@ is_tbd() const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to->is_tbd();
case T_trinary_operation:
@ -1075,6 +1262,10 @@ is_tbd() const {
void CPPExpression::
output(ostream &out, int indent_level, CPPScope *scope, bool) const {
switch (_type) {
case T_nullptr:
out << "nullptr";
break;
case T_integer:
out << _u._integer;
break;
@ -1090,8 +1281,29 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
break;
case T_string:
out << '"';
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
{
switch (_type) {
case T_wstring:
out << 'L';
break;
case T_u8string:
out << "u8";
break;
case T_u16string:
out << "u";
break;
case T_u32string:
out << "U";
break;
default:
break;
}
// We don't really care about preserving the encoding for now.
out << '"';
string::const_iterator si;
for (si = _str.begin(); si != _str.end(); ++si) {
switch (*si) {
@ -1193,6 +1405,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
out << ")";
break;
case T_alignof:
out << "alignof(";
_u._typecast._to->output(out, indent_level, scope, false);
out << ")";
break;
case T_unary_operation:
switch (_u._op._operator) {
case UNARY_NOT:
@ -1208,9 +1426,8 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
break;
case UNARY_MINUS:
out << "(- ";
out << '-';
_u._op._op1->output(out, indent_level, scope, false);
out << ")";
break;
case UNARY_STAR:
@ -1362,6 +1579,24 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
out << ")";
break;
case T_literal:
_u._literal._value->output(out, indent_level, scope, false);
if (_u._literal._operator != NULL) {
string name = _u._literal._operator->get_simple_name();
assert(name.substr(0, 12) == "operator \"\" ");
out << name.substr(12);
}
break;
case T_raw_literal:
out << _str;
if (_u._literal._operator != NULL) {
string name = _u._literal._operator->get_simple_name();
assert(name.substr(0, 12) == "operator \"\" ");
out << name.substr(12);
}
break;
default:
out << "(** invalid operand type " << (int)_type << " **)";
}
@ -1456,6 +1691,9 @@ is_equal(const CPPDeclaration *other) const {
}
switch (_type) {
case T_nullptr:
return true;
case T_integer:
return _u._integer == ot->_u._integer;
@ -1463,6 +1701,10 @@ is_equal(const CPPDeclaration *other) const {
return _u._real == ot->_u._real;
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str == ot->_str;
case T_variable:
@ -1483,6 +1725,7 @@ is_equal(const CPPDeclaration *other) const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to == ot->_u._typecast._to;
case T_unary_operation:
@ -1496,6 +1739,14 @@ is_equal(const CPPDeclaration *other) const {
return *_u._op._op1 == *ot->_u._op._op1 &&
*_u._op._op2 == *ot->_u._op._op2;
case T_literal:
return *_u._literal._value == *ot->_u._literal._value &&
_u._literal._operator == ot->_u._literal._operator;
case T_raw_literal:
return _str == ot->_str &&
_u._literal._operator == ot->_u._literal._operator;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}
@ -1520,6 +1771,9 @@ is_less(const CPPDeclaration *other) const {
}
switch (_type) {
case T_nullptr:
return false;
case T_integer:
return _u._integer < ot->_u._integer;
@ -1527,6 +1781,10 @@ is_less(const CPPDeclaration *other) const {
return _u._real < ot->_u._real;
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str < ot->_str;
case T_variable:
@ -1549,6 +1807,7 @@ is_less(const CPPDeclaration *other) const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to < ot->_u._typecast._to;
case T_trinary_operation:
@ -1566,6 +1825,18 @@ is_less(const CPPDeclaration *other) const {
case T_unary_operation:
return *_u._op._op1 < *ot->_u._op._op1;
case T_literal:
if (_u._literal._operator != ot->_u._literal._operator) {
return _u._literal._operator < ot->_u._literal._operator;
}
return *_u._literal._value < *ot->_u._literal._value;
case T_raw_literal:
if (_u._literal._operator != ot->_u._literal._operator) {
return _u._literal._operator < ot->_u._literal._operator;
}
return _str < ot->_str;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}

View File

@ -30,9 +30,10 @@ class CPPFunctionGroup;
////////////////////////////////////////////////////////////////////
class CPPExpression : public CPPDeclaration {
public:
CPPExpression(unsigned long long value);
CPPExpression(int value);
CPPExpression(const string &value);
CPPExpression(double value);
CPPExpression(long double value);
CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
CPPScope *global_scope, CPPPreprocessor *error_sink = NULL);
CPPExpression(int unary_operator, CPPExpression *op1);
@ -43,6 +44,14 @@ public:
static CPPExpression construct_op(CPPType *type, CPPExpression *op1);
static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL);
static CPPExpression sizeof_func(CPPType *type);
static CPPExpression alignof_func(CPPType *type);
static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
static CPPExpression literal(long double value, CPPInstance *lit_op);
static CPPExpression literal(CPPExpression *value, CPPInstance *lit_op);
static CPPExpression raw_literal(const string &raw, CPPInstance *lit_op);
static const CPPExpression &get_nullptr();
~CPPExpression();
@ -92,9 +101,14 @@ public:
enum Type {
T_nullptr,
T_integer,
T_real,
T_string,
T_wstring,
T_u8string,
T_u16string,
T_u32string,
T_variable,
T_function,
T_unknown_ident,
@ -104,16 +118,19 @@ public:
T_new,
T_default_new,
T_sizeof,
T_alignof,
T_unary_operation,
T_binary_operation,
T_trinary_operation,
T_literal,
T_raw_literal,
};
Type _type;
string _str;
union {
int _integer;
double _real;
unsigned long long _integer;
long double _real;
CPPInstance *_variable;
CPPFunctionGroup *_fgroup;
CPPIdentifier *_ident;
@ -131,6 +148,11 @@ public:
CPPExpression *_op2;
CPPExpression *_op3;
} _op;
class {
public:
CPPInstance *_operator;
CPPExpression *_value;
} _literal;
} _u;
protected:
@ -146,5 +168,3 @@ operator << (ostream &out, const CPPExpression::Result &result) {
}
#endif

View File

@ -29,7 +29,8 @@ CPPExtensionType(CPPExtensionType::Type type,
CPPIdentifier *ident, CPPScope *current_scope,
const CPPFile &file) :
CPPType(file),
_type(type), _ident(ident)
_type(type), _ident(ident),
_alignment(NULL)
{
if (_ident != NULL) {
_ident->_native_scope = current_scope;

View File

@ -65,9 +65,9 @@ public:
virtual CPPExtensionType *as_extension_type();
Type _type;
CPPIdentifier *_ident;
CPPExpression *_alignment;
};
ostream &operator << (ostream &out, CPPExtensionType::Type type);

View File

@ -38,7 +38,8 @@ CPPInstance(CPPType *type, const string &name, int storage_class) :
CPPDeclaration(CPPFile()),
_type(type),
_ident(new CPPIdentifier(name)),
_storage_class(storage_class)
_storage_class(storage_class),
_alignment(NULL)
{
_initializer = NULL;
}
@ -53,7 +54,8 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
CPPDeclaration(CPPFile()),
_type(type),
_ident(ident),
_storage_class(storage_class)
_storage_class(storage_class),
_alignment(NULL)
{
_initializer = NULL;
}
@ -69,7 +71,8 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
CPPInstance::
CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
const CPPFile &file) :
CPPDeclaration(file)
CPPDeclaration(file),
_alignment(NULL)
{
_type = ii->unroll_type(type);
_ident = ii->_ident;
@ -102,7 +105,8 @@ CPPInstance(const CPPInstance &copy) :
_type(copy._type),
_ident(copy._ident),
_initializer(copy._initializer),
_storage_class(copy._storage_class)
_storage_class(copy._storage_class),
_alignment(copy._alignment)
{
assert(_type != NULL);
}
@ -153,6 +157,9 @@ operator == (const CPPInstance &other) const {
if (_storage_class != other._storage_class) {
return false;
}
if (_alignment != other._alignment) {
return false;
}
// We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based
@ -199,6 +206,9 @@ operator < (const CPPInstance &other) const {
if (_storage_class != other._storage_class) {
return _storage_class < other._storage_class;
}
if (_alignment != other._alignment) {
return _alignment < other._alignment;
}
// We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based
@ -252,6 +262,29 @@ set_initializer(CPPExpression *initializer) {
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::set_alignment
// Access: Public
// Description: Sets the number of bytes to align this instance to.
////////////////////////////////////////////////////////////////////
void CPPInstance::
set_alignment(int align) {
_alignment = new CPPExpression(align);
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::set_alignment
// Access: Public
// Description: Sets the expression that is used to determine the
// required alignment for the variable. This should
// be a constant expression, but we don't presently
// verify that it is.
////////////////////////////////////////////////////////////////////
void CPPInstance::
set_alignment(CPPExpression *const_expr) {
_alignment = const_expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::is_scoped
// Access: Public
@ -536,6 +569,11 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
get_template_scope()->_parameters.write_formal(out, scope);
indent(out, indent_level);
}
if (_alignment != NULL) {
out << "alignas(" << *_alignment << ") ";
}
if (_storage_class & SC_static) {
out << "static ";
}

View File

@ -77,6 +77,8 @@ public:
bool operator < (const CPPInstance &other) const;
void set_initializer(CPPExpression *initializer);
void set_alignment(int align);
void set_alignment(CPPExpression *const_expr);
bool is_scoped() const;
CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope,
@ -111,6 +113,7 @@ public:
CPPExpression *_initializer;
int _storage_class;
CPPExpression *_alignment;
private:
typedef map<const CPPTemplateParameterList *, CPPInstance *, CPPTPLCompare> Instantiations;

View File

@ -26,6 +26,7 @@
#include "cppBison.h"
#include "indent.h"
#include "pstrtod.h"
#include "string_utils.h"
#include <assert.h>
#include <ctype.h>
@ -404,6 +405,7 @@ get_next_token0() {
// keyword. We make a special case for this, because it's
// occasionally scoped in normal use.
token._lval = result;
_last_token_loc = token._lloc;
return token;
}
_saved_tokens.push_back(token);
@ -1803,9 +1805,7 @@ get_quoted_char(int c) {
result.u.integer = 0;
}
loc.last_line = get_line_number();
loc.last_column = get_col_number();
return CPPToken(CHAR_TOK, loc, str, result);
return get_literal(CHAR_TOK, loc, str, result);
}
////////////////////////////////////////////////////////////////////
@ -1822,9 +1822,7 @@ get_quoted_string(int c) {
string str = scan_quoted(c);
loc.last_line = get_line_number();
loc.last_column = get_col_number();
return CPPToken(STRING, loc, str);
return get_literal(SIMPLE_STRING, loc, str);
}
////////////////////////////////////////////////////////////////////
@ -1848,25 +1846,51 @@ get_identifier(int c) {
name += get();
c = peek();
}
if (c == '\'' || c == '"') {
// This is actually a wide-character or wide-string literal or
// some such: a string with an alphanumeric prefix. We don't
// necessarily try to parse it correctly; for most purposes, we
// don't care.
get();
CPPToken token(0);
if (c == '\'') {
token = get_quoted_char(c);
} else {
token = get_quoted_string(c);
}
token._lloc.first_column = loc.first_column;
return token;
}
loc.last_line = get_line_number();
loc.last_column = get_col_number();
if ((c == '\'' || c == '"') && name != "operator") {
// This is actually a wide-character or wide-string literal or
// some such. Figure out the correct character type to use.
// We had to add in an exception in order to support operator"".
CPPExpression::Type type;
if (name == "L") {
type = CPPExpression::T_wstring;
} else if (name == "u8") {
type = CPPExpression::T_u8string;
} else if (name == "u") {
type = CPPExpression::T_u16string;
} else if (name == "U") {
type = CPPExpression::T_u32string;
} else {
type = CPPExpression::T_string;
warning("unrecognized literal prefix " + name, loc);
}
get();
string str = scan_quoted(c);
loc.last_line = get_line_number();
loc.last_column = get_col_number();
YYSTYPE result;
if (c == '\'') {
// We don't really care about the type for now.
if (!str.empty()) {
result.u.integer = (int)str[0];
} else {
result.u.integer = 0;
}
return get_literal(CHAR_TOK, loc, str, result);
} else {
result.u.expr = new CPPExpression(str);
result.u.expr->_type = type;
return get_literal(STRING_LITERAL, loc, str, result);
}
}
_last_c = 0;
// Is it a manifest?
@ -1898,6 +1922,171 @@ get_identifier(int c) {
return CPPToken(SIMPLE_IDENTIFIER, loc, name);
}
////////////////////////////////////////////////////////////////////
// Function: CPPPreprocessor::get_literal
// Access: Private
// Description: Under the assumption that we've just parsed a
// string or real constant, parse a following custom
// literal, and returns a token for it.
////////////////////////////////////////////////////////////////////
CPPToken CPPPreprocessor::
get_literal(int token, YYLTYPE loc, const string &str, const YYSTYPE &value) {
string suffix;
int c = peek();
if (isalpha(c) || c == '_') {
// A literal seems to be following directly.
while (c != EOF && (isalnum(c) || c == '_')) {
suffix += get();
c = peek();
}
}
loc.last_line = get_line_number();
loc.last_column = get_col_number();
if (suffix.empty()) {
// There is no suffix.
return CPPToken(token, loc, str, value);
}
// Handle built-in literal suffixes.
if (token == INTEGER) {
if (cmp_nocase(suffix, "u") == 0 ||
cmp_nocase(suffix, "l") == 0 ||
cmp_nocase(suffix, "ul") == 0 || cmp_nocase(suffix, "lu") == 0 ||
cmp_nocase(suffix, "ll") == 0 ||
cmp_nocase(suffix, "ull") == 0 || cmp_nocase(suffix, "llu") == 0) {
// These are built-in integer suffixes. Right now, we don't try to
// distinguish between them.
return CPPToken(INTEGER, loc, str, value);
}
} else if (token == REAL) {
if (suffix == "f" || suffix == "F" ||
suffix == "l" || suffix == "L") {
return CPPToken(REAL, loc, str, value);
}
}
// Find the literal operator for this literal.
CPPIdentifier *ident = new CPPIdentifier("operator \"\" " + suffix);
CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope, this);
if (decl == NULL || decl->get_subtype() != CPPDeclaration::ST_function_group) {
error("unknown literal suffix " + suffix, loc);
return CPPToken(token, loc, str, value);
}
// Find the overload with the appropriate signature.
CPPExpression *expr = NULL;
CPPInstance *instance = NULL;
CPPInstance *raw_instance = NULL;
CPPFunctionGroup *fgroup = decl->as_function_group();
CPPFunctionGroup::Instances::iterator it;
for (it = fgroup->_instances.begin(); it != fgroup->_instances.end(); ++it) {
if ((*it)->_type == NULL) {
continue;
}
CPPFunctionType *ftype = (*it)->_type->as_function_type();
if (ftype == NULL || ftype->_parameters == NULL) {
continue;
}
CPPParameterList::Parameters &params = ftype->_parameters->_parameters;
if (token == STRING_LITERAL || token == SIMPLE_STRING) {
// A custom string literal must take a second size_t argument.
if (params.size() != 2) continue;
} else {
if (params.size() != 1) continue;
}
CPPInstance *param = params[0];
if (param == NULL || param->_type == NULL) {
continue;
}
CPPType *type = param->_type;
while (type->get_subtype() == CPPDeclaration::ST_const) {
type = type->as_const_type()->_wrapped_around;
}
if (type->get_subtype() == CPPDeclaration::ST_simple) {
// It's a primitive type. Check that it matches the appropriate token.
CPPSimpleType::Type simple = type->as_simple_type()->_type;
if (token == INTEGER && simple == CPPSimpleType::T_int) {
expr = new CPPExpression(value.u.integer);
instance = (*it);
break;
} else if (token == REAL && simple == CPPSimpleType::T_double) {
expr = new CPPExpression(value.u.real);
instance = (*it);
break;
} else if (token == CHAR_TOK && (simple == CPPSimpleType::T_char ||
simple == CPPSimpleType::T_wchar_t ||
simple == CPPSimpleType::T_char16_t ||
simple == CPPSimpleType::T_char32_t)) {
// We currently don't have the means to check the exact character type.
expr = new CPPExpression(value.u.integer);
instance = (*it);
break;
}
} else if (type->get_subtype() == CPPDeclaration::ST_pointer) {
// Must be a const pointer. Unwrap it.
type = type->as_pointer_type()->_pointing_at;
if (type == NULL || type->get_subtype() != CPPDeclaration::ST_const) {
continue;
}
type = type->as_const_type()->_wrapped_around;
if (type == NULL || type->get_subtype() != CPPDeclaration::ST_simple) {
continue;
}
CPPSimpleType::Type simple = type->as_simple_type()->_type;
if (simple == CPPSimpleType::T_char && params.size() == 1) {
// This is the raw literal operator. Store it, but don't break;
// a non-raw version of the operator might follow, which we'd prefer.
raw_instance = (*it);
} else if (token == SIMPLE_STRING && simple == CPPSimpleType::T_char) {
expr = new CPPExpression(str);
instance = (*it);
break;
} else if (token == STRING_LITERAL) {
// Verify that the character type of the string literal matches
// the character type of the parameter.
CPPExpression::Type str_type = value.u.expr->_type;
if ((str_type == CPPExpression::T_string && simple == CPPSimpleType::T_char) ||
(str_type == CPPExpression::T_wstring && simple == CPPSimpleType::T_wchar_t) ||
(str_type == CPPExpression::T_u8string && simple == CPPSimpleType::T_char) ||
(str_type == CPPExpression::T_u16string && simple == CPPSimpleType::T_char16_t) ||
(str_type == CPPExpression::T_u32string && simple == CPPSimpleType::T_char32_t)) {
expr = value.u.expr;
instance = (*it);
break;
}
}
}
}
YYSTYPE result;
if (instance != NULL) {
result.u.expr = new CPPExpression(CPPExpression::literal(expr, instance));
return CPPToken(CUSTOM_LITERAL, loc, str, result);
}
if ((token == REAL || token == INTEGER) && raw_instance != NULL) {
// For numeric constants, we can fall back to a raw literal operator.
result.u.expr = new CPPExpression(CPPExpression::raw_literal(str, instance));
return CPPToken(CUSTOM_LITERAL, loc, str, result);
}
error(fgroup->_name + " has no suitable overload for literal of this type", loc);
result.u.expr = NULL;
return CPPToken(CUSTOM_LITERAL, loc, str, result);
}
////////////////////////////////////////////////////////////////////
// Function: CPPPreprocessor::expand_manifest
// Access: Private
@ -2196,20 +2385,13 @@ get_number(int c) {
c = peek();
}
while (c == 'L' || c == 'U' || c == 'l' || c == 'u') {
// We allow (and ignore) an 'L' and/or 'U' following the number.
get();
c = peek();
}
loc.last_line = get_line_number();
loc.last_column = get_col_number();
_last_c = 0;
YYSTYPE result;
result.u.integer = strtol(num.c_str(), (char **)NULL, 16);
return CPPToken(INTEGER, loc, num, result);
return get_literal(INTEGER, loc, num, result);
}
while (c != EOF && isdigit(c)) {
@ -2229,7 +2411,7 @@ get_number(int c) {
}
}
if (decimal_point) {
if (decimal_point || c == 'e' || c == 'E') {
if (tolower(c) == 'e') {
// An exponent is allowed.
num += get();
@ -2244,28 +2426,17 @@ get_number(int c) {
}
}
if (c == 'f') {
// We allow (and ignore) an 'f' following the number.
get();
c = peek();
}
loc.last_line = get_line_number();
loc.last_column = get_col_number();
YYSTYPE result;
result.u.real = pstrtod(num.c_str(), (char **)NULL);
return CPPToken(REAL, loc, num, result);
return get_literal(REAL, loc, num, result);
}
// This is a decimal or octal integer number.
while (c == 'L' || c == 'U') {
// We allow (and ignore) an 'L' and/or 'U' following the number.
get();
c = peek();
}
loc.last_line = get_line_number();
loc.last_column = get_col_number();
@ -2282,7 +2453,7 @@ get_number(int c) {
result.u.integer = strtol(num.c_str(), (char **)NULL, 10);
}
return CPPToken(INTEGER, loc, num, result);
return get_literal(INTEGER, loc, num, result);
}
////////////////////////////////////////////////////////////////////
@ -2292,6 +2463,11 @@ get_number(int c) {
////////////////////////////////////////////////////////////////////
int CPPPreprocessor::
check_keyword(const string &name) {
if (name == "alignas") return KW_ALIGNAS;
if (name == "alignof") return KW_ALIGNOF;
if (name == "__alignof") return KW_ALIGNOF;
if (name == "__alignof__") return KW_ALIGNOF;
if (name == "auto") return KW_AUTO;
if (name == "__begin_publish") return KW_BEGIN_PUBLISH;
if (name == "__blocking") return KW_BLOCKING;
if (name == "bool") return KW_BOOL;
@ -2303,6 +2479,9 @@ check_keyword(const string &name) {
if (name == "const") return KW_CONST;
if (name == "__const") return KW_CONST;
if (name == "__const__") return KW_CONST;
if (name == "constexpr") return KW_CONSTEXPR;
if (name == "decltype") return KW_DECLTYPE;
if (name == "default") return KW_DEFAULT;
if (name == "delete") return KW_DELETE;
if (name == "double") return KW_DOUBLE;
if (name == "dynamic_cast") return KW_DYNAMIC_CAST;
@ -2329,6 +2508,7 @@ check_keyword(const string &name) {
if (name == "mutable") return KW_MUTABLE;
if (name == "namespace") return KW_NAMESPACE;
if (name == "noexcept") return KW_NOEXCEPT;
if (name == "nullptr") return KW_NULLPTR;
if (name == "new") return KW_NEW;
if (name == "operator") return KW_OPERATOR;
if (name == "private") return KW_PRIVATE;

View File

@ -142,6 +142,8 @@ private:
CPPToken get_quoted_char(int c);
CPPToken get_quoted_string(int c);
CPPToken get_identifier(int c);
CPPToken get_literal(int token, YYLTYPE loc, const string &str,
const YYSTYPE &result = YYSTYPE());
CPPToken expand_manifest(const CPPManifest *manifest);
void extract_manifest_args(const string &name, int num_args,
int va_arg, vector_string &args);

View File

@ -313,7 +313,7 @@ add_using(CPPUsing *using_decl, CPPScope *global_scope,
_using.insert(scope);
} else {
if (error_sink != NULL) {
error_sink->warning("Attempt to use undefined namespace: " + using_decl->_ident->get_fully_scoped_name());
error_sink->warning("Attempt to use undefined namespace: " + using_decl->_ident->get_fully_scoped_name(), using_decl->_ident->_loc);
}
}
} else {
@ -322,7 +322,7 @@ add_using(CPPUsing *using_decl, CPPScope *global_scope,
handle_declaration(decl, global_scope, error_sink);
} else {
if (error_sink != NULL) {
error_sink->warning("Attempt to use unknown symbol: " + using_decl->_ident->get_fully_scoped_name());
error_sink->warning("Attempt to use unknown symbol: " + using_decl->_ident->get_fully_scoped_name(), using_decl->_ident->_loc);
}
}
}

View File

@ -150,6 +150,10 @@ output(ostream &out, int, CPPScope *, bool) const {
out << "void";
break;
case T_nullptr:
out << "decltype(nullptr)";
break;
case T_parameter:
out << "parameter";
break;

View File

@ -37,6 +37,11 @@ public:
T_double,
T_void,
// We need something to represent the type of nullptr so that we
// can return it from decltype(nullptr). Note that this is not
// the same as nullptr_t, which is a typedef of decltype(nullptr).
T_nullptr,
// T_parameter is a special type which is assigned to expressions
// that are discovered where a formal parameter was expected.
// This is a special case for handling cases like this:

View File

@ -119,8 +119,12 @@ output(ostream &out) const {
out << "CHAR_TOK " << _lval.u.integer << " = " << _lval.str;
break;
case STRING:
out << "STRING " << _lval.str;
case SIMPLE_STRING:
out << "SIMPLE_STRING " << _lval.str;
break;
case STRING_LITERAL:
out << "STRING_LITERAL " << *_lval.u.expr;
break;
case SIMPLE_IDENTIFIER:

View File

@ -22,5 +22,9 @@
#include <stdtypedefs.h>
#define offsetof(type,member) ((size_t) &(((type*)0)->member))
typedef decltype(nullptr) nullptr_t;
#endif

View File

@ -44,5 +44,26 @@ public:
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;
namespace std {
template<class T> struct hash;
template<> struct hash<string>;
template<> struct hash<u16string>;
template<> struct hash<u32string>;
template<> struct hash<wstring>;
namespace string_literals {
string operator "" s(const char *str, size_t len);
wstring operator "" s(const wchar_t *str, size_t len);
u16string operator "" s(const char16_t *str, size_t len);
u32string operator "" s(const char32_t *str, size_t len);
}
namespace literals {
using namespace string_literals;
}
}
#endif