panda3d/dtool/src/cppparser/cppBison.yxx

2817 lines
64 KiB
Plaintext

// Filename: cppBison.y
// Created by: drose (16Jan99)
//
////////////////////////////////////////////////////////////////////
%{
#include "cppBisonDefs.h"
#include "cppParser.h"
#include "cppExpression.h"
#include "cppSimpleType.h"
#include "cppExtensionType.h"
#include "cppStructType.h"
#include "cppEnumType.h"
#include "cppFunctionType.h"
#include "cppTBDType.h"
#include "cppMakeProperty.h"
#include "cppMakeSeq.h"
#include "cppParameterList.h"
#include "cppInstance.h"
#include "cppClassTemplateParameter.h"
#include "cppTemplateParameterList.h"
#include "cppInstanceIdentifier.h"
#include "cppTypedef.h"
#include "cppTypeDeclaration.h"
#include "cppVisibility.h"
#include "cppIdentifier.h"
#include "cppScope.h"
#include "cppTemplateScope.h"
#include "cppNamespace.h"
#include "cppUsing.h"
////////////////////////////////////////////////////////////////////
// Defining the interface to the parser.
////////////////////////////////////////////////////////////////////
CPPScope *current_scope = NULL;
CPPScope *global_scope = NULL;
CPPPreprocessor *current_lexer = NULL;
static CPPStructType *current_struct = NULL;
static CPPEnumType *current_enum = NULL;
static int current_storage_class = 0;
static CPPType *current_type = NULL;
static CPPExpression *current_expr = NULL;
static int publish_nest_level = 0;
static CPPVisibility publish_previous;
static YYLTYPE publish_loc;
static vector<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);
}
static void
yyerror(const string &msg, YYLTYPE &loc) {
current_lexer->error(msg, loc.first_line, loc.first_column);
}
static void
yywarning(const string &msg, YYLTYPE &loc) {
current_lexer->warning(msg, loc.first_line, loc.first_column);
}
static int
yylex(YYSTYPE *lval, YYLTYPE *lloc) {
CPPToken token = current_lexer->get_next_token();
*lval = token._lval;
*lloc = token._lloc;
return token._token;
}
void
parse_cpp(CPPParser *cp) {
CPPScope *old_scope = current_scope;
CPPScope *old_global_scope = global_scope;
CPPPreprocessor *old_lexer = current_lexer;
current_scope = cp;
global_scope = cp;
current_lexer = cp;
publish_nest_level = 0;
yyparse();
if (publish_nest_level != 0) {
yyerror("Unclosed __begin_publish", publish_loc);
publish_nest_level = 0;
}
current_scope = old_scope;
global_scope = old_global_scope;
current_lexer = old_lexer;
}
CPPExpression *
parse_const_expr(CPPPreprocessor *pp, CPPScope *new_current_scope,
CPPScope *new_global_scope) {
CPPScope *old_scope = current_scope;
CPPScope *old_global_scope = global_scope;
CPPPreprocessor *old_lexer = current_lexer;
CPPExpression *old_expr = current_expr;
current_scope = new_current_scope;
global_scope = new_global_scope;
current_expr = (CPPExpression *)NULL;
current_lexer = pp;
yyparse();
CPPExpression *result = current_expr;
current_scope = old_scope;
global_scope = old_global_scope;
current_lexer = old_lexer;
current_expr = old_expr;
return result;
}
CPPType *
parse_type(CPPPreprocessor *pp, CPPScope *new_current_scope,
CPPScope *new_global_scope) {
CPPScope *old_scope = current_scope;
CPPScope *old_global_scope = global_scope;
CPPPreprocessor *old_lexer = current_lexer;
CPPType *old_type = current_type;
current_scope = new_current_scope;
global_scope = new_global_scope;
current_type = (CPPType *)NULL;
current_lexer = pp;
yyparse();
CPPType *result = current_type;
current_scope = old_scope;
global_scope = old_global_scope;
current_lexer = old_lexer;
current_type = old_type;
return result;
}
static void
push_scope(CPPScope *new_scope) {
last_scopes.push_back(current_scope);
if (new_scope != NULL) {
current_scope = new_scope;
}
}
static void
pop_scope() {
assert(!last_scopes.empty());
current_scope = last_scopes.back();
last_scopes.pop_back();
}
static void
push_storage_class(int new_storage_class) {
last_storage_classes.push_back(current_storage_class);
current_storage_class = new_storage_class;
}
static void
pop_storage_class() {
assert(!last_storage_classes.empty());
current_storage_class = last_storage_classes.back();
last_storage_classes.pop_back();
}
static void
push_struct(CPPStructType *new_struct) {
last_structs.push_back(current_struct);
current_struct = new_struct;
}
static void
pop_struct() {
assert(!last_structs.empty());
current_struct = last_structs.back();
last_structs.pop_back();
}
%}
/* This is a bison-specific declaration to enable recursive calls to
yyparse(). It changes the calling sequence to yylex(), passing
pointers to the current yylval and yylloc. */
%pure_parser
%token <u.real> REAL
%token <u.integer> INTEGER
%token <u.integer> CHAR_TOK
%token <str> STRING SIMPLE_IDENTIFIER
%token <u.identifier> IDENTIFIER TYPENAME_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_STAR
%token UNARY_REF
%token POINTSAT
%token SCOPE
%token PLUSPLUS
%token MINUSMINUS
%token TIMESEQUAL
%token DIVIDEEQUAL
%token MODEQUAL
%token PLUSEQUAL
%token MINUSEQUAL
%token OREQUAL
%token ANDEQUAL
%token XOREQUAL
%token LSHIFTEQUAL
%token RSHIFTEQUAL
%token KW_BEGIN_PUBLISH
%token KW_BLOCKING
%token KW_BOOL
%token KW_CATCH
%token KW_CHAR
%token KW_WCHAR_T
%token KW_CLASS
%token KW_CONST
%token KW_DELETE
%token KW_DOUBLE
%token KW_DYNAMIC_CAST
%token KW_ELSE
%token KW_END_PUBLISH
%token KW_ENUM
%token KW_EXTENSION
%token KW_EXTERN
%token KW_EXPLICIT
%token KW_PUBLISHED
%token KW_FALSE
%token KW_FLOAT
%token KW_FRIEND
%token KW_FOR
%token KW_GOTO
%token KW_IF
%token KW_INLINE
%token KW_INT
%token KW_LONG
%token KW_LONGLONG
%token KW_MAKE_PROPERTY
%token KW_MAKE_SEQ
%token KW_MUTABLE
%token KW_NAMESPACE
%token KW_NEW
%token KW_OPERATOR
%token KW_PRIVATE
%token KW_PROTECTED
%token KW_PUBLIC
%token KW_REGISTER
%token KW_RETURN
%token KW_SHORT
%token KW_SIGNED
%token KW_SIZEOF
%token KW_STATIC
%token KW_STATIC_CAST
%token KW_STRUCT
%token KW_TEMPLATE
%token KW_THROW
%token KW_TRUE
%token KW_TRY
%token KW_TYPEDEF
%token KW_TYPENAME
%token KW_UNION
%token KW_UNSIGNED
%token KW_USING
%token KW_VIRTUAL
%token KW_VOID
%token KW_VOLATILE
%token KW_WHILE
/* These special tokens are used to set the starting state of the
parser. The lexer places the appropriate one of these on the head
of the input stream. */
%token START_CPP
%token START_CONST_EXPR
%token START_TYPE
%type <u.integer> storage_class
%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.param_list> formal_parameter_list
%type <u.param_list> formal_parameters
%type <u.expr> template_parameter_maybe_initialize
%type <u.expr> maybe_initialize
%type <u.expr> maybe_initialize_or_function_body
%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> empty_instance_identifier
%type <u.type> type
%type <u.decl> 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> anonymous_enum
%type <u.enum_type> named_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> typedefname*/
%type <u.identifier> name
%type <str> string
/* 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_BOOL
%left '{' ',' ';'
%nonassoc KW_THROW
%right ':'
%right '='
%right '?'
%left OROR
%left ANDAND
%left '|'
%left '^'
%left '&'
%left EQCOMPARE NECOMPARE
%left LECOMPARE GECOMPARE '<' '>'
%left LSHIFT RSHIFT
%left '+' '-'
%left '*' '/' '%'
%left POINTSAT_STAR DOT_STAR
%right UNARY PLUSPLUS MINUSMINUS '~'
%left POINTSAT '.' '(' '['
%right SCOPE
%nonassoc KW_NEW KW_DELETE KW_TRY KW_CATCH
%%
grammar:
START_CPP cpp
| START_CONST_EXPR const_expr
{
current_expr = $2;
}
| START_TYPE full_type
{
current_type = $2;
}
;
cpp:
empty
| cpp ';'
| cpp declaration
;
constructor_inits:
constructor_init
| constructor_inits ',' constructor_init
;
constructor_init:
name '(' optional_const_expr_comma ')'
{
delete $3;
}
;
/* This is principally for the syntax: extern "C" { ... }.
We use storage_class instead of simply KW_EXTERN to avoid
shift/reduce conflicts with yacc's limited differentiation
ability. */
extern_c:
storage_class '{'
{
push_storage_class((current_storage_class & ~CPPInstance::SC_c_binding) |
($1 & CPPInstance::SC_c_binding));
}
cpp '}'
{
pop_storage_class();
}
;
declaration:
type_like_declaration
| template_declaration
| extern_c
| namespace_declaration
| using_declaration
| friend_declaration
| KW_TYPEDEF typedef_declaration
| KW_BEGIN_PUBLISH
{
if (publish_nest_level != 0) {
yyerror("Unclosed __begin_publish", publish_loc);
publish_nest_level = 0;
current_scope->set_current_vis(V_public);
}
publish_previous = current_scope->get_current_vis();
publish_loc = @1;
publish_nest_level++;
current_scope->set_current_vis(V_published);
}
| KW_END_PUBLISH
{
if (publish_nest_level != 1) {
yyerror("Unmatched __end_publish", @1);
} else {
current_scope->set_current_vis(publish_previous);
}
publish_nest_level = 0;
}
| KW_PUBLISHED ':'
{
current_scope->set_current_vis(V_published);
}
| KW_PUBLIC ':'
{
if (publish_nest_level > 0) {
current_scope->set_current_vis(V_published);
} else {
current_scope->set_current_vis(V_public);
}
}
| KW_PROTECTED ':'
{
current_scope->set_current_vis(V_protected);
}
| KW_PRIVATE ':'
{
current_scope->set_current_vis(V_private);
}
| KW_MAKE_PROPERTY '(' IDENTIFIER ',' IDENTIFIER ')' ';'
{
CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
}
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), NULL, current_scope, @1.file);
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
}
| KW_MAKE_PROPERTY '(' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
{
CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
}
CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @1);
}
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
setter->as_function_group(),
current_scope, @1.file);
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
}
| KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
{
CPPMakeSeq *make_seq = new CPPMakeSeq($3->get_simple_name(), $5->get_simple_name(), $7->get_simple_name(), @1.file);
current_scope->add_declaration(make_seq, global_scope, current_lexer, @1);
}
;
friend_declaration:
KW_FRIEND
{
CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("temp"),
V_public);
push_scope(new_scope);
}
declaration
{
delete current_scope;
pop_scope();
}
;
storage_class:
empty
{
$$ = 0;
}
| storage_class KW_EXTERN
{
$$ = $1 | (int)CPPInstance::SC_extern;
}
| storage_class KW_EXTERN string
{
$$ = $1 | (int)CPPInstance::SC_extern;
if ($3 == "C") {
$$ |= (int)CPPInstance::SC_c_binding;
} else if ($3 == "C++") {
$$ &= ~(int)CPPInstance::SC_c_binding;
} else {
yywarning("Ignoring unknown linkage type \"" + $3 + "\"", @3);
}
}
| storage_class KW_STATIC
{
$$ = $1 | (int)CPPInstance::SC_static;
}
| storage_class KW_INLINE
{
$$ = $1 | (int)CPPInstance::SC_inline;
}
| storage_class KW_VIRTUAL
{
$$ = $1 | (int)CPPInstance::SC_virtual;
}
| storage_class KW_EXPLICIT
{
$$ = $1 | (int)CPPInstance::SC_explicit;
}
| storage_class KW_VOLATILE
{
$$ = $1 | (int)CPPInstance::SC_volatile;
}
| storage_class KW_MUTABLE
{
$$ = $1 | (int)CPPInstance::SC_mutable;
}
| storage_class KW_REGISTER
{
$$ = $1 | (int)CPPInstance::SC_register;
}
| storage_class KW_BLOCKING
{
$$ = $1 | (int)CPPInstance::SC_blocking;
}
| storage_class KW_EXTENSION
{
$$ = $1 | (int)CPPInstance::SC_extension;
}
;
type_like_declaration:
multiple_var_declaration
{
/* multiple_var_declaration adds itself to the scope. */
}
| storage_class type_decl ';'
{
// We don't really care about the storage class here. In fact, it's
// not actually legal to define a class or struct using a particular
// storage class, but we require it just to help yacc out in its
// parsing.
current_scope->add_declaration($2, global_scope, current_lexer, @2);
}
| storage_class function_prototype maybe_initialize_or_function_body
{
if ($2 != (CPPInstance *)NULL) {
$2->_storage_class |= (current_storage_class | $1);
current_scope->add_declaration($2, global_scope, current_lexer, @2);
$2->set_initializer($3);
}
}
;
multiple_var_declaration:
storage_class type_decl
{
// We don't need to push/pop type, because we can't nest
// multiple_var_declarations.
if ($2->as_type_declaration()) {
current_type = $2->as_type_declaration()->_type;
} else {
current_type = $2->as_type();
}
push_storage_class($1);
}
multiple_instance_identifiers
{
pop_storage_class();
}
| storage_class KW_CONST type
{
// We don't need to push/pop type, because we can't nest
// multiple_var_declarations.
current_type = $3;
push_storage_class($1);
}
multiple_const_instance_identifiers
{
pop_storage_class();
}
/* We don't need to include a rule for variables that point to
functions, because we get those from the function_prototype
definition. */
;
multiple_instance_identifiers:
instance_identifier maybe_initialize_or_function_body
{
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(inst, global_scope, current_lexer, @1);
}
| instance_identifier maybe_initialize ',' multiple_instance_identifiers
{
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(inst, global_scope, current_lexer, @1);
}
;
multiple_const_instance_identifiers:
instance_identifier maybe_initialize_or_function_body
{
$1->add_modifier(IIT_const);
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(inst, global_scope, current_lexer, @1);
}
| instance_identifier maybe_initialize ',' multiple_const_instance_identifiers
{
$1->add_modifier(IIT_const);
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(inst, global_scope, current_lexer, @1);
}
;
typedef_declaration:
storage_class type_decl
{
// We don't need to push/pop type, because we can't nest
// multiple_var_declarations.
if ($2->as_type_declaration()) {
current_type = $2->as_type_declaration()->_type;
} else {
current_type = $2->as_type();
}
push_storage_class($1);
}
typedef_instance_identifiers
{
pop_storage_class();
}
| storage_class KW_CONST type
{
// We don't need to push/pop type, because we can't nest
// multiple_var_declarations.
current_type = $3;
push_storage_class($1);
}
typedef_const_instance_identifiers
{
pop_storage_class();
}
| storage_class function_prototype maybe_initialize_or_function_body
{
if ($2 != (CPPDeclaration *)NULL) {
CPPInstance *inst = $2->as_instance();
if (inst != (CPPInstance *)NULL) {
inst->_storage_class |= (current_storage_class | $1);
current_scope->add_declaration(inst, global_scope, current_lexer, @2);
current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @2);
}
}
}
;
typedef_instance_identifiers:
instance_identifier maybe_initialize_or_function_body
{
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
}
| instance_identifier maybe_initialize ',' typedef_instance_identifiers
{
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
}
;
typedef_const_instance_identifiers:
instance_identifier maybe_initialize_or_function_body
{
$1->add_modifier(IIT_const);
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
}
| instance_identifier maybe_initialize ',' typedef_const_instance_identifiers
{
$1->add_modifier(IIT_const);
CPPInstance *inst = new CPPInstance(current_type, $1,
current_storage_class,
@1.file);
inst->set_initializer($2);
current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
}
;
function_prototype:
/* Functions with implicit return types, and constructors */
IDENTIFIER '('
{
push_scope($1->get_scope(current_scope, global_scope));
}
formal_parameter_list ')' function_post
{
pop_scope();
CPPType *type;
if ($1->get_simple_name() == current_scope->get_simple_name()) {
// This is a constructor, and has no return.
type = new CPPSimpleType(CPPSimpleType::T_void);
} else {
// This isn't a constructor, so it has an implicit return type of
// int.
type = new CPPSimpleType(CPPSimpleType::T_int);
}
CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($1);
ii->add_func_modifier($4, $6);
$$ = new CPPInstance(type, ii, 0, @1.file);
}
| TYPENAME_IDENTIFIER '('
{
push_scope($1->get_scope(current_scope, global_scope));
}
formal_parameter_list ')' function_post
{
pop_scope();
CPPType *type;
if ($1->get_simple_name() == current_scope->get_simple_name()) {
// This is a constructor, and has no return.
type = new CPPSimpleType(CPPSimpleType::T_void);
} else {
// This isn't a constructor, so it has an implicit return type of
// int.
type = new CPPSimpleType(CPPSimpleType::T_int);
}
CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($1);
ii->add_func_modifier($4, $6);
$$ = new CPPInstance(type, ii, 0, @1.file);
}
/* Destructors */
| '~' name '('
{
push_scope($2->get_scope(current_scope, global_scope));
}
formal_parameter_list ')' function_post
{
pop_scope();
if ($2->is_scoped()) {
yyerror("Invalid destructor name: ~" + $2->get_fully_scoped_name(), @2);
} else {
CPPIdentifier *ident =
new CPPIdentifier("~" + $2->get_simple_name(), @2.file);
delete $2;
CPPType *type;
type = new CPPSimpleType(CPPSimpleType::T_void);
CPPInstanceIdentifier *ii = new CPPInstanceIdentifier(ident);
ii->add_func_modifier($5, $7);
$$ = new CPPInstance(type, ii, 0, @2.file);
}
}
/* This is a special case: a function pointer declaration that looks
at first a lot like a constructor declaration. This is provided to
help yacc sort out the differences. It isn't an ideal solution,
because it doesn't catch a lot of subtle variants on this form--but
this will get at least the 99% most common uses. */
| TYPENAME_IDENTIFIER '(' '*' instance_identifier ')' '('
{
push_scope($4->get_scope(current_scope, global_scope));
}
formal_parameter_list ')' function_post
{
pop_scope();
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
assert(type != NULL);
CPPInstanceIdentifier *ii = $4;
ii->add_modifier(IIT_pointer);
ii->add_func_modifier($8, $10);
$$ = new CPPInstance(type, ii, 0, @1.file);
}
| TYPENAME_IDENTIFIER '(' SCOPING '*' instance_identifier ')' '('
{
push_scope($5->get_scope(current_scope, global_scope));
}
formal_parameter_list ')' function_post
{
pop_scope();
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
assert(type != NULL);
CPPInstanceIdentifier *ii = $5;
ii->add_scoped_pointer_modifier($3);
ii->add_func_modifier($9, $11);
$$ = new CPPInstance(type, ii, 0, @1.file);
}
/* Typecast operators */
| KW_OPERATOR type not_paren_formal_parameter_identifier '('
{
if ($1 != NULL) {
push_scope($1->get_scope(current_scope, global_scope));
}
}
formal_parameter_list ')' function_post
{
if ($1 != NULL) {
pop_scope();
}
// We use formal_parameter_identifier, because that can match a type
// name with or without an identifier, but especially without, which
// is what follows the keyword "operator" in a typecast function.
// As an added bonus, the type of the formal_parameter will be the
// typecast type, i.e. the return type of the typecast function.
// We give typecast operators the name "operator typecast <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, @1.file);
} else {
ident->add_name(name);
}
$$ = CPPInstance::make_typecast_function
(new CPPInstance($2, $3, 0, @3.file), ident, $6, $8);
}
| KW_OPERATOR KW_CONST type not_paren_formal_parameter_identifier '('
{
if ($1 != NULL) {
push_scope($1->get_scope(current_scope, global_scope));
}
}
formal_parameter_list ')' function_post
{
if ($1 != NULL) {
pop_scope();
}
CPPIdentifier *ident = $1;
if (ident == NULL) {
ident = new CPPIdentifier("operator typecast", @1.file);
} else {
ident->add_name("operator typecast");
}
$4->add_modifier(IIT_const);
$$ = CPPInstance::make_typecast_function
(new CPPInstance($3, $4, 0, @4.file), ident, $7, $9);
}
/* Not actually a function prototype, but maybe a template
instantiation. Just included here (instead of somewhere else) to
avoid shift/reduce conflicts. */
| IDENTIFIER
{
CPPDeclaration *decl =
$1->find_symbol(current_scope, global_scope, current_lexer);
if (decl != (CPPDeclaration *)NULL) {
$$ = decl->as_instance();
} else {
$$ = (CPPInstance *)NULL;
}
}
;
function_post:
empty
{
$$ = 0;
}
| KW_CONST
{
$$ = (int)CPPFunctionType::F_const_method;
}
| function_post KW_THROW '(' ')'
{
$$ = $1;
}
| function_post KW_THROW '(' name ')'
{
$$ = $1;
}
;
function_operator:
'!'
{
$$ = "!";
}
| '~'
{
$$ = "~";
}
| '*'
{
$$ = "*";
}
| '/'
{
$$ = "/";
}
| '%'
{
$$ = "%";
}
| '+'
{
$$ = "+";
}
| '-'
{
$$ = "-";
}
| '|'
{
$$ = "|";
}
| '&'
{
$$ = "&";
}
| '^'
{
$$ = "^";
}
| OROR
{
$$ = "||";
}
| ANDAND
{
$$ = "&&";
}
| EQCOMPARE
{
$$ = "==";
}
| NECOMPARE
{
$$ = "!=";
}
| LECOMPARE
{
$$ = "<=";
}
| GECOMPARE
{
$$ = ">=";
}
| '<'
{
$$ = "<";
}
| '>'
{
$$ = ">";
}
| LSHIFT
{
$$ = "<<";
}
| RSHIFT
{
$$ = ">>";
}
| '='
{
$$ = "=";
}
| ','
{
$$ = ",";
}
| PLUSPLUS
{
$$ = "++";
}
| MINUSMINUS
{
$$ = "--";
}
| TIMESEQUAL
{
$$ = "*=";
}
| DIVIDEEQUAL
{
$$ = "/=";
}
| MODEQUAL
{
$$ = "%=";
}
| PLUSEQUAL
{
$$ = "+=";
}
| MINUSEQUAL
{
$$ = "-=";
}
| OREQUAL
{
$$ = "|=";
}
| ANDEQUAL
{
$$ = "&=";
}
| XOREQUAL
{
$$ = "^=";
}
| LSHIFTEQUAL
{
$$ = "<<=";
}
| RSHIFTEQUAL
{
$$ = ">>=";
}
| POINTSAT
{
$$ = "->";
}
| '[' ']'
{
$$ = "[]";
}
| '(' ')'
{
$$ = "()";
}
| KW_NEW
{
$$ = "new";
}
| KW_DELETE
{
$$ = "delete";
}
;
more_template_declaration:
type_like_declaration
| template_declaration
;
template_declaration:
KW_TEMPLATE
{
push_scope(new CPPTemplateScope(current_scope));
}
'<' template_formal_parameters '>' more_template_declaration
{
pop_scope();
}
;
template_formal_parameters:
empty
| template_nonempty_formal_parameters
;
template_nonempty_formal_parameters:
template_formal_parameter
{
CPPTemplateScope *ts = current_scope->as_template_scope();
assert(ts != NULL);
ts->add_template_parameter($1);
}
| template_nonempty_formal_parameters ',' template_formal_parameter
{
CPPTemplateScope *ts = current_scope->as_template_scope();
assert(ts != NULL);
ts->add_template_parameter($3);
}
;
template_formal_parameter:
KW_CLASS name
{
$$ = CPPType::new_type(new CPPClassTemplateParameter($2));
}
| KW_CLASS name '=' full_type
{
$$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
}
| KW_TYPENAME name
{
$$ = CPPType::new_type(new CPPClassTemplateParameter($2));
}
| KW_TYPENAME name '=' full_type
{
$$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
}
| template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize
{
CPPInstance *inst = new CPPInstance($1, $2, 0, @2.file);
inst->set_initializer($3);
$$ = inst;
}
| KW_CONST template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize
{
$3->add_modifier(IIT_const);
CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file);
inst->set_initializer($4);
$$ = inst;
}
;
template_formal_parameter_type:
simple_type
{
$$ = CPPType::new_type($1);
}
| IDENTIFIER
{
yywarning("Not a type: " + $1->get_fully_scoped_name(), @1);
$$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
}
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
assert($$ != NULL);
}
;
instance_identifier:
name
{
$$ = new CPPInstanceIdentifier($1);
}
| KW_OPERATOR function_operator
{
// For an operator function. We implement this simply by building a
// ficticious name for the function; in other respects it's just
// like a regular function.
CPPIdentifier *ident = $1;
if (ident == NULL) {
ident = new CPPIdentifier("operator "+$2, @2.file);
} else {
ident->_names.push_back("operator "+$2);
}
$$ = new CPPInstanceIdentifier(ident);
}
| KW_CONST instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| '*' instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_pointer);
}
| '&' instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_reference);
}
| SCOPING '*' instance_identifier %prec UNARY
{
$$ = $3;
$$->add_scoped_pointer_modifier($1);
}
| instance_identifier '[' optional_const_expr ']'
{
$$ = $1;
$$->add_array_modifier($3);
}
| instance_identifier ':' INTEGER
{
// bitfield definition. We ignore the bitfield for now.
$$ = $1;
}
| '(' instance_identifier ')'
{
$$ = $2;
$$->add_modifier(IIT_paren);
}
| instance_identifier '('
{
push_scope($1->get_scope(current_scope, global_scope));
}
formal_parameter_list ')' function_post
{
pop_scope();
$$ = $1;
if ($4->is_parameter_expr() && $6 == 0) {
// Oops, this must have been an instance declaration with a
// parameter list, not a function prototype.
$$->add_initializer_modifier($4);
} else {
// This was (probably) a function prototype.
$$->add_func_modifier($4, $6);
}
}
;
formal_parameter_list:
empty
{
$$ = new CPPParameterList;
}
| ELLIPSIS
{
$$ = new CPPParameterList;
$$->_includes_ellipsis = true;
}
| formal_parameters
{
$$ = $1;
}
| formal_parameters ',' ELLIPSIS
{
$$ = $1;
$$->_includes_ellipsis = true;
}
| formal_parameters ELLIPSIS
{
$$ = $1;
$$->_includes_ellipsis = true;
}
;
formal_parameters:
formal_parameter
{
$$ = new CPPParameterList;
$$->_parameters.push_back($1);
}
| formal_parameters ',' formal_parameter
{
$$ = $1;
$$->_parameters.push_back($3);
}
;
template_parameter_maybe_initialize:
empty
{
$$ = (CPPExpression *)NULL;
}
| '=' no_angle_bracket_const_expr
{
$$ = $2;
}
;
maybe_initialize:
empty
{
$$ = (CPPExpression *)NULL;
}
| '=' const_expr
{
$$ = $2;
}
;
maybe_initialize_or_function_body:
';'
{
$$ = (CPPExpression *)NULL;
}
| '{' code '}'
{
$$ = (CPPExpression *)NULL;
}
| ':' constructor_inits '{' code '}'
{
$$ = (CPPExpression *)NULL;
}
| '=' const_expr ';'
{
$$ = $2;
}
| '=' '{' structure_init '}'
{
$$ = (CPPExpression *)NULL;
}
;
structure_init:
empty
| structure_init_body
| structure_init_body ','
;
structure_init_body:
const_expr
{
}
| '{' structure_init '}'
| structure_init_body ',' const_expr
| structure_init_body ',' '{' structure_init '}'
;
formal_parameter:
type formal_parameter_identifier maybe_initialize
{
$$ = new CPPInstance($1, $2, 0, @2.file);
$$->set_initializer($3);
}
| IDENTIFIER formal_parameter_identifier maybe_initialize
{
yywarning("Not a type: " + $1->get_fully_scoped_name(), @1);
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
$$ = new CPPInstance(type, $2, 0, @2.file);
$$->set_initializer($3);
}
| KW_CONST type formal_parameter_identifier maybe_initialize
{
$3->add_modifier(IIT_const);
$$ = new CPPInstance($2, $3, 0, @3.file);
$$->set_initializer($4);
}
| formal_const_expr
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_parameter));
$$ = new CPPInstance(type, "expr");
$$->set_initializer($1);
}
;
not_paren_formal_parameter_identifier:
empty
{
$$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
}
| IDENTIFIER
{
$$ = new CPPInstanceIdentifier($1);
}
| TYPENAME_IDENTIFIER
{
$$ = new CPPInstanceIdentifier($1);
}
| KW_CONST not_paren_formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| '*' not_paren_formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_pointer);
}
| '&' not_paren_formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_reference);
}
| SCOPING '*' not_paren_formal_parameter_identifier %prec UNARY
{
$$ = $3;
$$->add_scoped_pointer_modifier($1);
}
| not_paren_formal_parameter_identifier '[' optional_const_expr ']'
{
$$ = $1;
$$->add_array_modifier($3);
}
;
formal_parameter_identifier:
empty
{
$$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
}
| IDENTIFIER
{
$$ = new CPPInstanceIdentifier($1);
}
| TYPENAME_IDENTIFIER
{
$$ = new CPPInstanceIdentifier($1);
}
| KW_CONST formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| '*' formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_pointer);
}
| '&' formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_reference);
}
| SCOPING '*' formal_parameter_identifier %prec UNARY
{
$$ = $3;
$$->add_scoped_pointer_modifier($1);
}
| formal_parameter_identifier '[' optional_const_expr ']'
{
$$ = $1;
$$->add_array_modifier($3);
}
| '(' formal_parameter_identifier ')' '(' formal_parameter_list ')' function_post
{
$$ = $2;
$$->add_modifier(IIT_paren);
$$->add_func_modifier($5, $7);
}
| '(' formal_parameter_identifier ')'
{
$$ = $2;
$$->add_modifier(IIT_paren);
}
;
empty_instance_identifier:
empty
{
$$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
}
| KW_CONST empty_instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| '*' empty_instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_pointer);
}
| '&' empty_instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_reference);
}
| SCOPING '*' empty_instance_identifier %prec UNARY
{
$$ = $3;
$$->add_scoped_pointer_modifier($1);
}
| empty_instance_identifier '[' optional_const_expr ']'
{
$$ = $1;
$$->add_array_modifier($3);
}
| '(' empty_instance_identifier ')' '(' formal_parameter_list ')' function_post
{
$$ = $2;
$$->add_modifier(IIT_paren);
$$->add_func_modifier($5, $7);
}
;
type:
simple_type
{
$$ = CPPType::new_type($1);
}
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
assert($$ != NULL);
}
| KW_TYPENAME name
{
$$ = CPPType::new_type(new CPPTBDType($2));
}
| anonymous_struct
{
$$ = CPPType::new_type($1);
}
| named_struct
{
$$ = CPPType::new_type($1);
}
| anonymous_enum
{
$$ = CPPType::new_type($1);
}
| named_enum
{
$$ = CPPType::new_type($1);
}
| struct_keyword name
{
CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
if (type != NULL) {
$$ = type;
} else {
CPPExtensionType *et =
CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file))
->as_extension_type();
CPPScope *scope = $2->get_scope(current_scope, global_scope);
if (scope != NULL) {
scope->define_extension_type(et);
}
$$ = et;
}
}
| enum_keyword name
{
CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
if (type != NULL) {
$$ = type;
} else {
CPPExtensionType *et =
CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file))
->as_extension_type();
CPPScope *scope = $2->get_scope(current_scope, global_scope);
if (scope != NULL) {
scope->define_extension_type(et);
}
$$ = et;
}
}
;
type_decl:
simple_type
{
$$ = CPPType::new_type($1);
}
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
assert($$ != NULL);
}
| KW_TYPENAME name
{
$$ = CPPType::new_type(new CPPTBDType($2));
}
| anonymous_struct
{
$$ = CPPType::new_type($1);
}
| named_struct
{
$$ = new CPPTypeDeclaration(CPPType::new_type($1));
}
| anonymous_enum
{
$$ = CPPType::new_type($1);
}
| named_enum
{
$$ = new CPPTypeDeclaration(CPPType::new_type($1));
}
| struct_keyword name
{
CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
if (type != NULL) {
$$ = type;
} else {
CPPExtensionType *et =
CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file))
->as_extension_type();
CPPScope *scope = $2->get_scope(current_scope, global_scope);
if (scope != NULL) {
scope->define_extension_type(et);
}
$$ = et;
}
}
| enum_keyword name
{
CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
if (type != NULL) {
$$ = type;
} else {
CPPExtensionType *et =
CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file))
->as_extension_type();
CPPScope *scope = $2->get_scope(current_scope, global_scope);
if (scope != NULL) {
scope->define_extension_type(et);
}
$$ = et;
}
}
;
predefined_type:
simple_type
{
$$ = CPPType::new_type($1);
}
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
assert($$ != NULL);
}
| KW_TYPENAME name
{
$$ = CPPType::new_type(new CPPTBDType($2));
}
| struct_keyword name
{
CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
if (type != NULL) {
$$ = type;
} else {
CPPExtensionType *et =
CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file))
->as_extension_type();
CPPScope *scope = $2->get_scope(current_scope, global_scope);
if (scope != NULL) {
scope->define_extension_type(et);
}
$$ = et;
}
}
| enum_keyword name
{
CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
if (type != NULL) {
$$ = type;
} else {
CPPExtensionType *et =
CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file))
->as_extension_type();
CPPScope *scope = $2->get_scope(current_scope, global_scope);
if (scope != NULL) {
scope->define_extension_type(et);
}
$$ = et;
}
}
;
full_type:
type empty_instance_identifier
{
CPPInstance *inst = new CPPInstance($1, $2, 0, @1.file);
$$ = inst->_type;
delete inst;
}
| KW_CONST type empty_instance_identifier
{
$3->add_modifier(IIT_const);
CPPInstance *inst = new CPPInstance($2, $3, 0, @1.file);
$$ = inst->_type;
delete inst;
}
;
anonymous_struct:
struct_keyword '{'
{
CPPVisibility starting_vis =
($1 == CPPExtensionType::T_class) ? V_private : V_public;
CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("anon"),
starting_vis);
CPPStructType *st = new CPPStructType($1, NULL, current_scope,
new_scope, @1.file);
new_scope->set_struct_type(st);
push_scope(new_scope);
push_struct(st);
}
cpp '}'
{
$$ = current_struct;
current_struct->_incomplete = false;
pop_struct();
pop_scope();
}
;
named_struct:
struct_keyword name
{
CPPVisibility starting_vis =
($1 == CPPExtensionType::T_class) ? V_private : V_public;
CPPScope *scope = $2->get_scope(current_scope, global_scope, current_lexer);
if (scope == NULL) {
scope = current_scope;
}
CPPScope *new_scope = new CPPScope(scope, $2->_names.back(),
starting_vis);
CPPStructType *st = new CPPStructType($1, $2, current_scope,
new_scope, @1.file);
new_scope->set_struct_type(st);
current_scope->define_extension_type(st);
push_scope(new_scope);
push_struct(st);
}
maybe_class_derivation '{' cpp '}'
{
$$ = current_struct;
current_struct->_incomplete = false;
pop_struct();
pop_scope();
}
;
maybe_class_derivation:
empty
| class_derivation
;
class_derivation:
':' base_specification
| class_derivation ',' base_specification
;
base_specification:
KW_PUBLIC class_derivation_name
{
current_struct->append_derivation($2, V_public, false);
}
| KW_PROTECTED class_derivation_name
{
current_struct->append_derivation($2, V_protected, false);
}
| KW_PRIVATE class_derivation_name
{
current_struct->append_derivation($2, V_private, false);
}
| KW_VIRTUAL KW_PUBLIC class_derivation_name
{
current_struct->append_derivation($3, V_public, true);
}
| KW_VIRTUAL KW_PROTECTED class_derivation_name
{
current_struct->append_derivation($3, V_protected, true);
}
| KW_VIRTUAL KW_PRIVATE class_derivation_name
{
current_struct->append_derivation($3, V_private, true);
}
| KW_PUBLIC KW_VIRTUAL class_derivation_name
{
current_struct->append_derivation($3, V_public, true);
}
| KW_PROTECTED KW_VIRTUAL class_derivation_name
{
current_struct->append_derivation($3, V_protected, true);
}
| KW_PRIVATE KW_VIRTUAL class_derivation_name
{
current_struct->append_derivation($3, V_private, true);
}
;
anonymous_enum:
enum_keyword '{'
{
current_enum = new CPPEnumType(NULL, current_scope, @1.file);
}
enum_body '}'
{
$$ = current_enum;
current_enum = NULL;
}
;
named_enum:
enum_keyword name '{'
{
current_enum = new CPPEnumType($2, current_scope, @1.file);
}
enum_body '}'
{
$$ = current_enum;
current_enum = NULL;
}
;
enum_body:
empty
| enum_body_no_trailing_comma
| enum_body_no_trailing_comma ','
;
enum_body_no_trailing_comma:
name
{
assert(current_enum != NULL);
current_enum->add_element($1->get_simple_name(), current_scope);
}
| name '=' const_expr
{
assert(current_enum != NULL);
current_enum->add_element($1->get_simple_name(), current_scope, $3);
}
| enum_body_no_trailing_comma ',' name
{
assert(current_enum != NULL);
current_enum->add_element($3->get_simple_name(), current_scope);
}
| enum_body_no_trailing_comma ',' name '=' const_expr
{
assert(current_enum != NULL);
current_enum->add_element($3->get_simple_name(), current_scope, $5);
}
;
enum_keyword:
KW_ENUM
{
$$ = CPPExtensionType::T_enum;
}
;
struct_keyword:
KW_CLASS
{
$$ = CPPExtensionType::T_class;
}
| KW_STRUCT
{
$$ = CPPExtensionType::T_struct;
}
| KW_UNION
{
$$ = CPPExtensionType::T_union;
}
;
namespace_declaration:
KW_NAMESPACE name '{'
{
CPPScope *scope = $2->find_scope(current_scope, global_scope, current_lexer);
if (scope == NULL) {
// This must be a new namespace declaration.
CPPScope *parent_scope =
$2->get_scope(current_scope, global_scope, current_lexer);
if (parent_scope == NULL) {
parent_scope = current_scope;
}
scope = new CPPScope(parent_scope, $2->_names.back(), V_public);
}
CPPNamespace *nspace = new CPPNamespace($2, scope, @1.file);
current_scope->add_declaration(nspace, global_scope, current_lexer, @1);
current_scope->define_namespace(nspace);
push_scope(scope);
}
cpp '}'
{
pop_scope();
}
| KW_NAMESPACE '{' cpp '}'
;
using_declaration:
KW_USING name
{
CPPUsing *using_decl = new CPPUsing($2, false, @1.file);
current_scope->add_declaration(using_decl, global_scope, current_lexer, @1);
current_scope->add_using(using_decl, global_scope, current_lexer);
}
| KW_USING KW_NAMESPACE name
{
CPPUsing *using_decl = new CPPUsing($3, true, @1.file);
current_scope->add_declaration(using_decl, global_scope, current_lexer, @1);
current_scope->add_using(using_decl, global_scope, current_lexer);
}
;
simple_type:
simple_int_type
| simple_float_type
| simple_void_type
;
simple_int_type:
KW_BOOL
{
$$ = new CPPSimpleType(CPPSimpleType::T_bool);
}
| KW_CHAR
{
$$ = new CPPSimpleType(CPPSimpleType::T_char);
}
| KW_WCHAR_T
{
$$ = new CPPSimpleType(CPPSimpleType::T_wchar_t);
}
| KW_SHORT
{
$$ = new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_short);
}
| KW_LONG
{
$$ = new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_long);
}
| KW_LONGLONG
{
$$ = new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_longlong);
}
| KW_UNSIGNED
{
$$ = new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_unsigned);
}
| KW_SIGNED
{
$$ = new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_signed);
}
| KW_INT
{
$$ = new CPPSimpleType(CPPSimpleType::T_int);
}
| KW_SHORT simple_int_type
{
$$ = $2;
$$->_flags |= CPPSimpleType::F_short;
}
| KW_LONG simple_int_type
{
$$ = $2;
if ($$->_flags & CPPSimpleType::F_long) {
$$->_flags |= CPPSimpleType::F_longlong;
} else {
$$->_flags |= CPPSimpleType::F_long;
}
}
| KW_UNSIGNED simple_int_type
{
$$ = $2;
$$->_flags |= CPPSimpleType::F_unsigned;
}
| KW_SIGNED simple_int_type
{
$$ = $2;
$$->_flags |= CPPSimpleType::F_signed;
}
;
simple_float_type:
KW_FLOAT
{
$$ = new CPPSimpleType(CPPSimpleType::T_float);
}
| KW_LONG KW_FLOAT
{
$$ = new CPPSimpleType(CPPSimpleType::T_float,
CPPSimpleType::F_long);
}
| KW_DOUBLE
{
$$ = new CPPSimpleType(CPPSimpleType::T_double);
}
| KW_LONG KW_LONG KW_FLOAT
{
$$ = new CPPSimpleType(CPPSimpleType::T_float,
CPPSimpleType::F_longlong);
}
| KW_LONG KW_DOUBLE
{
$$ = new CPPSimpleType(CPPSimpleType::T_double,
CPPSimpleType::F_long);
}
;
simple_void_type:
KW_VOID
{
$$ = new CPPSimpleType(CPPSimpleType::T_void);
}
;
/* We don't care what the code is. We just want to be sure we match
up opening and closing braces properly. For anything else, we'll
accept just token salad. */
code:
{
current_lexer->_resolve_identifiers = false;
}
code_block
{
current_lexer->_resolve_identifiers = true;
}
;
code_block:
empty
| code_block element
;
element:
REAL
{
}
| INTEGER
{
}
| STRING
{
}
| CHAR_TOK
{
}
| IDENTIFIER
{
}
| TYPENAME_IDENTIFIER
{
}
| SCOPING
{
}
| SIMPLE_IDENTIFIER
{
}
| ELLIPSIS | OROR | ANDAND
| EQCOMPARE | NECOMPARE | LECOMPARE | GECOMPARE
| LSHIFT | RSHIFT | POINTSAT_STAR | DOT_STAR | POINTSAT
| SCOPE | PLUSPLUS | MINUSMINUS
| TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
| OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL
| KW_BOOL | KW_CATCH | KW_CHAR | KW_WCHAR_T | KW_CLASS | KW_CONST
| KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM
| KW_EXTERN | KW_EXPLICIT | KW_FALSE
| KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
| KW_IF | KW_INLINE | KW_INT
| KW_LONG | KW_MUTABLE | KW_NEW | KW_PRIVATE | KW_PROTECTED
| KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_RETURN
| KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_CAST
| KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF | KW_TYPENAME
| KW_UNION | KW_UNSIGNED | KW_VIRTUAL | KW_VOID | KW_VOLATILE
| KW_WHILE
| KW_OPERATOR
{
}
| '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
| '<' | '>' | '(' | ')' | '.' | ',' | ';' | ':' | '[' | ']'
| '?' | '{' code_block '}'
;
optional_const_expr:
empty
{
$$ = (CPPExpression *)NULL;
}
| const_expr
{
$$ = $1;
}
;
optional_const_expr_comma:
empty
{
$$ = (CPPExpression *)NULL;
}
| const_expr_comma
{
$$ = $1;
}
;
const_expr_comma:
const_expr
{
$$ = $1;
}
| const_expr_comma ',' const_expr
{
$$ = new CPPExpression(',', $1, $3);
}
;
no_angle_bracket_const_expr:
const_operand
{
$$ = $1;
}
| '(' full_type ')' no_angle_bracket_const_expr %prec UNARY
{
$$ = new CPPExpression(CPPExpression::typecast_op($2, $4));
}
| KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')'
{
$$ = new CPPExpression(CPPExpression::typecast_op($3, $6));
}
| KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')'
{
$$ = new CPPExpression(CPPExpression::typecast_op($3, $6));
}
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| '!' no_angle_bracket_const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_NOT, $2);
}
| '~' no_angle_bracket_const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_NEGATE, $2);
}
| '-' no_angle_bracket_const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
}
| '*' no_angle_bracket_const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_STAR, $2);
}
| '&' no_angle_bracket_const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_REF, $2);
}
| no_angle_bracket_const_expr '*' no_angle_bracket_const_expr
{
$$ = new CPPExpression('*', $1, $3);
}
| no_angle_bracket_const_expr '/' no_angle_bracket_const_expr
{
$$ = new CPPExpression('/', $1, $3);
}
| no_angle_bracket_const_expr '%' no_angle_bracket_const_expr
{
$$ = new CPPExpression('%', $1, $3);
}
| no_angle_bracket_const_expr '+' no_angle_bracket_const_expr
{
$$ = new CPPExpression('+', $1, $3);
}
| no_angle_bracket_const_expr '-' no_angle_bracket_const_expr
{
$$ = new CPPExpression('-', $1, $3);
}
| no_angle_bracket_const_expr '|' no_angle_bracket_const_expr
{
$$ = new CPPExpression('|', $1, $3);
}
| no_angle_bracket_const_expr '^' no_angle_bracket_const_expr
{
$$ = new CPPExpression('^', $1, $3);
}
| no_angle_bracket_const_expr '&' no_angle_bracket_const_expr
{
$$ = new CPPExpression('&', $1, $3);
}
| no_angle_bracket_const_expr OROR no_angle_bracket_const_expr
{
$$ = new CPPExpression(OROR, $1, $3);
}
| no_angle_bracket_const_expr ANDAND no_angle_bracket_const_expr
{
$$ = new CPPExpression(ANDAND, $1, $3);
}
| no_angle_bracket_const_expr EQCOMPARE no_angle_bracket_const_expr
{
$$ = new CPPExpression(EQCOMPARE, $1, $3);
}
| no_angle_bracket_const_expr NECOMPARE no_angle_bracket_const_expr
{
$$ = new CPPExpression(NECOMPARE, $1, $3);
}
| no_angle_bracket_const_expr LECOMPARE no_angle_bracket_const_expr
{
$$ = new CPPExpression(LECOMPARE, $1, $3);
}
| no_angle_bracket_const_expr GECOMPARE no_angle_bracket_const_expr
{
$$ = new CPPExpression(GECOMPARE, $1, $3);
}
| no_angle_bracket_const_expr LSHIFT no_angle_bracket_const_expr
{
$$ = new CPPExpression(LSHIFT, $1, $3);
}
| no_angle_bracket_const_expr RSHIFT no_angle_bracket_const_expr
{
$$ = new CPPExpression(RSHIFT, $1, $3);
}
| no_angle_bracket_const_expr '?' no_angle_bracket_const_expr ':' no_angle_bracket_const_expr
{
$$ = new CPPExpression('?', $1, $3, $5);
}
| no_angle_bracket_const_expr '[' const_expr ']'
{
$$ = new CPPExpression('[', $1, $3);
}
| no_angle_bracket_const_expr '(' const_expr_comma ')'
{
$$ = new CPPExpression('f', $1, $3);
}
| no_angle_bracket_const_expr '(' ')'
{
$$ = new CPPExpression('f', $1);
}
| no_angle_bracket_const_expr '.' no_angle_bracket_const_expr
{
$$ = new CPPExpression('.', $1, $3);
}
| no_angle_bracket_const_expr POINTSAT no_angle_bracket_const_expr
{
$$ = new CPPExpression(POINTSAT, $1, $3);
}
| '(' const_expr_comma ')'
{
$$ = $2;
}
;
const_expr:
const_operand
{
$$ = $1;
}
| '(' full_type ')' const_expr %prec UNARY
{
$$ = new CPPExpression(CPPExpression::typecast_op($2, $4));
}
| KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')'
{
$$ = new CPPExpression(CPPExpression::typecast_op($3, $6));
}
| KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')'
{
$$ = new CPPExpression(CPPExpression::typecast_op($3, $6));
}
| TYPENAME_IDENTIFIER '(' optional_const_expr_comma ')'
{
// A constructor call.
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
assert(type != NULL);
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_INT '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_CHAR '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_WCHAR_T '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_BOOL '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_SHORT '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_short));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_LONG '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_long));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_UNSIGNED '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_unsigned));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_SIGNED '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_signed));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_FLOAT '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_float));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_DOUBLE '(' optional_const_expr_comma ')'
{
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double));
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_NEW predefined_type %prec UNARY
{
$$ = new CPPExpression(CPPExpression::new_op($2));
}
| KW_NEW predefined_type '(' optional_const_expr_comma ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::new_op($2, $4));
}
| '!' const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_NOT, $2);
}
| '~' const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_NEGATE, $2);
}
| '-' const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
}
| '*' const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_STAR, $2);
}
| '&' const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_REF, $2);
}
| const_expr '*' const_expr
{
$$ = new CPPExpression('*', $1, $3);
}
| const_expr '/' const_expr
{
$$ = new CPPExpression('/', $1, $3);
}
| const_expr '%' const_expr
{
$$ = new CPPExpression('%', $1, $3);
}
| const_expr '+' const_expr
{
$$ = new CPPExpression('+', $1, $3);
}
| const_expr '-' const_expr
{
$$ = new CPPExpression('-', $1, $3);
}
| const_expr '|' const_expr
{
$$ = new CPPExpression('|', $1, $3);
}
| const_expr '^' const_expr
{
$$ = new CPPExpression('^', $1, $3);
}
| const_expr '&' const_expr
{
$$ = new CPPExpression('&', $1, $3);
}
| const_expr OROR const_expr
{
$$ = new CPPExpression(OROR, $1, $3);
}
| const_expr ANDAND const_expr
{
$$ = new CPPExpression(ANDAND, $1, $3);
}
| const_expr EQCOMPARE const_expr
{
$$ = new CPPExpression(EQCOMPARE, $1, $3);
}
| const_expr NECOMPARE const_expr
{
$$ = new CPPExpression(NECOMPARE, $1, $3);
}
| const_expr LECOMPARE const_expr
{
$$ = new CPPExpression(LECOMPARE, $1, $3);
}
| const_expr GECOMPARE const_expr
{
$$ = new CPPExpression(GECOMPARE, $1, $3);
}
| const_expr '<' const_expr
{
$$ = new CPPExpression('<', $1, $3);
}
| const_expr '>' const_expr
{
$$ = new CPPExpression('>', $1, $3);
}
| const_expr LSHIFT const_expr
{
$$ = new CPPExpression(LSHIFT, $1, $3);
}
| const_expr RSHIFT const_expr
{
$$ = new CPPExpression(RSHIFT, $1, $3);
}
| const_expr '?' const_expr ':' const_expr
{
$$ = new CPPExpression('?', $1, $3, $5);
}
| const_expr '[' const_expr ']'
{
$$ = new CPPExpression('[', $1, $3);
}
| const_expr '(' const_expr_comma ')'
{
$$ = new CPPExpression('f', $1, $3);
}
| const_expr '(' ')'
{
$$ = new CPPExpression('f', $1);
}
| const_expr '.' const_expr
{
$$ = new CPPExpression('.', $1, $3);
}
| const_expr POINTSAT const_expr
{
$$ = new CPPExpression(POINTSAT, $1, $3);
}
| '(' const_expr_comma ')'
{
$$ = $2;
}
;
const_operand:
INTEGER
{
$$ = new CPPExpression($1);
}
| KW_TRUE
{
$$ = new CPPExpression(true);
}
| KW_FALSE
{
$$ = new CPPExpression(false);
}
| CHAR_TOK
{
$$ = new CPPExpression($1);
}
| REAL
{
$$ = new CPPExpression($1);
}
| string
{
$$ = new CPPExpression($1);
}
| IDENTIFIER
{
$$ = new CPPExpression($1, current_scope, global_scope, current_lexer);
}
;
/* This is used for a const_expr as a "formal parameter", which really
means an instance declaration using a parameter list (which looks a
lot like a function prototype). It differs from const_expr mainly
in that it forbids some expressions unless they are parenthesized,
to avoid shift/reduce conflicts with the actual formal parameter
definition. */
formal_const_expr:
formal_const_operand
{
$$ = $1;
}
| '(' full_type ')' const_expr %prec UNARY
{
$$ = new CPPExpression(CPPExpression::typecast_op($2, $4));
}
| KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')'
{
$$ = new CPPExpression(CPPExpression::typecast_op($3, $6));
}
| KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')'
{
$$ = new CPPExpression(CPPExpression::typecast_op($3, $6));
}
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_NEW predefined_type %prec UNARY
{
$$ = new CPPExpression(CPPExpression::new_op($2));
}
| KW_NEW predefined_type '(' optional_const_expr_comma ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::new_op($2, $4));
}
| '!' const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_NOT, $2);
}
| '~' const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_NEGATE, $2);
}
| '-' const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
}
| '&' const_expr %prec UNARY
{
$$ = new CPPExpression(UNARY_REF, $2);
}
| formal_const_expr '*' const_expr
{
$$ = new CPPExpression('*', $1, $3);
}
| formal_const_expr '/' const_expr
{
$$ = new CPPExpression('/', $1, $3);
}
| formal_const_expr '%' const_expr
{
$$ = new CPPExpression('%', $1, $3);
}
| formal_const_expr '+' const_expr
{
$$ = new CPPExpression('+', $1, $3);
}
| formal_const_expr '-' const_expr
{
$$ = new CPPExpression('-', $1, $3);
}
| formal_const_expr '|' const_expr
{
$$ = new CPPExpression('|', $1, $3);
}
| formal_const_expr '^' const_expr
{
$$ = new CPPExpression('^', $1, $3);
}
| formal_const_expr '&' const_expr
{
$$ = new CPPExpression('&', $1, $3);
}
| formal_const_expr OROR const_expr
{
$$ = new CPPExpression(OROR, $1, $3);
}
| formal_const_expr ANDAND const_expr
{
$$ = new CPPExpression(ANDAND, $1, $3);
}
| formal_const_expr EQCOMPARE const_expr
{
$$ = new CPPExpression(EQCOMPARE, $1, $3);
}
| formal_const_expr NECOMPARE const_expr
{
$$ = new CPPExpression(NECOMPARE, $1, $3);
}
| formal_const_expr LECOMPARE const_expr
{
$$ = new CPPExpression(LECOMPARE, $1, $3);
}
| formal_const_expr GECOMPARE const_expr
{
$$ = new CPPExpression(GECOMPARE, $1, $3);
}
| formal_const_expr '<' const_expr
{
$$ = new CPPExpression('<', $1, $3);
}
| formal_const_expr '>' const_expr
{
$$ = new CPPExpression('>', $1, $3);
}
| formal_const_expr LSHIFT const_expr
{
$$ = new CPPExpression(LSHIFT, $1, $3);
}
| formal_const_expr RSHIFT const_expr
{
$$ = new CPPExpression(RSHIFT, $1, $3);
}
| formal_const_expr '?' const_expr ':' const_expr
{
$$ = new CPPExpression('?', $1, $3, $5);
}
| formal_const_expr '[' const_expr ']'
{
$$ = new CPPExpression('[', $1, $3);
}
| formal_const_expr '(' const_expr_comma ')'
{
$$ = new CPPExpression('f', $1, $3);
}
| formal_const_expr '(' ')'
{
$$ = new CPPExpression('f', $1);
}
| formal_const_expr '.' const_expr
{
$$ = new CPPExpression('.', $1, $3);
}
| formal_const_expr POINTSAT const_expr
{
$$ = new CPPExpression(POINTSAT, $1, $3);
}
| '(' const_expr_comma ')'
{
$$ = $2;
}
;
formal_const_operand:
INTEGER
{
$$ = new CPPExpression($1);
}
| KW_TRUE
{
$$ = new CPPExpression(true);
}
| KW_FALSE
{
$$ = new CPPExpression(false);
}
| CHAR_TOK
{
$$ = new CPPExpression($1);
}
| REAL
{
$$ = new CPPExpression($1);
}
| string
{
$$ = new CPPExpression($1);
}
;
class_derivation_name:
name
{
CPPType *type = $1->find_type(current_scope, global_scope, true);
if (type == NULL) {
type = CPPType::new_type(new CPPTBDType($1));
}
$$ = type;
}
| struct_keyword name
{
CPPType *type = $2->find_type(current_scope, global_scope, true, current_lexer);
if (type == NULL) {
type = CPPType::new_type(new CPPTBDType($2));
}
$$ = type;
}
| KW_TYPENAME name
{
$$ = CPPType::new_type(new CPPTBDType($2));
}
;
/*
typedefname:
TYPENAME_IDENTIFIER
{
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
assert(type != NULL);
$$ = type;
}
| KW_TYPENAME name
{
$$ = CPPType::new_type(new CPPTBDType($2));
}
;
*/
name:
IDENTIFIER
{
$$ = $1;
}
| TYPENAME_IDENTIFIER
{
$$ = $1;
}
;
string:
STRING
{
$$ = $1;
}
| string STRING
{
$$ = $1 + $2;
}
;
empty:
;