From cecfba7b6fd2bf47cae4308e565babb2c7bf8a8d Mon Sep 17 00:00:00 2001 From: petr000 Date: Wed, 18 May 2011 14:42:01 +0200 Subject: [PATCH] Create dir for MSVC version source files. Update commentaries at source files. --- examples/test.cpp | 14 +- src/doxyConfig | 4 +- src/iooper.h | 20 +- src/visualizer.cpp | 79 ++++--- src_MSVC/iooper.h | 310 +++++++++++++++++++++++++ src_MSVC/stringoper.h | 358 +++++++++++++++++++++++++++++ src_MSVC/visualizer.cpp | 489 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1215 insertions(+), 59 deletions(-) create mode 100644 src_MSVC/iooper.h create mode 100644 src_MSVC/stringoper.h create mode 100644 src_MSVC/visualizer.cpp diff --git a/examples/test.cpp b/examples/test.cpp index 3a0ec11..8498130 100644 --- a/examples/test.cpp +++ b/examples/test.cpp @@ -18,8 +18,8 @@ struct state_1; // definice stavu struct state_2; // definice stavu struct state_3; // definice stavu struct state_4; // definice stavu -struct EvA : sc::event< EvA > {};//stisteno A -struct EvN : sc::event< EvN > {};//stisteno N +struct EvYes : sc::event< EvYes > {};//stisteno A +struct EvNo : sc::event< EvNo > {};//stisteno N struct EvTimer : sc::event< EvTimer > {};//vyprsel cas struct DU : sc::state_machine< DU, state_1 > {};//Nastaveni inicializacniho stavu @@ -39,8 +39,8 @@ struct state_1 : sc::simple_state< state_1, DU> // stav state_1() { cout<<"Chcete zformatovat vas disk (a/n) ? \n";}//FSM_Entry ~state_1() {}//FSM_Exit typedef mpl::list< // reakce na udalosti - sc::transition< EvA, state_4 >, - sc::transition< EvN, state_2 > > reactions; + sc::transition< EvYes, state_4 >, + sc::transition< EvNo, state_2 > > reactions; }; struct state_2 : sc::simple_state< state_2, DU > { @@ -81,7 +81,7 @@ struct state_3 : sc::simple_state< state_3, DU > } ~state_3() {} typedef mpl::list< - sc::transition< EvN, state_1 >, + sc::transition< EvNo, state_1 >, sc::transition< EvTimer, state_4 > > reactions; }; struct state_4 : sc::simple_state< state_4, DU > @@ -111,8 +111,8 @@ void *nacitani (void * ptr) while(1) { cin >> s; - if (s == "n") Zm.process_event (EvN()); - if (s == "a") Zm.process_event (EvA()); + if (s == "n") Zm.process_event (EvNo()); + if (s == "a") Zm.process_event (EvYes()); if (s == "exit") break; } return NULL; diff --git a/src/doxyConfig b/src/doxyConfig index a9ac51d..a6d3286 100644 --- a/src/doxyConfig +++ b/src/doxyConfig @@ -298,12 +298,12 @@ SYMBOL_CACHE_SIZE = 0 # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES -EXTRACT_ALL = NO +EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. -EXTRACT_PRIVATE = NO +EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. diff --git a/src/iooper.h b/src/iooper.h index a8a8910..a5bd254 100644 --- a/src/iooper.h +++ b/src/iooper.h @@ -1,4 +1,4 @@ - +/** @file */ //////////////////////////////////////////////////////////////////////////////////////// // // This file is part of Boost Statechart Viewer. @@ -30,14 +30,14 @@ using namespace std; * This class provides saving information about state machine to a specified output file. It saves states and transitions and also it creates the transition table. */ class IO_operations -{ - list transitions; - list states; - list events; - string outputFilename; +{ + list transitions; /** list of transitions */ + list states; /** list of states */ + list events; /** list of events */ + string outputFilename; string name_of_machine; string name_of_first_state; - string *table; + string *table; /** transition table. It is being allocated when starting the creation of output file. */ int nState; int cols, rows; /** This function finds place in the transition table to put a transition there. */ @@ -58,7 +58,8 @@ class IO_operations return -1; } public: - IO_operations() {} + IO_operations() {} /** Implicit constructor */ + /** Constructor that fill in all private variables in this class */ IO_operations( const string outputFile, const string FSM_name, const string firstState, const list trans, const list state, const list ev ) { outputFilename = outputFile; @@ -68,7 +69,8 @@ class IO_operations states = state; events = ev; } - ~IO_operations() + + ~IO_operations() /** destructor. It deallocates the transition table.*/ { delete table; } diff --git a/src/visualizer.cpp b/src/visualizer.cpp index 4616906..475682b 100644 --- a/src/visualizer.cpp +++ b/src/visualizer.cpp @@ -1,4 +1,4 @@ -/** @file */ +/** @file */ //////////////////////////////////////////////////////////////////////////////////////// // // This file is part of Boost Statechart Viewer. @@ -54,27 +54,24 @@ using namespace std; */ class MyDiagnosticClient : public TextDiagnosticPrinter { - /** - * Variables for saving numbers of warnings, errors, ... - */ - int nwarnings; + int nwarnings; /** Save number of Warnings occured during diagnostic */ int nnotes; int nignored; int nerrors; public: - /** - * Initialize number of warnings, errors, ... - */ - MyDiagnosticClient(llvm::raw_ostream &os, const DiagnosticOptions &diags, bool OwnsOutputStream = false):TextDiagnosticPrinter(os, diags, OwnsOutputStream = false) + /** + * Initialize number of warnings, errors, ... + */ + MyDiagnosticClient(llvm::raw_ostream &os, const DiagnosticOptions &diags, bool OwnsOutputStream = false):TextDiagnosticPrinter(os, diags, OwnsOutputStream = false) { nwarnings=0; nnotes=0; nignored=0; nerrors = 0; } - /** - * This method prints diagnostic and counts diagnostic types. - */ + /** + * This method prints diagnostic and counts diagnostic types. + */ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info) { TextDiagnosticPrinter::HandleDiagnostic(DiagLevel, Info); // print diagnostic information using library implementation @@ -88,10 +85,10 @@ class MyDiagnosticClient : public TextDiagnosticPrinter exit(1); } } - /** - * Print statistics about diagnostic - */ - void print_stats() + /** + * Print statistics about diagnostic. + */ + void print_stats() { cout<<"\n--Diagnostic Info--\n"; cout<<"Number of ignored: "< transitions; - list cReactions; + list transitions; + list cReactions; /** list of custom reactions. After all files are traversed this list should be empty. */ list events; list states; string name_of_machine; string name_of_start; - FullSourceLoc *fsloc; + FullSourceLoc *fsloc; /** Full Source Location instance for holding Source Manager. */ public: - list getStates() /** Return list of states. */ + list getStates() /** Return list of states. */ { return states; } - list getTransitions() /** Return list of transitions. */ + list getTransitions() /** Return list of transitions. */ { return transitions; } - list getEvents() /** Return list of events. */ + list getEvents() /** Return list of events. */ { return events; } - string getStateMachine() /** Return name of the state machine. */ + string getStateMachine() /** Return name of the state machine. */ { return name_of_machine; } - string getNameOfFirstState() /** Return name of start state. */ + string getNameOfFirstState() /** Return name of start state. */ { return name_of_start; } - virtual void Initialize(ASTContext &ctx)/** Run after the AST is constructed before the consumer starts to work. So this function works like constructor. */ + virtual void Initialize(ASTContext &ctx)/** Run after the AST is constructed before the consumer starts to work. So this function works like constructor. */ { fsloc = new FullSourceLoc(* new SourceLocation(), ctx.getSourceManager()); name_of_start = ""; @@ -163,10 +160,10 @@ class FindStates : public ASTConsumer } /** -* Traverse global decls using DeclGroupRef for handling all global decls. But only interesting decls are processed. Interesting decls are Struct, Class, Method and Namespace. +* Traverse global decls using DeclGroupRef for handling all global decls. But only interesting decls are processed. Interesting decls are Struct, Class, C++ methods and Namespace. * When Namespace is found it recursively traverse all decls inside this Namespace using method recursive_visit. */ - virtual void HandleTopLevelDecl(DeclGroupRef DGR) + virtual void HandleTopLevelDecl(DeclGroupRef DGR) { SourceLocation loc; string line, output, event; @@ -203,9 +200,9 @@ class FindStates : public ASTConsumer /** * It is used to recursive traverse decls in Namespaces. This method do the same as HandleTopLevelDecl. */ - void recursive_visit(const DeclContext *declCont) + void recursive_visit(const DeclContext *declCont) { - string line, output, event; + string line, output, event; llvm::raw_string_ostream x(output); SourceLocation loc; for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i) @@ -239,7 +236,7 @@ class FindStates : public ASTConsumer * This function works with class or struct. It splits the decl into 3 interesting parts. * The state machine decl, state decl and event decl. */ - void struct_class(const Decl *decl) + void struct_class(const Decl *decl) { string output, line, ret, trans, event; llvm::raw_string_ostream x(output); @@ -280,9 +277,9 @@ class FindStates : public ASTConsumer /** * This function provides traversing all methods and other context indide class. If -* typedef or classic method decl is found. Transitions inside it are beiing founded. +* typedef or classic method decl is found. If typedef is found then it is being testted for transitions and custom reactions. */ - void methods_in_class(const Decl *decl, const string state) + void methods_in_class(const Decl *decl, const string state) { string output, line, ret, trans, event; llvm::raw_string_ostream x(output); @@ -326,10 +323,10 @@ class FindStates : public ASTConsumer } } - /** - * Traverse Method declaration using classes Stmt. - */ - void method_decl(const Decl *decl) + /** + * Traverse method declaration using classes with main class Stmt. + */ + void method_decl(const Decl *decl) { string output, line, event; llvm::raw_string_ostream x(output); @@ -363,7 +360,7 @@ class FindStates : public ASTConsumer } } - void find_return_stmt(Stmt *statemt,string event) /** Traverse all statements in function for finding return Statement*/ + void find_return_stmt(Stmt *statemt,string event) /** Traverse all statements in function for finding all return Statements.*/ { if(statemt->getStmtClass() == 99) test_stmt(dyn_cast(statemt)->getSubStmt(), event); else @@ -375,7 +372,7 @@ class FindStates : public ASTConsumer } } - void test_stmt(Stmt *stmt, string event) /** test statement for its kind*/ + void test_stmt(Stmt *stmt, string event) /** test statement for its kind Using number as identifier for all Statement Classes.*/ { const SourceManager &sman = fsloc->getManager(); int type; diff --git a/src_MSVC/iooper.h b/src_MSVC/iooper.h new file mode 100644 index 0000000..a5bd254 --- /dev/null +++ b/src_MSVC/iooper.h @@ -0,0 +1,310 @@ +/** @file */ +//////////////////////////////////////////////////////////////////////////////////////// +// +// This file is part of Boost Statechart Viewer. +// +// Boost Statechart Viewer is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Boost Statechart Viewer is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boost Statechart Viewer. If not, see . +// +//////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "stringoper.h" + +using namespace std; + +/** +* This class provides saving information about state machine to a specified output file. It saves states and transitions and also it creates the transition table. +*/ +class IO_operations +{ + list transitions; /** list of transitions */ + list states; /** list of states */ + list events; /** list of events */ + string outputFilename; + string name_of_machine; + string name_of_first_state; + string *table; /** transition table. It is being allocated when starting the creation of output file. */ + int nState; + int cols, rows; + /** This function finds place in the transition table to put a transition there. */ + int find_place(string model, int type) + { + if(type == 1) + { + for(int i = 3;i trans, const list state, const list ev ) + { + outputFilename = outputFile; + name_of_machine = FSM_name; + name_of_first_state = firstState; + transitions = trans; + states = state; + events = ev; + } + + ~IO_operations() /** destructor. It deallocates the transition table.*/ + { + delete table; + } + + void setEvents(list events) /** Set list of events to an attribute */ + { + this->events = events; + } + + void setTransitions(list transitions) /** Set list of transitions to an attribute */ + { + this->transitions = transitions; + } + + void setStates(list states) /** Set list of states to an attribute */ + { + this->states = states; + } + + void setNameOfStateMachine(string name_of_FSM) /** Set name of FSM to an attribute */ + { + name_of_machine = name_of_FSM; + } + + void setNameOfFirstState(string first_state) /** Set name of start state to an attribute */ + { + name_of_first_state = first_state; + } + + void setOutputFilename(string outputFilename) /** Set name of an output file to an attribute */ + { + this->outputFilename = outputFilename; + } + + bool write_states(ofstream& filestr) /** This method write states to the output file and also to transition table. */ + { + int pos1, pos2, cnt, subs; + nState = 1; + string context, state, ctx, sState, str; + list nstates = states; + context = name_of_machine; + table[0] = "S"; + table[1] = "Context"; + table[2] = "State"; + for(list::iterator i = nstates.begin();i!=nstates.end();i++) // write all states in the context of the automaton + { + state = *i; + cnt = count(state,','); + if(cnt==1) + { + pos1 = state.find(","); + ctx = cut_namespaces(state.substr(pos1+1)); + if(ctx.compare(0,context.length(),context)==0) + { + str = cut_namespaces(state.substr(0,pos1)); + filestr<::iterator i = nstates.begin();i!=nstates.end();i++) + { + state = *i; + cnt = count(state,','); + if(cnt==1) + { + pos1 = state.find(","); + ctx = cut_namespaces(state.substr(pos1+1)); + if(ctx.compare(0,context.length(),context)==0) + { + str = cut_namespaces(state.substr(0,pos1)); + filestr<::iterator i = transitions.begin();i!=transitions.end();i++) // write all transitions + { + params = *i; + pos1 = params.find(","); + state = cut_namespaces(params.substr(0,pos1)); + filestr<"; + pos2 = params.rfind(","); + dest = cut_namespaces(params.substr(pos2+1)); + filestr<::iterator i = events.begin();i!=events.end();i++) + { + table[j] = *i; + j++; + } + } + + void save_to_file() /** Create output file stream and write there the name of state machine. It controls the whole process of writing into output files. */ + { + if(!name_of_first_state.empty()) + { + ofstream filestr(outputFilename.c_str()); + filestr<<"digraph "<< name_of_machine<< " {\n"; + cols = events.size()+3; + rows = states.size()+1; + table = new string [cols*rows]; + fill_table_with_events(); + if(!write_states(filestr)) + { + cerr<<"Error during writing states.\n"; + filestr<<"}"; + filestr.close(); + return; + } + write_transitions(filestr); + filestr<<"}"; + filestr.close(); + print_table(); + } + else cout<<"No state machine was found. So no output file was created.\n"; + return; + } + + void print_table() /** This function prints the transition table. At first it counts the size of all columns. */ + { + cout<<"\nTRANSITION TABLE\n"; + unsigned * len = new unsigned[cols]; + len[0] = 1; + string line = "-|---|-"; + for(int i = 1; i. +// +//////////////////////////////////////////////////////////////////////////////////////// + +#include + +using namespace std; +using namespace clang; + +string clean_spaces(const string line) /** Remove gaps from string.*/ +{ + unsigned i; + string new_line = ""; + for(i = 0;i') brackets-=1; + if(line[i]==',' && brackets == 0) break; + } + return line.substr(i+1); +} + +string get_first_base(const string line) /** Get the first super class of this declarations. */ +{ + unsigned i; + int brackets = 0; + for(i = 0;i') brackets-=1; + if(line[i]==',' && brackets == 0) break; + } + return line.substr(0,i); +} + +bool is_state(const string line) /** Test if this declaration is a state. It is used to test the base classes. */ +{ + if(cut_namespaces(line).compare(0,12,"simple_state")==0) + { + return true; + } + else + { + if(cut_namespaces(line).compare(0,5,"state")==0) + { + return true; + } + return false; + } +} + +string cut_type(string line) /** This function cuts type of the declaration from the string. */ +{ + unsigned i; + for(i = 0;i') + { + if(pos==0) break; + else pos-=1; + } + } + return str.substr(0,i); +} + +bool test_model(const string line, const string model) /** Test the string to has a specified model. */ +{ + if(cut_namespaces(line).compare(0,model.length(),model)==0) + { + return true; + } + else + { + return false; + } +} + +string get_params(string line) /** Return parameters of the specified transition */ +{ + int pos_front = line.find("<")+1; + int pos_end = line.find(">"); + return line.substr(pos_front,pos_end-pos_front); +} + +string find_states(const CXXRecordDecl *cRecDecl, string line) /** test if the struct/class is he state (must be derived from simple_state or state). */ +{ + string super_class = get_super_class(line), base, params; + if(cRecDecl->getNumBases()>1) + { + for(unsigned i = 0; igetNumBases();i++ ) + { + if(i!=cRecDecl->getNumBases()-1) base = get_first_base(super_class); + else base = super_class; + if(is_state(super_class)) + { + params = get_params(super_class); + } + else + { + super_class = get_next_base(super_class); + } + } + } + else + { + if(is_state(super_class)) + { + params = get_params(super_class); + } + else params = ""; + } + return params; +} + +string find_name_of_machine(const CXXRecordDecl *cRecDecl, string line) /** Find name of the state machine and the start state. */ +{ + string super_class = get_super_class(line), base, params; + if(cRecDecl->getNumBases()>1) + { + for(unsigned i = 0; igetNumBases();i++ ) + { + if(i!=cRecDecl->getNumBases()-1) base = get_first_base(super_class); + else base = super_class; + if(test_model(base,"state_machine")) + { + params = get_params(base); + } + else + { + super_class = get_next_base(super_class); + } + } + } + else + { + if(test_model(super_class,"state_machine")) + { + params = get_params(super_class); + } + } + return params; +} + +string find_transitions (const string name_of_state, string line) /** Traverse all methods for finding declarations of transitions. */ +{ + string dest, params, base, trans; + int num = count(line,'<'); + if(num>1) + { + num-=1; + if(is_list(line)) + { + line = get_inner_part(line); + } + } + for(int j = 0;jgetNumBases()>1) + { + for(unsigned i = 0; igetNumBases();i++ ) + { + if(i!=cRecDecl->getNumBases()-1) base = get_first_base(super_class); + else base = super_class; + if(test_model(base,"event")) return true; + else + { + super_class = get_next_base(super_class); + } + } + } + else + { + if(test_model(super_class,"event"))return true; + } + return false; +} + diff --git a/src_MSVC/visualizer.cpp b/src_MSVC/visualizer.cpp new file mode 100644 index 0000000..5c93918 --- /dev/null +++ b/src_MSVC/visualizer.cpp @@ -0,0 +1,489 @@ +/** @file */ +//////////////////////////////////////////////////////////////////////////////////////// +// +// This file is part of Boost Statechart Viewer. +// +// Boost Statechart Viewer is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Boost Statechart Viewer is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boost Statechart Viewer. If not, see . +// +//////////////////////////////////////////////////////////////////////////////////////// + +//standard header files +#include + +//LLVM Header files +#include "llvm\Support\raw_ostream.h" +#include "llvm\Support\Host.h" +#include "llvm\Config\config.h" + +//clang header files +#include "clang\Frontend\TextDiagnosticPrinter.h" +#include "clang\Lex\HeaderSearch.h" +#include "clang\Basic\FileManager.h" +#include "clang\Frontend\Utils.h" +#include "clang\Basic\TargetInfo.h" +#include "clang\Lex\Preprocessor.h" +#include "clang\Frontend\CompilerInstance.h" +#include "clang\AST\ASTConsumer.h" +#include "clang\Sema\Lookup.h" +#include "clang\Parse\ParseAST.h" +#include "clang\Basic\Version.h" +#include "clang\Driver\Driver.h" +#include "clang\Driver\Compilation.h" + +//my own header files +#include "iooper.h" + +using namespace clang; +using namespace clang::driver; +using namespace std; + +/** + * This class provides Simple diagnostic Client. It uses implementation in library for printing diagnostci information. + * Also it counts number of warnings, errors, ... When an error occurs the program is stopped. + */ +class MyDiagnosticClient : public TextDiagnosticPrinter +{ + int nwarnings; /** Save number of Warnings occured during diagnostic */ + int nnotes; + int nignored; + int nerrors; + public: + /** + * Initialize number of warnings, errors, ... + */ + MyDiagnosticClient(llvm::raw_ostream &os, const DiagnosticOptions &diags, bool OwnsOutputStream = false):TextDiagnosticPrinter(os, diags, OwnsOutputStream = false) + { + nwarnings=0; + nnotes=0; + nignored=0; + nerrors = 0; + } + /** + * This method prints diagnostic and counts diagnostic types. + */ + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info) + { + TextDiagnosticPrinter::HandleDiagnostic(DiagLevel, Info); // print diagnostic information using library implementation + switch (DiagLevel) // count number of all diagnostic information + { + case 0 : nignored+=1; break; + case 1 : nnotes+=1; break; + case 2 : nwarnings+=1; break; + default : nerrors+=1; + print_stats(); + exit(1); + } + } + /** + * Print statistics about diagnostic. + */ + void print_stats() + { + cout<<"\n--Diagnostic Info--\n"; + cout<<"Number of ignored: "< transitions; + list cReactions; /** list of custom reactions. After all files are traversed this list should be empty. */ + list events; + list states; + string name_of_machine; + string name_of_start; + FullSourceLoc *fsloc; /** Full Source Location instance for holding Source Manager. */ + public: + + list getStates() /** Return list of states. */ + { + return states; + } + + list getTransitions() /** Return list of transitions. */ + { + return transitions; + } + + list getEvents() /** Return list of events. */ + { + return events; + } + + string getStateMachine() /** Return name of the state machine. */ + { + return name_of_machine; + } + + string getNameOfFirstState() /** Return name of start state. */ + { + return name_of_start; + } + + virtual void Initialize(ASTContext &ctx)/** Run after the AST is constructed before the consumer starts to work. So this function works like constructor. */ + { + fsloc = new FullSourceLoc(* new SourceLocation(), ctx.getSourceManager()); + name_of_start = ""; + name_of_machine = ""; + } + +/** +* Traverse global decls using DeclGroupRef for handling all global decls. But only interesting decls are processed. Interesting decls are Struct, Class, C++ methods and Namespace. +* When Namespace is found it recursively traverse all decls inside this Namespace using method recursive_visit. +*/ + virtual void HandleTopLevelDecl(DeclGroupRef DGR) + { + SourceLocation loc; + string line, output, event; + llvm::raw_string_ostream x(output); + for (DeclGroupRef::iterator i = DGR.begin(), e = DGR.end(); i != e; ++i) + { + const Decl *decl = *i; + loc = decl->getLocation(); + if(loc.isValid()) + { + if(decl->getKind()==35) + { + method_decl(decl); + } + if (const TagDecl *tagDecl = dyn_cast(decl)) + { + if(tagDecl->isStruct() || tagDecl->isClass()) //is it a struct or class + { + struct_class(decl); + } + } + if(const NamespaceDecl *namespaceDecl = dyn_cast(decl)) + { + + DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl); + recursive_visit(declCont); + + } + } + output = ""; + } + } + +/** +* It is used to recursive traverse decls in Namespaces. This method do the same as HandleTopLevelDecl. +*/ + void recursive_visit(const DeclContext *declCont) + { + string line, output, event; + llvm::raw_string_ostream x(output); + SourceLocation loc; + for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i) + { + const Decl *decl = *i; + loc = decl->getLocation(); + if(loc.isValid()) + { + if(decl->getKind()==35) + { + method_decl(decl); + } + else if (const TagDecl *tagDecl = dyn_cast(decl)) + { + if(tagDecl->isStruct() || tagDecl->isClass()) //is it a structure or class + { + struct_class(decl); + } + } + else if(const NamespaceDecl *namespaceDecl = dyn_cast(decl)) + { + DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl); + recursive_visit(declCont); + } + } + output = ""; + } + } + +/** +* This function works with class or struct. It splits the decl into 3 interesting parts. +* The state machine decl, state decl and event decl. +*/ + void struct_class(const Decl *decl) + { + string output, line, ret, trans, event; + llvm::raw_string_ostream x(output); + decl->print(x); + line = get_line_of_code(x.str()); + output = ""; + int pos; + const NamedDecl *namedDecl = dyn_cast(decl); + if(is_derived(line)) + { + const CXXRecordDecl *cRecDecl = dyn_cast(decl); + + if(find_events(cRecDecl, line)) + { + events.push_back(namedDecl->getNameAsString()); + } + else if(name_of_machine == "") + { + ret = find_name_of_machine(cRecDecl, line); + if(!ret.empty()) + { + pos = ret.find(","); + name_of_machine = ret.substr(0,pos); + name_of_start = ret.substr(pos+1); + } + } + else + { + ret = find_states(cRecDecl, line); + if(!ret.empty()) + { + states.push_back(ret); + methods_in_class(decl,namedDecl->getNameAsString()); + } + } + } + } + +/** +* This function provides traversing all methods and other context indide class. If +* typedef or classic method decl is found. If typedef is found then it is being testted for transitions and custom reactions. +*/ + void methods_in_class(const Decl *decl, const string state) + { + string output, line, ret, trans, event; + llvm::raw_string_ostream x(output); + int pos, num; + const TagDecl *tagDecl = dyn_cast(decl); + const DeclContext *declCont = tagDecl->castToDeclContext(tagDecl); + output=""; + for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i) + { + if (i->getKind()==26) // typedefs + { + i->print(x); + output = x.str(); + line = clean_spaces(cut_type(output)); + ret = find_transitions(state,line); + if(!ret.empty()) + { + num = count(ret,';')+1; + for(int i = 0;igetKind()==35) method_decl(decl);// C++ method + } + } + + /** + * Traverse method declaration using classes with main class Stmt. + */ + void method_decl(const Decl *decl) + { + string output, line, event; + llvm::raw_string_ostream x(output); + if(decl->hasBody()) + { + decl->print(x); + line = get_return(x.str()); + if(test_model(line,"result")) + { + const FunctionDecl *fDecl = dyn_cast(decl); + const ParmVarDecl *pvd = fDecl->getParamDecl(0); + QualType qt = pvd->getOriginalType(); + event = qt.getAsString(); + if(event[event.length()-1]=='&') event = event.substr(0,event.length()-2); + event = event.substr(event.rfind(" ")+1); + line = dyn_cast(decl)->getQualifiedNameAsString(); + line = cut_namespaces(line.substr(0,line.rfind("::"))); + line.append(","); + line.append(event); + find_return_stmt(decl->getBody(),line); + for(list::iterator i = cReactions.begin();i!=cReactions.end();i++) // erase info about it from list of custom reactions + { + event = *i; + if(line.compare(event)==0) + { + cReactions.erase(i); + break; + } + } + } + } + } + + void find_return_stmt(Stmt *statemt,string event) /** Traverse all statements in function for finding all return Statements.*/ + { + if(statemt->getStmtClass() == 99) test_stmt(dyn_cast(statemt)->getSubStmt(), event); + else + { + for (Stmt::child_range range = statemt->children(); range; ++range) + { + test_stmt(*range, event); + } + } + } + + void test_stmt(Stmt *stmt, string event) /** test statement for its kind Using number as identifier for all Statement Classes.*/ + { + const SourceManager &sman = fsloc->getManager(); + int type; + string line, param; + type = stmt->getStmtClass(); + switch(type) + { + case 8 : find_return_stmt(dyn_cast(stmt)->getBody(), event); // do + break; + case 86 : find_return_stmt(dyn_cast(stmt)->getBody(), event); // for + break; + case 88 : find_return_stmt(dyn_cast(stmt)->getThen(), event); //if then + find_return_stmt(dyn_cast(stmt)->getElse(), event); //if else + break; + case 90 : find_return_stmt(dyn_cast(stmt)->getSubStmt(), event); //label + break; + case 98 : line = sman.getCharacterData(dyn_cast(stmt)->getReturnLoc()); + line = get_line_of_code(line).substr(6); + line = line.substr(0,line.find("(")); + if(test_model(line,"transit")) + { + param = get_params(line); + transitions.push_back(event.append(",").append(param)); + } + break; + case 99 : find_return_stmt(stmt, event); + break; + case 101 : find_return_stmt(dyn_cast(stmt)->getBody(), event); // switch + break; + case 102 : find_return_stmt(dyn_cast(stmt)->getBody(), event); // while + break; + } + } + +}; +/** + * Main function provides all initialization before starting analysis of AST. Diagnostic Client is initialized, + * Command line options are processed. + */ +int main(int argc, char **argv) +{ + string inputFilename = ""; + string outputFilename = "graph.dot"; // initialize output Filename + DiagnosticOptions dopts; + dopts.ShowColors=1; + MyDiagnosticClient *mdc = new MyDiagnosticClient(llvm::errs(), dopts); + llvm::IntrusiveRefCntPtr dis(new DiagnosticIDs()); + Diagnostic diag(dis,mdc); + FileManager fm( * new FileSystemOptions()); + SourceManager sm (diag, fm); + HeaderSearch *headers = new HeaderSearch(fm); + + Driver TheDriver(LLVM_BINDIR, llvm::sys::getHostTriple(), "", false, false, diag); + TheDriver.setCheckInputsExist(true); + TheDriver.CCCIsCXX = 1; + TheDriver.ResourceDir = LLVM_PREFIX "\lib\clang\\" CLANG_VERSION_STRING; + + CompilerInvocation compInv; + llvm::SmallVector Args(argv, argv + argc); + llvm::OwningPtr C(TheDriver.BuildCompilation(Args.size(), + Args.data())); + const driver::JobList &Jobs = C->getJobs(); + const driver::Command *Cmd = cast(*Jobs.begin()); + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + for(unsigned i = 0; i2) + { + string str = Args[i]; + outputFilename = str.substr(2); + } + else outputFilename = Args[i+1]; + break; + } + } + + CompilerInvocation::CreateFromArgs(compInv, + const_cast(CCArgs.data()), + const_cast(CCArgs.data())+CCArgs.size(), + diag); + + HeaderSearchOptions hsopts = compInv.getHeaderSearchOpts(); + LangOptions lang = compInv.getLangOpts(); + CompilerInvocation::setLangDefaults(lang, IK_ObjCXX); + TargetInfo *ti = TargetInfo::CreateTargetInfo(diag, compInv.getTargetOpts()); + FrontendOptions f = compInv.getFrontendOpts(); + inputFilename = f.Inputs[0].second; + + cout<<"Input filename: "<BeginSourceFile(lang, &pp);//start using diagnostic + ParseAST(pp, &c, ctx, false, false); + mdc->EndSourceFile(); //end using diagnostic + IO_operations *io = new IO_operations(outputFilename, c.getStateMachine(), c.getNameOfFirstState(), c.getTransitions(), c.getStates(), c.getEvents()); + io->save_to_file(); + io->print_stats(); + mdc->print_stats(); + return 0; +} -- 2.39.2