Browse Source

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

rdb 10 years ago
parent
commit
b65ad853fe

File diff suppressed because it is too large
+ 518 - 489
dtool/src/cppparser/cppBison.cxx.prebuilt


+ 220 - 202
dtool/src/cppparser/cppBison.h.prebuilt

@@ -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
 
 
 

+ 114 - 66
dtool/src/cppparser/cppBison.yxx

@@ -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_literal SIMPLE_STRING
+{
+  // The right string takes on the literal type of the left.
   $$ = $1;
+  $$->_str += $2;
 }
-        | string STRING
+        | string_literal STRING_LITERAL
 {
-  $$ = $1 + $2;
+  // 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;
 }
         ;
 

+ 2 - 2
dtool/src/cppparser/cppBisonDefs.h

@@ -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;

+ 287 - 16
dtool/src/cppparser/cppExpression.cxx

@@ -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));
+
+  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))));
 
-  CPPType *char_star_type =
-    CPPType::new_type(new CPPPointerType(const_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 << " **)";
   }

+ 25 - 5
dtool/src/cppparser/cppExpression.h

@@ -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
-
-

+ 2 - 1
dtool/src/cppparser/cppExtensionType.cxx

@@ -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;

+ 1 - 1
dtool/src/cppparser/cppExtensionType.h

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

+ 42 - 4
dtool/src/cppparser/cppInstance.cxx

@@ -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 ";
   }

+ 3 - 0
dtool/src/cppparser/cppInstance.h

@@ -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;

+ 222 - 42
dtool/src/cppparser/cppPreprocessor.cxx

@@ -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 == '"') {
+
+  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: a string with an alphanumeric prefix.  We don't
-    // necessarily try to parse it correctly; for most purposes, we
-    // don't care.
+    // 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();
-    CPPToken token(0);
+    string str = scan_quoted(c);
+
+    loc.last_line = get_line_number();
+    loc.last_column = get_col_number();
+
+    YYSTYPE result;
     if (c == '\'') {
-      token = get_quoted_char(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 {
-      token = get_quoted_string(c);
+      result.u.expr = new CPPExpression(str);
+      result.u.expr->_type = type;
+      return get_literal(STRING_LITERAL, loc, str, result);
     }
-    token._lloc.first_column = loc.first_column;
-    return token;
   }
 
-  loc.last_line = get_line_number();
-  loc.last_column = get_col_number();
-
   _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;

+ 2 - 0
dtool/src/cppparser/cppPreprocessor.h

@@ -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);

+ 2 - 2
dtool/src/cppparser/cppScope.cxx

@@ -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);
       }
     }
   }

+ 4 - 0
dtool/src/cppparser/cppSimpleType.cxx

@@ -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;

+ 5 - 0
dtool/src/cppparser/cppSimpleType.h

@@ -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:

+ 6 - 2
dtool/src/cppparser/cppToken.cxx

@@ -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:

+ 4 - 0
dtool/src/parser-inc/stddef.h

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

+ 21 - 0
dtool/src/parser-inc/string

@@ -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

Some files were not shown because too many files changed in this diff