Coccinelle release 1.0.0-rc3
[bpt/coccinelle.git] / parsing_cocci / parser_cocci_menhir.mly
index d4aa669..ef6df83 100644 (file)
@@ -35,12 +35,75 @@ parameter needs both a type and an identifier *)
 module Ast0 = Ast0_cocci
 module Ast = Ast_cocci
 module P = Parse_aux
+
+(* ---------------------------------------------------------------------- *)
+(* support for TMeta *)
+
+let print_meta (r,n) = r^"."^n
+
+let meta_metatable = Hashtbl.create(101)
+
+let coerce_tmeta newty name builder matcher =
+  try
+    let x = Hashtbl.find meta_metatable name in
+    if not (matcher x)
+    then
+      failwith
+       (Printf.sprintf "Metavariable %s is used as %s"
+          (print_meta name) newty)
+  with Not_found ->
+    (if !Flag_parsing_cocci.show_SP
+    then
+      Common.pr2
+       (Printf.sprintf
+          "Metavariable %s is assumed to be %s metavariable"
+          (print_meta name) newty));
+    Hashtbl.add meta_metatable name builder
+
+let tmeta_to_type (name,pure,clt) =
+  (coerce_tmeta "a type" name (TMetaType(name,pure,clt))
+     (function TMetaType(_,_,_) -> true | _ -> false));
+  Ast0.wrap(Ast0.MetaType(P.clt2mcode name clt,pure))
+
+let tmeta_to_field (name,pure,clt) =
+  (coerce_tmeta "a field" name (TMetaField(name,pure,clt))
+     (function TMetaField(_,_,_) -> true | _ -> false));
+  P.meta_field (name,pure,clt)
+
+let tmeta_to_exp (name,pure,clt) =
+  (coerce_tmeta "an expression" name
+     (TMetaExp(name,Ast0.NoConstraint,pure,None,clt))
+     (function TMetaExp(_,_,_,_,_) -> true | _ -> false));
+  Ast0.wrap
+    (Ast0.MetaExpr(P.clt2mcode name clt,Ast0.NoConstraint,None,Ast.ANY,pure))
+
+let tmeta_to_param (name,pure,clt) =
+  (coerce_tmeta "a parameter" name (TMetaParam(name,pure,clt))
+     (function TMetaParam(_,_,_) -> true | _ -> false));
+  Ast0.wrap(Ast0.MetaParam(P.clt2mcode name clt,pure))
+
+let tmeta_to_statement (name,pure,clt) =
+  (coerce_tmeta "a statement" name (TMetaType(name,pure,clt))
+     (function TMetaType(_,_,_) -> true | _ -> false));
+  P.meta_stm (name,pure,clt)
+
+let tmeta_to_seed_id (name,pure,clt) =
+  (coerce_tmeta "an identifier" name
+     (TMetaId(name,Ast.IdNoConstraint,Ast.NoVal,pure,clt))
+     (function TMetaId(_,_,_,_,_) -> true | _ -> false));
+  Ast.SeedId name
+
+let tmeta_to_ident (name,pure,clt) =
+  (coerce_tmeta "an identifier" name
+     (TMetaId(name,Ast.IdNoConstraint,Ast.NoVal,pure,clt))
+     (function TMetaId(_,_,_,_,_) -> true | _ -> false));
+  Ast0.wrap(Ast0.MetaId(P.clt2mcode name clt,Ast.IdNoConstraint,Ast.NoVal,pure))
 %}
 
 %token EOF
 
 %token TIdentifier TExpression TStatement TFunction TLocal TType TParameter
-%token TIdExpression TInitialiser TDeclaration TField
+%token TIdExpression TInitialiser TDeclaration TField TMetavariable
 %token Tlist TFresh TConstant TError TWords TWhy0 TPlus0 TBang0
 %token TPure TContext TGenerated
 %token TTypedef TDeclarer TIterator TName TPosition TPosAny
@@ -49,6 +112,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
 
@@ -61,12 +125,14 @@ module P = Parse_aux
 %token <string * Data.clt> TIdent TTypeId TDeclarerId TIteratorId
 %token <Ast_cocci.added_string * Data.clt> TPragma
 
-%token <Parse_aux.idinfo>        TMetaId TMetaFunc TMetaLocalFunc
+%token <Parse_aux.midinfo>       TMetaId
+%token <Parse_aux.idinfo>        TMetaFunc TMetaLocalFunc
 %token <Parse_aux.idinfo>        TMetaIterator TMetaDeclarer
 %token <Parse_aux.expinfo>       TMetaErr
 %token <Parse_aux.info>          TMetaParam TMetaStm TMetaStmList TMetaType
-%token <Parse_aux.info>          TMetaInit TMetaDecl TMetaField
-%token <Parse_aux.list_info>     TMetaParamList TMetaExpList
+%token <Parse_aux.info>          TMetaInit TMetaDecl TMetaField TMeta
+%token <Parse_aux.list_info>     TMetaParamList TMetaExpList TMetaInitList
+%token <Parse_aux.list_info>     TMetaFieldList
 %token <Parse_aux.typed_expinfo> TMetaExp TMetaIdExp TMetaLocalIdExp TMetaConst
 %token <Parse_aux.pos_info>      TMetaPos
 
@@ -81,7 +147,7 @@ module P = Parse_aux
 
 %token <string>  TPathIsoFile
 %token <string * Data.clt> TIncludeL TIncludeNL
-%token <Data.clt * token> TDefine
+%token <Data.clt * token> TDefine TUndef
 %token <Data.clt * token * int * int> TDefineParam
 %token <string * Data.clt> TMinusFile TPlusFile
 
@@ -263,6 +329,8 @@ incl:
 | TUsing TPathIsoFile { Data.Iso(Common.Right $2) }
 | TVirtual comma_list(pure_ident)
     { let names = List.map P.id2name $2 in
+      Iteration.parsed_virtual_rules :=
+       Common.union_set names !Iteration.parsed_virtual_rules;
       (* ensure that the names of virtual and real rules don't overlap *)
       List.iter
       (function name -> Hashtbl.add Data.all_metadecls name [])
@@ -329,6 +397,22 @@ metadec:
          let tok = check_meta(Ast.MetaExpListDecl(arity,name,lenname)) in
          !Data.add_explist_meta name lenname pure; tok)
        len ids }
+| ar=arity ispure=pure
+    TField 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.MetaFieldListDecl(arity,name,lenname)) in
+         !Data.add_field_list_meta name lenname pure; tok)
+       len ids }
+| ar=arity ispure=pure
+    TInitialiser 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.MetaInitListDecl(arity,name,lenname)) in
+         !Data.add_initlist_meta name lenname pure; tok)
+       len ids }
 
 list_len:
   pure_ident_or_meta_ident { Common.Left $1 }
@@ -338,11 +422,15 @@ list_len:
   TFresh TIdentifier
     { (fun name check_meta seed ->
       let tok = check_meta(Ast.MetaFreshIdDecl(name,seed)) in
-      !Data.add_fresh_id_meta name; tok) }
+      !Data.add_fresh_id_meta name seed; tok) }
 
 /* metavariable kinds with no constraints, etc */
 %inline metakind:
-  TParameter
+  TMetavariable
+    { (fun arity name pure check_meta ->
+      let tok = check_meta(Ast.MetaMetaDecl(arity,name)) in
+      !Data.add_meta_meta name pure; tok) }
+| TParameter
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaParamDecl(arity,name)) in
       !Data.add_param_meta name pure; tok) }
@@ -364,6 +452,11 @@ list_len:
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaInitDecl(arity,name)) in
       !Data.add_init_meta name pure; tok) }
+| TInitialiser Tlist
+    { (fun arity name pure check_meta ->
+      let len = Ast.AnyLen in
+      let tok = check_meta(Ast.MetaInitListDecl(arity,name,len)) in
+      !Data.add_initlist_meta name len pure; tok) }
 | TStatement
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaStmDecl(arity,name)) in
@@ -376,6 +469,11 @@ list_len:
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaFieldDecl(arity,name)) in
       !Data.add_field_meta name pure; tok) }
+| TField Tlist
+    { (fun arity name pure check_meta ->
+      let len = Ast.AnyLen in
+      let tok = check_meta(Ast.MetaFieldListDecl(arity,name,len)) in
+      !Data.add_field_list_meta name len pure; tok) }
 | TStatement Tlist
     { (fun arity name pure check_meta ->
       let tok = check_meta(Ast.MetaStmListDecl(arity,name)) in
@@ -407,6 +505,9 @@ list_len:
         let vl = List.assoc name virtual_env in
         !Data.add_virt_id_meta_found name vl; []
        with Not_found ->
+        Iteration.parsed_virtual_identifiers :=
+          Common.union_set [name]
+            !Iteration.parsed_virtual_identifiers;
         let name = ("virtual",name) in
         let tok = check_meta(Ast.MetaIdDecl(arity,name)) in
         !Data.add_virt_id_meta_not_found name pure; tok in
@@ -455,14 +556,9 @@ list_len:
       | Some _ ->
          !Data.add_local_idexp_meta ty name constraints pure;
          check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) }
-| TExpression m=nonempty_list(TMul)
+| TExpression ty=expression_type
     { (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
-    { (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)
@@ -470,6 +566,17 @@ list_len:
       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 ->
@@ -501,10 +608,11 @@ list_len:
       !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)
@@ -551,6 +659,12 @@ 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, Some i)) }
 | s=Tenum i=ioption(ident) l=TOBrace ids=enum_decl_list r=TCBrace
@@ -558,9 +672,9 @@ non_signable_types:
     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
+| s=struct_or_union i=type_ident // allow typedef name
     { Ast0.wrap(Ast0.StructUnionName(s, Some i)) }
-| s=struct_or_union i=ioption(ident)
+| s=struct_or_union i=ioption(type_ident)
     l=TOBrace d=struct_decl_list r=TCBrace
     { (if i = None && !Data.in_iso
     then failwith "structures must be named in the iso file");
@@ -595,14 +709,19 @@ ctype:
       Ast0.wrap
        (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
 
+mctype:
+| TMeta { tmeta_to_type $1 }
+| ctype {$1}
+
 /* signed, unsigned alone not allowed */
 typedef_ctype:
   cv=ioption(const_vol) ty=all_basic_types m=list(TMul)
     { P.pointerify (P.make_cv cv ty) m }
-| lp=TOPar0 t=midzero_list(ctype,ctype) rp=TCPar0
+| lp=TOPar0 t=midzero_list(mctype,mctype) rp=TCPar0
     { let (mids,code) = t in
       Ast0.wrap
        (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
+| TMeta { tmeta_to_type $1 }
 
 /* ---------------------------------------------------------------------- */
 
@@ -616,6 +735,8 @@ struct_decl:
 
 struct_decl_one:
     | TMetaField { P.meta_field $1 }
+    | TMetaFieldList { P.meta_field_list $1 }
+    | TMeta { tmeta_to_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)) }
@@ -652,8 +773,8 @@ continue_struct_decl_list:
 /* 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
+    | disj_ident    { Ast0.wrap(Ast0.Ident($1)) }
+    | disj_ident TEq enum_val
        { let id = Ast0.wrap(Ast0.Ident($1)) in
        Ast0.wrap
          (Ast0.Assignment
@@ -665,6 +786,7 @@ enum_val:
  | TInt
      { let (x,clt) = $1 in
      Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) }
+ | TMeta { tmeta_to_exp $1 }
  | TMetaConst
      { let (nm,constraints,pure,ty,clt) = $1 in
      Ast0.wrap
@@ -693,13 +815,13 @@ minus_body:
     /*ew=loption(error_words)*/
     { match f@b(*@ew*) with
       [] -> raise (Semantic_cocci.Semantic "minus slice can't be empty")
-    | code -> Top_level.top_level code }
+    | code -> code }
 
 plus_body:
     f=loption(filespec)
     b=loption(plus_start)
     /*ew=loption(error_words)*/
-    { Top_level.top_level (f@b(*@ew*)) }
+    { f@b(*@ew*) }
 
 minus_exp_body:
     f=loption(filespec)
@@ -707,13 +829,13 @@ minus_exp_body:
     /*ew=loption(error_words)*/
     { match f@[b](*@ew*) with
       [] -> raise (Semantic_cocci.Semantic "minus slice can't be empty")
-    | code -> Top_level.top_level code }
+    | code -> code }
 
 plus_exp_body:
     f=loption(filespec)
     b=top_eexpr
     /*ew=loption(error_words)*/
-    { Top_level.top_level (f@[b](*@ew*)) }
+    { f@[b](*@ew*) }
 
 filespec:
   TMinusFile TPlusFile
@@ -744,6 +866,23 @@ includes:
                            P.clt2mcode
                              (Ast.NonLocal (Parse_aux.str2inc (P.id2name $1)))
                              (P.drop_bef clt))) }
+| TUndef TLineEnd
+    { let (clt,ident) = $1 in
+      let aft = P.get_aft clt in (* move stuff after the define to the ident *)
+      Ast0.wrap
+      (Ast0.Undef
+        (P.clt2mcode "#undef" (P.drop_aft clt),
+         (match ident with
+           TMetaId((nm,constraints,seed,pure,clt)) ->
+             let clt = P.set_aft aft clt in
+             Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,seed,pure))
+         | TIdent((nm,clt)) ->
+             let clt = P.set_aft aft clt in
+             Ast0.wrap(Ast0.Id(P.clt2mcode nm clt))
+         | _ ->
+             raise
+               (Semantic_cocci.Semantic
+                  "unexpected name for a #define")))) }
 | d=defineop TLineEnd
     { d (Ast0.wrap(Ast0.DOTS([]))) }
 | d=defineop t=ctype TLineEnd
@@ -763,15 +902,19 @@ includes:
 defineop:
   TDefine
     { let (clt,ident) = $1 in
+      let aft = P.get_aft clt in (* move stuff after the define to the ident *)
       function body ->
        Ast0.wrap
          (Ast0.Define
-            (P.clt2mcode "#define" clt,
+            (P.clt2mcode "#define" (P.drop_aft clt),
              (match ident with
-               TMetaId((nm,constraints,pure,clt)) ->
-                 Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure))
-             | TIdent(nm_pure) ->
-                 Ast0.wrap(Ast0.Id(P.id2mcode nm_pure))
+               TMetaId((nm,constraints,seed,pure,clt)) ->
+                 let clt = P.set_aft aft clt in
+                 Ast0.wrap
+                   (Ast0.MetaId(P.clt2mcode nm clt,constraints,seed,pure))
+             | TIdent((nm,clt)) ->
+                 let clt = P.set_aft aft clt in
+                 Ast0.wrap(Ast0.Id(P.clt2mcode nm clt))
              | _ ->
                  raise
                    (Semantic_cocci.Semantic
@@ -780,29 +923,32 @@ defineop:
              body)) }
 | TDefineParam define_param_list_option TCPar
     { let (clt,ident,parenoff,parencol) = $1 in
+      let aft = P.get_aft clt in (* move stuff after the define to the ( *)
       (* clt is the start of the #define itself *)
       let (arity,line,lline,offset,col,strbef,straft,pos) = clt in
       let lp =
        P.clt2mcode "("
-         (arity,line,lline,parenoff,parencol,[],[],Ast0.NoMetaPos) in
+         (arity,line,lline,parenoff,parencol,[],[],[]) in
       function body ->
        Ast0.wrap
          (Ast0.Define
-            (P.clt2mcode "#define" clt,
+            (P.clt2mcode "#define" (P.drop_aft clt),
              (match ident with
-               TMetaId((nm,constraints,pure,clt)) ->
-                 Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure))
-             | TIdent(nm_pure) ->
-                 Ast0.wrap(Ast0.Id(P.id2mcode nm_pure))
+               TMetaId((nm,constraints,seed,pure,clt)) ->
+                 Ast0.wrap
+                   (Ast0.MetaId(P.clt2mcode nm clt,constraints,seed,pure))
+             | TIdent((nm,clt)) ->
+                 Ast0.wrap(Ast0.Id(P.clt2mcode nm clt))
              | _ ->
                  raise
                    (Semantic_cocci.Semantic
                       "unexpected name for a #define")),
-             Ast0.wrap (Ast0.DParams (lp,$2,P.clt2mcode ")" $3)),body)) }
+             (let clt = P.set_aft aft $3 in
+             Ast0.wrap (Ast0.DParams (lp,$2,P.clt2mcode ")" clt))),body)) }
 
 /* ---------------------------------------------------------------------- */
 
-dparam: ident { Ast0.wrap(Ast0.DParam $1) }
+dparam: mident { Ast0.wrap(Ast0.DParam $1) }
 
 define_param_list_option:
     empty_list_start(dparam,TEllipsis)
@@ -816,7 +962,7 @@ define_param_list_option:
 
 funproto:
   s=ioption(storage) t=ctype
-  id=func_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg
+  id=fn_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg
       { Ast0.wrap
          (Ast0.UnInit
             (s,
@@ -827,7 +973,7 @@ funproto:
 
 fundecl:
   f=fninfo
-  TFunDecl i=func_ident lp=TOPar d=decl_list(decl) rp=TCPar
+  TFunDecl i=fn_ident lp=TOPar d=decl_list(decl) rp=TCPar
   lb=TOBrace b=fun_start rb=TCBrace
       { P.verify_parameter_declarations (Ast0.undots d);
        Ast0.wrap(Ast0.FunDecl((Ast0.default_info(),Ast0.context_befaft()),
@@ -882,10 +1028,10 @@ storage:
        | s=Tregister    { P.clt2mcode Ast.Register s }
        | s=Textern      { P.clt2mcode Ast.Extern s }
 
-decl: t=ctype i=ident
-       { Ast0.wrap(Ast0.Param(t, Some i)) }
+decl: t=ctype i=disj_ident a=list(array_dec)
+       { let t = P.arrayify t a in Ast0.wrap(Ast0.Param(t, Some i)) }
     | t=ctype { (*verify in FunDecl*) Ast0.wrap(Ast0.Param(t, None)) }
-    | t=ctype lp=TOPar s=TMul i=ident rp=TCPar
+    | 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
@@ -896,6 +1042,7 @@ decl: t=ctype i=ident
     | TMetaParam
        { let (nm,pure,clt) = $1 in
        Ast0.wrap(Ast0.MetaParam(P.clt2mcode nm clt,pure)) }
+    | TMeta { tmeta_to_param $1 }
 
 name_opt_decl:
       decl  { $1 }
@@ -916,9 +1063,10 @@ const_vol:
 
 statement:
   includes { $1 } /* shouldn't be allowed to be a single_statement... */
+| TMeta { tmeta_to_statement $1}
 | TMetaStm
     { P.meta_stm $1 }
-| expr TPtVirg
+| option(expr) TPtVirg
     { P.exp_stm $1 $2 }
 | TIf TOPar eexpr TCPar single_statement %prec TIf
     { P.ifthen $1 $2 $3 $4 $5 }
@@ -939,8 +1087,8 @@ statement:
 | TReturn TPtVirg { P.ret $1 $2 }
 | TBreak TPtVirg { P.break $1 $2 }
 | TContinue TPtVirg { P.cont $1 $2 }
-| ident TDotDot { P.label $1 $2 }
-| TGoto ident TPtVirg { P.goto $1 $2 $3 }
+| mident TDotDot { P.label $1 $2 }
+| TGoto disj_ident TPtVirg { P.goto $1 $2 $3 }
 | TOBrace fun_start TCBrace
     { P.seq $1 $2 $3 }
 
@@ -974,7 +1122,7 @@ what about statement metavariables? */
 rule_elem_statement:
   one_decl_var
     { Ast0.wrap(Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),$1)) }
-| expr TPtVirg { P.exp_stm $1 $2 }
+| option(expr) TPtVirg { P.exp_stm $1 $2 }
 | TReturn eexpr TPtVirg { P.ret_exp $1 $2 $3 }
 | TReturn TPtVirg { P.ret $1 $2 }
 | TBreak TPtVirg { P.break $1 $2 }
@@ -1128,15 +1276,8 @@ one_decl_var:
 
 
 d_ident:
-    ident list(array_dec)
-      { ($1,
-        function t ->
-          List.fold_right
-            (function (l,i,r) ->
-              function rest ->
-                Ast0.wrap
-                  (Ast0.Array(rest,P.clt2mcode "[" l,i,P.clt2mcode "]" r)))
-            $2 t) }
+    disj_ident list(array_dec)
+      { ($1, function t -> P.arrayify t $2) }
 
 array_dec: l=TOCro i=option(eexpr) r=TCCro { (l,i,r) }
 
@@ -1168,11 +1309,23 @@ initialize2:
            /* gccext:, labeled elements */
 | 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
+| mident TDotDot initialize2
     { Ast0.wrap(Ast0.InitGccName($1,P.clt2mcode ":" $2,$3)) } /* in old kernel */
+  | TMetaInit
+      {let (nm,pure,clt) = $1 in
+      Ast0.wrap(Ast0.MetaInit(P.clt2mcode nm clt,pure)) }
+  | TMetaInitList
+      {let (nm,lenname,pure,clt) = $1 in
+      let nm = P.clt2mcode nm clt 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.MetaInitList(nm,lenname,pure)) }
 
 designator:
- | TDot ident
+ | TDot disj_ident
      { Ast0.DesignatorField (P.clt2mcode "." $1,$2) }
  | TOCro eexpr TCCro
      { Ast0.DesignatorIndex (P.clt2mcode "[" $1,$2,P.clt2mcode "]" $3) }
@@ -1245,11 +1398,13 @@ decl_statement_expr:
 
 /*****************************************************************************/
 
-/* The following cannot contain <... ...> at the top level.  This can only
-be allowed as an expression when the expression is delimited on both sides
-by expression-specific markers.  In that case, the rule eexpr is used, which
+/* expr cannot contain <... ...> at the top level.  This can only
+be allowed as an expression when the expression is delimited on the left
+by an expression-specific marker.  In that case, the rule eexpr is used, which
 allows <... ...> anywhere.  Hopefully, this will not be too much of a problem
-in practice. */
+in practice.
+dot_expressions is the most permissive.  all three kinds of expressions use
+this once an expression_specific token has been seen */
 expr:  basic_expr(expr,invalid) { $1 }
 /* allows ... and nests */
 eexpr: basic_expr(eexpr,dot_expressions) { $1 }
@@ -1276,11 +1431,12 @@ nest_expressions:
     { Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<+..." $1,
                              Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))),
                              P.clt2mcode "...+>" c, None, true)) }
+| TMeta { tmeta_to_exp $1 }
 
 //whenexp: TWhen TNotEq w=eexpr TLineEnd { w }
 
 basic_expr(recurser,primary_extra):
-  assign_expr(recurser,primary_extra)                        { $1 }
+   assign_expr(recurser,primary_extra)                     { $1 }
 
 assign_expr(r,pe):
     cond_expr(r,pe)                        { $1 }
@@ -1306,41 +1462,74 @@ assign_expr_bis:
 
 cond_expr(r,pe):
     arith_expr(r,pe)                         { $1 }
-  | l=arith_expr(r,pe) w=TWhy t=option(eexpr) dd=TDotDot r=cond_expr(r,pe)
+  | l=arith_expr(r,pe) w=TWhy t=option(eexpr) dd=TDotDot r=eexpr/*see parser_c*/
       { Ast0.wrap(Ast0.CondExpr (l, P.clt2mcode "?" w, t,
                                 P.clt2mcode ":" dd, r)) }
 
 arith_expr(r,pe):
     cast_expr(r,pe)                         { $1 }
-  | arith_expr(r,pe) TMul    arith_expr(r,pe)
+  | arith_expr(r,pe) TMul    arith_expr_bis
       { P.arith_op Ast.Mul $1 $2 $3 }
-  | arith_expr(r,pe) TDmOp    arith_expr(r,pe)
+  | arith_expr(r,pe) TDmOp    arith_expr_bis
       { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
-  | arith_expr(r,pe) TPlus   arith_expr(r,pe)
+  | arith_expr(r,pe) TPlus   arith_expr_bis
       { P.arith_op Ast.Plus $1 $2 $3 }
-  | arith_expr(r,pe) TMinus  arith_expr(r,pe)
+  | arith_expr(r,pe) TMinus  arith_expr_bis
       { P.arith_op Ast.Minus $1 $2 $3 }
-  | arith_expr(r,pe) TShLOp    arith_expr(r,pe)
+  | arith_expr(r,pe) TShLOp    arith_expr_bis
       { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
-  | arith_expr(r,pe) TShROp    arith_expr(r,pe)
+  | arith_expr(r,pe) TShROp    arith_expr_bis
       { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
-  | arith_expr(r,pe) TLogOp    arith_expr(r,pe)
+  | arith_expr(r,pe) TLogOp    arith_expr_bis
       { let (op,clt) = $2 in P.logic_op op $1 clt $3 }
-  | arith_expr(r,pe) TEqEq   arith_expr(r,pe)
+  | arith_expr(r,pe) TEqEq   arith_expr_bis
       { P.logic_op Ast.Eq $1 $2 $3 }
-  | arith_expr(r,pe) TNotEq  arith_expr(r,pe)
+  | arith_expr(r,pe) TNotEq  arith_expr_bis
       { P.logic_op Ast.NotEq $1 $2 $3 }
-  | arith_expr(r,pe) TAnd    arith_expr(r,pe)
+  | arith_expr(r,pe) TAnd    arith_expr_bis
       { P.arith_op Ast.And $1 $2 $3 }
-  | arith_expr(r,pe) TOr     arith_expr(r,pe)
+  | arith_expr(r,pe) TOr     arith_expr_bis
       { P.arith_op Ast.Or $1 $2 $3 }
-  | arith_expr(r,pe) TXor    arith_expr(r,pe)
+  | arith_expr(r,pe) TXor    arith_expr_bis
       { P.arith_op Ast.Xor $1 $2 $3 }
-  | arith_expr(r,pe) TAndLog arith_expr(r,pe)
+  | arith_expr(r,pe) TAndLog arith_expr_bis
       { P.logic_op Ast.AndLog $1 $2 $3 }
-  | arith_expr(r,pe) TOrLog  arith_expr(r,pe)
+  | arith_expr(r,pe) TOrLog  arith_expr_bis
       { P.logic_op Ast.OrLog $1 $2 $3 }
 
+// allows dots now that an expression-specific token has been seen
+// need an extra rule because of recursion restrictions
+arith_expr_bis:
+    cast_expr(eexpr,dot_expressions)                         { $1 }
+  | arith_expr_bis TMul    arith_expr_bis
+      { P.arith_op Ast.Mul $1 $2 $3 }
+  | arith_expr_bis TDmOp    arith_expr_bis
+      { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+  | arith_expr_bis TPlus   arith_expr_bis
+      { P.arith_op Ast.Plus $1 $2 $3 }
+  | arith_expr_bis TMinus  arith_expr_bis
+      { P.arith_op Ast.Minus $1 $2 $3 }
+  | arith_expr_bis TShLOp    arith_expr_bis
+      { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+  | arith_expr_bis TShROp    arith_expr_bis
+      { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+  | arith_expr_bis TLogOp    arith_expr_bis
+      { let (op,clt) = $2 in P.logic_op op $1 clt $3 }
+  | arith_expr_bis TEqEq   arith_expr_bis
+      { P.logic_op Ast.Eq $1 $2 $3 }
+  | arith_expr_bis TNotEq  arith_expr_bis
+      { P.logic_op Ast.NotEq $1 $2 $3 }
+  | arith_expr_bis TAnd    arith_expr_bis
+      { P.arith_op Ast.And $1 $2 $3 }
+  | arith_expr_bis TOr     arith_expr_bis
+      { P.arith_op Ast.Or $1 $2 $3 }
+  | arith_expr_bis TXor    arith_expr_bis
+      { P.arith_op Ast.Xor $1 $2 $3 }
+  | arith_expr_bis TAndLog arith_expr_bis
+      { P.logic_op Ast.AndLog $1 $2 $3 }
+// no OrLog because it is left associative and this is for
+// a right argument, not sure why not the same problem for AndLog
+
 cast_expr(r,pe):
     unary_expr(r,pe)                      { $1 }
   | lp=TOPar t=ctype rp=TCPar e=cast_expr(r,pe)
@@ -1349,16 +1538,35 @@ cast_expr(r,pe):
 
 unary_expr(r,pe):
     postfix_expr(r,pe)                   { $1 }
-  | TInc unary_expr(r,pe)
+  | TInc unary_expr_bis
       { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Inc $1)) }
-  | TDec unary_expr(r,pe)
+  | TDec unary_expr_bis
       { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Dec $1)) }
   | unary_op cast_expr(r,pe)
       { let mcode = $1 in Ast0.wrap(Ast0.Unary($2, mcode)) }
-  | TBang unary_expr(r,pe)
+  | TBang unary_expr_bis
+      { let mcode = P.clt2mcode Ast.Not $1 in
+      Ast0.wrap(Ast0.Unary($2, mcode)) }
+  | TSizeof unary_expr_bis
+      { Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" $1, $2)) }
+  | s=TSizeof lp=TOPar t=ctype rp=TCPar
+      { Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s,
+                                   P.clt2mcode "(" lp,t,
+                                   P.clt2mcode ")" rp)) }
+
+// version that allows dots
+unary_expr_bis:
+    postfix_expr(eexpr,dot_expressions)                   { $1 }
+  | TInc unary_expr_bis
+      { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Inc $1)) }
+  | TDec unary_expr_bis
+      { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Dec $1)) }
+  | unary_op cast_expr(eexpr,dot_expressions)
+      { let mcode = $1 in Ast0.wrap(Ast0.Unary($2, mcode)) }
+  | TBang unary_expr_bis
       { let mcode = P.clt2mcode Ast.Not $1 in
       Ast0.wrap(Ast0.Unary($2, mcode)) }
-  | TSizeof unary_expr(r,pe)
+  | TSizeof unary_expr_bis
       { Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" $1, $2)) }
   | s=TSizeof lp=TOPar t=ctype rp=TCPar
       { Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s,
@@ -1376,9 +1584,9 @@ postfix_expr(r,pe):
  | postfix_expr(r,pe) TOCro eexpr TCCro
      { Ast0.wrap(Ast0.ArrayAccess ($1,P.clt2mcode "[" $2,$3,
                                       P.clt2mcode "]" $4)) }
- | postfix_expr(r,pe) TDot   ident
+ | postfix_expr(r,pe) TDot   disj_ident
      { Ast0.wrap(Ast0.RecordAccess($1, P.clt2mcode "." $2, $3)) }
- | postfix_expr(r,pe) TPtrOp ident
+ | postfix_expr(r,pe) TPtrOp disj_ident
      { Ast0.wrap(Ast0.RecordPtAccess($1, P.clt2mcode "->" $2,
                                     $3)) }
  | postfix_expr(r,pe) TInc
@@ -1392,6 +1600,9 @@ postfix_expr(r,pe):
 
 primary_expr(recurser,primary_extra):
    func_ident   { Ast0.wrap(Ast0.Ident($1)) }
+ | TAndLog ident
+     { let op = P.clt2mcode Ast.GetRefLabel $1 in
+     Ast0.wrap(Ast0.Unary(Ast0.wrap(Ast0.Ident($2)), op)) }
  | TInt
      { let (x,clt) = $1 in
      Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) }
@@ -1490,7 +1701,15 @@ pure_ident_or_meta_ident_with_seed:
 
 seed_elem:
   TString { let (x,_) = $1 in Ast.SeedString x }
-| TMetaId { let (x,_,_,_) = $1 in Ast.SeedId x }
+| TMetaId { let (x,_,_,_,_) = $1 in Ast.SeedId x }
+| TMeta {failwith "tmeta"}
+| TVirtual TDot pure_ident
+    { let nm = ("virtual",P.id2name $3) in
+     Iteration.parsed_virtual_identifiers :=
+       Common.union_set [snd nm]
+        !Iteration.parsed_virtual_identifiers;
+    try Ast.SeedString (List.assoc (snd nm) !Flag.defined_virtual_env)
+    with Not_found -> Ast.SeedId nm }
 | TRuleName TDot pure_ident
     { let nm = ($1,P.id2name $3) in
       P.check_meta(Ast.MetaIdDecl(Ast.NONE,nm));
@@ -1518,7 +1737,14 @@ pure_ident_or_meta_ident_with_idconstraint_virt(constraint_type):
          None -> (i, Ast.IdNoConstraint)
        | Some constraint_ -> (i,constraint_))
     }
-| TVirtual TDot pure_ident { Common.Right (P.id2name $3) }
+| TVirtual TDot pure_ident
+    {
+     let nm = P.id2name $3 in
+     Iteration.parsed_virtual_identifiers :=
+       Common.union_set [nm]
+        !Iteration.parsed_virtual_identifiers;
+     Common.Right nm
+    }
 
 pure_ident_or_meta_ident_with_idconstraint(constraint_type):
        i=pure_ident_or_meta_ident c=option(constraint_type)
@@ -1675,11 +1901,17 @@ not_pos:
                 (function mv -> Ast.MetaPosDecl(Ast.NONE,mv)))
             l }
 
-func_ident: pure_ident
-         { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
-     | TMetaId
+func_ident:
+       ident { $1 }
+     | TMetaFunc
          { let (nm,constraints,pure,clt) = $1 in
-        Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) }
+        Ast0.wrap(Ast0.MetaFunc(P.clt2mcode nm clt,constraints,pure)) }
+     | TMetaLocalFunc
+        { let (nm,constraints,pure,clt) = $1 in
+        Ast0.wrap
+          (Ast0.MetaLocalFunc(P.clt2mcode nm clt,constraints,pure)) }
+
+fn_ident: disj_ident { $1 }
      | TMetaFunc
          { let (nm,constraints,pure,clt) = $1 in
         Ast0.wrap(Ast0.MetaFunc(P.clt2mcode nm clt,constraints,pure)) }
@@ -1691,26 +1923,45 @@ func_ident: pure_ident
 ident: pure_ident
          { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
      | TMetaId
-         { let (nm,constraints,pure,clt) = $1 in
-         Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) }
+         { let (nm,constraints,seed,pure,clt) = $1 in
+         Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,seed,pure)) }
+
+mident: pure_ident
+         { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
+     | TMeta { tmeta_to_ident $1 }
+     | TMetaId
+         { let (nm,constraints,seed,pure,clt) = $1 in
+         Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,seed,pure)) }
+
+disj_ident:
+       mident { $1 }
+     | lp=TOPar0 t=midzero_list(disj_ident,disj_ident) rp=TCPar0
+        { let (mids,code) = t in
+        Ast0.wrap
+          (Ast0.DisjId(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
+
+type_ident: disj_ident { $1 }
+     | TTypeId
+         { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
 
 decl_ident:
        TDeclarerId
          { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
      | TMetaDeclarer
          { let (nm,constraints,pure,clt) = $1 in
-         Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) }
+         Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,Ast.NoVal,pure)) }
 
 iter_ident:
        TIteratorId
          { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
      | TMetaIterator
          { let (nm,constraints,pure,clt) = $1 in
-         Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) }
+         Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,Ast.NoVal,pure)) }
 
 typedef_ident:
        pure_ident
          { Ast0.wrap(Ast0.TypeName(P.id2mcode $1)) }
+     | TMeta { tmeta_to_type $1 }
      | TMetaType
          { let (nm,pure,clt) = $1 in
         Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) }
@@ -1824,7 +2075,7 @@ when_body_sequence.
 
 /* doesn't allow only ... */
 minus_start:
-  fundecl                { [Ast0.wrap(Ast0.DECL($1))] }
+  fundecl                { [Ast0.wrap(Ast0.OTHER($1))] }
 | ctype                  { [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Ty($1))))] }
 | top_init          { [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.TopInit($1))))] }
 | toplevel_seq_startne(toplevel_after_dots_init)
@@ -1882,7 +2133,7 @@ plus_start:
                                           { (Ast0.wrap(Ast0.OTHER($1)))::$2 }
 | expr plus_after_exp
                      { (Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp($1)))))::$2 }
-| fundecl plus_after_stm                     { Ast0.wrap(Ast0.DECL($1))::$2 }
+| fundecl plus_after_stm                     { Ast0.wrap(Ast0.OTHER($1))::$2 }
 | decl_statement_expr plus_after_stm
                 { (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1)@$2 }
 
@@ -1895,14 +2146,14 @@ plus_after_dots:
 | TNothing plus_after_exp                                                {$2}
 | expr plus_after_exp
                      { (Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp($1)))))::$2 }
-| fundecl plus_after_stm                     { Ast0.wrap(Ast0.DECL($1))::$2 }
+| fundecl plus_after_stm                     { Ast0.wrap(Ast0.OTHER($1))::$2 }
 | decl_statement_expr plus_after_stm
                 { (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1)@$2 }
 
 plus_after_stm:
   /* empty */                                                            {[]}
 | stm_dots plus_after_dots                { (Ast0.wrap(Ast0.OTHER($1)))::$2 }
-| fundecl plus_after_stm                     { Ast0.wrap(Ast0.DECL($1))::$2 }
+| fundecl plus_after_stm                     { Ast0.wrap(Ast0.OTHER($1))::$2 }
 | decl_statement plus_after_stm
                 { (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1)@$2 }
 
@@ -2092,6 +2343,9 @@ script_name_decl:
         (($2, nm), mv) }
   | TShLOp TVirtual TDot cocci=pure_ident
       { let nm = P.id2name cocci in
+        Iteration.parsed_virtual_identifiers :=
+          Common.union_set [nm]
+            !Iteration.parsed_virtual_identifiers;
         let name = ("virtual", nm) in
         let mv = Ast.MetaIdDecl(Ast.NONE,name) in
         (name,mv) }