00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <string>
00018 #include <fstream.h>
00019 #include <cstdlib>
00020 #include <unistd.h>
00021 #include <stdio.h>
00022 #include <utility>
00023 #include <list>
00024 #include <vector>
00025 #include <stdexcept>
00026
00027
00028 #define PR(x) cout << #x << " = " << (x) << endl;
00029
00030 struct ClassInfo {
00031 ClassInfo();
00032 string name;
00033 size_t bodyStart;
00034 size_t bodyEnd;
00035 bool correct;
00036 void print();
00037 };
00038
00039 ClassInfo::ClassInfo() : correct(false), bodyStart(0), bodyEnd(0) {}
00040
00041 void ClassInfo::print()
00042 {
00043 cout << "name = " << name << endl;
00044 cout << "bodyStart = " << bodyStart << endl;
00045 cout << "bodyEnd = " << bodyEnd << endl;
00046 }
00047
00048 size_t ccount(string& s, char c)
00049 {
00050 size_t n = 0;
00051 for (int i=0; i<s.size(); i++)
00052 if (s[i] == c) n++;
00053 return n;
00054 }
00055
00056 int main(int argc, char* argv[])
00057 {
00058 long i, j, k;
00059
00060 if (argc < 2) {
00061 cerr << "Usage: " << argv[0] << " file ..." << endl;
00062 return 2;
00063 }
00064
00065 vector<string> inputFileList;
00066 for (i=1; i<argc; i++)
00067 inputFileList.push_back(argv[i]);
00068
00069
00070 for (int iFile=0; iFile<inputFileList.size(); iFile++) {
00071
00072 string inputfile = inputFileList[iFile];
00073
00074 if (access(inputfile.c_str(), R_OK) != 0) {
00075 cerr << argv[0] << ": cannot access file " << inputfile << endl;
00076 continue;
00077 }
00078
00079 cout << "preparing file " << inputfile << " .";
00080
00081 string tempfile1(tempnam(".",0)); tempfile1 += ".cc";
00082 string tempfile2(tempnam(".",0)); tempfile2 += ".cc";
00083 string command;
00084 #if defined(DEBUG)
00085 PR(tempfile1);
00086 PR(tempfile2);
00087 #endif
00088
00089
00090
00091
00092 command = "expand ";
00093 command += inputfile;
00094 command += "| sed 's/\\#.*include/\\/\\/&/g' > ";
00095 command += tempfile1;
00096 #if defined(DEBUG)
00097 cout << command << endl;
00098 #endif
00099 system(command.c_str());
00100 cout << '.'; cout.flush();
00101
00102
00103
00104
00105
00106 command = "g++ -E ";
00107 command += tempfile1;
00108 command += " | grep -v ";
00109 command += tempfile1;
00110 command += " > ";
00111 command += tempfile2;
00112 #if defined(DEBUG)
00113 cout << command << endl;
00114 #endif
00115 system(command.c_str());
00116 cout << '.'; cout.flush();
00117
00118
00119
00120
00121
00122
00123
00124 long len, pos;
00125 string line;
00126 string bigLine;
00127 char c;
00128 ifstream ifs(tempfile2.c_str());
00129 while (ifs.good()) {
00130 getline(ifs, line, '\n');
00131 if (ifs.eof()) break;
00132 if (line.empty()) continue;
00133 line += ' ';
00134 for (i=0; i<line.size(); i++) {
00135 c = line[i];
00136 switch(c) {
00137 case ';':
00138 bigLine += ";\n";
00139 break;
00140 case '{':
00141 bigLine += "\n{\n";
00142 break;
00143 case '}':
00144 if (i+1 < line.size() && line[i+1] == ';') {
00145 bigLine += "\n};\n";
00146 i++;
00147 }
00148 else
00149 bigLine += "\n}\n";
00150 break;
00151 case '\t':
00152 break;
00153 default:
00154 bigLine += c;
00155 break;
00156 }
00157 }
00158 }
00159 ifs.close();
00160 cout << '.'; cout.flush();
00161 pos = 0;
00162 while(pos < bigLine.size()) {
00163 pos = bigLine.find("public:", pos);
00164 if (pos != string::npos) {
00165 bigLine.replace(pos, 7 , "public:\n");
00166 pos += 7;
00167 }
00168 else
00169 break;
00170 }
00171 pos = 0;
00172 while(pos < bigLine.size()) {
00173 pos = bigLine.find("private:", pos);
00174 if (pos != string::npos) {
00175 bigLine.replace(pos, 8 , "private:\n");
00176 pos += 8;
00177 }
00178 else
00179 break;
00180 }
00181 pos = 0;
00182 while(pos < bigLine.size()) {
00183 pos = bigLine.find("protected:", pos);
00184 if (pos != string::npos) {
00185 bigLine.replace(pos, 10 , "protected:\n");
00186 pos += 10;
00187 }
00188 else
00189 break;
00190 }
00191 cout << '.'; cout.flush();
00192
00193
00194
00195
00196 pos = 0;
00197 while(pos < bigLine.size()) {
00198 pos = bigLine.find("inline ", pos);
00199 if (pos != string::npos) {
00200 bigLine.erase(pos, 7);
00201 }
00202 else
00203 break;
00204 }
00205 cout << '.'; cout.flush();
00206
00207
00208
00209
00210 pos = 0;
00211 while(pos < bigLine.size()) {
00212 pos = bigLine.find(":", pos);
00213 if (pos != string::npos) {
00214 bigLine.replace(pos, 1, " : ");
00215 pos += 3;
00216 }
00217 else
00218 break;
00219 }
00220 cout << '.'; cout.flush();
00221
00222
00223
00224
00225 pos = 0;
00226 bool reset = false;
00227 while(true) {
00228 pos = bigLine.find(" ", pos);
00229 if (pos != string::npos) {
00230 bigLine.erase(pos, 1);
00231 reset = false;
00232 }
00233 else {
00234 if (reset) break;
00235 }
00236 if (pos >= bigLine.size()) {
00237 reset = true;
00238 pos = 0;
00239 }
00240 }
00241 cout << '.'; cout.flush();
00242
00243
00244
00245
00246 vector<string> allLines;
00247 line.erase();
00248 bool beginLine = true;
00249 for (i=0; i<bigLine.size(); i++) {
00250 c = bigLine[i];
00251 switch(c) {
00252 case ' ':
00253 if (!beginLine)
00254 line += c;
00255 break;
00256 case '\n':
00257 if (!line.empty()) {
00258 line += c;
00259 allLines.push_back(line);
00260 }
00261 line.erase();
00262 beginLine = true;
00263 break;
00264 default:
00265 line += c;
00266 beginLine = false;
00267 break;
00268 }
00269 }
00270 bigLine.erase();
00271 cout << '.'; cout.flush();
00272
00273 #if defined(DEBUG)
00274 copy(allLines.begin(), allLines.end(), ostream_iterator<string>(cout));
00275 #endif
00276
00277
00278
00279
00280
00281 for (i=0; i<allLines.size(); i++) {
00282 line = allLines[i];
00283 pos = line.find("operator ",0);
00284 if (pos != string::npos) line.replace(pos, 9 , "operator");
00285 pos = line.find("< class",0);
00286 if (pos != string::npos) line.replace(pos, 7 , "<class");
00287 pos = line.find(" < ",0);
00288 if (pos != string::npos) line.replace(pos, 3 , "<");
00289 pos = line.find(" > ",0);
00290 if (pos != string::npos) line.replace(pos, 3 , "> ");
00291 pos = line.find(" >",0);
00292 if (pos != string::npos) line.replace(pos, 2 , ">");
00293 pos = line.find(" & ",0);
00294 if (pos != string::npos) line.replace(pos, 3 , "& ");
00295 pos = line.find("template <",0);
00296 if (pos != string::npos) line.replace(pos, 10 , "template<");
00297 pos = line.find("private :",0);
00298 if (pos != string::npos) line.replace(pos, 9 , "private:");
00299 pos = line.find("protected :",0);
00300 if (pos != string::npos) line.replace(pos, 11 , "protected:");
00301 pos = line.find("public :",0);
00302 if (pos != string::npos) line.replace(pos, 8 , "public:");
00303 pos = line.find(": :",0);
00304 if (pos != string::npos) line.replace(pos, 3 , "::");
00305 pos = line.find(" :: ",0);
00306 if (pos != string::npos) line.replace(pos, 4 , "::");
00307 allLines[i] = line;
00308 }
00309 cout << '.'; cout.flush();
00310
00311
00312
00313
00314 vector<string>::iterator viter;
00315 vector<string> theText;
00316 bool inPrivateRegion = false;
00317 bool inProtectedRegion = false;
00318 for (viter = allLines.begin(); viter != allLines.end(); viter++) {
00319 if (inPrivateRegion) {
00320 if (viter->find("protected:") != string::npos ||
00321 viter->find("public:") != string::npos ||
00322 *viter == string("};\n"))
00323 inPrivateRegion = false;
00324 }
00325 else {
00326 if (viter->find("private:") != string::npos)
00327 inPrivateRegion = true;
00328 }
00329 if (inProtectedRegion) {
00330 if (viter->find("private:") != string::npos ||
00331 viter->find("public:") != string::npos ||
00332 *viter == string("};\n"))
00333 inProtectedRegion = false;
00334 }
00335 else {
00336 if (viter->find("protected:") != string::npos)
00337 inProtectedRegion = true;
00338 }
00339
00340 if (!inPrivateRegion && !inProtectedRegion &&
00341 *viter != string("\n") && !viter->empty())
00342 theText.push_back(*viter);
00343 }
00344 allLines.clear();
00345 cout << '.'; cout.flush();
00346
00347
00348
00349
00350 vector<ClassInfo> classInfo;
00351 size_t pos1, pos2;
00352 for (k=0; k<theText.size(); k++) {
00353 if ((pos=theText[k].rfind("class ")) != string::npos &&
00354 theText[k].rfind(";") == string::npos ) {
00355 if (pos-1 >= 0) {
00356 if (theText[k][pos-1] == '<' ||
00357 theText[k][pos-1] == ',') continue;
00358 }
00359 if (pos-2 >= 0) {
00360 if (theText[k][pos-2] == '<' ||
00361 theText[k][pos-2] == ',') continue;
00362 }
00363 ClassInfo info;
00364 pos1 = theText[k].find_first_not_of(' ', pos+5);
00365 pos2 = theText[k].find_first_of(' ', pos1)-1;
00366 info.name = theText[k].substr(pos1, pos2-pos1+1);
00367 info.bodyStart = k+1;
00368 classInfo.push_back(info);
00369 }
00370 if ((pos=theText[k].find("enum ")) != string::npos) {
00371 ClassInfo info;
00372 pos1 = theText[k].find_first_not_of(' ', pos+4);
00373 pos2 = theText[k].find_first_of(' ', pos1)-1;
00374 info.name = theText[k].substr(pos1, pos2-pos1+1);
00375 info.bodyStart = k+1;
00376 classInfo.push_back(info);
00377 }
00378 if ((pos=theText[k].find("struct ")) != string::npos) {
00379 ClassInfo info;
00380 pos1 = theText[k].find_first_not_of(' ', pos+4);
00381 pos2 = theText[k].find_first_of(' ', pos1)-1;
00382 info.name = theText[k].substr(pos1, pos2-pos1+1);
00383 info.bodyStart = k+1;
00384 classInfo.push_back(info);
00385 }
00386 }
00387 cout << '.'; cout.flush();
00388
00389
00390
00391
00392
00393 vector<size_t> tmp;
00394 for (k = 0; k<theText.size(); k++) {
00395 if (theText[k].find("};") != string::npos) {
00396 tmp.push_back(k);
00397 }
00398 }
00399 #if defined(DEBUG)
00400 PR(tmp.size());
00401 PR(classInfo.size());
00402 #endif
00403 if (tmp.size() != classInfo.size()) {
00404 cout << " . error" << endl;
00405 cout << argv[0] << ": tmp.size() != classInfo.size()" << endl;
00406 remove(tempfile1.c_str());
00407 remove(tempfile2.c_str());
00408 theText.clear();
00409 continue;
00410 }
00411
00412
00413 int dist, minDist;
00414 pair<size_t, size_t> minPair;
00415 int nMatches = 0;
00416
00417 while (nMatches != classInfo.size()) {
00418 minDist = theText.size();
00419 for (k=0; k<tmp.size(); k++) {
00420 if (tmp[k] == 0) continue;
00421 for (i=0; i<classInfo.size(); i++) {
00422 if (classInfo[i].correct) continue;
00423 dist = tmp[k]-classInfo[i].bodyStart;
00424 if (dist < 0) continue;
00425 if (dist < minDist) {
00426 minDist = dist;
00427 minPair.first = k;
00428 minPair.second = i;
00429 }
00430 }
00431 }
00432 classInfo[minPair.second].bodyEnd = tmp[minPair.first];
00433 classInfo[minPair.second].correct = true;
00434 tmp[minPair.first] = 0;
00435 nMatches++;
00436 }
00437 cout << '.'; cout.flush();
00438 #if defined(DEBUG)
00439 for (i=0; i<classInfo.size(); i++) {
00440 classInfo[i].print();
00441 }
00442 #endif
00443
00444
00445
00446
00447
00448
00449 vector<bool> markForDelete(theText.size(), false);
00450 bool isStart;
00451 size_t leftBrackets;
00452 size_t rightBrackets;
00453 for (k=0; k<theText.size(); k++) {
00454 if (theText[k][0] == '{') {
00455 isStart = true;
00456 for (i=0; i<classInfo.size(); i++) {
00457 if (classInfo[i].bodyStart == k) {
00458 isStart = false;
00459 break;
00460 }
00461 }
00462 if (k-1 >= 0 &&
00463 theText[k-1].find("namespace") != string::npos &&
00464 theText[k-1].find("using") == string::npos) {
00465 isStart = false;
00466 break;
00467 }
00468 if (isStart) {
00469 leftBrackets = rightBrackets = 0;
00470 theText[k-1].insert(theText[k-1].size()-1, ";");
00471 for (j=k; j<theText.size(); j++) {
00472 markForDelete[j] = true;
00473
00474
00475 leftBrackets += ccount(theText[j], '{');
00476 rightBrackets += ccount(theText[j], '}');
00477 if (j > k && leftBrackets == rightBrackets) {
00478 isStart == false;
00479 break;
00480 }
00481 }
00482 }
00483 }
00484 }
00485 #if defined(DEBUG)
00486 for (k=0; k<theText.size(); k++) {
00487 if (markForDelete[k]) cout << "DELETE>>>";
00488 cout << theText[k];
00489 }
00490 #endif
00491 for (k=0; k<theText.size(); k++)
00492 if (markForDelete[k]) theText[k].erase();
00493 cout << '.'; cout.flush();
00494
00495
00496
00497
00498
00499
00500
00501 bool isClassDeclaration;
00502 bool isInsideClassBody;
00503 for (k=0; k<theText.size(); k++) {
00504 if (theText[k].find("::") != string::npos) {
00505 isInsideClassBody = false;
00506 for (i=0; i<classInfo.size(); i++) {
00507 if (k > classInfo[i].bodyStart && k < classInfo[i].bodyEnd)
00508 isInsideClassBody = true;
00509 }
00510 if (!isInsideClassBody) theText[k].erase();
00511 }
00512 if (theText[k].find("extern \"C\"") != string::npos) theText[k].erase();
00513 pos = theText[k].find(" ;",0);
00514 if (pos != string::npos) theText[k].replace(pos, 2 , ";");
00515 isClassDeclaration = false;
00516 for (i=0; i<classInfo.size(); i++) {
00517 if (classInfo[i].bodyStart-1 == k)
00518 isClassDeclaration = true;
00519 }
00520 if (!isClassDeclaration) {
00521 pos = theText[k].find(" : ",0);
00522 if (pos != string::npos) {
00523 theText[k].erase(pos, theText[k].size()-pos);
00524 line += '\n';
00525 }
00526 }
00527 }
00528 cout << '.'; cout.flush();
00529
00530
00531
00532
00533 pos = inputfile.rfind('/');
00534 if (pos != string::npos)
00535 inputfile.erase(0, pos+1);
00536
00537 string keywordFile(inputfile); keywordFile += ".keywords";
00538 string outFile(inputfile); outFile += ".out";
00539
00540
00541
00542
00543 ofstream keyfs(keywordFile.c_str());
00544 ofstream outfs(outFile.c_str());
00545 for (k=0; k<theText.size(); k++) {
00546 if (!theText[k].empty() && theText[k] != "\n")
00547 outfs << theText[k];
00548 }
00549 for (i=0; i<classInfo.size(); i++) keyfs << classInfo[i].name << endl;
00550 cout << '.'; cout.flush();
00551
00552
00553
00554
00555 remove(tempfile1.c_str());
00556 remove(tempfile2.c_str());
00557
00558 theText.clear();
00559 #if defined(DEBUG)
00560 copy(theText.begin(), theText.end(), ostream_iterator<string>(cout, "\n"));
00561 #endif
00562 cout << ". done" << endl;
00563 }
00564 return 0;
00565 }