00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
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
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
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
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
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
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() == ".") { 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
00269 tree<AstNode>::iterator parent = t.parent(iRoot);
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
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)) {
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
00347 if (fname == "__construct")
00348 fname = cname;
00349 else if (fname == "__destruct")
00350 fname = "~" + cname;
00351 else if (fname == "__clone")
00352 return;
00353 }
00354 }
00355
00356 tree<AstNode>::iterator params = getNodeIter(start, "parameter_list", tr);
00357 if (tr.number_of_children(params) > 0) {
00358
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
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
00416
00417 map<string, tree<AstNode>::iterator> specialFunctions;
00418
00419
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
00427 specialFunctions.insert(make_pair(jter->getValue(), iter));
00428 break;
00429 }
00430 }
00431 }
00432 }
00433 }
00434
00435
00436 for (tree<AstNode>::iterator iter=tr.begin(methodList);iter!=tr.end(methodList);++iter)
00437 {
00438 if (iter->getType() == "class_statement")
00439 {
00440
00441 addFunctionCpp(iter, tr, buffer, true, cname);
00442 }
00443 }
00444
00445 if (specialFunctions.find("__construct") == specialFunctions.end()) {
00446
00447 buffer << ("\n " + cname + "() {}\n");
00448 }
00449 if (specialFunctions.find("__destruct") == specialFunctions.end()) {
00450
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
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
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
00483 buffer << ("\n\nint main() {\n");
00484
00485 writeSiblingsCPP(tr, tr.begin(), buffer,false,false,true);
00486 buffer << ("return 0;\n}\n\n");
00487
00488
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
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