fprintf(header, ";\n");
}
-void write_constdef(const var_t *v)
+int is_const_decl(const var_t *var)
{
- fprintf(header, "#define %s (", v->name);
- write_expr(header, v->eval, 0, 1, NULL, NULL);
- fprintf(header, ")\n\n");
+ const type_t *t;
+ /* strangely, MIDL accepts a const attribute on any pointer in the
+ * declaration to mean that data isn't being instantiated. this appears
+ * to be a bug, but there is no benefit to being incompatible with MIDL,
+ * so we'll do the same thing */
+ for (t = var->type; ; )
+ {
+ if (is_attr(t->attrs, ATTR_CONST))
+ return TRUE;
+ else if (is_ptr(t))
+ t = t->ref;
+ else break;
+ }
+ return FALSE;
}
-void write_externdef(const var_t *v)
+void write_declaration(const var_t *v, int is_in_interface)
{
- fprintf(header, "extern const ");
- write_type_def_or_decl(header, v->type, FALSE, "%s", v->name);
- fprintf(header, ";\n\n");
+ if (is_const_decl(v) && v->eval)
+ {
+ fprintf(header, "#define %s (", v->name);
+ write_expr(header, v->eval, 0, 1, NULL, NULL);
+ fprintf(header, ")\n\n");
+ }
+ else if (v->type->type != RPC_FC_FUNCTION || !is_in_interface)
+ {
+ switch (v->stgclass)
+ {
+ case STG_NONE:
+ case STG_REGISTER: /* ignored */
+ break;
+ case STG_STATIC:
+ fprintf(header, "static ");
+ break;
+ case STG_EXTERN:
+ fprintf(header, "extern ");
+ break;
+ }
+ write_type_def_or_decl(header, v->type, FALSE, "%s", v->name);
+ fprintf(header, ";\n\n");
+ }
}
void write_library(const typelib_t *typelib)
#define YYERROR_VERBOSE
unsigned char pointer_default = RPC_FC_UP;
+static int is_in_interface = FALSE;
static int is_object_interface = FALSE;
/* are we inside a library block? */
static int is_inside_library = FALSE;
static statement_t *make_statement(enum statement_type type);
static statement_t *make_statement_type_decl(type_t *type);
static statement_t *make_statement_reference(type_t *type);
-static statement_t *make_statement_init_decl(var_t *var);
-static statement_t *make_statement_extern(var_t *var);
+static statement_t *make_statement_declaration(var_t *var);
static statement_t *make_statement_library(typelib_t *typelib);
static statement_t *make_statement_cppquote(const char *str);
static statement_t *make_statement_importlib(const char *str);
static statement_t *make_statement_module(type_t *type);
static statement_t *make_statement_import(const char *str);
static statement_list_t *append_statement(statement_list_t *list, statement_t *stmt);
+static func_list_t *append_func_from_statement(func_list_t *list, statement_t *stmt);
#define tsENUM 1
#define tsSTRUCT 2
%token tPUBLIC
%token tRANGE
%token tREADONLY tREF
+%token tREGISTER
%token tREQUESTEDIT
%token tRESTRICTED
%token tRETVAL
%token tSIZEIS tSIZEOF
%token tSMALL
%token tSOURCE
+%token tSTATIC
%token tSTDCALL
%token tSTRICTCONTEXTHANDLE
%token tSTRING tSTRUCT
%type <expr> m_expr expr expr_const expr_int_const array
%type <expr_list> m_exprs /* exprs expr_list */ expr_list_int_const
%type <ifinfo> interfacehdr
+%type <stgclass> storage_cls_spec
%type <declspec> decl_spec decl_spec_no_type m_decl_spec_no_type
%type <type> inherit interface interfacedef interfacedec
%type <type> dispinterface dispinterfacehdr dispinterfacedef
%type <type> type
%type <ifref> coclass_int
%type <ifref_list> coclass_ints
-%type <var> arg ne_union_field union_field s_field case enum constdef externdef
+%type <var> arg ne_union_field union_field s_field case enum declaration
%type <var_list> m_args no_args args fields ne_union_fields cases enums enum_list dispint_props field
%type <var> m_ident t_ident ident
-%type <declarator> declarator direct_declarator
+%type <declarator> declarator direct_declarator init_declarator
%type <declarator_list> declarator_list
%type <func> funcdef
%type <func_list> int_statements dispint_meths
;
int_statements: { $$ = NULL; }
- | int_statements funcdef ';' { $$ = append_func( $1, $2 ); }
- | int_statements statement { $$ = $1; }
+ | int_statements statement { $$ = append_func_from_statement( $1, $2 ); }
;
semicolon_opt:
| ';'
;
-statement: constdef ';' { $$ = make_statement_init_decl($1);
- if (!parse_only && do_header) { write_constdef($1); }
- }
- | cppquote { $$ = make_statement_cppquote($1); }
+statement:
+ cppquote { $$ = make_statement_cppquote($1); }
| enumdef ';' { $$ = make_statement_type_decl($1);
if (!parse_only && do_header) {
write_type_def_or_decl(header, $1, FALSE, NULL);
fprintf(header, ";\n\n");
}
}
- | externdef ';' { $$ = make_statement_extern($1);
- if (!parse_only && do_header) write_externdef($1);
+ | declaration ';' { $$ = make_statement_declaration($1);
+ if (!parse_only && do_header) write_declaration($1, is_in_interface);
}
| import { $$ = make_statement_import($1); }
| structdef ';' { $$ = make_statement_type_decl($1);
}
;
-constdef: tCONST decl_spec declarator '=' expr_const
- { $$ = reg_const($3->var);
- set_type($$, $2, $3, FALSE);
- $$->eval = $5;
- free($3);
- }
- ;
-
enums: { $$ = NULL; }
| enum_list ',' { $$ = $1; }
| enum_list
}
;
-externdef: tEXTERN tCONST decl_spec declarator { $$ = $4->var;
- set_type($$, $3, $4, FALSE);
- free($4);
- }
- ;
-
fields: { $$ = NULL; }
| fields field { $$ = append_var_list($1, $2); }
;
}
;
+declaration:
+ attributes decl_spec init_declarator
+ { $$ = $3->var;
+ $$->attrs = $1;
+ set_type($$, $2, $3, FALSE);
+ free($3);
+ }
+ | decl_spec init_declarator { $$ = $2->var;
+ set_type($$, $1, $2, FALSE);
+ free($2);
+ }
+ ;
+
m_ident: { $$ = NULL; }
| ident
;
;
dispinterfacehdr: attributes dispinterface { attr_t *attrs;
+ is_in_interface = TRUE;
is_object_interface = TRUE;
$$ = $2;
if ($$->defined) error_loc("multiple definition error\n");
$$->funcs = $4;
if (!parse_only && do_header) write_dispinterface($$);
if (!parse_only && do_idfile) write_diid($$);
+ is_in_interface = FALSE;
}
| dispinterfacehdr
'{' interface ';' '}' { $$ = $1;
$$->funcs = $3->funcs;
if (!parse_only && do_header) write_dispinterface($$);
if (!parse_only && do_idfile) write_diid($$);
+ is_in_interface = FALSE;
}
;
if (is_attr($1, ATTR_POINTERDEFAULT))
pointer_default = get_attrv($1, ATTR_POINTERDEFAULT);
is_object_interface = is_object($1);
+ is_in_interface = TRUE;
if ($2->defined) error_loc("multiple definition error\n");
$2->attrs = check_iface_attrs($2->name, $1);
$2->defined = TRUE;
if (!parse_only && local_stubs) write_locals(local_stubs, $$, TRUE);
if (!parse_only && do_idfile) write_iid($$);
pointer_default = $1.old_pointer_default;
+ is_in_interface = FALSE;
}
/* MIDL is able to import the definition of a base class from inside the
* definition of a derived class, I'll try to support it with this rule */
if (!parse_only && local_stubs) write_locals(local_stubs, $$, TRUE);
if (!parse_only && do_idfile) write_iid($$);
pointer_default = $1.old_pointer_default;
+ is_in_interface = FALSE;
}
| dispinterfacedef semicolon_opt { $$ = $1; }
;
}
;
+storage_cls_spec:
+ tEXTERN { $$ = STG_EXTERN; }
+ | tSTATIC { $$ = STG_STATIC; }
+ | tREGISTER { $$ = STG_REGISTER; }
+ ;
+
function_specifier:
tINLINE { $$ = make_attr(ATTR_INLINE); }
;
decl_spec_no_type:
type_qualifier m_decl_spec_no_type { $$ = make_decl_spec(NULL, $2, NULL, $1, STG_NONE); }
| function_specifier m_decl_spec_no_type { $$ = make_decl_spec(NULL, $2, NULL, $1, STG_NONE); }
+ | storage_cls_spec m_decl_spec_no_type { $$ = make_decl_spec(NULL, $2, NULL, NULL, $1); }
;
declarator:
| declarator_list ',' declarator { $$ = append_declarator( $1, $3 ); }
;
+init_declarator:
+ declarator { $$ = $1; }
+ | declarator '=' expr_const { $$ = $1; $1->var->eval = $3; }
+ ;
+
pointer_type:
tREF { $$ = RPC_FC_RP; }
| tUNIQUE { $$ = RPC_FC_UP; }
/* ATTR_BINDABLE */ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "bindable" },
/* ATTR_BROADCAST */ { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "broadcast" },
/* ATTR_CALLAS */ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "call_as" },
- /* ATTR_CALLCONV */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL },
+ /* ATTR_CALLCONV */ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, NULL },
/* ATTR_CASE */ { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, "case" },
/* ATTR_CONST */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "const" },
/* ATTR_CONTEXTHANDLE */ { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, "context_handle" },
return stmt;
}
-static statement_t *make_statement_init_decl(var_t *var)
+static statement_t *make_statement_declaration(var_t *var)
{
- statement_t *stmt = make_statement(STMT_INITDECL);
- stmt->u.var = var;
- return stmt;
-}
-
-static statement_t *make_statement_extern(var_t *var)
-{
- statement_t *stmt = make_statement(STMT_EXTERN);
+ statement_t *stmt = make_statement(STMT_DECLARATION);
stmt->u.var = var;
+ if (var->stgclass == STG_EXTERN && var->eval)
+ warning("'%s' initialised and declared extern\n", var->name);
+ if (is_const_decl(var))
+ {
+ if (var->eval)
+ reg_const(var);
+ }
+ else if ((var->stgclass == STG_NONE || var->stgclass == STG_REGISTER) &&
+ var->type->type != RPC_FC_FUNCTION)
+ error_loc("instantiation of data is illegal\n");
return stmt;
}
list_add_tail( list, &stmt->entry );
return list;
}
+
+static func_list_t *append_func_from_statement(func_list_t *list, statement_t *stmt)
+{
+ if (stmt->type == STMT_DECLARATION)
+ {
+ var_t *var = stmt->u.var;
+ if (var->stgclass == STG_NONE && var->type->type == RPC_FC_FUNCTION)
+ {
+ check_function_attrs(var->name, var->type->attrs);
+ return append_func(list, make_func(stmt->u.var));
+ }
+ }
+ return list;
+}