Translation.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002     This file is part of PHP-AST Project by Romain Gaucher (http://rgaucher.info).
00003 
00004     PHP-AST is free software: you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation, either version 3 of the License, or
00007     (at your option) any later version.
00008 
00009     PHP-AST/ORACLE is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with PHP-AST.  If not, see <http://www.gnu.org/licenses/>.
00016 ------------------------------------------------------------------------------*/
00017 
00018 #include "AstNode.h"
00019 #include "tree.h"
00020 #include "AstContainer.h"
00021 #include "Translation.h"
00022 #include <vector>
00023 #include <list>
00024 #include <string>
00025 #include <map>
00026 #include <fstream>
00027 using namespace std;
00028 
00029 
00030 list<string> classVarNames;
00031 
00032 
00033 #define CPPHEADERSIZE 2
00034 const string cppheader[CPPHEADERSIZE] = {
00035     "#include <iostream>\n",
00036     "#include \"libphp.h\"\n\n"
00037 };
00038 
00039 
00040 string cppBufferize(const string& __in) {
00041     string buf = "";
00042 
00043     return buf;
00044 }
00045 
00046 string indent(unsigned nbIndent) {
00047     string r = "";
00048     for (unsigned i=0;i<nbIndent;i++)
00049         r += '\t';
00050     return r;
00051 }
00052 
00053 /*
00054 
00055     chars = "{}"
00056     for l in r:
00057         if len(l) == 0 or l == "\n":
00058             string += " "
00059         elif l in chars:
00060             string += l
00061             if l == "}": indent -= 1
00062             formated.append((indent,string))
00063             if l == "{": indent += 1
00064             string = ""
00065         else:
00066             string += l
00067             if l == ';' and 'for' not in string:
00068                 formated.append((indent,string))
00069                 string = ""
00070 
00071 */
00072 
00073 void StringBuffer::format() {
00074     string out="";
00075     string temp="";
00076     unsigned nind = 0;
00077     for (std::string::const_iterator iter=buffer.begin();iter!=buffer.end();++iter)
00078     {
00079         const char c = *iter;
00080         if (c == '\n') {
00081             continue;
00082         }
00083         else if (c == '{' || c == '}') {
00084             temp += c;
00085             if (c == '}') nind--;
00086             out += (indent(nind) + temp + "\n");
00087             if (c == '{') nind++;
00088             temp = "";
00089         }
00090         else {
00091             temp += c;
00092             if (c == ';') {
00093                 out += (indent(nind) + temp + "\n");
00094                 temp = "";
00095             }
00096         }
00097     }
00098     buffer = out;
00099 
00100 }
00101 
00102 
00103 void StringBuffer::write(const std::string& fname) {
00104     ofstream out(fname.c_str());
00105     out << buffer;
00106     out.close();
00107 }
00108 
00109 
00110 std::ostream& operator<<(std::ostream& stream, const StringBuffer& b) {
00111     stream << b.buffer << std::endl;
00112     return stream;
00113 }
00114 
00115 
00116 string varname(const string& phpname, bool correctQuote = false) {
00117     string name;
00118     for (string::const_iterator i=phpname.begin();i!=phpname.end();++i) {
00119         if (*i == '$')
00120             continue;
00121         else if (correctQuote and *i == '\'')
00122             name += '"';
00123         else
00124             name += *i;
00125     }
00126     return name;
00127 }
00128 
00129 
00130 
00131 string getNodeValue(const tree<AstNode>::iterator& start, const string& type, const tree<AstNode>& tr)
00132 {
00133     for (tree<AstNode>::iterator iter=tr.begin(start);iter!=tr.end(start);++iter) {
00134         if (iter->getType() == type) {
00135             for (;iter->getType() != "text" && iter!=tr.end(start);++iter)
00136                 ;
00137             if (iter->getType() == "text")
00138                 return iter->getValue();
00139             else
00140                 return string();
00141         }
00142     }
00143     return string();
00144 }
00145 
00146 tree<AstNode>::iterator getNodeIter(const tree<AstNode>::iterator& start, const string& type, const tree<AstNode>& tr)
00147 {
00148     for (tree<AstNode>::iterator iter=tr.begin(start);iter!=tr.end(start);++iter) {
00149         if (iter->getType() == type)
00150             return iter;
00151     }
00152     return tr.end();
00153 }
00154 
00155 bool functionReturnValue(const tree<AstNode>::iterator& start, const tree<AstNode>& tr)
00156 {
00157     for (tree<AstNode>::iterator iter=tr.begin(start);iter!=tr.end(start);++iter) {
00158         if (iter->getType() == "T_RETURN") {
00159             tree<AstNode>::iterator p = tr.parent(iter);
00160             if (tr.number_of_children(p) > 2)
00161                 return true;
00162         }
00163     }
00164     return false;
00165 }
00166 
00167 bool isAChildrenOf(const tree<AstNode>::iterator& start, const string& type, const tree<AstNode>& tr)
00168 {
00169     unsigned nC = tr.number_of_children(start);
00170     if (nC > 0) {
00171         for (unsigned i=0;i<nC;i++) {
00172             if (tr.child(start, i)->getType() == type)
00173                 return true;
00174         }
00175     }
00176     return false;
00177 }
00178 
00179 bool classAssignement(const tree<AstNode>::iterator& start, const tree<AstNode>& t) {
00180     for (tree<AstNode>::iterator iter=t.begin(start);iter!=t.end(start);++iter) {
00181         if (iter->getType() == "T_NEW") {
00182             return true;
00183         }
00184     }
00185     return false;
00186 }
00187 
00188 string className(const tree<AstNode>::iterator& start, const tree<AstNode>& t) {
00189     for (tree<AstNode>::iterator iter=t.begin(start);iter!=t.end(start);++iter) {
00190         if (iter->getType() == "class_name_reference") {
00191             for (tree<AstNode>::iterator jter=t.begin(iter);jter!=t.end(iter);++jter) {
00192                 if (jter->getType() == "text") {
00193                     return jter->getValue();
00194                 }
00195             }
00196             return string();
00197         }
00198     }
00199     return string();
00200 }
00201 
00202 
00203 string subVarName(const tree<AstNode>::iterator& it, const tree<AstNode>& tr)
00204 {
00205     tree<AstNode>::iterator iter = it;
00206     // go the the variable
00207     for (;iter != tr.end(it); ++iter) {
00208         if (iter->getType() == "reference_variable")
00209         {
00210             unsigned nbchilds = tr.number_of_children(iter);
00211             if (nbchilds == 1) {
00212                 if (tr.child(iter, 0)->getType() == "compound_variable") {
00213                     // single variables
00214                     tree<AstNode>::iterator var = iter;
00215                     for(;var->getType() != "text"; ++var)
00216                         ;
00217                     return (var->getValue());
00218                 }
00219             }
00220             else if (nbchilds == 4) {
00221                 // array ?
00222                 tree<AstNode>::iterator array = tr.child(iter, 0);
00223                 tree<AstNode>::iterator index = tr.child(iter, 2);
00224                 for(;array->getType() != "text" && array != tr.end(); ++array)
00225                     ;
00226                 for(;index->getType() != "text" && index != tr.end(); ++index)
00227                     ;
00228                 return array->getValue() + "[" + index->getValue() + "]";
00229             }
00230         }
00231         else if (iter->getType() == "expr_without_variable")
00232         {
00233             // go to the T_VARIABLE
00234             tree<AstNode>::iterator var = iter;
00235             for(;var->getType() != "T_VARIABLE"; ++var)
00236                 ;
00237             var = tr.child(var, 0);
00238             return var->getValue();
00239         }
00240     }
00241     // backtrack for: strings, functions, class
00242     return string();
00243 }
00244 
00245 void writeSiblingsCPP(const tree<AstNode>& t, const tree<AstNode>::iterator& iRoot, StringBuffer& buf,
00246                       bool inString = false, bool inFct = false, bool inMain = false, bool inClass = false, bool inFctCall = false)
00247 {
00248     if(t.empty())
00249         return;
00250     string type = iRoot->getType();
00251     if (type == "root") {
00252         tree<AstNode>::sibling_iterator iChildren = t.begin(iRoot);
00253         writeSiblingsCPP(t,iChildren,buf,inString,inFct,inMain,inClass,inFctCall);
00254     }
00255     else if (t.number_of_children(iRoot) == 0) {
00256         if (iRoot->getValue().length() > 0) {
00257             if (iRoot->getValue() == ".") { /* concatenate transformation */  buf << " + "; }
00258             else if (t.parent(iRoot)->getType() == "T_ENCAPSED_AND_WHITESPACE")
00259                 buf << (varname(iRoot->getValue(), false) + " ");
00260             else
00261                 buf << (varname(iRoot->getValue(), true) + " ");
00262         }
00263     }
00264     else {
00265         int siblingNum;
00266         tree<AstNode>::sibling_iterator iChildren;
00267         if (type == "T_ECHO" or type == "T_INCLUDE" or type == "T_PRINT") {
00268             // gotta be a function
00269             tree<AstNode>::iterator parent = t.parent(iRoot); // go to the parent in order to get all information
00270             string funcName = getNodeValue(parent, type, t);
00271             string contentNodeName = "echo_expr_list";
00272             if (type == "T_INCLUDE" or type == "T_PRINT") {
00273                 contentNodeName = "expr";
00274             }
00275             // must be always true, otherwise, the AST is ill-formed
00276             buf << (funcName + "(");
00277             writeSiblingsCPP(t,getNodeIter(parent, contentNodeName, t),buf,inString,inFct,inMain,inClass,inFctCall);
00278             buf << "); ";
00279         }
00280         else if (type == "expr_without_variable" && t.number_of_children(iRoot) == 3 
00281         &&       t.child(iRoot,1)->getType() == "CHAR61"
00282         &&       classAssignement(t.child(iRoot,2), t)) { // assignement + class + new 
00283             string cname = className(t.child(iRoot,2), t);
00284             if (cname.length() > 0) {
00285                 string v = varname(subVarName(t.child(iRoot,0), t));
00286                 buf << cname << "* " << v << " = new " << cname << "()\n";
00287                 classVarNames.push_back(v);
00288             }
00289             else {
00290                 for (iChildren = t.begin(iRoot), siblingNum = 0; iChildren != t.end(iRoot); ++iChildren)
00291                 {
00292                     string subtype = iChildren->getType();
00293                     if (subtype == "T_ECHO" or subtype == "T_INCLUDE" or subtype == "T_PRINT") {
00294                         writeSiblingsCPP(t,iChildren,buf,inString,inFct,inMain,inClass,inFctCall);
00295                         break;
00296                     }
00297                     else if (inMain && (subtype == "unticked_function_declaration_statement" ||  subtype == "unticked_class_declaration_statement")) {
00298                         continue;
00299                     }
00300                     else
00301                         writeSiblingsCPP(t,iChildren,buf,inString,inFct,inMain,inClass,inFctCall);
00302                 }
00303             }
00304         }
00305         else {
00306             for (iChildren = t.begin(iRoot), siblingNum = 0; iChildren != t.end(iRoot); ++iChildren)
00307             {
00308                 string subtype = iChildren->getType();
00309                 if (subtype == "T_ECHO" or subtype == "T_INCLUDE" or subtype == "T_PRINT") {
00310                     writeSiblingsCPP(t,iChildren,buf,inString,inFct,inMain,inClass,inFctCall);
00311                     break;
00312                 }
00313                 else if (inMain && (subtype == "unticked_function_declaration_statement" ||  subtype == "unticked_class_declaration_statement")) {
00314                     continue;
00315                 }
00316                 else
00317                     writeSiblingsCPP(t,iChildren,buf,inString,inFct,inMain,inClass,inFctCall);
00318             }
00319         }
00320     }
00321 }
00322 
00323 void writeCPP(const tree<AstNode>& tr, StringBuffer& buf)
00324 {
00325     if (tr.empty()) {
00326         throw length_error("writeCPP - The AST tree is empty");
00327         return;
00328     }
00329     for(tree<AstNode>::sibling_iterator iRoots = tr.begin(); iRoots != tr.end(); iRoots++) {
00330         writeSiblingsCPP(tr,iRoots,buf);
00331     }
00332 }
00333 
00334 
00335 
00336 void addFunctionCpp(const tree<AstNode>::iterator& start, const tree<AstNode>& tr, StringBuffer& buffer, bool fromClass = false, const string cname = "")
00337 {
00338     string fname;
00339     vector<string> paramVars;
00340     bool returnValue = functionReturnValue(start, tr);
00341     fname = getNodeValue(start, "T_STRING", tr);
00342     
00343     if (fromClass)
00344     {
00345         if (utils::start_with(fname,"__")) {
00346             // looks like a constructor, copy etc.
00347             if (fname == "__construct")
00348                 fname = cname;
00349             else if (fname == "__destruct")
00350                 fname = "~" + cname;
00351             else if (fname == "__clone") // I'll do by myself!
00352                 return;
00353         }
00354     }
00355 
00356     tree<AstNode>::iterator params = getNodeIter(start, "parameter_list", tr);
00357     if (tr.number_of_children(params) > 0) {
00358         // fill paramVars
00359         for (tree<AstNode>::iterator iter=tr.begin(params);iter!=tr.end(params);++iter) {
00360             if (iter->getType() == "T_VARIABLE") {
00361                 paramVars.push_back(varname(tr.child(iter, 0)->getValue()));
00362             }
00363         }
00364     }
00365     string decl = "";
00366     if (returnValue)
00367         decl += "PhpObject ";
00368     else if (fname != cname)
00369         decl += "void ";
00370     decl += fname;
00371     decl += "( ";
00372     unsigned t = paramVars.size();
00373     if (t > 0) {
00374         decl += ("PhpObject& loc_" + paramVars[0]);
00375         for (unsigned i=1;i<t;i++)
00376         decl += (", PhpObject& " + paramVars[i]);
00377     }
00378     decl += " ) {\n";
00379     buffer << (decl);
00380     StringBuffer localFuncContent;
00381     tree<AstNode>::iterator content;
00382 
00383     content = getNodeIter(start, "inner_statement_list", tr);
00384 
00385     writeSiblingsCPP(tr, content, localFuncContent, false, true);
00386     for (vector<string>::const_iterator iter=paramVars.begin();iter!=paramVars.end();++iter) {
00387         localFuncContent.replace(" " + *iter + " ", " loc_" + *iter + " ");
00388     }
00389     buffer << localFuncContent;
00390     buffer << ("}\n");
00391 }
00392 
00393 
00394 void addClassCpp(const tree<AstNode>::iterator& start, const tree<AstNode>& tr, StringBuffer& buffer)
00395 {
00396     // Check for the class name
00397     string cname, extend="";
00398     cname = getNodeValue(start, "T_STRING", tr);
00399     tree<AstNode>::iterator extends = getNodeIter(start, "extends_from", tr);
00400     
00401     buffer << "class " + cname;
00402 
00403     if (tr.number_of_children(extends) > 0) {
00404         for (tree<AstNode>::iterator iter=tr.begin(extends);iter!=tr.end(extends);++iter) {
00405             if (iter->getType() == "T_STRING") {
00406                 extend = tr.child(iter, 0)->getValue();
00407                 break;
00408             }
00409         }
00410         buffer << " : public " + extend;
00411     }
00412     buffer << "{\n";
00413 
00414     tree<AstNode>::iterator methodList = getNodeIter(start, "class_statement_list", tr);
00415     // Add the methods in the content
00416 
00417     map<string, tree<AstNode>::iterator> specialFunctions;
00418 
00419     // Check if there is contructor
00420     for (tree<AstNode>::iterator iter=tr.begin(methodList);iter!=tr.end(methodList);++iter) {
00421         if (iter->getType() == "class_statement") {
00422             for (tree<AstNode>::iterator jter=tr.begin(iter);jter!=tr.end(iter);++jter) {
00423                 if (jter->getType() == "T_STRING") {
00424                     jter = tr.child(jter, 0);
00425                     if (jter->getType() == "text" && utils::start_with(jter->getValue(), "__")) {
00426                         // special function
00427                         specialFunctions.insert(make_pair(jter->getValue(), iter));
00428                         break;
00429                     }
00430                 }
00431             }
00432         }
00433     }
00434     
00435     // Add the function definitions
00436     for (tree<AstNode>::iterator iter=tr.begin(methodList);iter!=tr.end(methodList);++iter)
00437     {
00438         if (iter->getType() == "class_statement")
00439         {
00440             //cout << "One call to method? declaration..." << endl;
00441             addFunctionCpp(iter, tr, buffer, true, cname);
00442         }
00443     }
00444 
00445     if (specialFunctions.find("__construct") == specialFunctions.end()) {
00446         // write the default constructor
00447         buffer << ("\n " + cname + "() {}\n");
00448     }
00449     if (specialFunctions.find("__destruct") == specialFunctions.end()) {
00450         // write the default constructor
00451         buffer << ("\n ~" + cname + "() {}\n");
00452     }
00453     buffer << ("\n " + cname + "(const "+ cname + "& ____c) {}\n");
00454     buffer << "\n};\n";
00455 }
00456 
00457 StringBuffer Ast2Cpp::operator()(const tree<AstNode>& tr, const MapClasses* classes, const MapVariables* vars, 
00458                                  const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00459 {
00460     StringBuffer buffer, beg;
00461     classVarNames.clear();
00462 
00463     for (unsigned i=0;i<CPPHEADERSIZE;i++) {
00464         beg << (cppheader[i]);
00465     }
00466 
00467     // Add the classes definitions
00468     for (tree<AstNode>::iterator iter=tr.begin();iter!=tr.end();++iter) {
00469         if (iter->getType() == "unticked_class_declaration_statement")
00470             addClassCpp(iter, tr, buffer);
00471     }
00472 
00473     // Add the function definitions
00474     for (tree<AstNode>::iterator iter=tr.begin();iter!=tr.end();++iter)
00475     {
00476         if (iter->getType() == "unticked_function_declaration_statement")
00477         {
00478             addFunctionCpp(iter, tr, buffer);
00479         }
00480     }
00481 
00482     // Add the main
00483     buffer << ("\n\nint main() {\n");
00484     //cout << "Main" << endl;
00485     writeSiblingsCPP(tr, tr.begin(), buffer,false,false,true);
00486     buffer << ("return 0;\n}\n\n");
00487 
00488     // Add all variables as global
00489     for(MapVariables::const_iterator iter = vars->begin(); iter != vars->end(); ++iter) {
00490         if (find(classVarNames.begin(),classVarNames.end(),varname(iter->first)) == classVarNames.end()) {
00491             string def = "PhpObject " + varname(iter->first) + ";\n";
00492             beg << (def);
00493         }
00494     }
00495     beg << ("\n");
00496 
00497     buffer.format();
00498     buffer.insert_begin(beg);
00499     return buffer;
00500 }
00501 
00502 
00503 
00504 StringBuffer Ast2Php::operator()(const tree<AstNode>& tr, const MapClasses* classes, const MapVariables* vars, 
00505                                  const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00506 {
00507     StringBuffer buffer, out;
00508     // Add the classes definitions
00509     for (tree<AstNode>::iterator iter=tr.begin();iter!=tr.end();++iter) {
00510         if (iter->getType() == "text")
00511             buffer << iter->getValue() + " ";
00512     }
00513     buffer.format();
00514     out << "<?php\n\n";
00515     out << buffer;
00516     out << "\n\n?>";
00517     return out;
00518 }
00519 
00520 
00521 

Generated on Wed Feb 27 20:31:06 2008 for php.ast.svn.src. by  doxygen 1.5.3