Commit | Line | Data |
---|---|---|
34e49164 C |
1 | (* Copyright (C) 2002-2008 Yoann Padioleau |
2 | * | |
3 | * This program is free software; you can redistribute it and/or | |
4 | * modify it under the terms of the GNU General Public License (GPL) | |
5 | * version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * file license.txt for more details. | |
11 | *) | |
12 | open Common | |
13 | ||
14 | (* Tricks used to handle the ambiguity in the grammar with the typedef | |
15 | * which impose a cooperation between the lexer and the parser. | |
16 | * | |
17 | * An example by hughes casse: "in the symbol table, local | |
18 | * definition must replace type definition in order to correctly parse | |
19 | * local variable in functions body. This is the only way to correctly | |
20 | * handle this kind of exception, that is, | |
21 | * | |
22 | * typedef ... ID; int f(int *p) {int ID; return (ID) * *p;} If ID | |
23 | * isn't overload, last expression is parsed as a type cast, if it | |
24 | * isn't, this a multiplication." | |
25 | * | |
26 | * Why parse_typedef_fix2 ? Cos when introduce new variable, for | |
27 | * instance when declare parameters for a function such as int var_t, | |
28 | * then the var_t must not be lexed as a typedef, so we must disable | |
29 | * temporaly the typedef mechanism to allow variable with same name as | |
30 | * a typedef. *) | |
31 | ||
32 | (* parse_typedef_fix *) | |
33 | let _handle_typedef = ref true | |
34 | ||
35 | (* parse_typedef_fix2 *) | |
36 | let enable_typedef () = _handle_typedef := true | |
37 | let disable_typedef () = _handle_typedef := false | |
38 | ||
39 | let is_enabled_typedef () = !_handle_typedef | |
40 | ||
41 | ||
42 | ||
43 | ||
44 | type identkind = TypeDefI | IdentI | |
45 | ||
46 | (* Ca marche ce code ? on peut avoir un typedef puis un ident puis | |
47 | * un typedef nested ? oui car Hashtbl (dans scoped_h_env) gere l'historique. | |
48 | * | |
49 | * oldsimple: but slow, take 2 secondes on some C files | |
50 | * let (typedef: typedef list list ref) = ref [[]] | |
51 | *) | |
52 | let (_typedef : (string, identkind) Common.scoped_h_env ref) = | |
53 | ref (Common.empty_scoped_h_env ()) | |
54 | ||
55 | let is_typedef s = if !_handle_typedef then | |
56 | (match (Common.optionise (fun () -> Common.lookup_h_env s !_typedef)) with | |
57 | | Some TypeDefI -> true | |
58 | | Some IdentI -> false | |
59 | | None -> false | |
60 | ) | |
61 | else false | |
62 | ||
63 | let new_scope() = Common.new_scope_h _typedef | |
64 | let del_scope() = Common.del_scope_h _typedef | |
65 | ||
66 | let add_typedef s = Common.add_in_scope_h _typedef (s, TypeDefI) | |
67 | let add_ident s = Common.add_in_scope_h _typedef (s, IdentI) | |
68 | ||
69 | let add_typedef_root s = | |
70 | if !Flag_parsing_c.add_typedef_root | |
71 | then | |
72 | Hashtbl.add !_typedef.scoped_h s TypeDefI | |
73 | else add_typedef s (* have far more .failed without this *) | |
74 | ||
75 | ||
76 | (* Used by parse_c when do some error recovery. The parse error may | |
77 | * have some bad side effects on typedef hash, so recover this. | |
78 | *) | |
79 | let _old_state = ref (Common.clone_scoped_h_env !_typedef) | |
80 | ||
81 | let save_typedef_state () = | |
82 | _old_state := Common.clone_scoped_h_env !_typedef | |
83 | ||
84 | let restore_typedef_state () = | |
85 | _typedef := !_old_state | |
86 | ||
87 | ||
88 | ||
89 | ||
485bce71 C |
90 | type context = |
91 | | InTopLevel | |
92 | | InFunction | |
93 | | InStruct | |
94 | | InParameter | |
95 | | InInitializer | |
96 | | InEnum | |
91eba41f C |
97 | (* InExpr ? but then orthogonal to InFunction. Could assign InExpr for |
98 | * instance after a '=' as in 'a = (irq_t) b;' | |
99 | *) | |
485bce71 C |
100 | |
101 | let is_top_or_struct = function | |
102 | | InTopLevel | |
103 | | InStruct | |
104 | -> true | |
105 | | _ -> false | |
106 | ||
34e49164 | 107 | type lexer_hint = { |
485bce71 C |
108 | mutable context_stack: context Common.stack; |
109 | } | |
34e49164 C |
110 | |
111 | let default_hint () = { | |
485bce71 | 112 | context_stack = [InTopLevel]; |
34e49164 C |
113 | } |
114 | ||
115 | let _lexer_hint = ref (default_hint()) | |
116 | ||
485bce71 C |
117 | let current_context () = List.hd !_lexer_hint.context_stack |
118 | let push_context ctx = | |
119 | !_lexer_hint.context_stack <- ctx::!_lexer_hint.context_stack | |
120 | let pop_context () = | |
121 | !_lexer_hint.context_stack <- List.tl !_lexer_hint.context_stack | |
122 | ||
123 | ||
34e49164 C |
124 | |
125 | let lexer_reset_typedef () = | |
126 | begin | |
127 | _handle_typedef := true; | |
128 | _typedef := Common.empty_scoped_h_env (); | |
485bce71 | 129 | _lexer_hint := (default_hint ()); |
34e49164 C |
130 | end |
131 |