]> git.ozlabs.org Git - ccan-lca-2011.git/blob - ccan/cdump/cdump_parse.c
cdump: first cut of translation of Tridge's genstruct junkcode.
[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                 bundle = talloc_asprintf_append(bundle, "_%s", type[i]);
131                 unbundle = talloc_asprintf_append(unbundle, "_%s", type[i]);
132                 size = talloc_asprintf_append(size, "%s ", type[i]);
133         }
134         size[strlen(size)-1] = ')';
135
136         off += handle_general(ctx, outer_struct_name, definitions, ptr_count,
137                               size, tok + off, flags, dynlen, bundle, unbundle);
138         return off;
139 }
140
141 static size_t parse_element(const void *ctx, const char *outer_struct_name,
142                             char **definitions, char **tok)
143 {
144         const char *dynlen = NULL, *flags = "0";
145         char **type;
146         unsigned int typelen;
147         size_t i;
148
149         if (streq(tok[0], "enum"))
150                 flags = talloc_strdup(ctx, "CDUMP_FLAG_ALWAYS");
151
152         type = tok;
153         for (i = typelen = 0; tok[i]; i++) {
154                 /* These mean we've passed the variable name */
155                 if (streq(tok[i], "[")
156                     || streq(tok[i], ",")) {
157                         if (typelen == 0) {
158                                 typelen = i - 1;
159                         }
160                 }
161                 /* End of expression means we've passed variable name, too */
162                 if (streq(tok[i], ";")) {
163                         if (typelen == 0) {
164                                 typelen = i - 1;
165                         }
166                         break;
167                 }
168                 /* This marks the end of the type: parse_one swallows *s. */
169                 if (streq(tok[i], "*")) {
170                         if (typelen == 0) {
171                                 typelen = i;
172                         }
173                 }
174                 if (streq(tok[i], "CDUMP_LEN")) {
175                         dynlen = talloc_asprintf(ctx, "\"%s\"", tok[i+2]);
176                         if (typelen == 0) {
177                                 typelen = i - 1;
178                         }
179                 }
180         }
181         i = typelen;
182
183         /* They could be comma-separated, so process them all. */
184         do {
185                 i += parse_one(ctx, outer_struct_name, definitions,
186                                type, typelen, tok+i, dynlen, flags);
187                 if (tok[i] && streq(tok[i], ","))
188                         i++;
189         } while (tok[i] && !streq(tok[i], ";") && !strstarts(tok[i], "CDUMP_"));
190
191         while (tok[i] && !streq(tok[i], ";"))
192                 i++;
193
194         return i + 1;
195 }
196
197 static unsigned parse_struct(const void *ctx,
198                              const char *name, char **tok,
199                              char **declarations, char **definitions)
200 {
201         unsigned int i = 1, len;
202
203         *declarations = talloc_asprintf_append(*declarations,
204 "bool cdump_bundle_struct_%s(struct cdump_string *, const void *, unsigned);\n"
205 "bool cdump_unbundle_struct_%s(const void *, void *, const char *);\n"
206 "extern const struct cdump_desc cdump_struct_%s[];\n",
207                                                name, name, name);
208
209         *definitions = talloc_asprintf_append(*definitions,
210 "const struct cdump_desc cdump_struct_%s[] = {\n",
211                                               name);
212         while (!streq(tok[i], "}")) {
213                 len = parse_element(ctx, name, definitions, tok + i);
214                 if (!len)
215                         return 0;
216                 i += len;
217                 if (!tok[i])
218                         return 0;
219         }
220         *definitions = talloc_asprintf_append(*definitions,
221         "\t{ NULL, 0, 0, 0, 0, NULL, 0, NULL, NULL } };\n"
222         "bool cdump_bundle_struct_%s(struct cdump_string *p, const void *ptr, unsigned indent)\n"
223         "{\n"
224         "       return cdump_bundle_struct(cdump_struct_%s, p, ptr, indent);\n"
225         "}\n"
226         "bool cdump_unbundle_struct_%s(const void *ctx, void *ptr, const char *str)\n"
227         "{\n"
228         "       return cdump_unbundle_struct(ctx, cdump_struct_%s, ptr, str);\n"
229         "}\n"
230         "\n",
231                                               name, name, name, name);
232         return i + 1;
233 }
234
235 static unsigned parse_enum(const void *ctx,
236                            const char *name, char **tok,
237                            char **declarations, char **definitions)
238 {
239         unsigned int i = 1;
240         
241         *declarations = talloc_asprintf_append(*declarations,
242 "bool cdump_bundle_enum_%s(struct cdump_string *, const void *, unsigned);\n"
243 "bool cdump_unbundle_enum_%s(const void *, void *, const char *);\n"
244 "extern const struct cdump_enum cdump_enum_%s[];\n",
245                                                name, name, name);
246
247         *definitions = talloc_asprintf_append(*definitions,
248 "const struct cdump_enum cdump_enum_%s[] = {\n",
249                                               name);
250         while (!streq(tok[i], "}")) {
251                 *definitions = talloc_asprintf_append(*definitions,
252                                                       "\t{ \"%s\", %s },\n",
253                                                       tok[i], tok[i]);
254                 while (!streq(tok[i], ",")) {
255                         if (streq(tok[i], "}")) {
256                                 i--;
257                                 break;
258                         }
259                         i++;
260                 }
261                 i++;
262         }
263
264         *definitions = talloc_asprintf_append(*definitions,
265         "\t{ NULL, 0 } };\n"
266         "bool cdump_bundle_enum_%s(struct cdump_string *p, const void *ptr, unsigned indent)\n"
267         "{\n"
268         "       return cdump_bundle_enum(cdump_enum_%s, p, ptr, indent);\n"
269         "}\n"
270         "bool cdump_unbundle_enum_%s(const void *ctx, void *ptr, const char *str)\n"
271         "{\n"
272         "       return cdump_unbundle_enum(cdump_enum_%s, ptr, str);\n"
273         "}\n"
274         "\n",
275                                               name, name, name, name);
276         return i + 1;
277 }
278
279 /* World's hackiest parser, inspired by Tridge's genstruct.pl. */
280 char *cdump_parse(const void *ctx, const char *code,
281                   char **declarations, char **definitions)
282 {
283         char **tokens = tokenize(ctx, code);
284         unsigned int i, len;
285
286         *declarations = talloc_strdup(ctx, "");
287         *definitions = talloc_strdup(ctx, "");
288
289         for (i = 0; i < talloc_array_length(tokens)-1; i++) {
290                 if (!streq(tokens[i], "CDUMP_SAVED"))
291                         continue;
292                 if (i + 3 >= talloc_array_length(tokens)-1)
293                         return talloc_strdup(ctx, "EOF after CDUMP_SAVED");
294
295                 if (streq(tokens[i+1], "struct")) {
296                         len = parse_struct(ctx, tokens[i+2], tokens + i + 3,
297                                            declarations, definitions);
298                 } else if (streq(tokens[i+1], "enum")) {
299                         len = parse_enum(ctx, tokens[i+2], tokens + i + 3,
300                                          declarations, definitions);
301                 } else
302                         return talloc_asprintf(ctx, "Unknown saved type"
303                                                " '%s'", tokens[i+1]);
304                 if (len == 0)
305                         return talloc_asprintf(ctx, "Invalid %s '%s'",
306                                                tokens[i+1], tokens[i+2]);
307                 i += len + 2;
308         }
309
310         return NULL;
311 }