]> git.ozlabs.org Git - ccan-lca-2011.git/blob - ccan/cdump/cdump_parse.c
Add slides images.
[ccan-lca-2011.git] / ccan / cdump / cdump_parse.c
1 #include <ccan/cdump/cdump_parse.h>
2 #include <ccan/talloc/talloc.h>
3 #include <ccan/str/str.h>
4 #include <stdlib.h>
5 #include <stdbool.h>
6 #include <ctype.h>
7
8 static void add_token(char ***toks, const char *tok, unsigned toklen)
9 {
10         size_t len = talloc_array_length(*toks);
11
12         *toks = talloc_realloc(NULL, *toks, char *, len+1);
13         (*toks)[len] = talloc_strndup(*toks, tok, toklen);
14 }
15
16 /* Simplified tokenizer: comments and preproc directives removed,
17    identifiers are a token, others are single char tokens. */
18 static char **tokenize(const void *ctx, const char *code)
19 {
20         unsigned int i, len, tok_start = -1;
21         bool start_of_line = true;
22         char **ret = talloc_array(ctx, char *, 0);
23
24         for (i = 0; code[i]; i += len) {
25                 if (code[i] == '#' && start_of_line) {
26                         /* Preprocessor line. */
27                         len = strcspn(code+i, "\n");
28                 } else if (code[i] == '/' && code[i+1] == '/') {
29                         /* One line comment. */
30                         len = strcspn(code+i, "\n");
31                         if (tok_start != -1U) {
32                                 add_token(&ret, code+tok_start, i - tok_start);
33                                 tok_start = -1U;
34                         }
35                 } else if (code[i] == '/' && code[i+1] == '*') {
36                         /* Multi-line comment. */
37                         const char *end = strstr(code+i+2, "*/");
38                         len = (end + 2) - (code + i);
39                         if (!end)
40                                 len = strlen(code + i);
41                         if (tok_start != -1U) {
42                                 add_token(&ret, code+tok_start, i - tok_start);
43                                 tok_start = -1U;
44                         }
45                 } else if (isalnum(code[i]) || code[i] == '_') {
46                         /* Identifier or part thereof */
47                         if (tok_start == -1U)
48                                 tok_start = i;
49                         len = 1;
50                 } else if (!isspace(code[i])) {
51                         /* Punctuation: treat as single char token. */
52                         if (tok_start != -1U) {
53                                 add_token(&ret, code+tok_start, i - tok_start);
54                                 tok_start = -1U;
55                         }
56                         add_token(&ret, code+i, 1);
57                         len = 1;
58                 } else {
59                         /* Whitespace. */
60                         if (tok_start != -1U) {
61                                 add_token(&ret, code+tok_start, i - tok_start);
62                                 tok_start = -1U;
63                         }
64                         len = 1;
65                 }
66                 if (code[i] == '\n')
67                         start_of_line = true;
68                 else if (!isspace(code[i]))
69                         start_of_line = false;
70         }
71
72         /* Add terminating NULL. */
73         ret = talloc_realloc(NULL, ret, char *, talloc_array_length(ret)+1);
74         ret[talloc_array_length(ret)-1] = NULL;
75
76         return ret;
77 }
78
79 static size_t handle_general(const void *ctx, const char *outer_struct_name,
80                              char **definitions, unsigned int ptr_count,
81                              const char *size, char **tok, const char *flags,
82                              const char *dynlen, const char *bundle,
83                              const char *unbundle)
84 {
85         size_t off = 1;
86         char *array_len = NULL;
87
88         /* handle arrays, treat multidimensional arrays as 1 dimensional */
89         while (streq(tok[off], "[")) {
90                 if (!array_len)
91                         array_len = talloc_strdup(ctx, "(");
92                 else
93                         array_len = talloc_asprintf_append(array_len, " * (");
94                 off++;
95                 while (!streq(tok[off], "]")) {
96                         array_len = talloc_asprintf_append(array_len,
97                                                            "%s ", tok[off]);
98                         off++;
99                 }
100                 array_len[strlen(array_len)-1] = ')';
101                 off++;
102         }
103
104         *definitions = talloc_asprintf_append(*definitions,
105        "\t{ \"%s\", %u, %s, offsetof(struct %s, %s), %s, %s, %s, %s, %s },\n",
106                 tok[0], ptr_count, size, outer_struct_name, tok[0],
107                 array_len ? array_len : "0", dynlen ? dynlen : "NULL", flags,
108                 bundle, unbundle);
109
110         return off;
111 }
112
113 static size_t parse_one(const void *ctx, const char *outer_struct_name,
114                         char **definitions, char **type, unsigned typelen,
115                         char **tok, const char *dynlen, const char *flags)
116 {
117         unsigned int i, ptr_count = 0;
118         size_t off = 0;
119         char *bundle, *unbundle, *size;
120
121         while (streq(tok[off], "*")) {
122                 ptr_count++;
123                 off++;
124         }
125
126         bundle = talloc_strdup(ctx, "cdump_bundle");
127         unbundle = talloc_strdup(ctx, "cdump_unbundle");
128         size = talloc_strdup(ctx, "sizeof(");
129         for (i = 0; i < typelen; i++) {
130                 /* Const is irrelevant for bundling. */
131                 if (streq(type[i], "const"))
132                         continue;
133                 bundle = talloc_asprintf_append(bundle, "_%s", type[i]);
134                 unbundle = talloc_asprintf_append(unbundle, "_%s", type[i]);
135                 size = talloc_asprintf_append(size, "%s ", type[i]);
136         }
137         size[strlen(size)-1] = ')';
138
139         off += handle_general(ctx, outer_struct_name, definitions, ptr_count,
140                               size, tok + off, flags, dynlen, bundle, unbundle);
141         return off;
142 }
143
144 static size_t parse_element(const void *ctx, const char *outer_struct_name,
145                             char **definitions, char **tok)
146 {
147         const char *dynlen = NULL, *flags = "0";
148         char **type;
149         unsigned int typelen;
150         size_t i;
151
152         if (streq(tok[0], "enum"))
153                 flags = talloc_strdup(ctx, "CDUMP_FLAG_ALWAYS");
154
155         type = tok;
156         for (i = typelen = 0; tok[i]; i++) {
157                 /* These mean we've passed the variable name */
158                 if (streq(tok[i], "[")
159                     || streq(tok[i], ",")) {
160                         if (typelen == 0) {
161                                 typelen = i - 1;
162                         }
163                 }
164                 /* End of expression means we've passed variable name, too */
165                 if (streq(tok[i], ";")) {
166                         if (typelen == 0) {
167                                 typelen = i - 1;
168                         }
169                         break;
170                 }
171                 /* This marks the end of the type: parse_one swallows *s. */
172                 if (streq(tok[i], "*")) {
173                         if (typelen == 0) {
174                                 typelen = i;
175                         }
176                 }
177                 if (streq(tok[i], "CDUMP_LEN")) {
178                         dynlen = talloc_asprintf(ctx, "\"%s\"", tok[i+2]);
179                         if (typelen == 0) {
180                                 typelen = i - 1;
181                         }
182                 }
183                 if (streq(tok[i], "CDUMP_IGNORE"))
184                         goto skip;
185         }
186         i = typelen;
187
188         /* They could be comma-separated, so process them all. */
189         do {
190                 i += parse_one(ctx, outer_struct_name, definitions,
191                                type, typelen, tok+i, dynlen, flags);
192                 if (tok[i] && streq(tok[i], ","))
193                         i++;
194         } while (tok[i] && !streq(tok[i], ";") && !strstarts(tok[i], "CDUMP_"));
195
196 skip:
197         while (tok[i] && !streq(tok[i], ";"))
198                 i++;
199
200         return i + 1;
201 }
202
203 static unsigned parse_struct(const void *ctx,
204                              const char *name, char **tok,
205                              char **declarations, char **definitions)
206 {
207         unsigned int i = 1, len;
208
209         *declarations = talloc_asprintf_append(*declarations,
210 "bool cdump_bundle_struct_%s(struct cdump_string *, const void *, unsigned);\n"
211 "bool cdump_unbundle_struct_%s(const void *, void *, const char *);\n"
212 "extern const struct cdump_desc cdump_struct_%s[];\n",
213                                                name, name, name);
214
215         *definitions = talloc_asprintf_append(*definitions,
216 "const struct cdump_desc cdump_struct_%s[] = {\n",
217                                               name);
218         while (!streq(tok[i], "}")) {
219                 len = parse_element(ctx, name, definitions, tok + i);
220                 if (!len)
221                         return 0;
222                 i += len;
223                 if (!tok[i])
224                         return 0;
225         }
226         *definitions = talloc_asprintf_append(*definitions,
227         "\t{ NULL, 0, 0, 0, 0, NULL, 0, NULL, NULL } };\n"
228         "bool cdump_bundle_struct_%s(struct cdump_string *p, const void *ptr, unsigned indent)\n"
229         "{\n"
230         "       return cdump_bundle_struct(cdump_struct_%s, p, ptr, indent);\n"
231         "}\n"
232         "bool cdump_unbundle_struct_%s(const void *ctx, void *ptr, const char *str)\n"
233         "{\n"
234         "       return cdump_unbundle_struct(ctx, cdump_struct_%s, ptr, str);\n"
235         "}\n"
236         "\n",
237                                               name, name, name, name);
238         return i + 1;
239 }
240
241 static unsigned parse_enum(const void *ctx,
242                            const char *name, char **tok,
243                            char **declarations, char **definitions)
244 {
245         unsigned int i = 1;
246         
247         *declarations = talloc_asprintf_append(*declarations,
248 "bool cdump_bundle_enum_%s(struct cdump_string *, const void *, unsigned);\n"
249 "bool cdump_unbundle_enum_%s(const void *, void *, const char *);\n"
250 "extern const struct cdump_enum cdump_enum_%s[];\n",
251                                                name, name, name);
252
253         *definitions = talloc_asprintf_append(*definitions,
254 "const struct cdump_enum cdump_enum_%s[] = {\n",
255                                               name);
256         while (!streq(tok[i], "}")) {
257                 *definitions = talloc_asprintf_append(*definitions,
258                                                       "\t{ \"%s\", %s },\n",
259                                                       tok[i], tok[i]);
260                 while (!streq(tok[i], ",")) {
261                         if (streq(tok[i], "}")) {
262                                 i--;
263                                 break;
264                         }
265                         i++;
266                 }
267                 i++;
268         }
269
270         *definitions = talloc_asprintf_append(*definitions,
271         "\t{ NULL, 0 } };\n"
272         "bool cdump_bundle_enum_%s(struct cdump_string *p, const void *ptr, unsigned indent)\n"
273         "{\n"
274         "       return cdump_bundle_enum(cdump_enum_%s, p, ptr, indent);\n"
275         "}\n"
276         "bool cdump_unbundle_enum_%s(const void *ctx, void *ptr, const char *str)\n"
277         "{\n"
278         "       return cdump_unbundle_enum(cdump_enum_%s, ptr, str);\n"
279         "}\n"
280         "\n",
281                                               name, name, name, name);
282         return i + 1;
283 }
284
285 /* World's hackiest parser, inspired by Tridge's genstruct.pl. */
286 char *cdump_parse(const void *ctx, const char *code,
287                   char **declarations, char **definitions)
288 {
289         char **tokens = tokenize(ctx, code);
290         unsigned int i, len;
291
292         *declarations = talloc_strdup(ctx, "");
293         *definitions = talloc_strdup(ctx, "");
294
295         for (i = 0; i < talloc_array_length(tokens)-1; i++) {
296                 if (!streq(tokens[i], "CDUMP_SAVED"))
297                         continue;
298                 if (i + 3 >= talloc_array_length(tokens)-1)
299                         return talloc_strdup(ctx, "EOF after CDUMP_SAVED");
300
301                 if (streq(tokens[i+1], "struct")) {
302                         len = parse_struct(ctx, tokens[i+2], tokens + i + 3,
303                                            declarations, definitions);
304                 } else if (streq(tokens[i+1], "enum")) {
305                         len = parse_enum(ctx, tokens[i+2], tokens + i + 3,
306                                          declarations, definitions);
307                 } else
308                         return talloc_asprintf(ctx, "Unknown saved type"
309                                                " '%s'", tokens[i+1]);
310                 if (len == 0)
311                         return talloc_asprintf(ctx, "Invalid %s '%s'",
312                                                tokens[i+1], tokens[i+2]);
313                 i += len + 2;
314         }
315
316         return NULL;
317 }