mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
2817 lines
64 KiB
Plaintext
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:
|
|
;
|