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:
parent
02f5412a53
commit
ec81a78f01
|
@ -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,60 +1168,68 @@ 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_attr ? ptr_attr : RPC_FC_RP;
|
||||||
v->type->type = ptr_type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!arr && ptr_attr)
|
else if (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;
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue