7 #include "llvm/Support/raw_ostream.h"
8 #include "llvm/System/Host.h"
9 #include "llvm/Config/config.h"
11 #include "clang/Frontend/DiagnosticOptions.h"
12 #include "clang/Frontend/TextDiagnosticPrinter.h"
14 #include "clang/Basic/LangOptions.h"
15 #include "clang/Basic/FileSystemOptions.h"
17 #include "clang/Index/TranslationUnit.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "clang/Lex/HeaderSearch.h"
20 #include "clang/Basic/FileManager.h"
22 #include "clang/Frontend/HeaderSearchOptions.h"
23 #include "clang/Frontend/Utils.h"
25 #include "clang/Basic/TargetOptions.h"
26 #include "clang/Basic/TargetInfo.h"
28 #include "clang/Lex/Preprocessor.h"
29 #include "clang/Frontend/PreprocessorOptions.h"
30 #include "clang/Frontend/FrontendOptions.h"
32 #include "clang/Frontend/CompilerInvocation.h"
34 #include "clang/Basic/IdentifierTable.h"
35 #include "clang/Basic/Builtins.h"
37 #include "clang/AST/ASTContext.h"
38 #include "clang/AST/ASTConsumer.h"
39 #include "clang/Sema/Sema.h"
40 #include "clang/AST/DeclBase.h"
41 #include "clang/AST/Type.h"
42 #include "clang/AST/Decl.h"
43 #include "clang/Sema/Lookup.h"
44 #include "clang/Sema/Ownership.h"
45 #include "clang/AST/DeclGroup.h"
47 #include "clang/Parse/Parser.h"
49 #include "clang/Parse/ParseAST.h"
50 #include "clang/Basic/Version.h"
52 #include "llvm/Support/CommandLine.h"
55 #include "stringoper.h"
56 #include "commandlineopt.h"
58 using namespace clang;
61 class MyDiagnosticClient : public TextDiagnosticPrinter
64 MyDiagnosticClient(llvm::raw_ostream &os, const DiagnosticOptions &diags, bool OwnsOutputStream = false):TextDiagnosticPrinter(os, diags, OwnsOutputStream = false){}
65 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info)
67 TextDiagnosticPrinter::HandleDiagnostic(DiagLevel, Info);
68 if(DiagLevel == 3) exit(1);
72 class FindStates : public ASTConsumer
74 std::list<string> transitions;
75 std::list<string> states;
76 std::string name_of_machine;
77 std::string name_of_start;
81 virtual void Initialize(ASTContext &ctx)//run after the AST is constructed
86 SourceManager &sman = ctx.getSourceManager();
87 fSloc = new FullSourceLoc(loc, sman);
90 virtual void HandleTopLevelDecl(DeclGroupRef DGR)// traverse all top level declarations
92 const SourceManager &sman = fSloc->getManager();
95 std::string super_class, output;
96 llvm::raw_string_ostream x(output);
97 for (DeclGroupRef::iterator i = DGR.begin(), e = DGR.end(); i != e; ++i)
99 const Decl *decl = *i;
100 loc = decl->getLocation();
103 const NamedDecl *namedDecl = dyn_cast<NamedDecl>(decl);
104 //std::cout<<decl->getDeclKindName()<<"\n";
105 if (const TagDecl *tagDecl = dyn_cast<TagDecl>(decl))
107 if(tagDecl->isStruct() || tagDecl->isClass()) //is it a structure or class
109 const CXXRecordDecl *cRecDecl = dyn_cast<CXXRecordDecl>(decl);
112 line = cut_commentary(clean_spaces(get_line_of_code(x.str())));
116 if(name_of_machine == "")
118 find_name_of_machine(cRecDecl, line);
122 if(find_states(cRecDecl, line))
124 const DeclContext *declCont = tagDecl->castToDeclContext(tagDecl);
125 std::cout << "New state: " << namedDecl->getNameAsString() << "\n";
126 find_transitions(namedDecl->getNameAsString(), declCont);
132 if(const NamespaceDecl *namespaceDecl = dyn_cast<NamespaceDecl>(decl))
134 DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl);
135 //declCont->dumpDeclContext();
136 recursive_visit(declCont);
142 void recursive_visit(const DeclContext *declCont) //recursively visit all decls hidden inside namespaces
144 const SourceManager &sman = fSloc->getManager();
145 std::string line, output;
147 llvm::raw_string_ostream x(output);
148 for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i)
150 const Decl *decl = *i;
151 const NamedDecl *namedDecl = dyn_cast<NamedDecl>(decl);
153 //std::cout<<"a "<<decl->getDeclKindName()<<"\n";
154 loc = decl->getLocation();
157 if (const TagDecl *tagDecl = dyn_cast<TagDecl>(decl))
159 if(tagDecl->isStruct() || tagDecl->isClass()) //is it a structure or class
161 const CXXRecordDecl *cRecDecl = dyn_cast<CXXRecordDecl>(decl);
163 line = cut_commentary(clean_spaces(get_line_of_code(x.str())));
167 if(name_of_machine == "")
169 find_name_of_machine(cRecDecl, line);
173 if(find_states(cRecDecl, line))
175 const DeclContext *declCont = tagDecl->castToDeclContext(tagDecl);
176 //states.push_back(namedDecl->getNameAsString());
177 std::cout << "New state: " << namedDecl->getNameAsString() << "\n";
178 find_transitions(namedDecl->getNameAsString(), declCont);
184 if(const NamespaceDecl *namespaceDecl = dyn_cast<NamespaceDecl>(decl))
186 DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl);
187 //declCont->dumpDeclContext();
188 recursive_visit(declCont);
193 bool find_states(const CXXRecordDecl *cRecDecl, std::string line) // test if the struct/class is the state (must be derived from simple_state)
195 std::string super_class = get_super_class(line), base;
196 if(cRecDecl->getNumBases()>1)
198 for(unsigned i = 0; i<cRecDecl->getNumBases();i++ )
200 if(i!=cRecDecl->getNumBases()-1) base = get_first_base(super_class);
201 else base = super_class;
202 if(is_state(super_class))
204 //std::cout<<get_params(super_class);
205 states.push_back(get_params(super_class));
210 super_class = get_next_base(super_class);
217 if(is_state(super_class))
219 //std::cout<<get_params(super_class);
220 states.push_back(get_params(super_class));
227 void find_name_of_machine(const CXXRecordDecl *cRecDecl, std::string line) // find name of the state machine and the start state
229 std::string super_class = get_super_class(line), base, params;
232 if(cRecDecl->getNumBases()>1)
234 for(unsigned i = 0; i<cRecDecl->getNumBases();i++ )
236 if(i!=cRecDecl->getNumBases()-1) base = get_first_base(super_class);
237 else base = super_class;
240 params = get_params(base);
241 pos = params.find(",");
242 name_of_machine = params.substr(0,pos);
243 name_of_start = params.substr(pos);
244 std::cout<<"Name of the state machine: "<<name_of_machine<<"\n";
245 std::cout<<"Name of the first state: "<<name_of_start<<"\n";
249 super_class = get_next_base(super_class);
255 if(is_machine(super_class))
257 //std::cout<<super_class;
258 params = get_params(super_class);
260 pos = params.find(",");
261 name_of_machine = cut_namespaces(params.substr(0,pos));
262 name_of_start = cut_namespaces(params.substr(pos+1));
263 std::cout<<"Name of the state machine:"<<name_of_machine<<"\n";
264 std::cout<<"Name of the first state:"<<name_of_start<<"\n";
269 void find_transitions (const std::string name_of_state,const DeclContext *declCont) // traverse all methods for finding declarations of transitions
271 std::string output, line, dest, params, base;
272 llvm::raw_string_ostream x(output);
274 for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i)
276 const Decl *decl = *i;
277 if (const TypedefDecl *typedDecl = dyn_cast<TypedefDecl>(decl))
281 line = clean_spaces(cut_typedef(output));
282 num = count(output,'<');
288 line = get_inner_part(line);
291 for(int j = 0;j<num;j++)
293 if(j!=num-1) base = get_first_base(line);
295 if(is_transition(base))
297 dest = name_of_state;
298 params = get_params(base);
301 transitions.push_back(dest);
302 line = get_next_base(line);
306 line = get_next_base(line);
314 void save_to_file(std::string output)
316 std::string state, str, context, ctx;
317 int pos1, pos2, cnt, subs;
318 std::ofstream filestr(output.c_str());
319 std::cout<<output<<"\n";
320 filestr<<"digraph "<< name_of_machine<< " {\n";
321 context = name_of_machine;
322 for(list<string>::iterator i = states.begin();i!=states.end();i++) // write all states in the context of the automaton
325 cnt = count(state,',');
328 pos1 = state.find(",");
329 ctx = cut_namespaces(state.substr(pos1+1));
330 //std::cout<<name_of_machine.length();
331 if(ctx.compare(0,context.length(),context)==0)
333 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
340 pos1 = state.find(",");
341 pos2 = state.rfind(",");
342 ctx = cut_namespaces(state.substr(pos1+1,pos2-pos1-1));
343 //std::cout<<ctx<<" "<<context<<"\n";
344 if(ctx.compare(0,context.length(),context)==0)
346 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
350 filestr<<name_of_start<<" [peripheries=2] ;\n";
352 while(!states.empty()) // substates ?
354 state = states.front();
355 filestr<<"subgraph cluster"<<subs<<" {\n";
356 pos1 = state.find(",");
357 pos2 = state.rfind(",");
358 context = cut_namespaces(state.substr(0,pos1));
359 filestr<<"label=\""<<context<<"\";\n";
360 filestr<<cut_namespaces(state.substr(pos2+1))<<" [peripheries=2] ;\n";
362 //std::cout<<states.size();
363 for(list<string>::iterator i = states.begin();i!=states.end();i++)
366 cnt = count(state,',');
367 //std::cout<<state<<" \n";
370 pos1 = state.find(",");
371 ctx = cut_namespaces(state.substr(pos1+1));
373 //std::cout<<ctx<<" "<<context<<"\n";
374 if(ctx.compare(0,context.length(),context)==0)
376 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
383 pos1 = state.find(",");
384 pos2 = state.rfind(",");
385 ctx = cut_namespaces(state.substr(pos1+1,pos2-pos1-1));
386 if(ctx.compare(0,context.length(),context)==0)
388 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
389 //std::cout<<ctx<<"\n";
396 for(list<string>::iterator i = transitions.begin();i!=transitions.end();i++) // write all transitions
399 pos1 = state.find(",");
400 filestr<<cut_namespaces(state.substr(0,pos1))<<"->";
401 pos2 = state.rfind(",");
402 filestr<<cut_namespaces(state.substr(pos2+1));
403 filestr<<"[label=\""<<cut_namespaces(state.substr(pos1+1,pos2-pos1-1))<<"\"];\n";
410 int main(int argc, char *argv[])
412 llvm::cl::ParseCommandLineOptions(argc, argv);
413 std::cout<<"Input file: "<<inputFilename<<"\n";
414 FILE* fileI = fopen(inputFilename.c_str(), "r");
417 perror(inputFilename.c_str());
421 DiagnosticOptions diagnosticOptions;
422 llvm::IntrusiveRefCntPtr<DiagnosticIDs> dis(new DiagnosticIDs());
423 MyDiagnosticClient *mdc = new MyDiagnosticClient(llvm::outs(), diagnosticOptions);
424 Diagnostic diag(dis,mdc);
425 diag.setIgnoreAllWarnings(true);
426 FileSystemOptions fileSysOpt;
430 FileManager fm (fileSysOpt);
432 SourceManager sm ( diag, fm);
433 HeaderSearch *headers = new HeaderSearch(fm);
434 CompilerInvocation::setLangDefaults(lang, IK_ObjCXX);
436 HeaderSearchOptions hsopts;
437 hsopts.ResourceDir=LLVM_PREFIX "/lib/clang/" CLANG_VERSION_STRING;
438 for(unsigned i = 0; i<includeFiles.size();i++)
440 hsopts.AddPath(includeFiles[i],
441 clang::frontend::Angled,
447 to.Triple = llvm::sys::getHostTriple();
448 TargetInfo *ti = TargetInfo::CreateTargetInfo(diag, to);
449 clang::ApplyHeaderSearchOptions(
454 Preprocessor pp(diag, lang, *ti, sm, *headers);
455 pp.getBuiltinInfo().InitializeBuiltins(pp.getIdentifierTable(),
456 pp.getLangOptions());
458 PreprocessorOptions ppio;
459 InitializePreprocessor(pp, ppio,hsopts,f);
460 const FileEntry *file = fm.getFile(inputFilename);
461 sm.createMainFileID(file);
462 IdentifierTable tab(lang);
464 Builtin::Context builtins(*ti);
466 ASTContext ctx(lang, sm, *ti, tab, sel, builtins,0);
467 mdc->BeginSourceFile(lang, &pp);
468 ParseAST(pp, &c, ctx, false, false);
469 mdc->EndSourceFile();
470 c.save_to_file(outputFile);