Index: /trunk/FACT++/src/rootifysql.cc
===================================================================
--- /trunk/FACT++/src/rootifysql.cc	(revision 19091)
+++ /trunk/FACT++/src/rootifysql.cc	(revision 19092)
@@ -103,4 +103,146 @@
 }
 
+struct ExplainParser
+{
+    string sql;
+
+    vector<string> vec;
+
+    string substitute(string _str, const regex &expr)
+    {
+        smatch match;
+        while (regex_search(_str, match, expr, regex_constants::format_first_only))
+        {
+            const auto &len = match.length(0);
+            const auto &pos = match.position(0);
+            const auto &str = match.str(0);
+
+            const auto it = find(vec.cbegin(), vec.cend(), str);
+            const size_t id = it==vec.cend() ? vec.size() : it-vec.cbegin();
+
+            _str.replace(pos, len, "{"+to_string(id)+"}");
+
+            if (it==vec.cend())
+                vec.push_back(str);//.substr(1, str.size()-2));
+        }
+
+        return _str;
+    }
+
+    string substitute(const string &str, const string &expr)
+    {
+        return substitute(str, regex(expr));
+    }
+
+    vector<string> queries;
+
+    string backsubstitute(const size_t &_idx,const size_t &indent)
+    {
+        string str = vec[_idx];
+
+        regex reg0("\\/\\*\\ select\\#[0-9]+\\ \\*\\/\\ select\\ ");
+
+        smatch match;
+        if (regex_search(str, match, reg0))
+        {
+            if (match.position(0)<2)
+            {
+                // substitute all expressions (blah AS blah)
+                str = substitute(str, "([0-9]+|\\{[0-9]+\\})\\ AS\\ \\{[0-9]+\\}");
+
+                if (str[match.position(0)-1]=='(')
+                    cout << '(' << endl;
+
+                keywords(str.substr(match.position(0)), indent+4);
+
+                if (str[match.position(0)-1]=='(')
+                    cout << setw(indent+1) << ')' << endl;
+
+                return "";//"("+to_string(_idx)+")";
+            }
+        }
+
+
+        // search for "KEYWORD expression"
+        regex reg1("\\{[0-9]+\\}");
+
+        //smatch match;
+        while (regex_search(str, match, reg1, regex_constants::format_first_only))
+        {
+            const auto &len = match.length(0);
+            const auto &pos = match.position(0);
+            const auto &arg = match.str(0);      // Argument
+
+            const auto idx = atoi(arg.c_str()+1);
+
+            str.replace(pos, len, backsubstitute(idx, indent));
+        }
+
+        return str;
+    }
+
+    void keywords(string str, const size_t &indent=0)
+    {
+        // search for "KEYWORD expression"
+        regex reg("(\\/\\*\\ [a-z]+\\#[0-9]+\\ \\*\\/)?\\ ([a-z ]+)\\ (\\{[0-9]+\\}([, ]\\{[0-9]+\\})*)?");
+
+        smatch match;
+        while (regex_search(str, match, reg))
+        {
+            //const auto &len = match.length(0);
+            //const auto &pos = match.position(0);
+            const auto &com = match.str(1);      // Comment
+            const auto &tok = match.str(2);      // Token
+            const auto &arg = match.str(3);      // Argument
+
+            if (!com.empty())
+                cout << setw(indent) << ' ' << "\033[34m" << com << "\033[0m" << '\n';
+
+            cout << setw(indent) << ' ' << "\033[33m" << tok << "\033[0m" << '\n';
+            //cout << "   " << arg << '\n';
+
+            vector<string> exprs;
+            boost::split(exprs, arg, boost::is_any_of(", "));
+            for (auto &expr : exprs)
+            {
+                if (expr.empty())
+                    continue;
+
+                const auto idx = atoi(expr.c_str()+1);
+
+                cout << setw(indent+4) << ' ' << backsubstitute(idx, indent+4) << (tok=="select"?',':' ') << endl;
+            }
+
+            str = str.substr(match.position(0)+match.length(0));
+        }
+
+    }
+
+
+    ExplainParser(const string &_sql) : sql(_sql)
+    {
+        // substitute all strings
+        sql = substitute(sql, "'[^']*'");
+
+        // substitute all escaped sequences
+        sql = substitute(sql, "`[^`]*`");
+
+        // substitute all paranthesis
+        sql = substitute(sql, "\\([^\\(\\)]*\\)");
+
+        // substitute all names (xxx.yyy.zzz)
+        sql = substitute(sql, "\\{[0-9]+\\}(\\.\\{[0-9]+\\})+");
+
+        // substitute all expressions (blah AS blah)
+        sql = substitute(sql, "([0-9]+|\\{[0-9]+\\}) AS\\ \\{[0-9]+\\}");
+
+        sql = regex_replace(sql, regex("\\ on\\{"), " on {");
+
+        keywords(sql);
+
+        cout << endl;
+    }
+};
+
 void print(string sql)
 {
@@ -111,164 +253,26 @@
 void format(string sql)
 {
-    regex reg1("`[^`]*`");
-
-    vector<string> vec;
-
-    cout << "[" << endl;
-    smatch match;
-    while (regex_search(sql, match, reg1, regex_constants::format_first_only))
-    {
-        const auto &len = match.length(0);
-        const auto &pos = match.position(0);
-        const auto &str = match.str(0);
-
-
-        const auto it = find(vec.cbegin(), vec.cend(), str);
-        const size_t id = it==vec.cend() ? vec.size() : it-vec.cbegin();
-
-        sql.replace(pos, len, "{"+to_string(id)+"}");
-
-        if (it==vec.cend())
-        {
-            cout << match.size() << "|";
-            cout << id << "|" << len << "|" << pos << "|" << str << endl;
-
-            vec.push_back(str);//.substr(1, str.size()-2));
-        }
-    }
-
-
-    cout << "]" << endl;
-
-    cout << endl << sql << endl;
-
-
-    regex reg2("\\([^\\(\\)]*\\)");
-
-    cout << "[" << endl;
-    while (regex_search(sql, match, reg2, regex_constants::format_first_only))
-    {
-        const auto &len = match.length(0);
-        const auto &pos = match.position(0);
-        const auto &str = match.str(0);
-
-        const auto it = find(vec.cbegin(), vec.cend(), str);
-        const size_t id = it==vec.cend() ? vec.size() : it-vec.cbegin();
-
-        sql.replace(pos, len, "{"+to_string(id)+"}");
-
-        if (it==vec.cend())
-        {
-            cout << match.size() << "|";
-            cout << id << "|" << len << "|" << pos << "|" << str << endl;
-
-            vec.push_back(str);//.substr(1, str.size()-2));
-        }
-    }
-
-    cout << "]" << endl;
-
-    cout << endl << sql << endl;
-
-
-    regex reg3a("\\{[0-9]+\\}(\\.\\{[0-9]+\\})+");
-
-    cout << "[" << endl;
-    while (regex_search(sql, match, reg3a, regex_constants::format_first_only))
-    {
-        const auto &len = match.length(0);
-        const auto &pos = match.position(0);
-        const auto &str = match.str(0);
-
-        const auto it = find(vec.cbegin(), vec.cend(), str);
-        const size_t id = it==vec.cend() ? vec.size() : it-vec.cbegin();
-
-        sql.replace(pos, len, "{"+to_string(id)+"}");
-
-        if (it==vec.cend())
-        {
-            cout << match.size() << "|";
-            cout << id << "|" << len << "|" << pos << "|" << str << endl;
-
-            vec.push_back(str);//.substr(1, str.size()-2));
-        }
-    }
-
-    cout << "]" << endl;
-
-    cout << endl << sql << endl;
-
-
-    regex reg3("\\{[0-9]+\\}+\\ AS\\ \\{[0-9]+\\}");
-
-    cout << "[" << endl;
-    while (regex_search(sql, match, reg3, regex_constants::format_first_only))
-    {
-        const auto &len = match.length(0);
-        const auto &pos = match.position(0);
-        const auto &str = match.str(0);
-
-        const auto it = find(vec.cbegin(), vec.cend(), str);
-        const size_t id = it==vec.cend() ? vec.size() : it-vec.cbegin();
-
-        sql.replace(pos, len, "{"+to_string(id)+"}");
-
-        if (it==vec.cend())
-        {
-            cout << match.size() << "|";
-            cout << id << "|" << len << "|" << pos << "|" << str << endl;
-
-            vec.push_back(str);//.substr(1, str.size()-2));
-        }
-    }
-
-    cout << "]" << endl;
-
-    cout << endl << sql << endl;
-
-    regex reg4("(\\/\\*\\ [a-z]+\\#[0-9]+\\ \\*\\/)?\\ ([a-z ]+)\\ (\\{[0-9]+\\}(,\\{[0-9]+\\})*)");
-
-    while (regex_search(sql, match, reg4))
-    {
-        //const auto &len = match.length(0);
-        //const auto &pos = match.position(0);
-        const auto &com = match.str(1);      // Comment
-        const auto &tok = match.str(2);      // Token
-        const auto &arg = match.str(3);      // Argument
-
-        if (!com.empty())
-            cout << '\n' << com << '\n';
-
-        cout << tok << '\n';
-        //cout << "   " << arg << '\n';
-
-        vector<string> exprs;
-        boost::split(exprs, arg, boost::is_any_of(","));
-        for (auto &expr : exprs)
-            cout << "   " << expr << " | " << vec[atoi(expr.c_str()+1)] << "," << endl;
-
-        sql = sql.substr(match.position(0)+match.length(0));
-    }
-
-    cout << endl;
-
-
-     /*
-
-    regex reg5("\\{[0-9]+\\}");
-
-    cout << "SELECT\n";
-
-    const string select = match.str(0);
-
-    vector<string> exprs;
-    boost::split(exprs, select, boost::is_any_of(","));
-    for (auto &expr : exprs)
-        cout << "   " << expr << " | " << vec[atoi(expr.c_str()+1)] << "," << endl;
-    }
-
-    */
-
-/*
+    ExplainParser p(sql);
+
+    // (COMMENT)?(TOKEN\\ *|,\\ *|\\ *)?expr[ ]*
+
+    // TOKEN = [:alnum: _]
+    // expr  = {[0-9]+}
+    // Special case "expr AS expr"
+    // Special case "expr AND expr"
+
+    /*
+     COMMENT
+     TOKEN
+        expr AS expr,
+        expr AS expr,
+        expr
+     TOKEN
+        expr
+     TOKEN
+        expr AND expr
+     */
+
+    /*
 
     SELECT
