Pastebin PRO Accounts February SPECIAL! For a limited time only get 40% discount on a LIFETIME PRO account!
SHARE
TWEET
To michimikochi
- /* michimikochiさんへ(6)C++ バージョン
- 【修正内容】
- ------------------------------
- 2016.02.04:
- プログラム起動時入力テキスト引数対応
- コマンド入力機能対応
- 抽出機能対応
- 抽出結果UMLtxt出力対応
- ------------------------------
- 2016.01.29:
- コードURL http://pastebin.com/qN9Czzy1
- 複数のPlantUML.txtの読み込みに対応しました。
- 遷移IDのスタートIDをT1からT0に変更しました。
- int reachable(CElement *e, set<CElement*> &C, set<TRANSITION*> &X)関数にて
- 関連要素抽出アルゴリズムを考察中
- ------------------------------
- 2016.01.27:
- コードURL http://pastebin.com/rBfvTWj8
- 遷移ID追加。
- 状態一覧の遷移表示をIDのみに変更。
- MACHINEクラスのインスタンスをローカル変数に変更。
- コード推考
- ------------------------------
- 2016.01.26:
- output_machine機能追加。
- コード推敲
- 質問URL
- http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14155410319
- http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10155203385
- http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12155160442
- http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12155022762
- ------------------------------------------------------------
- 【入力テキストの条件】
- 状態名、イベント名、[ガード条件]、/アクション
- にはスペースを含む事はできません。
- イベント名、[ガード条件]、/アクション は1つの遷移に対して各1つずつしか指定できません。
- ------------------------------------------------------------
- 【メモ】
- [*] が開始状態 or 終了状態を表す
- [*] が含まれているとPlantUMLが状態マシン図と判断する
- イベント 遷移が起こるきっかけとなる出来事
- ガード条件 遷移が許される条件。
- アクション 遷移が起きた時に実行される操作
- 各要素は省略することができます。
- ただし、省略しているとイベントかアクションか区別がつかないので、
- "/" を残すことがあります。
- イベント名 [ガード条件] /アクション
- 状態A-------------------→状態B
- ------------------------------------------------------------
- -----stm_Test1.txt の中身-----
- @startuml{stm Test.png}
- [*] -> S1
- S1 -> S2 : /x=j
- S2 -> S1 : /j=i+1
- S2 -> S3
- S3 -> S4
- S4 -> S5
- S5 -> S6
- S40 -> S41 : /y=0
- S50 -> S2
- S60 -> S61 : [y==0] /x=j
- S70 -> S71
- S80 -> S81 : /x=0
- S100 --> [*]
- @enduml
- -----実行結果-----
- ----- プログラムで生成した res.txt (抽出結果)の中身 -----
- @startuml{stm Test.png}
- [*] -> S1
- S1 -> S2 : /x=j
- S2 -> S1 : /j=i+1
- S40 -> S41 : /y=0
- S50 -> S2
- S60 -> S61 : [y==0] /x=j
- @enduml
- ----- コンソールの表示 -----
- C:\>C++PlantUML stm_Test1.txt
- inputuml stm_Test1.txt
- ----------Analyze stm_Test1.txt---------------
- 遷移元=初期状態
- 遷移矢印=->
- 遷移先=S1
- -----
- 遷移元=S1
- 遷移矢印=->
- 遷移先=S2
- コロン:
- アクション=/x=j
- -----
- 遷移元=S2
- 遷移矢印=->
- 遷移先=S1
- コロン:
- アクション=/j=i+1
- -----
- 遷移元=S2
- 遷移矢印=->
- 遷移先=S3
- -----
- 遷移元=S3
- 遷移矢印=->
- 遷移先=S4
- -----
- 遷移元=S4
- 遷移矢印=->
- 遷移先=S5
- -----
- 遷移元=S5
- 遷移矢印=->
- 遷移先=S6
- -----
- 遷移元=S40
- 遷移矢印=->
- 遷移先=S41
- コロン:
- アクション=/y=0
- -----
- 遷移元=S50
- 遷移矢印=->
- 遷移先=S2
- -----
- 遷移元=S60
- 遷移矢印=->
- 遷移先=S61
- コロン:
- ガード=[y==0]
- アクション=/x=j
- -----
- 遷移元=S70
- 遷移矢印=->
- 遷移先=S71
- -----
- 遷移元=S80
- 遷移矢印=->
- 遷移先=S81
- コロン:
- アクション=/x=0
- -----
- 遷移元=S100
- 遷移矢印=-->
- 遷移先=終了状態
- ------------------------------------------------------------
- input command(?=help)>?
- ?:ヘルプを表示します
- exit:プログラムを終了します
- inputuml ファイル名:指定UMLファイルを読み込みます。
- db:入力ファイルを解析したDBを表示します。
- outputuml ファイル名:DBをUMLtxt化して、指定ファイルに書き込みます。
- safe(stateID),reachable(stateID),live(stateID):
- stateIDで指定された状態の関連遷移と関連要素を抽出します。
- res:抽出された関連遷移と関連要素を表示します。
- outputres ファイル名:指定ファイルに抽出UMLtxtを書き込みます。
- ------------------------------------------------------------
- input command(?=help)>db
- ----------遷移一覧----------
- {id=T0,src=初期状態,arw=->,tgt=S1,evt=,grd=,act=}
- {id=T1,src=S1,arw=->,tgt=S2,evt=,grd=,act=/x=j}
- {id=T2,src=S2,arw=->,tgt=S1,evt=,grd=,act=/j=i+1}
- {id=T3,src=S2,arw=->,tgt=S3,evt=,grd=,act=}
- {id=T4,src=S3,arw=->,tgt=S4,evt=,grd=,act=}
- {id=T5,src=S4,arw=->,tgt=S5,evt=,grd=,act=}
- {id=T6,src=S5,arw=->,tgt=S6,evt=,grd=,act=}
- {id=T7,src=S40,arw=->,tgt=S41,evt=,grd=,act=/y=0}
- {id=T8,src=S50,arw=->,tgt=S2,evt=,grd=,act=}
- {id=T9,src=S60,arw=->,tgt=S61,evt=,grd=[y==0],act=/x=j}
- {id=T10,src=S70,arw=->,tgt=S71,evt=,grd=,act=}
- {id=T11,src=S80,arw=->,tgt=S81,evt=,grd=,act=/x=0}
- {id=T12,src=S100,arw=-->,tgt=終了状態,evt=,grd=,act=}
- ----------状態一覧----------
- {id=初期状態,src={},tgt={初期状態}}
- {id=S1,src={初期状態,S2},tgt={S1}}
- {id=S2,src={S1,S50},tgt={S2,S2}}
- {id=S3,src={S2},tgt={S3}}
- {id=S4,src={S3},tgt={S4}}
- {id=S5,src={S4},tgt={S5}}
- {id=S6,src={S5},tgt={}}
- {id=S40,src={},tgt={S40}}
- {id=S41,src={S40},tgt={}}
- {id=S50,src={},tgt={S50}}
- {id=S60,src={},tgt={S60}}
- {id=S61,src={S60},tgt={}}
- {id=S70,src={},tgt={S70}}
- {id=S71,src={S70},tgt={}}
- {id=S80,src={},tgt={S80}}
- {id=S81,src={S80},tgt={}}
- {id=S100,src={},tgt={S100}}
- {id=終了状態,src={S100},tgt={}}
- ------------------------------------------------------------
- input command(?=help)>safe(S2)
- -----抽出関連遷移一覧-----
- {id=T0,src=初期状態,arw=->,tgt=S1,evt=,grd=,act=}
- {id=T1,src=S1,arw=->,tgt=S2,evt=,grd=,act=/x=j}
- {id=T2,src=S2,arw=->,tgt=S1,evt=,grd=,act=/j=i+1}
- {id=T7,src=S40,arw=->,tgt=S41,evt=,grd=,act=/y=0}
- {id=T8,src=S50,arw=->,tgt=S2,evt=,grd=,act=}
- {id=T9,src=S60,arw=->,tgt=S61,evt=,grd=[y==0],act=/x=j}
- -----抽出関連要素一覧-----
- {type=State,S1}
- {type=State,S2}
- {type=State,S40}
- {type=State,S50}
- {type=State,S60}
- {type=State,初期状態}
- {type=Action,/j=i+1}
- {type=Action,/x=j}
- {type=Action,/y=0}
- {type=Variable,y}
- ------------------------------------------------------------
- input command(?=help)>outputres res.txt
- ------------------------------------------------------------
- input command(?=help)>exit
- プログラムを終了します
- */
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <vector>
- #include <string>
- #include <set>
- #include <algorithm>
- using namespace std;
- //デフォルトの「コピーコンストラクタ」と「代入演算子」を禁止するマクロ
- //※これを private: エリアに置くことで上記を禁止に出来る
- //※禁止する理由は、デフォルトのコピーコンストラクタと代入演算子は、
- // memcpy()のようにメモリを単純コピーするだけなので、
- // 動的メモリを管理するメンバがいる場合、メモリリーク等を引き起こす危険があるため
- #define DISARROW_COPY_AND_ASSGIN(ClassName) \
- ClassName(const ClassName&); \
- void operator=(const ClassName&);
- class TRANSITION;//構造体の前方宣言(構造体の名前だけコンパイラに教える)
- //遷移動的配列文字列化関数のプロトタイプ宣言
- string TransVectorToString(const vector<TRANSITION*> &tpv,const string &separator);
- string TransVectorToIdString(const vector<TRANSITION*> &tpv,const string &separator);
- //------------------------------------------------------------
- //要素クラス
- class CElement:public string{
- private:
- //デフォルトの「コピーコンストラクタ」と「代入演算子」を禁止するマクロ
- //DISARROW_COPY_AND_ASSGIN(CElement);
- public:
- enum EleType {State,Action,Variable};//要素クラスがサポートするタイプ
- private:
- EleType mType;//要素タイプ
- public:
- //------------------------------
- //デフォルトコンストラクタ
- CElement(){}
- //------------------------------
- //初期化引数有りコンストラクタ
- CElement(EleType type,const string &text):string(text){//基本クラスのstringのコンストラクタを呼び出す
- mType = type;
- }
- //------------------------------
- //コピーコンストラクタ
- CElement(const CElement &obj):mType(obj.mType),string(obj){
- }
- //------------------------------
- //デストラクタ
- ~CElement(){
- }
- //------------------------------
- //要素タイプを返す
- EleType GetType(){
- return mType;
- }
- //------------------------------
- //要素クラス変数の内容文字列を返す
- string ToString()const{
- static const string EleTypeStrings[]={"State","Action","Variable"};
- ostringstream os;
- os << "{type=";
- if(mType < (int)(sizeof(EleTypeStrings)/sizeof(EleTypeStrings[0]))){
- os << EleTypeStrings[mType];
- }else{
- os << "Unknown";
- }
- os << "," << *this << "}";
- return os.str();
- }
- //------------------------------
- //代入演算子
- CElement &operator=(const CElement &obj){
- this->mType = obj.mType;
- *(string*)this = obj;//基本クラスの代入演算子を用いる
- return *this;
- }
- //------------------------------
- //等価演算子
- bool operator==(const CElement &obj)const{
- if(mType == obj.mType){
- //タイプが同じ時
- return (string)(*this)==(string)(obj);//基本クラスの比較に従う
- }else{
- return false;//タイプが異なる時
- }
- }
- //------------------------------
- //小なり演算子(STLのset<CElement>に必要)
- bool operator<(const CElement &obj)const{
- if(mType == obj.mType){
- //タイプが同じ時
- return ((string)(*this)<(string)(obj));//基本クラスの比較に従う
- }else{
- //タイプが異なる時
- } return mType < obj.mType;//タイプの比較に従う
- }
- };
- //------------------------------------------------------------
- //状態クラス
- class STATE{
- private:
- //デフォルトの「コピーコンストラクタ」と「代入演算子」を禁止するマクロ
- DISARROW_COPY_AND_ASSGIN(STATE);
- public:
- string id;//状態の名前
- vector<TRANSITION*> src;//受けている遷移ポインタ動的配列
- vector<TRANSITION*> tgt;//出ている遷移ポインタ動的配列
- //------------------------------
- //コンストラクタ(指定文字列でIDを初期化する)
- STATE(const string &arg_id):id(arg_id){}
- //------------------------------
- //デストラクタ(破棄される時に実行される。デバッグ用)
- ~STATE(){
- //cout << "~STATE()\n";
- }
- //------------------------------
- //STATEの表示用文字列を返す
- string ToString()const{
- ostringstream os;//文字を溜め込むことが出来る
- os << "{id=" << id << ","
- "src={" << TransVectorToIdString(src,",") << "},"
- "tgt={" << TransVectorToIdString(tgt,",") << "}}";
- return os.str();//溜め込んだ文字を返す
- }
- };
- //------------------------------------------------------------
- //遷移情報を管理するクラス
- class TRANSITION{
- private:
- //デフォルトの「コピーコンストラクタ」と「代入演算子」を禁止するマクロ
- DISARROW_COPY_AND_ASSGIN(TRANSITION);
- public:
- //ポインタメンバのデータ割り当て解放はMACHINEが行う
- string id;//遷移の名前
- STATE *src;//遷移元の状態ポインタ
- string arw;//★矢印(追加しました)
- STATE *tgt;//遷移先の状態ポインタ
- string evt;//イベント
- string grd;//ガード
- string act;//アクション
- //------------------------------
- //コンストラクタ(特に何もしない)
- TRANSITION(){}
- //------------------------------
- //デストラクタ(デバッグ用)
- ~TRANSITION(){
- //cout << "~TRANSITION()\n";
- }
- //------------------------------
- //TRANSITIONの表示用文字列を返す
- string ToString()const{
- ostringstream os;//文字を溜め込むことが出来る
- os << "{id="<<id<<",src="<<src->id<<",arw="<<arw<<",tgt="<<tgt->id
- <<",evt="<<evt<<",grd="<<grd<<",act="<<act<<"}";
- return os.str();//溜め込んだ文字を返す
- }
- };
- //------------------------------------------------------------
- //コマンド入力行をトークンにして返します。
- //(主に"file name"のように空白を含むファイル名を一つのトークンとして取り出す事が主機能)
- vector<string> CmdlineToArgv(const string &line)
- {
- vector<string> argv;//コマンドラインをトークンに切り分けたもの(戻り値)
- string token;//トークン取り出し作業用
- for(size_t i=0;i<line.length();i++){
- if(line[i]==' '){
- //区切り文字の時
- if(token.length()){
- //トークンがある時
- argv.push_back(token);//トークンを登録
- token.clear();//トークンをクリア
- }
- }else if(line[i] == '\"'){
- //区切り無視スタートの時
- for(i++;i<line.length();i++){
- if(line[i] == '\"'){
- //区切り無視エンドの時
- break;//区切り記号無視区間終了
- }else{
- //区切り無視エンドでない時
- token.push_back(line[i]);//トークンに文字を追加
- }
- }
- }else{
- //区切りでなく、区切り無視スタートでもない時(トークンの一部)
- token.push_back(line[i]);
- }
- }
- if(token.length()){
- //トークンがある時
- argv.push_back(token);
- }
- return argv;
- }
- //------------------------------------------------------------
- //マシン・クラス(状態と遷移の動的メモリを管理する)
- class MACHINE{
- private://-----プライベート・メンバ--------------------
- //デフォルトの「コピーコンストラクタ」と「代入演算子」を禁止するマクロ
- DISARROW_COPY_AND_ASSGIN(MACHINE);
- //-----プライベート・メンバ変数-----
- vector<STATE *> mStatePtrVector;//状態一覧動的配列(st)
- vector<TRANSITION *> mTransPtrVector;//遷移一覧動的配列(tr)
- STATE *init;//初期状態へのポインタ
- string mInputFileName;//読込んだファイル名
- string mFileHeader;//ファイルのヘッダ?の行
- int mNextTransNumber;//デフォルトの次の遷移ID番号を管理する変数
- //------------------------------
- //指定IDの状態を生成登録し、ポインタを取得する
- //(既に存在する場合は、ポインタを返す。ポインタをDB以外でdeleteしてはいけない)
- STATE *CreateState(const string &id)
- {
- STATE *sp = GetState(id);//同じ状態名が、DBに存在するか探す
- if(sp) return sp;//存在する時、そのポインタを返す。
- //同じ状態名が存在しなかった時
- sp = new STATE(id);//指定IDを持つ状態を生成する
- mStatePtrVector.push_back(sp);//動的配列に登録する
- if(sp->id == "初期状態"){
- //初期状態を返すタイミングでinitに記憶する
- init = sp;
- }
- return sp;//状態のポインタを返す
- }
- //指定IDの状態のポインタを取得する。(※存在しない場合は、NULLを返す)
- STATE *GetState(const string &id)const
- {
- for(size_t i=0;i<mStatePtrVector.size();i++){
- if(mStatePtrVector[i]->id == id){
- //既に同じ状態名が存在する時
- return mStatePtrVector[i];//状態のポインタを返す
- }
- }
- //見つからなかった時
- return NULL;
- }
- //------------------------------
- //遷移を生成登録し、そのポインタを取得する(必ずDBに登録される)
- TRANSITION *AddTrans(STATE *srcState,const string &arrow,STATE *targetState,
- const string &event,const string &guard,const string &action){
- TRANSITION *tp = new TRANSITION();////MACHINE管理
- //遷移にデータを書き込む
- tp->id = NewTransID();
- tp->src = srcState;
- tp->arw = arrow;
- tp->tgt = targetState;
- tp->evt = event;//MACHINE管理
- tp->grd = guard;//MACHINE管理
- tp->act = action;//MACHINE管理
- mTransPtrVector.push_back(tp);//DBに登録する
- return tp;//作成した遷移のポインタを返す
- }
- string NewTransID(){
- ostringstream os;
- os << "T" << mNextTransNumber++;
- return os.str();
- }
- public://-----公開メンバ--------------------
- //------------------------------
- //DBをクリアする
- void Clear(){
- //状態データを破棄する
- for(size_t i=0;i<mStatePtrVector.size();i++){
- delete mStatePtrVector[i];//new で作成したメモリを解放する
- }
- mStatePtrVector.clear();//状態一覧動的配列を空にする
- //遷移データを破棄する
- for(size_t i=0;i<mTransPtrVector.size();i++){
- delete mTransPtrVector[i];//new で作成したメモリを解放する
- }
- mTransPtrVector.clear();//遷移一覧動的配列を空にする
- init = NULL;//★初期状態へのポインタを無効にする
- mInputFileName.clear();
- mFileHeader.clear();
- mNextTransNumber=0;//デフォルト遷移ID番号カウンタ
- }
- //------------------------------
- //コンストラクタ
- MACHINE(){
- Clear();//全データをクリアする
- }
- //------------------------------
- //デストラクタ(MACHINEが破棄されるタイミングで呼び出される)
- ~MACHINE(){
- Clear();
- }
- //------------------------------
- //指定ステートIDがDBに存在する場合、trueを返す
- bool IsStateExists(const string &state_id)const{
- return (GetState(state_id) != NULL);
- }
- //------------------------------
- //作成した全状態情報を表示する
- void PrintStateALL(void)
- {
- printf("----------状態一覧----------\n");
- for(size_t i=0;i<mStatePtrVector.size();i++){
- cout << mStatePtrVector[i]->ToString() << endl;
- }
- }
- //------------------------------
- //作成した全遷移を表示する
- void PrintTransALL(void)
- {
- printf("----------遷移一覧----------\n");
- cout << TransVectorToString(mTransPtrVector,"\n") << endl;
- }
- //------------------------------
- //指定ファイルにPlantUMLテキストを書き込む
- void output_machine(string file_name,const vector<TRANSITION*> *extractionResults=NULL){
- ofstream ofs(file_name.c_str());
- if(ofs.fail()){
- //書込みファイルのオープンに失敗した時
- cerr << "Output file(" << file_name << ") open error.\n";
- return;
- }
- ofs << mFileHeader << endl;
- ofs << endl;
- if(extractionResults == NULL){
- //対象遷移一覧が無い時
- extractionResults = &mTransPtrVector;
- }
- for(size_t i=0;i<extractionResults->size();i++){
- //遷移の数だけ
- const TRANSITION *trans = (*extractionResults)[i];
- ofs << (trans->src->id == "初期状態" ? (string)"[*]" : trans->src->id);
- ofs << " " << trans->arw;
- ofs << " " << (trans->tgt->id == "終了状態" ? (string)"[*]" : trans->tgt->id);
- //イベント・ガード・アクションの文字列を作る
- string evtGrdActStr;
- if(trans->evt.length()) evtGrdActStr += " " + trans->evt;
- if(trans->grd.length()) evtGrdActStr += " " + trans->grd;
- if(trans->act.length()) evtGrdActStr += " " + trans->act;
- if(evtGrdActStr.length()){
- //イベント・ガード・アクション文字列がある時
- //コロンに続いて、イベント・ガード・アクション文字列を追加
- ofs << " :" << evtGrdActStr;
- }
- ofs << endl;//改行
- }
- ofs << endl;//改行のみ
- ofs << "@enduml\n";//
- }
- //------------------------------
- //指定ファイルのPlantUML情報を読み込み、DBを構築する
- //※この関数を呼び出すと、DBがクリアされます。
- //※よって、一つのファイルのDBしか構築できません。
- void input_machine(string file_name)//MACHINEのメンバ関数にしました
- {
- //-----ファイル内容の例-----
- //startuml{stm_M1.png}
- //
- //[*] -> S1
- //S1 -> S2 : a
- //S2 -> S1 : [b==0]
- //S2 -> S3
- //S3 --> [*]
- //
- //@enduml
- Clear();//DB初期化
- ifstream ifs(file_name.c_str());//入力ファイルストリーム
- if(ifs.fail()){
- //読み込みファイルのオープンに失敗した時
- cerr << "Input file(" << file_name << ") open error.\n";
- return;
- }
- cout << "----------Analyze " << file_name << "----------";
- for(string buff;getline(ifs,buff);){
- //ファイルから行の読み込みに成功している間(buffには改行コードは読込まれない)
- if(buff.length() == 0)continue;//1文字も無い時、次の行へ
- if(buff[0] == '@'){//先頭が@の時
- const string headerStr = "@startuml";
- if(buff.substr(0,headerStr.length()) == headerStr){
- //読込んだ行の先頭部分がヘッダだった時
- mFileHeader = buff;//ファイルヘッダ行を保存
- }
- continue;//次の行へ
- }
- cout<<"-----\n";
- //行の先頭が@および改行以外の時(遷移情報の時)
- //遷移元、矢印、遷移先、コロンを読み込む
- string src,arrow,target,colon,event,guard,action;
- istringstream iss(buff);//読込んだ1行を入力文字列ストリームにする
- iss >> src >> arrow >> target >> colon;
- if(src=="[*]")src="初期状態";//初期状態の名称変更処理
- if(target=="[*]")target="終了状態";//終了状態の名称変更処理
- cout << "遷移元="<<src<<endl;
- cout << "遷移矢印="<<arrow<<endl;
- cout << "遷移先="<<target<<endl;
- if(colon == ":"){
- //コロンがあった時
- cout << "コロン"<<colon<<endl;
- //イベント名、[ガード条件]、/アクション があれば読み込む
- int k;
- for(k=0;k<3;k++){
- string p;
- iss >> p;
- if(p.length()==0)break;//何も読み込めなかった時
- switch(p[0]){
- case '[':// [ガード条件]
- guard = p;
- cout<<"ガード="<<guard<<endl;
- break;
- case '/':// /アクション
- action = p;
- cout<<"アクション="<<action<<endl;
- break;
- default://イベント名
- event = p;
- cout<<"イベント名="<<event<<endl;
- break;
- }
- }
- }
- //-----読込データを元に「状態」と「遷移」を作成する-----
- //指定IDの状態を生成登録しポインタを得る(既に存在する時は、そのポインタを得る)
- STATE *srcState = CreateState(src);
- //指定IDの状態を生成登録しポインタを得る(既に存在する時は、そのポインタを得る)
- STATE *targetState = CreateState(target);
- //遷移をDBに追加し、そのポインタを取得する(必ずDBに登録される)
- TRANSITION *tp = AddTrans(srcState,arrow,targetState,event,guard,action);
- //状態に遷移を追加する
- //遷移元状態には遷移をターゲット遷移として登録
- srcState->tgt.push_back(tp);
- //遷移先状態には遷移をソース遷移として登録
- targetState->src.push_back(tp);
- }
- mInputFileName = file_name;//読み込みファイル名を保存
- }
- //------------------------------
- //指定要素集合からチェック済み要素集合に含まれない最初の要素のポインタを得る
- bool GetNotCheckedElement(const set<CElement> &pool, const set<CElement> &Checked, CElement ¬CheckElement)
- {
- for(set<CElement>::const_iterator it = pool.begin();it != pool.end(); it++){
- //poolに登録されている要素数分
- if(Checked.find(*it) == Checked.end()){
- //poolの要素がCheckedになかった時
- notCheckElement = *it;//Checkedに無かった要素をセットする
- return true;//チェックに含まれない要素があった
- }
- }
- return false;//全部チェックに入っている要素だった
- }
- //==============================
- //関連要素を抽出する関数関連
- //------------------------------
- //文字列の中から変数名を探して返す関数
- string SearchVariableName(const string text)
- {
- const static string CalcCharList="=<>!+-*/";
- for(size_t i=0;i<CalcCharList.size();i++){
- size_t find_index = text.find(CalcCharList[i],0);
- if(find_index == string::npos)continue;//見つからなかった時
- //見つかった時
- string variable;
- for(int k=find_index-1;k>=0;k--){
- if(isalpha(text[k])){
- variable = text[k]+variable;
- }
- //アルファベットでない時
- break;
- }
- return variable;
- }
- //演算子が無い時
- return "";//空文字列を返す
- }
- // 抽象化の説明をさせていただきます.
- // 抽象化モデルは仕様に対する関連要素と関連要素間の遷移によって
- // 作成されます.
- //
- // 関連要素は与えられた要求仕様に対して影響を与える
- // 状態,メッセージ,変数と定義します.
- //
- // また,関連要素に影響を与える要素も間接的に仕様に影響を与えるため関連要素であると定義できます.
- //
- // 関連要素の判定は入力された状態マシン図の遷移に着目して定めることができます.
- //
- // 【状態に対しての関連要素】
- // その状態を遷移先とする遷移
- //
- // 【メッセージに対しての関連要素】
- // そのメッセージをアクションに含む遷移
- //
- // 【変数に対しての関連要素】
- // その変数をアクションの左辺に持つ遷移
- //
- // 【遷移の関連要素】
- // 遷移に記述されている
- // ・アクション
- // ・ガードにある変数
- // ・遷移元の状態であると定義します.
- //------------------------------
- //抽出関数
- int abstraction_machine(CElement &e,//要求仕様
- set<CElement> &C,//仕様関連要素集合
- set<TRANSITION*> &X//仕様関連遷移集合
- )
- {
- //仕様関連遷移Xと、仕様関連要素集合C
- X.clear();//空にする
- C.clear();//空にする
- C.insert(e);//最初の要素を追加する
- set<CElement> Checked;//Checked={};//★チェック済み要素一覧
- set<CElement> NotChecked;//チェックしていない要素一覧
- for(;GetNotCheckedElement(C,Checked,e);){
- //チェックしていない要素がある時
- set<TRANSITION*> T;//T={};//関連遷移一覧=空
- switch(e.GetType()){//eのタイプは何?
- case CElement::EleType::State://状態の時
- for(size_t i=0;i< mTransPtrVector.size();i++) {
- if(mTransPtrVector[i]->tgt->id == e){
- T.insert(mTransPtrVector[i]); //Tにtを加える
- }
- }
- break;
- case CElement::EleType::Action://アクションの時
- for(size_t i=0;i< mTransPtrVector.size();i++) {
- if(mTransPtrVector[i]->act == e){
- //遷移に同じアクションがある時
- T.insert(mTransPtrVector[i]); //Tにtを加える
- }
- }
- break;
- case CElement::EleType::Variable://変数の時
- for(size_t i=0;i< mTransPtrVector.size();i++) {
- if(SearchVariableName(mTransPtrVector[i]->act) == e){
- //遷移のアクションに同じ変数があった時
- T.insert(mTransPtrVector[i]); //Tにtを加える
- }
- }
- break;
- default://それ以外
- cerr << "Unknown element type("<<e.GetType()<<").\n";
- break;
- }
- //要素に関連する遷移に対して、遷移の関連要素を「仕様関連要素集合に追加する」
- for(set<TRANSITION*>::const_iterator it=T.begin(); it!=T.end(); it++){
- //関連遷移の全要素に適用
- if((*it)->act.length()){
- //アクションがある時
- //「アクション」を関連要素集合に追加
- C.insert(CElement(CElement::EleType::Action,(*it)->act));
- }
- //ガードに変数があればこれをCに追加
- string grdVariable = SearchVariableName((*it)->grd);
- if(grdVariable.length()){
- //ガードに変数がある時
- //「ガードにある変数」を関連要素集合に追加
- C.insert(CElement(CElement::EleType::Variable,grdVariable));
- }
- //「遷移の元状態」を関連要素集合に追加
- if((*it)->src->id.length()){
- //有効な元状態がある時
- C.insert(CElement(CElement::EleType::State, (*it)->src->id));
- }
- }
- Checked.insert(e);//チェック済みにeを追加
- //X=X+T;//仕様関連遷移集合に関連遷移を加える
- for(set<TRANSITION*>::const_iterator it = T.begin();it != T.end();it++){
- X.insert(*it);
- }
- } //for()に変更。while(C(e)!= Checked)//関連要素がチェック済みと異なる間
- return 0;
- }
- };
- //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
- //表示文字列作成関数
- ///------------------------------------------------------------
- //遷移の動的配列をstringに変換する
- string TransVectorToIdString(const vector<TRANSITION*> &tpc,const string &separator)
- {
- ostringstream os;//文字を溜め込むことが出来る
- for(vector<TRANSITION*>::const_iterator it = tpc.begin();it != tpc.end();it++){
- if(it != tpc.begin())os << separator;//初回以外は、セパレータを挿入する
- os << (*it)->src->id;
- }
- return os.str();//溜め込んだ文字を返す
- }
- ///------------------------------------------------------------
- //遷移の動的配列をstringに変換する
- string TransVectorToString(const vector<TRANSITION*> &tpc,const string &separator)
- {
- ostringstream os;//文字を溜め込むことが出来る
- for(vector<TRANSITION*>::const_iterator it = tpc.begin();it != tpc.end();it++){
- if(it != tpc.begin())os << separator;//初回以外は、セパレータを挿入する
- os << (*it)->ToString();
- }
- return os.str();//溜め込んだ文字を返す
- }
- //------------------------------------------------------------
- //遷移の動的配列をstringに変換する
- string TransSetToString(const set<TRANSITION*> &tpc,const string &separator)
- {
- ostringstream os;//文字を溜め込むことが出来る
- for(set<TRANSITION*>::const_iterator it = tpc.begin();it != tpc.end();it++){
- if(it != tpc.begin())os << separator;//初回以外は、セパレータを挿入する
- os << (*it)->ToString();
- }
- return os.str();//溜め込んだ文字を返す
- }
- //------------------------------------------------------------
- //遷移の動的配列をstringに変換する
- string ElementSetToString(const set<CElement> &tpc,const string &separator)
- {
- ostringstream os;//文字を溜め込むことが出来る
- for(set<CElement>::const_iterator it = tpc.begin();it != tpc.end();it++){
- if(it != tpc.begin())os << separator;//初回以外は、セパレータを挿入する
- os << (*it).ToString();
- }
- return os.str();//溜め込んだ文字を返す
- }
- //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
- //------------------------------------------------------------
- //コマンド処理関数
- //
- int CommandLoop(const string &inputUmlFileName="")
- {
- MACHINE Machine;
- set<CElement> C;//関連要素集合
- set<TRANSITION*> X;//関連遷移集合
- istringstream CmdFileIss;//コマンドファイルの内容を保持する入力文字列ストリーム
- if(inputUmlFileName != ""){
- //自動読み込みUMLtxtファイル名が指定されているとき
- //指定ファイルをUMLtxtファイルとして読み込む
- cout << "inputuml "<<inputUmlFileName<<endl;
- Machine.input_machine(inputUmlFileName);
- }
- //コマンドループ
- for(size_t i=0;true;i++){
- cout << "------------------------------------------------------------\n";
- cout << "input command(?=help)>";
- string command_line;//入力されたコマンドラインを保持する
- //#define DEBUG //※ここのコメント解除するとデバッグ用自動コマンド入力が有効になります
- #ifdef DEBUG
- //デバッグ用自動コマンド入力文字列
- static string debugCmd[]={
- "cmdfile PlantUmlCommand.txt",
- "inputuml stm_M3.txt",
- "db",
- "outputuml stm_M3-2.txt",
- "safe(S1)",
- "res",
- "outputres stm_M3-res.txt",
- };
- if(i<sizeof(debugCmd)/sizeof(debugCmd[0])){
- //処理していないデバッグ用自動コマンド入力文字列がまだあるとき
- //コマンド入力を偽装する
- cout << (command_line = debugCmd[i]) << endl;
- }
- else
- #endif
- {
- if(getline(CmdFileIss,command_line)){
- //コマンドファイル文字列ストリームから読み込めた時
- //エコー表示
- cout << command_line << endl;
- }else{
- //コマンドファイル文字列ストリームから取り出せなかった時は、
- //標準入力からコマンドを読み込む
- if(!getline(cin, command_line)){
- //読み込めなかった時
- return -1;//プログラム終了
- }
- }
- }
- //入力行をトークンに分割する
- vector<string> argv = CmdlineToArgv(command_line);
- if(argv.size()<2)argv.resize(2);//要素数が少ない時は増やす
- const string &command = argv[0];
- const string &arg1 = argv[1];
- char stateID[256];//状態名読み込みバッファ
- if(command == ""){
- //空行は何もしない
- }else if(command == "?"){
- //ヘルプ表示の時
- cout << "?:ヘルプを表示します\n\n";
- cout << "exit:プログラムを終了します\n\n";
- cout << "inputuml ファイル名:指定UMLファイルを読み込みます。\n\n";
- cout << "db:入力ファイルを解析したDBを表示します。\n\n";
- cout << "outputuml ファイル名:DBをUMLtxt化して、指定ファイルに書き込みます。\n\n";
- cout << "safe(stateID),reachable(stateID),live(stateID):\n";
- cout << "stateIDで指定された状態の関連遷移と関連要素を抽出します。\n\n";
- cout << "res:抽出された関連遷移と関連要素を表示します。\n\n";
- cout << "outputres ファイル名:指定ファイルに抽出UMLtxtを書き込みます。\n\n";
- continue;
- }else if(command == "exit"){
- return 1;//プログラム終了
- }else if(command == "cmdfile" && arg1.length()){
- ifstream ifs(arg1.c_str());
- if(ifs.fail()){
- //コマンドファイルのオープンに失敗した時
- cout << "コマンドファイル("<<arg1<<")の読み込みに失敗しました。\n";
- }else{
- //コマンドファイルのオープンに成功した時
- ostringstream os;
- string line;
- while(getline(ifs,line)){
- os << line << endl;
- //cout << line << endl;
- }
- CmdFileIss.str(os.str());
- }
- }else if(command == "inputuml" && arg1.length()){ //inputuml file_name
- //ファイル読み込みの時
- C.clear();
- X.clear();
- Machine.input_machine(arg1);
- Machine.PrintTransALL();
- Machine.PrintStateALL();
- }else if(command == "db"){
- //入力ファイル情報を表示する
- Machine.PrintTransALL();
- Machine.PrintStateALL();
- }else if(command == "outputuml" && arg1.length()){
- //入力ファイル情報をファイルに書き出す
- Machine.output_machine(arg1);
- }else if(sscanf(command_line.c_str(),"safe(%128[^)])",stateID)==1 ||
- sscanf(command_line.c_str(),"reachable(%128[^)])",stateID)==1 ||
- sscanf(command_line.c_str(),"live(%128[^)])",stateID)==1){
- //ステート文字列の読み取りに成功した時
- if(!Machine.IsStateExists(stateID)){
- //状態が見つからない時
- cout << "指定された状態名("<<stateID<<")が見つかりませんでした。\n";
- continue;//コマンド入力へ
- }
- CElement e(CElement::EleType::State,stateID);
- Machine.abstraction_machine(e,C,X);
- cout << "-----抽出関連遷移一覧-----\n";
- cout << TransSetToString(X,"\n") << endl;
- cout << "-----抽出関連要素一覧-----\n";
- cout << ElementSetToString(C,"\n") << endl;
- }else if(command == "res"){
- //抽出情報を表示する
- cout << "-----抽出関連遷移一覧-----\n";
- cout << TransSetToString(X,"\n") << endl;
- cout << "-----抽出関連要素一覧-----\n";
- cout << ElementSetToString(C,"\n") << endl;
- }else if(command == "outputres" && arg1.length()){
- //ファイル名の読み取りに成功した時
- vector<TRANSITION*> vT(X.size());//遷移の動的配列サイズを抽出個数分確保
- copy(X.begin(),X.end(),vT.begin());//set→vectorに要素をコピー()
- Machine.output_machine(arg1,&vT);
- }else{
- //全ての読み取りパターンに失敗した時
- cout << "認識できないコマンドです("<<command_line<<")\n";
- }
- }
- return 0;
- }
- int main(int argc, char *argv[])
- {
- if(argc >= 2){
- //引数がある時
- CommandLoop(argv[1]);//第1引数をUMLtxtファイル名としてコマンドに与える
- }else{
- //引数がない時は、コマンドループを引数無しで呼び出す
- CommandLoop();
- }
- cout << "プログラムを終了します\n";
- //system("pause");
- return 0;
- }
RAW Paste Data