1
#include "Puma/CCParser.h"
2
#include "Puma/ErrorStream.h"
3
#include "Puma/UnitIterator.h"
4
#include "Puma/CTokens.h"
5
#include "Puma/PreParser.h"
10
typedef std::set<int> LineNumbers;
11
typedef std::map<const char*,LineNumbers> Macros;
14
int main (int argc, char **argv) {
16
std::cout << "Extract C preprocessor macro names from a file" << std::endl;
17
std::cout << "usage: macronames <filename>" << std::endl;
22
Puma::ErrorStream err;
23
Puma::CProject project(err, argc, argv);
24
Puma::Unit *file = project.scanFile(argv[argc-1]);
26
std::cerr << argv[argc-1] << ": unable to scan input file" << std::endl;
30
// find macro names in the token lists of #if, #elseif,
31
// #ifdef, and #ifndef directives
33
Puma::UnitIterator token(*file);
34
for (; *token; ++token) {
35
if (token->is_preprocessor()) {
36
int type = token->type();
37
if (type == TOK_PRE_IF || type == TOK_PRE_ELIF) {
38
// search for identifiers, ignore special identifier "defined"
39
int line = token->location().line();
40
for (++token; *token; ++token) {
41
if (token->is_whitespace()) {
42
// white space, let's see if it is the end of the directive
43
const char *c = token->text().c_str();
44
for (; *c && *c != '\n'; c++);
46
// end of directive, stop searching for macro names
49
} else if (token->is_identifier() && strcmp(token->text().c_str(), "defined") != 0) {
51
macros[token->text().c_str()].insert(token->location().line());
54
} else if (type == TOK_PRE_IFDEF || type == TOK_PRE_IFNDEF) {
55
// skip comments and white spaces
56
for (++token; *token && (token->is_comment() || token->is_whitespace()); ++token);
57
if (*token && token->is_identifier()) {
59
macros[token->text().c_str()].insert(token->location().line());
65
// print the macro names and the line numbers where they are called (XML)
66
std::cout << "<?xml version=\"1.0\"?>\n<macros>" << std::endl;
67
Macros::const_iterator macro = macros.begin();
68
for (; macro != macros.end(); ++macro) {
69
std::cout << " <macro name=\"" << macro->first << "\">" << std::endl;
70
LineNumbers::const_iterator number = macro->second.begin();
71
for (; number != macro->second.end(); ++number) {
72
std::cout << " <line>" << *number << "</line>" << std::endl;
74
std::cout << " </macro>" << std::endl;
76
std::cout << "</macros>" << std::endl;