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