📄 extractcode.cpp
字号:
};
// 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 + -