import std.stdio; import syntax.dparse; class data : IParser { char[] dat; uint i =0; uint pos() {return i;} void pos(uint j){ i = j;} void mark() { writef(">>\"%s\"\n", dat[i..($-i)>20? i+20: $]); } } struct GrammarParser { PObject Terminal(char[] str : "NAME")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); int i = lex.i; for({} i < lex.dat.length; i++) switch(lex.dat[i]) { case ' ', '\t', '\n', '\r': continue; case 'a','b','c','d','e','f','g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N', 'O','P','Q','R','S','T','U','V','W','X','Y','Z', '_': goto more; default: debug(dParse_runtime) writef("fail at %s:%d with %x\n", str,__LINE__, lex.dat[i]); return new PObjectFail(); } debug(dParse_runtime) writef("fail at %s:%d with EOF\n", str,__LINE__); return new PObjectFail(); more: int start = i; i++; for({} i < lex.dat.length; i++) if(!( ('a' <= lex.dat[i] && lex.dat[i] <= 'z') || ('A' <= lex.dat[i] && lex.dat[i] <= 'Z') || ('0' <= lex.dat[i] && lex.dat[i] <= '9') || (lex.dat[i] == '_') )) break; lex.i = i; assert(i <= lex.dat.length); return new PObjectBox!(char[])(lex.dat[start..i]); } PObject Terminal(char[] str : "COLLON")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); foreach(int i, char c; lex.dat[lex.i..$]) switch(c) { case ':': lex.i += 1+i; return new PObjectPass(); case ' ', '\t', '\n', '\r': continue; default: return new PObjectFail(); } return new PObjectFail(); } PObject Terminal(char[] str : "STAR")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); foreach(int i, char c; lex.dat[lex.i..$]) switch(c) { case '*': lex.i += 1+i; return new PObjectPass(); case ' ', '\t', '\n', '\r': continue; default: return new PObjectFail(); } return new PObjectFail(); } PObject Terminal(char[] str : "PLUS")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); foreach(int i, char c; lex.dat[lex.i..$]) switch(c) { case '+': lex.i += 1+i; return new PObjectPass(); case ' ', '\t', '\n', '\r': continue; default: return new PObjectFail(); } return new PObjectFail(); } PObject Terminal(char[] str : "QMARK")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); foreach(int i, char c; lex.dat[lex.i..$]) switch(c) { case '?': lex.i += 1+i; return new PObjectPass(); case ' ', '\t', '\n', '\r': continue; default: return new PObjectFail(); } return new PObjectFail(); } PObject Terminal(char[] str : "PIPE")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); foreach(int i, char c; lex.dat[lex.i..$]) { switch(c) { case '|': lex.i += 1+i; return new PObjectPass(); case ' ', '\t', '\n', '\r': continue; default: return new PObjectFail(); } } return new PObjectFail(); } PObject Terminal(char[] str : "SEMICOLLON")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); foreach(int i, char c; lex.dat[lex.i..$]) { switch(c) { case ';': lex.i += 1+i; return new PObjectPass(); case ' ', '\t', '\n', '\r': continue; default: return new PObjectFail(); } } return new PObjectFail(); } PObject Terminal(char[] str : "SLASH")(IParser p) { debug(dParse_runtime) writef("in %s\n", str); auto lex = cast(data) p; assert(lex !is null); foreach(int i, char c; lex.dat[lex.i..$]) switch(c) { case '/': lex.i += 1+i; return new PObjectPass(); case ' ', '\t', '\n', '\r': continue; default: return new PObjectFail(); } return new PObjectFail(); } template Terminal(char[] str ) { PObject Terminal(IParser i); pragma(msg, ""~str~""); } template Action(char[]str) { PObject Action(PObject[] p); pragma(msg, ""~str~""); } PObject Action(char[]s:"pass1")(PObject[1]p){return p[0];} PObject Action(char[]s:"pass2nd")(PObject[2]p){return p[1];} PObject Action(char[]s:"formRule")(PObject[5]p) { // NAME COLLON Option ElseOption* SEMICOLLON auto name = cast(PObjectBox!(char[])) p[0]; auto first = cast(PObjectBox!(Opt)) p[2]; auto rest = cast(PObjectSet) p[3]; assert(name !is null, p[0].BaseName ~" != " ~ typeof(name).stringof); assert(first !is null, p[2].BaseName ~" != " ~ typeof(first).stringof); assert(rest !is null, p[3].BaseName ~" != " ~ typeof(rest).stringof); GRule ret; ret.name = name.Get; ret.opts.length = 1 + rest.Count(); ret.opts[0] = first.Get; foreach(int i, po; rest.get) { auto box = cast(PObjectBox!(Opt))po; assert(box !is null); ret.opts[i+1] = box.Get; } return new PObjectBox!(GRule)(ret); } PObject Action(char[]s:"formOpt")(PObject[3]p) { // NAME SLASH Parts* auto name = cast(PObjectBox!(char[])) p[0]; auto rest = cast(PObjectSet) p[2]; Opt ret; ret.name = name.Get; ret.parts.length = rest.Count(); foreach(int i, po; rest.get) { auto box = cast(PObjectBox!(Part))po; assert(box !is null); ret.parts[i] = box.Get; } return new PObjectBox!(Opt)(ret); } PObject Action(char[]s:"any")(PObject[2]p) { auto name = cast(PObjectBox!(char[])) p[0]; Part ret; ret.name = name.Get; ret.type = Part.Type.any; return new PObjectBox!(Part)(ret); } PObject Action(char[]s:"many")(PObject[2]p) { auto name = cast(PObjectBox!(char[])) p[0]; Part ret; ret.name = name.Get; ret.type = Part.Type.many; return new PObjectBox!(Part)(ret); } PObject Action(char[]s:"maybe")(PObject[2]p) { auto name = cast(PObjectBox!(char[])) p[0]; Part ret; ret.name = name.Get; ret.type = Part.Type.maybe; return new PObjectBox!(Part)(ret); } PObject Action(char[]s:"one")(PObject[1]p) { auto name = cast(PObjectBox!(char[])) p[0]; Part ret; ret.name = name.Get; ret.type = Part.Type.one; return new PObjectBox!(Part)(ret); } static const char[] gram = " Gram : pass1 / Rule+ ; Rule : formRule / NAME COLLON Option ElseOption* SEMICOLLON ; Option : formOpt / NAME SLASH Parts*; ElseOption : pass2nd / PIPE Option ; Parts: any / NAME STAR | many / NAME PLUS | maybe / NAME QMARK | one / NAME; "; static const char[] mix = MakeMixin!("Gram",ReduceWhite(gram)); // pragma(msg,mix); mixin(mix); } struct GRule { char[] name; Opt[] opts; char[] toString() { char[] ret = ""; foreach(Opt p; opts) ret ~= p.toString ~ " |\n"; return name ~ " : \n" ~ ret[0..$-3] ~ " ;\n\n"; } } struct Opt { char[] name; Part[] parts; char[] toString() { char[] ret = ""; foreach(Part p; parts) ret ~= p.toString ~ " "; return name ~ " / " ~ ret; } } struct Part { char[] name; enum Type { any=0, many=1, maybe=2, one=3 } Type type; char[] toString() { return name ~ "*+? "[type]; } } void main() { data d = new data;; // d.dat = ReduceWhite(GrammarParser.gram.dup); d.dat = ReduceWhite("song: bill / jonny be good | bob / hello+ world ; ".dup); GrammarParser gp; auto g = gp.Parser(d); assert(g !is null); assert(!g.fail); writef("Parsing returned: %s\n", g.BaseName); foreach(ind, r;(cast(PObjectSet)g).get) { writef(" Object #%d is: %s\n", ind, r.BaseName); writef("%s\n\n", (cast(PObjectBox!(GRule ))r).Get.toString); } }