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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
(** Main entry point of the stub parser *)
open Mopsa_utils
open Mopsa_c_parser
open Clang_AST
open C_AST
open Location
let debug fmt = Debug.debug ~channel:"c_stubs_parser.main" fmt
let starts_with text prefix =
(String.length text >= String.length prefix) &&
(String.sub text 0 (String.length prefix) = prefix)
let (com,_) =
let = com.Clang_AST.com_text |>
String.trim
in
starts_with comment "/*$"
let (com,_) =
let = com.Clang_AST.com_text |>
String.trim
in
starts_with comment "/*$="
let (com,_) =
let = com.Clang_AST.com_text |>
String.trim
in
starts_with comment "/*$!"
exception StubNotFound
let rec parse_cst func ?(selector=is_stub_comment) prj enums predicates cache =
match Hashtbl.find_opt cache func.func_org_name with
| Some cst -> cst
| None ->
match List.find_opt selector func.func_com with
| None -> raise StubNotFound
| Some (com,macros) ->
let = com.com_text in
let file = com.com_range.range_begin.loc_file in
let line = com.com_range.range_begin.loc_line in
let col = com.com_range.range_begin.loc_column in
let buf = Lexing.from_string comment in
buf.lex_curr_p <- {
pos_fname = file;
pos_lnum = line;
pos_bol = 0;
pos_cnum = col;
};
try
let cst = Parser.parse_stub (Passes.Preprocessor.read predicates macros enums Lexer.read) buf in
let cst' = Passes.Scoping.doit cst in
Hashtbl.add cache func.func_org_name cst';
cst'
with
| Passes.Preprocessor.AliasFound alias ->
begin match StringMap.find_opt alias prj.proj_funcs with
| None -> raise StubNotFound
| Some f ->
parse_cst f prj enums predicates cache
end
| Lexer.SyntaxError s ->
let range = Location.from_lexing_range (Lexing.lexeme_start_p buf) (Lexing.lexeme_end_p buf) in
Exceptions.syntax_error range "%s" s
| Parser.Error ->
let range = Location.from_lexing_range (Lexing.lexeme_start_p buf) (Lexing.lexeme_end_p buf) in
Exceptions.unnamed_syntax_error range
(** Parse the stub specification from comments of a function *)
let rec
(func:C_AST.func)
?(selector=is_stub_comment)
(prj:C_AST.project)
(enums:Z.t C_AST.StringMap.t)
(predicates:Passes.Preprocessor.predicate C_AST.StringMap.t)
(cache:(string,Cst.stub) Hashtbl.t)
: Ast.stub
=
let cst = parse_cst func ~selector prj enums predicates cache in
debug "stub of function %s:@\n @[%a]" func.func_org_name Cst.pp_stub cst;
Passes.Cst_to_ast.doit prj func cst
(** Parse comment of a stub directive *)
let
(com:(Clang_AST.comment * C_AST.macro C_AST.StringMap.t) list)
(range:Clang_AST.range)
(prj:C_AST.project)
(enums:Z.t C_AST.StringMap.t)
(predicates:Passes.Preprocessor.predicate C_AST.StringMap.t)
(stubs:(string,Cst.stub) Hashtbl.t)
: Ast.stub
=
let func = {
func_uid = 0;
func_org_name = "$directive:" ^ (Clang_dump.string_of_range range);
func_unique_name = "$directive:" ^ (Clang_dump.string_of_range range);
func_is_static = false;
func_return = C_AST.T_void, C_AST.no_qual;
func_parameters = [||];
func_body = None;
func_static_vars = [];
func_local_vars = [];
func_variadic = false;
func_range = range;
func_name_range = range;
func_com = com;
}
in
parse_function_comment func ~selector:is_directive_comment prj enums predicates stubs
(** Parse a comment of predicates declarations *)
let (coms:(Clang_AST.comment * Clang_AST.macro StringMap.t) list) : Passes.Preprocessor.predicate list =
coms |> List.fold_left (fun acc (com,macros) ->
if is_predicates_comment (com,macros) then
let = com.com_text in
let file = com.com_range.range_begin.loc_file in
let line = com.com_range.range_begin.loc_line in
let col = com.com_range.range_begin.loc_column in
let buf = Lexing.from_string comment in
buf.lex_curr_p <- {
pos_fname = file;
pos_lnum = line;
pos_bol = 0;
pos_cnum = col;
};
try
Passes.Preprocessor.parse_predicates Lexer.read buf @ acc
with
| Lexer.SyntaxError s ->
let range = Location.from_lexing_range (Lexing.lexeme_start_p buf) (Lexing.lexeme_end_p buf) in
Exceptions.syntax_error range "%s" s
else
acc
) []