widl: Construct the pointer chain while parsing pointers, rather than storing a ptr_level.

This method is more flexible and somewhat simpler.
This commit is contained in:
Rob Shearman 2008-04-24 19:03:50 +01:00 committed by Alexandre Julliard
parent 02f5412a53
commit ec81a78f01
2 changed files with 95 additions and 89 deletions

View File

@ -98,11 +98,14 @@ static var_t *make_var(char *name);
static pident_list_t *append_pident(pident_list_t *list, pident_t *p); static pident_list_t *append_pident(pident_list_t *list, pident_t *p);
static pident_t *make_pident(var_t *var); static pident_t *make_pident(var_t *var);
static func_list_t *append_func(func_list_t *list, func_t *func); static func_list_t *append_func(func_list_t *list, func_t *func);
static func_t *make_func(var_t *def, var_list_t *args); static func_t *make_func(var_t *def);
static type_t *make_class(char *name); static type_t *make_class(char *name);
static type_t *make_safearray(type_t *type); static type_t *make_safearray(type_t *type);
static type_t *make_builtin(char *name); static type_t *make_builtin(char *name);
static type_t *make_int(int sign); static type_t *make_int(int sign);
static type_t *make_func_type(var_list_t *args);
static void type_set_function_callconv(type_t *type, char *callconv);
static type_t *append_ptrchain_type(type_t *ptrchain, type_t *type);
static type_t *reg_type(type_t *type, const char *name, int t); static type_t *reg_type(type_t *type, const char *name, int t);
static type_t *reg_typedefs(type_t *type, var_list_t *names, attr_list_t *attrs); static type_t *reg_typedefs(type_t *type, var_list_t *names, attr_list_t *attrs);
@ -690,11 +693,10 @@ s_field: m_attributes type pident array { $$ = $3->var;
funcdef: funcdef:
m_attributes type pident { var_t *v = $3->var; m_attributes type pident { var_t *v = $3->var;
var_list_t *args = $3->args;
v->attrs = check_function_attrs(v->name, $1); v->attrs = check_function_attrs(v->name, $1);
set_type(v, $2, $3, NULL, FALSE); set_type(v, $2, $3, NULL, FALSE);
free($3); free($3);
$$ = make_func(v, args); $$ = make_func(v);
} }
; ;
@ -897,27 +899,23 @@ moduledef: modulehdr '{' int_statements '}'
} }
; ;
pident: '*' pident %prec PPTR { $$ = $2; $$->ptr_level++; } pident: '*' pident %prec PPTR { $$ = $2; $$->type = make_type(pointer_default, $$->type); }
| tCONST pident { $$ = $2; /* FIXME */ } | tCONST pident { $$ = $2; /* FIXME */ }
| callconv pident { $$ = $2; | callconv pident { $$ = $2; type_set_function_callconv($$->func_type, $1); }
if ($$->callconv) parser_warning("multiple calling conventions %s, %s for function %s\n", $$->callconv, $1, $$->var->name);
$$->callconv = $1;
}
| direct_ident | direct_ident
; ;
func_ident: direct_ident '(' m_args ')' func_ident: direct_ident '(' m_args ')'
{ $$ = $1; { $$ = $1;
$1->args = $3; $$->type = append_ptrchain_type($$->type, make_func_type($3));
$1->is_func = TRUE;
} }
; ;
direct_ident: ident { $$ = make_pident($1); } direct_ident: ident { $$ = make_pident($1); }
| '(' pident ')' { $$ = $2; } | '(' pident ')' { $$ = $2; }
| func_ident { $$ = $1; | func_ident { $$ = $1;
$$->func_ptr_level = $$->ptr_level; $$->func_type = $$->type;
$$->ptr_level = 0; $$->type = NULL;
} }
; ;
@ -1170,62 +1168,70 @@ type_t *make_type(unsigned char type, type_t *ref)
return t; return t;
} }
static type_t *make_func_type(var_list_t *args)
{
type_t *t = make_type(RPC_FC_FUNCTION, NULL);
t->fields_or_args = args;
return t;
}
static void type_set_function_callconv(type_t *type, char *callconv)
{
if (!type)
error_loc("calling convention applied to non-function-pointer type\n");
for (; is_ptr(type); type = type->ref)
;
assert(type->type == RPC_FC_FUNCTION);
type->attrs = append_attr(NULL, make_attrp(ATTR_CALLCONV, callconv));
}
static type_t *append_ptrchain_type(type_t *ptrchain, type_t *type)
{
type_t *ptrchain_type;
if (!ptrchain)
return type;
for (ptrchain_type = ptrchain; ptrchain_type->ref; ptrchain_type = ptrchain_type->ref)
;
ptrchain_type->ref = type;
return ptrchain;
}
static void set_type(var_t *v, type_t *type, const pident_t *pident, array_dims_t *arr, static void set_type(var_t *v, type_t *type, const pident_t *pident, array_dims_t *arr,
int top) int top)
{ {
expr_list_t *sizes = get_attrp(v->attrs, ATTR_SIZEIS); expr_list_t *sizes = get_attrp(v->attrs, ATTR_SIZEIS);
expr_list_t *lengs = get_attrp(v->attrs, ATTR_LENGTHIS); expr_list_t *lengs = get_attrp(v->attrs, ATTR_LENGTHIS);
int ptr_attr = get_attrv(v->attrs, ATTR_POINTERTYPE); int ptr_attr = get_attrv(v->attrs, ATTR_POINTERTYPE);
int ptr_type = ptr_attr;
int sizeless, has_varconf; int sizeless, has_varconf;
expr_t *dim; expr_t *dim;
type_t *atype, **ptype; type_t *atype, **ptype;
int ptr_level = (pident ? pident->ptr_level : 0);
v->type = type; /* add type onto the end of the pointers in pident->type */
v->type = append_ptrchain_type(pident ? pident->type : NULL, type);
if (!ptr_type && top) /* the highest level of pointer specified should default to the var's ptr attr
ptr_type = RPC_FC_RP; * or (RPC_FC_RP if not specified and it's a top level ptr), not
* pointer_default so we need to fix that up here */
for ( ; 0 < ptr_level; --ptr_level) if (!arr)
{ {
v->type = make_type(pointer_default, v->type); const type_t *ptr = NULL;
if (ptr_level == 1 && ptr_type && !arr) for (ptr = v->type; ptr; )
{ {
v->type->type = ptr_type; if (ptr->kind == TKIND_ALIAS)
ptr_type = 0; ptr = ptr->orig;
else
break;
} }
} if (ptr && is_ptr(ptr) && (ptr_attr || top))
if (ptr_type && !arr)
{
if (is_ptr(v->type))
{
if (v->type->type != ptr_type)
{ {
/* duplicate type to avoid changing original type */
v->type = duptype(v->type, 1); v->type = duptype(v->type, 1);
v->type->type = ptr_type; v->type->type = ptr_attr ? ptr_attr : RPC_FC_RP;
} }
} else if (ptr_attr)
else if (!arr && ptr_attr)
error_loc("%s: pointer attribute applied to non-pointer type\n", v->name); error_loc("%s: pointer attribute applied to non-pointer type\n", v->name);
} }
if (pident && pident->is_func) {
int func_ptr_level = pident->func_ptr_level;
v->type = make_type(RPC_FC_FUNCTION, v->type);
v->type->fields_or_args = pident->args;
if (pident->callconv)
v->type->attrs = append_attr(NULL, make_attrp(ATTR_CALLCONV, pident->callconv));
else if (is_object_interface) {
static char *stdmethodcalltype;
if (!stdmethodcalltype) stdmethodcalltype = strdup("STDMETHODCALLTYPE");
v->type->attrs = append_attr(NULL, make_attrp(ATTR_CALLCONV, stdmethodcalltype));
}
for (; func_ptr_level > 0; func_ptr_level--)
v->type = make_type(ptr_type, v->type);
}
sizeless = FALSE; sizeless = FALSE;
if (arr) LIST_FOR_EACH_ENTRY_REV(dim, arr, expr_t, entry) if (arr) LIST_FOR_EACH_ENTRY_REV(dim, arr, expr_t, entry)
{ {
@ -1338,6 +1344,26 @@ static void set_type(var_t *v, type_t *type, const pident_t *pident, array_dims_
break; break;
} }
} }
/* v->type is currently pointing the the type on the left-side of the
* declaration, so we need to fix this up so that it is the return type of the
* function and make v->type point to the function side of the declaration */
if (pident && pident->func_type)
{
type_t *t;
type_t *return_type = v->type;
v->type = pident->func_type;
for (t = v->type; is_ptr(t); t = t->ref)
;
assert(t->type == RPC_FC_FUNCTION);
t->ref = return_type;
if (is_object_interface && !is_attr(t->attrs, ATTR_CALLCONV))
{
static char *stdmethodcalltype;
if (!stdmethodcalltype) stdmethodcalltype = strdup("STDMETHODCALLTYPE");
t->attrs = append_attr(NULL, make_attrp(ATTR_CALLCONV, stdmethodcalltype));
}
}
} }
static ifref_list_t *append_ifref(ifref_list_t *list, ifref_t *iface) static ifref_list_t *append_ifref(ifref_list_t *list, ifref_t *iface)
@ -1400,11 +1426,8 @@ static pident_t *make_pident(var_t *var)
{ {
pident_t *p = xmalloc(sizeof(*p)); pident_t *p = xmalloc(sizeof(*p));
p->var = var; p->var = var;
p->is_func = FALSE; p->type = NULL;
p->ptr_level = 0; p->func_type = NULL;
p->func_ptr_level = 0;
p->args = NULL;
p->callconv = NULL;
return p; return p;
} }
@ -1420,11 +1443,11 @@ static func_list_t *append_func(func_list_t *list, func_t *func)
return list; return list;
} }
static func_t *make_func(var_t *def, var_list_t *args) static func_t *make_func(var_t *def)
{ {
func_t *f = xmalloc(sizeof(func_t)); func_t *f = xmalloc(sizeof(func_t));
f->def = def; f->def = def;
f->args = args; f->args = def->type->fields_or_args;
f->ignore = parse_only; f->ignore = parse_only;
f->idx = -1; f->idx = -1;
return f; return f;
@ -1522,9 +1545,7 @@ static void fix_incomplete(void)
static type_t *reg_typedefs(type_t *type, pident_list_t *pidents, attr_list_t *attrs) static type_t *reg_typedefs(type_t *type, pident_list_t *pidents, attr_list_t *attrs)
{ {
type_t *ptr = type;
const pident_t *pident; const pident_t *pident;
int ptrc = 0;
int is_str = is_attr(attrs, ATTR_STRING); int is_str = is_attr(attrs, ATTR_STRING);
unsigned char ptr_type = get_attrv(attrs, ATTR_POINTERTYPE); unsigned char ptr_type = get_attrv(attrs, ATTR_POINTERTYPE);
@ -1562,32 +1583,22 @@ static type_t *reg_typedefs(type_t *type, pident_list_t *pidents, attr_list_t *a
var_t *name = pident->var; var_t *name = pident->var;
if (name->name) { if (name->name) {
type_t *cur = ptr; type_t *cur = append_ptrchain_type(pident->type, type);
int cptr = pident->ptr_level; if (pident->func_type)
if (cptr > ptrc) { {
while (cptr > ptrc) { type_t *t;
cur = ptr = make_type(pointer_default, cur); type_t *return_type = cur;
ptrc++; cur = pident->func_type;
} for (t = cur; is_ptr(t); t = t->ref)
} else { ;
while (cptr < ptrc) { assert(t->type == RPC_FC_FUNCTION);
cur = cur->ref; t->ref = return_type;
cptr++; if (is_object_interface && !is_attr(t->attrs, ATTR_CALLCONV))
} {
}
if (pident->is_func) {
int func_ptr_level = pident->func_ptr_level;
cur = make_type(RPC_FC_FUNCTION, cur);
cur->fields_or_args = pident->args;
if (pident->callconv)
cur->attrs = append_attr(NULL, make_attrp(ATTR_CALLCONV, pident->callconv));
else if (is_object_interface) {
static char *stdmethodcalltype; static char *stdmethodcalltype;
if (!stdmethodcalltype) stdmethodcalltype = strdup("STDMETHODCALLTYPE"); if (!stdmethodcalltype) stdmethodcalltype = strdup("STDMETHODCALLTYPE");
cur->attrs = append_attr(NULL, make_attrp(ATTR_CALLCONV, stdmethodcalltype)); t->attrs = append_attr(NULL, make_attrp(ATTR_CALLCONV, stdmethodcalltype));
} }
for (; func_ptr_level > 0; func_ptr_level--)
cur = make_type(pointer_default, cur);
} }
cur = alias(cur, name->name); cur = alias(cur, name->name);
cur->attrs = attrs; cur->attrs = attrs;

View File

@ -272,13 +272,8 @@ struct _var_t {
struct _pident_t { struct _pident_t {
var_t *var; var_t *var;
int ptr_level; type_t *type;
type_t *func_type;
int is_func;
/* levels of indirection for function pointers */
int func_ptr_level;
var_list_t *args;
char *callconv;
/* parser-internal */ /* parser-internal */
struct list entry; struct list entry;