import std.file; import std.stdio; char[][char[]] rules; void main(char[][] args) { //std.stdio.writefln("read %s", args[1]); char[] f = cast(char[])std.file.read(args[1]); char[] cond = ""; char[] rule = ""; int state = 0; //std.stdio.writefln("flen = %d", f.length); for(int p = 0 ; p < f.length; p++) { //std.stdio.writefln("got char %s", "" ~ f[p]); switch(f[p]) { case ':': state = 1; continue; case ';': if (state == 1) { //std.stdio.writefln("ADD RULE %s => %s", cond, rule); makerule(cond,rule); //rules[cond] = rule; } state = 0; cond = ""; rule = ""; continue; case '\n': if (state == 1) { rule ~= ' '; continue; } continue; case '/': if (f[p+1] == '*') { p+=2; while (p < f.length) { if (f[p] != '*') { p++; continue; } if (f[p+1] != '/') { p++; continue; } p+=2; break; } // got end of comment... } if (f[p+1] == '/') { p+=2; while (f[p] != '\n') { p++; } continue; } default: if ((state == 1) && (f[p] == '"')) { rule ~= f[p]; p++; while (f[p] != '"') { rule ~= f[p]; p++; } rule ~= '"'; continue; } if ((state == 1) && (f[p] == '\'')) { rule ~= f[p]; p++; while (f[p] != '\'') { rule ~= f[p]; p++; } rule ~= '\''; continue; } if (state == 0) { if (std.string.iswhite(f[p])) { continue; } cond ~= f[p]; continue; } rule ~= f[p]; continue; } } // dumpe the rules foreach(r,c; rules) { // std.stdio.writefln("RULE: %s => %s", r,c); } } class Rule { char type; // S=string, A=and following, O = Option list. char[] str = ""; Rule[] seq; this (char t, char[] s) { this.type = t; this.str = s; } char[] toString(int indent = 0) { char[] ret = ""; for (int i=0; i< indent; i++ ) { ret ~= " "; } ret ~= "RULE(" ~ this.type~ "): "; switch(type) { case 'C': return ret ~ "char: " ~ str ~"\n"; case 'R': return ret ~ "Range: " ~ str ~"\n"; case 'S': return ret ~ "string: " ~ str ~"\n"; case 'I': return ret ~ "ident: " ~ str~"\n"; default: ret ~= type ~ ":\n"; foreach(r ;seq) { ret ~= r.toString(indent+1); } } return ret; } void rationalize() { if (this.type == 'O') { if (seq.length == 1 && seq[0].type == 'A') { this.type = seq[0].type; this.seq = seq[0].seq; } } if (this.type == 'A') { if (seq.length == 1 && (seq[0].type == '*')) { this.type = seq[0].type; this.seq = seq[0].seq; return; // no more sub ents... } if (seq.length == 1 && (seq[0].type == '+')) { this.type = seq[0].type; this.seq = seq[0].seq; return; // no more sub ents... } if (seq.length == 1 && (seq[0].type == '?')) { this.type = seq[0].type; this.seq = seq[0].seq; return; // no more sub ents... } if (seq.length == 1 && (seq[0].type == 'I' || seq[0].type == 'S' || seq[0].type == 'C') ) { this.type = seq[0].type; this.str = seq[0].str; this.seq = null; return; // no more sub ents... } // do we have any '|' in our list.. bool haveOr = false; Rule[] newseqs; Rule newRule = new Rule('A', ""); foreach(s;seq) { if (s.type =='|') { haveOr = true; newseqs ~= newRule; newRule = new Rule('A',""); continue; } newRule.seq ~= s; } if (haveOr) { newseqs ~= newRule; this.seq = newseqs; this.type = 'O'; this.rationalize(); } } foreach(s; seq) { s.rationalize(); } } bool seqIsSimple() { if (this.type == '*') { return false; } if (this.type == '?') { return false; } if (this.type == '+') { return false; } foreach(s;seq) { if (s.type == 'I') { continue; } if (s.type == 'S') { continue; } if (s.type == 'C') { continue; } if (s.type == 'A') { if (!s.seqIsSimple()) { return false; } continue; } if (s.type == 'O') { if (!s.seqIsSimple()) { return false; } continue; } return false; } return true; } char[] toSource(bool addif=0) { char[] rstart = addif ? " if (" : ""; char[] rend = addif ? ") { return locret(); }" : ""; switch(this.type) { case 'I': return rstart ~ this.str ~ "()"~ rend; case 'S': return rstart ~ "parserIsString(" ~ this.str ~ ")" ~ rend; case 'C': return "parserIsChar(" ~ this.str ~ ")"~ rend; case 'O': // list of options... // results are different depending on if this is top level or not... char[] ret; if (seqIsSimple()) { ret ~= rstart ~ (seq.length > 1 ? "(" : ""); foreach(i,s;seq) { ret ~= i > 0 ? " \n\t\t|| " : ""; ret ~= s.toSource(); } ret ~= seq.length > 1 ? ")" : ""; return ret ~ rend; } /* foreach(i,s;seq) { switch(s.type) { case 'I','S','C': ret ~= "if (" ~ s.toSource() ~ ") { return locret(); }"; } } */ throw new Exception(toString()); // fixme !!! complex situations.. // fall through... case 'A': char[] ret; if ((addif==false) && (seq.length && seq[0].type == '=')) { // predecated condition.. - looks againe... ret = " if (!("; foreach(i,s;seq[0].seq) { ret ~= i > 0 ? " && " : ""; ret ~= s.toSource() ; } ret ~= ")) { parserSetPos(mark); return false;}\n"; ret ~= " if ("; for(int i=1 ; i < seq.length ;i++) { auto s = seq[i]; ret ~= i > 1 ? " && " : ""; ret ~= s.toSource() ; } ret ~= ") { return locret(); }\n"; ret ~= " parserSetPos(mark); return false;\n"; return ret; } if (seqIsSimple()) { ret ~= rstart ~ (seq.length > 1 ? "(" : ""); foreach(i,s;seq) { ret ~= i > 0 ? " && " : ""; ret ~= s.toSource() ; } ret ~= seq.length > 1 ? ")" : ""; return ret ~ rend; } throw new Exception(toString()); case '*': if (addif==false) { char[] ret = " while("; // same as 'A': ???? foreach(i,s;seq) { ret ~= i > 0 ? " && " : ""; ret ~= s.toSource() ; } ret ~= ") { }\n"; ret ~= " return true;"; // no clean up.! return ret; } throw new Exception(toString()); case '+': if (addif==false) { char[] ret = " bool match=false; while("; // same as 'A': ???? foreach(i,s;seq) { ret ~= i > 0 ? " && " : ""; ret ~= s.toSource() ; } ret ~= ") { match = true}\n"; ret ~= " return match ;"; // no clean up.! return ret; } throw new Exception(toString()); case '?': if (addif==false) { char[] ret = " if ("; foreach(i,s;seq) { ret ~= i > 0 ? " && " : ""; ret ~= s.toSource() ; } ret ~= ") { return locret(); }\n"; ret ~= " parserSetPos(mark); return true;\n"; return ret; } throw new Exception(toString()); /* // fixme !!! complex situations.. case '?': case '*': if (seqIsSimple()) { // same as 'A': ???? char[] ret = seq.length > 1 ? "(" : ""; foreach(i,s;seq) { ret ~= i > 0 ? " && " : ""; ret ~= s.toSource() ; } ret ~= seq.length > 1 ? ")" : ""; return ret; } return toString(); */ default : throw new Exception(toString()); } } } void makerule(char[] rule, char[] conds) { conds = std.string.replace(conds, "\n", " " ); writefln("// RULE: %s : %s", rule, conds); writefln("bool %s()\n{", rule); writefln(" int mark = parserGetPos();"); writefln(" bool locret() { /* call handler */ return true; }\n"); Rule top = new Rule('O', ""); int i=0; Rule parseRule() { //writefln("startrule %s", conds[i..length]); Rule activeRule = new Rule('A', ""); while (i < conds.length) { if (conds[i] == '\'') { char[] str = "\'"; i++; while (conds[i] != '\'') { str ~= conds[i]; i++; } str ~= "\'"; activeRule.seq ~= new Rule('C', str); i++; continue; } if (conds[i] == '"') { char[] str = "\""; i++; while (conds[i] != '"') { str ~= conds[i]; i++; } str ~= "\""; activeRule.seq ~= new Rule('S', str); i++; continue; } if (conds[i] == '|') { // return the rule.. i++; activeRule.seq ~= new Rule('|', ""); continue; } if (conds[i] == '.') { i++; i++; activeRule.seq ~= new Rule('R', ".."); continue; } if (conds[i] == ')') { i++; //writefln("<<"); return activeRule; } if (conds[i] == '(') { i++; //writefln("got ("); Rule newrule = parseRule(); //writefln("got newrule" ~ newrule.toString()); if (i == conds.length) { activeRule.seq ~= newrule; return activeRule; } if (conds[i] == '*') { newrule.type = '*'; activeRule.seq ~= newrule; i++; continue; } if (conds[i] == '?') { newrule.type = '?'; activeRule.seq ~= newrule; i++; continue; } if (conds[i] == '+') { newrule.type = '+'; activeRule.seq ~= newrule; i++; continue; } if (conds[i] == '=') { newrule.type = '='; activeRule.seq ~= newrule; i++; i++; continue; } newrule.type = '('; activeRule.seq ~= newrule; continue; } if (std.string.iswhite(conds[i])) { i++; continue; } char[] method =""; while (std.string.find(std.string.letters ~ '_' ~ std.string.digits , conds[i]) > -1) { method ~= conds[i]; i++; if (i == conds.length) { break; } } activeRule.seq ~= new Rule('I', method ); continue; } return activeRule; } int depth = 0; for(i=0; i < conds.length; i++) { top.seq ~= parseRule(); } top.rationalize(); //writefln("%s", top.toString(true)); if (top.seqIsSimple()) { writefln("%s", top.toSource(true)); writefln("\n parserSetPos(mark);"); writefln(" return false;"); } else { writefln("%s", top.toSource(false)); //writefln("%s", top.toString(true)); } writefln("}\n"); } /** translations (xxxx)? == eg. one or none of: (xxxx(opt)) ?? but will it be optimized??? (xxxx)? == eg. one or none of: */