// Filename: cppBison.y // Created by: drose (16Jan99) // //////////////////////////////////////////////////////////////////// %{ #include "cppBisonDefs.h" #include "cppParser.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 "cppTypedef.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 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); } static void yyerror(const string &msg, YYLTYPE &loc) { current_lexer->error(msg, loc.first_line, loc.first_column); } static void yywarning(const string &msg, YYLTYPE &loc) { current_lexer->warning(msg, loc.first_line, loc.first_column); } 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. */ %pure_parser %token REAL %token INTEGER %token CHAR_TOK %token STRING SIMPLE_IDENTIFIER %token IDENTIFIER TYPENAME_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_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_BEGIN_PUBLISH %token KW_BLOCKING %token KW_BOOL %token KW_CATCH %token KW_CHAR %token KW_WCHAR_T %token KW_CLASS %token KW_CONST %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_FLOAT %token KW_FRIEND %token KW_FOR %token KW_GOTO %token KW_IF %token KW_INLINE %token KW_INT %token KW_LONG %token KW_LONGLONG %token KW_MAKE_PROPERTY %token KW_MAKE_SEQ %token KW_MUTABLE %token KW_NAMESPACE %token KW_NEW %token KW_OPERATOR %token KW_PRIVATE %token KW_PROTECTED %token KW_PUBLIC %token KW_REGISTER %token KW_RETURN %token KW_SHORT %token KW_SIGNED %token KW_SIZEOF %token KW_STATIC %token KW_STATIC_CAST %token KW_STRUCT %token KW_TEMPLATE %token KW_THROW %token KW_TRUE %token KW_TRY %token KW_TYPEDEF %token KW_TYPENAME %token KW_UNION %token KW_UNSIGNED %token KW_USING %token KW_VIRTUAL %token KW_VOID %token KW_VOLATILE %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 function_prototype %type function_post %type function_operator %type template_formal_parameter %type template_formal_parameter_type %type instance_identifier %type formal_parameter_list %type formal_parameters %type template_parameter_maybe_initialize %type maybe_initialize %type maybe_initialize_or_function_body %type formal_parameter %type not_paren_formal_parameter_identifier %type formal_parameter_identifier %type empty_instance_identifier %type type %type type_decl %type predefined_type %type full_type %type anonymous_struct %type named_struct %type anonymous_enum %type named_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 typedefname*/ %type name %type string /* 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_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; } ; /* 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 | using_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 '(' 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(), @1); } 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 '(' 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(), @1); } CPPDeclaration *setter = $7->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: " + $7->get_fully_scoped_name(), @1); } CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), setter->as_function_group(), current_scope, @1.file); current_scope->add_declaration(make_property, global_scope, current_lexer, @1); } | KW_MAKE_SEQ '(' name ',' name ',' name ')' ';' { 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); } ; 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; } | storage_class KW_EXTERN { $$ = $1 | (int)CPPInstance::SC_extern; } | storage_class KW_EXTERN string { $$ = $1 | (int)CPPInstance::SC_extern; if ($3 == "C") { $$ |= (int)CPPInstance::SC_c_binding; } else if ($3 == "C++") { $$ &= ~(int)CPPInstance::SC_c_binding; } else { yywarning("Ignoring unknown linkage type \"" + $3 + "\"", @3); } } | storage_class KW_STATIC { $$ = $1 | (int)CPPInstance::SC_static; } | storage_class KW_INLINE { $$ = $1 | (int)CPPInstance::SC_inline; } | storage_class KW_VIRTUAL { $$ = $1 | (int)CPPInstance::SC_virtual; } | storage_class KW_EXPLICIT { $$ = $1 | (int)CPPInstance::SC_explicit; } | storage_class KW_VOLATILE { $$ = $1 | (int)CPPInstance::SC_volatile; } | storage_class KW_MUTABLE { $$ = $1 | (int)CPPInstance::SC_mutable; } | storage_class KW_REGISTER { $$ = $1 | (int)CPPInstance::SC_register; } | storage_class KW_BLOCKING { $$ = $1 | (int)CPPInstance::SC_blocking; } | storage_class KW_EXTENSION { $$ = $1 | (int)CPPInstance::SC_extension; } ; type_like_declaration: multiple_var_declaration { /* multiple_var_declaration adds itself to the scope. */ } | 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 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); } } ; multiple_var_declaration: storage_class 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); } multiple_instance_identifiers { pop_storage_class(); } | storage_class KW_CONST type { // We don't need to push/pop type, because we can't nest // multiple_var_declarations. current_type = $3; push_storage_class($1); } multiple_const_instance_identifiers { pop_storage_class(); } /* 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 maybe_initialize_or_function_body { 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 maybe_initialize ',' multiple_instance_identifiers { 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); } ; multiple_const_instance_identifiers: instance_identifier maybe_initialize_or_function_body { $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 maybe_initialize ',' multiple_const_instance_identifiers { $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 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 KW_CONST type { // We don't need to push/pop type, because we can't nest // multiple_var_declarations. current_type = $3; push_storage_class($1); } typedef_const_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); current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @2); } } } ; typedef_instance_identifiers: instance_identifier maybe_initialize_or_function_body { CPPInstance *inst = new CPPInstance(current_type, $1, current_storage_class, @1.file); inst->set_initializer($2); current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1); } | instance_identifier maybe_initialize ',' typedef_instance_identifiers { CPPInstance *inst = new CPPInstance(current_type, $1, current_storage_class, @1.file); inst->set_initializer($2); current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1); } ; typedef_const_instance_identifiers: instance_identifier maybe_initialize_or_function_body { $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(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1); } | instance_identifier maybe_initialize ',' typedef_const_instance_identifiers { $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(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1); } ; function_prototype: /* Functions with implicit return types, and constructors */ IDENTIFIER '(' { push_scope($1->get_scope(current_scope, global_scope)); } formal_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); } | TYPENAME_IDENTIFIER '(' { push_scope($1->get_scope(current_scope, global_scope)); } formal_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); } /* Destructors */ | '~' name '(' { push_scope($2->get_scope(current_scope, global_scope)); } formal_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.file); 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)); } formal_parameter_list ')' function_post { pop_scope(); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); 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)); } formal_parameter_list ')' function_post { pop_scope(); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); 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)); } } formal_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, @1.file); } 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)); } } formal_parameter_list ')' function_post { if ($1 != NULL) { pop_scope(); } CPPIdentifier *ident = $1; if (ident == NULL) { ident = new CPPIdentifier("operator typecast", @1.file); } 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; } | KW_CONST { $$ = (int)CPPFunctionType::F_const_method; } | function_post KW_THROW '(' ')' { $$ = $1; } | function_post KW_THROW '(' name ')' { $$ = $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(); } ; 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); } ; template_formal_parameter: KW_CLASS name { $$ = CPPType::new_type(new CPPClassTemplateParameter($2)); } | KW_CLASS name '=' full_type { $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4)); } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPClassTemplateParameter($2)); } | KW_TYPENAME name '=' full_type { $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4)); } | 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: 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); assert($$ != NULL); } ; instance_identifier: name { $$ = 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.file); } else { ident->_names.push_back("operator "+$2); } $$ = new CPPInstanceIdentifier(ident); } | KW_CONST instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | '*' instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | SCOPING '*' instance_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | instance_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } | instance_identifier ':' INTEGER { // bitfield definition. We ignore the bitfield for now. $$ = $1; } | '(' instance_identifier ')' { $$ = $2; $$->add_modifier(IIT_paren); } | instance_identifier '(' { push_scope($1->get_scope(current_scope, global_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); } } ; 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_function_body: ';' { $$ = (CPPExpression *)NULL; } | '{' code '}' { $$ = (CPPExpression *)NULL; } | ':' constructor_inits '{' code '}' { $$ = (CPPExpression *)NULL; } | '=' const_expr ';' { $$ = $2; } | '=' '{' 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 '}' ; formal_parameter: type formal_parameter_identifier maybe_initialize { $$ = new CPPInstance($1, $2, 0, @2.file); $$->set_initializer($3); } | IDENTIFIER formal_parameter_identifier maybe_initialize { yywarning("Not a type: " + $1->get_fully_scoped_name(), @1); CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); $$ = new CPPInstance(type, $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); } | 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); } | IDENTIFIER { $$ = new CPPInstanceIdentifier($1); } | TYPENAME_IDENTIFIER { $$ = new CPPInstanceIdentifier($1); } | KW_CONST not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | '*' not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' not_paren_formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_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); } | IDENTIFIER { $$ = new CPPInstanceIdentifier($1); } | TYPENAME_IDENTIFIER { $$ = new CPPInstanceIdentifier($1); } | KW_CONST formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | '*' formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' formal_parameter_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_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 ')' '(' formal_parameter_list ')' function_post { $$ = $2; $$->add_modifier(IIT_paren); $$->add_func_modifier($5, $7); } | '(' formal_parameter_identifier ')' { $$ = $2; $$->add_modifier(IIT_paren); } ; empty_instance_identifier: empty { $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL); } | KW_CONST empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_const); } | '*' empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_pointer); } | '&' empty_instance_identifier %prec UNARY { $$ = $2; $$->add_modifier(IIT_reference); } | SCOPING '*' empty_instance_identifier %prec UNARY { $$ = $3; $$->add_scoped_pointer_modifier($1); } | empty_instance_identifier '[' optional_const_expr ']' { $$ = $1; $$->add_array_modifier($3); } | '(' empty_instance_identifier ')' '(' formal_parameter_list ')' function_post { $$ = $2; $$->add_modifier(IIT_paren); $$->add_func_modifier($5, $7); } ; type: simple_type { $$ = CPPType::new_type($1); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); assert($$ != NULL); } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPTBDType($2)); } | anonymous_struct { $$ = CPPType::new_type($1); } | named_struct { $$ = CPPType::new_type($1); } | anonymous_enum { $$ = CPPType::new_type($1); } | named_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 { 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; } } ; type_decl: simple_type { $$ = CPPType::new_type($1); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); 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)); } | anonymous_enum { $$ = CPPType::new_type($1); } | named_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 { 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; } } ; predefined_type: simple_type { $$ = CPPType::new_type($1); } | TYPENAME_IDENTIFIER { $$ = $1->find_type(current_scope, global_scope, false, current_lexer); 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; } } ; full_type: type empty_instance_identifier { CPPInstance *inst = new CPPInstance($1, $2, 0, @1.file); $$ = inst->_type; delete inst; } | KW_CONST type empty_instance_identifier { $3->add_modifier(IIT_const); CPPInstance *inst = new CPPInstance($2, $3, 0, @1.file); $$ = inst->_type; delete inst; } ; 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 { 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_class_derivation '{' cpp '}' { $$ = current_struct; current_struct->_incomplete = false; pop_struct(); pop_scope(); } ; maybe_class_derivation: empty | class_derivation ; class_derivation: ':' base_specification | class_derivation ',' base_specification ; base_specification: 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); } ; anonymous_enum: enum_keyword '{' { current_enum = new CPPEnumType(NULL, current_scope, @1.file); } enum_body '}' { $$ = current_enum; current_enum = NULL; } ; named_enum: enum_keyword name '{' { current_enum = new CPPEnumType($2, current_scope, @1.file); } enum_body '}' { $$ = current_enum; current_enum = NULL; } ; enum_body: empty | enum_body_no_trailing_comma | enum_body_no_trailing_comma ',' ; enum_body_no_trailing_comma: name { assert(current_enum != NULL); current_enum->add_element($1->get_simple_name(), current_scope); } | name '=' const_expr { assert(current_enum != NULL); current_enum->add_element($1->get_simple_name(), current_scope, $3); } | enum_body_no_trailing_comma ',' name { assert(current_enum != NULL); current_enum->add_element($3->get_simple_name(), current_scope); } | enum_body_no_trailing_comma ',' name '=' const_expr { assert(current_enum != NULL); current_enum->add_element($3->get_simple_name(), current_scope, $5); } ; enum_keyword: KW_ENUM { $$ = CPPExtensionType::T_enum; } ; 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_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 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_SHORT { $$ = new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_short); } | KW_LONG { $$ = new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_long); } | KW_LONGLONG { $$ = new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_longlong); } | 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_LONG KW_FLOAT { $$ = new CPPSimpleType(CPPSimpleType::T_float, CPPSimpleType::F_long); } | KW_DOUBLE { $$ = new CPPSimpleType(CPPSimpleType::T_double); } | KW_LONG KW_LONG KW_FLOAT { $$ = new CPPSimpleType(CPPSimpleType::T_float, CPPSimpleType::F_longlong); } | 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 { } | STRING { } | 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_WCHAR_T | KW_CLASS | KW_CONST | 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_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 { } | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%' | '<' | '>' | '(' | ')' | '.' | ',' | ';' | ':' | '[' | ']' | '?' | '{' 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)); } | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6)); } | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_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 { 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); } } | '*' 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)); } | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6)); } | TYPENAME_IDENTIFIER '(' optional_const_expr_comma ')' { // A constructor call. CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); 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_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_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)); } | '!' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NOT, $2); } | '~' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NEGATE, $2); } | '-' 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); } } | '*' 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 { $$ = new CPPExpression($1); } | IDENTIFIER { $$ = new CPPExpression($1, current_scope, global_scope, current_lexer); } ; /* 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)); } | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' { $$ = new CPPExpression(CPPExpression::typecast_op($3, $6)); } | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_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)); } | '!' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NOT, $2); } | '~' const_expr %prec UNARY { $$ = new CPPExpression(UNARY_NEGATE, $2); } | '-' 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); } } | '&' 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 { $$ = new CPPExpression($1); } ; 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)); } ; /* typedefname: TYPENAME_IDENTIFIER { CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); assert(type != NULL); $$ = type; } | KW_TYPENAME name { $$ = CPPType::new_type(new CPPTBDType($2)); } ; */ name: IDENTIFIER { $$ = $1; } | TYPENAME_IDENTIFIER { $$ = $1; } ; string: STRING { $$ = $1; } | string STRING { $$ = $1 + $2; } ; empty: ;