diff --git a/tools/widl/header.c b/tools/widl/header.c index e3538e66555..6c39bd2e50c 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -477,18 +477,49 @@ void write_typedef(type_t *type) 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) diff --git a/tools/widl/header.h b/tools/widl/header.h index c2cecd5bfb8..6f2fe25b0d0 100644 --- a/tools/widl/header.h +++ b/tools/widl/header.h @@ -57,8 +57,7 @@ extern void write_locals(FILE *fp, const type_t *iface, int body); extern void write_coclass(type_t *cocl); extern void write_coclass_forward(type_t *cocl); extern void write_typedef(type_t *type); -extern void write_constdef(const var_t *v); -extern void write_externdef(const var_t *v); +extern void write_declaration(const var_t *v, int is_in_interface); extern void write_library(const typelib_t *typelib); extern void write_user_types(void); extern void write_context_handle_rundowns(void); @@ -70,6 +69,7 @@ extern const var_t* get_context_handle_var(const func_t* func); extern int has_out_arg_or_return(const func_t *func); extern void write_guid(FILE *f, const char *guid_prefix, const char *name, const UUID *uuid); +extern int is_const_decl(const var_t *var); static inline int last_ptr(const type_t *type) { diff --git a/tools/widl/parser.l b/tools/widl/parser.l index 096f6a0c15e..1c8868460b3 100644 --- a/tools/widl/parser.l +++ b/tools/widl/parser.l @@ -239,10 +239,12 @@ static const struct keyword keywords[] = { {"module", tMODULE}, {"pascal", tPASCAL}, {"properties", tPROPERTIES}, + {"register", tREGISTER}, {"short", tSHORT}, {"signed", tSIGNED}, {"sizeof", tSIZEOF}, {"small", tSMALL}, + {"static", tSTATIC}, {"stdcall", tSTDCALL}, {"struct", tSTRUCT}, {"switch", tSWITCH}, diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 42ce54d13b0..92c609791ef 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -68,6 +68,7 @@ #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; @@ -159,14 +160,14 @@ static void add_explicit_handle_if_necessary(func_t *func); 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 @@ -267,6 +268,7 @@ static statement_list_t *append_statement(statement_list_t *list, statement_t *s %token tPUBLIC %token tRANGE %token tREADONLY tREF +%token tREGISTER %token tREQUESTEDIT %token tRESTRICTED %token tRETVAL @@ -277,6 +279,7 @@ static statement_list_t *append_statement(statement_list_t *list, statement_t *s %token tSIZEIS tSIZEOF %token tSMALL %token tSOURCE +%token tSTATIC %token tSTDCALL %token tSTRICTCONTEXTHANDLE %token tSTRING tSTRUCT @@ -300,6 +303,7 @@ static statement_list_t *append_statement(statement_list_t *list, statement_t *s %type m_expr expr expr_const expr_int_const array %type m_exprs /* exprs expr_list */ expr_list_int_const %type interfacehdr +%type storage_cls_spec %type decl_spec decl_spec_no_type m_decl_spec_no_type %type inherit interface interfacedef interfacedec %type dispinterface dispinterfacehdr dispinterfacedef @@ -309,10 +313,10 @@ static statement_list_t *append_statement(statement_list_t *list, statement_t *s %type type %type coclass_int %type coclass_ints -%type arg ne_union_field union_field s_field case enum constdef externdef +%type arg ne_union_field union_field s_field case enum declaration %type m_args no_args args fields ne_union_fields cases enums enum_list dispint_props field %type m_ident t_ident ident -%type declarator direct_declarator +%type declarator direct_declarator init_declarator %type declarator_list %type funcdef %type int_statements dispint_meths @@ -386,26 +390,23 @@ imp_statements: { $$ = NULL; } ; 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); @@ -616,14 +617,6 @@ case: tCASE expr_int_const ':' union_field { attr_t *a = make_attrp(ATTR_CASE, } ; -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 @@ -736,12 +729,6 @@ expr_const: expr { $$ = $1; } ; -externdef: tEXTERN tCONST decl_spec declarator { $$ = $4->var; - set_type($$, $3, $4, FALSE); - free($4); - } - ; - fields: { $$ = NULL; } | fields field { $$ = append_var_list($1, $2); } ; @@ -785,6 +772,19 @@ funcdef: } ; +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 ; @@ -877,6 +877,7 @@ dispinterface: tDISPINTERFACE aIDENTIFIER { $$ = get_type(0, $2, 0); $$->kind = ; dispinterfacehdr: attributes dispinterface { attr_t *attrs; + is_in_interface = TRUE; is_object_interface = TRUE; $$ = $2; if ($$->defined) error_loc("multiple definition error\n"); @@ -905,6 +906,7 @@ dispinterfacedef: dispinterfacehdr '{' $$->funcs = $4; if (!parse_only && do_header) write_dispinterface($$); if (!parse_only && do_idfile) write_diid($$); + is_in_interface = FALSE; } | dispinterfacehdr '{' interface ';' '}' { $$ = $1; @@ -912,6 +914,7 @@ dispinterfacedef: dispinterfacehdr '{' $$->funcs = $3->funcs; if (!parse_only && do_header) write_dispinterface($$); if (!parse_only && do_idfile) write_diid($$); + is_in_interface = FALSE; } ; @@ -928,6 +931,7 @@ interfacehdr: attributes interface { $$.interface = $2; 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; @@ -945,6 +949,7 @@ interfacedef: interfacehdr inherit 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 */ @@ -959,6 +964,7 @@ interfacedef: interfacehdr inherit 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; } ; @@ -984,6 +990,12 @@ moduledef: modulehdr '{' int_statements '}' } ; +storage_cls_spec: + tEXTERN { $$ = STG_EXTERN; } + | tSTATIC { $$ = STG_STATIC; } + | tREGISTER { $$ = STG_REGISTER; } + ; + function_specifier: tINLINE { $$ = make_attr(ATTR_INLINE); } ; @@ -1008,6 +1020,7 @@ m_decl_spec_no_type: { $$ = NULL; } 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: @@ -1032,6 +1045,11 @@ declarator_list: | 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; } @@ -2228,7 +2246,7 @@ struct allowed_attr allowed_attr[] = /* 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" }, @@ -2754,17 +2772,20 @@ static statement_t *make_statement_reference(type_t *type) 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; } @@ -2847,3 +2868,17 @@ static statement_list_t *append_statement(statement_list_t *list, statement_t *s 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; +} diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index 111ea63037a..c3a39483929 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -209,8 +209,7 @@ enum storage_class enum statement_type { STMT_LIBRARY, - STMT_INITDECL, - STMT_EXTERN, + STMT_DECLARATION, STMT_TYPE, STMT_TYPEREF, STMT_MODULE,