Coccinelle release-1.0.0-rc11
[bpt/coccinelle.git] / parsing_cocci / parser_cocci_menhir.mly
index 1e71638..448662c 100644 (file)
@@ -1,23 +1,27 @@
 /*
-* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen
-* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
-* 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.
-*/
+ * Copyright 2012, INRIA
+ * Julia Lawall, Gilles Muller
+ * Copyright 2010-2011, 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.
+ */
 
 
 %{
@@ -33,21 +37,85 @@ 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
+%token TIdExpression TInitialiser TDeclaration TField TMetavariable TSymbol
 %token Tlist TFresh TConstant TError TWords TWhy0 TPlus0 TBang0
-%token TPure TContext
+%token TPure TContext TGenerated
 %token TTypedef TDeclarer TIterator TName TPosition TPosAny
-%token TUsing TDisable TExtends TDepends TOn TEver TNever TExists TForall TScript
-%token TReverse TNothing
+%token TUsing TDisable TExtends TDepends TOn TEver TNever TExists TForall
+%token TScript TInitialize TFinalize TNothing TVirtual
 %token<string> TRuleName
 
 %token<Data.clt> Tchar Tshort Tint Tdouble Tfloat Tlong
-%token<Data.clt> Tvoid Tstruct Tunion
+%token<Data.clt> Tsize_t Tssize_t Tptrdiff_t
+%token<Data.clt> Tvoid Tstruct Tunion Tenum
 %token<Data.clt> Tunsigned Tsigned
 
 %token<Data.clt> Tstatic Tauto Tregister Textern Tinline Ttypedef
@@ -56,17 +124,22 @@ module P = Parse_aux
 
 %token <Data.clt> TIf TElse TWhile TFor TDo TSwitch TCase TDefault TReturn
 %token <Data.clt> TBreak TContinue TGoto TSizeof TFunDecl
-%token <string * Data.clt> TIdent TTypeId TDeclarerId TIteratorId
-
-%token <Parse_aux.idinfo>     TMetaId TMetaFunc TMetaLocalFunc
-%token <Parse_aux.idinfo>     TMetaIterator TMetaDeclarer
-%token <Parse_aux.expinfo>    TMetaErr 
-%token <Parse_aux.info>       TMetaParam TMetaStm TMetaStmList TMetaType
-%token <Parse_aux.list_info>  TMetaParamList TMetaExpList
-%token <Parse_aux.typed_info> TMetaExp TMetaIdExp TMetaLocalIdExp TMetaConst
-%token <Parse_aux.pos_info>   TMetaPos
-
-%token TArob TArobArob TPArob
+%token <string * Data.clt> TIdent TTypeId TDeclarerId TIteratorId TSymId
+%token <Ast_cocci.added_string * Data.clt> TPragma
+
+%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 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
+
+%token TArob TArobArob
+%token <Data.clt> TPArob
 %token <string> TScriptData
 
 %token <Data.clt> TEllipsis TOEllipsis TCEllipsis TPOEllipsis TPCEllipsis
@@ -75,10 +148,10 @@ module P = Parse_aux
 %token <Data.clt> TWhy TDotDot TBang TOPar TOPar0
 %token <Data.clt> TMid0 TCPar TCPar0
 
-%token <string>  TPragma TPathIsoFile
+%token <string>  TPathIsoFile
 %token <string * Data.clt> TIncludeL TIncludeNL
-%token <Data.clt * token> TDefine
-%token <Data.clt * token * int> TDefineParam
+%token <Data.clt * token> TDefine TUndef
+%token <Data.clt * token * int * int> TDefineParam
 %token <string * Data.clt> TMinusFile TPlusFile
 
 %token <Data.clt> TInc TDec
@@ -89,10 +162,10 @@ module P = Parse_aux
 %token <Data.clt> TAndLog
 %token <Data.clt> TOr
 %token <Data.clt> TXor
-%token <Data.clt> TAnd 
-%token <Data.clt> TEqEq TNotEq
+%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
@@ -102,12 +175,14 @@ module P = Parse_aux
 
 %token <Data.clt> TPtrOp
 
-%token TMPtVirg
+%token TMPtVirg TCppConcatOp
 %token <Data.clt> TEq TDot TComma TPtVirg
 %token <Ast_cocci.assignOp * Data.clt> TAssign
 
 %token TIso TRightIso TIsoExpression TIsoStatement TIsoDeclaration TIsoType
-%token TIsoTopLevel TIsoArgExpression TIsoTestExpression
+%token TIsoTopLevel TIsoArgExpression TIsoTestExpression TIsoToTestExpression
+
+%token TUnderscore
 
 %token TInvalid
 
@@ -119,10 +194,10 @@ module P = Parse_aux
 %left TAndLog
 %left TOr
 %left TXor
-%left TAnd 
+%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 */
 
@@ -142,7 +217,7 @@ module P = Parse_aux
 %type <Ast0_cocci.rule> plus_exp_main
 
 %start include_main
-%type <(string,string) Common.either list> include_main
+%type <Data.incl_iso list> include_main
 
 %start iso_rule_name
 %type <Ast_cocci.rulename>
@@ -155,7 +230,7 @@ rule_name
 %start meta_main
 %type <(Ast_cocci.metavar,Ast_cocci.metavar) Common.either list> meta_main
 
-%start <string * (string * string)> 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
@@ -199,8 +274,17 @@ rule_name:
   nm=ioption(pure_ident) extends d=depends i=loption(choose_iso)
     a=loption(disable) e=exists ee=is_expression TArob
       { P.make_cocci_rule_name_result nm d i a e ee }
-  | TScript TDotDot lang=pure_ident d=depends TArob
-      { P.make_script_rule_name_result lang d }
+  | TGenerated extends d=depends i=loption(choose_iso)
+    a=loption(disable) e=exists ee=is_expression TArob
+      /* 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 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
+      { P.make_final_script_rule_name_result lang d }
 
 extends:
   /* empty */                                     { () }
@@ -208,19 +292,18 @@ extends:
     { !Data.install_bindings (parent) }
 
 depends:
-  /* empty */              { Ast.NoDep }
+  /* empty */              { Ast0.NoDep }
 | TDepends TOn parents=dep { parents }
 
 dep:
-  pnrule           { $1 }
-| dep TAndLog dep  { Ast.AndDep($1, $3) }
-| dep TOrLog  dep  { Ast.OrDep ($1, $3) }
-
-pnrule:
-  TRuleName        { Ast.Dep      $1 }
-| TBang TRuleName  { Ast.AntiDep  $2 }
-| TEver TRuleName  { Ast.EverDep  $2 }
-| TNever TRuleName { Ast.NeverDep $2 }
+  TRuleName        { Ast0.Dep $1 }
+| TBang TRuleName  { Ast0.AntiDep (Ast0.Dep $2) }
+| TBang TOPar dep TCPar
+                   { Ast0.AntiDep $3 }
+| TEver TRuleName  { Ast0.EverDep $2 }
+| TNever TRuleName { Ast0.NeverDep $2 }
+| dep TAndLog dep  { Ast0.AndDep($1, $3) }
+| dep TOrLog  dep  { Ast0.OrDep ($1, $3) }
 | TOPar dep TCPar  { $2 }
 
 choose_iso:
@@ -232,7 +315,6 @@ disable:
 exists:
   TExists { Ast.Exists }
 | TForall { Ast.Forall }
-| TReverse TForall { Ast.ReverseForall }
 |         { Ast.Undetermined }
 
 is_expression: // for more flexible parsing of top level expressions
@@ -244,76 +326,161 @@ include_main:
 | list(incl) TArobArob { $1 }
 
 incl:
-  TUsing TString      { Common.Left(P.id2name $2) }
-| TUsing TPathIsoFile { Common.Right $2 }
+  TIncludeL           { let (x,_) = $1 in Data.Include(x) }
+| TUsing TString      { Data.Iso(Common.Left(P.id2name $2)) }
+| 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 [])
+      names;
+      Data.Virt(names) }
 
 metadec:
   ar=arity ispure=pure
   kindfn=metakind ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
     { P.create_metadec ar ispure kindfn ids }
+| kindfn=metakind_fresh ids=comma_list(pure_ident_or_meta_ident_with_seed)
+    TMPtVirg
+    { P.create_fresh_metadec kindfn ids }
+| ar=arity ispure=pure
+  kindfn=metakind_atomic_maybe_virt
+  ids=
+  comma_list(pure_ident_or_meta_ident_with_idconstraint_virt(re_or_not_eqid))
+    TMPtVirg
+    { let (normal,virt) = Common.partition_either (fun x -> x) ids in
+    let (idfn,virtfn) = kindfn in
+    function cr ->
+      (P.create_metadec_with_constraints ar ispure idfn normal cr) @
+      (P.create_metadec_virt ar ispure virtfn virt cr) }
 | ar=arity ispure=pure
   kindfn=metakind_atomic
-  ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_eq)) TMPtVirg
-    { P.create_metadec_ne ar ispure kindfn ids }
+  ids=comma_list(pure_ident_or_meta_ident_with_idconstraint(re_or_not_eqid))
+    TMPtVirg
+    { P.create_metadec_with_constraints ar ispure kindfn ids }
 | ar=arity ispure=pure
   kindfn=metakind_atomic_expi
-  ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_eqe)) TMPtVirg
-    { P.create_metadec_ne ar ispure kindfn ids }
+  ids=comma_list(pure_ident_or_meta_ident_with_econstraint(re_or_not_eqe_or_sub))
+    TMPtVirg
+    { P.create_metadec_with_constraints ar ispure kindfn ids }
 | ar=arity ispure=pure
   kindfn=metakind_atomic_expe
-  ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_ceq)) TMPtVirg
-    { P.create_metadec_ne ar ispure kindfn ids }
+  ids=comma_list(pure_ident_or_meta_ident_with_econstraint(not_ceq_or_sub))
+    TMPtVirg
+    { P.create_metadec_with_constraints ar ispure kindfn ids }
 | ar=arity TPosition a=option(TPosAny)
-    ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_pos)) TMPtVirg
-    { let kindfn arity name pure check_meta constraints =
+    ids=comma_list(pure_ident_or_meta_ident_with_x_eq(not_pos)) TMPtVirg
+    (* pb: position variables can't be inherited from normal rules, and then
+       there is no way to inherit from a generated rule, so there is no point
+       to have a position variable *)
+    { (if !Data.in_generating
+      then failwith "position variables not allowed in a generated rule file");
+      let kindfn arity name pure check_meta constraints =
       let tok = check_meta(Ast.MetaPosDecl(arity,name)) in
       let any = match a with None -> Ast.PER | Some _ -> Ast.ALL in
       !Data.add_pos_meta name constraints any; tok in
-    P.create_metadec_ne ar false kindfn ids }
+    P.create_metadec_with_constraints ar false kindfn ids }
+| ar=arity ispure=pure
+    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,lenname)) in
+         !Data.add_paramlist_meta name lenname pure; tok)
+       len ids }
 | ar=arity ispure=pure
-    TParameter 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.MetaParamListDecl(arity,name,Some lenname)) in
-         !Data.add_paramlist_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 }
 | ar=arity ispure=pure
-    TExpression Tlist TOCro id=pure_ident_or_meta_ident TCCro
+    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.MetaExpListDecl(arity,name,Some lenname)) in
-         !Data.add_explist_meta name (Some lenname) pure; tok)
-       id ids }
+         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 }
+| TSymbol ids=comma_list(pure_ident) TMPtVirg
+    { (fun _ ->
+        let add_sym = fun (nm,_) -> !Data.add_symbol_meta nm in
+          List.iter add_sym 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
+    { (fun name check_meta seed ->
+      let tok = check_meta(Ast.MetaFreshIdDecl(name,seed)) in
+      !Data.add_fresh_id_meta name seed; tok) }
 
+/* metavariable kinds with no constraints, etc */
 %inline metakind:
-  TFresh TIdentifier
+  TMetavariable
     { (fun arity name pure check_meta ->
-      let tok = check_meta(Ast.MetaFreshIdDecl(arity,name)) in
-      !Data.add_id_meta name [] pure; tok) }
+      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) }
 | 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
-      !Data.add_type_meta name pure; tok) } 
+      !Data.add_type_meta name pure; tok) }
+| TInitialiser
+    { (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
       !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) }
+| 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
@@ -334,13 +501,27 @@ metadec:
       then (!Data.add_iterator_name name; [])
       else raise (Semantic_cocci.Semantic "bad iterator")) }
 
+%inline metakind_atomic_maybe_virt:
+  TIdentifier
+    {
+     let idfn arity name pure check_meta constraints =
+       let tok = check_meta(Ast.MetaIdDecl(arity,name)) in
+       !Data.add_id_meta name constraints pure; tok in
+     let virtfn arity name pure check_meta virtual_env =
+       try
+        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
+     (idfn,virtfn) }
 
 %inline metakind_atomic:
-  TIdentifier
-    { (fun arity name pure check_meta constraints ->
-      let tok = check_meta(Ast.MetaIdDecl(arity,name)) in
-      !Data.add_id_meta name constraints pure; tok) }
-| TFunction
+  TFunction
     { (fun arity name pure check_meta constraints ->
       let tok = check_meta(Ast.MetaFuncDecl(arity,name)) in
       !Data.add_func_meta name constraints pure; tok) }
@@ -382,14 +563,9 @@ metadec:
       | 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)
@@ -397,6 +573,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 ->
@@ -405,28 +592,34 @@ metadec:
 | vl=meta_exp_type // no error if use $1 but doesn't type check
     { (fun arity name pure check_meta constraints ->
       let ty = Some vl in
-      List.iter
-       (function c ->
-         match Ast0.unwrap c with
-           Ast0.Constant(_) ->
-             if not
-                 (List.exists
-                    (function
-                        Type_cocci.BaseType(Type_cocci.IntType,_) -> true
-                      | Type_cocci.BaseType(Type_cocci.ShortType,_) -> true
-                      | Type_cocci.BaseType(Type_cocci.LongType,_) -> true
-                      | _ -> false)
-                    vl)
-             then failwith "metavariable with int constraint must be an int"
-         | _ -> ())
-       constraints;
+      (match constraints with
+       Ast0.NotExpCstrt constraints ->
+         List.iter
+           (function c ->
+             match Ast0.unwrap c with
+               Ast0.Constant(_) ->
+                 if not
+                     (List.exists
+                        (function
+                            Type_cocci.BaseType(Type_cocci.IntType) -> true
+                          | Type_cocci.BaseType(Type_cocci.ShortType) -> true
+                          | Type_cocci.BaseType(Type_cocci.LongType) -> true
+                          | _ -> false)
+                        vl)
+                 then
+                   failwith "metavariable with int constraint must be an int"
+             | _ -> ())
+           constraints
+      |        _ -> ());
       let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in
-      !Data.add_exp_meta ty name constraints pure; tok) }
-
+      !Data.add_exp_meta ty name constraints pure; tok)
+    }
 
 meta_exp_type:
-  t=ctype
+  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)
@@ -437,59 +630,147 @@ arity: TBang0 { Ast.UNIQUE }
      | TPlus0 { Ast.MULTI }
      | /* empty */ { Ast.NONE }
 
-generic_ctype:
-       q=ctype_qualif
-         { Ast0.wrap(Ast0.ImplicitInt(q)) }
-     | q=ioption(ctype_qualif) ty=Tchar
-         { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.CharType ty, q)) }
-     | q=ioption(ctype_qualif) ty=Tshort
-         { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.ShortType ty, q)) }
-     | q=ioption(ctype_qualif) ty=Tint
-         { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.IntType ty, q)) }
-     | t=Tdouble
-         { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.DoubleType t, None)) }
-     | t=Tfloat
-         { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.FloatType t, None)) }
-     | q=ioption(ctype_qualif) ty=Tlong
-         { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.LongType ty, q)) }
-     | s=struct_or_union i=ident
-        { Ast0.wrap(Ast0.StructUnionName(s, Some i)) }
-     | s=struct_or_union i=ioption(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");
-           Ast0.wrap(Ast0.StructUnionDef(Ast0.wrap(Ast0.StructUnionName(s, i)),
-                                        P.clt2mcode "{" l,
-                                        d, P.clt2mcode "}" r)) }
-     | s=TMetaType l=TOBrace d=struct_decl_list r=TCBrace
-        { let (nm,pure,clt) = s in
-        let ty =
-          Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) in
-        Ast0.wrap
-          (Ast0.StructUnionDef(ty,P.clt2mcode "{" l,d,P.clt2mcode "}" r)) }
-     | r=TRuleName TDot p=TIdent
-        { let nm = (r,P.id2name p) in
-        (* this is only possible when we are in a metavar decl.  Otherwise,
-           it will be represented already as a MetaType *)
-        let _ = P.check_meta(Ast.MetaTypeDecl(Ast.NONE,nm)) in
-        Ast0.wrap(Ast0.MetaType(P.clt2mcode nm (P.id2clt p),
-                                Ast0.Impure (*will be ignored*))) }
-     | p=TTypeId
-        { Ast0.wrap(Ast0.TypeName(P.id2mcode p)) }
-     | p=TMetaType
-        { let (nm,pure,clt) = p in
-        Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) }
+/* ---------------------------------------------------------------------- */
+
+%inline
+signable_types:
+  ty=Tchar
+    { Ast0.wrap(Ast0.BaseType(Ast.CharType,[P.clt2mcode "char" ty])) }
+| ty=Tshort
+    { Ast0.wrap(Ast0.BaseType(Ast.ShortType,[P.clt2mcode "short" ty])) }
+| ty1=Tshort ty2=Tint
+    { Ast0.wrap
+       (Ast0.BaseType
+          (Ast.ShortIntType,[P.clt2mcode "short" ty1;P.clt2mcode "int" ty2])) }
+| ty=Tint
+    { Ast0.wrap(Ast0.BaseType(Ast.IntType,[P.clt2mcode "int" ty])) }
+| p=TMetaType
+    { let (nm,pure,clt) = p in
+      Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) }
+| r=TRuleName TDot p=TIdent
+    { let nm = (r,P.id2name p) in
+    (* this is only possible when we are in a metavar decl.  Otherwise,
+       it will be represented already as a MetaType *)
+    let _ = P.check_meta(Ast.MetaTypeDecl(Ast.NONE,nm)) in
+    Ast0.wrap(Ast0.MetaType(P.clt2mcode nm (P.id2clt p),
+                           Ast0.Impure (*will be ignored*))) }
+| ty1=Tlong
+    { Ast0.wrap(Ast0.BaseType(Ast.LongType,[P.clt2mcode "long" ty1])) }
+| ty1=Tlong ty2=Tint
+    { Ast0.wrap
+       (Ast0.BaseType
+          (Ast.LongIntType,[P.clt2mcode "long" ty1;P.clt2mcode "int" ty2])) }
+| ty1=Tlong ty2=Tlong
+    { Ast0.wrap
+       (Ast0.BaseType
+          (Ast.LongLongType,
+           [P.clt2mcode "long" ty1;P.clt2mcode "long" ty2])) }
+| ty1=Tlong ty2=Tlong ty3=Tint
+    { Ast0.wrap
+       (Ast0.BaseType
+          (Ast.LongLongIntType,
+           [P.clt2mcode "long" ty1;P.clt2mcode "long" ty2;
+             P.clt2mcode "int" ty3])) }
+
+%inline
+non_signable_types:
+  ty=Tvoid
+    { Ast0.wrap(Ast0.BaseType(Ast.VoidType,[P.clt2mcode "void" ty])) }
+| ty1=Tlong ty2=Tdouble
+    { Ast0.wrap
+       (Ast0.BaseType
+          (Ast.LongDoubleType,
+           [P.clt2mcode "long" ty1;P.clt2mcode "double" ty2])) }
+| ty=Tdouble
+    { 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
+    { (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=type_ident // allow typedef name
+    { Ast0.wrap(Ast0.StructUnionName(s, Some i)) }
+| 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");
+      Ast0.wrap(Ast0.StructUnionDef(Ast0.wrap(Ast0.StructUnionName(s, i)),
+                                   P.clt2mcode "{" l,
+                                   d, P.clt2mcode "}" r)) }
+| s=TMetaType l=TOBrace d=struct_decl_list r=TCBrace
+    { let (nm,pure,clt) = s in
+    let ty = Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) in
+    Ast0.wrap(Ast0.StructUnionDef(ty,P.clt2mcode "{" l,d,P.clt2mcode "}" r)) }
+| p=TTypeId
+    { Ast0.wrap(Ast0.TypeName(P.id2mcode p)) }
+
+%inline
+all_basic_types:
+  r=Tsigned ty=signable_types
+    { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Signed r,Some ty)) }
+| r=Tunsigned ty=signable_types
+    { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Unsigned r,Some ty)) }
+| ty=signable_types { ty }
+| ty=non_signable_types { ty }
+
+ctype:
+  cv=ioption(const_vol) ty=all_basic_types m=list(TMul)
+    { P.pointerify (P.make_cv cv ty) m }
+| r=Tsigned
+    { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Signed r,None)) }
+| r=Tunsigned
+    { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Unsigned r,None)) }
+| lp=TOPar0 t=midzero_list(ctype,ctype) rp=TCPar0
+    { let (mids,code) = t in
+      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(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 }
+
+/* ---------------------------------------------------------------------- */
 
 struct_or_union:
        s=Tstruct { P.clt2mcode Ast.Struct s }
      | u=Tunion  { P.clt2mcode Ast.Union u }
 
 struct_decl:
-      TNothing { [] }
+      TNothing        { [] }
+    | struct_decl_one { [$1] }
+
+struct_decl_one:
+    | TMetaField { P.meta_field $1 }
+    | TMetaFieldList { P.meta_field_list $1 }
+    | TMeta { tmeta_to_field $1 }
+    | lp=TOPar0 t=midzero_list(struct_decl_one,struct_decl_one) rp=TCPar0
+       { let (mids,code) = t in
+       Ast0.wrap
+         (Ast0.DisjDecl(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
     | t=ctype d=d_ident pv=TPtVirg
         { let (id,fn) = d in
-        [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] }
-    | t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+        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
         let t =
@@ -497,11 +778,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))] }
-     | cv=ioption(const_vol) i=pure_ident d=d_ident pv=TPtVirg
+        Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv)) }
+     | cv=ioption(const_vol) i=pure_ident_or_symbol 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)) }
@@ -509,71 +790,82 @@ 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 */                        { [] }
 | struct_decl struct_decl_list_start { $1@$2 }
 | struct_decl                        { $1 }
 
-ctype:
-       cv=ioption(const_vol) ty=generic_ctype m=list(TMul)
-        { P.pointerify (P.make_cv cv ty) m }
-     | cv=ioption(const_vol) t=Tvoid m=nonempty_list(TMul)
-         { let ty =
-            Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in
-          P.pointerify (P.make_cv cv ty) m }
-   | lp=TOPar0 t=midzero_list(ctype,ctype) rp=TCPar0
-      /* more hacks */
-    { let (mids,code) = t in
-      Ast0.wrap
-       (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
 
+/* ---------------------------------------------------------------------- */
+/* very restricted what kinds of expressions can appear in an enum decl */
 
-fn_ctype: // allows metavariables
-       ty=generic_ctype m=list(TMul) { P.pointerify ty m }
-     | t=Tvoid m=list(TMul)
-         { P.pointerify
-            (Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)))
-            m }
+enum_decl_one:
+    | disj_ident    { Ast0.wrap(Ast0.Ident($1)) }
+    | disj_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)) }
+ | TMeta { tmeta_to_exp $1 }
+ | 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)) }
 
-ctype_qualif:
-       Tunsigned   { P.clt2mcode Ast.Unsigned $1 }
-     | Tsigned     { P.clt2mcode Ast.Signed $1 }
+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
 declarations, statements, and expressions for the subterms */
 
-minus_body: 
+minus_body:
     f=loption(filespec)
     b=loption(minus_start)
-    ew=loption(error_words)
-    { match f@b@ew with
+    /*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: 
+plus_body:
     f=loption(filespec)
     b=loption(plus_start)
-    ew=loption(error_words)
-    { Top_level.top_level (f@b@ew) }
+    /*ew=loption(error_words)*/
+    { f@b(*@ew*) }
 
 minus_exp_body:
     f=loption(filespec)
     b=top_eexpr
-    ew=loption(error_words)
-    { match f@[b]@ew with
+    /*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) }
+    /*ew=loption(error_words)*/
+    { f@[b](*@ew*) }
 
 filespec:
   TMinusFile TPlusFile
@@ -584,7 +876,8 @@ filespec:
 includes:
   TIncludeL
     { Ast0.wrap
-             (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt $1)),
+             (Ast0.Include(P.clt2mcode "#include"
+                             (P.drop_pos (P.drop_aft (P.id2clt $1))),
                            let (arity,ln,lln,offset,col,strbef,straft,pos) =
                              P.id2clt $1 in
                            let clt =
@@ -594,7 +887,8 @@ includes:
                              (P.drop_bef clt))) }
 | TIncludeNL
     { Ast0.wrap
-             (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt $1)),
+             (Ast0.Include(P.clt2mcode "#include"
+                             (P.drop_pos (P.drop_aft (P.id2clt $1))),
                            let (arity,ln,lln,offset,col,strbef,straft,pos) =
                              P.id2clt $1 in
                            let clt =
@@ -602,6 +896,28 @@ 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))
+         | TSymId(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
     { let ty = Ast0.wrap(Ast0.TopExp(Ast0.wrap(Ast0.TypeExp(t)))) in
       d (Ast0.wrap(Ast0.DOTS([ty]))) }
@@ -619,15 +935,22 @@ 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))
+             | TSymId(nm,clt) ->
+                 let clt = P.set_aft aft clt in
+                 Ast0.wrap(Ast0.Id(P.clt2mcode nm clt))
              | _ ->
                  raise
                    (Semantic_cocci.Semantic
@@ -635,60 +958,49 @@ defineop:
              Ast0.wrap Ast0.NoParams,
              body)) }
 | TDefineParam define_param_list_option TCPar
-    { let (clt,ident,parenoff) = $1 in
+    { 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,0,[],[],Ast0.NoMetaPos) in
+       P.clt2mcode "("
+         (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))
+             | TSymId(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)) }
 
 /* ---------------------------------------------------------------------- */
 
-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: mident { 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))) }
 
 /*****************************************************************************/
 
 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,
@@ -696,23 +1008,13 @@ funproto:
                (Ast0.FunctionType(Some t,
                                   P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)),
              id, P.clt2mcode ";" pt)) }
-| s=ioption(storage) t=Tvoid
-  id=func_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg
-    { let t = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in
-      Ast0.wrap
-        (Ast0.UnInit
-          (s,
-           Ast0.wrap
-             (Ast0.FunctionType(Some t,
-                                P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)),
-           id, P.clt2mcode ";" pt)) }
-
 
 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
-      { Ast0.wrap(Ast0.FunDecl((Ast0.default_info(),Ast0.context_befaft()),
+      { P.verify_parameter_declarations (Ast0.undots d);
+       Ast0.wrap(Ast0.FunDecl((Ast0.default_info(),Ast0.context_befaft()),
                               f, i,
                               P.clt2mcode "(" lp, d,
                               P.clt2mcode ")" rp,
@@ -727,7 +1029,7 @@ fninfo:
          List.find (function Ast0.FStorage(_) -> true | _ -> false) $2 in
        raise (Semantic_cocci.Semantic "duplicate storage")
       with Not_found -> (Ast0.FStorage($1))::$2 }
-  | t=fn_ctype r=fninfo_nt { (Ast0.FType(t))::r }
+  | t=ctype r=fninfo_nt { (Ast0.FType(t))::r }
   | Tinline  fninfo
       { try
        let _ = List.find (function Ast0.FInline(_) -> true | _ -> false) $2 in
@@ -764,9 +1066,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)) }
-    | t=fn_ctype lp=TOPar s=TMul i=ident rp=TCPar
+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=disj_ident rp=TCPar
        lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
         { let fnptr =
          Ast0.wrap
@@ -774,17 +1077,14 @@ decl: t=ctype i=ident
               (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)) }
-    | t=Tvoid
-       { let ty = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in
-          Ast0.wrap(Ast0.VoidParam(ty)) }
     | 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 }
-    | t=ctype { Ast0.wrap(Ast0.Param(t, None)) }
-    | t=fn_ctype lp=TOPar s=TMul rp=TCPar
+    | t=ctype lp=TOPar s=TMul rp=TCPar
        lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
         { let fnptr =
          Ast0.wrap
@@ -801,9 +1101,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 }
@@ -818,14 +1119,14 @@ statement:
     { P.doloop $1 $2 $3 $4 $5 $6 $7 }
 | iter_ident TOPar eexpr_list_option TCPar single_statement
     { P.iterator $1 $2 $3 $4 $5 }
-| TSwitch TOPar eexpr TCPar TOBrace list(case_line) TCBrace
-    { P.switch $1 $2 $3 $4 $5 $6 $7 }
+| TSwitch TOPar eexpr TCPar TOBrace list(decl_var) list(case_line) TCBrace
+    { P.switch $1 $2 $3 $4 $5 (List.concat $6) $7 $8 }
 | TReturn eexpr TPtVirg { P.ret_exp $1 $2 $3 }
 | 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 }
 
@@ -839,7 +1140,19 @@ stm_dots:
     { Ast0.wrap(Ast0.Nest(P.clt2mcode "<+..." $1, b,
                          P.clt2mcode "...+>" c, List.concat w, true)) }
 
-whenppdecs: w=whens(when_start,rule_elem_statement)
+%inline stm_dots_ell:
+  a=TEllipsis w=list(whenppdecs)
+    { Ast0.wrap(Ast0.Dots(P.clt2mcode "..." a, List.concat w)) }
+
+%inline stm_dots_nest:
+  a=TOEllipsis w=list(whenppdecs) b=nest_start c=TCEllipsis
+    { Ast0.wrap(Ast0.Nest(P.clt2mcode "<..." a, b,
+                         P.clt2mcode "...>" c, List.concat w, false)) }
+| a=TPOEllipsis w=list(whenppdecs) b=nest_start c=TPCEllipsis
+    { Ast0.wrap(Ast0.Nest(P.clt2mcode "<+..." a, b,
+                         P.clt2mcode "...+>" c, List.concat w, true)) }
+
+whenppdecs: w=whens(when_start,rule_elem_statement,any_strict)
     { w }
 
 /* a statement that fits into a single rule_elem.  should nests be included?
@@ -847,7 +1160,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 }
@@ -871,11 +1184,25 @@ single_statement:
                     List.map (function x -> Ast0.wrap(Ast0.DOTS([x]))) code,
                     mids, P.clt2mcode ")" $3)) }
 
+iso_statement: /* statement or declaration used in statement context */
+    statement                         { $1 }
+  | decl_var
+      { match $1 with
+       [decl] ->
+         Ast0.wrap
+           (Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),decl))
+      |        _ -> failwith "exactly one decl allowed in statement iso" }
+
 case_line:
     TDefault TDotDot fun_start
-      { Ast0.wrap(Ast0.Default(P.clt2mcode "default" $1,P.clt2mcode ":" $2,$3)) }
+      { Ast0.wrap
+         (Ast0.Default(P.clt2mcode "default" $1,P.clt2mcode ":" $2,$3)) }
   | TCase eexpr TDotDot fun_start
       { Ast0.wrap(Ast0.Case(P.clt2mcode "case" $1,$2,P.clt2mcode ":" $3,$4)) }
+/*  | lp=TOPar0 t=midzero_list(case_line,case_line) rp=TCPar0
+    { let (mids,code) = ([],[t]) in
+      Ast0.wrap
+       (Ast0.DisjCase(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) } */
 
 /* In the following, an identifier as a type is not fully supported.  Indeed,
 the language is ambiguous: what is foo * bar; */
@@ -884,6 +1211,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) ->
@@ -894,7 +1222,7 @@ decl_var:
       {let (id,fn) = d in
       [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]}
   /* type is a typedef name */
-  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident
+  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident_or_symbol
       d=comma_list(d_ident) pv=TPtVirg
       { List.map
          (function (id,fn) ->
@@ -902,8 +1230,8 @@ decl_var:
              P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
            Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv)))
          d }
-  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident d=d_ident q=TEq
-      e=initialize pv=TPtVirg
+  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident_or_symbol
+      d=d_ident q=TEq e=initialize pv=TPtVirg
       { let (id,fn) = d in
       !Data.add_type_name (P.id2name i);
       let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
@@ -911,7 +1239,7 @@ decl_var:
                           P.clt2mcode ";" pv))] }
   /* function pointer type */
   | s=ioption(storage)
-    t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+    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
@@ -923,9 +1251,15 @@ decl_var:
         [Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))] }
   | decl_ident TOPar eexpr_list_option TCPar TPtVirg
       { [Ast0.wrap(Ast0.MacroDecl($1,P.clt2mcode "(" $2,$3,
-                                 P.clt2mcode ")" $4,P.clt2mcode ";" $5))] } 
+                                 P.clt2mcode ")" $4,P.clt2mcode ";" $5))] }
+  | decl_ident TOPar eexpr_list_option TCPar q=TEq e=initialize TPtVirg
+      { [Ast0.wrap
+           (Ast0.MacroDeclInit
+              ($1,P.clt2mcode "(" $2,$3,
+               P.clt2mcode ")" $4,P.clt2mcode "=" q,e,
+               P.clt2mcode ";" $7))] }
   | s=ioption(storage)
-    t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+    t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
     lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
     q=TEq e=initialize pv=TPtVirg
       { let (id,fn) = d in
@@ -935,13 +1269,17 @@ decl_var:
               (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1,
                P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
       [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]}
-  | s=Ttypedef t=ctype id=typedef_ident pv=TPtVirg
+  | s=Ttypedef t=typedef_ctype id=comma_list(typedef_ident) pv=TPtVirg
       { let s = P.clt2mcode "typedef" s in
-        [Ast0.wrap(Ast0.Typedef(s,t,id,P.clt2mcode ";" pv))] }
+        List.map
+         (function id ->
+           Ast0.wrap(Ast0.Typedef(s,t,id,P.clt2mcode ";" pv)))
+         id }
 
 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)) }
@@ -950,13 +1288,13 @@ one_decl_var:
       { let (id,fn) = d in
       Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv)) }
   /* type is a typedef name */
-  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident
+  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident_or_symbol
       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(s,fn idtype,id,P.clt2mcode ";" pv)) }
-  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident d=d_ident q=TEq
-      e=initialize pv=TPtVirg
+  | s=ioption(storage) cv=ioption(const_vol) i=pure_ident_or_symbol
+      d=d_ident q=TEq e=initialize pv=TPtVirg
       { let (id,fn) = d in
       !Data.add_type_name (P.id2name i);
       let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
@@ -964,7 +1302,7 @@ one_decl_var:
                           P.clt2mcode ";" pv)) }
   /* function pointer type */
   | s=ioption(storage)
-    t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+    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
@@ -976,9 +1314,15 @@ one_decl_var:
         Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) }
   | decl_ident TOPar eexpr_list_option TCPar TPtVirg
       { Ast0.wrap(Ast0.MacroDecl($1,P.clt2mcode "(" $2,$3,
-                                 P.clt2mcode ")" $4,P.clt2mcode ";" $5)) } 
+                                 P.clt2mcode ")" $4,P.clt2mcode ";" $5)) }
+  | decl_ident TOPar eexpr_list_option TCPar q=TEq e=initialize TPtVirg
+      { Ast0.wrap
+            (Ast0.MacroDeclInit
+               ($1,P.clt2mcode "(" $2,$3,
+                P.clt2mcode ")" $4,P.clt2mcode "=" q,e,
+                P.clt2mcode ";" $7)) }
   | s=ioption(storage)
-    t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+    t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
     lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
     q=TEq e=initialize pv=TPtVirg
       { let (id,fn) = d in
@@ -991,15 +1335,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) }
 
@@ -1007,59 +1344,57 @@ 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)) }
 
 initialize2:
   /*arithexpr and not eexpr because can have ambiguity with comma*/
   /*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 */
-| TDot ident TEq initialize2
-    { Ast0.wrap(Ast0.InitGccDotName(P.clt2mcode "." $1,$2,P.clt2mcode "=" $3,$4)) }
-| ident TDotDot initialize2
+| list(designator) TEq initialize2 /*can we have another of these on the rhs?*/
+    { Ast0.wrap(Ast0.InitGccExt($1,P.clt2mcode "=" $2,$3)) }
+| mident TDotDot initialize2
     { Ast0.wrap(Ast0.InitGccName($1,P.clt2mcode ":" $2,$3)) } /* in old kernel */
-| TOCro eexpr TCCro TEq initialize2
-    { Ast0.wrap(Ast0.InitGccIndex(P.clt2mcode "[" $1,$2,P.clt2mcode "]" $3,
-                                 P.clt2mcode "=" $4,$5)) }
-| TOCro eexpr TEllipsis eexpr TCCro TEq initialize2
-    { Ast0.wrap(Ast0.InitGccRange(P.clt2mcode "[" $1,$2,P.clt2mcode "..." $3,
-                                 $4,P.clt2mcode "]" $5,P.clt2mcode "=" $6,$7)) }
+  | 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 disj_ident
+     { Ast0.DesignatorField (P.clt2mcode "." $1,$2) }
+ | TOCro eexpr TCCro
+     { Ast0.DesignatorIndex (P.clt2mcode "[" $1,$2,P.clt2mcode "]" $3) }
+ | TOCro eexpr TEllipsis eexpr TCCro
+     { Ast0.DesignatorRange (P.clt2mcode "[" $1,$2,P.clt2mcode "..." $3,
+                            $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 }
-| 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 }
-| i=initialize2 c=TComma r=comma_initializers(dotter)
-    { (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))])::
-      r }
-
-comma_initializers2(dotter):
-  /* empty */ { [] }
-| 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:
@@ -1122,16 +1457,23 @@ 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
+The arg versions don't allow sequences, to avoid conflicting with commas in
+argument lists.
+ */
 expr:  basic_expr(expr,invalid) { $1 }
 /* allows ... and nests */
-eexpr: basic_expr(eexpr,dot_expressions) { $1 }
+eexpr: pre_basic_expr(eexpr,dot_expressions) { $1 }
+eargexpr: basic_expr(eexpr,dot_expressions) { $1 } /* no sequences */
 /* allows nests but not .... */
-dexpr: basic_expr(eexpr,nest_expressions) { $1 }
+dexpr: pre_basic_expr(eexpr,nest_expressions) { $1 }
+dargexpr: basic_expr(eexpr,nest_expressions) { $1 } /* no sequences */
 
 top_eexpr:
   eexpr { Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp($1)))) }
@@ -1143,20 +1485,28 @@ dot_expressions:
   TEllipsis { Ast0.wrap(Ast0.Edots(P.clt2mcode "..." $1,None)) }
 | nest_expressions { $1 }
 
+/* not clear what whencode would mean, so just drop it */
 nest_expressions:
-  TOEllipsis w=option(whenexp) e=expr_dots(TEllipsis) c=TCEllipsis
+  TOEllipsis e=expr_dots(TEllipsis) c=TCEllipsis
     { Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<..." $1,
                              Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))),
-                             P.clt2mcode "...>" c, w, false)) }
-| TPOEllipsis w=option(whenexp) e=expr_dots(TEllipsis) c=TPCEllipsis
+                             P.clt2mcode "...>" c, None, false)) }
+| TPOEllipsis e=expr_dots(TEllipsis) c=TPCEllipsis
     { Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<+..." $1,
                              Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))),
-                             P.clt2mcode "...+>" c, w, true)) }
+                             P.clt2mcode "...+>" c, None, true)) }
+| TMeta { tmeta_to_exp $1 }
+
+//whenexp: TWhen TNotEq w=eexpr TLineEnd { w }
 
-whenexp: TWhen TNotEq w=eexpr TLineEnd { w }
+pre_basic_expr(recurser,primary_extra):
+   basic_expr(recurser,primary_extra)                     { $1 }
+ | pre_basic_expr(recurser,primary_extra) TComma
+     basic_expr(recurser,primary_extra)
+     { Ast0.wrap(Ast0.Sequence($1,P.clt2mcode "," $2,$3)) }
 
 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 }
@@ -1182,39 +1532,75 @@ 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=eargexpr/*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) TShOp    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_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)
@@ -1223,16 +1609,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_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_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(r,pe)
+  | TDec unary_expr_bis
       { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Dec $1)) }
-  | unary_op unary_expr(r,pe)
+  | unary_op cast_expr(eexpr,dot_expressions)
       { 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(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,
@@ -1250,9 +1655,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
@@ -1263,9 +1668,26 @@ postfix_expr(r,pe):
      { Ast0.wrap(Ast0.FunCall($1,P.clt2mcode "(" $2,
                              $3,
                              P.clt2mcode ")" $4)) }
+ /*(* gccext: also called compound literals *)
+   empty case causes conflicts */
+ | TOPar ctype TCPar TOBrace initialize_list TCBrace
+     { let init =
+       if P.struct_initializer $5
+       then
+        let il = P.drop_dot_commas $5 in
+        Ast0.wrap
+          (Ast0.InitList(P.clt2mcode "{" $4,il,P.clt2mcode "}" $6,false))
+       else
+        Ast0.wrap
+          (Ast0.InitList(P.clt2mcode "{" $4,$5,P.clt2mcode "}" $6,true)) in
+     Ast0.wrap
+       (Ast0.Constructor(P.clt2mcode "(" $1, $2, P.clt2mcode ")" $3, init)) }
 
 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)) }
@@ -1321,54 +1743,233 @@ no_dot_start_end(grammar,dotter):
 pure_ident:
      TIdent { $1 }
 
+pure_ident_or_symbol:
+    pure_ident { $1 }
+  | TSymId { $1 }
+
+pure_ident_kwd:
+   | TIdentifier { "identifier" }
+   | TExpression { "expression" }
+   | TStatement { "statement" }
+   | TFunction { "function" }
+   | TLocal { "local" }
+   | TType { "type" }
+   | TParameter { "parameter" }
+   | TIdExpression { "idexpression" }
+   | TInitialiser { "initialiser" }
+   | Tlist { "list" }
+   | TFresh { "fresh" }
+   | TConstant { "constant" }
+   | TError { "error" }
+   | TWords { "words" }
+   | TPure { "pure" }
+   | TContext { "context" }
+   | TGenerated { "generated" }
+   | TTypedef { "typedef" }
+   | TDeclarer { "declarer" }
+   | TIterator { "iterator" }
+   | TName { "name" }
+   | TPosition { "position" }
+   | TSymbol { "symbol" }
+
 meta_ident:
-       TRuleName TDot pure_ident { (Some $1,P.id2name $3) }
+     TRuleName TDot pure_ident     { (Some $1,P.id2name $3) }
+   | TRuleName TDot pure_ident_kwd { (Some $1,$3) }
 
 pure_ident_or_meta_ident:
        pure_ident                { (None,P.id2name $1) }
+     | pure_ident_kwd            { (None,$1) }
      | meta_ident                { $1 }
-     | Tlist                     { (None,"list") }
-     | TError                    { (None,"error") }
-     | TType                     { (None,"type") }
-
-pure_ident_or_meta_ident_with_not_eq(not_eq):
-       i=pure_ident_or_meta_ident l=loption(not_eq) { (i,l) }
 
-not_eq:
-       TNotEq i=pure_ident
+wrapped_sym_ident:
+  TSymId { Ast0.wrap(Ast0.Id(P.sym2mcode $1)) }
+
+pure_ident_or_meta_ident_with_seed:
+       pure_ident_or_meta_ident { ($1,Ast.NoVal) }
+     | pure_ident_or_meta_ident TEq
+        separated_nonempty_list(TCppConcatOp,seed_elem)
+        { match $3 with
+          [Ast.SeedString s] -> ($1,Ast.StringSeed s)
+        | _ -> ($1,Ast.ListSeed $3) }
+
+seed_elem:
+  TString { let (x,_) = $1 in Ast.SeedString 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));
+      Ast.SeedId nm }
+
+pure_ident_or_meta_ident_with_x_eq(x_eq):
+       i=pure_ident_or_meta_ident l=loption(x_eq)
+    {
+      (i, l)
+    }
+
+pure_ident_or_meta_ident_with_econstraint(x_eq):
+       i=pure_ident_or_meta_ident optc=option(x_eq)
+    {
+      match optc with
+         None   -> (i, Ast0.NoConstraint)
+       | Some c -> (i, c)
+    }
+
+pure_ident_or_meta_ident_with_idconstraint_virt(constraint_type):
+  i=pure_ident_or_meta_ident c=option(constraint_type)
+    {
+      Common.Left
+        (match c with
+         None -> (i, Ast.IdNoConstraint)
+       | Some constraint_ -> (i,constraint_))
+    }
+| 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)
+    {
+      match c with
+         None -> (i, Ast.IdNoConstraint)
+       | Some constraint_ -> (i,constraint_)
+    }
+
+re_or_not_eqid:
+   re=regexp_eqid {Ast.IdRegExpConstraint re}
+ | ne=not_eqid    {ne}
+
+regexp_eqid:
+     TTildeEq re=TString
+         { (if !Data.in_iso
+           then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+           then failwith "constraints not allowed in a generated rule file");
+          let (s,_) = re in Ast.IdRegExp (s,Regexp.regexp s)
+        }
+ | TTildeExclEq re=TString
+         { (if !Data.in_iso
+           then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+           then failwith "constraints not allowed in a generated rule file");
+          let (s,_) = re in Ast.IdNotRegExp (s,Regexp.regexp s)
+        }
+
+not_eqid:
+       TNotEq i=pure_ident_or_meta_ident
          { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
-          [Ast0.wrap(Ast0.Id(P.id2mcode i))] }
-     | TNotEq TOBrace l=comma_list(pure_ident) TCBrace
+          (if !Data.in_generating
+           (* pb: constraints not stored with metavars; too lazy to search for
+             them in the pattern *)
+          then failwith "constraints not allowed in a generated rule file");
+          (match i with
+            (Some rn,id) ->
+              let i =
+                P.check_inherited_constraint i
+                  (function mv -> Ast.MetaIdDecl(Ast.NONE,mv)) in
+              Ast.IdNegIdSet([],[i])
+          | (None,i) -> Ast.IdNegIdSet([i],[])) }
+     | TNotEq TOBrace l=comma_list(pure_ident_or_meta_ident) TCBrace
         { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
-          List.map (function i -> Ast0.wrap(Ast0.Id(P.id2mcode i))) l }
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
+          let (str,meta) =
+            List.fold_left
+              (function (str,meta) ->
+                function
+                  (Some rn,id) as i ->
+                    let i =
+                      P.check_inherited_constraint i
+                        (function mv -> Ast.MetaIdDecl(Ast.NONE,mv)) in
+                    (str,i::meta)
+                | (None,i) -> (i::str,meta))
+              ([],[]) l in
+          Ast.IdNegIdSet(str,meta)
+        }
+
+re_or_not_eqe_or_sub:
+   re=regexp_eqid {Ast0.NotIdCstrt  re}
+ | ne=not_eqe     {Ast0.NotExpCstrt ne}
+ | s=sub          {Ast0.SubExpCstrt s}
+
+not_ceq_or_sub:
+   ceq=not_ceq    {Ast0.NotExpCstrt ceq}
+ | s=sub          {Ast0.SubExpCstrt s}
 
 not_eqe:
        TNotEq i=pure_ident
          { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
-          [Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))] }
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
+          [Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))]
+        }
      | TNotEq TOBrace l=comma_list(pure_ident) TCBrace
         { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
           List.map
             (function i ->
-              Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))))
-            l }
+               Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))))
+            l
+        }
 
 not_ceq:
        TNotEq i=ident_or_const
          { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
           [i] }
      | TNotEq TOBrace l=comma_list(ident_or_const) TCBrace
         { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
           l }
 
+sub:
+     (* has to be inherited because not clear how to check subterm constraints
+       in the functorized CTL engine, so need the variable to be bound
+       already when bind the subterm constrained metavariable *)
+       TSub i=meta_ident
+         { (if !Data.in_iso
+          then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
+          let i =
+            P.check_inherited_constraint i
+              (function mv -> Ast.MetaExpDecl(Ast.NONE,mv,None)) in
+          [i] }
+     | TSub TOBrace l=comma_list(meta_ident) TCBrace
+        { (if !Data.in_iso
+          then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
+           List.map
+            (function i ->
+              P.check_inherited_constraint i
+                (function mv -> Ast.MetaExpDecl(Ast.NONE,mv,None)))
+            l}
+
 ident_or_const:
        i=pure_ident { Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))) }
+     | wrapped_sym_ident { Ast0.wrap(Ast0.Ident($1)) }
      | TInt
         { let (x,clt) = $1 in
         Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) }
@@ -1377,30 +1978,34 @@ not_pos:
        TNotEq i=meta_ident
          { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
-          match i with
-            (None,_) -> failwith "constraint must be an inherited variable"
-          | (Some rule,name) ->
-              let i = (rule,name) in
-              P.check_meta(Ast.MetaPosDecl(Ast.NONE,i));
-              [i] }
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
+          let i =
+            P.check_inherited_constraint i
+              (function mv -> Ast.MetaPosDecl(Ast.NONE,mv)) in
+          [i] }
      | TNotEq TOBrace l=comma_list(meta_ident) TCBrace
         { (if !Data.in_iso
           then failwith "constraints not allowed in iso file");
+          (if !Data.in_generating
+          then failwith "constraints not allowed in a generated rule file");
           List.map
-            (function
-                (None,_) ->
-                  failwith "constraint must be an inherited variable"
-              | (Some rule,name) ->
-                  let i = (rule,name) in
-                  P.check_meta(Ast.MetaPosDecl(Ast.NONE,i));
-                  i)
+            (function i ->
+              P.check_inherited_constraint i
+                (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)) }
@@ -1411,27 +2016,48 @@ func_ident: pure_ident
 
 ident: pure_ident
          { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
+     | wrapped_sym_ident { $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)) }
+     | wrapped_sym_ident { $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
+       pure_ident_or_symbol
          { 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)) }
@@ -1439,46 +2065,80 @@ typedef_ident:
 /*****************************************************************************/
 
 decl_list(decl):
-   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 }
 
-error_words:
+/* ---------------------------------------------------------------------- */
+
+/* error words make it complicated to be able to use error as a metavariable
+name or a type in a metavariable list; for that we would like to allow TError
+as an ident, but that makes conflicts with this rule.  To add back error words,
+need to find some appropriate delimiter for it, but it has not been used much
+so just drop it */
+/*error_words:
     TError TWords TEq TOCro cl=comma_list(dexpr) TCCro
       { [Ast0.wrap(Ast0.ERRORWORDS(cl))] }
+*/
 
 /* ---------------------------------------------------------------------- */
 /* sequences of statements and expressions */
@@ -1511,12 +2171,19 @@ 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_start(toplevel_after_dots_init)
+| toplevel_seq_startne(toplevel_after_dots_init)
     { List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1 }
 
+toplevel_seq_startne(after_dots_init):
+  a=stm_dots_ell b=after_dots_init           { a::b }
+| a=stm_dots_nest b=after_dots_init           { a::b }
+| a=stm_dots_nest                      { [a] }
+| expr toplevel_after_exp            { (Ast0.wrap(Ast0.Exp($1)))::$2 }
+| decl_statement_expr toplevel_after_stm  { $1@$2 }
+
 toplevel_seq_start(after_dots_init):
   stm_dots after_dots_init           { $1::$2 }
 | expr toplevel_after_exp            { (Ast0.wrap(Ast0.Exp($1)))::$2 }
@@ -1544,7 +2211,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 */
@@ -1557,7 +2229,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 }
 
@@ -1570,14 +2242,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 }
 
@@ -1643,49 +2315,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 }
+    dargexpr { 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))) }
 
 /****************************************************************************/
 
@@ -1704,7 +2355,7 @@ edots_when(dotter,when_grammar):
     d=dotter                                      { (d,None) }
   | d=dotter TWhen TNotEq w=when_grammar TLineEnd { (d,Some w) }
 
-whens(when_grammar,simple_when_grammar):
+whens(when_grammar,simple_when_grammar,any_strict):
     TWhen TNotEq w=when_grammar TLineEnd { [Ast0.WhenNot w] }
   | TWhen TEq w=simple_when_grammar TLineEnd { [Ast0.WhenAlways w] }
   | TWhen comma_list(any_strict) TLineEnd
@@ -1724,18 +2375,22 @@ any_strict:
 *****************************************************************************/
 
 iso_main:
-  TIsoExpression e1=dexpr el=list(iso(dexpr)) EOF
-    { P.iso_adjust (function x -> Ast0.ExprTag x) e1 el }
-| TIsoArgExpression e1=dexpr el=list(iso(dexpr)) EOF
-    { P.iso_adjust (function x -> Ast0.ArgExprTag x) e1 el }
-| TIsoTestExpression e1=dexpr el=list(iso(dexpr)) EOF
-    { P.iso_adjust (function x -> Ast0.TestExprTag x) e1 el }
-| TIsoStatement s1=single_statement sl=list(iso(single_statement)) EOF
-    { P.iso_adjust (function x -> Ast0.StmtTag x) s1 sl }
+  TIsoExpression e1=eexpr el=list(iso(eexpr)) EOF
+    { let fn x = Ast0.ExprTag x in P.iso_adjust fn fn e1 el }
+| TIsoArgExpression e1=eexpr el=list(iso(eexpr)) EOF
+    { let fn x = Ast0.ArgExprTag x in P.iso_adjust fn fn e1 el }
+| TIsoTestExpression e1=eexpr el=list(iso(eexpr)) EOF
+    { let fn x = Ast0.TestExprTag x in P.iso_adjust fn fn e1 el }
+| TIsoToTestExpression e1=eexpr el=list(iso(eexpr)) EOF
+    { let ffn x = Ast0.ExprTag x in
+      let fn x =  Ast0.TestExprTag x in
+      P.iso_adjust ffn fn e1 el }
+| TIsoStatement s1=iso_statement sl=list(iso(iso_statement)) EOF
+    { let fn x = Ast0.StmtTag x in P.iso_adjust fn fn s1 sl }
 | TIsoType t1=ctype tl=list(iso(ctype)) EOF
-    { P.iso_adjust (function x -> Ast0.TypeCTag x) t1 tl }
+    { let fn x = Ast0.TypeCTag x in P.iso_adjust fn fn t1 tl }
 | TIsoTopLevel e1=nest_start el=list(iso(nest_start)) EOF
-    { P.iso_adjust (function x -> Ast0.DotsStmtTag x) e1 el }
+    { let fn x = Ast0.DotsStmtTag x in P.iso_adjust fn fn e1 el }
 | TIsoDeclaration d1=decl_var dl=list(iso(decl_var)) EOF
     { let check_one = function
        [x] -> x
@@ -1750,7 +2405,7 @@ iso_main:
            Common.Left x -> Common.Left(check_one x)
          | Common.Right x -> Common.Right(check_one x))
        dl in
-    P.iso_adjust (function x -> Ast0.DeclTag x) d1 dl }
+    let fn x = Ast0.DeclTag x in P.iso_adjust fn fn d1 dl }
 
 iso(term):
     TIso t=term { Common.Left t }
@@ -1765,5 +2420,28 @@ never_used: TPragma { () }
   | TPArob TMetaPos { () }
   | TScriptData     { () }
 
-script_meta_main: py=pure_ident TShOp TRuleName TDot cocci=pure_ident TMPtVirg
-  { (P.id2name py, ($3, P.id2name cocci)) }
+script_meta_main:
+    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:
+    TShLOp TRuleName TDot cocci=pure_ident
+      { let nm = P.id2name cocci in
+        let mv = Parse_aux.lookup $2 nm in
+        (($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) }