on master help sign in
Redo the generator/generated so they work together
commite2e3b164cefcd52104c5527e907174ece3082a7d authorNeil Mitchell <ndmitchell@gmail.com> dateWed 3 Jan 2018, 21:40 (9 years ago) parent75f8a57
2 files changed+351−15
gen/Lib.hs+4−3 gen/test.c+347−12
gen/Lib.hs+4−3
@@ -102,8 +102,8 @@ implies known x = all (fromCharSet x) poss
102102
103103charSetC :: [CharSet] -> ([String], CharSet -> String)
104104charSetC sets =
105− (["const char parse_table[256] = {" ++ intercalate "," ("0":map disp chars) ++ "};"]
106− ,\x -> fromMaybe ("parse_table[*p] & " ++ showBit (bit $ fromJust $ elemIndex x hard)) $ simple x)
105+ (["static const char internal_parse_table[256] = {" ++ intercalate "," ("0":map disp chars) ++ "};"]
106+ ,\x -> fromMaybe ("internal_parse_table[*p] & " ++ showBit (bit $ fromJust $ elemIndex x hard)) $ simple x)
107107 where
108108 showBit x = "0x" ++ showHex (x :: Int) ""
109109 disp c = showBit $ foldr (.|.) 0 [bit i | (i, h) <- zip [0..] hard, fromCharSet h c]
@@ -171,7 +171,8 @@ runC = f 0
171171prettyC :: Show o => [C o] -> [String]
172172prettyC xs =
173173 prefix ++
174− ["const char* parser(const char* p ARGUMENTS){"] ++
174+ ["static const char* parser(const char* p ARGUMENTS){"
175+ ," VARIABLES;"] ++
175176 fi xs ++
176177 [" return NULL;"
177178 ,"}"]
gen/test.c+347−12
@@ -1,29 +1,364 @@
11
2+#include "../cbits/hexml.h"
3+#include <stdlib.h>
4+#include <string.h>
5+#include <assert.h>
6+#include <ctype.h>
27#include <stdio.h>
3−#define ARGUMENTS
48
5−#define parse_table hexml_parse_table
6−#define parser hexml_parser
9+typedef int bool;
10+
11+/////////////////////////////////////////////////////////////////////
12+// TYPES
13+
14+static inline int end(str s) { return s.start + s.length; }
15+
16+static inline str start_length(int32_t start, int32_t length)
17+{
18+ assert(start >= 0 && length >= 0);
19+ str res;
20+ res.start = start;
21+ res.length = length;
22+ return res;
23+}
24+
25+static inline str start_end(int32_t start, int32_t end)
26+{
27+ return start_length(start, end - start);
28+}
29+
30+typedef struct
31+{
32+ int size;
33+ int used;
34+ attr* attrs; // dynamically allocated buffer
35+ attr* alloc; // what to call free on
36+} attr_buffer;
37+
38+typedef struct
39+{
40+ // have a cursor at the front, which is all the stuff I have written out, final
41+ // have a cursor at the end, which is stack scoped, so children write out, then I do
42+ // when you commit, you copy over from end to front
43+
44+ // nodes
45+ int size;
46+ int used_front; // front entries, stored for good
47+ int used_back; // back entries, stack based, copied into front
48+ node* nodes; // dynamically allocated buffer
49+ node* alloc; // what to call free on
50+} node_buffer;
51+
52+
53+struct document
54+{
55+ const char* body; // pointer to initial argument, not owned by us
56+
57+ // things only used while parsing
58+ const char* cursor; // pointer to where we are in body
59+ const char* end; // pointer to one past the last char
60+ // if cursor is > end we have gone past the end
61+
62+ char* error_message;
63+ node_buffer nodes;
64+ attr_buffer attrs;
65+};
66+
67+static inline int doc_length(const document* d) { return (int) (d->end - d->body); }
68+static inline int doc_position(const document* d) { return (int) (d->cursor - d->body); }
69+
70+
71+/////////////////////////////////////////////////////////////////////
72+// RENDER CODE
73+
74+typedef struct
75+{
76+ const document* d;
77+ char* buffer;
78+ int length;
79+ int cursor;
80+} render;
81+
82+static inline void render_char(render* r, char c)
83+{
84+ if (r->cursor < r->length)
85+ r->buffer[r->cursor] = c;
86+ r->cursor++;
87+}
88+
89+static inline void bound(int idx, int mn, int mx)
90+{
91+ assert(idx >= mn && idx <= mx);
92+}
93+
94+static inline void bound_str(str s, int mn, int mx)
95+{
96+ assert(s.length >= 0);
97+ bound(s.start, mn, mx);
98+ bound(end(s), mn, mx);
99+}
100+
101+static void render_str(render* r, str s)
102+{
103+ bound_str(s, 0, doc_length(r->d));
104+ for (int i = 0; i < s.length; i++)
105+ render_char(r, r->d->body[s.start + i]);
106+}
107+
108+static void render_tag(render* r, const node* n);
109+
110+static void render_content(render* r, const node* n)
111+{
112+ bound_str(n->inner, 0, doc_length(r->d));
113+ bound_str(n->nodes, 0, r->d->nodes.used_front);
114+ bound_str(n->attrs, 0, r->d->attrs.used);
115+
116+ int done = n->inner.start;
117+ for (int i = 0; i < n->nodes.length; i++)
118+ {
119+ node* x = &r->d->nodes.nodes[n->nodes.start + i];
120+ render_str(r, start_end(done, x->outer.start));
121+ done = end(x->outer);
122+ render_tag(r, x);
123+ }
124+ render_str(r, start_end(done, end(n->inner)));
125+}
126+
127+static void render_tag(render* r, const node* n)
128+{
129+ render_char(r, '<');
130+ render_str(r, n->name);
131+ for (int i = 0; i < n->attrs.length; i++)
132+ {
133+ attr* x = &r->d->attrs.attrs[n->attrs.start + i];
134+ render_char(r, ' ');
135+ render_str(r, x->name);
136+ render_char(r, '=');
137+ render_char(r, '\"');
138+ render_str(r, x->value);
139+ render_char(r, '\"');
140+ }
141+ render_char(r, '>');
142+ render_content(r, n);
143+ render_char(r, '<');
144+ render_char(r, '/');
145+ render_str(r, n->name);
146+ render_char(r, '>');
147+}
148+
149+int hexml_node_render(const document* d, const node* n, char* buffer, int length)
150+{
151+ render r;
152+ r.d = d;
153+ r.buffer = buffer;
154+ r.length = length;
155+ r.cursor = 0;
156+ // The root node (and only the root node) has an empty length, so just render its innards
157+ if (n->name.length == 0)
158+ render_content(&r, n);
159+ else
160+ render_tag(&r, n);
161+ return r.cursor;
162+}
163+
164+
165+/////////////////////////////////////////////////////////////////////
166+// NOT THE PARSER
167+
168+char* hexml_document_error(const document* d){return d->error_message;}
169+node* hexml_document_node(const document* d){return &d->nodes.nodes[0];}
170+
171+void hexml_document_free(document* d)
172+{
173+ free(d->error_message);
174+ free(d->nodes.alloc);
175+ free(d->attrs.alloc);
176+ free(d);
177+}
178+
179+node* hexml_node_children(const document* d, const node* n, int* res)
180+{
181+ *res = n->nodes.length;
182+ return &d->nodes.nodes[n->nodes.start];
183+}
184+
185+attr* hexml_node_attributes(const document* d, const node* n, int* res)
186+{
187+ *res = n->attrs.length;
188+ return &d->attrs.attrs[n->attrs.start];
189+}
190+
191+
192+attr* hexml_node_attribute(const document* d, const node* n, const char* s, int slen)
193+{
194+ if (slen == -1) slen = (int) strlen(s);
195+ const int limit = end(n->attrs);
196+ for (int i = n->attrs.start; i < limit; i++)
197+ {
198+ attr* r = &d->attrs.attrs[i];
199+ if (r->name.length == slen && memcmp(s, &d->body[r->name.start], slen) == 0)
200+ return r;
201+ }
202+ return NULL;
203+}
204+
205+// Search for given strings within a node
206+node* hexml_node_child(const document* d, const node* parent, const node* prev, const char* s, int slen)
207+{
208+ if (slen == -1) slen = (int) strlen(s);
209+ int i = prev == NULL ? parent->nodes.start : (int) (prev + 1 - d->nodes.nodes);
210+ const int limit = end(parent->nodes);
211+ for (; i < limit; i++)
212+ {
213+ node* r = &d->nodes.nodes[i];
214+ if (r->name.length == slen && memcmp(s, &d->body[r->name.start], slen) == 0)
215+ return r;
216+ }
217+ return NULL;
218+}
219+
220+/////////////////////////////////////////////////////////////////////
221+// PARSING CODE
222+
223+static inline void node_alloc(node_buffer* b, int ask)
224+{
225+ int space = b->size - b->used_back - b->used_front;
226+ if (space >= ask) return;
227+ int size2 = (b->size + 1000 + ask) * 2;
228+ node* buf2 = malloc(size2 * sizeof(node));
229+ assert(buf2);
230+ memcpy(buf2, b->nodes, b->used_front * sizeof(node));
231+ memcpy(&buf2[size2 - b->used_back], &b->nodes[b->size - b->used_back], b->used_back * sizeof(node));
232+ free(b->alloc);
233+ b->size = size2;
234+ b->nodes = buf2;
235+ b->alloc = buf2;
236+}
237+
238+static inline void attr_alloc(attr_buffer* b, int ask)
239+{
240+ int space = b->size - b->used;
241+ if (space >= ask) return;
242+ int size2 = (b->size + 1000 + ask) * 2;
243+ attr* buf2 = malloc(size2 * sizeof(attr));
244+ assert(buf2);
245+ memcpy(buf2, b->attrs, b->used * sizeof(attr));
246+ free(b->alloc);
247+ b->size = size2;
248+ b->attrs = buf2;
249+ b->alloc = buf2;
250+}
251+
252+static void set_error(document* d, const char* msg)
253+{
254+ if (d->error_message != NULL) return; // keep the first error message
255+ d->error_message = malloc(strlen(msg)+1);
256+ assert(d->error_message);
257+ strcpy(d->error_message, msg);
258+}
259+
260+#define ARGUMENTS , document* d
261+#define VARIABLES const char *tag_start, *name_start, *name_end, *quote_start, *quote_end
262+
263+static inline str gap(const char* ref, const char* start, const char* end)
264+{
265+ return start_end(start - ref, end - ref);
266+}
7267
8268#define abort(x) return x
9−#define NameStart printf("NameStart %s\n", p)
10−#define NameEnd printf("NameEnd %s\n", p)
11−#define QuoteStart printf("QuoteStart %s\n", p)
12−#define QuoteEnd printf("QuoteEnd %s\n", p)
269+#define NameStart name_start = p
270+#define NameEnd name_end = p
271+#define QuoteStart quote_start = p
272+#define QuoteEnd \
273+ quote_end = p; \
274+ attr_alloc(&d->attrs, 1); \
275+ d->attrs.attrs[d->attrs.used].name = gap(d->body, name_start, name_end); \
276+ d->attrs.attrs[d->attrs.used].value = gap(d->body, quote_start, quote_end); \
277+ d->attrs.used++;
13278#define AttribsStart printf("AttribsStart %s\n", p)
14279#define AttribsEnd printf("AttribsEnd %s\n", p)
15−#define Tag printf("Tag %s\n", p)
16−#define hexml_Tag printf("Tag %s\n", p)
280+#define Tag tag_start = p
17281#define TagComment printf("TagComment %s\n", p)
18282#define TagOpen printf("TagOpen %s\n", p)
19283#define TagClose printf("TagClose %s\n", p)
20−#define TagOpenClose printf("TagOpenClose %s\n", p)
284+#define TagOpenClose \
285+ d->nodes.nodes[d->nodes.used_front].outer = gap(d->body, tag_start, p); \
286+ printf("TagOpenClose %s\n", p)
21287
22288#include "test.h"
23289
290+// Based on looking at ~50Kb XML documents, they seem to have ~700 attributes
291+// and ~300 nodes, so size appropriately to cope with that.
292+typedef struct
293+{
294+ document document;
295+ attr attrs[1000];
296+ node nodes[500];
297+} buffer;
298+
299+document* hexml_document_parse(const char* s, int slen)
300+{
301+ if (slen == -1) slen = (int) strlen(s);
302+ assert(s[slen] == 0);
303+ // init_parse_table();
304+
305+ buffer* buf = malloc(sizeof(buffer));
306+ assert(buf);
307+ document* d = &buf->document;
308+ d->body = s;
309+ d->cursor = s;
310+ d->end = &s[slen];
311+ d->error_message = NULL;
312+ d->attrs.size = 1000;
313+ d->attrs.used = 0;
314+ d->attrs.attrs = buf->attrs;
315+ d->attrs.alloc = NULL;
316+ d->nodes.size = 500;
317+ d->nodes.used_back = 0;
318+ d->nodes.used_front = 1;
319+ d->nodes.nodes = buf->nodes;
320+ d->nodes.alloc = NULL;
321+
322+ d->nodes.nodes[0].name = start_length(0, 0);
323+ d->nodes.nodes[0].outer = start_length(0, slen);
324+ d->nodes.nodes[0].inner = start_length(0, slen);
325+ d->nodes.nodes[0].attrs = start_length(0, 0);
326+
327+ // Introduce an intermediate result, otherwise behaviour is undefined
328+ // because there is no guaranteed ordering between LHS and RHS evaluation
329+ const char* res = parser(s, d);
330+ if (res != NULL)
331+ d->error_message = strdup(res);
332+ // d->nodes.nodes[0].nodes = content;
333+ return d;
334+}
335+
336+void main()
337+{
338+ const document* d = hexml_document_parse("<test foo='123 xyz'/>", -1);
339+ char buf[1000];
340+ int len = hexml_node_render(d, hexml_document_node(d), buf, sizeof(buf));
341+ buf[len] = 0;
342+ printf("Result = %s\n", buf);
343+}
24344
345+/*
25346void main()
26347{
27− const char* res = hexml_parser("<test foo='123 xyz'/>");
28− printf("Result %s\n", res);
348+ setbuf(stdout, NULL);
349+ char* body = "<?xml version=\"1.0\" lang=\"ja\"?><foo><bar baz=\"qux\">quux</bar><bar baz=\"bar\">hoge</bar><piyo>&gt;piyopiyo&lt;</piyo></foo><foo2 />";
350+ body = "<test>X</test> ";
351+ document* doc = document_parse(body, -1);
352+ char* err = document_error(doc);
353+ if (err == NULL)
354+ {
355+ int len = document_render(doc, NULL, 0);
356+ char* s = malloc(len + 1);
357+ document_render(doc, s, len);
358+ s[len] = 0;
359+ printf("Parse successful, %s\n", s);
360+ }
361+ else
362+ printf("Parse failed, %s\n", err);
29363}
364+*/