Date: 18 Apr 2002 05:53:51 -0700 From: Max Okumoto <okumoto@ucsd.edu> To: freebsd-libh@FreeBSD.ORG Subject: *.cd.cc parser Message-ID: <hf662p417k.fsf@multivac.sdsc.edu>
next in thread | raw e-mail | index | archive | help
Here is my *cd.cc parser can people check if it parses and generates
the same kind of output as the perl version? Currently the only difference
that I can find is the sort order of the header includes. The ordering
is for perl hashs vs C++ map<>. Which should not cause any problems...
I don't really plan to use it in the build process, since that would
complicate matters. I am looking into merging it with HSystem.
*.cd.cc -> build_systems_*.cc -> tcl_interface_gen_* -> LibTclInterface_*.cc
would become
*.cd.cc -> LibTclInterface_*.cc
Max Okumoto
---------------------%<----------------%<--------------
/**
* @file
*/
#include <fstream>
#include <map>
#include <set>
#include <string>
#include <vector>
extern "C" {
#include <unistd.h> /* getopt() */
#include <string.h> /* strlen() */
}
class ClassDescParser {
typedef string FilePath;
typedef string DirPath;
typedef string SysName;
typedef string ClassDesc;
typedef set<FilePath> FileSet;
typedef vector<ClassDesc> ClassDescV;
typedef map<FilePath, ClassDescV> MapV;
typedef map<DirPath, SysName> Map;
FileSet files;
MapV classes;
Map systems;
public:
/**
* Process the contents of the ClassDescription file (*.cd.cc).
*
* @param filename name of file to process.
*/
void
process_file(const string &filename)
{
ifstream file(filename.c_str());
char buff[4096];
while (file.getline(buff, sizeof(buff))) {
string line(buff);
/* remove C++ style comments from line */
string::size_type pos = line.find("//");
if (pos != string::npos) {
line.erase(pos);
}
/*
* LanguageInterface::Object::ClassDescription ([^\s]+)::sClassDescription[^A-Za-z0-9]/
*/
string prefix("LanguageInterface::Object::ClassDescription ");
string suffix("::sClassDescription");
/* Find lines which contain prefix */
pos = line.find(prefix);
if (pos == string::npos) {
continue; /* line does not contain prefix */
}
string cd = line.substr(pos + prefix.length());
pos = cd.find(suffix);
/* class description must also contain the suffix */
assert(pos != string::npos);
/* char following suffix should not be alpha or number */
assert(!isalnum(cd[pos + suffix.length()]));
cd.erase(pos);
assert(cd.find_first_of(" \t") == string::npos);
classes[filename].push_back(cd);
}
file.close();
files.insert(filename);
}
/**
* Output the build_systems_*.cc file.
*
* @param prog Name of generator program.
* @param the_only_system (Don't know yet.)
*/
void
gen_file(const string &prog, const string *the_only_system)
{
cout << "/*\n"
" * This file is automatically generated by " << prog << ",\n"
" * do not edit!\n"
" */\n"
"\n"
"#ifndef HSystem_hh\n"
"#include \"HSystem.hh\"\n"
"#endif\n"
"\n"
"#define H_BUILD_SYSTEMS 1\n"
"\n";
for (MapV::iterator i = classes.begin(); i != classes.end(); ++i) {
FilePath filename = i->first;
string::size_type pos = filename.rfind('/');
assert(pos != string::npos); /* contains at least 1 slash */
string system = filename.substr(0, pos);
string file = filename.substr(pos + 1);
if (the_only_system == NULL) {
pos = system.rfind('/');
assert(pos != string::npos); /* contains 1 slash */
systems[system] = system.substr(pos + 1);
} else {
systems[*the_only_system] = *the_only_system;
}
pos = system.rfind('/');
pos = system.rfind('/', pos);
string systemdir = system.substr(pos + 1);
/* remove ".cd.cc" suffix */
pos = file.find(".cd.cc");
assert(pos != string::npos); /* contains ".cd.cc" */
assert(file.length() == pos + strlen(".cd.cc")); /* at end */
file.erase(pos);
if (systemdir == "common") {
cout << "#ifndef " << file << "_hh\n"
"#include \"" << file << ".hh\"\n"
"#endif\n"
"\n";
} else {
cout << "#ifndef " << file << "_hh\n"
"#include \"" << systemdir << "/" << file << ".hh\"\n"
"#endif\n"
"\n";
}
}
cout << "void\n"
"build_systems(Systems& systems)\n"
"{\n";
for (Map::iterator i = systems.begin(); i != systems.end(); ++i) {
DirPath system = i->first;
SysName sysname = i->second;
cout <<
"\tpair<Systems::iterator,bool> s = systems.insert(HSystem(\"" << sysname << "\"));\n"
"\tif (!s.second)\n"
"\t throw runtime_error(string(\"System \") + s.first->name + \" already exists\");\n"
"\tHSystem& system = const_cast<HSystem&>(*s.first);\n";
for (FileSet::iterator j = files.begin(); j != files.end(); ++j) {
FilePath filename = *j;
if ((the_only_system != NULL) || (filename.substr(0, system.length() + 1) == (system + '/'))) {
ClassDescV cl = classes[filename];
for (ClassDescV::iterator k = cl.begin(); k != cl.end(); ++k) {
cout <<
"\tsystem.add_class(" << *k << "::thisClassDescription(),\n"
"\t\t\t" << *k << "::fileToInclude());\n";
}
}
}
}
cout << "} /* build systems */ \n"
"\n";
}
};
/**
* Outputs usage information.
*
* @param prog Name of binary
*/
static void
usage(const string &prog)
{
cout << "Usage: " << prog << " -s <system> <file-to-scan> ...\n";
}
/**
* The main program.
*
* It parses the command line arguments, and checks for input files.
*/
int
main(int argc, char *argv[])
{
/*************************************************************************
* Parse command line args
*************************************************************************/
const string prog(argv[0]);
string *the_only_system = NULL;
int c;
while ((c = getopt(argc, argv, "s:")) != -1) {
switch (c) {
case 's':
the_only_system = new string(optarg);
break;
case '?':
default:
usage(prog);
return(1); /* bad cli options */
}
}
argc -= optind;
argv += optind;
if (argc < 1) {
usage(prog);
return(1); /* missing input files */
}
/*************************************************************************
* process files
*************************************************************************/
ClassDescParser parser;
for (int i = 0; i < argc; ++i) {
parser.process_file(argv[i]);
}
parser.gen_file(prog, the_only_system);
delete the_only_system;
return(0);
}
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-libh" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?hf662p417k.fsf>
