diff --git a/Makefile b/Makefile
index 92ccb6f36b481cf0198b9f721cc00d5c4b3864f2..9d94325ae423e998f608e5d2d06ac95347178f4e 100644
--- a/Makefile
+++ b/Makefile
@@ -125,11 +125,13 @@ FRAMAC_PTESTS:=$(FRAMAC_PTESTS_SRC)/ptests.exe
 # WTESTS is internal
 FRAMAC_WTESTS:=$(FRAMAC_PTESTS_SRC)/wtests.exe
 
-# Frama-C also have ptest directories in plugins, so we do not use default
-PTEST_ALL_DIRS:=tests $(wildcard src/plugins/*/tests)
+# Frama-C also has ptest directories in plugins, so we do not use default
+PTEST_ALL_DIRS:=tests $(wildcard src/plugins/*/tests) \
+  src/kernel_internals/parsing/tests
 
 # Test aliasing definition allowing ./configure --disable-<plugin>
-PTEST_ALIASES:=@tests/ptests @src/plugins/ptests
+PTEST_ALIASES:=@tests/ptests @src/plugins/ptests \
+  @src/kernel_internals/parsing/tests/ptests
 
 # WP tests need WP cache
 PTEST_USE_WP_CACHE:=yes
diff --git a/bin/test.sh b/bin/test.sh
index c6da0cac0fc4aca2b94f1a61a25a109579eb789b..2e9558da3943989b9fb0281c5226ec96da649254 100755
--- a/bin/test.sh
+++ b/bin/test.sh
@@ -35,7 +35,7 @@ DUNE_LOG=./.test-errors.log
 CACHEDIR=$(pwd -P)/.wp-cache
 FRAMAC_WP_CACHE_GIT=git@git.frama-c.com:frama-c/wp-cache.git
 
-TEST_DIRS="tests/* src/plugins/*/tests/*"
+TEST_DIRS="tests/* src/plugins/*/tests/* src/kernel_internals/parsing/tests"
 
 # --------------------------------------------------------------------------
 # ---  Help Message
diff --git a/dune b/dune
index a9457494dad99f7ab49c7bdacfb046af3e4955fd..82fbcdc86de6cb46540b47b9919e8171a30c3959 100644
--- a/dune
+++ b/dune
@@ -20,6 +20,9 @@
 ;;                                                                        ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(env
+  (trace-menhir (menhir_flags --trace)))
+
 (alias (name default) (deps (alias install)))
 (dirs bin headers man share src tools tests)
 
diff --git a/src/kernel_internals/parsing/dune b/src/kernel_internals/parsing/dune
index 9e358da57e09828bd2f73d9a4b618d62e32f9607..bfa9e3a404a65b96ae8d8df4010c44a4dd05d998 100644
--- a/src/kernel_internals/parsing/dune
+++ b/src/kernel_internals/parsing/dune
@@ -24,7 +24,11 @@
 (ocamllex logic_preprocess)
 (ocamllex logic_lexer)
 
-(ocamlyacc logic_parser)
+(menhir
+  (modules logic_parser)
+  ; "--fixed-exception" fixes compatibility with ocamlyacc Parsing.Parse_error
+  (flags :standard --fixed-exception --explain --dump --comment)
+)
 
 (menhir
   (modules cparser)
diff --git a/src/kernel_internals/parsing/logic_lexer.mll b/src/kernel_internals/parsing/logic_lexer.mll
index 5177559a48298019210e3bcaf5bc700e4aaebc41..876f7d98eb124a74204704059a26eb1561ba2225 100644
--- a/src/kernel_internals/parsing/logic_lexer.mll
+++ b/src/kernel_internals/parsing/logic_lexer.mll
@@ -103,127 +103,113 @@
 
   let identifier, is_acsl_keyword =
     let all_kw = Hashtbl.create 37 in
-    let c_kw = Hashtbl.create 37 in
     let type_kw = Hashtbl.create 3 in
     List.iter
-      (fun (i,t,flag) ->
-         Hashtbl.add all_kw i t;
-         if flag then Hashtbl.add c_kw i t
-      )
+      (fun (i,t) -> Hashtbl.add all_kw i t;)
       [
-        "admit", (fun _ -> ADMIT), false;
-        "allocates", (fun _ -> ALLOCATES), false;
-        "assert", (fun _ -> ASSERT), false;
-        "assigns", (fun _ -> ASSIGNS), false;
-        "assumes", (fun _ -> ASSUMES), false;
-        "at", (fun _ -> EXT_AT), false;
+        "admit", (fun _ -> ADMIT);
+        "allocates", (fun _ -> ALLOCATES);
+        "assert", (fun _ -> ASSERT);
+        "assigns", (fun _ -> ASSIGNS);
+        "assumes", (fun _ -> ASSUMES);
+        "at", (fun _ -> EXT_AT);
         (* ACSL extension for external spec file *)
-        "axiom", (fun _ -> AXIOM), false;
-        "axiomatic", (fun _ -> AXIOMATIC), false;
-        "behavior", (fun _ -> BEHAVIOR), false;
-        "behaviors", (fun _ -> BEHAVIORS), false;
-        "_Bool", (fun _ -> BOOL), true;
-        "breaks", (fun _ -> BREAKS), false;
-        "case", (fun _ -> CASE), true;
-        "char", (fun _ -> CHAR), true;
-        "check", (fun _ -> CHECK), false;
-        "complete", (fun _ -> COMPLETE), false;
-        "const", (fun _ -> CONST), true;
-        "continues", (fun _ -> CONTINUES), false;
-        "contract", (fun _ -> CONTRACT), false;
+        "axiom", (fun _ -> AXIOM);
+        "axiomatic", (fun _ -> AXIOMATIC);
+        "behavior", (fun _ -> BEHAVIOR);
+        "behaviors", (fun _ -> BEHAVIORS);
+        "_Bool", (fun _ -> BOOL);
+        "breaks", (fun _ -> BREAKS);
+        "case", (fun _ -> CASE);
+        "char", (fun _ -> CHAR);
+        "check", (fun _ -> CHECK);
+        "complete", (fun _ -> COMPLETE);
+        "const", (fun _ -> CONST);
+        "continues", (fun _ -> CONTINUES);
+        "contract", (fun _ -> CONTRACT);
         (* ACSL extension for external spec file *)
-        "decreases", (fun _ -> DECREASES), false;
-        "disjoint", (fun _ -> DISJOINT), false;
-        "double", (fun _ -> DOUBLE), true;
-        "else", (fun _ -> ELSE), true;
-        "ensures", (fun _ -> ENSURES), false ;
-        "enum", (fun _ -> ENUM), true;
-        "exits", (fun _ -> EXITS), false;
-        "frees", (fun _ -> FREES), false;
-        "function", (fun _ -> FUNCTION), false;
+        "decreases", (fun _ -> DECREASES);
+        "disjoint", (fun _ -> DISJOINT);
+        "double", (fun _ -> DOUBLE);
+        "else", (fun _ -> ELSE);
+        "ensures", (fun _ -> ENSURES);
+        "enum", (fun _ -> ENUM);
+        "exits", (fun _ -> EXITS);
+        "frees", (fun _ -> FREES);
+        "function", (fun _ -> FUNCTION);
         (* ACSL extension for external spec file *)
-        "float", (fun _ -> FLOAT), true;
-        "for", (fun _ -> FOR), true;
-        "global", (fun _ -> GLOBAL), false;
-        "if", (fun _ -> IF), true;
-	"impact", (fun _ -> IMPACT), false;
-	"inductive", (fun _ -> INDUCTIVE), false;
-	"include", (fun _ -> INCLUDE), false;
+        "float", (fun _ -> FLOAT);
+        "for", (fun _ -> FOR);
+        "global", (fun _ -> GLOBAL);
+        "if", (fun _ -> IF);
+	"impact", (fun _ -> IMPACT);
+	"inductive", (fun _ -> INDUCTIVE);
+	"include", (fun _ -> INCLUDE);
         (* ACSL extension for external spec file *)
-        "int", (fun _ -> INT), true;
-        "invariant", (fun _ -> INVARIANT), false;
-        "label", (fun _ -> LABEL), false;
-        "lemma", (fun _ -> LEMMA), false;
-        "let", (fun _ -> EXT_LET), false;
+        "int", (fun _ -> INT);
+        "invariant", (fun _ -> INVARIANT);
+        "label", (fun _ -> LABEL);
+        "lemma", (fun _ -> LEMMA);
+        "let", (fun _ -> EXT_LET);
         (* ACSL extension for external spec file *)
-        "logic", (fun _ -> LOGIC), false;
-        "long", (fun _ -> LONG), true;
-        "loop", (fun _ -> LOOP), false;
-        "model", (fun _ -> MODEL), false;
+        "logic", (fun _ -> LOGIC);
+        "long", (fun _ -> LONG);
+        "loop", (fun _ -> LOOP);
+        "model", (fun _ -> MODEL);
         (* ACSL extension for model fields *)
-        "module", (fun _ -> MODULE), false;
+        "module", (fun _ -> MODULE);
         (* ACSL extension for external spec file *)
-        "pragma", (fun _ -> PRAGMA), false;
-        "predicate", (fun _ -> PREDICATE), false;
-        "reads", (fun _ -> READS), true;
-        (* treated specifically in the parser to
-           avoid issue in volatile clause. *)
-        "requires", (fun _ -> REQUIRES), false;
-        "returns", (fun _ -> RETURNS), false;
-        "short", (fun _ -> SHORT), true;
-        "signed", (fun _ -> SIGNED), true;
-        "sizeof", (fun _ -> SIZEOF), true;
-        "slice", (fun _ -> SLICE), false;
-        "struct", (fun _ -> STRUCT), true;
-        "terminates", (fun _ -> TERMINATES), false;
-        "type", (fun _ -> TYPE), false;
-        "union", (fun _ -> UNION), true;
-        "unsigned", (fun _ -> UNSIGNED), true;
-        "variant", (fun _ -> VARIANT), false;
-        "void", (fun _ -> VOID), true;
-        "volatile", (fun _ -> VOLATILE), true;
-        "writes", (fun _ -> WRITES), true;
-        (* treated specifically in the parser to
-           avoid issue in volatile clause. *)
+        "pragma", (fun _ -> PRAGMA);
+        "predicate", (fun _ -> PREDICATE);
+        "reads", (fun _ -> READS);
+        "requires", (fun _ -> REQUIRES);
+        "returns", (fun _ -> RETURNS);
+        "short", (fun _ -> SHORT);
+        "signed", (fun _ -> SIGNED);
+        "sizeof", (fun _ -> SIZEOF);
+        "slice", (fun _ -> SLICE);
+        "struct", (fun _ -> STRUCT);
+        "terminates", (fun _ -> TERMINATES);
+        "type", (fun _ -> TYPE);
+        "union", (fun _ -> UNION);
+        "unsigned", (fun _ -> UNSIGNED);
+        "variant", (fun _ -> VARIANT);
+        "void", (fun _ -> VOID);
+        "volatile", (fun _ -> VOLATILE);
+        "writes", (fun _ -> WRITES);
         "__FC_FILENAME__",
         (fun loc ->
            let filename =
              Filepath.(Normalized.to_pretty_string (fst loc).pos_path)
            in
-           STRING_LITERAL (false,filename)),
-        true;
+           STRING_LITERAL (false,filename));
       ];
     List.iter (fun (x, y) -> Hashtbl.add type_kw x y)
       ["integer", INTEGER; "real", REAL; "boolean", BOOLEAN; ];
     (fun s loc ->
       try
-        (Hashtbl.find (if Logic_utils.is_kw_c_mode () then c_kw else all_kw) s)
+        (Hashtbl.find all_kw s)
         loc
       with Not_found ->
         let res =
-          if not (Logic_utils.is_kw_c_mode ()) then begin
-            match Logic_env.extension_category s with
-            | exception Not_found -> None
-            | Cil_types.Ext_contract -> Some (EXT_CONTRACT s)
-            | Cil_types.Ext_global ->
-              begin
-                match Logic_env.is_extension_block s with
-                | false -> Some (EXT_GLOBAL s)
-                | true -> Some (EXT_GLOBAL_BLOCK s)
-              end
-            | Cil_types.Ext_code_annot _ -> Some (EXT_CODE_ANNOT s)
-          end
-          else None
+          match Logic_env.extension_category s with
+          | exception Not_found -> None
+          | Cil_types.Ext_contract -> Some (EXT_CONTRACT s)
+          | Cil_types.Ext_global ->
+            begin
+              match Logic_env.is_extension_block s with
+              | false -> Some (EXT_GLOBAL s)
+              | true -> Some (EXT_GLOBAL_BLOCK s)
+            end
+          | Cil_types.Ext_code_annot _ -> Some (EXT_CODE_ANNOT s)
         in
         match res with
         | None ->
-        if Logic_env.typename_status s then TYPENAME s
-        else
-          (try
-             Hashtbl.find type_kw s
-           with Not_found ->
-             if Logic_utils.is_rt_type_mode () then TYPENAME s
-               else IDENTIFIER s)
+          if Logic_env.typename_status s then TYPENAME s
+          else
+            (try
+               Hashtbl.find type_kw s
+             with Not_found -> IDENTIFIER s)
         | Some lex -> lex
     ),
     (fun s -> Hashtbl.mem all_kw s || Hashtbl.mem type_kw s)
@@ -555,8 +541,7 @@ and comment = parse
     dest_lexbuf.lex_abs_pos <- src_pos.pos_cnum
 
   let parse_from_position f (pos, s : Filepath.position * string) =
-    let finally _ = Logic_utils.exit_kw_c_mode () in
-    let output = Kernel.logwith finally ~wkey:Kernel.wkey_annot_error
+    let output = Kernel.warning ~wkey:Kernel.wkey_annot_error
     in
     let lb = from_string s in
     set_initial_position lb (Cil_datatype.Position.to_lexing_pos pos);
diff --git a/src/kernel_internals/parsing/logic_parser.mly b/src/kernel_internals/parsing/logic_parser.mly
index be05d3183e02f95e78977ecc0cb83e7af031ed6b..d10a972435e8ed7c85c1a17a24a7063cabb66a11 100644
--- a/src/kernel_internals/parsing/logic_parser.mly
+++ b/src/kernel_internals/parsing/logic_parser.mly
@@ -30,20 +30,19 @@
   open Logic_ptree
   open Logic_utils
 
-  let loc () =
+  let loc (start_pos, end_pos) =
     Cil_datatype.Location.of_lexing_loc
-      (symbol_start_pos (), symbol_end_pos ())
-  let lexeme_start nb =
-    Cil_datatype.Position.of_lexing_pos (Parsing.rhs_start_pos nb)
-  let lexeme_end nb =
-    Cil_datatype.Position.of_lexing_pos (Parsing.rhs_end_pos nb)
-  let lexeme_loc nb = (lexeme_start nb, lexeme_end nb)
-
-  let info x = { lexpr_node = x; lexpr_loc = loc () }
-  let loc_info loc x = { lexpr_node = x; lexpr_loc = loc }
+      (start_pos, end_pos)
+
+  let pos pos =
+    Cil_datatype.Position.of_lexing_pos pos
+
+  let loc_info lexpr_loc x = { lexpr_node = x; lexpr_loc }
   let loc_start x = fst x.lexpr_loc
   let loc_end x = snd x.lexpr_loc
 
+  let info start_end x = loc_info (loc start_end) x
+
   (* Normalize p1 && (p2 && p3) into (p1 && p2) && p3 *)
   let rec pland p1 p2 =
     match p2.lexpr_node with
@@ -59,17 +58,17 @@
         PLor(loc_info loc (plor p1 p3),p4)
       | _ -> PLor(p1,p2)
 
-  let clause_order i name1 name2 =
+  let clause_order start_end name1 name2 =
     raise
       (Not_well_formed
-         (lexeme_loc i,
+         (loc start_end,
           "wrong order of clause in contract: "
           ^ name1 ^ " after " ^ name2 ^ "."))
 
-  let missing i token next_token =
+  let missing start_end token next_token =
     raise
       (Not_well_formed
-         (lexeme_loc i,
+         (loc start_end,
           Format.asprintf "expecting '%s' before %s" token next_token))
 
   type sense_of_relation = Unknown | Disequal | Less | Greater
@@ -97,17 +96,9 @@
     let l = Stack.pop type_variables_stack in
     List.iter Logic_env.remove_typename l
 
-  let rt_type = ref false
-
-  let set_rt_type () = rt_type:= true
-
-  let reset_rt_type () = rt_type:=false
+  let loc_decl start_end d = { decl_node = d; decl_loc = loc start_end }
 
-  let is_rt_type () = !rt_type
-
-  let loc_decl d = { decl_node = d; decl_loc = loc () }
-
-  let loc_ext d = { extended_node = d; extended_loc = loc () }
+  let loc_ext start_end d = { extended_node = d; extended_loc = loc start_end }
 
   let filter_from l = function
     | FromAny ->
@@ -168,16 +159,16 @@
       | FreeAlloc(f1,a1),FreeAlloc(f2,a2) -> FreeAlloc(f2@f1,a2@a1)
 
   (* a1 represents the assigns _after_ the current clause a2. *)
-  let concat_assigns a1 a2 =
+  let concat_assigns start_pos a1 a2 =
     match a1,a2 with
         WritesAny,a -> Writes (concat_froms [] a)
       | Writes [], [] -> a1
       | Writes [], _  | Writes _, [] ->
         raise (
-          Not_well_formed (loc(),"Mixing \\nothing and a real location"))
+          Not_well_formed (loc start_pos,"Mixing \\nothing and a real location"))
       | Writes a1, a2 -> Writes (concat_froms (concat_froms [] a2) a1)
 
-  let concat_loop_assigns_allocation annots bhvs2 a2 fa2=
+  let concat_loop_assigns_allocation start_pos annots bhvs2 a2 fa2=
     (* NB: this is supposed to merge assigns related to named behaviors, in
        case of annotation like
        for a,b: assigns x,y;
@@ -203,7 +194,7 @@
             (match both with
               | [] -> bhvs2, ca::acc
               | _ ->
-                let common_annot = AAssigns(both,concat_assigns a1 a2) in
+                let common_annot = AAssigns(both,concat_assigns start_pos a1 a2) in
                 let annots =
                   match only1 with
                     | [] -> common_annot :: acc
@@ -339,24 +330,6 @@
 
 %%
 
-enter_kw_c_mode:
-/* empty */ { enter_kw_c_mode () }
-
-exit_kw_c_mode:
-/* empty */ { exit_kw_c_mode () }
-
-enter_rt_type:
-/* empty */ { if is_rt_type () then enter_rt_type_mode () }
-
-exit_rt_type:
-/* empty */ { if is_rt_type () then exit_rt_type_mode () }
-
-begin_rt_type:
-/* empty */ { set_rt_type () }
-
-end_rt_type:
-/* empty */ { reset_rt_type () }
-
 /*** predicates and terms ***/
 
 lexpr_list:
@@ -370,7 +343,7 @@ ne_lexpr_list:
 ;
 
 lexpr_eof:
-| full_lexpr EOF { $1 }
+| lexpr EOF { $1 }
 ;
 
 lexpr_option:
@@ -380,30 +353,30 @@ lexpr_option:
 
 lexpr:
   /* predicates */
-| lexpr IMPLIES lexpr { info (PLimplies ($1, $3)) }
-| lexpr IFF lexpr { info (PLiff ($1, $3)) }
-| lexpr OR lexpr     { info (plor $1 $3) }
-| lexpr AND lexpr    { info (pland $1 $3) }
-| lexpr HATHAT lexpr    { info (PLxor ($1, $3)) }
+| lexpr IMPLIES lexpr { info $sloc (PLimplies ($1, $3)) }
+| lexpr IFF lexpr { info $sloc (PLiff ($1, $3)) }
+| lexpr OR lexpr     { info $sloc (plor $1 $3) }
+| lexpr AND lexpr    { info $sloc (pland $1 $3) }
+| lexpr HATHAT lexpr    { info $sloc (PLxor ($1, $3)) }
 /* terms */
-| lexpr AMP lexpr { info (PLbinop ($1, Bbw_and, $3)) }
-| lexpr PIPE lexpr { info (PLbinop ($1, Bbw_or, $3)) }
-| lexpr HAT lexpr { info (PLbinop ($1, Bbw_xor, $3)) }
-| lexpr BIMPLIES lexpr { info (PLbinop (info (PLunop (Ubw_not, $1)), Bbw_or, $3)) }
-| lexpr BIFF lexpr { info (PLbinop (info (PLunop (Ubw_not, $1)), Bbw_xor, $3)) }
-| lexpr IN lexpr { info (PLapp ("\\subset", [], [info ((PLset [$1]));$3])) }
+| lexpr AMP lexpr { info $sloc (PLbinop ($1, Bbw_and, $3)) }
+| lexpr PIPE lexpr { info $sloc (PLbinop ($1, Bbw_or, $3)) }
+| lexpr HAT lexpr { info $sloc (PLbinop ($1, Bbw_xor, $3)) }
+| lexpr BIMPLIES lexpr { info $sloc (PLbinop (info $sloc (PLunop (Ubw_not, $1)), Bbw_or, $3)) }
+| lexpr BIFF lexpr { info $sloc (PLbinop (info $sloc (PLunop (Ubw_not, $1)), Bbw_xor, $3)) }
+| lexpr IN lexpr { info $sloc (PLapp ("\\subset", [], [info $sloc (PLset [$1]);$3])) }
 | lexpr QUESTION lexpr COLON2 lexpr %prec prec_question
-    { info (PLif ($1, $3, $5)) }
+    { info $sloc (PLif ($1, $3, $5)) }
 /* both terms and predicates */
-| any_identifier COLON lexpr %prec prec_named { info (PLnamed ($1, $3)) }
+| any_identifier COLON lexpr %prec prec_named { info $sloc (PLnamed ($1, $3)) }
 | string COLON lexpr %prec prec_named
       { let (iswide,str) = $1 in
         if iswide then begin
-           let l = loc () in
+           let l = loc $sloc in
            raise (Not_well_formed(l, "Wide strings are not allowed as labels."))
          end;
         let str = escape str in
-         info (PLnamed (str, $3))
+         info $sloc (PLnamed (str, $3))
        }
 | lexpr_rel { $1 }
 ;
@@ -416,24 +389,25 @@ lexpr_rel:
         let relation = loc_info loc (PLrel($1,rel,rhs)) in
         match oth_rel with
             None -> relation
-          | Some oth_relation -> info (pland relation oth_relation)
+          | Some oth_relation -> info $sloc (pland relation oth_relation)
       }
 ;
 
 lexpr_binder:
-| LET bounded_var EQUAL lexpr SEMICOLON lexpr %prec LET {info (PLlet($2,$4,$6))}
+| LET bounded_var EQUAL lexpr SEMICOLON lexpr %prec LET
+      { info $sloc (PLlet($2,$4,$6))}
 | FORALL binders SEMICOLON lexpr  %prec prec_forall
-      { info (PLforall ($2, $4)) }
+      { info $sloc (PLforall ($2, $4)) }
 | EXISTS binders SEMICOLON lexpr  %prec prec_exists
-      { info (PLexists ($2, $4)) }
+      { info $sloc (PLexists ($2, $4)) }
 | LAMBDA binders SEMICOLON lexpr  %prec prec_lambda
-      { info (PLlambda ($2,$4)) }
+      { info $sloc (PLlambda ($2,$4)) }
 ;
 
 lexpr_end_rel:
   lexpr_inner  { $1 }
 | lexpr_binder { $1 }
-| NOT lexpr_binder { info (PLnot $2) }
+| NOT lexpr_binder { info $sloc (PLnot $2) }
 ;
 
 rel_list:
@@ -455,7 +429,7 @@ rel_list:
       in
       $1,$2,sense,Some oth_rel
     else begin
-      let loc = lexeme_start 1, lexeme_end 3 in
+      let loc = loc $sloc in
       raise (Not_well_formed(loc,"Inconsistent relation chain."));
     end
   }
@@ -470,7 +444,7 @@ relation:
 | NE    { Neq }
     /* C. Marche: added to produce better error messages */
 | EQUAL {
-      let l = loc () in
+      let l = loc $sloc in
       raise
         (Not_well_formed(l,
                          "Assignment operators not allowed in annotations."))
@@ -485,119 +459,119 @@ lexpr_inner:
       else
         StringConstant content
       in
-      info (PLconstant cst)
+      info $sloc (PLconstant cst)
     }
-| NOT lexpr_inner { info (PLnot $2) }
-| TRUE { info PLtrue }
-| FALSE { info PLfalse }
-| OBJECT_POINTER opt_label_1 LPAR lexpr RPAR { info (PLobject_pointer ($2,$4)) }
-| VALID opt_label_1 LPAR lexpr RPAR { info (PLvalid ($2,$4)) }
-| VALID_READ opt_label_1 LPAR lexpr RPAR { info (PLvalid_read ($2,$4)) }
-| VALID_FUNCTION LPAR lexpr RPAR { info (PLvalid_function $3) }
+| NOT lexpr_inner { info $sloc (PLnot $2) }
+| TRUE { info $sloc PLtrue }
+| FALSE { info $sloc PLfalse }
+| OBJECT_POINTER opt_label_1 LPAR lexpr RPAR { info $sloc (PLobject_pointer ($2,$4)) }
+| VALID opt_label_1 LPAR lexpr RPAR { info $sloc (PLvalid ($2,$4)) }
+| VALID_READ opt_label_1 LPAR lexpr RPAR { info $sloc (PLvalid_read ($2,$4)) }
+| VALID_FUNCTION LPAR lexpr RPAR { info $sloc (PLvalid_function $3) }
 | VALID_INDEX opt_label_1 LPAR lexpr COMMA lexpr RPAR {
-  let source = fst (loc ()) in
+  let source = pos $symbolstartpos in
   obsolete ~source "\\valid_index(addr,idx)" ~now:"\\valid(addr+idx)";
-  info (PLvalid ($2,info (PLbinop ($4, Badd, $6)))) }
+  info $sloc (PLvalid ($2,info $sloc (PLbinop ($4, Badd, $6)))) }
 | VALID_RANGE opt_label_1 LPAR lexpr COMMA lexpr COMMA lexpr RPAR {
-  let source = fst (loc ()) in
+  let source = pos $symbolstartpos in
   obsolete "\\valid_range(addr,min,max)"
     ~source ~now:"\\valid(addr+(min..max))";
-  info (PLvalid
-          ($2,info (PLbinop ($4, Badd, (info (PLrange((Some $6),Some $8)))))))
+  info $sloc (PLvalid
+          ($2,info $sloc (PLbinop ($4, Badd, (info $sloc (PLrange((Some $6),Some $8)))))))
 }
-| INITIALIZED opt_label_1 LPAR lexpr RPAR { info (PLinitialized ($2,$4)) }
-| DANGLING opt_label_1 LPAR lexpr RPAR { info (PLdangling ($2,$4)) }
-| FRESH opt_label_2 LPAR lexpr COMMA lexpr RPAR { info (PLfresh ($2,$4, $6)) }
-| BASE_ADDR opt_label_1 LPAR lexpr RPAR { info (PLbase_addr ($2,$4)) }
-| BLOCK_LENGTH opt_label_1 LPAR lexpr RPAR { info (PLblock_length ($2,$4)) }
-| OFFSET opt_label_1 LPAR lexpr RPAR { info (PLoffset ($2,$4)) }
-| ALLOCABLE opt_label_1 LPAR lexpr RPAR { info (PLallocable ($2,$4)) }
-| FREEABLE opt_label_1 LPAR lexpr RPAR { info (PLfreeable ($2,$4)) }
+| INITIALIZED opt_label_1 LPAR lexpr RPAR { info $sloc (PLinitialized ($2,$4)) }
+| DANGLING opt_label_1 LPAR lexpr RPAR { info $sloc (PLdangling ($2,$4)) }
+| FRESH opt_label_2 LPAR lexpr COMMA lexpr RPAR { info $sloc (PLfresh ($2,$4, $6)) }
+| BASE_ADDR opt_label_1 LPAR lexpr RPAR { info $sloc (PLbase_addr ($2,$4)) }
+| BLOCK_LENGTH opt_label_1 LPAR lexpr RPAR { info $sloc (PLblock_length ($2,$4)) }
+| OFFSET opt_label_1 LPAR lexpr RPAR { info $sloc (PLoffset ($2,$4)) }
+| ALLOCABLE opt_label_1 LPAR lexpr RPAR { info $sloc (PLallocable ($2,$4)) }
+| FREEABLE opt_label_1 LPAR lexpr RPAR { info $sloc (PLfreeable ($2,$4)) }
 | ALLOCATION opt_label_1 LPAR lexpr RPAR
-  { let source = fst(loc()) in
+  { let source = pos $symbolstartpos in
     Kernel.not_yet_implemented ~source "\\allocation" }
 | AUTOMATIC {
-  let source = fst(loc()) in
+  let source = pos $symbolstartpos in
   Kernel.not_yet_implemented ~source "\\automatic" }
 | DYNAMIC {
-  let source = fst(loc()) in
+  let source = pos $symbolstartpos in
   Kernel.not_yet_implemented ~source "\\dynamic" }
 | REGISTER {
-  let source = fst(loc()) in
+  let source = pos $symbolstartpos in
   Kernel.not_yet_implemented ~source "\\register" }
 | STATIC {
-  let source = fst(loc()) in
+  let source = pos $symbolstartpos in
   Kernel.not_yet_implemented ~source "\\static" }
 | UNALLOCATED {
-  let source = fst(loc()) in
+  let source = pos $symbolstartpos in
   Kernel.not_yet_implemented ~source "\\unallocated" }
-| NULL { info PLnull }
-| constant { info (PLconstant $1) }
-| lexpr_inner PLUS lexpr_inner { info (PLbinop ($1, Badd, $3)) }
-| lexpr_inner MINUS lexpr_inner { info (PLbinop ($1, Bsub, $3)) }
-| lexpr_inner STAR lexpr_inner { info (PLbinop ($1, Bmul, $3)) }
-| lexpr_inner SLASH lexpr_inner { info (PLbinop ($1, Bdiv, $3)) }
-| lexpr_inner PERCENT lexpr_inner { info (PLbinop ($1, Bmod, $3)) }
-| lexpr_inner STARHAT lexpr_inner  { info (PLrepeat ($1, $3)) }
-| lexpr_inner ARROW identifier_or_typename { info (PLarrow ($1, $3)) }
-| lexpr_inner DOT identifier_or_typename { info (PLdot ($1, $3)) }
-| lexpr_inner LSQUARE range RSQUARE { info (PLarrget ($1, $3)) }
-| lexpr_inner LSQUARE lexpr RSQUARE { info (PLarrget ($1, $3)) }
-| LSQUAREPIPE lexpr_list RSQUAREPIPE {info (PLlist $2) }
-| MINUS lexpr_inner %prec prec_unary_op { info (PLunop (Uminus, $2)) }
+| NULL { info $sloc PLnull }
+| constant { info $sloc (PLconstant $1) }
+| lexpr_inner PLUS lexpr_inner { info $sloc (PLbinop ($1, Badd, $3)) }
+| lexpr_inner MINUS lexpr_inner { info $sloc (PLbinop ($1, Bsub, $3)) }
+| lexpr_inner STAR lexpr_inner { info $sloc (PLbinop ($1, Bmul, $3)) }
+| lexpr_inner SLASH lexpr_inner { info $sloc (PLbinop ($1, Bdiv, $3)) }
+| lexpr_inner PERCENT lexpr_inner { info $sloc (PLbinop ($1, Bmod, $3)) }
+| lexpr_inner STARHAT lexpr_inner  { info $sloc (PLrepeat ($1, $3)) }
+| lexpr_inner ARROW identifier_or_typename_full { info $sloc (PLarrow ($1, $3)) }
+| lexpr_inner DOT identifier_or_typename_full { info $sloc (PLdot ($1, $3)) }
+| lexpr_inner LSQUARE range RSQUARE { info $sloc (PLarrget ($1, $3)) }
+| lexpr_inner LSQUARE lexpr RSQUARE { info $sloc (PLarrget ($1, $3)) }
+| LSQUAREPIPE lexpr_list RSQUAREPIPE { info $sloc (PLlist $2) }
+| MINUS lexpr_inner %prec prec_unary_op { info $sloc (PLunop (Uminus, $2)) }
 | PLUS  lexpr_inner %prec prec_unary_op { $2 }
-| TILDE lexpr_inner { info (PLunop (Ubw_not, $2)) }
-| STAR  lexpr_inner %prec prec_unary_op { info (PLunop (Ustar, $2)) }
-| AMP   lexpr_inner %prec prec_unary_op { info (PLunop (Uamp, $2)) }
-| SIZEOF LPAR lexpr RPAR { info (PLsizeofE $3) }
-| SIZEOF LPAR cast_logic_type RPAR { info (PLsizeof $3) }
-| OLD LPAR lexpr RPAR { info (PLold $3) }
-| AT LPAR lexpr COMMA label_name RPAR { info (PLat ($3, $5)) }
-| RESULT { info PLresult }
+| TILDE lexpr_inner { info $sloc (PLunop (Ubw_not, $2)) }
+| STAR  lexpr_inner %prec prec_unary_op { info $sloc (PLunop (Ustar, $2)) }
+| AMP   lexpr_inner %prec prec_unary_op { info $sloc (PLunop (Uamp, $2)) }
+| SIZEOF LPAR lexpr RPAR { info $sloc (PLsizeofE $3) }
+| SIZEOF LPAR cast_logic_type RPAR { info $sloc (PLsizeof $3) }
+| OLD LPAR lexpr RPAR { info $sloc (PLold $3) }
+| AT LPAR lexpr COMMA label_name RPAR { info $sloc (PLat ($3, $5)) }
+| RESULT { info $sloc PLresult }
 | SEPARATED LPAR ne_lexpr_list RPAR
-      { info (PLseparated $3) }
-| identifier LPAR ne_lexpr_list RPAR
-      { info (PLapp ($1, [], $3)) }
-| identifier LBRACE ne_label_args RBRACE LPAR ne_lexpr_list RPAR
-      { info (PLapp ($1, $3, $6)) }
-| identifier LBRACE ne_label_args RBRACE
-      { info (PLapp ($1, $3, [])) }
-| identifier  { info (PLvar $1) }
-| PI  { info (PLvar "\\pi") }
-| lexpr_inner GTGT lexpr_inner { info (PLbinop ($1, Brshift, $3))}
-| lexpr_inner LTLT lexpr_inner { info (PLbinop ($1, Blshift, $3))}
-| LPAR lexpr RPAR { info $2.lexpr_node }
-| LPAR range RPAR { info $2.lexpr_node }
+      { info $sloc (PLseparated $3) }
+| full_identifier LPAR ne_lexpr_list RPAR
+      { info $sloc (PLapp ($1, [], $3)) }
+| full_identifier LBRACE ne_label_args RBRACE LPAR ne_lexpr_list RPAR
+      { info $sloc (PLapp ($1, $3, $6)) }
+| full_identifier LBRACE ne_label_args RBRACE
+      { info $sloc (PLapp ($1, $3, [])) }
+| full_identifier  { info $sloc (PLvar $1) }
+| PI  { info $sloc (PLvar "\\pi") }
+| lexpr_inner GTGT lexpr_inner { info $sloc (PLbinop ($1, Brshift, $3))}
+| lexpr_inner LTLT lexpr_inner { info $sloc (PLbinop ($1, Blshift, $3))}
+| LPAR lexpr RPAR { info $sloc $2.lexpr_node }
+| LPAR range RPAR { info $sloc $2.lexpr_node }
 | LPAR cast_logic_type RPAR lexpr_inner %prec prec_cast
-      { info (PLcast ($2, $4)) }
-| TYPEOF LPAR lexpr RPAR { info (PLtypeof $3) }
-| BSTYPE LPAR type_spec RPAR { info (PLtype $3) }
-| BSTYPE LPAR type_spec stars RPAR { info (PLtype ($4 $3)) }
+      { info $sloc (PLcast ($2, $4)) }
+| TYPEOF LPAR lexpr RPAR { info $sloc (PLtypeof $3) }
+| BSTYPE LPAR type_spec(typename) RPAR { info $sloc (PLtype $3) }
+| BSTYPE LPAR type_spec(typename) stars RPAR { info $sloc (PLtype ($4 $3)) }
     /* tsets */
-| EMPTY { info PLempty }
-| BSUNION LPAR lexpr_list RPAR { info (PLunion $3) }
-| INTER LPAR lexpr_list RPAR { info (PLinter $3) }
+| EMPTY { info $sloc PLempty }
+| BSUNION LPAR lexpr_list RPAR { info $sloc (PLunion $3) }
+| INTER LPAR lexpr_list RPAR { info $sloc (PLinter $3) }
 | LBRACE lexpr_list RBRACE
-      { info (PLset ($2)) }
+      { info $sloc (PLset ($2)) }
 | LBRACE lexpr PIPE binders RBRACE
-      {info (PLcomprehension ($2,$4,None)) }
+      { info $sloc (PLcomprehension ($2,$4,None)) }
 | LBRACE lexpr PIPE binders SEMICOLON lexpr RBRACE
-      { info (PLcomprehension ($2,$4,Some $6)) }
+      { info $sloc (PLcomprehension ($2,$4,Some $6)) }
     /* Aggregated object initialization */
 | LBRACE field_init RBRACE
-      { info (PLinitField($2)) }
+      { info $sloc (PLinitField($2)) }
 | LBRACE array_init RBRACE
-      { info (PLinitIndex($2)) }
+      { info $sloc (PLinitIndex($2)) }
 | LBRACE lexpr WITH update RBRACE
       { List.fold_left
-	  (fun a (path,upd_val) -> info (PLupdate(a,path,upd_val))) $2 $4 }
+	  (fun a (path,upd_val) -> info $sloc (PLupdate(a,path,upd_val))) $2 $4 }
 /*
-| LET bounded_var EQUAL lexpr SEMICOLON lexpr %prec LET {info (PLlet($2,$4,$6))}*/
+| LET bounded_var EQUAL lexpr SEMICOLON lexpr %prec LET { info $sloc (PLlet($2,$4,$6))}*/
 ;
 
 ne_label_args:
-| identifier_or_typename { [ $1 ] }
-| identifier_or_typename COMMA ne_label_args { $1 :: $3 }
+| identifier_or_typename_full { [ $1 ] }
+| identifier_or_typename_full COMMA ne_label_args { $1 :: $3 }
 
 string:
 | STRING_LITERAL { $1 }
@@ -609,13 +583,13 @@ string:
 ;
 
 range:
-| lexpr_option DOTDOT lexpr_option { info (PLrange($1,$3)) }
+| lexpr_option DOTDOT lexpr_option { info $sloc (PLrange($1,$3)) }
 ;
 
 /*** Aggregated object initialization ***/
 
 field_path_elt:
-| DOT identifier_or_typename { $2 }
+| DOT identifier_or_typename_full { $2 }
 ;
 field_init_elt:
 | field_path_elt EQUAL lexpr { ($1, $3) }
@@ -681,7 +655,7 @@ binders_reentrance:
 ;
 
 decl_spec:
-| type_spec var_spec { ($1, let (modif, name) = $2 in (modif $1, name))  }
+| type_spec(typename) var_spec { ($1, let (modif, name) = $2 in (modif $1, name))  }
 ;
 
 var_spec:
@@ -701,12 +675,12 @@ constant:
 
 array_size:
 | INT_CONSTANT { ASinteger $1 }
-| identifier { ASidentifier $1 }
+| full_identifier { ASidentifier $1 }
 | /* empty */ { ASnone }
 ;
 
 var_spec_bis:
-| identifier     { ((fun x -> x),(fun x -> x), $1) }
+| full_identifier     { ((fun x -> x),(fun x -> x), $1) }
 | var_spec_bis LSQUARE array_size RSQUARE
       { let (outer, inner, name) = $1 in
           (outer, (fun x -> inner (LTarray (x,$3))), name)
@@ -723,7 +697,7 @@ abs_param_type_list:
 | /* empty */    { [ ] }
 | abs_param_list { $1 }
 | abs_param_list COMMA DOTDOTDOT {
-  let source = fst(loc()) in
+  let source = pos $symbolstartpos in
   Kernel.not_yet_implemented ~source "variadic C function types"
   }
 ;
@@ -740,50 +714,50 @@ abs_param:
 | logic_type { $1 }
 ;
 
-/*** restricted type expressions ***/
-
-id_as_typename:
-| identifier { LTnamed($1, []) }
-;
-
 ne_parameters:
 | parameter { [$1] }
 | parameter COMMA ne_parameters { $1 :: $3 }
 ;
 
 parameter:
-| type_spec var_spec { let (modif, name) = $2 in (modif $1, name)}
-| id_as_typename var_spec { let (modif, name) = $2 in (modif $1, name) }
+| type_spec(identifier_or_typename) var_spec
+  { let (modif, name) = $2 in (modif $1, name)}
 ;
 
 
 /*** type expressions ***/
 
-logic_type:
-| type_spec abs_spec_option { $2 $1 }
+logic_type_gen(tname):
+| type_spec(tname) abs_spec_option { $2 $1 }
+;
+
+typename:
+| name = TYPENAME { name }
+/* TODO treat the case of an ACSL keyword that is also a typedef */
 ;
 
+logic_type: logic_type_gen(typename) { $1 }
+
 cv:
   CONST { cv_const }
 | VOLATILE { cv_volatile }
 | BSGHOST { cv_ghost }
 ;
 
-type_spec_cv:
-     type_spec cv_after { $2 $1 }
-|    cv type_spec_cv { LTattribute ($2, $1) }
+type_spec_cv(tname):
+     type_spec(tname) cv_after { $2 $1 }
+|    cv type_spec_cv(tname) { LTattribute ($2, $1) }
 
 cv_after:
   /* empty */ { fun t -> t }
 | cv cv_after { fun t -> $2 (LTattribute (t,$1)) }
 
 cast_logic_type:
- | type_spec_cv abs_spec_cv_option { $2 $1 }
+ | type_spec_cv(TYPENAME) abs_spec_cv_option { $2 $1 }
 ;
 
 logic_rt_type:
-| id_as_typename { $1 }
-| begin_rt_type logic_type end_rt_type { $2 }
+| logic_type_gen(identifier_or_typename) { $1 }
 ;
 
 abs_spec_option:
@@ -849,7 +823,7 @@ tabs:
     }
 ;
 
-type_spec:
+type_spec(tname):
 | INTEGER        { LTinteger }
 | REAL           { LTreal }
 | BOOLEAN        { LTnamed (Utf8_logic.boolean,[]) }
@@ -889,62 +863,62 @@ type_spec:
 | FLOAT             { LTfloat FFloat }
 | DOUBLE            { LTfloat FDouble }
 | LONG DOUBLE       { LTfloat FLongDouble }
-| STRUCT exit_rt_type identifier_or_typename { LTstruct $3 }
-| ENUM   exit_rt_type identifier_or_typename { LTenum $3 }
-| UNION  exit_rt_type identifier_or_typename  { LTunion $3 }
-| TYPENAME          { LTnamed ($1,[]) }
-| TYPENAME LT enter_rt_type  ne_logic_type_list GT exit_rt_type
-      { LTnamed($1,$4) }
+| STRUCT id = identifier_or_typename_full { LTstruct id }
+| ENUM id = identifier_or_typename_full { LTenum id }
+| UNION id = identifier_or_typename_full  { LTunion id }
+| name = tname          { LTnamed (name,[]) }
+| name = tname LT prms = ne_logic_type_list(tname) GT { LTnamed(name,prms) }
 ;
 
-ne_logic_type_list:
-| logic_type                          { [$1] }
-| logic_type COMMA enter_rt_type ne_logic_type_list { $1 :: $4 }
-;
-
-/*** from annotations ***/
-
-full_lexpr:
-| enter_kw_c_mode lexpr exit_kw_c_mode { $2 }
+ne_logic_type_list(tname):
+| l = separated_nonempty_list(COMMA,logic_type_gen(tname)) { l }
 ;
 
 full_identifier:
-| enter_kw_c_mode identifier exit_kw_c_mode { $2 }
-;
-
-full_identifier_or_typename:
-| enter_kw_c_mode identifier_or_typename exit_kw_c_mode { $2 }
-;
-
-full_parameters:
-| enter_kw_c_mode ne_parameters exit_kw_c_mode { $2 }
-;
-
-full_parameter:
-| enter_kw_c_mode parameter exit_kw_c_mode { $2 }
-;
-
-full_zones:
-| enter_kw_c_mode zones exit_kw_c_mode  { $2 }
-;
-
-full_ne_zones:
-| enter_kw_c_mode ne_zones exit_kw_c_mode { $2 }
-;
-
-full_ne_lexpr_list:
-enter_kw_c_mode ne_lexpr_list exit_kw_c_mode { $2 }
-;
-
-full_logic_type:
-| enter_kw_c_mode logic_type exit_kw_c_mode { $2 }
-;
-
-full_logic_rt_type:
-| enter_kw_c_mode logic_rt_type exit_kw_c_mode { $2 }
-
-full_assigns:
-| enter_kw_c_mode assigns exit_kw_c_mode { $2 }
+| id = identifier { id }
+| ADMIT { "admit" }
+| ALLOCATES { "allocates" }
+| ASSERT { "assert" }
+| ASSIGNS { "assigns" }
+| ASSUMES { "assumes" }
+| EXT_AT { "at" }
+| AXIOM { "axiom" }
+| AXIOMATIC { "axiomatic" }
+| BEHAVIOR { "behavior" }
+| BREAKS { "breaks" }
+| CHECK { "check" }
+| COMPLETE { "complete" }
+| CONTINUES { "continues" }
+| CONTRACT { "contract" }
+| DECREASES { "decreases" }
+| DISJOINT { "disjoint" }
+| ENSURES { "ensures" }
+| EXITS { "exits" }
+| FREES { "frees" }
+| FUNCTION { "function" }
+| GLOBAL { "global" }
+| IMPACT { "impact" }
+| INDUCTIVE { "inductive" }
+| INCLUDE { "include" }
+| INVARIANT { "invariant" }
+| LEMMA { "lemma" }
+| EXT_LET { "let" }
+| LOGIC { "logic" }
+| LOOP { "loop" }
+| MODEL { "model" }
+| MODULE { "module" }
+| PRAGMA { "pragma" }
+| PREDICATE { "predicate" }
+| REQUIRES { "requires" }
+| RETURNS { "returns" }
+| SLICE { "slice" }
+| TERMINATES { "terminates" }
+| TYPE { "type" }
+| VARIANT { "variant" }
+| id = EXT_CODE_ANNOT { id }
+| id = EXT_CONTRACT { id }
+| id = EXT_GLOBAL { id }
+| id = EXT_GLOBAL_BLOCK { id }
 ;
 
 /*** ACSL extension for external spec file ***/
@@ -964,10 +938,10 @@ ext_global_clauses:
 ;
 
 ext_global_clause:
-| decl  { Ext_decl (loc_decl $1) }
-| EXT_LET any_identifier EQUAL full_lexpr SEMICOLON { Ext_macro (false, $2, $4) }
-| GLOBAL EXT_LET any_identifier EQUAL full_lexpr SEMICOLON { Ext_macro (true, $3, $5) }
-| INCLUDE string SEMICOLON { let b,s = $2 in Ext_include(b,s, loc()) }
+| decl  { Ext_decl (loc_decl $sloc $1) }
+| EXT_LET any_identifier EQUAL lexpr SEMICOLON { Ext_macro (false, $2, $4) }
+| GLOBAL EXT_LET any_identifier EQUAL lexpr SEMICOLON { Ext_macro (true, $3, $5) }
+| INCLUDE string SEMICOLON { let b,s = $2 in Ext_include(b,s, loc $sloc) }
 ;
 
 ext_global_specs_opt:
@@ -1026,7 +1000,7 @@ ext_fun_specs:
 
 ext_fun_spec:
 | ext_at_stmt_markup ext_stmt_loop_spec
-    { Ext_stmt($1,$2,loc()) }
+    { Ext_stmt($1,$2,loc $sloc) }
 | ext_contract_markup contract
     { let s,pos = $2 in Ext_spec (s,pos) }
 ;
@@ -1050,7 +1024,7 @@ ext_module_markup:
 ;
 
 ext_function_markup:
-| FUNCTION ext_identifier COLON { $2, loc() }
+| FUNCTION ext_identifier COLON { $2, loc $sloc }
 ;
 
 ext_contract_markup:
@@ -1094,54 +1068,54 @@ contract:
         else if $2<>None || $3<>None ||
                 behaviors<>[] || completes<>[] ||disjoints<>[]
         then behaviors
-        else raise (Not_well_formed (loc(),"Empty annotation is not allowed"))
+        else raise (Not_well_formed (loc $sloc,"Empty annotation is not allowed"))
       in
         { spec_terminates = $2;
           spec_variant = $3;
           spec_behavior = behaviors;
           spec_complete_behaviors = completes;
           spec_disjoint_behaviors = disjoints;
-        }, loc()
+        }, loc $sloc
     }
-| requires ne_terminates REQUIRES { clause_order 3 "requires" "terminates" }
+| requires ne_terminates REQUIRES { clause_order $loc($3) "requires" "terminates" }
 | requires terminates ne_decreases REQUIRES
-      { clause_order 4 "requires" "decreases" }
+      { clause_order $loc($4) "requires" "decreases" }
 | requires terminates ne_decreases TERMINATES
-      { clause_order 4 "terminates" "decreases" }
+      { clause_order $loc($4) "terminates" "decreases" }
 | requires terminates decreases ne_simple_clauses REQUIRES
-      { clause_order 5 "requires" "post-condition, assigns or allocates" }
+      { clause_order $loc($5) "requires" "post-condition, assigns or allocates" }
 | requires terminates decreases ne_simple_clauses TERMINATES
-      { clause_order 5 "terminates" "post-condition, assigns or allocates" }
+      { clause_order $loc($5) "terminates" "post-condition, assigns or allocates" }
 | requires terminates decreases ne_simple_clauses DECREASES
-      { clause_order 5 "decreases" "post-condition, assigns or allocates" }
+      { clause_order $loc($5) "decreases" "post-condition, assigns or allocates" }
 | requires terminates decreases simple_clauses ne_behaviors TERMINATES
-      { clause_order 6 "terminates" "behavior" }
+      { clause_order $loc($6) "terminates" "behavior" }
 | requires terminates decreases simple_clauses ne_behaviors DECREASES
-      { clause_order 6 "decreases" "behavior" }
+      { clause_order $loc($6) "decreases" "behavior" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   REQUIRES
-      { clause_order 7 "requires" "complete or disjoint" }
+      { clause_order $loc($7) "requires" "complete or disjoint" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   TERMINATES
-      { clause_order 7 "terminates" "complete or disjoint" }
+      { clause_order $loc($7) "terminates" "complete or disjoint" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   DECREASES
-      { clause_order 7 "decreases" "complete or disjoint" }
+      { clause_order $loc($7) "decreases" "complete or disjoint" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   BEHAVIOR
-      { clause_order 7 "behavior" "complete or disjoint" }
+      { clause_order $loc($7) "behavior" "complete or disjoint" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   ASSIGNS
-      { clause_order 7 "assigns" "complete or disjoint" }
+      { clause_order $loc($7) "assigns" "complete or disjoint" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   ALLOCATES
-      { clause_order 7 "allocates" "complete or disjoint" }
+      { clause_order $loc($7) "allocates" "complete or disjoint" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   FREES
-      { clause_order 7 "frees" "complete or disjoint" }
+      { clause_order $loc($7) "frees" "complete or disjoint" }
 | requires terminates decreases simple_clauses behaviors ne_complete_or_disjoint
   post_cond_kind
-      { clause_order 7 "post-condition" "complete or disjoint" }
+      { clause_order $loc($7) "post-condition" "complete or disjoint" }
 ;
 
 // use that to detect potentially missing ';' at end of clause
@@ -1164,9 +1138,6 @@ clause_kw:
 | FREES {"frees"}
 | COMPLETE {"complete"}
 | DISJOINT {"disjoint"}
-/* often, we'll be in c_kw_mode, where these keywords are
-   recognized as identifiers... */
-| IDENTIFIER { $1 }
 | EXT_CONTRACT { $1 }
 | EOF { "end of annotation" }
 ;
@@ -1177,22 +1148,22 @@ requires:
 ;
 
 ne_requires:
-| REQUIRES full_lexpr SEMICOLON requires { toplevel_pred Assert $2::$4 }
-| CHECK_REQUIRES full_lexpr SEMICOLON requires { toplevel_pred Check $2 :: $4 }
-| ADMIT_REQUIRES full_lexpr SEMICOLON requires { toplevel_pred Admit $2 :: $4 }
-| REQUIRES full_lexpr clause_kw { missing 2 ";" $3 }
-| CHECK_REQUIRES full_lexpr clause_kw { missing 2 ";" $3 }
-| ADMIT_REQUIRES full_lexpr clause_kw { missing 2 ";" $3 }
+| REQUIRES lexpr SEMICOLON requires { toplevel_pred Assert $2::$4 }
+| CHECK_REQUIRES lexpr SEMICOLON requires { toplevel_pred Check $2 :: $4 }
+| ADMIT_REQUIRES lexpr SEMICOLON requires { toplevel_pred Admit $2 :: $4 }
+| REQUIRES lexpr clause_kw { missing $loc($2) ";" $3 }
+| CHECK_REQUIRES lexpr clause_kw { missing $loc($2) ";" $3 }
+| ADMIT_REQUIRES lexpr clause_kw { missing $loc($2) ";" $3 }
 ;
 
 terminates:
-| /* epsilon */              { None }
+| /* epsilon */ { None }
 | ne_terminates { Some $1 }
 ;
 
 ne_terminates:
-| TERMINATES full_lexpr SEMICOLON { $2 }
-| TERMINATES full_lexpr clause_kw { missing 2 ";" $3 }
+| TERMINATES lexpr SEMICOLON { $2 }
+| TERMINATES lexpr clause_kw { missing $loc($2) ";" $3 }
 ;
 
 decreases:
@@ -1202,12 +1173,12 @@ decreases:
 
 ne_decreases:
 | DECREASES variant SEMICOLON { $2 }
-| DECREASES variant clause_kw { missing 2 ";" $3 }
+| DECREASES variant clause_kw { missing $loc($2) ";" $3 }
 ;
 
 variant:
-| full_lexpr FOR any_identifier { ($1, Some $3) }
-| full_lexpr                    { ($1, None) }
+| lexpr FOR any_identifier { ($1, Some $3) }
+| lexpr                    { ($1, None) }
 ;
 
 simple_clauses:
@@ -1216,11 +1187,11 @@ simple_clauses:
 ;
 
 allocation:
-| ALLOCATES full_zones { FreeAlloc([],$2) }
-| FREES full_zones { FreeAlloc($2,[]) }
+| ALLOCATES zones { FreeAlloc([],$2) }
+| FREES zones { FreeAlloc($2,[]) }
 
 ne_simple_clauses:
-| post_cond_kind full_lexpr SEMICOLON simple_clauses
+| post_cond_kind lexpr SEMICOLON simple_clauses
     { let tp_kind, kind = $1 in
       let allocation,assigns,post_cond,extended = $4 in
       allocation,assigns,
@@ -1230,31 +1201,27 @@ ne_simple_clauses:
       let a = concat_allocation allocation $1 in
       a,assigns,post_cond,extended
     }
-| ASSIGNS full_assigns SEMICOLON simple_clauses
+| ASSIGNS assigns SEMICOLON simple_clauses
     { let allocation,assigns,post_cond,extended = $4 in
-      let a = concat_assigns assigns $2
+      let a = concat_assigns $sloc assigns $2
       in allocation,a,post_cond,extended
     }
-| EXT_CONTRACT grammar_extension SEMICOLON simple_clauses
+| EXT_CONTRACT extension_content SEMICOLON simple_clauses
     { let allocation,assigns,post_cond,extended = $4 in
       let processed = Logic_env.preprocess_extension $1 $2 in
       allocation,assigns,post_cond,($1,processed)::extended
     }
-| post_cond_kind full_lexpr clause_kw { missing 2 ";" $3 }
-| allocation clause_kw { missing 1 ";" $2 }
-| ASSIGNS full_assigns clause_kw { missing 2 ";" $3 }
-| EXT_CONTRACT ne_grammar_extension clause_kw { missing 1 ";" $3 }
+| post_cond_kind lexpr clause_kw { missing $loc($2) ";" $3 }
+| allocation clause_kw { missing $loc($1) ";" $2 }
+| ASSIGNS assigns clause_kw { missing $loc($2) ";" $3 }
+| EXT_CONTRACT ne_grammar_extension clause_kw { missing $loc($1) ";" $3 }
 ;
 
 ne_grammar_extension:
-| full_zones { $1 }
+| zones { $1 }
 ;
 
 /* possibly empty list of terms, for ACSL extensions registered by plugins. */
-grammar_extension:
-| enter_kw_c_mode extension_content exit_kw_c_mode { $2 }
-;
-
 extension_content:
 | /* epsilon */ { [] }
 | zones { $1 }
@@ -1278,21 +1245,22 @@ ne_behaviors:
             ~assumes ~requires ~post_cond ~assigns ~allocation ~extended ()
         in b::behaviors
       }
+;
 
 behavior_body:
 | assumes requires simple_clauses { $1,$2,$3 }
 | assumes ne_requires ASSUMES
-      { clause_order 3 "assumes" "requires" }
+      { clause_order $loc($3) "assumes" "requires" }
 | assumes requires ne_simple_clauses ASSUMES
-      { clause_order 4 "assumes" "assigns or post-condition" }
+      { clause_order $loc($4) "assumes" "assigns or post-condition" }
 | assumes requires ne_simple_clauses REQUIRES
-      { clause_order 4 "requires" "assigns or post-condition" }
+      { clause_order $loc($4) "requires" "assigns or post-condition" }
 ;
 
 assumes:
 | /* epsilon */ { [] }
-| ASSUMES full_lexpr SEMICOLON assumes { $2::$4 }
-| ASSUMES full_lexpr clause_kw { missing 2 ";" $3 }
+| ASSUMES lexpr SEMICOLON assumes { $2::$4 }
+| ASSUMES lexpr clause_kw { missing $loc($2) ";" $3 }
 ;
 
 complete_or_disjoint:
@@ -1309,8 +1277,8 @@ ne_complete_or_disjoint:
 /* complete behaviors decreases; is valid (provided there's a behavior
    named decreases)
 */
-| COMPLETE BEHAVIORS ne_behavior_name_list clause_kw { missing 3 ";" $4 }
-| DISJOINT BEHAVIORS ne_behavior_name_list clause_kw { missing 3 ";" $4 }
+| COMPLETE BEHAVIORS ne_behavior_name_list clause_kw { missing $loc($3) ";" $4 }
+| DISJOINT BEHAVIORS ne_behavior_name_list clause_kw { missing $loc($3) ";" $4 }
 ;
 
 /*** assigns and tsets ***/
@@ -1342,23 +1310,23 @@ annotation:
       { let (b,v,p) = $1 in
         (* TODO: do better, do not lose the structure ! *)
         let l = b@v@p in
-        Aloop_annot (loc (), l) }
+        Aloop_annot (loc $sloc, l) }
 | FOR ne_behavior_name_list COLON contract_or_code_annotation
       { $4 $2 }
-| pragma_or_code_annotation { Acode_annot (loc(),$1) }
+| pragma_or_code_annotation { Acode_annot (loc $sloc,$1) }
 | pragma_or_code_annotation beg_pragma_or_code_annotation
       { raise
-          (Not_well_formed (loc(),
+          (Not_well_formed (loc $sloc,
                             "Only one code annotation is allowed per comment"))
       }
-| full_identifier_or_typename { Aattribute_annot (loc (), $1) }
-| BSGHOST { Aattribute_annot(loc(),"\\ghost") }
+| identifier { Aattribute_annot (loc $sloc, $1) }
+| BSGHOST { Aattribute_annot(loc $sloc,"\\ghost") }
 ;
 
 contract_or_code_annotation:
 | contract
       { fun bhvs -> let s, pos = $1 in Acode_annot (pos, AStmtSpec (bhvs,s)) }
-| code_annotation { fun bhvs -> Acode_annot (loc(), ($1 bhvs)) }
+| code_annotation { fun bhvs -> Acode_annot (loc $sloc, ($1 bhvs)) }
 ;
 
 /*** loop annotations ***/
@@ -1388,7 +1356,7 @@ loop_annot_stack:
 | loop_invariant loop_annot_opt
     { let (i,fa,a,b,v,p,e) = $2 in ($1::i,fa,a,b,v,p,e) }
 | loop_effects loop_annot_opt
-    { let (i,fa,a,b,v,p,e) = $2 in (i,fa,concat_assigns a $1,b,v,p,e) }
+    { let (i,fa,a,b,v,p,e) = $2 in (i,fa,concat_assigns $sloc a $1,b,v,p,e) }
 | loop_allocation loop_annot_opt
     { let (i,fa,a,b,v,p,e) = $2 in (i,concat_allocation fa $1,a,b,v,p,e) }
 | FOR ne_behavior_name_list COLON loop_annot_stack
@@ -1396,7 +1364,7 @@ loop_annot_stack:
       let behav = $2 in
       let invs = List.map (fun i -> AInvariant(behav,true,i)) i in
       let ext = List.map (fun x -> AExtended(behav,true,x)) e in
-      let oth = concat_loop_assigns_allocation b behav a fa in
+      let oth = concat_loop_assigns_allocation $sloc b behav a fa in
       ([],FreeAllocAny,WritesAny,invs@ext@oth,v,p,[])
     }
 | loop_variant loop_annot_opt
@@ -1440,7 +1408,7 @@ loop_annot_opt:
 ;
 
 loop_effects:
-| LOOP ASSIGNS full_assigns SEMICOLON { $3 }
+| LOOP ASSIGNS assigns SEMICOLON { $3 }
 ;
 
 loop_allocation:
@@ -1448,18 +1416,18 @@ loop_allocation:
 ;
 
 loop_invariant:
-| LOOP INVARIANT full_lexpr SEMICOLON { toplevel_pred Assert $3 }
-| CHECK_LOOP INVARIANT full_lexpr SEMICOLON { toplevel_pred Check $3 }
-| ADMIT_LOOP INVARIANT full_lexpr SEMICOLON { toplevel_pred Admit $3 }
+| LOOP INVARIANT lexpr SEMICOLON { toplevel_pred Assert $3 }
+| CHECK_LOOP INVARIANT lexpr SEMICOLON { toplevel_pred Check $3 }
+| ADMIT_LOOP INVARIANT lexpr SEMICOLON { toplevel_pred Admit $3 }
 ;
 
 loop_variant:
-| LOOP VARIANT variant SEMICOLON { loc(),$3 }
+| LOOP VARIANT variant SEMICOLON { loc $sloc,$3 }
 ;
 
 /* Grammar Extensibility for plugins */
 loop_grammar_extension:
-| LOOP EXT_CODE_ANNOT grammar_extension SEMICOLON {
+| LOOP EXT_CODE_ANNOT extension_content SEMICOLON {
   let open Cil_types in
   let ext = $2 in
   try
@@ -1470,17 +1438,17 @@ loop_grammar_extension:
       | Ext_code_annot (Ext_here | Ext_next_stmt) ->
         raise
           (Not_well_formed
-            (lexeme_loc 2, ext ^ " is not a loop annotation extension"))
+            (loc $loc($2), ext ^ " is not a loop annotation extension"))
       | _ -> raise Not_found
     end
   with Not_found ->
-    Kernel.fatal ~source:(lexeme_start 2)
+    Kernel.fatal ~source:(pos $startpos($2))
       "%s is not a code annotation extension. Parser got wrong lexeme." ext
 }
 ;
 
 loop_pragma:
-| LOOP PRAGMA any_identifier full_ne_lexpr_list SEMICOLON
+| LOOP PRAGMA any_identifier ne_lexpr_list SEMICOLON
   { if $3 = "UNROLL_LOOP" || $3 = "UNROLL" then
       (if $3 <> "UNROLL" then
 	 Format.eprintf "Warning: use of deprecated keyword '%s'.\nShould use 'UNROLL' instead.@." $3;
@@ -1489,7 +1457,7 @@ loop_pragma:
       Widen_variables $4
     else if $3 = "WIDEN_HINTS" then
       Widen_hints $4
-    else raise (Not_well_formed (loc(),"Unknown loop pragma")) }
+    else raise (Not_well_formed (loc $sloc,"Unknown loop pragma")) }
 ;
 
 /*** code annotations ***/
@@ -1516,19 +1484,19 @@ pragma_or_code_annotation:
 ;
 
 code_annotation:
-| ASSERT full_lexpr SEMICOLON
+| ASSERT lexpr SEMICOLON
   { fun bhvs -> AAssert (bhvs,toplevel_pred Assert $2) }
-| CHECK full_lexpr SEMICOLON
+| CHECK lexpr SEMICOLON
   { fun bhvs -> AAssert (bhvs,toplevel_pred Check $2) }
-| ADMIT full_lexpr SEMICOLON
+| ADMIT lexpr SEMICOLON
   { fun bhvs -> AAssert (bhvs,toplevel_pred Admit $2) }
-| INVARIANT full_lexpr SEMICOLON
+| INVARIANT lexpr SEMICOLON
   { fun bhvs -> AInvariant (bhvs,false,toplevel_pred Assert $2) }
-| CHECK_INVARIANT full_lexpr SEMICOLON
+| CHECK_INVARIANT lexpr SEMICOLON
   { fun bhvs -> AInvariant (bhvs,false,toplevel_pred Check $2) }
-| ADMIT_INVARIANT full_lexpr SEMICOLON
+| ADMIT_INVARIANT lexpr SEMICOLON
   { fun bhvs -> AInvariant (bhvs,false,toplevel_pred Admit $2) }
-| EXT_CODE_ANNOT grammar_extension SEMICOLON
+| EXT_CODE_ANNOT extension_content SEMICOLON
   { fun bhvs ->
     let open Cil_types in
     let ext = $1 in
@@ -1540,46 +1508,47 @@ code_annotation:
         | Ext_code_annot Ext_next_loop ->
           raise
             (Not_well_formed
-               (lexeme_loc 1,
+               (loc $loc($1),
                  ext ^ " is not a loop annotation extension. It can't be used \
                          as plain code annotation extension"))
         | _ -> raise Not_found
       end
     with Not_found ->
-      Kernel.fatal ~source:(lexeme_start 1)
+      Kernel.fatal ~source:(pos $startpos($1))
         "%s is not a code annotation extension. Parser got wrong lexeme" ext
   }
 ;
 
 slice_pragma:
-| SLICE PRAGMA any_identifier full_lexpr SEMICOLON
+| SLICE PRAGMA any_identifier lexpr SEMICOLON
     { if $3 = "expr" then SPexpr $4
-      else raise (Not_well_formed (loc(), "Unknown slice pragma")) }
+      else raise (Not_well_formed (loc $sloc, "Unknown slice pragma")) }
 | SLICE PRAGMA any_identifier SEMICOLON
     { if $3 = "ctrl" then SPctrl
       else if $3 = "stmt" then SPstmt
-      else raise (Not_well_formed (loc(), "Unknown slice pragma")) }
+      else raise (Not_well_formed (loc $sloc, "Unknown slice pragma")) }
 ;
 
 impact_pragma:
-| IMPACT PRAGMA any_identifier full_lexpr SEMICOLON
+| IMPACT PRAGMA any_identifier lexpr SEMICOLON
     { if $3 = "expr" then IPexpr $4
-      else raise (Not_well_formed (loc(), "Unknown impact pragma")) }
+      else raise (Not_well_formed (loc $sloc, "Unknown impact pragma")) }
 | IMPACT PRAGMA any_identifier SEMICOLON
     { if $3 = "stmt" then IPstmt
-      else raise (Not_well_formed (loc(), "Unknown impact pragma")) }
+      else raise (Not_well_formed (loc $sloc, "Unknown impact pragma")) }
 ;
 
 /*** declarations and logical definitions ***/
 
 decl_list:
-| decl            { [loc_decl $1] }
-| decl decl_list  { (loc_decl $1) :: $2 }
+| decl            { [loc_decl $sloc $1] }
+| decl decl_list  { (loc_decl $loc($1) $1) :: $2 }
+;
 
 decl:
-| GLOBAL INVARIANT any_identifier COLON full_lexpr SEMICOLON
+| GLOBAL INVARIANT any_identifier COLON lexpr SEMICOLON
     { LDinvariant ($3, $5) }
-| VOLATILE full_ne_zones volatile_opt SEMICOLON { LDvolatile ($2, $3) }
+| VOLATILE ne_zones volatile_opt SEMICOLON { LDvolatile ($2, $3) }
 | type_annot {LDtype_annot $1}
 | model_annot {LDmodel_annot $1}
 | logic_def  { $1 }
@@ -1588,7 +1557,7 @@ decl:
 ;
 
 ext_decl:
-| EXT_GLOBAL grammar_extension SEMICOLON {
+| EXT_GLOBAL extension_content SEMICOLON {
      let processed = Logic_env.preprocess_extension $1 $2 in
      Ext_lexpr($1, processed)
    }
@@ -1608,7 +1577,7 @@ ext_decls:
 ;
 
 ext_decl_loc:
-| ext_decl { loc_ext $1 }
+| ext_decl { loc_ext $sloc $1 }
 ;
 
 volatile_opt:
@@ -1630,17 +1599,18 @@ volatile_opt:
 ;
 
 type_annot:
-| TYPE INVARIANT any_identifier LPAR full_parameter RPAR EQUAL
-    full_lexpr SEMICOLON
+| TYPE INVARIANT any_identifier LPAR parameter RPAR EQUAL
+    lexpr SEMICOLON
   { let typ,name = $5 in{ inv_name = $3; this_name = name; this_type = typ; inv = $8; } }
 ;
 
 opt_semicolon:
 | /* epsilon */ { }
 | SEMICOLON { }
+;
 
 model_annot:
-| MODEL type_spec LBRACE full_parameter opt_semicolon RBRACE SEMICOLON
+| MODEL type_spec(typename) LBRACE parameter opt_semicolon RBRACE SEMICOLON
   { let typ,name = $4 in
     { model_for_type = $2; model_name = name; model_type = typ; }
   }
@@ -1674,17 +1644,17 @@ opt_parameters:
 ;
 
 parameters:
-| LPAR full_parameters RPAR { $2 }
+| LPAR ne_parameters RPAR { $2 }
 ;
 
 logic_def:
 /* logic function definition */
-| LOGIC full_logic_rt_type poly_id opt_parameters EQUAL full_lexpr SEMICOLON
+| LOGIC logic_rt_type poly_id opt_parameters EQUAL lexpr SEMICOLON
     { let (id, labels, tvars) = $3 in
       exit_type_variables_scope ();
       LDlogic_def (id, labels, tvars, $2, $4, $6) }
 /* predicate definition */
-| PREDICATE poly_id opt_parameters EQUAL full_lexpr SEMICOLON
+| PREDICATE poly_id opt_parameters EQUAL lexpr SEMICOLON
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
       LDpredicate_def (id, labels, tvars, $3, $5) }
@@ -1693,15 +1663,15 @@ logic_def:
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
       LDinductive_def(id, labels, tvars, $3, $5) }
-| LEMMA poly_id COLON full_lexpr SEMICOLON
+| LEMMA poly_id COLON lexpr SEMICOLON
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
       LDlemma (id, labels, tvars, toplevel_pred Assert $4) }
-| CHECK_LEMMA poly_id COLON full_lexpr SEMICOLON
+| CHECK_LEMMA poly_id COLON lexpr SEMICOLON
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
       LDlemma (id, labels, tvars, toplevel_pred Check $4) }
-| ADMIT_LEMMA poly_id COLON full_lexpr SEMICOLON
+| ADMIT_LEMMA poly_id COLON lexpr SEMICOLON
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
       LDlemma (id, labels, tvars, toplevel_pred Admit $4) }
@@ -1716,9 +1686,9 @@ logic_def:
 
 deprecated_logic_decl:
 /* OBSOLETE: logic function declaration */
-| LOGIC full_logic_rt_type poly_id opt_parameters SEMICOLON
+| LOGIC logic_rt_type poly_id opt_parameters SEMICOLON
     { let (id, labels, tvars) = $3 in
-      let source = fst (loc ()) in
+      let source = pos $symbolstartpos in
       exit_type_variables_scope ();
       obsolete  "logic declaration" ~source ~now:"an axiomatic block";
       LDlogic_reads (id, labels, tvars, $2, $4, None) }
@@ -1726,7 +1696,7 @@ deprecated_logic_decl:
 | PREDICATE poly_id opt_parameters SEMICOLON
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
-      let source = fst (loc ()) in
+      let source = pos $symbolstartpos in
       obsolete "logic declaration" ~source ~now:"an axiomatic block";
       LDpredicate_reads (id, labels, tvars, $3, None) }
 /* OBSOLETE: type declaration */
@@ -1734,16 +1704,16 @@ deprecated_logic_decl:
     { let (id,tvars) = $2 in
       Logic_env.add_typename id;
       exit_type_variables_scope ();
-      let source = fst (loc ()) in
+      let source = pos $symbolstartpos in
       obsolete "logic type declaration" ~source ~now:"an axiomatic block";
       LDtype(id,tvars,None)
     }
 /* OBSOLETE: axiom */
-| AXIOM poly_id COLON full_lexpr SEMICOLON
+| AXIOM poly_id COLON lexpr SEMICOLON
     { let (id,_,_) = $2 in
       raise
 	(Not_well_formed
-	   (loc(),"Axiom " ^ id ^ " is declared outside of an axiomatic."))
+	   (loc $sloc,"Axiom " ^ id ^ " is declared outside of an axiomatic."))
     }
 ;
 
@@ -1758,7 +1728,7 @@ logic_decls:
 logic_decl:
 | logic_def  { $1 }
 /* logic function declaration */
-| LOGIC full_logic_rt_type poly_id opt_parameters reads_clause SEMICOLON
+| LOGIC logic_rt_type poly_id opt_parameters reads_clause SEMICOLON
     { let (id, labels, tvars) = $3 in
       exit_type_variables_scope ();
       LDlogic_reads (id, labels, tvars, $2, $4, $5) }
@@ -1774,25 +1744,25 @@ logic_decl:
       exit_type_variables_scope ();
       LDtype(id,tvars,None) }
 /* axiom */
-| AXIOM poly_id COLON full_lexpr SEMICOLON
+| AXIOM poly_id COLON lexpr SEMICOLON
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
       LDlemma (id, labels, tvars, toplevel_pred Admit $4) }
 ;
 
 logic_decl_loc:
-| logic_decl { loc_decl $1 }
+| logic_decl { loc_decl $sloc $1 }
 ;
 
 
 reads_clause:
 | /* epsilon */ { None }
-| READS full_zones { Some $2 }
+| READS zones { Some $2 }
 ;
 
 typedef:
 | ne_datacons_list { TDsum $1 }
-| full_logic_type { TDsyn $1 }
+| logic_type { TDsyn $1 }
 ;
 
 datacons_list:
@@ -1811,13 +1781,13 @@ datacons:
 ;
 
 ne_type_list:
-| full_logic_type { [$1] }
-| full_logic_type COMMA ne_type_list { $1::$3 }
+| logic_type { [$1] }
+| logic_type COMMA ne_type_list { $1::$3 }
 
 indcases:
 | /* epsilon */
     { [] }
-| CASE poly_id COLON full_lexpr SEMICOLON indcases
+| CASE poly_id COLON lexpr SEMICOLON indcases
     { let (id,labels,tvars) = $2 in
       exit_type_variables_scope ();
       (id,labels,tvars,$4)::$6 }
@@ -1838,15 +1808,15 @@ opt_label_1:
 | opt_label_list { match $1 with
 		     | [] -> None
 		     | l::[] -> Some l
-		     | _ -> raise (Not_well_formed (loc(),"Only one label is allowed")) }
+		     | _ -> raise (Not_well_formed (loc $sloc,"Only one label is allowed")) }
 ;
 
 opt_label_2:
 | opt_label_list { match $1 with
 		     | [] -> None
 		     | l1::l2::[] -> Some (l1,l2)
-		     | _::[] -> raise (Not_well_formed (loc(),"One label is missing"))
-		     | _ -> raise (Not_well_formed (loc(),"Only two labels are allowed")) }
+		     | _::[] -> raise (Not_well_formed (loc $sloc,"One label is missing"))
+		     | _ -> raise (Not_well_formed (loc $sloc,"Only two labels are allowed")) }
 ;
 
 opt_label_list:
@@ -1874,19 +1844,20 @@ behavior_name:
 ;
 
 any_identifier:
-| identifier_or_typename { $1 }
+| identifier { $1 }
+| is_acsl_typename { $1 }
+| TYPENAME { $1 }
 | keyword { $1 }
 ;
 
-identifier_or_typename: /* allowed as C field names */
+identifier_or_typename:
+| TYPENAME { $1 }
+| full_identifier { $1 }
+
+
+identifier_or_typename_full: /* allowed as C field names */
 | is_acsl_typename  { $1 }
-| TYPENAME { $1 } /* followed by the same list than 'identifier' */
-| IDENTIFIER { $1 }
-/* token list used inside acsl clauses: */
-| BEHAVIORS  { "behaviors" }
-| LABEL      { "label" }
-| READS      { "reads" }
-| WRITES     { "writes" }
+| identifier_or_typename { $1 }
 ;
 
 identifier: /* part included into 'identifier_or_typename', but duplicated to avoid parsing conflicts */
@@ -1899,15 +1870,15 @@ identifier: /* part included into 'identifier_or_typename', but duplicated to av
 ;
 
 bounded_var:
-| identifier { $1 }
+| full_identifier { $1 }
 | is_acsl_typename /* Since TYPENAME cannot be accepted by lexpr rule */
     { raise
-	(Not_well_formed(loc (),
+	(Not_well_formed(loc $sloc,
 			 "Type names are not allowed as binding variable"))
     }
 | TYPENAME  /* Since TYPENAME cannot be accepted by lexpr rule */
     { raise
-	(Not_well_formed(loc (),
+	(Not_well_formed(loc $sloc,
 			 "Type names are not allowed as binding variable"))
     }
 ;
diff --git a/src/kernel_internals/parsing/tests/check_logic_parser.ml b/src/kernel_internals/parsing/tests/check_logic_parser.ml
index 7f6c9593da02981a51c698e0eaba009421b288d1..8435c5578611286dc8a5dd42015f84e1913f0fd7 100644
--- a/src/kernel_internals/parsing/tests/check_logic_parser.ml
+++ b/src/kernel_internals/parsing/tests/check_logic_parser.ml
@@ -73,12 +73,21 @@ let add_tokens s =
   in add_token s
 
 let wildcard_rules =
-  [ "bs_keyword"; "wildcard"; "keyword"; "c_keyword";
-    "non_logic_keyword"; "acsl_c_keyword"; "is_ext_spec";
+  [ "acsl_c_keyword";
+    "any_identifier";
+    "bs_keyword";
+    "c_keyword";
+    "identifier";
+    "identifier_or_typename";
+    "is_acsl_decl_or_code_annot";
+    "is_acsl_other";
+    "is_acsl_spec";
     "is_acsl_typename";
-    "is_acsl_spec"; "is_acsl_decl_or_code_annot";
-    "is_acsl_other"; "post_cond";
-    "identifier_or_typename"
+    "is_ext_spec";
+    "keyword";
+    "non_logic_keyword";
+    "post_cond";
+    "wildcard";
   ]
 
 let find_rule_name s =
diff --git a/src/kernel_internals/parsing/tests/dune b/src/kernel_internals/parsing/tests/dune
index ba23e4861fb5a8289dc4e7fc5a1ae2af05299163..d77efd63c875dc4d3dd43be7f7f4ed3cb0997954 100644
--- a/src/kernel_internals/parsing/tests/dune
+++ b/src/kernel_internals/parsing/tests/dune
@@ -28,11 +28,11 @@
 )
 
 (rule
- (alias run-coding-tests)
+ (alias run-kernel-tests)
  (deps ../logic_parser.mly)
  (action  (run %{dep:./check_logic_parser.exe})))
 
 (alias
-  (deps (alias run-coding-tests) )
+  (deps (alias run-kernel-tests) )
   (name ptests)
 )
diff --git a/src/kernel_services/ast_queries/logic_utils.ml b/src/kernel_services/ast_queries/logic_utils.ml
index 06ea9e8192ac0a83de4cf26b18d79c885963b8ea..0af75114af3d582931d53b4b77dd12730b333c34 100644
--- a/src/kernel_services/ast_queries/logic_utils.ml
+++ b/src/kernel_services/ast_queries/logic_utils.ml
@@ -2362,38 +2362,6 @@ class complete_types =
 
 let complete_types f = Cil.visitCilFile (new complete_types) f
 
-(* ************************************************************************* *)
-(** {2 Parsing utilities} *)
-(* ************************************************************************* *)
-
-(** Hack to allow typedefs whose names are ACSL keywords: the state of the
-    lexer depends on the parser rule. See logic_lexer.mll and
-    logic_parser.mly for more details. *)
-
-(**
-   - false => keywords are all ACSL keywords
-   - true => only C keywords are recognized as such.
-     (other remains plain identifiers/typenames)
-*)
-let kw_c_mode = ref false
-
-let enter_kw_c_mode () = kw_c_mode := true
-
-let exit_kw_c_mode () = kw_c_mode := false
-
-let is_kw_c_mode () = !kw_c_mode
-
-let rt_type_mode = ref false
-
-(** enter a mode where any identifier is considered a type name. Needed for
-    for return type of a logic function, as the list of admissible variables
-    will be known afterwards. *)
-let enter_rt_type_mode () = rt_type_mode:=true
-
-let exit_rt_type_mode () = rt_type_mode:=false
-
-let is_rt_type_mode () = !rt_type_mode
-
 let pointer_comparable ?loc t1 t2 =
   let preds = Logic_env.find_all_logic_functions "\\pointer_comparable" in
   let cfct_ptr = TPtr (TFun(Cil.voidType,None,false,[]),[]) in
diff --git a/src/kernel_services/ast_queries/logic_utils.mli b/src/kernel_services/ast_queries/logic_utils.mli
index c1df4b07514bb6cb767675155981b9a7fc376c74..1e94484c56da83f416155892b65fd691c73a0069 100644
--- a/src/kernel_services/ast_queries/logic_utils.mli
+++ b/src/kernel_services/ast_queries/logic_utils.mli
@@ -491,20 +491,6 @@ class simplify_const_lval: (varinfo -> init option) -> Cil.cilVisitor
     @since Neon-20140301 *)
 val complete_types: file -> unit
 
-(** {2 Parsing hackery} *)
-(** Values that control the various modes of the parser and lexer for logic.
-    Use with care.
-*)
-
-val kw_c_mode : bool ref
-val enter_kw_c_mode : unit -> unit
-val exit_kw_c_mode : unit -> unit
-val is_kw_c_mode : unit -> bool
-val rt_type_mode : bool ref
-val enter_rt_type_mode : unit -> unit
-val exit_rt_type_mode : unit -> unit
-val is_rt_type_mode : unit -> bool
-
 (*
 Local Variables:
 compile-command: "make -C ../../.."
diff --git a/tests/spec/oracle/polymorph.res.oracle b/tests/spec/oracle/polymorph.res.oracle
index 0884261f3ea740425f4218ac742bc5fbef20b9df..983912ed0325cf0fb458343ef9e56fbf11e8df06 100644
--- a/tests/spec/oracle/polymorph.res.oracle
+++ b/tests/spec/oracle/polymorph.res.oracle
@@ -1,7 +1,8 @@
 [kernel] Parsing polymorph.c (with preprocessing)
 [kernel] polymorph.c:1: Warning: 
   parsing obsolete ACSL construct 'logic type declaration'. 'an axiomatic block' should be used instead.
-[kernel:annot-error] polymorph.c:4: Warning: unexpected token 'a'
+[kernel] polymorph.c:4: Warning: 
+  parsing obsolete ACSL construct 'logic declaration'. 'an axiomatic block' should be used instead.
 [kernel] polymorph.c:6: Warning: 
   parsing obsolete ACSL construct 'logic declaration'. 'an axiomatic block' should be used instead.
 [kernel] polymorph.c:8: Warning: 
@@ -10,6 +11,8 @@
   parsing obsolete ACSL construct 'logic declaration'. 'an axiomatic block' should be used instead.
 [kernel] polymorph.c:13: Warning: 
   parsing obsolete ACSL construct 'logic declaration'. 'an axiomatic block' should be used instead.
+[kernel:annot-error] polymorph.c:4: Warning: 
+  no such type a. Ignoring global annotation
 [kernel:annot-error] polymorph.c:13: Warning: 
   some type variable appears only in the return type. All type variables need to occur also in the parameters types.. Ignoring global annotation
 [kernel:annot-error] polymorph.c:22: Warning: