Re: [Cocci] [PATCH 03/26] parsing_cocci: parser: Add direct_declarator/direct_abstract_d rules

2020-03-19 Thread Julia Lawall



On Thu, 19 Mar 2020, Jaskaran Singh wrote:

> On Wed, 2020-03-18 at 18:31 +0100, Julia Lawall wrote:
> >
> > On Mon, 16 Mar 2020, Jaskaran Singh wrote:
> >
> > > The direct_declarator rule and the direct_abstract_d rule are
> > > present in the C parser. Add similar rules to the SmPL parser so
> > > that
> > > declarators are parsed as they are in the C parser.
> > >
> > > For the type ParenType, direct_declarator and direct_abstract_d
> > > only
> > > allow the following productions:
> > >
> > >   ( * id  [ .* ] ) ( params )
> > >
> > > i.e. a function pointer or an array of function pointers. The
> > > compromise
> > > is flexibility in the range of productions, mainly because
> > > collateral
> > > evolutions needed by having a flexible rule are very large and
> > > distasteful.
> >
> > It is not clear what is meant by flexible.  Can you give an example
> > of
> > what will not be supported?
> >
>
> Well, it's mainly anything that uses ParenType for anything other than
> a function pointer or an array of function pointers. Examples of
> productions that aren't supported:
>
> int (**x[])(params); // array of pointer to function pointer
>
> int (*x[][])(params); // array of array of function pointers
>
> int ((*x))(params); // ident wrapped in double parantheses
>
> To be honest, I think the first two and similar ones (i.e. array of
> array of ... pointer to pointer to ) can be supported by
> implementing some kind of loop, but don't know about other
> productions.

OK.  You could add these to the log message for future reference.  The
double parentheses seem like a low priority.  Perhaps the first two could
be useful at some point.

thanks,
julia


>
> Cheers,
> Jaskaran.
>
> > julia
> >
> > > Replace usage of the older d_ident rule in the SmPL parser with the
> > > above mentioned rules. All usages of d_ident, however, have not
> > > been
> > > removed due to reduce/reduce conflicts.
> > >
> > > Remove rules/productions that parse function pointers with usage of
> > > direct_declarator and direct_abstract_d.
> > >
> > > Signed-off-by: Jaskaran Singh 
> > > ---
> > >  parsing_cocci/parser_cocci_menhir.mly | 239 +-
> > > 
> > >  1 file changed, 116 insertions(+), 123 deletions(-)
> > >
> > > diff --git a/parsing_cocci/parser_cocci_menhir.mly
> > > b/parsing_cocci/parser_cocci_menhir.mly
> > > index 26958f63..fade830f 100644
> > > --- a/parsing_cocci/parser_cocci_menhir.mly
> > > +++ b/parsing_cocci/parser_cocci_menhir.mly
> > > @@ -1116,33 +1116,17 @@ struct_decl_one:
> > >   { let (mids,code) = t in
> > >   Ast0.wrap
> > > (Ast0.ConjField(P.id2mcode lp,code,mids, P.id2mcode rp)) }
> > > -| t=ctype d=d_ident_option bf=struct_bitfield? pv=TPtVirg
> > > +| t=ctype d=direct_decl_option(disj_ident) bf=struct_bitfield?
> > > pv=TPtVirg
> > >{ let (id,fn) = d in
> > >Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
> > > -| t=ctype lp1=TOPar st=TMul d=d_ident_option rp1=TCPar
> > > - lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
> > > - bf=struct_bitfield? pv=TPtVirg
> > > -{ let (id,fn) = d in
> > > -let t =
> > > -   Ast0.wrap
> > > - (Ast0.FunctionPointer
> > > -(t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode
> > > ")" rp1,
> > > - P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
> > > -Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
> > > - | cv=ioption(const_vol) i=pure_ident_or_symbol
> > > d=d_ident_option
> > > +| cv=ioption(const_vol) i=pure_ident_or_symbol
> > > +  d=direct_decl_option(disj_ident)
> > >bf=struct_bitfield?
> > >pv=TPtVirg
> > >{ let (id,fn) = d in
> > >let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode
> > > i))) in
> > >Ast0.wrap(Ast0.Field(fn idtype,id,bf,P.clt2mcode ";" pv)) }
> > >
> > > -d_ident_option:
> > > -  { None, (fun x -> x) }
> > > - | d=d_ident {
> > > -   let (id, fn) = d in
> > > -   (Some id, fn)
> > > -}
> > > -
> > >  struct_bitfield:
> > > c=TDotDot e=expr { (P.clt2mcode ":" c, e) }
> > >
> > > @@ -1529,17 +1513,9 @@ storage:
> > > | s=Tregister{ P.clt2mcode Ast.Register s }
> > > | s=Textern  { P.clt2mcode Ast.Extern s }
> > >
> > > -decl: t=ctype i=disj_ident a=list(array_dec)
> > > - { let t = P.arrayify t a in Ast0.wrap(Ast0.Param(t, Some i)) }
> > > +decl: t=ctype d=direct_declarator(disj_ident)
> > > + { let (i,fn) = d in Ast0.wrap(Ast0.Param(fn t, Some i)) }
> > >  | t=ctype { (*verify in FunDecl*) Ast0.wrap(Ast0.Param(t,
> > > None)) }
> > > -| t=ctype lp=TOPar s=TMul i=disj_ident rp=TCPar
> > > - lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
> > > -{ let fnptr =
> > > -   Ast0.wrap
> > > - (Ast0.FunctionPointer
> > > -(t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")"
> > > rp,
> > > - P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in
> > > - Ast0.wrap(Ast0.Param(fnptr, Some i)) }
> > >  | TMetaParam
> > >   { 

Re: [Cocci] [PATCH 03/26] parsing_cocci: parser: Add direct_declarator/direct_abstract_d rules

2020-03-18 Thread Jaskaran Singh
On Wed, 2020-03-18 at 18:31 +0100, Julia Lawall wrote:
> 
> On Mon, 16 Mar 2020, Jaskaran Singh wrote:
> 
> > The direct_declarator rule and the direct_abstract_d rule are
> > present in the C parser. Add similar rules to the SmPL parser so
> > that
> > declarators are parsed as they are in the C parser.
> > 
> > For the type ParenType, direct_declarator and direct_abstract_d
> > only
> > allow the following productions:
> > 
> > ( * id  [ .* ] ) ( params )
> > 
> > i.e. a function pointer or an array of function pointers. The
> > compromise
> > is flexibility in the range of productions, mainly because
> > collateral
> > evolutions needed by having a flexible rule are very large and
> > distasteful.
> 
> It is not clear what is meant by flexible.  Can you give an example
> of
> what will not be supported?
> 

Well, it's mainly anything that uses ParenType for anything other than
a function pointer or an array of function pointers. Examples of
productions that aren't supported:

int (**x[])(params); // array of pointer to function pointer

int (*x[][])(params); // array of array of function pointers

int ((*x))(params); // ident wrapped in double parantheses

To be honest, I think the first two and similar ones (i.e. array of
array of ... pointer to pointer to ) can be supported by
implementing some kind of loop, but don't know about other
productions.

Cheers,
Jaskaran.

> julia
> 
> > Replace usage of the older d_ident rule in the SmPL parser with the
> > above mentioned rules. All usages of d_ident, however, have not
> > been
> > removed due to reduce/reduce conflicts.
> > 
> > Remove rules/productions that parse function pointers with usage of
> > direct_declarator and direct_abstract_d.
> > 
> > Signed-off-by: Jaskaran Singh 
> > ---
> >  parsing_cocci/parser_cocci_menhir.mly | 239 +-
> > 
> >  1 file changed, 116 insertions(+), 123 deletions(-)
> > 
> > diff --git a/parsing_cocci/parser_cocci_menhir.mly
> > b/parsing_cocci/parser_cocci_menhir.mly
> > index 26958f63..fade830f 100644
> > --- a/parsing_cocci/parser_cocci_menhir.mly
> > +++ b/parsing_cocci/parser_cocci_menhir.mly
> > @@ -1116,33 +1116,17 @@ struct_decl_one:
> > { let (mids,code) = t in
> > Ast0.wrap
> >   (Ast0.ConjField(P.id2mcode lp,code,mids, P.id2mcode rp)) }
> > -| t=ctype d=d_ident_option bf=struct_bitfield? pv=TPtVirg
> > +| t=ctype d=direct_decl_option(disj_ident) bf=struct_bitfield?
> > pv=TPtVirg
> >  { let (id,fn) = d in
> >  Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
> > -| t=ctype lp1=TOPar st=TMul d=d_ident_option rp1=TCPar
> > -   lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
> > -   bf=struct_bitfield? pv=TPtVirg
> > -{ let (id,fn) = d in
> > -let t =
> > - Ast0.wrap
> > -   (Ast0.FunctionPointer
> > -  (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode
> > ")" rp1,
> > -   P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
> > -Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
> > - | cv=ioption(const_vol) i=pure_ident_or_symbol
> > d=d_ident_option
> > +| cv=ioption(const_vol) i=pure_ident_or_symbol
> > +  d=direct_decl_option(disj_ident)
> >  bf=struct_bitfield?
> >  pv=TPtVirg
> >  { let (id,fn) = d in
> >  let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode
> > i))) in
> >  Ast0.wrap(Ast0.Field(fn idtype,id,bf,P.clt2mcode ";" pv)) }
> > 
> > -d_ident_option:
> > -{ None, (fun x -> x) }
> > - | d=d_ident {
> > -   let (id, fn) = d in
> > -   (Some id, fn)
> > -}
> > -
> >  struct_bitfield:
> > c=TDotDot e=expr { (P.clt2mcode ":" c, e) }
> > 
> > @@ -1529,17 +1513,9 @@ storage:
> > | s=Tregister{ P.clt2mcode Ast.Register s }
> > | s=Textern  { P.clt2mcode Ast.Extern s }
> > 
> > -decl: t=ctype i=disj_ident a=list(array_dec)
> > -   { let t = P.arrayify t a in Ast0.wrap(Ast0.Param(t, Some i)) }
> > +decl: t=ctype d=direct_declarator(disj_ident)
> > +   { let (i,fn) = d in Ast0.wrap(Ast0.Param(fn t, Some i)) }
> >  | t=ctype { (*verify in FunDecl*) Ast0.wrap(Ast0.Param(t,
> > None)) }
> > -| t=ctype lp=TOPar s=TMul i=disj_ident rp=TCPar
> > -   lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
> > -{ let fnptr =
> > - Ast0.wrap
> > -   (Ast0.FunctionPointer
> > -  (t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")"
> > rp,
> > -   P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in
> > -   Ast0.wrap(Ast0.Param(fnptr, Some i)) }
> >  | TMetaParam
> > { let (nm,cstr,pure,clt) = $1 in
> > Ast0.wrap(Ast0.MetaParam(P.clt2mcode nm clt,cstr,pure)) }
> > @@ -1547,14 +1523,6 @@ decl: t=ctype i=disj_ident a=list(array_dec)
> > 
> >  name_opt_decl:
> >decl  { $1 }
> > -| t=ctype lp=TOPar s=TMul rp=TCPar
> > -   lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
> > -{ let fnptr =
> > - Ast0.wrap
> > -   (Ast0.FunctionPointer
> > -  

Re: [Cocci] [PATCH 03/26] parsing_cocci: parser: Add direct_declarator/direct_abstract_d rules

2020-03-18 Thread Julia Lawall



On Mon, 16 Mar 2020, Jaskaran Singh wrote:

> The direct_declarator rule and the direct_abstract_d rule are
> present in the C parser. Add similar rules to the SmPL parser so that
> declarators are parsed as they are in the C parser.
>
> For the type ParenType, direct_declarator and direct_abstract_d only
> allow the following productions:
>
>   ( * id  [ .* ] ) ( params )
>
> i.e. a function pointer or an array of function pointers. The compromise
> is flexibility in the range of productions, mainly because collateral
> evolutions needed by having a flexible rule are very large and
> distasteful.

It is not clear what is meant by flexible.  Can you give an example of
what will not be supported?

julia

> Replace usage of the older d_ident rule in the SmPL parser with the
> above mentioned rules. All usages of d_ident, however, have not been
> removed due to reduce/reduce conflicts.
>
> Remove rules/productions that parse function pointers with usage of
> direct_declarator and direct_abstract_d.
>
> Signed-off-by: Jaskaran Singh 
> ---
>  parsing_cocci/parser_cocci_menhir.mly | 239 +-
>  1 file changed, 116 insertions(+), 123 deletions(-)
>
> diff --git a/parsing_cocci/parser_cocci_menhir.mly 
> b/parsing_cocci/parser_cocci_menhir.mly
> index 26958f63..fade830f 100644
> --- a/parsing_cocci/parser_cocci_menhir.mly
> +++ b/parsing_cocci/parser_cocci_menhir.mly
> @@ -1116,33 +1116,17 @@ struct_decl_one:
>   { let (mids,code) = t in
>   Ast0.wrap
> (Ast0.ConjField(P.id2mcode lp,code,mids, P.id2mcode rp)) }
> -| t=ctype d=d_ident_option bf=struct_bitfield? pv=TPtVirg
> +| t=ctype d=direct_decl_option(disj_ident) bf=struct_bitfield? pv=TPtVirg
>{ let (id,fn) = d in
>Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
> -| t=ctype lp1=TOPar st=TMul d=d_ident_option rp1=TCPar
> - lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
> - bf=struct_bitfield? pv=TPtVirg
> -{ let (id,fn) = d in
> -let t =
> -   Ast0.wrap
> - (Ast0.FunctionPointer
> -(t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1,
> - P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
> -Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
> - | cv=ioption(const_vol) i=pure_ident_or_symbol d=d_ident_option
> +| cv=ioption(const_vol) i=pure_ident_or_symbol
> +  d=direct_decl_option(disj_ident)
>bf=struct_bitfield?
>pv=TPtVirg
>{ let (id,fn) = d in
>let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
>Ast0.wrap(Ast0.Field(fn idtype,id,bf,P.clt2mcode ";" pv)) }
>
> -d_ident_option:
> -  { None, (fun x -> x) }
> - | d=d_ident {
> -   let (id, fn) = d in
> -   (Some id, fn)
> -}
> -
>  struct_bitfield:
> c=TDotDot e=expr { (P.clt2mcode ":" c, e) }
>
> @@ -1529,17 +1513,9 @@ storage:
> | s=Tregister{ P.clt2mcode Ast.Register s }
> | s=Textern  { P.clt2mcode Ast.Extern s }
>
> -decl: t=ctype i=disj_ident a=list(array_dec)
> - { let t = P.arrayify t a in Ast0.wrap(Ast0.Param(t, Some i)) }
> +decl: t=ctype d=direct_declarator(disj_ident)
> + { let (i,fn) = d in Ast0.wrap(Ast0.Param(fn t, Some i)) }
>  | t=ctype { (*verify in FunDecl*) Ast0.wrap(Ast0.Param(t, None)) }
> -| t=ctype lp=TOPar s=TMul i=disj_ident rp=TCPar
> - lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
> -{ let fnptr =
> -   Ast0.wrap
> - (Ast0.FunctionPointer
> -(t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp,
> - P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in
> - Ast0.wrap(Ast0.Param(fnptr, Some i)) }
>  | TMetaParam
>   { let (nm,cstr,pure,clt) = $1 in
>   Ast0.wrap(Ast0.MetaParam(P.clt2mcode nm clt,cstr,pure)) }
> @@ -1547,14 +1523,6 @@ decl: t=ctype i=disj_ident a=list(array_dec)
>
>  name_opt_decl:
>decl  { $1 }
> -| t=ctype lp=TOPar s=TMul rp=TCPar
> - lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
> -{ let fnptr =
> -   Ast0.wrap
> - (Ast0.FunctionPointer
> -(t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp,
> - P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in
> - Ast0.wrap(Ast0.Param(fnptr, None)) }
>
>  const_vol:
>Tconst   { P.clt2mcode Ast.Const $1 }
> @@ -1684,13 +1652,15 @@ decl_var:
>  t=ctype pv=TPtVirg
>{ [Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv))] }
>| TMetaDecl { [P.meta_decl $1] }
> -  | s=ioption(storage) t=ctype d=comma_list(d_ident) pv=TPtVirg
> +  | s=ioption(storage) t=ctype
> +  d=comma_list(direct_declarator(disj_ident)) pv=TPtVirg
>{ List.map
> (function (id,fn) ->
>   Ast0.wrap(Ast0.UnInit(s,fn t,id,[],P.clt2mcode ";" pv)))
> d }
>| f=funproto { [f] }
> -  | s=ioption(storage) t=ctype d=d_ident a=attr_list q=TEq e=initialize
> +  | s=ioption(storage) t=ctype 

[Cocci] [PATCH 03/26] parsing_cocci: parser: Add direct_declarator/direct_abstract_d rules

2020-03-16 Thread Jaskaran Singh
The direct_declarator rule and the direct_abstract_d rule are
present in the C parser. Add similar rules to the SmPL parser so that
declarators are parsed as they are in the C parser.

For the type ParenType, direct_declarator and direct_abstract_d only
allow the following productions:

( * id  [ .* ] ) ( params )

i.e. a function pointer or an array of function pointers. The compromise
is flexibility in the range of productions, mainly because collateral
evolutions needed by having a flexible rule are very large and
distasteful.

Replace usage of the older d_ident rule in the SmPL parser with the
above mentioned rules. All usages of d_ident, however, have not been
removed due to reduce/reduce conflicts.

Remove rules/productions that parse function pointers with usage of
direct_declarator and direct_abstract_d.

Signed-off-by: Jaskaran Singh 
---
 parsing_cocci/parser_cocci_menhir.mly | 239 +-
 1 file changed, 116 insertions(+), 123 deletions(-)

diff --git a/parsing_cocci/parser_cocci_menhir.mly 
b/parsing_cocci/parser_cocci_menhir.mly
index 26958f63..fade830f 100644
--- a/parsing_cocci/parser_cocci_menhir.mly
+++ b/parsing_cocci/parser_cocci_menhir.mly
@@ -1116,33 +1116,17 @@ struct_decl_one:
{ let (mids,code) = t in
Ast0.wrap
  (Ast0.ConjField(P.id2mcode lp,code,mids, P.id2mcode rp)) }
-| t=ctype d=d_ident_option bf=struct_bitfield? pv=TPtVirg
+| t=ctype d=direct_decl_option(disj_ident) bf=struct_bitfield? pv=TPtVirg
 { let (id,fn) = d in
 Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
-| t=ctype lp1=TOPar st=TMul d=d_ident_option rp1=TCPar
-   lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
-   bf=struct_bitfield? pv=TPtVirg
-{ let (id,fn) = d in
-let t =
- Ast0.wrap
-   (Ast0.FunctionPointer
-  (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1,
-   P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
-Ast0.wrap(Ast0.Field(fn t,id,bf,P.clt2mcode ";" pv)) }
- | cv=ioption(const_vol) i=pure_ident_or_symbol d=d_ident_option
+| cv=ioption(const_vol) i=pure_ident_or_symbol
+  d=direct_decl_option(disj_ident)
 bf=struct_bitfield?
 pv=TPtVirg
 { let (id,fn) = d in
 let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
 Ast0.wrap(Ast0.Field(fn idtype,id,bf,P.clt2mcode ";" pv)) }
 
-d_ident_option:
-{ None, (fun x -> x) }
- | d=d_ident {
-   let (id, fn) = d in
-   (Some id, fn)
-}
-
 struct_bitfield:
c=TDotDot e=expr { (P.clt2mcode ":" c, e) }
 
@@ -1529,17 +1513,9 @@ storage:
| s=Tregister{ P.clt2mcode Ast.Register s }
| s=Textern  { P.clt2mcode Ast.Extern s }
 
-decl: t=ctype i=disj_ident a=list(array_dec)
-   { let t = P.arrayify t a in Ast0.wrap(Ast0.Param(t, Some i)) }
+decl: t=ctype d=direct_declarator(disj_ident)
+   { let (i,fn) = d in Ast0.wrap(Ast0.Param(fn t, Some i)) }
 | t=ctype { (*verify in FunDecl*) Ast0.wrap(Ast0.Param(t, None)) }
-| t=ctype lp=TOPar s=TMul i=disj_ident rp=TCPar
-   lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
-{ let fnptr =
- Ast0.wrap
-   (Ast0.FunctionPointer
-  (t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp,
-   P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in
-   Ast0.wrap(Ast0.Param(fnptr, Some i)) }
 | TMetaParam
{ let (nm,cstr,pure,clt) = $1 in
Ast0.wrap(Ast0.MetaParam(P.clt2mcode nm clt,cstr,pure)) }
@@ -1547,14 +1523,6 @@ decl: t=ctype i=disj_ident a=list(array_dec)
 
 name_opt_decl:
   decl  { $1 }
-| t=ctype lp=TOPar s=TMul rp=TCPar
-   lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
-{ let fnptr =
- Ast0.wrap
-   (Ast0.FunctionPointer
-  (t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp,
-   P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in
-   Ast0.wrap(Ast0.Param(fnptr, None)) }
 
 const_vol:
   Tconst   { P.clt2mcode Ast.Const $1 }
@@ -1684,13 +1652,15 @@ decl_var:
 t=ctype pv=TPtVirg
   { [Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv))] }
   | TMetaDecl { [P.meta_decl $1] }
-  | s=ioption(storage) t=ctype d=comma_list(d_ident) pv=TPtVirg
+  | s=ioption(storage) t=ctype
+  d=comma_list(direct_declarator(disj_ident)) pv=TPtVirg
   { List.map
  (function (id,fn) ->
Ast0.wrap(Ast0.UnInit(s,fn t,id,[],P.clt2mcode ";" pv)))
  d }
   | f=funproto { [f] }
-  | s=ioption(storage) t=ctype d=d_ident a=attr_list q=TEq e=initialize
+  | s=ioption(storage) t=ctype d=direct_declarator(disj_ident)
+a=attr_list q=TEq e=initialize
   pv=TPtVirg
   {let (id,fn) = d in
   [Ast0.wrap
@@ -1711,18 +1681,6 @@ decl_var:
   let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
   [Ast0.wrap(Ast0.Init(s,fn idtype,id,a,P.clt2mcode "=" q,e,