File: lexer_parser.ml

package info (click to toggle)
coccinelle 1.0.8.deb-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 26,148 kB
  • sloc: ml: 136,392; ansic: 23,594; sh: 2,189; makefile: 2,157; perl: 1,576; lisp: 840; python: 823; awk: 70; csh: 12
file content (151 lines) | stat: -rw-r--r-- 4,377 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
(* Yoann Padioleau
 *
 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
 * Copyright (C) 2002, 2006 Yoann Padioleau
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License (GPL)
 * version 2 as published by the Free Software Foundation.
 *
 * This program 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
 * file license.txt for more details.
 *)
open Common

(* Tricks used to handle the ambiguity in the grammar with the typedef
 * which impose a cooperation between the lexer and the parser.
 *
 * An example by Hug_es Cassé: "in the symbol table, local
 * definition must replace type definition in order to correctly parse
 * local variable in functions body. This is the only way to correctly
 * handle this kind of exception, that is,
 *
 * typedef ... ID; int f(int *p) {int ID; return (ID) * *p;} If ID
 * isn't overload, last expression is parsed as a type cast, if it
 * isn't, this a multiplication."
 *
 * Why parse_typedef_fix2 ? Cos when introduce new variable, for
 * instance when declare parameters for a function such as int var_t,
 * then the var_t must not be lexed as a typedef, so we must disable
 * temporary the typedef mechanism to allow variable with same name as
 * a typedef. *)

(* parse_typedef_fix *)
let _handle_typedef = ref true

let _always_look_typedef = ref false

(* parse_typedef_fix2 *)
let enable_typedef ()  = _handle_typedef := true
let disable_typedef () = _handle_typedef := false

let is_enabled_typedef () = !_handle_typedef

let _kr_possible = ref true
let is_kr_possible _ = !_kr_possible
let kr_impossible _ =
  if not !Flag_parsing_c.force_kr then _kr_possible := false



type identkind = TypeDefI | IdentI

(* Ca marche ce code ? on peut avoir un typedef puis un ident puis
 * un typedef nested ? oui car Hashtbl (dans scoped_h_env) gere l'historique.
 *
 * oldsimple:  but slow,  take 2 secondes on some C files
 *    let (typedef: typedef list list ref) = ref [[]]
 *)
let (_typedef : (string, identkind) Common.scoped_h_env ref) =
  ref (Common.empty_scoped_h_env ())

let is_typedef s  =
  if !_handle_typedef || !_always_look_typedef then
  (match (Common.optionise (fun () -> Common.lookup_h_env s !_typedef)) with
  | Some TypeDefI -> true
  | Some IdentI -> false
  | None -> false
  )
  else false

let new_scope() = Common.new_scope_h _typedef
let del_scope() = Common.del_scope_h _typedef

let add_typedef  s =
  Common.add_in_scope_h _typedef (s, TypeDefI)
let add_ident s    = Common.add_in_scope_h _typedef (s, IdentI)

let add_typedef_root s i =
  let expanded i =
    match i.Ast_c.pinfo with
      Ast_c.ExpandedTok _ -> true
    | _ -> false in
  if not(expanded i)
  then
    begin
      if !Flag_parsing_c.add_typedef_root
      then
	Hashtbl.add !_typedef.scoped_h s TypeDefI
      else add_typedef s (* have far more .failed without this *)
    end

(* Used by parse_c when do some error recovery. The parse error may
 * have some bad side effects on typedef hash, so recover this.
 *)
let _old_state = ref (Common.clone_scoped_h_env !_typedef)

let save_typedef_state () =
  _old_state := Common.clone_scoped_h_env !_typedef

let restore_typedef_state () =
  _typedef := !_old_state




type context =
  | InTopLevel
  | InFunction
  | InStruct
  | InParameter
  | InInitializer
  | InEnum
(* InExpr ? but then orthogonal to InFunction. Could assign InExpr for
 * instance after a '=' as in 'a = (irq_t) b;'
 *)

let is_top_or_struct = function
  | InTopLevel
  | InStruct
      -> true
  | _ -> false

type lexer_hint = {
  mutable context_stack: context Common.stack;
 }

let default_hint () = {
  context_stack = [InTopLevel];
}

let _lexer_hint = ref (default_hint())

let current_context () = List.hd !_lexer_hint.context_stack
let push_context ctx =
  !_lexer_hint.context_stack <- ctx::!_lexer_hint.context_stack
let pop_context () =
  !_lexer_hint.context_stack <- List.tl !_lexer_hint.context_stack



let lexer_reset_typedef saved_typedefs =
  begin
    _handle_typedef := true;
    _kr_possible := true;
    (match saved_typedefs with
      None -> _typedef := Common.empty_scoped_h_env ()
    | Some t -> _typedef := t);
    _lexer_hint := (default_hint ());
  end