mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
4026 lines
101 KiB
Plaintext
4026 lines
101 KiB
Plaintext
/**
|
|
* @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<CPPScope *> last_scopes;
|
|
static vector<int> last_storage_classes;
|
|
static vector<CPPStructType *> 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 <u.real> REAL
|
|
%token <u.integer> INTEGER
|
|
%token <u.integer> CHAR_TOK
|
|
%token <str> SIMPLE_STRING SIMPLE_IDENTIFIER
|
|
%token <u.expr> STRING_LITERAL CUSTOM_LITERAL
|
|
%token <u.identifier> IDENTIFIER TYPENAME_IDENTIFIER TYPEPACK_IDENTIFIER SCOPING
|
|
%token <u.type> 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 <u.integer> storage_class
|
|
%type <u.instance> constructor_prototype
|
|
%type <u.instance> function_prototype
|
|
%type <u.integer> function_post
|
|
%type <str> function_operator
|
|
%type <u.decl> template_formal_parameter
|
|
%type <u.type> template_formal_parameter_type
|
|
%type <u.inst_ident> instance_identifier
|
|
%type <u.inst_ident> instance_identifier_and_maybe_trailing_return_type
|
|
%type <u.param_list> function_parameter_list
|
|
%type <u.param_list> function_parameters
|
|
%type <u.param_list> formal_parameter_list
|
|
%type <u.param_list> formal_parameters
|
|
%type <u.closure_type> capture_list
|
|
%type <u.capture> capture
|
|
%type <u.expr> template_parameter_maybe_initialize
|
|
%type <u.expr> maybe_initialize
|
|
%type <u.expr> maybe_initialize_or_constructor_body
|
|
%type <u.expr> maybe_initialize_or_function_body
|
|
%type <u.instance> function_parameter
|
|
%type <u.instance> formal_parameter
|
|
%type <u.inst_ident> not_paren_formal_parameter_identifier
|
|
%type <u.inst_ident> formal_parameter_identifier
|
|
%type <u.inst_ident> parameter_pack_identifier
|
|
%type <u.inst_ident> not_paren_empty_instance_identifier
|
|
%type <u.inst_ident> empty_instance_identifier
|
|
%type <u.type> type type_pack
|
|
%type <u.decl> type_decl
|
|
%type <u.decl> var_type_decl
|
|
%type <u.type> predefined_type
|
|
%type <u.type> full_type
|
|
%type <u.struct_type> anonymous_struct
|
|
%type <u.struct_type> named_struct
|
|
%type <u.enum_type> enum
|
|
%type <u.extension_enum> enum_keyword
|
|
%type <u.extension_enum> struct_keyword
|
|
%type <u.simple_type> simple_type
|
|
%type <u.simple_type> simple_int_type
|
|
%type <u.simple_type> simple_float_type
|
|
%type <u.simple_type> simple_void_type
|
|
%type <u.type> class_derivation_name
|
|
%type <u.type> enum_element_type
|
|
%type <u.type> maybe_trailing_return_type
|
|
/*%type <u.type> typedefname*/
|
|
%type <u.identifier> name
|
|
%type <u.identifier> name_no_final
|
|
%type <u.expr> string_literal
|
|
|
|
/* We need to treat KW_OPERATOR as a scopable keyword. */
|
|
%type <u.identifier> KW_OPERATOR
|
|
|
|
%type <u.expr> optional_const_expr
|
|
%type <u.expr> optional_const_expr_comma
|
|
%type <u.expr> const_expr_comma
|
|
%type <u.expr> no_angle_bracket_const_expr
|
|
%type <u.expr> const_expr
|
|
%type <u.expr> const_operand
|
|
%type <u.expr> formal_const_expr
|
|
%type <u.expr> 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 <name>",
|
|
// where <name> 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 <typeinfo>", @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 <typeinfo>", @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 <typeinfo>", @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 <typeinfo>", @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:
|
|
;
|