⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 extractcode.cpp

📁 Think in C++ 第二版源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
};



// Static initialization:

map<string,CompilerData> 

  CompilerData::compilerInfo;

set<string> CompilerData::_compilerNames;



void CompilerData::readDB(istream& in) {

  string compiler; // Name of current compiler

  string s;

  while(getline(in, s)) {

    if(s.find("#//" "/:~") == 0)

      return; // Found end tag

    s = trim(s);

    if(s.length() == 0) continue; // Blank line

    if(s[0] == '#') continue; // Comment

    if(s[0] == '{') { // Different compiler

      compiler = s.substr(0, s.find('}'));

      compiler = trim(compiler.substr(1));

      if(compiler.length() != 0)

        _compilerNames.insert(compiler);

      continue; // Changed compiler name

    }

    if(s[0] == '(') { // Object file extension

      string obj = s.substr(1);

      obj = trim(obj.substr(0, obj.find(')')));

      compilerInfo[compiler].objExtension =obj;

      continue;

    }

    if(s[0] == '[') { // Executable extension

      string exe = s.substr(1);

      exe = trim(exe.substr(0, exe.find(']')));

      compilerInfo[compiler].exeExtension =exe;

      continue;

    }

    if(s[0] == '&') { // Special directive

      if(s.find("dos") != string::npos)

        compilerInfo[compiler]._dos = true;

      else if(s.find("unix") != string::npos)

        compilerInfo[compiler]._unix = true;

      else

        error("Compiler Information Database", 

          "unknown special directive: " + s);

      continue;

    }

    if(s[0] == '@') { // Makefile rule

      string rule(s.substr(1)); // Remove the @

      if(rule[0] == ' ') // Space means tab

        rule = '\t' + trim(rule);

      compilerInfo[compiler].rules

        .push_back(rule); 

      continue;

    }

    // Otherwise, it's a failure line:

    compilerInfo[compiler].fails.insert(s);

  }

  error("CompileDB.txt","Missing end tag");

}



void CompilerData::addFailures(CodeFile& cf) {

  set<string>::iterator it = 

    _compilerNames.begin();

  while(it != _compilerNames.end()) {

    if(compilerInfo[*it]

       .fails.count(cf.rawName()) != 0)

      cf.addFailure(*it);

    it++;

  }

}



string CompilerData::obj(string compiler) {

  if(compilerInfo.count(compiler) != 0) {

    string ext(

      compilerInfo[compiler].objExtension);

    if(ext.length() != 0)

      ext = '.' + ext; // Use '.' if it exists

    return ext;

  } else

    return "No such compiler information";

}



string CompilerData::exe(string compiler) {

  if(compilerInfo.count(compiler) != 0) {

    string ext(

      compilerInfo[compiler].exeExtension);

    if(ext.length() != 0)

      ext = '.' + ext; // Use '.' if it exists

    return ext;

  } else

    return "No such compiler information";

}



void CompilerData::writeRules(

  string compiler, ostream& os) {

  if(_compilerNames.count(compiler) == 0) {

    os << "No info on this compiler" << endl;

    return;

  }

  vector<string>& r = 

    compilerInfo[compiler].rules;

  copy(r.begin(), r.end(), 

    ostream_iterator<string>(os, "\n"));

}



string CompilerData::adjustPath(

  string compiler, string path) {

  // Use STL replace() algorithm:

  if(compilerInfo[compiler]._dos)

    replace(path.begin(), path.end(), '/', '\\');

  return path;

}



void CompilerData::dump(ostream& os) {

  ostream_iterator<string> out(os, "\n");

  *out++ = "Compiler Names:";

  copy(_compilerNames.begin(), 

    _compilerNames.end(), out);

  map<string, CompilerData>::iterator compIt;

  for(compIt = compilerInfo.begin(); 

    compIt != compilerInfo.end(); compIt++) {

    os << "******************************\n";

    os << "Compiler: [" << (*compIt).first <<

      "]" << endl;

    CompilerData& cd = (*compIt).second;

    os << "objExtension: " << cd.objExtension

      << "\nexeExtension: " << cd.exeExtension 

      << endl;

    *out++ = "Rules:";

    copy(cd.rules.begin(), cd.rules.end(), out);

    cout << "Won't compile with: " << endl;

    copy(cd.fails.begin(), cd.fails.end(), out);

  }

}



// ---------- Manage makefile creation ----------

// Create the makefile for this directory, based

// on each of the CodeFile entries:

class Makefile {

  vector<CodeFile> codeFiles;

  // All the different paths 

  // (for creating the Master makefile):

  static set<string> paths;

  void 

  createMakefile(string compiler, string path);

public:

  Makefile() {}

  void addEntry(CodeFile& cf) {

    paths.insert(cf.path()); // Record all paths

    // Tell it what compilers don't work with it:

    CompilerData::addFailures(cf);

    codeFiles.push_back(cf);

  }

  // Write the makefile for each compiler:

  void writeMakefiles(string path);

  // Create the master makefile:

  static void writeMaster(string flag = "");

};



// Static initialization:

set<string> Makefile::paths;



void Makefile::writeMakefiles(string path) {

  if(trim(path).length() == 0)

    return; // No makefiles in root directory

  PushDirectory pd(path);

  set<string>& compilers = 

    CompilerData::compilerNames();

  set<string>::iterator it = compilers.begin();

  while(it != compilers.end())

    createMakefile(*it++, path);

}



void Makefile::createMakefile(

  string compiler, string path) {

  string // File name extensions:

    exe(CompilerData::exe(compiler)),

    obj(CompilerData::obj(compiler));

  string filename(compiler + ".makefile");

  ofstream makefile(filename.c_str());

  makefile << 

    "# From Thinking in C++, 2nd Edition\n"

    "# At http://www.BruceEckel.com\n"

    "# (c) Bruce Eckel 1999\n"

    "# Copyright notice in Copyright.txt\n"

    "# Automatically-generated MAKEFILE \n"

    "# For examples in directory "+ path + "\n"

    "# using the " + compiler + " compiler\n"

    "# Note: does not make files that will \n"

    "# not compile with this compiler\n"

    "# Invoke with: make -f " 

    + compiler + ".makefile\n"

    << endl;

  CompilerData::writeRules(compiler, makefile);

  vector<string> makeAll, makeTest, 

    makeBugs, makeDeps, linkCmd;

  // Write the "all" dependencies:

  makeAll.push_back("all: ");

  makeTest.push_back("test: all ");

  makeBugs.push_back("bugs: ");

  string line;

  vector<CodeFile>::iterator it;

  for(it = codeFiles.begin(); 

    it != codeFiles.end(); it++) {

    CodeFile& cf = *it;

    if(cf.targetType() == executable) {

      line = "\\\n\t"+cf.targetName()+ exe + ' ';

      if(cf.compilesOK(compiler) == false) {

        makeBugs.push_back(

          CompilerData::adjustPath(

            compiler,line));

      } else {

        makeAll.push_back(

          CompilerData::adjustPath(

            compiler,line));

        line = "\\\n\t" + cf.targetName() + exe +

          ' ' + cf.testArgs() + ' ';

        makeTest.push_back(

          CompilerData::adjustPath(

            compiler,line));

      }

      // Create the link command:

      int linkdeps = cf.link().size();

      string linklist;

      for(int i = 0; i < linkdeps; i++)

        linklist += 

          cf.link().operator[](i) + obj + " ";

      line = cf.targetName() + exe + ": "

        + linklist + "\n\t$(CPP) $(OFLAG)"

        + cf.targetName() + exe

        + ' ' + linklist + "\n\n";

      linkCmd.push_back(

        CompilerData::adjustPath(compiler,line));

    }

    // Create dependencies

    if(cf.targetType() == executable

      || cf.targetType() == object) {

      int compiledeps = cf.compile().size();

      string objlist(cf.base() + obj + ": ");

      for(int i = 0; i < compiledeps; i++)

        objlist += 

          cf.compile().operator[](i) + " ";

      makeDeps.push_back(

        CompilerData::adjustPath(

          compiler, objlist) +"\n");

    }      

  }

  ostream_iterator<string> mkos(makefile, "");

  *mkos++ = "\n";

  // The "all" target:

  copy(makeAll.begin(), makeAll.end(), mkos);

  *mkos++ = "\n\n";

  // Remove continuation marks from makeTest:

  vector<string>::iterator si = makeTest.begin();

  int bsl;

  for(; si != makeTest.end(); si++)

    if((bsl= (*si).find("\\\n")) != string::npos)

      (*si).erase(bsl, strlen("\\"));

  // Now print the "test" target:

  copy(makeTest.begin(), makeTest.end(), mkos);

  *mkos++ = "\n\n";

  // The "bugs" target:

  copy(makeBugs.begin(), makeBugs.end(), mkos);

  if(makeBugs.size() == 1)

    *mkos++ = "\n\t@echo No compiler bugs in "

      "this directory!";

  *mkos++ = "\n\n";

  // Link commands:

  copy(linkCmd.begin(), linkCmd.end(), mkos);

  *mkos++ = "\n";

  // Demendencies:

  copy(makeDeps.begin(), makeDeps.end(), mkos);

  *mkos++ = "\n";

}



void Makefile::writeMaster(string flag) {

  string filename = "makefile";

  if(flag.length() != 0)

    filename += '.' + flag;

  ofstream makefile(filename.c_str());

  makefile << "# Master makefile for "

    "Thinking in C++, 2nd Ed. by Bruce Eckel\n"

    "# at http://www.BruceEckel.com\n"

    "# Compiles all the code in the book\n"

    "# Copyright notice in Copyright.txt\n\n"

    "help: \n"

    "\t@echo To compile all programs from \n"

    "\t@echo Thinking in C++, 2nd Ed., type\n"

    "\t@echo one of the following commands,\n"

    "\t@echo according to your compiler:\n";

  set<string>& n = CompilerData::compilerNames();

  set<string>::iterator nit;

  for(nit = n.begin(); nit != n.end(); nit++)

    makefile << 

      string("\t@echo make " + *nit + "\n");

  makefile << endl;

  // Make for each compiler:

  for(nit = n.begin(); nit != n.end(); nit++) {

    makefile << *nit << ":\n";

    for(set<string>::iterator it = paths.begin();

      it != paths.end(); it++) {

      // Ignore the root directory:

      if((*it).length() == 0) continue;

      makefile << "\tcd " << *it;

      // Different commands for unix vs. dos:

      if(CompilerData::isUnix(*nit))

        makefile << "; ";

      else

        makefile << "\n\t";

      makefile << "make -f " << *nit 

        << ".makefile";

      if(flag.length() != 0) {

        makefile << ' ';

        if(flag == "bugs")

          makefile << "-i ";

        makefile << flag;

      }

      makefile << "\n";

      if(CompilerData::isUnix(*nit) == false)

        makefile << "\tcd ..\n";

    }

    makefile << endl;

  }

}



int main(int argc, char* argv[]) {

  if(argc < 2) {

    error("Command line error", usage);

    exit(1);

  }

  // For development & testing, leave off notice:

  if(argc == 3)

    if(string(argv[2]) == "-nocopyright")

      copyright = "";

  // Open the input file to read the compiler

  // information database:

  ifstream in(argv[1]);

  if(!in) {

    error(string("can't open ") + argv[1],usage);

    exit(1);

  }

  string s;

  while(getline(in, s)) {

    // Break up the strings to prevent a match when

    // this code is seen by this program:

    if(s.find("#:" " :CompileDB.txt") 

      != string::npos) {

      // Parse the compiler information database:

      CompilerData::readDB(in);

      break; // Out of while loop

    }

  }

  if(in.eof())

    error("CompileDB.txt", "Can't find data");

  in.seekg(0, ios::beg); // Back to beginning

  map<string, Makefile> makeFiles;

  while(getline(in, s)) {

    // Look for tag at beginning of line:

    if(s.find("//" ":") == 0

       || s.find("/*" ":") == 0

       || s.find("#" ":") == 0) {

      CodeFile cf(in, s);

      cf.write();  // Tell it to write itself

      makeFiles[cf.path()].addEntry(cf);

    }

  }

  // Write all the makefiles, telling each

  // the path where it belongs:

  map<string, Makefile>::iterator mfi;

  for(mfi = makeFiles.begin(); 

    mfi != makeFiles.end(); mfi++)

    (*mfi).second.writeMakefiles((*mfi).first);

  // Create the master makefile:

  Makefile::writeMaster();

  // Write the makefile that tries the bug files:

  Makefile::writeMaster("bugs");

} ///:~

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -