|
From: <ma...@us...> - 2012-07-26 06:21:32
|
Revision: 1445
http://scstudio.svn.sourceforge.net/scstudio/?rev=1445&view=rev
Author: madzin
Date: 2012-07-26 06:21:21 +0000 (Thu, 26 Jul 2012)
Log Message:
-----------
Draft of Mscgen support, the functionality is not tested properly and is not implemented in full range of mscgen semantics.
Modified Paths:
--------------
trunk/src/data/CMakeLists.txt
trunk/tests/CMakeLists.txt
Added Paths:
-----------
trunk/src/data/mscgen/
trunk/src/data/mscgen/CMakeLists.txt
trunk/src/data/mscgen/Mscgen.g
trunk/src/data/mscgen/MscgenContext.cpp
trunk/src/data/mscgen/MscgenContext.h
trunk/src/data/mscgen/MscgenContext_Impl.h
trunk/src/data/mscgen/display_error.cpp
trunk/src/data/mscgen/display_error.h
trunk/src/data/mscgen/export.h
trunk/src/data/mscgen/module.cpp
trunk/src/data/mscgen/mscgen.h
trunk/src/data/mscgen/mscgen_load.cpp
trunk/src/data/mscgen/string_list_printer.h
Modified: trunk/src/data/CMakeLists.txt
===================================================================
--- trunk/src/data/CMakeLists.txt 2012-07-22 07:52:20 UTC (rev 1444)
+++ trunk/src/data/CMakeLists.txt 2012-07-26 06:21:21 UTC (rev 1445)
@@ -45,6 +45,7 @@
# build import-export formatters
ADD_SUBDIRECTORY(engmann)
ADD_SUBDIRECTORY(Z120)
+ADD_SUBDIRECTORY(mscgen)
ADD_SUBDIRECTORY(modelchecking)
# build transformers
ADD_SUBDIRECTORY(beautify)
Added: trunk/src/data/mscgen/CMakeLists.txt
===================================================================
--- trunk/src/data/mscgen/CMakeLists.txt (rev 0)
+++ trunk/src/data/mscgen/CMakeLists.txt 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,41 @@
+# do not make antlr a mandatory prerequisite
+IF(ANTLR_FOUND)
+ ADD_DEFINITIONS(-DHAVE_ANTLR)
+ INCLUDE_DIRECTORIES(${ANTLR_INCLUDE_DIR})
+
+ ADD_CUSTOM_COMMAND(
+ OUTPUT MscgenLexer.c MscgenLexer.h MscgenParser.c MscgenParser.h
+ COMMAND ${JAVA_RUNTIME} -classpath ${ANTLR_CLASSPATH} org.antlr.Tool Mscgen.g
+ DEPENDS Mscgen.g)
+
+ SET(PARSER_SOURCES
+ mscgen_load.cpp
+ Mscgen.g
+ MscgenContext.h
+ MscgenContext_Impl.h
+ MscgenContext.cpp
+ display_error.h
+ display_error.cpp
+ MscgenLexer.c
+ MscgenParser.c)
+
+ SET(PARSER_LIBRARIES
+ ${ANTLR_LIBRARIES})
+ENDIF(ANTLR_FOUND)
+
+ADD_LIBRARY(scmscgen SHARED
+ export.h
+ module.cpp
+ mscgen.h
+ ${PARSER_SOURCES}
+)
+
+TARGET_LINK_LIBRARIES(scmscgen
+ scmsc
+ ${PARSER_LIBRARIES}
+)
+
+INSTALL(TARGETS scmscgen
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
Added: trunk/src/data/mscgen/Mscgen.g
===================================================================
--- trunk/src/data/mscgen/Mscgen.g (rev 0)
+++ trunk/src/data/mscgen/Mscgen.g 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,215 @@
+grammar Mscgen;
+
+options
+{
+ language = C;
+ k=3;
+}
+
+//TODO error reporting not tested yet
+@lexer::includes
+{
+ #include "data/mscgen/MscgenContext.h"
+ #include "data/mscgen/display_error.h"
+
+ struct s_Mscgen* printer;
+ void scstudio_lexer_error_reporting(pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames);
+}
+
+@lexer::apifuncs
+{
+ RECOGNIZER->displayRecognitionError = &scstudio_lexer_error_reporting;
+}
+
+@lexer::members
+{
+ void scstudio_lexer_error_reporting(pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames)
+ {
+ lexer_error(printer, recognizer, tokenNames);
+ }
+}
+
+@parser::includes
+{
+ #include "data/mscgen/MscgenContext.h"
+ #include "data/mscgen/display_error.h"
+ #include "data/mscgen/MscgenLexer.h"
+
+ void scstudio_error_reporting(pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames);
+}
+
+@parser::apifuncs
+{
+ RECOGNIZER->displayRecognitionError = &scstudio_error_reporting;
+}
+
+@members
+{
+ struct MscgenContext* context;
+
+// void scstudio_error_reporting(pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames)
+// {
+// display_error(context, recognizer, tokenNames);
+// }
+}
+
+fragment
+Letter:
+ 'a'..'z' | 'A'..'Z'
+;
+
+fragment
+Decimal_Digit:
+ '0'..'9'
+;
+
+String:
+ (Letter | Decimal_Digit | '_')+
+ | '"' ~('"')+ '"' // " comment added due to syntax highlighting
+;
+
+WHITESPACE:
+ ('\t' | ' ' | '\r' | '\n')+ { $channel = HIDDEN; }
+;
+
+LINE_COMMENT:
+ ('#' | '//') ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
+;
+
+COMMENT:
+ '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
+;
+
+msc [struct s_Mscgen* msc_gen] returns [struct s_Msc** mscs]:
+ {
+ context = new_context(msc_gen);
+ printer = msc_gen;
+ init(context);
+ }
+
+ (
+ 'msc' '{' optlist ';' entitylist ';' arclist ';' '}'
+ | 'msc' '{' entitylist ';' arclist ';' '}'
+ )
+
+ {
+ $mscs = get_total_msc(context);
+ delete_context(context);
+ }
+;
+
+optlist: opt (',' optlist)?
+;
+
+opt: optval '=' String
+;
+
+optval: 'hscale'
+ | 'width'
+ | 'arcgradient'
+ | 'wordwraparcs'
+;
+
+entitylist: entity (',' entitylist)? // list of entities a.k. list of instances
+ // entity (',' entity)*
+;
+
+
+entity:
+ String ('[' attrlist ']')* // entity definition,
+
+ { add_instance(context, (char*) $String.text->chars); }
+;
+
+arclist:
+ arc ((';' | ',') arclist)?
+;
+
+arc
+ @init { clean_message(context); }
+ :
+
+ ( arcrel ('[' attrlist ']')? { add_message(context); } )
+ | (graphics ('[' attrlist ']')?)
+;
+
+graphics:
+ '...'
+ | '---' // comment or action
+ | '|||' // space
+;
+
+arcrel:
+ String relation_box String // ask for semantics
+ | String relation_bi String // ask for semantics
+ | a=String relation_to b=String
+ { add_from_to(context, (char*) $a.text->chars, (char*) $b.text->chars); }
+ | String relation_line String // ask for semantics
+ | a=String relation_from b=String
+ { add_from_to(context, (char*) $b.text->chars, (char*) $a.text->chars); }
+ | a=String relation_to b='*' // broadcast
+ { add_from_to(context, (char*) $a.text->chars, (char*) $b.text->chars); }
+ | a='*' relation_from b=String // broadcast
+ { add_from_to(context, (char*) $b.text->chars, (char*) $a.text->chars); }
+;
+
+relation_box: 'box'
+ | 'abox'
+ | 'rbox'
+ | 'note'
+;
+
+relation_line: '--'
+ | '=='
+ | '..'
+ | '::'
+;
+
+relation_bi: '<->'
+ | '<=>'
+ | '<.>'
+ | '<<=>>'
+ | '<:>'
+;
+
+relation_to: '->' // message
+ | '=>' // message
+ | '.>'
+ | '=>>' // message
+ | ':>' // message
+ | '-x' { add_lost_message_flag(context); } // lost message
+;
+
+relation_from: '<-' // message
+ | '<=' // message
+ | '<.' //
+ | '<<=' // message
+ | '<:' // message
+ | 'x-' { add_lost_message_flag(context); }// lost message
+;
+
+attrlist:
+ { clean_attributes(context); }
+
+ attr (',' attr)*
+;
+
+attr:
+ attrval '=' String
+
+ { add_attr(context, (char*) $attrval.text->chars, (char*) $String.text->chars); }
+;
+
+attrval:
+ 'label'
+ | 'url'
+ | 'id'
+ | 'idurl'
+ | 'linecolour'
+ | 'textcolour'
+ | 'textbgcolour'
+ | 'arclinecolour'
+ | 'arctextcolour'
+ | 'arctextbgcolour'
+ | 'arcskip'
+;
Added: trunk/src/data/mscgen/MscgenContext.cpp
===================================================================
--- trunk/src/data/mscgen/MscgenContext.cpp (rev 0)
+++ trunk/src/data/mscgen/MscgenContext.cpp 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,202 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2008 Matus Madzin <go...@ma...>
+ *
+ * $Id: Context.cpp 1439 2012-07-08 21:36:59Z madzin $
+ */
+
+/*
+ * we use ANTRL v3 (ANTLR 3.1.1)
+ * see http://www.antlr.org
+ */
+
+/*
+ * Maximal number of warning/error message is 34
+ */
+
+#ifndef __MscgenParserStruct__
+#define __MscgenParserStruct__
+
+#include "MscgenContext_Impl.h"
+
+/*
+ * Set beginning values
+ */
+void init(struct MscgenContext* context)
+{
+ context->msc = new BMsc(L"mscgen");
+ context->attributes = new Attributes;
+
+ context->attributes->label = "";
+ context->attributes->url = "";
+ context->attributes->id = "";
+ context->attributes->idurl = "";
+ context->attributes->linecolour = "";
+ context->attributes->textcolour = "";
+ context->attributes->textbgcolour = "";
+ context->attributes->arclinecolour = "";
+ context->attributes->arctextcolour = "";
+ context->attributes->arctextbgcolour = "";
+ context->attributes->arcskip = "";
+
+ context->message = new Message;
+
+ context->message->from = "";
+ context->message->to = "";
+ context->message->incomplete = false;
+
+ context->instances.clear();
+}
+
+/*
+ * Memory initialization.
+ */
+struct MscgenContext* new_context(struct s_Mscgen* mscgen)
+{
+ MscgenContext* context = new MscgenContext;
+
+ //TODO
+ if(mscgen == NULL)
+ std::cerr << "Fatal error" << std::endl;
+
+ context->mscgen = static_cast<Mscgen*> (mscgen);
+
+ return context;
+}
+
+/*
+ * Free memory space
+ */
+void delete_context(struct MscgenContext* context)
+{
+ delete context;
+}
+
+void add_instance(struct MscgenContext* context, char* name)
+{
+ InstancePtr instance = new Instance(TOWSTRING(context->attributes->label));
+ StrictOrderAreaPtr strict(new StrictOrderArea());
+ instance->add_area(strict);
+
+ context->msc->add_instance(instance);
+ context->instances.insert(std::make_pair(name, instance));
+}
+
+void add_from_to(struct MscgenContext* context, char* from, char* to)
+{
+ context->message->from = from;
+ context->message->to = to;
+}
+
+void add_message(struct MscgenContext* context)
+{
+ InstancePtr instance_from = context->instances[context->message->from];
+ EventPtr event_from = instance_from->get_last()->add_event();
+
+ InstancePtr instance_to;
+ EventPtr event_to;
+
+ // complete message
+ if(!context->message->incomplete)
+ {
+ instance_to = context->instances[context->message->to];
+ event_to = instance_to->get_last()->add_event();
+
+ CompleteMessagePtr message = new CompleteMessage(TOWSTRING(context->attributes->label));
+ message->glue_events(event_from, event_to);
+
+ return ;
+ }
+
+ // incomplete message
+ //TODO the third parameter in constructor is (not) supposed to be filled???? what is the semantics of the third parameter?
+ IncompleteMessagePtr message = new IncompleteMessage(LOST, TOWSTRING(context->attributes->label));
+ message->glue_event(event_from);
+}
+
+void clean_attributes(struct MscgenContext* context)
+{
+ context->attributes->label = "";
+ context->attributes->url = "";
+ context->attributes->id = "";
+ context->attributes->idurl = "";
+ context->attributes->linecolour = "";
+ context->attributes->textcolour = "";
+ context->attributes->textbgcolour = "";
+ context->attributes->arclinecolour = "";
+ context->attributes->arctextcolour = "";
+ context->attributes->arctextbgcolour = "";
+ context->attributes->arcskip = "";
+}
+
+void clean_message(struct MscgenContext* context)
+{
+ context->message->from = "";
+ context->message->to = "";
+ context->message->incomplete = false;
+}
+
+void add_lost_message_flag(struct MscgenContext* context)
+{
+ context->message->incomplete = true;
+}
+
+void add_attr(struct MscgenContext* context, char* name, char* value)
+{
+ std::string s_name = name;
+ std::string s_value = value;
+
+ const char* attr[] = {"label", "url", "id", "idurl", "linecolour", "textcolour", "textbgcolour", "arclinecolour", "arctextcolour", "arctextbgcolour", "arcskip"};
+ size_t index = std::find(attr, attr+10, s_name) - attr; //returns an index in array
+
+ //remove all '"' from the string which is stored in value
+ s_value.erase(std::remove(s_value.begin(), s_value.end(), '"'), s_value.end());
+
+ switch(index)
+ {
+ case 0: context->attributes->label = s_value; break;
+ case 1: context->attributes->url = s_value; break;
+ case 2: context->attributes->id = s_value; break;
+ case 3: context->attributes->idurl = s_value; break;
+ case 4: context->attributes->linecolour = s_value; break;
+ case 5: context->attributes->textcolour = s_value; break;
+ case 6: context->attributes->textbgcolour = s_value; break;
+ case 7: context->attributes->arclinecolour = s_value; break;
+ case 8: context->attributes->arctextcolour = s_value; break;
+ case 9: context->attributes->arctextbgcolour = s_value; break;
+ case 10: context->attributes->arcskip = s_value; break;
+ default: context->mscgen->print_report(RS_WARNING, stringize() << L"Warning 01: Unknown attribute " << TOWSTRING(s_name) << L".");
+ }
+}
+
+struct s_Msc** get_total_msc(struct MscgenContext* context)
+{
+ s_Msc** result = NULL;
+ Msc* msc = context->msc.get();
+
+ if(msc == NULL)
+ return result;
+
+ result = new s_Msc*[2];
+
+ intrusive_ptr_add_ref(msc);
+ result[0] = static_cast<s_Msc*>(msc);
+ result[1] = NULL;
+
+ return result;
+}
+
+#endif
+
+// $Id: Context.cpp 1439 2012-07-08 21:36:59Z madzin $
Added: trunk/src/data/mscgen/MscgenContext.h
===================================================================
--- trunk/src/data/mscgen/MscgenContext.h (rev 0)
+++ trunk/src/data/mscgen/MscgenContext.h 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,66 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2008 Matus Madzin <go...@ma...>
+ *
+ * $Id: Context.h 1439 2012-07-08 21:36:59Z madzin $
+ */
+
+#ifndef _MSCGEN_CONTEXT_H
+#define _MSCGEN_CONTEXT_H
+
+/*
+ * we use ANTRL v3 (ANTLR 3.1.1)
+ * see http://www.antlr.org
+ */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct MscgenContext;
+struct s_Msc;
+struct s_Mscgen;
+
+struct Message;
+struct Attributes;
+
+struct MscgenContext* new_context(struct s_Mscgen* mscgen);
+
+void init(struct MscgenContext* context);
+
+void delete_context(struct MscgenContext* context);
+
+void add_instance(struct MscgenContext* context, char* name);
+
+void add_from_to(struct MscgenContext* context, char* from, char* to);
+
+void add_message(struct MscgenContext* context);
+
+void clean_attributes(struct MscgenContext* context);
+
+void clean_message(struct MscgenContext* context);
+
+void add_lost_message_flag(struct MscgenContext* context);
+
+void add_attr(struct MscgenContext* context, char* name, char* value);
+
+struct s_Msc** get_total_msc(struct MscgenContext* context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MSCGEN_CONTEXT_H */
+
+// $Id: Context.h 1439 2012-07-08 21:36:59Z madzin $
Added: trunk/src/data/mscgen/MscgenContext_Impl.h
===================================================================
--- trunk/src/data/mscgen/MscgenContext_Impl.h (rev 0)
+++ trunk/src/data/mscgen/MscgenContext_Impl.h 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,81 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2008 Matus Madzin <go...@ma...>
+ *
+ * $Id: Context_Impl.h 1439 2012-07-08 21:36:59Z madzin $
+ */
+
+/*
+ * we use ANTRL v3 (ANTLR 3.1.1)
+ * see http://www.antlr.org
+ */
+
+#ifndef _MscgenContext_Impl_
+#define _MscgenContext_Impl_
+
+#include "data/mscgen/MscgenContext.h"
+#include <stdlib.h>
+#include <string>
+#include <iostream>
+#include <map>
+#include <vector>
+#include <list>
+#include <set>
+#include "data/msc.h"
+#include "mscgen.h"
+
+enum hmsc_node_type {reference, connection, condition};
+
+
+struct MscgenContext
+{
+ BMscPtr msc;
+ Message* message;
+ Attributes* attributes;
+ Mscgen* mscgen;
+
+ std::map<std::string, InstancePtr> instances;
+
+ ~MscgenContext() {}
+};
+
+struct Message
+{
+ std::string from;
+ std::string to;
+ bool incomplete;
+
+ ~Message() {}
+};
+
+struct Attributes
+{
+ std::string label;
+ std::string url;
+ std::string id;
+ std::string idurl;
+ std::string linecolour;
+ std::string textcolour;
+ std::string textbgcolour;
+ std::string arclinecolour;
+ std::string arctextcolour;
+ std::string arctextbgcolour;
+ std::string arcskip;
+
+ ~Attributes() {}
+};
+
+#endif // _MscgenContext_Impl_
+
+// $Id: Context_Impl.h 1439 2012-07-08 21:36:59Z madzin $
Added: trunk/src/data/mscgen/display_error.cpp
===================================================================
--- trunk/src/data/mscgen/display_error.cpp (rev 0)
+++ trunk/src/data/mscgen/display_error.cpp 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,272 @@
+#include "data/mscgen/display_error.h"
+#include "data/mscgen/MscgenContext_Impl.h"
+
+// Implementation based on src/runtime/C/antlr3baserecognizer.c, display()
+
+void reportError (pANTLR3_BASE_RECOGNIZER recognizer)
+{
+ if (recognizer->state->errorRecovery == ANTLR3_TRUE)
+ {
+ return;
+ }
+
+ // Signal we are in error recovery now
+ recognizer->state->errorRecovery = ANTLR3_TRUE;
+
+ // Indicate this recognizer had an error while processing.
+ recognizer->state->errorCount++;
+
+ // Call the error display routine
+ recognizer->displayRecognitionError(recognizer, recognizer->state->tokenNames);
+}
+
+void display_error(struct MscgenContext* context, pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames)
+{
+ stringize report;
+
+ // Retrieve some info for easy reading.
+ pANTLR3_EXCEPTION ex = recognizer->state->exception;
+ pANTLR3_COMMON_TOKEN theToken= (pANTLR3_COMMON_TOKEN)(recognizer->state->exception->token);
+
+ // See if there is a 'filename' we can use
+ if (ex->streamName == NULL)
+ {
+ if (((pANTLR3_COMMON_TOKEN)(ex->token))->type == ANTLR3_TOKEN_EOF)
+ {
+ report << "<EOF>";
+ }
+ else
+ {
+ report << "<unknown>";
+ }
+ }
+ else
+ {
+ pANTLR3_STRING ftext = ex->streamName->to8(ex->streamName);
+
+ char* last_slash = (char *)ftext->chars;
+ bool slash_present = false;
+ // strip file path
+ for(char *ch = (char *)ftext->chars; *ch != 0; ch++)
+ {
+ if(*ch == '\\' || *ch == '/')
+ {
+ last_slash = ch;
+ slash_present = true;
+ }
+ }
+
+ if(slash_present)
+ {
+ report << last_slash+1
+ << "[" << theToken->getLine(theToken)
+ << "," << theToken->getCharPositionInLine(theToken) << "]";
+ }
+ else
+ {
+ report << last_slash
+ << "[" << theToken->getLine(theToken)
+ << "," << theToken->getCharPositionInLine(theToken) << "]";
+ }
+ }
+
+ report << " ";
+
+ // Note that in the general case, errors thrown by tree parsers indicate a problem
+ // with the output of the parser or with the tree grammar itself. The job of the parser
+ // is to produce a perfect (in traversal terms) syntactically correct tree, so errors
+ // at that stage should really be semantic errors that your own code determines and handles
+ // in whatever way is appropriate.
+ switch (ex->type)
+ {
+ case ANTLR3_UNWANTED_TOKEN_EXCEPTION:
+
+ // Indicates that the recognizer was fed a token which seesm to be
+ // spurious input. We can detect this when the token that follows
+ // this unwanted token would normally be part of the syntactically
+ // correct stream. Then we can see that the token we are looking at
+ // is just something that should not be there and throw this exception.
+ if (tokenNames == NULL)
+ {
+ report << "Unwanted input";
+ }
+ else
+ {
+ if (ex->expecting == ANTLR3_TOKEN_EOF)
+ {
+ report << "Unwanted input: expected <EOF>";
+ }
+ else
+ {
+ report << "Unwanted input: expected " << (char*)(tokenNames[ex->expecting]);
+ }
+ }
+ break;
+
+ case ANTLR3_MISSING_TOKEN_EXCEPTION:
+
+ // Indicates that the recognizer detected that the token we just
+ // hit would be valid syntactically if preceeded by a particular
+ // token. Perhaps a missing ';' at line end or a missing ',' in an
+ // expression list, and such like.
+ if (tokenNames == NULL)
+ {
+ report << "Missing token (" << ex->expecting << ")";
+ }
+ else
+ {
+ if (ex->expecting == ANTLR3_TOKEN_EOF)
+ {
+ report << "Missing <EOF>";
+ }
+ else
+ {
+ report << "Missing " << (char*)(tokenNames[ex->expecting]);
+ }
+ }
+ break;
+
+ case ANTLR3_RECOGNITION_EXCEPTION:
+
+ // Indicates that the recognizer received a token
+ // in the input that was not predicted. This is the basic exception type
+ // from which all others are derived. So we assume it was a syntax error.
+ // You may get this if there are not more tokens and more are needed
+ // to complete a parse for instance.
+ report << "Syntax error";
+ break;
+
+ case ANTLR3_MISMATCHED_TOKEN_EXCEPTION:
+
+ // We were expecting to see one thing and got another. This is the
+ // most common error if we coudl not detect a missing or unwanted token.
+ // Here you can spend your efforts to
+ // derive more useful error messages based on the expected
+ // token set and the last token and so on. The error following
+ // bitmaps do a good job of reducing the set that we were looking
+ // for down to something small. Knowing what you are parsing may be
+ // able to allow you to be even more specific about an error.
+ if (tokenNames == NULL)
+ {
+ report << "Syntax error";
+ }
+ else
+ {
+ if (ex->expecting == ANTLR3_TOKEN_EOF)
+ {
+ report << "Expected <EOF>";
+ }
+ else
+ {
+ report << "Expected " << tokenNames[ex->expecting];
+ }
+ }
+ break;
+
+ case ANTLR3_NO_VIABLE_ALT_EXCEPTION:
+
+ // We could not pick any alt decision from the input given
+ // so god knows what happened - however when you examine your grammar,
+ // you should. It means that at the point where the current token occurred
+ // that the DFA indicates nowhere to go from here.
+ report << "Cannot match to any predicted input";
+ break;
+
+ case ANTLR3_MISMATCHED_SET_EXCEPTION:
+ {
+
+ // This means we were able to deal with one of a set of
+ // possible tokens at this point, but we did not see any
+ // member of that set.
+ report << "Unexpected input";
+
+ // What tokens could we have accepted at this point in the parse?
+ pANTLR3_BITSET errBits = antlr3BitsetLoad(ex->expectingSet);
+ ANTLR3_UINT32 numbits = errBits->numBits(errBits);
+ ANTLR3_UINT32 size = errBits->size(errBits);
+
+ if (size > 0)
+ {
+ ANTLR3_UINT32 count = 0;
+ report << ": expected one of";
+
+ // However many tokens we could have dealt with here, it is usually
+ // not useful to print ALL of the set here. I arbitrarily chose 8
+ // here, but you should do whatever makes sense for you of course.
+ // No token number 0, so look for bit 1 and on.
+ for(ANTLR3_UINT32 bit = 1; bit < numbits && count < 8 && count < size; bit++)
+ {
+ // TODO: This doesn;t look right - should be asking if the bit is set!!
+ if (tokenNames[bit])
+ {
+ report << (count > 0 ? ", " : " ") << "<" << tokenNames[bit] << ">";
+ count++;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case ANTLR3_EARLY_EXIT_EXCEPTION:
+
+ // We entered a loop requiring a number of token sequences
+ // but found a token that ended that sequence earlier than
+ // we should have done.
+ report << "Missing elements";
+ break;
+
+ default:
+
+ // We don't handle any other exceptions here, but you can
+ // if you wish. If we get an exception that hits this point
+ // then we are just going to report what we know about the
+ // token.
+ report << "Syntax not recognized";
+ break;
+ }
+
+ report << ".";
+
+ context->mscgen->print_report(RS_ERROR, report);
+}
+
+void lexer_error(struct s_Mscgen* mscgen, pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames)
+{
+ Mscgen* printer = static_cast<Mscgen*> (mscgen);
+ stringize report;
+
+ // Retrieve some info for easy reading.
+ pANTLR3_LEXER lexer = (pANTLR3_LEXER)(recognizer->super);
+ pANTLR3_EXCEPTION ex = lexer->rec->state->exception;
+
+ // See if there is a 'filename' we can use
+ if(ex->name == NULL)
+ report << "-unknown source-";
+ else
+ {
+ pANTLR3_STRING ftext = ex->streamName->to8(ex->streamName);
+
+ char* last_slash = (char *)ftext->chars;
+ bool slash_present = false;
+ // strip file path
+ for(char *ch = (char *)ftext->chars; *ch != 0; ch++)
+ {
+ if(*ch == '\\' || *ch == '/')
+ {
+ last_slash = ch;
+ slash_present = true;
+ }
+ }
+
+ if(slash_present)
+ report << last_slash+1;
+ else
+ report << last_slash;
+ }
+ report << "[" << recognizer->state->exception->line << "," << ex->charPositionInLine+1 << "] Lexer error.";
+
+ printer->print_report(RS_ERROR, report);
+}
+
+// $Id: display_error.cpp 1013 2010-12-13 16:34:52Z madzin $
Added: trunk/src/data/mscgen/display_error.h
===================================================================
--- trunk/src/data/mscgen/display_error.h (rev 0)
+++ trunk/src/data/mscgen/display_error.h 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,22 @@
+#ifndef _MscgenDisplay_H
+#define _MscgenDisplay_H
+
+#include<antlr3.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void reportError (pANTLR3_BASE_RECOGNIZER recognizer);
+
+void display_error(struct MscgenContext* context, pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames);
+
+void lexer_error(struct s_Mscgen* z, pANTLR3_BASE_RECOGNIZER recognizer, pANTLR3_UINT8 *tokenNames);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _MscgenDisplay_H
+
+// $Id: display_error.h 1006 2010-12-08 20:34:49Z madzin $
Added: trunk/src/data/mscgen/export.h
===================================================================
--- trunk/src/data/mscgen/export.h (rev 0)
+++ trunk/src/data/mscgen/export.h 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,37 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2008 Petr Gotthard <pet...@ce...>
+ *
+ * $Id: export.h 146 2009-01-03 16:08:45Z gotthardp $
+ */
+
+#ifndef _SCMSCGEN_EXPORT_H
+#define _SCMSCGEN_EXPORT_H
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4251)
+
+#if defined(scMSCGEN_EXPORTS)
+#define SCMSCGEN_EXPORT __declspec(dllexport)
+#else
+#define SCMSCGEN_EXPORT __declspec(dllimport)
+#endif
+
+#else
+#define SCMSCGEN_EXPORT
+#endif
+
+#endif /* _SCMSCGEN_EXPORT_H */
+
+// $Id: export.h 146 2009-01-03 16:08:45Z gotthardp $
Added: trunk/src/data/mscgen/module.cpp
===================================================================
--- trunk/src/data/mscgen/module.cpp (rev 0)
+++ trunk/src/data/mscgen/module.cpp 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,33 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2009 Petr Gotthard <pet...@ce...>
+ *
+ * $Id: module.cpp 1377 2012-04-12 17:52:43Z lkorenciak $
+ */
+
+#include "data/mscgen/mscgen.h"
+
+// module initialization function
+// note: the Visio add-on searches for a function of this name
+extern "C" SCMSCGEN_EXPORT
+Formatter** init_formatters()
+{
+ Formatter **result = new Formatter* [2];
+ result[0] = new Mscgen();
+ result[1] = NULL;
+
+ return result;
+}
+
+// $Id: module.cpp 1377 2012-04-12 17:52:43Z lkorenciak $
Added: trunk/src/data/mscgen/mscgen.h
===================================================================
--- trunk/src/data/mscgen/mscgen.h (rev 0)
+++ trunk/src/data/mscgen/mscgen.h 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,134 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2008-2009 Petr Gotthard <pet...@ce...>
+ *
+ * $Id: z120.h 1222 2011-12-11 21:16:08Z obouda $
+ */
+
+#ifndef _MSCGEN_H
+#define _MSCGEN_H
+
+#include "data/formatter.h"
+#include "data/mscgen/export.h"
+
+struct s_Mscgen { };
+
+/* String modifier to print Z.120 character strings in a correct character set.
+ */
+//class VALID_CHARACTER_STRING
+//{
+//public:
+// VALID_CHARACTER_STRING(const std::wstring &text)
+// : m_text(text)
+// { }
+
+// friend std::ostream&
+// operator<<(std::ostream& os, const VALID_CHARACTER_STRING& value);
+
+//private:
+// std::wstring m_text;
+//};
+
+class SCMSCGEN_EXPORT Mscgen : public s_Mscgen, public Formatter
+
+#ifdef HAVE_ANTLR
+ , public ImportFormatter
+#endif
+{
+public:
+ //! file extension used to distinguish this format
+ // note: DLL in Windows cannot return pointers to static data
+ virtual std::string get_extension() const
+ { return "mpr"; }
+ //! human readable description of this format
+ virtual std::string get_description() const
+ { return "Mscgen Textual Format"; }
+
+#ifdef HAVE_ANTLR
+ //! import MSC document
+ virtual std::vector<MscPtr> load_msc(const std::string &filename);
+ //! Returns a list of transformation for this format.
+ virtual TransformationList get_transformations(MscPtr msc) const;
+#endif
+ //! Returns a list of preconditions for this format.
+// virtual PreconditionList get_preconditions(MscPtr msc) const;
+
+ //! export MSC document
+ // virtual int save_msc(std::ostream& stream, const std::wstring &name,
+// const MscPtr& selected_msc, const std::vector<MscPtr>& msc = std::vector<MscPtr>());
+
+// void print_keyword_warning(const std::string& name)
+// {
+// if(m_warned_names.find(name) == m_warned_names.end())
+// {
+// print_report(RS_WARNING, stringize()
+// << L"Warning: Name '" << TOWSTRING(name) << "' is a reserved keyword.");
+// m_warned_names.insert(name);
+// }
+// }
+protected:
+// int save_msc(std::ostream& stream, const MscPtr& msc);
+ // note: insertion to m_printing must not invalidate iterators
+ std::list<MscPtr> m_printing;
+
+ //! export a basic MSC drawing
+// int save_bmsc(std::ostream& stream, const BMscPtr& bmsc);
+ //! export a HMSC drawing
+// int save_hmsc(std::ostream& stream, const HMscPtr& hmsc);
+
+// template<class OutputStreamType>
+// void print_element_attributes(OutputStreamType& stream, const MscElementPtr& element);
+
+ // print global comments
+ // note: used when the comment is attached to BMsc or HMsc
+// template<class C>
+// void print_texts(std::ostream& stream, const boost::intrusive_ptr<C>& commentable)
+// {
+// for(CommentPtrSet::const_iterator cpos = commentable->get_comments().begin();
+// cpos != commentable->get_comments().end(); cpos++)
+// {
+// print_element_attributes(stream, *cpos);
+// stream << "text '" << VALID_CHARACTER_STRING((*cpos)->get_text()) << "';" << std::endl;
+// }
+// }
+
+ // print local comments
+ // note: used when the comment is attached to Event, HMscNode, etc.
+// template<class C>
+// void print_comments(std::ostream& stream, const boost::intrusive_ptr<C>& commentable)
+// {
+// for(CommentPtrSet::const_iterator cpos = commentable->get_comments().begin();
+// cpos != commentable->get_comments().end(); cpos++)
+// {
+// print_element_attributes(stream, *cpos);
+// stream << " comment '" << VALID_CHARACTER_STRING((*cpos)->get_text()) << "'";
+// }
+// }
+
+// void print_event(std::ostream& stream,
+// PtrIDMap<MscMessagePtr>& message_id_map, const EventPtr& event);
+// void print_time_relations(std::ostream& stream,
+// PtrIDMap<EventPtr>& event_id_map, const EventPtr& event);
+// void print_time_relations1(std::ostream& stream,
+// const ReferenceNodePtr& reference_node, TimeRelationRefNodePtrSet relations);
+// void print_time_relations2(std::ostream& stream,
+// PtrIDMap<HMscNodePtr>& node_id_map, const std::string& title,
+// const ReferenceNodePtr& reference_node, TimeRelationRefNodePtrSet relations);
+
+ std::set<std::string> m_warned_names;
+};
+
+#endif /* _Z120_H */
+
+// $Id: z120.h 1222 2011-12-11 21:16:08Z obouda $
Added: trunk/src/data/mscgen/mscgen_load.cpp
===================================================================
--- trunk/src/data/mscgen/mscgen_load.cpp (rev 0)
+++ trunk/src/data/mscgen/mscgen_load.cpp 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,121 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2008-2009 Petr Gotthard <pet...@ce...>
+ *
+ * $Id: z120_load.cpp 1301 2012-01-23 09:35:01Z xrehak $
+ */
+
+#include "mscgen.h"
+// Process "Z120.g" with ANTLR 3.1.1 to produce the following files.
+#include "MscgenLexer.h"
+#include "MscgenParser.h"
+
+std::vector<MscPtr> Mscgen::load_msc(const std::string &filename)
+{
+ std::vector<MscPtr> result;
+
+#ifdef ANTLR3_ENC_8BIT
+ // ANTLR version >= 3.4
+ pANTLR3_INPUT_STREAM input =
+ antlr3FileStreamNew((pANTLR3_UINT8)filename.c_str(), ANTLR3_ENC_8BIT);
+#else
+ // ANTLR version 3.1.*
+ pANTLR3_INPUT_STREAM input =
+ antlr3AsciiFileStreamNew((pANTLR3_UINT8)filename.c_str());
+#endif
+
+ if (input == NULL || input < 0)
+ {
+ print_report(RS_ERROR,
+ stringize() << "Cannot open file '" << TOWSTRING(filename) << "'.");
+
+ return result;
+ }
+
+ pMscgenLexer lxr = MscgenLexerNew(input);
+
+ if (lxr == NULL)
+ {
+ input->close(input); input = NULL;
+
+ return result;
+ }
+
+ pANTLR3_COMMON_TOKEN_STREAM tstream =
+ antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lxr));
+
+ if (tstream == NULL)
+ {
+ lxr->free(lxr); lxr = NULL;
+ input->close(input); input = NULL;
+
+ return result;
+ }
+
+ pMscgenParser psr = MscgenParserNew(tstream);
+
+ if (psr == NULL)
+ {
+ tstream->free(tstream); tstream = NULL;
+ lxr->free(lxr); lxr = NULL;
+ input->close(input); input = NULL;
+
+ return result;
+ }
+
+ s_Msc** my_mscs = psr->msc(psr, static_cast<s_Mscgen*>(this));
+
+ if (my_mscs == NULL)
+ {
+ print_report(RS_ERROR, stringize() << "Error 22: Syntax error ");
+
+ psr->free(psr); psr = NULL;
+ tstream->free(tstream); tstream = NULL;
+ lxr->free(lxr); lxr = NULL;
+ input->close(input); input = NULL;
+
+ return result;
+ }
+
+ for(int i = 0; my_mscs[i] != NULL; i++)
+ {
+ Msc* my_msc = static_cast<Msc*>(my_mscs[i]);
+ if(my_msc == NULL)
+ continue;
+
+ result.push_back(my_msc);
+ // my_msc is an extern "C" pointer to an object pointed by smart pointers
+ // the counter was increased in get_msc_fun() to avoid premature delete
+ intrusive_ptr_release(my_msc);
+ }
+
+ delete[] my_mscs;
+
+ psr->free(psr); psr = NULL;
+ tstream->free(tstream); tstream = NULL;
+ lxr->free(lxr); lxr = NULL;
+ input->close(input); input = NULL;
+
+ return result;
+}
+
+
+ImportFormatter::TransformationList Mscgen::get_transformations(MscPtr msc) const
+{
+ ImportFormatter::TransformationList result;
+ result.push_back(L"Beautify");
+ return result;
+}
+
+// $Id: z120_load.cpp 1301 2012-01-23 09:35:01Z xrehak $
Added: trunk/src/data/mscgen/string_list_printer.h
===================================================================
--- trunk/src/data/mscgen/string_list_printer.h (rev 0)
+++ trunk/src/data/mscgen/string_list_printer.h 2012-07-26 06:21:21 UTC (rev 1445)
@@ -0,0 +1,298 @@
+/*
+ * scstudio - Sequence Chart Studio
+ * http://scstudio.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Copyright (c) 2008-2009 Petr Gotthard <pet...@ce...>
+ *
+ * $Id: string_list_printer.h 1230 2011-12-13 00:38:38Z obouda $
+ */
+
+#ifndef _STRING_LIST_PRINTER_H
+#define _STRING_LIST_PRINTER_H
+
+#include <vector>
+#include <string>
+#include <sstream>
+#include <algorithm>
+#include <functional>
+
+/**
+ * \brief A utility class for printing a list of strings sorted in lexicographic order.
+ *
+ * The printer should be used in the cases when a list of strings should be printed,
+ * while their mutual order is not important (all item permutations are equivallent).
+ *
+ * The items are sorted lexicographically by default. Alternatively, a sorting key
+ * may be specified for each item, which is used as a primary sorting key. Item
+ * values are then used as secondary sorting keys.
+ *
+ * The contents may be printed to an ostream or a stringstream (or generally anything
+ * with overloaded operator <<).
+ *
+ * Simple usage example:
+ * <code>
+ * StringListPrinter printer("connect: ", ", ", ";\n");
+ * printer.add_item("L2");
+ * printer.add_item("L1");
+ * printer.add_item("L0");
+ * printer.add_item("L1");
+ * printer.print(std::cout); // prints "connect: L0, L1, L1, L2;\n"
+ * </code>
+ *
+ * Items may also be specified by consecutive filling operations:
+ * <code>
+ * StringListPrinter printer;
+ * printer.set_item_separator(","); // an alternative way for specifying parameters
+ * printer << 'L';
+ * printer << 42;
+ * printer.commit_item(); // adds item "L42"
+ * printer << 'L';
+ * printer << 13;
+ * printer.commit_item(); // adds item "L13"
+ * // the stream for filling current item can be had for other functions directly
+ * // printing to a stream:
+ * print_element_attributes(printer.get_current_stream(), *spos); // could print "[attributes]"
+ * printer << "L50";
+ * printer.commit_item();
+ * printer.print(std::cout); // prints "[attributes]L50,L13,L42"
+ * </code>
+ *
+ * Note the last item is placed as the first item, as "/" < "L". If some order should be
+ * directed, a custom key may be specified both for add_item() and commit_item() methods:
+ * <code>
+ * StringListPrinter printer;
+ * printer.add_item("abc", "2");
+ * printer << "def";
+ * printer.commit_item("3");
+ * printer.add_item("xyz", "1");
+ * printer.print(std::cout); // prints "xyzabcdef"
+ * </code>
+ * ...and the type of keys may be specified as a basic template class argument:
+ * <code>
+ * BasicStringListPrinter<int> printer;
+ * printer.add_item("abc", 2);
+ * printer << "def";
+ * printer.commit_item(3);
+ * printer.add_item("xyz", 1);
+ * printer.print(std::cout); // prints "xyzabcdef"
+ * </code>
+ *
+ * The printer may print to anything overloading operator <<:
+ * <code>
+ * StringListPrinter printer;
+ * printer.add_item("a").add_item("b").add_item("c"); // note the fluent interface
+ * stringstream ss;
+ * printer.print(ss);
+ * std::cout << ss.str(); // prints "abc"
+ * </code>
+ * ... even another StringListPrinter:
+ * <code>
+ * StringListPrinter sub1("sub1head ", ", ", " sub1tail");
+ * sub1.add_item("A").add_item("B").add_item("C");
+ * StringListPrinter sub2("sub2head ", ", ", " sub2tail");
+ * sub2.add_item("X").add_item("Y").add_item("Z");
+ * StringListPrinter main("mainhead ", "; ", " maintail"); // do not confuse with "Mein Teil" by Rammstein ;-)
+ * sub1.print(main.get_current_stream());
+ * main.commit_item();
+ * sub2.print(main.get_current_stream());
+ * main.commit_item();
+ * main.print(std::cout); // prints "mainhead sub1head A, B, C sub1tail; sub2head X, Y, Z sub2tail maintail"
+ * </code>
+ *
+ * For the cases lexicographic ordering is not suitable, a custom comparator (both
+ * for items and keys) may be specified as a template argument. Similarly, the item
+ * and key datatypes are also templated. Note, however, that operator == must be defined
+ * on the key type, ItemComparator must compare std::basic_string<CharType> objects,
+ * and KeyComparator must compare KeyType objects.
+ * <code>
+ * StringListPrinter<int, wchar_t, std::greater<int>, std::less<std::wstring> > printer(L"head ");
+ * // printer now uses wstrings, integers as keys; sorting by keys is descending:
+ * printer.add_item(L"abc", 3).add_item(L"def", 1).add_item(L"xyz", 2);
+ * printer.print(std::wcout); // prints: "head abcxyzdef"
+ * </code>
+ *
+ *
+ * @author Ondrej Bouda <ond...@wh...>
+ */
+#define ItemType std::basic_string<CharType>
+template <typename KeyType = std::string,
+ typename CharType = char,
+ class KeyComparator = std::less<KeyType>,
+ class ItemComparator = std::less<std::basic_string<CharType> >
+ >
+class BasicStringListPrinter
+{
+private:
+ //! structure for storing items to be printed; sorted primarily by the key, secondarily by the item itself
+ struct Item
+ {
+ ItemType m_val;
+ KeyType m_key;
+ ItemComparator m_item_comp;
+ KeyComparator m_key_comp;
+
+ Item(ItemType val, KeyType key) : m_val(val), m_key(key) {}
+
+ bool operator<(const Item& another) const
+ {
+ return m_key_comp(m_key, another.m_key) || (m_key == another.m_key && m_item_comp(m_val, another.m_val));
+ }
+ };
+
+ ItemType m_head;
+ ItemType m_item_separator;
+ ItemType m_tail;
+
+ //! list of items to be printed
+ std::vector<Item> m_items;
+
+ //! current item string stream - may be used for consecutively filling a single item, commited by commit_item()
+ std::basic_stringstream<CharType> m_current_item_stream;
+
+public:
+ //! if some of the arguments are passed, they are used as head, item_separator and tail, respectively
+ BasicStringListPrinter(ItemType head = ItemType(), ItemType item_separator = ItemType(), ItemType tail = ItemType())
+ : m_head(head), m_item_separator(item_separator), m_tail(tail)
+ {}
+
+ //! returns a string which will be printed before all the items, but only if there really are some items
+ ItemType get_head() const {
+ return m_head;
+ }
+
+ //! returns a string which will be printed between every two items
+ ItemType get_item_separator() const
+ {
+ return m_item_separator;
+ }
+
+ //! returns a string which will be printed after all the items, but only if there really were some items
+ ItemType get_tail() const
+ {
+ return m_tail;
+ }
+
+ /**
+ * \brief sets a string which will be printed before all the items, but only if there really are some items
+ * provides a fluent interface
+ */
+ BasicStringListPrinter& set_head(ItemType new_head)
+ {
+ m_head = new_head;
+ return *this;
+ }
+
+ /**
+ * \brief sets a string which will be printed between every two items
+ * provides a fluent interface
+ */
+ BasicStringListPrinter& set_item_separator(ItemType new_item_separator)
+ {
+ m_item_separator = new_item_separator;
+ return *this;
+ }
+
+ /**
+ * \brief sets a string which will be printed after all the items, but only if there really were some items
+ * provides a fluent interface
+ */
+ BasicStringListPrinter& set_tail(ItemType new_tail)
+ {
+ m_tail = new_tail;
+ return *this;
+ }
+
+ /**
+ * \brief returns the number of items in the printer (not counting a possible uncommitted item)
+ */
+ int size() const
+ {
+ return m_items.size();
+ }
+
+ /**
+ * \brief checks whether the printer is empty, i.e. there have not been any items added yet
+ */
+ bool empty() const
+ {
+ return m_items.empty();
+ }
+
+ /**
+ * \brief removes all committed items from the printer (any uncommitted item is untouched, though)
+ */
+ void clear()
+ {
+ m_items.clear();
+ }
+
+ /**
+ * \brief adds a single item to the string list, under a given key (or "" key if not specified)
+ * provides a fluent interface
+ */
+ BasicStringListPrinter& add_item(ItemType item, KeyType key = KeyType())
+ {
+ m_items.push_back(Item(item, key));
+ return *this;
+ }
+
+ //! adds all the contents that have been pushed to the printer via operator<< under a given key and clears the push stream
+ void commit_item(KeyType key = KeyType())
+ {
+ m_items.push_back(Item(m_current_item_stream.str(), key));
+ m_current_item_stream.str("");
+ }
+
+ /**
+ * \brief pushes an item part to the current item stream (which may be committed later using commit_item())
+ * provides a fluent interface
+ */
+ template <typename T>
+ BasicStringListPrinter& operator<<(T item_part)
+ {
+ get_current_stream() << item_part;
+ return *this;
+ }
+
+ //! returns the current item stream for pushing item parts (which may be committed later using commit_item())
+ std::basic_stringstream<CharType>& get_current_stream()
+ {
+ return m_current_item_stream;
+ }
+
+ //! prints the set contents including the specified head and tail (if there are some items) to a stream
+ template <class Stream>
+ Stream& print(Stream& out)
+ {
+ if (m_items.empty())
+ return out;
+
+ std::sort(m_items.begin(), m_items.end());
+
+ out << m_head;
+ for (typename std::vector<Item>::const_iterator it = m_items.begin();
+ it != m_items.end(); ++it)
+ {
+ if (it != m_items.begin())
+ out << m_item_separator;
+ out << it->m_val;
+ }
+ out << m_tail;
+ return out;
+ }
+};
+
+typedef BasicStringListPrinter<> StringListPrinter;
+
+#endif /* _STRING_LIST_PRINTER_H */
+
+// $Id: string_list_printer.h 1230 2011-12-13 00:38:38Z obouda $
Modified: trunk/tests/CMakeLists.txt
===================================================================
--- trunk/tests/CMakeLists.txt 2012-07-22 07:52:20 UTC (rev 1444)
+++ trunk/tests/CMakeLists.txt 2012-07-26 06:21:21 UTC (rev 1445)
@@ -111,6 +111,7 @@
ENDMACRO(ADD_Z120_TEST)
ADD_SUBDIRECTORY(z120_test)
+ADD_SUBDIRECTORY(mscgen)
SET(MEMBER_SEQUENCE 6)
MACRO(ADD_MEMBER_TEST FILE1 FILE2)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|