1 /* radare - LGPL - Copyright 2019 - thestr4ng3r */
2
3 #include <r_parse.h>
4
5 #include <mpc.h>
6
7 struct r_parse_ctype_t {
8 mpc_parser_t *integerlit;
9 mpc_parser_t *identifier;
10 mpc_parser_t *qualifier;
11 mpc_parser_t *pointer;
12 mpc_parser_t *array;
13 mpc_parser_t *type;
14 };
15
16 #define ALL_PARSERS(ctype) ctype->integerlit, ctype->identifier, ctype->qualifier, ctype->pointer, ctype->array, ctype->type
17 #define ALL_PARSERS_COUNT 6
18
19 static const char *lang =
20 "integerlit : /0x[0-9A-Fa-f]+/ | /[0-9]+/;"
21 "identifier : (\"struct\" | \"union\" | \"enum\")? /[a-zA-Z_][0-9a-zA-Z_]+/;"
22 "qualifier : \"const\";"
23 "pointer : <qualifier>? '*';"
24 "array : '[' <integerlit> ']';"
25 "type : <qualifier>? <identifier> (<pointer> | <array>)*;";
26
27
r_parse_ctype_new(void)28 R_API RParseCType *r_parse_ctype_new(void) {
29 RParseCType *ctype = R_NEW (RParseCType);
30 if (!ctype) {
31 return NULL;
32 }
33
34 ctype->integerlit = mpc_new ("integerlit");
35 ctype->identifier = mpc_new ("identifier");
36 ctype->qualifier = mpc_new ("qualifier");
37 ctype->pointer = mpc_new ("pointer");
38 ctype->array = mpc_new ("array");
39 ctype->type = mpc_new ("type");
40
41 mpc_err_t *err = mpca_lang (MPCA_LANG_DEFAULT, lang, ALL_PARSERS (ctype), NULL);
42 if (err) {
43 mpc_err_print (err);
44 mpc_err_delete (err);
45 r_parse_ctype_free (ctype);
46 return NULL;
47 }
48
49 return ctype;
50 }
51
r_parse_ctype_free(RParseCType * ctype)52 R_API void r_parse_ctype_free(RParseCType *ctype) {
53 if (!ctype) {
54 return;
55 }
56 mpc_cleanup (ALL_PARSERS_COUNT, ALL_PARSERS (ctype));
57 free (ctype);
58 }
59
is_qualifier_const(mpc_ast_t * a)60 static bool is_qualifier_const(mpc_ast_t *a) {
61 return strcmp (a->tag, "qualifier|string") == 0
62 && a->contents
63 && strcmp (a->contents, "const") == 0;
64 }
65
is_identifier_string(mpc_ast_t * a)66 static bool is_identifier_string(mpc_ast_t *a) {
67 return strcmp (a->tag, "identifier|regex") == 0
68 && a->contents;
69 }
70
is_identifier_kind(mpc_ast_t * a)71 static bool is_identifier_kind(mpc_ast_t *a) {
72 return strcmp (a->tag, "identifier|>") == 0
73 && a->children_num == 2
74 && strcmp (a->children[0]->tag, "string") == 0
75 && a->children[0]->contents
76 && strcmp (a->children[1]->tag, "regex") == 0
77 && a->children[1]->contents;
78 }
79
is_non_const_pointer(mpc_ast_t * a)80 static bool is_non_const_pointer(mpc_ast_t *a) {
81 return strcmp (a->tag, "pointer|char") == 0
82 && a->contents
83 && strcmp (a->contents, "*") == 0;
84 }
85
is_const_pointer(mpc_ast_t * a)86 static bool is_const_pointer(mpc_ast_t *a) {
87 return strcmp (a->tag, "pointer|>") == 0
88 && a->children_num == 2
89 && is_qualifier_const (a->children[0])
90 && strcmp (a->children[1]->tag, "char") == 0
91 && a->children[1]->contents
92 && strcmp (a->children[1]->contents, "*") == 0;
93 }
94
is_array(mpc_ast_t * a)95 static bool is_array(mpc_ast_t *a) {
96 return strcmp (a->tag, "array|>") == 0
97 && a->children_num == 3
98 && strcmp (a->children[0]->tag, "char") == 0
99 && a->children[0]->contents
100 && strcmp (a->children[0]->contents, "[") == 0
101 && strcmp (a->children[1]->tag, "integerlit|regex") == 0
102 && a->children[1]->contents
103 && strcmp (a->children[2]->tag, "char") == 0
104 && a->children[2]->contents
105 && strcmp (a->children[2]->contents, "]") == 0;
106 }
107
ctype_convert_ast(mpc_ast_t * a)108 static RParseCTypeType *ctype_convert_ast(mpc_ast_t *a) {
109 bool is_const = false;
110 RParseCTypeType *cur = NULL;
111 int i;
112 for (i = 0; i < a->children_num; i++) {
113 mpc_ast_t *child = a->children[i];
114
115 // const
116 if (is_qualifier_const (child)) {
117 is_const = true;
118 }
119
120 // (struct|union|enum)? <identifier>
121 else if (r_str_startswith (child->tag, "identifier|")) {
122 if (cur) {
123 // identifier should always be the innermost type
124 goto beach;
125 }
126 cur = R_NEW0 (RParseCTypeType);
127 if (!cur) {
128 goto beach;
129 }
130 cur->kind = R_PARSE_CTYPE_TYPE_KIND_IDENTIFIER;
131 cur->identifier.is_const = is_const;
132 cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_UNSPECIFIED;
133 if (is_identifier_string (child)) {
134 cur->identifier.name = strdup (child->contents);
135 } else if (is_identifier_kind (child)) {
136 if (strcmp (child->children[0]->contents, "struct") == 0) {
137 cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_STRUCT;
138 } else if (strcmp (child->children[0]->contents, "union") == 0) {
139 cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_UNION;
140 } else if (strcmp (child->children[0]->contents, "enum") == 0) {
141 cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_ENUM;
142 }
143 cur->identifier.name = strdup (child->children[1]->contents);
144 } else {
145 goto beach;
146 }
147 if (!cur->identifier.name) {
148 goto beach;
149 }
150 is_const = false;
151 }
152
153 // <identifier>
154 else if (is_identifier_string (child)) {
155 if (cur) {
156 // identifier should always be the innermost type
157 goto beach;
158 }
159 cur = R_NEW0 (RParseCTypeType);
160 if (!cur) {
161 goto beach;
162 }
163 cur->kind = R_PARSE_CTYPE_TYPE_KIND_IDENTIFIER;
164 cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_UNSPECIFIED;
165 cur->identifier.is_const = is_const;
166 cur->identifier.name = strdup (child->contents);
167 if (!cur->identifier.name) {
168 goto beach;
169 }
170 is_const = false;
171 }
172
173 // *
174 else if (is_non_const_pointer (child)) {
175 RParseCTypeType *pointer = R_NEW0 (RParseCTypeType);
176 if (!pointer) {
177 goto beach;
178 }
179 pointer->kind = R_PARSE_CTYPE_TYPE_KIND_POINTER;
180 pointer->pointer.is_const = false;
181 pointer->pointer.type = cur;
182 cur = pointer;
183 }
184
185 // const *
186 else if (is_const_pointer (child)) {
187 RParseCTypeType *pointer = R_NEW0 (RParseCTypeType);
188 if (!pointer) {
189 goto beach;
190 }
191 pointer->kind = R_PARSE_CTYPE_TYPE_KIND_POINTER;
192 pointer->pointer.is_const = true;
193 pointer->pointer.type = cur;
194 cur = pointer;
195 }
196
197 // <array>
198 else if (is_array (child)) {
199 RParseCTypeType *array = R_NEW0 (RParseCTypeType);
200 if (!array) {
201 goto beach;
202 }
203 array->kind = R_PARSE_CTYPE_TYPE_KIND_ARRAY;
204 array->array.count = strtoull (child->children[1]->contents, NULL, 0);
205 array->array.type = cur;
206 cur = array;
207 }
208
209 else {
210 goto beach;
211 }
212 }
213
214 return cur;
215 beach:
216 r_parse_ctype_type_free (cur);
217 return NULL;
218 }
219
r_parse_ctype_parse(RParseCType * ctype,const char * str,char ** error)220 R_API RParseCTypeType *r_parse_ctype_parse(RParseCType *ctype, const char *str, char **error) {
221 mpc_result_t r;
222 if (mpc_parse ("<string>", str, ctype->type, &r)) {
223 RParseCTypeType *ret = ctype_convert_ast (r.output);
224 if (error) {
225 *error = !ret ? strdup ("internal error") : NULL;
226 }
227 mpc_ast_delete (r.output);
228 return ret;
229 } else {
230 if (error) {
231 *error = mpc_err_string (r.error);
232 }
233 mpc_err_delete (r.error);
234 return NULL;
235 }
236 }
237
r_parse_ctype_type_free(RParseCTypeType * type)238 R_API void r_parse_ctype_type_free(RParseCTypeType *type) {
239 if (!type) {
240 return;
241 }
242 switch (type->kind) {
243 case R_PARSE_CTYPE_TYPE_KIND_IDENTIFIER:
244 free (type->identifier.name);
245 break;
246 case R_PARSE_CTYPE_TYPE_KIND_POINTER:
247 r_parse_ctype_type_free (type->pointer.type);
248 break;
249 case R_PARSE_CTYPE_TYPE_KIND_ARRAY:
250 r_parse_ctype_type_free (type->array.type);
251 break;
252 }
253 free (type);
254 }
255