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, REAL = 258,
INTEGER = 259, INTEGER = 259,
CHAR_TOK = 260, CHAR_TOK = 260,
STRING = 261, SIMPLE_STRING = 261,
SIMPLE_IDENTIFIER = 262, SIMPLE_IDENTIFIER = 262,
IDENTIFIER = 263, STRING_LITERAL = 263,
TYPENAME_IDENTIFIER = 264, CUSTOM_LITERAL = 264,
SCOPING = 265, IDENTIFIER = 265,
TYPEDEFNAME = 266, TYPENAME_IDENTIFIER = 266,
ELLIPSIS = 267, SCOPING = 267,
OROR = 268, TYPEDEFNAME = 268,
ANDAND = 269, ELLIPSIS = 269,
EQCOMPARE = 270, OROR = 270,
NECOMPARE = 271, ANDAND = 271,
LECOMPARE = 272, EQCOMPARE = 272,
GECOMPARE = 273, NECOMPARE = 273,
LSHIFT = 274, LECOMPARE = 274,
RSHIFT = 275, GECOMPARE = 275,
POINTSAT_STAR = 276, LSHIFT = 276,
DOT_STAR = 277, RSHIFT = 277,
UNARY = 278, POINTSAT_STAR = 278,
UNARY_NOT = 279, DOT_STAR = 279,
UNARY_NEGATE = 280, UNARY = 280,
UNARY_MINUS = 281, UNARY_NOT = 281,
UNARY_STAR = 282, UNARY_NEGATE = 282,
UNARY_REF = 283, UNARY_MINUS = 283,
POINTSAT = 284, UNARY_STAR = 284,
SCOPE = 285, UNARY_REF = 285,
PLUSPLUS = 286, POINTSAT = 286,
MINUSMINUS = 287, SCOPE = 287,
TIMESEQUAL = 288, PLUSPLUS = 288,
DIVIDEEQUAL = 289, MINUSMINUS = 289,
MODEQUAL = 290, TIMESEQUAL = 290,
PLUSEQUAL = 291, DIVIDEEQUAL = 291,
MINUSEQUAL = 292, MODEQUAL = 292,
OREQUAL = 293, PLUSEQUAL = 293,
ANDEQUAL = 294, MINUSEQUAL = 294,
XOREQUAL = 295, OREQUAL = 295,
LSHIFTEQUAL = 296, ANDEQUAL = 296,
RSHIFTEQUAL = 297, XOREQUAL = 297,
KW_BEGIN_PUBLISH = 298, LSHIFTEQUAL = 298,
KW_BLOCKING = 299, RSHIFTEQUAL = 299,
KW_BOOL = 300, KW_ALIGNAS = 300,
KW_CATCH = 301, KW_ALIGNOF = 301,
KW_CHAR = 302, KW_AUTO = 302,
KW_CHAR16_T = 303, KW_BEGIN_PUBLISH = 303,
KW_CHAR32_T = 304, KW_BLOCKING = 304,
KW_CLASS = 305, KW_BOOL = 305,
KW_CONST = 306, KW_CATCH = 306,
KW_DELETE = 307, KW_CHAR = 307,
KW_DOUBLE = 308, KW_CHAR16_T = 308,
KW_DYNAMIC_CAST = 309, KW_CHAR32_T = 309,
KW_ELSE = 310, KW_CLASS = 310,
KW_END_PUBLISH = 311, KW_CONST = 311,
KW_ENUM = 312, KW_CONSTEXPR = 312,
KW_EXTENSION = 313, KW_DECLTYPE = 313,
KW_EXTERN = 314, KW_DEFAULT = 314,
KW_EXPLICIT = 315, KW_DELETE = 315,
KW_PUBLISHED = 316, KW_DOUBLE = 316,
KW_FALSE = 317, KW_DYNAMIC_CAST = 317,
KW_FLOAT = 318, KW_ELSE = 318,
KW_FRIEND = 319, KW_END_PUBLISH = 319,
KW_FOR = 320, KW_ENUM = 320,
KW_GOTO = 321, KW_EXTENSION = 321,
KW_IF = 322, KW_EXTERN = 322,
KW_INLINE = 323, KW_EXPLICIT = 323,
KW_INT = 324, KW_PUBLISHED = 324,
KW_LONG = 325, KW_FALSE = 325,
KW_LONGLONG = 326, KW_FLOAT = 326,
KW_MAKE_PROPERTY = 327, KW_FRIEND = 327,
KW_MAKE_SEQ = 328, KW_FOR = 328,
KW_MUTABLE = 329, KW_GOTO = 329,
KW_NAMESPACE = 330, KW_IF = 330,
KW_NEW = 331, KW_INLINE = 331,
KW_NOEXCEPT = 332, KW_INT = 332,
KW_OPERATOR = 333, KW_LONG = 333,
KW_PRIVATE = 334, KW_LONGLONG = 334,
KW_PROTECTED = 335, KW_MAKE_PROPERTY = 335,
KW_PUBLIC = 336, KW_MAKE_SEQ = 336,
KW_REGISTER = 337, KW_MUTABLE = 337,
KW_RETURN = 338, KW_NAMESPACE = 338,
KW_SHORT = 339, KW_NEW = 339,
KW_SIGNED = 340, KW_NOEXCEPT = 340,
KW_SIZEOF = 341, KW_NULLPTR = 341,
KW_STATIC = 342, KW_OPERATOR = 342,
KW_STATIC_ASSERT = 343, KW_PRIVATE = 343,
KW_STATIC_CAST = 344, KW_PROTECTED = 344,
KW_STRUCT = 345, KW_PUBLIC = 345,
KW_TEMPLATE = 346, KW_REGISTER = 346,
KW_THROW = 347, KW_RETURN = 347,
KW_TRUE = 348, KW_SHORT = 348,
KW_TRY = 349, KW_SIGNED = 349,
KW_TYPEDEF = 350, KW_SIZEOF = 350,
KW_TYPENAME = 351, KW_STATIC = 351,
KW_UNION = 352, KW_STATIC_ASSERT = 352,
KW_UNSIGNED = 353, KW_STATIC_CAST = 353,
KW_USING = 354, KW_STRUCT = 354,
KW_VIRTUAL = 355, KW_TEMPLATE = 355,
KW_VOID = 356, KW_THROW = 356,
KW_VOLATILE = 357, KW_TRUE = 357,
KW_WCHAR_T = 358, KW_TRY = 358,
KW_WHILE = 359, KW_TYPEDEF = 359,
START_CPP = 360, KW_TYPENAME = 360,
START_CONST_EXPR = 361, KW_UNION = 361,
START_TYPE = 362 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 #endif
/* Tokens. */ /* Tokens. */
#define REAL 258 #define REAL 258
#define INTEGER 259 #define INTEGER 259
#define CHAR_TOK 260 #define CHAR_TOK 260
#define STRING 261 #define SIMPLE_STRING 261
#define SIMPLE_IDENTIFIER 262 #define SIMPLE_IDENTIFIER 262
#define IDENTIFIER 263 #define STRING_LITERAL 263
#define TYPENAME_IDENTIFIER 264 #define CUSTOM_LITERAL 264
#define SCOPING 265 #define IDENTIFIER 265
#define TYPEDEFNAME 266 #define TYPENAME_IDENTIFIER 266
#define ELLIPSIS 267 #define SCOPING 267
#define OROR 268 #define TYPEDEFNAME 268
#define ANDAND 269 #define ELLIPSIS 269
#define EQCOMPARE 270 #define OROR 270
#define NECOMPARE 271 #define ANDAND 271
#define LECOMPARE 272 #define EQCOMPARE 272
#define GECOMPARE 273 #define NECOMPARE 273
#define LSHIFT 274 #define LECOMPARE 274
#define RSHIFT 275 #define GECOMPARE 275
#define POINTSAT_STAR 276 #define LSHIFT 276
#define DOT_STAR 277 #define RSHIFT 277
#define UNARY 278 #define POINTSAT_STAR 278
#define UNARY_NOT 279 #define DOT_STAR 279
#define UNARY_NEGATE 280 #define UNARY 280
#define UNARY_MINUS 281 #define UNARY_NOT 281
#define UNARY_STAR 282 #define UNARY_NEGATE 282
#define UNARY_REF 283 #define UNARY_MINUS 283
#define POINTSAT 284 #define UNARY_STAR 284
#define SCOPE 285 #define UNARY_REF 285
#define PLUSPLUS 286 #define POINTSAT 286
#define MINUSMINUS 287 #define SCOPE 287
#define TIMESEQUAL 288 #define PLUSPLUS 288
#define DIVIDEEQUAL 289 #define MINUSMINUS 289
#define MODEQUAL 290 #define TIMESEQUAL 290
#define PLUSEQUAL 291 #define DIVIDEEQUAL 291
#define MINUSEQUAL 292 #define MODEQUAL 292
#define OREQUAL 293 #define PLUSEQUAL 293
#define ANDEQUAL 294 #define MINUSEQUAL 294
#define XOREQUAL 295 #define OREQUAL 295
#define LSHIFTEQUAL 296 #define ANDEQUAL 296
#define RSHIFTEQUAL 297 #define XOREQUAL 297
#define KW_BEGIN_PUBLISH 298 #define LSHIFTEQUAL 298
#define KW_BLOCKING 299 #define RSHIFTEQUAL 299
#define KW_BOOL 300 #define KW_ALIGNAS 300
#define KW_CATCH 301 #define KW_ALIGNOF 301
#define KW_CHAR 302 #define KW_AUTO 302
#define KW_CHAR16_T 303 #define KW_BEGIN_PUBLISH 303
#define KW_CHAR32_T 304 #define KW_BLOCKING 304
#define KW_CLASS 305 #define KW_BOOL 305
#define KW_CONST 306 #define KW_CATCH 306
#define KW_DELETE 307 #define KW_CHAR 307
#define KW_DOUBLE 308 #define KW_CHAR16_T 308
#define KW_DYNAMIC_CAST 309 #define KW_CHAR32_T 309
#define KW_ELSE 310 #define KW_CLASS 310
#define KW_END_PUBLISH 311 #define KW_CONST 311
#define KW_ENUM 312 #define KW_CONSTEXPR 312
#define KW_EXTENSION 313 #define KW_DECLTYPE 313
#define KW_EXTERN 314 #define KW_DEFAULT 314
#define KW_EXPLICIT 315 #define KW_DELETE 315
#define KW_PUBLISHED 316 #define KW_DOUBLE 316
#define KW_FALSE 317 #define KW_DYNAMIC_CAST 317
#define KW_FLOAT 318 #define KW_ELSE 318
#define KW_FRIEND 319 #define KW_END_PUBLISH 319
#define KW_FOR 320 #define KW_ENUM 320
#define KW_GOTO 321 #define KW_EXTENSION 321
#define KW_IF 322 #define KW_EXTERN 322
#define KW_INLINE 323 #define KW_EXPLICIT 323
#define KW_INT 324 #define KW_PUBLISHED 324
#define KW_LONG 325 #define KW_FALSE 325
#define KW_LONGLONG 326 #define KW_FLOAT 326
#define KW_MAKE_PROPERTY 327 #define KW_FRIEND 327
#define KW_MAKE_SEQ 328 #define KW_FOR 328
#define KW_MUTABLE 329 #define KW_GOTO 329
#define KW_NAMESPACE 330 #define KW_IF 330
#define KW_NEW 331 #define KW_INLINE 331
#define KW_NOEXCEPT 332 #define KW_INT 332
#define KW_OPERATOR 333 #define KW_LONG 333
#define KW_PRIVATE 334 #define KW_LONGLONG 334
#define KW_PROTECTED 335 #define KW_MAKE_PROPERTY 335
#define KW_PUBLIC 336 #define KW_MAKE_SEQ 336
#define KW_REGISTER 337 #define KW_MUTABLE 337
#define KW_RETURN 338 #define KW_NAMESPACE 338
#define KW_SHORT 339 #define KW_NEW 339
#define KW_SIGNED 340 #define KW_NOEXCEPT 340
#define KW_SIZEOF 341 #define KW_NULLPTR 341
#define KW_STATIC 342 #define KW_OPERATOR 342
#define KW_STATIC_ASSERT 343 #define KW_PRIVATE 343
#define KW_STATIC_CAST 344 #define KW_PROTECTED 344
#define KW_STRUCT 345 #define KW_PUBLIC 345
#define KW_TEMPLATE 346 #define KW_REGISTER 346
#define KW_THROW 347 #define KW_RETURN 347
#define KW_TRUE 348 #define KW_SHORT 348
#define KW_TRY 349 #define KW_SIGNED 349
#define KW_TYPEDEF 350 #define KW_SIZEOF 350
#define KW_TYPENAME 351 #define KW_STATIC 351
#define KW_UNION 352 #define KW_STATIC_ASSERT 352
#define KW_UNSIGNED 353 #define KW_STATIC_CAST 353
#define KW_USING 354 #define KW_STRUCT 354
#define KW_VIRTUAL 355 #define KW_TEMPLATE 355
#define KW_VOID 356 #define KW_THROW 356
#define KW_VOLATILE 357 #define KW_TRUE 357
#define KW_WCHAR_T 358 #define KW_TRY 358
#define KW_WHILE 359 #define KW_TYPEDEF 359
#define START_CPP 360 #define KW_TYPENAME 360
#define START_CONST_EXPR 361 #define KW_UNION 361
#define START_TYPE 362 #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.real> REAL
%token <u.integer> INTEGER %token <u.integer> INTEGER
%token <u.integer> CHAR_TOK %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.identifier> IDENTIFIER TYPENAME_IDENTIFIER SCOPING
%token <u.type> TYPEDEFNAME %token <u.type> TYPEDEFNAME
@ -245,6 +246,9 @@ pop_struct() {
%token LSHIFTEQUAL %token LSHIFTEQUAL
%token RSHIFTEQUAL %token RSHIFTEQUAL
%token KW_ALIGNAS
%token KW_ALIGNOF
%token KW_AUTO
%token KW_BEGIN_PUBLISH %token KW_BEGIN_PUBLISH
%token KW_BLOCKING %token KW_BLOCKING
%token KW_BOOL %token KW_BOOL
@ -254,6 +258,9 @@ pop_struct() {
%token KW_CHAR32_T %token KW_CHAR32_T
%token KW_CLASS %token KW_CLASS
%token KW_CONST %token KW_CONST
%token KW_CONSTEXPR
%token KW_DECLTYPE
%token KW_DEFAULT
%token KW_DELETE %token KW_DELETE
%token KW_DOUBLE %token KW_DOUBLE
%token KW_DYNAMIC_CAST %token KW_DYNAMIC_CAST
@ -280,6 +287,7 @@ pop_struct() {
%token KW_NAMESPACE %token KW_NAMESPACE
%token KW_NEW %token KW_NEW
%token KW_NOEXCEPT %token KW_NOEXCEPT
%token KW_NULLPTR
%token KW_OPERATOR %token KW_OPERATOR
%token KW_PRIVATE %token KW_PRIVATE
%token KW_PROTECTED %token KW_PROTECTED
@ -348,7 +356,7 @@ pop_struct() {
%type <u.type> enum_element_type %type <u.type> enum_element_type
/*%type <u.type> typedefname*/ /*%type <u.type> typedefname*/
%type <u.identifier> name %type <u.identifier> name
%type <str> string %type <u.expr> string_literal
/* We need to treat KW_OPERATOR as a scopable keyword. */ /* We need to treat KW_OPERATOR as a scopable keyword. */
%type <u.identifier> KW_OPERATOR %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); 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); 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(); CPPExpression::Result result = $3->evaluate();
if (result._type == CPPExpression::RT_error) { if (result._type == CPPExpression::RT_error) {
yywarning("static_assert requires a constant expression", @3); yywarning("static_assert requires a constant expression", @3);
} else if (!result.as_boolean()) { } 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 ')' | KW_STATIC_ASSERT '(' const_expr ')'
@ -571,7 +581,7 @@ storage_class:
{ {
$$ = $1 | (int)CPPInstance::SC_extern; $$ = $1 | (int)CPPInstance::SC_extern;
} }
| storage_class KW_EXTERN string | storage_class KW_EXTERN SIMPLE_STRING
{ {
$$ = $1 | (int)CPPInstance::SC_extern; $$ = $1 | (int)CPPInstance::SC_extern;
if ($3 == "C") { if ($3 == "C") {
@ -1266,6 +1276,21 @@ instance_identifier:
ident->_names.push_back("operator "+$2); 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); $$ = new CPPInstanceIdentifier(ident);
} }
| KW_CONST instance_identifier %prec UNARY | KW_CONST instance_identifier %prec UNARY
@ -1691,6 +1716,15 @@ type:
} }
$$ = et; $$ = 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; $$ = 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: element:
REAL REAL
{
}
| INTEGER | INTEGER
{ | SIMPLE_STRING
} | STRING_LITERAL
| STRING | CUSTOM_LITERAL
{
}
| CHAR_TOK | CHAR_TOK
{
}
| IDENTIFIER | IDENTIFIER
{
}
| TYPENAME_IDENTIFIER | TYPENAME_IDENTIFIER
{
}
| SCOPING | SCOPING
{
}
| SIMPLE_IDENTIFIER | SIMPLE_IDENTIFIER
{
}
| ELLIPSIS | OROR | ANDAND | ELLIPSIS | OROR | ANDAND
| EQCOMPARE | NECOMPARE | LECOMPARE | GECOMPARE | EQCOMPARE | NECOMPARE | LECOMPARE | GECOMPARE
| LSHIFT | RSHIFT | POINTSAT_STAR | DOT_STAR | POINTSAT | LSHIFT | RSHIFT | POINTSAT_STAR | DOT_STAR | POINTSAT
| SCOPE | PLUSPLUS | MINUSMINUS | SCOPE | PLUSPLUS | MINUSMINUS
| TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
| OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL | OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL
| KW_BOOL | KW_CATCH | KW_CHAR | KW_CHAR16_T | KW_CHAR32_T | KW_ALIGNAS | KW_ALIGNOF | KW_AUTO | KW_BOOL | KW_CATCH
| KW_WCHAR_T | KW_CLASS | KW_CONST | 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_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM
| KW_EXTERN | KW_EXPLICIT | KW_FALSE | KW_EXTERN | KW_EXPLICIT | KW_FALSE
| KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
| KW_IF | KW_INLINE | KW_INT | KW_IF | KW_INLINE | KW_INT | KW_LONG | KW_MUTABLE
| KW_LONG | KW_MUTABLE | KW_NEW | KW_PRIVATE | KW_PROTECTED | KW_NEW | KW_NULLPTR | KW_OPERATOR | KW_PRIVATE | KW_PROTECTED
| KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_RETURN | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_RETURN
| KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_CAST | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_ASSERT
| KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF | KW_TYPENAME | KW_STATIC_CAST | KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY
| KW_UNION | KW_UNSIGNED | KW_VIRTUAL | KW_VOID | KW_VOLATILE | KW_TYPEDEF | KW_TYPENAME | KW_UNION | KW_UNSIGNED | KW_VIRTUAL
| KW_WHILE | KW_VOID | KW_VOLATILE | KW_WCHAR_T | KW_WHILE
| KW_OPERATOR
{ {
} }
| '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%' | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
@ -2314,6 +2343,10 @@ no_angle_bracket_const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY | KW_SIZEOF '(' full_type ')' %prec UNARY
{ {
$$ = new CPPExpression(CPPExpression::sizeof_func($3)); $$ = 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 | '!' no_angle_bracket_const_expr %prec UNARY
{ {
@ -2325,15 +2358,7 @@ no_angle_bracket_const_expr:
} }
| '-' no_angle_bracket_const_expr %prec UNARY | '-' no_angle_bracket_const_expr %prec UNARY
{ {
if ($2->_type == CPPExpression::T_integer) { $$ = new CPPExpression(UNARY_MINUS, $2);
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
} }
| '*' no_angle_bracket_const_expr %prec UNARY | '*' no_angle_bracket_const_expr %prec UNARY
{ {
@ -2544,6 +2569,10 @@ const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY | KW_SIZEOF '(' full_type ')' %prec UNARY
{ {
$$ = new CPPExpression(CPPExpression::sizeof_func($3)); $$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
} }
| KW_NEW predefined_type %prec UNARY | KW_NEW predefined_type %prec UNARY
{ {
@ -2563,15 +2592,7 @@ const_expr:
} }
| '-' const_expr %prec UNARY | '-' const_expr %prec UNARY
{ {
if ($2->_type == CPPExpression::T_integer) { $$ = new CPPExpression(UNARY_MINUS, $2);
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
} }
| '*' const_expr %prec UNARY | '*' const_expr %prec UNARY
{ {
@ -2704,13 +2725,21 @@ const_operand:
{ {
$$ = new CPPExpression($1); $$ = new CPPExpression($1);
} }
| string | string_literal
{ {
$$ = new CPPExpression($1); $$ = $1;
}
| CUSTOM_LITERAL
{
$$ = $1;
} }
| IDENTIFIER | IDENTIFIER
{ {
$$ = new CPPExpression($1, current_scope, global_scope, current_lexer); $$ = 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 | KW_SIZEOF '(' full_type ')' %prec UNARY
{ {
$$ = new CPPExpression(CPPExpression::sizeof_func($3)); $$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
} }
| KW_NEW predefined_type %prec UNARY | KW_NEW predefined_type %prec UNARY
{ {
@ -2760,15 +2793,7 @@ formal_const_expr:
} }
| '-' const_expr %prec UNARY | '-' const_expr %prec UNARY
{ {
if ($2->_type == CPPExpression::T_integer) { $$ = new CPPExpression(UNARY_MINUS, $2);
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
} }
| '&' const_expr %prec UNARY | '&' const_expr %prec UNARY
{ {
@ -2897,9 +2922,17 @@ formal_const_operand:
{ {
$$ = new CPPExpression($1); $$ = 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_literal:
STRING SIMPLE_STRING
{
$$ = new CPPExpression($1);
}
| STRING_LITERAL
{ {
$$ = $1; $$ = $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: public:
string str; string str;
union { union {
int integer; unsigned long long integer;
double real; long double real;
CPPScope *scope; CPPScope *scope;
CPPDeclaration *decl; CPPDeclaration *decl;
CPPInstance *instance; 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 // Function: CPPExpression::Constructor
// Access: Public // Access: Public
@ -220,7 +233,7 @@ CPPExpression(int value) :
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPPExpression:: CPPExpression::
CPPExpression(double value) : CPPExpression(long double value) :
CPPDeclaration(CPPFile()) CPPDeclaration(CPPFile())
{ {
_type = T_real; _type = T_real;
@ -397,6 +410,89 @@ sizeof_func(CPPType *type) {
return expr; 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 // Function: CPPExpression::Destructor
// Access: Public // Access: Public
@ -416,13 +512,20 @@ evaluate() const {
Result r1, r2; Result r1, r2;
switch (_type) { switch (_type) {
case T_nullptr:
return Result((void *)0);
case T_integer: case T_integer:
return Result(_u._integer); return Result((int)_u._integer);
case T_real: case T_real:
return Result(_u._real); return Result((double)_u._real);
case T_string: case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return Result(); return Result();
case T_variable: case T_variable:
@ -468,6 +571,17 @@ evaluate() const {
case T_sizeof: case T_sizeof:
return Result(); 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: case T_binary_operation:
assert(_u._op._op2 != NULL); assert(_u._op._op2 != NULL);
r2 = _u._op._op2->evaluate(); r2 = _u._op._op2->evaluate();
@ -652,6 +766,10 @@ evaluate() const {
abort(); abort();
} }
case T_literal:
case T_raw_literal:
return Result();
default: default:
cerr << "**invalid operand**\n"; cerr << "**invalid operand**\n";
abort(); abort();
@ -671,25 +789,51 @@ determine_type() const {
CPPType *t1 = (CPPType *)NULL; CPPType *t1 = (CPPType *)NULL;
CPPType *t2 = (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::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::new_type(new CPPSimpleType(CPPSimpleType::T_bool));
CPPType *float_type = static CPPType *float_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double)); CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double));
CPPType *char_type = static CPPType *char_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char)); CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char));
CPPType *const_char_type = static CPPType *wchar_type =
CPPType::new_type(new CPPConstType(char_type)); CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
CPPType *char_star_type = static CPPType *char16_type =
CPPType::new_type(new CPPPointerType(const_char_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) { switch (_type) {
case T_nullptr:
return nullptr_type;
case T_integer: case T_integer:
return int_type; return int_type;
@ -697,7 +841,19 @@ determine_type() const {
return float_type; return float_type;
case T_string: 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: case T_variable:
return _u._variable->_type; return _u._variable->_type;
@ -725,7 +881,11 @@ determine_type() const {
return CPPType::new_type(new CPPPointerType(_u._typecast._to)); return CPPType::new_type(new CPPPointerType(_u._typecast._to));
case T_sizeof: 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_binary_operation:
case T_trinary_operation: case T_trinary_operation:
@ -819,6 +979,18 @@ determine_type() const {
abort(); 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: default:
cerr << "**invalid operand**\n"; cerr << "**invalid operand**\n";
abort(); abort();
@ -842,9 +1014,14 @@ is_fully_specified() const {
} }
switch (_type) { switch (_type) {
case T_nullptr:
case T_integer: case T_integer:
case T_real: case T_real:
case T_string: case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return false; return false;
case T_variable: case T_variable:
@ -865,6 +1042,7 @@ is_fully_specified() const {
case T_default_construct: case T_default_construct:
case T_default_new: case T_default_new:
case T_sizeof: case T_sizeof:
case T_alignof:
return _u._typecast._to->is_fully_specified(); return _u._typecast._to->is_fully_specified();
case T_trinary_operation: case T_trinary_operation:
@ -882,6 +1060,13 @@ is_fully_specified() const {
case T_unary_operation: case T_unary_operation:
return _u._op._op1->is_fully_specified(); 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: default:
return true; return true;
} }
@ -972,6 +1157,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
case T_default_construct: case T_default_construct:
case T_default_new: case T_default_new:
case T_sizeof: case T_sizeof:
case T_alignof:
rep->_u._typecast._to = rep->_u._typecast._to =
_u._typecast._to->substitute_decl(subst, current_scope, global_scope) _u._typecast._to->substitute_decl(subst, current_scope, global_scope)
->as_type(); ->as_type();
@ -1042,6 +1228,7 @@ is_tbd() const {
case T_default_construct: case T_default_construct:
case T_default_new: case T_default_new:
case T_sizeof: case T_sizeof:
case T_alignof:
return _u._typecast._to->is_tbd(); return _u._typecast._to->is_tbd();
case T_trinary_operation: case T_trinary_operation:
@ -1075,6 +1262,10 @@ is_tbd() const {
void CPPExpression:: void CPPExpression::
output(ostream &out, int indent_level, CPPScope *scope, bool) const { output(ostream &out, int indent_level, CPPScope *scope, bool) const {
switch (_type) { switch (_type) {
case T_nullptr:
out << "nullptr";
break;
case T_integer: case T_integer:
out << _u._integer; out << _u._integer;
break; break;
@ -1090,8 +1281,29 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
break; break;
case T_string: 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; string::const_iterator si;
for (si = _str.begin(); si != _str.end(); ++si) { for (si = _str.begin(); si != _str.end(); ++si) {
switch (*si) { switch (*si) {
@ -1193,6 +1405,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
out << ")"; out << ")";
break; break;
case T_alignof:
out << "alignof(";
_u._typecast._to->output(out, indent_level, scope, false);
out << ")";
break;
case T_unary_operation: case T_unary_operation:
switch (_u._op._operator) { switch (_u._op._operator) {
case UNARY_NOT: case UNARY_NOT:
@ -1208,9 +1426,8 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
break; break;
case UNARY_MINUS: case UNARY_MINUS:
out << "(- "; out << '-';
_u._op._op1->output(out, indent_level, scope, false); _u._op._op1->output(out, indent_level, scope, false);
out << ")";
break; break;
case UNARY_STAR: case UNARY_STAR:
@ -1362,6 +1579,24 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
out << ")"; out << ")";
break; 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: default:
out << "(** invalid operand type " << (int)_type << " **)"; out << "(** invalid operand type " << (int)_type << " **)";
} }
@ -1456,6 +1691,9 @@ is_equal(const CPPDeclaration *other) const {
} }
switch (_type) { switch (_type) {
case T_nullptr:
return true;
case T_integer: case T_integer:
return _u._integer == ot->_u._integer; return _u._integer == ot->_u._integer;
@ -1463,6 +1701,10 @@ is_equal(const CPPDeclaration *other) const {
return _u._real == ot->_u._real; return _u._real == ot->_u._real;
case T_string: case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str == ot->_str; return _str == ot->_str;
case T_variable: case T_variable:
@ -1483,6 +1725,7 @@ is_equal(const CPPDeclaration *other) const {
case T_default_construct: case T_default_construct:
case T_default_new: case T_default_new:
case T_sizeof: case T_sizeof:
case T_alignof:
return _u._typecast._to == ot->_u._typecast._to; return _u._typecast._to == ot->_u._typecast._to;
case T_unary_operation: case T_unary_operation:
@ -1496,6 +1739,14 @@ is_equal(const CPPDeclaration *other) const {
return *_u._op._op1 == *ot->_u._op._op1 && return *_u._op._op1 == *ot->_u._op._op1 &&
*_u._op._op2 == *ot->_u._op._op2; *_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: default:
cerr << "(** invalid operand type " << (int)_type << " **)"; cerr << "(** invalid operand type " << (int)_type << " **)";
} }
@ -1520,6 +1771,9 @@ is_less(const CPPDeclaration *other) const {
} }
switch (_type) { switch (_type) {
case T_nullptr:
return false;
case T_integer: case T_integer:
return _u._integer < ot->_u._integer; return _u._integer < ot->_u._integer;
@ -1527,6 +1781,10 @@ is_less(const CPPDeclaration *other) const {
return _u._real < ot->_u._real; return _u._real < ot->_u._real;
case T_string: case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str < ot->_str; return _str < ot->_str;
case T_variable: case T_variable:
@ -1549,6 +1807,7 @@ is_less(const CPPDeclaration *other) const {
case T_default_construct: case T_default_construct:
case T_default_new: case T_default_new:
case T_sizeof: case T_sizeof:
case T_alignof:
return _u._typecast._to < ot->_u._typecast._to; return _u._typecast._to < ot->_u._typecast._to;
case T_trinary_operation: case T_trinary_operation:
@ -1566,6 +1825,18 @@ is_less(const CPPDeclaration *other) const {
case T_unary_operation: case T_unary_operation:
return *_u._op._op1 < *ot->_u._op._op1; 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: default:
cerr << "(** invalid operand type " << (int)_type << " **)"; cerr << "(** invalid operand type " << (int)_type << " **)";
} }

View File

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

View File

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

View File

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

View File

@ -38,7 +38,8 @@ CPPInstance(CPPType *type, const string &name, int storage_class) :
CPPDeclaration(CPPFile()), CPPDeclaration(CPPFile()),
_type(type), _type(type),
_ident(new CPPIdentifier(name)), _ident(new CPPIdentifier(name)),
_storage_class(storage_class) _storage_class(storage_class),
_alignment(NULL)
{ {
_initializer = NULL; _initializer = NULL;
} }
@ -53,7 +54,8 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
CPPDeclaration(CPPFile()), CPPDeclaration(CPPFile()),
_type(type), _type(type),
_ident(ident), _ident(ident),
_storage_class(storage_class) _storage_class(storage_class),
_alignment(NULL)
{ {
_initializer = NULL; _initializer = NULL;
} }
@ -69,7 +71,8 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
CPPInstance:: CPPInstance::
CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class, CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
const CPPFile &file) : const CPPFile &file) :
CPPDeclaration(file) CPPDeclaration(file),
_alignment(NULL)
{ {
_type = ii->unroll_type(type); _type = ii->unroll_type(type);
_ident = ii->_ident; _ident = ii->_ident;
@ -102,7 +105,8 @@ CPPInstance(const CPPInstance &copy) :
_type(copy._type), _type(copy._type),
_ident(copy._ident), _ident(copy._ident),
_initializer(copy._initializer), _initializer(copy._initializer),
_storage_class(copy._storage_class) _storage_class(copy._storage_class),
_alignment(copy._alignment)
{ {
assert(_type != NULL); assert(_type != NULL);
} }
@ -153,6 +157,9 @@ operator == (const CPPInstance &other) const {
if (_storage_class != other._storage_class) { if (_storage_class != other._storage_class) {
return false; return false;
} }
if (_alignment != other._alignment) {
return false;
}
// We *do* care about the identifier. We need to differentiate // We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based // types of function variables, among possibly other things, based
@ -199,6 +206,9 @@ operator < (const CPPInstance &other) const {
if (_storage_class != other._storage_class) { if (_storage_class != other._storage_class) {
return _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 // We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based // 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 // Function: CPPInstance::is_scoped
// Access: Public // Access: Public
@ -536,6 +569,11 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
get_template_scope()->_parameters.write_formal(out, scope); get_template_scope()->_parameters.write_formal(out, scope);
indent(out, indent_level); indent(out, indent_level);
} }
if (_alignment != NULL) {
out << "alignas(" << *_alignment << ") ";
}
if (_storage_class & SC_static) { if (_storage_class & SC_static) {
out << "static "; out << "static ";
} }

View File

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

View File

@ -26,6 +26,7 @@
#include "cppBison.h" #include "cppBison.h"
#include "indent.h" #include "indent.h"
#include "pstrtod.h" #include "pstrtod.h"
#include "string_utils.h"
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
@ -404,6 +405,7 @@ get_next_token0() {
// keyword. We make a special case for this, because it's // keyword. We make a special case for this, because it's
// occasionally scoped in normal use. // occasionally scoped in normal use.
token._lval = result; token._lval = result;
_last_token_loc = token._lloc;
return token; return token;
} }
_saved_tokens.push_back(token); _saved_tokens.push_back(token);
@ -1803,9 +1805,7 @@ get_quoted_char(int c) {
result.u.integer = 0; result.u.integer = 0;
} }
loc.last_line = get_line_number(); return get_literal(CHAR_TOK, loc, str, result);
loc.last_column = get_col_number();
return CPPToken(CHAR_TOK, loc, str, result);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1822,9 +1822,7 @@ get_quoted_string(int c) {
string str = scan_quoted(c); string str = scan_quoted(c);
loc.last_line = get_line_number(); return get_literal(SIMPLE_STRING, loc, str);
loc.last_column = get_col_number();
return CPPToken(STRING, loc, str);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1848,25 +1846,51 @@ get_identifier(int c) {
name += get(); name += get();
c = peek(); 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_line = get_line_number();
loc.last_column = get_col_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; _last_c = 0;
// Is it a manifest? // Is it a manifest?
@ -1898,6 +1922,171 @@ get_identifier(int c) {
return CPPToken(SIMPLE_IDENTIFIER, loc, name); 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 // Function: CPPPreprocessor::expand_manifest
// Access: Private // Access: Private
@ -2196,20 +2385,13 @@ get_number(int c) {
c = peek(); 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_line = get_line_number();
loc.last_column = get_col_number(); loc.last_column = get_col_number();
_last_c = 0;
YYSTYPE result; YYSTYPE result;
result.u.integer = strtol(num.c_str(), (char **)NULL, 16); 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)) { 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') { if (tolower(c) == 'e') {
// An exponent is allowed. // An exponent is allowed.
num += get(); 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_line = get_line_number();
loc.last_column = get_col_number(); loc.last_column = get_col_number();
YYSTYPE result; YYSTYPE result;
result.u.real = pstrtod(num.c_str(), (char **)NULL); 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. // 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_line = get_line_number();
loc.last_column = get_col_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); 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:: int CPPPreprocessor::
check_keyword(const string &name) { 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 == "__begin_publish") return KW_BEGIN_PUBLISH;
if (name == "__blocking") return KW_BLOCKING; if (name == "__blocking") return KW_BLOCKING;
if (name == "bool") return KW_BOOL; 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 == "__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 == "delete") return KW_DELETE;
if (name == "double") return KW_DOUBLE; if (name == "double") return KW_DOUBLE;
if (name == "dynamic_cast") return KW_DYNAMIC_CAST; 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 == "mutable") return KW_MUTABLE;
if (name == "namespace") return KW_NAMESPACE; if (name == "namespace") return KW_NAMESPACE;
if (name == "noexcept") return KW_NOEXCEPT; if (name == "noexcept") return KW_NOEXCEPT;
if (name == "nullptr") return KW_NULLPTR;
if (name == "new") return KW_NEW; if (name == "new") return KW_NEW;
if (name == "operator") return KW_OPERATOR; if (name == "operator") return KW_OPERATOR;
if (name == "private") return KW_PRIVATE; if (name == "private") return KW_PRIVATE;

View File

@ -142,6 +142,8 @@ private:
CPPToken get_quoted_char(int c); CPPToken get_quoted_char(int c);
CPPToken get_quoted_string(int c); CPPToken get_quoted_string(int c);
CPPToken get_identifier(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); CPPToken expand_manifest(const CPPManifest *manifest);
void extract_manifest_args(const string &name, int num_args, void extract_manifest_args(const string &name, int num_args,
int va_arg, vector_string &args); int va_arg, vector_string &args);

View File

@ -313,7 +313,7 @@ add_using(CPPUsing *using_decl, CPPScope *global_scope,
_using.insert(scope); _using.insert(scope);
} else { } else {
if (error_sink != NULL) { 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 { } else {
@ -322,7 +322,7 @@ add_using(CPPUsing *using_decl, CPPScope *global_scope,
handle_declaration(decl, global_scope, error_sink); handle_declaration(decl, global_scope, error_sink);
} else { } else {
if (error_sink != NULL) { 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"; out << "void";
break; break;
case T_nullptr:
out << "decltype(nullptr)";
break;
case T_parameter: case T_parameter:
out << "parameter"; out << "parameter";
break; break;

View File

@ -37,6 +37,11 @@ public:
T_double, T_double,
T_void, 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 // T_parameter is a special type which is assigned to expressions
// that are discovered where a formal parameter was expected. // that are discovered where a formal parameter was expected.
// This is a special case for handling cases like this: // 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; out << "CHAR_TOK " << _lval.u.integer << " = " << _lval.str;
break; break;
case STRING: case SIMPLE_STRING:
out << "STRING " << _lval.str; out << "SIMPLE_STRING " << _lval.str;
break;
case STRING_LITERAL:
out << "STRING_LITERAL " << *_lval.u.expr;
break; break;
case SIMPLE_IDENTIFIER: case SIMPLE_IDENTIFIER:

View File

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

View File

@ -44,5 +44,26 @@ public:
typedef basic_string<char> string; typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring; 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 #endif