widl: Add the parsing of storage classes into declaration-specifiers.
authorRob Shearman <rob@codeweavers.com>
Wed, 30 Apr 2008 14:23:23 +0000 (15:23 +0100)
committerAlexandre Julliard <julliard@winehq.org>
Wed, 30 Apr 2008 14:59:47 +0000 (16:59 +0200)
Support the static and register keywords.

This consolidates externdef and constdef rules into one declaration rule.

tools/widl/header.c
tools/widl/header.h
tools/widl/parser.l
tools/widl/parser.y
tools/widl/widltypes.h

index e3538e66555104f3b05a0e24f083ad8042c0d5ed..6c39bd2e50c3d19995ca07a90b102db52fd7820b 100644 (file)
@@ -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)
index c2cecd5bfb8fcaa1ec7cc43ddec54c9e6ecd2b68..6f2fe25b0d021557d632fbbf908609ca8aee3838 100644 (file)
@@ -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)
 {
index 096f6a0c15e8c1855da05abea5c3078e0636d0a9..1c8868460b3a04df89305930ab3336ccdee1e99c 100644 (file)
@@ -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},
index 42ce54d13b0e6936225d89a3254e2fd382675e06..92c609791ef6cd2e48217bf9f266603b80b8d30a 100644 (file)
@@ -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 <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
@@ -309,10 +313,10 @@ static statement_list_t *append_statement(statement_list_t *list, statement_t *s
 %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
@@ -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;
+}
index 111ea63037a241a5c6f086550bd7d5bc8dacc9b6..c3a39483929a0de9d8ed888aa357fd6fd3e8482c 100644 (file)
@@ -209,8 +209,7 @@ enum storage_class
 enum statement_type
 {
     STMT_LIBRARY,
-    STMT_INITDECL,
-    STMT_EXTERN,
+    STMT_DECLARATION,
     STMT_TYPE,
     STMT_TYPEREF,
     STMT_MODULE,