widl function pointers

Ove Kaaven ovek at arcticnet.no
Wed Feb 11 09:29:59 CST 2004


This implements full function pointer support in widl. Alexandre's
previous patch for it didn't seem like it would know the difference
between int* (*pfn)() and int (**pfn)(), so I've done it differently
(and allowed function pointers in structure fields and typedefs while I
was at it); hence, this patch reverses his patch and implements my way
instead.

Incidentally, that means I also reversed his indentation suppression of
the arguments of these function pointers, but I don't see the "old"
indentation as a problem - after all, MIDL does not suppress indentation
of function pointer arguments, why should widl?

But I could probably submit a patch with Alexandre's indentation changes
preserved if he's really attached to it.

Log:
Implement proper function pointer support.

Index: header.c
===================================================================
RCS file: /home/wine/wine/tools/widl/header.c,v
retrieving revision 1.20
diff -u -r1.20 header.c
--- header.c	7 Jan 2004 04:21:27 -0000	1.20
+++ header.c	11 Feb 2004 15:14:41 -0000
@@ -120,27 +120,39 @@
   if (!v) return;
   if (v->type) {
     indent(0);
-    write_type(h, v->type, NULL, v->tname);
-    if (get_name(v)) {
-      fprintf(h, " ");
+    if (v->type->funcs && !v->type->type) {
+      /* function pointer */
+      var_t *def = v->type->funcs->def;
+      write_type(h, def->type, def, def->tname);
+      fprintf(h, " (STDMETHODCALLTYPE ");
       write_pident(h, v);
+      fprintf(h, ")(\n");
+      write_args(h, v->type->funcs->args, NULL, 0);
+      fprintf(h, ")");
     }
     else {
-      /* not all C/C++ compilers support anonymous structs and unions */
-      switch (v->type->type) {
-      case RPC_FC_STRUCT:
-      case RPC_FC_ENCAPSULATED_UNION:
-        fprintf(h, " DUMMYSTRUCTNAME");
-        break;
-      case RPC_FC_NON_ENCAPSULATED_UNION:
-        fprintf(h, " DUMMYUNIONNAME");
-        break;
-      default:
-        /* ? */
-        break;
+      write_type(h, v->type, NULL, v->tname);
+      if (get_name(v)) {
+        fprintf(h, " ");
+        write_pident(h, v);
       }
+      else {
+        /* not all C/C++ compilers support anonymous structs and unions */
+        switch (v->type->type) {
+        case RPC_FC_STRUCT:
+        case RPC_FC_ENCAPSULATED_UNION:
+          fprintf(h, " DUMMYSTRUCTNAME");
+          break;
+        case RPC_FC_NON_ENCAPSULATED_UNION:
+          fprintf(h, " DUMMYUNIONNAME");
+          break;
+        default:
+          /* ? */
+          break;
+        }
+      }
+      write_array(h, v->array, 1);
     }
-    write_array(h, v->array, 1);
     fprintf(h, ";\n");
   }
 }
@@ -290,13 +302,26 @@
   while (NEXT_LINK(names)) names = NEXT_LINK(names);
   lname = names;
   fprintf(header, "typedef ");
-  write_type(header, type, NULL, tname);
-  fprintf(header, " ");
-  while (names) {
+  if (type->funcs && !type->type) {
+    /* function pointer */
+    var_t *def = type->funcs->def;
+    write_type(header, def->type, def, def->tname);
+    fprintf(header, " (STDMETHODCALLTYPE ");
     write_pident(header, names);
-    if (PREV_LINK(names))
-      fprintf(header, ", ");
-    names = PREV_LINK(names);
+    fprintf(header, ")(\n");
+    write_args(header, type->funcs->args, NULL, 0);
+    fprintf(header, ")");
+    if (PREV_LINK(names)) yyerror("can't emit more than one function pointer per typedef\n");
+  }
+  else {
+    write_type(header, type, NULL, tname);
+    fprintf(header, " ");
+    while (names) {
+      write_pident(header, names);
+      if (PREV_LINK(names))
+        fprintf(header, ", ");
+      names = PREV_LINK(names);
+    }
   }
   fprintf(header, ";\n");
 
@@ -449,19 +474,8 @@
       fprintf(header, ")(%s", arg ? "THIS_ " : "THIS" );
       while (arg) {
 	write_type(header, arg->type, arg, arg->tname);
-        if (arg->args)
-        {
-          fprintf(header, " (STDMETHODCALLTYPE *");
-          write_name(header,arg);
-          fprintf( header,")(");
-          write_args(header, arg->args, NULL, 0, FALSE);
-          fprintf(header,")");
-        }
-        else
-        {
-          fprintf(header, " ");
-          write_name(header,arg);
-        }
+	fprintf(header, " ");
+	write_name(header,arg);
 	write_array(header, arg->array, 0);
 	arg = PREV_LINK(arg);
 	if (arg) fprintf(header, ", ");
@@ -517,53 +531,47 @@
   return idx;
 }
 
-void write_args(FILE *h, var_t *arg, char *name, int method, int do_indent)
+void write_args(FILE *h, var_t *arg, char *name, int method)
 {
   int count = 0;
   if (arg) {
     while (NEXT_LINK(arg))
       arg = NEXT_LINK(arg);
   }
-  if (do_indent)
-  {
-      if (h == header) {
-          indentation++;
-          indent(0);
-      } else fprintf(h, "    ");
-  }
+  if (h == header) {
+    indentation++;
+    indent(0);
+  } else fprintf(h, "    ");
   if (method == 1) {
     fprintf(h, "%s* This", name);
     count++;
   }
   while (arg) {
     if (count) {
-        if (do_indent)
-        {
-            fprintf(h, ",\n");
-            if (h == header) indent(0);
-            else fprintf(h, "    ");
-        }
-        else fprintf(h, ",");
+      fprintf(h, ",\n");
+      if (h == header) indent(0);
+      else fprintf(h, "    ");
     }
-    write_type(h, arg->type, arg, arg->tname);
-    if (arg->args)
-    {
-      fprintf(h, " (STDMETHODCALLTYPE *");
-      write_name(h,arg);
-      fprintf(h, ")(");
-      write_args(h, arg->args, NULL, 0, FALSE);
+    if (arg->type->funcs && !arg->type->type) {
+      /* function pointer */
+      var_t *def = arg->type->funcs->def;
+      write_type(h, def->type, def, def->tname);
+      fprintf(h, " (STDMETHODCALLTYPE ");
+      write_pident(h, arg);
+      fprintf(h, ")(\n");
+      write_args(h, arg->type->funcs->args, NULL, 0);
       fprintf(h, ")");
     }
-    else
-    {
+    else {
+      write_type(h, arg->type, arg, arg->tname);
       fprintf(h, " ");
       write_name(h, arg);
+      write_array(h, arg->array, 0);
     }
-    write_array(h, arg->array, 0);
     arg = PREV_LINK(arg);
     count++;
   }
-  if (do_indent && h == header) indentation--;
+  if (h == header) indentation--;
 }
 
 static void write_cpp_method_def(type_t *iface)
@@ -581,7 +589,7 @@
       fprintf(header, " STDMETHODCALLTYPE ");
       write_name(header, def);
       fprintf(header, "(\n");
-      write_args(header, cur->args, iface->name, 2, TRUE);
+      write_args(header, cur->args, iface->name, 2);
       fprintf(header, ") = 0;\n");
       fprintf(header, "\n");
     }
@@ -607,7 +615,7 @@
       fprintf(header, " (STDMETHODCALLTYPE *");
       write_name(header, def);
       fprintf(header, ")(\n");
-      write_args(header, cur->args, name, 1, TRUE);
+      write_args(header, cur->args, name, 1);
       fprintf(header, ");\n");
       fprintf(header, "\n");
     }
@@ -635,7 +643,7 @@
       fprintf(header, " CALLBACK %s_", iface->name);
       write_name(header, def);
       fprintf(header, "_Proxy(\n");
-      write_args(header, cur->args, iface->name, 1, TRUE);
+      write_args(header, cur->args, iface->name, 1);
       fprintf(header, ");\n");
       /* stub prototype */
       fprintf(header, "void __RPC_STUB %s_", iface->name);
@@ -657,14 +665,14 @@
         fprintf(header, " CALLBACK %s_", iface->name);
         write_name(header, mdef);
         fprintf(header, "_Proxy(\n");
-        write_args(header, m->args, iface->name, 1, TRUE);
+        write_args(header, m->args, iface->name, 1);
         fprintf(header, ");\n");
         /* stub prototype - use remotable prototype */
         write_type(header, def->type, def, def->tname);
         fprintf(header, " __RPC_STUB %s_", iface->name);
         write_name(header, mdef);
         fprintf(header, "_Stub(\n");
-        write_args(header, cur->args, iface->name, 1, TRUE);
+        write_args(header, cur->args, iface->name, 1);
         fprintf(header, ");\n");
       }
       else {
@@ -687,7 +695,7 @@
     fprintf(header, " ");
     write_name(header, def);
     fprintf(header, "(\n");
-    write_args(header, cur->args, iface->name, 0, TRUE);
+    write_args(header, cur->args, iface->name, 0);
     fprintf(header, ");\n");
 
     cur = PREV_LINK(cur);
Index: header.h
===================================================================
RCS file: /home/wine/wine/tools/widl/header.h,v
retrieving revision 1.5
diff -u -r1.5 header.h
--- header.h	7 Jan 2004 04:21:27 -0000	1.5
+++ header.h	11 Feb 2004 15:14:41 -0000
@@ -31,7 +31,7 @@
 extern int is_object(attr_t *a);
 extern int is_local(attr_t *a);
 extern var_t *is_callas(attr_t *a);
-extern void write_args(FILE *h, var_t *arg, char *name, int obj, int do_indent);
+extern void write_args(FILE *h, var_t *arg, char *name, int obj);
 extern void write_forward(type_t *iface);
 extern void write_interface(type_t *iface);
 extern void write_typedef(type_t *type, var_t *names);
Index: parser.y
===================================================================
RCS file: /home/wine/wine/tools/widl/parser.y,v
retrieving revision 1.12
diff -u -r1.12 parser.y
--- parser.y	7 Jan 2004 04:21:27 -0000	1.12
+++ parser.y	11 Feb 2004 15:14:41 -0000
@@ -184,9 +184,10 @@
 %type <type> enumdef structdef typedef uniondef
 %type <ifref> gbl_statements coclass_ints coclass_int
 %type <tref> type
-%type <var> m_args no_args args arg
-%type <var> fields field s_field cases case enums enum_list enum constdef externdef
+%type <var> m_args no_args args arg_list var_spec
+%type <var> fields field cases case enums enum_list enum constdef externdef
 %type <var> m_ident t_ident ident p_ident pident pident_list
+%type <var> funcptr p_funcptr pfuncptr
 %type <var> dispint_props
 %type <func> funcdef int_statements
 %type <func> dispint_meths
@@ -265,29 +266,28 @@
 no_args:  tVOID					{ $$ = NULL; }
 	;
 
-args:	  arg
-	| args ',' arg				{ LINK($3, $1); $$ = $3; }
+args:	  arg_list
 	| no_args
 	;
 
+arg_list: var_spec
+	| args ',' var_spec			{ LINK($3, $1); $$ = $3; }
+	;
+
 /* split into two rules to get bison to resolve a tVOID conflict */
-arg:	  attributes type pident array		{ $$ = $3;
+var_spec: attributes type pident array		{ $$ = $3;
 						  set_type($$, $2, $4);
 						  $$->attrs = $1;
 						}
 	| type pident array			{ $$ = $2;
 						  set_type($$, $1, $3);
 						}
-	| attributes type pident '(' m_args ')'	{ $$ = $3;
-						  $$->ptr_level--;
-						  set_type($$, $2, NULL);
+	| attributes type pfuncptr		{ $$ = $3;
+						  set_type($$->type->funcs->def, $2, NULL);
 						  $$->attrs = $1;
-						  $$->args = $5;
 						}
-	| type pident '(' m_args ')'		{ $$ = $2;
-						  $$->ptr_level--;
-						  set_type($$, $1, NULL);
-						  $$->args = $4;
+	| type pfuncptr				{ $$ = $2;
+						  set_type($$->type->funcs->def, $1, NULL);
 						}
 	;
 
@@ -331,6 +331,7 @@
 	| tIDEMPOTENT				{ $$ = make_attr(ATTR_IDEMPOTENT); }
 	| tIIDIS '(' ident ')'			{ $$ = make_attrp(ATTR_IIDIS, $3); }
 	| tIN					{ $$ = make_attr(ATTR_IN); }
+	| tINPUTSYNC				{ $$ = make_attr(ATTR_INPUTSYNC); }
 	| tLENGTHIS '(' m_exprs ')'		{ $$ = make_attrp(ATTR_LENGTHIS, $3); }
 	| tLOCAL				{ $$ = make_attr(ATTR_LOCAL); }
 	| tOBJECT				{ $$ = make_attr(ATTR_OBJECT); }
@@ -464,15 +465,15 @@
 						}
 	;
 
-field:	  s_field ';'				{ $$ = $1; }
-	| m_attributes uniondef ';'		{ $$ = make_var(NULL); $$->type = $2; $$->attrs = $1; }
+field:	  var_spec ';'				{ $$ = $1; }
+	/* can't use m_attributes here, need to use two uniondef rules, as bison
+	 * gets confused if we don't match the rule split in var_spec */
+	| attributes uniondef ';'		{ $$ = make_var(NULL); $$->type = $2; $$->attrs = $1; }
+	| uniondef ';'				{ $$ = make_var(NULL); $$->type = $1; }
 	| attributes ';'			{ $$ = make_var(NULL); $$->attrs = $1; }
 	| ';'					{ $$ = NULL; }
 	;
 
-s_field:  m_attributes type pident array	{ $$ = $3; set_type($$, $2, $4); $$->attrs = $1; }
-	;
-
 funcdef:
 	  m_attributes type callconv pident
 	  '(' m_args ')'			{ set_type($4, $2, NULL);
@@ -570,7 +571,7 @@
 	;
 
 dispint_props: tPROPERTIES ':'			{ $$ = NULL; }
-	| dispint_props s_field ';'		{ LINK($2, $1); $$ = $2; }
+	| dispint_props var_spec ';'		{ LINK($2, $1); $$ = $2; }
 	;
 
 dispint_meths: tMETHODS ':'			{ $$ = NULL; }
@@ -660,6 +661,30 @@
 	| pident_list ',' pident		{ LINK($3, $1); $$ = $3; }
 	;
 
+funcptr:  '(' p_ident ')'
+	  '(' m_args ')'			{ $$ = $2;
+						  $$->type = make_type(0, NULL);
+						  $$->type->funcs = make_func(make_var(NULL), $5);
+						  if (!$$->ptr_level) yyerror("%s must be a pointer\n", $$->name);
+						}
+	/* for syntactical consistency */
+	| ident
+	  '(' m_args ')'			{ $$ = $1;
+						  $$->type = make_type(0, NULL);
+						  $$->type->funcs = make_func(make_var(NULL), $3);
+						  yyerror("%s must be a pointer\n", $$->name);
+						}
+	;
+
+p_funcptr: '*' pfuncptr %prec PPTR		{ $$ = $2; $$->type->funcs->def->ptr_level++; }
+	| tCONST p_funcptr			{ $$ = $2; /* FIXME */ }
+	;
+
+pfuncptr: funcptr
+	| p_funcptr
+	| '(' pfuncptr ')'			{ $$ = $2; }
+	;
+
 pointer_type:
 	  tREF					{ $$ = RPC_FC_RP; }
 	| tUNIQUE				{ $$ = RPC_FC_UP; }
@@ -691,6 +716,13 @@
 						  if (!parse_only) write_typedef($$, $4);
 						  reg_types($$, $4, 0);
 						}
+	| tTYPEDEF m_attributes type pfuncptr	{
+						  $$ = $4->type;
+						  set_type($$->funcs->def, $3, NULL);
+						  $$->attrs = $2;
+						  if (!parse_only) write_typedef($$, $4);
+						  reg_types($$, $4, 0);
+						}
 	;
 
 uniondef: tUNION t_ident '{' fields '}'		{ $$ = get_typev(RPC_FC_NON_ENCAPSULATED_UNION, $2, tsUNION);
@@ -698,7 +730,7 @@
 						  $$->defined = TRUE;
 						}
 	| tUNION t_ident
-	  tSWITCH '(' s_field ')'
+	  tSWITCH '(' var_spec ')'
 	  m_ident '{' cases '}'			{ var_t *u = $7;
 						  $$ = get_typev(RPC_FC_ENCAPSULATED_UNION, $2, tsUNION);
 						  if (!u) u = make_var("tagged_union");
Index: proxy.c
===================================================================
RCS file: /home/wine/wine/tools/widl/proxy.c,v
retrieving revision 1.9
diff -u -r1.9 proxy.c
--- proxy.c	7 Jan 2004 04:21:27 -0000	1.9
+++ proxy.c	11 Feb 2004 15:14:42 -0000
@@ -71,7 +71,7 @@
   fprintf(proxy, " CALLBACK %s_", iface->name);
   write_name(proxy, def);
   fprintf(proxy, "_Proxy(\n");
-  write_args(proxy, cur->args, iface->name, 1, TRUE);
+  write_args(proxy, cur->args, iface->name, 1);
   fprintf(proxy, ")\n");
   fprintf(proxy, "{\n");
   /* local variables */
Index: widltypes.h
===================================================================
RCS file: /home/wine/wine/tools/widl/widltypes.h,v
retrieving revision 1.11
diff -u -r1.11 widltypes.h
--- widltypes.h	7 Jan 2004 04:21:27 -0000	1.11
+++ widltypes.h	11 Feb 2004 15:14:42 -0000
@@ -161,7 +161,6 @@
   int ptr_level;
   expr_t *array;
   type_t *type;
-  var_t *args;  /* for function pointers */
   char *tname;
   attr_t *attrs;
   expr_t *eval;





More information about the wine-patches mailing list