Release coccinelle-0.2.4
[bpt/coccinelle.git] / parsing_cocci / parser_cocci_menhir.mly
index 198bb27..7ab9278 100644 (file)
  */
 
 
+/*
+ * Copyright 2010, INRIA, University of Copenhagen
+ * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
+ * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
+ * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
+ * This file is part of Coccinelle.
+ *
+ * Coccinelle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, according to version 2 of the License.
+ *
+ * Coccinelle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Coccinelle.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The authors reserve the right to distribute this or future versions of
+ * Coccinelle under other licenses.
+ */
+
+
 %{
 
 (* Not clear how to allow function declarations to specify a return type
@@ -40,7 +64,7 @@ module P = Parse_aux
 %token EOF
 
 %token TIdentifier TExpression TStatement TFunction TLocal TType TParameter
-%token TIdExpression TInitialiser
+%token TIdExpression TInitialiser TDeclaration TField
 %token Tlist TFresh TConstant TError TWords TWhy0 TPlus0 TBang0
 %token TPure TContext TGenerated
 %token TTypedef TDeclarer TIterator TName TPosition TPosAny
@@ -49,6 +73,7 @@ module P = Parse_aux
 %token<string> TRuleName
 
 %token<Data.clt> Tchar Tshort Tint Tdouble Tfloat Tlong
+%token<Data.clt> Tsize_t Tssize_t Tptrdiff_t
 %token<Data.clt> Tvoid Tstruct Tunion Tenum
 %token<Data.clt> Tunsigned Tsigned
 
@@ -65,7 +90,7 @@ module P = Parse_aux
 %token <Parse_aux.idinfo>        TMetaIterator TMetaDeclarer
 %token <Parse_aux.expinfo>       TMetaErr
 %token <Parse_aux.info>          TMetaParam TMetaStm TMetaStmList TMetaType
-%token <Parse_aux.info>          TMetaInit
+%token <Parse_aux.info>          TMetaInit TMetaDecl TMetaField
 %token <Parse_aux.list_info>     TMetaParamList TMetaExpList
 %token <Parse_aux.typed_expinfo> TMetaExp TMetaIdExp TMetaLocalIdExp TMetaConst
 %token <Parse_aux.pos_info>      TMetaPos
@@ -96,7 +121,7 @@ module P = Parse_aux
 %token <Data.clt> TAnd
 %token <Data.clt> TEqEq TNotEq TTildeEq TTildeExclEq TSub
 %token <Ast_cocci.logicalOp * Data.clt> TLogOp /* TInf TSup TInfEq TSupEq */
-%token <Ast_cocci.arithOp * Data.clt>   TShOp  /* TShl TShr */
+%token <Ast_cocci.arithOp * Data.clt>   TShLOp TShROp  /* TShl TShr */
 %token <Ast_cocci.arithOp * Data.clt>   TDmOp  /* TDiv TMod */
 %token <Data.clt> TPlus TMinus
 %token <Data.clt> TMul TTilde
@@ -128,7 +153,7 @@ module P = Parse_aux
 %left TAnd
 %left TEqEq TNotEq
 %left TLogOp /* TInf TSup TInfEq TSupEq */
-%left TShOp /* TShl TShr */
+%left TShLOp TShROp /* TShl TShr */
 %left TPlus TMinus
 %left TMul TDmOp /* TDiv TMod */
 
@@ -161,7 +186,7 @@ rule_name
 %start meta_main
 %type <(Ast_cocci.metavar,Ast_cocci.metavar) Common.either list> meta_main
 
-%start <(string option (*string*) * string option (*ast*)) * Ast_cocci.meta_name * Ast_cocci.metavar> script_meta_main
+%start <(string option (*string*) * string option (*ast*)) * (Ast_cocci.meta_name * Ast_cocci.metavar) option> script_meta_main
 
 %start iso_main
 %type <Ast0_cocci.anything list list> iso_main
@@ -210,8 +235,8 @@ rule_name:
       /* these rules have no name as a cheap way to ensure that no normal
       rule inherits their metavariables or depends on them */
       { P.make_generated_rule_name_result None d i a e ee }
-  | TScript TDotDot lang=pure_ident d=depends TArob
-      { P.make_script_rule_name_result lang d }
+  | TScript TDotDot lang=pure_ident nm=ioption(pure_ident) d=depends TArob
+      { P.make_script_rule_name_result lang nm d }
   | TInitialize TDotDot lang=pure_ident d=depends TArob
       { P.make_initial_script_rule_name_result lang d }
   | TFinalize TDotDot lang=pure_ident d=depends TArob
@@ -314,23 +339,25 @@ metadec:
       !Data.add_pos_meta name constraints any; tok in
     P.create_metadec_with_constraints ar false kindfn ids }
 | ar=arity ispure=pure
-    TParameter Tlist TOCro id=pure_ident_or_meta_ident TCCro
+    TParameter Tlist TOCro len=list_len TCCro
     ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
     { P.create_len_metadec ar ispure
        (fun lenname arity name pure check_meta ->
-         let tok =
-           check_meta(Ast.MetaParamListDecl(arity,name,Some lenname)) in
-         !Data.add_paramlist_meta name (Some lenname) pure; tok)
-       id ids }
+         let tok = check_meta(Ast.MetaParamListDecl(arity,name,lenname)) in
+         !Data.add_paramlist_meta name lenname pure; tok)
+       len ids }
 | ar=arity ispure=pure
-    TExpression Tlist TOCro id=pure_ident_or_meta_ident TCCro
+    TExpression Tlist TOCro len=list_len TCCro
     ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
     { P.create_len_metadec ar ispure
        (fun lenname arity name pure check_meta ->
-         let tok =
-           check_meta(Ast.MetaExpListDecl(arity,name,Some lenname)) in
-         !Data.add_explist_meta name (Some lenname) pure; tok)
-       id ids }
+         let tok = check_meta(Ast.MetaExpListDecl(arity,name,lenname)) in
+         !Data.add_explist_meta name lenname pure; tok)
+       len ids }
+
+list_len:
+  pure_ident_or_meta_ident { Common.Left $1 }
+| TInt { let (x,clt) = $1 in Common.Right (int_of_string x) }
 
 %inline metakind_fresh:
   TFresh TIdentifier
@@ -346,12 +373,14 @@ metadec:
       !Data.add_param_meta name pure; tok) }
 | TParameter Tlist
     { (fun arity name pure check_meta ->
-      let tok = check_meta(Ast.MetaParamListDecl(arity,name,None)) in
-      !Data.add_paramlist_meta name None pure; tok) }
+      let len = Ast.AnyLen in
+      let tok = check_meta(Ast.MetaParamListDecl(arity,name,len)) in
+      !Data.add_paramlist_meta name len pure; tok) }
 | TExpression Tlist
     { (fun arity name pure check_meta ->
-      let tok = check_meta(Ast.MetaExpListDecl(arity,name,None)) in
-      !Data.add_explist_meta name None pure; tok) }
+      let len = Ast.AnyLen in
+      let tok = check_meta(Ast.MetaExpListDecl(arity,name,len)) in
+      !Data.add_explist_meta name len pure; tok) }
 | TType
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaTypeDecl(arity,name)) in
@@ -364,6 +393,14 @@ metadec:
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaStmDecl(arity,name)) in
       !Data.add_stm_meta name pure; tok) }
+| TDeclaration
+    { (fun arity name pure check_meta ->
+      let tok = check_meta(Ast.MetaDeclDecl(arity,name)) in
+      !Data.add_decl_meta name pure; tok) }
+| TField
+    { (fun arity name pure check_meta ->
+      let tok = check_meta(Ast.MetaFieldDecl(arity,name)) in
+      !Data.add_field_meta name pure; tok) }
 | TStatement Tlist
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaStmListDecl(arity,name)) in
@@ -443,14 +480,9 @@ metadec:
       | Some _ ->
          !Data.add_local_idexp_meta ty name constraints pure;
          check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) }
-| TExpression m=nonempty_list(TMul)
-    { (fun arity name pure check_meta constraints ->
-      let ty = Some [P.ty_pointerify Type_cocci.Unknown m] in
-      let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in
-      !Data.add_exp_meta ty name constraints pure; tok) }
-| vl=meta_exp_type TOCro TCCro
+| TExpression ty=expression_type
     { (fun arity name pure check_meta constraints ->
-      let ty = Some (List.map (function x -> Type_cocci.Array x) vl) in
+      let ty = Some [ty] in
       let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in
       !Data.add_exp_meta ty name constraints pure; tok) }
 | TConstant ty=ioption(meta_exp_type)
@@ -458,6 +490,17 @@ metadec:
       let tok = check_meta(Ast.MetaConstDecl(arity,name,ty)) in
       !Data.add_const_meta ty name constraints pure; tok) }
 
+expression_type:
+  m=nonempty_list(TMul) { P.ty_pointerify Type_cocci.Unknown m }
+| Tenum m=list(TMul)
+    { P.ty_pointerify (Type_cocci.EnumName Type_cocci.NoName) m }
+| Tstruct m=list(TMul)
+    { P.ty_pointerify
+       (Type_cocci.StructUnionName (Type_cocci.Struct,Type_cocci.NoName)) m }
+| Tunion m=list(TMul)
+    { P.ty_pointerify
+       (Type_cocci.StructUnionName (Type_cocci.Union,Type_cocci.NoName)) m }
+
 %inline metakind_atomic_expe:
   TExpression
     { (fun arity name pure check_meta constraints ->
@@ -489,10 +532,11 @@ metadec:
       !Data.add_exp_meta ty name constraints pure; tok)
     }
 
-
 meta_exp_type:
   t=typedef_ctype
     { [Ast0_cocci.ast0_type_to_type t] }
+| t=typedef_ctype TOCro TCCro
+    { [Type_cocci.Array (Ast0_cocci.ast0_type_to_type t)] }
 | TOBrace t=comma_list(ctype) TCBrace m=list(TMul)
     { List.map
        (function x -> P.ty_pointerify (Ast0_cocci.ast0_type_to_type x) m)
@@ -539,8 +583,19 @@ non_signable_types:
     { Ast0.wrap(Ast0.BaseType(Ast.DoubleType,[P.clt2mcode "double" ty])) }
 | ty=Tfloat
     { Ast0.wrap(Ast0.BaseType(Ast.FloatType,[P.clt2mcode "float" ty])) }
+| ty=Tsize_t
+    { Ast0.wrap(Ast0.BaseType(Ast.SizeType,[P.clt2mcode "size_t" ty])) }
+| ty=Tssize_t
+    { Ast0.wrap(Ast0.BaseType(Ast.SSizeType,[P.clt2mcode "ssize_t" ty])) }
+| ty=Tptrdiff_t
+    { Ast0.wrap(Ast0.BaseType(Ast.PtrDiffType,[P.clt2mcode "ptrdiff_t" ty])) }
 | s=Tenum i=ident
-    { Ast0.wrap(Ast0.EnumName(P.clt2mcode "enum" s, i)) }
+    { Ast0.wrap(Ast0.EnumName(P.clt2mcode "enum" s, Some i)) }
+| s=Tenum i=ioption(ident) l=TOBrace ids=enum_decl_list r=TCBrace
+    { (if i = None && !Data.in_iso
+    then failwith "enums must be named in the iso file");
+      Ast0.wrap(Ast0.EnumDef(Ast0.wrap(Ast0.EnumName(P.clt2mcode "enum" s, i)),
+                            P.clt2mcode "{" l, ids, P.clt2mcode "}" r)) }
 | s=struct_or_union i=ident
     { Ast0.wrap(Ast0.StructUnionName(s, Some i)) }
 | s=struct_or_union i=ioption(ident)
@@ -594,10 +649,14 @@ struct_or_union:
      | u=Tunion  { P.clt2mcode Ast.Union u }
 
 struct_decl:
-      TNothing { [] }
+      TNothing        { [] }
+    | struct_decl_one { [$1] }
+
+struct_decl_one:
+    | TMetaField { P.meta_field $1 }
     | t=ctype d=d_ident pv=TPtVirg
         { let (id,fn) = d in
-        [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] }
+        Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv)) }
     | t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
        lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar pv=TPtVirg
         { let (id,fn) = d in
@@ -606,11 +665,11 @@ struct_decl:
            (Ast0.FunctionPointer
               (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1,
                P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
-        [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] }
+        Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv)) }
      | cv=ioption(const_vol) i=pure_ident d=d_ident pv=TPtVirg
         { let (id,fn) = d in
         let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
-        [Ast0.wrap(Ast0.UnInit(None,fn idtype,id,P.clt2mcode ";" pv))] }
+        Ast0.wrap(Ast0.UnInit(None,fn idtype,id,P.clt2mcode ";" pv)) }
 
 struct_decl_list:
    struct_decl_list_start { Ast0.wrap(Ast0.DOTS($1)) }
@@ -618,8 +677,8 @@ struct_decl_list:
 struct_decl_list_start:
   struct_decl                        { $1 }
 | struct_decl struct_decl_list_start { $1@$2 }
-| d=edots_when(TEllipsis,struct_decl) r=continue_struct_decl_list
-    { (P.mkddots "..." d)::r }
+| d=edots_when(TEllipsis,struct_decl_one) r=continue_struct_decl_list
+    { (P.mkddots_one "..." d)::r }
 
 continue_struct_decl_list:
   /* empty */                        { [] }
@@ -627,6 +686,40 @@ continue_struct_decl_list:
 | struct_decl                        { $1 }
 
 
+/* ---------------------------------------------------------------------- */
+/* very restricted what kinds of expressions can appear in an enum decl */
+
+enum_decl_one:
+    | ident    { Ast0.wrap(Ast0.Ident($1)) }
+    | ident TEq enum_val
+       { let id = Ast0.wrap(Ast0.Ident($1)) in
+       Ast0.wrap
+         (Ast0.Assignment
+            (id,P.clt2mcode Ast.SimpleAssign $2,Ast0.set_arg_exp $3,
+             false)) }
+
+enum_val:
+   ident    { Ast0.wrap(Ast0.Ident($1)) }
+ | TInt
+     { let (x,clt) = $1 in
+     Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) }
+ | TMetaConst
+     { let (nm,constraints,pure,ty,clt) = $1 in
+     Ast0.wrap
+       (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.CONST,pure)) }
+ | TMetaExp
+     { let (nm,constraints,pure,ty,clt) = $1 in
+     Ast0.wrap
+       (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ANY,pure)) }
+ | TMetaIdExp
+     { let (nm,constraints,pure,ty,clt) = $1 in
+     Ast0.wrap
+       (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ID,pure)) }
+
+enum_decl_list:
+   nonempty_list_start(enum_decl_one,edots_when(TEllipsis,enum_decl_one))
+     { Ast0.wrap(Ast0.DOTS($1 P.mkedots (fun c -> Ast0.EComma c))) }
+
 /*****************************************************************************/
 
 /* have to inline everything to avoid conflicts? switch to proper
@@ -747,33 +840,15 @@ defineop:
 
 /* ---------------------------------------------------------------------- */
 
-define_param_list: define_param_list_start
-     {let circle x =
-       match Ast0.unwrap x with Ast0.DPcircles(_) -> true | _ -> false in
-     if List.exists circle $1
-     then Ast0.wrap(Ast0.CIRCLES($1))
-     else Ast0.wrap(Ast0.DOTS($1)) }
-
-define_param_list_start:
-    ident { [Ast0.wrap(Ast0.DParam $1)] }
-  | ident TComma define_param_list_start
-      { Ast0.wrap(Ast0.DParam $1)::
-       Ast0.wrap(Ast0.DPComma(P.clt2mcode "," $2))::$3 }
-  | d=TEllipsis r=list(dp_comma_args(TEllipsis))
-      { (P.mkdpdots "..." d)::
-       (List.concat (List.map (function x -> x (P.mkdpdots "...")) r)) }
-
-dp_comma_args(dotter):
-  c=TComma d=dotter
-    { function dot_builder ->
-      [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," c)); dot_builder d] }
-| TComma ident
-    { function dot_builder ->
-      [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," $1));
-       Ast0.wrap(Ast0.DParam $2)] }
-
-define_param_list_option: define_param_list { $1 }
-         | /* empty */     { Ast0.wrap(Ast0.DOTS([])) }
+dparam: ident { Ast0.wrap(Ast0.DParam $1) }
+
+define_param_list_option:
+    empty_list_start(dparam,TEllipsis)
+      { Ast0.wrap
+         (Ast0.DOTS
+            ($1
+               (fun _ d -> Ast0.wrap(Ast0.DPdots(P.clt2mcode "," d)))
+               (fun c -> Ast0.DPComma c))) }
 
 /*****************************************************************************/
 
@@ -979,6 +1054,7 @@ a disjunction on a statement with a declaration in each branch */
 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
       { List.map
          (function (id,fn) ->
@@ -1040,6 +1116,7 @@ decl_var:
 one_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=d_ident pv=TPtVirg
       { let (id,fn) = d in
         Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) }
@@ -1105,11 +1182,12 @@ initialize:
     eexpr
       { Ast0.wrap(Ast0.InitExpr($1)) }
   | TOBrace initialize_list TCBrace
-      { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) }
-  | TOBrace TCBrace
-      { Ast0.wrap
-         (Ast0.InitList(P.clt2mcode "{" $1,Ast0.wrap(Ast0.DOTS []),
-                        P.clt2mcode "}" $2)) }
+    { if P.struct_initializer $2
+    then
+      let il = P.drop_dot_commas $2 in
+      Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,il,P.clt2mcode "}" $3,false))
+    else
+      Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3,true)) }
   | TMetaInit
       {let (nm,pure,clt) = $1 in
       Ast0.wrap(Ast0.MetaInit(P.clt2mcode nm clt,pure)) }
@@ -1119,13 +1197,14 @@ initialize2:
   /*dots and nests probably not allowed at top level, haven't looked into why*/
   arith_expr(eexpr,invalid) { Ast0.wrap(Ast0.InitExpr($1)) }
 | TOBrace initialize_list TCBrace
-    { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) }
-| TOBrace TCBrace
-    { Ast0.wrap
-       (Ast0.InitList(P.clt2mcode "{" $1,Ast0.wrap(Ast0.DOTS []),
-                      P.clt2mcode "}" $2)) }
+    { if P.struct_initializer $2
+    then
+      let il = P.drop_dot_commas $2 in
+      Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,il,P.clt2mcode "}" $3,false))
+    else
+      Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3,true)) }
            /* gccext:, labeled elements */
-| list(designator) TEq initialize2
+| list(designator) TEq initialize2 /*can we have another of these on the rhs?*/
     { Ast0.wrap(Ast0.InitGccExt($1,P.clt2mcode "=" $2,$3)) }
 | ident TDotDot initialize2
     { Ast0.wrap(Ast0.InitGccName($1,P.clt2mcode ":" $2,$3)) } /* in old kernel */
@@ -1140,34 +1219,8 @@ designator:
                             $4,P.clt2mcode "]" $5) }
 
 initialize_list:
-   initialize_list_start { Ast0.wrap(Ast0.DOTS($1)) }
-
-initialize_list_start:
-  initialize2 TComma { [$1;Ast0.wrap(Ast0.IComma(P.clt2mcode "," $2))] }
-| initialize2 TComma initialize_list_start
-    { $1::Ast0.wrap(Ast0.IComma(P.clt2mcode "," $2))::$3 }
-| TNothing initialize_list_start
-    { $2 } /* + code only */
-| d=edots_when(TEllipsis,initialize)
-      r=comma_initializers(edots_when(TEllipsis,initialize))
-    { (P.mkidots "..." d)::
-      (List.concat(List.map (function x -> x (P.mkidots "...")) r)) }
-
-comma_initializers(dotter):
-  /* empty */ { [] }
-| d=dotter r=comma_initializers2(dotter)
-      { (function dot_builder -> [dot_builder d])::r }
-| TNothing r=comma_initializers(dotter) { r }
-| i=initialize2 c=TComma r=comma_initializers(dotter)
-    { (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))])::
-      r }
-
-comma_initializers2(dotter):
-  /* empty */ { [] }
-| TNothing r=comma_initializers(dotter) { r }
-| i=initialize2 c=TComma r=comma_initializers(dotter)
-    { (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))])::
-      r }
+   empty_list_start(initialize2,edots_when(TEllipsis,initialize))
+     { Ast0.wrap(Ast0.DOTS($1 P.mkidots (fun c -> Ast0.IComma c))) }
 
 /* a statement that is part of a list */
 decl_statement:
@@ -1305,7 +1358,9 @@ arith_expr(r,pe):
       { P.arith_op Ast.Plus $1 $2 $3 }
   | arith_expr(r,pe) TMinus  arith_expr(r,pe)
       { P.arith_op Ast.Minus $1 $2 $3 }
-  | arith_expr(r,pe) TShOp    arith_expr(r,pe)
+  | arith_expr(r,pe) TShLOp    arith_expr(r,pe)
+      { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+  | arith_expr(r,pe) TShROp    arith_expr(r,pe)
       { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
   | arith_expr(r,pe) TLogOp    arith_expr(r,pe)
       { let (op,clt) = $2 in P.logic_op op $1 clt $3 }
@@ -1701,41 +1756,68 @@ typedef_ident:
 /*****************************************************************************/
 
 decl_list(decl):
-  /* empty */ { Ast0.wrap(Ast0.DOTS([])) }
-| decl_list_start(decl)
-     {let circle x =
-       match Ast0.unwrap x with Ast0.Pcircles(_) -> true | _ -> false in
-     if List.exists circle $1
-     then Ast0.wrap(Ast0.CIRCLES($1))
-     else Ast0.wrap(Ast0.DOTS($1)) }
-
-decl_list_start(decl):
-  one_dec(decl)  { [$1] }
-| one_dec(decl) TComma decl_list_start(decl)
-    { $1::Ast0.wrap(Ast0.PComma(P.clt2mcode "," $2))::$3 }
-| TEllipsis list(comma_decls(TEllipsis,decl))
-    { Ast0.wrap(Ast0.Pdots(P.clt2mcode "..." $1))::
-      (List.concat(List.map (function x -> x (P.mkpdots "...")) $2)) }
+  empty_list_start(one_dec(decl),TEllipsis)
+     { Ast0.wrap
+        (Ast0.DOTS
+           ($1
+              (fun _ d -> Ast0.wrap(Ast0.Pdots(P.clt2mcode "..." d)))
+              (fun c -> Ast0.PComma c))) }
 
 one_dec(decl):
   decl  { $1 }
 | TMetaParamList
     { let (nm,lenname,pure,clt) = $1 in
     let nm = P.clt2mcode nm clt in
-    let lenname =
-      match lenname with
-       Some nm -> Some(P.clt2mcode nm clt)
-      | None -> None in
+      let lenname =
+       match lenname with
+         Ast.AnyLen -> Ast0.AnyListLen
+       | Ast.MetaLen nm -> Ast0.MetaListLen(P.clt2mcode nm clt)
+       | Ast.CstLen n -> Ast0.CstListLen n in
     Ast0.wrap(Ast0.MetaParamList(nm,lenname,pure)) }
 
-comma_decls(dotter,decl):
-  TComma dotter
-    { function dot_builder ->
-      [Ast0.wrap(Ast0.PComma(P.clt2mcode "," $1));
-       dot_builder $2] }
-| TComma one_dec(decl)
-    { function dot_builder ->
-      [Ast0.wrap(Ast0.PComma(P.clt2mcode "," $1)); $2] }
+/* ---------------------------------------------------------------------- */
+/* comma list parser, used for fn params, fn args, enums, initlists,
+   #define params */
+
+/* enums: enum_decl, edots_when(TEllipsis,enum_decl_one)
+fun s d -> P.mkedots "..." d
+fun c -> Ast0.EComma c
+ */
+
+empty_list_start(elem,dotter):
+  /* empty */ { fun build_dots build_comma -> [] }
+| nonempty_list_start(elem,dotter) { $1 }
+
+nonempty_list_start(elem,dotter): /* dots allowed */
+  elem { fun build_dots build_comma -> [$1] }
+| elem TComma
+    { fun build_dots build_comma ->
+      $1::[Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| elem TComma nonempty_list_start(elem,dotter)
+    { fun build_dots build_comma ->
+      $1::(Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+      ($3 build_dots build_comma) }
+| TNothing nonempty_list_start(elem,dotter) { $2 }
+| d=dotter { fun build_dots build_comma -> [(build_dots "..." d)] }
+| d=dotter TComma
+      { fun build_dots build_comma ->
+       [(build_dots "..." d);Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| d=dotter TComma r=continue_list(elem,dotter)
+    { fun build_dots build_comma ->
+      (build_dots "..." d)::
+      (Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+      (r build_dots build_comma) }
+
+continue_list(elem,dotter): /* dots not allowed */
+  elem { fun build_dots build_comma -> [$1] }
+| elem TComma
+    { fun build_dots build_comma ->
+      $1::[Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| elem TComma nonempty_list_start(elem,dotter)
+    { fun build_dots build_comma ->
+      $1::(Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+      ($3 build_dots build_comma) }
+| TNothing nonempty_list_start(elem,dotter) { $2 }
 
 /* ---------------------------------------------------------------------- */
 
@@ -1820,7 +1902,12 @@ toplevel_after_stm:
 
 top_init:
   TOInit initialize_list TCBrace
-    { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) }
+    { if P.struct_initializer $2
+    then
+      let il = P.drop_dot_commas $2 in
+      Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,il,P.clt2mcode "}" $3,false))
+    else
+      Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3,true)) }
 
 /* ------------------------------------------------------------------------ */
 /* Plus top level */
@@ -1919,49 +2006,28 @@ when_start:
 
 /* ---------------------------------------------------------------------- */
 
-eexpr_list:
-  eexpr_list_start
-     {let circle x =
-       match Ast0.unwrap x with Ast0.Ecircles(_) -> true | _ -> false in
-     let star x =
-       match Ast0.unwrap x with Ast0.Estars(_) -> true | _ -> false in
-     if List.exists circle $1
-     then Ast0.wrap(Ast0.CIRCLES($1))
-     else
-       if List.exists star $1
-       then Ast0.wrap(Ast0.STARS($1))
-       else Ast0.wrap(Ast0.DOTS($1)) }
-
 /* arg expr.  may contain a type or a explist metavariable */
 aexpr:
-    eexpr
-      { Ast0.set_arg_exp $1 }
+    dexpr { Ast0.set_arg_exp $1 }
   | TMetaExpList
       { let (nm,lenname,pure,clt) = $1 in
       let nm = P.clt2mcode nm clt in
       let lenname =
        match lenname with
-         Some nm -> Some(P.clt2mcode nm clt)
-       | None -> None in
+         Ast.AnyLen -> Ast0.AnyListLen
+       | Ast.MetaLen nm -> Ast0.MetaListLen(P.clt2mcode nm clt)
+       | Ast.CstLen n -> Ast0.CstListLen n in
       Ast0.wrap(Ast0.MetaExprList(nm,lenname,pure)) }
   | ctype
       { Ast0.set_arg_exp(Ast0.wrap(Ast0.TypeExp($1))) }
 
-eexpr_list_start:
-    aexpr { [$1] }
-  | aexpr TComma eexpr_list_start
-      { $1::Ast0.wrap(Ast0.EComma(P.clt2mcode "," $2))::$3 }
-
-comma_args(dotter):
-  c=TComma d=dotter
-    { function dot_builder ->
-      [Ast0.wrap(Ast0.EComma(P.clt2mcode "," c)); dot_builder d] }
-| TComma aexpr
-    { function dot_builder ->
-      [Ast0.wrap(Ast0.EComma(P.clt2mcode "," $1)); $2] }
-
-eexpr_list_option: eexpr_list { $1 }
-         | /* empty */     { Ast0.wrap(Ast0.DOTS([])) }
+eexpr_list_option:
+    empty_list_start(aexpr,TEllipsis)
+      { Ast0.wrap
+         (Ast0.DOTS
+            ($1
+               (fun _ d -> Ast0.wrap(Ast0.Edots(P.clt2mcode "..." d,None)))
+               (fun c -> Ast0.EComma c))) }
 
 /****************************************************************************/
 
@@ -2046,26 +2112,24 @@ never_used: TPragma { () }
   | TScriptData     { () }
 
 script_meta_main:
-  py=pure_ident script_name_decl
-  { let (nm,mv) = $2 in
-    ((Some (P.id2name py), None), nm, mv) }
-  | TOPar TUnderscore TComma ast=pure_ident TCPar script_name_decl
-  { let (nm,mv) = $6 in
-    ((None, Some (P.id2name ast)), nm, mv) }
-  | TOPar str=pure_ident TComma TUnderscore TCPar script_name_decl
-  { let (nm,mv) = $6 in
-    ((Some (P.id2name str), None), nm, mv) }
-  | TOPar str=pure_ident TComma ast=pure_ident TCPar script_name_decl
-  { let (nm,mv) = $6 in
-    ((Some (P.id2name str), Some (P.id2name ast)), nm, mv) }
+    py=pure_ident TMPtVirg
+  { ((Some (P.id2name py), None), None) }
+  | py=pure_ident script_name_decl TMPtVirg
+  { ((Some (P.id2name py), None), Some $2) }
+  | TOPar TUnderscore TComma ast=pure_ident TCPar script_name_decl TMPtVirg
+  { ((None, Some (P.id2name ast)), Some $6) }
+  | TOPar str=pure_ident TComma TUnderscore TCPar script_name_decl TMPtVirg
+  { ((Some (P.id2name str), None), Some $6) }
+  | TOPar str=pure_ident TComma ast=pure_ident TCPar script_name_decl TMPtVirg
+  { ((Some (P.id2name str), Some (P.id2name ast)), Some $6) }
 
 script_name_decl:
-    TShOp TRuleName TDot cocci=pure_ident TMPtVirg
+    TShLOp TRuleName TDot cocci=pure_ident
       { let nm = P.id2name cocci in
         let mv = Parse_aux.lookup $2 nm in
         (($2, nm), mv) }
-  | TShOp TVirtual TDot cocci=pure_ident TMPtVirg
+  | TShLOp TVirtual TDot cocci=pure_ident
       { let nm = P.id2name cocci in
         let name = ("virtual", nm) in
         let mv = Ast.MetaIdDecl(Ast.NONE,name) in
-       (name,mv) }
+        (name,mv) }