/** * @file cppBison.yxx * @author drose * @date 1999-01-16 */ %{ #include "cppBisonDefs.h" #include "cppParser.h" #include "cppClosureType.h" #include "cppExpression.h" #include "cppSimpleType.h" #include "cppExtensionType.h" #include "cppStructType.h" #include "cppEnumType.h" #include "cppFunctionType.h" #include "cppTBDType.h" #include "cppMakeProperty.h" #include "cppMakeSeq.h" #include "cppParameterList.h" #include "cppInstance.h" #include "cppClassTemplateParameter.h" #include "cppTemplateParameterList.h" #include "cppInstanceIdentifier.h" #include "cppTypedefType.h" #include "cppTypeDeclaration.h" #include "cppVisibility.h" #include "cppIdentifier.h" #include "cppScope.h" #include "cppTemplateScope.h" #include "cppNamespace.h" #include "cppUsing.h" //////////////////////////////////////////////////////////////////// // Defining the interface to the parser. //////////////////////////////////////////////////////////////////// CPPScope *current_scope = NULL; CPPScope *global_scope = NULL; CPPPreprocessor *current_lexer = NULL; static CPPStructType *current_struct = NULL; static CPPEnumType *current_enum = NULL; static int current_storage_class = 0; static CPPType *current_type = NULL; static CPPExpression *current_expr = NULL; static CPPClosureType *current_closure = NULL; static int publish_nest_level = 0; static CPPVisibility publish_previous; static YYLTYPE publish_loc; static vector last_scopes; static vector last_storage_classes; static vector last_structs; int yyparse(); #define YYERROR_VERBOSE static void yyerror(const string &msg) { current_lexer->error(msg, current_lexer->_last_token_loc); } static void yyerror(YYLTYPE *loc, const string &msg) { current_lexer->error(msg, *loc); } static void yyerror(const string &msg, YYLTYPE &loc) { current_lexer->error(msg, loc); } static void yywarning(const string &msg, YYLTYPE &loc) { current_lexer->warning(msg, loc); } static int yylex(YYSTYPE *lval, YYLTYPE *lloc) { CPPToken token = current_lexer->get_next_token(); *lval = token._lval; *lloc = token._lloc; return token._token; } void parse_cpp(CPPParser *cp) { CPPScope *old_scope = current_scope; CPPScope *old_global_scope = global_scope; CPPPreprocessor *old_lexer = current_lexer; current_scope = cp; global_scope = cp; current_lexer = cp; publish_nest_level = 0; yyparse(); if (publish_nest_level != 0) { yyerror("Unclosed __begin_publish", publish_loc); publish_nest_level = 0; } current_scope = old_scope; global_scope = old_global_scope; current_lexer = old_lexer; } CPPExpression * parse_const_expr(CPPPreprocessor *pp, CPPScope *new_current_scope, CPPScope *new_global_scope) { CPPScope *old_scope = current_scope; CPPScope *old_global_scope = global_scope; CPPPreprocessor *old_lexer = current_lexer; CPPExpression *old_expr = current_expr; current_scope = new_current_scope; global_scope = new_global_scope; current_expr = (CPPExpression *)NULL; current_lexer = pp; yyparse(); CPPExpression *result = current_expr; current_scope = old_scope; global_scope = old_global_scope; current_lexer = old_lexer; current_expr = old_expr; return result; } CPPType * parse_type(CPPPreprocessor *pp, CPPScope *new_current_scope, CPPScope *new_global_scope) { CPPScope *old_scope = current_scope; CPPScope *old_global_scope = global_scope; CPPPreprocessor *old_lexer = current_lexer; CPPType *old_type = current_type; current_scope = new_current_scope; global_scope = new_global_scope; current_type = (CPPType *)NULL; current_lexer = pp; yyparse(); CPPType *result = current_type; current_scope = old_scope; global_scope = old_global_scope; current_lexer = old_lexer; current_type = old_type; return result; } static void push_scope(CPPScope *new_scope) { last_scopes.push_back(current_scope); if (new_scope != NULL) { current_scope = new_scope; } } static void pop_scope() { assert(!last_scopes.empty()); current_scope = last_scopes.back(); last_scopes.pop_back(); } static void push_storage_class(int new_storage_class) { last_storage_classes.push_back(current_storage_class); current_storage_class = new_storage_class; } static void pop_storage_class() { assert(!last_storage_classes.empty()); current_storage_class = last_storage_classes.back(); last_storage_classes.pop_back(); } static void push_struct(CPPStructType *new_struct) { last_structs.push_back(current_struct); current_struct = new_struct; } static void pop_struct() { assert(!last_structs.empty()); current_struct = last_structs.back(); last_structs.pop_back(); } %} /* This is a bison-specific declaration to enable recursive calls to yyparse(). It changes the calling sequence to yylex(), passing pointers to the current yylval and yylloc. Bison 2.7 introduces a different syntax that will also pass the current yylloc to yyerror, but we have to support Bison versions as old as 2.5 for now. */ /*%define api.pure full*/ %pure-parser %locations %token REAL %token INTEGER %token CHAR_TOK %token SIMPLE_STRING SIMPLE_IDENTIFIER %token STRING_LITERAL CUSTOM_LITERAL %token IDENTIFIER TYPENAME_IDENTIFIER TYPEPACK_IDENTIFIER SCOPING %token TYPEDEFNAME %token ELLIPSIS %token OROR %token ANDAND %token EQCOMPARE %token NECOMPARE %token LECOMPARE %token GECOMPARE %token LSHIFT %token RSHIFT %token POINTSAT_STAR %token DOT_STAR %token UNARY %token UNARY_NOT %token UNARY_NEGATE %token UNARY_MINUS %token UNARY_PLUS %token UNARY_STAR %token UNARY_REF %token POINTSAT %token SCOPE %token PLUSPLUS %token MINUSMINUS %token TIMESEQUAL %token DIVIDEEQUAL %token MODEQUAL %token PLUSEQUAL %token MINUSEQUAL %token OREQUAL %token ANDEQUAL %token XOREQUAL %token LSHIFTEQUAL %token RSHIFTEQUAL %token KW_ALIGNAS %token KW_ALIGNOF %token KW_AUTO %token KW_BEGIN_PUBLISH %token KW_BLOCKING %token KW_BOOL %token KW_CATCH %token KW_CHAR %token KW_CHAR16_T %token KW_CHAR32_T %token KW_CLASS %token KW_CONST %token KW_CONSTEXPR %token KW_CONST_CAST %token KW_DECLTYPE %token KW_DEFAULT %token KW_DELETE %token KW_DOUBLE %token KW_DYNAMIC_CAST %token KW_ELSE %token KW_END_PUBLISH %token KW_ENUM %token KW_EXTENSION %token KW_EXTERN %token KW_EXPLICIT %token KW_PUBLISHED %token KW_FALSE %token KW_FINAL %token KW_FLOAT %token KW_FRIEND %token KW_FOR %token KW_GOTO %token KW_HAS_VIRTUAL_DESTRUCTOR %token KW_IF %token KW_INLINE %token KW_INT %token KW_IS_ABSTRACT %token KW_IS_BASE_OF %token KW_IS_CLASS %token KW_IS_CONSTRUCTIBLE %token KW_IS_CONVERTIBLE_TO %token KW_IS_DESTRUCTIBLE %token KW_IS_EMPTY %token KW_IS_ENUM %token KW_IS_FINAL %token KW_IS_FUNDAMENTAL %token KW_IS_POD %token KW_IS_POLYMORPHIC %token KW_IS_STANDARD_LAYOUT %token KW_IS_TRIVIAL %token KW_IS_UNION %token KW_LONG %token KW_MAKE_MAP_PROPERTY %token KW_MAKE_PROPERTY %token KW_MAKE_PROPERTY2 %token KW_MAKE_SEQ %token KW_MAKE_SEQ_PROPERTY %token KW_MUTABLE %token KW_NAMESPACE %token KW_NEW %token KW_NOEXCEPT %token KW_NULLPTR %token KW_OPERATOR %token KW_OVERRIDE %token KW_PRIVATE %token KW_PROTECTED %token KW_PUBLIC %token KW_REGISTER %token KW_REINTERPRET_CAST %token KW_RETURN %token KW_SHORT %token KW_SIGNED %token KW_SIZEOF %token KW_STATIC %token KW_STATIC_ASSERT %token KW_STATIC_CAST %token KW_STRUCT %token KW_TEMPLATE %token KW_THREAD_LOCAL %token KW_THROW %token KW_TRUE %token KW_TRY %token KW_TYPEDEF %token KW_TYPEID %token KW_TYPENAME %token KW_UNDERLYING_TYPE %token KW_UNION %token KW_UNSIGNED %token KW_USING %token KW_VIRTUAL %token KW_VOID %token KW_VOLATILE %token KW_WCHAR_T %token KW_WHILE /* These special tokens are used to set the starting state of the parser. The lexer places the appropriate one of these on the head of the input stream. */ %token START_CPP %token START_CONST_EXPR %token START_TYPE %type storage_class %type constructor_prototype %type function_prototype %type function_post %type function_operator %type template_formal_parameter %type template_formal_parameter_type %type instance_identifier %type instance_identifier_and_maybe_trailing_return_type %type function_parameter_list %type function_parameters %type formal_parameter_list %type formal_parameters %type capture_list %type capture %type template_parameter_maybe_initialize %type maybe_initialize %type maybe_initialize_or_constructor_body %type maybe_initialize_or_function_body %type function_parameter %type formal_parameter %type not_paren_formal_parameter_identifier %type formal_parameter_identifier %type parameter_pack_identifier %type not_paren_empty_instance_identifier %type empty_instance_identifier %type type type_pack %type type_decl %type var_type_decl %type predefined_type %type full_type %type anonymous_struct %type named_struct %type enum %type enum_keyword %type struct_keyword %type simple_type %type simple_int_type %type simple_float_type %type simple_void_type %type class_derivation_name %type enum_element_type %type maybe_trailing_return_type /*%type typedefname*/ %type name %type name_no_final %type string_literal /* We need to treat KW_OPERATOR as a scopable keyword. */ %type KW_OPERATOR %type optional_const_expr %type optional_const_expr_comma %type const_expr_comma %type no_angle_bracket_const_expr %type const_expr %type const_operand %type formal_const_expr %type formal_const_operand /* Precedence rules. */ %left IDENTIFIER TYPENAME_IDENTIFIER TYPEDEFNAME KW_ENUM ELLIPSIS KW_OPERATOR KW_TYPENAME KW_INT KW_SHORT KW_UNSIGNED KW_SIGNED KW_LONG KW_FLOAT KW_DOUBLE KW_CHAR KW_WCHAR_T KW_CHAR16_T KW_CHAR32_T KW_BOOL %left '{' ',' ';' %nonassoc KW_THROW %right ':' %right '=' %right '?' %left OROR %left ANDAND %left '|' %left '^' %left '&' %left EQCOMPARE NECOMPARE %left LECOMPARE GECOMPARE '<' '>' %left LSHIFT RSHIFT %left '+' '-' %left '*' '/' '%' %left POINTSAT_STAR DOT_STAR %right UNARY PLUSPLUS MINUSMINUS '~' %left POINTSAT '.' '(' '[' %right SCOPE %nonassoc KW_NEW KW_DELETE KW_TRY KW_CATCH %% grammar: START_CPP cpp | START_CONST_EXPR const_expr { current_expr = $2; } | START_TYPE full_type { current_type = $2; } ; cpp: empty | cpp ';' | cpp declaration ; constructor_inits: constructor_init | constructor_inits ',' constructor_init ; constructor_init: name '(' optional_const_expr_comma ')' { delete $3; } | name '(' optional_const_expr_comma ')' ELLIPSIS { delete $3; } | name '{' optional_const_expr_comma '}' { delete $3; } ; /* This is principally for the syntax: extern "C" { ... }. We use storage_class instead of simply KW_EXTERN to avoid shift/reduce conflicts with yacc's limited differentiation ability. */ extern_c: storage_class '{' { push_storage_class((current_storage_class & ~CPPInstance::SC_c_binding) | ($1 & CPPInstance::SC_c_binding)); } cpp '}' { pop_storage_class(); } ; declaration: type_like_declaration | template_declaration | extern_c | namespace_declaration | friend_declaration | KW_TYPEDEF typedef_declaration | KW_BEGIN_PUBLISH { if (publish_nest_level != 0) { yyerror("Unclosed __begin_publish", publish_loc); publish_nest_level = 0; current_scope->set_current_vis(V_public); } publish_previous = current_scope->get_current_vis(); publish_loc = @1; publish_nest_level++; current_scope->set_current_vis(V_published); } | KW_END_PUBLISH { if (publish_nest_level != 1) { yyerror("Unmatched __end_publish", @1); } else { current_scope->set_current_vis(publish_previous); } publish_nest_level = 0; } | KW_PUBLISHED ':' { current_scope->set_current_vis(V_published); } | KW_PUBLIC ':' { if (publish_nest_level > 0) { current_scope->set_current_vis(V_published); } else { current_scope->set_current_vis(V_public); } } | KW_PROTECTED ':' { current_scope->set_current_vis(V_protected); } | KW_PRIVATE ':' { current_scope->set_current_vis(V_private); } | KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ')' ';' { CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5); } CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), NULL, current_scope, @1.file); current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } | KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5); } else { CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer); CPPFunctionGroup *setter_func = NULL; if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @7); } else { setter_func = setter->as_function_group(); } CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), setter_func, current_scope, @1.file); current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } } | KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5); } else { CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer); CPPFunctionGroup *setter_func = NULL; if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @7); } else { setter_func = setter->as_function_group(); } CPPDeclaration *deleter = $9->find_symbol(current_scope, global_scope, current_lexer); if (deleter == (CPPDeclaration *)NULL || deleter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("reference to non-existent or invalid delete method: " + $9->get_fully_scoped_name(), @9); deleter = NULL; } CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), setter_func, current_scope, @1.file); if (deleter) { make_property->_del_function = deleter->as_function_group(); } current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } } | KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); length_getter = NULL; } CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); } CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), NULL, current_scope, @1.file); make_property->_length_function = length_getter->as_function_group(); current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } | KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); length_getter = NULL; } CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); } else { CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); CPPFunctionGroup *setter_func = NULL; if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); } else { setter_func = setter->as_function_group(); } CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), setter_func, current_scope, @1.file); make_property->_length_function = length_getter->as_function_group(); current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } } | KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); length_getter = NULL; } CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); } else { CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); CPPFunctionGroup *setter_func = NULL; if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); } else { setter_func = setter->as_function_group(); } CPPDeclaration *deleter = $11->find_symbol(current_scope, global_scope, current_lexer); if (deleter == (CPPDeclaration *)NULL || deleter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("reference to non-existent or invalid delete method: " + $11->get_fully_scoped_name(), @11); deleter = NULL; } CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), setter_func, current_scope, @1.file); make_property->_length_function = length_getter->as_function_group(); if (deleter) { make_property->_del_function = deleter->as_function_group(); } current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } } | KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer); if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid has-function: " + $5->get_fully_scoped_name(), @5); } CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); } if (hasser && getter) { CPPMakeProperty *make_property; make_property = new CPPMakeProperty($3, hasser->as_function_group(), getter->as_function_group(), NULL, NULL, current_scope, @1.file); current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } } | KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer); if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid has-function: " + $5->get_fully_scoped_name(), @5); } CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); } CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); } CPPDeclaration *clearer = $11->find_symbol(current_scope, global_scope, current_lexer); if (clearer == (CPPDeclaration *)NULL || clearer->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("Reference to non-existent or invalid clear-function: " + $11->get_fully_scoped_name(), @11); } if (hasser && getter && setter && clearer) { CPPMakeProperty *make_property; make_property = new CPPMakeProperty($3, hasser->as_function_group(), getter->as_function_group(), setter->as_function_group(), clearer->as_function_group(), current_scope, @1.file); current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } } | KW_MAKE_SEQ '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' { CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); length_getter = NULL; } CPPDeclaration *element_getter = $7->find_symbol(current_scope, global_scope, current_lexer); if (element_getter == (CPPDeclaration *)NULL || element_getter->get_subtype() != CPPDeclaration::ST_function_group) { yyerror("reference to non-existent or invalid element method: " + $7->get_fully_scoped_name(), @5); element_getter = NULL; } if (length_getter != (CPPDeclaration *)NULL && element_getter != (CPPDeclaration *)NULL) { CPPMakeSeq *make_seq = new CPPMakeSeq($3, length_getter->as_function_group(), element_getter->as_function_group(), current_scope, @1.file); current_scope->add_declaration(make_seq, global_scope, current_lexer, @1); } } | 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()) { stringstream str; str << *$5; yywarning("static_assert failed: " + str.str(), @3); } } | KW_STATIC_ASSERT '(' const_expr ')' ';' { // This alternative version of static_assert was introduced in C++17. 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", @3); } } ; friend_declaration: KW_FRIEND { CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("temp"), V_public); push_scope(new_scope); } declaration { delete current_scope; pop_scope(); } ; storage_class: empty { $$ = 0; } | KW_CONST storage_class { // This isn't really a storage class, but it helps with parsing. $$ = $2 | (int)CPPInstance::SC_const; } | KW_EXTERN storage_class { $$ = $2 | (int)CPPInstance::SC_extern; } | KW_EXTERN SIMPLE_STRING storage_class { $$ = $3 | (int)CPPInstance::SC_extern; if ($2 == "C") { $$ |= (int)CPPInstance::SC_c_binding; } else if ($2 == "C++") { $$ &= ~(int)CPPInstance::SC_c_binding; } else { yywarning("Ignoring unknown linkage type \"" + $2 + "\"", @2); } } | KW_STATIC storage_class { $$ = $2 | (int)CPPInstance::SC_static; } | KW_INLINE storage_class { $$ = $2 | (int)CPPInstance::SC_inline; } | KW_VIRTUAL storage_class { $$ = $2 | (int)CPPInstance::SC_virtual; } | KW_EXPLICIT storage_class { $$ = $2 | (int)CPPInstance::SC_explicit; } | KW_REGISTER storage_class { $$ = $2 | (int)CPPInstance::SC_register; } | KW_VOLATILE storage_class { $$ = $2 | (int)CPPInstance::SC_volatile; } | KW_MUTABLE storage_class { $$ = $2 | (int)CPPInstance::SC_mutable; } | KW_CONSTEXPR storage_class { $$ = $2 | (int)CPPInstance::SC_constexpr; } | KW_BLOCKING storage_class { $$ = $2 | (int)CPPInstance::SC_blocking; } | KW_EXTENSION storage_class { $$ = $2 | (int)CPPInstance::SC_extension; } | KW_THREAD_LOCAL storage_class { $$ = $2 | (int)CPPInstance::SC_thread_local; } | '[' '[' attribute_specifiers ']' ']' storage_class { // Ignore attribute specifiers for now. $$ = $6; } ; attribute_specifiers: attribute_specifier | attribute_specifier ',' attribute_specifiers ; attribute_specifier: name | name '(' formal_parameter_list ')' ; type_like_declaration: storage_class var_type_decl { // We don't need to push/pop type, because we can't nest // type_like_declaration. if ($2->as_type_declaration()) { current_type = $2->as_type_declaration()->_type; } else { current_type = $2->as_type(); } push_storage_class($1); } multiple_instance_identifiers { pop_storage_class(); } | storage_class type_decl ';' { // We don't really care about the storage class here. In fact, it's // not actually legal to define a class or struct using a particular // storage class, but we require it just to help yacc out in its // parsing. current_scope->add_declaration($2, global_scope, current_lexer, @2); } | storage_class constructor_prototype maybe_initialize_or_constructor_body { if ($2 != (CPPInstance *)NULL) { $2->_storage_class |= (current_storage_class | $1); current_scope->add_declaration($2, global_scope, current_lexer, @2); $2->set_initializer($3); } } | storage_class function_prototype maybe_initialize_or_function_body { if ($2 != (CPPInstance *)NULL) { $2->_storage_class |= (current_storage_class | $1); current_scope->add_declaration($2, global_scope, current_lexer, @2); $2->set_initializer($3); } } | using_declaration /* We don't need to include a rule for variables that point to functions, because we get those from the function_prototype definition. */ ; multiple_instance_identifiers: instance_identifier_and_maybe_trailing_return_type maybe_initialize_or_function_body { if (current_storage_class & CPPInstance::SC_const) { $1->add_modifier(IIT_const); } CPPInstance *inst = new CPPInstance(current_type, $1, current_storage_class, @1.file); inst->set_initializer($2); current_scope->add_declaration(inst, global_scope, current_lexer, @1); } | instance_identifier_and_maybe_trailing_return_type maybe_initialize ',' multiple_instance_identifiers { if (current_storage_class & CPPInstance::SC_const) { $1->add_modifier(IIT_const); } CPPInstance *inst = new CPPInstance(current_type, $1, current_storage_class, @1.file); inst->set_initializer($2); current_scope->add_declaration(inst, global_scope, current_lexer, @1); } ; typedef_declaration: storage_class var_type_decl { // We don't need to push/pop type, because we can't nest // multiple_var_declarations. if ($2->as_type_declaration()) { current_type = $2->as_type_declaration()->_type; } else { current_type = $2->as_type(); } push_storage_class($1); } typedef_instance_identifiers { pop_storage_class(); } | storage_class function_prototype maybe_initialize_or_function_body { if ($2 != (CPPDeclaration *)NULL) { CPPInstance *inst = $2->as_instance(); if (inst != (CPPInstance *)NULL) { inst->_storage_class |= (current_storage_class | $1); current_scope->add_declaration(inst, global_scope, current_lexer, @2); CPPTypedefType *typedef_type = new CPPTypedefType(inst->_type, inst->_ident, current_scope); current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @2); } } } ; typedef_instance_identifiers: instance_identifier_and_maybe_trailing_return_type maybe_initialize_or_function_body { if (current_storage_class & CPPInstance::SC_const) { $1->add_modifier(IIT_const); } CPPType *target_type = current_type; CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file); current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @1); } | instance_identifier_and_maybe_trailing_return_type maybe_initialize ',' typedef_instance_identifiers { if (current_storage_class & CPPInstance::SC_const) { $1->add_modifier(IIT_const); } CPPType *target_type = current_type; CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file); current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @1); } ; constructor_prototype: /* Functions with implicit return types, and constructors */ IDENTIFIER '(' { push_scope($1->get_scope(current_scope, global_scope)); } function_parameter_list ')' function_post { CPPType *type; if ($1->get_simple_name() == current_scope->get_simple_name() || $1->get_simple_name() == string("~") + current_scope->get_simple_name()) { // This is a constructor, and has no return. type = new CPPSimpleType(CPPSimpleType::T_void); } else { // This isn't a constructor, so it has an implicit return type of // int. yywarning("function has no return type, assuming int", @1); type = new CPPSimpleType(CPPSimpleType::T_int); } pop_scope(); CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($1); ii->add_func_modifier($4, $6); $$ = new CPPInstance(type, ii, 0, @1.file); } | TYPENAME_IDENTIFIER '(' { push_scope($1->get_scope(current_scope, global_scope)); } function_parameter_list ')' function_post { pop_scope(); CPPType *type; if ($1->get_simple_name() == current_scope->get_simple_name()) { // This is a constructor, and has no return. type = new CPPSimpleType(CPPSimpleType::T_void); } else { // This isn't a constructor, so it has an implicit return type of // int. type = new CPPSimpleType(CPPSimpleType::T_int); } CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($1); ii->add_func_modifier($4, $6); $$ = new CPPInstance(type, ii, 0, @1.file); } ; function_prototype: /* Destructors */ '~' name '(' { push_scope($2->get_scope(current_scope, global_scope)); } function_parameter_list ')' function_post { pop_scope(); if ($2->is_scoped()) { yyerror("Invalid destructor name: ~" + $2->get_fully_scoped_name(), @2); } else { CPPIdentifier *ident = new CPPIdentifier("~" + $2->get_simple_name(), @2); delete $2; CPPType *type; type = new CPPSimpleType(CPPSimpleType::T_void); CPPInstanceIdentifier *ii = new CPPInstanceIdentifier(ident); ii->add_func_modifier($5, $7); $$ = new CPPInstance(type, ii, 0, @2.file); } } /* This is a special case: a function pointer declaration that looks at first a lot like a constructor declaration. This is provided to help yacc sort out the differences. It isn't an ideal solution, because it doesn't catch a lot of subtle variants on this form--but this will get at least the 99% most common uses. */ | TYPENAME_IDENTIFIER '(' '*' instance_identifier ')' '(' { push_scope($4->get_scope(current_scope, global_scope)); } function_parameter_list ')' function_post maybe_trailing_return_type { pop_scope(); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); if (type == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert(type != NULL); CPPInstanceIdentifier *ii = $4; ii->add_modifier(IIT_pointer); ii->add_func_modifier($8, $10); $$ = new CPPInstance(type, ii, 0, @1.file); } | TYPENAME_IDENTIFIER '(' SCOPING '*' instance_identifier ')' '(' { push_scope($5->get_scope(current_scope, global_scope)); } function_parameter_list ')' function_post maybe_trailing_return_type { pop_scope(); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); if (type == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert(type != NULL); CPPInstanceIdentifier *ii = $5; ii->add_scoped_pointer_modifier($3); ii->add_func_modifier($9, $11); $$ = new CPPInstance(type, ii, 0, @1.file); } /* Typecast operators */ | KW_OPERATOR type not_paren_formal_parameter_identifier '(' { if ($1 != NULL) { push_scope($1->get_scope(current_scope, global_scope)); } } function_parameter_list ')' function_post { if ($1 != NULL) { pop_scope(); } // We use formal_parameter_identifier, because that can match a type // name with or without an identifier, but especially without, which // is what follows the keyword "operator" in a typecast function. // As an added bonus, the type of the formal_parameter will be the // typecast type, i.e. the return type of the typecast function. // We give typecast operators the name "operator typecast ", // where is a simple name of the type to be typecast. Use // the method's return type to determine the full type description. string name = "operator typecast " + $2->get_simple_name(); CPPIdentifier *ident = $1; if (ident == NULL) { ident = new CPPIdentifier(name, @2); } else { ident->add_name(name); } $$ = CPPInstance::make_typecast_function (new CPPInstance($2, $3, 0, @3.file), ident, $6, $8); } | KW_OPERATOR KW_CONST type not_paren_formal_parameter_identifier '(' { if ($1 != NULL) { push_scope($1->get_scope(current_scope, global_scope)); } } function_parameter_list ')' function_post { if ($1 != NULL) { pop_scope(); } CPPIdentifier *ident = $1; if (ident == NULL) { ident = new CPPIdentifier("operator typecast", @4); } else { ident->add_name("operator typecast"); } $4->add_modifier(IIT_const); $$ = CPPInstance::make_typecast_function (new CPPInstance($3, $4, 0, @4.file), ident, $7, $9); } /* Not actually a function prototype, but maybe a template instantiation. Just included here (instead of somewhere else) to avoid shift/reduce conflicts. */ | IDENTIFIER { CPPDeclaration *decl = $1->find_symbol(current_scope, global_scope, current_lexer); if (decl != (CPPDeclaration *)NULL) { $$ = decl->as_instance(); } else { $$ = (CPPInstance *)NULL; } } ; function_post: empty { $$ = 0; } | function_post KW_CONST { $$ = $1 | (int)CPPFunctionType::F_const_method; } | function_post KW_VOLATILE { $$ = $1 | (int)CPPFunctionType::F_volatile_method; } | function_post KW_NOEXCEPT { $$ = $1 | (int)CPPFunctionType::F_noexcept; } /* | function_post KW_NOEXCEPT '(' const_expr ')' { CPPExpression::Result result = $4->evaluate(); if (result._type == CPPExpression::RT_error) { yywarning("noexcept requires a constant expression", @4); } else if (result.as_boolean()) { $$ = $1 | (int)CPPFunctionType::F_noexcept; } }*/ | function_post KW_FINAL { $$ = $1 | (int)CPPFunctionType::F_final; } | function_post KW_OVERRIDE { $$ = $1 | (int)CPPFunctionType::F_override; } | function_post '&' { $$ = $1 | (int)CPPFunctionType::F_lvalue_method; } | function_post ANDAND { $$ = $1 | (int)CPPFunctionType::F_rvalue_method; } | function_post KW_MUTABLE { // Used for lambdas, currently ignored. $$ = $1; } | function_post KW_CONSTEXPR { // Used for lambdas in C++17, currently ignored. $$ = $1; } | function_post KW_THROW '(' ')' { $$ = $1; } | function_post KW_THROW '(' name ')' { $$ = $1; } | function_post KW_THROW '(' name ELLIPSIS ')' { $$ = $1; } /* | function_post '[' '[' attribute_specifiers ']' ']' { $$ = $1; }*/ ; function_operator: '!' { $$ = "!"; } | '~' { $$ = "~"; } | '*' { $$ = "*"; } | '/' { $$ = "/"; } | '%' { $$ = "%"; } | '+' { $$ = "+"; } | '-' { $$ = "-"; } | '|' { $$ = "|"; } | '&' { $$ = "&"; } | '^' { $$ = "^"; } | OROR { $$ = "||"; } | ANDAND { $$ = "&&"; } | EQCOMPARE { $$ = "=="; } | NECOMPARE { $$ = "!="; } | LECOMPARE { $$ = "<="; } | GECOMPARE { $$ = ">="; } | '<' { $$ = "<"; } | '>' { $$ = ">"; } | LSHIFT { $$ = "<<"; } | RSHIFT { $$ = ">>"; } | '=' { $$ = "="; } | ',' { $$ = ","; } | PLUSPLUS { $$ = "++"; } | MINUSMINUS { $$ = "--"; } | TIMESEQUAL { $$ = "*="; } | DIVIDEEQUAL { $$ = "/="; } | MODEQUAL { $$ = "%="; } | PLUSEQUAL { $$ = "+="; } | MINUSEQUAL { $$ = "-="; } | OREQUAL { $$ = "|="; } | ANDEQUAL { $$ = "&="; } | XOREQUAL { $$ = "^="; } | LSHIFTEQUAL { $$ = "<<="; } | RSHIFTEQUAL { $$ = ">>="; } | POINTSAT { $$ = "->"; } | '[' ']' { $$ = "[]"; } | '(' ')' { $$ = "()"; } | KW_NEW { $$ = "new"; } | KW_DELETE { $$ = "delete"; } ; more_template_declaration: type_like_declaration | template_declaration ; template_declaration: KW_TEMPLATE { push_scope(new CPPTemplateScope(current_scope)); } '<' template_formal_parameters '>' more_template_declaration { pop_scope(); } | KW_TEMPLATE type_like_declaration ; template_formal_parameters: empty | template_nonempty_formal_parameters ; template_nonempty_formal_parameters: template_formal_parameter { CPPTemplateScope *ts = current_scope->as_template_scope(); assert(ts != NULL); ts->add_template_parameter($1); } | template_nonempty_formal_parameters ',' template_formal_parameter { CPPTemplateScope *ts = current_scope->as_template_scope(); assert(ts != NULL); ts->add_template_parameter($3); } ; typename_keyword: KW_CLASS | KW_TYPENAME ; template_formal_parameter: typename_keyword { $$ = CPPType::new_type(new CPPClassTemplateParameter((CPPIdentifier *)NULL)); } | typename_keyword name { $$ = CPPType::new_type(new CPPClassTemplateParameter($2)); } | typename_keyword name '=' full_type { $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4)); } | typename_keyword ELLIPSIS { CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter((CPPIdentifier *)NULL); ctp->_packed = true; $$ = CPPType::new_type(ctp); } | typename_keyword ELLIPSIS name { CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($3); ctp->_packed = true; $$ = CPPType::new_type(ctp); } | template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize { CPPInstance *inst = new CPPInstance($1, $2, 0, @2.file); inst->set_initializer($3); $$ = inst; } | KW_CONST template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize { $3->add_modifier(IIT_const); CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file); inst->set_initializer($4); $$ = inst; } | template_formal_parameter_type parameter_pack_identifier { CPPInstance *inst = new CPPInstance($1, $2, 0, @2.file); $$ = inst; } | KW_CONST template_formal_parameter_type parameter_pack_identifier { $3->add_modifier(IIT_const); CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file); $$ = inst; } ; template_formal_parameter_type: simple_type { $$ = CPPType::new_type($1); } | IDENTIFIER { yywarning("Not a type: " + $1->get_fully_scoped_name(), @1); $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); if ($$ == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert($$ != NULL); } | TYPEPACK_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); if ($$ == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert($$ != NULL); } ; instance_identifier: name_no_final { $$ = new CPPInstanceIdentifier($1); } | KW_OPERATOR function_operator { // For an operator function. We implement this simply by building a // ficticious name for the function; in other respects it's just // like a regular function. CPPIdentifier *ident = $1; if (ident == NULL) { ident = new CPPIdentifier("operator "+$2, @2); } else { 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 { $$ = $2; $$->add_modifier(IIT_const); } | KW_VOLATILE instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_volatile); } | '*' instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | ANDAND instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' instance_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | instance_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } | '(' instance_identifier ')' { $$ = $2; $$->add_modifier(IIT_paren); } | instance_identifier '(' { // Create a scope for this function (in case it is a function) CPPScope *scope = new CPPScope($1->get_scope(current_scope, global_scope), CPPNameComponent(""), V_private); // It still needs to be able to pick up any template arguments, if this is // a definition for a method template. Add a fake "using" declaration to // accomplish this. scope->_using.insert(current_scope); push_scope(scope); } formal_parameter_list ')' function_post { pop_scope(); $$ = $1; if ($4->is_parameter_expr() && $6 == 0) { // Oops, this must have been an instance declaration with a // parameter list, not a function prototype. $$->add_initializer_modifier($4); } else { // This was (probably) a function prototype. $$->add_func_modifier($4, $6); } } ; instance_identifier_and_maybe_trailing_return_type: instance_identifier maybe_trailing_return_type { // This is handled a bit awkwardly right now. Ideally it'd be wrapped // up in the instance_identifier rule, but then more needs to happen in // order to avoid shift/reduce conflicts. if ($2 != NULL) { $1->add_trailing_return_type($2); } $$ = $1; } | instance_identifier ':' INTEGER { // Bitfield definition. $1->_bit_width = $3; $$ = $1; } ; maybe_trailing_return_type: empty { $$ = NULL; } | POINTSAT predefined_type empty_instance_identifier { $$ = $3->unroll_type($2); } | POINTSAT KW_CONST predefined_type empty_instance_identifier { $4->add_modifier(IIT_const); $$ = $4->unroll_type($3); } ; function_parameter_list: empty { $$ = new CPPParameterList; } | ELLIPSIS { $$ = new CPPParameterList; $$->_includes_ellipsis = true; } | function_parameters { $$ = $1; } | function_parameters ',' ELLIPSIS { $$ = $1; $$->_includes_ellipsis = true; } | function_parameters ELLIPSIS { $$ = $1; $$->_includes_ellipsis = true; } ; function_parameters: function_parameter { $$ = new CPPParameterList; $$->_parameters.push_back($1); } | function_parameters ',' function_parameter { $$ = $1; $$->_parameters.push_back($3); } ; formal_parameter_list: empty { $$ = new CPPParameterList; } | ELLIPSIS { $$ = new CPPParameterList; $$->_includes_ellipsis = true; } | formal_parameters { $$ = $1; } | formal_parameters ',' ELLIPSIS { $$ = $1; $$->_includes_ellipsis = true; } | formal_parameters ELLIPSIS { $$ = $1; $$->_includes_ellipsis = true; } ; formal_parameters: formal_parameter { $$ = new CPPParameterList; $$->_parameters.push_back($1); } | formal_parameters ',' formal_parameter { $$ = $1; $$->_parameters.push_back($3); } ; template_parameter_maybe_initialize: empty { $$ = (CPPExpression *)NULL; } | '=' no_angle_bracket_const_expr { $$ = $2; } ; maybe_initialize: empty { $$ = (CPPExpression *)NULL; } | '=' const_expr { $$ = $2; } ; maybe_initialize_or_constructor_body: ';' { $$ = (CPPExpression *)NULL; } | '{' code '}' { $$ = (CPPExpression *)NULL; } | ':' constructor_inits '{' code '}' { $$ = (CPPExpression *)NULL; } | '=' KW_DEFAULT ';' { $$ = new CPPExpression(CPPExpression::get_default()); } | '=' KW_DELETE ';' { $$ = new CPPExpression(CPPExpression::get_delete()); } ; maybe_initialize_or_function_body: ';' { $$ = (CPPExpression *)NULL; } | '{' code '}' { $$ = (CPPExpression *)NULL; } | '=' const_expr ';' { $$ = $2; } | '=' KW_DEFAULT ';' { $$ = new CPPExpression(CPPExpression::get_default()); } | '=' KW_DELETE ';' { $$ = new CPPExpression(CPPExpression::get_delete()); } | '=' '{' structure_init '}' { $$ = (CPPExpression *)NULL; } ; structure_init: empty | structure_init_body | structure_init_body ',' ; structure_init_body: const_expr { } | '{' structure_init '}' | structure_init_body ',' const_expr | structure_init_body ',' '{' structure_init '}' ; function_parameter: type formal_parameter_identifier maybe_initialize { $$ = new CPPInstance($1, $2, 0, @2.file); $$->set_initializer($3); } | KW_CONST type formal_parameter_identifier maybe_initialize { $3->add_modifier(IIT_const); $$ = new CPPInstance($2, $3, 0, @3.file); $$->set_initializer($4); } | KW_CONST KW_REGISTER type formal_parameter_identifier maybe_initialize { $4->add_modifier(IIT_const); $$ = new CPPInstance($3, $4, 0, @3.file); $$->set_initializer($5); } | type_pack parameter_pack_identifier maybe_initialize { $$ = new CPPInstance($1, $2, 0, @2.file); $$->set_initializer($3); } | KW_CONST type_pack parameter_pack_identifier maybe_initialize { $3->add_modifier(IIT_const); $$ = new CPPInstance($2, $3, 0, @3.file); $$->set_initializer($4); } | KW_CONST KW_REGISTER type_pack parameter_pack_identifier maybe_initialize { $4->add_modifier(IIT_const); $$ = new CPPInstance($3, $4, 0, @3.file); $$->set_initializer($5); } | KW_REGISTER function_parameter { $$ = $2; } ; /* A "formal parameter" is like a function parameter, except that it parses * instance declarations (that look like functions declaration) as well, and * as such accepts constexpr parameters. */ formal_parameter: function_parameter { $$ = $1; } | formal_const_expr { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_parameter)); $$ = new CPPInstance(type, "expr"); $$->set_initializer($1); } ; not_paren_formal_parameter_identifier: empty { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); } | name_no_final { $$ = new CPPInstanceIdentifier($1); } | KW_CONST not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | KW_VOLATILE not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_volatile); } | '*' not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | ANDAND not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' not_paren_formal_parameter_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | not_paren_formal_parameter_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } ; formal_parameter_identifier: empty { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); } | name_no_final { $$ = new CPPInstanceIdentifier($1); } | KW_CONST formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | KW_VOLATILE formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_volatile); } | '*' formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | ANDAND formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' formal_parameter_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | formal_parameter_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } | '(' formal_parameter_identifier ')' '(' function_parameter_list ')' function_post { $$ = $2; $$->add_modifier(IIT_paren); $$->add_func_modifier($5, $7); } | '(' formal_parameter_identifier ')' { $$ = $2; $$->add_modifier(IIT_paren); } ; parameter_pack_identifier: ELLIPSIS { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); $$->_packed = true; } | ELLIPSIS name { $$ = new CPPInstanceIdentifier($2); $$->_packed = true; } | KW_CONST parameter_pack_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | KW_VOLATILE parameter_pack_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_volatile); } | '*' parameter_pack_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' parameter_pack_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | ANDAND parameter_pack_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' parameter_pack_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | parameter_pack_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } | '(' parameter_pack_identifier ')' '(' function_parameter_list ')' function_post { $$ = $2; $$->add_modifier(IIT_paren); $$->add_func_modifier($5, $7); } | '(' parameter_pack_identifier ')' { $$ = $2; $$->add_modifier(IIT_paren); } ; not_paren_empty_instance_identifier: empty { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); } | ELLIPSIS { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); $$->_packed = true; } | ELLIPSIS name { $$ = new CPPInstanceIdentifier($2); $$->_packed = true; } | KW_CONST not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | KW_VOLATILE not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_volatile); } | '*' not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | ANDAND not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' not_paren_empty_instance_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | not_paren_empty_instance_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } ; empty_instance_identifier: empty { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); } | ELLIPSIS { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); $$->_packed = true; } | ELLIPSIS name { $$ = new CPPInstanceIdentifier($2); $$->_packed = true; } | KW_CONST empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | KW_VOLATILE empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_volatile); } | '*' not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | ANDAND not_paren_empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' not_paren_empty_instance_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | not_paren_empty_instance_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } | '(' function_parameter_list ')' function_post maybe_trailing_return_type { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); $$->add_modifier(IIT_paren); $$->add_func_modifier($2, $4, $5); } | '(' '*' not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post maybe_trailing_return_type { $$ = $3; $$->add_modifier(IIT_pointer); $$->add_modifier(IIT_paren); $$->add_func_modifier($6, $8, $9); } | '(' '&' not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post maybe_trailing_return_type { $$ = $3; $$->add_modifier(IIT_reference); $$->add_modifier(IIT_paren); $$->add_func_modifier($6, $8, $9); } | '(' ANDAND not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post maybe_trailing_return_type { $$ = $3; $$->add_modifier(IIT_rvalue_reference); $$->add_modifier(IIT_paren); $$->add_func_modifier($6, $8, $9); } ; type: simple_type { $$ = CPPType::new_type($1); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); if ($$ == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert($$ != NULL); } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPTBDType($2)); } | anonymous_struct { $$ = CPPType::new_type($1); } | named_struct { $$ = CPPType::new_type($1); } | enum { $$ = CPPType::new_type($1); } | struct_keyword name { CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_type(et); } $$ = et; } } | enum_keyword name_no_final ':' enum_element_type { CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_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); } } | KW_UNDERLYING_TYPE '(' full_type ')' { CPPEnumType *enum_type = $3->as_enum_type(); if (enum_type == NULL) { yyerror("an enumeration type is required", @3); $$ = $3; } else { $$ = enum_type->get_underlying_type(); } } | KW_AUTO { $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); } ; type_pack: TYPEPACK_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); if ($$ == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert($$ != NULL); } ; type_decl: simple_type { $$ = CPPType::new_type($1); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); if ($$ == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert($$ != NULL); } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPTBDType($2)); } | anonymous_struct { $$ = CPPType::new_type($1); } | named_struct { $$ = new CPPTypeDeclaration(CPPType::new_type($1)); } | enum { $$ = new CPPTypeDeclaration(CPPType::new_type($1)); } | struct_keyword name { CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_type(et); } $$ = et; } } | enum_keyword name_no_final ':' enum_element_type { CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_type(et); } $$ = et; } } | enum_keyword name { yywarning(string("C++ does not permit forward declaration of untyped enum ") + $2->get_fully_scoped_name(), @1); CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_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); } } | KW_UNDERLYING_TYPE '(' full_type ')' { CPPEnumType *enum_type = $3->as_enum_type(); if (enum_type == NULL) { yyerror("an enumeration type is required", @3); $$ = $3; } else { $$ = enum_type->get_underlying_type(); } } | KW_AUTO { $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); } ; predefined_type: simple_type { $$ = CPPType::new_type($1); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); if ($$ == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert($$ != NULL); } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPTBDType($2)); } | struct_keyword name { CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_type(et); } $$ = et; } } | enum_keyword name { CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_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); } } | KW_UNDERLYING_TYPE '(' full_type ')' { CPPEnumType *enum_type = $3->as_enum_type(); if (enum_type == NULL) { yyerror("an enumeration type is required", @3); $$ = $3; } else { $$ = enum_type->get_underlying_type(); } } | KW_AUTO { $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); } ; var_type_decl: type_decl { $$ = $1; } | IDENTIFIER { yyerror(string("unknown type '") + $1->get_fully_scoped_name() + "'", @1); $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); } full_type: type empty_instance_identifier { $$ = $2->unroll_type($1); } | KW_CONST type empty_instance_identifier { $3->add_modifier(IIT_const); $$ = $3->unroll_type($2); } | type_pack empty_instance_identifier { $$ = $2->unroll_type($1); } | KW_CONST type_pack empty_instance_identifier { $3->add_modifier(IIT_const); $$ = $3->unroll_type($2); } ; anonymous_struct: struct_keyword '{' { CPPVisibility starting_vis = ($1 == CPPExtensionType::T_class) ? V_private : V_public; CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("anon"), starting_vis); CPPStructType *st = new CPPStructType($1, NULL, current_scope, new_scope, @1.file); new_scope->set_struct_type(st); push_scope(new_scope); push_struct(st); } cpp '}' { $$ = current_struct; current_struct->_incomplete = false; pop_struct(); pop_scope(); } ; named_struct: struct_keyword name_no_final { CPPVisibility starting_vis = ($1 == CPPExtensionType::T_class) ? V_private : V_public; CPPScope *scope = $2->get_scope(current_scope, global_scope, current_lexer); if (scope == NULL) { scope = current_scope; } CPPScope *new_scope = new CPPScope(scope, $2->_names.back(), starting_vis); CPPStructType *st = new CPPStructType($1, $2, current_scope, new_scope, @1.file); new_scope->set_struct_type(st); current_scope->define_extension_type(st); push_scope(new_scope); push_struct(st); } maybe_final maybe_class_derivation '{' cpp '}' { $$ = current_struct; current_struct->_incomplete = false; pop_struct(); pop_scope(); } ; maybe_final: empty | KW_FINAL { current_struct->_final = true; } ; maybe_class_derivation: empty | class_derivation ; class_derivation: ':' base_specification | class_derivation ',' base_specification ; base_specification: class_derivation_name { current_struct->append_derivation($1, V_unknown, false); } | KW_PUBLIC class_derivation_name { current_struct->append_derivation($2, V_public, false); } | KW_PROTECTED class_derivation_name { current_struct->append_derivation($2, V_protected, false); } | KW_PRIVATE class_derivation_name { current_struct->append_derivation($2, V_private, false); } | KW_VIRTUAL KW_PUBLIC class_derivation_name { current_struct->append_derivation($3, V_public, true); } | KW_VIRTUAL KW_PROTECTED class_derivation_name { current_struct->append_derivation($3, V_protected, true); } | KW_VIRTUAL KW_PRIVATE class_derivation_name { current_struct->append_derivation($3, V_private, true); } | KW_PUBLIC KW_VIRTUAL class_derivation_name { current_struct->append_derivation($3, V_public, true); } | KW_PROTECTED KW_VIRTUAL class_derivation_name { current_struct->append_derivation($3, V_protected, true); } | KW_PRIVATE KW_VIRTUAL class_derivation_name { current_struct->append_derivation($3, V_private, true); } ; enum: enum_decl '{' enum_body '}' { $$ = current_enum; current_enum = NULL; } ; enum_decl: enum_keyword ':' enum_element_type { current_enum = new CPPEnumType($1, NULL, $3, current_scope, NULL, @1.file); } | enum_keyword { current_enum = new CPPEnumType($1, NULL, current_scope, NULL, @1.file); } | enum_keyword name_no_final ':' enum_element_type { CPPScope *new_scope = new CPPScope(current_scope, $2->_names.back(), V_public); current_enum = new CPPEnumType($1, $2, $4, current_scope, new_scope, @1.file); } | enum_keyword name_no_final { CPPScope *new_scope = new CPPScope(current_scope, $2->_names.back(), V_public); current_enum = new CPPEnumType($1, $2, current_scope, new_scope, @1.file); } ; enum_element_type: simple_int_type { $$ = CPPType::new_type($1); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); } ; enum_body_trailing_comma: empty | enum_body_trailing_comma name ',' { assert(current_enum != NULL); current_enum->add_element($2->get_simple_name(), NULL, current_lexer, @2); } | enum_body_trailing_comma name '=' const_expr ',' { assert(current_enum != NULL); current_enum->add_element($2->get_simple_name(), $4, current_lexer, @2); }; enum_body: enum_body_trailing_comma | enum_body_trailing_comma name { assert(current_enum != NULL); current_enum->add_element($2->get_simple_name(), NULL, current_lexer, @2); } | enum_body_trailing_comma name '=' const_expr { assert(current_enum != NULL); current_enum->add_element($2->get_simple_name(), $4, current_lexer, @2); } ; enum_keyword: KW_ENUM { $$ = CPPExtensionType::T_enum; } | KW_ENUM KW_CLASS { $$ = CPPExtensionType::T_enum_class; } | KW_ENUM KW_STRUCT { $$ = CPPExtensionType::T_enum_struct; } ; struct_keyword: KW_CLASS { $$ = CPPExtensionType::T_class; } | KW_STRUCT { $$ = CPPExtensionType::T_struct; } | KW_UNION { $$ = CPPExtensionType::T_union; } ; namespace_declaration: KW_NAMESPACE name '{' { CPPScope *scope = $2->find_scope(current_scope, global_scope, current_lexer); if (scope == NULL) { // This must be a new namespace declaration. CPPScope *parent_scope = $2->get_scope(current_scope, global_scope, current_lexer); if (parent_scope == NULL) { parent_scope = current_scope; } scope = new CPPScope(parent_scope, $2->_names.back(), V_public); } CPPNamespace *nspace = new CPPNamespace($2, scope, @1.file); current_scope->add_declaration(nspace, global_scope, current_lexer, @1); current_scope->define_namespace(nspace); push_scope(scope); } cpp '}' { pop_scope(); } | KW_INLINE KW_NAMESPACE name '{' { CPPScope *scope = $3->find_scope(current_scope, global_scope, current_lexer); if (scope == NULL) { // This must be a new namespace declaration. CPPScope *parent_scope = $3->get_scope(current_scope, global_scope, current_lexer); if (parent_scope == NULL) { parent_scope = current_scope; } scope = new CPPScope(parent_scope, $3->_names.back(), V_public); } CPPNamespace *nspace = new CPPNamespace($3, scope, @2.file); nspace->_is_inline = true; current_scope->add_declaration(nspace, global_scope, current_lexer, @2); current_scope->define_namespace(nspace); push_scope(scope); } cpp '}' { pop_scope(); } | KW_NAMESPACE '{' cpp '}' | KW_INLINE KW_NAMESPACE '{' cpp '}' ; using_declaration: KW_USING name ';' { CPPUsing *using_decl = new CPPUsing($2, false, @1.file); current_scope->add_declaration(using_decl, global_scope, current_lexer, @1); current_scope->add_using(using_decl, global_scope, current_lexer); } | KW_USING name '=' full_type ';' { // This is really just an alternative way to declare a typedef. CPPTypedefType *typedef_type = new CPPTypedefType($4, $2, current_scope); typedef_type->_using = true; current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @1); } | KW_USING KW_NAMESPACE name ';' { CPPUsing *using_decl = new CPPUsing($3, true, @1.file); current_scope->add_declaration(using_decl, global_scope, current_lexer, @1); current_scope->add_using(using_decl, global_scope, current_lexer); } ; simple_type: simple_int_type | simple_float_type | simple_void_type ; simple_int_type: KW_BOOL { $$ = new CPPSimpleType(CPPSimpleType::T_bool); } | KW_CHAR { $$ = new CPPSimpleType(CPPSimpleType::T_char); } | KW_WCHAR_T { $$ = new CPPSimpleType(CPPSimpleType::T_wchar_t); } | KW_CHAR16_T { $$ = new CPPSimpleType(CPPSimpleType::T_char16_t); } | KW_CHAR32_T { $$ = new CPPSimpleType(CPPSimpleType::T_char32_t); } | KW_SHORT { $$ = new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_short); } | KW_LONG { $$ = new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_long); } | KW_UNSIGNED { $$ = new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_unsigned); } | KW_SIGNED { $$ = new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_signed); } | KW_INT { $$ = new CPPSimpleType(CPPSimpleType::T_int); } | KW_SHORT simple_int_type { $$ = $2; $$->_flags |= CPPSimpleType::F_short; } | KW_LONG simple_int_type { $$ = $2; if ($$->_flags & CPPSimpleType::F_long) { $$->_flags |= CPPSimpleType::F_longlong; } else { $$->_flags |= CPPSimpleType::F_long; } } | KW_UNSIGNED simple_int_type { $$ = $2; $$->_flags |= CPPSimpleType::F_unsigned; } | KW_SIGNED simple_int_type { $$ = $2; $$->_flags |= CPPSimpleType::F_signed; } ; simple_float_type: KW_FLOAT { $$ = new CPPSimpleType(CPPSimpleType::T_float); } | KW_DOUBLE { $$ = new CPPSimpleType(CPPSimpleType::T_double); } | KW_LONG KW_DOUBLE { $$ = new CPPSimpleType(CPPSimpleType::T_double, CPPSimpleType::F_long); } ; simple_void_type: KW_VOID { $$ = new CPPSimpleType(CPPSimpleType::T_void); } ; /* We don't care what the code is. We just want to be sure we match up opening and closing braces properly. For anything else, we'll accept just token salad. */ code: { current_lexer->_resolve_identifiers = false; } code_block { current_lexer->_resolve_identifiers = true; } ; code_block: empty | code_block element ; element: REAL | INTEGER | SIMPLE_STRING | STRING_LITERAL | CUSTOM_LITERAL | CHAR_TOK | IDENTIFIER | TYPENAME_IDENTIFIER | TYPEPACK_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_ALIGNAS | KW_ALIGNOF | KW_AUTO | KW_BOOL | KW_CATCH | KW_CHAR | KW_CHAR16_T | KW_CHAR32_T | KW_CLASS | KW_CONST | KW_CONSTEXPR | KW_CONST_CAST | KW_DECLTYPE | KW_DEFAULT | KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM | KW_EXTERN | KW_EXPLICIT | KW_FALSE | KW_FINAL | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO | KW_IF | KW_INLINE | KW_INT | KW_LONG | KW_MUTABLE | KW_NAMESPACE | KW_NEW | KW_NULLPTR | KW_OPERATOR | KW_OVERRIDE | KW_PRIVATE | KW_PROTECTED | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_REINTERPRET_CAST | KW_RETURN | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_ASSERT | KW_STATIC_CAST | KW_STRUCT | KW_TEMPLATE | KW_THREAD_LOCAL | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF | KW_TYPEID | KW_TYPENAME | KW_UNDERLYING_TYPE | KW_UNION | KW_UNSIGNED | KW_USING | KW_VIRTUAL | KW_VOID | KW_VOLATILE | KW_WCHAR_T | KW_WHILE { } | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%' | '<' | '>' | '(' | ')' | '.' | ',' | ';' | ':' | '[' | ']' | '?' | '{' code_block '}' ; optional_const_expr: empty { $$ = (CPPExpression *)NULL; } | const_expr { $$ = $1; } ; optional_const_expr_comma: empty { $$ = (CPPExpression *)NULL; } | const_expr_comma { $$ = $1; } ; const_expr_comma: const_expr { $$ = $1; } | const_expr_comma ',' const_expr { $$ = new CPPExpression(',', $1, $3); } ; no_angle_bracket_const_expr: const_operand { $$ = $1; } | '(' full_type ')' no_angle_bracket_const_expr %prec UNARY { $$ = new CPPExpression(CPPExpression::typecast_op($2, $4)); } | KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_static_cast)); } | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_dynamic_cast)); } | KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_const_cast)); } | KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_reinterpret_cast)); } | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_func($3)); } | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4)); } | KW_ALIGNOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::alignof_func($3)); } | '!' no_angle_bracket_const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NOT, $2); } | '~' no_angle_bracket_const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NEGATE, $2); } | '-' no_angle_bracket_const_expr %prec UNARY { $$ = new CPPExpression(UNARY_MINUS, $2); } | '+' no_angle_bracket_const_expr %prec UNARY { $$ = new CPPExpression(UNARY_PLUS, $2); } | '*' no_angle_bracket_const_expr %prec UNARY { $$ = new CPPExpression(UNARY_STAR, $2); } | '&' no_angle_bracket_const_expr %prec UNARY { $$ = new CPPExpression(UNARY_REF, $2); } | no_angle_bracket_const_expr '*' no_angle_bracket_const_expr { $$ = new CPPExpression('*', $1, $3); } | no_angle_bracket_const_expr '/' no_angle_bracket_const_expr { $$ = new CPPExpression('/', $1, $3); } | no_angle_bracket_const_expr '%' no_angle_bracket_const_expr { $$ = new CPPExpression('%', $1, $3); } | no_angle_bracket_const_expr '+' no_angle_bracket_const_expr { $$ = new CPPExpression('+', $1, $3); } | no_angle_bracket_const_expr '-' no_angle_bracket_const_expr { $$ = new CPPExpression('-', $1, $3); } | no_angle_bracket_const_expr '|' no_angle_bracket_const_expr { $$ = new CPPExpression('|', $1, $3); } | no_angle_bracket_const_expr '^' no_angle_bracket_const_expr { $$ = new CPPExpression('^', $1, $3); } | no_angle_bracket_const_expr '&' no_angle_bracket_const_expr { $$ = new CPPExpression('&', $1, $3); } | no_angle_bracket_const_expr OROR no_angle_bracket_const_expr { $$ = new CPPExpression(OROR, $1, $3); } | no_angle_bracket_const_expr ANDAND no_angle_bracket_const_expr { $$ = new CPPExpression(ANDAND, $1, $3); } | no_angle_bracket_const_expr EQCOMPARE no_angle_bracket_const_expr { $$ = new CPPExpression(EQCOMPARE, $1, $3); } | no_angle_bracket_const_expr NECOMPARE no_angle_bracket_const_expr { $$ = new CPPExpression(NECOMPARE, $1, $3); } | no_angle_bracket_const_expr LECOMPARE no_angle_bracket_const_expr { $$ = new CPPExpression(LECOMPARE, $1, $3); } | no_angle_bracket_const_expr GECOMPARE no_angle_bracket_const_expr { $$ = new CPPExpression(GECOMPARE, $1, $3); } | no_angle_bracket_const_expr LSHIFT no_angle_bracket_const_expr { $$ = new CPPExpression(LSHIFT, $1, $3); } | no_angle_bracket_const_expr RSHIFT no_angle_bracket_const_expr { $$ = new CPPExpression(RSHIFT, $1, $3); } | no_angle_bracket_const_expr '?' no_angle_bracket_const_expr ':' no_angle_bracket_const_expr { $$ = new CPPExpression('?', $1, $3, $5); } | no_angle_bracket_const_expr '[' const_expr ']' { $$ = new CPPExpression('[', $1, $3); } | no_angle_bracket_const_expr '(' const_expr_comma ')' { $$ = new CPPExpression('f', $1, $3); } | no_angle_bracket_const_expr '(' ')' { $$ = new CPPExpression('f', $1); } | no_angle_bracket_const_expr '.' no_angle_bracket_const_expr { $$ = new CPPExpression('.', $1, $3); } | no_angle_bracket_const_expr POINTSAT no_angle_bracket_const_expr { $$ = new CPPExpression(POINTSAT, $1, $3); } | '(' const_expr_comma ')' { $$ = $2; } ; const_expr: const_operand { $$ = $1; } | '(' full_type ')' const_expr %prec UNARY { $$ = new CPPExpression(CPPExpression::typecast_op($2, $4)); } | KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_static_cast)); } | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_dynamic_cast)); } | KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_const_cast)); } | KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_reinterpret_cast)); } | TYPENAME_IDENTIFIER '(' optional_const_expr_comma ')' { // A constructor call. CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); if (type == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert(type != NULL); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_INT '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_CHAR '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_WCHAR_T '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_CHAR16_T '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_CHAR32_T '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_BOOL '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_SHORT '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_short)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_LONG '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_long)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_UNSIGNED '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_unsigned)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_SIGNED '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_signed)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_FLOAT '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_float)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_DOUBLE '(' optional_const_expr_comma ')' { CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_func($3)); } | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4)); } | KW_ALIGNOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::alignof_func($3)); } | KW_NEW predefined_type %prec UNARY { $$ = new CPPExpression(CPPExpression::new_op($2)); } | KW_NEW predefined_type '(' optional_const_expr_comma ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::new_op($2, $4)); } | KW_TYPEID '(' full_type ')' { CPPIdentifier ident(""); ident.add_name("std"); ident.add_name("type_info"); CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); if (!std_type_info) { yywarning("cannot use typeid before including ", @1); } $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); } | KW_TYPEID '(' const_expr ')' { CPPIdentifier ident(""); ident.add_name("std"); ident.add_name("type_info"); CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); if (!std_type_info) { yywarning("cannot use typeid before including ", @1); } $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); } | '!' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NOT, $2); } | '~' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NEGATE, $2); } | '-' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_MINUS, $2); } | '+' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_PLUS, $2); } | '*' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_STAR, $2); } | '&' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_REF, $2); } | const_expr '*' const_expr { $$ = new CPPExpression('*', $1, $3); } | const_expr '/' const_expr { $$ = new CPPExpression('/', $1, $3); } | const_expr '%' const_expr { $$ = new CPPExpression('%', $1, $3); } | const_expr '+' const_expr { $$ = new CPPExpression('+', $1, $3); } | const_expr '-' const_expr { $$ = new CPPExpression('-', $1, $3); } | const_expr '|' const_expr { $$ = new CPPExpression('|', $1, $3); } | const_expr '^' const_expr { $$ = new CPPExpression('^', $1, $3); } | const_expr '&' const_expr { $$ = new CPPExpression('&', $1, $3); } | const_expr OROR const_expr { $$ = new CPPExpression(OROR, $1, $3); } | const_expr ANDAND const_expr { $$ = new CPPExpression(ANDAND, $1, $3); } | const_expr EQCOMPARE const_expr { $$ = new CPPExpression(EQCOMPARE, $1, $3); } | const_expr NECOMPARE const_expr { $$ = new CPPExpression(NECOMPARE, $1, $3); } | const_expr LECOMPARE const_expr { $$ = new CPPExpression(LECOMPARE, $1, $3); } | const_expr GECOMPARE const_expr { $$ = new CPPExpression(GECOMPARE, $1, $3); } | const_expr '<' const_expr { $$ = new CPPExpression('<', $1, $3); } | const_expr '>' const_expr { $$ = new CPPExpression('>', $1, $3); } | const_expr LSHIFT const_expr { $$ = new CPPExpression(LSHIFT, $1, $3); } | const_expr RSHIFT const_expr { $$ = new CPPExpression(RSHIFT, $1, $3); } | const_expr '?' const_expr ':' const_expr { $$ = new CPPExpression('?', $1, $3, $5); } | const_expr '[' const_expr ']' { $$ = new CPPExpression('[', $1, $3); } | const_expr '(' const_expr_comma ')' { $$ = new CPPExpression('f', $1, $3); } | const_expr '(' ')' { $$ = new CPPExpression('f', $1); } | const_expr '.' const_expr { $$ = new CPPExpression('.', $1, $3); } | const_expr POINTSAT const_expr { $$ = new CPPExpression(POINTSAT, $1, $3); } | '(' const_expr_comma ')' { $$ = $2; } ; const_operand: INTEGER { $$ = new CPPExpression($1); } | KW_TRUE { $$ = new CPPExpression(true); } | KW_FALSE { $$ = new CPPExpression(false); } | CHAR_TOK { $$ = new CPPExpression($1); } | REAL { $$ = new CPPExpression($1); } | string_literal { $$ = $1; } | CUSTOM_LITERAL { $$ = $1; } | IDENTIFIER { $$ = new CPPExpression($1, current_scope, global_scope, current_lexer); } | KW_FINAL { // A variable named "final". C++11 explicitly permits this. CPPIdentifier *ident = new CPPIdentifier("final", @1); $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); } | KW_OVERRIDE { // A variable named "override". C++11 explicitly permits this. CPPIdentifier *ident = new CPPIdentifier("override", @1); $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); } | KW_NULLPTR { $$ = new CPPExpression(CPPExpression::get_nullptr()); } | '[' capture_list ']' function_post maybe_trailing_return_type '{' code '}' { $2->_flags = $4; $2->_return_type = $5; $$ = new CPPExpression(CPPExpression::lambda($2)); } | '[' capture_list ']' '(' function_parameter_list ')' function_post maybe_trailing_return_type '{' code '}' { $2->_parameters = $5; $2->_flags = $7; $2->_return_type = $8; $$ = new CPPExpression(CPPExpression::lambda($2)); } | KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_HAS_VIRTUAL_DESTRUCTOR, $3)); } | KW_IS_ABSTRACT '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ABSTRACT, $3)); } | KW_IS_BASE_OF '(' full_type ',' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3, $5)); } | KW_IS_CLASS '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3)); } | KW_IS_CONSTRUCTIBLE '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3)); } | KW_IS_CONSTRUCTIBLE '(' full_type ',' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3, $5)); } | KW_IS_CONVERTIBLE_TO '(' full_type ',' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONVERTIBLE_TO, $3, $5)); } | KW_IS_DESTRUCTIBLE '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_DESTRUCTIBLE, $3)); } | KW_IS_EMPTY '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_EMPTY, $3)); } | KW_IS_ENUM '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ENUM, $3)); } | KW_IS_FINAL '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FINAL, $3)); } | KW_IS_FUNDAMENTAL '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FUNDAMENTAL, $3)); } | KW_IS_POD '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POD, $3)); } | KW_IS_POLYMORPHIC '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POLYMORPHIC, $3)); } | KW_IS_STANDARD_LAYOUT '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_STANDARD_LAYOUT, $3)); } | KW_IS_TRIVIAL '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_TRIVIAL, $3)); } | KW_IS_UNION '(' full_type ')' { $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_UNION, $3)); } ; /* This is used for a const_expr as a "formal parameter", which really means an instance declaration using a parameter list (which looks a lot like a function prototype). It differs from const_expr mainly in that it forbids some expressions unless they are parenthesized, to avoid shift/reduce conflicts with the actual formal parameter definition. */ formal_const_expr: formal_const_operand { $$ = $1; } | '(' full_type ')' const_expr %prec UNARY { $$ = new CPPExpression(CPPExpression::typecast_op($2, $4)); } | KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_static_cast)); } | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_dynamic_cast)); } | KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_const_cast)); } | KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_reinterpret_cast)); } | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_func($3)); } | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4)); } | KW_ALIGNOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::alignof_func($3)); } | KW_NEW predefined_type %prec UNARY { $$ = new CPPExpression(CPPExpression::new_op($2)); } | KW_NEW predefined_type '(' optional_const_expr_comma ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::new_op($2, $4)); } | KW_TYPEID '(' full_type ')' { CPPIdentifier ident(""); ident.add_name("std"); ident.add_name("type_info"); CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); if (!std_type_info) { yywarning("cannot use typeid before including ", @1); } $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); } | KW_TYPEID '(' const_expr ')' { CPPIdentifier ident(""); ident.add_name("std"); ident.add_name("type_info"); CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); if (!std_type_info) { yywarning("cannot use typeid before including ", @1); } $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); } | '!' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NOT, $2); } | '~' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NEGATE, $2); } | '-' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_MINUS, $2); } | '+' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_PLUS, $2); } | '&' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_REF, $2); } | formal_const_expr '*' const_expr { $$ = new CPPExpression('*', $1, $3); } | formal_const_expr '/' const_expr { $$ = new CPPExpression('/', $1, $3); } | formal_const_expr '%' const_expr { $$ = new CPPExpression('%', $1, $3); } | formal_const_expr '+' const_expr { $$ = new CPPExpression('+', $1, $3); } | formal_const_expr '-' const_expr { $$ = new CPPExpression('-', $1, $3); } | formal_const_expr '|' const_expr { $$ = new CPPExpression('|', $1, $3); } | formal_const_expr '^' const_expr { $$ = new CPPExpression('^', $1, $3); } | formal_const_expr '&' const_expr { $$ = new CPPExpression('&', $1, $3); } | formal_const_expr OROR const_expr { $$ = new CPPExpression(OROR, $1, $3); } | formal_const_expr ANDAND const_expr { $$ = new CPPExpression(ANDAND, $1, $3); } | formal_const_expr EQCOMPARE const_expr { $$ = new CPPExpression(EQCOMPARE, $1, $3); } | formal_const_expr NECOMPARE const_expr { $$ = new CPPExpression(NECOMPARE, $1, $3); } | formal_const_expr LECOMPARE const_expr { $$ = new CPPExpression(LECOMPARE, $1, $3); } | formal_const_expr GECOMPARE const_expr { $$ = new CPPExpression(GECOMPARE, $1, $3); } | formal_const_expr '<' const_expr { $$ = new CPPExpression('<', $1, $3); } | formal_const_expr '>' const_expr { $$ = new CPPExpression('>', $1, $3); } | formal_const_expr LSHIFT const_expr { $$ = new CPPExpression(LSHIFT, $1, $3); } | formal_const_expr RSHIFT const_expr { $$ = new CPPExpression(RSHIFT, $1, $3); } | formal_const_expr '?' const_expr ':' const_expr { $$ = new CPPExpression('?', $1, $3, $5); } | formal_const_expr '[' const_expr ']' { $$ = new CPPExpression('[', $1, $3); } | formal_const_expr '(' const_expr_comma ')' { $$ = new CPPExpression('f', $1, $3); } | formal_const_expr '(' ')' { $$ = new CPPExpression('f', $1); } | formal_const_expr '.' const_expr { $$ = new CPPExpression('.', $1, $3); } | formal_const_expr POINTSAT const_expr { $$ = new CPPExpression(POINTSAT, $1, $3); } | '(' const_expr_comma ')' { $$ = $2; } ; formal_const_operand: INTEGER { $$ = new CPPExpression($1); } | KW_TRUE { $$ = new CPPExpression(true); } | KW_FALSE { $$ = new CPPExpression(false); } | CHAR_TOK { $$ = new CPPExpression($1); } | REAL { $$ = new CPPExpression($1); } | string_literal { $$ = $1; } | CUSTOM_LITERAL { $$ = $1; } | IDENTIFIER { $$ = new CPPExpression($1, current_scope, global_scope, current_lexer); } | KW_FINAL { // A variable named "final". C++11 explicitly permits this. CPPIdentifier *ident = new CPPIdentifier("final", @1); $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); } | KW_OVERRIDE { // A variable named "override". C++11 explicitly permits this. CPPIdentifier *ident = new CPPIdentifier("override", @1); $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); } | KW_NULLPTR { $$ = new CPPExpression(CPPExpression::get_nullptr()); } ; /* The contents of the [] list preceding a lambda expression. */ capture_list: empty { $$ = new CPPClosureType(); } | '=' { $$ = new CPPClosureType(CPPClosureType::CT_by_value); } | '&' { $$ = new CPPClosureType(CPPClosureType::CT_by_reference); } | capture { $$ = new CPPClosureType(); $$->_captures.push_back(*$1); delete $1; } | capture_list ',' capture { $$ = $1; $$->_captures.push_back(*$3); delete $3; } ; capture: '&' name { $$ = new CPPClosureType::Capture; $$->_name = $2->get_simple_name(); $$->_type = CPPClosureType::CT_by_reference; } | '&' name ELLIPSIS { $$ = new CPPClosureType::Capture; $$->_name = $2->get_simple_name(); $$->_type = CPPClosureType::CT_by_reference; } | name { $$ = new CPPClosureType::Capture; $$->_name = $1->get_simple_name(); if ($$->_name == "this") { $$->_type = CPPClosureType::CT_by_reference; } else { $$->_type = CPPClosureType::CT_by_value; } } | '*' name { $$ = new CPPClosureType::Capture; $$->_name = $2->get_simple_name(); $$->_type = CPPClosureType::CT_by_value; if ($$->_name != "this") { yywarning("only capture name 'this' may be preceded by an asterisk", @2); } } ; class_derivation_name: name { CPPType *type = $1->find_type(current_scope, global_scope, true); if (type == NULL) { type = CPPType::new_type(new CPPTBDType($1)); } $$ = type; } | struct_keyword name { CPPType *type = $2->find_type(current_scope, global_scope, true, current_lexer); if (type == NULL) { type = CPPType::new_type(new CPPTBDType($2)); } $$ = type; } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPTBDType($2)); } | name ELLIPSIS { CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($1); ctp->_packed = true; $$ = CPPType::new_type(ctp); } ; /* typedefname: TYPENAME_IDENTIFIER { CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); if (type == NULL) { yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); } assert(type != NULL); $$ = type; } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPTBDType($2)); } ; */ /* Note that we should also accept "final" and "override" as valid names, * according to C++11. */ name: IDENTIFIER { $$ = $1; } | TYPENAME_IDENTIFIER { $$ = $1; } | TYPEPACK_IDENTIFIER { $$ = $1; } | KW_FINAL { $$ = new CPPIdentifier("final", @1); } | KW_OVERRIDE { $$ = new CPPIdentifier("override", @1); } | KW_SIGNED { // This is not a keyword in Python, so it is useful to be able to use this // in MAKE_PROPERTY definitions, etc. $$ = new CPPIdentifier("signed", @1); } | KW_FLOAT { $$ = new CPPIdentifier("float", @1); } | KW_PUBLIC { $$ = new CPPIdentifier("public", @1); } | KW_PRIVATE { $$ = new CPPIdentifier("private", @1); } | KW_STATIC { $$ = new CPPIdentifier("static", @1); } ; /* A variant on name that's used for structs, where we disallow final * to disambiguate the case of struct A final {}; */ name_no_final: IDENTIFIER { $$ = $1; } | TYPENAME_IDENTIFIER { $$ = $1; } | TYPEPACK_IDENTIFIER { $$ = $1; } | KW_OVERRIDE { $$ = new CPPIdentifier("override", @1); } ; 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_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; } ; empty: ;