root/trunk/dparser/convert.d

Revision 269, 12.0 kB (checked in by BCS, 8 months ago)

fixed a debug output issue
added a grammar fixer utility

Line 
1 import std.stdio;
2 import std.string;
3
4 import syntax.dparse;
5
6 class data : IParser
7 {
8     char[] dat;
9     uint i =0;
10     uint pos()      {return i;}
11     void pos(uint j){ i = j;}
12
13     void mark()
14     {
15         writef(">>\"%s\"\n", dat[i..($-i)>60? i+60: $]);
16     }
17 }
18
19
20
21 class GrammarParser
22 {
23
24     PObject Terminal(char[] str : "NAME")(IParser p)
25     {
26         debug(dParse_runtime) writef("in %s\n", str);
27         auto lex = cast(data) p;
28         assert(lex !is null);
29
30         int i = lex.i;
31
32         for({} i < lex.dat.length; i++)
33             switch(lex.dat[i])
34             {
35                 case ' ', '\t', '\n', '\r': continue;
36
37                 case 'a','b','c','d','e','f','g','h','i','j','k','l','m','n',
38                      'o','p','q','r','s','t','u','v','w','x','y','z',
39                      'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
40                      'O','P','Q','R','S','T','U','V','W','X','Y','Z',
41                      '_':
42                     goto more;
43
44                 default:
45                     debug(dParse_runtime) writef("fail at %s:%d with %x\n", str,__LINE__, lex.dat[i]);
46                     return new PObjectFail();
47             }
48
49         debug(dParse_runtime) writef("fail at %s:%d with EOF\n", str,__LINE__);
50         return new PObjectFail();
51
52         more:
53
54         int start = i;
55
56         i++;
57
58         for({} i < lex.dat.length; i++)
59             if(!(
60                 ('a' <= lex.dat[i] && lex.dat[i] <= 'z') ||
61                 ('A' <= lex.dat[i] && lex.dat[i] <= 'Z') ||
62                 ('0' <= lex.dat[i] && lex.dat[i] <= '9') ||
63                 (lex.dat[i] == '_')
64                 ))
65             break;
66
67         lex.i = i;
68
69         assert(i <= lex.dat.length);
70
71         return new PObjectBox!(char[])(lex.dat[start..i]);
72     }
73
74     PObject Terminal(char[] str : "COLLON")(IParser p)
75     {
76         debug(dParse_runtime) writef("in %s\n", str);
77         auto lex = cast(data) p;
78         assert(lex !is null);
79
80         foreach(int i, char c; lex.dat[lex.i..$])
81             switch(c)
82             {
83                 case ':':
84                     lex.i += 1+i;
85                     return new PObjectPass();
86
87                 case ' ', '\t', '\n', '\r':  continue;
88                 default:  return new PObjectFail();
89             }
90         return new PObjectFail();
91     }
92
93     PObject Terminal(char[] str : "STAR")(IParser p)
94     {
95         debug(dParse_runtime) writef("in %s\n", str);
96         auto lex = cast(data) p;
97         assert(lex !is null);
98
99         foreach(int i, char c; lex.dat[lex.i..$])
100             switch(c)
101             {
102                 case '*':
103                     lex.i += 1+i;
104                     return new PObjectPass();
105
106                 case ' ', '\t', '\n', '\r':  continue;
107                 default:  return new PObjectFail();
108             }
109         return new PObjectFail();
110     }
111
112     PObject Terminal(char[] str : "PLUS")(IParser p)
113     {
114         debug(dParse_runtime) writef("in %s\n", str);
115         auto lex = cast(data) p;
116         assert(lex !is null);
117
118         foreach(int i, char c; lex.dat[lex.i..$])
119             switch(c)
120             {
121                 case '+':
122                     lex.i += 1+i;
123                     return new PObjectPass();
124
125                 case ' ', '\t', '\n', '\r':  continue;
126                 default:  return new PObjectFail();
127             }
128         return new PObjectFail();
129     }
130
131     PObject Terminal(char[] str : "QMARK")(IParser p)
132     {
133         debug(dParse_runtime) writef("in %s\n", str);
134         auto lex = cast(data) p;
135         assert(lex !is null);
136
137         foreach(int i, char c; lex.dat[lex.i..$])
138             switch(c)
139             {
140                 case '?':
141                     lex.i += 1+i;
142                     return new PObjectPass();
143
144                 case ' ', '\t', '\n', '\r':  continue;
145                 default:  return new PObjectFail();
146             }
147         return new PObjectFail();
148     }
149
150     PObject Terminal(char[] str : "PIPE")(IParser p)
151     {
152         debug(dParse_runtime) writef("in %s\n", str);
153         auto lex = cast(data) p;
154         assert(lex !is null);
155
156         foreach(int i, char c; lex.dat[lex.i..$])
157         {
158             switch(c)
159             {
160                 case '|':
161                     lex.i += 1+i;
162                     return new PObjectPass();
163
164                 case ' ', '\t', '\n', '\r':  continue;
165                 default:  return new PObjectFail();
166             }
167         }
168         return new PObjectFail();
169     }
170
171     PObject Terminal(char[] str : "SEMICOLLON")(IParser p)
172     {
173         debug(dParse_runtime) writef("in %s\n", str);
174         auto lex = cast(data) p;
175         assert(lex !is null);
176
177         foreach(int i, char c; lex.dat[lex.i..$])
178         {
179             switch(c)
180             {
181                 case ';':
182                     lex.i += 1+i;
183                     return new PObjectPass();
184
185                 case ' ', '\t', '\n', '\r':  continue;
186                 default:  return new PObjectFail();
187             }
188         }
189         return new PObjectFail();
190     }
191
192     PObject Terminal(char[] str : "SLASH")(IParser p)
193     {
194         debug(dParse_runtime) writef("in %s\n", str);
195         auto lex = cast(data) p;
196         assert(lex !is null);
197
198         foreach(int i, char c; lex.dat[lex.i..$])
199             switch(c)
200             {
201                 case '/':
202                     lex.i += 1+i;
203                     return new PObjectPass();
204
205                 case ' ', '\t', '\n', '\r':  continue;
206                 default:  return new PObjectFail();
207             }
208         return new PObjectFail();
209     }
210
211     template Terminal(char[] str ) { PObject Terminal(IParser i); pragma(msg, "<need type=ter>"~str~"</need>"); }
212     template Action(char[]str) { PObject Action(PObject[] p); pragma(msg, "<need type=act>"~str~"</need>"); }
213
214     PObject Action(char[]s:"pass1")(PObject[1]p){return p[0];}
215     PObject Action(char[]s:"pass2nd")(PObject[2]p){return p[1];}
216
217     PObject Action(char[]s:"formRule")(PObject[5]p)
218     {
219         // NAME COLLON Option ElseOption* SEMICOLLON
220         auto name = cast(PObjectBox!(char[])) p[0];
221         auto first = cast(PObjectBox!(Opt)) p[2];
222         auto rest = cast(PObjectSet) p[3];
223         assert(name !is null, p[0].BaseName ~" != " ~ typeof(name).stringof);
224         assert(first !is null, p[2].BaseName ~" != " ~ typeof(first).stringof);
225         assert(rest !is null, p[3].BaseName ~" != " ~ typeof(rest).stringof);
226
227         GRule ret;
228         ret.name = name.Get;
229
230         ret.opts.length = 1 + rest.Count();
231
232         ret.opts[0] = first.Get;
233         foreach(int i, po; rest.get)
234         {
235             auto box = cast(PObjectBox!(Opt))po;
236             assert(box !is null);
237             ret.opts[i+1] = box.Get;
238         }
239
240         return new PObjectBox!(GRule)(ret);
241     }
242
243     PObject Action(char[]s:"formOpt")(PObject[3]p)
244     {
245         // NAME SLASH Parts*
246         auto name = cast(PObjectBox!(char[])) p[0];
247         auto rest = cast(PObjectSet) p[2];
248
249         Opt ret;
250         ret.name = name.Get;
251
252         ret.parts.length = rest.Count();
253         foreach(int i, po; rest.get)
254         {
255             auto box = cast(PObjectBox!(Part))po;
256             assert(box !is null);
257             ret.parts[i] = box.Get;
258         }
259
260         return new PObjectBox!(Opt)(ret);
261     }
262
263     PObject Action(char[]s:"any")(PObject[2]p)
264     {
265         auto name = cast(PObjectBox!(char[])) p[0];
266
267         Part ret;
268
269         ret.name = name.Get;
270         ret.type = Part.Type.any;
271
272         return new PObjectBox!(Part)(ret);
273     }
274
275     PObject Action(char[]s:"many")(PObject[2]p)
276     {
277         auto name = cast(PObjectBox!(char[])) p[0];
278
279         Part ret;
280
281         ret.name = name.Get;
282         ret.type = Part.Type.many;
283
284         return new PObjectBox!(Part)(ret);
285     }
286
287     PObject Action(char[]s:"maybe")(PObject[2]p)
288     {
289         auto name = cast(PObjectBox!(char[])) p[0];
290
291         Part ret;
292
293         ret.name = name.Get;
294         ret.type = Part.Type.maybe;
295
296         return new PObjectBox!(Part)(ret);
297     }
298
299     PObject Action(char[]s:"one")(PObject[1]p)
300     {
301         auto name = cast(PObjectBox!(char[])) p[0];
302
303         Part ret;
304
305         ret.name = name.Get;
306         ret.type = Part.Type.one;
307
308         return new PObjectBox!(Part)(ret);
309     }
310
311     static const char[] gram =
312     "
313     Gram : pass1 / Rule+ ;
314     Rule : formRule / NAME COLLON Option ElseOption* RuleEnd ;
315     RuleEnd :
316         pass1 / PIPE |
317         pass1 / SEMICOLLON;
318     Option : formOpt / NAME SLASH Parts*;
319     ElseOption : pass2nd / PIPE Option ;
320     Parts:
321         any / NAME STAR |
322         many / NAME PLUS |
323         maybe / NAME QMARK |
324         one / NAME;
325     ";
326     static const char[] mix = MakeMixin!("Gram",ReduceWhite(gram));
327     //pragma(msg,mix);
328     mixin(mix);
329 }
330
331 struct GRule
332 {
333     char[] name;
334     Opt[] opts;
335
336     char[] toString()
337     {
338         char[] ret = "";
339
340 //      writef("%s > %d\n", name, opts.length);
341
342         foreach(Opt p; opts)
343             ret ~= p.toString ~ " |\n";
344
345 //      writef("--%s==\n\n", ret);
346
347         return  name ~ " : \n" ~ ret[0..$-3] ~ " ;\n\n";
348     }
349 }
350
351 struct Opt
352 {
353     char[] name;
354     Part[] parts;
355
356     char[] toString()
357     {
358         char[] ret = "";
359
360         foreach(Part p; parts)
361             ret ~= p.toString ~ " ";
362
363         return \t ~ name ~ " / " ~ ret;
364     }
365 }
366
367 struct Part
368 {
369     char[] name;
370     enum Type { any=0, many=1, maybe=2, one=3 }
371     Type type;
372
373     char[] toString() { return name ~ "*+? "[type]; }
374 }
375
376 import std.file;
377 import std.cstream;
378
379 void main(char[][] argv)
380 {
381     bool
382         printOrg = false,
383         ConvertRec = false,
384         TestRec = false,
385         DmpFinal = true;
386
387     char[] filename = "";
388
389     foreach(arg;argv[1..$])
390         if(arg.length >= 2)
391             switch(arg[0..2])
392             {
393                 case "-o": printOrg   = (arg[2..$] != "-"); break;
394                 case "-c": ConvertRec = (arg[2..$] != "-"); break;
395                 case "-t": TestRec    = (arg[2..$] != "-"); break;
396                 case "-f": DmpFinal   = (arg[2..$] != "-"); break;
397                 default: filename = arg; break;
398             }
399         else
400             {filename = arg;}
401
402     data d = new data;
403
404     if(filename != "")
405         d.dat = ReduceWhite(cast(char[])std.file.read(filename));
406     else
407     {
408         //d.dat = ReduceWhite(GrammarParser.gram.dup);
409         //d.dat = ReduceWhite("AttributeSpecifier: dummy / Attribute  opCollin  | dummy / Attribute DeclarationBlock | ;".dup);
410         //d.dat = "Foo: A1 / Foo B | A2 / Foo C D | A3 / Foo E | A4 / F | A5 / G H ;".dup;
411         assert(false, "no file");
412     }
413
414     GrammarParser gp = new GrammarParser;
415
416     auto g = gp.Parser(d);
417     assert(g !is null);
418     assert(!g.fail);
419
420     GRule[] inp;
421     GRule[] outp;
422
423
424     auto parsed = (cast(PObjectSet)g).get;
425     inp.length = parsed.length;
426
427     //writef("Parsing returned: %s\n", g.BaseName);
428     foreach(ind, r;parsed)
429     {
430         //writef("  Object #%d is: %s\n", ind, r.BaseName);
431         inp[ind] = (cast(PObjectBox!(GRule ))r).Get;
432     }
433
434     if(printOrg)
435     {
436         foreach(r; inp) writef(">>%s", r.toString);
437     }
438
439     bool b;
440     if(ConvertRec)
441         do
442         {
443             b = false;
444            
445             b |= Convert2(inp);
446
447             int index = 0;
448
449             foreach(r; inp) b |= Convert(r, outp, index);
450
451             inp = outp[0..index];
452         } while(b)
453
454     if(TestRec)
455     {
456         GRule*[char[]] rules;
457         int[GRule*] state;
458         foreach(inout r; inp)
459         {
460             rules[r.name] = &r;
461             state[&r] = 0;
462         }
463
464         bool newc = true;
465
466         char[] breaker;
467
468         int Walk(GRule* r)
469         {
470             int max = state[r];
471
472             if(max != 0) return max;
473            
474             state[r] = -1;
475
476             foreach(o; r.opts)
477             {
478                 GRule* first;
479                 //derr.writef("%s\n", o.toString);
480                 assert(o.parts.length > 0, r.name~":"~o.name~" has no parts");
481                 if(auto s = o.parts[0].name in rules)
482                     first = *s;
483                 else
484                     continue;
485
486                 int step = Walk(rules[first.name]);
487
488                 if(step == -1)
489                 {
490                     newc = false;
491                     if(breaker == null)
492                         breaker = first.name;
493
494                     writef("%s<-", first.name);
495
496                     if(breaker == r.name)
497                     {
498                         breaker= null;
499                         writef("%s\n", r.name);
500                         continue;
501                     }
502                     return -1;
503                 }
504
505                 max = max > step ? max : step;
506             }
507
508             max++;
509             state[r] = max;
510             return max;
511         }
512
513         int max = 0;
514         foreach(inout r; inp)
515         {
516             int step = Walk(&r);
517             max = max > step ? max : step;
518         }
519
520         if(!newc)
521         {
522             writef("\nfound cycle\n\n");
523             return;
524         }
525     }
526
527     if(DmpFinal)
528     {
529         foreach(r; inp) writef("%s", r.toString);
530     }
531 }
532
533 bool Convert(inout GRule gr, inout GRule[] outp, inout int index)
534 {
535     foreach(Opt o; gr.opts)
536         if(o.parts.length > 0 && o.parts[0].name == gr.name)
537             goto patch;
538
539     if(outp.length <= index)
540         outp.length = outp.length + 10;
541
542     outp[index] = gr;
543     index++;
544
545     return false;
546
547     patch:
548
549     GRule first, rest;
550     rest.name = "__LRT_"~gr.name;
551     first.name = gr.name;
552
553     Part p;
554     p.name = rest.name;
555     p.type = Part.Type.any;
556
557     Opt n;
558
559     foreach(Opt o; gr.opts)
560     {
561         //writef("%s\n", o.name);
562         if(o.parts.length > 0 && o.parts[0].name == gr.name)
563         {   // recusive
564             n.name = format("$(L,%d,%s)",o.parts.length-1,o.name);
565             n.parts = o.parts[1..$];
566             rest.opts ~= n;
567         }
568         else
569         {   // non recursive
570             n.name = format("$(T,%d,%s)",o.parts.length,o.name);
571