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);
}
}