Pastebin PRO Accounts February SPECIAL! For a limited time only get 40% discount on a LIFETIME PRO account!
SHARE
TWEET
To michimikochi
- /* michimikochiさんへ(4)C++ バージョン(遷移ID追加)
- 【お知らせ】
- ・前回からまたあちこち変更しています。
- 【修正内容】
- 2016.01.27:
- 遷移ID追加。
- 状態一覧の遷移表示をIDのみに変更。
- MACHINEクラスのインスタンスをローカル変数に変更。
- コード推考
- 2016.01.26:
- output_machine機能追加。
- コード推敲
- 質問URL
- 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 M1.txt の中身-----
- @startuml{stm_M1.png}
- [*] -> S1
- S1 -> S2 : a
- S2 -> S1 : [b==0]
- S2 -> S3
- S3 --> [*]
- @enduml
- -----実行結果-----
- ----- プログラムで生成した stm M1-2.txt の中身 -----
- @startuml{stm_M1.png}
- [*] -> S1
- S1 -> S2 : a
- S2 -> S1 : [b==0]
- S2 -> S3
- S3 --> [*]
- @enduml
- ----- コンソールの表示 -----
- -----
- 遷移元=初期状態
- 遷移矢印=->
- 遷移先=S1
- -----
- 遷移元=S1
- 遷移矢印=->
- 遷移先=S2
- コロン:
- イベント名=a
- -----
- 遷移元=S2
- 遷移矢印=->
- 遷移先=S1
- コロン:
- ガード=[b==0]
- -----
- 遷移元=S2
- 遷移矢印=->
- 遷移先=S3
- -----
- 遷移元=S3
- 遷移矢印=-->
- 遷移先=終了状態
- ----------遷移一覧----------
- {id=T1,src=初期状態,arw=->,tgt=S1,evt=,grd=,act=}
- {id=T2,src=S1,arw=->,tgt=S2,evt=a,grd=,act=}
- {id=T3,src=S2,arw=->,tgt=S1,evt=,grd=[b==0],act=}
- {id=T4,src=S2,arw=->,tgt=S3,evt=,grd=,act=}
- {id=T5,src=S3,arw=-->,tgt=終了状態,evt=,grd=,act=}
- ----------状態一覧----------
- {id=初期状態,src={},tgt={T1}}
- {id=S1,src={T1,T3},tgt={T2}}
- {id=S2,src={T2},tgt={T3,T4}}
- {id=S3,src={T4},tgt={T5}}
- {id=終了状態,src={T5},tgt={}}
- 続行するには何かキーを押してください . . .
- */
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <vector>
- #include <string>
- 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 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:
- 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();//溜め込んだ文字を返す
- }
- };
- //------------------------------------------------------------
- //クラス(状態と遷移の動的メモリを管理する)
- class MACHINE{
- private://-----プライベート・メンバ--------------------
- //デフォルトの「コピーコンストラクタ」と「代入演算子」を禁止するマクロ
- DISARROW_COPY_AND_ASSGIN(MACHINE);
- //-----プライベート・メンバ変数-----
- vector<STATE *> mStatePtrVector;//状態一覧動的配列(st)
- vector<TRANSITION *> mTransPtrVector;//遷移一覧動的配列(tr)
- STATE *init;//初期状態へのポインタ
- string mFileHeader;//ファイルのヘッダ?の行
- int mNextTransIdNumber;
- //------------------------------
- //指定IDの状態ポインタを取得する(無い時、DBに登録される。ポインタをDB以外でdeleteしてはいけない)
- STATE *GetState(const string &id)
- {
- for(size_t i=0;i<mStatePtrVector.size();i++){
- if(mStatePtrVector[i]->id == id){
- //既に同じ状態名が存在する時
- return mStatePtrVector[i];//状態のポインタを返す
- }
- }
- //同じ状態名が存在しなかった時
- STATE *sp = new STATE(id);//指定IDを持つ状態を生成する
- mStatePtrVector.push_back(sp);//動的配列に登録する
- if(sp->id == "初期状態"){
- //初期状態を返すタイミングでinitに記憶する
- init = sp;
- }
- return sp;//状態のポインタを返す
- }
- //------------------------------
- //遷移を生成登録し、そのポインタを取得する(必ずDBに登録される)
- TRANSITION *AddTrans(STATE *srcState,const string &arrow,STATE *targetState,
- const string &event,const string &guard,const string &action){
- TRANSITION *tp = new TRANSITION();//遷移メモリを生成する
- //遷移にデータを書き込む
- tp->id = NewTransID();
- tp->src = srcState;
- tp->arw = arrow;
- tp->tgt = targetState;
- tp->evt = event;
- tp->grd = guard;
- tp->act = action;
- mTransPtrVector.push_back(tp);//DBの動的配列に登録する
- return tp;//作成した遷移のポインタを返す
- }
- string NewTransID(){
- ostringstream os;
- os << "T" << ++mNextTransIdNumber;
- return os.str();
- }
- public://-----公開メンバ--------------------
- //------------------------------
- //コンストラクタ
- MACHINE(){
- init = NULL;
- mNextTransIdNumber=0;
- }
- //------------------------------
- //デストラクタ(MACHINEが破棄されるタイミングで呼び出される)
- ~MACHINE(){
- //状態データを破棄する
- for(size_t i=0;i<mStatePtrVector.size();i++){
- delete mStatePtrVector[i];//new で作成したメモリを解放する
- }
- mStatePtrVector.clear();//状態一覧動的配列を空にする
- init = NULL;//★初期状態へのポインタを無効にする
- //遷移データを破棄する
- for(size_t i=0;i<mTransPtrVector.size();i++){
- delete mTransPtrVector[i];//new で作成したメモリを解放する
- }
- mTransPtrVector.clear();//遷移一覧動的配列を空にする
- }
- //------------------------------
- //作成した全状態情報を表示する
- 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 input_machine(string file_name)//MACHINEのメンバ関数にしました
- {
- //-----ファイル内容の例-----
- //startuml{stm_M1.png}
- //
- //[*] -> S1
- //S1 -> S2 : a
- //S2 -> S1 : [b==0]
- //S2 -> S3
- //S3 --> [*]
- //
- //@enduml
- ifstream ifs(file_name.c_str());//入力ファイルストリーム
- if(ifs.fail()){
- //読み込みファイルのオープンに失敗した時
- cerr << "Input file(" << file_name << ") open error.\n";
- return;
- }
- 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;//次の行へ
- }
- printf("-----\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の状態ポインタを取得する(無い時、DBに登録される)
- STATE *srcState = GetState(src);
- //指定ID状態ポインタを取得する(無い時、DBに登録される)
- STATE *targetState = GetState(target);
- //遷移を生成登録し、そのポインタを取得する(必ずDBに登録される)
- TRANSITION *tp = AddTrans(srcState,arrow,targetState,event,guard,action);
- //状態に遷移を追加する
- //遷移元状態には遷移をターゲット遷移として登録
- srcState->tgt.push_back(tp);
- //遷移先状態には遷移をソース遷移として登録
- targetState->src.push_back(tp);
- }
- }
- //------------------------------
- //指定ファイルにPlantUMLテキストを書き込みます
- void output_machine(string file_name){
- ofstream ofs(file_name.c_str());
- if(ofs.fail()){
- //書込みファイルのオープンに失敗した時
- cerr << "Output file(" << file_name << ") open error.\n";
- return;
- }
- ofs << mFileHeader << endl;
- ofs << endl;
- for(size_t i=0;i<mTransPtrVector.size();i++){
- //遷移の数だけ
- const TRANSITION *trans = mTransPtrVector[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";//
- }
- };
- //------------------------------------------------------------
- //遷移の動的配列をstringに変換する
- string TransVectorToString(const vector<TRANSITION*> &tpv,const string &separator)
- {
- ostringstream os;//文字を溜め込むことが出来る
- for(size_t i=0;i<tpv.size();i++){
- if(i)os << separator;//初回以外は、セパレータを挿入する
- os << tpv[i]->ToString();
- }
- return os.str();//溜め込んだ文字を返す
- }
- //------------------------------------------------------------
- //遷移の動的配列をstringに変換する
- string TransVectorToIdString(const vector<TRANSITION*> &tpv,const string &separator)
- {
- ostringstream os;//文字を溜め込むことが出来る
- for(size_t i=0;i<tpv.size();i++){
- if(i)os << separator;//初回以外は、セパレータを挿入する
- os << tpv[i]->id;
- }
- return os.str();//溜め込んだ文字を返す
- }
- //------------------------------------------------------------
- int main(void){
- MACHINE Machine;//データベースクラスのインスタンス(実体=オブジェクト=メモリ)
- Machine.input_machine("stm M1.txt");
- Machine.output_machine("stm M1-2.txt");
- Machine.PrintTransALL();
- Machine.PrintStateALL();
- system("pause");
- return 0;
- }
RAW Paste Data