]> gitweb.hamatoma.de Git - reqt/commitdiff
Refactoring: names similar to crepublib
authorhama <hama@siduction.net>
Fri, 3 Apr 2015 23:06:57 +0000 (01:06 +0200)
committerhama <hama@siduction.net>
Fri, 3 Apr 2015 23:06:57 +0000 (01:06 +0200)
155 files changed:
appl/qfilesearch [new submodule]
base/ReByteStorage.cpp [new file with mode: 0644]
base/ReByteStorage.hpp [new file with mode: 0644]
base/ReCharPtrMap.cpp [new file with mode: 0644]
base/ReCharPtrMap.hpp [new file with mode: 0644]
base/ReConfig.cpp [new file with mode: 0644]
base/ReConfig.hpp [new file with mode: 0644]
base/ReConfigurator.hpp [new file with mode: 0644]
base/ReContainer.cpp [new file with mode: 0644]
base/ReContainer.hpp [new file with mode: 0644]
base/ReException.cpp [new file with mode: 0644]
base/ReException.hpp [new file with mode: 0644]
base/ReLogger.cpp [new file with mode: 0644]
base/ReLogger.hpp [new file with mode: 0644]
base/ReQString.cpp [new file with mode: 0644]
base/ReQtring.hpp [new file with mode: 0644]
base/ReStringUtil.cpp [new file with mode: 0644]
base/ReStringUtil.hpp [new file with mode: 0644]
base/ReTerminator.cpp [new file with mode: 0644]
base/ReTerminator.hpp [new file with mode: 0644]
base/ReTest.cpp [new file with mode: 0644]
base/ReTest.hpp [new file with mode: 0644]
base/ReWriter.cpp [new file with mode: 0644]
base/ReWriter.hpp [new file with mode: 0644]
base/rebase.hpp [new file with mode: 0644]
base/testrplexample.cpp [new file with mode: 0644]
cunit/cuReConfig.cpp [new file with mode: 0644]
cunit/cuReContainer.cpp [new file with mode: 0644]
cunit/cuReEnigma.cpp [new file with mode: 0644]
cunit/main.cpp [new file with mode: 0644]
cunit/rplastree_test.cpp [new file with mode: 0644]
cunit/rplbench.cpp [new file with mode: 0644]
cunit/rplbytestorage_test.cpp [new file with mode: 0644]
cunit/rplcharptrmap_test.cpp [new file with mode: 0644]
cunit/rplexception_test.cpp [new file with mode: 0644]
cunit/rpllexer_test.cpp [new file with mode: 0644]
cunit/rplmatrix_test.cpp [new file with mode: 0644]
cunit/rplmfparser_test.cpp [new file with mode: 0644]
cunit/rplqstring_test.cpp [new file with mode: 0644]
cunit/rplsource_test.cpp [new file with mode: 0644]
cunit/rplstring_test.cpp [new file with mode: 0644]
cunit/rplvm_test.cpp [new file with mode: 0644]
cunit/rplwriter_test.cpp [new file with mode: 0644]
cunit/unittests.pro [new file with mode: 0644]
expr/ReASTree.cpp [new file with mode: 0644]
expr/ReASTree.hpp [new file with mode: 0644]
expr/ReAsClasses.cpp [new file with mode: 0644]
expr/ReAsClasses.hpp [new file with mode: 0644]
expr/ReLexer.cpp [new file with mode: 0644]
expr/ReLexer.hpp [new file with mode: 0644]
expr/ReMFParser.cpp [new file with mode: 0644]
expr/ReMFParser.hpp [new file with mode: 0644]
expr/ReParser.cpp [new file with mode: 0644]
expr/ReParser.hpp [new file with mode: 0644]
expr/ReSource.cpp [new file with mode: 0644]
expr/ReSource.hpp [new file with mode: 0644]
expr/ReVM.cpp [new file with mode: 0644]
expr/ReVM.hpp [new file with mode: 0644]
expr/reexpr.hpp [new file with mode: 0644]
math/ReEnigma.cpp [new file with mode: 0644]
math/ReEnigma.hpp [new file with mode: 0644]
math/ReMatrix.cpp [new file with mode: 0644]
math/ReMatrix.hpp [new file with mode: 0644]
math/ReRandom.cpp [new file with mode: 0644]
math/ReRandom.hpp [new file with mode: 0644]
math/remath.hpp [new file with mode: 0644]
net/ReNetConfig.cpp [new file with mode: 0644]
net/ReNetConfig.hpp [new file with mode: 0644]
net/ReTCPClient.cpp [new file with mode: 0644]
net/ReTCPClient.hpp [new file with mode: 0644]
net/ReTCPPeer.cpp [new file with mode: 0644]
net/ReTCPPeer.hpp [new file with mode: 0644]
net/ReTCPServer.cpp [new file with mode: 0644]
net/ReTCPServer.hpp [new file with mode: 0644]
net/renet.hpp [new file with mode: 0644]
remodules.hpp [new file with mode: 0644]
rplcore/rplbytestorage.cpp [deleted file]
rplcore/rplbytestorage.hpp [deleted file]
rplcore/rplcharptrmap.cpp [deleted file]
rplcore/rplcharptrmap.hpp [deleted file]
rplcore/rplconfig.cpp [deleted file]
rplcore/rplconfig.hpp [deleted file]
rplcore/rplconfigurator.hpp [deleted file]
rplcore/rplcontainer.cpp [deleted file]
rplcore/rplcontainer.hpp [deleted file]
rplcore/rplcore.hpp [deleted file]
rplcore/rplexception.cpp [deleted file]
rplcore/rplexception.hpp [deleted file]
rplcore/rpllogger.cpp [deleted file]
rplcore/rpllogger.hpp [deleted file]
rplcore/rplqstring.cpp [deleted file]
rplcore/rplqstring.hpp [deleted file]
rplcore/rplstring.cpp [deleted file]
rplcore/rplstring.hpp [deleted file]
rplcore/rplterminator.cpp [deleted file]
rplcore/rplterminator.hpp [deleted file]
rplcore/rpltest.cpp [deleted file]
rplcore/rpltest.hpp [deleted file]
rplcore/rplwriter.cpp [deleted file]
rplcore/rplwriter.hpp [deleted file]
rplcore/testrplexample.cpp [deleted file]
rplexpr/rplasclasses.cpp [deleted file]
rplexpr/rplasclasses.hpp [deleted file]
rplexpr/rplastree.cpp [deleted file]
rplexpr/rplastree.hpp [deleted file]
rplexpr/rplexpr.hpp [deleted file]
rplexpr/rpllexer.cpp [deleted file]
rplexpr/rpllexer.hpp [deleted file]
rplexpr/rplmfparser.cpp [deleted file]
rplexpr/rplmfparser.hpp [deleted file]
rplexpr/rplparser.cpp [deleted file]
rplexpr/rplparser.hpp [deleted file]
rplexpr/rplsource.cpp [deleted file]
rplexpr/rplsource.hpp [deleted file]
rplexpr/rplvm.cpp [deleted file]
rplexpr/rplvm.hpp [deleted file]
rplmath/rplenigma.cpp [deleted file]
rplmath/rplenigma.hpp [deleted file]
rplmath/rplmath.hpp [deleted file]
rplmath/rplmatrix.cpp [deleted file]
rplmath/rplmatrix.hpp [deleted file]
rplmath/rplrandom.cpp [deleted file]
rplmath/rplrandom.hpp [deleted file]
rplmodules.hpp [deleted file]
rplnet/rplnet.hpp [deleted file]
rplnet/rplnetconfig.cpp [deleted file]
rplnet/rplnetconfig.hpp [deleted file]
rplnet/rpltcpclient.cpp [deleted file]
rplnet/rpltcpclient.hpp [deleted file]
rplnet/rpltcppeer.cpp [deleted file]
rplnet/rpltcppeer.hpp [deleted file]
rplnet/rpltcpserver.cpp [deleted file]
rplnet/rpltcpserver.hpp [deleted file]
rplstatic/getsrc.pl [deleted file]
rplstatic/rplstatic.pro [deleted file]
rplstatic/rplstaticlib.cpp [deleted file]
rplstatic/rplstaticlib.hpp [deleted file]
static/rplstatic.pro [new file with mode: 0644]
static/rplstaticlib.cpp [new file with mode: 0644]
static/rplstaticlib.hpp [new file with mode: 0644]
unittests/main.cpp [deleted file]
unittests/rplastree_test.cpp [deleted file]
unittests/rplbench.cpp [deleted file]
unittests/rplbytestorage_test.cpp [deleted file]
unittests/rplcharptrmap_test.cpp [deleted file]
unittests/rplexception_test.cpp [deleted file]
unittests/rpllexer_test.cpp [deleted file]
unittests/rplmatrix_test.cpp [deleted file]
unittests/rplmfparser_test.cpp [deleted file]
unittests/rplqstring_test.cpp [deleted file]
unittests/rplsource_test.cpp [deleted file]
unittests/rplstring_test.cpp [deleted file]
unittests/rplvm_test.cpp [deleted file]
unittests/rplwriter_test.cpp [deleted file]
unittests/unittests.pro [deleted file]

diff --git a/appl/qfilesearch b/appl/qfilesearch
new file mode 160000 (submodule)
--- /dev/null
+++ b/appl/qfilesearch
@@ -0,0 +1 @@
+Subproject commit 0000000000000000000000000000000000000000
diff --git a/base/ReByteStorage.cpp b/base/ReByteStorage.cpp
new file mode 100644 (file)
index 0000000..033c048
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ *
+ * @brief A very efficient storage for bytes and C strings.
+ */
+/** @file rplcore/rplbytestorage.hpp
+ *
+ * @brief Definitions for a very efficient storage for bytes and C strings.
+ */
+
+#include "base/rebase.hpp"
+/** @class ReByteStorage ReByteStorage.hpp "base/ReByteStorage.hpp"
+ *
+ * @brief Implements a very efficient byte storage.
+ *
+ * Efficiency: Allocation of one block needs mostly only 1 comparison
+ * and 2 assignments.
+ *
+ * Restriction: The blocks can be returned (freed) only all together, not block by block.
+ * This can be an advantage!
+ *
+ * Process:
+ * The storage manages large buffers. Allocation can be done only in the
+ * last buffer. If the buffer has too little space for the new block a new
+ * buffer will be allocated and linked into the buffer list.
+ * One buffer can store dozens or hundreds of blocks. Therefore allocation and
+ * freeing is much cheeper than allocation by <code>new()</code>.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param bufferSize    the size of one buffer
+ */
+ReByteStorage::ReByteStorage(int bufferSize) :
+    m_bufferSize(bufferSize),
+    m_buffer(NULL),
+    m_rest(0),
+    m_freePosition(NULL),
+    m_summarySize(0),
+    m_buffers(0)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReByteStorage::~ReByteStorage()
+{
+    const uint8_t* ptr = m_buffer;
+    while(ptr != NULL){
+        const uint8_t* old = ptr;
+        ptr = *(const uint8_t**)(ptr);
+        delete[] old;
+        m_buffers--;
+    }
+    assert(m_buffers == 0);
+}
+
+/**
+ * @brief Allocates a block in a new allocated buffer.
+ *
+ * This method will be called if the buffer has too little space.
+ * A new buffer will be allocated and the block will be allocated
+ * in this new block.
+ *
+ * @note The block address is returned, but the allocation must be done outside!
+ *
+ * @param   size of the new block (inclusive the trailing '\0')
+ * @return  a new block with the <code>size</code> bytes
+ */
+char* ReByteStorage::allocBuffer(int size)
+{
+    m_rest = size + sizeof(uint8_t*) <= (size_t) m_bufferSize
+            ? m_bufferSize : size + sizeof(uint8_t*);
+    m_summarySize += m_rest;
+    m_buffers++;
+    uint8_t* rc = new uint8_t[m_rest];
+    * (uint8_t**)rc = m_buffer;
+    m_buffer = rc;
+    rc += sizeof(uint8_t*);
+    // the block allocation will be done outside!
+    m_freePosition = rc;
+    m_rest -= sizeof(uint8_t*);
+    return reinterpret_cast<char*>(rc);
+}
+
+/**
+ * @brief Duplicates a string into a new allocated block.
+ *
+ * @param source    the source string
+ * @param size      the length of the string.
+ *                  If < 0 <code>strlen(source)</code> will be used
+ * @return          a copy of the source string. The copy ends always with '\0'
+ */
+const char* ReByteStorage::allocateChars(const char* source, int size)
+{
+    if (size < 0)
+        size = strlen(source);
+    const char* rc = allocateChars(size + 1);
+    memcpy((void*) rc, source, size);
+    ((char*)rc)[size] = '\0';
+    return rc;
+}
+
+/**
+ * @brief Duplicates a string into a new allocated block.
+ *
+ * The unicode string will be converted into an UTF-8 string.
+ *
+ * @param source    the source string
+ * @return          a copy of the source string. The copy ends always with '\0'
+ */
+const char* ReByteStorage::allocUtf8(const ReString& source)
+{
+    const char* rc = allocateChars(source.toUtf8().constData());
+    return rc;
+}
+
+/**
+ * @brief Allocates a byte block without initialization.
+ *
+ * @param size  the size of the block to allocate
+ *
+ * @return  a byte block (without a trailing '\0')
+ */
+uint8_t* ReByteStorage::allocateBytes(int size)
+{
+    uint8_t* rc = size <= m_rest ? m_freePosition
+            : reinterpret_cast<uint8_t*>(allocBuffer(size));
+    m_freePosition += size;
+    m_rest -= size;
+    return rc;
+}
+
+/**
+ * @brief Allocates a byte block initialized by '\0'.
+ *
+ * @param size  the size of the block to allocate
+ *
+ * @return  a byte block (without a trailing '\0')
+ */
+uint8_t* ReByteStorage::allocateZeros(int size)
+{
+    uint8_t* rc = allocateBytes(size);
+    memset(rc, 0, size);
+    return rc;
+}
+
+/**
+ * @brief Copy a byte block to a new allocated byte block.
+ *
+ * @param source    the source to copy
+ * @param size      the size of the block to allocate
+ * @return          a byte block (without a trailing '\0')
+ */
+uint8_t* ReByteStorage::allocateBytes(void* source, int size)
+{
+    uint8_t* rc = allocateBytes(size);
+    memcpy(rc, source, size);
+    return rc;
+}
diff --git a/base/ReByteStorage.hpp b/base/ReByteStorage.hpp
new file mode 100644 (file)
index 0000000..51496b6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RECHARSTORAGE_HPP
+#define RECHARSTORAGE_HPP
+
+class ReByteStorage
+{
+public:
+    ReByteStorage(int blockSize);
+    ~ReByteStorage();
+public:
+    char* allocBuffer(int size);
+    /**
+     * @brief Allocates a char block.
+     *
+     * @return a new block
+     */
+    inline char* allocateChars(int size){
+        char* rc = size <= m_rest ? (char*) m_freePosition
+                                        : allocBuffer(size);
+        m_freePosition += size;
+        m_rest -= size;
+        return rc;
+    }
+    const char* allocateChars(const char* source, int size = -1);
+    const char* allocUtf8(const ReString& source);
+    uint8_t* allocateBytes(int size);
+    uint8_t* allocateZeros(int size);
+    uint8_t*allocateBytes(void* source, int size);
+private:
+    int m_bufferSize;
+    uint8_t* m_buffer;
+    int m_rest;
+    uint8_t* m_freePosition;
+    int64_t m_summarySize;
+    int m_buffers;
+};
+
+#endif // RECHARSTORAGE_HPP
diff --git a/base/ReCharPtrMap.cpp b/base/ReCharPtrMap.cpp
new file mode 100644 (file)
index 0000000..d421b62
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#include "base/rebase.hpp"
+
+/** @class ReKeyCharPtr ReCharPtrMap.hpp "base/ReCharPtrMap.hpp"
+ *
+ * @brief Allows using <code>char*</code> pointers as key in <code>QMap</code>.
+ *
+ * The template <code>QMap</code> uses the operator < to search in the map.
+ * But the <code>char*</code> pointers have no such an operator.
+ * The solution is the class <code>RplMapCharPtr</code> which implements
+ * this operator.
+ *
+ * <code>strcmp()</code> is used to implement the '<' operator.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param ptr   the key used in the map.
+ *              @note the pointer will be stored in the map as a key,
+ *              not the content
+ */
+ReKeyCharPtr::ReKeyCharPtr(const char* ptr) :
+    m_ptr(ptr)
+{
+}
+
+
+/** @class ReCharPtrMap ReCharPtrMap.hpp "base/ReCharPtrMap.hpp"
+ *
+ * @brief A template for a map using const char* as keys.
+ *
+ * The value type is dynamic (a parameter type of the template).
+ *
+ * <b>Usage:</b>
+ * <pre><code>
+ * ReCharPtrMap<int> ids;
+ * if (! id.contains("jonny"))
+ *    ids["jonny"] = 1;
+ * </code></pre>
+ *
+ * <b>Important</b>:<br>
+ * Keys used with this class must be unchangable and must live during the
+ * whole life of the map.
+ *
+ * <b>Wrong example:</b>
+ * <pre><code>
+ * ReCharPtrMap<int> ids;
+ * void init(int keyNo, int value){
+ *    char key[10];
+ *    qsnprintf(buffer, sizeof buffer, "key%d", keyNo);
+ *    ids[key] = value;
+ * }
+ * init(1, 100);
+ * </code></pre>
+ * The lifetime of the key is the body of the function <code>init()</code>.
+ * The key becomes invalid after the call.
+ */
diff --git a/base/ReCharPtrMap.hpp b/base/ReCharPtrMap.hpp
new file mode 100644 (file)
index 0000000..f76bcfb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RECHARPTRMAP_HPP
+#define RECHARPTRMAP_HPP
+
+class ReKeyCharPtr {
+    friend bool operator <(ReKeyCharPtr const& op1, ReKeyCharPtr const& op2);
+public:
+    ReKeyCharPtr(const char* ptr);
+private:
+    const char* m_ptr;
+};
+/**
+ * @brief Compares two instances of the class <code>ReKeyCharPtr</code>.
+ * @param op1   1st operand
+ * @param op2   2nd operand
+ * @return      true: op1 < op2<br>
+ *              false: op1 >= op2
+ */
+inline bool operator <(ReKeyCharPtr const& op1, ReKeyCharPtr const& op2){
+    bool rc = strcmp(op1.m_ptr, op2.m_ptr) < 0;
+    return rc;
+}
+
+template <class ValueType>
+class  ReCharPtrMap : public QMap<ReKeyCharPtr, ValueType>
+{
+};
+
+#endif // RECHARPTRMAP_HPP
diff --git a/base/ReConfig.cpp b/base/ReConfig.cpp
new file mode 100644 (file)
index 0000000..b605572
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#include "base/rebase.hpp"
+
+/** @file
+ *
+ * @brief Reading/writing configuration files.
+ */
+/** @file rplcore/rplconfig.hpp
+ *
+ * @brief Definitions for reading/writing configuration files.
+ */
+
+/** @class ReConfig ReConfig.hpp "base/ReConfig.hpp"
+ *
+ * @brief Imports and exports a configuration file into a QHash instance.
+ *
+ * The format of the file:<br>
+ * DEFS or COMMENTS
+ *
+ * DEFS ::= KEY=VALUE
+ *
+ * KEY is a string starting with an alphanumeric character and does not contain a '='
+ *
+ * VALUE is a string
+ */
+
+enum Locations {
+    LOC_WRITE_1 = LOC_FIRST_OF(LOC_CONFIG),   // 10201
+    LOC_WRITE_2,
+    LOC_READ_1,
+    LOC_READ_2,
+};
+
+/**
+ * Constructor.
+ *
+ * Initializes the logger and reads the configuration file
+ *
+ * @param file          name of the configuration file. May be NULL
+ * @param readOnly      true: the configuration must not be written
+ * @param logger        NULL or a logger
+ */
+ReConfig::ReConfig(const char* file, bool readOnly, ReLogger* logger) :
+    m_file(file),
+    m_lineList(),
+    m_readOnly(readOnly),
+    m_logger(logger),
+    m_ownLogger(logger == NULL) {
+    if(logger == NULL) {
+        initLogger();
+    }
+    if(file != NULL)
+        read(file);
+}
+
+/**
+ * Destructor.
+ *
+ * Frees the resources.
+ */
+ReConfig::~ReConfig() {
+    if(m_ownLogger)
+        delete m_logger;
+    m_logger = NULL;
+}
+
+/**
+ * Inititializes a logger.
+ */
+void ReConfig::initLogger() {
+    m_logger = new ReLogger();
+    ReMemoryAppender* appender = new ReMemoryAppender();
+    appender->setAutoDelete(true);
+    m_logger->addAppender(appender);
+
+    ReStreamAppender* appender2 = new ReStreamAppender(stdout);
+    appender2->setAutoDelete(true);
+    m_logger->addAppender(appender2);
+}
+
+/**
+ * Returns  configuration value as an integer.
+ *
+ * @param key           key of the wanted value
+ * @param defaultValue  if the key does not exist this is the result
+ * @return              defaultValue: key does not exist
+ *                      otherwise: the value assigned to key
+ */
+int ReConfig::asInt(const char* key, int defaultValue) const {
+    int rc = defaultValue;
+    if(contains(key)) {
+        rc = atoi((*this)[key]);
+    }
+    return rc;
+}
+
+/**
+ * Returns the configuration value as a boolean.
+ *
+ * @param key           key of the wanted value
+ * @param defaultValue  if the key does not exist this is the result
+ * @return              defaultValue: key does not exist
+ *                      otherwise: the value assigned to key
+ */
+bool ReConfig::asBool(const char* key, bool defaultValue) const {
+    bool rc = defaultValue;
+    if(contains(key)) {
+        QByteArray value = (*this)[key].toLower();
+        rc = value == "1" || value == "y" || value == "yes" || value == "t"
+             || value == "true";
+    }
+
+    return rc;
+}
+
+/**
+ * Returns a configuration value.
+ *
+ * @param key           key of the wanted value
+ * @param defaultValue  if the key does not exist this is the result
+ * @return              defaultValue: key does not exist
+ */
+QByteArray ReConfig::asString(const char* key, const char* defaultValue) {
+    QByteArray rc = defaultValue;
+    if(contains(key)) {
+        rc = (*this)[key];
+    }
+    return rc;
+}
+
+/**
+ * Reads a configuration file.
+ *
+ * @param file  file to read.
+ * @return      true: OK<br>
+ *              false: error occurred
+ */
+bool ReConfig::read(const char* file) {
+    bool rc = true;
+    m_lineList.reserve(1024);
+    FILE* fp = fopen(file, "r");
+    if(fp == NULL) {
+        m_logger->logv(LOG_ERROR, LOC_READ_1, "cannot read: %s", file);
+        rc = false;
+    } else {
+        char line[64000];
+        char* separator;
+        int lineNo = 0;
+        while(fgets(line, sizeof line, fp) != NULL) {
+            lineNo++;
+            m_lineList.append(line);
+            if(isalnum(line[0]) && (separator = strchr(line, '=')) != NULL) {
+                QByteArray key(line, separator - line);
+                QByteArray value(separator + 1);
+                key = key.trimmed();
+                value = value.trimmed();
+                if(contains(key))
+                    m_logger->logv(LOG_WARNING, LOC_READ_2,
+                                   "defined more than once: %s-%d: %s", file, lineNo, line);
+                else
+                    insert(key, value);
+            }
+        }
+    }
+    return rc;
+}
+
+/**
+ * Writes a configuration file.
+ *
+ * @param file  file to write.
+ * @return      true: OK<br>
+ *              false: error occurred
+ */
+bool ReConfig::write(const char* file) {
+    bool rc = false;
+    if(m_readOnly)
+        m_logger->log(LOG_ERROR, LOC_WRITE_1, "cannot write: (readonly");
+    else {
+        m_logger->logv(LOG_ERROR, LOC_WRITE_2, "not implemented: write(%s)",
+                       file);
+    }
+    return rc;
+}
+
diff --git a/base/ReConfig.hpp b/base/ReConfig.hpp
new file mode 100644 (file)
index 0000000..70fa36e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RECONFIG_HPP
+#define RECONFIG_HPP
+
+class ReConfig : public ReConfigurator, public QHash<QByteArray, QByteArray> {
+public:
+    ReConfig(const char* file = NULL, bool readOnly = true,
+              ReLogger* logger = NULL);
+    virtual ~ReConfig();
+
+public:
+    bool read(const char* file);
+    bool write(const char* file);
+    void clear();
+    const QList<QByteArray>& getLines() const;
+
+    virtual bool asBool(const char* key, bool defaultValue) const;
+    virtual int asInt(const char* key, int defaultValue) const;
+    virtual QByteArray asString(const char* key, const char* defaultValue);
+private:
+    void initLogger();
+private:
+    const char* m_file;
+    QList<QByteArray> m_lineList;
+    bool m_readOnly;
+    ReLogger* m_logger;
+    // true: the logger must be destroyed in the destructor
+    bool m_ownLogger;
+};
+
+#endif // RECONFIG_HPP
diff --git a/base/ReConfigurator.hpp b/base/ReConfigurator.hpp
new file mode 100644 (file)
index 0000000..ab201bc
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RECONFIGURATOR_HPP
+#define RECONFIGURATOR_HPP
+
+class ReConfigurator {
+public:
+    virtual int asInt(const char* key, int defaultValue) const = 0;
+    virtual bool asBool(const char* key, bool defaultValue) const = 0;
+    virtual QByteArray asString(const char* key, const char* defaultValue) = 0;
+};
+
+#endif // RECONFIGURATOR_HPP
diff --git a/base/ReContainer.cpp b/base/ReContainer.cpp
new file mode 100644 (file)
index 0000000..9e8e251
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#include "base/rebase.hpp"
+
+/** @file
+ * @brief Implements a portable data container.
+ */
+
+/** @file recore/ReContainer.hpp
+ *
+ * @brief Definition for a portable data container.
+ */
+
+/** @class ReContainer ReContainer.hpp "base/ReContainer.hpp"
+ *
+ * @brief Implements a portable data container.
+ *
+ * The container contains a list of "bags".
+ * Each bag contains a sequence of items (with a simple data type).
+ * The items are portable: transported to another architecture
+ * the item is restored correct (independent of big/little endian).
+ *
+ * Format:
+ * container ::= magic header_size_hex2 container_size_hex '[' list_count ']' bag_descr list_of_bags<br>
+ * list_of_bag ::= bag1 bag2 ...<br>
+ * bag_descr ::= bag_type1 bag_type2 ... ':'<br>
+ * bag_types := i(nteger) ' ' | s(tring) | b(indata255) | B(indata64k) X(blob4G)<br>
+ * item_list ::= item1 item2...<br>
+ * The binary items (bBX) are byte sequences with a starting size element.
+ * The size element can be a byte (255) or a word (64k) or a double word(4G).
+ * The order of the size element is big endian.
+ *
+ * Example (additional blanks for readibility):
+ * <pre>
+ * Rpl&1 09 36[2]cis:!7b Nirwana &lt;0&gt; Y -ab34 A long string with an trailing '0' &lt;0&gt;
+ * </pre>
+ * magic header: Rpl&1 length: 09h data length: 46h bag count: 2 item types: char int string
+ *
+ */
+
+enum {
+    // 11000
+    LOC_FILL_1 = LOC_CONTAINER * 1000,
+    LOC_FILL_2,
+    LOC_FILL_3,
+    LOC_NEXT_BAG_1,
+    LOC_NEXT_ITEM_1,
+    LOC_NEXT_ITEM_2 = 11005,
+    LOC_NEXT_INT_1,
+    LOC_NEXT_ITEM_3,
+    LOC_NEXT_BAG_2,
+};
+
+const char* ReContainer::MAGIC_1 = "Rpl&1";
+
+/**
+ * @brief Constructor.
+ *
+ * @param sizeHint      Probable length of the container
+ */
+ReContainer::ReContainer(size_t sizeHint) :
+    m_data(""),
+    m_countBags(0),
+    m_typeList(""),
+    m_ixItem(0),
+    m_ixBag(0),
+    m_readPosition(NULL) {
+    if (sizeHint > 0)
+        m_data.reserve(sizeHint);
+}
+
+/**
+ * @brief Destructor.
+ */
+ReContainer::~ReContainer() {
+}
+
+/**
+ * @brief Adds an type to the type list.
+ *
+ * @param tag   the type tag
+ */
+void ReContainer::addType(type_tag_t tag) {
+    if(m_countBags == 0)
+        startBag();
+    if(m_countBags == 1)
+        m_typeList.append((char) tag);
+}
+
+/**
+ * @brief Starts a new bag.
+ */
+void ReContainer::startBag() {
+    m_countBags++;
+    m_ixBag = 0;
+}
+/**
+ * @brief Adds a character to the current bag.
+ *
+ * @param value    value to insert
+ */
+void ReContainer::addChar(char value) {
+    addType(TAG_CHAR);
+    //if (m_typeList.at(m_ixBag) != TAG_INT)
+    //   ReLogger::logAndThrow(LOG_ERROR, __FILE__, __LINE__, 1, "unexpected type: %c instead of c", m_typeList.at(m_ixBag));
+    m_data.append(value);
+}
+/**
+ * @brief Adds an integer to the current bag.
+ *
+ * @param value    value to add
+ */
+void ReContainer::addInt(int value) {
+    addType(TAG_INT);
+    char buffer[64];
+    char* ptr = buffer;
+    if(value < 0) {
+        *ptr++ = '-';
+        value = - value;
+    }
+    qsnprintf(ptr, sizeof buffer - 1, "%x ", value);
+    m_data.append(buffer);
+}
+/**
+ * @brief Adds an integer to the current bag.
+ *
+ * @param value    value to add
+ */
+void ReContainer::addInt(int64_t value) {
+    addType(TAG_INT);
+    char buffer[128];
+    qsnprintf(buffer, sizeof buffer, "%llx ", value);
+    m_data.append(buffer);
+}
+
+/**
+ * @brief Adds a string to the current bag.n
+ *
+ * @param value    value to add
+ */
+void ReContainer::addString(const char* value) {
+    addType(TAG_STRING);
+    // store with trailing '\0'
+    m_data.append(value, strlen(value) + 1);
+}
+/**
+ * @brief Adds binary data to the current bag.
+ *
+ * @param value     binary data
+ * @param size      size of the binary data in bytes
+ */
+void ReContainer::addData(uint8_t* value, size_t size) {
+    if(size <= 255) {
+        addType(TAG_DATA255);
+        m_data.append((char) size);
+    } else if(size <= 0xffff) {
+        addType(TAG_DATA64K);
+        m_data.append((char)(size / 256));
+        m_data.append((char)(size % 256));
+        m_data.append((const char*) value, size);
+    } else {
+        addType(TAG_DATA4G);
+        m_data.append((char)(size / 256 / 256 / 256));
+        m_data.append((char)(size / 256 / 256 % 256));
+        m_data.append((char)(size / 256 % 256));
+        m_data.append((char)(size % 256));
+        m_data.append((const char*) value, size);
+    }
+    addType(TAG_DATA255);
+
+}
+
+/**
+ * @brief Returns the container byte buffer.
+ *
+ * @return the container as a byte array
+ */
+const QByteArray& ReContainer::getData() {
+    if(m_typeList.length() != 0) {
+        char buffer[128];
+        // RPL&1 0a b5[2]cis: !12
+        qsnprintf(buffer, sizeof buffer, "%x[%d]%s:", (unsigned int) m_data.length(),
+                 m_countBags, m_typeList.data());
+        char header[128+8];
+        qsnprintf(header, sizeof header, "%s%02x%s", MAGIC_1,
+                 (unsigned int) strlen(buffer), buffer);
+        m_data.insert(0, header);
+    }
+    return m_data;
+}
+
+/**
+ * @brief Fills the container with an byte array.
+ *
+ * @param data      the container as a byte array
+ */
+void ReContainer::fill(const QByteArray& data) {
+    m_data = data;
+    const char* ptr = m_data.data();
+    if(strncmp(ptr, MAGIC_1, strlen(MAGIC_1)) != 0)
+        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_1, "container has no magic",
+                                      data.data(), data.length());
+    ptr += strlen(MAGIC_1);
+    unsigned int headerSize = 0;
+    if(sscanf(ptr, "%02x", &headerSize) != 1)
+        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
+                                      "container has no header size", ptr, 2);
+    ptr += 2;
+
+    unsigned int dataSize = 0;
+    unsigned int countBags = 0;
+    if(sscanf(ptr, "%x[%x]", &dataSize, &countBags) != 2)
+        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
+                                      "container has no data_size[bag_count]", ptr, 16);
+    m_countBags = countBags;
+    ptr = strchr(ptr, ']') + 1;
+    const char* end = ptr + strspn(ptr, "cisdDX!");
+    if(end == ptr || *end != ':') {
+        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
+                                      "container has no valid typelist", ptr, 16);
+    }
+    m_typeList.clear();
+    m_typeList.append(ptr, end - ptr);
+    m_ixBag = -1;
+    m_readPosition = (uint8_t*) end + 1;
+
+
+}
+/**
+ * @brief Returns the number of bags in the container.
+ *
+ * @return the number of bags
+ */
+int ReContainer::getCountBags() const {
+    return m_countBags;
+}
+/**
+ * @brief Sets the begin of the new bag.
+ */
+void ReContainer::nextBag() {
+    if(m_ixItem < m_typeList.length() && m_ixItem != -1)
+        throw ReException(LOG_ERROR, LOC_NEXT_BAG_1, NULL,
+                           "end of bag not reached: remaining items: %s",
+                           m_typeList.data() + m_ixItem);
+    m_ixItem = 0;
+    m_ixBag++;
+    if(m_ixBag >= m_countBags)
+        throw ReException(LOG_ERROR, LOC_NEXT_BAG_2, NULL,
+                           "no more bags: %d", m_ixBag);
+}
+/**
+ * @brief Sets the next item.
+ *
+ * @param expected      the expected data type
+ */
+void ReContainer::nextItem(type_tag_t expected) {
+    if(m_ixBag < 0) {
+        m_ixBag = 0;
+        m_ixItem = 0;
+    }
+    if(m_ixItem >= m_typeList.length())
+        throw ReException(LOG_ERROR, LOC_NEXT_ITEM_1, "no more items in the bag");
+    type_tag_t current = (type_tag_t) m_typeList.at(m_ixItem);
+    // Unify all data types:
+    if(current == TAG_DATA4G || current == TAG_DATA64K)
+        current = TAG_DATA255;
+    if(current != expected)
+        throw ReException(LOG_ERROR, LOC_NEXT_ITEM_2, NULL,
+                           "current item is a %c, not a %c",
+                           (char) m_typeList.at(m_ixItem), (char) expected);
+    m_ixItem++;
+    if(m_readPosition > (uint8_t*)(m_data.data() + m_data.length()))
+        throw ReException(LOG_ERROR, LOC_NEXT_ITEM_3, NULL,
+                           "container size too small. Bag: %d of %d Item: %d of %d",
+                           1 + m_ixBag, m_countBags, 1 + m_ixItem, m_typeList.length());
+}
+
+/**
+ * @brief Reads the next character from the current item in the current bag.
+ *
+ * @return  the next char from the container
+ */
+char ReContainer::nextChar() {
+    nextItem(TAG_CHAR);
+    char rc = *m_readPosition++;
+    return rc;
+}
+
+/**
+ * @brief Reads the next integer from the current item in the current bag.
+ *
+ * @return  the next integer from the container
+ */
+int ReContainer::nextInt() {
+    nextItem(TAG_INT);
+    bool isNegativ = *m_readPosition == '-';
+    if(isNegativ)
+        m_readPosition++;
+    unsigned int value = 0;
+    if(sscanf((const char*) m_readPosition, "%x ", &value) != 1)
+        throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
+                                      "not a hex_number<blank>", m_readPosition, 16);
+    m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
+    if(isNegativ)
+        value = - value;
+    return value;
+}
+/**
+ * @brief Reads the next integer from the current item in the current bag.
+ *
+ * @return  the next integer from the container
+ */
+int64_t ReContainer::nextInt64() {
+    nextItem(TAG_INT);
+    bool isNegativ = *m_readPosition == '-';
+    if(isNegativ)
+        m_readPosition++;
+    uint64_t value = 0;
+    if(sscanf((const char*) m_readPosition, "%llx ", &value) != 1)
+        throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
+                                      "not a hex_number<blank>", m_readPosition, 16);
+    m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
+    if(isNegativ)
+        value = - value;
+    return (int64_t) value;
+}
+
+/**
+ * @brief Reads the next string from the current item in the current bag.
+ *
+ * @return  the next '\0' delimited string from the container
+ */
+const char* ReContainer::nextString() {
+    nextItem(TAG_STRING);
+    const char* rc = (const char*) m_readPosition;
+    m_readPosition += strlen(rc) + 1;
+    return rc;
+}
+
+/**
+ * @brief Reads the next string from the current item in the current bag.
+ *
+ * @param data      OUT: the next data item from the container
+ * @param append    true: the item data will be appended to data<br>
+ *                  false: data contains the item data only
+ * @return          the size of the read data
+ */
+size_t ReContainer::nextData(QByteArray& data, bool append) {
+    nextItem(TAG_DATA255);
+    type_tag_t tag = (type_tag_t) m_typeList.at(m_ixItem - 1);
+    size_t length = 0;
+    switch(tag) {
+    case TAG_DATA4G:
+        for(int ix = 3; ix >= 0; ix--) {
+            length = 256 * length + m_readPosition[ix];
+        }
+        m_readPosition += 4;
+        break;
+    case TAG_DATA64K:
+        length = *m_readPosition++ * 256;
+        length += *m_readPosition++;
+        break;
+    case TAG_DATA255:
+        length = *m_readPosition++;
+        break;
+    default:
+        break;
+    }
+    if(! append)
+        data.clear();
+    data.append((const char*) m_readPosition, length);
+    m_readPosition += length;
+    return length;
+}
+
+
+
+/**
+ * @brief Dumps a container as a human readable string.
+ *
+ * @param title             will be used in the first line
+ * @param maxBags           if there are more bags they will be ignored
+ * @param maxStringLength   if strings are longer the will be cut
+ * @param maxBlobLength     maximum count of bytes which will be dumped
+ * @param separatorItems    separator between two items, e.g. '\\n' or '|'
+ * @return                  a human readable string describing the container
+ */
+QByteArray ReContainer::dump(const char* title,
+                              int maxBags, int maxStringLength, int maxBlobLength,
+                              char separatorItems) {
+    QByteArray rc;
+    rc.reserve(64000);
+    rc.append("=== ").append(title).append('\n');
+    rc.append("Bags: ").append(ReStringUtil::toNumber(m_countBags));
+    rc.append(" Types: ").append(m_typeList).append('\n');
+    // save the current state:
+    int safeIxBag = m_ixBag;
+    int safeIxItem = m_ixItem;
+    m_ixBag = -1;
+    m_ixItem = 0;
+    int iValue;
+    QByteArray sValue;
+    if(maxBags > m_countBags)
+        maxBags = m_countBags;
+    for(int ixBag = 0; ixBag < maxBags; ixBag++) {
+        rc.append("--- bag ").append(ReStringUtil::toNumber(ixBag)).append(":\n");
+        nextBag();
+        QByteArray item;
+        int maxLength;
+        for(int ixItem = 0; ixItem < m_typeList.length(); ixItem++) {
+            type_tag_t currentType = (type_tag_t) m_typeList.at(ixItem);
+            switch(currentType) {
+            case TAG_CHAR:
+                rc.append(" c: ").append(nextChar()).append(separatorItems);
+                break;
+            case TAG_INT:
+                iValue = nextInt();
+                rc.append(" i: ").append(ReStringUtil::toNumber(iValue)).append(" / ");
+                rc.append(ReStringUtil::toNumber(iValue, "%x")).append(separatorItems);
+                break;
+            case TAG_STRING:
+                sValue = nextString();
+                if(sValue.length() > maxStringLength)
+                    sValue = sValue.left(maxStringLength);
+                rc.append(" s: ").append(sValue).append(separatorItems);
+                break;
+            case TAG_DATA255:
+            case TAG_DATA64K:
+            case TAG_DATA4G:
+                nextData(item, false);
+                rc.append(' ').append((char) currentType).append(": [");
+                rc.append(ReStringUtil::toNumber(item.length())).append("] ");
+                maxLength = item.length() < maxBlobLength ? item.length() : maxBlobLength;
+                rc.append(ReStringUtil::hexDump(item.data(), maxLength,
+                                             16)).append(separatorItems);
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    // restore the current state:
+    m_ixBag = safeIxBag;
+    m_ixItem = safeIxItem;
+    return rc;
+}
+
diff --git a/base/ReContainer.hpp b/base/ReContainer.hpp
new file mode 100644 (file)
index 0000000..5a08aca
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RECONTAINER_HPP
+#define RECONTAINER_HPP
+
+// the sources generated from QT include this file directly:
+#ifndef RPLCORE_HPP
+#include <QByteArray>
+#include <QDataStream>
+#endif
+class ReContainer {
+public:
+    typedef enum {
+
+        TAG_CHAR = 'c',     ///< one character
+        TAG_INT = 'i',      ///< an integer number, up to 64 bit
+        TAG_STRING = 's',   ///< a string ending with a '\\0'
+        TAG_DATA255 = 'd',  ///< binary data, up to 255 bytes long
+        TAG_DATA64K = 'D',  ///< binary data, up to 64 KiBytes long
+        TAG_DATA4G = 'X',   ///< binary data, up to 4 GiBytes long
+        TAG_CONTAINER = '!' ///< a container (recursion)
+    } type_tag_t;
+    static const char* MAGIC_1;
+public:
+    ReContainer(size_t sizeHint);
+    virtual ~ReContainer();
+private:
+    // No copy constructor: no implementation!
+    ReContainer(const ReContainer& source);
+    // Prohibits assignment operator: no implementation!
+    ReContainer& operator =(const ReContainer& source);
+public:
+    // Building the container:
+    void addType(type_tag_t tag);
+    void startBag();
+    void addChar(char cc);
+    void addInt(int value);
+    void addInt(int64_t value);
+    void addString(const char* value);
+    void addData(uint8_t* value, size_t size);
+    const QByteArray& getData();
+
+    // Getting data from the container:
+    void fill(const QByteArray& data);
+    int getCountBags() const;
+    const char* getTypeList() const;
+    void nextBag();
+    char nextChar();
+    int nextInt();
+    int64_t nextInt64();
+    const char* nextString();
+    size_t nextData(QByteArray& data, bool append = false);
+
+    QByteArray dump(const char* title,
+                    int maxBags, int maxStringLength = 80, int maxBlobLength = 16,
+                    char separatorItems = '\n');
+private:
+    void nextItem(type_tag_t expected);
+private:
+    // the complete data of the container
+    QByteArray m_data;
+    // the number of elements in the container
+    int m_countBags;
+    // a string with the data types of a bag
+    QByteArray m_typeList;
+
+    // Getting data from the container:
+
+    // current read position in m_typeList
+    int m_ixItem;
+    // the index of the current current bag:
+    int m_ixBag;
+    // read position in m_data:
+    const uint8_t* m_readPosition;
+};
+
+#endif // RECONTAINER_HPP
diff --git a/base/ReException.cpp b/base/ReException.cpp
new file mode 100644 (file)
index 0000000..0af373d
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+/** @mainpage
+ *
+ * @note A real public library for QT.
+ *
+ * This library contains the module groups
+ * <ul>
+ * <li>rplcore: basic definitions, used in all other module groups</li>
+ * <li>rplmath: mathematic definitions and tools</li>
+ * <li>rplexpr: definition for parsing and interpretation of languages</li>
+ * <li>rplnet: definitions and tools for tcp/udp communication</li>
+ * </ul>
+ *
+ * Each module group has a central include file, which organizes the necessary
+ * include files. You had to include only the central include file.
+ *
+ * Example:
+ * <pre><code>
+ * #include "base/rebase.hpp"
+ * #include "expr/reexpr.hpp"
+ * </code></pre>
+ * In this case all definitions of rplcore and rplexpr are available.
+ */
+/** @file
+ * @brief Generally usable exceptions.
+ */
+/** @file rplcore/rplexception.hpp
+ *
+ * @brief Definitions for a generally usable exceptions.
+ */
+#include "base/rebase.hpp"
+
+/** @class ReException ReException.hpp "base/ReException.hpp"
+ *
+ * @brief A generally usable exception with or without logging.
+ *
+ * <b>Note</b>: If the logger is not given by parameter
+ * the usage of the global logger is not threadsafe.
+ */
+class ReException;
+
+
+/**
+ * @brief Constructor.
+ *
+ * For derived classes only!
+ */
+ReException::ReException() :
+    m_message("")
+{
+}
+
+/**
+ * @brief Constructor.
+ *
+ * @param format    the reason of the exception
+ * @param ...       the values for the placeholders in the format.
+ */
+ReException::ReException(const char* format, ...) :
+    m_message("") {
+    char buffer[64000];
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    m_message = buffer;
+}
+
+/**
+ * @brief Constructor.
+ *
+ * This constructor automatically logs the given data.
+ *
+ * @param level     the logging level, e.g. LOG_ERROR
+ * @param location  an unique identifier for the location
+ *                  where the exception was thrown
+ * @param format    the reason of the exception.
+ *                  Can contain placeholders (@see
+ *                  std::printf())
+ * @param ...       the values of the placeholders
+ *                  in <code>format</code>
+ * @param logger    if NULL the global logger will be used
+ */
+ReException::ReException(ReLoggerLevel level, int location,
+                           ReLogger* logger, const char* format, ...) :
+    m_message("") {
+    char buffer[64000];
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    m_message = buffer;
+    if(logger == NULL)
+        logger = ReLogger::globalLogger();
+    logger->log(level, location, buffer);
+}
+
+
+/** @class RplRangeException rplexception.hpp "rplcore/rplexception.hpp"
+ *
+ * @brief An exception for integer range errors.
+ *
+ * The error will be logged.
+ *
+ * <b>Note</b>: If the logger is not given by parameter
+ * the usage of the global logger is not threadsafe.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * This exception can be used if a value does not be
+ * inside a given range.
+ *
+ * This constructor automatically logs the given data.
+ *
+ * @param level     the logging level, e.g. LOG_ERROR
+ * @param location  an unique identifier for the location
+ *                  where the exception was thrown
+ * @param current   the current value
+ * @param lbound    the minimum of the allowed values
+ * @param ubound    the maximum of the allowed values
+ * @param message   the reason. If NULL a generic
+ *                  message will be used
+ * @param logger    if NULL the global logger will be used
+ */
+
+ReRangeException::ReRangeException(ReLoggerLevel level, int location,
+                                     size_t current,
+                                     size_t lbound, size_t ubound, const char* message, ReLogger* logger) :
+    ReException("") {
+    char buffer[64000];
+    if(message == NULL)
+        message = "value outside limits";
+    qsnprintf(buffer, sizeof buffer, "%s: %lu [%lu, %lu]",
+             message == NULL ? "" : message,
+             current, lbound, ubound);
+    if(logger == NULL)
+        logger = ReLogger::globalLogger();
+    logger->log(level, location, buffer);
+}
+
+/** @class RplInvalidDataException rplexception.hpp "rplcore/rplexception.hpp"
+ *
+ * @brief An exception usable if binary data have the wrong structure.
+ *
+ * The data will be dumped as hex and ASCII dump.
+ *
+ * <b>Note</b>: If the logger is not given by parameter
+ * the usage of the global logger is not threadsafe.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * This exception can be used if data does not have a given fomat.
+ *
+ * This constructor automatically logs the given data. This data
+ * will be dumped (hexadecimal dump and ASCII interpretation).
+ *
+ * @param level     the logging level, e.g. LOG_ERROR
+ * @param location  an unique identifier for the location
+ *                  where the exception was thrown
+ * @param message   the reason
+ * @param data      pointer to binary data
+ * @param dataSize  the size of the data which should be dumped
+ * @param logger    if NULL the global logger will be used
+ */
+RplInvalidDataException::RplInvalidDataException(ReLoggerLevel level,
+        int location,
+        const char* message, const void* data,
+        size_t dataSize, ReLogger* logger) :
+    ReException("") {
+    char buffer[64000];
+    if(message == NULL)
+        message = "invalid data: ";
+    if(data == NULL)
+        data = "";
+    if(dataSize > 16)
+        dataSize = 16;
+    size_t ix;
+    char* ptr = buffer + strlen(buffer);
+    for(ix = 0; ix < dataSize; ix++) {
+        qsnprintf(ptr, sizeof(buffer) - (ptr - buffer) - 1, "%02x ",
+                 ((unsigned char*) data)[ix]);
+        ptr += strlen(ptr);
+    }
+    for(ix = 0; ix < dataSize; ix++) {
+        char cc = ((char*) data)[ix];
+        if(cc > ' ' && cc <= '~')
+            *ptr++ = cc;
+        else
+            *ptr++ = '.';
+    }
+    if(logger == NULL)
+        logger = ReLogger::globalLogger();
+    logger->log(level, location, buffer);
+}
diff --git a/base/ReException.hpp b/base/ReException.hpp
new file mode 100644 (file)
index 0000000..8fb8113
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef REEXCEPTION_HPP
+#define REEXCEPTION_HPP
+
+// the sources generated from QT include this file directly:
+#ifndef RPLCORE_HPP
+#include <QByteArray>
+#endif
+
+class ReException {
+protected:
+    ReException();
+public:
+    ReException(const char* message, ...);
+    ReException(ReLoggerLevel level, int location, const char* message,
+                 ReLogger* logger = NULL);
+    ReException(ReLoggerLevel level, int location, ReLogger* logger,
+                 const char* message, ...);
+    const QByteArray& getMessage() const {
+        return m_message;
+    }
+protected:
+    QByteArray m_message;
+};
+
+class ReRangeException : public ReException {
+public:
+    ReRangeException(ReLoggerLevel level, int location, size_t current,
+                      size_t lbound, size_t ubound,
+                      const char* message = NULL, ReLogger* logger = NULL);
+};
+
+class RplInvalidDataException : public ReException {
+public:
+    RplInvalidDataException(ReLoggerLevel level, int location, const char* message,
+        const void* data = NULL, size_t dataSize = 0, ReLogger* logger = NULL);
+};
+
+#endif // REEXCEPTION_HPP
diff --git a/base/ReLogger.cpp b/base/ReLogger.cpp
new file mode 100644 (file)
index 0000000..0e913f7
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+
+/** @file
+ * A configurable logger for different output media.
+ */
+/** @file rplcore/rpllogger.hpp
+ *
+ * Definitions for a configurable logger for different output media.
+ */
+#include "base/rebase.hpp"
+#include <QDir>
+#include <iostream>
+
+enum {
+    LOC_ADD_APPENDER_1 = LOC_FIRST_OF(LOC_LOGGER), // 10101
+};
+
+ReLogger* ReLogger::m_globalLogger = NULL;
+
+/**
+ * @brief Returns the global logger.
+ *
+ * If it does not exist it will be created (singleton).
+ *
+ * @return the global logger
+ */
+ReLogger* ReLogger::globalLogger() {
+    if(m_globalLogger == NULL) {
+        m_globalLogger = new ReLogger();
+        m_globalLogger->buildStandardAppender("globallogger");
+    }
+    return m_globalLogger;
+}
+/**
+ * @brief Frees the resources of the global logger.
+ */
+void ReLogger::destroyGlobalLogger() {
+    delete m_globalLogger;
+    m_globalLogger = NULL;
+}
+
+/** @class ReAppender rpllogger.hpp "rplcore/rpllogger.hpp"
+ *
+ * @brief Puts the logging info to a medium (e.g. a file).
+ *
+ * This is an abstract base class.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param name         identifies the logger. Useful for ReLogger::findLogger()
+ */
+ReAppender::ReAppender(const QByteArray& name) :
+    m_name(name),
+    m_level(LOG_INFO) {
+
+}
+/**
+ * @brief Destructor.
+ */
+ReAppender::~ReAppender() {
+}
+
+/**
+ * Returns the name.
+ *
+ * @return             the name of the instance
+ */
+const char* ReAppender::getName() const {
+    return m_name.data();
+}
+
+/**
+ * @brief Sets the level.
+ *
+ * @param level
+ */
+void ReAppender::setLevel(ReLoggerLevel level) {
+    m_level = level;
+}
+/**
+ * @brief Returns the level.
+ *
+ * @return             the level
+ */
+ReLoggerLevel ReAppender::getLevel() const {
+    return m_level;
+}
+/**
+ * @brief Checks whether the current location should be logged.
+ *
+ * @param level                the level of the location.
+ * @return                     true: the location level is greater or equals to the appender's level
+ */
+bool ReAppender::isActive(ReLoggerLevel level) {
+    return level <= m_level;
+}
+
+/**
+ * @brief Sets or clears the automatic deletions.
+ *
+ * @param onNotOff             the state of the auto deletion
+ */
+void ReAppender::setAutoDelete(bool onNotOff) {
+    m_autoDelete = onNotOff;
+}
+
+/**
+ * @brief Returns the state of the auto deletion.
+ *
+ * @return     true: the logger destroys the instance
+ */
+bool ReAppender::isAutoDelete() const {
+    return m_autoDelete;
+}
+
+/** @class ReLogger rpllogger.hpp "rplcore/rpllogger.hpp"
+ *
+ * @brief Implements a logger.
+ *
+ * The logger takes the call from the calling location.
+ * But the output assumes the class <code>ReAppender</code>,
+ * more exactly: a subclass from the abstract class
+ * <code>ReAppender</code>,
+ *
+ * For single threaded applications there is a possability of
+ * a global logger. In this case the logger can be got with the static
+ * method <code>ReLogger::globalLogger()</code>.
+ *
+ * <b>Note</b>: using the global logger is <b>not threadsafe</b>!
+ *
+ * Each call of the logger should be provided by a <b>unique identifier</b>
+ * named the <b>location</b>. This allows to find the error quickly.
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReLogger::ReLogger() :
+    // m_appenders(),
+    m_countAppenders(0),
+    m_stdPrefix(),
+    m_mutex(),
+    m_withLocking(false) {
+    memset(m_appenders, 0, sizeof m_appenders);
+}
+
+/**
+ * @brief Destructor.
+ */
+ReLogger::~ReLogger() {
+    for(size_t ix = 0; ix < m_countAppenders; ix++) {
+        ReAppender* appender = m_appenders[ix];
+        if(appender->isAutoDelete()) {
+            delete appender;
+        }
+        m_appenders[ix] = NULL;
+    }
+}
+/**
+ * @brief Returns the first char of a logging line displaying the logging level.
+ *
+ * @param level                the level to "convert"
+ * @return                     the assigned prefix char
+ */
+char ReLogger::getPrefixOfLevel(ReLoggerLevel level) const {
+    char rc = ' ';
+    switch(level) {
+    case LOG_ERROR:
+        rc = '!';
+        break;
+    case LOG_WARNING:
+        rc = '+';
+        break;
+    case LOG_INFO:
+        rc = ' ';
+        break;
+    case LOG_DEBUG:
+        rc = '=';
+        break;
+    default:
+        rc = '?';
+        break;
+    }
+    return rc;
+}
+
+/**
+ * @brief Tests whether at least one appender is active for a given level.
+ *
+ * @param level     level to test
+ * @return          false: all appenders are not activated by this level<br>
+ *                  true: otherwise
+ */
+bool ReLogger::isActive(ReLoggerLevel level) const {
+    bool rc = false;
+    for(size_t ix = 0; ix < m_countAppenders; ix++) {
+        ReAppender* appender = m_appenders[ix];
+        if(appender->isActive(level)) {
+            rc = true;
+            break;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Sets the log level for all appenders.
+ *
+ * @param level     level to set
+ */
+void ReLogger::setLevel(ReLoggerLevel level) {
+    for(size_t ix = 0; ix < m_countAppenders; ix++) {
+        ReAppender* appender = m_appenders[ix];
+        appender->setLevel(level);
+    }
+}
+
+/**
+ * @brief Sets or clears the state "with locking".
+ *
+ * @param onNotOff   true: the logger is thread save.<br>
+ *                   false: not thread save
+ */
+void ReLogger::setWithLocking(bool onNotOff) {
+    m_withLocking = onNotOff;
+}
+
+/**
+ * @brief Returns the standard prefix of a logging line.
+ *
+ * If it does not exist it will be created.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @return                     the standard logging line prefix
+ */
+const QByteArray& ReLogger::getStdPrefix(ReLoggerLevel level, int location) {
+    if(m_stdPrefix.isEmpty())
+        m_stdPrefix = buildStdPrefix(level, location);
+    return m_stdPrefix;
+}
+
+/**
+ * @brief Logs (or not) the calling location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param message      the logging message
+ * @return                     true: for chaining
+ */
+bool ReLogger::log(ReLoggerLevel level, int location, const char* message) {
+    m_stdPrefix = "";
+    bool first = true;
+    for(size_t ix = 0; ix < m_countAppenders; ix++) {
+        ReAppender* appender = m_appenders[ix];
+        if(appender->isActive(level)) {
+            if(first && m_withLocking)
+                m_mutex.lock();
+            appender->log(level, location, message, this);
+        }
+    }
+    if(! first && m_withLocking)
+        m_mutex.unlock();
+    return true;
+}
+/**
+ * @brief Logs (or not) the calling location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param message      the logging message
+ * @return                     true: for chaining
+ */
+bool ReLogger::log(ReLoggerLevel level, int location,
+                    const QByteArray& message) {
+    return log(level, location, message.data());
+}
+
+/**
+ * @brief Logs (or not) the calling location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param message      the logging message
+ * @return                     true: for chaining
+ */
+bool ReLogger::log(ReLoggerLevel level, int location,
+                    const ReString& message) {
+    return log(level, location, message.toUtf8().data());
+}
+
+/**
+ * @brief Logs (or not) the calling location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param format       the logging message with placeholders (like printf).
+ * @param ...          the values of the placeholders (varargs)
+ * @return                     true: for chaining
+ */
+bool ReLogger::logv(ReLoggerLevel level, int location, const char* format,
+                     ...) {
+    char buffer[64000];
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    return log(level, location, buffer);
+}
+
+/**
+ * @brief Logs (or not) the calling location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param format       the logging message with placeholders (like printf).
+ * @param ...          the values of the placeholders (varargs)
+ * @return                     true: for chaining
+ */
+bool ReLogger::logv(ReLoggerLevel level, int location,
+                     const QByteArray& format, ...) {
+    char buffer[64000];
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    return log(level, location, buffer);
+}
+
+/**
+ * @brief Logs (or not) the calling location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param format       the logging message with placeholders (like printf).
+ * @param varlist      variable arguments
+ * @return                     true: for chaining
+ */
+bool ReLogger::log(ReLoggerLevel level, int location, const char* format,
+                    va_list& varlist) {
+    char buffer[64000];
+    qvsnprintf(buffer, sizeof buffer, format, varlist);
+    return log(level, location, buffer);
+}
+
+/**
+ * @brief Builds the standard prefix of a logging line.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ */
+QByteArray ReLogger::buildStdPrefix(ReLoggerLevel level, int location) {
+    time_t now = time(NULL);
+    struct tm* now2 = localtime(&now);
+    char buffer[64];
+    qsnprintf(buffer, sizeof buffer, "%c%d.%02d.%02d %02d:%02d:%02d (%d): ",
+             getPrefixOfLevel(level),
+             now2->tm_year + 1900,
+             now2->tm_mon + 1,
+             now2->tm_mday,
+             now2->tm_hour,
+             now2->tm_min,
+             now2->tm_sec,
+             location);
+    return QByteArray(buffer);
+}
+
+/**
+ * @brief Adds an appender.
+ *
+ * @param appender             appender to add
+ */
+void ReLogger::addAppender(ReAppender* appender) {
+    if(m_countAppenders < sizeof m_appenders / sizeof m_appenders[0]) {
+        m_appenders[m_countAppenders++] = appender;
+    } else {
+        log(LOG_ERROR, LOC_ADD_APPENDER_1, "too many appenders");
+    }
+}
+
+/**
+ * @brief Returns the appender with a given name.
+ *
+ * @param name  the appender's name
+ *
+ * @return      NULL: no appender with this name is registered<br>
+ *              otherwise: the wanted appender
+ */
+ReAppender* ReLogger::findAppender(const char* name) const {
+    ReAppender* rc = NULL;
+    for(size_t ix = 0; ix < m_countAppenders; ix++) {
+        ReAppender* current = m_appenders[ix];
+        if(strcmp(name, current->getName()) == 0) {
+            rc = current;
+            break;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Builds the standard appender configured by a configuration file.
+ *
+ * @param config               configuration file
+ * @param prefix        the prefix of the key in the config file
+ *                      (in front of "name")
+ * @param defaultLogfilePrefix
+ *                      the prefix of the log file if no entry in the
+ *                      configuration file
+ */
+void ReLogger::buildStandardAppender(ReConfig* config,
+                                      const char* prefix,
+                                      const char* defaultLogfilePrefix) {
+    QByteArray sPrefix(prefix);
+    QByteArray logFilePrefix = config->asString(sPrefix + "name",
+                                                defaultLogfilePrefix);
+
+    int maxSize = config->asInt( + "maxsize", 10100100);
+    int maxCount = config->asInt(sPrefix + "maxfiles", 5);
+    buildStandardAppender(logFilePrefix, maxSize, maxCount);
+    QByteArray sLevel = config->asString(sPrefix + "level", "info");
+    ReLoggerLevel level = LOG_INFO;
+    if (strcasecmp(sLevel.constData(), "error") == 0)
+        level = LOG_ERROR;
+    else if (strcasecmp(sLevel, "warning") == 0)
+        level = LOG_WARNING;
+    else if (strcasecmp(sLevel, "debug") == 0)
+        level = LOG_DEBUG;
+    setLevel(level);
+}
+
+/**
+ * @brief Builds the standard appender for the instance: a console logger and a file logger.
+ *
+ * @param prefix               the prefix of the log file name, e.g. /var/log/server
+ * @param maxSize              the maximum of the file size
+ * @param maxCount             the maximal count of files. If neccessary the oldest file will be deleted
+ */
+void ReLogger::buildStandardAppender(const QByteArray& prefix, int maxSize,
+                                      int maxCount) {
+    ReStreamAppender* streamAppender = new ReStreamAppender(stderr);
+    streamAppender->setAutoDelete(true);
+    addAppender((ReAppender*) streamAppender);
+    ReFileAppender* fileAppender = new ReFileAppender(prefix, maxSize, maxCount);
+    fileAppender->setAutoDelete(true);
+    addAppender((ReAppender*) fileAppender);
+}
+
+/** @class ReStreamAppender rpllogger.hpp "rplcore/rpllogger.hpp"
+ *
+ * @brief Puts the logging info to a standard output stream.
+ *
+ * The possible streams are <code>std::stdout</code> or  <code>std::stderr</code>
+ */
+
+
+/**
+ * @brief Constructor.
+ */
+ReStreamAppender::ReStreamAppender(FILE* file, const char* appenderName) :
+    ReAppender(QByteArray(appenderName)),
+    m_fp(file) {
+}
+
+/**
+ * @brief Destructor.
+ */
+ReStreamAppender::~ReStreamAppender() {
+    fflush(m_fp);
+}
+
+
+/**
+ * @brief Logs (or not) the current location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param message      the logging message
+ * @param logger    the calling logger
+ */
+void ReStreamAppender::log(ReLoggerLevel level, int location,
+                            const char* message, ReLogger* logger) {
+    const QByteArray& prefix = logger->getStdPrefix(level, location);
+    fputs(prefix, m_fp);
+    fputs(message, m_fp);
+    fputc('\n', m_fp);
+    fflush(m_fp);
+}
+#pragma GCC diagnostic warning "-Wunused-parameter"
+
+
+/** @class ReFileAppender rpllogger.hpp "rplcore/rpllogger.hpp"
+ *
+ * @brief Puts the logging info to a file.
+ *
+ * The appender creates a collection of files to limit the used disk space.
+ * Each logfile is limited to a given size. And the number of files is limited.
+ * If the count exceeds the oldest file will be deleted.
+ *
+ * Each logfile's name has a given name prefix, a running number
+ * and the suffix ".log", e.g. "globallogger.003.log".
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param prefix               the prefix of the log file name, e.g. /var/log/server
+ * @param maxSize              the maximum of the file size
+ * @param maxCount             the maximal count of files. If neccessary the oldest file will be deleted
+ * @param appenderName the name of the appender. @see ReLogger::findAppender()
+ */
+ReFileAppender::ReFileAppender(const QByteArray& prefix, int maxSize,
+                                 int maxCount, const char* appenderName) :
+    ReAppender(QByteArray(appenderName)),
+    m_prefix(prefix),
+    m_maxSize(maxSize),
+    m_maxCount(maxCount),
+    m_currentSize(0),
+    m_currentNo(0),
+    m_fp(NULL) {
+    open();
+}
+
+/**
+ * @brief Destructor.
+ */
+ReFileAppender::~ReFileAppender() {
+    if(m_fp != NULL) {
+        fclose(m_fp);
+        m_fp = NULL;
+    }
+}
+
+/**
+ * @brief Opens the next log file.
+ */
+void ReFileAppender::open() {
+    if(m_fp != NULL)
+        fclose(m_fp);
+    char fullName[512];
+    qsnprintf(fullName, sizeof fullName, "%s.%03d.log", m_prefix.data(),
+             ++m_currentNo);
+    m_fp = fopen(fullName, "a");
+    if(m_fp == NULL)
+        fprintf(stderr, "cannot open: %s\n", fullName);
+    else {
+        //@ToDo
+        m_currentSize = 0;
+    }
+}
+
+/**
+ * @brief Logs (or not) the current location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param message      the logging message
+ * @param logger    the calling logger
+ */
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+void ReFileAppender::log(ReLoggerLevel level, int location,
+                          const char* message,
+                          ReLogger* logger) {
+    if(m_fp != NULL) {
+        const QByteArray& prefix = logger->getStdPrefix(level, location);
+        fputs(prefix, m_fp);
+        fputs(message, m_fp);
+        fputc('\n', m_fp);
+        fflush(m_fp);
+    }
+}
+#pragma GCC diagnostic warning "-Wunused-parameter"
+
+/** @class ReMemoryAppender rpllogger.hpp "rplcore/rpllogger.hpp"
+ *
+ * @brief Puts the logging info to an internal buffer.
+ *
+ * This line list can be required: <code>getLines()</code>.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param maxLines      the maximum of lines.
+ *                      If the buffer is full the oldest lines will be deleted
+ * @param appenderName  NULL or the name of the appender
+ */
+ReMemoryAppender::ReMemoryAppender(int maxLines, const char* appenderName) :
+    ReAppender(appenderName),
+    m_lines(),
+    m_maxLines(maxLines),
+    m_addPrefix(true)
+{
+    m_lines.reserve(maxLines);
+}
+
+/**
+ * @brief Destructor.
+ */
+ReMemoryAppender::~ReMemoryAppender() {
+}
+
+/**
+ * Logs (or not) the current location.
+ *
+ * @param level                the level of the location
+ * @param location     an unique identifier of the location
+ * @param message      the logging message
+ * @param logger    the calling logger
+ */
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+void ReMemoryAppender::log(ReLoggerLevel level, int location,
+                            const char* message,
+                            ReLogger* logger) {
+    if(m_lines.size() >= m_maxLines)
+        m_lines.removeFirst();
+    if (! m_addPrefix)
+        m_lines.append(message);
+    else {
+        QByteArray msg(logger->getStdPrefix(level, location));
+        msg += message;
+        m_lines.append(msg);
+    }
+}
+#pragma GCC diagnostic warning "-Wunused-parameter"
+
+/**
+ * @brief Returns the list of lines.
+ *
+ * @return the line list
+ */
+const QList<QByteArray>& ReMemoryAppender::getLines() const {
+    return m_lines;
+}
+
+/**
+ * @brief Deletes all log lines.
+ */
+void ReMemoryAppender::clear() {
+    m_lines.clear();
+}
diff --git a/base/ReLogger.hpp b/base/ReLogger.hpp
new file mode 100644 (file)
index 0000000..125a6f6
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RELOGGER_HPP
+#define RELOGGER_HPP
+
+/**
+ *
+ */
+class ReLogger;
+class ReConfig;
+/**
+ * @brief Logging level: for controlling of the logging.
+ *
+ * Each logging location defines one of the following level.
+ * If the level of an appender is lower or equals to this level
+ * the logging is done.
+ */
+enum ReLoggerLevel {
+    LOG_ERROR = 10,         ///< marks an error.
+    LOG_WARNING = 15,       ///< marks a warning
+    LOG_INFO = 20,          ///< marks an information
+    LOG_DEBUG = 25          ///< for debug purpose only
+};
+
+class ReAppender {
+public:
+    ReAppender(const QByteArray& name);
+    virtual ~ReAppender();
+private:
+    // No copy constructor: no implementation!
+    ReAppender(const ReAppender& source);
+    // Prohibits assignment operator: no implementation!
+    ReAppender& operator =(const ReAppender& source);
+public:
+    virtual void log(ReLoggerLevel level, int location, const char* message,
+                     ReLogger* logger) = 0;
+    bool isActive(ReLoggerLevel level);
+    void setLevel(ReLoggerLevel level);
+    void setAutoDelete(bool onNotOff);
+    bool isAutoDelete() const;
+    ReLoggerLevel getLevel() const;
+    const char* getName() const;
+
+private:
+    // Name of the appender. Used to find the appender in a list of appenders
+    QByteArray m_name;
+    // only locations with a lower or equal level will be logged
+    ReLoggerLevel m_level;
+    // true: the logger destroys the instance. false: the deletion must be done outside of the logger
+    bool m_autoDelete;
+};
+
+class ReLogger {
+public:
+    static ReLogger* globalLogger();
+    static void destroyGlobalLogger();
+private:
+    // the standard logger, can be called (with globalLogger()) from each location
+    static ReLogger* m_globalLogger;
+public:
+    ReLogger();
+    virtual ~ReLogger();
+private:
+    // No copy constructor: no implementation!
+    ReLogger(const ReLogger& source);
+    // Prohibits assignment operator: no implementation!
+    ReLogger& operator =(const ReLogger& source);
+public:
+    bool log(ReLoggerLevel level, int location, const char* message);
+    bool log(ReLoggerLevel level, int location, const QByteArray& message);
+    bool log(ReLoggerLevel level, int location, const ReString& message);
+    bool logv(ReLoggerLevel level, int location, const char* format, ...);
+    bool logv(ReLoggerLevel level, int location, const QByteArray& format, ...);
+    bool log(ReLoggerLevel level, int location, const char* format,
+             va_list& varlist);
+    void addAppender(ReAppender* appender);
+    ReAppender* findAppender(const char* name) const;
+    void buildStandardAppender(ReConfig* config, const char* prefix = "logfile.",
+                               const char* defaultLoggerName = "logger");
+    void buildStandardAppender(const QByteArray& prefix, int maxSize = 10*1024*1024,
+                               int maxCount = 5);
+    QByteArray buildStdPrefix(ReLoggerLevel level, int location);
+    const QByteArray& getStdPrefix(ReLoggerLevel level, int location);
+    char getPrefixOfLevel(ReLoggerLevel level) const;
+    bool isActive(ReLoggerLevel level) const;
+    void setLevel(ReLoggerLevel level);
+    void setWithLocking(bool onNotOff);
+private:
+    // the assigned appenders:
+    ReAppender* m_appenders[16];
+    // the number of appenders in m_appenders:
+    size_t m_countAppenders;
+    // "" or the cache of the prefix of the current logging line: This can be reused by any appender.
+    QByteArray m_stdPrefix;
+    QMutex m_mutex;
+    bool m_withLocking;
+};
+
+/**
+ * Implements an appender which puts the messages to a standard stream: stdout or stderr
+ */
+class ReStreamAppender : public ReAppender {
+public:
+    ReStreamAppender(FILE* stream, const char* appenderName = "FileAppender");
+    virtual ~ReStreamAppender();
+public:
+    virtual void log(ReLoggerLevel level, int location, const char* message,
+                     ReLogger* logger);
+private:
+    // stdout or stderr:
+    FILE* m_fp;
+};
+
+/**
+ * Implements an appender which puts the messages to a file
+ */
+class ReFileAppender : public ReAppender {
+public:
+    ReFileAppender(const QByteArray& name, int maxSize, int maxCount,
+                    const char* appenderName = "FileAppender");
+    virtual ~ReFileAppender();
+public:
+    void open();
+    virtual void log(ReLoggerLevel level, int location, const char* message,
+                     ReLogger* logger);
+
+private:
+    // prefix of the log file name. Will be appended by ".<no>.log"
+    QByteArray m_prefix;
+    // maximal size of a logging file:
+    int m_maxSize;
+    // maximal count of logging files. If neccessary the oldest file will be deleted.
+    int m_maxCount;
+    // the size of the current log file:
+    int m_currentSize;
+    // the number of the current log file:
+    int m_currentNo;
+    // the current log file:
+    FILE* m_fp;
+};
+
+/**
+ * Stores the log messages in a list.
+ */
+class ReMemoryAppender : public ReAppender {
+public:
+    ReMemoryAppender(int maxLines = 1024,
+                      const char* appenderName = "MemoryAppender");
+    ~ReMemoryAppender();
+public:
+    virtual void log(ReLoggerLevel level, int location, const char* message,
+                     ReLogger* logger);
+    const QList<QByteArray>& getLines() const;
+    void clear();
+private:
+    QList<QByteArray> m_lines;
+    // maximum count of m_lines. If larger the oldest lines will be deleted.
+    int m_maxLines;
+    // true: standard prefix (level + datetime) will be stored too.
+    bool m_addPrefix;
+};
+
+#endif // RELOGGER_HPP
diff --git a/base/ReQString.cpp b/base/ReQString.cpp
new file mode 100644 (file)
index 0000000..171401b
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Missed operation for <code>ReString</code>s.
+ */
+/** @file rplcore/rplqstring.hpp
+ *
+ * @brief Definitions for missed operation for <code>ReString</code>s.
+ */
+#include "base/rebase.hpp"
+
+
+/**
+ * @brief Determines the length and vlaue of an integer.
+ *
+ * @param text      the number as text
+ * @param start     the first index to inspect
+ * @param radix     the base of the number sytem: 8 (octal), 10 or 16
+ * @param pValue     OUT: the value of the integer. May be NULL
+ *
+ * @return          <=0: no integer found
+ *                  otherwise: the length of the integer
+ */
+int ReQString::lengthOfUInt64(const ReString& text, int start,
+    int radix, quint64* pValue)
+{
+    int inputLength = text.size();
+    int64_t value = 0;
+    int ix = start;
+    int cc;
+    if (radix == 10){
+        while (ix < inputLength){
+            if ( (cc = text[ix].unicode()) >= '0' && cc <= '9')
+                value = value * 10 + cc - '0';
+            else
+                break;
+            ix++;
+        }
+    } else if (radix == 16){
+            while (ix < inputLength){
+                if ( (cc = text[ix].unicode()) >= '0' && cc <= '9')
+                    value = value * 16 + cc - '0';
+                else if (cc >= 'A' && cc <= 'F')
+                    value = value * 16 + cc - 'A' + 10;
+                else if (cc >= 'a' && cc <= 'f')
+                    value = value * 16 + cc - 'a' + 10;
+                else
+                    break;
+                ix++;
+            }
+    } else if (radix == 8){
+            while (ix < inputLength){
+                if ( (cc = text[ix].unicode()) >= '0' && cc <= '7')
+                    value = value * 8 + cc - '0';
+                else
+                    break;
+                ix++;
+            }
+    } else {
+        throw ReException("ReQString::lengthOfInt(): wrong radix: %d", radix);
+    }
+    if (pValue != NULL)
+        *pValue = value;
+    return ix - start;
+}
+/**
+ * @brief Determines the length and value of an unsigned integer.
+ *
+ * @param text      the number as text
+ * @param start     the first index to inspect
+ * @param radix     the base of the number sytem: 8 (octal), 10 or 16
+ * @param pValue     OUT: the value of the integer. May be NULL
+ *
+ * @return          0: no integer found
+ *                  otherwise: the length of the integer
+ */
+int ReQString::lengthOfUInt(const ReString& text, int start,
+    int radix, uint* pValue)
+{
+    quint64 value;
+    int rc = lengthOfUInt64(text, start, radix, &value);
+    if (pValue != NULL)
+        *pValue = (uint) value;
+    return rc;
+}
+
+/**
+ * @brief Determines the length and value of a floting point number.
+ *
+ * @param text      the number as text
+ * @param start     the first index to inspect
+ * @param pValue     OUT: the value of the integer. May be NULL
+ *
+ * @return          <=0: no real number found
+ *                  otherwise: the length of the floating point number
+ */
+int ReQString::lengthOfReal(const ReString& text, int start, qreal* pValue)
+{
+    int inputLength = text.size();
+    qreal value = 0.0;
+    int cc;
+    int ix = start;
+    while (ix < inputLength){
+        if ( (cc = text[ix].unicode()) >= '0' && cc <= '9')
+            value = value * 10 + (cc - '0');
+        else
+            break;
+        ix++;
+    }
+    // found: a digit has been found (in front of or behind the '.'
+    bool found = ix > start;
+    if (ix < inputLength && text[ix].unicode() == '.'){
+        ix++;
+    }
+    if (ix < inputLength && text[ix].isDigit()){
+        found = true;
+        qreal divisor = 1;
+        qreal precision = 0;
+        while ( ix < inputLength && (cc = text[ix].unicode()) >= '0' && cc <= '9'){
+            divisor *= 10;
+            precision = precision*10 + cc - '0';
+            ix++;
+        }
+        value += precision / divisor;
+    } else if (! found){
+        ix = start;
+    }
+    if (found && ix + 1 < inputLength && toupper(text[ix].unicode()) == 'E'){
+        int savePoint = ix;
+        ix++;
+        bool negative = false;
+        if ( (cc = text[ix].unicode()) == '+')
+            ix++;
+        else if (cc == '-'){
+            ix++;
+            negative = true;
+        }
+        if (ix >= inputLength || ! text[ix].isDigit())
+                ix = savePoint;
+        else{
+            int exponent = 0;
+            while (ix < inputLength && text[ix].isDigit()){
+                exponent = exponent * 10 + text[ix].unicode() - '0';
+                ix++;
+            }
+            if (negative)
+                value /= qPow(10, exponent);
+            else
+                value *= qPow(10, exponent);
+        }
+    }
+    if (pValue)
+        *pValue = value;
+    return found ? ix - start : 0;
+}
+
+/**
+ * @brief Converts a ReString into an utf-8 string
+ *
+ * The expression <code>qstring.toUtf8().constData()</code> is not allowed
+ * in a variable argument list like sprintf. This is a thread save workaround.
+ *
+ * @param source        string to convert
+ * @param buffer        OUT: target buffer
+ * @param bufferSize    size of the target buffer
+ * @return              <code>buffer</code>
+ */
+char*ReQString::utf8(const ReString& source, char buffer[], size_t bufferSize)
+{
+    QByteArray val = source.toUtf8();
+    if (val.length() < (int) bufferSize)
+        bufferSize = val.length() + 1;
+    memcpy(buffer, val.constData(), bufferSize - 1);
+    buffer[bufferSize - 1] = '\0';
+    return buffer;
+}
diff --git a/base/ReQtring.hpp b/base/ReQtring.hpp
new file mode 100644 (file)
index 0000000..3a3bcf5
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLQSTRING_HPP
+#define RPLQSTRING_HPP
+
+class ReQString
+{
+public:
+    static int lengthOfUInt64(const ReString& text, int start = 0,
+        int radix = 10, quint64* value = NULL);
+    static int lengthOfUInt(const ReString& text, int start, int radix,
+        uint* pValue);
+    static int lengthOfReal(const ReString& text, int start = 0,
+        qreal* value = NULL);
+    /**
+     * @brief Returns the value of a hexadecimal digit.
+     *
+     * @param digit     a (unicode) character
+     * @return          -1: not a hexadecimal digit<br>
+     *                  otherwise: the value, e.g. 10 for 'a'
+     */
+    inline static int valueOfHexDigit(int digit){
+        return digit >= '0' && digit <= '9' ? digit - '0'
+                : digit >= 'A' && digit <= 'F' ? digit - 'A' + 10
+                   : digit >= 'a' && digit <= 'f' ? digit - 'a' + 10 : -1;
+    }
+    static char* utf8(const ReString& source, char buffer[], size_t bufferSize);
+};
+
+#endif // RPLQSTRING_HPP
diff --git a/base/ReStringUtil.cpp b/base/ReStringUtil.cpp
new file mode 100644 (file)
index 0000000..0afebec
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+/** @file
+ * @brief Missed operations for <code>QByteArray</code>s.
+ */
+/** @file base/ReStringUtil.cpp
+ *
+ * @brief Definitions for missed operations for <code>QByteArray</code>s.
+ */
+#include "base/rebase.hpp"
+
+/** @class ReStringUtil ReStringUtil.hpp "base/ReStringUtil.hpp"
+ *
+ * @brief Implements some services around strings.
+ *
+ * This is a class with static members only.
+ */
+
+/**
+ * @brief Counts the occurrences of a given char in a string.
+ *
+ * @param line the text to inspect
+ * @param cc   the char to count
+ * @return             the number of <code>cc</code> in the text
+ */
+int ReStringUtil::countChar(const char* line, char cc)
+{
+    const char* ptr = line;
+    int rc = 0;
+    while( (ptr = strchr(ptr, cc)) != NULL){
+        rc++;
+        ptr++;
+    }
+    return rc;
+}
+/**
+ * Counts the occurrences of a string in a string.
+ *
+ * @param source    in this string will be searched
+ * @param item      this item will be searched
+ * @return          the count of occurrences
+ */
+int ReStringUtil::count(const char* source, const char* item) {
+    const char* end = source;
+    int rc = 0;
+    int lengthItem = strlen(item);
+    while(true) {
+        const char* start = end;
+        end = strstr(start, item);
+        if(end == NULL)
+            break;
+        else {
+            rc++;
+            end += lengthItem;
+        }
+    }
+    return rc;
+}
+
+/**
+ * Returns a string with a given maximum length.
+ *
+ * @param source        the source
+ * @param maxLength     the maximum length of the result
+ * @param buffer        Out: used if length of the result is shorter
+ * @param appendix      if the result is cut this string will be appended.<br>
+ *                      May be NULL.
+ * @return              source: the source is enough short<br>
+ *                      the prefix of source with the given length
+ */
+const QByteArray& ReStringUtil::cutString(const QByteArray& source, int maxLength,
+                                       QByteArray& buffer, const char* appendix) {
+    QByteArray& rc = source.length() <= maxLength ? (QByteArray&) source : buffer;
+    if(source.length() > maxLength) {
+        buffer = source.left(maxLength);
+        if(appendix != NULL && appendix[0] != '\0')
+            buffer.append(appendix);
+    }
+    return rc;
+}
+static char s_fileSeparator = 0;
+
+/**
+ * @brief Returns the os specific file path separator.
+ * @return the file path separator, e.g. "/" for linux
+ */
+const char* ReStringUtil::fileSeparator(){
+    return fileSeparatorChar() == '/' ? "/" : "\\";
+}
+
+/**
+ * @brief Returns the os specific file path separator.
+ * @return the file path separator, e.g. '/' for linux
+ */
+char ReStringUtil::fileSeparatorChar(){
+    if (s_fileSeparator == 0){
+        const char* path = getenv("PATH");
+        if (path != NULL){
+            s_fileSeparator = strchr(path, ';') != NULL
+                    || strchr(path, '\\') != NULL ? '\\' : '/';
+        } else {
+            if (getenv("windows") != NULL)
+                s_fileSeparator = '\\';
+            else
+                s_fileSeparator = '/';
+        }
+    }
+    return s_fileSeparator;
+}
+
+/**
+ * Builds a hexadecimal dump.
+ *
+ * Format: a sequence of hex digits followed by the ascii interpretation.
+ *
+ * Example: "42 30 61  B0a"
+ *
+ * @param data              data to convert
+ * @param length            length of data
+ * @param bytesPerLine      one line containes so many bytes of data
+ * @return                  the hex dump
+ */
+QByteArray ReStringUtil::hexDump(uint8_t* data, int length, int bytesPerLine) {
+    QByteArray rc;
+    int fullLines = length / bytesPerLine;
+    int expectedLength = (bytesPerLine * 4 + 2) * (fullLines + 1);
+    rc.reserve(expectedLength + 100);
+    int ixData = 0;
+    int col;
+    char buffer[16];
+    for(int lineNo = 0; lineNo < fullLines; lineNo++) {
+        for(col = 0; col < bytesPerLine; col++) {
+            qsnprintf(buffer, sizeof buffer, "%02x ", data[ixData + col]);
+            rc.append(buffer);
+        }
+        rc.append(' ');
+        for(col = 0; col < bytesPerLine; col++) {
+            uint8_t cc = data[ixData + col];
+            rc.append(cc > ' ' && cc < 128 ? (char) cc : '.');
+        }
+        ixData += bytesPerLine;
+        rc.append('\n');
+    }
+    // incomplete last line:
+    int restBytes = length - ixData;
+    if(restBytes > 0) {
+        for(col = 0; col < restBytes; col++) {
+            qsnprintf(buffer, sizeof buffer, "%02x ", data[ixData + col]);
+            rc.append(buffer);
+        }
+        for(col = restBytes; col < bytesPerLine; col++) {
+            rc.append("   ");
+        }
+        rc.append(' ');
+        for(col = 0; col < restBytes; col++) {
+            uint8_t cc = data[ixData + col];
+            rc.append(cc > ' ' && cc < 128 ? (char) cc : '.');
+        }
+        rc.append('\n');
+    }
+    return rc;
+}
+
+
+/**
+ * Reads a file into a string.
+ *
+ * @param file              file to read
+ * @param removeLastNewline true: if the last character is a newline
+ *                          the result will not contain this
+ * @return                  the file's content
+ */
+QByteArray ReStringUtil::read(const char* file, bool removeLastNewline) {
+    QByteArray rc;
+    struct stat info;
+    size_t size;
+    if(stat(file, &info) == 0 && (size = info.st_size) > 0) {
+        FILE* fp = fopen(file, "r");
+        if(fp != NULL) {
+            rc.resize(info.st_size);
+            fread(rc.data(), 1, size, fp);
+            fclose(fp);
+            if(removeLastNewline && rc.at(size - 1) == '\n') {
+                rc.resize(size - 1);
+            }
+        }
+    }
+    return rc;
+}
+
+QByteArray ReStringUtil::replaceNode(const char* source, const char* newNode){
+    char sep = fileSeparatorChar();
+    const char* ptr = strrchr(source, sep);
+    QByteArray rc;
+    rc.reserve(strlen(source) + strlen(newNode) + 1);
+    if (ptr == NULL){
+        rc.append(source).append(sep).append(newNode);
+    } else if (ptr[0] == '\0'){
+        rc.append(source).append(newNode);
+    } else {
+        rc.append(source, ptr - source + 1).append(newNode);
+    }
+    return rc;
+}
+
+/**
+ * Converts a string into an array of strings.
+ *
+ * @param source        string to convert
+ * @param separator     the separator between the items to split
+ * @return              an array with the splitted source
+ */
+QList<QByteArray> ReStringUtil::toArray(const char* source,
+                                       const char* separator) {
+    const char* end = source;
+    QList<QByteArray> rc;
+    rc.reserve(count(source, separator) + 1);
+    int lengthItem = strlen(separator);
+    while(*end != '\0') {
+        const char* start = end;
+        end = strstr(start, separator);
+        if(end == NULL) {
+            end = start + strlen(start);
+        }
+        rc.append(QByteArray(start, end - start));
+        if(end[0] != '\0')
+            end += lengthItem;
+    }
+    return rc;
+}
+
+QByteArray ReStringUtil::toCString(const char* source, int maxLength){
+    if (maxLength <= 0)
+        maxLength = strlen(source);
+    int binaries = 0;
+    int ix;
+    for (ix = 0; ix < maxLength; ix++)
+        if (source[ix] < ' '){
+            binaries++;
+        }
+    QByteArray rc;
+    rc.reserve(maxLength + 3 * binaries + 1);
+    char cc;
+    for (ix = 0; ix < maxLength; ix++)
+        if ( (cc = source[ix]) >= ' '){
+            rc += source[ix];
+        } else {
+            switch(cc){
+            case '\0':
+                // stop looping:
+                ix = maxLength;
+                break;
+            case '\n':
+                rc += "\\n";
+                break;
+            case '\r':
+                rc += "\\r";
+                break;
+            case '\t':
+                rc += "\\t";
+                break;
+            default:
+            {
+                char buffer[5];
+                qsnprintf(buffer, sizeof buffer, "\\x%02x",
+                         ((unsigned int) cc) % 0xff);
+                rc += buffer;
+                break;
+            }
+            }
+        }
+    return rc;
+}
+
+/**
+ * Return an integer as an QByteArray.
+ *
+ * @param value     value to convert
+ * @param format    format like in sprintf()
+ * @return          the ascii form of the value
+ */
+QByteArray ReStringUtil::toNumber(int value, const char* format) {
+    char buffer[128];
+    qsnprintf(buffer, sizeof buffer, format, value);
+    return QByteArray(buffer);
+}
+
+/**
+ * Writes a string to a file.
+ *
+ * @param file      the file's name
+ * @param content   NULL or the file's content
+ * @param mode      the file open mode: "w" for write, "a" for append
+ * @return          true: successful<br>
+ *                  false: error occurred
+ */
+bool ReStringUtil::write(const char* file, const char* content, const char* mode) {
+    FILE* fp = fopen(file, mode);
+    if(fp != NULL) {
+        fputs(content, fp);
+        fclose(fp);
+    }
+    return fp != NULL;
+}
+/**
+ * @brief Returns the length of the number string.
+ *
+ * @param text                  a text to inspect
+ * @param skipTrailingSpaces    true: if spaces are behind the number
+ *                              the result contains the length of these
+ * @return             0: not a number<br>
+ *                             otherwise: the length of the number string
+ */
+int ReStringUtil::lengthOfNumber(const char* text, bool skipTrailingSpaces){
+    int rc = 0;
+    bool found = false;
+    const char* ptr = text;
+    while(isspace(*ptr))
+        ptr++;
+    if ( (*ptr == '+' || *ptr == '-'))
+        ptr++;
+    found = isdigit(*ptr);
+    while(isdigit(*ptr)){
+        ptr++;
+    }
+    if (*ptr == '.'){
+        ptr++;
+        if (isdigit(*ptr)){
+            found = true;
+            while(isdigit(*ptr))
+                ptr++;
+        }
+    }
+    if (found && toupper(*ptr) == 'E'){
+        const char* ptrToE = ptr;
+        ptr++;
+        if (*ptr == '+' || *ptr == '-')
+            ptr++;
+        if (! isdigit(*ptr))
+            ptr = ptrToE;
+        else {
+            while(isdigit(*ptr))
+                ptr++;
+        }
+    }
+    if (found && skipTrailingSpaces){
+        while(isspace(*ptr)){
+            ptr++;
+        }
+    }
+    rc = ! found ? 0 : ptr - text;
+    return rc;
+}
+/**
+ * @brief Adds the count of the possible separators.
+ *
+ * @param countCommas          IN/OUT: number of ','
+ * @param countSemicolons      IN/OUT: number of ';'
+ * @param countPipes           IN/OUT: number of '|'
+ * @param countBlanks          IN/OUT: number of ' '
+ */
+static void addSeparators(const char* line, int& commas, int& semicolons,
+        int& pipes, int& blanks)
+{
+    commas += ReStringUtil::countChar(line, ',');
+    semicolons += ReStringUtil::countChar(line, ';');
+    pipes += ReStringUtil::countChar(line, '|');
+    blanks += ReStringUtil::countChar(line, ' ');
+}
+
+/**
+ * @brief Finds the separator of the CSV file.
+ *
+ * If the file contain TABs the result is TAB.
+ * If not:
+ * Inspects the first 5 lines and counts the possible separators.
+ * The most found separator will be returned.
+ *
+ * @param fp                   CSV file
+ * @param buffer               a line buffer
+ * @param bufferSize   the size of <code>buffer[]</code>
+ */
+char ReStringUtil::findCsvSeparator(FILE* fp, char* buffer, size_t bufferSize){
+    char rc = '\0';
+    int lineNo = 0;
+    int maxLines = 5;
+    const char* line;
+    int commas = 0;
+    int semicolons = 0;
+    int pipes = 0;
+    int blanks = 0;
+    while(++lineNo < maxLines && (line = fgets(buffer, bufferSize, fp)) != NULL){
+        if (strchr(line, '\t') != NULL){
+            rc = '\t';
+            break;
+        }
+        addSeparators(line, commas, semicolons, pipes, blanks);
+    }
+    fseek(fp, 0, SEEK_SET);
+    if (rc != '\t'){
+        if (semicolons > 0 && commas > 0){
+            // if ',' is decimal separator and ';' is the column separator:
+            // Add one semicolon per line because of number of values is
+            // 1 greater than the number of separators
+            semicolons += lineNo;
+        }
+        if (commas + semicolons + pipes == 0) {
+            rc = blanks > 0 ? ' ' : '\0';
+        } else if (semicolons >= commas && semicolons >= pipes)
+            rc = ';';
+        else if (commas > semicolons && commas > pipes)
+            rc = ',';
+        else if (pipes > commas && pipes > semicolons)
+            rc = '|';
+    }
+    return rc;
+}
+
+/**
+ * @brief Determines the length and vlaue of an integer.
+ *
+ * @param text      the number as text
+ * @param radix     the base of the number system: 8 (octal), 10 or 16
+ * @param pValue    OUT: the value of the integer. May be NULL
+ *
+ * @return          <=0: no integer found
+ *                  otherwise: the length of the integer
+ */
+int ReStringUtil::lengthOfUInt64(const char* text, int radix, quint64* pValue)
+{
+    int64_t value = 0;
+    int length = 0;
+    int cc;
+    if (radix == 10){
+        while ( (cc = text[length]) >= '0' && cc <= '9'){
+            value = value * 10 + cc - '0';
+            length++;
+        }
+    } else if (radix == 16){
+            while (true){
+                if ( (cc = text[length]) >= '0' && cc <= '9')
+                    value = value * 16 + cc - '0';
+                else if (cc >= 'A' && cc <= 'F')
+                    value = value * 16 + cc - 'A' + 10;
+                else if (cc >= 'a' && cc <= 'f')
+                    value = value * 16 + cc - 'a' + 10;
+                else
+                    break;
+                length++;
+            }
+    } else if (radix == 8){
+            while (true){
+                if ( (cc = text[length]) >= '0' && cc <= '7')
+                    value = value * 8 + cc - '0';
+                else
+                    break;
+                length++;
+            }
+    } else {
+        throw ReException("ReStringUtil::lengthOfInt(): wrong radix: %d", radix);
+    }
+    if (pValue != NULL)
+        *pValue = value;
+    return length;
+}
+
+/**
+ * @brief Determines the length and value of a floting point number.
+ *
+ * @param text      the number as text
+ * @param pValue     OUT: the value of the integer. May be NULL
+ *
+ * @return          <=0: no real number found
+ *                  otherwise: the length of the floating point number
+ */
+int ReStringUtil::lengthOfReal(const char* text, qreal* pValue)
+{
+    qreal value = 0.0;
+    int cc;
+    int length = 0;
+    while (true){
+        if ( (cc = text[length]) >= '0' && cc <= '9')
+            value = value * 10 + (cc - '0');
+        else
+            break;
+        length++;
+    }
+    // found: a digit has been found (in front of or behind the '.'
+    bool found = length > 0;
+    if (text[length] == '.'){
+        length++;
+    }
+    if (isdigit(text[length])){
+        found = true;
+        qreal divisor = 1;
+        qreal precision = 0;
+        while ( (cc = text[length]) >= '0' && cc <= '9'){
+            divisor *= 10;
+            precision = precision*10 + cc - '0';
+            length++;
+        }
+        value += precision / divisor;
+    } else if (! found){
+        length = 0;
+    }
+    if (found && toupper(text[length]) == 'E'){
+        int savePoint = length;
+        length++;
+        bool negative = false;
+        if ( (cc = text[length]) == '+')
+            length++;
+        else if (cc == '-'){
+            length++;
+            negative = true;
+        }
+        if (! isdigit(text[length]))
+                length = savePoint;
+        else{
+            int exponent = 0;
+            while (isdigit(text[length])){
+                exponent = exponent * 10 + text[length] - '0';
+                length++;
+            }
+            if (negative)
+                value /= qPow(10, exponent);
+            else
+                value *= qPow(10, exponent);
+        }
+    }
+    if (pValue)
+        *pValue = value;
+    return found ? length : 0;
+}
+
diff --git a/base/ReStringUtil.hpp b/base/ReStringUtil.hpp
new file mode 100644 (file)
index 0000000..831503c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RPLSTRING_HPP
+#define RPLSTRING_HPP
+
+class ReStringUtil {
+public:
+    static int countChar(const char* line, char cc);
+    static int count(const char* source, const char* item);
+    static const QByteArray& cutString(const QByteArray& source, int maxLength,
+                                       QByteArray& buffer, const char* appendix = "...");
+    static const char* fileSeparator();
+    static char fileSeparatorChar();
+    static QByteArray hexDump(uint8_t* data, int length, int bytesPerLine = 16);
+    static QByteArray hexDump(const void* data, int length, int bytesPerLine = 16) {
+        return hexDump((uint8_t*) data, length, bytesPerLine);
+    }
+    static QByteArray read(const char* file, bool removeLastNewline = true);
+    static QByteArray replaceNode(const char* source, const char* newNode);
+    static bool write(const char* file, const char* content = NULL,
+                      const char* mode = "w");
+    static QList<QByteArray> toArray(const char* source, const char* separator);
+    static QByteArray toCString(const char* source, int maxLength = -1);
+    static QByteArray toNumber(int value, const char* format = "%d");
+    static int lengthOfNumber(const char* text, bool skipTrailingSpaces = false);
+    static char findCsvSeparator(FILE* fp, char* buffer, size_t bufferSize);
+    static int lengthOfUInt64(const char* text, int radix, quint64* pValue);
+    static int lengthOfReal(const char* text, qreal* pValue);
+};
+
+#endif // RPLSTRING_HPP
diff --git a/base/ReTerminator.cpp b/base/ReTerminator.cpp
new file mode 100644 (file)
index 0000000..45f46d1
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+/** @file
+ * @brief Implements a thread stopper.
+ */
+/** @file
+ * @brief Definitions for a thread stopper.
+ */
+#include "base/rebase.hpp"
+
+enum {
+    LOC_CAUSE_TERMINATION_1 = LOC_FIRST_OF(LOC_TERMINATOR), // 10901
+};
+
+/**
+ * @class ReTerminator ReTerminator.hpp "rplcore/ReTerminator.hpp"
+ *
+ * @brief Implements a thread stopper.
+ *
+ * Allows to terminate a thread avoiding unfreeing resources, deadlocks etc.
+ *
+ * The application must create one instance of a <code>ReTerminator</code>.
+ * All threads get this instance and call them periodically if the application should stop.
+ * If yes they finish their work, free the resources and stop.
+ *
+ */
+
+/**
+ * @brief Constructor.
+ * @param logger    NULL or the logger. Used to protocol the termination
+ */
+ReTerminator::ReTerminator(ReLogger* logger) :
+    m_stop(false),
+    m_logger(logger) {
+}
+
+/**
+ * @brief Destructor.
+ */
+ReTerminator::~ReTerminator() {
+}
+
+/**
+ * @brief Defines the stop of all threads.
+ *
+ * @param reason    the reason of the termination. Will be logged (if a logger is defined)
+ * @param file      NULL or the file of the caller. Normally set with <code>__FILE__</code>
+ * @param lineNo    0 or the line number of the caller. Normally set with <code>__LINE__</code>
+ * @param level     log level
+ * @param location  0 or the location of the caller
+ */
+void ReTerminator::causeTermination(const char* reason, const char* file,
+                                     int lineNo, ReLoggerLevel level, int location) {
+    if(m_logger != NULL) {
+        QByteArray message(reason);
+        if(file != NULL) {
+            message.append(" [").append(file).append(lineNo).append("]");
+        }
+        m_logger->log(level, location == 0 ? LOC_CAUSE_TERMINATION_1 : location,
+                      message);
+    }
+    m_stop = true;
+}
+
+/**
+ * @brief Tests whether the thread should be stopped.
+ * @return  true: the thread should be stopped.<br>
+ *          false: otherwise
+ */
+bool ReTerminator::isStopped() const {
+    return m_stop;
+}
+
diff --git a/base/ReTerminator.hpp b/base/ReTerminator.hpp
new file mode 100644 (file)
index 0000000..e96ff27
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RPLTERMINATOR_HPP
+#define RPLTERMINATOR_HPP
+
+class ReTerminator {
+public:
+    ReTerminator(ReLogger* logger = NULL);
+    virtual ~ReTerminator();
+private:
+    // No copy constructor: no implementation!
+    ReTerminator(const ReTerminator& source);
+    // Prohibits assignment operator: no implementation!
+    ReTerminator& operator =(const ReTerminator& source);
+public:
+    void causeTermination(const char* reason, const char* file = NULL,
+                          int lineNo = 0, ReLoggerLevel level = LOG_ERROR, int location = 0);
+    bool isStopped() const;
+private:
+    bool m_stop;
+    ReLogger* m_logger;
+};
+
+#endif // RPLTERMINATOR_HPP
diff --git a/base/ReTest.cpp b/base/ReTest.cpp
new file mode 100644 (file)
index 0000000..1bccfe3
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+/** @file
+ * @brief A testing tool like JUnit.
+ */
+/** @file rplcore/rpltest.hpp
+ *
+ * @brief Definitions for a testing tool like JUnit.
+ */
+#include "base/rebase.hpp"
+
+/** @class ReTest rpltest.hpp "rplcore/repltest"
+ *
+ * @brief Implements an unit test base class similar JUnit for java.
+ *
+ * Example for usage:
+ *
+ * @see rplexample.cpp
+ */
+class ReTest;
+
+/**
+ * @brief Constructor.
+ *
+ * @param name
+ */
+ReTest::ReTest(const char* name) :
+    m_errors(0),
+    m_name(name),
+    m_logger(),
+    m_memoryAppender(1024),
+    m_memoryLogger()
+{
+    m_memoryAppender.setAutoDelete(false);
+    m_logger.buildStandardAppender(getTempDir("rpltest"));
+    log(QByteArray("Start of ") + m_name);
+    m_memoryLogger.addAppender(&m_memoryAppender);
+    try {
+        run();
+    } catch(ReException e) {
+        error("unexpected RplException: %s", e.getMessage().constData());
+    } catch(...){
+        error("unknown Exception");
+    }
+
+    if(m_errors > 0) {
+        error("Unit %s has %d error(s)", m_name.data(), m_errors);
+        // error() increments, we decrement:
+        m_errors--;
+    }
+}
+
+/**
+ * @brief Destructor.
+ */
+ReTest::~ReTest() {
+}
+
+/**
+ * Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(int expected, int current, const char* file,
+                           int lineNo) {
+    if(expected != current)
+        error("%s-%d: error: %d != %d / %x != %x)", file, lineNo, expected, current,
+              (unsigned int) expected, (unsigned int) current);
+    return expected == current;
+}
+
+/**
+ * Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(int64_t expected, int64_t current, const char* file,
+                           int lineNo) {
+    if(expected != current)
+        error("%s-%d: error: %lld != %lld / %llx != %llx)", file, lineNo,
+              expected, current, (quint64) expected, (quint64) current);
+    return expected == current;
+}
+
+
+/**
+ * Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(qreal expected, qreal current, const char* file,
+                           int lineNo) {
+    if(expected != current)
+        error("%s-%d: error: %d != %d / %x != %x)", file, lineNo, expected, current,
+              (unsigned int) expected, (unsigned int) current);
+    return expected == current;
+}
+
+/**
+ * @brief Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(const char* expected, const ReString& current,
+                           const char* file, int lineNo) {
+    bool equal = assertEquals(expected, current.toUtf8().constData(), file,
+                              lineNo);
+    return equal;
+}
+
+/**
+ * @brief Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(const ReString& expected, const ReString& current,
+                           const char* file, int lineNo) {
+    bool equal = assertEquals(expected.toUtf8().constData(),
+        current.toUtf8().constData(), file, lineNo);
+    return equal;
+}
+
+
+/**
+ * @brief Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(const char* expected, const char* current,
+                           const char* file, int lineNo) {
+    bool equal = strcmp(expected, current) == 0;
+    if(! equal) {
+        if(strchr(expected, '\n') != NULL || strchr(current, '\n')) {
+            QList<QByteArray> exp = ReStringUtil::toArray(expected, "\n");
+            QList<QByteArray> cur = ReStringUtil::toArray(current, "\n");
+            equal = assertEquals(exp, cur, file, lineNo);
+        } else {
+            int ix = 0;
+            while(expected[ix] == current[ix] && expected[ix] != '\0')
+                ix++;
+            char pointer[12+1];
+            char* ptr = pointer;
+            int maxIx = ix > 10 ? 10 : ix;
+            for(int ii = 0; ii < maxIx - 1; ii++)
+                *ptr++ = '-';
+            *ptr++ = '^';
+            *ptr = '\0';
+            if(ix < 10)
+                error("%s-%d: error: diff at index %d\n%s\n%s\n%s",
+                      file, lineNo, ix, expected, current, pointer);
+            else
+                error("%s-%d: error: diff at index %d\n%s\n...%s\n...%s\n%s",
+                      file, lineNo, ix, current,
+                      expected + ix - 10 + 3,
+                      current + ix - 10 + 3,
+                      pointer);
+        }
+    }
+    return equal;
+}
+
+/**
+ * @brief Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(const QList<QByteArray>& expected,
+                           const QList<QByteArray>& current, const char* file, int lineNo) {
+    int nMax = expected.size();
+    bool rc = true;
+    if(current.size() < nMax)
+        nMax = current.size();
+    for(int ix = 0; ix < nMax; ix++) {
+        if(expected.at(ix) != current.at(ix)) {
+            error("%s-%d: difference in line %d", file, lineNo, ix+1);
+            m_errors--;
+            assertEquals(expected.at(ix).constData(), current.at(ix).constData(),
+                         file, lineNo);
+            rc = false;
+            break;
+        }
+    }
+    if(rc) {
+        if(expected.size() > nMax)
+            error("%s-%d: less lines than expected (%d):\n%s",
+                  file, lineNo, nMax, expected.at(nMax).constData());
+        else if(expected.size() < nMax)
+            error("%s-%d: more lines than expected (%d):\n%s",
+                  file, lineNo, nMax, current.at(nMax).constData());
+    }
+    return rc;
+}
+/**
+ * @brief Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(const QByteArray& expected,
+                           const QByteArray& current, const char* file, int lineNo) {
+    return assertEquals(expected.data(), current.data(), file, lineNo);
+}
+
+/**
+ * @brief Tests the equality of two values.
+ *
+ * Differences will be logged.
+ *
+ * @param expected      the expected value
+ * @param current       the current value
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: equal
+ */
+bool ReTest::assertEquals(const char* expected, const QByteArray& current,
+                           const char* file, int lineNo) {
+    return assertEquals(expected, current.constData(), file, lineNo);
+}
+
+/**
+ * @brief Tests whether a value is true.
+ *
+ * A value of false will be logged.
+ *
+ * @param condition     value to test
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              <code>condition</code>
+ */
+bool ReTest::assertTrue(bool condition, const char* file, int lineNo) {
+    if(! condition)
+        error("%s-%d: not TRUE", file, lineNo);
+    return condition;
+}
+
+/**
+ * @brief Tests whether a value is false.
+ *
+ * A value of true will be logged.
+ *
+ * @param condition     value to test
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              <code>! condition</code>
+ */
+bool ReTest::assertFalse(bool condition, const char* file, int lineNo) {
+    if(condition)
+        error("%s-%d: not FALSE", file, lineNo);
+    return ! condition;
+}
+
+/**
+ * @brief Tests whether a value is NULL.
+ *
+ * A value of not NULL will be logged.
+ *
+ * @param ptr           value to test
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: ptr is NULL
+ */
+bool ReTest::assertNull(const void* ptr, const char* file, int lineNo) {
+    if(ptr != NULL)
+        error("%s-%d: not NULL", file, lineNo);
+    return ptr == NULL;
+}
+
+/**
+ * @brief Tests whether a value is not NULL.
+ *
+ * A value of NULL will be logged.
+ *
+ * @param ptr           value to test
+ * @param file          the file containing the test
+ * @param lineNo        the line number containing the test
+ * @return              true: ptr is not NULL
+ */
+bool ReTest::assertNotNull(const void* ptr, const char* file, int lineNo) {
+    if(ptr == NULL)
+        error("%s-%d: is NULL", file, lineNo);
+    return ptr != NULL;
+}
+
+/**
+ * @brief Compares two files line by line.
+ *
+ * @param expected  the file with the expected content
+ * @param current   the file with the current content
+ * @param file      the source file (point of the comparison)
+ * @param lineNo    the source position (point of the comparison)
+ * @return          true: the files are equal<br>
+ *                  false: otherwise
+ */
+bool ReTest::assertEqualFiles(const char* expected, const char* current,
+       const char* file, int lineNo)
+{
+    bool rc = false;
+    QByteArray expectedContent = ReStringUtil::read(expected, true);
+    QByteArray currentContent = ReStringUtil::read(current, true);
+    if (expectedContent.isEmpty()){
+        char buffer[512];
+        qsnprintf(buffer, sizeof buffer, "%s has no content. Does it exist?",
+                 expected);
+        error(buffer);
+    } else if (currentContent.isEmpty()){
+        char buffer[512];
+        qsnprintf(buffer, sizeof buffer, "%s has no content. Does it exist?",
+                 current);
+        error(buffer);
+    } else {
+        QList<QByteArray> expLines = expectedContent.split('\n');
+        QList<QByteArray> curLines = currentContent.split('\n');
+        rc = assertEquals(expLines, curLines, file, lineNo);
+    }
+    return rc;
+}
+
+/**
+ * @brief Writes an info.
+ *
+ * @param message   message to show
+ * @return          true (for chaining)
+ */
+bool ReTest::log(const char* message) {
+    m_logger.log(LOG_INFO, 0, message);
+    return true;
+}
+
+
+/**
+ * @brief Writes an error.
+ *
+ * @param format    message to show. With placeholders like <code>std::printf()</code>
+ * @param ...       the values for the placeholders in <code>format</code>
+ * @return          false (for chaining)
+ */
+bool ReTest::error(const char* format, ...) {
+    m_errors++;
+    va_list ap;
+    va_start(ap, format);
+    m_logger.log(LOG_ERROR, 0, format, ap);
+    va_end(ap);
+    return false;
+}
+
+/**
+ * @brief Tests whether the m_memoryLogger has a message containing a given pattern.
+ *
+ * @param pattern   regular expression to search
+ * @return          true: pattern has been found<br>
+ *                  false: otherwise
+ */
+bool ReTest::logContains(const char* pattern)
+{
+    const QList<QByteArray>& lines = m_memoryAppender.getLines();
+    QRegularExpression rexpr(pattern);
+    bool rc = false;
+    QRegularExpressionMatch match;
+    for (int ii = 0; ii < lines.size(); ii++){
+        const QByteArray& line = lines.at(ii);
+        match = rexpr.match(line);
+        if (match.hasMatch()){
+            rc = true;
+            break;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns the name of a directory in the temp dir.
+ *
+ * If the named directory does not exist it will be created.
+ *
+ * @param node          NULL or the node (name without path)
+ * @param parent        NULL or a node of the parent
+ * @param withSeparator true: the result ends with slash/backslash
+ * @return              the name of an existing directory
+ */
+QByteArray ReTest::getTempDir(const char* node, const char* parent,
+                               bool withSeparator) {
+    QByteArray temp("c:\\temp");
+    struct stat info;
+    const char* ptr;
+    if((ptr = getenv("TMP")) != NULL)
+        temp = ptr;
+    else if((ptr = getenv("TEMP")) != NULL)
+        temp = ptr;
+    else if(stat("/tmp", &info) == 0)
+        temp = "/tmp";
+    char sep = m_separator = temp.indexOf('/') >= 0 ? '/' : '\\';
+    if(temp.at(temp.length() - 1) != sep)
+        temp += sep;
+    if(parent != NULL) {
+        temp += parent;
+        if(stat(temp.constData(), &info) != 0)
+            mkdir(temp.constData(), (-1));
+        temp += sep;
+    }
+    if(node != NULL) {
+        temp += node;
+        temp += sep;
+        if(stat(temp.data(), &info) != 0)
+            mkdir(temp.data(), -1);
+    }
+    if(! withSeparator)
+        temp.resize(temp.length() - 1);
+    return temp;
+}
+
+/**
+ * @brief Returns a name of a file in a temporary directory.
+ *
+ * @param node              the file's name without path
+ * @param parent            NULL or the name of a subdirectory the file will be inside
+ * @param deleteIfExists    true: if the file exists it will be removed
+ * @return                  the full name of a temporary file
+ */
+QByteArray ReTest::getTempFile(const char* node, const char* parent,
+                                bool deleteIfExists) {
+    QByteArray dir = getTempDir(parent);
+    QByteArray rc = dir;
+    if (! rc.endsWith(m_separator))
+        rc += m_separator;
+    rc += node;
+    struct stat info;
+    if(deleteIfExists && stat(rc.constData(), &info) == 0)
+        unlink(rc.constData());
+    return rc;
+}
diff --git a/base/ReTest.hpp b/base/ReTest.hpp
new file mode 100644 (file)
index 0000000..ec04340
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RETEST_HPP
+#define RETEST_HPP
+
+// the sources generated from QT include this file directly:
+class ReTest {
+public:
+    ReTest(const char* name);
+    virtual ~ReTest();
+private:
+    // No copy constructor: no implementation!
+    ReTest(const ReTest& source);
+    // Prohibits assignment operator: no implementation!
+    ReTest& operator =(const ReTest& source);
+public:
+    bool assertEquals(int expected, int current, const char* file, int lineNo);
+    bool assertEquals(int64_t expected, int64_t current, const char* file, int lineNo);
+    bool assertEquals(qreal expected, qreal current, const char* file, int lineNo);
+    bool assertEquals(const char* expected, const ReString& current,
+                      const char* file, int lineNo);
+    bool assertEquals(const ReString& expected, const ReString& current,
+                      const char* file, int lineNo);
+    bool assertEquals(const char* expected, const char* current,
+                      const char* file, int lineNo);
+    bool assertEquals(const QByteArray& expected, const QByteArray& current,
+                      const char* file, int lineNo);
+    bool assertEquals(const char* expected, const QByteArray& current,
+                      const char* file, int lineNo);
+    bool assertEquals(const QList<QByteArray>& expected,
+                      const QList<QByteArray>& current, const char* file, int lineNo);
+    bool assertTrue(bool condition, const char* file, int lineNo);
+    bool assertFalse(bool condition, const char* file, int lineNo);
+    bool assertNull(const void* ptr, const char* file, int lineNo);
+    bool assertNotNull(const void* ptr, const char* file, int lineNo);
+    bool assertEqualFiles(const char* expected, const char* current,
+                          const char* file, int lineNo);
+    bool log(const char* message);
+    bool error(const char* message, ...);
+    QByteArray getTempDir(const char* node, const char* parent = NULL,
+                          bool withSeparator = true);
+    QByteArray getTempFile(const char* node, const char* parent = NULL,
+                           bool deleteIfExists = true);
+    bool logContains(const char* pattern);
+    virtual void run(void) = 0;
+
+protected:
+    int m_errors;
+    QByteArray m_name;
+    ReLogger m_logger;
+    // for testing of logging code:
+    ReMemoryAppender m_memoryAppender;
+    ReLogger m_memoryLogger;
+    char m_separator;
+};
+#define checkEqu(expected, current) assertEquals(expected, current, __FILE__, __LINE__)
+#define checkT(current) assertTrue(current, __FILE__, __LINE__)
+#define checkF(current) assertFalse(current, __FILE__, __LINE__)
+#define checkN(current) assertNull(current, __FILE__, __LINE__)
+#define checkNN(current) assertNotNull(current, __FILE__, __LINE__)
+#define checkFiles(expected, current) assertEqualFiles(expected, current, __FILE__, __LINE__)
+#endif // RETEST_HPP
diff --git a/base/ReWriter.cpp b/base/ReWriter.cpp
new file mode 100644 (file)
index 0000000..ecfb73d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief A writer to an output media.
+ *
+ * Implementation of the abstract base class <code>ReWriter</code> and
+ * the concrete derivation <code>ReFileWriter</code>.
+ */
+/** @file rplcore/rplwriter.hpp
+ *
+ * @brief Definitions for a writer to an output media.
+ */
+#include "base/rebase.hpp"
+
+const char* ReWriter::m_tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+int ReWriter::m_maxIndention = strlen(ReWriter::m_tabs);
+
+/** @class ReWriter ReWriter.hpp "rplcore/ReWriter.hpp"
+ *
+ * @brief Implements an abstract base class for producing text lines.
+ *
+ */
+
+/**
+ * @brief Destructor.
+ *
+ * Closes the output medium.
+ * Ensures that the destructors of the derived classes are virtual.
+ */
+ReWriter::~ReWriter()
+{
+    close();
+}
+
+/**
+ * @brief Closes the output medium.
+ *
+ * This method does nothing, but overriding methods should free the resources.
+ *
+ * @note The method must be designed so that it can be called multiple times.
+ */
+void ReWriter::close()
+{
+}
+/**
+ * @brief Puts a given count of "\t" to the output medium.
+ *
+ * @param indent    indention level, number of "\t"
+ */
+void ReWriter::indent(int indent)
+{
+    if (indent > m_maxIndention)
+        indent = m_maxIndention;
+    format("%.*s", indent, m_tabs);
+}
+
+/**
+ * @brief Formats a string and write it to the output medium.
+ *
+ * @param format    format string with placeholders like <code>sprintf()</code>
+ * @param ...       variable arguments, values for the placeholders
+ */
+void ReWriter::format(const char* format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    write(ap, format);
+    va_end(ap);
+}
+/**
+ * @brief Formats a line and write it to the output medium.
+ *
+ * @param format    format string with placeholders like <code>sprintf()</code>
+ * @param ...       variable arguments, values for the placeholders
+ */
+void ReWriter::formatLine(const char* format, ...)
+{
+    char buffer[64000];
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    writeLine(buffer);
+}
+
+/**
+ * @brief Formats a message and writes it to the output medium.
+ *
+ * @param ap        variable argument list (like in <code>vsprintf</code>)
+ * @param format    format string with placeholders
+ */
+void ReWriter::write(va_list ap, const char* format)
+{
+    char buffer[64000];
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    write(buffer);
+}
+
+/**
+ * @brief Writes a line with indention to the output medium.
+ *
+ * @param indent    indention level. Indention is limited to 20
+ * @param line      the line to write
+ */
+void ReWriter::writeIndented(int indent, const char* line)
+{
+    ReWriter::indent(indent);
+    writeLine(line);
+}
+
+/**
+ * @brief Writes a line with indention to the output medium.
+ *
+ * @param indent    indention level. Indention is limited to 20
+ * @param format    format string with placeholders like <code>sprintf</code>
+ * @param ...       the values for the placeholders (variable arguments)
+ */
+void ReWriter::formatIndented(int indent, const char* format, ...)
+{
+    ReWriter::indent(indent);
+
+    char buffer[64000];
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    writeLine(buffer);
+}
+
+/** @class ReWriter rplwriter.hpp "rplcore/rplwriter.hpp"
+ *
+ * @brief Implements a class which writes lines into a file.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param filename          the file's name
+ * @param mode              write mode, "w" for write or "a" for append
+ * @param additionalStream  if not NULL the content will be written to this
+ *                          stream too. Normal usage: <code>stdout</code> or
+ *                          <code>stderr</code>
+ * @param eoln              line end: "\n" or "\r\n"
+ */
+ReFileWriter::ReFileWriter(const char* filename, const char* mode,
+                             FILE* additionalStream, const char* eoln) :
+    m_fp(fopen(filename, mode)),
+    m_name(filename),
+    m_eoln(eoln),
+    m_additionalStream(additionalStream)
+{
+}
+
+/**
+ * @brief Writes a string to the file.
+ * @param message   the string to write
+ */
+void ReFileWriter::write(const char* message)
+{
+    if (m_fp != NULL)
+        fputs(message, m_fp);
+    if (m_additionalStream != NULL)
+        fputs(message, m_additionalStream);
+}
+
+/**
+ * @brief Writes a line to the file.
+ * @param line   the line to write. If NULL an empty line will be written
+ */
+void ReFileWriter::writeLine(const char* line)
+{
+    if (m_fp != NULL){
+        if (line != NULL)
+            fputs(line, m_fp);
+        fputs(m_eoln, m_fp);
+    }
+    if (m_additionalStream != NULL){
+        if (line != NULL)
+            fputs(line, m_additionalStream);
+        fputc('\n', m_additionalStream);
+    }
+}
+
+/**
+ * @brief Closes the output file.
+ */
+void ReFileWriter::close()
+{
+    if (m_fp != NULL){
+        fclose(m_fp);
+        m_fp = NULL;
+    }
+    m_additionalStream = NULL;
+}
diff --git a/base/ReWriter.hpp b/base/ReWriter.hpp
new file mode 100644 (file)
index 0000000..a53120b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef REWRITER_HPP
+#define REWRITER_HPP
+
+class ReWriter
+{
+public:
+    virtual ~ReWriter();
+public:
+    /**
+     * @brief Writes a text to the output medium.
+     *
+     * @param message   the message
+     */
+    virtual void write(const char* message) = 0;
+    /**
+     * @brief Writes a text line to the output medium.
+     *
+     * @param line   the text line. If NULL an empty line will be written
+     */
+    virtual void writeLine(const char* line = NULL) = 0;
+    virtual void close();
+public:
+    void indent(int indent);
+    void format(const char* format, ...);
+    void formatLine(const char* format, ...);
+    void write(va_list ap, const char* format);
+    void writeIndented(int indent, const char* line);
+    void formatIndented(int indent, const char* format, ...);
+protected:
+    static const char* m_tabs;
+    static int m_maxIndention;
+};
+
+class ReFileWriter : public ReWriter
+{
+public:
+    ReFileWriter(const char* filename, const char* mode = "w",
+                  FILE* additionalStream = NULL, const char* eoln =  "\n");
+public:
+    virtual void write(const char* line);
+    virtual void writeLine(const char* line = NULL);
+    virtual void close();
+protected:
+    FILE* m_fp;
+    QByteArray m_name;
+    QByteArray m_eoln;
+    FILE* m_additionalStream;
+};
+
+#endif // REWRITER_HPP
diff --git a/base/rebase.hpp b/base/rebase.hpp
new file mode 100644 (file)
index 0000000..a415c98
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RECORE_HPP
+#define RECORE_HPP
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <QAbstractSocket>
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QThread>
+#include <QIODevice>
+#include <QTextStream>
+#include <QHash>
+#include <QVector>
+#include <QDataStream>
+#include <QMutex>
+#include <QRegularExpression>
+#include <QtCore/qmath.h>
+
+typedef unsigned char uint8_t;
+//typedef qint64 int64_t;
+typedef quint64 uint64_t;
+typedef qint32 int32_t;
+typedef quint32 uint32_t;
+typedef qreal real_t;
+typedef QString ReString;
+#define RPL_UNUSED(x) (void)(x)
+
+#include "remodules.hpp"
+#include "base/ReByteStorage.hpp"
+#include "base/ReCharPtrMap.hpp"
+#include "base/ReWriter.hpp"
+#include "base/ReLogger.hpp"
+#include "base/ReException.hpp"
+#include "base/ReContainer.hpp"
+#include "base/ReStringUtil.hpp"
+#include "base/ReQtring.hpp"
+#include "base/ReConfigurator.hpp"
+#include "base/ReConfig.hpp"
+#include "base/ReTerminator.hpp"
+#include "base/ReTest.hpp"
+
+#endif // RECORE_HPP
diff --git a/base/testrplexample.cpp b/base/testrplexample.cpp
new file mode 100644 (file)
index 0000000..0c89591
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+include "project.hpp"
+
+#include "base/base.hpp"
+// Code to test:
+int add(int a, int b) {
+    return a+b;
+}
+QByteArray concat(const char* a, const char* b) {
+    return QByteArray(a) + " " + b;
+}
+const char* firstDot(const char* s) {
+    return strchr(s, '.');
+}
+/**
+ * @brief Example for usage of the class ReTest.
+ */
+class TestRplExample : public ReTest {
+public:
+    TestRplExample() : ReTest("RplExample") {}
+
+public:
+    void testInt() {
+        log("testing add...");
+        // compare 2 integers:
+        checkEqu(2, add(1, 1));
+    }
+    void testString() {
+        // compare 2 strings:
+        checkEqu("Be good", concat("Be", "good"));
+        // test for not NULL:
+        checkN(firstDot("Hi."));
+        // test for  NULL:
+        checkNN(firstDot("Hi"));
+    }
+    virtual void doIt() {
+        testInt();
+        testString();
+    }
+};
+void testRplExample() {
+    TestRplExample test;
+    test.run();
+}
diff --git a/cunit/cuReConfig.cpp b/cunit/cuReConfig.cpp
new file mode 100644 (file)
index 0000000..76fa172
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * cuReConfig.cpp
+ *
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+
+#include "base/rebase.hpp"
+/**
+ * @brief Unit test of ReConfig.
+ */
+class TestReConfig: public ReTest {
+public:
+    TestReConfig() :
+        ReTest("ReConfig") {
+    }
+
+public:
+    void testBasic() {
+        QByteArray fn = getTempFile("test.data", "config");
+        ReStringUtil::write(fn, "#comment\na=1\nb.1==x\n#=\nB=zzz");
+        ReConfig config(fn.constData());
+        checkEqu(3, config.size());
+        checkEqu("1", config["a"]);
+        checkEqu("=x", config["b.1"]);
+        checkEqu("zzz", config["B"]);
+    }
+    void testAsX() {
+        QByteArray fn = getTempFile("test.data", "config");
+        ReStringUtil::write(fn, "i=123\nb=1\nb2=true\nb3=yes\ns=abc");
+        ReConfig config(fn.constData());
+        checkEqu(5, config.size());
+        checkEqu(123, config.asInt("i", -1));
+        checkEqu(-1, config.asInt("I", -1));
+        checkT(config.asBool("b", false));
+        checkT(config.asBool("b2", false));
+        checkT(config.asBool("b3", false));
+        checkT(config.asBool("-", true));
+        checkF(config.asBool("-", false));
+        checkEqu("abc", config.asString("s", "x"));
+        checkEqu("x", config.asString("S", "x"));
+    }
+
+    virtual void run() {
+        testAsX();
+        testBasic();
+
+    }
+};
+
+void testReConfig() {
+    TestReConfig test;
+}
+
+
+
+
diff --git a/cunit/cuReContainer.cpp b/cunit/cuReContainer.cpp
new file mode 100644 (file)
index 0000000..8b3b38e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * cuReContainer.cpp
+ *
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#include "base/rebase.hpp"
+/**
+ * @brief Unit test for <code>ReContainer</code>
+ */
+class TestRplContainer : public ReTest {
+public:
+    TestRplContainer() : ReTest("RplContainer") {}
+
+public:
+    void testBasic() {
+        ReContainer container(256);
+        //  Rpl&1 09 36[2]cis:!7b Nirwana &lt;0&gt; Y -ab34 A long string with an trailing '0' &lt;0&gt<br>
+        container.startBag();
+        container.addChar('!');
+        container.addInt(123);
+        container.addString("Nirwana");
+        container.startBag();
+        container.addChar('Y');
+        container.addInt(-0xab34);
+        container.addString("A long string with an trailing '0'");
+
+        QByteArray data = container.getData();
+
+        ReContainer container2(256);
+        container2.fill(data);
+        checkEqu(2, container2.getCountBags());
+        checkEqu('!', container2.nextChar());
+        checkEqu(123, container2.nextInt());
+        checkEqu("Nirwana", container2.nextString());
+        container2.nextBag();
+        checkEqu('Y', container2.nextChar());
+        checkEqu(-0xab34, container2.nextInt());
+        checkEqu("A long string with an trailing '0'", container2.nextString());
+
+        log(("Example: " + data).constData());
+    }
+
+    virtual void run() {
+        testBasic();
+    }
+};
+
+void testRplContainer() {
+    TestRplContainer test;
+}
+
+
+
+
diff --git a/cunit/cuReEnigma.cpp b/cunit/cuReEnigma.cpp
new file mode 100644 (file)
index 0000000..6688df5
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#include "base/rebase.hpp"
+/**
+ * @brief Unit test for <code>ReEnigma</code>.
+ */
+class TestReEnigma : public ReTest {
+public:
+    TestReEnigma() : ReTest("ReEnigma") {}
+
+public:
+    void testOneCharset(const char* value, const char* charSet,
+                        const char* expected) {
+        ReEnigma enigma;
+        enigma.addByteSecret(QByteArray("Geheim"));
+        enigma.setSeed(0);
+        QByteArray encoded = value;
+        QByteArray booster;
+        enigma.encode(encoded.data(), encoded.length(), charSet, booster);
+        //printString(encoded.constData());
+        QByteArray decoded = encoded;
+        enigma.setSeed(0);
+        enigma.decode(decoded.data(), decoded.length(), charSet, booster);
+        checkEqu(value, decoded.constData());
+        checkEqu(expected, encoded);
+    }
+
+    void printCharSets() {
+        QByteArray value;
+        value.reserve(256);
+        unsigned char cc;
+        for(cc = ' '; cc <= 127; cc++) {
+            if(cc == '"' || cc == '\\')
+                value.append('\\');
+            value.append(cc);
+        }
+        printf("%s\n", value.constData());
+        value.resize(0);
+        for(cc = 128; cc >= 128; cc++) {
+            char buf[10];
+            if(cc % 32 == 0)
+                value.append("\n");
+            sprintf(buf, "\\x%02x", cc);
+            value.append(buf);
+        }
+        printf("%s\n", value.constData());
+    }
+    void printString(const char* value) {
+        QByteArray v;
+        unsigned char cc;
+        while((cc = (unsigned char) *value++) != 0) {
+            if(cc == '\\' || cc == '"') {
+                v.append('\\');
+                v.append(cc);
+            } else if(cc >= 127) {
+                char buffer[10];
+                sprintf(buffer, "\\x%02x", cc);
+                v.append(buffer);
+            } else {
+                v.append(cc);
+            }
+        }
+        printf("%s\n", v.constData());
+    }
+    void testOneBytes(const char* bytes) {
+        ReEnigma enigma;
+        enigma.addByteSecret("Hello World");
+        enigma.setSeed(0x1234);
+
+        QByteArray encoded(bytes);
+        enigma.change(encoded);
+
+        enigma.setSeed(0x1234);
+        QByteArray decoded(encoded);
+        enigma.change(decoded);
+        checkEqu(bytes, decoded);
+    }
+
+    void testBytes() {
+        testOneBytes("abcdefg");
+        testOneBytes("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    }
+
+    void testCharSet() {
+        //testOneCharset("&()[]{}Weiß der Geier/Kuckuck?", ReEnigma::SET_32_255, "2Kc\x9a\xfeQ\xd7\xa84sx)*\xfb\xd2z\xf4\"W\xb0\xee\xb0\xd1\x84\xace\xf8_u*T");
+        testOneCharset("\\Weiß der Geier/Kuckuck?", ReEnigma::SET_32_127,
+                       "(Z?hßaZ_#/QZ+Oi|SI^=<,)A");
+        testOneCharset("01234567890abcdef", ReEnigma::SET_HEXDIGITS,
+                       "c4c25b08735c53a63");
+        testOneCharset("data$1%3.^~", ReEnigma::SET_FILENAME, "^voazo-n%$b");
+        testOneCharset("Weiß der Geier!", ReEnigma::SET_ALPHANUM, "weyß BCk 19NoO!");
+        testOneCharset("12345678901234567890", ReEnigma::SET_DECIMALS,
+                       "97394833084815683977");
+        testOneCharset("000000000000000000000000000", ReEnigma::SET_DECIMALS,
+                       "850592651836811261879625929");
+    }
+
+    virtual void doIt() {
+        testBytes();
+        testCharSet();
+    }
+};
+
+void testReEnigma() {
+    TestReEnigma test;
+    test.run();
+}
diff --git a/cunit/main.cpp b/cunit/main.cpp
new file mode 100644 (file)
index 0000000..56bafc5
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+#include "../rplcore/rplcore.hpp"
+#include "../rplmath/rplmath.hpp"
+
+#include <QCoreApplication>
+
+void testCore(){
+    extern void testReString();
+    testReString();
+
+    extern void testReCharPtrMap();
+    testReCharPtrMap();
+
+    extern void testRplWriter();
+    testRplWriter();
+
+    extern void testRplByteStorage();
+    testRplByteStorage();
+
+    extern void testRplQString();
+    testRplQString();
+
+    extern void testReString();
+    testReString();
+
+    extern void testRplException();
+    testRplException();
+}
+
+void testExpr(){
+    extern void testRplMFParser();
+    testRplMFParser();
+
+    extern void testRplBenchmark();
+    //testRplBenchmark();
+
+    extern void testReVM();
+    testReVM();
+
+    extern void testReSource();
+    testReSource();
+
+    extern void testRplLexer();
+    testRplLexer();
+
+    extern void testRplMFParser();
+    testRplMFParser();
+
+    extern void testReASTree();
+    testReASTree();
+
+    extern void testReVM();
+    testReVM();
+
+}
+
+void testStandard(){
+    testExpr();
+    testCore();
+    extern void testRplMatrix();
+    testRplMatrix();
+
+}
+
+void labor(){
+}
+
+int main(int argc, char *argv[])
+{
+    //labor();
+    if (argc > 1)
+        printf("not used: %s\n", argv[1]);
+
+    testStandard();
+
+}
diff --git a/cunit/rplastree_test.cpp b/cunit/rplastree_test.cpp
new file mode 100644 (file)
index 0000000..2f03043
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Unit test of the abstract syntax tree.
+ */
+
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestReASTree : public ReTest{
+private:
+    ReSource m_source;
+    ReStringReader m_reader;
+    ReStringSourceUnit m_unit;
+    ReASTree m_tree;
+public:
+    TestReASTree() :
+        ReTest("ReASTree"),
+        m_source(),
+        m_reader(m_source),
+        m_unit("<main>", "", &m_reader),
+        m_tree()
+    {}
+public:
+    void testReASException() {
+        try{
+            m_reader.addSource("<main>", "12");
+            m_source.addReader(&m_reader);
+            m_source.addSourceUnit(m_reader.currentSourceUnit());
+            const ReSourcePosition* pos = m_source.newPosition(2);
+            throw ReASException(pos, "simple string: %s", "Hi");
+            checkF(true);
+        } catch (ReASException exc){
+            checkEqu("<main>:0:2: simple string: Hi", exc.getMessage().constData());
+        }
+    }
+    void testReASVariant(){
+        ReASVariant val1;
+        val1.setFloat(2.5E-2);
+        checkEqu(2.5E-2, val1.asFloat());
+        ReASVariant val2(val1);
+        checkEqu(2.5E-2, val2.asFloat());
+
+        val1.setInt(4321);
+        checkEqu(4321, val1.asInt());
+        val2 = val1;
+        checkEqu(4321, val2.asInt());
+
+        val1.setBool(false);
+        checkF(val1.asBool());
+        val2 = val1;
+        checkF(val2.asBool());
+
+        val1.setBool(true);
+        checkT(val1.asBool());
+        val2 = val1;
+        checkT(val2.asBool());
+
+        val1.setString("High noon!");
+        checkEqu("High noon!", *val1.asString());
+        val2 = val1;
+        val1.setString("Bye");
+        checkEqu("High noon!", *val2.asString());
+        ReASVariant val3(val1);
+        checkEqu("Bye", *val3.asString());
+    }
+    void testReASConstant(){
+        ReASConstant constant;
+        //constant.value().setString("Jonny");
+        ReASVariant value;
+        //constant.calc(value);
+        //checkEqu("Jonny", *value.asString());
+    }
+    void testReASNamedValue(){
+        ReASNamedValue value(NULL, m_tree.symbolSpaces()[0], "gugo",
+                ReASNamedValue::A_GLOBAL);
+        checkEqu("gugo", value.name());
+    }
+    virtual void doIt() {
+        testReASNamedValue();
+        testReASConstant();
+        testReASException();
+        testReASVariant();
+    }
+};
+void testReASTree() {
+    TestReASTree test;
+    test.run();
+}
+
+
+
+
+
+
diff --git a/cunit/rplbench.cpp b/cunit/rplbench.cpp
new file mode 100644 (file)
index 0000000..74dc740
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Unit test of the abstract syntax tree.
+ */
+
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestRplBenchmark : public ReTest{
+private:
+    const char* m_filename;
+    ReSource m_source;
+    ReFileReader m_reader;
+    ReASTree m_tree;
+public:
+    TestRplBenchmark() :
+        ReTest("RplBenchmark"),
+        m_filename("/home/ws/qt/rplqt/bench/mfbench.mf"),
+        m_source(),
+        m_reader(m_source),
+        m_tree()
+    {
+        m_source.addReader(&m_reader);
+        m_reader.addSource(m_filename);
+    }
+public:
+    void benchmark() {
+        time_t start = time(NULL);
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        time_t end = time(NULL);
+        printf("compilation: %d sec\n", int(end - start));
+    }
+    virtual void doIt() {
+        try{
+            ReFileSourceUnit* unit = dynamic_cast<ReFileSourceUnit*>
+                    (m_reader.currentSourceUnit());
+            if (unit != NULL && ! unit->isOpen())
+                throw ReException("file not found: %s", m_filename);
+            benchmark();
+        } catch(ReException ex){
+            printf("%s\n", ex.getMessage().constData());
+        }
+    }
+};
+void testRplBenchmark() {
+    TestRplBenchmark test;
+    test.run();
+}
+
+
+
diff --git a/cunit/rplbytestorage_test.cpp b/cunit/rplbytestorage_test.cpp
new file mode 100644 (file)
index 0000000..52437d2
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+/** @file
+ * @brief Unit test of the byte and C string storage.
+ */
+
+#include "../base/rebase.hpp"
+#include "../base/ReTest.hpp"
+
+class TestRplByteStorage : public ReTest{
+public:
+    TestRplByteStorage() :
+        ReTest("RplByteStorage")
+    {}
+private:
+    void testChars(){
+        ReByteStorage store(100);
+        char* s1 = store.allocateChars(4);
+        memcpy((void*) s1, "123", 4);
+        const char* s2 = store.allocateChars("abc");
+        const char* s3 = store.allocateChars("defghij", 3);
+        checkEqu(s1, "123");
+        checkEqu(s2, "abc");
+        checkEqu(s3, "def");
+        const char* ptr = s1 + 4;
+        checkT(ptr == s2);
+        ptr += 4;
+        checkT(ptr == s3);
+    }
+
+    void testBytes(){
+        ReByteStorage store(100);
+        uint8_t* s1 = store.allocateBytes(4);
+        memcpy((void*) s1, "1234", 4);
+        uint8_t* s2 = store.allocateBytes((void*) "abcd", 4);
+        uint8_t* s3 = store.allocateBytes((void*) "efghij", 4);
+        uint8_t* s4 = store.allocateZeros(4);
+
+        checkEqu("1234abcdefgh", (const char*) s1);
+        uint8_t* ptr = s1 + 4;
+        checkT(ptr == s2);
+        ptr += 4;
+        checkT(ptr == s3);
+        ptr += 4;
+        checkT(ptr == s4);
+        for (int ii = 0; ii < 4; ii++)
+            checkEqu(0, (int) s4[ii]);
+    }
+    void testBufferChange(){
+        ReByteStorage store(10);
+        char buffer[2];
+        buffer[1] = '\0';
+        for (int ii = 0; ii < 10000; ii++){
+            buffer[1] = 'A' + ii % 26;
+            store.allocateBytes(buffer, 1);
+        }
+        int a = 1;
+    }
+
+public:
+    virtual void doIt() {
+        testBufferChange();
+        testChars();
+        testBytes();
+    }
+};
+void testRplByteStorage() {
+    TestRplByteStorage test;
+    test.run();
+}
+
+
diff --git a/cunit/rplcharptrmap_test.cpp b/cunit/rplcharptrmap_test.cpp
new file mode 100644 (file)
index 0000000..8ad1d78
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+#include "base/rebase.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestReCharPtrMap : public ReTest{
+public:
+    TestReCharPtrMap() :
+        ReTest("ReCharPtrMap")
+    {
+    }
+protected:
+    void testBasic(){
+        ReCharPtrMap<const char*> map;
+        map["x"] = "x1";
+        checkT(map.contains("x"));
+        checkF(map.contains("y"));
+        checkEqu("x1", map["x"]);
+    }
+
+    virtual void doIt(void) {
+        testBasic();
+    }
+};
+void testReCharPtrMap() {
+    TestReCharPtrMap test;
+    test.run();
+}
diff --git a/cunit/rplexception_test.cpp b/cunit/rplexception_test.cpp
new file mode 100644 (file)
index 0000000..57293cb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+#include "base/rebase.hpp"
+#include "rplcore/rpltest.hpp"
+/** @file
+ * @brief Unit test of the basic exceptions.
+ */
+
+class TestRplException : public ReTest{
+public:
+    TestRplException() : ReTest("RplException") {}
+
+public:
+    void testBasic() {
+        try{
+            throw ReException("simple");
+            checkF(true);
+        } catch (ReException exc){
+            checkEqu("simple", exc.getMessage().constData());
+        }
+        try{
+            throw ReException("String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (ReException exc){
+            checkEqu("String: Hi and int -333", exc.getMessage().constData());
+        }
+        try{
+            throw ReException(LOG_INFO, 1234, &m_memoryLogger,
+                    "String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (ReException exc){
+            checkT(logContains("^ .*\\(1234\\): String: Hi and int -333"));
+        }
+        log("ok");
+    }
+    virtual void doIt() {
+        testBasic();
+    }
+};
+void testRplException() {
+    TestRplException test;
+    test.run();
+}
+
+
+
diff --git a/cunit/rpllexer_test.cpp b/cunit/rpllexer_test.cpp
new file mode 100644 (file)
index 0000000..060e824
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Unit test of the syntax symbol extractor.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestRplLexer : public ReTest, public ReToken{
+public:
+    TestRplLexer() :
+        ReTest("ReLexer"),
+        ReToken(TOKEN_ID)
+    {}
+
+public:
+    void testRplToken(){
+        // test constructor values:
+        checkEqu(TOKEN_ID, tokenType());
+        checkEqu(0, m_value.m_id);
+        checkT(m_string.isEmpty());
+        checkT(m_printableString.isEmpty());
+
+        m_value.m_id = 7422;
+        checkEqu(7422, ReToken::id());
+        m_string = "Wow!";
+        checkEqu("Wow!", ReToken::toString());
+        m_printableString = "GooGoo";
+        checkEqu("GooGoo", rawString());
+        m_tokenType = TOKEN_NUMBER;
+        checkEqu(TOKEN_NUMBER, tokenType());
+
+        clear();
+        checkEqu(TOKEN_UNDEF, tokenType());
+        checkEqu(0, m_value.m_id);
+        checkT(m_string.isEmpty());
+        checkT(m_printableString.isEmpty());
+
+        m_value.m_integer = 773322;
+        checkEqu(773322, asInteger());
+        m_value.m_real = 0.25;
+        checkEqu(0.25, asReal());
+    }
+
+    ReToken* checkToken(ReToken* token, RplTokenType type, int id = 0,
+                    const char* string = NULL){
+        checkEqu(type, token->tokenType());
+        if (id != 0)
+            checkEqu(id, token->id());
+        if (string != NULL)
+            checkEqu(string, token->toString());
+        return token;
+    }
+    enum { KEY_UNDEF, KEY_IF, KEY_THEN, KEY_ELSE, KEY_FI
+         };
+#   define KEYWORDS "if then else fi"
+    enum { OP_UNDEF, OP_PLUS, OP_TIMES, OP_DIV, OP_GT,
+           OP_LT, OP_GE, OP_LE, OP_EQ, OP_ASSIGN, OP_PLUS_ASSIGN, OP_DIV_ASSIGN,
+           OP_TIMES_ASSIGN
+         };
+#   define OPERATORS "+\n* /\n> < >= <= ==\n= += /= *="
+    enum { COMMENT_UNDEF, COMMENT_1, COMMENT_MULTILINE, COMMENT_2
+    };
+#   define COMMENTS "/* */ // \n"
+    void testSpace(){
+        ReSource source;
+        ReStringReader reader(source);
+#       define BLANKS1 "\t\t   \n"
+#       define BLANKS2 " \n"
+        reader.addSource("<main>", BLANKS1 BLANKS2);
+        source.addReader(&reader);
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_DECIMAL,
+                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS1);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS2);
+    }
+    void testNumeric(){
+        ReSource source;
+        ReStringReader reader(source);
+        const char* blanks = "321 0x73 7.8e+5";
+        reader.addSource("<main>", blanks);
+        source.addReader(&reader);
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
+        ReToken* token = checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkEqu(321, token->asInteger());
+        token = checkToken(lex.nextNonSpaceToken(), TOKEN_NUMBER);
+        checkEqu(0x73, token->asInteger());
+        token = checkToken(lex.nextNonSpaceToken(), TOKEN_REAL);
+        checkEqu(7.8e+5, token->asReal());
+    }
+
+    void testOperators(){
+        ReSource source;
+        ReStringReader reader(source);
+        const char* ops = "<< < <<< <= == = ( ) [ ]";
+        reader.addSource("<main>", ops);
+        source.addReader(&reader);
+        enum { UNDEF, SHIFT, LT, SHIFT2, LE, EQ, ASSIGN,
+               LPARENT, RPARENT, LBRACKET, RBRACKET };
+        ReLexer lex(&source, KEYWORDS, ops, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_TICK, ReLexer::STORE_ALL);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT2);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LE);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, EQ);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, ASSIGN);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
+        reader.addSource("<buffer2>", "(([[");
+        lex.startUnit("<buffer2>");
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
+    }
+
+    void testComments(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "/**/9//\n8/***/7// wow\n/*\n*\n*\n**/");
+        source.addReader(&reader);
+
+        enum { COMMENT_UNDEF, COMMENT_MULTILINE, COMMENT_1
+        };
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
+                   "/**/");
+        checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
+                   "//\n");
+        checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
+                   "/***/");
+        checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
+                   "// wow\n");
+        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
+                   "/*\n*\n*\n**/");
+    }
+    void testStrings(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "\"abc\\t\\r\\n\\a\\v\"'1\\x9Z\\x21A\\X9'");
+        source.addReader(&reader);
+
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_STRING, '"', "abc\t\r\n\a\v");
+        checkToken(lex.nextToken(), TOKEN_STRING, '\'', "1\tZ!A\t");
+    }
+    void testKeywords(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "if\n\tthen else\nfi");
+        source.addReader(&reader);
+
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_THEN);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_ELSE);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_FI);
+        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
+    }
+
+    void testIds(){
+        ReSource source;
+        ReStringReader reader(source);
+
+        reader.addSource("<main>", "i\n\tifs\n"
+            "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+        source.addReader(&reader);
+
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
+        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
+           "ifs");
+        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
+           "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+    }
+
+    void testBasic(){
+        ReSource source;
+        ReStringReader reader(source);
+        source.addReader(&reader);
+        reader.addSource("<main>", "if i>1 then i=1+2*_x9 fi");
+        ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        ReToken* token;
+        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
+        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
+        checkToken(lex.nextToken(), TOKEN_OPERATOR, OP_GT);
+        token = checkToken(lex.nextToken(), TOKEN_NUMBER);
+        checkEqu(1, token->asInteger());
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
+        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_THEN);
+        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
+
+    }
+    void testPrio(){
+        ReSource source;
+        ReStringReader reader(source);
+        source.addReader(&reader);
+        reader.addSource("x", "");
+        enum { O_UNDEF, O_ASSIGN, O_PLUS, O_MINUS, O_TIMES, O_DIV
+             };
+        ReLexer lex(&source, KEYWORDS,
+                     "=\n+ -\n* /", "=",
+                 COMMENTS,
+                 "A-Za-z_",
+                 "A-Za-z0-9_",
+                 ReLexer::NUMTYPE_ALL,
+                 ReLexer::SF_LIKE_C, ReLexer::STORE_ALL);
+        checkT(lex.prioOfOp(O_ASSIGN) < lex.prioOfOp(O_PLUS));
+        checkEqu(lex.prioOfOp(O_PLUS), lex.prioOfOp(O_MINUS));
+        checkT(lex.prioOfOp(O_MINUS) < lex.prioOfOp(O_TIMES));
+        checkEqu(lex.prioOfOp(O_TIMES), lex.prioOfOp(O_DIV));
+    }
+
+    virtual void doIt(void) {
+        testPrio();
+        testBasic();
+        testIds();
+        testKeywords();
+        testComments();
+        testStrings();
+        testOperators();
+        testNumeric();
+        testSpace();
+        testRplToken();
+    }
+};
+void testRplLexer() {
+    TestRplLexer test;
+    test.run();
+}
diff --git a/cunit/rplmatrix_test.cpp b/cunit/rplmatrix_test.cpp
new file mode 100644 (file)
index 0000000..d1507e4
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Matrix_test.cpp
+ *
+ *  Created on: 29.05.2014
+ *      Author: hm
+ */
+
+/** @file
+ * @brief Unit test of the matrices.
+ */
+
+#include "base/rebase.hpp"
+#include "rplmath/rplmath.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestRplMatrix : public ReTest{
+public:
+    TestRplMatrix() : ReTest("RplMatrix") {}
+
+public:
+    void fillMatrix(RplMatrix& mx, MatVal offset = 0){
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                mx.set(row, col, 100.0*row + col + offset);
+            }
+        }
+    }
+    void checkMatrix(const RplMatrix& mx, MatVal offset = 0){
+        int count = 0;
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                checkEqu(100.0*row + col + offset, mx.get(row, col));
+                count++;
+            }
+        }
+        checkEqu(mx.getCols()*mx.getRows(), count);
+    }
+    void fillConst(RplMatrix& mx, MatVal value){
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                mx.set(row, col, value);
+            }
+        }
+    }
+    void checkConst(const RplMatrix& mx, MatVal value){
+        int count = 0;
+        for(int row = 0; row < mx.getRows(); row++){
+            for (int col = 0; col < mx.getCols(); col++){
+                checkEqu(value, mx.get(row, col));
+                count++;
+            }
+        }
+        checkEqu(mx.getCols()*mx.getRows(), count);
+    }
+
+    void testBasic() {
+        Tuple2 tuple(-2.0, 0.5);
+        checkEqu(-2.0, tuple.m_value1);
+        checkEqu(0.5, tuple.m_value2);
+        RplMatrix mat("mx");
+        try{
+            throw RplMatrixException(mat, "String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (RplMatrixException exc){
+            checkEqu("mx: String: Hi and int -333", exc.getMessage());
+        }
+        RplMatrix mat2;
+        try{
+            throw RplMatrixException(mat2, "String: %s and int %d", "Hi", -333);
+            checkF(true);
+        } catch (RplMatrixException exc){
+            checkEqu("String: Hi and int -333", exc.getMessage());
+        }
+        checkEqu("mx", mat.getName());
+        checkEqu("", mat2.getName());
+
+        RplMatrix m2x3(2, 3, "m2x3");
+        checkEqu("m2x3", m2x3.getName());
+        checkEqu(2, m2x3.getRows());
+        checkEqu(3, m2x3.getCols());
+        fillMatrix(m2x3);
+        checkMatrix(m2x3);
+
+        RplMatrix mxCopy(m2x3);
+        checkEqu("m2x3-copy", mxCopy.getName());
+        checkEqu(2, mxCopy.getRows());
+        checkEqu(3, mxCopy.getCols());
+        checkMatrix(mxCopy);
+
+        RplMatrix mxCopy2("mxCopy2");
+        mxCopy2 = m2x3;
+        checkEqu("mxCopy2", mxCopy2.getName());
+        checkEqu(2, mxCopy2.getRows());
+        checkEqu(3, mxCopy2.getCols());
+        checkMatrix(mxCopy2);
+    }
+    void testAddOperators(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(3, 2, "m2");
+        fillMatrix(m2, 42);
+        checkMatrix(m2, 42);
+        RplMatrix m3(3, 2, "m3");
+        fillMatrix(m3, -42);
+        checkMatrix(m3, -42);
+
+        m1 += 42;
+        checkMatrix(m1, 42);
+
+        checkT(m1 == m2);
+        checkF(m1 == m3);
+
+        m1 -= 42;
+        checkMatrix(m1);
+        m1 -= m1;
+        checkConst(m1, 0);
+
+        fillMatrix(m1);
+        m1 -= m3;
+        checkConst(m1, 42);
+        m1 += m2;
+        checkMatrix(m1, 42*2);
+    }
+    void testCompareOperators(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(3, 2, "m2");
+        fillMatrix(m2);
+
+        checkT(m1 == m2);
+        checkF(m1 != m2);
+        // modify each element, comparism must return false:
+        int row, col;
+        for (row = 0; row < m2.getRows(); row++)
+            for (col = 0; col < m2.getCols(); col++){
+                fillMatrix(m2);
+                m2.set(row, col, -1);
+                checkF(m1 == m2);
+                checkT(m1 != m2);
+            }
+
+        fillConst(m1, 42);
+        checkT(m1 == 42);
+        checkF(m1 == 43);
+        checkT(m1 != 43);
+        for (row = 0; row < m1.getRows(); row++)
+            for (col = 0; col < m1.getCols(); col++){
+                fillMatrix(m1, 42);
+                m1.set(row, col, -1);
+                checkF(m1 == 42);
+                checkT(m1 != 42);
+            }
+    }
+
+    void testCheckDefinition(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(3, 2, "m2");
+        fillMatrix(m2);
+
+        m1.checkDefinition(1, 1);
+        m1.checkDefinition(1000, 1000);
+        m1.checkDefinition(0, 0);
+        try {
+            m1.checkDefinition(-1, 1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: row number negative: -1", exc.getMessage());
+        }
+        try {
+            m1.checkDefinition(1, -1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: column number negative: -1", exc.getMessage());
+        }
+
+    }
+    void testCheck(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+
+        m1.check(0, 0);
+        m1.check(3-1, 2-1);
+        try {
+            m1.check(-1, 1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid row: -1 not in [0,3[", exc.getMessage());
+        }
+        try {
+            m1.check(3, 1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid row: 3 not in [0,3[", exc.getMessage());
+        }
+        try {
+            m1.check(1, -1);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid column: -1 not in [0,2[", exc.getMessage());
+        }
+        try {
+            m1.check(1, 2);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: invalid column: 2 not in [0,2[", exc.getMessage());
+        }
+    }
+    void testCheckSameDimension(){
+        RplMatrix m1(3, 2, "m1");
+        RplMatrix m2(3, 2, "m2");
+
+        m1.checkSameDimension(m2);
+
+        m2.resize(2, 2);
+        try {
+            m1.checkSameDimension(m2);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: m2 has a different row count: 3 / 2", exc.getMessage());
+        }
+        m2.resize(3, 3);
+        try {
+            m1.checkSameDimension(m2);
+            checkT(false);
+        } catch(RplMatrixException exc){
+            checkEqu("m1: m2 has a different column count: 2 / 3", exc.getMessage());
+        }
+    }
+    void testResize(){
+        RplMatrix m1(3, 2, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        RplMatrix m2(2, 4, "m2");
+        fillConst(m2, 0);
+        checkConst(m2, 0);
+
+        m1.resize(2, 4);
+        checkEqu(2, m1.getRows());
+        checkEqu(4, m1.getCols());
+        checkT(m1 == m2);
+    }
+
+    void testMinMax(){
+        RplMatrix m1(4, 5, "m1");
+        fillMatrix(m1);
+        checkMatrix(m1);
+        m1.set(0, 0, -98);
+        m1.set(3, 4, 9999);
+        Tuple2 miniMax = m1.minMax();
+        checkEqu(-98.0, miniMax.m_value1);
+        checkEqu(9999.0, miniMax.m_value2);
+
+        fillMatrix(m1);
+        checkMatrix(m1);
+        m1.set(1, 1, 7777);
+        m1.set(3, 4, -987);
+        miniMax = m1.minMax();
+        checkEqu(-987.0, miniMax.m_value1);
+        checkEqu(7777.0, miniMax.m_value2);
+    }
+
+    void testTranspose()
+    {
+        RplMatrix m1(1, 5, "m1");
+        fillMatrix(m1);
+        RplMatrix m2(m1.transpose());
+
+        checkEqu(5, m2.getRows());
+        checkEqu(1, m2.getCols());
+
+        int row, col;
+        col = 0;
+        for (row = 0; row < 5; row++){
+            checkEqu(qreal(col*100+row), m2.get(row, 0));
+        }
+
+        m1.resize(35, 73);
+        fillMatrix(m1);
+        m2 = m1.transpose();
+
+        checkEqu(73, m2.getRows());
+        checkEqu(35, m2.getCols());
+
+        int count = 0;
+        for (row = 0; row < m2.getRows(); row++){
+            for (col = 0; col < m2.getCols(); col++){
+                checkEqu(qreal(col*100+row), m2.get(row, col));
+                count++;
+            }
+        }
+        checkEqu(73*35, count);
+    }
+    void testToString(){
+        RplMatrix m1(1, 1, "m1");
+        m1.set(0, 0, 2.34);
+        checkEqu("[2.340000,\n]", m1.toString().constData());
+        checkEqu("jonny[2.34000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
+
+        m1.resize(2, 1);
+        m1.set(0, 0, 2.34);
+        m1.set(1, 0, 55.5);
+
+        checkEqu("[2.340000,\n55.500000,\n]", m1.toString().constData());
+        checkEqu("jonny[2.34000 |55.50000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
+        log("");
+    }
+    void testReadCsv(){
+        QByteArray fn = getTempFile("rplmatrixtest.csv");
+        const char* content;
+        RplMatrix m1(1,1,"m1");
+
+        fillMatrix(m1);
+        content = ",Port0,Port1,Port2\n"
+                "element1,5,  -3E-99  , 0.5\n"
+                "element2,7,-22.3,44\n"
+                "\n"
+                "2 Elements, 3, Ports";
+        ReStringUtil::write(fn, content);
+        m1.readFromCvs(fn, 256);
+        checkEqu(2, m1.getRows());
+        checkEqu(3, m1.getCols());
+
+        checkEqu(5.0, m1.get(0, 0));
+        checkEqu(-3.0E-99, m1.get(0, 1));
+        checkEqu(0.5, m1.get(0, 2));
+
+        checkEqu(7.0, m1.get(1, 0));
+        checkEqu(-22.3, m1.get(1, 1));
+        checkEqu(44.0, m1.get(1, 2));
+
+        fillMatrix(m1);
+        content = "Port0,Port1,Port2\n"
+                "5,  -3E-99  , 0.5\n";
+        ReStringUtil::write(fn, content);
+        m1.readFromCvs(fn, 256);
+        checkEqu(1, m1.getRows());
+        checkEqu(3, m1.getCols());
+        checkEqu(5.0, m1.get(0, 0));
+        checkEqu(-3.0E-99, m1.get(0, 1));
+        checkEqu(0.5, m1.get(0, 2));
+
+
+/*
+    void readFromCvs(const char* filename, int maxLineLength = 1024*1024);
+    void readFromXml(const char* filename, const char* tagCol,
+            const char* tagRow, const char* tagTable,
+            int maxLineLength = 1024*1024);
+*/
+    }
+    virtual void doIt(void) {
+        testBasic();
+        testAddOperators();
+        testCompareOperators();
+        testCheckDefinition();
+        testCheck();
+        testCheckSameDimension();
+        testResize();
+        testMinMax();
+        testTranspose();
+        testToString();
+        testReadCsv();
+    }
+};
+void testRplMatrix() {
+    TestRplMatrix test;
+    test.run();
+}
diff --git a/cunit/rplmfparser_test.cpp b/cunit/rplmfparser_test.cpp
new file mode 100644 (file)
index 0000000..6cb4ede
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+/** @file
+ * @brief Unit test of the parser for the language "MF".
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestRplMFParser : public ReTest{
+private:
+    ReSource m_source;
+    ReASTree m_tree;
+    ReStringReader m_reader;
+    ReFileReader m_fileReader;
+    QByteArray m_currentSource;
+public:
+    TestRplMFParser() :
+        ReTest("ReMFParser"),
+        m_source(),
+        m_tree(),
+        m_reader(m_source),
+        m_fileReader(m_source)
+    {
+        m_source.addReader(&m_reader);
+    }
+protected:
+    void setSource(const char* content){
+        ReASItem::reset();
+        m_currentSource = content;
+        m_tree.clear();
+        m_source.clear();
+        m_reader.clear();
+        m_reader.addSource("<test>", content);
+        m_source.addReader(&m_reader);
+        m_source.addSourceUnit(m_reader.currentSourceUnit());
+    }
+    void setFileSource(const char* filename){
+        ReASItem::reset();
+        m_currentSource = ReStringUtil::read(filename);
+        m_tree.clear();
+        m_source.clear();
+        m_fileReader.clear();
+        m_fileReader.addSource(filename);
+        m_source.addReader(&m_fileReader);
+        m_source.addSourceUnit(m_fileReader.currentSourceUnit());
+    }
+
+private:
+    void checkAST(const char* fileExpected, int lineNo){
+        QByteArray fnExpected = "test";
+        fnExpected += QDir::separator().toLatin1();
+        fnExpected += "mfparser";
+        fnExpected += (char) QDir::separator().toLatin1();
+        fnExpected += fileExpected;
+        QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser");
+        m_tree.dump(fnCurrent, ReASTree::DMP_NO_GLOBALS, m_currentSource);
+        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
+                         __FILE__, lineNo);
+    }
+
+public:
+    void fileClassTest(){
+        setFileSource("test/rplmfparser/string1.mf");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("string1.txt", __LINE__);
+    }
+
+    void baseTest(){
+        setSource("2+3*4");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("baseTest.txt", __LINE__);
+    }
+
+    void varDefTest(){
+        setSource("const lazy Str s = 'Hi';\nconst List l;\nInt i = 3;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("varDefTest.txt", __LINE__);
+    }
+
+    void ifTest(){
+        setSource("Int a;\nInt b;\na = b = 2;\nif 11 < 12\nthen a = 13 * 14\nelse a = 15 / 16\nfi");
+        // setSource("Int a; if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("ifTest1.txt", __LINE__);
+        setSource("Str x;\nif 7 < 6\nthen x = '123';\nfi");
+        parser.parse();
+        checkAST("ifTest2.txt", __LINE__);
+    }
+    void whileTest(){
+        setSource("Int a = 20;\nwhile 3 < 5 do\n a = 7\nod");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("whileTest.txt", __LINE__);
+    }
+
+    void repeatTest(){
+        setSource("Int a;\nrepeat\na++;\nuntil a != 2 * 3;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("repeatTest.txt", __LINE__);
+    }
+    void forCTest(){
+        setSource("Int a;\nfor b from 10 to 1 step -2 do\na += 1;\nod");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("forC1.txt", __LINE__);
+        setSource("Int a; for to 10 do a += 1 od");
+        parser.parse();
+        checkAST("forC2.txt", __LINE__);
+    }
+    void opTest(){
+        checkEqu(25, ReMFParser::O_QUESTION);
+        checkEqu(37, ReMFParser::O_RSHIFT2);
+        checkEqu(41, ReMFParser::O_DEC);
+        checkEqu(48, ReMFParser::O_RBRACE);
+        setSource("Int a = 1;\nInt b = 100;\n--a;\nb++;\na--*++b**(8-3);\na=b=(a+(b-2)*3)");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("opTest1.txt", __LINE__);
+    }
+    void forItTest(){
+        setSource("Map a;\nfor x in a do\na += 1;\nod");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("forIt1.txt", __LINE__);
+    }
+    void listTest(){
+        ReMFParser parser(m_source, m_tree);
+        setSource("List b = [];");
+        parser.parse();
+        checkAST("list1.txt", __LINE__);
+        setSource("List a = [2+3, 3.14, 7, 'hi', a]; List b = [];");
+        parser.parse();
+        checkAST("list2.txt", __LINE__);
+    }
+    void mapTest(){
+        setSource("Map a = {};");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("map1.txt", __LINE__);
+        setSource("Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'};\nMap b = {};");
+        parser.parse();
+        checkAST("map2.txt", __LINE__);
+    }
+    void methodCallTest(){
+        //setSource("max(4,3.14);");
+        setSource("rand();\nsin(a);\nmax(1+2*3,4**(5-4));");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("methc1.txt", __LINE__);
+    }
+    void fieldTest(){
+        setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("field1.txt", __LINE__);
+    }
+
+    void methodTest(){
+        setSource("func Float pi: 3.1415; endf func Str delim(): '/' endf;");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("meth1.txt", __LINE__);
+        setSource("func Int fac(const Int n):\n"
+                  "Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi\n"
+                  "rc endf");
+        parser.parse();
+        checkAST("meth2.txt", __LINE__);
+        setSource("func Int max(Int a, Int b):\n Int rc = a;\n"
+                  "if a < b then rc = b; fi\nrc\n"
+                  "endf\n"
+                  "func Int max(const Int a, Int b, Int c):\n"
+                  "max(a, max(b, c))\n"
+                  "endf");
+        parser.parse();
+        checkAST("meth3.txt", __LINE__);
+        setSource("func Int max(const Int a, Int b, Int c):\n"
+                  "func Int max(Int a, Int b):\n Int rc = a;\n"
+                  "if a < b then rc = b; fi\nrc\n"
+                  "endf\n"
+                  "max(a, max(b, c))\n"
+                  "endf");
+        parser.parse();
+        checkAST("meth4.txt", __LINE__);
+    }
+    void mainTest(){
+        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("main1.txt", __LINE__);
+    }
+
+    virtual void doIt(void) {
+        mainTest();
+        varDefTest();
+        repeatTest();
+        baseTest();
+        whileTest();
+        methodTest();
+        fieldTest();
+        methodCallTest();
+        mapTest();
+        forItTest();
+        forCTest();
+        listTest();
+        opTest();
+        fileClassTest();
+    }
+};
+void testRplMFParser() {
+    TestRplMFParser test;
+    test.run();
+}
+
+
diff --git a/cunit/rplqstring_test.cpp b/cunit/rplqstring_test.cpp
new file mode 100644 (file)
index 0000000..8f9db55
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+/** @file
+ * @brief Unit test of the ReString tools.
+ */
+
+#include "base/rebase.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestRplQString : public ReTest {
+public:
+    TestRplQString() :
+        ReTest("ReQString")
+    {}
+
+public:
+    void testLengthOfUInt64(){
+        quint64 value = -3;
+        checkEqu(1, ReQString::lengthOfUInt64(ReString("0"), 0, 10, &value));
+        checkEqu(0LL, value);
+        checkEqu(3, ReQString::lengthOfUInt64("x432", 1, 10, &value));
+        checkEqu(432LL, value);
+        checkEqu(3, ReQString::lengthOfUInt64("x432 x", 1, 10, &value));
+        checkEqu(432LL, value);
+        checkEqu(3, ReQString::lengthOfUInt64("x432fabc x", 1, 10, &value));
+        checkEqu(432LL, value);
+        checkEqu(16, ReQString::lengthOfUInt64("a1234567890123567", 1, 10, &value));
+        checkEqu(1234567890123567LL, value);
+        checkEqu(10, ReQString::lengthOfUInt64("x1234abcdef", 1, 16, &value));
+        checkEqu(0x1234abcdefLL, value);
+        checkEqu(3, ReQString::lengthOfUInt64("432", 0, 8, &value));
+        checkEqu(0432LL, value);
+        checkEqu(6, ReQString::lengthOfUInt64(" 765432 ", 1, 8, &value));
+        checkEqu(0765432LL, value);
+
+        checkEqu(0, ReQString::lengthOfUInt64("1 ", 1, 8, &value));
+        checkEqu(0, ReQString::lengthOfUInt64("", 1, 8, &value));
+    }
+    void testLengthOfUInt(){
+        uint value = 3;
+        checkEqu(1, ReQString::lengthOfUInt(ReString("0"), 0, 10, &value));
+        checkEqu(0, value);
+        checkEqu(3, ReQString::lengthOfUInt("x432", 1, 10, &value));
+        checkEqu(432, value);
+        checkEqu(3, ReQString::lengthOfUInt("x432 x", 1, 10, &value));
+        checkEqu(432, value);
+        checkEqu(3, ReQString::lengthOfUInt("x432fabc x", 1, 10, &value));
+        checkEqu(432, value);
+        checkEqu(3, ReQString::lengthOfUInt("432", 0, 8, &value));
+        checkEqu(0432, value);
+        checkEqu(6, ReQString::lengthOfUInt(" 765432 ", 1, 8, &value));
+        checkEqu(0765432, value);
+
+        checkEqu(0, ReQString::lengthOfUInt("1 ", 1, 8, &value));
+        checkEqu(0, ReQString::lengthOfUInt("", 1, 8, &value));
+    }
+    void testLengthOfReal(){
+        qreal value;
+        checkEqu(4, ReQString::lengthOfReal(ReString("0.25"), 0, &value));
+        checkEqu(0.25, value);
+        checkEqu(3, ReQString::lengthOfReal(ReString("X.25"), 1, &value));
+        checkEqu(0.25, value);
+        checkEqu(1, ReQString::lengthOfReal(ReString(" 0"), 1, &value));
+        checkEqu(0.0, value);
+        checkEqu(17, ReQString::lengthOfReal(ReString("X12345678901234567"), 1, &value));
+        checkEqu(12345678901234567.0, value);
+        checkEqu(2, ReQString::lengthOfReal(ReString(".5"), 0, &value));
+        checkEqu(0.5, value);
+        checkEqu(5, ReQString::lengthOfReal(ReString("2.5e2x"), 0, &value));
+        checkEqu(250.0, value);
+        checkEqu(6, ReQString::lengthOfReal(ReString("2.5e+2"), 0, &value));
+        checkEqu(250.0, value);
+        checkEqu(7, ReQString::lengthOfReal(ReString("2.5E-33"), 0, &value));
+        checkEqu(2.5e-33, value);
+
+        checkEqu(3, ReQString::lengthOfReal(ReString("2.5E"), 0, &value));
+        checkEqu(2.5, value);
+        checkEqu(3, ReQString::lengthOfReal(ReString("2.5E+"), 0, &value));
+        checkEqu(2.5, value);
+        checkEqu(3, ReQString::lengthOfReal(ReString("2.5E-a"), 0, &value));
+        checkEqu(2.5, value);
+    }
+
+    void testValueOfHexDigit(){
+        checkEqu(0, ReQString::valueOfHexDigit('0'));
+        checkEqu(9, ReQString::valueOfHexDigit('9'));
+        checkEqu(10, ReQString::valueOfHexDigit('a'));
+        checkEqu(15, ReQString::valueOfHexDigit('f'));
+        checkEqu(10, ReQString::valueOfHexDigit('A'));
+        checkEqu(15, ReQString::valueOfHexDigit('F'));
+
+        checkEqu(-1, ReQString::valueOfHexDigit('0' - 1));
+        checkEqu(-1, ReQString::valueOfHexDigit('9' + 1));
+        checkEqu(-1, ReQString::valueOfHexDigit('A' - 1));
+        checkEqu(-1, ReQString::valueOfHexDigit('F' + 1));
+        checkEqu(-1, ReQString::valueOfHexDigit('a' - 1));
+        checkEqu(-1, ReQString::valueOfHexDigit('f' + 1));
+    }
+    void testUtf8(){
+        ReString name = "Heinz Müller";
+        char buffer[32];
+        checkEqu("Heinz Müller", ReQString::utf8(name, buffer, sizeof buffer));
+        memset(buffer, 'x', sizeof buffer);
+        checkEqu("Heinz", ReQString::utf8(name, buffer, (size_t) (5+1)));
+        checkEqu(buffer[6], 'x');
+    }
+
+    virtual void doIt(void) {
+        testUtf8();
+        testLengthOfUInt64();
+        testLengthOfUInt();
+        testLengthOfReal();
+        testValueOfHexDigit();
+    }
+};
+void testRplQString() {
+    TestRplQString test;
+    test.run();
+}
+
diff --git a/cunit/rplsource_test.cpp b/cunit/rplsource_test.cpp
new file mode 100644 (file)
index 0000000..e78a9c3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Unit test of the input media reader.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestReSource : public ReTest{
+public:
+    TestReSource() : ReTest("TestReSource") {}
+
+private:
+    QByteArray m_content1_1;
+    QByteArray m_content1_2;
+    QByteArray m_content2;
+    ReSource m_source;
+
+protected:
+    void init(){
+        m_content1_1 = "# test\nimport source2\n";
+        m_content1_2 = "a=1;\nveeeeeeeeery looooooooooooooong\n";
+        m_content2 = "x=2";
+    }
+
+    void testReStringSourceUnit(){
+        ReStringReader reader(m_source);
+        QByteArray content("a=1;\nveeeeeeeeery looooooooooooooong\n");
+        ReStringSourceUnit unit("test", content, &reader);
+        unit.setLineNo(144);
+        checkEqu(144, unit.lineNo());
+        checkEqu("test", unit.name());
+    }
+    void checkOne(int maxSize, ReReader& reader){
+        QByteArray total;
+        QByteArray buffer;
+        int lineNo = 0;
+        bool hasMore;
+        checkF(reader.openSourceUnit("unknownSource"));
+        checkT(reader.openSourceUnit("source1"));
+        while(reader.nextLine(maxSize, buffer, hasMore)){
+            lineNo++;
+            total += buffer;
+            buffer.clear();
+            while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
+                total += buffer;
+                buffer.clear();
+            }
+            bool isImport = total.endsWith("source2\n");
+            if (isImport){
+                reader.openSourceUnit("source2");
+                checkEqu("source2", reader.currentSourceUnit()->name());
+                while(reader.nextLine(maxSize, buffer, hasMore)){
+                    lineNo++;
+                    while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
+                        total += buffer;
+                        buffer.clear();
+                    }
+                }
+                checkEqu("source1", reader.currentSourceUnit()->name());
+            }
+        }
+        checkEqu(5, lineNo);
+        checkEqu(m_content1_1 + m_content2 + m_content1_2, total);
+
+    }
+
+    void testReStringReader(){
+        ReStringReader reader(m_source);
+        reader.addSource("source1", m_content1_1 + m_content1_2);
+        reader.addSource("source2", m_content2);
+        ReSourceUnit* unit = reader.openSourceUnit("source1");
+        checkNN(unit);
+        checkEqu("source1", unit->name());
+        checkEqu(0, unit->lineNo());
+        checkOne(6, reader);
+        checkOne(100, reader);
+        reader.replaceSource("source2", "content2");
+
+        unit = reader.openSourceUnit("source2");
+        QByteArray buffer;
+        bool hasMore;
+        checkT(reader.nextLine(50, buffer, hasMore));
+        checkEqu("content2", buffer);
+        checkF(hasMore);
+    }
+
+public:
+    virtual void doIt(void) {
+        init();
+        testReStringSourceUnit();
+        testReStringReader();
+    }
+};
+void testReSource() {
+    TestReSource test;
+    test.run();
+}
+
+
+
diff --git a/cunit/rplstring_test.cpp b/cunit/rplstring_test.cpp
new file mode 100644 (file)
index 0000000..313ae58
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Unit test of the QByteArray tools.
+ */
+#include "base/rebase.hpp"
+#include "rplcore/rpltest.hpp"
+/**
+ * @brief Unit test for <code>ReStringUtil</code>.
+ */
+class TestReString : public ReTest {
+public:
+    TestReString() : ReTest("ReStringUtil") {}
+
+public:
+    void testCountChar(){
+        checkEqu(1, ReStringUtil::countChar("x", 'x'));
+        checkEqu(0, ReStringUtil::countChar("X", 'x'));
+        checkEqu(2, ReStringUtil::countChar("xbxxbxx", 'b'));
+    }
+
+    void testCount() {
+        checkEqu(0, ReStringUtil::count("abc", " "));
+        checkEqu(1, ReStringUtil::count("abc", "b"));
+        checkEqu(2, ReStringUtil::count("axx", "x"));
+
+        checkEqu(0, ReStringUtil::count("abbc", "bbb"));
+        checkEqu(1, ReStringUtil::count("\n\n", "\n\n"));
+        checkEqu(2, ReStringUtil::count("  a  ", "  "));
+    }
+
+    void testCutString() {
+        QByteArray source("123");
+        QByteArray buffer;
+        checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 4, buffer));
+        checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 3, buffer));
+        checkEqu(QByteArray("12..."), ReStringUtil::cutString(source, 2, buffer));
+        checkEqu(QByteArray("12"), ReStringUtil::cutString(source, 2, buffer, ""));
+    }
+
+    void testHexDump() {
+        QByteArray data("abc123\nxyz");
+        checkEqu(QByteArray("61 62 63 31  abc1\n"
+                          "32 33 0a 78  23.x\n"
+                          "79 7a        yz\n"),
+               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 4));
+        checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a  abc123.xyz"),
+               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 10));
+        checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a        abc123.xyz"),
+               ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 12));
+    }
+
+    void testReadWrite() {
+        QByteArray fn = getTempFile("test.dat");
+        const char* content = "Hello world\nLine2\n";
+        checkT(ReStringUtil::write(fn, content));
+        checkEqu(content, ReStringUtil::read(fn, false));
+        checkEqu(content, ReStringUtil::read(fn, true) + "\n");
+    }
+
+    void testToArray() {
+        QList<QByteArray> array = ReStringUtil::toArray("1 abc 3", " ");
+        checkEqu(3, array.size());
+        checkEqu("1", array.at(0));
+        checkEqu("abc", array.at(1));
+        checkEqu("3", array.at(2));
+    }
+
+    void testToNumber() {
+        checkEqu("3", ReStringUtil::toNumber(3));
+        checkEqu("-33", ReStringUtil::toNumber(-33));
+        checkEqu("003", ReStringUtil::toNumber(3, "%03d"));
+    }
+
+    void testLengthOfNumber(){
+        checkEqu(3, ReStringUtil::lengthOfNumber("0.3xxx"));
+        checkEqu(5, ReStringUtil::lengthOfNumber(" \t0.3xxx"));
+        checkEqu(3, ReStringUtil::lengthOfNumber("-.3xxx"));
+        checkEqu(2, ReStringUtil::lengthOfNumber(".3exxx"));
+        checkEqu(2, ReStringUtil::lengthOfNumber(".3e+xxx"));
+        checkEqu(16, ReStringUtil::lengthOfNumber("1234567.9012E+77"));
+        checkEqu(17, ReStringUtil::lengthOfNumber("-1234567.9012E+77 "));
+        checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 ", true));
+        checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 x", true));
+        checkEqu(20, ReStringUtil::lengthOfNumber("  -1234567.9012E+77 x", true));
+    }
+
+    void checkCsv(const char* content, char expected){
+        QByteArray fn = getTempFile("testrplstring.csv");
+        ReStringUtil::write(fn, content);
+        FILE* fp = fopen(fn, "r");
+        checkNN(fp);
+        char buffer[256];
+        checkEqu(expected, ReStringUtil::findCsvSeparator(fp, buffer, sizeof buffer));
+        fclose(fp);
+    }
+
+    void testFindCsvSeparator(){
+        const char* content = ",,,\t;;;||||";
+        checkCsv(content, '\t');
+
+        content = "col1,col2\n1.5,3,5\n";
+        checkCsv(content, ',');
+
+        content = "col1;col2\n1,50;3.5\n"
+                 "7;8\n10;12\n13;14";
+        checkCsv(content, ';');
+
+        content = "0.3 7.8 8.9\n7.8 9.4 8.3";
+        checkCsv(content, ' ');
+
+        content = "0.3|7.8|8.9\n7.8|         9.4|8.3";
+        checkCsv(content, '|');
+
+        content = "0,3;7.8;8.9";
+        checkCsv(content, ';');
+    }
+    void testLengthOfUInt64(){
+        quint64 value = -3;
+        checkEqu(1, ReStringUtil::lengthOfUInt64("0", 10, &value));
+        checkEqu(0LL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432", 10, &value));
+        checkEqu(432LL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432 x", 10, &value));
+        checkEqu(432LL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432fabc x", 10, &value));
+        checkEqu(432LL, value);
+        checkEqu(16, ReStringUtil::lengthOfUInt64("1234567890123567", 10, &value));
+        checkEqu(1234567890123567LL, value);
+        checkEqu(10, ReStringUtil::lengthOfUInt64("1234abcdef", 16, &value));
+        checkEqu(0x1234abcdefLL, value);
+        checkEqu(3, ReStringUtil::lengthOfUInt64("432", 8, &value));
+        checkEqu(0432LL, value);
+        checkEqu(6, ReStringUtil::lengthOfUInt64("765432 ", 8, &value));
+        checkEqu(0765432LL, value);
+
+        checkEqu(0, ReStringUtil::lengthOfUInt64(" ", 8, &value));
+        checkEqu(0, ReStringUtil::lengthOfUInt64("", 8, &value));
+    }
+    void testLengthOfReal(){
+        qreal value;
+        checkEqu(1, ReStringUtil::lengthOfReal("0", &value));
+        checkEqu(0.0, value);
+        checkEqu(1, ReStringUtil::lengthOfReal("0%", &value));
+        checkEqu(0.0, value);
+        checkEqu(4, ReStringUtil::lengthOfReal("0.25", &value));
+        checkEqu(0.25, value);
+        checkEqu(3, ReStringUtil::lengthOfReal(".25", &value));
+        checkEqu(0.25, value);
+        checkEqu(17, ReStringUtil::lengthOfReal("12345678901234567", &value));
+        checkEqu(12345678901234567.0, value);
+        checkEqu(2, ReStringUtil::lengthOfReal(".5", &value));
+        checkEqu(0.5, value);
+        checkEqu(5, ReStringUtil::lengthOfReal("2.5e2x", &value));
+        checkEqu(250.0, value);
+        checkEqu(6, ReStringUtil::lengthOfReal("2.5e+2", &value));
+        checkEqu(250.0, value);
+        checkEqu(7, ReStringUtil::lengthOfReal("2.5E-33", &value));
+        checkEqu(2.5e-33, value);
+
+        checkEqu(3, ReStringUtil::lengthOfReal("2.5E", &value));
+        checkEqu(2.5, value);
+        checkEqu(3, ReStringUtil::lengthOfReal("2.5E+", &value));
+        checkEqu(2.5, value);
+        checkEqu(3, ReStringUtil::lengthOfReal("2.5E-a", &value));
+        checkEqu(2.5, value);
+    }
+
+    virtual void doIt() {
+        testLengthOfReal();
+        testLengthOfUInt64();
+        testCountChar();
+        testCount();
+        testCutString();
+        testToNumber();
+        testToArray();
+        testHexDump();
+        testReadWrite();
+        testLengthOfNumber();
+        testFindCsvSeparator();
+    }
+};
+
+void testReString() {
+    TestReString test;
+    test.run();
+}
+
+
+
diff --git a/cunit/rplvm_test.cpp b/cunit/rplvm_test.cpp
new file mode 100644 (file)
index 0000000..bb58cd2
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestReVM : public ReTest{
+private:
+    ReSource m_source;
+    ReASTree m_tree;
+    ReStringReader m_reader;
+    const char* m_currentSource;
+public:
+    TestReVM() :
+        ReTest("ReVM"),
+        m_source(),
+        m_tree(),
+        m_reader(m_source)
+    {
+        m_source.addReader(&m_reader);
+    }
+protected:
+    void setSource(const char* content){
+        ReASItem::reset();
+        m_currentSource = content;
+        m_tree.clear();
+        m_source.clear();
+        m_reader.clear();
+        m_reader.addSource("<test>", content);
+        m_source.addReader(&m_reader);
+        m_source.addSourceUnit(m_reader.currentSourceUnit());
+    }
+
+private:
+    void checkAST(const char* fileExpected, int lineNo){
+        QByteArray fnExpected = "test";
+        fnExpected += QDir::separator().toLatin1();
+        fnExpected += "ReVM";
+        fnExpected += (char) QDir::separator().toLatin1();
+        fnExpected += fileExpected;
+        QByteArray fnCurrent = getTempFile(fileExpected, "ReVM");
+        ReMFParser parser(m_source, m_tree);
+        parser.parse();
+        ReVirtualMachine vm(m_tree, m_source);
+        vm.setFlag(ReVirtualMachine::VF_TRACE_STATEMENTS);
+        ReFileWriter writer(fnCurrent);
+        vm.setTraceWriter(&writer);
+        writer.write(m_currentSource);
+        vm.executeModule("<test>");
+        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
+                         __FILE__, lineNo);
+    }
+public:
+    void baseTest(){
+        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
+        checkAST("baseTest.txt", __LINE__);
+    }
+    virtual void doIt(void) {
+        baseTest();
+    }
+};
+void testReVM() {
+    TestReVM test;
+    test.run();
+}
+
diff --git a/cunit/rplwriter_test.cpp b/cunit/rplwriter_test.cpp
new file mode 100644 (file)
index 0000000..0922749
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Unit test of the output media writers.
+ */
+
+#include "base/rebase.hpp"
+#include "rplcore/rpltest.hpp"
+/**
+ * @brief Unit test for <code>ReStringUtil</code>.
+ */
+class TestRplWriter : public ReTest {
+public:
+    TestRplWriter() : ReTest("ReWriter") {}
+
+private:
+    void testFileWriter(){
+        QByteArray fn = getTempFile("rplwriter.txt");
+        ReFileWriter writer(fn);
+        writer.writeLine("abc");
+        writer.formatLine("%04d", 42);
+        writer.writeIndented(3, "123");
+        writer.indent(2);
+        writer.write("pi");
+        writer.format("%3c%.2f", ':', 3.1415);
+        writer.writeLine();
+        writer.close();
+        QByteArray current = ReStringUtil::read(fn, false);
+        checkEqu("abc\n0042\n\t\t\t123\n\t\tpi  :3.14\n", current);
+    }
+
+public:
+    virtual void doIt(void) {
+        testFileWriter();
+    }
+};
+void testRplWriter() {
+    TestRplWriter test;
+    test.run();
+}
+
+
+
diff --git a/cunit/unittests.pro b/cunit/unittests.pro
new file mode 100644 (file)
index 0000000..0104a97
--- /dev/null
@@ -0,0 +1,49 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2014-05-31T00:01:23
+#
+#-------------------------------------------------
+
+QT       += core network
+
+QT       -= gui
+
+TARGET = unittests
+CONFIG   += console
+CONFIG   -= app_bundle
+
+INCLUDEPATH = ..
+
+TEMPLATE = app
+
+SOURCES += main.cpp \
+    ../rplcore/rpllogger.cpp \
+    ../rplcore/rpltest.cpp \
+    ../rplcore/rplstring.cpp \
+    ../rplcore/rplexception.cpp \
+    ../rplmath/rplmatrix.cpp \
+    ../rplexpr/rplsource.cpp \
+    ../rplexpr/rpllexer.cpp \
+    ../rplexpr/rplastree.cpp \
+    ../rplexpr/rplparser.cpp \
+    ../rplexpr/rplmfparser.cpp \
+    ../rplcore/rplqstring.cpp \
+    ../rplexpr/rplasclasses.cpp \
+    ../rplcore/rplbytestorage.cpp \
+    ../rplexpr/rplvm.cpp \
+    ../rplcore/rplwriter.cpp \
+    rplmatrix_test.cpp \
+    rplexception_test.cpp \
+    rplstring_test.cpp \
+    rplsource_test.cpp \
+    rpllexer_test.cpp \
+    rplqstring_test.cpp \
+    rplastree_test.cpp \
+    rplmfparser_test.cpp \
+    rplvm_test.cpp \
+    rplbytestorage_test.cpp \
+    rplwriter_test.cpp \
+    rplbench.cpp \
+    rplcharptrmap_test.cpp \
+    ../rplcore/rplcharptrmap.cpp
+
diff --git a/expr/ReASTree.cpp b/expr/ReASTree.cpp
new file mode 100644 (file)
index 0000000..593a67a
--- /dev/null
@@ -0,0 +1,3728 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+/** @file
+ *
+ * @brief Implementation of an Abstract Syntax Tree.
+ *
+ */
+/** @file rplexpr/rplastree.hpp
+ *
+ * @brief Definitions for an Abstract Syntax Tree.
+ *
+ */
+
+#include "../base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+enum {
+    LOC_VARDEF_EXEC_1 = LOC_FIRST_OF(LOC_ASTREE), // 11001
+    LOC_UNOP_CALC_1,
+    LOC_UNARY_CHECK_1,
+    LOC_UNARY_CHECK_2,
+    LOC_UNARY_CHECK_3, // 11005
+    LOC_BINOP_1,
+    LOC_BINOP_CALC_1,
+    LOC_BINOP_CALC_2,
+    LOC_BINOP_CALC_3,
+    LOC_BINOP_CALC_4, // 11010
+    LOC_BINOP_CALC_5,
+    LOC_BINOP_CALC_6,
+    LOC_BINOP_CALC_7,
+    LOC_BINOP_CALC_8,
+    LOC_BINOP_CALC_9,   // 11015
+    LOC_BINOP_CALC_10,
+    LOC_BINOP_CALC_11,
+    LOC_BINOP_CALC_12,
+    LOC_VARDEF_CHECK_1,
+    LOC_VARDEF_CHECK_2, // 11020
+    LOC_ITEM_STATEM_LIST_1,
+    LOC_CONV_CHECK_1,
+    LOC_CONV_TRY_1,
+    LOC_ITEM_FORCE_ERROR_1,
+    LOC_UNARY_CHECK_4,  // 11025
+    LOC_IF_CHECK_1,
+    LOC_IF_CHECK_2,
+    LOC_FORC_CHECK_1,
+    LOC_FORC_CHECK_2,
+    LOC_FORC_CHECK_3, // 11030
+    LOC_ITEM_AS_INT_1,
+    LOC_ITEM_AS_INT_2,
+    LOC_METHOD_CALL_CHECK_1,
+    LOC_MEHTOD_CALL_CHECK_2,
+    LOC_MEHTOD_CALL_CHECK_3,    // 11035
+    LOC_MEHTOD_CALL_CHECK_4,
+    LOC_COUNT
+};
+
+unsigned int ReASItem::m_nextId = 1;
+
+#define DEFINE_TABS(indent)  \
+    char tabs[32]; \
+    memset(tabs, '\t', sizeof tabs); \
+    tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0'
+
+/**
+ * @brief Writes a map into a file.
+ *
+ * The output is sorted by key.
+ *
+ * @param writer        writes to output
+ * @param map           map to dump
+ * @param withEndOfLine true: '\n' will be written at the end
+ */
+void dumpMap(ReWriter& writer, ReASMapOfVariants& map, bool withEndOfLine)
+{
+    QList<QByteArray> sorted;
+    sorted.reserve(map.size());
+    ReASMapOfVariants::iterator it;
+    for (it = map.begin(); it != map.end(); it++){
+       sorted.append(it.key());
+    }
+    qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
+    QList<QByteArray>::iterator it2;
+    bool first = true;
+    for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
+        ReASVariant* value = map[*it2];
+        writer.format("%c'%s':%s", first ? '{' : ',', (*it2).constData(),
+            value->toString().constData());
+        first = false;
+    }
+    if (first)
+        writer.write("{");
+    writer.write("}");
+    if (withEndOfLine)
+        writer.writeLine();
+}
+
+/** @class ReASException rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a specific exception for the Abstract Syntax Tree.
+ */
+
+/**
+ * @brief Builds the message.
+ *
+ * @param position  describes the position of the error/warning
+ * @param format    the reason of the exception
+ * @param varList   the values for the placeholders in the format.
+ */
+void ReASException::build(const ReSourcePosition* position,
+                                 const char* format, va_list varList)
+{
+    char buffer[64000];
+    if (position != NULL){
+        m_message = position->toString().toUtf8();
+        m_message += ": ";
+    }
+    qvsnprintf(buffer, sizeof buffer, format, varList);
+    m_message += buffer;
+}
+
+/**
+ * @brief Constructor.
+ *
+ * @param position  describes the position of the error/warning
+ * @param format    the reason of the exception
+ * @param ...       the values for the placeholders in the format.
+ */
+ReASException::ReASException(const ReSourcePosition* position,
+                                 const char* format, ...) :
+    ReException("")
+{
+    va_list ap;
+    va_start(ap, format);
+    build(position, format, ap);
+    va_end(ap);
+}
+
+/**
+ * @brief Constructor.
+ */
+ReASException::ReASException() :
+    ReException("")
+{
+}
+
+/** @class ReASVariant rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a class which can hold the value of any type.
+ *
+ * The VM uses some tricks (performance): Therefore this class
+ * must not be virtual!
+ */
+/**
+ * @brief Constructor.
+ */
+ReASVariant::ReASVariant() :
+    m_variantType(VT_UNDEF),
+    m_flags(VF_UNDEF),
+    // m_value(),
+    m_class(NULL)
+{
+}
+/**
+ * @brief Destructor.
+ */
+ReASVariant::~ReASVariant()
+{
+    destroyValue();
+    m_variantType = VT_UNDEF;
+}
+
+/**
+ * @brief Copy constructor.
+ * @param source    the source to copy
+ */
+ReASVariant::ReASVariant(const ReASVariant& source):
+    m_variantType(source.m_variantType),
+    m_flags(source.m_flags),
+    // m_value
+    m_class(source.m_class)
+{
+    copyValue(source);
+}
+
+/**
+ * @brief Assignment operator.
+ *
+ * @param source    the source to copy
+ * @return          the instance itself
+ */
+ReASVariant&ReASVariant::operator=(const ReASVariant& source)
+{
+    destroyValue();
+    m_variantType = source.m_variantType;
+    m_flags = source.m_flags;
+    m_class = source.m_class;
+    copyValue(source);
+    return *this;
+}
+
+/**
+ * @brief Copies the value.
+ * @param source    the source to copy
+ */
+void ReASVariant::copyValue(const ReASVariant& source)
+{
+    destroyValue();
+    m_variantType = source.m_variantType;
+    m_class = source.m_class;
+
+    switch(source.m_variantType)
+    {
+    case VT_BOOL:
+        m_value.m_bool = source.m_value.m_bool;
+        break;
+    case VT_FLOAT:
+        m_value.m_float = source.m_value.m_float;
+        break;
+    case VT_INTEGER:
+        m_value.m_int = source.m_value.m_int;
+        break;
+    case VT_UNDEF:
+        break;
+    default:
+        m_value.m_object = m_class->newValueInstance(source.m_value.m_object);
+        break;
+    }
+    m_flags = source.m_flags;
+}
+
+/**
+ * @brief Frees the resources of the instance.
+ */
+void ReASVariant::destroyValue()
+{
+    switch(m_variantType)
+    {
+    case VT_BOOL:
+    case VT_FLOAT:
+    case VT_INTEGER:
+    case VT_UNDEF:
+        break;
+    default:
+        if ((m_flags & VF_IS_COPY) == 0)
+            m_class->destroyValueInstance(m_value.m_object);
+        m_value.m_object = NULL;
+        break;
+    }
+    m_variantType = VT_UNDEF;
+}
+/**
+ * @brief Returns the variantType of the instance.
+ *
+ * @return  the variant type
+ */
+ReASVariant::VariantType ReASVariant::variantType() const
+{
+    return m_variantType;
+}
+
+/**
+ * @brief Return the name of the variant type.
+ *
+ * @return  the type as string
+ */
+const char*ReASVariant::nameOfType() const
+{
+    const char* rc = "?";
+    switch(m_variantType){
+    case VT_UNDEF:
+        rc = "<undef>";
+        break;
+    case VT_FLOAT:
+        rc = "Float";
+        break;
+    case VT_INTEGER:
+        rc = "Int";
+        break;
+    case VT_BOOL:
+        rc = "Bool";
+        break;
+    case VT_OBJECT:
+        rc = "Obj";
+        break;
+    default:
+        break;
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns the class (data type) of the instance.
+ *
+ * @return  the variant type
+ */
+const ReASClass* ReASVariant::getClass() const
+{
+    return m_class;
+}
+
+
+/**
+ * @brief Returns the numeric value.
+ *
+ * @return              the numeric value
+ * @throw RplException  the instance is not a numberic value
+ *
+ */
+qreal ReASVariant::asFloat() const
+{
+    if (m_variantType != VT_FLOAT)
+        throw ReException("ReASVariant::asNumber: not a number: %d",
+                           m_variantType);
+    return m_value.m_float;
+}
+/**
+ * @brief Returns the numeric value.
+ *
+ * @return              the numeric value
+ * @throw RplException  the instance is not a numberic value
+ *
+ */
+int ReASVariant::asInt() const
+{
+    if (m_variantType != VT_INTEGER)
+        throw ReException("ReASVariant::asInt: not an integer: %d",
+                           m_variantType);
+    return m_value.m_int;
+}
+
+/**
+ * @brief Returns the boolean value.
+ *
+ * @return              the boolean value
+ * @throw RplException  the instance is not a boolean value
+ *
+ */
+bool ReASVariant::asBool() const
+{
+    if (m_variantType != VT_BOOL)
+        throw ReException("ReASVariant::asBool: not a boolean: %d",
+                           m_variantType);
+    return m_value.m_bool;
+}
+
+/**
+ * @brief Returns the class specific value.
+ *
+ * @param clazz         OUT: the class of the instance. May be NULL
+ * @return              the class specific value
+ * @throw RplException  the instance is not a boolean value
+ *
+ */
+void* ReASVariant::asObject(const ReASClass** clazz) const
+{
+    if (m_variantType != VT_OBJECT)
+        throw ReException("ReASVariant::asObject: not an object: %d",
+                           m_variantType);
+    if (clazz != NULL)
+        *clazz = m_class;
+    return m_value.m_object;
+}
+
+/**
+ * @brief Returns the value as string.
+ *
+ * @return the value as string
+ * @throw RplException  the instance is not a string value
+ */
+const QByteArray* ReASVariant::asString() const
+{
+    const ReASClass* clazz;
+    const QByteArray* rc = static_cast<const QByteArray*>(asObject(&clazz));
+    if (clazz != ReASString::m_instance){
+        const QByteArray& name = clazz->name();
+        throw ReException("ReASVariant::asString: not a string: %s",
+                           name.constData());
+    }
+    return rc;
+}
+
+/**
+ * @brief Make the instance to a numeric value.
+ *
+ * @param number    the numeric value.
+ */
+void ReASVariant::setFloat(qreal number)
+{
+    destroyValue();
+    m_variantType = VT_FLOAT;
+    m_value.m_float = number;
+    m_class = ReASFloat::m_instance;
+}
+
+/**
+ * @brief Make the instance to an integer value.
+ *
+ * @param integer    the numeric value.
+ */
+void ReASVariant::setInt(int integer)
+{
+    destroyValue();
+    m_variantType = VT_INTEGER;
+    m_value.m_int = integer;
+    m_class = ReASInteger::m_instance;
+}
+
+/**
+ * @brief Make the instance to a boolean value.
+ *
+ * @param value    the boolean value.
+ */
+void ReASVariant::setBool(bool value)
+{
+    destroyValue();
+    m_variantType = VT_BOOL;
+    m_value.m_bool = value;
+    m_class = ReASBoolean::m_instance;
+}
+
+/**
+ * @brief Make the instance to a boolean value.
+ *
+ * @param string    the string value.
+ */
+void ReASVariant::setString(const QByteArray& string)
+{
+    // deletion in ReASVariant::destroyValue():
+    setObject(new QByteArray(string), ReASString::m_instance);
+}
+
+/**
+ * @brief Builds a string.
+ *
+ * @param maxLength     the maximum length of the result
+ * @return  the value as string
+ */
+QByteArray ReASVariant::toString(int maxLength) const
+{
+    QByteArray rc;
+    char buffer[256];
+    switch(m_variantType)
+    {
+    case VT_BOOL:
+        rc = m_value.m_bool ? "True" : "False";
+        break;
+    case VT_FLOAT:
+        qsnprintf(buffer, sizeof buffer, "%f", m_value.m_float);
+        rc = buffer;
+        break;
+    case VT_INTEGER:
+        qsnprintf(buffer, sizeof buffer, "%lld", m_value.m_int);
+        rc = buffer;
+        break;
+    case VT_OBJECT:
+        rc = m_class->toString(m_value.m_object, maxLength);
+        break;
+    default:
+    case VT_UNDEF:
+        rc = "None";
+        break;
+    }
+    return rc;
+}
+
+/**
+ * @brief Make the instance to an object.
+ *
+ * @param object    the class specific value object.
+ * @param clazz     the data type of the object
+ */
+void ReASVariant::setObject(void* object, const ReASClass* clazz)
+{
+    destroyValue();
+    m_variantType = VT_OBJECT;
+    m_value.m_object = object;
+    m_class = clazz;
+}
+
+
+/** @class ReASItem rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the abstract base class of all entries of an AST.
+ *
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param type  the type of the instance
+ */
+ReASItem::ReASItem(ReASItemType type) :
+    m_id(m_nextId++),
+    m_nodeType(type),
+    m_flags(0),
+    m_position(NULL)
+{
+}
+/**
+ * @brief Destructor.
+ */
+
+ReASItem::~ReASItem()
+{
+}
+
+/**
+ * @brief Checks a calculable node for correctness.
+ *
+ * @param description   description of the meaning, e.g. "start value"
+ * @param expectedClass the node must have this type
+ * @param parser        for error processing
+ * @return              <code>true</code>: instance and children are correct<br>
+ *                      <code>false</code>: otherwise
+ */
+bool ReASItem::checkAsCalculable(const char* description,
+                                  ReASClass* expectedClass, ReParser& parser)
+{
+    bool rc = true;
+    if (! check(parser))
+        rc = false;
+    if (rc){
+        ReASCalculable* expr = dynamic_cast<ReASCalculable*>(this);
+        if (expr == NULL)
+            rc = error(LOC_ITEM_AS_INT_1, parser, "%s not calculable: %s",
+                  description, nameOfItemType());
+        else if (expr->clazz() != ReASInteger::m_instance)
+            rc = error(LOC_ITEM_AS_INT_2, parser,
+                       "%s: wrong type %s instead of integer",
+                       description, expr->clazz()->name().constData());
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns the position of the item in the source code.
+ *
+ * @return the position of the item
+ */
+const ReSourcePosition* ReASItem::position() const
+{
+    return m_position;
+}
+
+/**
+ * @brief Stores the position in the source code.
+ *
+ * @param position  the position to store
+ */
+void ReASItem::setPosition(const ReSourcePosition* position)
+{
+    m_position = position;
+}
+
+/**
+ * @brief Returns the id of the instance.
+ *
+ * @return  the id
+ */
+unsigned int ReASItem::id() const
+{
+    return m_id;
+}
+
+/**
+ * @brief Returns the position as a string.
+ *
+ * @param buffer        OUT: the target buffer
+ * @param bufferSize    size of the target buffer
+ * @return              <code>buffer</code>
+ */
+char* ReASItem::positionStr(char buffer[], size_t bufferSize) const
+{
+    char* rc = (char*) "";
+    if (m_position != NULL)
+        rc = m_position->utf8(buffer, bufferSize);
+    return rc;
+}
+
+/**
+ * @brief Logs an internal error.
+ *
+ * @param logger    can write to the output medium
+ * @param location  identifies the error location
+ * @param format    string with placeholders (optional) like <code>sprintf()</code>
+ * @param ...       values for the placeholders
+ */
+void ReASItem::error(ReLogger* logger, int location, const char* format, ...)
+{
+    char buffer[1024];
+    int halfBufferSize = (sizeof buffer) / 2;
+    qsnprintf(buffer, halfBufferSize, "id: %d [%s]:", m_id,
+                 positionStr(buffer + halfBufferSize, halfBufferSize));
+    int length = strlen(buffer);
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer + length, (sizeof buffer) - length, format, ap);
+    va_end(ap);
+    logger->log(LOG_ERROR, location, buffer);
+}
+
+/**
+ * @brief Resets the static id counter.
+ */
+void ReASItem::reset()
+{
+    m_nextId = 1;
+}
+/**
+ * @brief Calculates an integer value.
+ *
+ * @param expr      a calculable node
+ * @param thread    the execution unit
+ * @return          the value described by the node <code>expr</code>
+ */
+int ReASItem::calcAsInteger(ReASItem* expr, ReVMThread& thread)
+{
+    ReASCalculable* expr2 = dynamic_cast<ReASCalculable*>(expr);
+    expr2->calc(thread);
+    ReASVariant& value = thread.popValue();
+    int rc = value.asInt();
+    return rc;
+}
+
+/**
+ * @brief Calculates an boolean value.
+ *
+ * @param expr      a calculable node
+ * @param thread    the execution unit
+ * @return          the value described by the node <code>expr</code>
+ */
+bool ReASItem::calcAsBoolean(ReASItem* expr, ReVMThread& thread)
+{
+    ReASCalculable* expr2 = dynamic_cast<ReASCalculable*>(expr);
+    expr2->calc(thread);
+    ReASVariant& value = thread.popValue();
+    bool rc = value.asBool();
+    return rc;
+}
+/**
+ * @brief Checks the correctness of a statement list.
+ *
+ * @param list      statement list to check
+ * @param parser    for error processing
+ * @return          <code>true</code>: all statements are correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASItem::checkStatementList(ReASItem* list, ReParser& parser)
+{
+    bool rc = true;
+
+    while(list != NULL){
+        if (! list->check(parser))
+            rc = false;
+        if (dynamic_cast<ReASStatement*>(list) == NULL)
+            rc = list->error(LOC_ITEM_STATEM_LIST_1, parser, "not a statement: %s",
+                    list->nameOfItemType());
+        ReASNode1* node = dynamic_cast<ReASNode1*>(list);
+        if (node == NULL){
+            list->error(LOC_ITEM_STATEM_LIST_1, parser, "not a node: %s",
+                        list->nameOfItemType());
+            list = NULL;
+        } else {
+            list = node->child();
+        }
+    }
+    return rc;
+}
+/**
+ * @brief Returns the node type.
+ *
+ * @return  the node type
+ */
+ReASItemType ReASItem::nodeType() const
+{
+    return m_nodeType;
+}
+
+/**
+ * @brief Returns the node type as a string.
+ *
+ * @return  the node type as string
+ */
+const char*ReASItem::nameOfItemType() const
+{
+    const char* rc = "?";
+    switch(m_nodeType){
+    case AST_CONSTANT:
+        rc = "constant";
+        break;
+    case AST_LIST_CONSTANT:
+        rc = "list";
+        break;
+    case AST_LIST_ENTRY:
+        rc = "listEntry";
+        break;
+    case AST_MAP_CONSTANT:
+        rc = "map";
+        break;
+    case AST_MAP_ENTRY:
+        rc = "mapEntry";
+        break;
+    case AST_NAMED_VALUE:
+        rc = "namedValue";
+        break;
+    case AST_INDEXED_VALUE:
+        rc = "indexedValue";
+        break;
+    case AST_FIELD:
+        rc = "field";
+        break;
+    case AST_VAR_DEFINITION:
+        rc = "varDef";
+        break;
+    case AST_EXPR_STATEMENT:
+        rc = "exprStatement";
+        break;
+    case AST_METHOD:
+        rc = "method";
+        break;
+    case AST_ARGUMENT:
+        rc = "arg";
+        break;
+    case AST_INTRINSIC_METHOD:
+        rc = "intrinsicMethod";
+        break;
+    case AST_PRE_UNARY_OP:
+        rc = "preUnary";
+        break;
+    case AST_POST_UNARY_OP:
+        rc = "postUnary";
+        break;
+    case AST_BINARY_OP:
+        rc = "binOp";
+        break;
+    case AST_METHOD_CALL:
+        rc = "methodCall";
+        break;
+    case AST_WHILE:
+        rc = "while";
+        break;
+    case AST_REPEAT:
+        rc = "repeat";
+        break;
+    case AST_IF:
+        rc = "if";
+        break;
+    case AST_CONDITION:
+        rc = "condition";
+        break;
+    case AST_ITERATED_FOR:
+        rc = "iFor";
+        break;
+    case AST_COUNTED_FOR:
+        rc = "cFor";
+        break;
+    case AST_SWITCH:
+        rc = "switch";
+        break;
+    case AST_LEAVE:
+        rc = "leave";
+        break;
+    case AST_CONTINUE:
+        rc = "continue";
+        break;
+    default:
+        break;
+    }
+    return rc;
+}
+/**
+ * @brief Returns the flags of the node.
+ *
+ * @return  the bitmask with the flags
+ */
+int ReASItem::flags() const
+{
+    return m_flags;
+}
+/**
+ * @brief Sets the flags of the node.
+ *
+ * @param flags     the new value of the bitmask
+ */
+void ReASItem::setFlags(int flags)
+{
+    m_flags = flags;
+}
+
+/**
+ * @brief Tests the compatibility of 2 data types.
+ * @param class1    1st class to inspect
+ * @param class2    2nd class to inspect
+ * @return          true: classes are compatible<br>
+ *                  false: otherwise
+ */
+bool ReASItem::typeCheck(ReASClass* class1, ReASClass* class2){
+    bool rc;
+    if (class1 == NULL || class2 == NULL)
+        rc = false;
+    else
+        //@ToDo: subclasses
+        rc = class1 == class2;
+    return rc;
+}
+
+/**
+ * @brief Issues an error message.
+ *
+ * @param location  an error specific id
+ * @param parser    for error processing
+ * @param format    the error message with placeholders (like <code>printf</code>)
+ * @param ...       the values for the placeholders
+ * @return          false (for chaining)
+ */
+bool ReASItem::error(int location, ReParser& parser, const char* format, ...)
+{
+    va_list varList;
+    va_start(varList, format);
+    parser.addMessage(ReParser::LT_ERROR, location, m_position, format, varList);
+    va_end(varList);
+    return false;
+}
+
+/**
+ * @brief Ensures the occurrence of an error.
+ *
+ * When called a previous error should be happend. If not an internal error
+ * will be issued.
+ *
+ * @param parser    for error processing
+ * @param info      additional info
+ * @return          <code>false</code> (for chaining)
+ */
+bool ReASItem::ensureError(ReParser& parser, const char* info)
+{
+    if (parser.errors() == 0)
+        error(LOC_ITEM_FORCE_ERROR_1, parser, "lost error (internal error): %s");
+    return false;
+}
+
+/** @class ReASCalculable rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief An abstract base class for items which calculates a value.
+ *
+ */
+/**
+ * @brief Constructor.
+ */
+ReASCalculable::ReASCalculable() :
+    m_class(NULL)
+{
+}
+/**
+ * @brief Returns the class of the node
+ * @return  the class
+ */
+
+ReASClass* ReASCalculable::clazz() const
+{
+    return m_class;
+}
+/**
+ * @brief Sets the class of the node.
+ * @param clazz     the new class
+ */
+void ReASCalculable::setClass(ReASClass* clazz)
+{
+    m_class = clazz;
+}
+
+/** @class ReASStorable rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the abstract base class of value containing items.
+ *
+ */
+
+/** @class ReASConstant rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a constant for the Abstract Syntax Tree.
+ *
+ */
+
+/**
+ * @brief Constructor.
+ *
+ */
+ReASConstant::ReASConstant() :
+    ReASItem(AST_CONSTANT),
+    m_value()
+{
+}
+
+/**
+ * @brief Copies the const value to the top of value stack.
+ *
+ * @param thread    IN/OUT: the execution unit, a VM thread
+ */
+void ReASConstant::calc(ReVMThread& thread)
+{
+    ReASVariant& value = thread.reserveValue();
+    value.copyValue(m_value);
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: a constant is always correct
+ */
+bool ReASConstant::check(ReParser& parser)
+{
+    return true;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASConstant::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "const id: %d value: %s %s", m_id,
+            m_value.toString().constData(),
+            positionStr(buffer, sizeof buffer));
+}
+
+/**
+ * @brief Returns the value of the constant.
+ *
+ * This method will be used to set the value of the constant:
+ * <pre><code>ReASConstant constant;
+ * constant.value().setString("Jonny");
+ *</code></pre>
+ *
+ * @return the internal value
+ */
+ReASVariant& ReASConstant::value()
+{
+    return m_value;
+}
+
+/** @class ReASListConstant rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a container for constant list entries.
+ *
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReASListConstant::ReASListConstant() :
+    ReASNode1(AST_LIST_CONSTANT),
+    ReASCalculable()
+{
+    m_value.setObject(ReASList::m_instance->newValueInstance(),
+                      ReASList::m_instance);
+}
+/**
+ * @brief Returns the list.
+ *
+ * @return  the list
+ */
+ReASListOfVariants* ReASListConstant::list(){
+     ReASListOfVariants* rc = static_cast<ReASListOfVariants*>
+             (m_value.asObject(NULL));
+     return rc;
+}
+
+/**
+ * @brief Copies the list constant to the top of value stack.
+ *
+ * @param thread    IN/OUT: the execution unit, a VM thread
+ */
+void ReASListConstant::calc(ReVMThread& thread)
+{
+    ReASVariant& value = thread.reserveValue();
+    value.copyValue(m_value);
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: a constant is always correct
+ */
+bool ReASListConstant::check(ReParser& parser)
+{
+    return true;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASListConstant::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "listConst id: %d %s", m_id,
+            positionStr(buffer, sizeof buffer));
+
+    QByteArray sValue = m_value.toString(8092);
+    writer.writeIndented(indent + 1, sValue.constData());
+}
+
+/**
+ * @brief Returns the value of the constant.
+ *
+ * This method will be used to set the value of the constant:
+ * <pre><code>ReASConstant constant;
+ * constant.value().setString("Jonny");
+ *</code></pre>
+ *
+ * @return the internal value
+ */
+ReASVariant& ReASListConstant::value()
+{
+    return m_value;
+}
+
+/** @class ReASMapConstant rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a hash map for constant list entries.
+ *
+ */
+/**
+ * @brief ReASMapConstant::ReASMapConstant
+ */
+ReASMapConstant::ReASMapConstant() :
+    ReASNode1(AST_MAP_CONSTANT),
+    ReASCalculable(),
+    m_value()
+{
+    m_value.setObject(new ReASMapOfVariants, ReASMap::m_instance);
+}
+
+/**
+ * @brief Copies the map constant to the top of value stack.
+ *
+ * @param thread    IN/OUT: the execution unit, a VM thread
+ */
+void ReASMapConstant::calc(ReVMThread& thread)
+{
+    ReASVariant& value = thread.reserveValue();
+    value.copyValue(m_value);
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: a constant is always correct
+ */
+bool ReASMapConstant::check(ReParser& parser)
+{
+   return true;
+}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASMapConstant::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "mapConst id: %d %s",
+            m_id, positionStr(buffer, sizeof buffer));
+    writer.indent(indent);
+    dumpMap(writer, *map(), true);
+}
+
+
+/**
+ * @brief Returns the value of the constant, containing a map.
+ *
+ * @return  the variant value
+ */
+ReASVariant& ReASMapConstant::value()
+{
+    return m_value;
+}
+
+/**
+ * @brief Returns the (low level) map of the constant.
+ *
+ * @return  the map of the constant
+ */
+ReASMapOfVariants* ReASMapConstant::map()
+{
+    ReASMapOfVariants* rc = static_cast<ReASMapOfVariants*>(
+                m_value.asObject(NULL));
+    return rc;
+}
+
+/** @class ReASNamedValue rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a named values, a constant or a variable
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param clazz         the data type (class)
+ * @param space         the current symbol space
+ * @param name          the name of the variable
+ * @param attributes    the attributes of the variable
+ */
+ReASNamedValue::ReASNamedValue(ReASClass* clazz,ReSymbolSpace* space,
+                                 const QByteArray& name, int attributes) :
+    ReASItem(AST_NAMED_VALUE),
+    m_name(name),
+    m_attributes(attributes),
+    m_symbolSpace(space),
+    m_variableNo(-1)
+{
+    m_class = clazz;
+}
+
+/**
+ * @brief Returns the name.
+ *
+ * @return the name
+ */
+const QByteArray& ReASNamedValue::name() const
+{
+    return m_name;
+}
+
+/**
+ * @brief Sets the symbol space.
+ * @param space
+ * @param variableNo
+ */
+void ReASNamedValue::setSymbolSpace(ReSymbolSpace* space, int variableNo)
+{
+    m_symbolSpace = space;
+    m_variableNo = variableNo;
+}
+/**
+ * @brief Copies the value of the variable to the top of value stack.
+ *
+ * @param thread    IN/OUT: the execution unit, a VM thread
+ */
+void ReASNamedValue::calc(ReVMThread& thread)
+{
+    thread.valueToTop(m_symbolSpace, m_variableNo);
+    if (thread.tracing())
+        thread.vm()->traceWriter()->format("nVal %s=%.80s",
+                    m_name.constData(),
+                    thread.topOfValues().toString().constData());
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASNamedValue::check(ReParser& parser)
+{
+    return true;
+}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASNamedValue::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "namedValue %s id: %d attr: 0x%x %s",
+            m_name.constData(), m_id, m_attributes,
+            positionStr(buffer, sizeof buffer));
+}
+
+/**
+ * @brief Returns the symbol space of the variable.
+ *
+ * @return  the symbol space
+ */
+ReSymbolSpace*ReASNamedValue::symbolSpace() const
+{
+    return m_symbolSpace;
+}
+
+/**
+ * @brief Sets the variable no in the instance.
+ *
+ * @param variableNo    the variable number
+ */
+void ReASNamedValue::setVariableNo(int variableNo)
+{
+    m_variableNo = variableNo;
+}
+
+
+/**
+ * @brief Returns the variable no of the variable.
+ *
+ * @return  the current number of the variable in the symbol space
+ */
+int ReASNamedValue::variableNo() const
+{
+    return m_variableNo;
+}
+
+/** @class ReASConversion rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a data type conversion.
+ *
+ * <code>m_child</code>: the expression which will be converted
+ */
+/**
+ * @brief Constructor.
+ * @param expression    the expression to convert
+ */
+ReASConversion::ReASConversion(ReASItem* expression) :
+    ReASNode1(AST_CONVERSION),
+    m_conversion(C_UNDEF)
+{
+    m_child = expression;
+    m_position = expression->position();
+}
+
+/**
+ * @brief Convert an expression to another data type.
+ *
+ * Possible conversions: @see <code>ReASConversion::Conversion</code>
+ *
+ * @param thread    execution value
+ */
+void ReASConversion::calc(ReVMThread& thread)
+{
+    ReASCalculable* expr = dynamic_cast<ReASCalculable*>(m_child);
+    expr->calc(thread);
+    ReASVariant& value = thread.topOfValues();
+
+    switch(m_conversion){
+    case C_INT_TO_FLOAT:
+        value.setFloat((qreal) value.asInt());
+        break;
+    case C_FLOAT_TO_INT:
+        value.setInt((int) value.asFloat());
+        break;
+    case C_BOOL_TO_INT:
+        value.setInt((int) value.asBool());
+        break;
+    case C_BOOL_TO_FLOAT:
+        value.setFloat((qreal) value.asBool());
+        break;
+    default:
+        break;
+    }
+    if (thread.tracing())
+        thread.vm()->traceWriter()->format("(%s): %s",
+                    m_class->name().constData(),
+                    value.toString().constData());
+}
+
+/**
+ * @brief Returns the conversion type of two classes.
+ *
+ * @param from  class to convert
+ * @param to    result class of the conversion
+ *
+ * @return      <code>C_UNDEF</code>: not convertable<br>
+ *              otherwise: the conversion type
+ */
+ReASConversion::Conversion ReASConversion::findConversion(ReASClass* from,
+             ReASClass* to)
+{
+    Conversion rc = C_UNDEF;
+    if (from == ReASFloat::m_instance){
+        if (to == ReASInteger::m_instance)
+            rc = C_FLOAT_TO_INT;
+    } else if (from == ReASInteger::m_instance){
+        if (to == ReASFloat::m_instance)
+            rc = C_INT_TO_FLOAT;
+    } else if (from == ReASBoolean::m_instance){
+        if (to == ReASInteger::m_instance)
+            rc = C_BOOL_TO_INT;
+        else if (to == ReASInteger::m_instance)
+            rc = C_BOOL_TO_INT;
+        else if (to == ReASFloat::m_instance)
+            rc = C_BOOL_TO_FLOAT;
+    }
+    return rc;
+}
+
+/**
+ * @brief Checks the node.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASConversion::check(ReParser& parser)
+{
+    bool rc = m_child != NULL && m_child->check(parser);
+    ReASCalculable* expr = dynamic_cast<ReASCalculable*>(m_child);
+    if (! rc || expr == NULL)
+        ensureError(parser, "ReASConversion::check");
+    else {
+        ReASClass* from = expr->clazz();
+        m_conversion = findConversion(from, m_class);
+        if (m_conversion != C_UNDEF)
+            rc = true;
+        else
+            parser.error(LOC_CONV_CHECK_1,
+                         "invalid data type conversion: %s -> %s",
+                         from->name().constData(),
+                         m_class->name().constData());
+    }
+    return rc;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASConversion::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "conversion %s id: %d expr: %d %s",
+                          m_class->name().constData(), m_id, m_child->id(),
+            positionStr(buffer, sizeof buffer));
+}
+
+/**
+ * @brief Tries to find a conversion to a given type.
+ *
+ * Checks if an expression has a given type. If not it will be tried to find
+ * a conversion. If this is not possible an error occurres. Otherwise the
+ * converter will be returned.
+ *
+ * @param expected  the expected data type
+ * @param expr      the expression to convert
+ * @param parser    for error processing
+ * @param isCorrect OUT: false: error has been detected<br>
+ *                  No change if no error
+ *
+ * @return          NULL: no conversion necessary<br>
+ *                  otherwise: a converter to the given type
+ */
+ReASConversion* ReASConversion::tryConversion(ReASClass* expected,
+    ReASItem* expr, ReParser& parser, bool& isCorrect)
+{
+    ReASConversion* rc = NULL;
+    if (! expr->check(parser))
+        isCorrect = false;
+    else {
+        ReASCalculable* expr2 = dynamic_cast<ReASCalculable*>(expr);
+        if (expr2 != NULL){
+            Conversion type = findConversion(expr2->clazz(), expected);
+            if (type == C_UNDEF){
+                isCorrect = parser.error(LOC_CONV_TRY_1,
+                             "invalid data type conversion: %s -> %s",
+                             expr2->clazz()->name().constData(),
+                             expected->name().constData());
+            } else if (expr2->clazz() != expected){
+                rc = new ReASConversion(expr);
+                rc->m_conversion = type;
+                rc->setClass(expected);
+            }
+        }
+    }
+    return rc;
+}
+
+/** @class ReASIndexedValue rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an indexed values (member of a list)
+ *
+ * <code>m_child</code>: the parent: a list/map expression
+ * <code>m_child2</code>: the index expression
+ */
+ReASIndexedValue::ReASIndexedValue() :
+    ReASNode2(AST_INDEXED_VALUE)
+{
+}
+
+/**
+ * @brief Calculates an indexed expression.
+ *
+ * Possible: list index or map index
+ *
+ * @param thread    execution value
+ */
+void ReASIndexedValue::calc(ReVMThread& thread)
+{
+    ReASCalculable* expr = dynamic_cast<ReASCalculable*>(m_child2);
+    expr->calc(thread);
+    ReASVariant& ixValue = thread.popValue();
+    int ix = ixValue.asInt();
+    ReASCalculable* list = dynamic_cast<ReASCalculable*>(m_child);
+    list->calc(thread);
+    ReASVariant& listValue = thread.popValue();
+    //@ToDo: access to the lists element: assignment or to stack
+    if (thread.tracing())
+        thread.vm()->traceWriter()->format("[%d]: %.80s",
+                    ix, thread.topOfValues().toString().constData());
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASIndexedValue::check(ReParser& parser)
+{
+    ReASCalculable* list = dynamic_cast<ReASCalculable*>(m_child);
+    bool rc = m_child != NULL && m_child->check(parser);
+    if (! rc || list == NULL)
+        ensureError(parser, "ReASIndexedValue::check");
+    else {
+        // index value:
+        // tryConversion() calls m_child2->check()!
+        ReASConversion* converter = ReASConversion::tryConversion(
+                    ReASInteger::m_instance, m_child2, parser, rc);
+        if (rc && converter != NULL)
+            m_child = converter;
+        if (rc){
+            //@ToDo: dynamic subclass of list / map
+            m_class = ReASString::m_instance;
+            rc = m_class != NULL && m_class == ReASInteger::m_instance;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Writes the internals into an output media.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASIndexedValue::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "indexedValue id: %d index: %d parent: %d %s",
+            m_id, m_child2->id(), m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    m_child2->dump(writer, indent + 1);
+    m_child->dump(writer, indent + 1);
+}
+
+/** @class RplVarDefinition rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements variable definition for the Abstract Syntax Tree.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: named value (name + default value expression)
+ * <code>m_child3</code>: initial value or NULL
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReASVarDefinition::ReASVarDefinition() :
+    ReASNode3(AST_VAR_DEFINITION),
+    ReASStatement(),
+    m_endOfScope(0)
+{
+    m_flags |= NF_STATEMENT;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASVarDefinition::dump(ReWriter& writer, int indent)
+{
+    ReASNamedValue* namedValue = dynamic_cast<ReASNamedValue*>(m_child2);
+    QByteArray name = namedValue->name();
+    char endOfScope[32];
+    endOfScope[0] = '\0';
+    if (m_endOfScope > 0)
+        qsnprintf(endOfScope, sizeof endOfScope, "-%d:0", m_endOfScope);
+    char buffer[256];
+    writer.formatIndented(indent,
+            "varDef %s %s id: %d namedValue: %d value: %d succ: %d %s%s",
+            clazz() == NULL ? "?" : clazz()->name().constData(),
+            name.constData(), m_id,
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer), endOfScope);
+    if (m_child2 != NULL)
+        m_child2->dump(writer, indent + 1);
+    if (m_child3 != NULL)
+        m_child3->dump(writer, indent + 1);
+}
+
+/**
+ * @brief Returns the name of the variable.
+ *
+ * @return  the name
+ */
+const QByteArray& ReASVarDefinition::name() const
+{
+    ReASNamedValue* namedValue = dynamic_cast<ReASNamedValue*>(m_child2);
+    const QByteArray& rc = namedValue->name();
+    return rc;
+}
+
+/**
+ * @brief Returns the data type (class) of the variable.
+ *
+ * @return  the data type
+ */
+ReASClass* ReASVarDefinition::clazz() const
+{
+    ReASNamedValue* namedValue = dynamic_cast<ReASNamedValue*>(m_child2);
+    ReASClass* rc = namedValue == NULL ? NULL : namedValue->clazz();
+    return rc;
+}
+/**
+ * @brief Returns the column of the scope end.
+ *
+ * 0 means end of method or end of class
+ *
+ * @return 0 or the column of the scope end
+ */
+int ReASVarDefinition::endOfScope() const
+{
+    return m_endOfScope;
+}
+
+/**
+ * @brief Sets the column of the scope end.
+ *
+ * @param endOfScope    the column of the scope end
+ */
+void ReASVarDefinition::setEndOfScope(int endOfScope)
+{
+    m_endOfScope = endOfScope;
+}
+
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASVarDefinition::check(ReParser& parser)
+{
+    ReASNamedValue* var = dynamic_cast<ReASNamedValue*>(m_child2);
+
+    bool rc = var != NULL && (m_child3 == NULL || m_child3->check(parser));
+    if (! rc)
+        ensureError(parser, "ReASVarDefinition::check");
+    else {
+        if (m_child3 != NULL){
+            // with initialization:
+            ReASCalculable* expr = dynamic_cast<ReASCalculable*>(m_child3);
+            if (expr == NULL)
+                rc = error(LOC_VARDEF_CHECK_1, parser,
+                           "Not a calculable expression: %s",
+                           m_child3->nameOfItemType());
+            else if (! typeCheck(var->clazz(), expr->clazz()))
+                rc = error(LOC_VARDEF_CHECK_2, parser,
+                             "data types are not compatible: %s/%s",
+                             var->clazz()->name().constData(),
+                             expr->clazz() == NULL ? "?"
+                                : expr->clazz()->name().constData());
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Executes the statement.
+ *
+ * @return  0: continue the current statement list<br>
+ */
+int ReASVarDefinition::execute(ReVMThread& thread)
+{
+    if (m_child3 != NULL){
+        // has an initialization:
+        ReASNamedValue* var = dynamic_cast<ReASNamedValue*>(m_child2);
+        ReASCalculable* expr = dynamic_cast<ReASCalculable*>(m_child3);
+        expr->calc(thread);
+        ReASVariant& value = thread.popValue();
+        ReASVariant& destination = thread.valueOfVariable(
+                    var->m_symbolSpace, var->m_variableNo);
+        if (thread.tracing())
+            thread.vm()->traceWriter()->format("%s = %.80s [%.80s]",
+                        var->m_name.constData(),
+                        value.toString().constData(),
+                        destination.toString().constData());
+        destination.copyValue(value);
+    }
+    return 0;
+}
+
+/** @class ReASExprStatement rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an statement consisting of an expression.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: expression
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReASExprStatement::ReASExprStatement() :
+    ReASNode2(AST_EXPR_STATEMENT),
+    ReASStatement()
+{
+    m_flags |= NF_STATEMENT;
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASExprStatement::check(ReParser& parser)
+{
+    bool rc = m_child2->check(parser);
+    if (rc){
+        ReASCalculable* expr = dynamic_cast<ReASCalculable*> (m_child2);
+        if (expr == NULL)
+            rc = ensureError(parser, "ReASExprStatement::check");
+    }
+    return rc;
+}
+/**
+ * @brief Executes the statement.
+ *
+ * @return  0: continue the current statement list<br>
+ */
+int ReASExprStatement::execute(ReVMThread& thread)
+{
+    ReASCalculable* expr = dynamic_cast<ReASCalculable*> (m_child2);
+    expr->calc(thread);
+    ReASVariant& value = thread.popValue();
+    if (thread.tracing())
+        thread.vm()->traceWriter()->format("expr: %s",
+                    value.toString().constData());
+    value.destroyValue();
+    return 0;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+
+void ReASExprStatement::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    if (m_id == 40)
+        m_id = 40;
+    writer.formatIndented(indent, "Expr id: %d expr: %d succ: %d %s", m_id,
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    if (m_child2 != NULL)
+        m_child2->dump(writer, indent + 1);
+}
+
+/** @class ReASNode1 rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an inner node of the abstract syntax tree with one child.
+ *
+ * This class is an abstract class.
+ */
+
+/**
+ * @brief ReASNode1::ReASNode1
+ * @param type
+ */
+ReASNode1::ReASNode1(ReASItemType type) :
+    ReASItem(type),
+    m_child(NULL)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASNode1::~ReASNode1()
+{
+    delete m_child;
+    m_child = NULL;
+}
+/**
+ * @brief Returns the child.
+ *
+ * @return  the child of the instance
+ */
+ReASItem* ReASNode1::child() const
+{
+    return m_child;
+}
+/**
+ * @brief Sets the child.
+ */
+void ReASNode1::setChild(ReASItem* child)
+{
+    m_child = child;
+}
+
+/**
+ * @brief Writes the internals of a statement list into a file.
+ *
+ * @param writer        writes to output media
+ * @param indent        the indent level of the statement list
+ * @param statements    the chain of statements to dump
+ */
+void ReASNode1::dumpStatements(ReWriter& writer, int indent,
+                                ReASItem* statements)
+{
+    ReASNode1* chain = dynamic_cast<ReASNode1*>(statements);
+    while (chain != NULL){
+        chain->dump(writer, indent);
+        chain = dynamic_cast<ReASNode1*>(chain->m_child);
+    }
+}
+
+
+/** @class ReASNode2 rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an inner node of the abstract syntax tree with two childs.
+ *
+ * This class is an abstract class.
+ */
+
+/**
+ * @brief ReASNode2::ReASNode2
+ * @param type
+ */
+ReASNode2::ReASNode2(ReASItemType type) :
+    ReASNode1(type),
+    m_child2(NULL)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASNode2::~ReASNode2()
+{
+    delete m_child2;
+    m_child2 = NULL;
+}
+ReASItem* ReASNode2::child2() const
+{
+    return m_child2;
+}
+
+void ReASNode2::setChild2(ReASItem* child2)
+{
+    m_child2 = child2;
+}
+
+
+/** @class ReASNode3 rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an inner node of the abstract syntax tree with 3 childs.
+ *
+ * This class is an abstract class.
+ */
+
+/**
+ * @brief ReASNode3::ReASNode3
+ * @param type
+ */
+ReASNode3::ReASNode3(ReASItemType type) :
+    ReASNode2(type),
+    m_child3(NULL)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASNode3::~ReASNode3()
+{
+    delete m_child3;
+    m_child3 = NULL;
+}
+/**
+ * @brief Returns the child3.
+ *
+ * @return  the child 3
+ */
+ReASItem* ReASNode3::child3() const
+{
+    return m_child3;
+}
+
+/**
+ * @brief Sets the child3.
+ *
+ * @param child3    the new child3
+ */
+void ReASNode3::setChild3(ReASItem* child3)
+{
+    m_child3 = child3;
+}
+
+
+/** @class ReASNode4 rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an inner node of the abstract syntax tree with 3 childs.
+ *
+ * This class is an abstract class.
+ */
+
+/**
+ * @brief ReASNode4::ReASNode4
+ * @param type
+ */
+ReASNode4::ReASNode4(ReASItemType type) :
+    ReASNode3(type),
+    m_child4(NULL)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASNode4::~ReASNode4()
+{
+    delete m_child4;
+    m_child4 = NULL;
+}
+
+/**
+ * @brief Returns the child4.
+ *
+ * @return  the child 4
+ */
+ReASItem* ReASNode4::child4() const
+{
+    return m_child4;
+}
+
+/**
+ * @brief Sets the child4.
+ *
+ * @param child4    the new child3
+ */
+void ReASNode4::setChild4(ReASItem* child4)
+{
+    m_child4 = child4;
+}
+
+
+/** @class ReASNode5 rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an inner node of the abstract syntax tree with 4 childs.
+ *
+ * This class is an abstract class.
+ */
+
+/**
+ * @brief ReASNode5::ReASNode5
+ * @param type
+ */
+ReASNode5::ReASNode5(ReASItemType type) :
+    ReASNode4(type),
+    m_child5(NULL)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASNode5::~ReASNode5()
+{
+    delete m_child5;
+    m_child5 = NULL;
+}
+
+/**
+ * @brief Returns the child5.
+ *
+ * @return  the child 5
+ */
+ReASItem* ReASNode5::child5() const
+{
+    return m_child5;
+}
+
+/**
+ * @brief Sets the child5.
+ *
+ * @param child5    the new child3
+ */
+void ReASNode5::setChild5(ReASItem* child5)
+{
+    m_child5 = child5;
+}
+
+/** @class ReASNode6 rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an inner node of the abstract syntax tree with 4 childs.
+ *
+ * This class is an abstract class.
+ */
+
+/**
+ * @brief ReASNode6::ReASNode6
+ * @param type
+ */
+ReASNode6::ReASNode6(ReASItemType type) :
+    ReASNode5(type),
+    m_child6(NULL)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASNode6::~ReASNode6()
+{
+    delete m_child6;
+    m_child6 = NULL;
+}
+
+/**
+ * @brief Returns the child5.
+ *
+ * @return  the child 5
+ */
+ReASItem* ReASNode6::child6() const
+{
+    return m_child6;
+}
+
+/**
+ * @brief Sets the child6.
+ *
+ * @param child6    the new child6
+ */
+void ReASNode6::setChild6(ReASItem* child6)
+{
+    m_child6 = child6;
+}
+
+/** @class ReASUnaryOp rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an unary operation.
+ *
+ * This is an operation with one operand, e.g. the boolean 'not' operation.
+ *
+ * <code>m_child</code>: operand
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param op    the operator id
+ * @param type  the node type
+ */
+ReASUnaryOp::ReASUnaryOp(UnaryOp op, ReASItemType type) :
+    ReASNode1(type),
+    m_operator(op)
+{
+}
+
+/**
+ * @brief Calculates the value of the unary operator.
+ *
+ * @param thread    IN/OUT: the execution unit, a VM thread
+ */
+void ReASUnaryOp::calc(ReVMThread& thread)
+{
+    ReASVariant& value = thread.topOfValues();
+    switch(m_operator){
+    case UOP_PLUS:
+        break;
+    case UOP_MINUS_INT:
+        value.setInt(- value.asInt());
+        break;
+    case UOP_MINUS_FLOAT:
+        value.setFloat(- value.asFloat());
+        break;
+    case UOP_NOT_BOOL:
+        value.setBool(! value.asBool());
+        break;
+    case UOP_NOT_INT:
+        value.setInt(~value.asInt());
+        break;
+    case UOP_DEC:
+    case UOP_INC:
+    default:
+        error(thread.logger(), LOC_UNOP_CALC_1, "unknown operator: %d", m_operator);
+        break;
+    }
+    if (thread.tracing())
+        thread.vm()->traceWriter()->format("unary %s: %s",
+                    nameOfOp(m_operator),
+                    value.toString().constData());
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASUnaryOp::check(ReParser& parser)
+{
+    bool rc = m_child->check(parser);
+    if (rc){
+        ReASCalculable* expr = dynamic_cast<ReASCalculable*>(m_child);
+        ReASClass* clazz = expr == NULL ? NULL : expr->clazz();
+        if (clazz == NULL){
+            rc = ensureError(parser, "ReASUnaryOp::check");
+        } else {
+            switch(m_operator){
+            case UOP_PLUS:
+                if (clazz != ReASInteger::m_instance
+                        && clazz != ReASFloat::m_instance)
+                    rc = error(LOC_UNARY_CHECK_1, parser,
+                                 "wrong data type for unary operator '+': %s",
+                                 clazz->name().constData());
+                break;
+            case UOP_MINUS_INT:
+                if (clazz != ReASFloat::m_instance)
+                    m_operator = UOP_MINUS_FLOAT;
+                else if (clazz != ReASInteger::m_instance)
+                    rc = error(LOC_UNARY_CHECK_2, parser,
+                                 "wrong data type for unary operator '-': %s",
+                                 clazz->name().constData());
+                break;
+            case UOP_NOT_BOOL:
+                if (clazz != ReASBoolean::m_instance)
+                    rc = error(LOC_UNARY_CHECK_3, parser,
+                                 "wrong data type for unary operator '!': %s",
+                                 clazz->name().constData());
+                break;
+            case UOP_NOT_INT:
+                if (clazz != ReASInteger::m_instance)
+                    rc = error(LOC_UNARY_CHECK_4, parser,
+                                 "wrong data type for unary operator '!': %s",
+                                 clazz->name().constData());
+                break;
+            case UOP_DEC:
+                break;
+            case UOP_INC:
+                break;
+            default:
+                throw ReASException(position(), "unknown operator: %d", m_operator);
+                break;
+            }
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns the operator of the unary operation.
+ *
+ * @return the operator
+ */
+int ReASUnaryOp::getOperator() const
+{
+    return m_operator;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASUnaryOp::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "Unary %d op: %s (%d) expr: %d %s",
+            m_id,
+            nameOfOp(m_operator),
+            m_operator,
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer) );
+    if (m_child != NULL)
+        m_child->dump(writer, indent + 1);
+}
+/**
+ * @brief Returns the name (a string) of an unary operator.
+ *
+ * @param op    the operand to convert
+ * @return      the name of the operator
+ */
+const char*ReASUnaryOp::nameOfOp(ReASUnaryOp::UnaryOp op)
+{
+    const char* rc;
+    switch (op){
+    case UOP_PLUS:
+        rc="+";
+        break;
+    case UOP_MINUS_INT:
+    case UOP_MINUS_FLOAT:
+        rc="-";
+        break;
+    case UOP_NOT_BOOL:
+        rc="!";
+        break;
+    case UOP_NOT_INT:
+        rc="~";
+        break;
+    case UOP_INC:
+        rc="++";
+        break;
+    case UOP_DEC:
+        rc="--";
+        break;
+    default:
+        throw ReException("unknown unary operator: %d", (int) op);
+        break;
+    }
+    return rc;
+}
+
+
+/** @class ReASStatement rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a base class for all statements.
+ *
+ * @note statements are always <code>ReASNode1</code> and m_child is used
+ * for the successors (next statement).
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReASStatement::ReASStatement()
+{
+}
+/**
+ * @brief Executes the statements of a statement list.
+ *
+ * @param list      statement list
+ * @param thread    execution unit
+ * @return  0: continue the current statement list<br>
+ *          n > 0: stop the n most inner statement lists (initialized by leave)
+ *          n < 0: stop the -n most inner statement lists (initialized by continue)
+ */
+int ReASStatement::executeStatementList(ReASItem* list, ReVMThread& thread)
+{
+    int rc = 0;
+    while(rc == 0 && list != NULL){
+        ReASStatement* statement = dynamic_cast<ReASStatement*>(list);
+        rc =statement->execute(thread);
+    }
+    return rc;
+}
+
+
+/** @class ReASIf rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an if statement.
+ *
+ * The if statement has a condition, a then-part and an optional else-part.
+ * If the condition is evaluated to true, the then-part will be executed.
+ * Otherwise the else-part if it exists.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: condition<br>
+ * <code>m_child3</code>: then part<br>
+ * <code>m_child4</code>: else part or NULL<br>
+ */
+
+ReASIf::ReASIf() :
+    ReASNode4(AST_IF)
+{
+    m_flags |= NF_STATEMENT;
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASIf::check(ReParser& parser)
+{
+    bool rc = true;
+    if (m_child2 == NULL)
+        rc = ensureError(parser, "'if' misses condition");
+    else if (m_child2->checkAsCalculable("condition", ReASBoolean::m_instance,
+                                         parser))
+        rc = false;
+    if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
+        rc = false;
+    if (m_child4 != NULL && ! checkStatementList(m_child4, parser))
+        rc = false;
+    return rc;
+}
+
+/**
+ * @brief Executes the statement.
+ *
+ * @return  0: continue the current statement list<br>
+ *          n > 0: stop the n most inner statement lists (initialized by leave)
+ *          n < 0: stop the -n most inner statement lists (initialized by continue)
+ */
+int ReASIf::execute(ReVMThread& thread)
+{
+    int rc = 0;
+    bool condition = calcAsBoolean(m_child2, thread);
+    if (thread.tracing())
+        thread.vm()->traceWriter()->format("if %s", condition ? "true" : "false");
+
+    ReASItem* list = condition ? m_child3 : m_child4;
+    if (list != NULL){
+        if ( (rc = executeStatementList(list, thread)) != 0){
+            if (rc < 0)
+                rc--;
+            else if (rc > 0)
+                rc++;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASIf::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent,
+           "If id: %d condition: %d then: %d else: %d succ: %d%s",
+            m_id,
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_child4 == NULL ? 0 : m_child4->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    m_child2->dump(writer, indent + 1);
+    if (m_child3 != NULL)
+        m_child3->dump(writer, indent + 1);
+    if (m_child4 != NULL)
+        m_child4->dump(writer, indent + 1);
+}
+
+/** @class ReASFor rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a for statement.
+ *
+ * The for statement has an initialization, a condition, a forwarding
+ * statement and a body.
+ * The initialization will be called first.
+ * Then the condition will be tested. If true the body will be executed
+ * and then the forwarding statement.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: body<br>
+ * <code>m_child3</code>: iterator variable<br>
+ * <code>m_child4</code>: container variable<br>
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param variable      NULL or the iterator variable
+ */
+ReASForIterated::ReASForIterated(ReASVarDefinition* variable) :
+    ReASNode4(AST_ITERATED_FOR),
+    ReASStatement()
+{
+    m_flags |= NF_STATEMENT;
+    m_child2 = variable;
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASForIterated::check(ReParser& parser)
+{
+    return false;
+}
+
+/**
+ * @brief Executes the statement.
+ *
+ * @return  0: continue the current statement list<br>
+ *          n > 0: stop the n most inner statement lists (initialized by leave)
+ *          n < 0: stop the -n most inner statement lists (initialized by continue)
+ */
+int ReASForIterated::execute(ReVMThread& thread)
+{
+    return 0;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASForIterated::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "forIt id: %d var: %d set: %d body: %d succ: %d %s",
+            m_id,
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_child4 == NULL ? 0 : m_child4->id(),
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    if (m_child3 != NULL)
+        m_child3->dump(writer, indent + 1);
+    if (m_child4 != NULL)
+        m_child4->dump(writer, indent + 1);
+    dumpStatements(writer, indent + 1, m_child2);
+}
+
+/** @class ReASForCounted rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a for statement.
+ *
+ * The for statement has an optional variable, an optional start value,
+ * an end value, an optional step and a body.
+ *
+ * The start and end value will be calculated.
+ * The body will be executed so many times given by the start and end value.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: body<br>
+ * <code>m_child3</code>: variable or NULL<br>
+ * <code>m_child4</code>: start value or NULL<br>
+ * <code>m_child5</code>: end value<br>
+ * <code>m_child6</code>: step value or NULL
+ *
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param variable      NULL or the counter variable
+ */
+ReASForCounted::ReASForCounted(ReASVarDefinition* variable) :
+    ReASNode6(AST_ITERATED_FOR),
+    ReASStatement()
+{
+    m_flags |= NF_STATEMENT;
+    m_child3 = variable;
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASForCounted::check(ReParser& parser)
+{
+    bool rc = true;
+    ReASNamedValue* var = NULL;
+    if (m_child3 != NULL){
+        var = dynamic_cast<ReASNamedValue*>(m_child3);
+        if (! m_child3->check(parser))
+            rc = false;
+        if (var == NULL)
+            rc = error(LOC_FORC_CHECK_1, parser, "not a variable: %s",
+                  m_child3->nameOfItemType());
+    }
+    ReASCalculable* expr;
+    if (m_child4 != NULL && ! m_child4->checkAsCalculable("start value",
+            ReASInteger::m_instance, parser))
+        rc = false;
+    if (m_child5 != NULL && ! m_child5->checkAsCalculable("end value",
+            ReASInteger::m_instance, parser))
+        rc = false;
+    if (m_child6 != NULL && ! m_child6->checkAsCalculable("step value",
+            ReASInteger::m_instance, parser))
+        rc = false;
+    if (m_child2 != NULL && ! checkStatementList(m_child2, parser))
+        rc = false;
+    return rc;
+}
+
+/**
+ * @brief Executes the statement.
+ *
+ * @return  0: continue the current statement list<br>
+ *          n > 0: stop the n most inner statement lists (initialized by leave)
+ *          n < 0: stop the -n most inner statement lists (initialized by continue)
+ */
+int ReASForCounted::execute(ReVMThread& thread)
+{
+    int rc = 0;
+    ReASStatement* body = dynamic_cast<ReASStatement*>(m_child2);
+    if (body == NULL)
+        throw ReASException(m_child2 == NULL ? m_position : m_child2->position(),
+                             "forc statement: body is not a statement");
+    int start = m_child4 == NULL ? 1 : calcAsInteger(m_child4, thread);
+    int end = m_child5 == NULL ? 0 : calcAsInteger(m_child5, thread);
+    int step = m_child6 == NULL ? 1 : calcAsInteger(m_child6, thread);
+    ReASNamedValue* var = m_child3 == NULL
+            ? NULL : dynamic_cast<ReASNamedValue*>(m_child3);
+    if (thread.tracing())
+        thread.vm()->traceWriter()->format("for %s from %d to %d step %d",
+            var == NULL ? "?" : var->name().constData(),
+            start, end, step);
+
+    for(int ii = start; ii <= end; ii += step){
+        //@ToDo: assign to the variable
+        int rc2 = body->execute(thread);
+        if (rc2 != 0){
+            if (rc2 > 0){
+                // rc comes from "break";
+                rc = rc2 - 1;
+            } else {
+                // rc comes from "continue";
+                if (rc2 == -1)
+                    continue;
+                else
+                    rc = rc2 + 1;
+            }
+            break;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASForCounted::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "forC id: %d var: %d from: %d to: %d step: %d body: %d succ: %d %s",
+            m_id,
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_child4 == NULL ? 0 : m_child4->id(),
+            m_child5 == NULL ? 0 : m_child5->id(),
+            m_child6 == NULL ? 0 : m_child6->id(),
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    if (m_child3 != NULL)
+        m_child3->dump(writer, indent + 1);
+    if (m_child4 != NULL)
+        m_child4->dump(writer, indent + 1);
+    if (m_child5 != NULL)
+        m_child5->dump(writer, indent + 1);
+    if (m_child6 != NULL)
+        m_child6->dump(writer, indent + 1);
+    dumpStatements(writer, indent + 1, m_child2);
+}
+
+/** @class ReASWhile rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a while statement.
+ *
+ * The while statement has an a condition and a body.
+ * The body will be executed while the condition returns true.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: condition<br>
+ * <code>m_child3</code>: body<br>
+ */
+
+ReASWhile::ReASWhile() :
+    ReASNode3(AST_WHILE),
+    ReASStatement()
+{
+    m_flags |= NF_STATEMENT;
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASWhile::check(ReParser& parser)
+{
+    bool rc = true;
+    if (m_child2 == NULL)
+        ensureError(parser, "missing condition for 'while''");
+    else
+        rc = m_child2->checkAsCalculable("condition", ReASBoolean::m_instance,
+                                         parser);
+    if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
+        rc = false;
+    return rc;
+}
+
+/**
+ * @brief Executes the statement.
+ *
+ * @return  0: continue the current statement list<br>
+ *          n > 0: stop the n most inner statement lists (initialized by leave)
+ *          n < 0: stop the -n most inner statement lists (initialized by continue)
+ */
+int ReASWhile::execute(ReVMThread& thread)
+{
+    int rc = 0;
+    ReASStatement* body = dynamic_cast<ReASStatement*>(m_child3);
+    if (thread.tracing())
+        thread.vm()->traceWriter()->write("while");
+    while(calcAsBoolean(m_child2, thread)){
+        int rc2 = body->execute(thread);
+        if (rc2 != 0){
+            if (rc2 > 0){
+                // rc comes from "break";
+                rc = rc2 - 1;
+            } else {
+                // rc comes from "continue";
+                if (rc2 == -1)
+                    continue;
+                else
+                    rc = rc2 + 1;
+            }
+            break;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASWhile::dump(ReWriter& writer, int indent)
+{
+
+    char buffer[256];
+    writer.formatIndented(indent, "while id: %d condition: %d body: %d succ: %d %s",
+            m_id,
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    if (m_child2 != NULL)
+        m_child2->dump(writer, indent + 1);
+    dumpStatements(writer, indent + 1, m_child3);
+}
+
+/** @class ReASRepeat rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a while statement.
+ *
+ * The while statement has an a condition and a body.
+ * The body will be executed while the condition returns true.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: condition<br>
+ * <code>m_child3</code>: body<br>
+ */
+
+ReASRepeat::ReASRepeat() :
+    ReASNode3(AST_REPEAT),
+    ReASStatement()
+{
+    m_flags |= NF_STATEMENT;
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASRepeat::check(ReParser& parser)
+{
+    bool rc = true;
+    if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
+        rc = false;
+    if (m_child2 == NULL)
+        ensureError(parser, "missing condition for 'repeat''");
+    else if (! m_child2->checkAsCalculable("condition", ReASBoolean::m_instance,
+                                         parser))
+        rc = false;
+    return rc;
+}
+
+/**
+ * @brief Executes the statement.
+ *
+ * Meaning of the childs:
+ * m_child: body
+ * m_child2: condition
+ */
+int ReASRepeat::execute(ReVMThread& thread)
+{
+    int rc = 0;
+    ReASStatement* body = dynamic_cast<ReASStatement*>(m_child3);
+    if (thread.tracing())
+        thread.vm()->traceWriter()->write("repeat");
+    do {
+        int rc2 = body->execute(thread);
+        if (rc2 != 0){
+            if (rc2 > 0){
+                // rc comes from "break";
+                rc = rc2 - 1;
+            } else {
+                // rc comes from "continue";
+                if (rc2 == -1)
+                    continue;
+                else
+                    rc = rc2 + 1;
+            }
+            break;
+        }
+    } while(! calcAsBoolean(m_child2, thread));
+    return rc;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASRepeat::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "repeat id: %d condition: %d body: %d succ: %d %s",
+            m_id,
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    if (m_child2 != NULL)
+        m_child2->dump(writer, indent + 1);
+    dumpStatements(writer, indent + 1, m_child3);
+}
+
+/** @class ReASClass rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the base class of an Abstract Syntax Tree class.
+ *
+ * This class is abstract.
+ */
+/**
+ * @brief Constructor.
+ */
+ReASClass::ReASClass(const QByteArray& name, ReASTree& tree) :
+    m_name(name),
+    m_symbols(NULL),
+    m_superClass(NULL),
+    m_tree(tree)
+{
+}
+
+/**
+ * @brief Destructor.
+ *
+ * Does nothing but forces a virtual destructor of all derived classes.
+ *
+ */
+ReASClass::~ReASClass()
+{
+
+}
+
+/**
+ * @brief Return the class name.
+ *
+ * @return the class name
+ */
+const QByteArray& ReASClass::name() const
+{
+    return m_name;
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASClass::dump(ReWriter& writer, int indent)
+{
+    writer.formatIndented(indent, "class %s super: %s", m_name.constData(),
+            m_superClass == NULL
+                ? "<none>" : m_superClass->name().constData());
+    m_symbols->dump(writer, indent);
+}
+
+/**
+ * @brief Sets the symbol space from the current in the tree.
+ */
+void ReASClass::setSymbols()
+{
+    m_symbols = m_tree.currentSpace();
+}
+
+/** @class ReASTree rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a manager for all parts of an Abstract Syntax Tree.
+ *
+ * It contains the global symbol space and maintainance a list of used modules.
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReASTree::ReASTree() :
+    m_global(NULL),
+    m_modules(),
+    m_symbolSpaces(),
+    m_currentSpace(NULL),
+    m_store(128*1024)
+{
+    init();
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASTree::~ReASTree()
+{
+    destroy();
+}
+
+/**
+ * @brief Initializes the instance.
+ *
+ * Used in the constructor and in clear.
+ */
+void ReASTree::init()
+{
+    m_global = ReSymbolSpace::createGlobal(*this);
+    m_symbolSpaces.append(m_global);
+    m_currentSpace = m_global;
+}
+
+/**
+ * @brief Frees the resources of the instance.
+ */
+void ReASTree::destroy()
+{
+    SymbolSpaceMap::iterator it;
+    for (it = m_symbolSpaceHeap.begin(); it != m_symbolSpaceHeap.end(); it++){
+        delete it.value();
+    }
+    m_symbolSpaceHeap.clear();
+}
+/**
+ * @brief Returns the string storage of the instance.
+ *
+ * @return  the efficient allocator for C strings
+ */
+ReByteStorage& ReASTree::store()
+{
+    return m_store;
+}
+
+/**
+ * @brief Handles the start of a new module.
+ *
+ * @param name  the module's name
+ * @return      true: the module is new<br>
+ *              false: the module is yet known
+ */
+bool ReASTree::startModule(ReSourceUnitName name)
+{
+    bool rc = m_modules.contains(name);
+    if (! rc){
+        // freed in ~ReASTree()
+        ReSymbolSpace* space = new ReSymbolSpace(ReSymbolSpace::SST_MODULE,
+            name, m_global);
+        m_symbolSpaceHeap[name] = space;
+        m_modules[name] = space;
+        m_symbolSpaces.append(space);
+        m_currentSpace = space;
+    }
+    return rc;
+}
+/**
+ * @brief Search for the symbol space of a given module.
+ *
+ * @param name  the module's name
+ * @return      NULL: not found<br>
+ *              otherwise: the symbol space of the module
+ */
+ReSymbolSpace* ReASTree::findmodule(const QByteArray& name)
+{
+    ReSymbolSpace* rc = m_modules.contains(name) ? m_modules[name] : NULL;
+    return rc;
+}
+
+/**
+ * @brief Handles the end of a module.
+ * @param name  the module's name
+ */
+void ReASTree::finishModule(ReSourceUnitName name)
+{
+    ReSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    if (top->name() != name)
+        throw ReException("ReASTree::finishModule(): module is not top: %s",
+                           name);
+    else {
+        m_symbolSpaces.removeLast();
+        // "global" is always the bottom:
+        m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    }
+}
+
+/**
+ * @brief Handles the start of a new class definition.
+ * @param name      name of the class/method
+ * @param type      the symbol space type
+ * @return          the new symbol space
+ */
+ReSymbolSpace* ReASTree::startClassOrMethod(const QByteArray& name,
+        ReSymbolSpace::SymbolSpaceType type)
+{
+    // the stack m_modules is never empty because of "global" and modules.
+    ReSymbolSpace* parent = m_symbolSpaces[m_symbolSpaces.size() - 1];
+    QByteArray fullName = parent->name() + "." + name;
+    // freed in ~ReASTree()
+    ReSymbolSpace* space = new ReSymbolSpace(type, fullName, parent);
+    m_symbolSpaceHeap[fullName] = space;
+    m_symbolSpaces.append(space);
+    m_currentSpace = space;
+    return space;
+}
+
+/**
+ * @brief Handles the end of a class definition.
+ *
+ * @param name  the name of the class (short form)
+ */
+void ReASTree::finishClassOrMethod(const QByteArray& name)
+{
+    ReSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    if (! top->name().endsWith("." + name))
+        throw ReException("ReASTree::finishModule(): class is not top: %s",
+                           name.constData());
+    else {
+        m_symbolSpaces.removeLast();
+        // "global" is the bottom always!
+        m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+    }
+}
+
+/**
+ * @brief Returns the stack of the symbol spaces.
+ *
+ * @return the stack with the active symbol spaces
+ */
+ReASTree::SymbolSpaceStack& ReASTree::symbolSpaces()
+{
+    return m_symbolSpaces;
+}
+/**
+ * @brief Returns the current symbol space (top of the stack).
+ *
+ * @return the current symbol space
+ */
+ReSymbolSpace* ReASTree::currentSpace() const
+{
+    return m_currentSpace;
+}
+
+/**
+ * @brief Removes all content from the abstract syntax tree.
+ */
+void ReASTree::clear()
+{
+    destroy();
+    //m_global->clear();
+    m_modules.clear();
+    m_symbolSpaces.clear();
+    init();
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param filename      filename
+ * @param flags         what to dump: sum of DMP_... flags
+ * @param header        NULL or a text put on the top
+ */
+void ReASTree::dump(const char* filename, int flags, const char* header)
+{
+    ReFileWriter writer(filename);
+    if (header != NULL)
+        writer.writeLine(header);
+    if (flags & DMP_GLOBALS){
+        m_global->dump(writer, 0, "=== Globals:");
+    }
+    if (flags & DMP_MODULES){
+        QList<QByteArray> sorted;
+        sorted.reserve(m_modules.size());
+        SymbolSpaceMap::iterator it;
+        for (it = m_modules.begin(); it != m_modules.end(); it++){
+           sorted.append(it.key());
+        }
+        qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
+        QList<QByteArray>::iterator it2;
+        for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
+            ReSymbolSpace* space = m_modules[*it2];
+            space->dump(writer, 0);
+        }
+    }
+    writer.close();
+}
+
+/** @class ReASMethodCall rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a method or function call for the Abstract Syntax Tree.
+ *
+ * <code>m_child</code>: next statement<br>
+ * <code>m_child2</code>: argument list<br>
+ * <code>m_child3</code>: parent (variable, field ...)
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param name      name of the method/function
+ * @param parent    NULL: it is a function<br>
+ *                  otherwise: the parent (variable, field ...)
+ */
+
+ReASMethodCall::ReASMethodCall(const QByteArray& name, ReASItem* parent) :
+    ReASNode3(AST_METHOD_CALL),
+    ReASStatement(),
+    m_name(name),
+    m_method(NULL)
+{
+    m_flags |= NF_STATEMENT;
+    m_child3 = parent;
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASMethodCall::check(ReParser& parser)
+{
+    bool rc = true;
+    ReASExprStatement* args = dynamic_cast<ReASExprStatement*>(m_child2);
+    int argCount = 0;
+    ReASMethod* method = m_method;
+    ReASVarDefinition* params = dynamic_cast<ReASVarDefinition*>(method->child2());
+    while (args != NULL && params != NULL){
+        argCount++;
+        ReASCalculable* argExpr = dynamic_cast<ReASCalculable*>
+                (args->child2());
+        if (argExpr == NULL)
+            rc = error(LOC_METHOD_CALL_CHECK_1, parser,
+                       "argument %d misses expr", argCount);
+        else {
+            ReASNamedValue* var;
+            ReASItem* param = params->child2();
+            if (param == NULL
+                    || (var = dynamic_cast<ReASNamedValue*>(param)) == NULL)
+                rc = error(LOC_MEHTOD_CALL_CHECK_2, parser,
+                    "parameter %d misses named value: %s", argCount,
+                    param == NULL ? "<null>" : param->nameOfItemType());
+            else {
+                // tryConversion() calls args->args->child2()->check()!
+                ReASConversion* converter = ReASConversion::tryConversion(
+                            var->clazz(), args->child2(), parser, rc);
+                if (rc && converter != NULL)
+                    args->setChild2(converter);
+
+            }
+        }
+        args = dynamic_cast<ReASExprStatement*>(args->child());
+        params = dynamic_cast<ReASVarDefinition*>(params->child());
+    }
+    if (args != NULL && params == NULL)
+        rc = error(LOC_MEHTOD_CALL_CHECK_3, parser,
+            "too many arguments: %d are enough", argCount);
+    else if (args == NULL && params != NULL && params->child3() != NULL)
+        rc = error(LOC_MEHTOD_CALL_CHECK_4, parser,
+            "too few arguments: %d are not enough", argCount);
+    return rc;
+}
+
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASMethodCall::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "call %s Id: %d args: %d parent: %d succ: %d %s",
+            m_name.constData(), m_id,
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    if (m_child2 != NULL)
+        m_child2->dump(writer, indent + 1);
+    if (m_child3 != NULL)
+        m_child3->dump(writer, indent + 1);
+}
+
+/**
+ * @brief Executes the method call.
+ *
+ * @return  0: continue the current statement list
+ */
+int ReASMethodCall::execute(ReVMThread& thread)
+{
+    int rc = 0;
+    ReASMethod* method = m_method;
+    ReStackFrame frame(this, m_method->symbols());
+    thread.pushFrame(&frame);
+    ReASExprStatement* args = dynamic_cast<ReASExprStatement*>(m_child2);
+    int ixArg = -1;
+    while (args != NULL){
+        ixArg++;
+        ReASCalculable* argExpr = dynamic_cast<ReASCalculable*>
+                (args->child2());
+        argExpr->calc(thread);
+        ReASVariant& value = thread.popValue();
+        ReASVariant& varValue = frame.valueOfVariable(ixArg);
+        varValue.copyValue(value);
+    }
+    thread.popFrame();
+    return rc;
+}
+
+ReASMethod* ReASMethodCall::method() const
+{
+    return m_method;
+}
+
+/**
+ * @brief Sets the method.
+ * @param method    method to set
+ */
+void ReASMethodCall::setMethod(ReASMethod* method)
+{
+    m_method = method;
+}
+
+/**
+ * @brief Returns the argument list.
+ *
+ * @return  the first element of an argument list
+ */
+ReASExprStatement* ReASMethodCall::arg1() const
+{
+    return dynamic_cast<ReASExprStatement*>(m_child2);
+}
+
+/** @class ReASException rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a call of a method or function.
+ *
+ * <code>m_child</code>: body
+ * <code>m_child2</code>: argument list (or NULL)
+ */
+
+/** @class ReASBinaryOp rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements binary operator for the Abstract Syntax Tree.
+ *
+ * <code>m_child</code>: left operand<br>
+ * <code>m_child2</code>: right operand
+ */
+/**
+ * @brief Constructor.
+ */
+ReASBinaryOp::ReASBinaryOp() :
+    ReASNode2(AST_BINARY_OP),
+    m_operator(BOP_UNDEF)
+{
+}
+
+/**
+ * @brief Calculates the binary operation.
+ *
+ * @param thread    IN/OUT: the bool value of the condition
+ */
+void ReASBinaryOp::calc(ReVMThread& thread)
+{
+    if (isAssignment())
+        assign(thread);
+    else{
+        ReASCalculable* op1 = dynamic_cast<ReASCalculable*>(m_child);
+        ReASCalculable* op2 = dynamic_cast<ReASCalculable*>(m_child2);
+        if (op1 == NULL || op2 == NULL)
+            error(thread.logger(), LOC_BINOP_CALC_1, "operand is null: %d / %d",
+                  m_child == NULL ? 0 : m_child->id(),
+                  m_child2 == NULL ? 0 : m_child2->id());
+        else{
+            op1->calc(thread);
+            op2->calc(thread);
+            ReASVariant& val1 = thread.top2OfValues();
+            ReASVariant& val2 = thread.topOfValues();
+            switch(m_operator){
+            case BOP_PLUS:
+                switch(val1.variantType()){
+                case ReASVariant::VT_FLOAT:
+                    val1.setFloat(val1.asFloat() + val2.asFloat());
+                    break;
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() + val2.asInt());
+                    break;
+                case ReASVariant::VT_OBJECT:
+                    //if (val1.getClass() == ReASString::m_instance)
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_2, "invalid type for '+': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_MINUS:
+                switch(val1.variantType()){
+                case ReASVariant::VT_FLOAT:
+                    val1.setFloat(val1.asFloat() - val2.asFloat());
+                    break;
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() - val2.asInt());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_3, "invalid type for '-': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_TIMES:
+                switch(val1.variantType()){
+                case ReASVariant::VT_FLOAT:
+                    val1.setFloat(val1.asFloat() * val2.asFloat());
+                    break;
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() * val2.asInt());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_4, "invalid type for '*': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_DIV:
+                switch(val1.variantType()){
+                case ReASVariant::VT_FLOAT:
+                    val1.setFloat(val1.asFloat() / val2.asFloat());
+                    break;
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() / val2.asInt());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_5, "invalid type for '/': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_MOD:
+                switch(val1.variantType()){
+                case ReASVariant::VT_FLOAT:
+                    val1.setFloat(fmod(val1.asFloat(), val2.asFloat()));
+                    break;
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() % val2.asInt());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_6, "invalid type for '%': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_POWER:
+                switch(val1.variantType()){
+                case ReASVariant::VT_FLOAT:
+                    val1.setFloat(fmod(val1.asFloat(), val2.asFloat()));
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_7, "invalid type for '**': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_LOG_OR:
+                switch(val1.variantType()){
+                case ReASVariant::VT_BOOL:
+                    val1.setBool(val1.asBool() || val2.asBool());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_8, "invalid type for '||': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_LOG_AND:
+                switch(val1.variantType()){
+                case ReASVariant::VT_BOOL:
+                    val1.setBool(val1.asBool() && val2.asBool());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_9, "invalid type for '&&': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_LOG_XOR:
+                switch(val1.variantType()){
+                case ReASVariant::VT_BOOL:
+                    val1.setBool(val1.asBool() != val2.asBool());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_9, "invalid type for '^^': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_BIT_OR:
+                switch(val1.variantType()){
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() | val2.asInt());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_10, "invalid type for '|': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_BIT_AND:
+                switch(val1.variantType()){
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() & val2.asInt());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_11, "invalid type for '&': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            case BOP_BIT_XOR:
+                switch(val1.variantType()){
+                case ReASVariant::VT_INTEGER:
+                    val1.setInt(val1.asInt() ^ val2.asInt());
+                    break;
+                default:
+                    error(thread.logger(), LOC_BINOP_CALC_12, "invalid type for '^': %s",
+                      val1.nameOfType());
+                    break;
+                }
+                break;
+            default:
+                break;
+            }
+            thread.popValue();
+        }
+    }
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASBinaryOp::check(ReParser& parser)
+{
+    return false;
+}
+
+/**
+ * @brief Returns the operator.
+ *
+ * @return the operator
+ */
+ReASBinaryOp::BinOperator ReASBinaryOp::getOperator() const
+{
+    return m_operator;
+}
+
+/**
+ * @brief Sets the operator.
+ *
+ * @param op    the operator
+ */
+void ReASBinaryOp::setOperator(BinOperator op)
+{
+    m_operator = op;
+}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASBinaryOp::dump(ReWriter& writer, int indent)
+{
+
+    const QByteArray& opName = nameOfOp(m_operator);
+    char buffer[256];
+    writer.formatIndented(indent, "BinOp id: %d op: %s (%d) left: %d right: %d %s",
+            m_id,
+            opName.constData(), m_operator,
+            m_child == NULL ? 0 : m_child->id(),
+            m_child2 == NULL ? 0 : m_child2->id(),
+            positionStr(buffer, sizeof buffer));
+    if (indent < 32 && m_child != NULL)
+        m_child->dump(writer, indent + 1);
+    if (indent < 32 && m_child2 != NULL)
+        m_child2->dump(writer, indent + 1);
+}
+
+/**
+ * @brief Does an assignment.
+ *
+ * @param thread
+ */
+void ReASBinaryOp::assign(ReVMThread& thread)
+{
+    ReASVariant& rValue = thread.lValue(m_child);
+    ReASCalculable* expr = dynamic_cast<ReASCalculable*>(m_child2);
+    if (expr == NULL)
+        error(thread.logger(), LOC_BINOP_1, "not a calculable: id: %d",
+              m_child2 == NULL ? 0 : m_child2->id());
+    else {
+        ReASVariant& value = thread.popValue();
+        switch(m_operator){
+        case BOP_ASSIGN:
+            break;
+        case BOP_PLUS_ASSIGN:
+            //switch(value.variantType()){
+
+            //}
+            break;
+        case BOP_MINUS_ASSIGN:
+        case BOP_TIMES_ASSIGN:
+        case BOP_DIV_ASSIGN:
+        case BOP_MOD_ASSIGN:
+        case BOP_POWER_ASSIGN:
+        case BOP_LOG_OR_ASSIGN:
+        case BOP_LOG_AND_ASSIGN:
+        case BOP_LOG_XOR_ASSIGN:
+        case BOP_BIT_OR_ASSIGN:
+        case BOP_BIT_AND_ASSIGN:
+        case BOP_BIT_XOR_ASSIGN:
+            break;
+        default:
+            break;
+        }
+        rValue.copyValue(value);
+    }
+}
+/**
+ * @brief Returns the name (a string) of a binary operator.
+ *
+ * @param op    operator to convert
+ *
+ * @return      the name of the operator
+ */
+const char* ReASBinaryOp::nameOfOp(ReASBinaryOp::BinOperator op)
+{
+    const char* rc;
+    switch (op){
+    case BOP_ASSIGN:
+        rc = "=";
+        break;
+    case BOP_PLUS_ASSIGN:
+        rc = "+=";
+        break;
+    case BOP_MINUS_ASSIGN:
+        rc = "-=";
+        break;
+    case BOP_TIMES_ASSIGN:
+        rc = "*=";
+        break;
+    case BOP_DIV_ASSIGN:
+        rc = "/=";
+        break;
+    case BOP_MOD_ASSIGN:
+        rc = "%=";
+        break;
+    case BOP_POWER_ASSIGN:
+        rc = "**=";
+        break;
+    case BOP_LOG_OR_ASSIGN:
+        rc = "||=";
+        break;
+    case BOP_LOG_AND_ASSIGN:
+        rc = "&&=";
+        break;
+    case BOP_LOG_XOR_ASSIGN:
+        rc = "^^=";
+        break;
+    case BOP_BIT_OR_ASSIGN:
+        rc = "|=";
+        break;
+    case BOP_BIT_AND_ASSIGN:
+        rc = "&=";
+        break;
+    case BOP_BIT_XOR_ASSIGN:
+        rc = "^=";
+        break;
+    case BOP_LSHIFT_ASSIGN:
+        rc = "<<=";
+        break;
+    case BOP_LOG_RSHIFT_ASSIGN:
+        rc = ">>=";
+        break;
+    case BOP_ARTITH_RSHIFT_ASSIGN:
+        rc = ">>>=";
+        break;
+    case BOP_PLUS:
+        rc = "+";
+        break;
+    case BOP_MINUS:
+        rc = "-";
+        break;
+    case BOP_TIMES:
+        rc = "*";
+        break;
+    case BOP_DIV:
+        rc = "/";
+        break;
+    case BOP_MOD:
+        rc = "%";
+        break;
+    case BOP_POWER:
+        rc = "**";
+        break;
+    case BOP_LOG_OR:
+        rc = "||";
+        break;
+    case BOP_LOG_AND:
+        rc = "&&";
+        break;
+    case BOP_LOG_XOR:
+        rc = "^^";
+        break;
+    case BOP_BIT_OR:
+        rc = "|";
+        break;
+    case BOP_BIT_AND:
+        rc = "&";
+        break;
+    case BOP_BIT_XOR:
+        rc = "^";
+        break;
+    case BOP_LSHIFT:
+        rc = ""; break;
+    case BOP_LOG_RSHIFT:
+        rc = ">>";
+        break;
+    case BOP_ARTITH_RSHIFT:
+        rc = ">>>";
+        break;
+    case BOP_EQ:
+        rc = "==";
+        break;
+    case BOP_NE:
+        rc = "!=";
+        break;
+    case BOP_LE:
+        rc = "<=";
+        break;
+    case BOP_LT:
+        rc = "<";
+        break;
+    case BOP_GE:
+        rc = ">=";
+        break;
+    case BOP_GT:
+        rc = ">";
+        break;
+    default:
+        throw ReException("unknown binary op %d", (int) op);
+    }
+    return rc;
+}
+
+/** @class ReASMethod rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a method definition for the Abstract Syntax Tree.
+ *
+ * The special case "function" (a method without class) is included.
+ *
+ * <code>m_child</code>: body<br>
+ * <code>m_child2</code>: parameter list (or NULL)
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param name      the method name
+ * @param tree      the abstract syntax tree
+ */
+ReASMethod::ReASMethod(const QByteArray& name, ReASTree& tree) :
+    ReASNode2(AST_METHOD),
+    m_name(name),
+    m_resultType(NULL),
+    m_symbols(NULL),
+    m_sibling(NULL),
+    m_tree(tree),
+    firstParamWithDefault(-1)
+{
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASMethod::check(ReParser& parser)
+{
+    return false;
+}
+
+/**
+ * @brief Executes the statement.
+ *
+ * This method will be never called. Must exit: Otherwise the class is abstract.
+ */
+int ReASMethod::execute(ReVMThread& thread)
+{
+    return 0;
+}
+
+
+/**
+ * @brief Writes the internals of the instance into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASMethod::dump(ReWriter& writer, int indent)
+{
+
+    char buffer[256];
+    writer.indent(indent);
+    writer.format("Method %s %s(",
+            m_resultType == NULL ? "<NoneType>" : m_resultType->name().constData(),
+            m_name.constData());
+    ReSymbolSpace* parent = m_symbols->parent();
+    writer.formatLine(") id: %d parent: %s args: %d body: %d %s", m_id,
+            parent == NULL ? "" : parent->name().constData(),
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    if (m_child2 != NULL)
+        m_child2->dump(writer, indent + 1);
+    dumpStatements(writer, indent + 1, m_child);
+    m_symbols->dump(writer, indent + 1);
+}
+/**
+ * @brief Returns the symbol space of the instance.
+ *
+ * @return  the symbol space
+ */
+ReSymbolSpace* ReASMethod::symbols() const
+{
+    return m_symbols;
+}
+
+/**
+ * @brief Sets the symbol space from the current of the tree.
+ */
+void ReASMethod::setSymbols()
+{
+    m_symbols = m_tree.currentSpace();
+}
+/**
+ * @brief Returns the name of the method
+ * @return  the name
+ */
+
+const QByteArray& ReASMethod::name() const
+{
+    return m_name;
+}
+
+/**
+ * @brief Tests whether an other method has the same signature (parameterlist).
+ * @param other     the method for comparison
+ * @return          true: same signature<br>
+ *                  false: otherwise
+ */
+bool ReASMethod::equalSignature(ReASMethod& other) const
+{
+    bool rc = true;
+    ReASExprStatement* args = dynamic_cast<ReASExprStatement*>(m_child2);
+    ReASExprStatement* otherArgs = dynamic_cast<ReASExprStatement*>(other.child2());
+
+    while(rc && (args != NULL || otherArgs != NULL)){
+        if (args == NULL || otherArgs == NULL)
+            rc = false;
+        else {
+            ReASVarDefinition* def = dynamic_cast<ReASVarDefinition*>(args->child2());
+            ReASVarDefinition* defOther = dynamic_cast<ReASVarDefinition*>(otherArgs->child2());
+            if (def->clazz() != defOther->clazz())
+                rc = false;
+        }
+    }
+    return rc;
+}
+/**
+ * @brief Returns the next overloaded method.
+ *
+ * @return  NULL: no other method available<br>
+ *          otherwise: the next method with the same name but another signature
+ */
+ReASMethod* ReASMethod::sibling() const
+{
+    return m_sibling;
+}
+
+/**
+ * @brief Sets the next overloaded method.
+ *
+ * @param sibling   another method with the same name but another signature
+ */
+void ReASMethod::setSibling(ReASMethod* sibling)
+{
+    m_sibling = sibling;
+}
+/**
+ * @brief Returns the index of the first parameter with a default value.
+ *
+ * @return  -1: no parameter has a default value<br>
+ *          otherwise: the index of the first parameter with a default
+ */
+int ReASMethod::getFirstParamWithDefault() const
+{
+    return firstParamWithDefault;
+}
+/**
+ * @brief Sets the index of the first parameter with default value
+ * @param value
+ */
+void ReASMethod::setFirstParamWithDefault(int value)
+{
+    firstParamWithDefault = value;
+}
+
+
+
+/** @class ReASField rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an class field for the Abstract Syntax Tree.
+ *
+ * <code>m_child</code>: parent (variable, field, method)
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param name      name of the field
+ */
+ReASField::ReASField(const QByteArray& name) :
+    ReASNode1(AST_FIELD),
+    m_name(name)
+{
+}
+
+/**
+ * @brief Checks the correctness of the instance.
+ *
+ * @param parser    for error processing
+ * @return          <code>true</code>: node is correct<br>
+ *                  <code>false</code>: otherwise
+ */
+bool ReASField::check(ReParser& parser)
+{
+    return false;
+}
+
+/**
+ * @brief Writes the internals of the instance into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level
+ */
+void ReASField::dump(ReWriter& writer, int indent)
+{
+    char buffer[256];
+    writer.formatIndented(indent, "field %s id: %d parent: %d succ: %s",
+            m_name.constData(), m_id,
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    m_child->dump(writer, indent + 1);
+}
+
+
diff --git a/expr/ReASTree.hpp b/expr/ReASTree.hpp
new file mode 100644 (file)
index 0000000..f7ec9f1
--- /dev/null
@@ -0,0 +1,759 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtwriterl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLASTREE_HPP
+#define RPLASTREE_HPP
+
+enum ReASItemType {
+    AST_UNDEF,
+    AST_CONSTANT,
+    AST_LIST_CONSTANT,
+    AST_LIST_ENTRY,
+    AST_MAP_CONSTANT,
+    AST_MAP_ENTRY,
+    AST_NAMED_VALUE,
+    AST_CONVERSION,
+    AST_INDEXED_VALUE,
+    AST_FIELD,
+    AST_VAR_DEFINITION,
+    AST_EXPR_STATEMENT,
+    AST_METHOD,
+    AST_ARGUMENT,
+    AST_INTRINSIC_METHOD,
+    AST_PRE_UNARY_OP,
+    AST_POST_UNARY_OP,
+    AST_BINARY_OP,
+    AST_METHOD_CALL,
+    AST_WHILE,
+    AST_REPEAT,
+    AST_IF,
+    AST_CONDITION,
+    AST_ITERATED_FOR,
+    AST_COUNTED_FOR,
+    AST_SWITCH,
+    AST_LEAVE,
+    AST_CONTINUE
+};
+
+class ReASException : public ReException {
+public:
+    ReASException();
+    ReASException(const ReSourcePosition* position, const char* format, ...);
+protected:
+    void build(const ReSourcePosition* position, const char* format,
+               va_list varList);
+};
+
+class ReASClass;
+class ReASNamedValue;
+class ReASItem;
+class ReASCondition;
+
+class ReASVariant {
+    /* The VM uses some tricks (performance): Therefore this class
+    * must not be virtual!
+    */
+public:
+    enum VariantType {
+        VT_UNDEF,
+        VT_FLOAT,
+        VT_INTEGER,
+        VT_BOOL,
+        VT_OBJECT
+    };
+    enum VariantFlags {
+        VF_UNDEF,
+        /// if DT_OBJECT: object is a copy, don't free at method end
+        VF_IS_COPY      = 1 << 1,
+        /// debugger: action if changed
+        VF_WATCH_POINT  = 1 << 2
+    };
+
+    friend class ReASCondition;
+public:
+    ReASVariant();
+    ~ReASVariant();
+    ReASVariant(const ReASVariant& source);
+    ReASVariant& operator=(const ReASVariant& source);
+    qreal asFloat() const;
+    int asInt() const;
+    bool asBool() const;
+    void* asObject(const ReASClass** clazz) const;
+    const QByteArray* asString() const;
+    void setFloat(qreal number);
+    void setInt(int integer);
+    void setBool(bool value);
+    void setObject(void* object, const ReASClass* clazz);
+    void setString(const QByteArray& string);
+    QByteArray toString(int maxLength = 80) const;
+    VariantType variantType() const;
+    const char* nameOfType() const;
+    const ReASClass* getClass() const;
+    void copyValue(const ReASVariant& source);
+    void destroyValue();
+private:
+    VariantType m_variantType:8;
+    /// bitmap of VF_... flags:
+    int m_flags:8;
+    union {
+        qreal m_float;
+        int m_int;
+        bool m_bool;
+        void* m_object;
+    } m_value;
+    const ReASClass* m_class;
+};
+
+class ReASTree;
+class ReParser;
+class ReVMThread;
+
+class ReASItem
+{
+public:
+    enum NodeFlags {
+        NF_UNDEF,
+        /// the node calculates a value:
+        NF_CALCULABLE   = 1 << 1,
+        /// the node calculates a value:
+        NF_STATEMENT    = 1 << 2,
+        /// the tree under this node is complete checked for data type correctness
+        NF_TYPECHECK_COMPLETE   = 1 << 3,
+        /// debugger: this node is a breakpoint
+        NF_BREAKPOINT           = 1 << 5
+    };
+
+public:
+    friend class ReASTree;
+    ReASItem(ReASItemType type);
+    virtual ~ReASItem();
+public:
+    virtual bool check(ReParser& parser) = 0;
+public:
+    bool checkAsCalculable(const char* description, ReASClass* expectedClass,
+                           ReParser& parser);
+    const ReSourcePosition* position() const;
+    void setPosition(const ReSourcePosition* position);
+    unsigned int id() const;
+    char* positionStr(char buffer[], size_t bufferSize) const;
+    void error(ReLogger* logger, int location, const char* format, ...);
+public:
+    /**
+     * @brief Writes the content of the instance into an output medium.
+     *
+     * @param writer    writes to output media
+     * @param indent    nesting level: so many tabs will be used as prefix
+     */
+    virtual void dump(ReWriter& writer,int indent) = 0;
+public:
+    static void reset();
+    static bool checkStatementList(ReASItem* list, ReParser& parser);
+    static int calcAsInteger(ReASItem* expr, ReVMThread& thread);
+    static bool calcAsBoolean(ReASItem* expr, ReVMThread& thread);
+public:
+    ReASItemType nodeType() const;
+    const char* nameOfItemType() const;
+
+    int flags() const;
+    void setFlags(int flags);
+
+    bool typeCheck(ReASClass* clazz1, ReASClass* clazz2);
+    bool error(int location, ReParser& parser, const char* format, ...);
+    bool ensureError(ReParser& parser, const char* info);
+protected:
+    unsigned int m_id:16;
+    ReASItemType m_nodeType:8;
+    int m_flags:5;
+    int m_dataType: 3;
+    const ReSourcePosition* m_position;
+private:
+    static unsigned int m_nextId;
+};
+
+class ReASNode1;
+class ReASCalculable
+{
+public:
+    ReASCalculable();
+public:
+    virtual void calc(ReVMThread& thread) = 0;
+public:
+    ReASClass* clazz() const;
+    void setClass(ReASClass* clazz);
+protected:
+    ReASClass* m_class;
+};
+
+class ReStackFrame;
+class ReASStorable : public ReASCalculable {
+};
+class ReVMThread;
+class ReASConstant : public ReASItem, public ReASCalculable
+{
+public:
+    ReASConstant();
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+public:
+    virtual void dump(ReWriter& writer,int indent);
+    ReASVariant& value();
+private:
+    ReASVariant m_value;
+};
+
+
+class ReASNode1 : public ReASItem
+{
+public:
+    ReASNode1(ReASItemType type);
+    virtual ~ReASNode1();
+public:
+    ReASItem* child() const;
+    void setChild(ReASItem* child);
+public:
+    static void dumpStatements(ReWriter& writer, int indent, ReASItem* statements);
+protected:
+    ReASItem* m_child;
+};
+
+class ReASNode2 : public ReASNode1
+{
+public:
+    ReASNode2(ReASItemType type);
+    virtual ~ReASNode2();
+public:
+    ReASItem* child2() const;
+    void setChild2(ReASItem* child2);
+
+protected:
+    ReASItem* m_child2;
+};
+
+class ReASNode3 : public ReASNode2
+{
+public:
+    ReASNode3(ReASItemType type);
+    virtual ~ReASNode3();
+public:
+    ReASItem* child3() const;
+    void setChild3(ReASItem* child3);
+
+protected:
+    ReASItem* m_child3;
+};
+
+class ReASNode4 : public ReASNode3
+{
+public:
+    ReASNode4(ReASItemType type);
+    virtual ~ReASNode4();
+public:
+    ReASItem* child4() const;
+    void setChild4(ReASItem* child4);
+
+protected:
+    ReASItem* m_child4;
+};
+
+class ReASNode5 : public ReASNode4
+{
+public:
+    ReASNode5(ReASItemType type);
+    virtual ~ReASNode5();
+public:
+    ReASItem*child5() const;
+    void setChild5(ReASItem* child5);
+protected:
+    ReASItem* m_child5;
+};
+class ReASNode6 : public ReASNode5
+{
+public:
+    ReASNode6(ReASItemType type);
+    virtual ~ReASNode6();
+public:
+    ReASItem*child6() const;
+    void setChild6(ReASItem* child5);
+protected:
+    ReASItem* m_child6;
+};
+
+typedef QList<ReASVariant*> ReASListOfVariants;
+typedef QMap<QByteArray, ReASVariant*> ReASMapOfVariants;
+
+class ReASListConstant : public ReASNode1, public ReASCalculable
+{
+public:
+    ReASListConstant();
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+
+public:
+    virtual void dump(ReWriter& writer,int indent);
+    ReASVariant& value();
+    ReASListOfVariants* list();
+private:
+    ReASVariant m_value;
+};
+class ReASMapConstant : public ReASNode1, public ReASCalculable
+{
+public:
+    ReASMapConstant();
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+public:
+    virtual void dump(ReWriter& writer,int indent);
+    ReASVariant& value();
+    ReASMapOfVariants* map();
+private:
+    ReASVariant m_value;
+};
+
+class ReSymbolSpace;
+class ReASNamedValue : public ReASItem, public ReASStorable
+{
+    friend class ReASVarDefinition;
+public:
+    enum Attributes {
+        A_NONE,
+        /// the value cannot be changed.
+        A_CONST         = 1<<1,
+        /// the variable/constant is found in the global namespace, not in a method
+        A_GLOBAL        = 1<<2,
+        /// the variable/constant is found in the module namespace, not in a method
+        A_MODULE_STATIC = 1<<3,
+        /// the evaluation should be lazy
+        A_LAZY          = 1<<4,
+        /// parameter of a method
+        A_PARAM         = 1<<5,
+        /// a automatic variable in counted for loops:
+        A_LOOP          = 1<<6
+    };
+
+public:
+    ReASNamedValue(ReASClass* clazz, ReSymbolSpace* space,
+                    const QByteArray& name, int attributes);
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+public:
+    const QByteArray& name() const;
+    void setSymbolSpace(ReSymbolSpace* space, int variableNo);
+    void dump(ReWriter& writer, int indent);
+    ReSymbolSpace* symbolSpace() const;
+    int variableNo() const;
+    void setVariableNo(int variableNo);
+protected:
+    QByteArray m_name;
+    int m_attributes;
+    ReSymbolSpace* m_symbolSpace;
+    int m_variableNo;
+};
+class ReASConversion : public ReASNode1, public ReASCalculable {
+public:
+    enum Conversion {
+        C_UNDEF,
+        C_INT_TO_FLOAT,
+        C_FLOAT_TO_INT,
+        C_BOOL_TO_INT,
+        C_BOOL_TO_FLOAT
+    };
+
+public:
+    ReASConversion(ReASItem* expression);
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+    virtual void dump(ReWriter& writer,int indent);
+public:
+    static ReASConversion* tryConversion(ReASClass* expected, ReASItem* expr,
+                                          ReParser& parser, bool& isCorrect);
+    static Conversion findConversion(ReASClass* from, ReASClass* to);
+private:
+    Conversion m_conversion;
+};
+
+class ReASIndexedValue : public ReASNode2, public ReASCalculable {
+public:
+    ReASIndexedValue();
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+public:
+    void dump(ReWriter& writer, int indent);
+};
+
+class ReASStatement
+{
+public:
+    ReASStatement();
+public:
+    virtual int execute(ReVMThread& thread) = 0;
+public:
+    static int executeStatementList(ReASItem* list, ReVMThread& thread);
+};
+
+
+class ReASVarDefinition : public ReASNode3, public ReASStatement
+{
+public:
+    ReASVarDefinition();
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+public:
+    void dump(ReWriter& writer, int indent);
+    const QByteArray& name() const;
+    int endOfScope() const;
+    void setEndOfScope(int endOfScope);
+    ReASClass* clazz() const;
+private:
+    /// the column of the blockend containing the definition.
+    /// if 0: end is end of method or end of class
+    /// Note: the source unit is stored in <code>ReASItem::m_sourcePosition</code>
+    int m_endOfScope;
+};
+
+class ReASExprStatement : public ReASNode2, public ReASStatement
+{
+public:
+    ReASExprStatement();
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+public:
+    void dump(ReWriter& writer, int indent);
+};
+
+class ReASUnaryOp : public ReASNode1, ReASCalculable
+{
+public:
+    enum UnaryOp {
+        UOP_UNDEF,
+        UOP_PLUS,
+        UOP_MINUS_INT,
+        UOP_MINUS_FLOAT,
+        UOP_NOT_BOOL,
+        UOP_NOT_INT,
+        UOP_INC,
+        UOP_DEC
+    };
+public:
+    ReASUnaryOp(UnaryOp op, ReASItemType type);
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+public:
+    int getOperator() const;
+    void dump(ReWriter& writer, int indent);
+public:
+    static const char* nameOfOp(UnaryOp op);
+private:
+    UnaryOp m_operator;
+};
+class ReASBinaryOp : public ReASNode2, public ReASCalculable
+{
+public:
+    enum BinOperator {
+        BOP_UNDEF,
+        BOP_ASSIGN,
+        BOP_PLUS_ASSIGN,
+        BOP_MINUS_ASSIGN,
+        BOP_TIMES_ASSIGN,
+        BOP_DIV_ASSIGN,
+        BOP_MOD_ASSIGN,
+        BOP_POWER_ASSIGN,
+        BOP_LOG_OR_ASSIGN,
+        BOP_LOG_AND_ASSIGN,
+        BOP_LOG_XOR_ASSIGN,
+        BOP_BIT_OR_ASSIGN,
+        BOP_BIT_AND_ASSIGN,
+        BOP_BIT_XOR_ASSIGN,
+        BOP_LSHIFT_ASSIGN,
+        BOP_LOG_RSHIFT_ASSIGN,
+        BOP_ARTITH_RSHIFT_ASSIGN,
+        BOP_PLUS,
+        BOP_MINUS,
+        BOP_TIMES,
+        BOP_DIV,
+        BOP_MOD,
+        BOP_POWER,
+        BOP_LOG_OR,
+        BOP_LOG_AND,
+        BOP_LOG_XOR,
+        BOP_BIT_OR,
+        BOP_BIT_AND,
+        BOP_BIT_XOR,
+        BOP_LSHIFT,
+        BOP_LOG_RSHIFT,
+        BOP_ARTITH_RSHIFT,
+        BOP_EQ,
+        BOP_NE,
+        BOP_LE,
+        BOP_LT,
+        BOP_GE,
+        BOP_GT,
+        BOB_COUNT
+    };
+private:
+    inline bool isAssignment() const {
+        return m_operator >= BOP_ASSIGN
+                && m_operator <= BOP_ARTITH_RSHIFT_ASSIGN;
+    }
+public:
+    ReASBinaryOp();
+public:
+    virtual void calc(ReVMThread& thread);
+    virtual bool check(ReParser& parser);
+public:
+    BinOperator getOperator() const;
+    void setOperator(BinOperator op);
+    void dump(ReWriter& writer, int indent);
+private:
+    void assign(ReVMThread& thread);
+public:
+    static const char* nameOfOp(BinOperator op);
+private:
+    BinOperator m_operator;
+};
+
+class ReASIf : public ReASNode4, public ReASStatement
+{
+public:
+    ReASIf();
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+    virtual void dump(ReWriter& writer, int indent);
+};
+
+class ReASForIterated : public ReASNode4, public ReASStatement
+{
+public:
+    ReASForIterated(ReASVarDefinition* variable);
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+    virtual void dump(ReWriter& writer, int indent);
+};
+
+class ReASForCounted : public ReASNode6, public ReASStatement
+{
+public:
+    ReASForCounted(ReASVarDefinition* variable);
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+    virtual void dump(ReWriter& writer, int indent);
+};
+
+class ReASWhile : public ReASNode3, public ReASStatement
+{
+public:
+    ReASWhile();
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+    virtual void dump(ReWriter& writer, int indent);
+};
+
+class ReASRepeat : public ReASNode3, public ReASStatement
+{
+public:
+    ReASRepeat();
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+    virtual void dump(ReWriter& writer, int indent);
+};
+
+class ReASMethod;
+class ReASMethodCall : public ReASNode3, public ReASStatement
+{
+public:
+    ReASMethodCall(const QByteArray& name, ReASItem* parent);
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+public:
+    void dump(ReWriter& writer, int indent);
+
+public:
+    ReASMethod* method() const;
+    void setMethod(ReASMethod* method);
+
+    ReASExprStatement* arg1() const;
+private:
+    QByteArray m_name;
+    ReASMethod* m_method;
+};
+
+class RplParameter : ReASItem
+{
+public:
+    RplParameter();
+    virtual ~RplParameter();
+private:
+    QByteArray m_name;
+    ReASNamedValue* m_default;
+};
+
+class ReASField : public ReASNode1
+{
+public:
+    ReASField(const QByteArray& name);
+public:
+    virtual bool check(ReParser& parser);
+public:
+    void dump(ReWriter& writer, int indent);
+private:
+    QByteArray m_name;
+};
+
+
+class ReASClass;
+class ReSymbolSpace;
+class ReASMethod : public ReASNode2
+{
+public:
+    ReASMethod(const QByteArray& name, ReASTree& tree);
+public:
+    virtual bool check(ReParser& parser);
+    virtual int execute(ReVMThread& thread);
+public:
+    void dump(ReWriter& writer, int indent);
+    ReSymbolSpace* symbols() const;
+    void setSymbols();
+    const QByteArray& name() const;
+    bool equalSignature(ReASMethod& other) const;
+    ReASMethod* sibling() const;
+    void setSibling(ReASMethod* sibling);
+    int getFirstParamWithDefault() const;
+    void setFirstParamWithDefault(int value);
+
+private:
+    QByteArray m_name;
+    ReASClass* m_resultType;
+    ReSymbolSpace* m_symbols;
+    // chain over all overloaded methods (same name, other signature):
+    ReASMethod* m_sibling;
+    ReASTree& m_tree;
+    // -1: no parameter with default value. >= 0: index of the first
+    int firstParamWithDefault;
+};
+
+class ReASClass {
+public:
+    typedef QMap<QByteArray, ReASMethod*> MethodMap;
+public:
+    ReASClass(const QByteArray& name, ReASTree& m_tree);
+    virtual ~ReASClass();
+public:
+    /**
+     * @brief Creates a value object (used in ReASVariant).
+     *
+     * @param source    NULL or a source to copy
+     * @return          a new value object (specific for the class)
+     */
+    virtual void* newValueInstance(void* source = NULL) const = 0;
+    /**
+     * @brief Destroys the given object.
+     *
+     * The object must be created by <code>newValueInstance()</code>.
+     *
+     * @param object    object to destroy
+     */
+    virtual void destroyValueInstance(void* object) const = 0;
+    /**
+     * @brief Returns the boolean value of a class specific value.
+     *
+     * Example: the boolean value of an the empty string is false
+     *
+     * @param object    object to test
+     * @return          false: the object represents the false value<br>
+     *                  true: otherwise
+     */
+    virtual bool boolValueOf(void* object) const = 0;
+    /**
+     * @brief Returns a string representation of an instance.
+     *
+     * @param object    the object to convert
+     * @param maxLength the maximum length of the result (string)
+     * @return          a string describing the <code>object</code>
+     */
+    virtual QByteArray toString(void *object, int maxLength = 80) const = 0;
+public:
+    const QByteArray& name() const;
+    virtual void dump(ReWriter& writer, int indent);
+    void setSymbols();
+protected:
+    QByteArray m_name;
+    ReSymbolSpace* m_symbols;
+    const ReASClass* m_superClass;
+    ReASTree& m_tree;
+};
+
+#include "rplexpr/rplasclasses.hpp"
+
+#include "ReParser.hpp"
+class ReSymbolSpace;
+class ReASTree
+{
+public:
+    enum {
+        DMP_NONE,
+        DMP_GLOBALS     = 1<<1,
+        DMP_MODULES     = 1<<2,
+        DMP_SPACE_STACK = 1<<3,
+        DMP_SPACE_HEAP  = 1<<4,
+        DMP_ALL         = DMP_GLOBALS | DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP,
+        DMP_NO_GLOBALS  = DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP
+    };
+    typedef QMap<QByteArray, ReSymbolSpace*> SymbolSpaceMap;
+    typedef QList<ReSymbolSpace*> SymbolSpaceStack;
+public:
+    ReASTree();
+    ~ReASTree();
+public:
+    bool startModule(ReSourceUnitName name);
+    void finishModule(ReSourceUnitName name);
+    ReSymbolSpace* startClassOrMethod(const QByteArray& name,
+        ReSymbolSpace::SymbolSpaceType type);
+    void finishClassOrMethod(const QByteArray& name);
+    SymbolSpaceStack& symbolSpaces();
+    ReSymbolSpace* currentSpace() const;
+    ReASClass* findClass(const QByteArray& name);
+    void clear();
+    void dump(const char* filename, int flags = DMP_ALL,
+              const char* header = NULL);
+    ReSymbolSpace*findmodule(const QByteArray& name);
+    ReSourcePosition* copyPosition();
+    ReByteStorage& store();
+
+protected:
+    void init();
+    void destroy();
+private:
+    // the mother of all symbol spaces.
+    ReSymbolSpace* m_global;
+    // contains all hit modules
+    SymbolSpaceMap m_modules;
+    // nested modules (import), classes and methods build this stack:
+    SymbolSpaceStack m_symbolSpaces;
+    // top of the stack:
+    ReSymbolSpace* m_currentSpace;
+    // contain all ever built symbol spaces:
+    SymbolSpaceMap m_symbolSpaceHeap;
+    ReByteStorage m_store;
+};
+
+#endif // RPLASTREE_HPP
diff --git a/expr/ReAsClasses.cpp b/expr/ReAsClasses.cpp
new file mode 100644 (file)
index 0000000..2d607b5
--- /dev/null
@@ -0,0 +1,1186 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Predefined classes of the virtual machine, e.g ReASInteger.
+ */
+/** @file rplexpr/rplasclasses.hpp
+ *
+ * @brief Definitions for predefined classes of the virtual machine.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/ReExpr.hpp"
+
+ReASList* ReASList::m_instance = NULL;
+ReASMap* ReASMap::m_instance = NULL;
+ReASFloat* ReASFloat::m_instance = NULL;
+ReASInteger* ReASInteger::m_instance = NULL;
+ReASString* ReASString::m_instance = NULL;
+ReASBoolean* ReASBoolean::m_instance = NULL;
+ReASVoid* ReASVoid::m_instance = NULL;
+ReASFormula* ReASFormula::m_instance = NULL;
+
+/** @class ReSymbolSpace rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a symbol space for the parser.
+ *
+ * A symbol space is a container of the classes and variables which can be used
+ * at a given moment while compiling.
+ *
+ * A symbol space could have a parent which is a symbol space too and extends
+ * the visible classes / variables.
+ *
+ * If an entry exists more than one time in a symbol space chain only the first
+ * can be seen.
+ *
+ * The "last" parent is named "global" and exists always. It contains the
+ * core classes like String, List and Map and methods like print.
+ *
+ * Each module hit by the compiler builds its own symbol space with global as parent.
+ *
+ * Each class defines a symbol space and takes the symbol space of the superclass
+ * as its parent. If there is no superclass the module's symbol space will be taken.
+ *
+ * Each method defines its own symbol space. The parent may be the symbol space
+ * of the module or of the class.
+ */
+/**
+ * @brief Constructor, only for the global symbol space.
+ *
+ * @param name      the symbol space's name
+ * @param parent    the parent of the symbol space
+ */
+ReSymbolSpace::ReSymbolSpace(ReASTree& tree) :
+    m_type(SST_GLOBAL),
+    m_name("$global"),
+    m_variables(),
+    m_classes(),
+    m_parent(NULL),
+    m_body(NULL),
+    m_listOfVars(),
+    m_tree(tree)
+{
+}
+/**
+ * @brief Constructor.
+ *
+ * @param type      the type of the symbol space: SST_MODULE, ...
+ * @param name      the symbol space's name
+ * @param parent    the parent of the symbol space
+ */
+ReSymbolSpace::ReSymbolSpace(ReSymbolSpace::SymbolSpaceType type,
+                               const QByteArray& name,
+                               ReSymbolSpace* parent) :
+    m_type(type),
+    m_name(name),
+    m_variables(),
+    m_classes(),
+    m_parent(parent),
+    m_body(NULL),
+    m_listOfVars(),
+    m_tree(parent->m_tree)
+{
+}
+
+
+/**
+ * @brief Destructor.
+ */
+ReSymbolSpace::~ReSymbolSpace()
+{
+    ClassMap::iterator it;
+    for (it = m_classes.begin(); it != m_classes.end(); it++){
+        delete it.value();
+    }
+    MethodMap::iterator it2;
+    for (it2 = m_methods.begin(); it2 != m_methods.end(); it2++){
+        delete it2.value();
+    }
+}
+
+/**
+ * @brief Starts a scope.
+ *
+ * A scope is an "area" where variables can be defined.
+ * A variable "lives" in a scope.
+ *
+ * Saves the status to restore it in <code>finishScope()</code>.
+ *
+ * @param scope     OUT: status info
+ */
+void ReSymbolSpace::startScope(ReASScope& scope)
+{
+    scope.m_varNoAtStart = m_listOfVars.size();
+}
+
+/**
+ * @brief Finishes a scope.
+ *
+ * Finishes the "live" of the variables created in the ending scope.
+ *
+ * @param endOfScope    line (inside the current source unit) which finishes the
+ *                      scope
+ * @param scope         the status of the scope at start.
+ */
+void ReSymbolSpace::finishScope(int endOfScope, ReASScope& scope)
+{
+    // in methods/classes not needed:
+    int ix = scope.m_varNoAtStart - scope.m_builtInVars;
+    int last = m_listOfVars.size();
+    for (; ix < last; ix++){
+        ReASVarDefinition* var = m_listOfVars[ix];
+        var->setEndOfScope(endOfScope);
+        const QByteArray& name = var->name();
+        if (m_variables.contains(name))
+            m_variables.remove(name);
+    }
+}
+
+/**
+ * @brief Search a variable in the symbol space.
+ *
+ * @param name  variable to find
+ *
+ * @return      NULL: not found<br>
+ *              otherwise: the variable
+ */
+ReASVarDefinition* ReSymbolSpace::findVariable(const QByteArray& name) const
+{
+    ReASVarDefinition* rc = NULL;
+    if (m_variables.contains(name))
+        rc = m_variables[name];
+    else if (m_parent != NULL)
+        rc = m_parent->findVariable(name);
+    return rc;
+}
+
+/**
+ * @brief Search the class in the symbol space hierarchy.
+ *
+ * @param name  Name of the class
+ * @return      NULL: not found<br>
+ *              otherwise: the class
+ */
+ReASClass* ReSymbolSpace::findClass(const QByteArray& name) const
+{
+    ReASClass* rc = NULL;
+    if (m_classes.contains(name))
+        rc = m_classes[name];
+    else if (m_parent != NULL)
+        rc = m_parent->findClass(name);
+    return rc;
+}
+
+/**
+ * @brief Find a method in the instance.
+ *
+ * @param name  the method's name
+ * @return      NULL: method not found
+ *              otherwise: the method description
+ */
+ReASMethod* ReSymbolSpace::findMethod(const QByteArray& name) const
+{
+    ReASMethod* rc = NULL;
+    if (m_methods.contains(name))
+        rc = m_methods[name];
+    return rc;
+}
+
+/**
+ * @brief Writes the content of the instance into a file.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level: so many tabs will be used as prefix
+ * @param header    NULL or the headline
+ */
+void ReSymbolSpace::dump(ReWriter& writer, int indent, const char* header)
+{
+    if (header != NULL)
+        writer.writeLine(header);
+    writer.formatIndented(indent, "= %s (%s) parent: %s", m_name.constData(),
+            spaceTypeName(m_type),
+            m_parent == NULL ? "<none>" : m_parent->name().constData());
+    QList<QByteArray> sorted;
+    if (m_classes.size() > 0){
+        writer.writeIndented(indent, "== Classes:");
+        sorted.reserve(m_classes.size());
+        ClassMap::iterator it;
+        for (it = m_classes.begin(); it != m_classes.end(); it++){
+           sorted.append(it.key());
+        }
+        qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
+        QList<QByteArray>::iterator it2;
+        for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
+            ReASClass* clazz = m_classes[*it2];
+            clazz->dump(writer, indent);
+        }
+    }
+    if (m_methods.size() > 0){
+        writer.writeIndented(indent, "== Methods:");
+        sorted.clear();
+        sorted.reserve(m_variables.size());
+        MethodMap::iterator it3;
+        for (it3 = m_methods.begin(); it3 != m_methods.end(); it3++){
+           sorted.append(it3.key());
+        }
+        qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
+        QList<QByteArray>::iterator it4;
+        for (it4 = sorted.begin(); it4 != sorted.end(); it4++){
+            ReASMethod* method = m_methods[*it4];
+            do {
+                method->dump(writer, indent);
+                method = method->sibling();
+            } while (method != NULL);
+        }
+    }
+
+    if (m_listOfVars.size() > 0){
+        writer.writeIndented(indent, "== Variables:");
+        QList<QByteArray>::iterator it6;
+        for (int ix = 0; ix < m_listOfVars.size(); ix++){
+            ReASVarDefinition* var = m_listOfVars[ix];
+            var->dump(writer, indent);
+        }
+    }
+    if (m_body != NULL){
+        writer.writeIndented(indent, "== Body:");
+        ReASNode1::dumpStatements(writer, indent, m_body);
+    }
+}
+
+/**
+ * @brief Returns the name of a space type.
+ *
+ * @param type  type to inspect
+ * @return      the name of the type
+ */
+const char*ReSymbolSpace::spaceTypeName(
+        ReSymbolSpace::SymbolSpaceType type)
+{
+    const char* rc = NULL;
+    switch(type){
+    case SST_UNDEF:
+        rc = "undef";
+        break;
+    case SST_GLOBAL:
+        rc = "global";
+        break;
+    case SST_MODULE:
+        rc = "module";
+        break;
+    case SST_CLASS:
+        rc = "class";
+        break;
+    case SST_METHOD:
+        rc = "method";
+        break;
+    default:
+        rc = "?";
+        break;
+    }
+    return rc;
+}
+
+/**
+ * @brief Initilizes the global symbol space.
+ *
+ * @param tree  the abstract syntax tree
+ * @return      the global symbol space
+ */
+ReSymbolSpace* ReSymbolSpace::createGlobal(ReASTree& tree)
+{
+    ReSymbolSpace* rc = new ReSymbolSpace(tree);
+    rc->m_tree = tree;
+    ReASInteger::m_instance = new ReASInteger(tree);
+    rc->m_classes[ReASInteger::m_instance->name()] = ReASInteger::m_instance;
+    ReASBoolean::m_instance = new ReASBoolean(tree);
+    rc->m_classes[ReASBoolean::m_instance->name()] = ReASBoolean::m_instance;
+    ReASFloat::m_instance = new ReASFloat(tree);
+    rc->m_classes[ReASFloat::m_instance->name()] = ReASFloat::m_instance;
+    ReASString::m_instance = new ReASString(tree);
+    rc->m_classes[ReASString::m_instance->name()] = ReASString::m_instance;
+    ReASList::m_instance = new ReASList(tree);
+    rc->m_classes[ReASList::m_instance->name()] = ReASList::m_instance;
+    ReASMap::m_instance = new ReASMap(tree);
+    rc->m_classes[ReASMap::m_instance->name()] = ReASMap::m_instance;
+    ReASVoid::m_instance = new ReASVoid(tree);
+    rc->m_classes[ReASVoid::m_instance->name()] = ReASVoid::m_instance;
+    ReASFormula::m_instance = new ReASFormula(tree);
+    rc->m_classes[ReASFormula::m_instance->name()] = ReASFormula::m_instance;
+    return rc;
+}
+/**
+ * @brief Returns the list of the variables.
+ *
+ * @return the list of the variables
+ */
+ReSymbolSpace::VariableList ReSymbolSpace::listOfVars() const
+{
+    return m_listOfVars;
+}
+
+/**
+ * @brief Returns the parent of the symbol space.
+ *
+ * @return  the symbolspace of the object (module, method, class..) containing
+ *          the object belonging to the instance
+ */
+ReSymbolSpace* ReSymbolSpace::parent() const
+{
+    return m_parent;
+}
+
+/**
+ * @brief Returns the body (an abstract syntax tree) of the symbol space.
+ *
+ * @return  NULL: no body available<br>
+ *          othewise: the body of the instance
+ */
+ReASItem* ReSymbolSpace::body() const
+{
+    return m_body;
+}
+
+/**
+ * @brief Sets the body (an abstract syntax tree) of the symbol space.
+ *
+ * @param body  the new body
+ */
+void ReSymbolSpace::setBody(ReASItem* body)
+{
+    m_body = body;
+}
+
+/**
+ * @brief Adds a variable to the symbol space.
+ *
+ * @param variable  the variable to add
+ * @param varNo     OUT: variable number, current number in the symbol space
+ * @return          NULL: success<br>
+ *                  otherwise: the already defined variable/method
+ */
+ReASItem* ReSymbolSpace::addVariable(ReASVarDefinition* variable, int& varNo)
+{
+    ReASItem* rc = NULL;
+    const QByteArray& name = variable->name();
+    if (m_variables.contains(name))
+        rc = m_variables[name];
+    else if (m_methods.contains(name))
+        rc = m_methods[name];
+    else {
+        m_variables[name] = variable;
+        varNo = m_listOfVars.size();
+        m_listOfVars.append(variable);
+    }
+    return rc;
+}
+
+/**
+ * @brief Adds a method to the symbol space.
+ *
+ * @param method    the method to add
+ * @return          NULL: success<br>
+ *                  otherwise: the already defined variable/method
+ */
+ReASItem* ReSymbolSpace::addMethod(ReASMethod* method)
+{
+    ReASItem* rc = NULL;
+    const QByteArray& name = method->name();
+    if (m_variables.contains(name))
+        rc = m_variables[name];
+    else if (! m_methods.contains(name)){
+        m_methods[name] = method;
+    } else {
+        ReASMethod* first = m_methods[name];
+        ReASMethod* oldMethod = first;
+        do {
+            if (oldMethod->equalSignature(*method))
+                rc = oldMethod;
+            else
+                oldMethod = oldMethod->sibling();
+        } while (rc == NULL && oldMethod != NULL);
+        if (rc == NULL){
+            method->setChild(first);
+            m_methods[name] = method;
+        }
+    }
+    return rc;
+}
+/**
+ * @brief Adds a class to the instance.
+ *
+ * @param clazz     the class to add
+ * @return          NULL: success<br>
+ *                  otherwise: the already defined class
+ */
+ReASUserClass* ReSymbolSpace::addClass(ReASUserClass* clazz)
+{
+    ReASUserClass* rc = NULL;
+    const QByteArray& name = clazz->name();
+    if (m_classes.contains(name)){
+        rc = dynamic_cast<ReASUserClass*>(m_classes[name]);
+    } else {
+        m_classes[name] = clazz;
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns the name of the symbol space.
+ *
+ * @return the name
+ */
+const QByteArray& ReSymbolSpace::name() const
+{
+    return m_name;
+}
+
+
+/** @class ReASBoolean rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a real value.
+ */
+/**
+ * @brief Constructor.
+ */
+ReASBoolean::ReASBoolean(ReASTree& tree) :
+    ReASClass("Bool", tree)
+{
+}
+/**
+ * @brief Creates a value object (used in ReASVariant).
+ *
+ * For Booleans nothing is to do!
+ *
+ * @param source    NULL or a source to copy
+ * @return          NULL
+ */
+void* ReASBoolean::newValueInstance(void*) const
+{
+    return NULL;
+}
+
+/**
+ * @brief Destroys the given object.
+ *
+ * For Booleans nothing is to do!
+ *
+ * @param object    object to destroy
+ */
+void ReASBoolean::destroyValueInstance(void*) const
+{
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object    the object to test (with type QList*)
+ * @return          false
+ */
+bool ReASBoolean::boolValueOf(void*) const
+{
+    return false;
+}
+
+/**
+ * @brief Returns a string representation of an instance.
+ *
+ * @param object    the object to convert
+ * @param maxLength not used
+ * @return          a string describing the <code>object</code>
+ */
+QByteArray ReASBoolean::toString(void* object, int) const
+{
+    return ((ReASVariant*) object)->asBool() ? "True" : "False";
+}
+
+/** @class ReASNumber rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is one of the values true and false.
+ */
+/**
+ * @brief Constructor.
+ */
+ReASFloat::ReASFloat(ReASTree& tree) :
+    ReASClass("Float", tree)
+{
+}
+
+ReASFloat::ReASFloat(const QByteArray& name, ReASTree& tree) :
+    ReASClass(name, tree)
+{
+    m_superClass = ReASFloat::m_instance;
+}
+/**
+ * @brief Creates a value object (used in ReASVariant).
+ *
+ * For Booleans nothing is to do!
+ *
+ * @param source    NULL or a source to copy
+ * @return          NULL
+ */
+void* ReASFloat::newValueInstance(void*) const
+{
+    return NULL;
+}
+
+/**
+ * @brief Destroys the given object.
+ *
+ * For Booleans nothing is to do!
+ *
+ * @param object    object to destroy
+ */
+void ReASFloat::destroyValueInstance(void*) const
+{
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object    the object to test
+ * @return          false
+ */
+bool ReASFloat::boolValueOf(void*) const
+{
+    return false;
+}
+
+/**
+ * @brief Returns a string representation of an instance.
+ *
+ * @param object    the object to convert
+ * @param maxLength not used
+ * @return          a string describing the <code>object</code>
+ */
+QByteArray ReASFloat::toString(void* object, int) const
+{
+    char buffer[256];
+
+    qsnprintf(buffer, sizeof buffer, "%f", ((ReASVariant *) object)->asFloat());
+    return buffer;
+}
+
+/** @class ReASInteger rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a one of the values true and false.
+ */
+/**
+ * @brief Constructor.
+ */
+ReASInteger::ReASInteger(ReASTree& tree) :
+    ReASFloat("Int", tree)
+{
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object    the object to test
+ * @return          false
+ */
+bool ReASInteger::boolValueOf(void*) const
+{
+    return false;
+}
+
+/**
+ * @brief Returns a string representation of an instance.
+ *
+ * @param object    the object to convert
+ * @param maxLength the maximum length of the result
+ * @return          a string describing the <code>object</code>
+ */
+QByteArray ReASInteger::toString(void* object, int maxLength) const
+{
+    char buffer[64];
+    qsnprintf(buffer, sizeof buffer, "%.*d", maxLength,
+              ((ReASVariant *) object)->asInt());
+    return buffer;
+}
+
+
+/** @class ReASString rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a string.
+ *
+ * A string is a mutable character sequence.
+ */
+/**
+ * @brief Constructor.
+ */
+ReASString::ReASString(ReASTree& tree) :
+    ReASClass("Str", tree)
+{
+}
+/**
+ * @brief Creates a value object (used in ReASVariant).
+ *
+ * @param source    NULL or a source to copy
+ * @return          a new value object (specific for the class)
+ */
+void* ReASString::newValueInstance(void* source) const
+{
+    QByteArray* rc = source == NULL ? new QByteArray() : new QByteArray(*(QByteArray*) source);
+    return (void*) rc;
+}
+
+/**
+ * @brief Destroys the given object.
+ *
+ * The object must be created by <code>newValueInstance()</code>.
+ *
+ * @param object    object to destroy
+ */
+void ReASString::destroyValueInstance(void* object) const
+{
+    delete (QByteArray*) object;
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object    the object to test (a QByteArray* instance)
+ * @return          false: the string is empty
+ *                  true: otherwise
+ */
+bool ReASString::boolValueOf(void* object) const
+{
+    bool rc = false;
+    if (object != NULL){
+        QByteArray* string = static_cast<QByteArray*>(object);
+        if (string == NULL)
+            throw ReException("ReASString.boolValueOf(): not a string");
+        rc = ! string->isEmpty();
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns a string representation of an instance.
+ *
+ * @param object    the object to convert
+ * @param maxLength the maximum length of the result
+ * @return          a string describing the <code>object</code>
+ */
+QByteArray ReASString::toString(void* object, int maxLength) const
+{
+    QByteArray rc;
+    QByteArray* string = reinterpret_cast<QByteArray*> (object);
+    int length = string->size();
+    if (length + 2 > maxLength)
+        length = maxLength - 2;
+    rc.reserve(length);
+    rc += "'";
+    if (string->size() < maxLength - 2) {
+        rc += *string;
+    } else {
+        rc += string->mid(0, maxLength - 2 - 3);
+        rc += "...";
+    }
+    rc += "'";
+    return rc;
+}
+
+/** @class ReASList rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a list.
+ *
+ * A list is a container of any values.  Values can be selected by the index.
+ */
+/**
+ * @brief Constructor.
+ */
+ReASList::ReASList(ReASTree& tree) :
+    ReASClass("List", tree)
+{
+}
+
+/**
+ * @brief Creates a value object (used in ReASVariant).
+ *
+ * @param source    NULL or a source to copy
+ * @return          a new value object (specific for the class)
+ */
+void* ReASList::newValueInstance(void* source) const
+{
+    ReASListOfVariants* rc = new ReASListOfVariants();
+    if (source != NULL){
+        ReASListOfVariants* source2 = (ReASListOfVariants*) source;
+        rc->reserve(source2->size());
+        ReASListOfVariants::iterator it;
+        for (it = source2->begin();
+                it != source2->end();
+                it++){
+            // deleting in destroyValue():
+            rc->append(new ReASVariant(*(*it)));
+        }
+    }
+    return (void*) rc;
+}
+
+/**
+ * @brief Destroys the given object.
+ *
+ * The object must be created by <code>newValueInstance()</code>.
+ *
+ * @param object    object to destroy
+ */
+void ReASList::destroyValueInstance(void* object) const
+{
+    delete static_cast<ReASListOfVariants*>(object);
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * @param object    the object to test (with type QList*)
+ * @return          false: the list is empty<br>
+ *                  true: otherwise
+ */
+bool ReASList::boolValueOf(void* object) const
+{
+    bool rc = false;
+    if (object != NULL){
+        ReASListOfVariants* list = static_cast<ReASListOfVariants*>(object);
+        if (list == NULL)
+            throw ReException("ReASList.boolValueOf(): not a list");
+        rc = ! list->empty();
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns a string representation of an instance.
+ *
+ * @param object    the object to convert
+ * @param maxLength unused
+ * @return          a string describing the <code>object</code>
+ */
+QByteArray ReASList::toString(void* object, int maxLength) const
+{
+    QByteArray rc;
+    rc.reserve(maxLength);
+    rc += "[";
+    ReASListOfVariants* list = reinterpret_cast<ReASListOfVariants*>(object);
+    ReASListOfVariants::iterator it;
+    bool first = true;
+    for(it = list->begin(); it != list->end(); it++){
+        if (first)
+            first = false;
+        else
+            rc += ",";
+        QByteArray part = (*it)->toString(maxLength - rc.size() - 5);
+        if (maxLength - rc.size() - 5 - part.size() <= 0){
+            rc += "...";
+            break;
+        } else {
+            rc += part;
+        }
+
+    }
+    rc += "]";
+    return rc;
+}
+
+/** @class ReASMap rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a map.
+ *
+ * A map is a container of (key, value) pairs.
+ * Values can be selected by the key.
+ */
+/**
+ * @brief Constructor.
+ */
+ReASMap::ReASMap(ReASTree& tree) :
+    ReASClass("Map", tree)
+{
+}
+/**
+ * @brief Creates a value object (used in ReASVariant).
+ *
+ * @param source    NULL or a source to copy
+ * @return          a new value object (specific for the class)
+ */
+void* ReASMap::newValueInstance(void* source) const
+{
+    ReASMapOfVariants* rc = new ReASMapOfVariants();
+    if (source != NULL){
+        ReASMapOfVariants* source2 =
+                static_cast<ReASMapOfVariants*>(source);
+        // rc->reserve(source2->size());
+        ReASMapOfVariants::iterator it;
+        for (it = source2->begin(); it != source2->end(); it++){
+            // deleting in destroyValue():
+            const QByteArray& key = it.key();
+            ReASVariant* value = new ReASVariant(*it.value());
+            (*rc)[key] = value;
+        }
+    }
+    return (void*) rc;
+}
+
+/**
+ * @brief Destroys the given object.
+ *
+ * The object must be created by <code>newValueInstance()</code>.
+ *
+ * @param object    object to destroy
+ */
+void ReASMap::destroyValueInstance(void* object) const
+{
+    delete (ReASMapOfVariants*) object;
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * @param object    the object to test (with type QMap*)
+ * @return
+ */
+bool ReASMap::boolValueOf(void* object) const
+{
+    bool rc = false;
+    if (object != NULL){
+        ReASMapOfVariants* map = reinterpret_cast<ReASMapOfVariants*>(object);
+        if (map == NULL)
+            throw ReException("ReASMap.boolValueOf(): not a map");
+        rc = map->empty() > 0;
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns a string representation of an instance.
+ *
+ * @param object    the object to convert
+ * @param maxLength maximal length of the result
+ * @return          a string describing the <code>object</code>
+ */
+QByteArray ReASMap::toString(void* object, int maxLength) const
+{
+    QByteArray rc;
+    rc.reserve(maxLength);
+    rc += "[";
+    ReASMapOfVariants* map = reinterpret_cast<ReASMapOfVariants*>(object);
+    ReASMapOfVariants::iterator it;
+    bool first = true;
+    for(it = map->begin(); it != map->end(); it++){
+        if (first)
+            first = false;
+        else
+            rc += ",";
+        if (maxLength - rc.size() - 5 - 2 - it.key().size() <= 0){
+            rc += "...";
+            break;
+        } else {
+            rc += "'";
+            rc += it.key();
+            rc += "':";
+        }
+        QByteArray part = it.value()->toString(maxLength - rc.size() - 5);
+        if (maxLength - rc.size() - 5 - part.size() <= 0){
+            rc += "...";
+            break;
+        } else {
+            rc += part;
+        }
+
+    }
+    rc += "}";
+    return rc;
+}
+
+
+/** @class ReVariable rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a variable of a symbol space.
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReVariable::ReVariable(const QByteArray& name) :
+    m_name(name),
+    m_namespace(NULL),
+    m_value(),
+    m_type(NULL)
+{
+
+}
+
+/**
+ * @brief Writes the content of the instance into an output media.
+ *
+ * @param writer    writes to output
+ * @param indent    nesting level: so many tabs will be used as prefix
+ */
+void ReVariable::dump(ReWriter& writer, int indent)
+{
+    const char* name1 =  m_type == NULL ? "NoneType" : m_type->name().constData();
+    QByteArray val = m_value.toString();
+    writer.formatIndented(indent, "%s %s: value: %s",
+           name1, m_name.constData(), val.constData());
+}
+/**
+ * @brief Returns the data type of the variable.
+ *
+ * @return  the class of the variable
+ */
+ReASClass* ReVariable::type() const
+{
+    return m_type;
+}
+
+/**
+ * @brief Sets the data type.
+ * @param type  the class of the variable
+ */
+void ReVariable::setType(ReASClass* type)
+{
+    m_type = type;
+}
+/**
+ * @brief Returns the name of the variable.
+ *
+ * @return  the name
+ */
+const QByteArray& ReVariable::name() const
+{
+    return m_name;
+}
+
+/** @class ReVariable rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a data type representing a none type.
+ */
+ReASVoid::ReASVoid(ReASTree& tree) :
+    ReASClass("Void", tree)
+{
+}
+
+/**
+ * @brief Instantiates a new object.
+ *
+ * In this case we do nothing.
+ *
+ * @param source    ignored
+ * @return
+ */
+void*ReASVoid::newValueInstance(void*) const
+{
+    return NULL;
+}
+
+/**
+ * @brief Destroys an object created by newValueInstance.
+ *
+ * In this case we do nothing.
+ *
+ * @param object    not used
+ */
+void ReASVoid::destroyValueInstance(void*) const
+{
+}
+
+/**
+ * @brief Returns the bool value of the given object
+ * @param object    ignored
+ * @return          false
+ */
+bool ReASVoid::boolValueOf(void*) const
+{
+    return false;
+}
+
+/**
+ * @brief Converts the object into a string.
+ *
+ * @param object    ignored
+ * @param maxLength ignored
+ * @return          the empty string
+ */
+QByteArray ReASVoid::toString(void*, int) const
+{
+    return QByteArray("");
+}
+
+/** @class ReASFormula rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a data type representing a calculated value.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param tree  the abstract syntax tree
+ */
+ReASFormula::ReASFormula(ReASTree& tree) :
+    ReASClass("Formula", tree)
+{
+}
+
+/**
+ * @brief Instantiates a new object.
+ *
+ * In this case we do nothing.
+ *
+ * @param expr      the result
+ * @return
+ */
+void* ReASFormula::newValueInstance(void* expr) const
+{
+    return expr;
+}
+
+/**
+ * @brief Destroys an object created by newValueInstance.
+ *
+ * In this case we do nothing.
+ *
+ * @param object    not used
+ */
+void ReASFormula::destroyValueInstance(void*) const
+{
+}
+
+/**
+ * @brief Returns the bool value of the given object
+ * @param object    ignored
+ * @return          false
+ */
+bool ReASFormula::boolValueOf(void*) const
+{
+    return false;
+}
+
+/**
+ * @brief Converts the object into a string.
+ *
+ * @param object    ignored
+ * @param maxLength ignored
+ * @return          the empty string
+ */
+QByteArray ReASFormula::toString(void* object, int) const
+{
+    ReASExprStatement* expr = static_cast<ReASExprStatement*>(object);
+
+    char buffer[64];
+    qsnprintf(buffer, sizeof buffer, "<formula %d>", expr->id());
+    return buffer;
+}
+
+/** @class ReASUserClass rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a data type representing an user defined class.
+ */
+
+
+/**
+ * @brief Constructor.
+ *
+ * @param name      name of the user defined class
+ * @param position  the position of the class definition
+ * @param tree      the abstract syntax tree
+ */
+ReASUserClass::ReASUserClass(const QByteArray& name,
+                               const ReSourcePosition* position,
+                               ReASTree& tree) :
+    ReASClass(name, tree),
+    m_position(position)
+{
+}
+
+/**
+ * @brief Creates an instance of an user defined class.
+ *
+ * @param source    the type (user defined class) of the result
+ * @return          an instance of an user defined class
+ */
+void*ReASUserClass::newValueInstance(void* source) const
+{
+    ReASUserClass* clazz = static_cast<ReASUserClass*>(source);
+    ReASUserObject* rc = new ReASUserObject(clazz);
+    return static_cast<void*>(rc);
+}
+
+void ReASUserClass::destroyValueInstance(void* object) const
+{
+    ReASUserObject* obj = static_cast<ReASUserObject*>(object);
+    delete obj;
+}
+
+/**
+ * @brief Returns the bool value of the object.
+ *
+ * @param object    object to test
+ * @return          true: object != NULL<br>
+ *                  false: object == NULL
+ */
+bool ReASUserClass::boolValueOf(void* object) const
+{
+    return object != NULL;
+}
+
+/**
+ * @brief Returns a string representation an instance of a user defined class.
+ *
+ * @param object        object to convert
+ * @param maxLength     maximum length of the string
+ * @return
+ */
+QByteArray ReASUserClass::toString(void*, int) const
+{
+    return m_name;
+}
+/**
+ * @brief Returns the source position of the instance.
+ *
+ * @return  the source position
+ */
+const ReSourcePosition* ReASUserClass::position() const
+{
+    return m_position;
+}
+
+
+
+/** @class ReASUserObject rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an instance of an user defined class.
+ */
+ReASUserObject::ReASUserObject(ReASUserClass* clazz) :
+    m_class(clazz),
+    m_fields(NULL)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReASUserObject::~ReASUserObject()
+{
+    delete[] m_fields;
+    m_fields = NULL;
+}
diff --git a/expr/ReAsClasses.hpp b/expr/ReAsClasses.hpp
new file mode 100644 (file)
index 0000000..53f3f90
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLASCLASSES_HPP
+#define RPLASCLASSES_HPP
+
+class ReSymbolSpace;
+class ReVariable {
+public:
+    ReVariable(const QByteArray& name);
+public:
+    void dump(ReWriter& writer, int indent);
+
+    ReASClass* type() const;
+    void setType(ReASClass* type);
+    const QByteArray& name() const;
+
+protected:
+    QByteArray m_name;
+    // NULL for "simple" variables (int, float, bool)
+    ReSymbolSpace* m_namespace;
+    ReASVariant m_value;
+    ReASClass* m_type;
+};
+
+class ReASScope
+{
+public:
+    int m_builtInVars;
+    int m_varNoAtStart;
+};
+
+class ReASUserClass;
+class ReASTree;
+class ReSymbolSpace
+{
+public:
+    enum SymbolSpaceType {
+        SST_UNDEF,
+        SST_GLOBAL,
+        SST_MODULE,
+        SST_CLASS,
+        SST_METHOD
+    };
+
+public:
+    typedef QMap<QByteArray, ReASVarDefinition*> VariableMap;
+    typedef QMap<QByteArray, ReASClass*> ClassMap;
+    typedef QMap<QByteArray, ReASMethod*> MethodMap;
+    typedef QList<ReASVarDefinition*> VariableList;
+private:
+    ReSymbolSpace(ReASTree& tree);
+public:
+    ReSymbolSpace(SymbolSpaceType type, const QByteArray& name,
+                   ReSymbolSpace* parent);
+    virtual ~ReSymbolSpace();
+public:
+    void startScope(ReASScope& scope);
+    void finishScope(int endOfScope, ReASScope& scope);
+    ReASVarDefinition* findVariable(const QByteArray& name) const;
+    ReASClass* findClass(const QByteArray& name) const;
+    ReASMethod* findMethod(const QByteArray& name) const;
+    void dump(ReWriter& writer, int indent, const char* header = NULL);
+    const QByteArray& name() const;
+    ReASItem* body() const;
+    void setBody(ReASItem* body);
+    ReASItem* addVariable(ReASVarDefinition* variable, int& varNo);
+    ReASItem* addMethod(ReASMethod* method);
+    ReASUserClass* addClass(ReASUserClass* clazz);
+    ReSymbolSpace* parent() const;
+    VariableList listOfVars() const;
+public:
+    static const char* spaceTypeName(SymbolSpaceType type);
+    static ReSymbolSpace* createGlobal(ReASTree& tree);
+private:
+    SymbolSpaceType m_type;
+    QByteArray m_name;
+    VariableMap m_variables;
+    ClassMap m_classes;
+    MethodMap m_methods;
+    ReSymbolSpace* m_parent;
+    ReASItem* m_body;
+    VariableList m_listOfVars;
+    ReASTree& m_tree;
+};
+
+class ReASBoolean : public ReASClass {
+public:
+    ReASBoolean(ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASBoolean* m_instance;
+};
+
+class ReASFloat : public ReASClass {
+public:
+    ReASFloat(ReASTree& tree);
+    ReASFloat(const QByteArray& name, ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASFloat* m_instance;
+};
+
+class ReASInteger : public ReASFloat {
+public:
+    ReASInteger(ReASTree& tree);
+public:
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASInteger* m_instance;
+};
+
+class ReASString : public ReASClass {
+public:
+    ReASString(ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASString* m_instance;
+};
+
+class ReASList : public ReASClass {
+public:
+    ReASList(ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASList* m_instance;
+};
+
+class ReASMap : public ReASClass {
+public:
+    ReASMap(ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASMap* m_instance;
+};
+
+class ReASVoid : public ReASClass {
+public:
+    ReASVoid(ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASVoid* m_instance;
+};
+
+class ReASFormula : public ReASClass {
+public:
+    ReASFormula(ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+public:
+    static ReASFormula* m_instance;
+};
+
+class ReASUserClass : public ReASClass {
+public:
+    ReASUserClass(const QByteArray& name, const ReSourcePosition* position,
+                   ReASTree& tree);
+public:
+    void* newValueInstance(void* source = NULL) const;
+    void destroyValueInstance(void* object) const;
+    virtual bool boolValueOf(void* object) const;
+    virtual QByteArray toString(void *object, int maxLength = 80) const;
+    const ReSourcePosition* position() const;
+
+private:
+    const ReSourcePosition* m_position;
+};
+
+class ReASUserObject {
+public:
+    ReASUserObject(ReASUserClass* clazz);
+    ~ReASUserObject();
+public:
+    void callMember();
+private:
+    ReASUserClass* m_class;
+    ReASVariant* m_fields;
+};
+
+#endif // RPLASCLASSES_HPP
diff --git a/expr/ReLexer.cpp b/expr/ReLexer.cpp
new file mode 100644 (file)
index 0000000..986ebc6
--- /dev/null
@@ -0,0 +1,1234 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+/** @file
+ * @brief Configurable scanner, which separates syntactic symbols from an input media.
+ */
+/** @file expr/ReLexer.hpp
+ * @brief Definitions for a configurable lexical analyser.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+#define CHAR_INFO_SIZE (int(sizeof m_charInfo / sizeof m_charInfo[0]))
+
+
+/** @class ReToken ReLexer.hpp "expr/ReLexer.hpp"
+ *
+ * @brief Implements specific exception for the lexer.
+ *
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param position  describes the position of the error/warning
+ * @param format    the reason of the exception
+ * @param ...       the values for the placeholders in the format.
+ */
+ReLexException::ReLexException(const ReSourcePosition& position,
+                                 const char* format, ...) :
+    ReException("")
+{
+    char buffer[64000];
+    m_message = position.toString().toUtf8();
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    m_message += buffer;
+}
+
+/** @class ReToken ReLexer.hpp "expr/ReLexer.hpp"
+ *
+ * @brief Implements a token which is the smallest unit for a parser.
+ *
+ */
+/**
+ * @brief Constructor.
+ * @param type  token type
+ */
+ReToken::ReToken(RplTokenType type) :
+    m_tokenType(type),
+    m_string(),
+    m_printableString()
+    // m_value
+{
+    memset(&m_value, 0, sizeof m_value);
+}
+
+/**
+ * @brief Destructor.
+ */
+ReToken::~ReToken()
+{
+}
+/**
+ * @brief Copy constructor.
+ *
+ * @param source    source to copy
+ */
+ReToken::ReToken(const ReToken& source) :
+    m_tokenType(source.m_tokenType),
+    m_string(source.m_string),
+    m_printableString(source.m_printableString),
+    m_value(source.m_value)
+{
+}
+/**
+ * @brief Assignment operator.
+ *
+ * @param source    source to copy
+ * @return
+ */
+ReToken& ReToken::operator =(const ReToken& source)
+{
+    m_tokenType = source.m_tokenType;
+    m_string = source.m_string;
+    m_value = source.m_value;
+    return *this;
+}
+
+/**
+ * @brief Returns the string representation of the instance
+ * @return a string representing the instance
+ */
+const QByteArray& ReToken::toString()
+{
+    return m_string;
+}
+
+/**
+ * @brief Returns the integer value of the token
+ *
+ * Only relevant if a TOKEN_NUMBER.
+ *
+ * @return the value of the token as integer
+ */
+int ReToken::asInteger() const
+{
+    return (int) m_value.m_integer;
+}
+
+/**
+ * @brief Returns the integer value of the token
+ *
+ * Only relevant if a TOKEN_NUMBER.
+ *
+ * @return the value of the token as unsigned integer (64 bit)
+ */
+quint64 ReToken::asUInt64() const
+{
+    return m_value.m_integer;
+}
+
+/**
+ * @brief Returns the floating point value of the token
+ *
+ * Only relevant if a TOKEN_REAL.
+ *
+ * @return the value of the token as floating point value
+ */
+qreal ReToken::asReal() const
+{
+    return m_value.m_real;
+}
+
+/**
+ * @brief Returns the floating point value of the token
+ *
+ * Only relevant if a TOKEN_NUMBER.
+ *
+ * @return the value of the token as floating point value
+ */
+const QByteArray& ReToken::rawString() const
+{
+    return m_printableString;
+}
+/**
+ * @brief Returns the id of the token.
+ *
+ * Ids are more handy than string, e.g. allowing switch statements.
+ *
+ * Only relevant for TOKEN_KEYWORD and TOKEN_OPERATOR.
+ *
+ * @return the id of the token
+ */
+int ReToken::id() const
+{
+    return m_value.m_id;
+}
+/**
+ * @brief Returns the token type.
+ * @return the token type
+ */
+RplTokenType ReToken::tokenType() const
+{
+    return m_tokenType;
+}
+
+/**
+ * @brief Checks whether the instance has a given token type.
+ *
+ * @param expected  the token type to compare
+ *
+ * @return  true: the expected type is the current<br>
+ *          false: otherwise
+ */
+bool ReToken::isTokenType(RplTokenType expected) const
+{
+    return m_tokenType == expected;
+}
+
+/**
+ * @brief Checks whether the instance is a given operator.
+ *
+ * @param expected      the expected operator
+ * @param alternative   0 or a second possibility
+ *
+ * @return  true: the instance is an operator and the expected or the alternative<br>
+ *          false: otherwise
+ */
+bool ReToken::isOperator(int expected, int alternative) const
+{
+    return m_tokenType == TOKEN_OPERATOR && (m_value.m_id == expected
+                                             || m_value.m_id == alternative);
+}
+
+/**
+ * @brief Checks whether the instance is a given keyword.
+ *
+ * @param expected      the expected keyword
+ * @param alternative   0 or a second possibility
+ *
+ * @return  true: the instance is a keyword and the expected or the alternative<br>
+ *          false: otherwise
+ */
+
+bool ReToken::isKeyword(int expected, int alternative) const
+{
+    return m_tokenType == TOKEN_KEYWORD && (m_value.m_id == expected
+                                             || m_value.m_id == alternative);
+}
+
+/**
+ * @brief Makes all members undefined.
+ */
+void ReToken::clear()
+{
+    m_string.clear();
+    m_printableString.clear();
+    m_tokenType = TOKEN_UNDEF;
+    m_value.m_integer = 0;
+}
+
+/**
+ * @brief Returns whether the token is a capitalized id
+ *
+ * @return  true: the token is an id and the first char is an upper case char<br>
+ *          false: otherwise
+ */
+bool ReToken::isCapitalizedId() const
+{
+    bool rc = m_tokenType == TOKEN_ID && isupper(m_string.at(0))
+            && (m_string.length() == 1 || islower(m_string.at(1)));
+    return rc;
+}
+
+/**
+ * @brief Returns the description of the current token.
+ *
+ * @return a description of the instance
+ */
+QByteArray ReToken::dump() const
+{
+    QByteArray rc;
+    rc = nameOfType(m_tokenType);
+    rc.append(": ").append(this->asUtf8());
+    return rc;
+}
+QByteArray ReToken::asUtf8() const
+{
+    char buffer[4096];
+    buffer[0] = '\0';
+
+    switch(m_tokenType){
+    case TOKEN_UNDEF:
+        break;
+    case TOKEN_STRING:
+        qsnprintf(buffer, sizeof buffer, "'%.*s'", int(sizeof buffer) - 1,
+                 m_printableString.constData());
+        break;
+    case TOKEN_NUMBER:
+        qsnprintf(buffer, sizeof buffer, "%lld", m_value.m_integer);
+        break;
+    case TOKEN_REAL:
+        qsnprintf(buffer, sizeof buffer, "%f", m_value.m_real);
+        break;
+    case TOKEN_KEYWORD:
+    case TOKEN_OPERATOR:
+        qsnprintf(buffer, sizeof buffer, "%lld", (int) m_value.m_id);
+        break;
+    case TOKEN_ID:
+        qsnprintf(buffer, sizeof buffer, "'%.*s'", int(sizeof buffer) - 1,
+                 m_string.constData());
+        break;
+    case TOKEN_COMMENT_REST_OF_LINE:
+    case TOKEN_COMMENT_START:
+    case TOKEN_COMMENT_END:
+    case TOKEN_SPACE:
+    case TOKEN_END_OF_SOURCE:
+    default:
+        break;
+    }
+    return buffer;
+}
+/**
+ * @brief Returns then name of a token type.
+ * @param   type  the type to convert
+ * @return  the token type name
+ */
+const char* ReToken::nameOfType(RplTokenType type)
+{
+    const char* rc = "?";
+
+    switch(type){
+    case TOKEN_UNDEF:
+        rc = "undef";
+        break;
+    case TOKEN_STRING:
+        rc = "String";
+        break;
+    case TOKEN_NUMBER:
+        rc = "Number";
+        break;
+    case TOKEN_REAL:
+        rc = "Real";
+        break;
+    case TOKEN_KEYWORD:
+        rc = "Keyword";
+        break;
+    case TOKEN_OPERATOR:
+        rc = "Operator";
+        break;
+    case TOKEN_ID:
+        rc = "Id";
+        break;
+    case TOKEN_COMMENT_REST_OF_LINE:
+        rc = "Comment-1-line";
+        break;
+    case TOKEN_COMMENT_START:
+        rc = "Comment-m-line";
+        break;
+    case TOKEN_COMMENT_END:
+        rc = "end of comment";
+        break;
+    case TOKEN_SPACE:
+        rc = "space";
+        break;
+    case TOKEN_END_OF_SOURCE:
+        rc = "end of source";
+        break;
+    default:
+        break;
+    }
+    return rc;
+}
+
+
+/** @class ReLexer ReLexer.hpp "expr/ReLexer.hpp"
+ *
+ * @brief Implements a lexical analyser.
+ *
+ * A lexical analyser reads a text source and separates the tokens for a parser.
+ * Tokens are the smallest elements of a parsing process.
+ *
+ */
+
+static void itemsToVector(const char* items, ReLexer::StringList& vector,
+                         int firstCharFlag, int secondCharFlag,
+                         int thirdCharFlag, int restCharFlag,
+                         int charInfo[])
+{
+    QByteArray array2(items);
+    QList<QByteArray> list = array2.split(' ');
+    QList<QByteArray>::iterator it;
+    int id = 0;
+    for (it = list.begin(); it < list.end(); it++){
+        QByteArray& item2 = *it;
+        QByteArray item(item2);
+        id++;
+        item.append(' ').append(id % 256).append(id / 256);
+        vector.append(item);
+        unsigned char cc = item2.at(0);
+        if (cc < 128)
+            charInfo[cc] |= firstCharFlag;
+        if(item2.size() > 1){
+            cc = item2.at(1);
+            if (cc < 128)
+                charInfo[cc] |= secondCharFlag;
+        }
+        if(item2.size() > 2){
+            cc = item2.at(2);
+            if (cc < 128)
+                charInfo[cc] |= thirdCharFlag;
+        }
+        if(item2.size() > 3){
+            const char* ptr = item2.constData() + 3;
+            while( (cc = *ptr++) != '\0'){
+                if (cc < 128)
+                    charInfo[cc] |= restCharFlag;
+            }
+        }
+    }
+    qSort(vector.begin(), vector.end(), qLess<QByteArray>());
+}
+
+static void charClassToCharInfo(const char* charClass, int flag,
+     int charInfo[])
+{
+    for (int ix = 0; charClass[ix] != '\0'; ix++){
+        unsigned char cc = (unsigned char) charClass[ix];
+        if (cc < 128)
+            charInfo[cc] |= flag;
+        if (charClass[ix+1] == '-'){
+            unsigned char ubound = charClass[ix+2];
+            if (ubound == '\0')
+                charInfo['-'] |= flag;
+            else if (cc >= ubound)
+                throw new ReException("wrong character class range: %c-%c (%s)",
+                         cc, ubound, charClass);
+            else {
+                for (int ii = cc + 1; ii <= ubound; ii++){
+                    charInfo[ii] |= flag;
+                }
+            }
+            ix += 2;
+        }
+    }
+}
+
+/**
+ * @brief Constructor.
+ *
+ * @param source        the input source handler
+ * @param keywords      a string with all keywords delimited by " ".
+ *                      Example: "if then else fi while do done"
+ * @param operators     a string with the operators separated by blank or "\n".
+ *                      "\n" separates the operators with the same priority.
+ *                      Lower position means lower priority
+ * @param rightAssociatives
+ *                      the operators which are right associative
+ * @param comments      a string with pairs of comment begin and end delimited
+ *                      by " ". The comment end can be "\n" for line end.
+ *                      Example: "/ * * / // \n" (ignore the blank in "* /")
+ * @param firstCharsId  string with the characters which are allowed as first
+ *                      characters of an id
+ * @param restCharsId   string with the characters which are allowed as non
+ *                      first characters of an id
+ * @param numericTypes  bit mask of allowed numeric,
+ *                      e.g. NUMTYPE_DECIMAL | NUMTYPE_HEXADECIMAL
+ * @param stringFeatures bit mask of the string features,
+ *                      e.g. SF_QUOTE | SF_TICK
+ * @param storageFlags  describes the things which should be stored, e.g.
+ *                      S_ORG_STRINGS | S_COMMENTS | S_BLANKS
+ */
+ReLexer::ReLexer(ReSource* source,
+        const char* keywords,
+        const char* operators, const char* rightAssociatives,
+        const char* comments,
+        const char* firstCharsId, const char* restCharsId, int numericTypes,
+        int stringFeatures, int storageFlags) :
+    m_source(source),
+    m_keywords(),
+    m_operators(),
+    m_commentStarts(),
+    m_commentEnds(),
+    //m_charInfo()
+    m_idFirstRare(),
+    m_idRestRare(),
+    m_numericTypes(numericTypes),
+    m_idRest2(),
+    m_currentToken(&m_token1),
+    m_waitingToken(NULL),
+    m_waitingToken2(NULL),
+    m_token1(TOKEN_UNDEF),
+    m_token2(TOKEN_UNDEF),
+    m_currentPosition(NULL),
+    m_waitingPosition1(NULL),
+    m_waitingPosition2(NULL),
+    m_maxTokenLength(64),
+    m_input(),
+    m_currentCol(0),
+    m_hasMoreInput(false),
+    m_stringFeatures(stringFeatures),
+    m_storageFlags(storageFlags),
+    // m_prioOfOp
+    // m_assocOfOp
+    #if defined (RPL_LEXER_TRACE)
+    m_trace(true),
+    #endif
+    m_opNames()
+{
+    memset(m_prioOfOp, 0, sizeof m_prioOfOp);
+    memset(m_assocOfOp, 0, sizeof m_assocOfOp);
+
+    memset(m_charInfo, 0, sizeof m_charInfo);
+    itemsToVector(keywords, m_keywords, CC_FIRST_KEYWORD, CC_2nd_KEYWORD,
+                  CC_3rd_KEYWORD, CC_REST_KEYWORD, m_charInfo);
+    prepareOperators(operators, rightAssociatives);
+    charClassToCharInfo(firstCharsId, CC_FIRST_ID, m_charInfo);
+    charClassToCharInfo(restCharsId, CC_REST_ID, m_charInfo);
+    initializeComments(comments);
+    m_input.reserve(m_maxTokenLength*2);
+}
+/**
+ * @brief Destructor.
+ */
+ReLexer::~ReLexer()
+{
+}
+
+/**
+ * @brief Returns the count of blanks in a given range of a string.
+ *
+ * @param start pointer to the first char to check
+ * @param end   pointer to the last char to check
+ * @return  the count of blanks
+ */
+int countBlanks(const char* start, const char* end){
+    int rc = 0;
+    while(start != end){
+        if (*start++ == ' '){
+            rc++;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Stores the operators in the internal members
+ *
+ * @param operators     a string with the operators separated by blank or '\n'.
+ *                      '\n' separates the operators with the same priority.
+ *                      Lower position means lower priority
+ */
+void ReLexer::prepareOperators(const char* operators,
+                                const char* rightAssociatives){
+    QByteArray op2(operators);
+    QByteArray rightAssociatives2(" ");
+    rightAssociatives2 += rightAssociatives;
+    op2.replace("\n", " ");
+    itemsToVector(op2.constData(), m_operators, CC_FIRST_OP, CC_2nd_OP,
+                  CC_3rd_OP, CC_REST_OP, m_charInfo);
+    // m_operators is now sorted:
+    // test whether the successor of 1 char operators is starting with this char:
+    // if not this operator will be marked with CC_OP_1_ONLY:
+    for (int ix = 0; ix < m_operators.size() - 1; ix++){
+        // the entries of m_operators end with ' ' and id:
+        if (m_operators.at(ix).size() == 1 + 2
+                && m_operators.at(ix).at(0) != m_operators.at(ix+1).at(0)){
+            int cc = (char) m_operators[ix].at(0);
+            m_charInfo[cc] |= CC_OP_1_ONLY;
+        }
+
+    }
+    m_opNames.reserve(m_operators.size() + 1);
+    op2 = " " + op2;
+    m_opNames = op2.split(' ');
+    QByteArray rAssoc = QByteArray(" ") + rightAssociatives + " ";
+    for (int opId = m_opNames.size() - 1; opId >= 1; opId--){
+        QByteArray item = " " + m_opNames[opId] + " ";
+        if (rAssoc.indexOf(item) >= 0)
+            m_assocOfOp[opId] = true;
+    }
+    const char* start = operators;
+    const char* end;
+    int prio = 0;
+    int endId = 0;
+    int startId = 1;
+    bool again = true;
+    while (again){
+        if ( (end = strchr(start, '\n')) == NULL){
+             end = strchr(start, '\0');
+             again = false;
+        }
+        prio++;
+        endId = startId + countBlanks(start, end) + 1 - 1;
+        while(startId <= endId){
+            m_prioOfOp[startId++] = prio;
+        }
+        start = end + 1;
+    }
+}
+
+void ReLexer::initializeComments(const char* comments)
+{
+    if (comments != NULL)
+    {
+        QByteArray starters;
+        QByteArray comments2(comments);
+        int ix = comments2.indexOf("  ");
+        if (ix >= 0)
+            throw ReException("more than one blank between comment pair(s): col %d %s",
+                               ix + 1, comments + ix);
+        // the index of m_commentEnds is the position number: we need a dummy entry:
+        m_commentEnds.append("");
+
+        QList<QByteArray> items = comments2.split(' ');
+        QList<QByteArray>::iterator it;
+        ix = 0;
+        for (it = items.begin(); it != items.end(); it++, ix++){
+             if (ix % 2 == 0){
+                if (ix > 0)
+                    starters += " ";
+                starters += *it;
+            }else{
+                 m_commentEnds.append(*it);
+            }
+        }
+        if (ix % 2 != 0)
+            throw ReException("not only pairs in the comment list");
+        itemsToVector(starters, m_commentStarts, CC_FIRST_COMMENT_START,
+             CC_2nd_COMMENT_START, CC_3rd_COMMENT_START, CC_REST_COMMENT_START,
+             m_charInfo);
+    }
+}
+/**
+ * @brief Searches the prefix of <code>m_input</code> in the vector.
+ *
+ * @param tokenLength   the length of the prefix in <code>m_input</code>
+ * @param vector        the vector to search. Each element contains the id
+ *                      as last entry
+ * @param id            the id of the entry in the vector. Only set if found
+ * @return
+ */
+int ReLexer::findInVector(int tokenLength, const StringList& vector)
+{
+    int id = 0;
+    int lbound = 0;
+    int ubound = vector.size() - 1;
+    // binary search over the sorted vector:
+    while(lbound <= ubound){
+        int half = (ubound + lbound) / 2;
+        int compareRc = 0;
+        int ix = 0;
+        const QByteArray& current = vector[half];
+        // vector items end with ' ' and id (2 byte):
+        int currentLength = current.size() - 3;
+        while(ix < tokenLength && compareRc == 0){
+            if (ix >= currentLength)
+                // current is shorter:
+                compareRc = 1;
+            else
+                compareRc = m_input.at(ix) - (int) current.at(ix);
+            ix++;
+        }
+        if (compareRc == 0 && current.at(ix) != ' ')
+            // token.size() < current.size():
+            compareRc = -1;
+        if (compareRc < 0)
+            ubound = half - 1;
+        else if (compareRc > 0)
+            lbound = half + 1;
+        else {
+            id = current[currentLength + 1] + current[currentLength + 2] * 256;
+            break;
+        }
+    }
+    return id;
+}
+/**
+ * @brief Reads data until enough data are available for one token.
+ *
+ * Data will be read from the current source unit.
+ * If this unit does not contain more data the next source unit from the stack
+ * will be used until the stack is empty.
+ *
+ * @return  false: no more input is available<br>
+ *          true: data are available
+ */
+bool ReLexer::fillInput()
+{
+    if (m_hasMoreInput){
+        if (m_input.size() < m_maxTokenLength){
+            m_source->currentReader()->fillBuffer(m_maxTokenLength, m_input,
+                                                  m_hasMoreInput);
+        }
+    }
+
+    while (m_input.size() == 0 && m_source->currentReader() != NULL){
+        if (m_source->currentReader()->nextLine(m_maxTokenLength,
+                                                  m_input, m_hasMoreInput)){
+            m_currentCol = 0;
+        }
+    }
+    return m_input.size() > 0;
+}
+
+/**
+ * @brief Finds a token with an id: TOKEN_OP, TOKEN_KEYWORD, ...
+ *
+ * @post    the token is removed from the input
+ *
+ * @param tokenType the token type
+ * @param flag2     the flag of the 2nd char
+ * @param names     the vector with the names, sorted
+ * @return          NULL: not found<br>
+ *                  otherwise: the token
+ */
+ReToken* ReLexer::findTokenWithId(RplTokenType tokenType, int flag2,
+                                   StringList& names)
+{
+    int length = 1;
+    int inputLength = m_input.size();
+    int cc;
+    if (inputLength > 1){
+        cc = m_input[1];
+        if (cc < CHAR_INFO_SIZE && (m_charInfo[cc] & flag2)){
+            length++;
+            if (inputLength > 2){
+                cc = m_input[2];
+                // the 3rd char flag is the "successor" of the 2nd char flag:
+                int flag = (flag2 << 1);
+                if (cc < CHAR_INFO_SIZE && (m_charInfo[cc] & flag)){
+                    length++;
+                    // the rest char flag is the "successor" of the 3nd char flag:
+                    flag <<= 1;
+                    while (length < inputLength){
+                        cc = m_input[length];
+                        if (cc < CHAR_INFO_SIZE && (m_charInfo[cc] & flag))
+                            length++;
+                        else
+                            break;
+                    }
+                }
+            }
+        }
+    }
+    ReToken* rc = NULL;
+    if (! (tokenType == TOKEN_KEYWORD && length < inputLength
+            && (cc = m_input[length]) < CHAR_INFO_SIZE
+            && (m_charInfo[cc] & CC_REST_ID))) {
+        int id;
+        // the length could be too long: the CC_2nd_.. flag could be ambigous
+        while( (id = findInVector(length, names)) <= 0){
+            if (length == 1 || tokenType == TOKEN_KEYWORD){
+                break;
+            }
+            length--;
+        }
+        if (id > 0){
+            rc = m_currentToken;
+            rc->m_tokenType = tokenType;
+            rc->m_value.m_id = id;
+            if (tokenType == TOKEN_COMMENT_START
+                    && (m_storageFlags & STORE_COMMENT) != 0)
+                rc->m_string.append(m_input.mid(0, length));
+            m_input.remove(0, length);
+            m_currentCol += length;
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Converts the number into a token.
+ *
+ * @return  the token with the number
+ */
+ReToken* ReLexer::scanNumber()
+{
+    int inputLength = m_input.size();
+    int cc;
+    int length;
+    quint64 value = 0;
+    if ( (cc = m_input[0]) == '0' && inputLength > 1
+            && (m_numericTypes & NUMTYPE_HEXADECIMAL)
+            && (m_input[1] == 'x' || m_input[1] == 'X')){
+        length = ReStringUtil::lengthOfUInt64(m_input.constData() + 2, 16, &value);
+        if (length > 0)
+            length += 2;
+        else
+            throw ReException("invalid hexadecimal number: no digit behind 'x");
+    } else if (cc == '0' && (m_numericTypes & NUMTYPE_OCTAL)
+               && inputLength > 1){
+        length = 1;
+        while (length < inputLength){
+            if ( (cc = m_input[length]) >= '0' && cc <= '7')
+                value = value * 8 + cc - '0';
+            else if (cc >= '8' && cc <= '9')
+                throw ReLexException(*m_currentPosition,
+                                      "invalid octal digit: %c", cc);
+            else
+                break;
+            length++;
+        }
+    } else {
+        length = 1;
+        value = cc - '0';
+        while (length < inputLength){
+            if ( (cc = m_input[length]) >= '0' && cc <= '9')
+                value = value * 10 + cc - '0';
+            else
+                break;
+            length++;
+        }
+    }
+    m_currentToken->m_value.m_integer = value;
+    m_currentToken->m_tokenType = TOKEN_NUMBER;
+    if (length + 1 < inputLength
+            && ((cc = m_input[length]) == '.' || toupper(cc) == 'E')){
+        qreal realValue;
+        int realLength = ReStringUtil::lengthOfReal(m_input.constData(), &realValue);
+        if (realLength > length){
+            m_currentToken->m_tokenType = TOKEN_REAL;
+            m_currentToken->m_value.m_real = realValue;
+            length = realLength;
+        }
+    }
+    m_input.remove(0, length);
+    m_currentCol += length;
+    return m_currentToken;
+}
+
+/**
+ * @brief Reads a string into the internal data.
+ * @return the token with the string
+ */
+ReToken*ReLexer::scanString()
+{
+    int delim = m_input[0];
+    int inputLength = m_input.size();
+    int cc;
+    int length = 1;
+    m_currentToken->m_tokenType = TOKEN_STRING;
+    m_currentToken->m_value.m_id = delim;
+    bool again = false;
+    do {
+        while(length < inputLength && (cc = m_input[length]) != delim){
+            length++;
+            if (cc != '\\'
+                || (m_stringFeatures
+                    & (SF_C_ESCAPING | SF_C_HEX_CHARS | SF_C_SPECIAL)) == 0){
+                m_currentToken->m_string.append(QChar(cc));
+            } else {
+                if (length >= inputLength)
+                    throw ReLexException(*m_currentPosition,
+                        "backslash without following character");
+                cc = m_input[length++];
+                if ( (m_stringFeatures & SF_C_HEX_CHARS) && toupper(cc) == 'X'){
+                    if (length >= inputLength)
+                        throw ReLexException(*m_currentPosition,
+                            "missing hexadecimal digit behind \\x");
+                    cc = m_input[length++];
+                    int hexVal = ReQString::valueOfHexDigit(cc);
+                    if (hexVal < 0)
+                        throw ReLexException(*m_currentPosition,
+                            "not a hexadecimal digit behind \\x: %lc",
+                            QChar(cc));
+                    if (length < inputLength){
+                       cc = m_input[length];
+                       int nibble = ReQString::valueOfHexDigit(cc);
+                       if (nibble >= 0){
+                           length++;
+                           hexVal = hexVal * 16 + nibble;
+                       }
+                    }
+                    m_currentToken->m_string.append(QChar(hexVal));
+                } else if ( (m_stringFeatures & SF_C_SPECIAL)){
+                    switch(cc){
+                    case 'r':
+                        cc = '\r';
+                        break;
+                    case 'n':
+                        cc = '\n';
+                        break;
+                    case 't':
+                        cc = '\t';
+                        break;
+                    case 'a':
+                        cc = '\a';
+                        break;
+                    case 'v':
+                        cc = '\v';
+                        break;
+                    case 'f':
+                        cc = '\f';
+                        break;
+                    default:
+                        break;
+                    }
+                    m_currentToken->m_string.append(QChar(cc));
+                } else {
+                   m_currentToken->m_string.append(QChar(cc));
+                }
+            }
+        }
+        if (cc == delim){
+            length++;
+        }
+        if ( (m_stringFeatures & SF_DOUBLE_DELIM) && length < inputLength
+             && m_input[length] == (char) delim){
+            m_currentToken->m_printableString.append(delim);
+            length++;
+            again = true;
+        }
+    }
+    while(again);
+    if (m_storageFlags & STORE_ORG_STRING)
+        m_currentToken->m_printableString.append(m_input.mid(0, length));
+    m_input.remove(0, length);
+    m_currentCol += length;
+    return m_currentToken;
+}
+
+/**
+ * @brief Reads a comment into the internal data.
+ *
+ * precondition: the current token is prepared yet
+ */
+void ReLexer::scanComment()
+{
+    int inputLength = m_input.size();
+    int length = 1;
+    QByteArray& commentEnd = m_commentEnds[m_currentToken->id()];
+    int ix;
+    if (commentEnd[0] == '\n'){
+        // single line comment:
+        if (m_storageFlags & STORE_COMMENT)
+            m_currentToken->m_string.append(m_input);
+        length = inputLength;
+    } else {
+        // multiline comment:
+        while( (ix = m_input.indexOf(commentEnd)) < 0){
+            if (m_storageFlags & STORE_COMMENT)
+                m_currentToken->m_string.append(m_input);
+            m_input.clear();
+            if (! fillInput())
+                throw ReLexException(*m_currentPosition,
+                    "comment end not found");
+        }
+        length = ix + commentEnd.size();
+        if (m_storageFlags & STORE_COMMENT)
+            m_currentToken->m_string
+                    .append(m_input.mid(0, length));
+    }
+    m_input.remove(0, length);
+    m_currentCol += length;
+}
+#if defined (RPL_LEXER_TRACE)
+bool ReLexer::trace() const
+{
+    return m_trace;
+}
+
+void ReLexer::setTrace(bool trace)
+{
+    m_trace = trace;
+}
+#endif
+/**
+ * @brief Returns the last read token.
+ *
+ * @return  the current token
+ */
+ReToken* ReLexer::currentToken() const
+{
+    return m_currentToken;
+}
+
+/**
+ * @brief Returns the current position.
+ *
+ * @return  the current source code position
+ */
+const ReSourcePosition* ReLexer::currentPosition() const
+{
+    return m_currentPosition;
+}
+
+/**
+ * @brief Returns the next token.
+ *
+ * @return the next token
+ */
+ReToken* ReLexer::nextToken()
+{
+    ReToken* rc = NULL;
+    int ix;
+    if (m_waitingToken != NULL){
+        rc = m_currentToken = m_waitingToken;
+        m_waitingToken = m_waitingToken2;
+        m_waitingToken2 = NULL;
+        m_currentPosition = m_waitingPosition1;
+        m_waitingPosition1 = m_waitingPosition2;
+        m_waitingPosition2 = NULL;
+    } else {
+        m_currentToken->clear();
+        ReReader* reader = m_source->currentReader();
+        if (reader == NULL)
+            m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE;
+        else {
+            m_waitingPosition2 = m_waitingPosition1;
+            m_waitingPosition1 = m_currentPosition;
+            m_currentPosition = m_source->newPosition(m_currentCol);
+            if (! fillInput()){
+                m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE;
+            } else {
+                int cc = m_input.at(0);
+                if (isspace(cc)){
+                    //waitingPosition = m_currentPosition;
+                    m_currentToken->m_tokenType = TOKEN_SPACE;
+                    ix = 1;
+                    while(ix < m_input.size() && isspace(m_input.at(ix)))
+                        ix++;
+                    if (m_storageFlags & STORE_BLANK){
+                        m_currentToken->m_string.append(m_input.mid(0, ix));
+                    }
+                    m_currentCol += ix;
+                    m_input.remove(0, ix);
+                    rc = m_currentToken;
+                } else if (isdigit(cc)){
+                    rc = scanNumber();
+                } else if ( (cc == '"' && (m_stringFeatures & SF_QUOTE) != 0)
+                           || (cc == '\'' && (m_stringFeatures & SF_TICK) != 0)){
+                    rc = scanString();
+                } else {
+                    if (cc >= CHAR_INFO_SIZE)
+                        throw ReLexException(*m_currentPosition,
+                            "no lexical symbol can start with this char: %lc",
+                            cc);
+                    else
+                    {
+                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_COMMENT_START)){
+                            rc = findTokenWithId(TOKEN_COMMENT_START,
+                                                 CC_2nd_COMMENT_START, m_commentStarts);
+                            if (rc != NULL)
+                                scanComment();
+                            //waitingPosition = m_currentPosition;
+                        }
+
+                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_OP)){
+                            if ( (m_charInfo[cc] & CC_OP_1_ONLY) == 0){
+                                rc = findTokenWithId(TOKEN_OPERATOR,
+                                                 CC_2nd_OP, m_operators);
+                            } else {
+                                rc = m_currentToken;
+                                rc->m_tokenType = TOKEN_OPERATOR;
+                                rc->m_value.m_id = findInVector(1, m_operators);
+                                m_input.remove(0, 1);
+                                m_currentCol += 1;
+                            }
+                        }
+                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_KEYWORD)){
+                            rc = findTokenWithId(TOKEN_KEYWORD,
+                                                 CC_2nd_KEYWORD, m_keywords);
+                        }
+                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_ID)){
+                            int length = 1;
+                            while(length < m_input.size()
+                                && (cc = m_input[length]) < CHAR_INFO_SIZE
+                                    && (m_charInfo[cc] & CC_REST_ID) != 0)
+                                  length++;
+                            rc = m_currentToken;
+                            rc->m_tokenType = TOKEN_ID;
+                                  rc->m_string.append(m_input.mid(0, length));
+                            m_input.remove(0, length);
+                            m_currentCol += length;
+                        }
+
+                    }
+                }
+            }
+        }
+    }
+    if (rc == NULL || rc->tokenType() == TOKEN_UNDEF){
+        if (m_input.size() == 0){
+            rc = m_currentToken;
+            rc->m_tokenType = TOKEN_END_OF_SOURCE;
+        } else {
+            QByteArray symbol = m_input.mid(0, qMin(20, m_input.size()-1));
+            throw ReLexException(*m_currentPosition,
+                "unknown lexical symbol: %s", symbol.constData());
+        }
+    }
+#if defined (RPL_LEXER_TRACE)
+    if (m_trace){
+        char buffer[256];
+        printf("token: %s pos: %s\n", m_currentToken->dump().constData(),
+               m_currentPosition->utf8(buffer, sizeof buffer));
+        if (strstr(buffer, "0:28") != NULL)
+            buffer[0] = 0;
+    }
+#endif
+    return rc;
+}
+/**
+ * @brief Reverses the last <code>nextToken()</code>.
+ *
+ * Makes that <code>nextToken()</code> returns the current token again.
+ */
+void ReLexer::undoLastToken()
+{
+    m_waitingToken = m_currentToken;
+    m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
+    m_waitingPosition1 = m_currentPosition;
+#if defined (RPL_LEXER_TRACE)
+    if (m_trace){
+        char buffer[256];
+        printf("undo last token: waiting-token:  %s pos: %s\n",
+               m_waitingToken->dump().constData(),
+               m_waitingPosition1->utf8(buffer, sizeof buffer));
+        if (strcmp(buffer, "<test>:2:6") == 0)
+            buffer[0] = 0;
+    }
+#endif
+}
+
+/**
+ * @brief Reverses the last <code>nextToken()</code>.
+ *
+ * Makes that <code>nextToken()</code> returns the current token again.
+ */
+void ReLexer::undoLastToken2()
+{
+    m_waitingToken2 = m_currentToken;
+    m_waitingToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
+    m_waitingPosition2 = m_waitingPosition1;
+    m_waitingPosition1 = m_currentPosition;
+}
+
+/**
+ * @brief Prevents the current token from data loss.
+ *
+ * Usage:
+ * <pre><code>
+ * token1 = nextToken();
+ * saveLastToken();
+ * token2 = nextToken();
+ * </code></pre>
+ * Then <code>token1</code> and <code>token2</code> contains the wanted content.
+ */
+void ReLexer::saveLastToken()
+{
+    if (m_waitingToken == NULL)
+        m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
+}
+
+/**
+ * @brief Returns the next relevant token, but the token remains "unread".
+ *
+ * @return the next token which is not a space/comment
+ */
+ReToken*ReLexer::peekNonSpaceToken()
+{
+    ReToken* token = nextNonSpaceToken();
+    undoLastToken();
+    return token;
+}
+/**
+ * @brief Returns the maximal length of a token
+ * @return  the maximal length of a token
+ */
+size_t ReLexer::maxTokenLength() const
+{
+    return m_maxTokenLength;
+}
+
+/**
+ * @brief Sets the maximal length of a token
+ *
+ * @param maxTokenLength    the new maximal length of a token
+ */
+void ReLexer::setMaxTokenLength(size_t maxTokenLength)
+{
+    m_maxTokenLength = maxTokenLength;
+}
+
+/**
+ * @brief ReLexer::nextNonSpaceToken
+ * @return
+ */
+ReToken* ReLexer::nextNonSpaceToken()
+{
+    ReToken* rc = NULL;
+    RplTokenType type;
+    do{
+        rc = nextToken();
+    } while( (type = m_currentToken->tokenType()) == TOKEN_SPACE
+             || type == TOKEN_COMMENT_START || type == TOKEN_COMMENT_END
+             || type == TOKEN_COMMENT_REST_OF_LINE);
+    return rc;
+}
+
+/**
+ * @brief Prepares a given source unit for reading.
+ *
+ * Saves the current source position onto the top of stack.
+ * Pushes the source unit onto the top of stack.
+ *
+ * Precondition: the unit must be known by exactly one reader
+ *
+ * @param unit  the new source unit
+ */
+void ReLexer::startUnit(ReSourceUnitName unit)
+{
+    m_source->startUnit(unit, *m_currentPosition);
+}
+/**
+ * @brief Returns the source of the instance.
+ *
+ * @return  the source of the instance
+ */
+ReSource* ReLexer::source()
+{
+    return m_source;
+}
+
+/**
+ * @brief Returns the priority of a given operator.
+ *
+ * @param op    the operator
+ * @return      the priority of the op
+ */
+int ReLexer::prioOfOp(int op) const
+{
+    int rc = op > 0 && (unsigned) op < sizeof m_prioOfOp / sizeof m_prioOfOp[0]
+            ? m_prioOfOp[op] : 0;
+    return rc;
+}
+
+/**
+ * @brief Returns the name of an operator.
+ *
+ * @param op    the operator id
+ * @return      the name of the operator
+ */
+const QByteArray&ReLexer::nameOfOp(int op) const
+{
+    const QByteArray& rc = m_opNames.at(op);
+    return rc;
+}
+
+/**
+ * @brief Returns whether an operator is right associative
+ * @param op    op to test
+ * @return      true: the operator is right associative<br>
+ *              false: otherwise
+ */
+bool ReLexer::isRightAssociative(int op) const
+{
+    bool rc = false;
+    if (op >= 0 && (unsigned) op < sizeof m_assocOfOp / sizeof m_assocOfOp[0]){
+        rc = m_assocOfOp[op];
+    }
+    return rc;
+}
+
+
diff --git a/expr/ReLexer.hpp b/expr/ReLexer.hpp
new file mode 100644 (file)
index 0000000..fea3b0d
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLLEXER_HPP
+#define RPLLEXER_HPP
+
+//#define RPL_LEXER_TRACE
+
+enum RplTokenType {
+    TOKEN_UNDEF,
+    TOKEN_STRING,
+    TOKEN_NUMBER,
+    TOKEN_REAL,
+    TOKEN_KEYWORD,
+    TOKEN_OPERATOR,
+    TOKEN_ID,
+    TOKEN_COMMENT_REST_OF_LINE,
+    TOKEN_COMMENT_START,
+    TOKEN_COMMENT_END,
+    TOKEN_SPACE,
+    TOKEN_END_OF_SOURCE,
+    TOKEN_COUNT
+};
+
+class ReLexException : public ReException {
+public:
+    ReLexException(const ReSourcePosition& position, const char* message, ...);
+};
+
+class ReLexer;
+
+class ReToken {
+public:
+    ReToken(RplTokenType type);
+    ~ReToken();
+    ReToken(const ReToken& source);
+    ReToken& operator =(const ReToken& source);
+public:
+    friend class ReLexer;
+    const QByteArray& toString();
+    bool isInteger();
+    int asInteger() const;
+    quint64 asUInt64() const;
+    qreal asReal() const;
+    const QByteArray& rawString() const;
+    int id() const;
+    RplTokenType tokenType() const;
+    bool isTokenType(RplTokenType expected) const;
+    bool isOperator(int expected, int alternative = 0) const;
+    bool isKeyword(int expected, int alternative = 0) const;
+    void clear();
+    bool isCapitalizedId() const;
+    QByteArray dump() const;
+    static const char* nameOfType(RplTokenType type);
+    QByteArray asUtf8() const;
+protected:
+    RplTokenType m_tokenType;
+    QByteArray m_string;
+    // only for TOKEN_STRING: copy from source but with escaped chars like "\\n"
+    QByteArray m_printableString;
+    union {
+        // only for TOKEN_KEYWORD and TOKEN_OPERATOR
+        int m_id;
+        quint64 m_integer;
+        qreal m_real;
+    } m_value;
+};
+
+
+class ReSource;
+class ReLexer
+{
+public:
+    typedef QList<QByteArray> StringList;
+    enum NumericType {
+        NUMTYPE_UNDEF,
+        NUMTYPE_DECIMAL     = 1 << 0,
+        NUMTYPE_OCTAL       = 1 << 1,
+        NUMTYPE_HEXADECIMAL = 1 << 2,
+        NUMTYPE_FLOAT       = 1 << 3,
+        ///
+        NUMTYPE_ALL_INTEGER = NUMTYPE_DECIMAL | NUMTYPE_OCTAL |NUMTYPE_HEXADECIMAL,
+        NUMTYPE_ALL         = NUMTYPE_ALL_INTEGER | NUMTYPE_FLOAT
+    };
+    enum CharClassTag {
+        CC_UNDEF                = 0,
+        /// this char is possible as first char of an id
+        CC_FIRST_ID             = 1 << 0,
+        /// this char is possible as 2nd char of an id
+        CC_2nd_ID               = 1 << 1,
+        /// this char is possible as 3rd char of an id
+        CC_3rd_ID               = 1 << 2,
+        /// this char is possible as 4th... char of an id
+        CC_REST_ID              = 1 << 3,
+        /// this char can start a comment
+        CC_FIRST_COMMENT_START  = 1 << 4,
+        /// this char can be the 2nd char of a comment start
+        CC_2nd_COMMENT_START    = 1 << 5,
+        /// this char can be the 3rd char of a comment start
+        CC_3rd_COMMENT_START    = 1 << 6,
+        /// this char can be the 4th ... of a comment start
+        CC_REST_COMMENT_START   = 1 << 7,
+        /// this char can start a keyword
+        CC_FIRST_KEYWORD        = 1 << 8,
+        /// this char can be the 2nd char of a keyword
+        CC_2nd_KEYWORD          = 1 << 9,
+        /// this char can be the 3rd char of a keyword
+        CC_3rd_KEYWORD          = 1 << 10,
+        /// this char can be the 4th... char of a keyword
+        CC_REST_KEYWORD         = 1 << 11,
+        /// this char can be the 1st char of an operator
+        CC_FIRST_OP             = 1 << 12,
+        /// this char can be the 2nd char of an operator
+        CC_2nd_OP               = 1 << 13,
+        /// this char can be the 3rd char of an operator
+        CC_3rd_OP               = 1 << 14,
+        /// this char can be the 4th... char of an operator
+        CC_REST_OP              = 1 << 15,
+        /// there is an operator with exactly this char
+        /// and there is no other operator starting with this char
+        CC_OP_1_ONLY            = 1 << 16
+    };
+    enum StringFeatures {
+        SF_UNDEF,
+        /// ' can be a string delimiter
+        SF_TICK         = 1 << 1,
+        /// " can be a string delimiter
+        SF_QUOTE        = 1 << 2,
+        /// character escaping like in C: "\x" is "x"
+        SF_C_ESCAPING   = 1 << 3,
+        /// special characters like in C: "\r" "\f" "\n" "\t" "\a"
+        SF_C_SPECIAL    = 1 << 4,
+        /// characters can be written in hexadecimal notation: "\x20" is " "
+        SF_C_HEX_CHARS  = 1 << 5,
+        /// A delimiter inside a string must be doubled (like in Pascal)
+        SF_DOUBLE_DELIM = 1 << 6,
+        // Redefinitions for better reading:
+        SF_LIKE_C       = SF_TICK | SF_QUOTE | SF_C_ESCAPING | SF_C_SPECIAL
+                            | SF_C_HEX_CHARS
+    };
+    enum StorageFlags {
+        S_UNDEF,
+        /// the original string will be stored in m_string too
+        /// (not only m_rawString)
+        STORE_ORG_STRING    = 1 << 1,
+        /// comments will be stored in m_string
+        STORE_COMMENT       = 1 << 2,
+        /// blanks will be stored in m_string
+        STORE_BLANK         = 1 << 3,
+        /// redefinitions for better reading:
+        STORE_NOTHING       = 0,
+        STORE_ALL           = STORE_ORG_STRING | STORE_COMMENT | STORE_BLANK
+    };
+
+public:
+    ReLexer(ReSource* source,
+        const char* keywords,
+        const char* operators,
+        const char* rightAssociatives,
+        const char* comments,
+        const char* firstCharsId = "a-zA-Z_",
+        const char* restCharsId = "a-zA-Z0-9_",
+        int numericTypes = NUMTYPE_DECIMAL | NUMTYPE_HEXADECIMAL | NUMTYPE_FLOAT,
+        int stringFeatures = SF_TICK | SF_QUOTE | SF_C_ESCAPING | SF_C_SPECIAL
+            | SF_C_HEX_CHARS,
+        int storageFlags = STORE_NOTHING);
+    virtual ~ReLexer();
+public:
+    ReToken* nextToken();
+    void undoLastToken();
+    void undoLastToken2();
+    void saveLastToken();
+    ReToken* peekNonSpaceToken();
+    ReToken* nextNonSpaceToken();
+    size_t maxTokenLength() const;
+    void setMaxTokenLength(size_t maxTokenLength);
+    void startUnit(ReSourceUnitName unit);
+    ReSource* source();
+    int prioOfOp(int op) const;
+    const QByteArray& nameOfOp(int op) const;
+    bool isRightAssociative(int op) const;
+    const ReSourcePosition* currentPosition() const;
+    ReToken* currentToken() const;
+#if defined RPL_LEXER_TRACE
+    bool trace() const;
+    void setTrace(bool trace);
+#endif
+private:
+    void prepareOperators(const char* operators, const char* rightAssociatives);
+    void initializeComments(const char* comments);
+    bool fillInput();
+    int findInVector(int tokenLength, const StringList& vector);
+    ReToken* findTokenWithId(RplTokenType tokenType, int flag2,
+                              StringList& names);
+    ReToken* scanNumber();
+    ReToken* scanString();
+    void scanComment();
+protected:
+    ReSource* m_source;
+    /// sorted, string ends with the id of the keyword
+    StringList m_keywords;
+    // sorted, string ends with the id of the operator
+    StringList m_operators;
+    // sorted, each entry ends with the id of the comment start
+    StringList m_commentStarts;
+    // index: id content: comment_end
+    StringList m_commentEnds;
+    // index: ord(char) content: a sum of CharClassTags
+    int m_charInfo[128];
+    // a list of QChars with ord(cc) > 127 and which can be the first char
+    QByteArray m_idFirstRare;
+    // index: ord(char) content: chr(ix) can be the non first char of an id
+    QByteArray m_idRestRare;
+    // a list of QChars with ord(cc) > 127 and which can be the first char
+    int m_numericTypes;
+    QByteArray m_idRest2;
+    ReToken* m_currentToken;
+    ReToken* m_waitingToken;
+    ReToken* m_waitingToken2;
+    ReToken m_token1;
+    ReToken m_token2;
+    const ReSourcePosition* m_currentPosition;
+    const ReSourcePosition* m_waitingPosition1;
+    const ReSourcePosition* m_waitingPosition2;
+    int m_maxTokenLength;
+    QByteArray m_input;
+    int m_currentCol;
+    bool m_hasMoreInput;
+    int m_stringFeatures;
+    int m_storageFlags;
+    /// priority of the operators: index: id of the operator. content: prio
+    char m_prioOfOp[128];
+    char m_assocOfOp[128];
+    QList<QByteArray> m_opNames;
+#if defined (RPL_LEXER_TRACE)
+    bool m_trace;
+#endif
+};
+
+
+#endif // RPLLEXER_HPP
diff --git a/expr/ReMFParser.cpp b/expr/ReMFParser.cpp
new file mode 100644 (file)
index 0000000..38475da
--- /dev/null
@@ -0,0 +1,1286 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief A parser for the language <b>ML</b>.
+ */
+/** @file
+ * @brief Definition for a parser for the language <b>ML</b>.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+enum MFLocations{
+    L_PARSE_OPERAND_RPARENTH = 2001,
+    L_PARSE_OPERAND_RPARENTH_INFO,
+    L_TERM_WRONG_STRING,
+    L_TERM_WRONG_NUMBER,
+    L_PARSE_OPERAND_WRONG   = 2005,
+    L_DEFINITION_NO_ID,
+    L_DEFINITION_WRONG_ID,
+    L_DEFINITION_UNKNOWN_CLASS,
+    L_DEFINITION_MISSING_ID,
+    L_DEFINITION_NO_OP      = 2010,
+    L_DEFINITION_NO_SEMICOLON,
+    L_PARSE_IF_NO_THEN,
+    L_PARSE_IF_NO_ELSE,
+    L_PARSE_IF_NO_FI,
+    L_PARSE_WHILE_NO_DO     = 2015,
+    L_PARSE_WHILE_NO_OD,
+    L_PARSE_REPEAT_NO_UNTIL,
+    L_PARSE_REPEAT_NO_SEMI,
+    L_PARSE_BODY_WRONG_ITEM,
+    L_PARSE_FOR_NO_TO       = 2020,
+    L_PARSE_LIST_NO_COMMA,
+    L_PARSE_MAP_BOOL,
+    L_PARSE_MAP_NONE,
+    L_PARSE_MAP_NUMERIC,
+    L_PARSE_MAP_EXPR        = 2025,
+    L_PARSE_MAP_EXPR2,
+    L_PARSE_MAP_NO_COLON,
+    L_PARSE_MAP_NO_COMMA,
+    L_PARSE_OPERAND_NOT_OPERAND = 2030,
+    L_PARSE_BODY_NO_START,
+    L_PARSE_OPERAND_NO_BRACKET,
+    L_PARSE_ARGS_NO_COMMA_OR_PARENT,
+    L_PARSE_OPERAND_NO_FIELD2,
+    L_PARSE_OPERAND_NO_BRACKET2 = 2035,
+    L_PARSE_OPERAND_NO_FIELD,
+    L_PARSE_METH_NO_CLASS,
+    L_PARSE_METH_NO_CLASS2,
+    L_PARSE_METH_NO_NAME,
+    L_PARSE_METH_NO_NAME2   = 2040,
+    L_PARSE_METH_NO_LPARENTH,
+    L_PARSE_METH_NO_COLON,
+    L_PARSE_PARAMLIST_NO_PARENTH,
+    L_PARSE_PARAMLIST_NO_PARENTH2,
+    L_PARSE_METH_NO_END     = 2045,
+    L_PARSE_METH_NO_END2,
+    L_PARSE_VAR_DEF_ALREADY_DEFINED,
+    L_PARSE_VAR_DEF_ALREADY_DEFINED2,
+    L_PARSE_CLASS_NO_NAME,
+    L_PARSE_CLASS_LOWERCASE = 2050,
+    L_PARSE_CLASS_ALREADY_DEFINED,
+    L_PARSE_CLASS_ALREADY_DEFINED2
+
+};
+
+/** @class ReMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
+ *
+ * @brief Implements a parser for the language MF.
+ *
+ * MF stands for Mathe Fan or Multiple Faces or ....
+ * This is an universal object oriented programming language with extension
+ * for matrix operations, simulation and graphics.
+ */
+
+ReMFParser::ReMFParser(ReSource& source, ReASTree& abstractSyntaxTree) :
+    ReParser(m_lexer, abstractSyntaxTree),
+    m_lexer(&source,
+            MF_KEYWORDS, MF_OPERATORS, MF_RIGHT_ASSOCIATIVES,
+            "/* */ // \n",
+            "a-zA-Z_", "a-zA-Z0-9_",
+            ReLexer::NUMTYPE_ALL, ReLexer::SF_LIKE_C)
+{
+}
+
+/**
+ * @brief Parses an if statement.
+ */
+ReASItem* ReMFParser::parseIf()
+{
+    ReASIf* rc = new ReASIf();
+    rc->setPosition(m_lexer.currentPosition());
+
+    ReASItem* condition = parseExpr(0);
+    if (! m_lexer.currentToken()->isKeyword(K_THEN))
+        syntaxError(L_PARSE_IF_NO_THEN, "'then' expected");
+    rc->setChild2(condition);
+    ReASItem* body = parseBody(K_ELSE, K_FI);
+    rc->setChild3(body);
+    if (! m_lexer.currentToken()->isKeyword(K_ELSE, K_FI))
+        syntaxError(L_PARSE_IF_NO_ELSE, "'else' or 'fi' expected");
+    if ( m_lexer.currentToken()->isKeyword(K_ELSE)){
+        ReASItem* body = parseBody(K_FI);
+        rc->setChild4(body);
+    }
+    if (! m_lexer.currentToken()->isKeyword(K_FI))
+        syntaxError(L_PARSE_IF_NO_FI, "'fi' expected");
+    m_lexer.nextNonSpaceToken();
+    return rc;
+}
+/**
+ * @brief Parses a while statement.
+ */
+
+ReASItem* ReMFParser::parseWhile()
+{
+    ReASWhile* rc = new ReASWhile();
+    rc->setPosition(m_lexer.currentPosition());
+
+    ReASItem* condition = parseExpr(0);
+    if (! m_lexer.currentToken()->isKeyword(K_DO))
+        syntaxError(L_PARSE_WHILE_NO_DO, "'do' expected");
+    rc->setChild2(condition);
+    ReASItem* body = parseBody(K_OD);
+    rc->setChild3(body);
+    if (! m_lexer.currentToken()->isKeyword(K_OD))
+        syntaxError(L_PARSE_WHILE_NO_OD, "'od'  expected");
+    m_lexer.nextNonSpaceToken();
+    return rc;
+}
+
+/**
+ * @brief Parses a repeat statement.
+ */
+ReASItem* ReMFParser::parseRepeat()
+{
+    ReASRepeat* rc = new ReASRepeat();
+    rc->setPosition(m_lexer.currentPosition());
+
+    ReASItem* body = parseBody(K_UNTIL);
+    rc->setChild3(body);
+    if (! m_lexer.currentToken()->isKeyword(K_UNTIL))
+        syntaxError(L_PARSE_REPEAT_NO_UNTIL, "'until'  expected");
+
+    ReASItem* condition = parseExpr(0);
+    if (! m_lexer.currentToken()->isOperator(O_SEMICOLON))
+        syntaxError(L_PARSE_REPEAT_NO_SEMI, "';' expected");
+    rc->setChild2(condition);
+    m_lexer.nextNonSpaceToken();
+    return rc;
+}
+
+/**
+ * @brief Creates a variable definition for a builtin variable.
+ * @param var   the basic variable data
+ * @return
+ */
+ReASVarDefinition* ReMFParser::buildVarDef(ReASNamedValue* var)
+{
+    ReASVarDefinition* rc = new ReASVarDefinition();
+    rc->setPosition(var->position());
+    rc->setChild2(var);
+    ReSymbolSpace* symbols = m_tree.currentSpace();
+    int varNo;
+    symbols->addVariable(rc, varNo);
+    var->setVariableNo(varNo);
+    return rc;
+}
+
+/**
+ * @brief Parses a for statement.
+ *
+ * Syntax:
+ * for [ VAR ] [ from START_EXPR ] to END_EXPR [ step STEP_EXPR ] do
+ * BODY od
+ *
+ * for VAR in ITERABLE_EXPR do BODY od
+ *
+ * @post            the token behind the do is read
+ * @return          the abstract syntax tree of the for statement
+ */
+ReASItem* ReMFParser::parseFor()
+{
+    int builtinVars = 1;
+    ReASNode2* rc = NULL;
+    const ReSourcePosition* startPosition = m_lexer.currentPosition();
+    ReToken* token = m_lexer.nextNonSpaceToken();
+    ReASNamedValue* var = NULL;
+    if (token->isTokenType(TOKEN_ID)){
+        var = new ReASNamedValue(ReASInteger::m_instance,
+                                  m_tree.currentSpace(), token->toString(),
+                                  ReASNamedValue::A_LOOP);
+        var->setPosition(m_lexer.currentPosition());
+        token = m_lexer.nextNonSpaceToken();
+    }
+    if (token->isKeyword(K_IN)){
+        ReASVarDefinition* varDef = buildVarDef(var);
+        ReASForIterated* node = new ReASForIterated(varDef);
+        rc = node;
+        node->setPosition(startPosition);
+        node->setChild3(var);
+        ReASItem* iterable = parseExpr(0);
+        node->setChild4(iterable);
+    } else {
+        if (var == NULL){
+            char name[32];
+            // Build a unique name inside the scope:
+            qsnprintf(name, sizeof name, "$%d_%d", startPosition->lineNo(),
+                      startPosition->column());
+            var = new ReASNamedValue(ReASInteger::m_instance,
+                                      m_tree.currentSpace(), name,
+                                      ReASNamedValue::A_LOOP);
+            var->setPosition(startPosition);
+        }
+        ReASVarDefinition* varDef = buildVarDef(var);
+        ReASForCounted* node = new ReASForCounted(varDef);
+        rc = node;
+        node->setPosition(startPosition);
+        node->setChild3(var);
+        if (token->isKeyword(K_FROM)){
+            node->setChild4(parseExpr(0));
+        }
+        if (! m_lexer.currentToken()->isKeyword(K_TO)){
+            syntaxError(L_PARSE_FOR_NO_TO, "'to' expected");
+        }
+        node->setChild5(parseExpr(0));
+        if (m_lexer.currentToken()->isKeyword(K_STEP)){
+            node->setChild6(parseExpr(0));
+        }
+    }
+    if (! m_lexer.currentToken()->isKeyword(K_DO))
+        syntaxError(L_PARSE_FOR_NO_TO, "'to' expected");
+    rc->setChild2(parseBody(K_OD, K_UNDEF, builtinVars));
+    m_lexer.nextNonSpaceToken();
+    return rc;
+}
+
+/**
+ * @brief Parses a variable definition.
+ *
+ * Syntax:
+ * Variable: { "const" | "lazy" }* TYPE id [ = EXPR ] [ ";" ]
+ * Parameter: { "const" | "lazy" }* TYPE id [ = EXPR ] { "," | ")" }
+ *
+ * @pre             first token of the definition is read
+ * @post            token behind the definition is read: ';', ',', ')'
+ * @param attribute attribute of the variable: A_PARAM...
+ * @return          a variable/parameter definition
+ */
+ReASVarDefinition* ReMFParser::parseVarDefinition(
+        ReASNamedValue::Attributes attribute)
+{
+    int attributes = attribute;
+    ReToken* token = m_lexer.currentToken();
+    while(token->isKeyword(K_CONST, K_LAZY)){
+        switch(token->id()){
+        case K_CONST:
+            attributes += ReASNamedValue::A_CONST;
+            break;
+        case K_LAZY:
+            attributes += ReASNamedValue::A_LAZY;
+            break;
+        default:
+            break;
+        }
+        token = m_lexer.nextNonSpaceToken();
+    }
+    if (! token->isTokenType(TOKEN_ID))
+        syntaxError(L_DEFINITION_NO_ID, "class name expected, but no id found");
+    if (! token->isCapitalizedId())
+        syntaxError(L_DEFINITION_WRONG_ID,
+                    "a class name must start with an upper case character");
+    ReASClass* clazz = m_tree.currentSpace()->findClass(token->toString());
+    if (clazz == NULL)
+        syntaxError(L_DEFINITION_UNKNOWN_CLASS, "unknown class");
+    token = m_lexer.nextNonSpaceToken();
+    if (! token->isTokenType(TOKEN_ID))
+        syntaxError(L_DEFINITION_MISSING_ID, "variable name expected");
+    ReSymbolSpace* symbols = m_tree.currentSpace();
+    // freed in the destructor of the nodes:
+    ReASNamedValue* namedValue = new ReASNamedValue(clazz, symbols,
+                                                      token->toString(),
+                                                      attributes);
+    namedValue->setPosition(m_lexer.currentPosition());
+    ReASVarDefinition* rc = new ReASVarDefinition();
+    rc->setPosition(m_lexer.currentPosition());
+    rc->setChild2(namedValue);
+    token = m_lexer.nextNonSpaceToken();
+    if (token->id() == O_ASSIGN){
+        ReASItem* value = parseExpr(0);
+        rc->setChild3(value);
+        token = m_lexer.currentToken();
+    }
+    int varNo = 0;
+    ReASItem* oldSymbol = symbols->addVariable(rc, varNo);
+    if (oldSymbol != NULL)
+        error(L_PARSE_VAR_DEF_ALREADY_DEFINED, oldSymbol->position(),
+              "symbol already defined", "previous definition");
+    namedValue->setVariableNo(varNo);
+    return rc;
+}
+
+/**
+ * @brief Reads the current tokens as an formula and returns the variant.
+ *
+ * @post            the token behind the formula is read
+ * @param parent    the parent for the formula: because of the destroying
+ *                  the new expression is chained into the parent
+ * @return          the variant containing the formula
+ */
+ReASVariant* ReMFParser::createFormula(ReASNode1* parent)
+{
+    ReASVariant* variant = NULL;
+    m_lexer.undoLastToken2();
+    ReASExprStatement* expr = dynamic_cast<ReASExprStatement*>
+            (parseExprStatement(false));
+    if (expr != NULL){
+        // chaining per m_child (= next statement) is for freeing while destruction:
+        expr->setChild(parent->child());
+        parent->setChild(expr);
+        // freed in the destructor of varList (~ReASVariant()):
+        variant = new ReASVariant();
+        variant->setObject(expr, ReASFormula::m_instance);
+    }
+    return variant;
+}
+
+/**
+ * @brief Converts the current expression into a <code>ReASVariant</code>.
+ *
+ * If the expression is a constant, the constant value will be the content
+ * of the variant. Otherwise a formula will be stored.
+ *
+ * @pre                 the first token of the variant expression is read
+ * @post                the token behind the variant expression is read
+ * @param token         the token to convert
+ * @param endsWithComma true: the 2nd token is a ','
+ * @param parent        the parent node of the expression
+ * @return              the variant with the token's content
+ */
+ReASVariant* ReMFParser::tokenToVariant(ReToken* token,
+        bool endsWithComma, ReASNode1* parent)
+{
+    ReASVariant* variant = NULL;
+    if (endsWithComma){
+        switch(token->tokenType()){
+        case TOKEN_NUMBER:
+            // freed in the destructor of varList (~ReASVariant()):
+            variant = new ReASVariant();
+            variant->setInt(token->asInteger());
+            break;
+        case TOKEN_STRING:
+            // freed in the destructor of varList (~ReASVariant()):
+            variant = new ReASVariant();
+            variant->setString(token->toString());
+            break;
+        case TOKEN_REAL:
+            // freed in the destructor of varList (~ReASVariant()):
+            variant = new ReASVariant();
+            variant->setFloat(token->asReal());
+            break;
+        case TOKEN_KEYWORD:
+            switch(token->id()){
+            case K_TRUE:
+            case K_FALSE:
+                // freed in the destructor of varList (~ReASVariant()):
+                variant = new ReASVariant();
+                variant->setBool(token->id() == K_TRUE);
+                break;
+            case K_NONE:
+                // freed in the destructor of varList (~ReASVariant()):
+                variant = new ReASVariant();
+                break;
+            default:
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    if (variant == NULL)
+        variant = createFormula(parent);
+    return variant;
+}
+
+/**
+ * @brief Parses a list.
+ *
+ * Syntax:<br>
+ * '[' [ EXPR_1 [ ',' EXPR_2 ...]] ']'
+ *
+ * @pre    '[' is the current token
+ * @post   the token behind the ']' is read
+ * @return a node of the abstract syntax tree
+ */
+ReASItem* ReMFParser::parseList()
+{
+    ReASListConstant* rc = new ReASListConstant();
+    ReASVariant& varList = rc->value();
+    ReASListOfVariants* list = static_cast<ReASListOfVariants*>
+            (varList.asObject(NULL));
+    rc->setPosition(m_lexer.currentPosition());
+    ReASVariant* variant;
+    bool again = true;
+    ReToken* token;
+    ReToken* token2;
+    // read the token behind '[':
+    token = m_lexer.nextNonSpaceToken();
+    if (token->isOperator(O_RBRACKET)){
+        // read token behind ']':
+        m_lexer.nextNonSpaceToken();
+    } else{
+        while(again){
+            m_lexer.saveLastToken();
+            token2 = m_lexer.nextNonSpaceToken();
+            variant = tokenToVariant(token, token2->isOperator(O_COMMA), rc);
+            token = m_lexer.currentToken();
+            if (token->isOperator(O_RBRACKET))
+                again = false;
+            else if (! token->isOperator(O_COMMA))
+                syntaxError(L_PARSE_LIST_NO_COMMA, "',' or ']' expected");
+            // read token behind ',' or ']'
+            token = m_lexer.nextNonSpaceToken();
+            if (variant != NULL)
+                list->append(variant);
+        }
+    }
+    return rc;
+}
+
+
+/**
+ * @brief Parses a map.
+ *
+ * Syntax:<br>
+ * '{' [ STRING_EXPR_1 ':' EXPR_1 [ ',' STRING_EXPR_2 ': EXPR_2 ...]] '}'
+ *
+ * @pre    '{' is the current token
+ * @post   the token behind the '}' is read
+ * @return a node of the abstract syntax tree
+ */
+ReASItem* ReMFParser::parseMap()
+{
+    ReASMapConstant* rc = new ReASMapConstant();
+    ReASVariant& varMap = rc->value();
+    ReASMapOfVariants* map = static_cast<ReASMapOfVariants*>
+            (varMap.asObject(NULL));
+    rc->setPosition(m_lexer.currentPosition());
+    ReASVariant* variant;
+    bool again = true;
+    ReToken* token;
+    ReToken* token2;
+    QByteArray key;
+    while(again){
+        token = m_lexer.nextNonSpaceToken();
+        if (token->isOperator(O_RBRACE))
+            again = false;
+        else{
+            key.clear();
+            switch(token->tokenType()){
+            case TOKEN_STRING:
+                // freed in the destructor of varList (~ReASVariant()):
+                key = token->toString();
+                break;
+            case TOKEN_KEYWORD:
+                switch(token->id()){
+                case K_TRUE:
+                case K_FALSE:
+                    syntaxError(L_PARSE_MAP_BOOL,
+                        "boolean value not allowed as key type. Use a string");
+                    break;
+                case K_NONE:
+                    syntaxError(L_PARSE_MAP_NONE,
+                        "'none' is  not allowed as key type. Use a string");
+                    break;
+                default:
+                    syntaxError(L_PARSE_MAP_EXPR,
+                        "a non constant expression is  not allowed as key type. Use a string");
+                    break;
+                }
+                break;
+            case TOKEN_NUMBER:
+            case TOKEN_REAL:
+                syntaxError(L_PARSE_MAP_NUMERIC,
+                    "numeric values not allowed as key type. Use a string");
+                break;
+            default:
+                syntaxError(L_PARSE_MAP_EXPR2,
+                    "a non constant expression is  not allowed as key type. Use a string");
+                break;
+            }
+            token = m_lexer.nextNonSpaceToken();
+            if (! token->isOperator(O_COLON)){
+                syntaxError(L_PARSE_MAP_NO_COLON, "':' expected");
+            } else {
+                token = m_lexer.nextNonSpaceToken();
+                m_lexer.saveLastToken();
+                token2 = m_lexer.nextNonSpaceToken();
+                variant = tokenToVariant(token, token2->isOperator(O_COMMA), rc);
+                (*map)[key] = variant;
+                variant = NULL;
+                token = m_lexer.currentToken();
+                if (token->isOperator(O_RBRACE))
+                    again = false;
+                else if (! token->isOperator(O_COMMA))
+                    syntaxError(L_PARSE_MAP_NO_COMMA, "',' or '}' expected");
+            }
+        }
+    }
+    m_lexer.nextNonSpaceToken();
+    return rc;
+}
+
+/**
+ * @brief Builds a node of a variable or a field (as an operand).
+ *
+ * @param name      name of the variable/field
+ * @param position  source position
+ * @param parent    NULL: result is a variable
+ *
+ * @return          a <code>ReASNamedValue</code> or a
+ *                  <code>ReASNamedValue</code> instance
+ */
+ReASItem* ReMFParser::buildVarOrField(const QByteArray& name,
+    const ReSourcePosition* position, ReASItem* parent)
+{
+    ReASItem* rc = NULL;
+    if (parent == NULL){
+        ReSymbolSpace* space = m_tree.currentSpace();
+        ReASVarDefinition* var = space->findVariable(name);
+        ReASClass* clazz = NULL;
+        if (var != NULL)
+            clazz = var->clazz();
+        ReASNamedValue* var2 = new ReASNamedValue(clazz, space,
+                                                   name, ReASNamedValue::A_NONE);
+        var2->setPosition(position);
+        rc = var2;
+    } else {
+        ReASField* field = new ReASField(name);
+        field->setPosition(position);
+        rc = field;
+        field->setChild(parent);
+    }
+    return rc;
+}
+/**
+ * @brief Converts a MF specific unary operator into one of AST.
+ *
+ * @param op    operator known by MF parser
+ *
+ * @return      operator known by the abstract syntax tree
+ */
+ReASUnaryOp::UnaryOp ReMFParser::convertUnaryOp(int op)
+{
+    ReASUnaryOp::UnaryOp rc;
+    switch(op){
+    case O_PLUS:
+        rc = ReASUnaryOp::UOP_PLUS;
+        break;
+    case O_MINUS:
+        rc = ReASUnaryOp::UOP_MINUS_INT;
+        break;
+    case O_NOT:
+        rc = ReASUnaryOp::UOP_NOT_BOOL;
+        break;
+    case O_BIT_NOT:
+        rc = ReASUnaryOp::UOP_NOT_INT;
+        break;
+    case O_INC:
+        rc = ReASUnaryOp::UOP_INC;
+        break;
+    case O_DEC:
+        rc = ReASUnaryOp::UOP_DEC;
+        break;
+    default:
+        throw ReException("unknown unary operator %d", op);
+        break;
+    }
+    return rc;
+}
+
+/**
+ * @brief Parses an operand.
+ *
+ * An operand is the first and the third part of a binary operation.
+ * Examples: constant, variable, method call, an expression in parentheses
+ *
+ * @post    the token behind the operand is read
+ * @return  the node with the operand
+ */
+ReASItem* ReMFParser::parseOperand(int level, ReASItem* parent)
+{
+    ReToken* token = m_lexer.nextNonSpaceToken();
+    const ReSourcePosition* startPosition = m_lexer.currentPosition();
+    ReASItem* rc = NULL;
+    bool readNext = true;
+    switch(token->tokenType()){
+    case TOKEN_OPERATOR:
+    {
+        Operator opId = (Operator) token->id();
+        if (parent != NULL && opId != O_LBRACKET)
+            syntaxError(L_PARSE_OPERAND_NO_FIELD,
+                    "field expected (behind a '.')");
+        if (opId == O_LBRACKET){
+            if (parent == NULL){
+                rc = parseList();
+                readNext = false;
+            } else {
+                ReASIndexedValue* value = new ReASIndexedValue();
+                value->setPosition(startPosition);
+                value->setChild(parent);
+                rc = value;
+                value->setChild2(parseExpr(level + 1));
+                if (! m_lexer.currentToken()->isOperator(O_RBRACKET))
+                    syntaxError(L_PARSE_OPERAND_NO_BRACKET2,
+                                "']' expected");
+            }
+        } else if (opId == O_LBRACE){
+            rc = parseMap();
+            readNext = false;
+        } else if (opId == O_LPARENTH){
+            rc = parseExpr(level + 1);
+            token = m_lexer.currentToken();
+            if(! token->isOperator(O_RPARENTH)){
+                // this call never comes back (exception!)
+                syntaxError(L_PARSE_OPERAND_RPARENTH,
+                            "')' expected", "(", startPosition);
+            }
+        } else if (IS_UNARY_OP(opId)){
+            ReASUnaryOp* op = new ReASUnaryOp(convertUnaryOp(token->id()),
+                                                AST_PRE_UNARY_OP);
+            op->setPosition(m_lexer.currentPosition());
+            op->setChild(parseOperand(level));
+            readNext = false;
+            rc = op;
+        } else
+            syntaxError(L_PARSE_OPERAND_NOT_OPERAND,
+                        "operand expected, not an operator");
+        break;
+    }
+    case TOKEN_STRING:
+    case TOKEN_NUMBER:
+    case TOKEN_REAL:
+    {
+        if (parent != NULL)
+            syntaxError(L_PARSE_OPERAND_NO_FIELD2,
+                    "field expected (behind a '.')");
+        ReASConstant* constant = new ReASConstant();
+        constant->setPosition(m_lexer.currentPosition());
+        rc = constant;
+        switch(token->tokenType()){
+        case TOKEN_STRING:
+            constant->value().setString(token->toString());
+            break;
+        case TOKEN_NUMBER:
+            constant->value().setInt(token->asInteger());
+            break;
+        case TOKEN_REAL:
+            constant->value().setFloat(token->asReal());
+            break;
+        default:
+            break;
+        }
+        break;
+    }
+    case TOKEN_ID:
+    {
+        QByteArray name = token->toString();
+        if (name == "a")
+            name = "a";
+        token = m_lexer.nextNonSpaceToken();
+        startPosition = m_lexer.currentPosition();
+        if (token->tokenType() != TOKEN_OPERATOR){
+            rc = buildVarOrField(name, startPosition, parent);
+            readNext = false;
+        } else {
+            if (token->id() == O_LPARENTH){
+                ReASMethodCall* call = new ReASMethodCall(name, parent);
+                call->setPosition(startPosition);
+
+                rc = call;
+                token = m_lexer.nextNonSpaceToken();
+                if (! token->isOperator(O_RPARENTH)){
+                    m_lexer.undoLastToken();
+                    ReASExprStatement* args = parseArguments();
+                    call->setChild2(args);
+                    readNext = false;
+                }
+            } else {
+                rc = buildVarOrField(name, startPosition, parent);
+                if (token->id() == O_LBRACKET){
+                    ReASItem* indexExpr = parseExpr(0);
+                    if (! m_lexer.currentToken()->isOperator(O_RBRACKET))
+                        syntaxError(L_PARSE_OPERAND_NO_BRACKET, "']' expected");
+                    dynamic_cast<ReASNode1*>(rc)->setChild(indexExpr);
+                } else {
+                    if (token->id() == O_INC || token->id() == O_DEC){
+                        ReASUnaryOp* op = new ReASUnaryOp(convertUnaryOp(
+                                                                token->id()),
+                                                            AST_POST_UNARY_OP);
+                        op->setChild(rc);
+                        rc = op;
+                    } else {
+                        readNext = false;
+                    }
+                }
+            }
+        }
+        break;
+    }
+    case TOKEN_END_OF_SOURCE:
+        readNext = false;
+        break;
+    default:
+        // this call never comes back (exception!)
+        syntaxError(L_PARSE_OPERAND_WRONG,
+                    "unexpected symbol detected. Operand expected");
+        break;
+    }
+    if (readNext)
+        m_lexer.nextNonSpaceToken();
+    if (m_lexer.currentToken()->isOperator(O_DOT, O_LBRACKET)){
+        if (m_lexer.currentToken()->asInteger() == O_LBRACKET)
+            m_lexer.undoLastToken();
+        rc = parseOperand(level, rc);
+    }
+    return rc;
+}
+/**
+ * @brief Converts a MF specific binary operator into one of AST.
+ *
+ * @param op    operator known by MF parser
+ *
+ * @return      operator known by the abstract syntax tree
+ */
+ReASBinaryOp::BinOperator ReMFParser::convertBinaryOp(int op){
+    ReASBinaryOp::BinOperator rc;
+    switch(op){
+    case ReMFParser::O_ASSIGN:
+        rc = ReASBinaryOp::BOP_ASSIGN;
+        break;
+    case ReMFParser::O_PLUS_ASSIGN:
+        rc = ReASBinaryOp::BOP_PLUS_ASSIGN;
+        break;
+    case ReMFParser::O_MINUS_ASSIGN:
+        rc = ReASBinaryOp::BOP_MINUS_ASSIGN;
+        break;
+    case ReMFParser::O_DIV_ASSIGN:
+        rc = ReASBinaryOp::BOP_DIV_ASSIGN;
+        break;
+    case ReMFParser::O_TIMES_ASSIGN:
+        rc = ReASBinaryOp::BOP_TIMES_ASSIGN;
+        break;
+    case ReMFParser::O_MOD_ASSIGN:
+        rc = ReASBinaryOp::BOP_MOD_ASSIGN;
+        break;
+    case ReMFParser::O_POWER_ASSIGN:
+        rc = ReASBinaryOp::BOP_POWER_ASSIGN;
+        break;
+    case ReMFParser::O_OR_ASSIGN:
+        rc = ReASBinaryOp::BOP_LOG_OR_ASSIGN;
+        break;
+    case ReMFParser::O_AND_ASSIGN:
+        rc = ReASBinaryOp::BOP_LOG_AND_ASSIGN;
+        break;
+    case ReMFParser::O_LSHIFT_ASSIGN:
+        rc = ReASBinaryOp::BOP_LSHIFT_ASSIGN;
+        break;
+    case ReMFParser::O_RSHIFT_ASSIGN:
+        rc = ReASBinaryOp::BOP_LOG_RSHIFT_ASSIGN;
+        break;
+    case ReMFParser::O_RSHIFT2_ASSIGN:
+        rc = ReASBinaryOp::BOP_ARTITH_RSHIFT_ASSIGN;
+        break;
+    case ReMFParser::O_OR:
+        rc = ReASBinaryOp::BOP_LOG_OR;
+        break;
+    case ReMFParser::O_AND:
+        rc = ReASBinaryOp::BOP_LOG_AND;
+        break;
+    case ReMFParser::O_EQ:
+        rc = ReASBinaryOp::BOP_EQ;
+        break;
+    case ReMFParser::O_NE:
+        rc = ReASBinaryOp::BOP_NE;
+        break;
+    case ReMFParser::O_LT:
+        rc = ReASBinaryOp::BOP_LT;
+        break;
+    case ReMFParser::O_GT:
+        rc = ReASBinaryOp::BOP_GT;
+        break;
+    case ReMFParser::O_LE:
+        rc = ReASBinaryOp::BOP_LE;
+        break;
+    case ReMFParser::O_GE:
+        rc = ReASBinaryOp::BOP_GE;
+        break;
+    case ReMFParser::O_PLUS:
+        rc = ReASBinaryOp::BOP_PLUS;
+        break;
+    case ReMFParser::O_MINUS:
+        rc = ReASBinaryOp::BOP_MINUS;
+        break;
+    case ReMFParser::O_DIV:
+        rc = ReASBinaryOp::BOP_DIV;
+        break;
+    case ReMFParser::O_MOD:
+        rc = ReASBinaryOp::BOP_MOD;
+        break;
+    case ReMFParser::O_TIMES:
+        rc = ReASBinaryOp::BOP_TIMES;
+        break;
+    case ReMFParser::O_POWER:
+        rc = ReASBinaryOp::BOP_POWER;
+        break;
+    case ReMFParser::O_XOR:
+        rc = ReASBinaryOp::BOP_LOG_XOR;
+        break;
+    case ReMFParser::O_BIT_OR:
+        rc = ReASBinaryOp::BOP_BIT_OR;
+        break;
+    case ReMFParser::O_BIT_AND:
+        rc = ReASBinaryOp::BOP_BIT_AND;
+        break;
+    case ReMFParser::O_LSHIFT:
+        rc = ReASBinaryOp::BOP_LSHIFT;
+        break;
+    case ReMFParser::O_RSHIFT:
+        rc = ReASBinaryOp::BOP_LOG_RSHIFT;
+        break;
+    case ReMFParser::O_RSHIFT2:
+        rc = ReASBinaryOp::BOP_ARTITH_RSHIFT;
+        break;
+    default:
+        throw ReException("unknown binary operator %d", op);
+        break;
+    }
+    return rc;
+}
+
+/**
+ * @brief Parses an expression.
+ *
+ * This method parses the part of an expression with the same parenthesis level.
+ * The nested parts will be processed recursivly by calling parseOperand which
+ * calls <code>parseExpr</code> in the case of inner parentheses.
+ *
+ * Example: a + (3 * 7 - 2)<br>
+ * expr with level 1: 3*7-2<br>
+ * expr with level 0: a + expr1<br>
+ *
+ * @pre         the nextNonSpaceToken() will return the first token of the expr.
+ * @post        the token behind the expression is read
+ *
+ * @param depth the level of the parenthesis
+ * @return      the abstract syntax tree representing the parsed expression
+ */
+ReASItem* ReMFParser::parseExpr(int depth){
+    ReToken* token;
+    ReASItem* top = parseOperand(depth);
+    if (top != NULL){
+        int lastPrio = INT_MAX;
+        bool again = true;
+        do {
+            token = m_lexer.currentToken();
+            switch(token->tokenType()){
+            case TOKEN_OPERATOR:
+            {
+                Operator opId = (Operator) token->id();
+                if (IS_BINARY_OP(opId)){
+                    ReASBinaryOp* op = new ReASBinaryOp();
+                    op->setPosition(m_lexer.currentPosition());
+                    op->setOperator(convertBinaryOp(opId));
+
+                    int prio = m_lexer.prioOfOp(token->id());
+                    if (prio < lastPrio
+                            || (prio == lastPrio
+                                && ! m_lexer.isRightAssociative(opId))){
+                        op->setChild(top);
+                        top = op;
+                    } else {
+                        // right assoc or higher priority:
+                        ReASBinaryOp* top2 = dynamic_cast<ReASBinaryOp*>(top);
+                        op->setChild(top2->child2());
+                        top2->setChild2(op);
+                    }
+                    lastPrio = prio;
+                    op->setChild2(parseOperand(depth));
+                } else
+                    again = false;
+                break;
+            }
+            case TOKEN_STRING:
+                syntaxError(L_TERM_WRONG_STRING, "Operator expected, not a string");
+                break;
+            case TOKEN_NUMBER:
+            case TOKEN_REAL:
+                syntaxError(L_TERM_WRONG_NUMBER, "Operator expected, not a number");
+                break;
+            case TOKEN_KEYWORD:
+            case TOKEN_ID:
+            case TOKEN_END_OF_SOURCE:
+            default:
+                again = false;
+                break;
+            }
+        } while(again);
+    }
+    return top;
+}
+
+
+/**
+ * @brief Parses an expression as a statement.
+ *
+ * @pre     the nextNonSpaceToken() will return the first token of the expr.<br>
+ *          Note: a ';' is part of the expression statement
+ * @post    the token behind the expression is read
+ * @param   eatSemicolon    true: a trailing ';' will be read
+ * @return                  the abstract syntax tree of the expression statement
+ */
+ReASItem* ReMFParser::parseExprStatement(bool eatSemicolon)
+{
+    ReASItem* item = parseExpr(0);
+    ReASExprStatement* statement = NULL;
+    if (item != NULL){
+        statement = new ReASExprStatement();
+        statement->setPosition(item->position());
+        statement->setChild2(item);
+    }
+    if (eatSemicolon && m_lexer.currentToken()->isOperator(O_SEMICOLON))
+        m_lexer.nextNonSpaceToken();
+    return statement;
+}
+
+/**
+ * @brief Parses a local variable.
+ *
+ * @return the variable definition
+ */
+ReASItem* ReMFParser::parseLocalVar(){
+    ReASItem* rc = parseVarDefinition(ReASNamedValue::A_NONE);
+    return rc;
+}
+
+/**
+ * @brief Parses the body.
+ *
+ * A body is a module, a class region or a method body.
+ *
+ * @param keywordStop   the first possible keyword which finishes the stm. list
+ * @param keywordStop2  the 2nd possible keyword which finishes the statements
+ * @param builtinVars   number of variables valid only in this body
+ * @return              the first element of the statement list
+ */
+ReASItem* ReMFParser::parseBody(Keyword keywordStop, Keyword keywordStop2,
+                                  int builtinVars)
+{
+    ReToken* token = m_lexer.nextNonSpaceToken();
+    ReASItem* item = NULL;
+    ReASItem* body = NULL;
+    ReASNode1* lastStatement = NULL;
+    ReASScope scope;
+    m_tree.currentSpace()->startScope(scope);
+    scope.m_builtInVars = builtinVars;
+    bool again = true;
+    const ReSourcePosition* lastPos = NULL;
+    do {
+        token = m_lexer.currentToken();
+        if (lastPos == m_lexer.currentPosition())
+            syntaxError(L_PARSE_BODY_NO_START, "no statement starts with this symbol");
+        lastPos = m_lexer.currentPosition();
+        // eat a superflous ';'
+        if (token->isOperator(O_SEMICOLON))
+            token = m_lexer.nextNonSpaceToken();
+        try {
+            switch(token->tokenType())
+            {
+            case TOKEN_OPERATOR:
+            case TOKEN_STRING:
+            case TOKEN_NUMBER:
+            case TOKEN_REAL:
+                m_lexer.undoLastToken();
+                item = parseExprStatement();
+                break;
+            case TOKEN_KEYWORD:
+                switch (token->id()){
+                case K_IF:
+                    item = parseIf();
+                    break;
+                case K_WHILE:
+                    item = parseWhile();
+                    break;
+                case K_REPEAT:
+                    item = parseRepeat();
+                    break;
+                case K_FOR:
+                    item = parseFor();
+                    break;
+                case K_CLASS:
+                    parseClass();
+                    item = NULL;
+                    break;
+                case K_FUNCTION:
+                case K_GENERATOR:
+                    parseMethod();
+                    item = NULL;
+                    break;
+                case K_IMPORT:
+                    parseImport();
+                    item = NULL;
+                    break;
+                case K_CONST:
+                case K_LAZY:
+                    item = parseLocalVar();
+                    break;
+                default:
+                    if (token->isKeyword(keywordStop, keywordStop2))
+                        again = false;
+                    break;
+                }
+                break;
+            case TOKEN_ID:
+            {
+                if (token->isCapitalizedId()){
+                    item = parseLocalVar();
+                } else {
+                    m_lexer.undoLastToken();
+                    item = parseExprStatement();
+                }
+                break;
+            }
+            case TOKEN_END_OF_SOURCE:
+                again = false;
+                break;
+            default:
+                break;
+            }
+            if (again && item != NULL){
+                if (body == NULL){
+                    body = item;
+                } else {
+                    lastStatement->setChild(item);
+                }
+                lastStatement = dynamic_cast<ReASNode1*>(item);
+                if (lastStatement == NULL)
+                    error(L_PARSE_BODY_WRONG_ITEM, "wrong item type: %d",
+                          item == NULL ? 0 : item->nodeType());
+                token = m_lexer.currentToken();
+                if (keywordStop != K_UNDEF
+                            && token->isKeyword(keywordStop, keywordStop2))
+                    again = false;
+            }
+        } catch(RSyntaxError exc){
+            // we look for the end of the statement:
+            token = m_lexer.currentToken();
+            RplTokenType type;
+            Operator op;
+            Keyword key;
+            while( (type = token->tokenType()) != TOKEN_END_OF_SOURCE)
+                if (type == TOKEN_OPERATOR
+                        && ((op = Operator(token->id())) == O_SEMICOLON
+                            || op == O_SEMI_SEMICOLON))
+                    break;
+                else if (type == TOKEN_KEYWORD){
+                    key = Keyword(token->id());
+                    if (key == K_ENDC || key == K_ENDF){
+                        // we need the token again!
+                        m_lexer.undoLastToken();
+                        break;
+                    } else if (key == K_FI || key == K_OD){
+                        break;
+                    } else {
+                        token = m_lexer.nextNonSpaceToken();
+                    }
+                } else {
+                    token = m_lexer.nextNonSpaceToken();
+                }
+        }
+    } while(again);
+
+    if (keywordStop != K_ENDF && keywordStop != K_ENDC
+            && keywordStop != K_UNDEF)
+        m_tree.currentSpace()->finishScope(m_lexer.currentPosition()->lineNo(),
+                                           scope);
+    return body;
+}
+
+/**
+ * @brief Parses a parameter list of a method/function.
+ *
+ * @pre     token behind '(' is read
+ * @post    token behind ')' is read
+ * @return
+ */
+ReASVarDefinition* ReMFParser::parseParameterList(){
+    ReASVarDefinition* rc = NULL;
+    ReASVarDefinition* last = NULL;
+    const ReSourcePosition* startPos = m_lexer.currentPosition();
+    ReASItem* definition = NULL;
+    do {
+        if (definition != NULL)
+            m_lexer.nextNonSpaceToken();
+        ReASVarDefinition* current = parseVarDefinition(ReASNamedValue::A_PARAM);
+        if (rc == NULL){
+            rc = current;
+        } else {
+            last->setChild(current);
+        }
+        last = current;
+    } while(m_lexer.currentToken()->isOperator(O_COMMA));
+    if (! m_lexer.currentToken()->isOperator(O_RPARENTH))
+        syntaxError(L_PARSE_PARAMLIST_NO_PARENTH, ") expected", ")", startPos);
+    m_lexer.nextNonSpaceToken();
+    return rc;
+}
+
+/**
+ * @brief Parses a class definition.
+ *
+ * The method definition will be stored in the symbol space of the parent
+ *
+ * @pre             token "func" is read
+ * @post            token behind "endf" is read
+ * @return          NULL
+ */
+void ReMFParser::parseMethod()
+{
+    ReASMethod* method = NULL;
+    const ReSourcePosition* startPos = m_lexer.currentPosition();
+    ReToken* token = m_lexer.nextNonSpaceToken();
+    if (! token->isTokenType(TOKEN_ID))
+        syntaxError(L_PARSE_METH_NO_CLASS, "type name expected");
+    QByteArray type = token->toString();
+    if (! isupper(type.at(0)))
+        syntaxError(L_PARSE_METH_NO_CLASS2,
+                    "type name expected (must start with an upper case character)");
+    token = m_lexer.nextNonSpaceToken();
+    if (! token->isTokenType(TOKEN_ID))
+        syntaxError(L_PARSE_METH_NO_NAME, "method name expected");
+    QByteArray name = token->toString();
+    if (! isupper(type.at(0)))
+        syntaxError(L_PARSE_METH_NO_CLASS2,
+                    "method name expected (must start with an lower case character)");
+    token = m_lexer.nextNonSpaceToken();
+    if (! token->isOperator(O_LPARENTH, O_COLON))
+        syntaxError(L_PARSE_METH_NO_LPARENTH, "'(' or ':' expected");
+
+    ReASVarDefinition* parameterList = NULL;
+    method = new ReASMethod(name, m_tree);
+    method->setPosition(startPos);
+    ReSymbolSpace* symbols = m_tree.currentSpace();
+    symbols->addMethod(method);
+    m_tree.startClassOrMethod(name, ReSymbolSpace::SST_METHOD);
+    method->setSymbols();
+    if (token->isOperator(O_LPARENTH)){
+      token = m_lexer.nextNonSpaceToken();
+      if (token->isOperator(O_RPARENTH)){
+          token = m_lexer.nextNonSpaceToken();
+      } else {
+          parameterList = parseParameterList();
+          method->setChild2(parameterList);
+      }
+    }
+    if (! token->isOperator(O_COLON))
+        syntaxError(L_PARSE_METH_NO_COLON, "':' expected");
+
+    method->setChild(parseBody(K_ENDF));
+    if (! m_lexer.currentToken()->isKeyword(K_ENDF))
+        syntaxError(L_PARSE_METH_NO_END, "end of function not found", "endf",
+                    startPos);
+    m_lexer.nextNonSpaceToken();
+    m_tree.finishClassOrMethod(name);
+}
+
+/**
+ * @brief Parses a class definition.
+ *
+ * @pre     "class" is read
+ * @post    token behind "endc" is read
+ */
+void ReMFParser::parseClass()
+{
+    const ReSourcePosition* startPos = m_lexer.currentPosition();
+    ReToken* token = m_lexer.nextNonSpaceToken();
+    if (! token->isTokenType(TOKEN_ID))
+        syntaxError(L_PARSE_CLASS_NO_NAME, "class name expected");
+    if (! token->isCapitalizedId())
+        syntaxError(L_PARSE_CLASS_LOWERCASE, "class name must start with an uppercase character");
+    QByteArray name = token->toString();
+    ReASUserClass* clazz = new ReASUserClass(name, startPos, m_tree);
+    ReSymbolSpace* parent = m_tree.currentSpace();
+    ReASUserClass* alreadyDefined = parent->addClass(clazz);
+    if (alreadyDefined != NULL){
+        error(L_PARSE_CLASS_ALREADY_DEFINED, alreadyDefined->position(),
+              "class already defined", "previous defined class");
+    }
+    m_tree.startClassOrMethod(name, ReSymbolSpace::SST_CLASS);
+    clazz->setSymbols();
+
+    m_tree.finishClassOrMethod(name);
+}
+
+/**
+ * @brief Parses a the import statement
+ */
+void ReMFParser::parseImport()
+{
+
+}
+
+/**
+ * @brief Parses a module.
+ *
+ * @pre     the first char of the module is the next char to read.
+ * @post    the total module is read
+ *
+ * @param name  the name of the module (without path)
+ */
+ReASItem* ReMFParser::parseModule(ReSourceUnitName name)
+{
+    m_tree.startModule(name);
+    // parse until EOF:
+    ReASItem* body = parseBody(K_UNDEF);
+    m_tree.finishModule(name);
+    return body;
+}
+/**
+ * @brief Parse the input given by the source.
+ */
+void ReMFParser::parse()
+{
+    ReSource* source = m_lexer.source();
+    ReSourceUnit* mainModule = source->currentReader()->currentSourceUnit();
+    ReSourceUnitName mainModuleName = mainModule->name();
+    try {
+        ReASItem* body = parseModule(mainModuleName);
+        ReSymbolSpace* module = m_tree.findmodule(mainModuleName);
+        if (module != NULL)
+            module->setBody(body);
+    } catch(RplParserStop exc){
+        printf("compiling aborted: %s\n", exc.reason());
+    }
+}
+
+/**
+ * @brief Parses an argument list in a method call.
+ *
+ * @pre     the token '(' is read
+ * @post    the token behind the ')' is read
+ * @return  the first element of the argument list
+ */
+ReASExprStatement* ReMFParser::parseArguments()
+{
+    ReASExprStatement* first = NULL;
+    ReASExprStatement* last = NULL;
+    bool again = false;
+    do {
+        ReASItem* expr = parseExpr(0);
+        if (! m_lexer.currentToken()->isOperator(O_COMMA, O_RPARENTH))
+            syntaxError(L_PARSE_ARGS_NO_COMMA_OR_PARENT, "',' or ')' expected");
+        again = m_lexer.currentToken()->isOperator(O_COMMA);
+        ReASExprStatement* current = new ReASExprStatement();
+        current->setPosition(expr->position());
+        current->setChild2(expr);
+        if (first == NULL)
+            first = last = current;
+        else{
+            last->setChild(current);
+            last = current;
+        }
+    } while (again);
+    // skip ')':
+    m_lexer.nextNonSpaceToken();
+    return first;
+}
+
diff --git a/expr/ReMFParser.hpp b/expr/ReMFParser.hpp
new file mode 100644 (file)
index 0000000..fb5aeca
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef REMFPARSER_HPP
+#define REMFPARSER_HPP
+
+class ReMFParser : public ReParser
+{
+public:
+    enum Keyword {
+        K_UNDEF, K_IF, K_THEN, K_ELSE, K_FI, K_WHILE, // 5
+        K_DO, K_OD, K_REPEAT, K_UNTIL, K_FOR, // 10
+        K_FROM, K_TO, K_STEP, K_IN, K_CASE, // 15
+        K_OF, K_ESAC, K_LEAVE, K_CONTINUE, K_PASS, // 20
+        K_CLASS, K_ENDC, K_ENDF, K_FUNCTION, K_GENERATOR, // 25
+        K_IMPORT, K_CONST, K_LAZY, K_NONE, K_TRUE, // 30
+        K_FALSE
+        };
+#define MF_KEYWORDS "if then else fi while do od repeat until" \
+    " for from to step in case of esac leave continue pass" \
+    " class endc endf func generator import" \
+    " const lazy none true false"
+    enum Operator {
+        O_UNDEF, O_SEMI_SEMICOLON, O_SEMICOLON, O_COMMA, O_COLON, // 4
+        O_ASSIGN, O_PLUS_ASSIGN, O_MINUS_ASSIGN, O_DIV_ASSIGN, O_TIMES_ASSIGN, // 8
+        O_MOD_ASSIGN, O_POWER_ASSIGN, O_OR_ASSIGN, O_AND_ASSIGN, // 13
+        O_LSHIFT_ASSIGN, O_RSHIFT_ASSIGN, O_RSHIFT2_ASSIGN, // 16
+        O_OR, O_AND, // 18
+        O_EQ, O_NE, // 20
+        O_LT, O_GT, O_LE, O_GE, // 24
+        O_QUESTION, // 25
+        O_PLUS, O_MINUS, // 27
+        O_DIV, O_MOD, O_TIMES, // 30
+        O_POWER, // 31
+        O_XOR, O_BIT_OR, O_BIT_AND, // 34
+        O_LSHIFT, O_RSHIFT, O_RSHIFT2, // 37
+        O_NOT, O_BIT_NOT, // 39
+        O_INC, O_DEC, // 41
+        O_DOT, O_LPARENTH, O_RPARENTH, O_LBRACKET, O_RBRACKET, O_LBRACE, O_RBRACE // 48
+    };
+#define IS_BINARY_OP(op) (Operator(op) >= O_ASSIGN && Operator(op) <= O_DOT)
+#define IS_UNARY_OP(op) (op==O_PLUS || op==O_MINUS || (op>=O_NOT && op<=O_DEC))
+
+/// \n separates the priority classes
+#define MF_OPERATORS ";; ; , :\n" \
+    "= += -= /= *= %= **= |= &= <<= >>= >>>=\n" \
+    "||\n" \
+    "&&\n" \
+    "== !=\n" \
+    "< > <= >=\n" \
+    "?\n" \
+    "+ -\n" \
+    "/ % *\n" \
+    "**\n" \
+    "^ | &\n" \
+    "<< >> >>>\n" \
+    "! ~\n" \
+    "++ --\n" \
+    ". ( ) [ ] { }"
+#define MF_RIGHT_ASSOCIATIVES "= += -= /= *= %= **= |= &= <<= >>= >>>= ** ."
+public:
+    ReMFParser(ReSource& source, ReASTree& ast);
+public:
+    ReASItem* parseIf();
+    ReASItem* parseWhile();
+    ReASItem* parseRepeat();
+    ReASItem* parseFor();
+    ReASVarDefinition* parseVarDefinition(ReASNamedValue::Attributes attribute);
+    ReASItem* parseExpr(int depth);
+    ReASItem* parseBody(Keyword keywordStop, Keyword keywordStop2 = K_UNDEF,
+                         int builtinVars = 0);
+    void parseMethod();
+    void parseClass();
+    void parseImport();
+    ReASItem* parseModule(ReSourceUnitName name);
+    void parse();
+    ReASItem*parseExprStatement(bool eatSemicolon = true);
+    ReASItem*parseList();
+    ReASItem*parseMap();
+protected:
+    ReASExprStatement* parseArguments();
+    ReASItem* parseOperand(int level, ReASItem* parent = NULL);
+    ReASVariant* tokenToVariant(ReToken* token, bool endsWithComma,
+                                 ReASNode1* parent);
+    ReASVariant*createFormula(ReASNode1* parent);
+    ReASItem* buildVarOrField(const QByteArray& name,
+                               const ReSourcePosition* position,
+                               ReASItem* parent);
+    ReASVarDefinition* parseParameterList();
+    ReASItem* parseLocalVar();
+    ReASVarDefinition* buildVarDef(ReASNamedValue* var);
+protected:
+    static ReASBinaryOp::BinOperator convertBinaryOp(int op);
+    static ReASUnaryOp::UnaryOp convertUnaryOp(int op);
+private:
+    ///syntax token builder.
+    /// Note: the super class contains a reference with the same name
+    ReLexer m_lexer;
+};
+
+#endif // REMFPARSER_HPP
diff --git a/expr/ReParser.cpp b/expr/ReParser.cpp
new file mode 100644 (file)
index 0000000..a0be1bb
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ *
+ * @brief Generally usable parts of an parser, e.g. error handling.
+ */
+/** @file expr/ReParser.hpp
+ *
+ * @brief Definition of a generally usable parts of an parser.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+
+/** @class RSyntaxError ReParser.hpp "expr/ReParser.hpp"
+ *
+ * @brief Implements an exception used for jumping out from many nested calls.
+ *
+ * We don't want to cancel the parse process if an syntax error has been
+ * occurred. Therefore we want to recreate after it.
+ * A relative simple solution:
+ * Ignoring the rest of the statement and start again with the next statement.
+ * Often the detection is done deep in an expression and we must jump out.
+ * This allows this exception.
+ */
+
+/**
+ * @brief Constructor.
+ * @param reason        the reason of the exception
+ * @return
+ */
+ReSyntaxError::ReSyntaxError(const char* reason) :
+    m_reason(reason)
+{
+}
+/**
+ * @brief Returns the description of the exception.
+ *
+ * @return  the reason
+ */
+const char* ReSyntaxError::reason() const
+{
+    return m_reason;
+}
+
+/** @class RplParserStop ReParser.hpp "expr/ReParser.hpp"
+ *
+ * @brief Implements an exception used for jumping out from many nested calls.
+ *
+ * In some situation we want to abort the parsing process.
+ * This exception allows this without high costs even the abort position
+ * is in a deep nested call.
+ */
+
+/**
+ * @brief Constructor.
+ * @param reason        the reason of the exception
+ */
+RplParserStop::RplParserStop(const char* reason) :
+    ReSyntaxError(reason)
+{
+}
+
+/** @class ReParser ReParser.hpp "expr/ReParser.hpp"
+ *
+ * @brief Implements a base class for parsers.
+ *
+ * This class offers common things for all parsers, e.g. error handling.
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param lexer     the tokenizer
+ * @param tree      the abstract syntax tree
+ */
+ReParser::ReParser(ReLexer& lexer, ReASTree& tree) :
+    m_lexer(lexer),
+    m_tree(tree),
+    m_messages(),
+    m_errors(0),
+    m_warnings(0),
+    m_maxErrors(20),
+    m_maxWarnings(20)
+{
+}
+
+/**
+ * @brief Common actions for the error/warning functions.
+ *
+ * @param prefix    first char in the message: 'E' (error) or 'W' (warning)
+ * @param location  unique id of the error/warning message
+ * @param position  position of the error/warning
+ * @param message   message with placeholdes like sprintf()
+ * @return          false (for chaining)
+ */
+bool ReParser::addSimpleMessage(LevelTag prefix, int location,
+                                 const ReSourcePosition* position,
+                                 const char* message){
+    char buffer[2048];
+    QByteArray msg;
+    qsnprintf(buffer, sizeof buffer, "%c%04d %s:%d-%d: ", prefix, location,
+             position->sourceUnit()->name(),
+             position->lineNo(), position->column());
+    int used = strlen(buffer);
+    int length = strlen(message);
+    if (length >= (int) sizeof buffer - used)
+        length = sizeof buffer - used - 1;
+    memcpy(buffer + used, message, length);
+    buffer[used + length] = '\0';
+    m_messages.append(buffer);
+    return false;
+}
+
+/**
+ * @brief Common actions for the error/warning functions.
+ *
+ * @param prefix    first char in the message: 'E' (error) or 'W' (warning)
+ * @param location  unique id of the error/warning message
+ * @param position  position of the error/warning
+ * @param format    message with placeholdes like sprintf()
+ * @param varList   the variable argument list
+ * @return          false (for chaining)
+ */
+bool ReParser::addMessage(LevelTag prefix, int location,
+                           const ReSourcePosition* position,
+                           const char* format, va_list varList){
+    char buffer[2048];
+    qvsnprintf(buffer, sizeof buffer, format, varList);
+    return addSimpleMessage(prefix, location, position, buffer);
+}
+
+/**
+ * @brief Adds an error message and throws an exception.
+ *
+ * The exception will be catched at a position where error recovery can take place.
+ *
+ * @param location  unique id of the error/warning message
+ * @param message   error message
+ */
+
+void ReParser::syntaxError(int location, const char* message)
+{
+    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
+    throw RSyntaxError(message);
+}
+
+/**
+ * @brief Adds an error message and throws an exception.
+ *
+ * This method is used if a closing symbol (e.g. a ')' or 'end') is missed.
+ * The message contains a %s as an placeholder for the position of the
+ * starting symbol.
+ * The exception will be catched at a position where error recovery
+ * can take place.
+ *
+ * @param location  unique id of the error
+ * @param message   message describing the error
+ * @param symbol    starting symbol corresponding to the missed closing symbol
+ * @param position  position of the starting symbol
+ */
+
+void ReParser::syntaxError(int location, const char* message,
+                            const char* symbol,
+                            const ReSourcePosition* position)
+{
+    char buffer[256];
+    char buffer2[512];
+    qsnprintf(buffer2, sizeof buffer2,
+            "The starting symbol %s is located here. Missing point: %s",
+            symbol, m_lexer.currentPosition()->utf8(buffer, sizeof buffer));
+
+    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
+    addSimpleMessage(LT_INFO, location + 1, position, buffer2);
+    throw RSyntaxError(message);
+}
+
+/**
+ * @brief Adds an error message.
+ *
+ * If too much errors an exception will be thrown to stop parsing.
+ *
+ * @param location  unique id of the error/warning message
+ * @param format    message with placeholdes like sprintf()
+ * @param ...       optional: the variable argument list
+ * @return          false (for chaining)
+ */
+bool ReParser::error(int location, const char* format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    addMessage(LT_ERROR, location, m_lexer.currentPosition(), format, ap);
+    va_end(ap);
+    if (++m_errors >= m_maxErrors)
+        throw RplParserStop("too many errors");
+    return false;
+}
+/**
+ * @brief Adds an error message with an additional info message.
+ *
+ * If too much errors an exception will be thrown to stop parsing.
+ *
+ * @param location  unique id of the error/warning message
+ * @param position  source position of the additional message
+ * @param message   describes the error
+ * @param message2  the additional message
+ * @param ...       optional: the variable argument list
+ * @return          false (for chaining)
+ */
+bool ReParser::error(int location, const ReSourcePosition* position,
+                      const char* message, const char* message2)
+{
+    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
+    addSimpleMessage(LT_INFO, location + 1, position, message2);
+    if (++m_errors >= m_maxErrors)
+        throw RplParserStop("too many errors");
+    return false;
+}
+
+/**
+ * @brief Adds a warning message.
+ *
+ * If too much warnings an exception will be thrown to stop parsing.
+ *
+ * @param location  unique id of the error/warning message
+ * @param format    message with placeholdes like sprintf()
+ * @param ...       optional: the variable argument list
+ */
+void ReParser::warning(int location, const char* format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    addMessage(LT_WARNING, location, m_lexer.currentPosition(), format, ap);
+    va_end(ap);
+    if (++m_warnings >= m_maxWarnings)
+        throw RplParserStop("too many warnings");
+}
+/**
+ * @brief Return the number of errors.
+ *
+ * @return the count of errors occurred until now
+ */
+int ReParser::errors() const
+{
+    return m_errors;
+}
+/**
+ * @brief Return the number of warnings.
+ *
+ * @return the count of errors occurred until now
+ */
+int ReParser::warnings() const
+{
+    return m_warnings;
+}
+
+
diff --git a/expr/ReParser.hpp b/expr/ReParser.hpp
new file mode 100644 (file)
index 0000000..80b9f15
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef REPARSER_HPP
+#define REPARSER_HPP
+
+class ReSyntaxError
+{
+public:
+    ReSyntaxError(const char* reason);
+public:
+    const char* reason() const;
+private:
+    const char* m_reason;
+};
+
+class RplParserStop : public ReSyntaxError {
+public:
+    RplParserStop(const char* reason);
+};
+
+class ReParser {
+public:
+    enum LevelTag {
+        LT_ERROR = 'E',
+        LT_WARNING = 'W',
+        LT_INFO = 'I'
+    };
+
+public:
+    typedef QList<QByteArray> MessageList;
+public:
+    ReParser(ReLexer& lexer, ReASTree& ast);
+public:
+    bool addSimpleMessage(LevelTag prefix, int location,
+                          const ReSourcePosition* pos,
+                          const char* message);
+    bool addMessage(LevelTag prefix, int location,
+                    const ReSourcePosition* pos,
+                    const char* format, va_list varList);
+    void syntaxError(int location, const char* message);
+    void syntaxError(int location, const char* message, const char* symbol,
+                     const ReSourcePosition* position);
+    bool error(int location, const char* format, ...);
+    bool error(int location, const ReSourcePosition* position,
+               const char* message, const char* message2);
+    void warning(int location, const char* format, ...);
+    int errors() const;
+    int warnings() const;
+protected:
+    ReLexer& m_lexer;
+    ReASTree& m_tree;
+    MessageList m_messages;
+    int m_errors;
+    int m_warnings;
+    int m_maxErrors;
+    int m_maxWarnings;
+};
+
+#endif // REPARSER_HPP
diff --git a/expr/ReSource.cpp b/expr/ReSource.cpp
new file mode 100644 (file)
index 0000000..b9e21e9
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ * @brief Reading from several input media.
+ *
+ * The abstract base class <code>ReReader</code> and its concrete derivations
+ * <code>ReStringReader</code>, <code>ReFileReader</code> are used to read
+ * from one medium.
+ * The <code>ReSource</code> combines several readers and build an uniquely
+ * usable input stream.
+ */
+/** @file expr/ReSource.hpp
+ *
+ * @brief Definitions for reading from several input media.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+
+/** @class ReSource ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Stores all source positions.
+ *
+ */
+
+/** @class ReSourceUnit ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Implements the base class of input source units.
+ *
+ * A source unit is set of input lines with a name, e.g. a file.
+ */
+
+/**
+ * @brief Constructor
+ * @param name      name of the unit
+ * @param reader    the reader which can read the unit
+ */
+ReSourceUnit::ReSourceUnit(ReSourceUnitName name, ReReader* reader) :
+    m_name(name),
+    m_lineNo(0),
+    m_reader(reader) {
+}
+
+/**
+ * @brief Destructor.
+ */
+ReSourceUnit::~ReSourceUnit() {
+}
+
+/**
+ * @brief Returns the name.
+ * @return  the name
+ */
+ReSourceUnitName ReSourceUnit::name() const {
+    return m_name.constData();
+}
+
+/**
+ * @brief Returns the line number.
+ *
+ * @return  the line number
+ */
+int ReSourceUnit::lineNo() const {
+    return m_lineNo;
+}
+
+/**
+ * @brief Sets the line number.
+ *
+ * @param lineNo    the new line number
+ */
+void ReSourceUnit::setLineNo(int lineNo) {
+    m_lineNo = lineNo;
+}
+/**
+ * @brief Returns the reader of the instance.
+ *
+ * @return  the reader belonging to the instance
+ */
+ReReader* ReSourceUnit::reader() const {
+    return m_reader;
+}
+
+/** @class ReSourcePosition ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Stores a precise position in the input source.
+ *
+ * The input source contains normally a lot of nested source units.
+ *
+ * Each source unit owns a name and a sequence of lines.
+ *
+ * The mostly used source unit is a text file.
+ *
+ * A precice position is the stack of source unit positions.
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReSourcePosition::ReSourcePosition() :
+    m_sourceUnit(NULL),
+    m_lineNo(0),
+    m_column(0),
+    m_caller(NULL)
+{
+}
+
+/**
+ * @brief Constructor.
+ *
+ * @param unit      name of the input source (normally a file)
+ * @param lineNo    line number inside the input source
+ * @param colNo     distance to the line start
+ */
+ReSourcePosition::ReSourcePosition(ReSourceUnit* unit, int lineNo,
+        int colNo) :
+    m_sourceUnit(unit),
+    m_lineNo(lineNo),
+    m_column(colNo),
+    m_caller(NULL)
+{
+    ReReader* reader = dynamic_cast<ReReader*>(unit->reader());
+    m_caller = reader->source().caller();
+}
+/**
+ * @brief Destructor
+ */
+ReSourcePosition::~ ReSourcePosition(){
+    // That should never occure!
+    assert(false);
+}
+
+/**
+ * @brief Placement new operator (for our own memory management).
+ *
+ * @param cbSize    size of the instance
+ * @param buffer    buffer for the instance
+ * @return          <code>buffer</code>
+ */
+void*ReSourcePosition::operator new(size_t, void* buffer)
+{
+    return buffer;
+}
+
+/**
+ * @brief Returns a description of the source position: "<unit>-<lineNo> (<col>):".
+ *
+ * @return a description of the instance
+ */
+ReString ReSourcePosition::toString() const
+{
+    char buffer[512];
+    utf8(buffer, sizeof buffer);
+
+    return ReString(buffer);
+}
+
+/**
+ * @brief Returns the position as a C string.
+ *
+ * @param buffer        OUT: the target buffer
+ * @param bufferSize    the size of the buffer
+ * @return              <code>buffer</code>
+ */
+char* ReSourcePosition::utf8(char buffer[], size_t bufferSize) const
+{
+    qsnprintf(buffer, bufferSize, "%s:%d:%d",
+             m_sourceUnit == NULL ? "" : m_sourceUnit->name(),
+             m_lineNo, m_column);
+    return buffer;
+}
+
+/**
+ * @brief Returns the line number.
+ * @return  the line number
+ */
+int ReSourcePosition::lineNo() const
+{
+    return m_lineNo;
+}
+
+/**
+ * @brief Sets the line number.
+ *
+ * @param lineNo    the new lineNo
+ */
+void ReSourcePosition::setLineNo(int lineNo)
+{
+    m_lineNo = lineNo;
+}
+/**
+ * @brief Returns the column.
+ *
+ * @return  the column of instance.
+ */
+int ReSourcePosition::column() const
+{
+    return m_column;
+}
+
+/**
+ * @brief Sets the column.
+ *
+ * @param column    the new column
+ */
+void ReSourcePosition::setColumn(int column)
+{
+    m_column = column;
+}
+
+/**
+ * @brief Returns the source unit belonging to the instance.
+ *
+ * @return  the source unit of the instance
+ */
+ReSourceUnit* ReSourcePosition::sourceUnit() const
+{
+    return m_sourceUnit;
+}
+
+/**
+ * @brief Sets the source unit.
+ *
+ * @param sourceUnit    the new source unit of the instance
+ */
+void ReSourcePosition::setSourceUnit(ReSourceUnit* sourceUnit)
+{
+    m_sourceUnit = sourceUnit;
+    m_lineNo = sourceUnit->lineNo();
+}
+
+
+/** @class ReReader ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Implements a base class for readers of different media.
+ */
+
+
+/**
+ * @brief Constructor.
+ *
+ * @param source    the parent
+ */
+ReReader::ReReader(ReSource& source) :
+    m_currentSourceUnit(NULL),
+    m_units(),
+    m_source(source) {
+}
+
+/**
+ * @brief Destructor.
+ */
+ReReader::~ReReader()
+{
+    clear();
+}
+
+/**
+ * @brief Frees the resources.
+ */
+void ReReader::clear()
+{
+    UnitMap::iterator it;
+    for(it = m_units.begin(); it != m_units.end(); it++) {
+        ReStringSourceUnit* unit = (ReStringSourceUnit*)(*it);
+        delete unit;
+    }
+    m_units.clear();
+    m_currentSourceUnit = NULL;
+}
+
+/**
+ * @brief Returns the source of the reader.
+ *
+ * @return the parent, a source instance
+ */
+ReSource&ReReader::source()
+{
+    return m_source;
+}
+/**
+ * @brief Returns the current source unit.
+ *
+ * @return the source unit
+ */
+ReSourceUnit* ReReader::currentSourceUnit() const {
+    return m_currentSourceUnit;
+}
+
+/**
+ * @brief Sets the current source unit.
+ *
+ * @param sourceUnit    the name of the new source unit
+ * @return              true: source unit exists<br>
+ *                      false: source unit not found
+ */
+bool ReReader::setCurrentSourceUnit(ReSourceUnitName& sourceUnit) {
+    bool rc = m_units.contains(sourceUnit);
+    if(rc) {
+        m_currentSourceUnit = m_units.value(sourceUnit);
+        m_source.pushSourceUnit(m_currentSourceUnit);
+    }
+    return rc;
+}
+
+/**
+ * @brief Removes the "latest" sourceUnit.
+ */
+void ReReader::removeSourceUnit() {
+
+    m_currentSourceUnit = m_source.popSourceUnit(this);;
+}
+
+/** @class ReSourcePositionBlock ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Efficient heap of <code>ReSourcePosition</code> instances.
+ *
+ * The <code>ReSourcePosition</code> heap is only growing. The deletion is
+ * done for all entries together.
+ * Therefore a simple allocation is possible with blocks.
+ */
+ReSourcePositionBlock::ReSourcePositionBlock() :
+    m_successor(NULL)
+    // m_positions
+{
+    memset(m_positions, 0, sizeof m_positions);
+}
+
+/** @class ReSource ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Administrates a set of input sources with different readers.
+ *
+ * An input stream can be built by some different resources, e.g. files
+ * and memory buffers. The ReSource can administrate these resources.
+ */
+/**
+ * @brief Constructor.
+ */
+ReSource::ReSource() :
+    m_sourcePositionStack(),
+    m_sourcePositionBlock(NULL),
+    m_countPositionBlock(RPL_POSITIONS_PER_BLOCK + 1),
+    m_readers(),
+    m_sourceUnits(),
+    m_unitStack(),
+    m_currentReader(NULL)
+{
+    // the stack should never be empty:
+    m_sourcePositionStack.push(NULL);
+}
+
+/**
+ * @brief Destructor.
+ */
+ReSource::~ReSource() {
+    destroy();
+}
+
+/**
+ * @brief Frees the resources of the instance.
+ */
+void ReSource::destroy()
+{
+    m_sourcePositionStack.clear();
+    m_readers.clear();
+    m_sourceUnits.clear();
+    m_currentReader = NULL;
+    ReSourcePositionBlock* block = m_sourcePositionBlock;
+    m_sourcePositionBlock = NULL;
+    m_countPositionBlock = RPL_POSITIONS_PER_BLOCK + 1;
+    while(block != NULL){
+        ReSourcePositionBlock* last = block;
+        block = block->m_successor;
+        delete last;
+    }
+}
+
+/**
+ * @brief Returns the permanently valid source unit name.
+ *
+ * If unit names can be local objects (not string constants
+ * like __FILE__) then this method must be overridden by
+ * a method which builds a permanently valid string.
+ *
+ * @param unit      unit to find
+ * @return          a permanently valid unit name
+ */
+ReSourceUnitName ReSource::permanentUnitName(ReSourceUnitName unit) {
+    return unit;
+}
+
+/**
+ * @brief Returns the stack with the positions of the open input resources.
+ *
+ * @return  the stack
+ */
+QStack<const ReSourcePosition*> ReSource::sourcePositionStack() const {
+    return m_sourcePositionStack;
+}
+
+/**
+ * @brief Returns the source unit stack.
+ * @return  the stack of the source units
+ */
+QStack<ReSourceUnit*>& ReSource::sourceUnitStack()
+{
+    return m_unitStack;
+}
+
+/**
+ * @brief Adds a source reader.
+ *
+ * @param reader    the new reader. Will be freed in the destructor
+ */
+void ReSource::addReader(ReReader* reader) {
+    m_readers.push_back(reader);
+    if (m_currentReader == NULL)
+        m_currentReader = reader;
+}
+
+/**
+ * @brief Adds a source unit.
+ *
+ * @param unit  the new unit. Will be freed in the destructor
+ */
+void ReSource::addSourceUnit(ReSourceUnit* unit) {
+    m_sourceUnits.push_back(unit);
+}
+
+/**
+ * @brief Starts a new source unit.
+ *
+ * Saves the current source position onto the top of stack.
+ * Pushes the source unit onto the top of stack.
+ *
+ * @param unit      the source unit
+ * @param caller    the position of the include
+ *
+ */
+bool ReSource::startUnit(ReSourceUnitName unit,
+                          const ReSourcePosition& caller) {
+    m_sourcePositionStack.push_back(&caller);
+    ReReader* reader = NULL;
+    QList<ReReader*>::iterator it;
+    for(it = m_readers.begin();
+            reader == NULL && it != m_readers.end();
+            it++) {
+        ReReader* current = *it;
+        if(current->openSourceUnit(unit)) {
+            reader = current;
+            m_currentReader = current;
+            break;
+        }
+    }
+    return reader != NULL;
+}
+
+/**
+ * @brief Pushes a source unit onto the stack.
+ *
+ * @param unit      the source unit
+ */
+void ReSource::pushSourceUnit(ReSourceUnit* unit) {
+    m_unitStack.push(unit);
+}
+
+/**
+ * @brief Removes the latest source unit from the stack.
+ *
+ * @param reader    the current reader
+ * @return          NULL: the current reader does not have an open source unit<br>
+ *                  otherwise: the last entry from the source unit stack
+ */
+ReSourceUnit* ReSource::popSourceUnit(ReReader* reader) {
+    ReSourceUnit* rc = NULL;
+    if(m_unitStack.size() > 0)
+        m_unitStack.pop();
+    m_currentReader = m_unitStack.size() <= 0
+                      ? NULL : m_unitStack.top()->reader();
+    if(m_currentReader == reader)
+        rc = m_unitStack.top();
+    else {
+        for(int ix = m_unitStack.size() - 2; ix >= 0; ix--){
+            if(m_unitStack[ix]->reader() == reader){
+                rc = m_unitStack[ix];
+                break;
+            }
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns the reader of the current source unit.
+ *
+ * @return  NULL: no reader active<br>
+ *          otherwise: the current reader
+ */
+ReReader* ReSource::currentReader() {
+    return m_currentReader;
+}
+
+/**
+ * @brief Returns a new instance of the current source position.
+ *
+ * The storage is done in a block (efficency).
+ *
+ * @param colNo     the column in the line
+ * @return          a new instance of a source position
+ */
+const ReSourcePosition* ReSource::newPosition(int colNo)
+{
+    if (m_countPositionBlock >= RPL_POSITIONS_PER_BLOCK){
+        ReSourcePositionBlock* newBlock = new ReSourcePositionBlock;
+        newBlock->m_successor = m_sourcePositionBlock;
+        m_sourcePositionBlock = newBlock;
+        m_countPositionBlock = 0;
+    }
+    unsigned offset = m_countPositionBlock * sizeof(ReSourcePosition);
+    m_countPositionBlock++;
+    char* posInBlock = &m_sourcePositionBlock->m_positions[offset];
+    ReSourceUnit* unit = dynamic_cast<ReSourceUnit*>(
+                m_currentReader->currentSourceUnit());
+    ReSourcePosition* rc = new (posInBlock) ReSourcePosition(
+                unit, unit->lineNo(), colNo);
+    return rc;
+}
+
+/**
+ * @brief Resets all states in the source.
+ */
+void ReSource::clear()
+{
+    destroy();
+}
+
+/**
+ * @brief Returns the top position of the source unit stack.
+ *
+ * @return  NULL: stack is empty<br>
+ *          the top of the source unit stack
+ */
+const ReSourcePosition* ReSource::caller() const
+{
+    return m_sourcePositionStack.size() == 0
+            ? NULL : m_sourcePositionStack.top();
+}
+
+/** @class ReStringSourceUnit ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Stores the state of a string based source unit.
+ *
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param name      name of the unit
+ * @param content   content of the unit
+ * @param reader    the parent
+ */
+ReStringSourceUnit::ReStringSourceUnit(ReSourceUnitName name,
+        const ReSourceUnitContent& content, ReStringReader* reader) :
+    ReSourceUnit(name, reader),
+    m_currentPosition(0),
+    m_content(content) {
+}
+
+/**
+ * @brief Destructor.
+ */
+ReStringSourceUnit::~ReStringSourceUnit() {
+}
+/**
+ * @brief Returns the current read position.
+ *
+ * @return      the offset (count of QChars) of the end of the last read block
+ *              inside m_content
+ */
+int ReStringSourceUnit::currentPosition() const {
+    return m_currentPosition;
+}
+
+/**
+ * @brief Sets the current read position.
+ *
+ * @param currentPosition   the offset (count of QChars) of the end of
+ *                          the last read block inside <code>m_content</code>
+ */
+void ReStringSourceUnit::setCurrentPosition(int currentPosition) {
+    m_currentPosition = currentPosition;
+}
+/**
+ * @brief Returns the content of the source unit.
+ *
+ * @return  the content
+ */
+ReSourceUnitContent ReStringSourceUnit::content() const {
+    return m_content.constData();
+}
+
+/** @class ReStringReader ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Implements a source which provides reading from memory based buffers.
+ *
+ * Examples for usage: interactive input
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param source    the parent
+ */
+ReStringReader::ReStringReader(ReSource& source) :
+    ReReader(source) {
+}
+
+/**
+ * @brief Destructor.
+ */
+ReStringReader::~ReStringReader() {
+    clear();
+}
+
+/**
+ * @brief Opens a new source unit.
+ *
+ * @param unit  name of the source
+ * @return      NULL: unknown source<br>
+ *              otherwise: an instance of a sub class of
+ *              <code>ReSourceUnit</code>
+ */
+ReSourceUnit* ReStringReader::openSourceUnit(ReSourceUnitName unit) {
+    ReSourceUnit* rc = NULL;
+    if(setCurrentSourceUnit(unit)) {
+        rc = m_currentSourceUnit;
+        ((ReStringSourceUnit*) rc)->setCurrentPosition(0);
+    }
+    return rc;
+}
+/**
+ * @brief Delivers the next line from the input medium or the first part of it.
+ *
+ * @param maxSize   if the line length is longer than this value, only the
+ *                  first part of the line will be returned
+ * @param buffer    OUT: the line will be put here
+ * @param hasMore   true: the line was longer than <code>maxSize</code>, only
+ *                  the first part of the line is put into the <code>buffer</code>
+ * @return          false: no more input available<br>
+ *                  true: success
+ */
+bool ReStringReader::nextLine(int maxSize, QByteArray& buffer, bool& hasMore) {
+    bool rc = m_currentSourceUnit != NULL;
+    if (rc){
+        m_currentSourceUnit->setLineNo(m_currentSourceUnit->lineNo() + 1);
+        rc = fillBuffer(maxSize, buffer, hasMore);
+    }
+    return rc;
+}
+
+/**
+ * @brief Delivers the next part of a long line.
+ *
+ * @param maxSize   if the remaining line length is longer than this value,
+ *                  only the a part of the line will be returned
+ * @param buffer    OUT: the part of line will be put here
+ * @param hasMore   true: the line was longer than <code>maxSize</code>, only
+ *                  the first part of the line is put into the <code>buffer</code>
+ * @return          false: no more input available<br>
+ *                  true: success
+ */
+bool ReStringReader::fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore) {
+    ReStringSourceUnit* unit  = (ReStringSourceUnit*) m_currentSourceUnit;
+    ReSourceUnitContent content = unit->content();
+    int startPos = unit->currentPosition();
+    const char* start = content + startPos;
+    const char* end = strchr(start, '\n');
+    hasMore = false;
+    int size = end == NULL ? strlen(start) : end - start + 1;
+    hasMore = false;
+    if(size > maxSize) {
+        size = maxSize;
+        hasMore = true;
+    }
+    if(size > 0) {
+        buffer.append(start, size);
+        unit->setCurrentPosition(startPos + size);
+    } else {
+        removeSourceUnit();
+    }
+    return size > 0;
+}
+
+/**
+ * @brief Adds a source buffer to the reader
+ *
+ * @param name      name of the medium
+ * @param content
+ */
+void ReStringReader::addSource(ReSourceUnitName name,
+                                ReSourceUnitContent content) {
+    // Deletion in the destructor of the base class ReReader
+    ReStringSourceUnit* unit = new ReStringSourceUnit(name, content, this);
+    m_units.insert(m_units.begin(), unit->name(), unit);
+    m_currentSourceUnit = unit;
+}
+
+/**
+ * @brief Replaces the content of a source unit.
+ *
+ * @param name      name of the source unit
+ * @param content   new content
+ */
+void ReStringReader::replaceSource(ReSourceUnitName name,
+                                    ReSourceUnitContent content)
+{
+    if (m_units.contains(name)){
+        ReStringSourceUnit* unit = dynamic_cast<ReStringSourceUnit*>(m_units[name]);
+        unit->m_content = content;
+    }
+}
+
+/** @class ReFileSourceUnit ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Stores the state of a file based source unit.
+ *
+ * This is the mostly used implementation of the ReSourceUnit/ReReader.
+ */
+
+
+ReFileSourceUnit::ReFileSourceUnit(ReSourceUnitName filename,
+                                     ReFileReader* reader) :
+    ReSourceUnit(filename, reader),
+    m_currentPosition(0),
+    m_fp(fopen(filename, "r")),
+    m_textStream(m_fp, QIODevice::ReadOnly),
+    m_line()
+{
+}
+
+
+/**
+ * @brief Destructor.
+ */
+ReFileSourceUnit::~ReFileSourceUnit()
+{
+    fclose(m_fp);
+}
+
+bool ReFileSourceUnit::isOpen() const
+{
+    return m_fp != NULL;
+}
+/** @class ReFileReader ReSource.hpp "expr/ReSource.hpp"
+ *
+ * @brief Implements a source which provides reading from memory based buffers.
+ *
+ * Examples for usage: interactive input
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReFileReader::ReFileReader(ReSource& source) :
+    ReReader(source)
+{
+}
+
+/**
+ * @brief Destructor.
+ */
+ReFileReader::~ReFileReader() {
+}
+
+/**
+ * @brief Opens a new source unit.
+ *
+ * @param unit  name of the source
+ * @return      NULL: unknown source<br>
+ *              otherwise: an instance of a sub class of
+ *              <code>ReSourceUnit</code>
+ */
+ReSourceUnit* ReFileReader::openSourceUnit(ReSourceUnitName unit) {
+    ReSourceUnit* rc = NULL;
+    if(m_units.contains(unit)) {
+        rc = *m_units.find(unit);
+        m_currentSourceUnit = static_cast<ReFileSourceUnit*>(rc);
+    }
+    return rc;
+}
+/**
+ * @brief Delivers the next line from the input medium or the first part of it.
+ *
+ * @param maxSize   if the line length is longer than this value, only the
+ *                  first part of the line will be returned
+ * @param buffer    OUT: the line will be put here
+ * @param hasMore   true: the line was longer than <code>maxSize</code>, only
+ *                  the first part of the line is put into the <code>buffer</code>
+ * @return          false: no more input available<br>
+ *                  true: success
+ */
+bool ReFileReader::nextLine(int maxSize, QByteArray& buffer, bool& hasMore) {
+    ReFileSourceUnit* unit  = static_cast<ReFileSourceUnit*>
+            (m_currentSourceUnit);
+    bool rc = ! feof(unit->m_fp);
+    if(! rc) {
+        m_source.popSourceUnit(this);
+    } else {
+        m_currentSourceUnit->setLineNo(m_currentSourceUnit->lineNo() + 1);
+        unit->m_currentPosition = 0;
+        QByteArray& line = unit->m_line;
+        line.reserve(maxSize+1);
+        if (fgets(line.data(), maxSize, unit->m_fp) == NULL)
+            rc = false;
+        else{
+            line[maxSize] = '\0';
+            line.resize(strlen(line.constData()));
+            rc = fillBuffer(maxSize, buffer, hasMore);
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Delivers the next part of a long line.
+ *
+ * @param maxSize   if the remaining line length is longer than this value,
+ *                  only the a part of the line will be returned
+ * @param buffer    OUT: the part of line will be put here
+ * @param hasMore   true: the line was longer than <code>maxSize</code>, only
+ *                  the first part of the line is put into the <code>buffer</code>
+ * @return          false: no more input available<br>
+ *                  true: success
+ */
+bool ReFileReader::fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore) {
+    ReFileSourceUnit* unit  = static_cast<ReFileSourceUnit*>(m_currentSourceUnit);
+    int start = unit->m_currentPosition;
+    QByteArray& content = unit->m_line;
+    int size = content.size() - start;
+    if(size > maxSize)
+        size = maxSize;
+    buffer += content.mid(start, size);
+    unit->m_currentPosition = (start += size);
+    hasMore = start < content.size();
+    return size > 0;
+}
+
+/**
+ * @brief Adds a source file to the reader
+ *
+ * @param filename  the file' name (relative or absolute)
+ */
+void ReFileReader::addSource(ReSourceUnitName filename) {
+    // Deleting in ~ReSourceUnit():
+    ReFileSourceUnit* unit = new ReFileSourceUnit(filename, this);
+    m_units.insert(m_units.begin(), unit->name(), unit);
+    m_currentSourceUnit = unit;
+}
+
+
diff --git a/expr/ReSource.hpp b/expr/ReSource.hpp
new file mode 100644 (file)
index 0000000..cba5ea0
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLSOURCE_HPP
+#define RPLSOURCE_HPP
+
+// type of buffer names and filenames. Codec: UTF-8
+typedef const char* ReSourceUnitName;
+
+typedef const char*  ReSourceUnitContent;
+
+class ReSource;
+class ReReader;
+
+class ReSourceUnit {
+public:
+    ReSourceUnit(const char* name, ReReader* reader);
+    virtual ~ReSourceUnit();
+public:
+    const char* name() const;
+    int lineNo() const;
+    void setLineNo(int lineNo);
+    ReReader* reader() const;
+
+protected:
+    QByteArray m_name;
+    int m_lineNo;
+    ReReader* m_reader;
+};
+
+class ReSourcePosition {
+public:
+    ReSourcePosition();
+    ReSourcePosition(ReSourceUnit* unit, int lineNo, int colNo);
+    ~ ReSourcePosition();
+    void* operator new(size_t cbSize, void* buffer);
+private:
+    /// forbid usage of the copy constructor!
+    ReSourcePosition(const ReSourcePosition& source);
+    /// forbid usage of the the assignment!
+    ReSourcePosition& operator=(const ReSourcePosition& source);
+public:
+    ReString toString() const;
+    int lineNo() const;
+    void setLineNo(int lineNo);
+
+    int column() const;
+    void setColumn(int column);
+
+    ReSourceUnit* sourceUnit() const;
+    void setSourceUnit(ReSourceUnit* sourceUnit);
+    char*utf8(char buffer[], size_t bufferSize) const;
+private:
+    ReSourceUnit* m_sourceUnit;
+    int m_lineNo;
+    int m_column;
+    const ReSourcePosition* m_caller;
+};
+
+class ReReader {
+public:
+    typedef ReCharPtrMap<ReSourceUnit*> UnitMap;
+public:
+    ReReader(ReSource& source);
+    ~ReReader();
+public:
+    /**
+     * @brief Prepares the reading from a given source unit.
+     *
+     * @param unit  name of the unit
+     * @return      NULL: unit not known<br>
+     *              otherwise: an instance with the state of the reader
+     *              for the source. This is normally a sub class of
+     *              <code>ReSourceUnit</code>
+     */
+    virtual ReSourceUnit* openSourceUnit(const char* unit) = 0;
+    /**
+     * @brief Reads the first part of the next line into a given buffer.
+     *
+     * @param maxSize   the maximum length of the read input.
+     *                  If a line is longer the next part must be read
+     *                  by <code>fillBuffer()</code>
+     * @param buffer    IN/OUT: the read input will be appended here
+     * @param hasMore   OUT: true: the line is longer than maxSize
+     * @return          true: the read was successful<br>
+     *                  false: no more input is available
+     */
+    virtual bool nextLine(int maxSize, QByteArray& buffer, bool& hasMore) = 0;
+    /**
+     * @brief Reads the next part of the current line into a given buffer.
+     *
+     * @param maxSize   the maximum length of the read input.
+     * @param buffer    IN/OUT: the read input will be appended here
+     * @param hasMore   OUT: true: the rest of line is longer than maxSize
+     * @return          true: the read was successful<br>
+     *                  false: no more input is available
+     */
+    virtual bool fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore) = 0;
+public:
+    virtual void clear();
+    ReSource& source();
+    ReSourceUnit* currentSourceUnit() const;
+    bool setCurrentSourceUnit(ReSourceUnitName& currentSourceUnit);
+protected:
+    void removeSourceUnit();
+
+protected:
+    ReSourceUnit* m_currentSourceUnit;
+    /// name -> source
+    UnitMap m_units;
+    ReSource& m_source;
+};
+
+#define RPL_POSITIONS_PER_BLOCK 512
+class ReSourcePositionBlock{
+    friend class ReSource;
+public:
+    ReSourcePositionBlock();
+private:
+    ReSourcePositionBlock* m_successor;
+    char m_positions[RPL_POSITIONS_PER_BLOCK * sizeof(ReSourcePosition)];
+};
+
+class ReSource {
+public:
+    ReSource();
+    virtual ~ReSource();
+public:
+    virtual const char* permanentUnitName(const char* unit);
+    void finishSourceUnit();
+    void addReader(ReReader* reader);
+    void addSourceUnit(ReSourceUnit* unit);
+    QStack<const ReSourcePosition*> sourcePositionStack() const;
+    QStack<ReSourceUnit*>& sourceUnitStack();
+
+    bool startUnit(const char* unit, const ReSourcePosition& caller);
+    void pushSourceUnit(ReSourceUnit* unit);
+    ReSourceUnit* popSourceUnit(ReReader* reader);
+    ReReader* currentReader();
+    const ReSourcePosition* newPosition(int colNo);
+    void clear();
+    const ReSourcePosition* caller() const;
+protected:
+    void destroy();
+protected:
+    // stack of the info about the stacked (open) source units:
+    QStack<const ReSourcePosition*> m_sourcePositionStack;
+    ReSourcePositionBlock* m_sourcePositionBlock;
+    int m_countPositionBlock;
+    QList<ReReader*> m_readers;
+    QList<ReSourceUnit*> m_sourceUnits;
+    // setCurrentSourceUnit() pushes one entry, removeSourceUnit() pops it
+    // (when end of input has been reached).
+    QStack<ReSourceUnit*> m_unitStack;
+    ReReader* m_currentReader;
+};
+
+class ReStringReader;
+
+class ReStringSourceUnit : public ReSourceUnit {
+    friend class ReStringReader;
+public:
+    ReStringSourceUnit(ReSourceUnitName name,
+                        const ReSourceUnitContent& content,
+                        ReStringReader* reader);
+    virtual ~ReStringSourceUnit();
+public:
+    int currentPosition() const;
+    void setCurrentPosition(int currentPosition);
+    ReSourceUnitContent content() const;
+
+private:
+    int m_currentPosition;
+    QByteArray m_content;
+};
+
+class ReStringReader : public ReReader{
+public:
+    ReStringReader(ReSource& source);
+    virtual ~ReStringReader();
+    // ReReader interface
+public:
+    virtual ReSourceUnit* openSourceUnit(ReSourceUnitName unit);
+    virtual bool nextLine(int maxSize, QByteArray& buffer, bool& hasMore);
+    virtual bool fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore);
+public:
+    void addSource(ReSourceUnitName name, ReSourceUnitContent content);
+    void replaceSource(ReSourceUnitName name, ReSourceUnitContent content);
+};
+
+class ReFileReader;
+
+class ReFileSourceUnit : public ReSourceUnit {
+    friend class ReFileReader;
+public:
+    ReFileSourceUnit(ReSourceUnitName filename, ReFileReader* reader);
+    virtual ~ReFileSourceUnit();
+public:
+    bool isOpen() const;
+private:
+    int m_currentPosition;
+    FILE* m_fp;
+    QTextStream m_textStream;
+    QByteArray m_line;
+};
+
+class ReFileReader : public ReReader{
+public:
+    ReFileReader(ReSource& source);
+    virtual ~ReFileReader();
+    // ReReader interface
+public:
+    virtual ReSourceUnit* openSourceUnit(ReSourceUnitName unit);
+    virtual bool nextLine(int maxSize, QByteArray& buffer, bool& hasMore);
+    virtual bool fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore);
+public:
+    void addSource(ReSourceUnitName filename);
+};
+
+
+#endif // RPLSOURCE_HPP
diff --git a/expr/ReVM.cpp b/expr/ReVM.cpp
new file mode 100644 (file)
index 0000000..1a4e177
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+/** @file
+ *
+ * @brief Implements an interpreter of an abstract syntax tree.
+ */
+
+/** @file expr/ReVM.hpp
+ *
+ * @brief Definitions for an interpreter of an abstract syntax tree.
+ */
+
+#include "base/rebase.hpp"
+#include "expr/reexpr.hpp"
+
+enum {
+    LOC_VAL_OF_VAR_1 = LOC_FIRST_OF(LOC_VM), // 11401
+    LOC_UNOP_1,
+    LOC_UNOP_2,
+    LOC_UNOP_3,
+    LOC_UNOP_4, // 10005
+    LOC_BINOP_1,
+    LOC_COUNT
+};
+
+int ReVMThread::m_nextId = 1;
+
+/** @class ReVMException ReVM.hpp "expr/ReVM.hpp"
+ *
+ * @brief Implements an exception for the virtual machine.
+ *
+ */
+/**
+ * @brief Constructor
+ * @param format    the message with placeholders
+ * @param ...       the values for the placeholders
+ */
+ReVMException::ReVMException(const char* format, ...) :
+    ReException("")
+{
+    char buffer[16000];
+    va_list ap;
+    va_start(ap, format);
+    qvsnprintf(buffer, sizeof buffer, format, ap);
+    va_end(ap);
+    m_message = buffer;
+}
+
+/** @class ReStackFrame ReVM.hpp "expr/ReVM.hpp"
+ *
+ * @brief Implements the storage for a symbol space.
+ *
+ * The owner of a symbol space can be "global", a module, a class, or a method.
+ * Some symbol spaces have more than one stack frame, e.g. a recursive called
+ * method.
+ */
+
+
+/**
+ * @brief Constructor.
+ *
+ * @param symbols   the symbol space belonging to the stack frame
+ */
+
+ReStackFrame::ReStackFrame(ReASItem* caller, ReSymbolSpace* symbols) :
+    m_countVariables(symbols->listOfVars().size()),
+    m_variables(NULL),
+    m_symbols(symbols),
+    m_caller(caller)
+{
+    if (m_countVariables > 0)
+        m_variables = new ReASVariant[m_countVariables];
+}
+
+/**
+ * @brief Destructor.
+ */
+ReStackFrame::~ReStackFrame()
+{
+    delete[] m_variables;
+    m_variables = NULL;
+}
+
+/**
+ * @brief Returns the storage of a variable given by the index.
+ *
+ * @param index the index of the variable
+ *
+ * @return      the storage of the variable
+ */
+ReASVariant& ReStackFrame::valueOfVariable(int index)
+{
+    if (index < 0 || index >= m_countVariables)
+        throw ReVMException("valueOfVariable(): invalid index: %d", index);
+    return m_variables[index];
+}
+/**
+ * @brief Returns the symbol space of the frame.
+ *
+ * @return  the symbol space
+ */
+ReSymbolSpace* ReStackFrame::symbols() const
+{
+    return m_symbols;
+}
+
+/** @class ReVMThread ReVM.hpp "expr/ReVM.hpp"
+ *
+ * @brief Implements a thread of the virtual machine.
+ *
+ * The virtual machine can execute many threads at the same time.
+ * Each thread has its own stack.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param maxStack  the maximal number of nested stack frames
+ * @param vm        the parent, the virtual machine
+ */
+ReVMThread::ReVMThread(int maxStack, ReVirtualMachine* vm) :
+    m_id(m_nextId++),
+    m_debugMode(false),
+    m_singleStep(false),
+    m_tracing(false),
+    m_maxStack(maxStack),
+    m_frameStack(),
+    // the stack is never empty!
+    m_topOfFrames(0),
+    m_valueStack(),
+    // the stack is never empty!
+    m_topOfValues(0),
+    m_vm(vm),
+    m_logger(new ReLogger())
+{
+    QByteArray prefix = "vm_thread_" + QByteArray::number(m_id);
+    m_logger->buildStandardAppender(prefix);
+    m_frameStack.reserve(maxStack);
+    // the stack is never empty!
+    m_frameStack.append(new ReStackFrame(vm->tree().symbolSpaces()[0]));
+    // the stack is never empty!
+    m_valueStack.append(new ReASVariant);
+}
+
+/**
+ * @brief Executes a statement list.
+ *
+ * @param statements    the first statement of a statement list chained by
+ *                      <code>m_child</code>
+ * @param space         the current symbol space
+ */
+void ReVMThread::execute(ReASNode1* statements, ReSymbolSpace* space)
+{
+    bool debugMode = m_debugMode;
+    ReASNode1 *next;
+    while(statements != NULL){
+        if (debugMode
+                && (m_singleStep
+                    || (statements->flags() & ReASItem::NF_BREAKPOINT) != 0))
+            debug(statements);
+        ReASStatement* statement = dynamic_cast<ReASStatement*>(statements);
+        if (statement != NULL)
+            statement->execute(*this);
+        statements = dynamic_cast<ReASNode1*>(statements->child());
+    }
+}
+
+/**
+ * @brief Handles a debugger break.
+ *
+ * @param statement the current statement (not yet executed)
+ */
+void ReVMThread::debug(ReASNode1* statement)
+{
+
+}
+
+/**
+ * @brief Returns the logger of the instance.
+ *
+ * @return  the logger
+ */
+ReLogger* ReVMThread::logger() const
+{
+    return m_logger;
+}
+/**
+ * @brief Reserves a value in the thread's value stack.
+ *
+ * @return  the reserved value
+ */
+ReASVariant&ReVMThread::reserveValue()
+{
+    ReASVariant* rc;
+    if (++m_topOfValues < m_valueStack.size()){
+        rc = m_valueStack[m_topOfValues];
+        rc->destroyValue();
+    } else {
+        rc = new ReASVariant();
+        m_valueStack.append(rc);
+    }
+    return *rc;
+}
+
+/**
+ * @brief Returns the top of the value stack.
+ *
+ * @return  the top of the value stack
+ */
+ReASVariant& ReVMThread::topOfValues()
+{
+    ReASVariant& rc = *m_valueStack[m_topOfValues];
+    return rc;
+}
+
+
+/**
+ * @brief Returns the entry under the top of the value stack.
+ *
+ * @return  the 2nd value the value stack
+ */
+ReASVariant& ReVMThread::top2OfValues()
+{
+    ReASVariant& rc = *m_valueStack[m_topOfValues-1];
+    return rc;
+}
+
+/**
+ * @brief Returns the top of stack and removes it.
+ *
+ * @return the old top of stack
+ */
+ReASVariant& ReVMThread::popValue()
+{
+    ReASVariant& rc = *m_valueStack[m_topOfValues];
+    if (m_topOfValues > 0)
+        m_topOfValues--;
+    return rc;
+}
+
+/**
+ * @brief Copies a variable value to the top of the stack.
+ *
+ * @param symbolSpace   the symbol space of the variable
+ * @param variableNo    the current no of the variable in the symbol space
+ */
+void ReVMThread::valueToTop(ReSymbolSpace* symbolSpace, int variableNo)
+{
+    //@ToDo
+}
+
+/**
+ * @brief Returns the "left value" (of an assignment).
+ * @param item
+ * @return
+ */
+ReASVariant& ReVMThread::lValue(ReASItem* item)
+{
+    ReASVariant* rc;
+    switch(item->nodeType()){
+    case AST_NAMED_VALUE:
+    {
+        ReASNamedValue* var = dynamic_cast<ReASNamedValue*>(item);
+        rc = &valueOfVariable(var->symbolSpace(), var->variableNo());
+        break;
+    }
+    default:
+        break;
+    }
+    return *rc;
+}
+
+/**
+ * @brief Returns the reference of the value of a variable.
+ *
+ * @param symbolSpace   the symbol space
+ * @param variableNo    the current number in the symbol space
+ * @return
+ */
+ReASVariant& ReVMThread::valueOfVariable(ReSymbolSpace* symbolSpace,
+                                          int variableNo)
+{
+    ReASVariant& rc = *m_valueStack[0];
+    int ix = m_topOfFrames;
+    ReStackFrame* frame = NULL;
+    for(int ix = m_topOfFrames; ix >= 0; ix--){
+        frame = m_frameStack[ix];
+        if (frame->symbols() == symbolSpace){
+            rc = frame->valueOfVariable(variableNo);
+            break;
+        }
+    }
+    if (frame == NULL)
+        m_logger->logv(LOG_ERROR, LOC_VAL_OF_VAR_1, "no frame has symbolspace %s",
+                      symbolSpace->name().constData());
+
+    return rc;
+}
+/**
+ * @brief Returns whether each execution step should be dumped.
+ * @return  true: tracing is on<br>
+ *          false: otherwise
+ */
+bool ReVMThread::tracing() const
+{
+    return m_tracing;
+}
+
+/**
+ * @brief Sets the tracing flag: if set each execution step is dumped.
+ * @param tracing   true: tracing will be done<br>
+ *                  false: tracing will not be done
+ */
+void ReVMThread::setTracing(bool tracing)
+{
+    m_tracing = tracing;
+}
+
+/**
+ * @brief Returns the parent, a virtual machine.
+ *
+ * @return  the virtual machine
+ */
+ReVirtualMachine* ReVMThread::vm() const
+{
+    return m_vm;
+}
+
+/**
+ * @brief Adds a frame to the frame stack.
+ *
+ * @param frame     frame to add
+ */
+void ReVMThread::pushFrame(ReStackFrame* frame)
+{
+    if (m_frameStack.size() >= m_maxStack)
+        throw ReASException(NULL, "too deep recursion: %d", m_maxStack);
+    m_frameStack.push_back(frame);
+}
+
+/**
+ * @brief Removes the top of the frames from the stack.
+ */
+void ReVMThread::popFrame()
+{
+    if (m_frameStack.size() <= 0)
+        throw ReASException(NULL, "frame stack is empty");
+    m_frameStack.pop_back();
+}
+
+/** @class ReVirtualMachine ReVM.hpp "expr/ReVM.hpp"
+ *
+ * @brief Implements a virtual machine.
+ *
+ * This is an execution unit which interprets an abstract syntax tree.
+ */
+ReVirtualMachine::ReVirtualMachine(ReASTree& tree, ReSource& source,
+                                     int maxStack) :
+    m_maxStack(maxStack),
+    m_threads(),
+    m_flags(VF_UNDEF),
+    m_source(source),
+    m_tree(tree),
+    m_trace()
+{
+    m_threads.reserve(8);
+    m_trace.reserve(1024);
+}
+
+/**
+ * @brief Executes the program in a module.
+ *
+ * @param module    the module's name
+ */
+void ReVirtualMachine::executeModule(const char* module)
+{
+    ReSymbolSpace* space = m_tree.findmodule(module);
+    if (space == NULL)
+        throw ReVMException("module not found: %s", module);
+    ReStackFrame frame(space);
+    ReSymbolSpace* mainSpace = NULL;
+    ReASItem* mainStatements = NULL;
+    ReASMethod* method = space->findMethod("main");
+    if (method != NULL){
+        mainStatements = method->child();
+        mainSpace = method->symbols();
+    }
+    addThread(space->body(), space, mainStatements, mainSpace);
+}
+
+/**
+ * @brief Adds a thread to the instance.
+ *
+ * @param initialization        the statements for initialization
+ * @param spaceInitialization   the symbol space of the initialization
+ * @param statements            the statement list to execute. This is normally
+ *                              the body of the main program
+ * @param space                 the symbol space of the statements, normally
+ *                              the symbol space of the main program
+ * @param maxStack  the maximal number of nested stack frames.
+ *                  <= 0: use the default
+ */
+void ReVirtualMachine::addThread(ReASItem* initialization,
+                                  ReSymbolSpace* spaceInitialization,
+                                  ReASItem* statements,
+                                  ReSymbolSpace* space,
+                                  int maxStack)
+{
+    ReVMThread* thread = new ReVMThread(
+                maxStack <= 0 ? m_maxStack : maxStack, this);
+    m_threads.append(thread);
+    if (initialization != NULL){
+        thread->execute(dynamic_cast<ReASNode1*>(initialization),
+                        spaceInitialization);
+    }
+    if (statements != NULL)
+        thread->execute(dynamic_cast<ReASNode1*>(statements), space);
+}
+/**
+ * @brief Tests whether a given flag is set.
+ *
+ * @param flag      flag to test
+ * @return          true: the flag is set<br>
+ *                  false: otherwise
+ */
+bool ReVirtualMachine::hasFlag(ReVirtualMachine::VMFlag flag) const
+{
+    bool rc = (m_flags & flag) != 0;
+    return rc;
+}
+/**
+ * @brief Adds a flag to the current flags.
+ *
+ * @param flag
+ * @return
+ */
+void ReVirtualMachine::setFlag(ReVirtualMachine::VMFlag flag)
+{
+    m_flags |= flag;
+}
+
+/**
+ * @brief Adds a flag to the current flags.
+ *
+ * @param flag
+ * @return
+ */
+void ReVirtualMachine::clearFlag(ReVirtualMachine::VMFlag flag)
+{
+    m_flags &= ~flag;
+}
+
+/**
+ * @brief Returns the trace writer.
+ * @return  the trace writer
+ */
+ReWriter* ReVirtualMachine::traceWriter() const
+{
+    return m_traceWriter;
+}
+
+/**
+ * @brief Sets the trace writer.
+ *
+ * @param traceWriter   the new writer
+ */
+void ReVirtualMachine::setTraceWriter(ReWriter* traceWriter)
+{
+    m_traceWriter = traceWriter;
+}
+/**
+ * @brief Returns the abstract symbol tree.
+ *
+ * @return  the abstract symbol tree
+ */
+ReASTree& ReVirtualMachine::tree() const
+{
+    return m_tree;
+}
+
diff --git a/expr/ReVM.hpp b/expr/ReVM.hpp
new file mode 100644 (file)
index 0000000..938a1a4
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef ReVM_HPP
+#define ReVM_HPP
+
+class ReVMException : public ReException {
+public:
+    ReVMException(const char* message, ...);
+};
+class ReStackFrame {
+public:
+    ReStackFrame(ReASItem* caller, ReSymbolSpace* symbols);
+    ~ReStackFrame();
+public:
+    ReASVariant& valueOfVariable(int index);
+    ReSymbolSpace* symbols() const;
+
+private:
+    int m_countVariables;
+    ReASVariant* m_variables;
+    ReSymbolSpace* m_symbols;
+    ReASItem* m_caller;
+};
+
+class ReVirtualMachine;
+class ReVMThread
+{
+    friend class ReASItem;
+    friend class ReASStatement;
+    friend class ReASCalculable;
+    friend class ReASCondition;
+public:
+    typedef QList<ReStackFrame*> StackFrameList;
+public:
+    ReVMThread(int maxStack, ReVirtualMachine* vm);
+public:
+    void execute(ReASNode1* statements, ReSymbolSpace* space);
+    virtual void debug(ReASNode1* statement);
+    ReWriter* errorWriter() const;
+    void setErrorWriter(ReWriter* errorWriter);
+    ReLogger* logger() const;
+    ReASVariant& reserveValue();
+    ReASVariant& topOfValues();
+    ReASVariant& top2OfValues();
+    ReASVariant& popValue();
+    void valueToTop(ReSymbolSpace* symbolSpace, int variableNo);
+    ReASVariant& lValue(ReASItem* item);
+    ReASVariant& valueOfVariable(ReSymbolSpace* symbolSpace, int variableNo);
+    bool tracing() const;
+    void setTracing(bool tracing);
+    ReVirtualMachine* vm() const;
+    void pushFrame(ReStackFrame* frame);
+    void popFrame();
+
+protected:
+    int m_id;
+    bool m_debugMode;
+    bool m_singleStep;
+    bool m_tracing;
+    int m_maxStack;
+    StackFrameList m_frameStack;
+    int m_topOfFrames;
+    QList<ReASVariant*> m_valueStack;
+    int m_topOfValues;
+    ReVirtualMachine* m_vm;
+    ReLogger* m_logger;
+private:
+    static int m_nextId;
+};
+
+class ReVirtualMachine
+{
+public:
+    enum VMFlag {
+        VF_UNDEF,
+        VF_TRACE_STATEMENTS     = 1<<1,
+        VF_TRACE_LOCALS         = 1<<2,
+        VF_TRACE_AUTO_VARIABLES = 1<<3
+
+    };
+    typedef QList<const char*> LineList;
+public:
+    ReVirtualMachine(ReASTree& tree, ReSource& source, int maxStack = 1024);
+public:
+    void executeModule(const char* module);
+    void addThread(ReASItem* initialization,
+                   ReSymbolSpace* spaceInitialization,
+                   ReASItem* statements, ReSymbolSpace* space,
+                   int maxStack = 0);
+    bool hasFlag(VMFlag flag) const;
+    void setFlag(VMFlag flag);
+    void clearFlag(VMFlag flag);
+    ReWriter* traceWriter() const;
+    void setTraceWriter(ReWriter* traceWriter);
+    ReASTree& tree() const;
+
+private:
+    int m_maxStack;
+    QList<ReVMThread*> m_threads;
+    int m_flags;
+    ReSource& m_source;
+    ReASTree& m_tree;
+    LineList m_trace;
+    ReWriter* m_traceWriter;
+};
+
+#endif // ReVM_HPP
diff --git a/expr/reexpr.hpp b/expr/reexpr.hpp
new file mode 100644 (file)
index 0000000..3cb43d5
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLEXPR_HPP
+#define RPLEXPR_HPP
+
+#include <QStack>
+#include <QRegularExpression>
+#include <QFile>
+#include <QTextStream>
+#include <QDir>
+#include <QtAlgorithms>
+#include <QVariant>
+
+#include "rplexpr/rplsource.hpp"
+#include "rplexpr/rpllexer.hpp"
+#include "rplexpr/rplastree.hpp"
+#include "rplexpr/ReVM.hpp"
+#include "rplexpr/rplparser.hpp"
+#include "rplexpr/rplmfparser.hpp"
+
+#endif // RPLEXPR_HPP
diff --git a/math/ReEnigma.cpp b/math/ReEnigma.cpp
new file mode 100644 (file)
index 0000000..f575f43
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ *
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+/** @file
+ *
+ * @brief Implements encryption and decryption engines.
+ */
+/** @file math/ReEnigma.hpp
+ *
+ * @brief Definitions for encryption and decryption engines.
+ */
+
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+
+/** @class ReEnigma::secret_t ReEnigma.hpp "math/ReEnigma.hpp"
+ *
+ * @brief Stores the internal structure of a <b>secret</b>.
+ *
+ * A secret can be a password, a salt, a certificate or simlar
+ * which makes an encryption individually.
+ */
+/** @class ReEnigma ReEnigma.hpp "math/ReEnigma.hpp"
+ *
+ * @brief Implements a portable en/decryption engine.
+ *
+ * It is used a symetric encryption.
+ * Therefore the encrypt methods can be used for decryption too.
+ *
+ * The encryption can be unique by using certificates.
+ * A certificate is a series of bytes affecting the pseudo random sequence.
+ *
+ * More than one certificate can be used.
+ *
+ * The encryption is done with an pseudo random generator.
+ *
+ * The portability (over byte order) is guaranteed if the
+ * pseudo random generator is portable (nomalizing big/little endian)
+ * and a 64 bit integer arithmetic is available.
+ *
+ */
+const char* ReEnigma::SET_DECIMALS = "0123456789";
+const char* ReEnigma::SET_HEXDIGITS = "0123456789abcdef";
+const char* ReEnigma::SET_ALPHANUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                      "abcdefghijklmnopqrstuvwxyz_";
+const char* ReEnigma::SET_FILENAME = " !^°$%&=+~#-.0123456789ABCDEFGHIJKLM"
+                                      "NOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
+const char* ReEnigma::SET_32_127 = " !\"#$%&'()*+,-./0123456789:;<=>?@"
+                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f";
+const char* ReEnigma::SET_32_255 = " !\"#$%&'()*+,-./0123456789:;<=>?@"
+                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
+                                    "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                                    "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                                    "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                                    "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
+const char* ReEnigma::SET_PRINTABLE_127 =
+    "\t\r\n !\"#$%&'()*+,-./0123456789:;<=>?@"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f";
+const char* ReEnigma::SET_PRINTABLE_255 =
+    "\t\r\n !\"#$%&'()*+,-./0123456789:;<=>?@"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
+    "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+    "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+    "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+    "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
+
+/**
+ * @brief Constructor.
+ *
+ * @param random    pseudo random generator
+ */
+ReEnigma::ReEnigma(ReRandom* random) :
+    m_random(random),
+    m_ownsRandom(false),
+    m_secrets(),
+    m_randomCalls(0),
+    m_randomSource("4711") {
+    m_randomSource.reserve(8096);
+    if(random == NULL) {
+        m_random = new ReRandom();
+        m_ownsRandom = true;
+    }
+}
+/**
+ * @brief Destructor.
+ */
+ReEnigma::~ReEnigma() {
+    if(m_ownsRandom) {
+        delete m_random;
+        m_random = NULL;
+    }
+}
+
+/**
+ * @brief Reads a certificate.
+ *
+ * @param filename      the name of the certificate
+ *
+ * @return              empty string: error while reading<br>
+ *                      otherwise: the certificate as byte array
+ */
+QByteArray ReEnigma::readCertificate(const char* filename) {
+    QByteArray rc = "not implemented: readCertificate(): ";
+    rc += filename;
+    assert(rc.isEmpty());
+    return rc;
+}
+
+inline void buildBooster(QByteArray& booster, const char* charSet) {
+    int size = 257;
+    booster.fill(0, size);
+    int ix = 0;
+    unsigned char cc;
+    while((cc = (unsigned char) *charSet++) != '\0') {
+        booster[cc] = ++ix;
+    }
+    booster[0] = ix;
+}
+
+/**
+ * @brief Encodes a string in place with a given character set.
+ *
+ * If a character of data is not included in the character set
+ * it remains unchanged
+ *
+ * @param data      IN: data to encode<br>
+ *                  OUT: data encoded
+ * @param size      length of <code>data</code>. If 0
+ * @param charSet   a string containing all valid characters
+ * @param booster   a performance booster. Once built it can be shared
+ *                  between all calls of encodeChar() and decodeChar()
+ *                  with the same character set<br>
+ *                  IN: "": not initialized otherwise: ready for work
+ *                  OUT: ready for work
+ */
+void ReEnigma::encode(char* data, int size, const char* charSet,
+                       QByteArray& booster) {
+    if(booster.length() == 0) {
+        buildBooster(booster, charSet);
+    }
+    int lengthOfCharSet = (int)(unsigned char) booster.at(0);
+    for(int ii = 0; ii < size; ii++) {
+        unsigned char cc = (unsigned char) data[ii];
+        int ix = booster.at(cc);
+        if(ix != 0) {
+            int next = nextInt(lengthOfCharSet);
+            int ix2 = (ix - 1 + next) % lengthOfCharSet;
+            data[ii] = charSet[ix2];
+        }
+    }
+}
+
+/**
+ * @brief Decodes a string in place with a given character set.
+ *
+ * If a character of data is not included in the character set
+ * it remains unchanged
+ *
+ * @param data      IN: data to decode<br>
+ *                  OUT: data decoded
+ * @param size      length of <code>data</code>. If 0
+ * @param charSet   a string containing all valid characters
+ * @param booster   a performance booster. Once built it can be shared
+ *                  between all calls of encodeChar() and decodeChar()
+ *                  with the same character set<br>
+ *                  IN: "": not initialized otherwise: ready for work
+ *                  OUT: ready for work
+ */
+void ReEnigma::decode(char* data, int size, const char* charSet,
+                       QByteArray& booster) {
+    if(booster.length() == 0) {
+        buildBooster(booster, charSet);
+    }
+    int lengthOfCharSet = (int)(unsigned char) booster.at(0);
+    for(int ii = 0; ii < size; ii++) {
+        unsigned char cc = (unsigned char) data[ii];
+        int ix = booster.at(cc);
+        if(ix != 0) {
+            int next = nextInt(lengthOfCharSet);
+            int ix2 = (lengthOfCharSet + ix -1 - next) % lengthOfCharSet;
+            data[ii] = charSet[ix2];
+        }
+    }
+}
+/**
+ * @brief Encodes or decode a byte array.
+ *
+ * The encoding method is symetric. Therefore it can encode and decode.
+ *
+ * @param data      IN: data to encode/decoded<br>
+ *                  OUT: data encoded/decoded
+ */
+void ReEnigma::change(QByteArray& data) {
+    int randomLength = m_randomSource.length();
+    for(int ix = data.length() - 1; ix >= 0; ix--) {
+        char item = data.at(ix);
+        item = (item ^ nextInt(0xff) ^ m_randomSource.at(ix % randomLength));
+        data[ix] = item;
+    }
+}
+
+/**
+ * @brief Adds a random source given by an byte array.
+ *
+ * A random source can be the binary form of an certificate,
+ * a salt, a password or similar.
+ *
+ * @param byteSecret  a byte sequence which influences the random generation
+ */
+void ReEnigma::addByteSecret(QByteArray byteSecret) {
+    // we expand it to a multiple of 64 bit:
+    int oldSize = byteSecret.length();
+    int newSize = (oldSize + 7) / 8 * 8;
+    int ix;
+    if(newSize > oldSize) {
+        byteSecret.resize(newSize);
+        int sum = 0;
+        int start = oldSize > 8 ? oldSize - 8 : 0;
+        for(ix = start; ix < oldSize; ix++) {
+            sum += ix + byteSecret.at(ix);
+        }
+        for(ix = oldSize; ix < newSize; ix++) {
+            sum += ix + 7;
+            byteSecret[ix] = (char)(sum + byteSecret.at(ix-1));
+        }
+    }
+    int count = newSize / 8;
+    secret_t* secret = new secret_t();
+    secret->m_count = count;
+    secret->m_list = new uint64_t[count];
+    m_secrets.append(secret);
+    for(ix = 0; ix < count; ix++) {
+        uint64_t value = 0;
+        for(int ix2 = 0; ix2 < 8; ix2++)
+            value = (value << 8) + byteSecret.at(ix * 8 + ix2);
+        secret->m_list[ix] = value;
+    }
+    QByteArray value;
+    QCryptographicHash hash(QCryptographicHash::Md5);
+    ReRandom rand;
+    hash.addData(m_randomSource.constData(), 4);
+    for(ix = 0; ix < byteSecret.length(); ix++) {
+        hash.addData(byteSecret.constData() + ix, 1);
+        QByteArray current = hash.result();
+        int ix2 = rand.nextInt(0, m_randomSource.length() - 1);
+        m_randomSource[ix2] = (m_randomSource.at(ix2) ^ current.at(0));
+        m_randomSource.insert(0, current);
+    }
+}
+
+/**
+ * @brief Returns the next random integer
+ * @param maxValue
+ * @return
+ */
+int ReEnigma::nextInt(int maxValue) {
+    uint64_t seed = 0;
+    QList<secret_t*>::const_iterator it;
+    int ixSecret = m_randomCalls++;
+    int ix = ixSecret;
+    for(it = m_secrets.constBegin(); it != m_secrets.constEnd(); ++it) {
+        secret_t* secret = *it;
+        seed |= ((secret->m_list[ixSecret % secret->m_count]) >> (ix % 8));
+    }
+    m_random->xorSeed(seed);
+    int rc = m_random->nextInt(0, maxValue);
+    return rc;
+}
+
+/**
+ * @brief Sets the pseudo random to a define state.
+ *
+ * @param seed  the initial state
+ */
+void ReEnigma::setSeed(uint64_t seed) {
+    m_random->setSeed(seed);
+    m_randomCalls = 0;
+}
+
diff --git a/math/ReEnigma.hpp b/math/ReEnigma.hpp
new file mode 100644 (file)
index 0000000..1f252c4
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef RPLENIGMA_HPP
+#define RPLENIGMA_HPP
+
+class ReEnigma {
+public:
+    ///> '0'..'9'
+    static const char* SET_DECIMALS;
+    ///> '0'..'9' 'a'..'f'
+    static const char* SET_HEXDIGITS;
+    ///> '0'..'9' 'A'..'Z' a'..'z' '_'
+    static const char* SET_ALPHANUM;
+    ///> '0'..'9' 'A'..'Z' z'..'z' '_'
+    static const char* SET_FILENAME;
+    ///> ' ' .. chr(127)
+    static const char* SET_32_127;
+    ///> ' ' .. chr(255)
+    static const char* SET_32_255;
+    ///> TAB, CR, NL, ' '..chr(127)
+    static const char* SET_PRINTABLE_127;
+    ///> TAB, CR, NL, ' '..chr(255)
+    static const char* SET_PRINTABLE_255;
+
+protected:
+    typedef struct {
+        int m_count;
+        uint64_t* m_list;
+    } secret_t;
+public:
+    ReEnigma(ReRandom* random = NULL);
+    virtual ~ReEnigma();
+private:
+    // No copy constructor: no implementation!
+    ReEnigma(const ReEnigma& source);
+    // Prohibits assignment operator: no implementation!
+    ReEnigma& operator =(const ReEnigma& source);
+public:
+    void encode(char* data, int size, const char* charSet, QByteArray& cache);
+    void decode(char* data, int size, const char* charSet, QByteArray& cache);
+    void change(QByteArray& data);
+    void addByteSecret(QByteArray byteSeed);
+    void setSeed(uint64_t seed);
+    QByteArray readCertificate(const char* filename);
+protected:
+    int nextInt(int maxValue);
+
+protected:
+    ///> a pseudo random generator
+    ReRandom* m_random;
+    ///> true: m_random must be destroyed (in the destructor).
+    bool m_ownsRandom;
+    ///> This values will be mixed with <code>m_random</code>' seed
+    QList<secret_t*> m_secrets;
+    ///> each call of setSeed sets this value to 0.
+    int m_randomCalls;
+    ///> a byte sequence derived from the secrets
+    QByteArray m_randomSource;
+};
+
+#endif // RPLENIGMA_HPP
diff --git a/math/ReMatrix.cpp b/math/ReMatrix.cpp
new file mode 100644 (file)
index 0000000..626fe26
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * RplMatrix.cpp
+ *
+ *  Created on: 29.05.2014
+ *      Author: hm
+ */
+
+/** @file
+ * @brief Implements 2 dimensional matrices.
+ */
+/** @file rplmath/rplmatrix.hpp
+ *
+ * @brief Definitions for 2 dimensional matrices.
+ */
+
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+
+RplMatrixException::RplMatrixException(const RplMatrix& RplMatrix,
+        const char* format, ...) :
+    ReException()
+{
+    if (! RplMatrix.getName().isEmpty())
+        m_message = RplMatrix.getName() + ": ";
+    char buffer[16*1024];
+
+    va_list args;
+    va_start(args, format);
+    qvsnprintf(buffer, sizeof buffer, format, args);
+    va_end(args);
+    m_message += buffer;
+}
+
+/**
+ * Constructor.
+ */
+RplMatrix::RplMatrix(const char* name) :
+    m_rows(0),
+    m_cols(0),
+    m_values(NULL),
+    m_name(name)
+{
+}
+
+/**
+ * Constructor.
+ *
+ * @param rows         number of rows
+ * @param cols         number of columns
+ * @param name      the name of the matrix
+ */
+RplMatrix::RplMatrix(int rows, int cols, const char* name):
+            m_rows(rows),
+            m_cols(cols),
+            m_values(new MatVal[rows*cols]),
+            m_name(name)
+{
+}
+/**
+ * Destructor.
+ */
+RplMatrix::~RplMatrix() {
+    delete m_values;
+    m_values = NULL;
+}
+
+/**
+ * Copy constructor.
+ *
+ * @param source       source to copy
+ */
+RplMatrix::RplMatrix(const RplMatrix& source) :
+    m_rows(0),
+    m_cols(0),
+    m_values(NULL),
+    m_name(source.m_name + QByteArray("-copy"))
+{
+    resize(source.m_rows, source.m_cols, source.m_values);
+}
+
+/**
+ * Checks the validity of the definition parameters.
+ *
+ * @param rows         the row number
+ * @param cols         the column number
+ * @throws RplMatrixException
+ */
+void RplMatrix::checkDefinition(int rows, int cols) const
+{
+    if (rows < 0)
+        throw RplMatrixException(*this, "row number negative: %d", rows);
+    if (cols < 0)
+        throw RplMatrixException(*this, "column number negative: %d", cols);
+    if (double(rows) * cols > 1.0*1000*1000)
+        throw RplMatrixException(*this, "too many elements: %d*%d", rows, cols);
+}
+
+/**
+ * Checks the validity of the indexes.
+ *
+ * @param row  the RplMatrix row number: 0..N-1
+ * @param col  the RplMatrix column number: 0..M-1
+ * @throws RplMatrixException
+ */
+void RplMatrix::check(int row, int col) const
+{
+    if (row < 0 || row >= m_rows)
+        throw RplMatrixException(*this, "invalid row: %d not in [0,%d[", row,
+                m_rows);
+    if (col < 0 || col >= m_cols)
+        throw RplMatrixException(*this, "invalid column: %d not in [0,%d[", col,
+                m_cols);
+}
+/**
+ * Checks whether a given Matrix has the same dimensions.
+ *
+ * @param operand      Matrix to compare
+ * @throws RplMatrixException
+ */
+void RplMatrix::checkSameDimension(const RplMatrix& operand) const
+{
+    if (m_rows != operand.getRows())
+        throw RplMatrixException(*this,
+                "%s has a different row count: %d / %d",
+                 operand.getName().constData(), m_rows, operand.getRows());
+    if (m_cols != operand.getCols())
+        throw RplMatrixException(*this,
+                "%s has a different column count: %d / %d",
+                operand.getName().constData(), m_cols, operand.getCols());
+}
+
+/**
+ * Assignment operator.
+ *
+ * @param source       the source to copy
+ */
+RplMatrix& RplMatrix::operator =(const RplMatrix& source)
+{
+    resize(source.m_rows, source.m_cols, source.m_values);
+    return *this;
+}
+/**
+ * Adds a Matrix to the instance.
+ *
+ * @param operand      Matrix to add
+ * @return                     the instance itself
+ */
+RplMatrix& RplMatrix::operator +=(const RplMatrix& operand)
+{
+    checkSameDimension(operand);
+    for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
+        m_values[ix] += operand.m_values[ix];
+    }
+    return *this;
+}
+/**
+ * Subtracts a matrix from the instance.
+ *
+ * @param operand      matrix to subtract
+ * @return                     the instance itself
+ */
+RplMatrix& RplMatrix::operator -=(const RplMatrix& operand)
+{
+    checkSameDimension(operand);
+    for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
+        m_values[ix] -= operand.m_values[ix];
+    }
+    return *this;
+}
+/**
+ * Builds the sum of the instance and a given matrix.
+ *
+ * @param operand      RplMatrix to add
+ * @return                     a new RplMatrix with the sum
+ */
+RplMatrix RplMatrix::operator +(const RplMatrix& operand)
+{
+    RplMatrix rc(*this);
+    rc += operand;
+    return rc;
+}
+/**
+ * Builds the difference of the instance and a given matrix.
+ *
+ * @param operand      matrix to subtract
+ * @return                     a new matrix with the difference
+ */
+RplMatrix RplMatrix::operator -(const RplMatrix& operand)
+{
+    RplMatrix rc(*this);
+    rc -= operand;
+    return rc;
+}
+/**
+ * Adds a scalar to the instance.
+ *
+ * @param scalar       scalar to add
+ * @return                     the instance itself
+ */
+RplMatrix& RplMatrix::operator +=(MatVal scalar)
+{
+    for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
+        m_values[ix] += scalar;
+    }
+    return *this;
+}
+/**
+ * Adds a scalar to the instance.
+ *
+ * @param scalar       scalar to add
+ * @return                     the instance itself
+ */
+RplMatrix& RplMatrix::operator -=(MatVal scalar)
+{
+    for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
+        m_values[ix] -= scalar;
+    }
+    return *this;
+}
+/**
+ * Builds the sum of the instance and a given scalar.
+ *
+ * @param scalar       scalar to add
+ * @return                     a new matrix with the sum
+ */
+RplMatrix RplMatrix::operator +(MatVal scalar)
+{
+    RplMatrix rc(*this);
+    rc += scalar;
+    return rc;
+}
+/**
+ * Builds the difference of the instance and a given scalar.
+ *
+ * @param scalar       scalar to subtract
+ * @return                     a new matrix with the sum
+ */
+RplMatrix RplMatrix::operator -(MatVal scalar)
+{
+    RplMatrix rc(*this);
+    rc -= scalar;
+    return rc;
+}
+/**
+ * Tests the equiness of the instance with a given matrix.
+ *
+ * @param operand      the matrix to compare
+ * @return                     true: the matrices are equal<br>
+ *                                     false: otherwise
+ */
+bool RplMatrix::operator ==(const RplMatrix& operand) const
+{
+    checkSameDimension(operand);
+    bool rc = true;
+    for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
+        if (m_values[ix] != operand.m_values[ix]){
+                rc = false;
+                break;
+            }
+    }
+    return rc;
+}
+/**
+ * Compares the instance with a given scalar.
+ *
+ * @param scalar       the scalar to compare
+ * @return                     true: all elements are equal to the scalar<br>
+ *                                     false: otherwise
+ */
+bool RplMatrix::operator ==(MatVal scalar) const
+{
+    bool rc = true;
+    for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
+        if (m_values[ix] != scalar){
+                rc = false;
+                break;
+            }
+    }
+    return rc;
+}
+/**
+ * Sets a new row-column pair.
+ */
+RplMatrix& RplMatrix::resize(int rows, int cols, const MatVal values[],
+        MatVal defaultValue)
+{
+    checkDefinition(rows, cols);
+    if (rows != m_rows || cols != m_cols){
+        delete m_values;
+        m_values = new MatVal[rows * cols];
+        m_rows = rows;
+        m_cols = cols;
+    }
+    if (values == NULL)
+    {
+        for (int ix = rows*cols - 1; ix >= 0; ix--){
+            m_values[ix] = defaultValue;
+        }
+    } else {
+        for (int ix = rows*cols - 1; ix >= 0; ix--){
+            m_values[ix] = values[ix];
+        }
+    }
+    return *this;
+}
+/**
+ * Returns the minimum and the maximum of the instance.
+ *
+ * @return             a tuple with the minimum and the maximum
+ */
+Tuple2 RplMatrix::minMax() const
+{
+#ifndef DBL_MAX
+#define DBL_MAX std::numeric_limits<qreal>::max()
+#define DBL_MIN std::numeric_limits<qreal>::min()
+#endif
+    Tuple2 rc(DBL_MAX, DBL_MIN);
+
+    for (int ix = m_rows*m_cols - 1; ix >= 0; ix--){
+        MatVal x;
+        if ( (x = m_values[ix]) < rc.m_value1)
+            rc.m_value1 = x;
+        if (x > rc.m_value2)
+            rc.m_value2 = x;
+    }
+    return rc;
+}
+
+/**
+ * Builds a matrix with exchanged rows and cols.
+ *
+ * @return     the transposed matrix
+ */
+RplMatrix RplMatrix::transpose() const
+{
+    RplMatrix rc(m_cols, m_rows);
+
+    for (int row = 0; row < m_rows; row++){
+        for (int col = 0; col < m_cols; col++){
+            rc.m_values[m_rows*col + row] = m_values[row * m_cols + col];
+        }
+    }
+    return rc;
+}
+QByteArray RplMatrix::toString(const char* prefix, const char* format,
+        const char* rowSeparator, const char* colSeparator) const
+{
+    char buffer[128];
+    Tuple2 minMaxi(minMax());
+    QByteArray rc;
+    qsnprintf(buffer, sizeof buffer, format, minMaxi.m_value1);
+    int length = strlen(buffer);
+    qsnprintf(buffer, sizeof buffer, format, minMaxi.m_value2);
+    int length2 = strlen(buffer);
+    if (length < length2)
+        length = length2;
+    qsnprintf(buffer, sizeof buffer, format,
+            (minMaxi.m_value1 + minMaxi.m_value2) / 2);
+    length2 = strlen(buffer);
+    if (length < length2)
+        length = length2;
+    if (prefix == NULL)
+        prefix = "";
+    length = m_rows * m_cols * (length + strlen(colSeparator))
+            + m_rows * strlen(rowSeparator) + strlen(prefix) + 20;
+    rc.reserve(length);
+    rc += prefix;
+    rc += "[";
+    for (int row = 0; row < m_rows; row++){
+        for (int col = 0; col < m_cols; col++){
+            qsnprintf(buffer, sizeof buffer, format, m_values[m_cols*row + col]);
+            rc += buffer;
+            rc += colSeparator;
+        }
+        rc += rowSeparator;
+    }
+    rc += "]";
+    return rc;
+}
+/**
+ * Finds the length of a column.
+ *
+ * @param text         the text to inspect
+ * @param separator    the column separator
+ * @return                     the count of chars between start and the next separator
+ */
+static int lengthOfColumn(const char* text, char separator){
+    const char* ptr = text;
+    while(*ptr == ' ')
+        ptr++;
+    char delimiter = 0;
+    if (*ptr == '"' || *ptr == '\''){
+        delimiter = *ptr++;
+    }
+    while(*ptr){
+        if (*ptr == '\\'){
+            ptr++;
+            if (*ptr != '\0')
+                ptr++;
+        } else if (*ptr == separator)
+            break;
+        else if (*ptr != delimiter){
+            ptr++;
+            while(*ptr && *ptr != separator)
+                ptr++;
+        }
+    }
+    int rc = ptr - text;
+    return rc;
+}
+/**
+ * Skips all columns with a content other than a numeric value.
+ *
+ * @param line         the text line
+ * @param separator    the column separator
+ * @return                     the start of a number or ""
+ */
+static const char* skipNonNumbers(const char* line, char separator)
+{
+    int len1, len2 = 0;
+
+    while ( (len1 = ReStringUtil::lengthOfNumber(line)) == 0
+        && (len2 = lengthOfColumn(line, separator)) > 0)
+        line += len2;
+    if (*line == separator)
+        line++;
+    return line;
+}
+/**
+ * Returns the count of numeric numbers in a CSV line.
+ *
+ * @param line the line from a CSV file
+ * @return             0: not only numbers are in the line<br>
+ *                             otherwise: the count of numeric columns in the line
+ */
+static int countNumbers(const char* line, char separator){
+    line = skipNonNumbers(line, separator);
+    bool again = true;
+    int rc = 0;
+    char cc;
+    while(again && (cc = *line) != '\0' && cc != '\n' && cc != '\r'){
+        int length = ReStringUtil::lengthOfNumber(line, true);
+        if (length == 0){
+            rc = 0;
+            again = false;
+        } else {
+            line += length;
+            rc++;
+            if (*line == separator)
+                line++;
+        }
+    }
+    return rc;
+}
+/**
+ * Reads a file with the CSV (comma separated values) format
+ * into the instance.
+ */
+void RplMatrix::readFromCvs(const char* filename, int maxLineLength)
+{
+    FILE* fp = fopen(filename, "r");
+    if (fp == NULL)
+        throw RplMatrixException(*this, "Cannot open %s (%d)", filename, errno);
+    char* buffer = new char[maxLineLength + 1];
+    const char* line;
+    char separator = ReStringUtil::findCsvSeparator(fp, buffer, maxLineLength);
+    int rows = 0;
+    int cols = 0;
+    int nCols;
+    // find the count of rows and columns:
+    while( (line = fgets(buffer, maxLineLength, fp)) != NULL)
+    {
+         if ( (nCols = countNumbers(line, separator)) > 0){
+            rows++;
+            if (nCols > cols)
+                cols = nCols;
+        }
+    }
+    resize(rows, cols);
+    // find the values
+    fseek(fp, 0, SEEK_SET);
+    int row = -1;
+    while( (line = fgets(buffer, maxLineLength, fp)) != NULL)
+    {
+        int nCols;
+        if ( (nCols = countNumbers(line, separator)) > 0){
+            row++;
+            line = skipNonNumbers(line, separator);
+            int col = -1;
+            int length;
+            const char* ptr;
+            while( (length = ReStringUtil::lengthOfNumber(line, true)) > 0){
+                col++;
+                ptr = line;
+                line += length;
+                while(*ptr == ' ')
+                    ptr++;
+                MatVal value = atof(ptr);
+                m_values[m_cols*row + col] = value;
+                if (*line == separator)
+                    line++;
+                else
+                    break;
+            }
+        }
+    }
+
+    fclose(fp);
+    delete buffer;
+}
+void RplMatrix::readFromXml(const char* filename, const char* tagCol,
+        const char* tagRow, const char* tagTable,
+        int maxLineLength)
+{
+    throw RplMatrixException(*this, "readFromXml not implementes: %s %s %s %s %d",
+        filename, tagCol, tagRow, tagTable, maxLineLength);
+}
+
diff --git a/math/ReMatrix.hpp b/math/ReMatrix.hpp
new file mode 100644 (file)
index 0000000..d0f168d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * RplMatrix.hpp
+ *
+ *  Created on: 29.05.2014
+ *      Author: hm
+ */
+
+#ifndef RplMatrix_HPP_
+#define RplMatrix_HPP_
+
+
+class RplMatrix;
+/**
+ * Implements a RplMatrix specific exception.
+ */
+class RplMatrixException : public ReException
+{
+public:
+    RplMatrixException(const RplMatrix& RplMatrix, const char* format, ...);
+};
+
+/**
+ * The type of a RplMatrix element.
+ */
+typedef qreal MatVal;
+
+class Tuple2 {
+public:
+       Tuple2(MatVal value1, MatVal value2) :
+               m_value1(value1),
+               m_value2(value2)
+       {}
+public:
+       MatVal m_value1;
+       MatVal m_value2;
+};
+/**
+ * Implements a RplMatrix with 2 dimensions.
+ */
+class RplMatrix {
+public:
+    RplMatrix(const char* name = NULL);
+    RplMatrix(int rows, int cols, const char* name = NULL);
+    virtual ~RplMatrix();
+    RplMatrix(const RplMatrix& source);
+    RplMatrix& operator =(const RplMatrix& source);
+public:
+    RplMatrix& operator +=(const RplMatrix& operand);
+    RplMatrix& operator -=(const RplMatrix& operand);
+    RplMatrix operator +(const RplMatrix& operand);
+    RplMatrix operator -(const RplMatrix& operand);
+    RplMatrix& operator +=(MatVal scalar);
+    RplMatrix& operator -=(MatVal scalar);
+    RplMatrix operator +(MatVal scalar);
+    RplMatrix operator -(MatVal scalar);
+    bool operator ==(const RplMatrix& operand) const;
+       bool operator ==(MatVal scalar) const;
+    inline bool operator !=(const RplMatrix& operand) const
+       { return ! (*this == operand); }
+       inline bool operator !=(MatVal operand)
+       { return ! (*this == operand); }
+public:
+    inline const QByteArray& getName() const
+       { return m_name; }
+       inline MatVal get(int row, int col) const
+       { check(row, col); return m_values[row*m_cols + col]; }
+    inline RplMatrix& set(int row, int col, MatVal value)
+       { check(row, col); m_values[row*m_cols + col] = value; return *this; }
+       inline int getRows() const
+       { return m_rows; }
+       inline int getCols() const
+       { return m_cols; }
+public:
+       void checkDefinition(int rows, int cols) const;
+       void check(int row, int col) const;
+    void checkSameDimension(const RplMatrix& operand) const;
+    RplMatrix& resize(int rows, int cols, const MatVal values[] = NULL,
+                       MatVal defaultValue = 0.0);
+       Tuple2 minMax() const;
+    RplMatrix transpose() const;
+    QByteArray toString(const char* prefix = NULL,
+                       const char* format = "%f",
+                       const char* rowSeparator = "\n",
+                       const char* colSeparator = ",") const;
+       void readFromCvs(const char* filename, int maxLineLength = 1024*1024);
+       void readFromXml(const char* filename, const char* tagCol,
+                       const char* tagRow, const char* tagTable,
+                       int maxLineLength = 1024*1024);
+protected:
+       int m_rows;
+       int m_cols;
+       MatVal* m_values;
+    QByteArray m_name;
+};
+
+#endif /* RplMatrix_HPP_ */
diff --git a/math/ReRandom.cpp b/math/ReRandom.cpp
new file mode 100644 (file)
index 0000000..4d38a4f
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+
+/** @file
+ *
+ * @brief Implements pseudo random generators.
+ */
+/** @file math/ReRandom.hpp
+ *
+ * @brief Definitions for pseudo random generators.
+ */
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+
+/** @class ReRandom ReRandom.hpp "math/ReRandom.hpp"
+ *
+ * @brief Implements a portable pseudo random generator.
+ *
+ */
+
+/**
+ * @brief Constructor.
+ */
+ReRandom::ReRandom() :
+    m_seed(0) {
+}
+
+/**
+ * @brief Destructor.
+ */
+ReRandom::~ReRandom() {
+}
+
+/**
+ * @brief Returns the next random number as 64 bit unsigned integer.
+ *
+ * @return the next random number.
+ */
+uint64_t ReRandom::nextInt64() {
+    // Donald Knuth recommands (for 64-Bit):
+    m_seed = m_seed * 6364136223846793005L + 1442695040888963407L;
+    return m_seed;
+}
+/**
+ * @brief Sets the random seed.
+ *
+ * @param seed      the new seed.
+ */
+void ReRandom::setSeed(uint64_t seed) {
+    m_seed = seed;
+}
+/**
+ * @brief Modifies the seed.
+ *
+ * @param seed      the XOR operand.
+ */
+void ReRandom::xorSeed(uint64_t seed) {
+    m_seed ^= seed;
+}
+
+/**
+ * @brief nextByte  returns the next random byte.
+ *
+ * @return          a pseudo random value 0..255
+ */
+uint8_t ReRandom::nextByte() {
+    uint64_t value = nextInt64();
+    // forget the last 3 bits:
+    uint8_t rc = (uint8_t)(value >> 3) % 256;
+    return rc;
+}
+
+/**
+ * @brief Returns the next pseudo random integer.
+ *
+ * @param minValue  the minimal result (including)
+ * @param maxValue  the maximal result (includeing)
+ * @return the next integer
+ */
+int ReRandom::nextInt(int minValue, int maxValue) {
+    uint64_t value = nextInt64();
+    uint64_t diff = maxValue - minValue;
+    int rc;
+    if(diff <= 0)
+        rc = minValue;
+    else
+        rc = (int)(minValue + value % diff);
+    return rc;
+}
+
+/**
+ * @brief Returns a random string.
+ *
+ * @param length    the length of the result
+ * @param minChar   all characters of the result are greater or equal than this value
+ * @param maxChar   all characters of the result are lower or equal than this value
+ * @return          a random string
+ */
+QByteArray ReRandom::nextString(int length, char minChar, char maxChar) {
+    QByteArray rc;
+    rc.resize(length);
+    for(int ii = 0; ii < length; ii++) {
+        rc[ii] = nextInt(minChar, maxChar);
+    }
+    return rc;
+}
+
+/**
+ * @brief Returns a random string.
+ *
+ * @param length    the length of the result
+ * @param charSet   a string with all allowed characters
+ * @return          a random string with characters from the given set
+ */
+QByteArray ReRandom::nextString(int length, char* charSet) {
+    QByteArray rc;
+    rc.resize(length);
+    int ubound = strlen(charSet) - 1;
+    for(int ii = 0; ii < length; ii++) {
+        rc[ii] = charSet[nextInt(0, ubound)];
+    }
+    return rc;
+}
+
diff --git a/math/ReRandom.hpp b/math/ReRandom.hpp
new file mode 100644 (file)
index 0000000..14e04f7
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef RERANDOM_HPP
+#define RERANDOM_HPP
+
+class ReRandom {
+public:
+    ReRandom();
+    virtual ~ReRandom();
+private:
+    // No copy constructor: no implementation!
+    ReRandom(const ReRandom& source);
+    // Prohibits assignment operator: no implementation!
+    ReRandom& operator =(const ReRandom& source);
+public:
+    virtual uint64_t nextInt64();
+    virtual void setSeed(uint64_t seed);
+    void xorSeed(uint64_t seed);
+    uint8_t nextByte();
+    int nextInt(int minValue, int maxValue);
+    QByteArray nextString(int length = 8, char minChar = ' ', char maxChar = 127);
+    QByteArray nextString(int length, char* charSet);
+protected:
+    uint64_t m_seed;
+};
+
+
+#endif // RERANDOM_HPP
diff --git a/math/remath.hpp b/math/remath.hpp
new file mode 100644 (file)
index 0000000..236f3fd
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RPLMATH_HPP
+#define RPLMATH_HPP
+
+#include <QCryptographicHash>
+#include <limits>
+#include "math/ReRandom.hpp"
+#include "math/ReEnigma.hpp"
+#include "math/ReMatrix.hpp"
+
+#endif // RPLMATH_HPP
diff --git a/net/ReNetConfig.cpp b/net/ReNetConfig.cpp
new file mode 100644 (file)
index 0000000..da7bcc1
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+#include "net/renet.hpp"
+
+const char* ReNetConfig::IP = "connection.ip";
+const char* ReNetConfig::PORT = "connection.port";
+const char* ReNetConfig::SLEEP_MILLISEC = "connection.sleepmillisec";
diff --git a/net/ReNetConfig.hpp b/net/ReNetConfig.hpp
new file mode 100644 (file)
index 0000000..9cef175
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLNETCONFIG_HPP
+#define RPLNETCONFIG_HPP
+
+class ReNetConfig
+{
+public:
+    static const char* IP;
+    static const char* PORT;
+    static const char* SLEEP_MILLISEC;
+};
+
+#endif // RPLNETCONFIG_HPP
diff --git a/net/ReTCPClient.cpp b/net/ReTCPClient.cpp
new file mode 100644 (file)
index 0000000..8912fe9
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+#include "net/renet.hpp"
+
+enum {
+    LOC_1 = LOC_FIRST_OF(LOC_TCPCLIENT), // 10701
+    LOC_HANDLE_ERROR_1,
+    LOC_SET_REMOTE_ADDRESS_1,
+};
+
+/** @class RplTcpClient rpltcpclient.hpp "rplnet/rpltcpclient.hpp"
+ *
+ * @brief Implements a TCP client.
+ *
+ * Use the protocol defined at <code>ReTCPServer</code>.
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param configurator  some parameters will be get from this configurator
+ * @param thread        current thread. Used for <code>sleep()</code>
+ * @param terminator    NULL or for controlled termination
+ * @param logger        a logger
+ */
+RplTcpClient::RplTcpClient(ReConfigurator& configurator, QThread* thread,
+                           ReTerminator* terminator,
+                           ReLogger* logger) :
+        m_peer(new ReTCPPeer(configurator, thread, terminator, false, logger)),
+        m_logger(logger),
+        m_configurator(configurator){
+    QByteArray ip = configurator.asString(ReNetConfig::IP, "localhost");
+    int port = configurator.asInt(ReNetConfig::PORT, 12345);
+    if(! ip.isEmpty() && port != 0)
+        setRemoteAddress(ip.constData(), port);
+}
+
+/**
+ * @brief Destructor.
+ */
+RplTcpClient::~RplTcpClient() {
+    delete m_peer;
+    m_peer = NULL;
+}
+
+/**
+ * @brief Defines the remote address for a client.
+ * @param ip    NULL or the ip to connect
+ * @param port  0 or the port to connect
+ */
+void RplTcpClient::setRemoteAddress(const char* ip, int port) {
+    QTcpSocket* socket = (QTcpSocket*) m_peer->getSocket();
+    delete socket;
+    if(ip == NULL || port == 0)
+        m_peer->setSocket(NULL);
+    else {
+        socket = new QTcpSocket();
+        connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
+                this, SLOT(handleError(QAbstractSocket::SocketError)));
+        m_peer->setSocket(socket);
+        m_peer->setAddress(ip, port);
+        m_logger->logv(LOG_INFO, LOC_SET_REMOTE_ADDRESS_1,
+                        "connect with %s:%d", ip, port);
+        socket->connectToHost(ReString(ip), port);
+        socket->waitForConnected();
+    }
+}
+
+/**
+ * @brief Returns the peer info.
+ * @return the peer info
+ */
+ReTCPPeer* RplTcpClient::getPeer() const {
+    return m_peer;
+}
+
+/**
+ * @brief Handles a network error.
+ *
+ * @param socketError   the error code
+ */
+void RplTcpClient::handleError(QAbstractSocket::SocketError socketError) {
+    if (m_logger != NULL)
+        m_logger->logv(LOG_ERROR, LOC_HANDLE_ERROR_1, "Network error %d",
+                       socketError);
+}
+
+/** @class RplClientThread rpltcpclient.hpp "rplnet/rpltcpclient.hpp"
+ *
+ * @brief Implements a thread usable for a tcp client.
+ *
+ * Each <code>ReTCPPeer</code> needs a thread. Therefore this class provides all things
+ * needed for a <code>RplTcpClient</code> which uses a <code>ReTCPPeer</code>.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param configurator  delivers some connection parameters
+ * @param logger        the logger. If NULL a default logger will be used
+ */
+RplClientThread::RplClientThread(ReConfigurator& configurator,
+                                 ReLogger* logger) :
+    m_client(NULL),
+    m_logger(logger),
+    m_configurator(configurator),
+    m_ownsLogger(false) {
+    m_client = new RplTcpClient(configurator, this, NULL, logger);
+}
+/**
+ * @brief Destructor.
+ */
+RplClientThread::~RplClientThread() {
+    delete m_client;
+    m_client = NULL;
+    if(m_ownsLogger) {
+        delete m_logger;
+        m_logger = NULL;
+    }
+}
+/**
+ * @brief Returns the peer which can be used for sending and receiving messages.
+ *
+ * @return the peer
+ */
+ReTCPPeer* RplClientThread::getPeer() const {
+    return m_client->getPeer();
+}
+
+/**
+ * @brief Returns the logger of the thread.
+ * @return the logger
+ */
+ReLogger* RplClientThread::getLogger() const {
+    return m_logger;
+}
+
+/**
+ * @brief Contains the main method of the thread.
+ *
+ * Calls <code>doIt()</code> for the real things.
+ */
+void RplClientThread::run() {
+    doIt();
+}
diff --git a/net/ReTCPClient.hpp b/net/ReTCPClient.hpp
new file mode 100644 (file)
index 0000000..227df7c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RPLTCPCLIENT_HPP
+#define RPLTCPCLIENT_HPP
+
+#ifndef RPLNET_HPP
+#include "renet.hpp"
+#endif
+
+class ReTCPPeer;
+
+class RplTcpClient : public QObject {
+    Q_OBJECT
+public:
+    RplTcpClient(ReConfigurator& configurator, QThread* thread,
+                 ReTerminator* terminator,
+                 ReLogger* logger = NULL);
+    virtual ~RplTcpClient();
+private:
+    // No copy constructor: no implementation!
+    RplTcpClient(const RplTcpClient& source);
+    // Prohibits assignment operator: no implementation!
+    RplTcpClient& operator =(const RplTcpClient& source);
+public:
+    ReTCPPeer* getPeer() const;
+private:
+    void setRemoteAddress(const char* ip, int port);
+public slots:
+    void handleError(QAbstractSocket::SocketError socketError);
+private:
+    ReTCPPeer* m_peer;
+    ReLogger* m_logger;
+    ReConfigurator& m_configurator;
+};
+
+class RplClientThread : public QThread {
+public:
+    RplClientThread(ReConfigurator& configurator,
+                    ReLogger* logger = NULL);
+    virtual ~RplClientThread();
+private:
+    // No copy constructor: no implementation!
+    RplClientThread(const RplClientThread& source);
+    // Prohibits the assignment operator. Not implemented!
+    RplClientThread& operator=(const RplClientThread& source);
+public:
+    /**
+     * @brief Does the main task of the thread.
+     *
+     * Will be called from <code>QThread::run()</code>.
+     * The implementations of this abstract method should be call <code>getPeer()</code>
+     * to send and receive messages.
+     */
+    virtual void doIt() = 0;
+    ReTCPPeer* getPeer() const;
+    ReLogger* getLogger() const;
+private:
+    virtual void run();
+protected:
+    RplTcpClient* m_client;
+    ReLogger* m_logger;
+    ReConfigurator& m_configurator;
+private:
+    bool m_ownsLogger;
+};
+
+#endif // RPLTCPCLIENT_HPP
diff --git a/net/ReTCPPeer.cpp b/net/ReTCPPeer.cpp
new file mode 100644 (file)
index 0000000..cd8dcf6
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+#include "net/renet.hpp"
+
+enum {
+    LOC_SEND_1 = LOC_FIRST_OF(LOC_TCPPEER), // 10801
+    LOC_READ_BYTES_1,
+    LOC_READ_BYTES_2,
+    LOC_READ_BYTES_3,
+    LOC_READ_BYTES_4,
+    LOC_HANDLE_ERROR_1,
+    LOC_SEND_2,
+};
+
+static int s_dummy = 0;
+
+/** @class ReTCPPeer rpltcppeer.hpp "rplnet/rpltcppeer.hpp"
+ *
+ * @brief Implements the common things for TCP server and client.
+ *
+ * The communication is done with the following protocol:
+ * <ul>
+ *  <li>The data is transmitted via TCP.</li>
+ *  <li>The data exchange is done with <b>info units</b>.
+ *  <li>Each info unit contains a header and the data.</li>
+ * </ul>
+ * The format of the header:
+ *<pre>FLAGS [SALT] COMMAND SIZE
+ * </pre>
+ * <ul>
+ *  <li>FLAGS (1 byte): a XOR sum of the flags defined in <code>rpltcppeer::flag_t</code>.</li>
+ *  <li>SALT (4 byte): a random value. Controls the encryption. Only available if <code>FLAG_ENCRYPT</code> is set.</li>
+ *  <li>COMMAND (5 byte): define the task to do (client to server) or the answer (server to client).
+ *  <li>SIZE (2 or 4 byte): the size of the data behind the header. 4 bytes if <code>FLAG_4_BYTE_SIZE</code> is set.</li>
+ * </ul>
+ *
+ */
+
+/**
+ * @brief Creates an instance of a <code>ReTCPPeer</code>.
+ *
+ * @param configurator  delivers some connection parameters
+ * @param thread        the current thread. Used for sleep()
+ * @param terminator    NULL or for controlled thread termination
+ * @param logger        logger. If Null the global logger will be taken (not thread safe!)
+ * @return              an instance of <code>ReTCPPeer</code>
+ */
+ReTCPPeer* ReTCPPeer::createPeer(ReConfigurator& configurator,
+                                   QThread* thread,
+                                   ReTerminator* terminator,
+                                   ReLogger* logger) {
+    return new ReTCPPeer(configurator, thread, terminator, logger);
+}
+
+/**
+ * @brief Constructor.
+ *
+ * @param configurator  delivers some connection parameters
+ * @param thread        the current thread. Used for sleep()
+ * @param terminator    NULL or for controlled thread termination
+ * @param isServer      true: the receiving does have a timeout
+ * @param logger        logger. If Null the global logger will be taken (not thread safe!)
+ */
+ReTCPPeer::ReTCPPeer(ReConfigurator& configurator, QThread* thread,
+                       ReTerminator* terminator,
+                       bool isServer,
+                       ReLogger* logger) :
+        m_socket(NULL),
+        m_logger(logger == NULL ? ReLogger::globalLogger() : logger),
+        m_thread(thread),
+        m_random(),
+        m_timeout(isServer ? 0 : configurator.asInt("connection.timeout", 60)),
+        m_terminator(terminator),
+        m_configurator(configurator),
+        m_isServer(isServer),
+        m_dataLocker(QMutex::NonRecursive),
+        m_waitForData() {
+    // Simulate a true random with time, and addresses from stack and code segment:
+    m_random.setSeed(time(NULL) + ((int64_t) this << 8) + ((int64_t) &s_dummy << 16)
+                     + ((int64_t) &createPeer << 24));
+}
+
+/**
+ * @brief Destructor.
+ */
+ReTCPPeer::~ReTCPPeer() {
+
+}
+
+/**
+ * @brief Sends a message via TCP.
+ *
+ * @param flags     a sum of FLAGS_... constants
+ * @param command   defines the content of the message
+ * @param data      NULL or additional data
+ * @return          true: success<br>
+ *                  false: error occurred
+ */
+bool ReTCPPeer::send(qint8 flags, const char* command,
+                      const QByteArray& data) {
+    bool rc = false;
+    QByteArray header;
+    QByteArray data2 = ReStringUtil::toCString(data.constData(), 20);
+    m_logger->logv(LOG_INFO, LOC_SEND_1, "send: flags: %x %s %s (%d)",
+        flags, command, data2.constData(), data.length());
+    header.reserve(16);
+    header.append((char) flags);
+    if(flags & FLAG_ENCRYPT) {
+        header.append((char) m_random.nextByte());
+        header.append((char) m_random.nextByte());
+        header.append((char) m_random.nextByte());
+        header.append((char) m_random.nextByte());
+    }
+    unsigned int length = data.length();
+    header.append(char(length % 256));
+    header.append(char((length >> 8) % 256));
+    if(flags & FLAG_4_BYTE_SIZE) {
+        header.append(char((length >> 16) % 256));
+        header.append(char((length >> 24) % 256));
+    }
+    length = strlen(command);
+    header.append(command, length < 5 ? length : 5);
+    while(length++ < 5) {
+        header.append(' ');
+    }
+    int64_t written = m_socket->write(header.constData(), header.length());
+    int64_t written2 = m_socket->write(data);
+    m_socket->flush();
+    int count = 0;
+    if(written != header.length() || written2 != data.length()) {
+        int endTime = time(NULL) + m_timeout;
+        // wait until the data are sent or timeout or external termination:
+        while(m_socket->bytesToWrite() > 0) {
+            m_thread->msleep(1);
+            if(++count % 20 == 0) {
+                if(m_terminator == NULL || m_terminator->isStopped()
+                        || time(NULL) > endTime)
+                    break;
+            }
+        }
+    }
+    if(m_logger->isActive(LOG_DEBUG))
+        m_logger->logv(LOG_DEBUG, LOC_SEND_1, "send %s: %s len=%d loops=%d %s",
+                       m_address.constData(), command, data.length(), count,
+                       ReStringUtil::hexDump((const void*) data.constData(), 16, 16).constData());
+    return rc;
+}
+
+/**
+ * @brief Reads an amount of bytes with a timeout.
+ *
+ * @param bytes     count of bytes to read
+ * @param maxTime   IN/OUT: last time the read must be ready
+ * @param loops     IN/OUT: number of sleeps
+ *
+ * @return          "": read not successful: timeout or termination or error<br>
+ *                  otherwise: the read bytes
+ */
+QByteArray ReTCPPeer::readBytes(int bytes, time_t maxTime, int& loops) {
+    QAbstractSocket* socket = getSocket();
+    bool success = true;
+    int64_t available;
+    long msec = m_configurator.asInt(ReNetConfig::SLEEP_MILLISEC, 1);
+    int divider = 1000L / (msec == 0 ? 1 : msec);
+    if (divider < 1)
+        divider = 1;
+    QMutexLocker locker(&m_dataLocker);
+    m_dataLocker.lock();
+
+    while(! m_waitForData.wait(&m_dataLocker, 1000L)){
+          if(loops == 0 && ! m_isServer)
+              maxTime = time(NULL) + m_timeout;
+          if(++loops % divider == 0 && ! m_isServer) {
+              if(time(NULL) > maxTime) {
+                  m_logger->logv(LOG_ERROR, LOC_READ_BYTES_1,
+                                 "receive: timeout (%d)", m_timeout);
+                  success = false;
+                  break;
+              }
+          }
+          if(m_terminator != NULL && m_terminator->isStopped()) {
+              m_logger->log(LOG_ERROR, LOC_READ_BYTES_2, "receive: stopped");
+              success = false;
+              break;
+          }
+    }
+    available = socket->bytesAvailable();
+    m_logger->logv(LOG_DEBUG, LOC_READ_BYTES_4,
+                   "readBytes(): available: %ld/%ld", available, bytes);
+    QByteArray rc;
+    if(success) {
+        rc = socket->read(bytes);
+        if(rc.length() != bytes) {
+            m_logger->logv(LOG_ERROR, LOC_READ_BYTES_3,
+                           "receive: too few bytes: %d of %d",
+                           rc.length(), bytes);
+        }
+    }
+    return rc;
+}
+
+int getInt(const QByteArray& data, int offset, int size) {
+    int rc = ((int)(unsigned char) data.at(offset++));
+    while(--size > 0) {
+        rc = rc * 256 + (unsigned char) data.at(offset++);
+    }
+    return rc;
+}
+
+/**
+ * @brief Receives a message via TCP.
+ *
+ * @param command   OUT: defines the content of the read message
+ * @param data      OUT: "" or additional data
+ * @return          true: success<br>
+ *                  false: error occurred
+ */
+bool ReTCPPeer::receive(QByteArray& command, QByteArray& data) {
+    bool rc = true;
+    command.clear();
+    data.clear();
+    QByteArray header;
+    header.reserve(16);
+    int minHeaderSize = 8;
+    int loops = 0;
+    time_t maxTime = 0;
+    uint8_t flags = 0;
+    header = readBytes(minHeaderSize, maxTime, loops);
+    if(header.length() > 0) {
+        flags = header.at(0);
+        int headerSize = minHeaderSize;
+        if((flags & FLAG_4_BYTE_SIZE) != 0)
+            headerSize += 2;
+        if((flags & FLAG_ENCRYPT) != 0)
+            headerSize += 4;
+        if(headerSize != minHeaderSize) {
+            QByteArray restHeader = readBytes(headerSize - minHeaderSize,
+                                              maxTime, loops);
+            if(restHeader.length() == 0)
+                header.clear();
+            else
+                header.append(restHeader);
+        }
+    }
+    rc = header.length() > 0;
+    if(rc) {
+        int offset = (flags & FLAG_ENCRYPT) == 0 ? 6 : 8;
+        int size = (flags & FLAG_4_BYTE_SIZE) == 0 ? 4 : 2;
+        int dataLength = getInt(header, offset, size);
+        command = header.mid(offset - 5, 5);
+        data = readBytes(dataLength, maxTime, loops);
+        rc = data.length() == dataLength;
+    }
+    return rc;
+
+}
+
+/**
+ * @brief Sends a message and receives an answer message via TCP.
+ *
+ * @param flags     a sum of FLAGS_... constants
+ * @param command       defines the content of the message to send
+ * @param data          NULL or additional data
+ * @param answer        OUT: the command of the answer
+ * @param answerData    OUT: "" or additional data of the answer
+ * @return              true: success<br>
+ *                      false: error occurred
+ */
+bool ReTCPPeer::sendAndReceive(uint8_t flags, char command [4],
+        QByteArray* data, QByteArray& answer,
+        QByteArray& answerData) {
+    answer.clear();
+    answerData.clear();
+    bool rc = send(flags, command, data == NULL ? QByteArray("") : *data);
+    if(rc)
+        rc = receive(answer, answerData);
+    return rc;
+}
+
+/**
+ * @brief Sets the socket.
+ *
+ * @param socket    the socket to set
+ */
+void ReTCPPeer::setSocket(QAbstractSocket* socket) {
+    m_socket = socket;
+    if (socket != NULL)
+        connect( m_socket, SIGNAL(readyRead()), SLOT(readTcpData()) );
+}
+
+/**
+ * @brief Reads the (ready) data from the socket.
+ */
+void ReTCPPeer::readTcpData() {
+    m_waitForData.wakeOne();
+}
+
+/**
+ * @brief Handles a network error.
+ *
+ * @param socketError   the error code
+ */
+void ReTCPPeer::handleError(QTcpSocket::SocketError socketError) {
+    m_logger->logv(LOG_ERROR, LOC_HANDLE_ERROR_1, "Network error %d",
+                   socketError);
+}
+
+/**
+ * @brief Returns a human readable peer address.
+ * @return a string with the peer address: e.g. "192.16.2.3:44335"
+ */
+QByteArray ReTCPPeer::getPeerAddress() {
+    QByteArray rc;
+    if(m_socket == NULL)
+        rc = "<not connected>";
+    else
+        rc = m_socket->peerAddress().toString().toUtf8();
+    return rc;
+}
+
+/**
+ * @brief Returns the socket.
+ *
+ * @return the socket
+ */
+QAbstractSocket* ReTCPPeer::getSocket() const {
+    return m_socket;
+}
+
+/**
+ * @brief Returns the port.
+ * @return the port of the peer.
+ */
+int ReTCPPeer::getPort(){
+    int port = m_configurator.asInt(ReNetConfig::PORT, 12345);
+    return port;
+}
+/**
+ * @brief Returns the ip address.
+ * @return  "": all addresses (for listening)<br>
+ *          otherwise: the address (e.g. 127.0.0.1)
+ */
+QByteArray ReTCPPeer::getIp(){
+    QByteArray ip = m_configurator.asString(ReNetConfig::IP, "");
+    return ip;
+}
+/**
+ * @brief Sets the address (ip:port).
+ * @param ip    the ip address
+ * @param port  the port
+ */
+void ReTCPPeer::setAddress(const char* ip, int port)
+{
+    m_address = QByteArray(ip) + ":" + QByteArray::number(port);
+}
diff --git a/net/ReTCPPeer.hpp b/net/ReTCPPeer.hpp
new file mode 100644 (file)
index 0000000..51f7dea
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RPLTCPPEER_HPP
+#define RPLTCPPEER_HPP
+
+#ifndef RPLNET_HPP
+#include "renet.hpp"
+#endif
+
+class ReTCPPeer : public QObject {
+    Q_OBJECT
+public:
+    enum {
+        ///> standard behaviour
+        FLAG_UNDEF,
+        ///> if set: the size field is 4 byte (max. 4 GByte) instead of 2 byte (64kByte)
+        FLAG_4_BYTE_SIZE = 1,
+        ///> if set the data are compressed by the gzip algorithm
+        FLAG_GZIP = 2,
+        ///> if set the data are encrypted. In front of the size field a 4 byte salt field exists.
+        ///> In this case all data behind the salt field are encrypted.
+        FLAG_ENCRYPT = 4,
+        ///> connection initialization of
+    } flag_t;
+public:
+    static ReTCPPeer* createPeer(ReConfigurator& configurator,
+                                  QThread* thread,
+                                  ReTerminator* terminator,
+                                  ReLogger* logger = NULL);
+public:
+    ReTCPPeer(ReConfigurator& configurator, QThread* thread,
+               ReTerminator* terminator,
+               bool isServer,
+               ReLogger* logger = NULL);
+    virtual ~ReTCPPeer();
+private:
+    // No copy constructor: no implementation!
+    ReTCPPeer(const ReTCPPeer& source);
+    // No assignment operator: no implementation!
+    ReTCPPeer& operator =(const ReTCPPeer& source);
+public:
+    virtual bool send(qint8 flags, const char* command, const QByteArray& data);
+    virtual bool receive(QByteArray& command, QByteArray& data);
+    virtual bool sendAndReceive(uint8_t flags, char command [4],
+                                QByteArray* data, QByteArray& answer, QByteArray& answerData);
+    void setSocket(QAbstractSocket* socket);
+    QAbstractSocket* getSocket() const;
+    QByteArray getPeerAddress();
+    void handleError(QTcpSocket::SocketError socketError);
+    int getPort();
+    QByteArray getIp();
+    void setAddress(const char* ip, int port);
+private:
+    QByteArray readBytes(int bytes, time_t maxTime, int& loops);
+
+public slots:
+    void readTcpData();
+
+private:
+    QAbstractSocket* m_socket;
+    // <ip>:<port>
+    QByteArray m_address;
+    ReLogger* m_logger;
+    QByteArray m_received;
+    int m_expected;
+    QThread* m_thread;
+    // Only used for salt generation:
+    ReRandom m_random;
+    ///> maximum allowed time (in seconds) for sending/receiving one info unit
+    int m_timeout;
+    ///> for controlled termination
+    ReTerminator* m_terminator;
+    ReConfigurator& m_configurator;
+    bool m_isServer;
+    QMutex m_dataLocker;
+    QWaitCondition m_waitForData;
+};
+
+#endif // RPLTCPPEER_HPP
diff --git a/net/ReTCPServer.cpp b/net/ReTCPServer.cpp
new file mode 100644 (file)
index 0000000..83a1326
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+#include "net/renet.hpp"
+
+enum {
+    LOC_RUN_1 = LOC_FIRST_OF(LOC_TCPSERVER), // 10601
+    LOC_TCP_TREAD_RUN_1,
+    LOC_TCP_TREAD_RUN_2,
+    LOC_TCP_INCOMING_CONNECTION_1,
+};
+
+/** @class ReTCPThread rpltcpserver.hpp "rplcore/rpltcpserver.hpp"
+ *
+ * @brief Serves one connection of a multihreaded TCP server.
+ *
+ * Note: The real thing is done by the ReTaskHandler instance.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param configurator  delivers some connection parameters
+ * @param socketDescriptor  socket of the connection to handle
+ * @param threadId          an unique id for the thread
+ * @param handler           does the work
+ */
+ReTCPThread::ReTCPThread(ReConfigurator& configurator,
+                           qintptr socketDescriptor, int threadId,
+                           ReTaskHandler* handler) :
+    m_threadId(threadId),
+    m_taskHandler(handler),
+    m_socketDescriptor(socketDescriptor),
+    m_configurator(configurator){
+}
+/**
+ * @brief Destructor.
+ */
+ReTCPThread::~ReTCPThread() {
+
+}
+
+/**
+ * @brief Does the proper thread task.
+ *
+ * Initializes the socket and loops for incoming commands.
+ */
+void ReTCPThread::run() {
+    QTcpSocket socket;
+    if(!socket.setSocketDescriptor(getSocketDescriptor())) {
+        emit error(socket.error());
+    } else {
+        ReTCPPeer peer(m_configurator, this, m_taskHandler->getTerminator(),
+                        true, m_taskHandler->getLogger());
+        peer.setSocket(&socket);
+        QByteArray addr = peer.getPeerAddress();
+        m_taskHandler->getLogger()->logv(LOG_DEBUG, LOC_TCP_TREAD_RUN_1,
+                                         "ReTCPThread::run(): start Peer: %s", addr.constData());
+        while(m_taskHandler->handle(&peer)) {
+            // do nothing
+        }
+        socket.disconnectFromHost();
+        socket.waitForDisconnected();
+        m_taskHandler->getLogger()->logv(LOG_DEBUG, LOC_TCP_TREAD_RUN_1,
+                                         "ReTCPThread::run(): end Peer: %s", addr.constData());
+    }
+}
+
+/**
+ * @brief Returns the thread id.
+ *
+ * @return the thread id
+ */
+int ReTCPThread::getThreadId() const {
+    return m_threadId;
+}
+/**
+ * @brief Returns the task handler.
+ *
+ * @return the task handler
+ */
+ReTaskHandler* ReTCPThread::getTaskHandler() const {
+    return m_taskHandler;
+}
+/**
+ * @brief Returns the tcp socket of the served connection.
+ *
+ * @return the socket
+ */
+qintptr ReTCPThread::getSocketDescriptor() const {
+    return m_socketDescriptor;
+}
+
+/** @class ReTCPServer rpltcpserver.hpp "rplcore/rpltcpserver"
+ *
+ * @brief Implements a multithreaded TCP server.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param configurator  some parameters will be get from this configurator
+ * @param taskHandler       this handler reads from the tcp and interprets the content
+ * @param threadFactory     creates a thread for a new connection
+ * @param logger            NULL or logger
+ * @param parent            NULL or the parent which deletes the childen
+ */
+ReTCPServer::ReTCPServer(ReConfigurator& configurator,
+                           ReTaskHandler* taskHandler,
+                           ReVMThreadFactory& threadFactory,
+                           ReLogger* logger,
+                           QObject* parent) :
+    QTcpServer(parent),
+    m_taskHandler(taskHandler),
+    m_threadId(0),
+    m_threadFactory(threadFactory),
+    m_configurator(configurator){
+}
+
+/**
+ * @brief The slot handling a new tcp connection.
+ *
+ * @param socketDescriptor  the tcp socket
+ */
+void ReTCPServer::incomingConnection(qintptr socketDescriptor) {
+    ReTCPThread* thread = m_threadFactory.create(m_configurator,
+                socketDescriptor, ++m_threadId, m_taskHandler);
+    m_taskHandler->getLogger()->log(LOG_DEBUG, LOC_TCP_INCOMING_CONNECTION_1,
+                                    "Connection detected");
+    QTcpServer::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+    thread->start();
+}
+
+/** @class ReTCPThread rpltcpserver.hpp "rplcore/rpltcpserver.hpp"
+ *
+ * @brief Defines a function pointer type to create a <code>ReTCPThread</code> instance.
+ *
+ */
+
+/** @class ReTaskHandler rpltcpserver.hpp "rplcore/rpltcpserver.hpp"
+ *
+ * @brief An abstract base class for an handler processing  an data unit.
+ *
+ * The handler knows the stucture of the data unit and can interpret this.
+ */
+/**
+ * @brief Constructor
+ *
+ * @param configurator  delivers some connection parameters
+ * @param terminator    external controller for thread termination
+ * @param logger        the logger
+ */
+ReTaskHandler::ReTaskHandler(ReConfigurator& configurator,
+                               ReTerminator* terminator, ReLogger* logger) :
+    m_answerFlags(0),
+    m_logger(logger),
+    m_terminator(terminator),
+    m_configurator(configurator){
+}
+
+/**
+ * @brief Destructor.
+ */
+ReTaskHandler::~ReTaskHandler() {
+}
+
+/**
+ * @brief Reads one data unit, processes it and sends the answer.
+ *
+ * @param peer      the communication partner
+ * @return          false: the application should stop<br>
+ *                  true: processing remains
+ */
+bool ReTaskHandler::handle(ReTCPPeer* peer) {
+    QByteArray command;
+    QByteArray data;
+    QByteArray answer;
+    QByteArray answerData;
+    bool rc = true;
+    if(peer->receive(command, data)) {
+        rc = process(command, data, answer, answerData);
+        if(answer.length() > 0) {
+            peer->send(m_answerFlags, answer, answerData);
+        }
+    }
+    return rc;
+}
+
+/**
+ * @brief Sets the thead id.
+ *
+ * @param id    the thread id
+ */
+void ReTaskHandler::setThreadId(int id) {
+    m_threadId = id;
+}
+
+/**
+ * @brief Gets the thread id.
+ *
+ * @return the thread id
+ */
+int ReTaskHandler::getThreadId() const {
+    return m_threadId;
+}
+
+/**
+ * @brief Returns the logger.
+ *
+ * @return  the logger
+ */
+ReLogger* ReTaskHandler::getLogger() const {
+    return m_logger;
+}
+
+/**
+ * @brief Returns the termination controller.
+ *
+ * @return the termination controller
+ */
+ReTerminator* ReTaskHandler::getTerminator() const {
+    return m_terminator;
+}
+
diff --git a/net/ReTCPServer.hpp b/net/ReTCPServer.hpp
new file mode 100644 (file)
index 0000000..bcbe5d0
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RPLTCPSERVER_HPP
+#define RPLTCPSERVER_HPP
+
+// the sources generated from QT include this file directly:
+#ifndef RPLNET_HPP
+#include "renet.hpp"
+#endif
+
+class ReTCPPeer;
+class ReTaskHandler {
+public:
+    ReTaskHandler(ReConfigurator& configurator,
+                   ReTerminator* terminator,
+                   ReLogger* logger);
+    virtual ~ReTaskHandler();
+public:
+
+    virtual bool handle(ReTCPPeer* peer);
+    /**
+     * @brief Processes one data unit from the socket.
+     *
+     * @param command       defines the meaning of the information unit
+     * @param data          "" or the data of the information unit
+     * @param answer        OUT: "" or the answer to send back
+     * @param answerData    OUT: "" or the answer data to send back
+     * @return              true: the receiving loop should be continued<br>
+     *                      false: the process should be stopped
+     */
+    virtual bool process(const QByteArray& command, const QByteArray& data,
+                         QByteArray& answer, QByteArray& answerData) = 0;
+    void setThreadId(int id);
+    int getThreadId() const;
+    ReLogger* getLogger() const;
+    ReTerminator* getTerminator() const;
+protected:
+    uint8_t m_answerFlags;
+private:
+    int m_threadId;
+    ReLogger* m_logger;
+    ReTerminator* m_terminator;
+    ReConfigurator& m_configurator;
+};
+
+class ReTCPThread : public QThread {
+    Q_OBJECT
+public:
+    ReTCPThread(ReConfigurator& m_configurator,
+                 qintptr socketDescriptor, int threadId,
+                 ReTaskHandler* handler);
+    virtual ~ReTCPThread();
+private:
+    // No copy constructor: no implementation!
+    ReTCPThread(const ReTCPThread& source);
+    // No assignment operator: no implementation!
+    ReTCPThread& operator=(const ReTCPThread& source);
+public:
+    void run();
+    int getThreadId() const;
+    ReTaskHandler* getTaskHandler() const;
+    qintptr getSocketDescriptor() const;
+
+signals:
+    void error(QTcpSocket::SocketError socketError);
+
+private:
+    // a unique id for the thread
+    int m_threadId;
+    // this handler interprets the info from the TCP connection
+    ReTaskHandler* m_taskHandler;
+    // the assigned socket
+    qintptr m_socketDescriptor;
+    ReConfigurator& m_configurator;
+};
+class ReThreadFactory {
+public:
+    virtual ReTCPThread* create(ReConfigurator& configurator,
+        qintptr socketDescriptor,
+        int threadId,
+        ReTaskHandler* handler) = 0;
+};
+
+class ReTCPPeer;
+class ReTCPServer : public QTcpServer, public ReTerminator {
+    Q_OBJECT
+public:
+    explicit ReTCPServer(ReConfigurator& configurator,
+            ReTaskHandler* taskHandler,
+            ReThreadFactory& threadFactory,
+            ReLogger* logger = NULL, QObject* parent = 0);
+private:
+    // No copy constructor: no implementation!
+    ReTCPServer(const ReTCPServer& source);
+    // No assignment operator: no implementation!
+    ReTCPServer& operator=(const ReTCPServer& source);
+public:
+    ReTCPPeer* getPeer() const;
+    bool handleTask();
+
+protected slots:
+    void incomingConnection(qintptr socketDescriptor);
+
+private:
+    ReTaskHandler* m_taskHandler;
+    int m_threadId;
+    ReTCPPeer* m_peer;
+    ReThreadFactory& m_threadFactory;
+    ReConfigurator& m_configurator;
+};
+
+#endif // RPLTCPSERVER_HPP
diff --git a/net/renet.hpp b/net/renet.hpp
new file mode 100644 (file)
index 0000000..f151faa
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+ */
+#ifndef RPLNET_HPP
+#define RPLNET_HPP
+
+#include <QThread>
+#include <QAbstractSocket>
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QThread>
+#include <QWaitCondition>
+#include <QMutexLocker>
+
+#include "net/ReTCPPeer.hpp"
+#include "net/ReTCPServer.hpp"
+#include "net/ReTCPClient.hpp"
+#include "net/ReNetConfig.hpp"
+
+#endif // RPLNET_HPP
diff --git a/remodules.hpp b/remodules.hpp
new file mode 100644 (file)
index 0000000..4cd4dc3
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef RPLMODULES_HPP
+#define RPLMODULES_HPP
+
+enum {
+    LOC_LOGGER = 101,
+    LOC_CONFIG,
+    LOC_CONTAINER,
+    LOC_EXCEPTION,
+    LOC_TEST, // 105
+    LOC_TCPSERVER,
+    LOC_TCPCLIENT,
+    LOC_TCPPEER,
+    LOC_TERMINATOR,
+    LOC_ASTREE, // 110
+    LOC_ASCLASSES,
+    LOC_LEXER,
+    LOC_SOURCE,
+    LOC_VM,
+    LOC_MFPARSER, // 115
+};
+#define LOC_FIRST_OF(moduleNo) (moduleNo*100+1)
+class RplModules{
+public:
+    static int fileToNumber(const char* file);
+    static const char* numberToFile(int location);
+};
+
+
+#endif // RPLMODULES_HPP
diff --git a/rplcore/rplbytestorage.cpp b/rplcore/rplbytestorage.cpp
deleted file mode 100644 (file)
index df1600b..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- *
- * @brief A very efficient storage for bytes and C strings.
- */
-/** @file rplcore/rplbytestorage.hpp
- *
- * @brief Definitions for a very efficient storage for bytes and C strings.
- */
-
-#include "rplcore/rplcore.hpp"
-
-/** @class RplByteStorage rplbytestorage.hpp "rplcore/rplbytestorage.hpp"
- *
- * @brief Implements a very efficient byte storage.
- *
- * Efficiency: Allocation of one block needs mostly only 1 comparison
- * and 2 assignments.
- *
- * Restriction: The blocks can be returned (freed) only once, not block by block.
- * This can be an advantage!
- *
- * Process:
- * The storage administrates large buffers. Allocation can be done only in the
- * last buffer. If the buffer has too little space for the new block a new
- * buffer will be allocated and linked into the buffer list.
- * One buffer can store dozens or hundreds of blocks. Therefore allocation and
- * freeing is much cheeper than allocation by <code>new()</code>.
- */
-
-/**
- * @brief Constructor.
- *
- * @param bufferSize    the size of one buffer
- */
-RplByteStorage::RplByteStorage(int bufferSize) :
-    m_bufferSize(bufferSize),
-    m_buffer(NULL),
-    m_rest(0),
-    m_freePosition(NULL),
-    m_summarySize(0),
-    m_buffers(0)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplByteStorage::~RplByteStorage()
-{
-    const uint8_t* ptr = m_buffer;
-    while(ptr != NULL){
-        const uint8_t* old = ptr;
-        ptr = *(const uint8_t**)(ptr);
-        delete[] old;
-        m_buffers--;
-    }
-    assert(m_buffers == 0);
-}
-
-/**
- * @brief Allocates a block in a new allocated buffer.
- *
- * This method will be called if the buffer has too little space.
- * A new buffer will be allocated and the block will be allocated
- * in this new block.
- *
- * @note The block address is returned, but the allocation must be done outside!
- *
- * @param   size of the new block (inclusive the trailing '\0')
- * @return  a new block with the <code>size</code> bytes
- */
-char* RplByteStorage::allocBuffer(int size)
-{
-    m_rest = size + sizeof(uint8_t*) <= (size_t) m_bufferSize
-            ? m_bufferSize : size + sizeof(uint8_t*);
-    m_summarySize += m_rest;
-    m_buffers++;
-    uint8_t* rc = new uint8_t[m_rest];
-    * (uint8_t**)rc = m_buffer;
-    m_buffer = rc;
-    rc += sizeof(uint8_t*);
-    // the block allocation will be done outside!
-    m_freePosition = rc;
-    m_rest -= sizeof(uint8_t*);
-    return reinterpret_cast<char*>(rc);
-}
-
-/**
- * @brief Duplicates a string into a new allocated block.
- *
- * @param source    the source string
- * @param size      the length of the string.
- *                  If < 0 <code>strlen(source)</code> will be used
- * @return          a copy of the source string. The copy ends always with '\0'
- */
-const char* RplByteStorage::allocateChars(const char* source, int size)
-{
-    if (size < 0)
-        size = strlen(source);
-    const char* rc = allocateChars(size + 1);
-    memcpy((void*) rc, source, size);
-    ((char*)rc)[size] = '\0';
-    return rc;
-}
-
-/**
- * @brief Duplicates a string into a new allocated block.
- *
- * The unicode string will be converted into an UTF-8 string.
- *
- * @param source    the source string
- * @return          a copy of the source string. The copy ends always with '\0'
- */
-const char* RplByteStorage::allocUtf8(const QString& source)
-{
-    const char* rc = allocateChars(source.toUtf8().constData());
-    return rc;
-}
-
-/**
- * @brief Allocates a byte block without initialization.
- *
- * @param size  the size of the block to allocate
- *
- * @return  a byte block (without a trailing '\0')
- */
-uint8_t* RplByteStorage::allocateBytes(int size)
-{
-    uint8_t* rc = size <= m_rest ? m_freePosition
-            : reinterpret_cast<uint8_t*>(allocBuffer(size));
-    m_freePosition += size;
-    m_rest -= size;
-    return rc;
-}
-
-/**
- * @brief Allocates a byte block initialized by '\0'.
- *
- * @param size  the size of the block to allocate
- *
- * @return  a byte block (without a trailing '\0')
- */
-uint8_t* RplByteStorage::allocateZeros(int size)
-{
-    uint8_t* rc = allocateBytes(size);
-    memset(rc, 0, size);
-    return rc;
-}
-
-/**
- * @brief Copy a byte block to a new allocated byte block.
- *
- * @param source    the source to copy
- * @param size      the size of the block to allocate
- * @return          a byte block (without a trailing '\0')
- */
-uint8_t* RplByteStorage::allocateBytes(void* source, int size)
-{
-    uint8_t* rc = allocateBytes(size);
-    memcpy(rc, source, size);
-    return rc;
-}
diff --git a/rplcore/rplbytestorage.hpp b/rplcore/rplbytestorage.hpp
deleted file mode 100644 (file)
index 41e0a9c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLCHARSTORAGE_HPP
-#define RPLCHARSTORAGE_HPP
-
-class RplByteStorage
-{
-public:
-    RplByteStorage(int blockSize);
-    ~RplByteStorage();
-public:
-    char* allocBuffer(int size);
-    /**
-     * @brief Allocates a char block.
-     *
-     * @return a new block
-     */
-    inline char* allocateChars(int size){
-        char* rc = size <= m_rest ? (char*) m_freePosition
-                                        : allocBuffer(size);
-        m_freePosition += size;
-        m_rest -= size;
-        return rc;
-    }
-    const char* allocateChars(const char* source, int size = -1);
-    const char* allocUtf8(const QString& source);
-    uint8_t* allocateBytes(int size);
-    uint8_t* allocateZeros(int size);
-    uint8_t*allocateBytes(void* source, int size);
-private:
-    int m_bufferSize;
-    uint8_t* m_buffer;
-    int m_rest;
-    uint8_t* m_freePosition;
-    qint64 m_summarySize;
-    int m_buffers;
-};
-
-#endif // RPLCHARSTORAGE_HPP
diff --git a/rplcore/rplcharptrmap.cpp b/rplcore/rplcharptrmap.cpp
deleted file mode 100644 (file)
index a995536..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#include "rplcore/rplcore.hpp"
-
-/** @class RplKeyCharPtr rplcharptrmap.hpp "rplcore/rplcharptrmap.hpp"
- *
- * @brief Allows using <code>char*</code> pointers as key in <code>QMap</code>.
- *
- * The template <code>QMap</code> uses the operator < to search in the map.
- * But the <code>char*</code> pointers have no such an operator.
- * The solution is the class <code>RplMapCharPtr</code> which implements
- * this operator.
- *
- * <code>strcmp()</code> is used to implement the '<' operator.
- */
-
-/**
- * @brief Constructor.
- *
- * @param ptr   the key used in the map.
- *              @note the pointer will be stored in the map as a key,
- *              not the content
- */
-RplKeyCharPtr::RplKeyCharPtr(const char* ptr) :
-    m_ptr(ptr)
-{
-}
-
-
-/** @class RplCharPtrMap rplcharptrmap.hpp "rplcore/rplcharptrmap.hpp"
- *
- * @brief A template for a map using const char* as keys.
- *
- * The value type is dynamic (a parameter type of the template).
- *
- * <b>Usage:</b>
- * <pre><code>
- * RplCharPtrMap<int> ids;
- * if (! id.contains("jonny"))
- *    ids["jonny"] = 1;
- * </code></pre>
- *
- * <b>Important</b>:<br>
- * Keys used with this class must be unchangable and must live during the
- * whole life of the map.
- *
- * <b>Wrong example:</b>
- * <pre><code>
- * RplCharPtrMap<int> ids;
- * void init(int keyNo, int value){
- *    char key[10];
- *    qsnprintf(buffer, sizeof buffer, "key%d", keyNo);
- *    ids[key] = value;
- * }
- * init(1, 100);
- * </code></pre>
- * The lifetime of the key is the body of the function <code>init()</code>.
- * The key becomes invalid after the call.
- */
diff --git a/rplcore/rplcharptrmap.hpp b/rplcore/rplcharptrmap.hpp
deleted file mode 100644 (file)
index 93df1c7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLCHARPTRMAP_HPP
-#define RPLCHARPTRMAP_HPP
-
-class RplKeyCharPtr {
-    friend bool operator <(RplKeyCharPtr const& op1, RplKeyCharPtr const& op2);
-public:
-    RplKeyCharPtr(const char* ptr);
-private:
-    const char* m_ptr;
-};
-/**
- * @brief Compares two instances of the class <code>RplKeyCharPtr</code>.
- * @param op1   1st operand
- * @param op2   2nd operand
- * @return      true: op1 < op2<br>
- *              false: op1 >= op2
- */
-inline bool operator <(RplKeyCharPtr const& op1, RplKeyCharPtr const& op2){
-    bool rc = strcmp(op1.m_ptr, op2.m_ptr) < 0;
-    return rc;
-}
-
-template <class ValueType>
-class  RplCharPtrMap : public QMap<RplKeyCharPtr, ValueType>
-{
-};
-
-#endif // RPLCHARPTRMAP_HPP
diff --git a/rplcore/rplconfig.cpp b/rplcore/rplconfig.cpp
deleted file mode 100644 (file)
index 642a647..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#include "rplcore/rplcore.hpp"
-
-/** @file
- *
- * @brief Reading/writing configuration files.
- */
-/** @file rplcore/rplconfig.hpp
- *
- * @brief Definitions for reading/writing configuration files.
- */
-
-/** @class RplConfig rplconfig.hpp "rplcore/rplconfig.hpp"
- *
- * @brief Imports and exports a configuration file into a QHash instance.
- *
- * The format of the file:<br>
- * DEFS or COMMENTS
- *
- * DEFS ::= KEY=VALUE
- *
- * KEY is a string starting with an alphanumeric character and does not contain a '='
- *
- * VALUE is a string
- */
-
-enum Locations {
-    LOC_WRITE_1 = RPL_FIRST_OF(RPLMODULE_CONFIG),   // 10201
-    LOC_WRITE_2,
-    LOC_READ_1,
-    LOC_READ_2,
-};
-
-/**
- * Constructor.
- *
- * Initializes the logger and reads the configuration file
- *
- * @param file          name of the configuration file. May be NULL
- * @param readOnly      true: the configuration must not be written
- * @param logger        NULL or a logger
- */
-RplConfig::RplConfig(const char* file, bool readOnly, RplLogger* logger) :
-    m_file(file),
-    m_lineList(),
-    m_readOnly(readOnly),
-    m_logger(logger),
-    m_ownLogger(logger == NULL) {
-    if(logger == NULL) {
-        initLogger();
-    }
-    if(file != NULL)
-        read(file);
-}
-
-/**
- * Destructor.
- *
- * Frees the resources.
- */
-RplConfig::~RplConfig() {
-    if(m_ownLogger)
-        delete m_logger;
-    m_logger = NULL;
-}
-
-/**
- * Inititializes a logger.
- */
-void RplConfig::initLogger() {
-    m_logger = new RplLogger();
-    RplMemoryAppender* appender = new RplMemoryAppender();
-    appender->setAutoDelete(true);
-    m_logger->addAppender(appender);
-
-    RplStreamAppender* appender2 = new RplStreamAppender(stdout);
-    appender2->setAutoDelete(true);
-    m_logger->addAppender(appender2);
-}
-
-/**
- * Returns  configuration value as an integer.
- *
- * @param key           key of the wanted value
- * @param defaultValue  if the key does not exist this is the result
- * @return              defaultValue: key does not exist
- *                      otherwise: the value assigned to key
- */
-int RplConfig::asInt(const char* key, int defaultValue) const {
-    int rc = defaultValue;
-    if(contains(key)) {
-        rc = atoi((*this)[key]);
-    }
-    return rc;
-}
-
-/**
- * Returns the configuration value as a boolean.
- *
- * @param key           key of the wanted value
- * @param defaultValue  if the key does not exist this is the result
- * @return              defaultValue: key does not exist
- *                      otherwise: the value assigned to key
- */
-bool RplConfig::asBool(const char* key, bool defaultValue) const {
-    bool rc = defaultValue;
-    if(contains(key)) {
-        QByteArray value = (*this)[key].toLower();
-        rc = value == "1" || value == "y" || value == "yes" || value == "t"
-             || value == "true";
-    }
-
-    return rc;
-}
-
-/**
- * Returns a configuration value.
- *
- * @param key           key of the wanted value
- * @param defaultValue  if the key does not exist this is the result
- * @return              defaultValue: key does not exist
- */
-QByteArray RplConfig::asString(const char* key, const char* defaultValue) {
-    QByteArray rc = defaultValue;
-    if(contains(key)) {
-        rc = (*this)[key];
-    }
-    return rc;
-}
-
-/**
- * Reads a configuration file.
- *
- * @param file  file to read.
- * @return      true: OK<br>
- *              false: error occurred
- */
-bool RplConfig::read(const char* file) {
-    bool rc = true;
-    m_lineList.reserve(1024);
-    FILE* fp = fopen(file, "r");
-    if(fp == NULL) {
-        m_logger->logv(LOG_ERROR, LOC_READ_1, "cannot read: %s", file);
-        rc = false;
-    } else {
-        char line[64000];
-        char* separator;
-        int lineNo = 0;
-        while(fgets(line, sizeof line, fp) != NULL) {
-            lineNo++;
-            m_lineList.append(line);
-            if(isalnum(line[0]) && (separator = strchr(line, '=')) != NULL) {
-                QByteArray key(line, separator - line);
-                QByteArray value(separator + 1);
-                key = key.trimmed();
-                value = value.trimmed();
-                if(contains(key))
-                    m_logger->logv(LOG_WARNING, LOC_READ_2,
-                                   "defined more than once: %s-%d: %s", file, lineNo, line);
-                else
-                    insert(key, value);
-            }
-        }
-    }
-    return rc;
-}
-
-/**
- * Writes a configuration file.
- *
- * @param file  file to write.
- * @return      true: OK<br>
- *              false: error occurred
- */
-bool RplConfig::write(const char* file) {
-    bool rc = false;
-    if(m_readOnly)
-        m_logger->log(LOG_ERROR, LOC_WRITE_1, "cannot write: (readonly");
-    else {
-        m_logger->logv(LOG_ERROR, LOC_WRITE_2, "not implemented: write(%s)",
-                       file);
-    }
-    return rc;
-}
-
-// ------------------
-#if ! defined RPL_TEST
-#define RPL_TEST
-#endif
-#ifdef RPL_TEST
-#include "rplcore/rpltest.hpp"
-/**
- * @brief Unit test of RplConfig.
- */
-class TestRplConfig: public RplTest {
-public:
-    TestRplConfig() :
-        RplTest("RplConfig") {
-    }
-
-public:
-    void testBasic() {
-        QByteArray fn = getTempFile("test.data", "config");
-        RplString::write(fn, "#comment\na=1\nb.1==x\n#=\nB=zzz");
-        RplConfig config(fn.constData());
-        checkE(3, config.size());
-        checkE("1", config["a"]);
-        checkE("=x", config["b.1"]);
-        checkE("zzz", config["B"]);
-    }
-    void testAsX() {
-        QByteArray fn = getTempFile("test.data", "config");
-        RplString::write(fn, "i=123\nb=1\nb2=true\nb3=yes\ns=abc");
-        RplConfig config(fn.constData());
-        checkE(5, config.size());
-        checkE(123, config.asInt("i", -1));
-        checkE(-1, config.asInt("I", -1));
-        checkT(config.asBool("b", false));
-        checkT(config.asBool("b2", false));
-        checkT(config.asBool("b3", false));
-        checkT(config.asBool("-", true));
-        checkF(config.asBool("-", false));
-        checkE("abc", config.asString("s", "x"));
-        checkE("x", config.asString("S", "x"));
-    }
-
-    virtual void doIt() {
-        testAsX();
-        testBasic();
-
-    }
-};
-
-#endif
-void testRplConfig() {
-#ifdef RPL_TEST
-    TestRplConfig test;
-    test.run();
-#endif
-}
diff --git a/rplcore/rplconfig.hpp b/rplcore/rplconfig.hpp
deleted file mode 100644 (file)
index abf3a71..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLCONFIG_HPP
-#define RPLCONFIG_HPP
-
-class RplConfig : public RplConfigurator, public QHash<QByteArray, QByteArray> {
-public:
-    RplConfig(const char* file = NULL, bool readOnly = true,
-              RplLogger* logger = NULL);
-    virtual ~RplConfig();
-
-public:
-    bool read(const char* file);
-    bool write(const char* file);
-    void clear();
-    const QList<QByteArray>& getLines() const;
-
-    virtual bool asBool(const char* key, bool defaultValue) const;
-    virtual int asInt(const char* key, int defaultValue) const;
-    virtual QByteArray asString(const char* key, const char* defaultValue);
-private:
-    void initLogger();
-private:
-    const char* m_file;
-    QList<QByteArray> m_lineList;
-    bool m_readOnly;
-    RplLogger* m_logger;
-    // true: the logger must be destroyed in the destructor
-    bool m_ownLogger;
-};
-
-#endif // RPLCONFIG_HPP
diff --git a/rplcore/rplconfigurator.hpp b/rplcore/rplconfigurator.hpp
deleted file mode 100644 (file)
index c651800..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLCONFIGURATOR_HPP
-#define RPLCONFIGURATOR_HPP
-
-class RplConfigurator {
-public:
-    virtual int asInt(const char* key, int defaultValue) const = 0;
-    virtual bool asBool(const char* key, bool defaultValue) const = 0;
-    virtual QByteArray asString(const char* key, const char* defaultValue) = 0;
-};
-
-#endif // RPLCONFIGURATOR_HPP
diff --git a/rplcore/rplcontainer.cpp b/rplcore/rplcontainer.cpp
deleted file mode 100644 (file)
index c05b7bf..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#include "rplcore/rplcore.hpp"
-
-/** @file
- * @brief Implements a portable data container.
- */
-
-/** @file rplcore/rplcontainer.hpp
- *
- * @brief Definition for a portable data container.
- */
-
-/** @class RplContainer rplcontainer.hpp "rplcore/rplcontainer.hpp"
- *
- * @brief Implements a portable data container.
- *
- * The container contains a list of "bags".
- * Each bag contains a sequence of items (with a simple data type).
- * The items are portable: transported to another architecture
- * the item is restored correct (independent of big/little endian).
- *
- * Format:
- * container ::= magic header_size_hex2 container_size_hex '[' list_count ']' bag_descr list_of_bags<br>
- * list_of_bag ::= bag1 bag2 ...<br>
- * bag_descr ::= bag_type1 bag_type2 ... ':'<br>
- * bag_types := i(nteger) ' ' | s(tring) | b(indata255) | B(indata64k) X(blob4G)<br>
- * item_list ::= item1 item2...<br>
- * The binary items (bBX) are byte sequences with a starting size element.
- * The size element can be a byte (255) or a word (64k) or a double word(4G).
- * The order of the size element is big endian.
- *
- * Example (additional blanks for readibility):
- * <pre>
- * Rpl&1 09 36[2]cis:!7b Nirwana &lt;0&gt; Y -ab34 A long string with an trailing '0' &lt;0&gt;
- * </pre>
- * magic header: Rpl&1 length: 09h data length: 46h bag count: 2 item types: char int string
- *
- */
-
-enum {
-    // 11000
-    LOC_FILL_1 = RPLMODULE_CONTAINER * 1000,
-    LOC_FILL_2,
-    LOC_FILL_3,
-    LOC_NEXT_BAG_1,
-    LOC_NEXT_ITEM_1,
-    LOC_NEXT_ITEM_2 = 11005,
-    LOC_NEXT_INT_1,
-    LOC_NEXT_ITEM_3,
-    LOC_NEXT_BAG_2,
-};
-
-const char* RplContainer::MAGIC_1 = "Rpl&1";
-
-/**
- * @brief Constructor.
- *
- * @param sizeHint      Probable length of the container
- */
-RplContainer::RplContainer(size_t sizeHint) :
-    m_data(""),
-    m_countBags(0),
-    m_typeList(""),
-    m_ixItem(0),
-    m_ixBag(0),
-    m_readPosition(NULL) {
-    if (sizeHint > 0)
-        m_data.reserve(sizeHint);
-}
-
-/**
- * @brief Destructor.
- */
-RplContainer::~RplContainer() {
-}
-
-/**
- * @brief Adds an type to the type list.
- *
- * @param tag   the type tag
- */
-void RplContainer::addType(type_tag_t tag) {
-    if(m_countBags == 0)
-        startBag();
-    if(m_countBags == 1)
-        m_typeList.append((char) tag);
-}
-
-/**
- * @brief Starts a new bag.
- */
-void RplContainer::startBag() {
-    m_countBags++;
-    m_ixBag = 0;
-}
-/**
- * @brief Adds a character to the current bag.
- *
- * @param value    value to insert
- */
-void RplContainer::addChar(char value) {
-    addType(TAG_CHAR);
-    //if (m_typeList.at(m_ixBag) != TAG_INT)
-    //   RplLogger::logAndThrow(LOG_ERROR, __FILE__, __LINE__, 1, "unexpected type: %c instead of c", m_typeList.at(m_ixBag));
-    m_data.append(value);
-}
-/**
- * @brief Adds an integer to the current bag.
- *
- * @param value    value to add
- */
-void RplContainer::addInt(int value) {
-    addType(TAG_INT);
-    char buffer[64];
-    char* ptr = buffer;
-    if(value < 0) {
-        *ptr++ = '-';
-        value = - value;
-    }
-    qsnprintf(ptr, sizeof buffer - 1, "%x ", value);
-    m_data.append(buffer);
-}
-/**
- * @brief Adds an integer to the current bag.
- *
- * @param value    value to add
- */
-void RplContainer::addInt(qint64 value) {
-    addType(TAG_INT);
-    char buffer[128];
-    qsnprintf(buffer, sizeof buffer, "%llx ", value);
-    m_data.append(buffer);
-}
-
-/**
- * @brief Adds a string to the current bag.n
- *
- * @param value    value to add
- */
-void RplContainer::addString(const char* value) {
-    addType(TAG_STRING);
-    // store with trailing '\0'
-    m_data.append(value, strlen(value) + 1);
-}
-/**
- * @brief Adds binary data to the current bag.
- *
- * @param value     binary data
- * @param size      size of the binary data in bytes
- */
-void RplContainer::addData(uint8_t* value, size_t size) {
-    if(size <= 255) {
-        addType(TAG_DATA255);
-        m_data.append((char) size);
-    } else if(size <= 0xffff) {
-        addType(TAG_DATA64K);
-        m_data.append((char)(size / 256));
-        m_data.append((char)(size % 256));
-        m_data.append((const char*) value, size);
-    } else {
-        addType(TAG_DATA4G);
-        m_data.append((char)(size / 256 / 256 / 256));
-        m_data.append((char)(size / 256 / 256 % 256));
-        m_data.append((char)(size / 256 % 256));
-        m_data.append((char)(size % 256));
-        m_data.append((const char*) value, size);
-    }
-    addType(TAG_DATA255);
-
-}
-
-/**
- * @brief Returns the container byte buffer.
- *
- * @return the container as a byte array
- */
-const QByteArray& RplContainer::getData() {
-    if(m_typeList.length() != 0) {
-        char buffer[128];
-        // RPL&1 0a b5[2]cis: !12
-        qsnprintf(buffer, sizeof buffer, "%x[%d]%s:", (unsigned int) m_data.length(),
-                 m_countBags, m_typeList.data());
-        char header[128+8];
-        qsnprintf(header, sizeof header, "%s%02x%s", MAGIC_1,
-                 (unsigned int) strlen(buffer), buffer);
-        m_data.insert(0, header);
-    }
-    return m_data;
-}
-
-/**
- * @brief Fills the container with an byte array.
- *
- * @param data      the container as a byte array
- */
-void RplContainer::fill(const QByteArray& data) {
-    m_data = data;
-    const char* ptr = m_data.data();
-    if(strncmp(ptr, MAGIC_1, strlen(MAGIC_1)) != 0)
-        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_1, "container has no magic",
-                                      data.data(), data.length());
-    ptr += strlen(MAGIC_1);
-    unsigned int headerSize = 0;
-    if(sscanf(ptr, "%02x", &headerSize) != 1)
-        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
-                                      "container has no header size", ptr, 2);
-    ptr += 2;
-
-    unsigned int dataSize = 0;
-    unsigned int countBags = 0;
-    if(sscanf(ptr, "%x[%x]", &dataSize, &countBags) != 2)
-        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
-                                      "container has no data_size[bag_count]", ptr, 16);
-    m_countBags = countBags;
-    ptr = strchr(ptr, ']') + 1;
-    const char* end = ptr + strspn(ptr, "cisdDX!");
-    if(end == ptr || *end != ':') {
-        throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
-                                      "container has no valid typelist", ptr, 16);
-    }
-    m_typeList.clear();
-    m_typeList.append(ptr, end - ptr);
-    m_ixBag = -1;
-    m_readPosition = (uint8_t*) end + 1;
-
-
-}
-/**
- * @brief Returns the number of bags in the container.
- *
- * @return the number of bags
- */
-int RplContainer::getCountBags() const {
-    return m_countBags;
-}
-/**
- * @brief Sets the begin of the new bag.
- */
-void RplContainer::nextBag() {
-    if(m_ixItem < m_typeList.length() && m_ixItem != -1)
-        throw RplException(LOG_ERROR, LOC_NEXT_BAG_1, NULL,
-                           "end of bag not reached: remaining items: %s",
-                           m_typeList.data() + m_ixItem);
-    m_ixItem = 0;
-    m_ixBag++;
-    if(m_ixBag >= m_countBags)
-        throw RplException(LOG_ERROR, LOC_NEXT_BAG_2, NULL,
-                           "no more bags: %d", m_ixBag);
-}
-/**
- * @brief Sets the next item.
- *
- * @param expected      the expected data type
- */
-void RplContainer::nextItem(type_tag_t expected) {
-    if(m_ixBag < 0) {
-        m_ixBag = 0;
-        m_ixItem = 0;
-    }
-    if(m_ixItem >= m_typeList.length())
-        throw RplException(LOG_ERROR, LOC_NEXT_ITEM_1, "no more items in the bag");
-    type_tag_t current = (type_tag_t) m_typeList.at(m_ixItem);
-    // Unify all data types:
-    if(current == TAG_DATA4G || current == TAG_DATA64K)
-        current = TAG_DATA255;
-    if(current != expected)
-        throw RplException(LOG_ERROR, LOC_NEXT_ITEM_2, NULL,
-                           "current item is a %c, not a %c",
-                           (char) m_typeList.at(m_ixItem), (char) expected);
-    m_ixItem++;
-    if(m_readPosition > (uint8_t*)(m_data.data() + m_data.length()))
-        throw RplException(LOG_ERROR, LOC_NEXT_ITEM_3, NULL,
-                           "container size too small. Bag: %d of %d Item: %d of %d",
-                           1 + m_ixBag, m_countBags, 1 + m_ixItem, m_typeList.length());
-}
-
-/**
- * @brief Reads the next character from the current item in the current bag.
- *
- * @return  the next char from the container
- */
-char RplContainer::nextChar() {
-    nextItem(TAG_CHAR);
-    char rc = *m_readPosition++;
-    return rc;
-}
-
-/**
- * @brief Reads the next integer from the current item in the current bag.
- *
- * @return  the next integer from the container
- */
-int RplContainer::nextInt() {
-    nextItem(TAG_INT);
-    bool isNegativ = *m_readPosition == '-';
-    if(isNegativ)
-        m_readPosition++;
-    unsigned int value = 0;
-    if(sscanf((const char*) m_readPosition, "%x ", &value) != 1)
-        throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
-                                      "not a hex_number<blank>", m_readPosition, 16);
-    m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
-    if(isNegativ)
-        value = - value;
-    return value;
-}
-/**
- * @brief Reads the next integer from the current item in the current bag.
- *
- * @return  the next integer from the container
- */
-qint64 RplContainer::nextInt64() {
-    nextItem(TAG_INT);
-    bool isNegativ = *m_readPosition == '-';
-    if(isNegativ)
-        m_readPosition++;
-    qint64 value = 0;
-    if(sscanf((const char*) m_readPosition, "%llx ", &value) != 1)
-        throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
-                                      "not a hex_number<blank>", m_readPosition, 16);
-    m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
-    if(isNegativ)
-        value = - value;
-    return value;
-}
-
-/**
- * @brief Reads the next string from the current item in the current bag.
- *
- * @return  the next '\0' delimited string from the container
- */
-const char* RplContainer::nextString() {
-    nextItem(TAG_STRING);
-    const char* rc = (const char*) m_readPosition;
-    m_readPosition += strlen(rc) + 1;
-    return rc;
-}
-
-/**
- * @brief Reads the next string from the current item in the current bag.
- *
- * @param data      OUT: the next data item from the container
- * @param append    true: the item data will be appended to data<br>
- *                  false: data contains the item data only
- * @return          the size of the read data
- */
-size_t RplContainer::nextData(QByteArray& data, bool append) {
-    nextItem(TAG_DATA255);
-    type_tag_t tag = (type_tag_t) m_typeList.at(m_ixItem - 1);
-    size_t length = 0;
-    switch(tag) {
-    case TAG_DATA4G:
-        for(int ix = 3; ix >= 0; ix--) {
-            length = 256 * length + m_readPosition[ix];
-        }
-        m_readPosition += 4;
-        break;
-    case TAG_DATA64K:
-        length = *m_readPosition++ * 256;
-        length += *m_readPosition++;
-        break;
-    case TAG_DATA255:
-        length = *m_readPosition++;
-        break;
-    default:
-        break;
-    }
-    if(! append)
-        data.clear();
-    data.append((const char*) m_readPosition, length);
-    m_readPosition += length;
-    return length;
-}
-
-
-
-/**
- * @brief Dumps a container as a human readable string.
- *
- * @param title             will be used in the first line
- * @param maxBags           if there are more bags they will be ignored
- * @param maxStringLength   if strings are longer the will be cut
- * @param maxBlobLength     maximum count of bytes which will be dumped
- * @param separatorItems    separator between two items, e.g. '\\n' or '|'
- * @return                  a human readable string describing the container
- */
-QByteArray RplContainer::dump(const char* title,
-                              int maxBags, int maxStringLength, int maxBlobLength,
-                              char separatorItems) {
-    QByteArray rc;
-    rc.reserve(64000);
-    rc.append("=== ").append(title).append('\n');
-    rc.append("Bags: ").append(RplString::toNumber(m_countBags));
-    rc.append(" Types: ").append(m_typeList).append('\n');
-    // save the current state:
-    int safeIxBag = m_ixBag;
-    int safeIxItem = m_ixItem;
-    m_ixBag = -1;
-    m_ixItem = 0;
-    int iValue;
-    QByteArray sValue;
-    if(maxBags > m_countBags)
-        maxBags = m_countBags;
-    for(int ixBag = 0; ixBag < maxBags; ixBag++) {
-        rc.append("--- bag ").append(RplString::toNumber(ixBag)).append(":\n");
-        nextBag();
-        QByteArray item;
-        int maxLength;
-        for(int ixItem = 0; ixItem < m_typeList.length(); ixItem++) {
-            type_tag_t currentType = (type_tag_t) m_typeList.at(ixItem);
-            switch(currentType) {
-            case TAG_CHAR:
-                rc.append(" c: ").append(nextChar()).append(separatorItems);
-                break;
-            case TAG_INT:
-                iValue = nextInt();
-                rc.append(" i: ").append(RplString::toNumber(iValue)).append(" / ");
-                rc.append(RplString::toNumber(iValue, "%x")).append(separatorItems);
-                break;
-            case TAG_STRING:
-                sValue = nextString();
-                if(sValue.length() > maxStringLength)
-                    sValue = sValue.left(maxStringLength);
-                rc.append(" s: ").append(sValue).append(separatorItems);
-                break;
-            case TAG_DATA255:
-            case TAG_DATA64K:
-            case TAG_DATA4G:
-                nextData(item, false);
-                rc.append(' ').append((char) currentType).append(": [");
-                rc.append(RplString::toNumber(item.length())).append("] ");
-                maxLength = item.length() < maxBlobLength ? item.length() : maxBlobLength;
-                rc.append(RplString::hexDump(item.data(), maxLength,
-                                             16)).append(separatorItems);
-                break;
-            default:
-                break;
-            }
-        }
-    }
-
-    // restore the current state:
-    m_ixBag = safeIxBag;
-    m_ixItem = safeIxItem;
-    return rc;
-}
-
-// ------------------
-#if ! defined RPL_TEST
-#define RPL_TEST
-#endif
-#ifdef RPL_TEST
-#include "rplcore/rpltest.hpp"
-/**
- * @brief Unit test for <code>RplContainer</code>
- */
-class TestRplContainer : public RplTest {
-public:
-    TestRplContainer() : RplTest("RplContainer") {}
-
-public:
-    void testBasic() {
-        RplContainer container(256);
-        //  Rpl&1 09 36[2]cis:!7b Nirwana &lt;0&gt; Y -ab34 A long string with an trailing '0' &lt;0&gt<br>
-        container.startBag();
-        container.addChar('!');
-        container.addInt(123);
-        container.addString("Nirwana");
-        container.startBag();
-        container.addChar('Y');
-        container.addInt(-0xab34);
-        container.addString("A long string with an trailing '0'");
-
-        QByteArray data = container.getData();
-
-        RplContainer container2(256);
-        container2.fill(data);
-        checkE(2, container2.getCountBags());
-        checkE('!', container2.nextChar());
-        checkE(123, container2.nextInt());
-        checkE("Nirwana", container2.nextString());
-        container2.nextBag();
-        checkE('Y', container2.nextChar());
-        checkE(-0xab34, container2.nextInt());
-        checkE("A long string with an trailing '0'", container2.nextString());
-
-        log(("Example: " + data).constData());
-    }
-
-    virtual void doIt() {
-        testBasic();
-    }
-};
-
-#endif
-void testRplContainer() {
-#ifdef RPL_TEST
-    TestRplContainer test;
-    test.run();
-#endif
-}
diff --git a/rplcore/rplcontainer.hpp b/rplcore/rplcontainer.hpp
deleted file mode 100644 (file)
index 621a616..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLCONTAINER_HPP
-#define RPLCONTAINER_HPP
-
-// the sources generated from QT include this file directly:
-#ifndef RPLCORE_HPP
-#include <QByteArray>
-#include <QDataStream>
-#endif
-class RplContainer {
-public:
-    typedef enum {
-
-        TAG_CHAR = 'c',     ///< one character
-        TAG_INT = 'i',      ///< an integer number, up to 64 bit
-        TAG_STRING = 's',   ///< a string ending with a '\\0'
-        TAG_DATA255 = 'd',  ///< binary data, up to 255 bytes long
-        TAG_DATA64K = 'D',  ///< binary data, up to 64 KiBytes long
-        TAG_DATA4G = 'X',   ///< binary data, up to 4 GiBytes long
-        TAG_CONTAINER = '!' ///< a container (recursion)
-    } type_tag_t;
-    static const char* MAGIC_1;
-public:
-    RplContainer(size_t sizeHint);
-    virtual ~RplContainer();
-private:
-    // No copy constructor: no implementation!
-    RplContainer(const RplContainer& source);
-    // Prohibits assignment operator: no implementation!
-    RplContainer& operator =(const RplContainer& source);
-public:
-    // Building the container:
-    void addType(type_tag_t tag);
-    void startBag();
-    void addChar(char cc);
-    void addInt(int value);
-    void addInt(qint64 value);
-    void addString(const char* value);
-    void addData(uint8_t* value, size_t size);
-    const QByteArray& getData();
-
-    // Getting data from the container:
-    void fill(const QByteArray& data);
-    int getCountBags() const;
-    const char* getTypeList() const;
-    void nextBag();
-    char nextChar();
-    int nextInt();
-    qint64 nextInt64();
-    const char* nextString();
-    size_t nextData(QByteArray& data, bool append = false);
-
-    QByteArray dump(const char* title,
-                    int maxBags, int maxStringLength = 80, int maxBlobLength = 16,
-                    char separatorItems = '\n');
-private:
-    void nextItem(type_tag_t expected);
-private:
-    // the complete data of the container
-    QByteArray m_data;
-    // the number of elements in the container
-    int m_countBags;
-    // a string with the data types of a bag
-    QByteArray m_typeList;
-
-    // Getting data from the container:
-
-    // current read position in m_typeList
-    int m_ixItem;
-    // the index of the current current bag:
-    int m_ixBag;
-    // read position in m_data:
-    const uint8_t* m_readPosition;
-};
-
-#endif // RPLCONTAINER_HPP
diff --git a/rplcore/rplcore.hpp b/rplcore/rplcore.hpp
deleted file mode 100644 (file)
index 8df4f75..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLCORE_HPP
-#define RPLCORE_HPP
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <assert.h>
-
-#include <QAbstractSocket>
-#include <QTcpSocket>
-#include <QTcpServer>
-#include <QThread>
-#include <QIODevice>
-#include <QTextStream>
-#include <QHash>
-#include <QVector>
-#include <QDataStream>
-#include <QMutex>
-#include <QRegularExpression>
-#include <QtMath>
-
-typedef unsigned char uint8_t;
-#define RPL_UNUSED(x) (void)(x)
-
-#include "rplmodules.hpp"
-#include "rplcore/rplbytestorage.hpp"
-#include "rplcore/rplcharptrmap.hpp"
-#include "rplcore/rplwriter.hpp"
-#include "rplcore/rpllogger.hpp"
-#include "rplcore/rplexception.hpp"
-#include "rplcore/rplcontainer.hpp"
-#include "rplcore/rplstring.hpp"
-#include "rplcore/rplqstring.hpp"
-#include "rplcore/rplconfigurator.hpp"
-#include "rplcore/rplconfig.hpp"
-#include "rplcore/rplterminator.hpp"
-
-#endif // RPLCORE_HPP
diff --git a/rplcore/rplexception.cpp b/rplcore/rplexception.cpp
deleted file mode 100644 (file)
index fac935f..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-/** @mainpage
- *
- * @note A real public library for QT.
- *
- * This library contains the module groups
- * <ul>
- * <li>rplcore: basic definitions, used in all other module groups</li>
- * <li>rplmath: mathematic definitions and tools</li>
- * <li>rplexpr: definition for parsing and interpretation of languages</li>
- * <li>rplnet: definitions and tools for tcp/udp communication</li>
- * </ul>
- *
- * Each module group has a central include file, which organizes the necessary
- * include files. You had to include only the central include file.
- *
- * Example:
- * <pre><code>
- * #include "rplcore/rplcore.hpp"
- * #include "rplexpr/rplexpr.hpp"
- * </code></pre>
- * In this case all definitions of rplcore and rplexpr are available.
- */
-/** @file
- * @brief Generally usable exceptions.
- */
-/** @file rplcore/rplexception.hpp
- *
- * @brief Definitions for a generally usable exceptions.
- */
-#include "rplcore/rplcore.hpp"
-
-/** @class RplException rplexception.hpp "rplcore/rplexception.hpp"
- *
- * @brief A generally usable exception with or without logging.
- *
- * <b>Note</b>: If the logger is not given by parameter
- * the usage of the global logger is not threadsafe.
- */
-class RplException;
-
-
-/**
- * @brief Constructor.
- *
- * For derived classes only!
- */
-RplException::RplException() :
-    m_message("")
-{
-}
-
-/**
- * @brief Constructor.
- *
- * @param format    the reason of the exception
- * @param ...       the values for the placeholders in the format.
- */
-RplException::RplException(const char* format, ...) :
-    m_message("") {
-    char buffer[64000];
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    m_message = buffer;
-}
-
-/**
- * @brief Constructor.
- *
- * This constructor automatically logs the given data.
- *
- * @param level     the logging level, e.g. LOG_ERROR
- * @param location  an unique identifier for the location
- *                  where the exception was thrown
- * @param format    the reason of the exception.
- *                  Can contain placeholders (@see
- *                  std::printf())
- * @param ...       the values of the placeholders
- *                  in <code>format</code>
- * @param logger    if NULL the global logger will be used
- */
-RplException::RplException(RplLoggerLevel level, int location,
-                           RplLogger* logger, const char* format, ...) :
-    m_message("") {
-    char buffer[64000];
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    m_message = buffer;
-    if(logger == NULL)
-        logger = RplLogger::globalLogger();
-    logger->log(level, location, buffer);
-}
-
-
-/** @class RplRangeException rplexception.hpp "rplcore/rplexception.hpp"
- *
- * @brief An exception for integer range errors.
- *
- * The error will be logged.
- *
- * <b>Note</b>: If the logger is not given by parameter
- * the usage of the global logger is not threadsafe.
- */
-
-/**
- * @brief Constructor.
- *
- * This exception can be used if a value does not be
- * inside a given range.
- *
- * This constructor automatically logs the given data.
- *
- * @param level     the logging level, e.g. LOG_ERROR
- * @param location  an unique identifier for the location
- *                  where the exception was thrown
- * @param current   the current value
- * @param lbound    the minimum of the allowed values
- * @param ubound    the maximum of the allowed values
- * @param message   the reason. If NULL a generic
- *                  message will be used
- * @param logger    if NULL the global logger will be used
- */
-
-RplRangeException::RplRangeException(RplLoggerLevel level, int location,
-                                     size_t current,
-                                     size_t lbound, size_t ubound, const char* message, RplLogger* logger) :
-    RplException("") {
-    char buffer[64000];
-    if(message == NULL)
-        message = "value outside limits";
-    qsnprintf(buffer, sizeof buffer, "%s: %lu [%lu, %lu]",
-             message == NULL ? "" : message,
-             current, lbound, ubound);
-    if(logger == NULL)
-        logger = RplLogger::globalLogger();
-    logger->log(level, location, buffer);
-}
-
-/** @class RplInvalidDataException rplexception.hpp "rplcore/rplexception.hpp"
- *
- * @brief An exception usable if binary data have the wrong structure.
- *
- * The data will be dumped as hex and ASCII dump.
- *
- * <b>Note</b>: If the logger is not given by parameter
- * the usage of the global logger is not threadsafe.
- */
-
-/**
- * @brief Constructor.
- *
- * This exception can be used if data does not have a given fomat.
- *
- * This constructor automatically logs the given data. This data
- * will be dumped (hexadecimal dump and ASCII interpretation).
- *
- * @param level     the logging level, e.g. LOG_ERROR
- * @param location  an unique identifier for the location
- *                  where the exception was thrown
- * @param message   the reason
- * @param data      pointer to binary data
- * @param dataSize  the size of the data which should be dumped
- * @param logger    if NULL the global logger will be used
- */
-RplInvalidDataException::RplInvalidDataException(RplLoggerLevel level,
-        int location,
-        const char* message, const void* data,
-        size_t dataSize, RplLogger* logger) :
-    RplException("") {
-    char buffer[64000];
-    if(message == NULL)
-        message = "invalid data: ";
-    if(data == NULL)
-        data = "";
-    if(dataSize > 16)
-        dataSize = 16;
-    size_t ix;
-    char* ptr = buffer + strlen(buffer);
-    for(ix = 0; ix < dataSize; ix++) {
-        qsnprintf(ptr, sizeof(buffer) - (ptr - buffer) - 1, "%02x ",
-                 ((unsigned char*) data)[ix]);
-        ptr += strlen(ptr);
-    }
-    for(ix = 0; ix < dataSize; ix++) {
-        char cc = ((char*) data)[ix];
-        if(cc > ' ' && cc <= '~')
-            *ptr++ = cc;
-        else
-            *ptr++ = '.';
-    }
-    if(logger == NULL)
-        logger = RplLogger::globalLogger();
-    logger->log(level, location, buffer);
-}
diff --git a/rplcore/rplexception.hpp b/rplcore/rplexception.hpp
deleted file mode 100644 (file)
index 64fd530..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLEXCEPTION_HPP
-#define RPLEXCEPTION_HPP
-
-// the sources generated from QT include this file directly:
-#ifndef RPLCORE_HPP
-#include <QByteArray>
-#endif
-
-class RplException {
-protected:
-    RplException();
-public:
-    RplException(const char* message, ...);
-    RplException(RplLoggerLevel level, int location, const char* message,
-                 RplLogger* logger = NULL);
-    RplException(RplLoggerLevel level, int location, RplLogger* logger,
-                 const char* message, ...);
-    const QByteArray& getMessage() const {
-        return m_message;
-    }
-protected:
-    QByteArray m_message;
-};
-
-class RplRangeException : public RplException {
-public:
-    RplRangeException(RplLoggerLevel level, int location, size_t current,
-                      size_t lbound, size_t ubound,
-                      const char* message = NULL, RplLogger* logger = NULL);
-};
-
-class RplInvalidDataException : public RplException {
-public:
-    RplInvalidDataException(RplLoggerLevel level, int location, const char* message,
-        const void* data = NULL, size_t dataSize = 0, RplLogger* logger = NULL);
-};
-
-#endif // RPLEXCEPTION_HPP
diff --git a/rplcore/rpllogger.cpp b/rplcore/rpllogger.cpp
deleted file mode 100644 (file)
index 84f20f7..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-
-/** @file
- * A configurable logger for different output media.
- */
-/** @file rplcore/rpllogger.hpp
- *
- * Definitions for a configurable logger for different output media.
- */
-#include "rplcore/rplcore.hpp"
-#include <QDir>
-#include <iostream>
-
-enum {
-    LOC_ADD_APPENDER_1 = RPL_FIRST_OF(RPLMODULE_LOGGER), // 10101
-};
-
-RplLogger* RplLogger::m_globalLogger = NULL;
-
-/**
- * @brief Returns the global logger.
- *
- * If it does not exist it will be created (singleton).
- *
- * @return the global logger
- */
-RplLogger* RplLogger::globalLogger() {
-    if(m_globalLogger == NULL) {
-        m_globalLogger = new RplLogger();
-        m_globalLogger->buildStandardAppender("globallogger");
-    }
-    return m_globalLogger;
-}
-/**
- * @brief Frees the resources of the global logger.
- */
-void RplLogger::destroyGlobalLogger() {
-    delete m_globalLogger;
-    m_globalLogger = NULL;
-}
-
-/** @class RplAppender rpllogger.hpp "rplcore/rpllogger.hpp"
- *
- * @brief Puts the logging info to a medium (e.g. a file).
- *
- * This is an abstract base class.
- */
-
-/**
- * @brief Constructor.
- *
- * @param name         identifies the logger. Useful for RplLogger::findLogger()
- */
-RplAppender::RplAppender(const QByteArray& name) :
-    m_name(name),
-    m_level(LOG_INFO) {
-
-}
-/**
- * @brief Destructor.
- */
-RplAppender::~RplAppender() {
-}
-
-/**
- * Returns the name.
- *
- * @return             the name of the instance
- */
-const char* RplAppender::getName() const {
-    return m_name.data();
-}
-
-/**
- * @brief Sets the level.
- *
- * @param level
- */
-void RplAppender::setLevel(RplLoggerLevel level) {
-    m_level = level;
-}
-/**
- * @brief Returns the level.
- *
- * @return             the level
- */
-RplLoggerLevel RplAppender::getLevel() const {
-    return m_level;
-}
-/**
- * @brief Checks whether the current location should be logged.
- *
- * @param level                the level of the location.
- * @return                     true: the location level is greater or equals to the appender's level
- */
-bool RplAppender::isActive(RplLoggerLevel level) {
-    return level <= m_level;
-}
-
-/**
- * @brief Sets or clears the automatic deletions.
- *
- * @param onNotOff             the state of the auto deletion
- */
-void RplAppender::setAutoDelete(bool onNotOff) {
-    m_autoDelete = onNotOff;
-}
-
-/**
- * @brief Returns the state of the auto deletion.
- *
- * @return     true: the logger destroys the instance
- */
-bool RplAppender::isAutoDelete() const {
-    return m_autoDelete;
-}
-
-/** @class RplLogger rpllogger.hpp "rplcore/rpllogger.hpp"
- *
- * @brief Implements a logger.
- *
- * The logger takes the call from the calling location.
- * But the output assumes the class <code>RplAppender</code>,
- * more exactly: a subclass from the abstract class
- * <code>RplAppender</code>,
- *
- * For single threaded applications there is a possability of
- * a global logger. In this case the logger can be got with the static
- * method <code>RplLogger::globalLogger()</code>.
- *
- * <b>Note</b>: using the global logger is <b>not threadsafe</b>!
- *
- * Each call of the logger should be provided by a <b>unique identifier</b>
- * named the <b>location</b>. This allows to find the error quickly.
- */
-
-/**
- * @brief Constructor.
- */
-RplLogger::RplLogger() :
-    // m_appenders(),
-    m_countAppenders(0),
-    m_stdPrefix(),
-    m_mutex(),
-    m_withLocking(false) {
-    memset(m_appenders, 0, sizeof m_appenders);
-}
-
-/**
- * @brief Destructor.
- */
-RplLogger::~RplLogger() {
-    for(size_t ix = 0; ix < m_countAppenders; ix++) {
-        RplAppender* appender = m_appenders[ix];
-        if(appender->isAutoDelete()) {
-            delete appender;
-        }
-        m_appenders[ix] = NULL;
-    }
-}
-/**
- * @brief Returns the first char of a logging line displaying the logging level.
- *
- * @param level                the level to "convert"
- * @return                     the assigned prefix char
- */
-char RplLogger::getPrefixOfLevel(RplLoggerLevel level) const {
-    char rc = ' ';
-    switch(level) {
-    case LOG_ERROR:
-        rc = '!';
-        break;
-    case LOG_WARNING:
-        rc = '+';
-        break;
-    case LOG_INFO:
-        rc = ' ';
-        break;
-    case LOG_DEBUG:
-        rc = '=';
-        break;
-    default:
-        rc = '?';
-        break;
-    }
-    return rc;
-}
-
-/**
- * @brief Tests whether at least one appender is active for a given level.
- *
- * @param level     level to test
- * @return          false: all appenders are not activated by this level<br>
- *                  true: otherwise
- */
-bool RplLogger::isActive(RplLoggerLevel level) const {
-    bool rc = false;
-    for(size_t ix = 0; ix < m_countAppenders; ix++) {
-        RplAppender* appender = m_appenders[ix];
-        if(appender->isActive(level)) {
-            rc = true;
-            break;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Sets the log level for all appenders.
- *
- * @param level     level to set
- */
-void RplLogger::setLevel(RplLoggerLevel level) {
-    for(size_t ix = 0; ix < m_countAppenders; ix++) {
-        RplAppender* appender = m_appenders[ix];
-        appender->setLevel(level);
-    }
-}
-
-/**
- * @brief Sets or clears the state "with locking".
- *
- * @param onNotOff   true: the logger is thread save.<br>
- *                   false: not thread save
- */
-void RplLogger::setWithLocking(bool onNotOff) {
-    m_withLocking = onNotOff;
-}
-
-/**
- * @brief Returns the standard prefix of a logging line.
- *
- * If it does not exist it will be created.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @return                     the standard logging line prefix
- */
-const QByteArray& RplLogger::getStdPrefix(RplLoggerLevel level, int location) {
-    if(m_stdPrefix.isEmpty())
-        m_stdPrefix = buildStdPrefix(level, location);
-    return m_stdPrefix;
-}
-
-/**
- * @brief Logs (or not) the calling location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param message      the logging message
- * @return                     true: for chaining
- */
-bool RplLogger::log(RplLoggerLevel level, int location, const char* message) {
-    m_stdPrefix = "";
-    bool first = true;
-    for(size_t ix = 0; ix < m_countAppenders; ix++) {
-        RplAppender* appender = m_appenders[ix];
-        if(appender->isActive(level)) {
-            if(first && m_withLocking)
-                m_mutex.lock();
-            appender->log(level, location, message, this);
-        }
-    }
-    if(! first && m_withLocking)
-        m_mutex.unlock();
-    return true;
-}
-/**
- * @brief Logs (or not) the calling location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param message      the logging message
- * @return                     true: for chaining
- */
-bool RplLogger::log(RplLoggerLevel level, int location,
-                    const QByteArray& message) {
-    return log(level, location, message.data());
-}
-
-/**
- * @brief Logs (or not) the calling location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param message      the logging message
- * @return                     true: for chaining
- */
-bool RplLogger::log(RplLoggerLevel level, int location,
-                    const QString& message) {
-    return log(level, location, message.toUtf8().data());
-}
-
-/**
- * @brief Logs (or not) the calling location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param format       the logging message with placeholders (like printf).
- * @param ...          the values of the placeholders (varargs)
- * @return                     true: for chaining
- */
-bool RplLogger::logv(RplLoggerLevel level, int location, const char* format,
-                     ...) {
-    char buffer[64000];
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    return log(level, location, buffer);
-}
-
-/**
- * @brief Logs (or not) the calling location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param format       the logging message with placeholders (like printf).
- * @param ...          the values of the placeholders (varargs)
- * @return                     true: for chaining
- */
-bool RplLogger::logv(RplLoggerLevel level, int location,
-                     const QByteArray& format, ...) {
-    char buffer[64000];
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    return log(level, location, buffer);
-}
-
-/**
- * @brief Logs (or not) the calling location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param format       the logging message with placeholders (like printf).
- * @param varlist      variable arguments
- * @return                     true: for chaining
- */
-bool RplLogger::log(RplLoggerLevel level, int location, const char* format,
-                    va_list& varlist) {
-    char buffer[64000];
-    qvsnprintf(buffer, sizeof buffer, format, varlist);
-    return log(level, location, buffer);
-}
-
-/**
- * @brief Builds the standard prefix of a logging line.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- */
-QByteArray RplLogger::buildStdPrefix(RplLoggerLevel level, int location) {
-    time_t now = time(NULL);
-    struct tm* now2 = localtime(&now);
-    char buffer[64];
-    qsnprintf(buffer, sizeof buffer, "%c%d.%02d.%02d %02d:%02d:%02d (%d): ",
-             getPrefixOfLevel(level),
-             now2->tm_year + 1900,
-             now2->tm_mon + 1,
-             now2->tm_mday,
-             now2->tm_hour,
-             now2->tm_min,
-             now2->tm_sec,
-             location);
-    return QByteArray(buffer);
-}
-
-/**
- * @brief Adds an appender.
- *
- * @param appender             appender to add
- */
-void RplLogger::addAppender(RplAppender* appender) {
-    if(m_countAppenders < sizeof m_appenders / sizeof m_appenders[0]) {
-        m_appenders[m_countAppenders++] = appender;
-    } else {
-        log(LOG_ERROR, LOC_ADD_APPENDER_1, "too many appenders");
-    }
-}
-
-/**
- * @brief Returns the appender with a given name.
- *
- * @param name  the appender's name
- *
- * @return      NULL: no appender with this name is registered<br>
- *              otherwise: the wanted appender
- */
-RplAppender* RplLogger::findAppender(const char* name) const {
-    RplAppender* rc = NULL;
-    for(size_t ix = 0; ix < m_countAppenders; ix++) {
-        RplAppender* current = m_appenders[ix];
-        if(strcmp(name, current->getName()) == 0) {
-            rc = current;
-            break;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Builds the standard appender configured by a configuration file.
- *
- * @param config               configuration file
- * @param prefix        the prefix of the key in the config file
- *                      (in front of "name")
- * @param defaultLogfilePrefix
- *                      the prefix of the log file if no entry in the
- *                      configuration file
- */
-void RplLogger::buildStandardAppender(RplConfig* config,
-                                      const char* prefix,
-                                      const char* defaultLogfilePrefix) {
-    QByteArray sPrefix(prefix);
-    QByteArray logFilePrefix = config->asString(sPrefix + "name",
-                                                defaultLogfilePrefix);
-
-    int maxSize = config->asInt( + "maxsize", 10100100);
-    int maxCount = config->asInt(sPrefix + "maxfiles", 5);
-    buildStandardAppender(logFilePrefix, maxSize, maxCount);
-    QByteArray sLevel = config->asString(sPrefix + "level", "info");
-    RplLoggerLevel level = LOG_INFO;
-    if (strcasecmp(sLevel.constData(), "error") == 0)
-        level = LOG_ERROR;
-    else if (strcasecmp(sLevel, "warning") == 0)
-        level = LOG_WARNING;
-    else if (strcasecmp(sLevel, "debug") == 0)
-        level = LOG_DEBUG;
-    setLevel(level);
-}
-
-/**
- * @brief Builds the standard appender for the instance: a console logger and a file logger.
- *
- * @param prefix               the prefix of the log file name, e.g. /var/log/server
- * @param maxSize              the maximum of the file size
- * @param maxCount             the maximal count of files. If neccessary the oldest file will be deleted
- */
-void RplLogger::buildStandardAppender(const QByteArray& prefix, int maxSize,
-                                      int maxCount) {
-    RplStreamAppender* streamAppender = new RplStreamAppender(stderr);
-    streamAppender->setAutoDelete(true);
-    addAppender((RplAppender*) streamAppender);
-    RplFileAppender* fileAppender = new RplFileAppender(prefix, maxSize, maxCount);
-    fileAppender->setAutoDelete(true);
-    addAppender((RplAppender*) fileAppender);
-}
-
-/** @class RplStreamAppender rpllogger.hpp "rplcore/rpllogger.hpp"
- *
- * @brief Puts the logging info to a standard output stream.
- *
- * The possible streams are <code>std::stdout</code> or  <code>std::stderr</code>
- */
-
-
-/**
- * @brief Constructor.
- */
-RplStreamAppender::RplStreamAppender(FILE* file, const char* appenderName) :
-    RplAppender(QByteArray(appenderName)),
-    m_fp(file) {
-}
-
-/**
- * @brief Destructor.
- */
-RplStreamAppender::~RplStreamAppender() {
-    fflush(m_fp);
-}
-
-
-/**
- * @brief Logs (or not) the current location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param message      the logging message
- * @param logger    the calling logger
- */
-void RplStreamAppender::log(RplLoggerLevel level, int location,
-                            const char* message, RplLogger* logger) {
-    const QByteArray& prefix = logger->getStdPrefix(level, location);
-    fputs(prefix, m_fp);
-    fputs(message, m_fp);
-    fputc('\n', m_fp);
-    fflush(m_fp);
-}
-#pragma GCC diagnostic warning "-Wunused-parameter"
-
-
-/** @class RplFileAppender rpllogger.hpp "rplcore/rpllogger.hpp"
- *
- * @brief Puts the logging info to a file.
- *
- * The appender creates a collection of files to limit the used disk space.
- * Each logfile is limited to a given size. And the number of files is limited.
- * If the count exceeds the oldest file will be deleted.
- *
- * Each logfile's name has a given name prefix, a running number
- * and the suffix ".log", e.g. "globallogger.003.log".
- */
-
-/**
- * @brief Constructor.
- *
- * @param prefix               the prefix of the log file name, e.g. /var/log/server
- * @param maxSize              the maximum of the file size
- * @param maxCount             the maximal count of files. If neccessary the oldest file will be deleted
- * @param appenderName the name of the appender. @see RplLogger::findAppender()
- */
-RplFileAppender::RplFileAppender(const QByteArray& prefix, int maxSize,
-                                 int maxCount, const char* appenderName) :
-    RplAppender(QByteArray(appenderName)),
-    m_prefix(prefix),
-    m_maxSize(maxSize),
-    m_maxCount(maxCount),
-    m_currentSize(0),
-    m_currentNo(0),
-    m_fp(NULL) {
-    open();
-}
-
-/**
- * @brief Destructor.
- */
-RplFileAppender::~RplFileAppender() {
-    if(m_fp != NULL) {
-        fclose(m_fp);
-        m_fp = NULL;
-    }
-}
-
-/**
- * @brief Opens the next log file.
- */
-void RplFileAppender::open() {
-    if(m_fp != NULL)
-        fclose(m_fp);
-    char fullName[512];
-    qsnprintf(fullName, sizeof fullName, "%s.%03d.log", m_prefix.data(),
-             ++m_currentNo);
-    m_fp = fopen(fullName, "a");
-    if(m_fp == NULL)
-        fprintf(stderr, "cannot open: %s\n", fullName);
-    else {
-        //@ToDo
-        m_currentSize = 0;
-    }
-}
-
-/**
- * @brief Logs (or not) the current location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param message      the logging message
- * @param logger    the calling logger
- */
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-void RplFileAppender::log(RplLoggerLevel level, int location,
-                          const char* message,
-                          RplLogger* logger) {
-    if(m_fp != NULL) {
-        const QByteArray& prefix = logger->getStdPrefix(level, location);
-        fputs(prefix, m_fp);
-        fputs(message, m_fp);
-        fputc('\n', m_fp);
-        fflush(m_fp);
-    }
-}
-#pragma GCC diagnostic warning "-Wunused-parameter"
-
-/** @class RplMemoryAppender rpllogger.hpp "rplcore/rpllogger.hpp"
- *
- * @brief Puts the logging info to an internal buffer.
- *
- * This line list can be required: <code>getLines()</code>.
- */
-
-/**
- * @brief Constructor.
- *
- * @param maxLines      the maximum of lines.
- *                      If the buffer is full the oldest lines will be deleted
- * @param appenderName  NULL or the name of the appender
- */
-RplMemoryAppender::RplMemoryAppender(int maxLines, const char* appenderName) :
-    RplAppender(appenderName),
-    m_lines(),
-    m_maxLines(maxLines),
-    m_addPrefix(true)
-{
-    m_lines.reserve(maxLines);
-}
-
-/**
- * @brief Destructor.
- */
-RplMemoryAppender::~RplMemoryAppender() {
-}
-
-/**
- * Logs (or not) the current location.
- *
- * @param level                the level of the location
- * @param location     an unique identifier of the location
- * @param message      the logging message
- * @param logger    the calling logger
- */
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-void RplMemoryAppender::log(RplLoggerLevel level, int location,
-                            const char* message,
-                            RplLogger* logger) {
-    if(m_lines.size() >= m_maxLines)
-        m_lines.removeFirst();
-    if (! m_addPrefix)
-        m_lines.append(message);
-    else {
-        QByteArray msg(logger->getStdPrefix(level, location));
-        msg += message;
-        m_lines.append(msg);
-    }
-}
-#pragma GCC diagnostic warning "-Wunused-parameter"
-
-/**
- * @brief Returns the list of lines.
- *
- * @return the line list
- */
-const QList<QByteArray>& RplMemoryAppender::getLines() const {
-    return m_lines;
-}
-
-/**
- * @brief Deletes all log lines.
- */
-void RplMemoryAppender::clear() {
-    m_lines.clear();
-}
diff --git a/rplcore/rpllogger.hpp b/rplcore/rpllogger.hpp
deleted file mode 100644 (file)
index 791d14c..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLLOGGER_HPP
-#define RPLLOGGER_HPP
-
-/**
- *
- */
-class RplLogger;
-class RplConfig;
-/**
- * @brief Logging level: for controlling of the logging.
- *
- * Each logging location defines one of the following level.
- * If the level of an appender is lower or equals to this level
- * the logging is done.
- */
-enum RplLoggerLevel {
-    LOG_ERROR = 10,         ///< marks an error.
-    LOG_WARNING = 15,       ///< marks a warning
-    LOG_INFO = 20,          ///< marks an information
-    LOG_DEBUG = 25          ///< for debug purpose only
-};
-
-class RplAppender {
-public:
-    RplAppender(const QByteArray& name);
-    virtual ~RplAppender();
-private:
-    // No copy constructor: no implementation!
-    RplAppender(const RplAppender& source);
-    // Prohibits assignment operator: no implementation!
-    RplAppender& operator =(const RplAppender& source);
-public:
-    virtual void log(RplLoggerLevel level, int location, const char* message,
-                     RplLogger* logger) = 0;
-    bool isActive(RplLoggerLevel level);
-    void setLevel(RplLoggerLevel level);
-    void setAutoDelete(bool onNotOff);
-    bool isAutoDelete() const;
-    RplLoggerLevel getLevel() const;
-    const char* getName() const;
-
-private:
-    // Name of the appender. Used to find the appender in a list of appenders
-    QByteArray m_name;
-    // only locations with a lower or equal level will be logged
-    RplLoggerLevel m_level;
-    // true: the logger destroys the instance. false: the deletion must be done outside of the logger
-    bool m_autoDelete;
-};
-
-class RplLogger {
-public:
-    static RplLogger* globalLogger();
-    static void destroyGlobalLogger();
-private:
-    // the standard logger, can be called (with globalLogger()) from each location
-    static RplLogger* m_globalLogger;
-public:
-    RplLogger();
-    virtual ~RplLogger();
-private:
-    // No copy constructor: no implementation!
-    RplLogger(const RplLogger& source);
-    // Prohibits assignment operator: no implementation!
-    RplLogger& operator =(const RplLogger& source);
-public:
-    bool log(RplLoggerLevel level, int location, const char* message);
-    bool log(RplLoggerLevel level, int location, const QByteArray& message);
-    bool log(RplLoggerLevel level, int location, const QString& message);
-    bool logv(RplLoggerLevel level, int location, const char* format, ...);
-    bool logv(RplLoggerLevel level, int location, const QByteArray& format, ...);
-    bool log(RplLoggerLevel level, int location, const char* format,
-             va_list& varlist);
-    void addAppender(RplAppender* appender);
-    RplAppender* findAppender(const char* name) const;
-    void buildStandardAppender(RplConfig* config, const char* prefix = "logfile.",
-                               const char* defaultLoggerName = "logger");
-    void buildStandardAppender(const QByteArray& prefix, int maxSize = 10*1024*1024,
-                               int maxCount = 5);
-    QByteArray buildStdPrefix(RplLoggerLevel level, int location);
-    const QByteArray& getStdPrefix(RplLoggerLevel level, int location);
-    char getPrefixOfLevel(RplLoggerLevel level) const;
-    bool isActive(RplLoggerLevel level) const;
-    void setLevel(RplLoggerLevel level);
-    void setWithLocking(bool onNotOff);
-private:
-    // the assigned appenders:
-    RplAppender* m_appenders[16];
-    // the number of appenders in m_appenders:
-    size_t m_countAppenders;
-    // "" or the cache of the prefix of the current logging line: This can be reused by any appender.
-    QByteArray m_stdPrefix;
-    QMutex m_mutex;
-    bool m_withLocking;
-};
-
-/**
- * Implements an appender which puts the messages to a standard stream: stdout or stderr
- */
-class RplStreamAppender : public RplAppender {
-public:
-    RplStreamAppender(FILE* stream, const char* appenderName = "FileAppender");
-    virtual ~RplStreamAppender();
-public:
-    virtual void log(RplLoggerLevel level, int location, const char* message,
-                     RplLogger* logger);
-private:
-    // stdout or stderr:
-    FILE* m_fp;
-};
-
-/**
- * Implements an appender which puts the messages to a file
- */
-class RplFileAppender : public RplAppender {
-public:
-    RplFileAppender(const QByteArray& name, int maxSize, int maxCount,
-                    const char* appenderName = "FileAppender");
-    virtual ~RplFileAppender();
-public:
-    void open();
-    virtual void log(RplLoggerLevel level, int location, const char* message,
-                     RplLogger* logger);
-
-private:
-    // prefix of the log file name. Will be appended by ".<no>.log"
-    QByteArray m_prefix;
-    // maximal size of a logging file:
-    int m_maxSize;
-    // maximal count of logging files. If neccessary the oldest file will be deleted.
-    int m_maxCount;
-    // the size of the current log file:
-    int m_currentSize;
-    // the number of the current log file:
-    int m_currentNo;
-    // the current log file:
-    FILE* m_fp;
-};
-
-/**
- * Stores the log messages in a list.
- */
-class RplMemoryAppender : public RplAppender {
-public:
-    RplMemoryAppender(int maxLines = 1024,
-                      const char* appenderName = "MemoryAppender");
-    ~RplMemoryAppender();
-public:
-    virtual void log(RplLoggerLevel level, int location, const char* message,
-                     RplLogger* logger);
-    const QList<QByteArray>& getLines() const;
-    void clear();
-private:
-    QList<QByteArray> m_lines;
-    // maximum count of m_lines. If larger the oldest lines will be deleted.
-    int m_maxLines;
-    // true: standard prefix (level + datetime) will be stored too.
-    bool m_addPrefix;
-};
-
-#endif // RPLLOGGER_HPP
diff --git a/rplcore/rplqstring.cpp b/rplcore/rplqstring.cpp
deleted file mode 100644 (file)
index 2cd8995..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Missed operation for <code>QString</code>s.
- */
-/** @file rplcore/rplqstring.hpp
- *
- * @brief Definitions for missed operation for <code>QString</code>s.
- */
-#include "rplcore/rplcore.hpp"
-
-
-/**
- * @brief Determines the length and vlaue of an integer.
- *
- * @param text      the number as text
- * @param start     the first index to inspect
- * @param radix     the base of the number sytem: 8 (octal), 10 or 16
- * @param pValue     OUT: the value of the integer. May be NULL
- *
- * @return          <=0: no integer found
- *                  otherwise: the length of the integer
- */
-int RplQString::lengthOfUInt64(const QString& text, int start,
-    int radix, quint64* pValue)
-{
-    int inputLength = text.size();
-    qint64 value = 0;
-    int ix = start;
-    int cc;
-    if (radix == 10){
-        while (ix < inputLength){
-            if ( (cc = text[ix].unicode()) >= '0' && cc <= '9')
-                value = value * 10 + cc - '0';
-            else
-                break;
-            ix++;
-        }
-    } else if (radix == 16){
-            while (ix < inputLength){
-                if ( (cc = text[ix].unicode()) >= '0' && cc <= '9')
-                    value = value * 16 + cc - '0';
-                else if (cc >= 'A' && cc <= 'F')
-                    value = value * 16 + cc - 'A' + 10;
-                else if (cc >= 'a' && cc <= 'f')
-                    value = value * 16 + cc - 'a' + 10;
-                else
-                    break;
-                ix++;
-            }
-    } else if (radix == 8){
-            while (ix < inputLength){
-                if ( (cc = text[ix].unicode()) >= '0' && cc <= '7')
-                    value = value * 8 + cc - '0';
-                else
-                    break;
-                ix++;
-            }
-    } else {
-        throw RplException("RplQString::lengthOfInt(): wrong radix: %d", radix);
-    }
-    if (pValue != NULL)
-        *pValue = value;
-    return ix - start;
-}
-/**
- * @brief Determines the length and value of an unsigned integer.
- *
- * @param text      the number as text
- * @param start     the first index to inspect
- * @param radix     the base of the number sytem: 8 (octal), 10 or 16
- * @param pValue     OUT: the value of the integer. May be NULL
- *
- * @return          0: no integer found
- *                  otherwise: the length of the integer
- */
-int RplQString::lengthOfUInt(const QString& text, int start,
-    int radix, uint* pValue)
-{
-    quint64 value;
-    int rc = lengthOfUInt64(text, start, radix, &value);
-    if (pValue != NULL)
-        *pValue = (uint) value;
-    return rc;
-}
-
-/**
- * @brief Determines the length and value of a floting point number.
- *
- * @param text      the number as text
- * @param start     the first index to inspect
- * @param pValue     OUT: the value of the integer. May be NULL
- *
- * @return          <=0: no real number found
- *                  otherwise: the length of the floating point number
- */
-int RplQString::lengthOfReal(const QString& text, int start, qreal* pValue)
-{
-    int inputLength = text.size();
-    qreal value = 0.0;
-    int cc;
-    int ix = start;
-    while (ix < inputLength){
-        if ( (cc = text[ix].unicode()) >= '0' && cc <= '9')
-            value = value * 10 + (cc - '0');
-        else
-            break;
-        ix++;
-    }
-    // found: a digit has been found (in front of or behind the '.'
-    bool found = ix > start;
-    if (ix < inputLength && text[ix].unicode() == '.'){
-        ix++;
-    }
-    if (ix < inputLength && text[ix].isDigit()){
-        found = true;
-        qreal divisor = 1;
-        qreal precision = 0;
-        while ( ix < inputLength && (cc = text[ix].unicode()) >= '0' && cc <= '9'){
-            divisor *= 10;
-            precision = precision*10 + cc - '0';
-            ix++;
-        }
-        value += precision / divisor;
-    } else if (! found){
-        ix = start;
-    }
-    if (found && ix + 1 < inputLength && toupper(text[ix].unicode()) == 'E'){
-        int savePoint = ix;
-        ix++;
-        bool negative = false;
-        if ( (cc = text[ix].unicode()) == '+')
-            ix++;
-        else if (cc == '-'){
-            ix++;
-            negative = true;
-        }
-        if (ix >= inputLength || ! text[ix].isDigit())
-                ix = savePoint;
-        else{
-            int exponent = 0;
-            while (ix < inputLength && text[ix].isDigit()){
-                exponent = exponent * 10 + text[ix].unicode() - '0';
-                ix++;
-            }
-            if (negative)
-                value /= qPow(10, exponent);
-            else
-                value *= qPow(10, exponent);
-        }
-    }
-    if (pValue)
-        *pValue = value;
-    return found ? ix - start : 0;
-}
-
-/**
- * @brief Converts a QString into an utf-8 string
- *
- * The expression <code>qstring.toUtf8().constData()</code> is not allowed
- * in a variable argument list like sprintf. This is a thread save workaround.
- *
- * @param source        string to convert
- * @param buffer        OUT: target buffer
- * @param bufferSize    size of the target buffer
- * @return              <code>buffer</code>
- */
-char*RplQString::utf8(const QString& source, char buffer[], size_t bufferSize)
-{
-    QByteArray val = source.toUtf8();
-    if (val.length() < (int) bufferSize)
-        bufferSize = val.length() + 1;
-    memcpy(buffer, val.constData(), bufferSize - 1);
-    buffer[bufferSize - 1] = '\0';
-    return buffer;
-}
diff --git a/rplcore/rplqstring.hpp b/rplcore/rplqstring.hpp
deleted file mode 100644 (file)
index 780ef24..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLQSTRING_HPP
-#define RPLQSTRING_HPP
-
-class RplQString
-{
-public:
-    static int lengthOfUInt64(const QString& text, int start = 0,
-        int radix = 10, quint64* value = NULL);
-    static int lengthOfUInt(const QString& text, int start, int radix,
-        uint* pValue);
-    static int lengthOfReal(const QString& text, int start = 0,
-        qreal* value = NULL);
-    /**
-     * @brief Returns the value of a hexadecimal digit.
-     *
-     * @param digit     a (unicode) character
-     * @return          -1: not a hexadecimal digit<br>
-     *                  otherwise: the value, e.g. 10 for 'a'
-     */
-    inline static int valueOfHexDigit(int digit){
-        return digit >= '0' && digit <= '9' ? digit - '0'
-                : digit >= 'A' && digit <= 'F' ? digit - 'A' + 10
-                   : digit >= 'a' && digit <= 'f' ? digit - 'a' + 10 : -1;
-    }
-    static char* utf8(const QString& source, char buffer[], size_t bufferSize);
-};
-
-#endif // RPLQSTRING_HPP
diff --git a/rplcore/rplstring.cpp b/rplcore/rplstring.cpp
deleted file mode 100644 (file)
index a8bd039..0000000
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-/** @file
- * @brief Missed operations for <code>QByteArray</code>s.
- */
-/** @file rplcore/rplstring.cpp
- *
- * @brief Definitions for missed operations for <code>QByteArray</code>s.
- */
-#include "rplcore.hpp"
-
-/** @class RplString rplstring.hpp "rplcore/rplstring.hpp"
- *
- * @brief Implements some services around strings.
- *
- * This is a class with static members only.
- */
-
-/**
- * @brief Counts the occurrences of a given char in a string.
- *
- * @param line the text to inspect
- * @param cc   the char to count
- * @return             the number of <code>cc</code> in the text
- */
-int RplString::countChar(const char* line, char cc)
-{
-    const char* ptr = line;
-    int rc = 0;
-    while( (ptr = strchr(ptr, cc)) != NULL){
-        rc++;
-        ptr++;
-    }
-    return rc;
-}
-/**
- * Counts the occurrences of a string in a string.
- *
- * @param source    in this string will be searched
- * @param item      this item will be searched
- * @return          the count of occurrences
- */
-int RplString::count(const char* source, const char* item) {
-    const char* end = source;
-    int rc = 0;
-    int lengthItem = strlen(item);
-    while(true) {
-        const char* start = end;
-        end = strstr(start, item);
-        if(end == NULL)
-            break;
-        else {
-            rc++;
-            end += lengthItem;
-        }
-    }
-    return rc;
-}
-
-/**
- * Returns a string with a given maximum length.
- *
- * @param source        the source
- * @param maxLength     the maximum length of the result
- * @param buffer        Out: used if length of the result is shorter
- * @param appendix      if the result is cut this string will be appended.<br>
- *                      May be NULL.
- * @return              source: the source is enough short<br>
- *                      the prefix of source with the given length
- */
-const QByteArray& RplString::cutString(const QByteArray& source, int maxLength,
-                                       QByteArray& buffer, const char* appendix) {
-    QByteArray& rc = source.length() <= maxLength ? (QByteArray&) source : buffer;
-    if(source.length() > maxLength) {
-        buffer = source.left(maxLength);
-        if(appendix != NULL && appendix[0] != '\0')
-            buffer.append(appendix);
-    }
-    return rc;
-}
-static char s_fileSeparator = 0;
-
-/**
- * @brief Returns the os specific file path separator.
- * @return the file path separator, e.g. "/" for linux
- */
-const char* RplString::fileSeparator(){
-    return fileSeparatorChar() == '/' ? "/" : "\\";
-}
-
-/**
- * @brief Returns the os specific file path separator.
- * @return the file path separator, e.g. '/' for linux
- */
-char RplString::fileSeparatorChar(){
-    if (s_fileSeparator == 0){
-        const char* path = getenv("PATH");
-        if (path != NULL){
-            s_fileSeparator = strchr(path, ';') != NULL
-                    || strchr(path, '\\') != NULL ? '\\' : '/';
-        } else {
-            if (getenv("windows") != NULL)
-                s_fileSeparator = '\\';
-            else
-                s_fileSeparator = '/';
-        }
-    }
-    return s_fileSeparator;
-}
-
-/**
- * Builds a hexadecimal dump.
- *
- * Format: a sequence of hex digits followed by the ascii interpretation.
- *
- * Example: "42 30 61  B0a"
- *
- * @param data              data to convert
- * @param length            length of data
- * @param bytesPerLine      one line containes so many bytes of data
- * @return                  the hex dump
- */
-QByteArray RplString::hexDump(uint8_t* data, int length, int bytesPerLine) {
-    QByteArray rc;
-    int fullLines = length / bytesPerLine;
-    int expectedLength = (bytesPerLine * 4 + 2) * (fullLines + 1);
-    rc.reserve(expectedLength + 100);
-    int ixData = 0;
-    int col;
-    char buffer[16];
-    for(int lineNo = 0; lineNo < fullLines; lineNo++) {
-        for(col = 0; col < bytesPerLine; col++) {
-            qsnprintf(buffer, sizeof buffer, "%02x ", data[ixData + col]);
-            rc.append(buffer);
-        }
-        rc.append(' ');
-        for(col = 0; col < bytesPerLine; col++) {
-            uint8_t cc = data[ixData + col];
-            rc.append(cc > ' ' && cc < 128 ? (char) cc : '.');
-        }
-        ixData += bytesPerLine;
-        rc.append('\n');
-    }
-    // incomplete last line:
-    int restBytes = length - ixData;
-    if(restBytes > 0) {
-        for(col = 0; col < restBytes; col++) {
-            qsnprintf(buffer, sizeof buffer, "%02x ", data[ixData + col]);
-            rc.append(buffer);
-        }
-        for(col = restBytes; col < bytesPerLine; col++) {
-            rc.append("   ");
-        }
-        rc.append(' ');
-        for(col = 0; col < restBytes; col++) {
-            uint8_t cc = data[ixData + col];
-            rc.append(cc > ' ' && cc < 128 ? (char) cc : '.');
-        }
-        rc.append('\n');
-    }
-    return rc;
-}
-
-
-/**
- * Reads a file into a string.
- *
- * @param file              file to read
- * @param removeLastNewline true: if the last character is a newline
- *                          the result will not contain this
- * @return                  the file's content
- */
-QByteArray RplString::read(const char* file, bool removeLastNewline) {
-    QByteArray rc;
-    struct stat info;
-    size_t size;
-    if(stat(file, &info) == 0 && (size = info.st_size) > 0) {
-        FILE* fp = fopen(file, "r");
-        if(fp != NULL) {
-            rc.resize(info.st_size);
-            fread(rc.data(), 1, size, fp);
-            fclose(fp);
-            if(removeLastNewline && rc.at(size - 1) == '\n') {
-                rc.resize(size - 1);
-            }
-        }
-    }
-    return rc;
-}
-
-QByteArray RplString::replaceNode(const char* source, const char* newNode){
-    char sep = fileSeparatorChar();
-    const char* ptr = strrchr(source, sep);
-    QByteArray rc;
-    rc.reserve(strlen(source) + strlen(newNode) + 1);
-    if (ptr == NULL){
-        rc.append(source).append(sep).append(newNode);
-    } else if (ptr[0] == '\0'){
-        rc.append(source).append(newNode);
-    } else {
-        rc.append(source, ptr - source + 1).append(newNode);
-    }
-    return rc;
-}
-
-/**
- * Converts a string into an array of strings.
- *
- * @param source        string to convert
- * @param separator     the separator between the items to split
- * @return              an array with the splitted source
- */
-QList<QByteArray> RplString::toArray(const char* source,
-                                       const char* separator) {
-    const char* end = source;
-    QList<QByteArray> rc;
-    rc.reserve(count(source, separator) + 1);
-    int lengthItem = strlen(separator);
-    while(*end != '\0') {
-        const char* start = end;
-        end = strstr(start, separator);
-        if(end == NULL) {
-            end = start + strlen(start);
-        }
-        rc.append(QByteArray(start, end - start));
-        if(end[0] != '\0')
-            end += lengthItem;
-    }
-    return rc;
-}
-
-QByteArray RplString::toCString(const char* source, int maxLength){
-    if (maxLength <= 0)
-        maxLength = strlen(source);
-    int binaries = 0;
-    int ix;
-    for (ix = 0; ix < maxLength; ix++)
-        if (source[ix] < ' '){
-            binaries++;
-        }
-    QByteArray rc;
-    rc.reserve(maxLength + 3 * binaries + 1);
-    char cc;
-    for (ix = 0; ix < maxLength; ix++)
-        if ( (cc = source[ix]) >= ' '){
-            rc += source[ix];
-        } else {
-            switch(cc){
-            case '\0':
-                // stop looping:
-                ix = maxLength;
-                break;
-            case '\n':
-                rc += "\\n";
-                break;
-            case '\r':
-                rc += "\\r";
-                break;
-            case '\t':
-                rc += "\\t";
-                break;
-            default:
-            {
-                char buffer[5];
-                qsnprintf(buffer, sizeof buffer, "\\x%02x",
-                         ((unsigned int) cc) % 0xff);
-                rc += buffer;
-                break;
-            }
-            }
-        }
-    return rc;
-}
-
-/**
- * Return an integer as an QByteArray.
- *
- * @param value     value to convert
- * @param format    format like in sprintf()
- * @return          the ascii form of the value
- */
-QByteArray RplString::toNumber(int value, const char* format) {
-    char buffer[128];
-    qsnprintf(buffer, sizeof buffer, format, value);
-    return QByteArray(buffer);
-}
-
-/**
- * Writes a string to a file.
- *
- * @param file      the file's name
- * @param content   NULL or the file's content
- * @param mode      the file open mode: "w" for write, "a" for append
- * @return          true: successful<br>
- *                  false: error occurred
- */
-bool RplString::write(const char* file, const char* content, const char* mode) {
-    FILE* fp = fopen(file, mode);
-    if(fp != NULL) {
-        fputs(content, fp);
-        fclose(fp);
-    }
-    return fp != NULL;
-}
-/**
- * @brief Returns the length of the number string.
- *
- * @param text                  a text to inspect
- * @param skipTrailingSpaces    true: if spaces are behind the number
- *                              the result contains the length of these
- * @return             0: not a number<br>
- *                             otherwise: the length of the number string
- */
-int RplString::lengthOfNumber(const char* text, bool skipTrailingSpaces){
-    int rc = 0;
-    bool found = false;
-    const char* ptr = text;
-    while(isspace(*ptr))
-        ptr++;
-    if ( (*ptr == '+' || *ptr == '-'))
-        ptr++;
-    found = isdigit(*ptr);
-    while(isdigit(*ptr)){
-        ptr++;
-    }
-    if (*ptr == '.'){
-        ptr++;
-        if (isdigit(*ptr)){
-            found = true;
-            while(isdigit(*ptr))
-                ptr++;
-        }
-    }
-    if (found && toupper(*ptr) == 'E'){
-        const char* ptrToE = ptr;
-        ptr++;
-        if (*ptr == '+' || *ptr == '-')
-            ptr++;
-        if (! isdigit(*ptr))
-            ptr = ptrToE;
-        else {
-            while(isdigit(*ptr))
-                ptr++;
-        }
-    }
-    if (found && skipTrailingSpaces){
-        while(isspace(*ptr)){
-            ptr++;
-        }
-    }
-    rc = ! found ? 0 : ptr - text;
-    return rc;
-}
-/**
- * @brief Adds the count of the possible separators.
- *
- * @param countCommas          IN/OUT: number of ','
- * @param countSemicolons      IN/OUT: number of ';'
- * @param countPipes           IN/OUT: number of '|'
- * @param countBlanks          IN/OUT: number of ' '
- */
-static void addSeparators(const char* line, int& commas, int& semicolons,
-        int& pipes, int& blanks)
-{
-    commas += RplString::countChar(line, ',');
-    semicolons += RplString::countChar(line, ';');
-    pipes += RplString::countChar(line, '|');
-    blanks += RplString::countChar(line, ' ');
-}
-
-/**
- * @brief Finds the separator of the CSV file.
- *
- * If the file contain TABs the result is TAB.
- * If not:
- * Inspects the first 5 lines and counts the possible separators.
- * The most found separator will be returned.
- *
- * @param fp                   CSV file
- * @param buffer               a line buffer
- * @param bufferSize   the size of <code>buffer[]</code>
- */
-char RplString::findCsvSeparator(FILE* fp, char* buffer, size_t bufferSize){
-    char rc = '\0';
-    int lineNo = 0;
-    int maxLines = 5;
-    const char* line;
-    int commas = 0;
-    int semicolons = 0;
-    int pipes = 0;
-    int blanks = 0;
-    while(++lineNo < maxLines && (line = fgets(buffer, bufferSize, fp)) != NULL){
-        if (strchr(line, '\t') != NULL){
-            rc = '\t';
-            break;
-        }
-        addSeparators(line, commas, semicolons, pipes, blanks);
-    }
-    fseek(fp, 0, SEEK_SET);
-    if (rc != '\t'){
-        if (semicolons > 0 && commas > 0){
-            // if ',' is decimal separator and ';' is the column separator:
-            // Add one semicolon per line because of number of values is
-            // 1 greater than the number of separators
-            semicolons += lineNo;
-        }
-        if (commas + semicolons + pipes == 0) {
-            rc = blanks > 0 ? ' ' : '\0';
-        } else if (semicolons >= commas && semicolons >= pipes)
-            rc = ';';
-        else if (commas > semicolons && commas > pipes)
-            rc = ',';
-        else if (pipes > commas && pipes > semicolons)
-            rc = '|';
-    }
-    return rc;
-}
-
-/**
- * @brief Determines the length and vlaue of an integer.
- *
- * @param text      the number as text
- * @param radix     the base of the number system: 8 (octal), 10 or 16
- * @param pValue    OUT: the value of the integer. May be NULL
- *
- * @return          <=0: no integer found
- *                  otherwise: the length of the integer
- */
-int RplString::lengthOfUInt64(const char* text, int radix, quint64* pValue)
-{
-    qint64 value = 0;
-    int length = 0;
-    int cc;
-    if (radix == 10){
-        while ( (cc = text[length]) >= '0' && cc <= '9'){
-            value = value * 10 + cc - '0';
-            length++;
-        }
-    } else if (radix == 16){
-            while (true){
-                if ( (cc = text[length]) >= '0' && cc <= '9')
-                    value = value * 16 + cc - '0';
-                else if (cc >= 'A' && cc <= 'F')
-                    value = value * 16 + cc - 'A' + 10;
-                else if (cc >= 'a' && cc <= 'f')
-                    value = value * 16 + cc - 'a' + 10;
-                else
-                    break;
-                length++;
-            }
-    } else if (radix == 8){
-            while (true){
-                if ( (cc = text[length]) >= '0' && cc <= '7')
-                    value = value * 8 + cc - '0';
-                else
-                    break;
-                length++;
-            }
-    } else {
-        throw RplException("RplString::lengthOfInt(): wrong radix: %d", radix);
-    }
-    if (pValue != NULL)
-        *pValue = value;
-    return length;
-}
-
-/**
- * @brief Determines the length and value of a floting point number.
- *
- * @param text      the number as text
- * @param pValue     OUT: the value of the integer. May be NULL
- *
- * @return          <=0: no real number found
- *                  otherwise: the length of the floating point number
- */
-int RplString::lengthOfReal(const char* text, qreal* pValue)
-{
-    qreal value = 0.0;
-    int cc;
-    int length = 0;
-    while (true){
-        if ( (cc = text[length]) >= '0' && cc <= '9')
-            value = value * 10 + (cc - '0');
-        else
-            break;
-        length++;
-    }
-    // found: a digit has been found (in front of or behind the '.'
-    bool found = length > 0;
-    if (text[length] == '.'){
-        length++;
-    }
-    if (isdigit(text[length])){
-        found = true;
-        qreal divisor = 1;
-        qreal precision = 0;
-        while ( (cc = text[length]) >= '0' && cc <= '9'){
-            divisor *= 10;
-            precision = precision*10 + cc - '0';
-            length++;
-        }
-        value += precision / divisor;
-    } else if (! found){
-        length = 0;
-    }
-    if (found && toupper(text[length]) == 'E'){
-        int savePoint = length;
-        length++;
-        bool negative = false;
-        if ( (cc = text[length]) == '+')
-            length++;
-        else if (cc == '-'){
-            length++;
-            negative = true;
-        }
-        if (! isdigit(text[length]))
-                length = savePoint;
-        else{
-            int exponent = 0;
-            while (isdigit(text[length])){
-                exponent = exponent * 10 + text[length] - '0';
-                length++;
-            }
-            if (negative)
-                value /= qPow(10, exponent);
-            else
-                value *= qPow(10, exponent);
-        }
-    }
-    if (pValue)
-        *pValue = value;
-    return found ? length : 0;
-}
-
diff --git a/rplcore/rplstring.hpp b/rplcore/rplstring.hpp
deleted file mode 100644 (file)
index ee8924c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLSTRING_HPP
-#define RPLSTRING_HPP
-
-class RplString {
-public:
-    static int countChar(const char* line, char cc);
-    static int count(const char* source, const char* item);
-    static const QByteArray& cutString(const QByteArray& source, int maxLength,
-                                       QByteArray& buffer, const char* appendix = "...");
-    static const char* fileSeparator();
-    static char fileSeparatorChar();
-    static QByteArray hexDump(uint8_t* data, int length, int bytesPerLine = 16);
-    static QByteArray hexDump(const void* data, int length, int bytesPerLine = 16) {
-        return hexDump((uint8_t*) data, length, bytesPerLine);
-    }
-    static QByteArray read(const char* file, bool removeLastNewline = true);
-    static QByteArray replaceNode(const char* source, const char* newNode);
-    static bool write(const char* file, const char* content = NULL,
-                      const char* mode = "w");
-    static QList<QByteArray> toArray(const char* source, const char* separator);
-    static QByteArray toCString(const char* source, int maxLength = -1);
-    static QByteArray toNumber(int value, const char* format = "%d");
-    static int lengthOfNumber(const char* text, bool skipTrailingSpaces = false);
-    static char findCsvSeparator(FILE* fp, char* buffer, size_t bufferSize);
-    static int lengthOfUInt64(const char* text, int radix, quint64* pValue);
-    static int lengthOfReal(const char* text, qreal* pValue);
-};
-
-#endif // RPLSTRING_HPP
diff --git a/rplcore/rplterminator.cpp b/rplcore/rplterminator.cpp
deleted file mode 100644 (file)
index 4fab794..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-/** @file
- * @brief Implements a thread stopper.
- */
-/** @file
- * @brief Definitions for a thread stopper.
- */
-#include "rplcore.hpp"
-
-enum {
-    LOC_CAUSE_TERMINATION_1 = RPL_FIRST_OF(RPLMODULE_TERMINATOR), // 10901
-};
-
-/**
- * @class RplTerminator rplterminator.hpp "rplcore/rplterminator.hpp"
- *
- * @brief Implements a thread stopper.
- *
- * Allows to terminate a thread avoiding unfreeing resources, deadlocks etc.
- *
- * The application must create one instance of a <code>RplTerminator</code>.
- * All threads gets this instance and call them periodically if the application should stop.
- * If yes they finish their work, frees the resources and stop.
- *
- */
-
-/**
- * @brief Constructor.
- * @param logger    NULL or the logger. Used to protocol the termination
- */
-RplTerminator::RplTerminator(RplLogger* logger) :
-    m_stop(false),
-    m_logger(logger) {
-}
-
-/**
- * @brief Destructor.
- */
-RplTerminator::~RplTerminator() {
-}
-
-/**
- * @brief Defines the stop of all threads.
- *
- * @param reason    the reason of the termination. Will be logged (if a logger is defined)
- * @param file      NULL or the file of the caller. Normally set with <code>__FILE__</code>
- * @param lineNo    0 or the line number of the caller. Normally set with <code>__LINE__</code>
- * @param level     log level
- * @param location  0 or the location of the caller
- */
-void RplTerminator::causeTermination(const char* reason, const char* file,
-                                     int lineNo, RplLoggerLevel level, int location) {
-    if(m_logger != NULL) {
-        QByteArray message(reason);
-        if(file != NULL) {
-            message.append(" [").append(file).append(lineNo).append("]");
-        }
-        m_logger->log(level, location == 0 ? LOC_CAUSE_TERMINATION_1 : location,
-                      message);
-    }
-    m_stop = true;
-}
-
-/**
- * @brief Tests whether the thread should be stopped.
- * @return  true: the thread should be stopped.<br>
- *          false: otherwise
- */
-bool RplTerminator::isStopped() const {
-    return m_stop;
-}
-
diff --git a/rplcore/rplterminator.hpp b/rplcore/rplterminator.hpp
deleted file mode 100644 (file)
index f0e49c1..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLTERMINATOR_HPP
-#define RPLTERMINATOR_HPP
-
-class RplTerminator {
-public:
-    RplTerminator(RplLogger* logger = NULL);
-    virtual ~RplTerminator();
-private:
-    // No copy constructor: no implementation!
-    RplTerminator(const RplTerminator& source);
-    // Prohibits assignment operator: no implementation!
-    RplTerminator& operator =(const RplTerminator& source);
-public:
-    void causeTermination(const char* reason, const char* file = NULL,
-                          int lineNo = 0, RplLoggerLevel level = LOG_ERROR, int location = 0);
-    bool isStopped() const;
-private:
-    bool m_stop;
-    RplLogger* m_logger;
-};
-
-#endif // RPLTERMINATOR_HPP
diff --git a/rplcore/rpltest.cpp b/rplcore/rpltest.cpp
deleted file mode 100644 (file)
index ea31b61..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-/** @file
- * @brief A testing tool like JUnit.
- */
-/** @file rplcore/rpltest.hpp
- *
- * @brief Definitions for a testing tool like JUnit.
- */
-#include "rplcore/rplcore.hpp"
-#include "rpltest.hpp"
-
-/** @class RplTest rpltest.hpp "rplcore/repltest"
- *
- * @brief Implements an unit test base class similar JUnit for java.
- *
- * Example for usage:
- *
- * @see rplexample.cpp
- */
-class RplTest;
-
-/**
- * @brief Constructor.
- *
- * @param name
- */
-RplTest::RplTest(const char* name) :
-    m_errors(0),
-    m_name(name),
-    m_logger(),
-    m_memoryAppender(1024),
-    m_memoryLogger()
-{
-    m_memoryAppender.setAutoDelete(false);
-    m_logger.buildStandardAppender(getTempDir("rpltest"));
-    log(QByteArray("Start of ") + m_name);
-    m_memoryLogger.addAppender(&m_memoryAppender);
-}
-
-/**
- * @brief Runs all tests of the test class.
- */
-void RplTest::run() {
-    try {
-        doIt();
-    } catch(RplException e) {
-        error("unexpected RplException: %s", e.getMessage().constData());
-    } catch(...){
-        error("unknown Exception");
-    }
-
-    if(m_errors > 0) {
-        error("Unit %s has %d error(s)", m_name.data(), m_errors);
-        // error() increments, we decrement:
-        m_errors--;
-    }
-}
-
-/**
- * @brief Destructor.
- */
-RplTest::~RplTest() {
-}
-
-/**
- * Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(int expected, int current, const char* file,
-                           int lineNo) {
-    if(expected != current)
-        error("%s-%d: error: %d != %d / %x != %x)", file, lineNo, expected, current,
-              (unsigned int) expected, (unsigned int) current);
-    return expected == current;
-}
-
-/**
- * Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(qint64 expected, qint64 current, const char* file,
-                           int lineNo) {
-    if(expected != current)
-        error("%s-%d: error: %lld != %lld / %llx != %llx)", file, lineNo,
-              expected, current, (quint64) expected, (quint64) current);
-    return expected == current;
-}
-
-
-/**
- * Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(qreal expected, qreal current, const char* file,
-                           int lineNo) {
-    if(expected != current)
-        error("%s-%d: error: %d != %d / %x != %x)", file, lineNo, expected, current,
-              (unsigned int) expected, (unsigned int) current);
-    return expected == current;
-}
-
-/**
- * @brief Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(const char* expected, const QString& current,
-                           const char* file, int lineNo) {
-    bool equal = assertEquals(expected, current.toUtf8().constData(), file,
-                              lineNo);
-    return equal;
-}
-
-/**
- * @brief Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(const QString& expected, const QString& current,
-                           const char* file, int lineNo) {
-    bool equal = assertEquals(expected.toUtf8().constData(),
-        current.toUtf8().constData(), file, lineNo);
-    return equal;
-}
-
-
-/**
- * @brief Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(const char* expected, const char* current,
-                           const char* file, int lineNo) {
-    bool equal = strcmp(expected, current) == 0;
-    if(! equal) {
-        if(strchr(expected, '\n') != NULL || strchr(current, '\n')) {
-            QList<QByteArray> exp = RplString::toArray(expected, "\n");
-            QList<QByteArray> cur = RplString::toArray(current, "\n");
-            equal = assertEquals(exp, cur, file, lineNo);
-        } else {
-            int ix = 0;
-            while(expected[ix] == current[ix] && expected[ix] != '\0')
-                ix++;
-            char pointer[12+1];
-            char* ptr = pointer;
-            int maxIx = ix > 10 ? 10 : ix;
-            for(int ii = 0; ii < maxIx - 1; ii++)
-                *ptr++ = '-';
-            *ptr++ = '^';
-            *ptr = '\0';
-            if(ix < 10)
-                error("%s-%d: error: diff at index %d\n%s\n%s\n%s",
-                      file, lineNo, ix, expected, current, pointer);
-            else
-                error("%s-%d: error: diff at index %d\n%s\n...%s\n...%s\n%s",
-                      file, lineNo, ix, current,
-                      expected + ix - 10 + 3,
-                      current + ix - 10 + 3,
-                      pointer);
-        }
-    }
-    return equal;
-}
-
-/**
- * @brief Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(const QList<QByteArray>& expected,
-                           const QList<QByteArray>& current, const char* file, int lineNo) {
-    int nMax = expected.size();
-    bool rc = true;
-    if(current.size() < nMax)
-        nMax = current.size();
-    for(int ix = 0; ix < nMax; ix++) {
-        if(expected.at(ix) != current.at(ix)) {
-            error("%s-%d: difference in line %d", file, lineNo, ix+1);
-            m_errors--;
-            assertEquals(expected.at(ix).constData(), current.at(ix).constData(),
-                         file, lineNo);
-            rc = false;
-            break;
-        }
-    }
-    if(rc) {
-        if(expected.size() > nMax)
-            error("%s-%d: less lines than expected (%d):\n%s",
-                  file, lineNo, nMax, expected.at(nMax).constData());
-        else if(expected.size() < nMax)
-            error("%s-%d: more lines than expected (%d):\n%s",
-                  file, lineNo, nMax, current.at(nMax).constData());
-    }
-    return rc;
-}
-/**
- * @brief Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(const QByteArray& expected,
-                           const QByteArray& current, const char* file, int lineNo) {
-    return assertEquals(expected.data(), current.data(), file, lineNo);
-}
-
-/**
- * @brief Tests the equality of two values.
- *
- * Differences will be logged.
- *
- * @param expected      the expected value
- * @param current       the current value
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: equal
- */
-bool RplTest::assertEquals(const char* expected, const QByteArray& current,
-                           const char* file, int lineNo) {
-    return assertEquals(expected, current.constData(), file, lineNo);
-}
-
-/**
- * @brief Tests whether a value is true.
- *
- * A value of false will be logged.
- *
- * @param condition     value to test
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              <code>condition</code>
- */
-bool RplTest::assertTrue(bool condition, const char* file, int lineNo) {
-    if(! condition)
-        error("%s-%d: not TRUE", file, lineNo);
-    return condition;
-}
-
-/**
- * @brief Tests whether a value is false.
- *
- * A value of true will be logged.
- *
- * @param condition     value to test
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              <code>! condition</code>
- */
-bool RplTest::assertFalse(bool condition, const char* file, int lineNo) {
-    if(condition)
-        error("%s-%d: not FALSE", file, lineNo);
-    return ! condition;
-}
-
-/**
- * @brief Tests whether a value is NULL.
- *
- * A value of not NULL will be logged.
- *
- * @param ptr           value to test
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: ptr is NULL
- */
-bool RplTest::assertNull(const void* ptr, const char* file, int lineNo) {
-    if(ptr != NULL)
-        error("%s-%d: not NULL", file, lineNo);
-    return ptr == NULL;
-}
-
-/**
- * @brief Tests whether a value is not NULL.
- *
- * A value of NULL will be logged.
- *
- * @param ptr           value to test
- * @param file          the file containing the test
- * @param lineNo        the line number containing the test
- * @return              true: ptr is not NULL
- */
-bool RplTest::assertNotNull(const void* ptr, const char* file, int lineNo) {
-    if(ptr == NULL)
-        error("%s-%d: is NULL", file, lineNo);
-    return ptr != NULL;
-}
-
-/**
- * @brief Compares two files line by line.
- *
- * @param expected  the file with the expected content
- * @param current   the file with the current content
- * @param file      the source file (point of the comparison)
- * @param lineNo    the source position (point of the comparison)
- * @return          true: the files are equal<br>
- *                  false: otherwise
- */
-bool RplTest::assertEqualFiles(const char* expected, const char* current,
-       const char* file, int lineNo)
-{
-    bool rc = false;
-    QByteArray expectedContent = RplString::read(expected, true);
-    QByteArray currentContent = RplString::read(current, true);
-    if (expectedContent.isEmpty()){
-        char buffer[512];
-        qsnprintf(buffer, sizeof buffer, "%s has no content. Does it exist?",
-                 expected);
-        error(buffer);
-    } else if (currentContent.isEmpty()){
-        char buffer[512];
-        qsnprintf(buffer, sizeof buffer, "%s has no content. Does it exist?",
-                 current);
-        error(buffer);
-    } else {
-        QList<QByteArray> expLines = expectedContent.split('\n');
-        QList<QByteArray> curLines = currentContent.split('\n');
-        rc = assertEquals(expLines, curLines, file, lineNo);
-    }
-    return rc;
-}
-
-/**
- * @brief Writes an info.
- *
- * @param message   message to show
- * @return          true (for chaining)
- */
-bool RplTest::log(const char* message) {
-    m_logger.log(LOG_INFO, 0, message);
-    return true;
-}
-
-
-/**
- * @brief Writes an error.
- *
- * @param format    message to show. With placeholders like <code>std::printf()</code>
- * @param ...       the values for the placeholders in <code>format</code>
- * @return          false (for chaining)
- */
-bool RplTest::error(const char* format, ...) {
-    m_errors++;
-    va_list ap;
-    va_start(ap, format);
-    m_logger.log(LOG_ERROR, 0, format, ap);
-    va_end(ap);
-    return false;
-}
-
-/**
- * @brief Tests whether the m_memoryLogger has a message containing a given pattern.
- *
- * @param pattern   regular expression to search
- * @return          true: pattern has been found<br>
- *                  false: otherwise
- */
-bool RplTest::logContains(const char* pattern)
-{
-    const QList<QByteArray>& lines = m_memoryAppender.getLines();
-    QRegularExpression rexpr(pattern);
-    bool rc = false;
-    QRegularExpressionMatch match;
-    for (int ii = 0; ii < lines.size(); ii++){
-        const QByteArray& line = lines.at(ii);
-        match = rexpr.match(line);
-        if (match.hasMatch()){
-            rc = true;
-            break;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Returns the name of a directory in the temp dir.
- *
- * If the named directory does not exist it will be created.
- *
- * @param node          NULL or the node (name without path)
- * @param parent        NULL or a node of the parent
- * @param withSeparator true: the result ends with slash/backslash
- * @return              the name of an existing directory
- */
-QByteArray RplTest::getTempDir(const char* node, const char* parent,
-                               bool withSeparator) {
-    QByteArray temp("c:\\temp");
-    struct stat info;
-    const char* ptr;
-    if((ptr = getenv("TMP")) != NULL)
-        temp = ptr;
-    else if((ptr = getenv("TEMP")) != NULL)
-        temp = ptr;
-    else if(stat("/tmp", &info) == 0)
-        temp = "/tmp";
-    char sep = m_separator = temp.indexOf('/') >= 0 ? '/' : '\\';
-    if(temp.at(temp.length() - 1) != sep)
-        temp += sep;
-    if(parent != NULL) {
-        temp += parent;
-        if(stat(temp.constData(), &info) != 0)
-            mkdir(temp.constData(), (-1));
-        temp += sep;
-    }
-    if(node != NULL) {
-        temp += node;
-        temp += sep;
-        if(stat(temp.data(), &info) != 0)
-            mkdir(temp.data(), -1);
-    }
-    if(! withSeparator)
-        temp.resize(temp.length() - 1);
-    return temp;
-}
-
-/**
- * @brief Returns a name of a file in a temporary directory.
- *
- * @param node              the file's name without path
- * @param parent            NULL or the name of a subdirectory the file will be inside
- * @param deleteIfExists    true: if the file exists it will be removed
- * @return                  the full name of a temporary file
- */
-QByteArray RplTest::getTempFile(const char* node, const char* parent,
-                                bool deleteIfExists) {
-    QByteArray dir = getTempDir(parent);
-    QByteArray rc = dir;
-    if (! rc.endsWith(m_separator))
-        rc += m_separator;
-    rc += node;
-    struct stat info;
-    if(deleteIfExists && stat(rc.constData(), &info) == 0)
-        unlink(rc.constData());
-    return rc;
-}
diff --git a/rplcore/rpltest.hpp b/rplcore/rpltest.hpp
deleted file mode 100644 (file)
index 5c7d3ac..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLTEST_HPP
-#define RPLTEST_HPP
-
-// the sources generated from QT include this file directly:
-#ifndef RPLCORE_HPP
-#include <QByteArray>
-#endif
-
-class RplTest {
-public:
-    RplTest(const char* name);
-    virtual ~RplTest();
-private:
-    // No copy constructor: no implementation!
-    RplTest(const RplTest& source);
-    // Prohibits assignment operator: no implementation!
-    RplTest& operator =(const RplTest& source);
-public:
-    bool assertEquals(int expected, int current, const char* file, int lineNo);
-    bool assertEquals(qint64 expected, qint64 current, const char* file, int lineNo);
-    bool assertEquals(qreal expected, qreal current, const char* file, int lineNo);
-    bool assertEquals(const char* expected, const QString& current,
-                      const char* file, int lineNo);
-    bool assertEquals(const QString& expected, const QString& current,
-                      const char* file, int lineNo);
-    bool assertEquals(const char* expected, const char* current,
-                      const char* file, int lineNo);
-    bool assertEquals(const QByteArray& expected, const QByteArray& current,
-                      const char* file, int lineNo);
-    bool assertEquals(const char* expected, const QByteArray& current,
-                      const char* file, int lineNo);
-    bool assertEquals(const QList<QByteArray>& expected,
-                      const QList<QByteArray>& current, const char* file, int lineNo);
-    bool assertTrue(bool condition, const char* file, int lineNo);
-    bool assertFalse(bool condition, const char* file, int lineNo);
-    bool assertNull(const void* ptr, const char* file, int lineNo);
-    bool assertNotNull(const void* ptr, const char* file, int lineNo);
-    bool assertEqualFiles(const char* expected, const char* current,
-                          const char* file, int lineNo);
-    bool log(const char* message);
-    bool error(const char* message, ...);
-    QByteArray getTempDir(const char* node, const char* parent = NULL,
-                          bool withSeparator = true);
-    QByteArray getTempFile(const char* node, const char* parent = NULL,
-                           bool deleteIfExists = true);
-    bool logContains(const char* pattern);
-    void run();
-protected:
-    virtual void doIt(void) = 0;
-
-protected:
-    int m_errors;
-    QByteArray m_name;
-    RplLogger m_logger;
-    // for testing of logging code:
-    RplMemoryAppender m_memoryAppender;
-    RplLogger m_memoryLogger;
-    char m_separator;
-};
-#define checkE(expected, current) assertEquals(expected, current, __FILE__, __LINE__)
-#define checkT(current) assertTrue(current, __FILE__, __LINE__)
-#define checkF(current) assertFalse(current, __FILE__, __LINE__)
-#define checkN(current) assertNull(current, __FILE__, __LINE__)
-#define checkNN(current) assertNotNull(current, __FILE__, __LINE__)
-#define checkFiles(expected, current) assertEqualFiles(expected, current, __FILE__, __LINE__)
-#endif // RPLTEST_HPP
diff --git a/rplcore/rplwriter.cpp b/rplcore/rplwriter.cpp
deleted file mode 100644 (file)
index 53e018b..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief A writer to an output media.
- *
- * Implementation of the abstract base class <code>RplWriter</code> and
- * the concrete derivation <code>RplFileWriter</code>.
- */
-/** @file rplcore/rplwriter.hpp
- *
- * @brief Definitions for a writer to an output media.
- */
-#include "rplcore/rplcore.hpp"
-
-const char* RplWriter::m_tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
-int RplWriter::m_maxIndention = strlen(RplWriter::m_tabs);
-
-/** @class RplWriter rplwriter.hpp "rplcore/rplwriter.hpp"
- *
- * @brief Implements an abstract base class for producing text lines.
- *
- */
-
-/**
- * @brief Destructor.
- *
- * Closes the output medium.
- * Ensures that the destructors of the derived classes are virtual.
- */
-RplWriter::~RplWriter()
-{
-    close();
-}
-
-/**
- * @brief Closes the output medium.
- *
- * This method does nothing, but overriding methods should free the resources.
- *
- * @note The method must be designed so that it can be called multiple times.
- */
-void RplWriter::close()
-{
-}
-/**
- * @brief Puts a given count of "\t" to the output medium.
- *
- * @param indent    indention level, number of "\t"
- */
-void RplWriter::indent(int indent)
-{
-    if (indent > m_maxIndention)
-        indent = m_maxIndention;
-    format("%.*s", indent, m_tabs);
-}
-
-/**
- * @brief Formats a string and write it to the output medium.
- *
- * @param format    format string with placeholders like <code>sprintf()</code>
- * @param ...       variable arguments, values for the placeholders
- */
-void RplWriter::format(const char* format, ...)
-{
-    va_list ap;
-    va_start(ap, format);
-    write(ap, format);
-    va_end(ap);
-}
-/**
- * @brief Formats a line and write it to the output medium.
- *
- * @param format    format string with placeholders like <code>sprintf()</code>
- * @param ...       variable arguments, values for the placeholders
- */
-void RplWriter::formatLine(const char* format, ...)
-{
-    char buffer[64000];
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    writeLine(buffer);
-}
-
-/**
- * @brief Formats a message and writes it to the output medium.
- *
- * @param ap        variable argument list (like in <code>vsprintf</code>)
- * @param format    format string with placeholders
- */
-void RplWriter::write(va_list ap, const char* format)
-{
-    char buffer[64000];
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    write(buffer);
-}
-
-/**
- * @brief Writes a line with indention to the output medium.
- *
- * @param indent    indention level. Indention is limited to 20
- * @param line      the line to write
- */
-void RplWriter::writeIndented(int indent, const char* line)
-{
-    RplWriter::indent(indent);
-    writeLine(line);
-}
-
-/**
- * @brief Writes a line with indention to the output medium.
- *
- * @param indent    indention level. Indention is limited to 20
- * @param format    format string with placeholders like <code>sprintf</code>
- * @param ...       the values for the placeholders (variable arguments)
- */
-void RplWriter::formatIndented(int indent, const char* format, ...)
-{
-    RplWriter::indent(indent);
-
-    char buffer[64000];
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    writeLine(buffer);
-}
-
-/** @class RplWriter rplwriter.hpp "rplcore/rplwriter.hpp"
- *
- * @brief Implements a class which writes lines into a file.
- */
-
-/**
- * @brief Constructor.
- *
- * @param filename          the file's name
- * @param mode              write mode, "w" for write or "a" for append
- * @param additionalStream  if not NULL the content will be written to this
- *                          stream too. Normal usage: <code>stdout</code> or
- *                          <code>stderr</code>
- * @param eoln              line end: "\n" or "\r\n"
- */
-RplFileWriter::RplFileWriter(const char* filename, const char* mode,
-                             FILE* additionalStream, const char* eoln) :
-    m_fp(fopen(filename, mode)),
-    m_name(filename),
-    m_eoln(eoln),
-    m_additionalStream(additionalStream)
-{
-}
-
-/**
- * @brief Writes a string to the file.
- * @param message   the string to write
- */
-void RplFileWriter::write(const char* message)
-{
-    if (m_fp != NULL)
-        fputs(message, m_fp);
-    if (m_additionalStream != NULL)
-        fputs(message, m_additionalStream);
-}
-
-/**
- * @brief Writes a line to the file.
- * @param line   the line to write. If NULL an empty line will be written
- */
-void RplFileWriter::writeLine(const char* line)
-{
-    if (m_fp != NULL){
-        if (line != NULL)
-            fputs(line, m_fp);
-        fputs(m_eoln, m_fp);
-    }
-    if (m_additionalStream != NULL){
-        if (line != NULL)
-            fputs(line, m_additionalStream);
-        fputc('\n', m_additionalStream);
-    }
-}
-
-/**
- * @brief Closes the output file.
- */
-void RplFileWriter::close()
-{
-    if (m_fp != NULL){
-        fclose(m_fp);
-        m_fp = NULL;
-    }
-    m_additionalStream = NULL;
-}
diff --git a/rplcore/rplwriter.hpp b/rplcore/rplwriter.hpp
deleted file mode 100644 (file)
index 7b661e3..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLWRITER_HPP
-#define RPLWRITER_HPP
-
-class RplWriter
-{
-public:
-    virtual ~RplWriter();
-public:
-    /**
-     * @brief Writes a text to the output medium.
-     *
-     * @param message   the message
-     */
-    virtual void write(const char* message) = 0;
-    /**
-     * @brief Writes a text line to the output medium.
-     *
-     * @param line   the text line. If NULL an empty line will be written
-     */
-    virtual void writeLine(const char* line = NULL) = 0;
-    virtual void close();
-public:
-    void indent(int indent);
-    void format(const char* format, ...);
-    void formatLine(const char* format, ...);
-    void write(va_list ap, const char* format);
-    void writeIndented(int indent, const char* line);
-    void formatIndented(int indent, const char* format, ...);
-protected:
-    static const char* m_tabs;
-    static int m_maxIndention;
-};
-
-class RplFileWriter : public RplWriter
-{
-public:
-    RplFileWriter(const char* filename, const char* mode = "w",
-                  FILE* additionalStream = NULL, const char* eoln =  "\n");
-public:
-    virtual void write(const char* line);
-    virtual void writeLine(const char* line = NULL);
-    virtual void close();
-protected:
-    FILE* m_fp;
-    QByteArray m_name;
-    QByteArray m_eoln;
-    FILE* m_additionalStream;
-};
-
-#endif // RPLWRITER_HPP
diff --git a/rplcore/testrplexample.cpp b/rplcore/testrplexample.cpp
deleted file mode 100644 (file)
index 695fbae..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-include "project.hpp"
-
-#include "rplcore/rpltest.hpp"
-// Code to test:
-int add(int a, int b) {
-    return a+b;
-}
-QByteArray concat(const char* a, const char* b) {
-    return QByteArray(a) + " " + b;
-}
-const char* firstDot(const char* s) {
-    return strchr(s, '.');
-}
-/**
- * @brief Example for usage of the class RplTest.
- */
-class TestRplExample : public RplTest {
-public:
-    TestRplExample() : RplTest("RplExample") {}
-
-public:
-    void testInt() {
-        log("testing add...");
-        // compare 2 integers:
-        checkE(2, add(1, 1));
-    }
-    void testString() {
-        // compare 2 strings:
-        checkE("Be good", concat("Be", "good"));
-        // test for not NULL:
-        checkN(firstDot("Hi."));
-        // test for  NULL:
-        checkNN(firstDot("Hi"));
-    }
-    virtual void doIt() {
-        testInt();
-        testString();
-    }
-};
-void testRplExample() {
-    TestRplExample test;
-    test.run();
-}
diff --git a/rplexpr/rplasclasses.cpp b/rplexpr/rplasclasses.cpp
deleted file mode 100644 (file)
index 11f21d6..0000000
+++ /dev/null
@@ -1,1186 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Predefined classes of the virtual machine, e.g RplASInteger.
- */
-/** @file rplexpr/rplasclasses.hpp
- *
- * @brief Definitions for predefined classes of the virtual machine.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-
-RplASList* RplASList::m_instance = NULL;
-RplASMap* RplASMap::m_instance = NULL;
-RplASFloat* RplASFloat::m_instance = NULL;
-RplASInteger* RplASInteger::m_instance = NULL;
-RplASString* RplASString::m_instance = NULL;
-RplASBoolean* RplASBoolean::m_instance = NULL;
-RplASVoid* RplASVoid::m_instance = NULL;
-RplASFormula* RplASFormula::m_instance = NULL;
-
-/** @class RplSymbolSpace rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a symbol space for the parser.
- *
- * A symbol space is a container of the classes and variables which can be used
- * at a given moment while compiling.
- *
- * A symbol space could have a parent which is a symbol space too and extends
- * the visible classes / variables.
- *
- * If an entry exists more than one time in a symbol space chain only the first
- * can be seen.
- *
- * The "last" parent is named "global" and exists always. It contains the
- * core classes like String, List and Map and methods like print.
- *
- * Each module hit by the compiler builds its own symbol space with global as parent.
- *
- * Each class defines a symbol space and takes the symbol space of the superclass
- * as its parent. If there is no superclass the module's symbol space will be taken.
- *
- * Each method defines its own symbol space. The parent may be the symbol space
- * of the module or of the class.
- */
-/**
- * @brief Constructor, only for the global symbol space.
- *
- * @param name      the symbol space's name
- * @param parent    the parent of the symbol space
- */
-RplSymbolSpace::RplSymbolSpace(RplASTree& tree) :
-    m_type(SST_GLOBAL),
-    m_name("$global"),
-    m_variables(),
-    m_classes(),
-    m_parent(NULL),
-    m_body(NULL),
-    m_listOfVars(),
-    m_tree(tree)
-{
-}
-/**
- * @brief Constructor.
- *
- * @param type      the type of the symbol space: SST_MODULE, ...
- * @param name      the symbol space's name
- * @param parent    the parent of the symbol space
- */
-RplSymbolSpace::RplSymbolSpace(RplSymbolSpace::SymbolSpaceType type,
-                               const QByteArray& name,
-                               RplSymbolSpace* parent) :
-    m_type(type),
-    m_name(name),
-    m_variables(),
-    m_classes(),
-    m_parent(parent),
-    m_body(NULL),
-    m_listOfVars(),
-    m_tree(parent->m_tree)
-{
-}
-
-
-/**
- * @brief Destructor.
- */
-RplSymbolSpace::~RplSymbolSpace()
-{
-    ClassMap::iterator it;
-    for (it = m_classes.begin(); it != m_classes.end(); it++){
-        delete it.value();
-    }
-    MethodMap::iterator it2;
-    for (it2 = m_methods.begin(); it2 != m_methods.end(); it2++){
-        delete it2.value();
-    }
-}
-
-/**
- * @brief Starts a scope.
- *
- * A scope is an "area" where variables can be defined.
- * A variable "lives" in a scope.
- *
- * Saves the status to restore it in <code>finishScope()</code>.
- *
- * @param scope     OUT: status info
- */
-void RplSymbolSpace::startScope(RplASScope& scope)
-{
-    scope.m_varNoAtStart = m_listOfVars.size();
-}
-
-/**
- * @brief Finishes a scope.
- *
- * Finishes the "live" of the variables created in the ending scope.
- *
- * @param endOfScope    line (inside the current source unit) which finishes the
- *                      scope
- * @param scope         the status of the scope at start.
- */
-void RplSymbolSpace::finishScope(int endOfScope, RplASScope& scope)
-{
-    // in methods/classes not needed:
-    int ix = scope.m_varNoAtStart - scope.m_builtInVars;
-    int last = m_listOfVars.size();
-    for (; ix < last; ix++){
-        RplASVarDefinition* var = m_listOfVars[ix];
-        var->setEndOfScope(endOfScope);
-        const QByteArray& name = var->name();
-        if (m_variables.contains(name))
-            m_variables.remove(name);
-    }
-}
-
-/**
- * @brief Search a variable in the symbol space.
- *
- * @param name  variable to find
- *
- * @return      NULL: not found<br>
- *              otherwise: the variable
- */
-RplASVarDefinition* RplSymbolSpace::findVariable(const QByteArray& name) const
-{
-    RplASVarDefinition* rc = NULL;
-    if (m_variables.contains(name))
-        rc = m_variables[name];
-    else if (m_parent != NULL)
-        rc = m_parent->findVariable(name);
-    return rc;
-}
-
-/**
- * @brief Search the class in the symbol space hierarchy.
- *
- * @param name  Name of the class
- * @return      NULL: not found<br>
- *              otherwise: the class
- */
-RplASClass* RplSymbolSpace::findClass(const QByteArray& name) const
-{
-    RplASClass* rc = NULL;
-    if (m_classes.contains(name))
-        rc = m_classes[name];
-    else if (m_parent != NULL)
-        rc = m_parent->findClass(name);
-    return rc;
-}
-
-/**
- * @brief Find a method in the instance.
- *
- * @param name  the method's name
- * @return      NULL: method not found
- *              otherwise: the method description
- */
-RplASMethod* RplSymbolSpace::findMethod(const QByteArray& name) const
-{
-    RplASMethod* rc = NULL;
-    if (m_methods.contains(name))
-        rc = m_methods[name];
-    return rc;
-}
-
-/**
- * @brief Writes the content of the instance into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level: so many tabs will be used as prefix
- * @param header    NULL or the headline
- */
-void RplSymbolSpace::dump(RplWriter& writer, int indent, const char* header)
-{
-    if (header != NULL)
-        writer.writeLine(header);
-    writer.formatIndented(indent, "= %s (%s) parent: %s", m_name.constData(),
-            spaceTypeName(m_type),
-            m_parent == NULL ? "<none>" : m_parent->name().constData());
-    QList<QByteArray> sorted;
-    if (m_classes.size() > 0){
-        writer.writeIndented(indent, "== Classes:");
-        sorted.reserve(m_classes.size());
-        ClassMap::iterator it;
-        for (it = m_classes.begin(); it != m_classes.end(); it++){
-           sorted.append(it.key());
-        }
-        qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
-        QList<QByteArray>::iterator it2;
-        for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
-            RplASClass* clazz = m_classes[*it2];
-            clazz->dump(writer, indent);
-        }
-    }
-    if (m_methods.size() > 0){
-        writer.writeIndented(indent, "== Methods:");
-        sorted.clear();
-        sorted.reserve(m_variables.size());
-        MethodMap::iterator it3;
-        for (it3 = m_methods.begin(); it3 != m_methods.end(); it3++){
-           sorted.append(it3.key());
-        }
-        qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
-        QList<QByteArray>::iterator it4;
-        for (it4 = sorted.begin(); it4 != sorted.end(); it4++){
-            RplASMethod* method = m_methods[*it4];
-            do {
-                method->dump(writer, indent);
-                method = method->sibling();
-            } while (method != NULL);
-        }
-    }
-
-    if (m_listOfVars.size() > 0){
-        writer.writeIndented(indent, "== Variables:");
-        QList<QByteArray>::iterator it6;
-        for (int ix = 0; ix < m_listOfVars.size(); ix++){
-            RplASVarDefinition* var = m_listOfVars[ix];
-            var->dump(writer, indent);
-        }
-    }
-    if (m_body != NULL){
-        writer.writeIndented(indent, "== Body:");
-        RplASNode1::dumpStatements(writer, indent, m_body);
-    }
-}
-
-/**
- * @brief Returns the name of a space type.
- *
- * @param type  type to inspect
- * @return      the name of the type
- */
-const char*RplSymbolSpace::spaceTypeName(
-        RplSymbolSpace::SymbolSpaceType type)
-{
-    const char* rc = NULL;
-    switch(type){
-    case SST_UNDEF:
-        rc = "undef";
-        break;
-    case SST_GLOBAL:
-        rc = "global";
-        break;
-    case SST_MODULE:
-        rc = "module";
-        break;
-    case SST_CLASS:
-        rc = "class";
-        break;
-    case SST_METHOD:
-        rc = "method";
-        break;
-    default:
-        rc = "?";
-        break;
-    }
-    return rc;
-}
-
-/**
- * @brief Initilizes the global symbol space.
- *
- * @param tree  the abstract syntax tree
- * @return      the global symbol space
- */
-RplSymbolSpace* RplSymbolSpace::createGlobal(RplASTree& tree)
-{
-    RplSymbolSpace* rc = new RplSymbolSpace(tree);
-    rc->m_tree = tree;
-    RplASInteger::m_instance = new RplASInteger(tree);
-    rc->m_classes[RplASInteger::m_instance->name()] = RplASInteger::m_instance;
-    RplASBoolean::m_instance = new RplASBoolean(tree);
-    rc->m_classes[RplASBoolean::m_instance->name()] = RplASBoolean::m_instance;
-    RplASFloat::m_instance = new RplASFloat(tree);
-    rc->m_classes[RplASFloat::m_instance->name()] = RplASFloat::m_instance;
-    RplASString::m_instance = new RplASString(tree);
-    rc->m_classes[RplASString::m_instance->name()] = RplASString::m_instance;
-    RplASList::m_instance = new RplASList(tree);
-    rc->m_classes[RplASList::m_instance->name()] = RplASList::m_instance;
-    RplASMap::m_instance = new RplASMap(tree);
-    rc->m_classes[RplASMap::m_instance->name()] = RplASMap::m_instance;
-    RplASVoid::m_instance = new RplASVoid(tree);
-    rc->m_classes[RplASVoid::m_instance->name()] = RplASVoid::m_instance;
-    RplASFormula::m_instance = new RplASFormula(tree);
-    rc->m_classes[RplASFormula::m_instance->name()] = RplASFormula::m_instance;
-    return rc;
-}
-/**
- * @brief Returns the list of the variables.
- *
- * @return the list of the variables
- */
-RplSymbolSpace::VariableList RplSymbolSpace::listOfVars() const
-{
-    return m_listOfVars;
-}
-
-/**
- * @brief Returns the parent of the symbol space.
- *
- * @return  the symbolspace of the object (module, method, class..) containing
- *          the object belonging to the instance
- */
-RplSymbolSpace* RplSymbolSpace::parent() const
-{
-    return m_parent;
-}
-
-/**
- * @brief Returns the body (an abstract syntax tree) of the symbol space.
- *
- * @return  NULL: no body available<br>
- *          othewise: the body of the instance
- */
-RplASItem* RplSymbolSpace::body() const
-{
-    return m_body;
-}
-
-/**
- * @brief Sets the body (an abstract syntax tree) of the symbol space.
- *
- * @param body  the new body
- */
-void RplSymbolSpace::setBody(RplASItem* body)
-{
-    m_body = body;
-}
-
-/**
- * @brief Adds a variable to the symbol space.
- *
- * @param variable  the variable to add
- * @param varNo     OUT: variable number, current number in the symbol space
- * @return          NULL: success<br>
- *                  otherwise: the already defined variable/method
- */
-RplASItem* RplSymbolSpace::addVariable(RplASVarDefinition* variable, int& varNo)
-{
-    RplASItem* rc = NULL;
-    const QByteArray& name = variable->name();
-    if (m_variables.contains(name))
-        rc = m_variables[name];
-    else if (m_methods.contains(name))
-        rc = m_methods[name];
-    else {
-        m_variables[name] = variable;
-        varNo = m_listOfVars.size();
-        m_listOfVars.append(variable);
-    }
-    return rc;
-}
-
-/**
- * @brief Adds a method to the symbol space.
- *
- * @param method    the method to add
- * @return          NULL: success<br>
- *                  otherwise: the already defined variable/method
- */
-RplASItem* RplSymbolSpace::addMethod(RplASMethod* method)
-{
-    RplASItem* rc = NULL;
-    const QByteArray& name = method->name();
-    if (m_variables.contains(name))
-        rc = m_variables[name];
-    else if (! m_methods.contains(name)){
-        m_methods[name] = method;
-    } else {
-        RplASMethod* first = m_methods[name];
-        RplASMethod* oldMethod = first;
-        do {
-            if (oldMethod->equalSignature(*method))
-                rc = oldMethod;
-            else
-                oldMethod = oldMethod->sibling();
-        } while (rc == NULL && oldMethod != NULL);
-        if (rc == NULL){
-            method->setChild(first);
-            m_methods[name] = method;
-        }
-    }
-    return rc;
-}
-/**
- * @brief Adds a class to the instance.
- *
- * @param clazz     the class to add
- * @return          NULL: success<br>
- *                  otherwise: the already defined class
- */
-RplASUserClass* RplSymbolSpace::addClass(RplASUserClass* clazz)
-{
-    RplASUserClass* rc = NULL;
-    const QByteArray& name = clazz->name();
-    if (m_classes.contains(name)){
-        rc = dynamic_cast<RplASUserClass*>(m_classes[name]);
-    } else {
-        m_classes[name] = clazz;
-    }
-    return rc;
-}
-
-/**
- * @brief Returns the name of the symbol space.
- *
- * @return the name
- */
-const QByteArray& RplSymbolSpace::name() const
-{
-    return m_name;
-}
-
-
-/** @class RplASBoolean rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the class of a Boolean.
- *
- * A Boolean is a real value.
- */
-/**
- * @brief Constructor.
- */
-RplASBoolean::RplASBoolean(RplASTree& tree) :
-    RplASClass("Bool", tree)
-{
-}
-/**
- * @brief Creates a value object (used in RplASVariant).
- *
- * For Booleans nothing is to do!
- *
- * @param source    NULL or a source to copy
- * @return          NULL
- */
-void* RplASBoolean::newValueInstance(void*) const
-{
-    return NULL;
-}
-
-/**
- * @brief Destroys the given object.
- *
- * For Booleans nothing is to do!
- *
- * @param object    object to destroy
- */
-void RplASBoolean::destroyValueInstance(void*) const
-{
-}
-
-/**
- * @brief Calculates the boolean value of an class specific object.
- *
- * This method should never be called.
- *
- * @param object    the object to test (with type QList*)
- * @return          false
- */
-bool RplASBoolean::boolValueOf(void*) const
-{
-    return false;
-}
-
-/**
- * @brief Returns a string representation of an instance.
- *
- * @param object    the object to convert
- * @param maxLength not used
- * @return          a string describing the <code>object</code>
- */
-QByteArray RplASBoolean::toString(void* object, int) const
-{
-    return ((RplASVariant*) object)->asBool() ? "True" : "False";
-}
-
-/** @class RplASNumber rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the class of a Boolean.
- *
- * A Boolean is one of the values true and false.
- */
-/**
- * @brief Constructor.
- */
-RplASFloat::RplASFloat(RplASTree& tree) :
-    RplASClass("Float", tree)
-{
-}
-
-RplASFloat::RplASFloat(const QByteArray& name, RplASTree& tree) :
-    RplASClass(name, tree)
-{
-    m_superClass = RplASFloat::m_instance;
-}
-/**
- * @brief Creates a value object (used in RplASVariant).
- *
- * For Booleans nothing is to do!
- *
- * @param source    NULL or a source to copy
- * @return          NULL
- */
-void* RplASFloat::newValueInstance(void*) const
-{
-    return NULL;
-}
-
-/**
- * @brief Destroys the given object.
- *
- * For Booleans nothing is to do!
- *
- * @param object    object to destroy
- */
-void RplASFloat::destroyValueInstance(void*) const
-{
-}
-
-/**
- * @brief Calculates the boolean value of an class specific object.
- *
- * This method should never be called.
- *
- * @param object    the object to test
- * @return          false
- */
-bool RplASFloat::boolValueOf(void*) const
-{
-    return false;
-}
-
-/**
- * @brief Returns a string representation of an instance.
- *
- * @param object    the object to convert
- * @param maxLength not used
- * @return          a string describing the <code>object</code>
- */
-QByteArray RplASFloat::toString(void* object, int) const
-{
-    char buffer[256];
-
-    qsnprintf(buffer, sizeof buffer, "%f", ((RplASVariant *) object)->asFloat());
-    return buffer;
-}
-
-/** @class RplASInteger rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the class of a Boolean.
- *
- * A Boolean is a one of the values true and false.
- */
-/**
- * @brief Constructor.
- */
-RplASInteger::RplASInteger(RplASTree& tree) :
-    RplASFloat("Int", tree)
-{
-}
-
-/**
- * @brief Calculates the boolean value of an class specific object.
- *
- * This method should never be called.
- *
- * @param object    the object to test
- * @return          false
- */
-bool RplASInteger::boolValueOf(void*) const
-{
-    return false;
-}
-
-/**
- * @brief Returns a string representation of an instance.
- *
- * @param object    the object to convert
- * @param maxLength the maximum length of the result
- * @return          a string describing the <code>object</code>
- */
-QByteArray RplASInteger::toString(void* object, int maxLength) const
-{
-    char buffer[64];
-    qsnprintf(buffer, sizeof buffer, "%.*d", maxLength,
-              ((RplASVariant *) object)->asInt());
-    return buffer;
-}
-
-
-/** @class RplASString rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the class of a string.
- *
- * A string is a mutable character sequence.
- */
-/**
- * @brief Constructor.
- */
-RplASString::RplASString(RplASTree& tree) :
-    RplASClass("Str", tree)
-{
-}
-/**
- * @brief Creates a value object (used in RplASVariant).
- *
- * @param source    NULL or a source to copy
- * @return          a new value object (specific for the class)
- */
-void* RplASString::newValueInstance(void* source) const
-{
-    QByteArray* rc = source == NULL ? new QByteArray() : new QByteArray(*(QByteArray*) source);
-    return (void*) rc;
-}
-
-/**
- * @brief Destroys the given object.
- *
- * The object must be created by <code>newValueInstance()</code>.
- *
- * @param object    object to destroy
- */
-void RplASString::destroyValueInstance(void* object) const
-{
-    delete (QByteArray*) object;
-}
-
-/**
- * @brief Calculates the boolean value of an class specific object.
- *
- * This method should never be called.
- *
- * @param object    the object to test (a QByteArray* instance)
- * @return          false: the string is empty
- *                  true: otherwise
- */
-bool RplASString::boolValueOf(void* object) const
-{
-    bool rc = false;
-    if (object != NULL){
-        QByteArray* string = static_cast<QByteArray*>(object);
-        if (string == NULL)
-            throw RplException("RplASString.boolValueOf(): not a string");
-        rc = ! string->isEmpty();
-    }
-    return rc;
-}
-
-/**
- * @brief Returns a string representation of an instance.
- *
- * @param object    the object to convert
- * @param maxLength the maximum length of the result
- * @return          a string describing the <code>object</code>
- */
-QByteArray RplASString::toString(void* object, int maxLength) const
-{
-    QByteArray rc;
-    QByteArray* string = reinterpret_cast<QByteArray*> (object);
-    int length = string->size();
-    if (length + 2 > maxLength)
-        length = maxLength - 2;
-    rc.reserve(length);
-    rc += "'";
-    if (string->size() < maxLength - 2) {
-        rc += *string;
-    } else {
-        rc += string->mid(0, maxLength - 2 - 3);
-        rc += "...";
-    }
-    rc += "'";
-    return rc;
-}
-
-/** @class RplASList rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the class of a list.
- *
- * A list is a container of any values.  Values can be selected by the index.
- */
-/**
- * @brief Constructor.
- */
-RplASList::RplASList(RplASTree& tree) :
-    RplASClass("List", tree)
-{
-}
-
-/**
- * @brief Creates a value object (used in RplASVariant).
- *
- * @param source    NULL or a source to copy
- * @return          a new value object (specific for the class)
- */
-void* RplASList::newValueInstance(void* source) const
-{
-    RplASListOfVariants* rc = new RplASListOfVariants();
-    if (source != NULL){
-        RplASListOfVariants* source2 = (RplASListOfVariants*) source;
-        rc->reserve(source2->size());
-        RplASListOfVariants::iterator it;
-        for (it = source2->begin();
-                it != source2->end();
-                it++){
-            // deleting in destroyValue():
-            rc->append(new RplASVariant(*(*it)));
-        }
-    }
-    return (void*) rc;
-}
-
-/**
- * @brief Destroys the given object.
- *
- * The object must be created by <code>newValueInstance()</code>.
- *
- * @param object    object to destroy
- */
-void RplASList::destroyValueInstance(void* object) const
-{
-    delete static_cast<RplASListOfVariants*>(object);
-}
-
-/**
- * @brief Calculates the boolean value of an class specific object.
- *
- * @param object    the object to test (with type QList*)
- * @return          false: the list is empty<br>
- *                  true: otherwise
- */
-bool RplASList::boolValueOf(void* object) const
-{
-    bool rc = false;
-    if (object != NULL){
-        RplASListOfVariants* list = static_cast<RplASListOfVariants*>(object);
-        if (list == NULL)
-            throw RplException("RplASList.boolValueOf(): not a list");
-        rc = ! list->empty();
-    }
-    return rc;
-}
-
-/**
- * @brief Returns a string representation of an instance.
- *
- * @param object    the object to convert
- * @param maxLength unused
- * @return          a string describing the <code>object</code>
- */
-QByteArray RplASList::toString(void* object, int maxLength) const
-{
-    QByteArray rc;
-    rc.reserve(maxLength);
-    rc += "[";
-    RplASListOfVariants* list = reinterpret_cast<RplASListOfVariants*>(object);
-    RplASListOfVariants::iterator it;
-    bool first = true;
-    for(it = list->begin(); it != list->end(); it++){
-        if (first)
-            first = false;
-        else
-            rc += ",";
-        QByteArray part = (*it)->toString(maxLength - rc.size() - 5);
-        if (maxLength - rc.size() - 5 - part.size() <= 0){
-            rc += "...";
-            break;
-        } else {
-            rc += part;
-        }
-
-    }
-    rc += "]";
-    return rc;
-}
-
-/** @class RplASMap rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the class of a map.
- *
- * A map is a container of (key, value) pairs.
- * Values can be selected by the key.
- */
-/**
- * @brief Constructor.
- */
-RplASMap::RplASMap(RplASTree& tree) :
-    RplASClass("Map", tree)
-{
-}
-/**
- * @brief Creates a value object (used in RplASVariant).
- *
- * @param source    NULL or a source to copy
- * @return          a new value object (specific for the class)
- */
-void* RplASMap::newValueInstance(void* source) const
-{
-    RplASMapOfVariants* rc = new RplASMapOfVariants();
-    if (source != NULL){
-        RplASMapOfVariants* source2 =
-                static_cast<RplASMapOfVariants*>(source);
-        // rc->reserve(source2->size());
-        RplASMapOfVariants::iterator it;
-        for (it = source2->begin(); it != source2->end(); it++){
-            // deleting in destroyValue():
-            const QByteArray& key = it.key();
-            RplASVariant* value = new RplASVariant(*it.value());
-            (*rc)[key] = value;
-        }
-    }
-    return (void*) rc;
-}
-
-/**
- * @brief Destroys the given object.
- *
- * The object must be created by <code>newValueInstance()</code>.
- *
- * @param object    object to destroy
- */
-void RplASMap::destroyValueInstance(void* object) const
-{
-    delete (RplASMapOfVariants*) object;
-}
-
-/**
- * @brief Calculates the boolean value of an class specific object.
- *
- * @param object    the object to test (with type QMap*)
- * @return
- */
-bool RplASMap::boolValueOf(void* object) const
-{
-    bool rc = false;
-    if (object != NULL){
-        RplASMapOfVariants* map = reinterpret_cast<RplASMapOfVariants*>(object);
-        if (map == NULL)
-            throw RplException("RplASMap.boolValueOf(): not a map");
-        rc = map->empty() > 0;
-    }
-    return rc;
-}
-
-/**
- * @brief Returns a string representation of an instance.
- *
- * @param object    the object to convert
- * @param maxLength maximal length of the result
- * @return          a string describing the <code>object</code>
- */
-QByteArray RplASMap::toString(void* object, int maxLength) const
-{
-    QByteArray rc;
-    rc.reserve(maxLength);
-    rc += "[";
-    RplASMapOfVariants* map = reinterpret_cast<RplASMapOfVariants*>(object);
-    RplASMapOfVariants::iterator it;
-    bool first = true;
-    for(it = map->begin(); it != map->end(); it++){
-        if (first)
-            first = false;
-        else
-            rc += ",";
-        if (maxLength - rc.size() - 5 - 2 - it.key().size() <= 0){
-            rc += "...";
-            break;
-        } else {
-            rc += "'";
-            rc += it.key();
-            rc += "':";
-        }
-        QByteArray part = it.value()->toString(maxLength - rc.size() - 5);
-        if (maxLength - rc.size() - 5 - part.size() <= 0){
-            rc += "...";
-            break;
-        } else {
-            rc += part;
-        }
-
-    }
-    rc += "}";
-    return rc;
-}
-
-
-/** @class RplVariable rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a variable of a symbol space.
- */
-
-/**
- * @brief Constructor.
- */
-RplVariable::RplVariable(const QByteArray& name) :
-    m_name(name),
-    m_namespace(NULL),
-    m_value(),
-    m_type(NULL)
-{
-
-}
-
-/**
- * @brief Writes the content of the instance into an output media.
- *
- * @param writer    writes to output
- * @param indent    nesting level: so many tabs will be used as prefix
- */
-void RplVariable::dump(RplWriter& writer, int indent)
-{
-    const char* name1 =  m_type == NULL ? "NoneType" : m_type->name().constData();
-    QByteArray val = m_value.toString();
-    writer.formatIndented(indent, "%s %s: value: %s",
-           name1, m_name.constData(), val.constData());
-}
-/**
- * @brief Returns the data type of the variable.
- *
- * @return  the class of the variable
- */
-RplASClass* RplVariable::type() const
-{
-    return m_type;
-}
-
-/**
- * @brief Sets the data type.
- * @param type  the class of the variable
- */
-void RplVariable::setType(RplASClass* type)
-{
-    m_type = type;
-}
-/**
- * @brief Returns the name of the variable.
- *
- * @return  the name
- */
-const QByteArray& RplVariable::name() const
-{
-    return m_name;
-}
-
-/** @class RplVariable rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a data type representing a none type.
- */
-RplASVoid::RplASVoid(RplASTree& tree) :
-    RplASClass("Void", tree)
-{
-}
-
-/**
- * @brief Instantiates a new object.
- *
- * In this case we do nothing.
- *
- * @param source    ignored
- * @return
- */
-void*RplASVoid::newValueInstance(void*) const
-{
-    return NULL;
-}
-
-/**
- * @brief Destroys an object created by newValueInstance.
- *
- * In this case we do nothing.
- *
- * @param object    not used
- */
-void RplASVoid::destroyValueInstance(void*) const
-{
-}
-
-/**
- * @brief Returns the bool value of the given object
- * @param object    ignored
- * @return          false
- */
-bool RplASVoid::boolValueOf(void*) const
-{
-    return false;
-}
-
-/**
- * @brief Converts the object into a string.
- *
- * @param object    ignored
- * @param maxLength ignored
- * @return          the empty string
- */
-QByteArray RplASVoid::toString(void*, int) const
-{
-    return QByteArray("");
-}
-
-/** @class RplASFormula rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a data type representing a calculated value.
- */
-
-/**
- * @brief Constructor.
- *
- * @param tree  the abstract syntax tree
- */
-RplASFormula::RplASFormula(RplASTree& tree) :
-    RplASClass("Formula", tree)
-{
-}
-
-/**
- * @brief Instantiates a new object.
- *
- * In this case we do nothing.
- *
- * @param expr      the result
- * @return
- */
-void* RplASFormula::newValueInstance(void* expr) const
-{
-    return expr;
-}
-
-/**
- * @brief Destroys an object created by newValueInstance.
- *
- * In this case we do nothing.
- *
- * @param object    not used
- */
-void RplASFormula::destroyValueInstance(void*) const
-{
-}
-
-/**
- * @brief Returns the bool value of the given object
- * @param object    ignored
- * @return          false
- */
-bool RplASFormula::boolValueOf(void*) const
-{
-    return false;
-}
-
-/**
- * @brief Converts the object into a string.
- *
- * @param object    ignored
- * @param maxLength ignored
- * @return          the empty string
- */
-QByteArray RplASFormula::toString(void* object, int) const
-{
-    RplASExprStatement* expr = static_cast<RplASExprStatement*>(object);
-
-    char buffer[64];
-    qsnprintf(buffer, sizeof buffer, "<formula %d>", expr->id());
-    return buffer;
-}
-
-/** @class RplASUserClass rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a data type representing an user defined class.
- */
-
-
-/**
- * @brief Constructor.
- *
- * @param name      name of the user defined class
- * @param position  the position of the class definition
- * @param tree      the abstract syntax tree
- */
-RplASUserClass::RplASUserClass(const QByteArray& name,
-                               const RplSourcePosition* position,
-                               RplASTree& tree) :
-    RplASClass(name, tree),
-    m_position(position)
-{
-}
-
-/**
- * @brief Creates an instance of an user defined class.
- *
- * @param source    the type (user defined class) of the result
- * @return          an instance of an user defined class
- */
-void*RplASUserClass::newValueInstance(void* source) const
-{
-    RplASUserClass* clazz = static_cast<RplASUserClass*>(source);
-    RplASUserObject* rc = new RplASUserObject(clazz);
-    return static_cast<void*>(rc);
-}
-
-void RplASUserClass::destroyValueInstance(void* object) const
-{
-    RplASUserObject* obj = static_cast<RplASUserObject*>(object);
-    delete obj;
-}
-
-/**
- * @brief Returns the bool value of the object.
- *
- * @param object    object to test
- * @return          true: object != NULL<br>
- *                  false: object == NULL
- */
-bool RplASUserClass::boolValueOf(void* object) const
-{
-    return object != NULL;
-}
-
-/**
- * @brief Returns a string representation an instance of a user defined class.
- *
- * @param object        object to convert
- * @param maxLength     maximum length of the string
- * @return
- */
-QByteArray RplASUserClass::toString(void*, int) const
-{
-    return m_name;
-}
-/**
- * @brief Returns the source position of the instance.
- *
- * @return  the source position
- */
-const RplSourcePosition* RplASUserClass::position() const
-{
-    return m_position;
-}
-
-
-
-/** @class RplASUserObject rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an instance of an user defined class.
- */
-RplASUserObject::RplASUserObject(RplASUserClass* clazz) :
-    m_class(clazz),
-    m_fields(NULL)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplASUserObject::~RplASUserObject()
-{
-    delete[] m_fields;
-    m_fields = NULL;
-}
diff --git a/rplexpr/rplasclasses.hpp b/rplexpr/rplasclasses.hpp
deleted file mode 100644 (file)
index fbb5df2..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLASCLASSES_HPP
-#define RPLASCLASSES_HPP
-
-class RplSymbolSpace;
-class RplVariable {
-public:
-    RplVariable(const QByteArray& name);
-public:
-    void dump(RplWriter& writer, int indent);
-
-    RplASClass* type() const;
-    void setType(RplASClass* type);
-    const QByteArray& name() const;
-
-protected:
-    QByteArray m_name;
-    // NULL for "simple" variables (int, float, bool)
-    RplSymbolSpace* m_namespace;
-    RplASVariant m_value;
-    RplASClass* m_type;
-};
-
-class RplASScope
-{
-public:
-    int m_builtInVars;
-    int m_varNoAtStart;
-};
-
-class RplASUserClass;
-class RplASTree;
-class RplSymbolSpace
-{
-public:
-    enum SymbolSpaceType {
-        SST_UNDEF,
-        SST_GLOBAL,
-        SST_MODULE,
-        SST_CLASS,
-        SST_METHOD
-    };
-
-public:
-    typedef QMap<QByteArray, RplASVarDefinition*> VariableMap;
-    typedef QMap<QByteArray, RplASClass*> ClassMap;
-    typedef QMap<QByteArray, RplASMethod*> MethodMap;
-    typedef QList<RplASVarDefinition*> VariableList;
-private:
-    RplSymbolSpace(RplASTree& tree);
-public:
-    RplSymbolSpace(SymbolSpaceType type, const QByteArray& name,
-                   RplSymbolSpace* parent);
-    virtual ~RplSymbolSpace();
-public:
-    void startScope(RplASScope& scope);
-    void finishScope(int endOfScope, RplASScope& scope);
-    RplASVarDefinition* findVariable(const QByteArray& name) const;
-    RplASClass* findClass(const QByteArray& name) const;
-    RplASMethod* findMethod(const QByteArray& name) const;
-    void dump(RplWriter& writer, int indent, const char* header = NULL);
-    const QByteArray& name() const;
-    RplASItem* body() const;
-    void setBody(RplASItem* body);
-    RplASItem* addVariable(RplASVarDefinition* variable, int& varNo);
-    RplASItem* addMethod(RplASMethod* method);
-    RplASUserClass* addClass(RplASUserClass* clazz);
-    RplSymbolSpace* parent() const;
-    VariableList listOfVars() const;
-public:
-    static const char* spaceTypeName(SymbolSpaceType type);
-    static RplSymbolSpace* createGlobal(RplASTree& tree);
-private:
-    SymbolSpaceType m_type;
-    QByteArray m_name;
-    VariableMap m_variables;
-    ClassMap m_classes;
-    MethodMap m_methods;
-    RplSymbolSpace* m_parent;
-    RplASItem* m_body;
-    VariableList m_listOfVars;
-    RplASTree& m_tree;
-};
-
-class RplASBoolean : public RplASClass {
-public:
-    RplASBoolean(RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASBoolean* m_instance;
-};
-
-class RplASFloat : public RplASClass {
-public:
-    RplASFloat(RplASTree& tree);
-    RplASFloat(const QByteArray& name, RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASFloat* m_instance;
-};
-
-class RplASInteger : public RplASFloat {
-public:
-    RplASInteger(RplASTree& tree);
-public:
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASInteger* m_instance;
-};
-
-class RplASString : public RplASClass {
-public:
-    RplASString(RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASString* m_instance;
-};
-
-class RplASList : public RplASClass {
-public:
-    RplASList(RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASList* m_instance;
-};
-
-class RplASMap : public RplASClass {
-public:
-    RplASMap(RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASMap* m_instance;
-};
-
-class RplASVoid : public RplASClass {
-public:
-    RplASVoid(RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASVoid* m_instance;
-};
-
-class RplASFormula : public RplASClass {
-public:
-    RplASFormula(RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-public:
-    static RplASFormula* m_instance;
-};
-
-class RplASUserClass : public RplASClass {
-public:
-    RplASUserClass(const QByteArray& name, const RplSourcePosition* position,
-                   RplASTree& tree);
-public:
-    void* newValueInstance(void* source = NULL) const;
-    void destroyValueInstance(void* object) const;
-    virtual bool boolValueOf(void* object) const;
-    virtual QByteArray toString(void *object, int maxLength = 80) const;
-    const RplSourcePosition* position() const;
-
-private:
-    const RplSourcePosition* m_position;
-};
-
-class RplASUserObject {
-public:
-    RplASUserObject(RplASUserClass* clazz);
-    ~RplASUserObject();
-public:
-    void callMember();
-private:
-    RplASUserClass* m_class;
-    RplASVariant* m_fields;
-};
-
-#endif // RPLASCLASSES_HPP
diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp
deleted file mode 100644 (file)
index de8e3e5..0000000
+++ /dev/null
@@ -1,3694 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-/** @file
- *
- * @brief Implementation of an Abstract Syntax Tree.
- *
- */
-/** @file rplexpr/rplastree.hpp
- *
- * @brief Definitions for an Abstract Syntax Tree.
- *
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-
-enum {
-    LOC_VARDEF_EXEC_1 = RPL_FIRST_OF(RPL_MODULE_ASTREE), // 11001
-    LOC_UNOP_CALC_1,
-    LOC_UNARY_CHECK_1,
-    LOC_UNARY_CHECK_2,
-    LOC_UNARY_CHECK_3, // 11005
-    LOC_BINOP_1,
-    LOC_BINOP_CALC_1,
-    LOC_BINOP_CALC_2,
-    LOC_BINOP_CALC_3,
-    LOC_BINOP_CALC_4, // 11010
-    LOC_BINOP_CALC_5,
-    LOC_BINOP_CALC_6,
-    LOC_BINOP_CALC_7,
-    LOC_BINOP_CALC_8,
-    LOC_BINOP_CALC_9,   // 11015
-    LOC_BINOP_CALC_10,
-    LOC_BINOP_CALC_11,
-    LOC_BINOP_CALC_12,
-    LOC_VARDEF_CHECK_1,
-    LOC_VARDEF_CHECK_2, // 11020
-    LOC_ITEM_STATEM_LIST_1,
-    LOC_CONV_CHECK_1,
-    LOC_CONV_TRY_1,
-    LOC_ITEM_FORCE_ERROR_1,
-    LOC_UNARY_CHECK_4,  // 11025
-    LOC_IF_CHECK_1,
-    LOC_IF_CHECK_2,
-    LOC_FORC_CHECK_1,
-    LOC_FORC_CHECK_2,
-    LOC_FORC_CHECK_3, // 11030
-    LOC_ITEM_AS_INT_1,
-    LOC_ITEM_AS_INT_2,
-    LOC_METHOD_CALL_CHECK_1,
-    LOC_MEHTOD_CALL_CHECK_2,
-    LOC_MEHTOD_CALL_CHECK_3,    // 11035
-    LOC_MEHTOD_CALL_CHECK_4,
-    LOC_COUNT
-};
-
-unsigned int RplASItem::m_nextId = 1;
-
-#define DEFINE_TABS(indent)  \
-    char tabs[32]; \
-    memset(tabs, '\t', sizeof tabs); \
-    tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0'
-
-/**
- * @brief Writes a map into a file.
- *
- * The output is sorted by key.
- *
- * @param writer        writes to output
- * @param map           map to dump
- * @param withEndOfLine true: '\n' will be written at the end
- */
-void dumpMap(RplWriter& writer, RplASMapOfVariants& map, bool withEndOfLine)
-{
-    QList<QByteArray> sorted;
-    sorted.reserve(map.size());
-    RplASMapOfVariants::iterator it;
-    for (it = map.begin(); it != map.end(); it++){
-       sorted.append(it.key());
-    }
-    qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
-    QList<QByteArray>::iterator it2;
-    bool first = true;
-    for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
-        RplASVariant* value = map[*it2];
-        writer.format("%c'%s':%s", first ? '{' : ',', (*it2).constData(),
-            value->toString().constData());
-        first = false;
-    }
-    if (first)
-        writer.write("{");
-    writer.write("}");
-    if (withEndOfLine)
-        writer.writeLine();
-}
-
-/** @class RplASException rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a specific exception for the Abstract Syntax Tree.
- */
-
-/**
- * @brief Builds the message.
- *
- * @param position  describes the position of the error/warning
- * @param format    the reason of the exception
- * @param varList   the values for the placeholders in the format.
- */
-void RplASException::build(const RplSourcePosition* position,
-                                 const char* format, va_list varList)
-{
-    char buffer[64000];
-    if (position != NULL){
-        m_message = position->toString().toUtf8();
-        m_message += ": ";
-    }
-    qvsnprintf(buffer, sizeof buffer, format, varList);
-    m_message += buffer;
-}
-
-/**
- * @brief Constructor.
- *
- * @param position  describes the position of the error/warning
- * @param format    the reason of the exception
- * @param ...       the values for the placeholders in the format.
- */
-RplASException::RplASException(const RplSourcePosition* position,
-                                 const char* format, ...) :
-    RplException("")
-{
-    va_list ap;
-    va_start(ap, format);
-    build(position, format, ap);
-    va_end(ap);
-}
-
-/**
- * @brief Constructor.
- */
-RplASException::RplASException() :
-    RplException("")
-{
-}
-
-/** @class RplASVariant rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a class which can hold the value of any type.
- *
- * The VM uses some tricks (performance): Therefore this class
- * must not be virtual!
- */
-/**
- * @brief Constructor.
- */
-RplASVariant::RplASVariant() :
-    m_variantType(VT_UNDEF),
-    m_flags(VF_UNDEF),
-    // m_value(),
-    m_class(NULL)
-{
-}
-/**
- * @brief Destructor.
- */
-RplASVariant::~RplASVariant()
-{
-    destroyValue();
-    m_variantType = VT_UNDEF;
-}
-
-/**
- * @brief Copy constructor.
- * @param source    the source to copy
- */
-RplASVariant::RplASVariant(const RplASVariant& source):
-    m_variantType(source.m_variantType),
-    m_flags(source.m_flags),
-    // m_value
-    m_class(source.m_class)
-{
-    copyValue(source);
-}
-
-/**
- * @brief Assignment operator.
- *
- * @param source    the source to copy
- * @return          the instance itself
- */
-RplASVariant&RplASVariant::operator=(const RplASVariant& source)
-{
-    destroyValue();
-    m_variantType = source.m_variantType;
-    m_flags = source.m_flags;
-    m_class = source.m_class;
-    copyValue(source);
-    return *this;
-}
-
-/**
- * @brief Copies the value.
- * @param source    the source to copy
- */
-void RplASVariant::copyValue(const RplASVariant& source)
-{
-    destroyValue();
-    m_variantType = source.m_variantType;
-    m_class = source.m_class;
-
-    switch(source.m_variantType)
-    {
-    case VT_BOOL:
-        m_value.m_bool = source.m_value.m_bool;
-        break;
-    case VT_FLOAT:
-        m_value.m_float = source.m_value.m_float;
-        break;
-    case VT_INTEGER:
-        m_value.m_int = source.m_value.m_int;
-        break;
-    case VT_UNDEF:
-        break;
-    default:
-        m_value.m_object = m_class->newValueInstance(source.m_value.m_object);
-        break;
-    }
-    m_flags = source.m_flags;
-}
-
-/**
- * @brief Frees the resources of the instance.
- */
-void RplASVariant::destroyValue()
-{
-    switch(m_variantType)
-    {
-    case VT_BOOL:
-    case VT_FLOAT:
-    case VT_INTEGER:
-    case VT_UNDEF:
-        break;
-    default:
-        if ((m_flags & VF_IS_COPY) == 0)
-            m_class->destroyValueInstance(m_value.m_object);
-        m_value.m_object = NULL;
-        break;
-    }
-    m_variantType = VT_UNDEF;
-}
-/**
- * @brief Returns the variantType of the instance.
- *
- * @return  the variant type
- */
-RplASVariant::VariantType RplASVariant::variantType() const
-{
-    return m_variantType;
-}
-
-/**
- * @brief Return the name of the variant type.
- *
- * @return  the type as string
- */
-const char*RplASVariant::nameOfType() const
-{
-    const char* rc = "?";
-    switch(m_variantType){
-    case VT_UNDEF:
-        rc = "<undef>";
-        break;
-    case VT_FLOAT:
-        rc = "Float";
-        break;
-    case VT_INTEGER:
-        rc = "Int";
-        break;
-    case VT_BOOL:
-        rc = "Bool";
-        break;
-    case VT_OBJECT:
-        rc = "Obj";
-        break;
-    default:
-        break;
-    }
-    return rc;
-}
-
-/**
- * @brief Returns the class (data type) of the instance.
- *
- * @return  the variant type
- */
-const RplASClass* RplASVariant::getClass() const
-{
-    return m_class;
-}
-
-
-/**
- * @brief Returns the numeric value.
- *
- * @return              the numeric value
- * @throw RplException  the instance is not a numberic value
- *
- */
-qreal RplASVariant::asFloat() const
-{
-    if (m_variantType != VT_FLOAT)
-        throw RplException("RplASVariant::asNumber: not a number: %d",
-                           m_variantType);
-    return m_value.m_float;
-}
-/**
- * @brief Returns the numeric value.
- *
- * @return              the numeric value
- * @throw RplException  the instance is not a numberic value
- *
- */
-int RplASVariant::asInt() const
-{
-    if (m_variantType != VT_INTEGER)
-        throw RplException("RplASVariant::asInt: not an integer: %d",
-                           m_variantType);
-    return m_value.m_int;
-}
-
-/**
- * @brief Returns the boolean value.
- *
- * @return              the boolean value
- * @throw RplException  the instance is not a boolean value
- *
- */
-bool RplASVariant::asBool() const
-{
-    if (m_variantType != VT_BOOL)
-        throw RplException("RplASVariant::asBool: not a boolean: %d",
-                           m_variantType);
-    return m_value.m_bool;
-}
-
-/**
- * @brief Returns the class specific value.
- *
- * @param clazz         OUT: the class of the instance. May be NULL
- * @return              the class specific value
- * @throw RplException  the instance is not a boolean value
- *
- */
-void* RplASVariant::asObject(const RplASClass** clazz) const
-{
-    if (m_variantType != VT_OBJECT)
-        throw RplException("RplASVariant::asObject: not an object: %d",
-                           m_variantType);
-    if (clazz != NULL)
-        *clazz = m_class;
-    return m_value.m_object;
-}
-
-/**
- * @brief Returns the value as string.
- *
- * @return the value as string
- * @throw RplException  the instance is not a string value
- */
-const QByteArray* RplASVariant::asString() const
-{
-    const RplASClass* clazz;
-    const QByteArray* rc = static_cast<const QByteArray*>(asObject(&clazz));
-    if (clazz != RplASString::m_instance){
-        const QByteArray& name = clazz->name();
-        throw RplException("RplASVariant::asString: not a string: %s",
-                           name.constData());
-    }
-    return rc;
-}
-
-/**
- * @brief Make the instance to a numeric value.
- *
- * @param number    the numeric value.
- */
-void RplASVariant::setFloat(qreal number)
-{
-    destroyValue();
-    m_variantType = VT_FLOAT;
-    m_value.m_float = number;
-    m_class = RplASFloat::m_instance;
-}
-
-/**
- * @brief Make the instance to an integer value.
- *
- * @param integer    the numeric value.
- */
-void RplASVariant::setInt(int integer)
-{
-    destroyValue();
-    m_variantType = VT_INTEGER;
-    m_value.m_int = integer;
-    m_class = RplASInteger::m_instance;
-}
-
-/**
- * @brief Make the instance to a boolean value.
- *
- * @param value    the boolean value.
- */
-void RplASVariant::setBool(bool value)
-{
-    destroyValue();
-    m_variantType = VT_BOOL;
-    m_value.m_bool = value;
-    m_class = RplASBoolean::m_instance;
-}
-
-/**
- * @brief Make the instance to a boolean value.
- *
- * @param string    the string value.
- */
-void RplASVariant::setString(const QByteArray& string)
-{
-    // deletion in RplASVariant::destroyValue():
-    setObject(new QByteArray(string), RplASString::m_instance);
-}
-
-/**
- * @brief Builds a string.
- *
- * @param maxLength     the maximum length of the result
- * @return  the value as string
- */
-QByteArray RplASVariant::toString(int maxLength) const
-{
-    QByteArray rc;
-    char buffer[256];
-    switch(m_variantType)
-    {
-    case VT_BOOL:
-        rc = m_value.m_bool ? "True" : "False";
-        break;
-    case VT_FLOAT:
-        qsnprintf(buffer, sizeof buffer, "%f", m_value.m_float);
-        rc = buffer;
-        break;
-    case VT_INTEGER:
-        qsnprintf(buffer, sizeof buffer, "%lld", m_value.m_int);
-        rc = buffer;
-        break;
-    case VT_OBJECT:
-        rc = m_class->toString(m_value.m_object, maxLength);
-        break;
-    default:
-    case VT_UNDEF:
-        rc = "None";
-        break;
-    }
-    return rc;
-}
-
-/**
- * @brief Make the instance to an object.
- *
- * @param object    the class specific value object.
- * @param clazz     the data type of the object
- */
-void RplASVariant::setObject(void* object, const RplASClass* clazz)
-{
-    destroyValue();
-    m_variantType = VT_OBJECT;
-    m_value.m_object = object;
-    m_class = clazz;
-}
-
-
-/** @class RplASItem rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the abstract base class of all entries of an AST.
- *
- */
-
-/**
- * @brief Constructor.
- *
- * @param type  the type of the instance
- */
-RplASItem::RplASItem(RplASItemType type) :
-    m_id(m_nextId++),
-    m_nodeType(type),
-    m_flags(0),
-    m_position(NULL)
-{
-}
-/**
- * @brief Destructor.
- */
-
-RplASItem::~RplASItem()
-{
-}
-
-/**
- * @brief Checks a calculable node for correctness.
- *
- * @param description   description of the meaning, e.g. "start value"
- * @param expectedClass the node must have this type
- * @param parser        for error processing
- * @return              <code>true</code>: instance and children are correct<br>
- *                      <code>false</code>: otherwise
- */
-bool RplASItem::checkAsCalculable(const char* description,
-                                  RplASClass* expectedClass, RplParser& parser)
-{
-    bool rc = true;
-    if (! check(parser))
-        rc = false;
-    if (rc){
-        RplASCalculable* expr = dynamic_cast<RplASCalculable*>(this);
-        if (expr == NULL)
-            rc = error(LOC_ITEM_AS_INT_1, parser, "%s not calculable: %s",
-                  description, nameOfItemType());
-        else if (expr->clazz() != RplASInteger::m_instance)
-            rc = error(LOC_ITEM_AS_INT_2, parser,
-                       "%s: wrong type %s instead of integer",
-                       description, expr->clazz()->name().constData());
-    }
-    return rc;
-}
-
-/**
- * @brief Returns the position of the item in the source code.
- *
- * @return the position of the item
- */
-const RplSourcePosition* RplASItem::position() const
-{
-    return m_position;
-}
-
-/**
- * @brief Stores the position in the source code.
- *
- * @param position  the position to store
- */
-void RplASItem::setPosition(const RplSourcePosition* position)
-{
-    m_position = position;
-}
-
-/**
- * @brief Returns the id of the instance.
- *
- * @return  the id
- */
-unsigned int RplASItem::id() const
-{
-    return m_id;
-}
-
-/**
- * @brief Returns the position as a string.
- *
- * @param buffer        OUT: the target buffer
- * @param bufferSize    size of the target buffer
- * @return              <code>buffer</code>
- */
-char* RplASItem::positionStr(char buffer[], size_t bufferSize) const
-{
-    char* rc = (char*) "";
-    if (m_position != NULL)
-        rc = m_position->utf8(buffer, bufferSize);
-    return rc;
-}
-
-/**
- * @brief Logs an internal error.
- *
- * @param logger    can write to the output medium
- * @param location  identifies the error location
- * @param format    string with placeholders (optional) like <code>sprintf()</code>
- * @param ...       values for the placeholders
- */
-void RplASItem::error(RplLogger* logger, int location, const char* format, ...)
-{
-    char buffer[1024];
-    int halfBufferSize = (sizeof buffer) / 2;
-    qsnprintf(buffer, halfBufferSize, "id: %d [%s]:", m_id,
-                 positionStr(buffer + halfBufferSize, halfBufferSize));
-    int length = strlen(buffer);
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer + length, (sizeof buffer) - length, format, ap);
-    va_end(ap);
-    logger->log(LOG_ERROR, location, buffer);
-}
-
-/**
- * @brief Resets the static id counter.
- */
-void RplASItem::reset()
-{
-    m_nextId = 1;
-}
-/**
- * @brief Calculates an integer value.
- *
- * @param expr      a calculable node
- * @param thread    the execution unit
- * @return          the value described by the node <code>expr</code>
- */
-int RplASItem::calcAsInteger(RplASItem* expr, RplVMThread& thread)
-{
-    RplASCalculable* expr2 = dynamic_cast<RplASCalculable*>(expr);
-    expr2->calc(thread);
-    RplASVariant& value = thread.popValue();
-    int rc = value.asInt();
-    return rc;
-}
-
-/**
- * @brief Calculates an boolean value.
- *
- * @param expr      a calculable node
- * @param thread    the execution unit
- * @return          the value described by the node <code>expr</code>
- */
-bool RplASItem::calcAsBoolean(RplASItem* expr, RplVMThread& thread)
-{
-    RplASCalculable* expr2 = dynamic_cast<RplASCalculable*>(expr);
-    expr2->calc(thread);
-    RplASVariant& value = thread.popValue();
-    bool rc = value.asBool();
-    return rc;
-}
-/**
- * @brief Checks the correctness of a statement list.
- *
- * @param list      statement list to check
- * @param parser    for error processing
- * @return          <code>true</code>: all statements are correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASItem::checkStatementList(RplASItem* list, RplParser& parser)
-{
-    bool rc = true;
-
-    while(list != NULL){
-        if (! list->check(parser))
-            rc = false;
-        if (dynamic_cast<RplASStatement*>(list) == NULL)
-            rc = list->error(LOC_ITEM_STATEM_LIST_1, parser, "not a statement: %s",
-                    list->nameOfItemType());
-        RplASNode1* node = dynamic_cast<RplASNode1*>(list);
-        if (node == NULL){
-            list->error(LOC_ITEM_STATEM_LIST_1, parser, "not a node: %s",
-                        list->nameOfItemType());
-            list = NULL;
-        } else {
-            list = node->child();
-        }
-    }
-    return rc;
-}
-/**
- * @brief Returns the node type.
- *
- * @return  the node type
- */
-RplASItemType RplASItem::nodeType() const
-{
-    return m_nodeType;
-}
-
-/**
- * @brief Returns the node type as a string.
- *
- * @return  the node type as string
- */
-const char*RplASItem::nameOfItemType() const
-{
-    const char* rc = "?";
-    switch(m_nodeType){
-    case AST_CONSTANT:
-        rc = "constant";
-        break;
-    case AST_LIST_CONSTANT:
-        rc = "list";
-        break;
-    case AST_LIST_ENTRY:
-        rc = "listEntry";
-        break;
-    case AST_MAP_CONSTANT:
-        rc = "map";
-        break;
-    case AST_MAP_ENTRY:
-        rc = "mapEntry";
-        break;
-    case AST_NAMED_VALUE:
-        rc = "namedValue";
-        break;
-    case AST_INDEXED_VALUE:
-        rc = "indexedValue";
-        break;
-    case AST_FIELD:
-        rc = "field";
-        break;
-    case AST_VAR_DEFINITION:
-        rc = "varDef";
-        break;
-    case AST_EXPR_STATEMENT:
-        rc = "exprStatement";
-        break;
-    case AST_METHOD:
-        rc = "method";
-        break;
-    case AST_ARGUMENT:
-        rc = "arg";
-        break;
-    case AST_INTRINSIC_METHOD:
-        rc = "intrinsicMethod";
-        break;
-    case AST_PRE_UNARY_OP:
-        rc = "preUnary";
-        break;
-    case AST_POST_UNARY_OP:
-        rc = "postUnary";
-        break;
-    case AST_BINARY_OP:
-        rc = "binOp";
-        break;
-    case AST_METHOD_CALL:
-        rc = "methodCall";
-        break;
-    case AST_WHILE:
-        rc = "while";
-        break;
-    case AST_REPEAT:
-        rc = "repeat";
-        break;
-    case AST_IF:
-        rc = "if";
-        break;
-    case AST_CONDITION:
-        rc = "condition";
-        break;
-    case AST_ITERATED_FOR:
-        rc = "iFor";
-        break;
-    case AST_COUNTED_FOR:
-        rc = "cFor";
-        break;
-    case AST_SWITCH:
-        rc = "switch";
-        break;
-    case AST_LEAVE:
-        rc = "leave";
-        break;
-    case AST_CONTINUE:
-        rc = "continue";
-        break;
-    default:
-        break;
-    }
-    return rc;
-}
-/**
- * @brief Returns the flags of the node.
- *
- * @return  the bitmask with the flags
- */
-int RplASItem::flags() const
-{
-    return m_flags;
-}
-/**
- * @brief Sets the flags of the node.
- *
- * @param flags     the new value of the bitmask
- */
-void RplASItem::setFlags(int flags)
-{
-    m_flags = flags;
-}
-
-/**
- * @brief Tests the compatibility of 2 data types.
- * @param class1    1st class to inspect
- * @param class2    2nd class to inspect
- * @return          true: classes are compatible<br>
- *                  false: otherwise
- */
-bool RplASItem::typeCheck(RplASClass* class1, RplASClass* class2){
-    bool rc;
-    if (class1 == NULL || class2 == NULL)
-        rc = false;
-    else
-        //@ToDo: subclasses
-        rc = class1 == class2;
-    return rc;
-}
-
-/**
- * @brief Issues an error message.
- *
- * @param location  an error specific id
- * @param parser    for error processing
- * @param format    the error message with placeholders (like <code>printf</code>)
- * @param ...       the values for the placeholders
- * @return          false (for chaining)
- */
-bool RplASItem::error(int location, RplParser& parser, const char* format, ...)
-{
-    va_list varList;
-    va_start(varList, format);
-    parser.addMessage(RplParser::LT_ERROR, location, m_position, format, varList);
-    va_end(varList);
-    return false;
-}
-
-/**
- * @brief Ensures the occurrence of an error.
- *
- * When called a previous error should be happend. If not an internal error
- * will be issued.
- *
- * @param parser    for error processing
- * @param info      additional info
- * @return          <code>false</code> (for chaining)
- */
-bool RplASItem::ensureError(RplParser& parser, const char* info)
-{
-    if (parser.errors() == 0)
-        error(LOC_ITEM_FORCE_ERROR_1, parser, "lost error (internal error): %s");
-    return false;
-}
-
-/** @class RplASCalculable rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief An abstract base class for items which calculates a value.
- *
- */
-/**
- * @brief Constructor.
- */
-RplASCalculable::RplASCalculable() :
-    m_class(NULL)
-{
-}
-/**
- * @brief Returns the class of the node
- * @return  the class
- */
-
-RplASClass* RplASCalculable::clazz() const
-{
-    return m_class;
-}
-/**
- * @brief Sets the class of the node.
- * @param clazz     the new class
- */
-void RplASCalculable::setClass(RplASClass* clazz)
-{
-    m_class = clazz;
-}
-
-/** @class RplASStorable rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the abstract base class of value containing items.
- *
- */
-
-/** @class RplASConstant rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a constant for the Abstract Syntax Tree.
- *
- */
-
-/**
- * @brief Constructor.
- *
- */
-RplASConstant::RplASConstant() :
-    RplASItem(AST_CONSTANT),
-    m_value()
-{
-}
-
-/**
- * @brief Copies the const value to the top of value stack.
- *
- * @param thread    IN/OUT: the execution unit, a VM thread
- */
-void RplASConstant::calc(RplVMThread& thread)
-{
-    RplASVariant& value = thread.reserveValue();
-    value.copyValue(m_value);
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: a constant is always correct
- */
-bool RplASConstant::check(RplParser& parser)
-{
-    return true;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASConstant::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "const id: %d value: %s %s", m_id,
-            m_value.toString().constData(),
-            positionStr(buffer, sizeof buffer));
-}
-
-/**
- * @brief Returns the value of the constant.
- *
- * This method will be used to set the value of the constant:
- * <pre><code>RplASConstant constant;
- * constant.value().setString("Jonny");
- *</code></pre>
- *
- * @return the internal value
- */
-RplASVariant& RplASConstant::value()
-{
-    return m_value;
-}
-
-/** @class RplASListConstant rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a container for constant list entries.
- *
- */
-
-/**
- * @brief Constructor.
- */
-RplASListConstant::RplASListConstant() :
-    RplASNode1(AST_LIST_CONSTANT),
-    RplASCalculable()
-{
-    m_value.setObject(RplASList::m_instance->newValueInstance(),
-                      RplASList::m_instance);
-}
-/**
- * @brief Returns the list.
- *
- * @return  the list
- */
-RplASListOfVariants* RplASListConstant::list(){
-     RplASListOfVariants* rc = static_cast<RplASListOfVariants*>
-             (m_value.asObject(NULL));
-     return rc;
-}
-
-/**
- * @brief Copies the list constant to the top of value stack.
- *
- * @param thread    IN/OUT: the execution unit, a VM thread
- */
-void RplASListConstant::calc(RplVMThread& thread)
-{
-    RplASVariant& value = thread.reserveValue();
-    value.copyValue(m_value);
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: a constant is always correct
- */
-bool RplASListConstant::check(RplParser& parser)
-{
-    return true;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASListConstant::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "listConst id: %d %s", m_id,
-            positionStr(buffer, sizeof buffer));
-
-    QByteArray sValue = m_value.toString(8092);
-    writer.writeIndented(indent + 1, sValue.constData());
-}
-
-/**
- * @brief Returns the value of the constant.
- *
- * This method will be used to set the value of the constant:
- * <pre><code>RplASConstant constant;
- * constant.value().setString("Jonny");
- *</code></pre>
- *
- * @return the internal value
- */
-RplASVariant& RplASListConstant::value()
-{
-    return m_value;
-}
-
-/** @class RplASMapConstant rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a hash map for constant list entries.
- *
- */
-/**
- * @brief RplASMapConstant::RplASMapConstant
- */
-RplASMapConstant::RplASMapConstant() :
-    RplASNode1(AST_MAP_CONSTANT),
-    RplASCalculable(),
-    m_value()
-{
-    m_value.setObject(new RplASMapOfVariants, RplASMap::m_instance);
-}
-
-/**
- * @brief Copies the map constant to the top of value stack.
- *
- * @param thread    IN/OUT: the execution unit, a VM thread
- */
-void RplASMapConstant::calc(RplVMThread& thread)
-{
-    RplASVariant& value = thread.reserveValue();
-    value.copyValue(m_value);
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: a constant is always correct
- */
-bool RplASMapConstant::check(RplParser& parser)
-{
-   return true;
-}
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASMapConstant::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "mapConst id: %d %s",
-            m_id, positionStr(buffer, sizeof buffer));
-    writer.indent(indent);
-    dumpMap(writer, *map(), true);
-}
-
-
-/**
- * @brief Returns the value of the constant, containing a map.
- *
- * @return  the variant value
- */
-RplASVariant& RplASMapConstant::value()
-{
-    return m_value;
-}
-
-/**
- * @brief Returns the (low level) map of the constant.
- *
- * @return  the map of the constant
- */
-RplASMapOfVariants* RplASMapConstant::map()
-{
-    RplASMapOfVariants* rc = static_cast<RplASMapOfVariants*>(
-                m_value.asObject(NULL));
-    return rc;
-}
-
-/** @class RplASNamedValue rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a named values, a constant or a variable
- */
-
-/**
- * @brief Constructor.
- *
- * @param clazz         the data type (class)
- * @param space         the current symbol space
- * @param name          the name of the variable
- * @param attributes    the attributes of the variable
- */
-RplASNamedValue::RplASNamedValue(RplASClass* clazz,RplSymbolSpace* space,
-                                 const QByteArray& name, int attributes) :
-    RplASItem(AST_NAMED_VALUE),
-    m_name(name),
-    m_attributes(attributes),
-    m_symbolSpace(space),
-    m_variableNo(-1)
-{
-    m_class = clazz;
-}
-
-/**
- * @brief Returns the name.
- *
- * @return the name
- */
-const QByteArray& RplASNamedValue::name() const
-{
-    return m_name;
-}
-
-/**
- * @brief Sets the symbol space.
- * @param space
- * @param variableNo
- */
-void RplASNamedValue::setSymbolSpace(RplSymbolSpace* space, int variableNo)
-{
-    m_symbolSpace = space;
-    m_variableNo = variableNo;
-}
-/**
- * @brief Copies the value of the variable to the top of value stack.
- *
- * @param thread    IN/OUT: the execution unit, a VM thread
- */
-void RplASNamedValue::calc(RplVMThread& thread)
-{
-    thread.valueToTop(m_symbolSpace, m_variableNo);
-    if (thread.tracing())
-        thread.vm()->traceWriter()->format("nVal %s=%.80s",
-                    m_name.constData(),
-                    thread.topOfValues().toString().constData());
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASNamedValue::check(RplParser& parser)
-{
-    return true;
-}
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASNamedValue::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "namedValue %s id: %d attr: 0x%x %s",
-            m_name.constData(), m_id, m_attributes,
-            positionStr(buffer, sizeof buffer));
-}
-
-/**
- * @brief Returns the symbol space of the variable.
- *
- * @return  the symbol space
- */
-RplSymbolSpace*RplASNamedValue::symbolSpace() const
-{
-    return m_symbolSpace;
-}
-
-/**
- * @brief Sets the variable no in the instance.
- *
- * @param variableNo    the variable number
- */
-void RplASNamedValue::setVariableNo(int variableNo)
-{
-    m_variableNo = variableNo;
-}
-
-
-/**
- * @brief Returns the variable no of the variable.
- *
- * @return  the current number of the variable in the symbol space
- */
-int RplASNamedValue::variableNo() const
-{
-    return m_variableNo;
-}
-
-/** @class RplASConversion rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a data type conversion.
- *
- * <code>m_child</code>: the expression which will be converted
- */
-/**
- * @brief Constructor.
- * @param expression    the expression to convert
- */
-RplASConversion::RplASConversion(RplASItem* expression) :
-    RplASNode1(AST_CONVERSION),
-    m_conversion(C_UNDEF)
-{
-    m_child = expression;
-    m_position = expression->position();
-}
-
-/**
- * @brief Convert an expression to another data type.
- *
- * Possible conversions: @see <code>RplASConversion::Conversion</code>
- *
- * @param thread    execution value
- */
-void RplASConversion::calc(RplVMThread& thread)
-{
-    RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child);
-    expr->calc(thread);
-    RplASVariant& value = thread.topOfValues();
-
-    switch(m_conversion){
-    case C_INT_TO_FLOAT:
-        value.setFloat((qreal) value.asInt());
-        break;
-    case C_FLOAT_TO_INT:
-        value.setInt((int) value.asFloat());
-        break;
-    case C_BOOL_TO_INT:
-        value.setInt((int) value.asBool());
-        break;
-    case C_BOOL_TO_FLOAT:
-        value.setFloat((qreal) value.asBool());
-        break;
-    default:
-        break;
-    }
-    if (thread.tracing())
-        thread.vm()->traceWriter()->format("(%s): %s",
-                    m_class->name().constData(),
-                    value.toString().constData());
-}
-
-/**
- * @brief Returns the conversion type of two classes.
- *
- * @param from  class to convert
- * @param to    result class of the conversion
- *
- * @return      <code>C_UNDEF</code>: not convertable<br>
- *              otherwise: the conversion type
- */
-RplASConversion::Conversion RplASConversion::findConversion(RplASClass* from,
-             RplASClass* to)
-{
-    Conversion rc = C_UNDEF;
-    if (from == RplASFloat::m_instance){
-        if (to == RplASInteger::m_instance)
-            rc = C_FLOAT_TO_INT;
-    } else if (from == RplASInteger::m_instance){
-        if (to == RplASFloat::m_instance)
-            rc = C_INT_TO_FLOAT;
-    } else if (from == RplASBoolean::m_instance){
-        if (to == RplASInteger::m_instance)
-            rc = C_BOOL_TO_INT;
-        else if (to == RplASInteger::m_instance)
-            rc = C_BOOL_TO_INT;
-        else if (to == RplASFloat::m_instance)
-            rc = C_BOOL_TO_FLOAT;
-    }
-    return rc;
-}
-
-/**
- * @brief Checks the node.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASConversion::check(RplParser& parser)
-{
-    bool rc = m_child != NULL && m_child->check(parser);
-    RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child);
-    if (! rc || expr == NULL)
-        ensureError(parser, "RplASConversion::check");
-    else {
-        RplASClass* from = expr->clazz();
-        m_conversion = findConversion(from, m_class);
-        if (m_conversion != C_UNDEF)
-            rc = true;
-        else
-            parser.error(LOC_CONV_CHECK_1,
-                         "invalid data type conversion: %s -> %s",
-                         from->name().constData(),
-                         m_class->name().constData());
-    }
-    return rc;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASConversion::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "conversion %s id: %d expr: %d %s",
-                          m_class->name().constData(), m_id, m_child->id(),
-            positionStr(buffer, sizeof buffer));
-}
-
-/**
- * @brief Tries to find a conversion to a given type.
- *
- * Checks if an expression has a given type. If not it will be tried to find
- * a conversion. If this is not possible an error occurres. Otherwise the
- * converter will be returned.
- *
- * @param expected  the expected data type
- * @param expr      the expression to convert
- * @param parser    for error processing
- * @param isCorrect OUT: false: error has been detected<br>
- *                  No change if no error
- *
- * @return          NULL: no conversion necessary<br>
- *                  otherwise: a converter to the given type
- */
-RplASConversion* RplASConversion::tryConversion(RplASClass* expected,
-    RplASItem* expr, RplParser& parser, bool& isCorrect)
-{
-    RplASConversion* rc = NULL;
-    if (! expr->check(parser))
-        isCorrect = false;
-    else {
-        RplASCalculable* expr2 = dynamic_cast<RplASCalculable*>(expr);
-        if (expr2 != NULL){
-            Conversion type = findConversion(expr2->clazz(), expected);
-            if (type == C_UNDEF){
-                isCorrect = parser.error(LOC_CONV_TRY_1,
-                             "invalid data type conversion: %s -> %s",
-                             expr2->clazz()->name().constData(),
-                             expected->name().constData());
-            } else if (expr2->clazz() != expected){
-                rc = new RplASConversion(expr);
-                rc->m_conversion = type;
-                rc->setClass(expected);
-            }
-        }
-    }
-    return rc;
-}
-
-/** @class RplASIndexedValue rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an indexed values (member of a list)
- *
- * <code>m_child</code>: the parent: a list/map expression
- * <code>m_child2</code>: the index expression
- */
-RplASIndexedValue::RplASIndexedValue() :
-    RplASNode2(AST_INDEXED_VALUE)
-{
-}
-
-/**
- * @brief Calculates an indexed expression.
- *
- * Possible: list index or map index
- *
- * @param thread    execution value
- */
-void RplASIndexedValue::calc(RplVMThread& thread)
-{
-    RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child2);
-    expr->calc(thread);
-    RplASVariant& ixValue = thread.popValue();
-    int ix = ixValue.asInt();
-    RplASCalculable* list = dynamic_cast<RplASCalculable*>(m_child);
-    list->calc(thread);
-    RplASVariant& listValue = thread.popValue();
-    //@ToDo: access to the lists element: assignment or to stack
-    if (thread.tracing())
-        thread.vm()->traceWriter()->format("[%d]: %.80s",
-                    ix, thread.topOfValues().toString().constData());
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASIndexedValue::check(RplParser& parser)
-{
-    RplASCalculable* list = dynamic_cast<RplASCalculable*>(m_child);
-    bool rc = m_child != NULL && m_child->check(parser);
-    if (! rc || list == NULL)
-        ensureError(parser, "RplASIndexedValue::check");
-    else {
-        // index value:
-        // tryConversion() calls m_child2->check()!
-        RplASConversion* converter = RplASConversion::tryConversion(
-                    RplASInteger::m_instance, m_child2, parser, rc);
-        if (rc && converter != NULL)
-            m_child = converter;
-        if (rc){
-            //@ToDo: dynamic subclass of list / map
-            m_class = RplASString::m_instance;
-            rc = m_class != NULL && m_class == RplASInteger::m_instance;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Writes the internals into an output media.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASIndexedValue::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "indexedValue id: %d index: %d parent: %d %s",
-            m_id, m_child2->id(), m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    m_child2->dump(writer, indent + 1);
-    m_child->dump(writer, indent + 1);
-}
-
-/** @class RplVarDefinition rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements variable definition for the Abstract Syntax Tree.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: named value (name + default value expression)
- * <code>m_child3</code>: initial value or NULL
- */
-
-/**
- * @brief Constructor.
- */
-RplASVarDefinition::RplASVarDefinition() :
-    RplASNode3(AST_VAR_DEFINITION),
-    RplASStatement(),
-    m_endOfScope(0)
-{
-    m_flags |= NF_STATEMENT;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASVarDefinition::dump(RplWriter& writer, int indent)
-{
-    RplASNamedValue* namedValue = dynamic_cast<RplASNamedValue*>(m_child2);
-    QByteArray name = namedValue->name();
-    char endOfScope[32];
-    endOfScope[0] = '\0';
-    if (m_endOfScope > 0)
-        qsnprintf(endOfScope, sizeof endOfScope, "-%d:0", m_endOfScope);
-    char buffer[256];
-    writer.formatIndented(indent,
-            "varDef %s %s id: %d namedValue: %d value: %d succ: %d %s%s",
-            clazz() == NULL ? "?" : clazz()->name().constData(),
-            name.constData(), m_id,
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child3 == NULL ? 0 : m_child3->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer), endOfScope);
-    if (m_child2 != NULL)
-        m_child2->dump(writer, indent + 1);
-    if (m_child3 != NULL)
-        m_child3->dump(writer, indent + 1);
-}
-
-/**
- * @brief Returns the name of the variable.
- *
- * @return  the name
- */
-const QByteArray& RplASVarDefinition::name() const
-{
-    RplASNamedValue* namedValue = dynamic_cast<RplASNamedValue*>(m_child2);
-    const QByteArray& rc = namedValue->name();
-    return rc;
-}
-
-/**
- * @brief Returns the data type (class) of the variable.
- *
- * @return  the data type
- */
-RplASClass* RplASVarDefinition::clazz() const
-{
-    RplASNamedValue* namedValue = dynamic_cast<RplASNamedValue*>(m_child2);
-    RplASClass* rc = namedValue == NULL ? NULL : namedValue->clazz();
-    return rc;
-}
-/**
- * @brief Returns the column of the scope end.
- *
- * 0 means end of method or end of class
- *
- * @return 0 or the column of the scope end
- */
-int RplASVarDefinition::endOfScope() const
-{
-    return m_endOfScope;
-}
-
-/**
- * @brief Sets the column of the scope end.
- *
- * @param endOfScope    the column of the scope end
- */
-void RplASVarDefinition::setEndOfScope(int endOfScope)
-{
-    m_endOfScope = endOfScope;
-}
-
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASVarDefinition::check(RplParser& parser)
-{
-    RplASNamedValue* var = dynamic_cast<RplASNamedValue*>(m_child2);
-
-    bool rc = var != NULL && (m_child3 == NULL || m_child3->check(parser));
-    if (! rc)
-        ensureError(parser, "RplASVarDefinition::check");
-    else {
-        if (m_child3 != NULL){
-            // with initialization:
-            RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child3);
-            if (expr == NULL)
-                rc = error(LOC_VARDEF_CHECK_1, parser,
-                           "Not a calculable expression: %s",
-                           m_child3->nameOfItemType());
-            else if (! typeCheck(var->clazz(), expr->clazz()))
-                rc = error(LOC_VARDEF_CHECK_2, parser,
-                             "data types are not compatible: %s/%s",
-                             var->clazz()->name().constData(),
-                             expr->clazz() == NULL ? "?"
-                                : expr->clazz()->name().constData());
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Executes the statement.
- *
- * @return  0: continue the current statement list<br>
- */
-int RplASVarDefinition::execute(RplVMThread& thread)
-{
-    if (m_child3 != NULL){
-        // has an initialization:
-        RplASNamedValue* var = dynamic_cast<RplASNamedValue*>(m_child2);
-        RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child3);
-        expr->calc(thread);
-        RplASVariant& value = thread.popValue();
-        RplASVariant& destination = thread.valueOfVariable(
-                    var->m_symbolSpace, var->m_variableNo);
-        if (thread.tracing())
-            thread.vm()->traceWriter()->format("%s = %.80s [%.80s]",
-                        var->m_name.constData(),
-                        value.toString().constData(),
-                        destination.toString().constData());
-        destination.copyValue(value);
-    }
-    return 0;
-}
-
-/** @class RplASExprStatement rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an statement consisting of an expression.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: expression
- */
-
-/**
- * @brief Constructor.
- */
-RplASExprStatement::RplASExprStatement() :
-    RplASNode2(AST_EXPR_STATEMENT),
-    RplASStatement()
-{
-    m_flags |= NF_STATEMENT;
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASExprStatement::check(RplParser& parser)
-{
-    bool rc = m_child2->check(parser);
-    if (rc){
-        RplASCalculable* expr = dynamic_cast<RplASCalculable*> (m_child2);
-        if (expr == NULL)
-            rc = ensureError(parser, "RplASExprStatement::check");
-    }
-    return rc;
-}
-/**
- * @brief Executes the statement.
- *
- * @return  0: continue the current statement list<br>
- */
-int RplASExprStatement::execute(RplVMThread& thread)
-{
-    RplASCalculable* expr = dynamic_cast<RplASCalculable*> (m_child2);
-    expr->calc(thread);
-    RplASVariant& value = thread.popValue();
-    if (thread.tracing())
-        thread.vm()->traceWriter()->format("expr: %s",
-                    value.toString().constData());
-    value.destroyValue();
-    return 0;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-
-void RplASExprStatement::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    if (m_id == 40)
-        m_id = 40;
-    writer.formatIndented(indent, "Expr id: %d expr: %d succ: %d %s", m_id,
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    if (m_child2 != NULL)
-        m_child2->dump(writer, indent + 1);
-}
-
-/** @class RplASNode1 rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an inner node of the abstract syntax tree with one child.
- *
- * This class is an abstract class.
- */
-
-/**
- * @brief RplASNode1::RplASNode1
- * @param type
- */
-RplASNode1::RplASNode1(RplASItemType type) :
-    RplASItem(type),
-    m_child(NULL)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplASNode1::~RplASNode1()
-{
-    delete m_child;
-    m_child = NULL;
-}
-/**
- * @brief Returns the child.
- *
- * @return  the child of the instance
- */
-RplASItem* RplASNode1::child() const
-{
-    return m_child;
-}
-/**
- * @brief Sets the child.
- */
-void RplASNode1::setChild(RplASItem* child)
-{
-    m_child = child;
-}
-
-/**
- * @brief Writes the internals of a statement list into a file.
- *
- * @param writer        writes to output media
- * @param indent        the indent level of the statement list
- * @param statements    the chain of statements to dump
- */
-void RplASNode1::dumpStatements(RplWriter& writer, int indent,
-                                RplASItem* statements)
-{
-    RplASNode1* chain = dynamic_cast<RplASNode1*>(statements);
-    while (chain != NULL){
-        chain->dump(writer, indent);
-        chain = dynamic_cast<RplASNode1*>(chain->m_child);
-    }
-}
-
-
-/** @class RplASNode2 rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an inner node of the abstract syntax tree with two childs.
- *
- * This class is an abstract class.
- */
-
-/**
- * @brief RplASNode2::RplASNode2
- * @param type
- */
-RplASNode2::RplASNode2(RplASItemType type) :
-    RplASNode1(type),
-    m_child2(NULL)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplASNode2::~RplASNode2()
-{
-    delete m_child2;
-    m_child2 = NULL;
-}
-RplASItem* RplASNode2::child2() const
-{
-    return m_child2;
-}
-
-void RplASNode2::setChild2(RplASItem* child2)
-{
-    m_child2 = child2;
-}
-
-
-/** @class RplASNode3 rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an inner node of the abstract syntax tree with 3 childs.
- *
- * This class is an abstract class.
- */
-
-/**
- * @brief RplASNode3::RplASNode3
- * @param type
- */
-RplASNode3::RplASNode3(RplASItemType type) :
-    RplASNode2(type),
-    m_child3(NULL)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplASNode3::~RplASNode3()
-{
-    delete m_child3;
-    m_child3 = NULL;
-}
-/**
- * @brief Returns the child3.
- *
- * @return  the child 3
- */
-RplASItem* RplASNode3::child3() const
-{
-    return m_child3;
-}
-
-/**
- * @brief Sets the child3.
- *
- * @param child3    the new child3
- */
-void RplASNode3::setChild3(RplASItem* child3)
-{
-    m_child3 = child3;
-}
-
-
-/** @class RplASNode4 rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an inner node of the abstract syntax tree with 3 childs.
- *
- * This class is an abstract class.
- */
-
-/**
- * @brief RplASNode4::RplASNode4
- * @param type
- */
-RplASNode4::RplASNode4(RplASItemType type) :
-    RplASNode3(type),
-    m_child4(NULL)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplASNode4::~RplASNode4()
-{
-    delete m_child4;
-    m_child4 = NULL;
-}
-
-/**
- * @brief Returns the child4.
- *
- * @return  the child 4
- */
-RplASItem* RplASNode4::child4() const
-{
-    return m_child4;
-}
-
-/**
- * @brief Sets the child4.
- *
- * @param child4    the new child3
- */
-void RplASNode4::setChild4(RplASItem* child4)
-{
-    m_child4 = child4;
-}
-
-
-/** @class RplASNode5 rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an inner node of the abstract syntax tree with 4 childs.
- *
- * This class is an abstract class.
- */
-
-/**
- * @brief RplASNode5::RplASNode5
- * @param type
- */
-RplASNode5::RplASNode5(RplASItemType type) :
-    RplASNode4(type),
-    m_child5(NULL)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplASNode5::~RplASNode5()
-{
-    delete m_child5;
-    m_child5 = NULL;
-}
-
-/**
- * @brief Returns the child5.
- *
- * @return  the child 5
- */
-RplASItem* RplASNode5::child5() const
-{
-    return m_child5;
-}
-
-/**
- * @brief Sets the child5.
- *
- * @param child5    the new child3
- */
-void RplASNode5::setChild5(RplASItem* child5)
-{
-    m_child5 = child5;
-}
-
-/** @class RplASNode6 rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an inner node of the abstract syntax tree with 4 childs.
- *
- * This class is an abstract class.
- */
-
-/**
- * @brief RplASNode6::RplASNode6
- * @param type
- */
-RplASNode6::RplASNode6(RplASItemType type) :
-    RplASNode5(type),
-    m_child6(NULL)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplASNode6::~RplASNode6()
-{
-    delete m_child6;
-    m_child6 = NULL;
-}
-
-/**
- * @brief Returns the child5.
- *
- * @return  the child 5
- */
-RplASItem* RplASNode6::child6() const
-{
-    return m_child6;
-}
-
-/**
- * @brief Sets the child6.
- *
- * @param child6    the new child6
- */
-void RplASNode6::setChild6(RplASItem* child6)
-{
-    m_child6 = child6;
-}
-
-/** @class RplASUnaryOp rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an unary operation.
- *
- * This is an operation with one operand, e.g. the boolean 'not' operation.
- *
- * <code>m_child</code>: operand
- */
-
-/**
- * @brief Constructor.
- *
- * @param op    the operator id
- * @param type  the node type
- */
-RplASUnaryOp::RplASUnaryOp(UnaryOp op, RplASItemType type) :
-    RplASNode1(type),
-    m_operator(op)
-{
-}
-
-/**
- * @brief Calculates the value of the unary operator.
- *
- * @param thread    IN/OUT: the execution unit, a VM thread
- */
-void RplASUnaryOp::calc(RplVMThread& thread)
-{
-    RplASVariant& value = thread.topOfValues();
-    switch(m_operator){
-    case UOP_PLUS:
-        break;
-    case UOP_MINUS_INT:
-        value.setInt(- value.asInt());
-        break;
-    case UOP_MINUS_FLOAT:
-        value.setFloat(- value.asFloat());
-        break;
-    case UOP_NOT_BOOL:
-        value.setBool(! value.asBool());
-        break;
-    case UOP_NOT_INT:
-        value.setInt(~value.asInt());
-        break;
-    case UOP_DEC:
-    case UOP_INC:
-    default:
-        error(thread.logger(), LOC_UNOP_CALC_1, "unknown operator: %d", m_operator);
-        break;
-    }
-    if (thread.tracing())
-        thread.vm()->traceWriter()->format("unary %s: %s",
-                    nameOfOp(m_operator),
-                    value.toString().constData());
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASUnaryOp::check(RplParser& parser)
-{
-    bool rc = m_child->check(parser);
-    if (rc){
-        RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child);
-        RplASClass* clazz = expr == NULL ? NULL : expr->clazz();
-        if (clazz == NULL){
-            rc = ensureError(parser, "RplASUnaryOp::check");
-        } else {
-            switch(m_operator){
-            case UOP_PLUS:
-                if (clazz != RplASInteger::m_instance
-                        && clazz != RplASFloat::m_instance)
-                    rc = error(LOC_UNARY_CHECK_1, parser,
-                                 "wrong data type for unary operator '+': %s",
-                                 clazz->name().constData());
-                break;
-            case UOP_MINUS_INT:
-                if (clazz != RplASFloat::m_instance)
-                    m_operator = UOP_MINUS_FLOAT;
-                else if (clazz != RplASInteger::m_instance)
-                    rc = error(LOC_UNARY_CHECK_2, parser,
-                                 "wrong data type for unary operator '-': %s",
-                                 clazz->name().constData());
-                break;
-            case UOP_NOT_BOOL:
-                if (clazz != RplASBoolean::m_instance)
-                    rc = error(LOC_UNARY_CHECK_3, parser,
-                                 "wrong data type for unary operator '!': %s",
-                                 clazz->name().constData());
-                break;
-            case UOP_NOT_INT:
-                if (clazz != RplASInteger::m_instance)
-                    rc = error(LOC_UNARY_CHECK_4, parser,
-                                 "wrong data type for unary operator '!': %s",
-                                 clazz->name().constData());
-                break;
-            case UOP_DEC:
-                break;
-            case UOP_INC:
-                break;
-            default:
-                throw RplASException(position(), "unknown operator: %d", m_operator);
-                break;
-            }
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Returns the operator of the unary operation.
- *
- * @return the operator
- */
-int RplASUnaryOp::getOperator() const
-{
-    return m_operator;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASUnaryOp::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "Unary %d op: %s (%d) expr: %d %s",
-            m_id,
-            nameOfOp(m_operator),
-            m_operator,
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer) );
-    if (m_child != NULL)
-        m_child->dump(writer, indent + 1);
-}
-/**
- * @brief Returns the name (a string) of an unary operator.
- *
- * @param op    the operand to convert
- * @return      the name of the operator
- */
-const char*RplASUnaryOp::nameOfOp(RplASUnaryOp::UnaryOp op)
-{
-    const char* rc;
-    switch (op){
-    case UOP_PLUS:
-        rc="+";
-        break;
-    case UOP_MINUS_INT:
-    case UOP_MINUS_FLOAT:
-        rc="-";
-        break;
-    case UOP_NOT_BOOL:
-        rc="!";
-        break;
-    case UOP_NOT_INT:
-        rc="~";
-        break;
-    case UOP_INC:
-        rc="++";
-        break;
-    case UOP_DEC:
-        rc="--";
-        break;
-    default:
-        throw RplException("unknown unary operator: %d", (int) op);
-        break;
-    }
-    return rc;
-}
-
-
-/** @class RplASStatement rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a base class for all statements.
- *
- * @note statements are always <code>RplASNode1</code> and m_child is used
- * for the successors (next statement).
- */
-
-/**
- * @brief Constructor.
- */
-RplASStatement::RplASStatement()
-{
-}
-/**
- * @brief Executes the statements of a statement list.
- *
- * @param list      statement list
- * @param thread    execution unit
- * @return  0: continue the current statement list<br>
- *          n > 0: stop the n most inner statement lists (initialized by leave)
- *          n < 0: stop the -n most inner statement lists (initialized by continue)
- */
-int RplASStatement::executeStatementList(RplASItem* list, RplVMThread& thread)
-{
-    int rc = 0;
-    while(rc == 0 && list != NULL){
-        RplASStatement* statement = dynamic_cast<RplASStatement*>(list);
-        rc =statement->execute(thread);
-    }
-    return rc;
-}
-
-
-/** @class RplASIf rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an if statement.
- *
- * The if statement has a condition, a then-part and an optional else-part.
- * If the condition is evaluated to true, the then-part will be executed.
- * Otherwise the else-part if it exists.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: condition<br>
- * <code>m_child3</code>: then part<br>
- * <code>m_child4</code>: else part or NULL<br>
- */
-
-RplASIf::RplASIf() :
-    RplASNode4(AST_IF)
-{
-    m_flags |= NF_STATEMENT;
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASIf::check(RplParser& parser)
-{
-    bool rc = true;
-    if (m_child2 == NULL)
-        rc = ensureError(parser, "'if' misses condition");
-    else if (m_child2->checkAsCalculable("condition", RplASBoolean::m_instance,
-                                         parser))
-        rc = false;
-    if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
-        rc = false;
-    if (m_child4 != NULL && ! checkStatementList(m_child4, parser))
-        rc = false;
-    return rc;
-}
-
-/**
- * @brief Executes the statement.
- *
- * @return  0: continue the current statement list<br>
- *          n > 0: stop the n most inner statement lists (initialized by leave)
- *          n < 0: stop the -n most inner statement lists (initialized by continue)
- */
-int RplASIf::execute(RplVMThread& thread)
-{
-    int rc = 0;
-    bool condition = calcAsBoolean(m_child2, thread);
-    if (thread.tracing())
-        thread.vm()->traceWriter()->format("if %s", condition ? "true" : "false");
-
-    RplASItem* list = condition ? m_child3 : m_child4;
-    if (list != NULL){
-        if ( (rc = executeStatementList(list, thread)) != 0){
-            if (rc < 0)
-                rc--;
-            else if (rc > 0)
-                rc++;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASIf::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent,
-           "If id: %d condition: %d then: %d else: %d succ: %d%s",
-            m_id,
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child3 == NULL ? 0 : m_child3->id(),
-            m_child4 == NULL ? 0 : m_child4->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    m_child2->dump(writer, indent + 1);
-    if (m_child3 != NULL)
-        m_child3->dump(writer, indent + 1);
-    if (m_child4 != NULL)
-        m_child4->dump(writer, indent + 1);
-}
-
-/** @class RplASFor rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a for statement.
- *
- * The for statement has an initialization, a condition, a forwarding
- * statement and a body.
- * The initialization will be called first.
- * Then the condition will be tested. If true the body will be executed
- * and then the forwarding statement.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: body<br>
- * <code>m_child3</code>: iterator variable<br>
- * <code>m_child4</code>: container variable<br>
- */
-
-/**
- * @brief Constructor.
- *
- * @param variable      NULL or the iterator variable
- */
-RplASForIterated::RplASForIterated(RplASVarDefinition* variable) :
-    RplASNode4(AST_ITERATED_FOR),
-    RplASStatement()
-{
-    m_flags |= NF_STATEMENT;
-    m_child2 = variable;
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASForIterated::check(RplParser& parser)
-{
-    return false;
-}
-
-/**
- * @brief Executes the statement.
- *
- * @return  0: continue the current statement list<br>
- *          n > 0: stop the n most inner statement lists (initialized by leave)
- *          n < 0: stop the -n most inner statement lists (initialized by continue)
- */
-int RplASForIterated::execute(RplVMThread& thread)
-{
-    return 0;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASForIterated::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "forIt id: %d var: %d set: %d body: %d succ: %d %s",
-            m_id,
-            m_child3 == NULL ? 0 : m_child3->id(),
-            m_child4 == NULL ? 0 : m_child4->id(),
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    if (m_child3 != NULL)
-        m_child3->dump(writer, indent + 1);
-    if (m_child4 != NULL)
-        m_child4->dump(writer, indent + 1);
-    dumpStatements(writer, indent + 1, m_child2);
-}
-
-/** @class RplASForCounted rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a for statement.
- *
- * The for statement has an optional variable, an optional start value,
- * an end value, an optional step and a body.
- *
- * The start and end value will be calculated.
- * The body will be executed so many times given by the start and end value.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: body<br>
- * <code>m_child3</code>: variable or NULL<br>
- * <code>m_child4</code>: start value or NULL<br>
- * <code>m_child5</code>: end value<br>
- * <code>m_child6</code>: step value or NULL
- *
- */
-
-/**
- * @brief Constructor.
- *
- * @param variable      NULL or the counter variable
- */
-RplASForCounted::RplASForCounted(RplASVarDefinition* variable) :
-    RplASNode6(AST_ITERATED_FOR),
-    RplASStatement()
-{
-    m_flags |= NF_STATEMENT;
-    m_child3 = variable;
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASForCounted::check(RplParser& parser)
-{
-    bool rc = true;
-    RplASNamedValue* var = NULL;
-    if (m_child3 != NULL){
-        var = dynamic_cast<RplASNamedValue*>(m_child3);
-        if (! m_child3->check(parser))
-            rc = false;
-        if (var == NULL)
-            rc = error(LOC_FORC_CHECK_1, parser, "not a variable: %s",
-                  m_child3->nameOfItemType());
-    }
-    RplASCalculable* expr;
-    if (m_child4 != NULL && ! m_child4->checkAsCalculable("start value",
-            RplASInteger::m_instance, parser))
-        rc = false;
-    if (m_child5 != NULL && ! m_child5->checkAsCalculable("end value",
-            RplASInteger::m_instance, parser))
-        rc = false;
-    if (m_child6 != NULL && ! m_child6->checkAsCalculable("step value",
-            RplASInteger::m_instance, parser))
-        rc = false;
-    if (m_child2 != NULL && ! checkStatementList(m_child2, parser))
-        rc = false;
-    return rc;
-}
-
-/**
- * @brief Executes the statement.
- *
- * @return  0: continue the current statement list<br>
- *          n > 0: stop the n most inner statement lists (initialized by leave)
- *          n < 0: stop the -n most inner statement lists (initialized by continue)
- */
-int RplASForCounted::execute(RplVMThread& thread)
-{
-    int rc = 0;
-    RplASStatement* body = dynamic_cast<RplASStatement*>(m_child2);
-    if (body == NULL)
-        throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
-                             "forc statement: body is not a statement");
-    int start = m_child4 == NULL ? 1 : calcAsInteger(m_child4, thread);
-    int end = m_child5 == NULL ? 0 : calcAsInteger(m_child5, thread);
-    int step = m_child6 == NULL ? 1 : calcAsInteger(m_child6, thread);
-    RplASNamedValue* var = m_child3 == NULL
-            ? NULL : dynamic_cast<RplASNamedValue*>(m_child3);
-    if (thread.tracing())
-        thread.vm()->traceWriter()->format("for %s from %d to %d step %d",
-            var == NULL ? "?" : var->name().constData(),
-            start, end, step);
-
-    for(int ii = start; ii <= end; ii += step){
-        //@ToDo: assign to the variable
-        int rc2 = body->execute(thread);
-        if (rc2 != 0){
-            if (rc2 > 0){
-                // rc comes from "break";
-                rc = rc2 - 1;
-            } else {
-                // rc comes from "continue";
-                if (rc2 == -1)
-                    continue;
-                else
-                    rc = rc2 + 1;
-            }
-            break;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASForCounted::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "forC id: %d var: %d from: %d to: %d step: %d body: %d succ: %d %s",
-            m_id,
-            m_child3 == NULL ? 0 : m_child3->id(),
-            m_child4 == NULL ? 0 : m_child4->id(),
-            m_child5 == NULL ? 0 : m_child5->id(),
-            m_child6 == NULL ? 0 : m_child6->id(),
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    if (m_child3 != NULL)
-        m_child3->dump(writer, indent + 1);
-    if (m_child4 != NULL)
-        m_child4->dump(writer, indent + 1);
-    if (m_child5 != NULL)
-        m_child5->dump(writer, indent + 1);
-    if (m_child6 != NULL)
-        m_child6->dump(writer, indent + 1);
-    dumpStatements(writer, indent + 1, m_child2);
-}
-
-/** @class RplASWhile rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a while statement.
- *
- * The while statement has an a condition and a body.
- * The body will be executed while the condition returns true.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: condition<br>
- * <code>m_child3</code>: body<br>
- */
-
-RplASWhile::RplASWhile() :
-    RplASNode3(AST_WHILE),
-    RplASStatement()
-{
-    m_flags |= NF_STATEMENT;
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASWhile::check(RplParser& parser)
-{
-    bool rc = true;
-    if (m_child2 == NULL)
-        ensureError(parser, "missing condition for 'while''");
-    else
-        rc = m_child2->checkAsCalculable("condition", RplASBoolean::m_instance,
-                                         parser);
-    if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
-        rc = false;
-    return rc;
-}
-
-/**
- * @brief Executes the statement.
- *
- * @return  0: continue the current statement list<br>
- *          n > 0: stop the n most inner statement lists (initialized by leave)
- *          n < 0: stop the -n most inner statement lists (initialized by continue)
- */
-int RplASWhile::execute(RplVMThread& thread)
-{
-    int rc = 0;
-    RplASStatement* body = dynamic_cast<RplASStatement*>(m_child3);
-    if (thread.tracing())
-        thread.vm()->traceWriter()->write("while");
-    while(calcAsBoolean(m_child2, thread)){
-        int rc2 = body->execute(thread);
-        if (rc2 != 0){
-            if (rc2 > 0){
-                // rc comes from "break";
-                rc = rc2 - 1;
-            } else {
-                // rc comes from "continue";
-                if (rc2 == -1)
-                    continue;
-                else
-                    rc = rc2 + 1;
-            }
-            break;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASWhile::dump(RplWriter& writer, int indent)
-{
-
-    char buffer[256];
-    writer.formatIndented(indent, "while id: %d condition: %d body: %d succ: %d %s",
-            m_id,
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child3 == NULL ? 0 : m_child3->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    if (m_child2 != NULL)
-        m_child2->dump(writer, indent + 1);
-    dumpStatements(writer, indent + 1, m_child3);
-}
-
-/** @class RplASRepeat rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a while statement.
- *
- * The while statement has an a condition and a body.
- * The body will be executed while the condition returns true.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: condition<br>
- * <code>m_child3</code>: body<br>
- */
-
-RplASRepeat::RplASRepeat() :
-    RplASNode3(AST_REPEAT),
-    RplASStatement()
-{
-    m_flags |= NF_STATEMENT;
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASRepeat::check(RplParser& parser)
-{
-    bool rc = true;
-    if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
-        rc = false;
-    if (m_child2 == NULL)
-        ensureError(parser, "missing condition for 'repeat''");
-    else if (! m_child2->checkAsCalculable("condition", RplASBoolean::m_instance,
-                                         parser))
-        rc = false;
-    return rc;
-}
-
-/**
- * @brief Executes the statement.
- *
- * Meaning of the childs:
- * m_child: body
- * m_child2: condition
- */
-int RplASRepeat::execute(RplVMThread& thread)
-{
-    int rc = 0;
-    RplASStatement* body = dynamic_cast<RplASStatement*>(m_child3);
-    if (thread.tracing())
-        thread.vm()->traceWriter()->write("repeat");
-    do {
-        int rc2 = body->execute(thread);
-        if (rc2 != 0){
-            if (rc2 > 0){
-                // rc comes from "break";
-                rc = rc2 - 1;
-            } else {
-                // rc comes from "continue";
-                if (rc2 == -1)
-                    continue;
-                else
-                    rc = rc2 + 1;
-            }
-            break;
-        }
-    } while(! calcAsBoolean(m_child2, thread));
-    return rc;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASRepeat::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "repeat id: %d condition: %d body: %d succ: %d %s",
-            m_id,
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child3 == NULL ? 0 : m_child3->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    if (m_child2 != NULL)
-        m_child2->dump(writer, indent + 1);
-    dumpStatements(writer, indent + 1, m_child3);
-}
-
-/** @class RplASClass rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements the base class of an Abstract Syntax Tree class.
- *
- * This class is abstract.
- */
-/**
- * @brief Constructor.
- */
-RplASClass::RplASClass(const QByteArray& name, RplASTree& tree) :
-    m_name(name),
-    m_symbols(NULL),
-    m_superClass(NULL),
-    m_tree(tree)
-{
-}
-
-/**
- * @brief Destructor.
- *
- * Does nothing but forces a virtual destructor of all derived classes.
- *
- */
-RplASClass::~RplASClass()
-{
-
-}
-
-/**
- * @brief Return the class name.
- *
- * @return the class name
- */
-const QByteArray& RplASClass::name() const
-{
-    return m_name;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASClass::dump(RplWriter& writer, int indent)
-{
-    writer.formatIndented(indent, "class %s super: %s", m_name.constData(),
-            m_superClass == NULL
-                ? "<none>" : m_superClass->name().constData());
-    m_symbols->dump(writer, indent);
-}
-
-/**
- * @brief Sets the symbol space from the current in the tree.
- */
-void RplASClass::setSymbols()
-{
-    m_symbols = m_tree.currentSpace();
-}
-
-/** @class RplASTree rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a manager for all parts of an Abstract Syntax Tree.
- *
- * It contains the global symbol space and maintainance a list of used modules.
- */
-
-/**
- * @brief Constructor.
- */
-RplASTree::RplASTree() :
-    m_global(NULL),
-    m_modules(),
-    m_symbolSpaces(),
-    m_currentSpace(NULL),
-    m_store(128*1024)
-{
-    init();
-}
-
-/**
- * @brief Destructor.
- */
-RplASTree::~RplASTree()
-{
-    destroy();
-}
-
-/**
- * @brief Initializes the instance.
- *
- * Used in the constructor and in clear.
- */
-void RplASTree::init()
-{
-    m_global = RplSymbolSpace::createGlobal(*this);
-    m_symbolSpaces.append(m_global);
-    m_currentSpace = m_global;
-}
-
-/**
- * @brief Frees the resources of the instance.
- */
-void RplASTree::destroy()
-{
-    SymbolSpaceMap::iterator it;
-    for (it = m_symbolSpaceHeap.begin(); it != m_symbolSpaceHeap.end(); it++){
-        delete it.value();
-    }
-    m_symbolSpaceHeap.clear();
-}
-/**
- * @brief Returns the string storage of the instance.
- *
- * @return  the efficient allocator for C strings
- */
-RplByteStorage& RplASTree::store()
-{
-    return m_store;
-}
-
-/**
- * @brief Handles the start of a new module.
- *
- * @param name  the module's name
- * @return      true: the module is new<br>
- *              false: the module is yet known
- */
-bool RplASTree::startModule(RplSourceUnitName name)
-{
-    bool rc = m_modules.contains(name);
-    if (! rc){
-        // freed in ~RplASTree()
-        RplSymbolSpace* space = new RplSymbolSpace(RplSymbolSpace::SST_MODULE,
-            name, m_global);
-        m_symbolSpaceHeap[name] = space;
-        m_modules[name] = space;
-        m_symbolSpaces.append(space);
-        m_currentSpace = space;
-    }
-    return rc;
-}
-/**
- * @brief Search for the symbol space of a given module.
- *
- * @param name  the module's name
- * @return      NULL: not found<br>
- *              otherwise: the symbol space of the module
- */
-RplSymbolSpace* RplASTree::findmodule(const QByteArray& name)
-{
-    RplSymbolSpace* rc = m_modules.contains(name) ? m_modules[name] : NULL;
-    return rc;
-}
-
-/**
- * @brief Handles the end of a module.
- * @param name  the module's name
- */
-void RplASTree::finishModule(RplSourceUnitName name)
-{
-    RplSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
-    if (top->name() != name)
-        throw RplException("RplASTree::finishModule(): module is not top: %s",
-                           name);
-    else {
-        m_symbolSpaces.removeLast();
-        // "global" is always the bottom:
-        m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
-    }
-}
-
-/**
- * @brief Handles the start of a new class definition.
- * @param name      name of the class/method
- * @param type      the symbol space type
- * @return          the new symbol space
- */
-RplSymbolSpace* RplASTree::startClassOrMethod(const QByteArray& name,
-        RplSymbolSpace::SymbolSpaceType type)
-{
-    // the stack m_modules is never empty because of "global" and modules.
-    RplSymbolSpace* parent = m_symbolSpaces[m_symbolSpaces.size() - 1];
-    QByteArray fullName = parent->name() + "." + name;
-    // freed in ~RplASTree()
-    RplSymbolSpace* space = new RplSymbolSpace(type, fullName, parent);
-    m_symbolSpaceHeap[fullName] = space;
-    m_symbolSpaces.append(space);
-    m_currentSpace = space;
-    return space;
-}
-
-/**
- * @brief Handles the end of a class definition.
- *
- * @param name  the name of the class (short form)
- */
-void RplASTree::finishClassOrMethod(const QByteArray& name)
-{
-    RplSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
-    if (! top->name().endsWith("." + name))
-        throw RplException("RplASTree::finishModule(): class is not top: %s",
-                           name.constData());
-    else {
-        m_symbolSpaces.removeLast();
-        // "global" is the bottom always!
-        m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
-    }
-}
-
-/**
- * @brief Returns the stack of the symbol spaces.
- *
- * @return the stack with the active symbol spaces
- */
-RplASTree::SymbolSpaceStack& RplASTree::symbolSpaces()
-{
-    return m_symbolSpaces;
-}
-/**
- * @brief Returns the current symbol space (top of the stack).
- *
- * @return the current symbol space
- */
-RplSymbolSpace* RplASTree::currentSpace() const
-{
-    return m_currentSpace;
-}
-
-/**
- * @brief Removes all content from the abstract syntax tree.
- */
-void RplASTree::clear()
-{
-    destroy();
-    //m_global->clear();
-    m_modules.clear();
-    m_symbolSpaces.clear();
-    init();
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param filename      filename
- * @param flags         what to dump: sum of DMP_... flags
- * @param header        NULL or a text put on the top
- */
-void RplASTree::dump(const char* filename, int flags, const char* header)
-{
-    RplFileWriter writer(filename);
-    if (header != NULL)
-        writer.writeLine(header);
-    if (flags & DMP_GLOBALS){
-        m_global->dump(writer, 0, "=== Globals:");
-    }
-    if (flags & DMP_MODULES){
-        QList<QByteArray> sorted;
-        sorted.reserve(m_modules.size());
-        SymbolSpaceMap::iterator it;
-        for (it = m_modules.begin(); it != m_modules.end(); it++){
-           sorted.append(it.key());
-        }
-        qSort(sorted.begin(), sorted.end(), qLess<QByteArray>());
-        QList<QByteArray>::iterator it2;
-        for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
-            RplSymbolSpace* space = m_modules[*it2];
-            space->dump(writer, 0);
-        }
-    }
-    writer.close();
-}
-
-/** @class RplASMethodCall rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a method or function call for the Abstract Syntax Tree.
- *
- * <code>m_child</code>: next statement<br>
- * <code>m_child2</code>: argument list<br>
- * <code>m_child3</code>: parent (variable, field ...)
- */
-/**
- * @brief Constructor.
- *
- * @param name      name of the method/function
- * @param parent    NULL: it is a function<br>
- *                  otherwise: the parent (variable, field ...)
- */
-
-RplASMethodCall::RplASMethodCall(const QByteArray& name, RplASItem* parent) :
-    RplASNode3(AST_METHOD_CALL),
-    RplASStatement(),
-    m_name(name),
-    m_method(NULL)
-{
-    m_flags |= NF_STATEMENT;
-    m_child3 = parent;
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASMethodCall::check(RplParser& parser)
-{
-    bool rc = true;
-    RplASExprStatement* args = dynamic_cast<RplASExprStatement*>(m_child2);
-    int argCount = 0;
-    RplASMethod* method = m_method;
-    RplASVarDefinition* params = dynamic_cast<RplASVarDefinition*>(method->child2());
-    while (args != NULL && params != NULL){
-        argCount++;
-        RplASCalculable* argExpr = dynamic_cast<RplASCalculable*>
-                (args->child2());
-        if (argExpr == NULL)
-            rc = error(LOC_METHOD_CALL_CHECK_1, parser,
-                       "argument %d misses expr", argCount);
-        else {
-            RplASNamedValue* var;
-            RplASItem* param = params->child2();
-            if (param == NULL
-                    || (var = dynamic_cast<RplASNamedValue*>(param)) == NULL)
-                rc = error(LOC_MEHTOD_CALL_CHECK_2, parser,
-                    "parameter %d misses named value: %s", argCount,
-                    param == NULL ? "<null>" : param->nameOfItemType());
-            else {
-                // tryConversion() calls args->args->child2()->check()!
-                RplASConversion* converter = RplASConversion::tryConversion(
-                            var->clazz(), args->child2(), parser, rc);
-                if (rc && converter != NULL)
-                    args->setChild2(converter);
-
-            }
-        }
-        args = dynamic_cast<RplASExprStatement*>(args->child());
-        params = dynamic_cast<RplASVarDefinition*>(params->child());
-    }
-    if (args != NULL && params == NULL)
-        rc = error(LOC_MEHTOD_CALL_CHECK_3, parser,
-            "too many arguments: %d are enough", argCount);
-    else if (args == NULL && params != NULL && params->child3() != NULL)
-        rc = error(LOC_MEHTOD_CALL_CHECK_4, parser,
-            "too few arguments: %d are not enough", argCount);
-    return rc;
-}
-
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASMethodCall::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "call %s Id: %d args: %d parent: %d succ: %d %s",
-            m_name.constData(), m_id,
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child3 == NULL ? 0 : m_child3->id(),
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    if (m_child2 != NULL)
-        m_child2->dump(writer, indent + 1);
-    if (m_child3 != NULL)
-        m_child3->dump(writer, indent + 1);
-}
-
-/**
- * @brief Executes the method call.
- *
- * @return  0: continue the current statement list
- */
-int RplASMethodCall::execute(RplVMThread& thread)
-{
-    int rc = 0;
-
-    return rc;
-}
-
-RplASMethod* RplASMethodCall::method() const
-{
-    return m_method;
-}
-
-/**
- * @brief Sets the method.
- * @param method    method to set
- */
-void RplASMethodCall::setMethod(RplASMethod* method)
-{
-    m_method = method;
-}
-
-/**
- * @brief Returns the argument list.
- *
- * @return  the first element of an argument list
- */
-RplASExprStatement* RplASMethodCall::arg1() const
-{
-    return dynamic_cast<RplASExprStatement*>(m_child2);
-}
-
-/** @class RplASException rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a call of a method or function.
- *
- * <code>m_child</code>: body
- * <code>m_child2</code>: argument list (or NULL)
- */
-
-/** @class RplASBinaryOp rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements binary operator for the Abstract Syntax Tree.
- *
- * <code>m_child</code>: left operand<br>
- * <code>m_child2</code>: right operand
- */
-/**
- * @brief Constructor.
- */
-RplASBinaryOp::RplASBinaryOp() :
-    RplASNode2(AST_BINARY_OP),
-    m_operator(BOP_UNDEF)
-{
-}
-
-/**
- * @brief Calculates the binary operation.
- *
- * @param thread    IN/OUT: the bool value of the condition
- */
-void RplASBinaryOp::calc(RplVMThread& thread)
-{
-    if (isAssignment())
-        assign(thread);
-    else{
-        RplASCalculable* op1 = dynamic_cast<RplASCalculable*>(m_child);
-        RplASCalculable* op2 = dynamic_cast<RplASCalculable*>(m_child2);
-        if (op1 == NULL || op2 == NULL)
-            error(thread.logger(), LOC_BINOP_CALC_1, "operand is null: %d / %d",
-                  m_child == NULL ? 0 : m_child->id(),
-                  m_child2 == NULL ? 0 : m_child2->id());
-        else{
-            op1->calc(thread);
-            op2->calc(thread);
-            RplASVariant& val1 = thread.top2OfValues();
-            RplASVariant& val2 = thread.topOfValues();
-            switch(m_operator){
-            case BOP_PLUS:
-                switch(val1.variantType()){
-                case RplASVariant::VT_FLOAT:
-                    val1.setFloat(val1.asFloat() + val2.asFloat());
-                    break;
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() + val2.asInt());
-                    break;
-                case RplASVariant::VT_OBJECT:
-                    //if (val1.getClass() == RplASString::m_instance)
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_2, "invalid type for '+': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_MINUS:
-                switch(val1.variantType()){
-                case RplASVariant::VT_FLOAT:
-                    val1.setFloat(val1.asFloat() - val2.asFloat());
-                    break;
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() - val2.asInt());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_3, "invalid type for '-': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_TIMES:
-                switch(val1.variantType()){
-                case RplASVariant::VT_FLOAT:
-                    val1.setFloat(val1.asFloat() * val2.asFloat());
-                    break;
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() * val2.asInt());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_4, "invalid type for '*': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_DIV:
-                switch(val1.variantType()){
-                case RplASVariant::VT_FLOAT:
-                    val1.setFloat(val1.asFloat() / val2.asFloat());
-                    break;
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() / val2.asInt());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_5, "invalid type for '/': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_MOD:
-                switch(val1.variantType()){
-                case RplASVariant::VT_FLOAT:
-                    val1.setFloat(fmod(val1.asFloat(), val2.asFloat()));
-                    break;
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() % val2.asInt());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_6, "invalid type for '%': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_POWER:
-                switch(val1.variantType()){
-                case RplASVariant::VT_FLOAT:
-                    val1.setFloat(fmod(val1.asFloat(), val2.asFloat()));
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_7, "invalid type for '**': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_LOG_OR:
-                switch(val1.variantType()){
-                case RplASVariant::VT_BOOL:
-                    val1.setBool(val1.asBool() || val2.asBool());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_8, "invalid type for '||': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_LOG_AND:
-                switch(val1.variantType()){
-                case RplASVariant::VT_BOOL:
-                    val1.setBool(val1.asBool() && val2.asBool());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_9, "invalid type for '&&': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_LOG_XOR:
-                switch(val1.variantType()){
-                case RplASVariant::VT_BOOL:
-                    val1.setBool(val1.asBool() != val2.asBool());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_9, "invalid type for '^^': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_BIT_OR:
-                switch(val1.variantType()){
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() | val2.asInt());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_10, "invalid type for '|': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_BIT_AND:
-                switch(val1.variantType()){
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() & val2.asInt());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_11, "invalid type for '&': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            case BOP_BIT_XOR:
-                switch(val1.variantType()){
-                case RplASVariant::VT_INTEGER:
-                    val1.setInt(val1.asInt() ^ val2.asInt());
-                    break;
-                default:
-                    error(thread.logger(), LOC_BINOP_CALC_12, "invalid type for '^': %s",
-                      val1.nameOfType());
-                    break;
-                }
-                break;
-            default:
-                break;
-            }
-            thread.popValue();
-        }
-    }
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASBinaryOp::check(RplParser& parser)
-{
-    return false;
-}
-
-/**
- * @brief Returns the operator.
- *
- * @return the operator
- */
-RplASBinaryOp::BinOperator RplASBinaryOp::getOperator() const
-{
-    return m_operator;
-}
-
-/**
- * @brief Sets the operator.
- *
- * @param op    the operator
- */
-void RplASBinaryOp::setOperator(BinOperator op)
-{
-    m_operator = op;
-}
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASBinaryOp::dump(RplWriter& writer, int indent)
-{
-
-    const QByteArray& opName = nameOfOp(m_operator);
-    char buffer[256];
-    writer.formatIndented(indent, "BinOp id: %d op: %s (%d) left: %d right: %d %s",
-            m_id,
-            opName.constData(), m_operator,
-            m_child == NULL ? 0 : m_child->id(),
-            m_child2 == NULL ? 0 : m_child2->id(),
-            positionStr(buffer, sizeof buffer));
-    if (indent < 32 && m_child != NULL)
-        m_child->dump(writer, indent + 1);
-    if (indent < 32 && m_child2 != NULL)
-        m_child2->dump(writer, indent + 1);
-}
-
-/**
- * @brief Does an assignment.
- *
- * @param thread
- */
-void RplASBinaryOp::assign(RplVMThread& thread)
-{
-    RplASVariant& rValue = thread.lValue(m_child);
-    RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child2);
-    if (expr == NULL)
-        error(thread.logger(), LOC_BINOP_1, "not a calculable: id: %d",
-              m_child2 == NULL ? 0 : m_child2->id());
-    else {
-        RplASVariant& value = thread.popValue();
-        switch(m_operator){
-        case BOP_ASSIGN:
-            break;
-        case BOP_PLUS_ASSIGN:
-            //switch(value.variantType()){
-
-            //}
-            break;
-        case BOP_MINUS_ASSIGN:
-        case BOP_TIMES_ASSIGN:
-        case BOP_DIV_ASSIGN:
-        case BOP_MOD_ASSIGN:
-        case BOP_POWER_ASSIGN:
-        case BOP_LOG_OR_ASSIGN:
-        case BOP_LOG_AND_ASSIGN:
-        case BOP_LOG_XOR_ASSIGN:
-        case BOP_BIT_OR_ASSIGN:
-        case BOP_BIT_AND_ASSIGN:
-        case BOP_BIT_XOR_ASSIGN:
-            break;
-        default:
-            break;
-        }
-        rValue.copyValue(value);
-    }
-}
-/**
- * @brief Returns the name (a string) of a binary operator.
- *
- * @param op    operator to convert
- *
- * @return      the name of the operator
- */
-const char* RplASBinaryOp::nameOfOp(RplASBinaryOp::BinOperator op)
-{
-    const char* rc;
-    switch (op){
-    case BOP_ASSIGN:
-        rc = "=";
-        break;
-    case BOP_PLUS_ASSIGN:
-        rc = "+=";
-        break;
-    case BOP_MINUS_ASSIGN:
-        rc = "-=";
-        break;
-    case BOP_TIMES_ASSIGN:
-        rc = "*=";
-        break;
-    case BOP_DIV_ASSIGN:
-        rc = "/=";
-        break;
-    case BOP_MOD_ASSIGN:
-        rc = "%=";
-        break;
-    case BOP_POWER_ASSIGN:
-        rc = "**=";
-        break;
-    case BOP_LOG_OR_ASSIGN:
-        rc = "||=";
-        break;
-    case BOP_LOG_AND_ASSIGN:
-        rc = "&&=";
-        break;
-    case BOP_LOG_XOR_ASSIGN:
-        rc = "^^=";
-        break;
-    case BOP_BIT_OR_ASSIGN:
-        rc = "|=";
-        break;
-    case BOP_BIT_AND_ASSIGN:
-        rc = "&=";
-        break;
-    case BOP_BIT_XOR_ASSIGN:
-        rc = "^=";
-        break;
-    case BOP_LSHIFT_ASSIGN:
-        rc = "<<=";
-        break;
-    case BOP_LOG_RSHIFT_ASSIGN:
-        rc = ">>=";
-        break;
-    case BOP_ARTITH_RSHIFT_ASSIGN:
-        rc = ">>>=";
-        break;
-    case BOP_PLUS:
-        rc = "+";
-        break;
-    case BOP_MINUS:
-        rc = "-";
-        break;
-    case BOP_TIMES:
-        rc = "*";
-        break;
-    case BOP_DIV:
-        rc = "/";
-        break;
-    case BOP_MOD:
-        rc = "%";
-        break;
-    case BOP_POWER:
-        rc = "**";
-        break;
-    case BOP_LOG_OR:
-        rc = "||";
-        break;
-    case BOP_LOG_AND:
-        rc = "&&";
-        break;
-    case BOP_LOG_XOR:
-        rc = "^^";
-        break;
-    case BOP_BIT_OR:
-        rc = "|";
-        break;
-    case BOP_BIT_AND:
-        rc = "&";
-        break;
-    case BOP_BIT_XOR:
-        rc = "^";
-        break;
-    case BOP_LSHIFT:
-        rc = ""; break;
-    case BOP_LOG_RSHIFT:
-        rc = ">>";
-        break;
-    case BOP_ARTITH_RSHIFT:
-        rc = ">>>";
-        break;
-    case BOP_EQ:
-        rc = "==";
-        break;
-    case BOP_NE:
-        rc = "!=";
-        break;
-    case BOP_LE:
-        rc = "<=";
-        break;
-    case BOP_LT:
-        rc = "<";
-        break;
-    case BOP_GE:
-        rc = ">=";
-        break;
-    case BOP_GT:
-        rc = ">";
-        break;
-    default:
-        throw RplException("unknown binary op %d", (int) op);
-    }
-    return rc;
-}
-
-/** @class RplASMethod rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a method definition for the Abstract Syntax Tree.
- *
- * The special case "function" (a method without class) is included.
- *
- * <code>m_child</code>: body<br>
- * <code>m_child2</code>: parameter list (or NULL)
- */
-/**
- * @brief Constructor.
- *
- * @param name      the method name
- * @param tree      the abstract syntax tree
- */
-RplASMethod::RplASMethod(const QByteArray& name, RplASTree& tree) :
-    RplASNode2(AST_METHOD),
-    m_name(name),
-    m_resultType(NULL),
-    m_symbols(NULL),
-    m_sibling(NULL),
-    m_tree(tree)
-{
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASMethod::check(RplParser& parser)
-{
-    return false;
-}
-
-/**
- * @brief Executes the statement.
- *
- * This method will be never called. Must exit: Otherwise the class is abstract.
- */
-int RplASMethod::execute(RplVMThread& thread)
-{
-    return 0;
-}
-
-
-/**
- * @brief Writes the internals of the instance into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASMethod::dump(RplWriter& writer, int indent)
-{
-
-    char buffer[256];
-    writer.indent(indent);
-    writer.format("Method %s %s(",
-            m_resultType == NULL ? "<NoneType>" : m_resultType->name().constData(),
-            m_name.constData());
-    RplSymbolSpace* parent = m_symbols->parent();
-    writer.formatLine(") id: %d parent: %s args: %d body: %d %s", m_id,
-            parent == NULL ? "" : parent->name().constData(),
-            m_child2 == NULL ? 0 : m_child2->id(),
-            m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    if (m_child2 != NULL)
-        m_child2->dump(writer, indent + 1);
-    dumpStatements(writer, indent + 1, m_child);
-    m_symbols->dump(writer, indent + 1);
-}
-/**
- * @brief Returns the symbol space of the instance.
- *
- * @return  the symbol space
- */
-RplSymbolSpace* RplASMethod::symbols() const
-{
-    return m_symbols;
-}
-
-/**
- * @brief Sets the symbol space from the current of the tree.
- */
-void RplASMethod::setSymbols()
-{
-    m_symbols = m_tree.currentSpace();
-}
-/**
- * @brief Returns the name of the method
- * @return  the name
- */
-
-const QByteArray& RplASMethod::name() const
-{
-    return m_name;
-}
-
-/**
- * @brief Tests whether an other method has the same signature (parameterlist).
- * @param other     the method for comparison
- * @return          true: same signature<br>
- *                  false: otherwise
- */
-bool RplASMethod::equalSignature(RplASMethod& other) const
-{
-    bool rc = true;
-    RplASExprStatement* args = dynamic_cast<RplASExprStatement*>(m_child2);
-    RplASExprStatement* otherArgs = dynamic_cast<RplASExprStatement*>(other.child2());
-
-    while(rc && (args != NULL || otherArgs != NULL)){
-        if (args == NULL || otherArgs == NULL)
-            rc = false;
-        else {
-            RplASVarDefinition* def = dynamic_cast<RplASVarDefinition*>(args->child2());
-            RplASVarDefinition* defOther = dynamic_cast<RplASVarDefinition*>(otherArgs->child2());
-            if (def->clazz() != defOther->clazz())
-                rc = false;
-        }
-    }
-    return rc;
-}
-/**
- * @brief Returns the next overloaded method.
- *
- * @return  NULL: no other method available<br>
- *          otherwise: the next method with the same name but another signature
- */
-RplASMethod* RplASMethod::sibling() const
-{
-    return m_sibling;
-}
-
-/**
- * @brief Sets the next overloaded method.
- *
- * @param sibling   another method with the same name but another signature
- */
-void RplASMethod::setSibling(RplASMethod* sibling)
-{
-    m_sibling = sibling;
-}
-
-
-/** @class RplASField rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an class field for the Abstract Syntax Tree.
- *
- * <code>m_child</code>: parent (variable, field, method)
- */
-
-/**
- * @brief Constructor.
- *
- * @param name      name of the field
- */
-RplASField::RplASField(const QByteArray& name) :
-    RplASNode1(AST_FIELD),
-    m_name(name)
-{
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser    for error processing
- * @return          <code>true</code>: node is correct<br>
- *                  <code>false</code>: otherwise
- */
-bool RplASField::check(RplParser& parser)
-{
-    return false;
-}
-
-/**
- * @brief Writes the internals of the instance into a file.
- *
- * @param writer    writes to output
- * @param indent    nesting level
- */
-void RplASField::dump(RplWriter& writer, int indent)
-{
-    char buffer[256];
-    writer.formatIndented(indent, "field %s id: %d parent: %d succ: %s",
-            m_name.constData(), m_id,
-            m_child == NULL ? 0 : m_child->id(),
-            positionStr(buffer, sizeof buffer));
-    m_child->dump(writer, indent + 1);
-}
-
-
diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp
deleted file mode 100644 (file)
index 899dfa4..0000000
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtwriterl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLASTREE_HPP
-#define RPLASTREE_HPP
-
-enum RplASItemType {
-    AST_UNDEF,
-    AST_CONSTANT,
-    AST_LIST_CONSTANT,
-    AST_LIST_ENTRY,
-    AST_MAP_CONSTANT,
-    AST_MAP_ENTRY,
-    AST_NAMED_VALUE,
-    AST_CONVERSION,
-    AST_INDEXED_VALUE,
-    AST_FIELD,
-    AST_VAR_DEFINITION,
-    AST_EXPR_STATEMENT,
-    AST_METHOD,
-    AST_ARGUMENT,
-    AST_INTRINSIC_METHOD,
-    AST_PRE_UNARY_OP,
-    AST_POST_UNARY_OP,
-    AST_BINARY_OP,
-    AST_METHOD_CALL,
-    AST_WHILE,
-    AST_REPEAT,
-    AST_IF,
-    AST_CONDITION,
-    AST_ITERATED_FOR,
-    AST_COUNTED_FOR,
-    AST_SWITCH,
-    AST_LEAVE,
-    AST_CONTINUE
-};
-
-class RplASException : public RplException {
-public:
-    RplASException();
-    RplASException(const RplSourcePosition* position, const char* format, ...);
-protected:
-    void build(const RplSourcePosition* position, const char* format,
-               va_list varList);
-};
-
-class RplASClass;
-class RplASNamedValue;
-class RplASItem;
-class RplASCondition;
-
-class RplASVariant {
-    /* The VM uses some tricks (performance): Therefore this class
-    * must not be virtual!
-    */
-public:
-    enum VariantType {
-        VT_UNDEF,
-        VT_FLOAT,
-        VT_INTEGER,
-        VT_BOOL,
-        VT_OBJECT
-    };
-    enum VariantFlags {
-        VF_UNDEF,
-        /// if DT_OBJECT: object is a copy, don't free at method end
-        VF_IS_COPY      = 1 << 1,
-        /// debugger: action if changed
-        VF_WATCH_POINT  = 1 << 2
-    };
-
-    friend class RplASCondition;
-public:
-    RplASVariant();
-    ~RplASVariant();
-    RplASVariant(const RplASVariant& source);
-    RplASVariant& operator=(const RplASVariant& source);
-    qreal asFloat() const;
-    int asInt() const;
-    bool asBool() const;
-    void* asObject(const RplASClass** clazz) const;
-    const QByteArray* asString() const;
-    void setFloat(qreal number);
-    void setInt(int integer);
-    void setBool(bool value);
-    void setObject(void* object, const RplASClass* clazz);
-    void setString(const QByteArray& string);
-    QByteArray toString(int maxLength = 80) const;
-    VariantType variantType() const;
-    const char* nameOfType() const;
-    const RplASClass* getClass() const;
-    void copyValue(const RplASVariant& source);
-    void destroyValue();
-private:
-    VariantType m_variantType:8;
-    /// bitmap of VF_... flags:
-    int m_flags:8;
-    union {
-        qreal m_float;
-        int m_int;
-        bool m_bool;
-        void* m_object;
-    } m_value;
-    const RplASClass* m_class;
-};
-
-class RplASTree;
-class RplParser;
-class RplVMThread;
-
-class RplASItem
-{
-public:
-    enum NodeFlags {
-        NF_UNDEF,
-        /// the node calculates a value:
-        NF_CALCULABLE   = 1 << 1,
-        /// the node calculates a value:
-        NF_STATEMENT    = 1 << 2,
-        /// the tree under this node is complete checked for data type correctness
-        NF_TYPECHECK_COMPLETE   = 1 << 3,
-        /// debugger: this node is a breakpoint
-        NF_BREAKPOINT           = 1 << 5
-    };
-
-public:
-    friend class RplASTree;
-    RplASItem(RplASItemType type);
-    virtual ~RplASItem();
-public:
-    virtual bool check(RplParser& parser) = 0;
-public:
-    bool checkAsCalculable(const char* description, RplASClass* expectedClass,
-                           RplParser& parser);
-    const RplSourcePosition* position() const;
-    void setPosition(const RplSourcePosition* position);
-    unsigned int id() const;
-    char* positionStr(char buffer[], size_t bufferSize) const;
-    void error(RplLogger* logger, int location, const char* format, ...);
-public:
-    /**
-     * @brief Writes the content of the instance into an output medium.
-     *
-     * @param writer    writes to output media
-     * @param indent    nesting level: so many tabs will be used as prefix
-     */
-    virtual void dump(RplWriter& writer,int indent) = 0;
-public:
-    static void reset();
-    static bool checkStatementList(RplASItem* list, RplParser& parser);
-    static int calcAsInteger(RplASItem* expr, RplVMThread& thread);
-    static bool calcAsBoolean(RplASItem* expr, RplVMThread& thread);
-public:
-    RplASItemType nodeType() const;
-    const char* nameOfItemType() const;
-
-    int flags() const;
-    void setFlags(int flags);
-
-    bool typeCheck(RplASClass* clazz1, RplASClass* clazz2);
-    bool error(int location, RplParser& parser, const char* format, ...);
-    bool ensureError(RplParser& parser, const char* info);
-protected:
-    unsigned int m_id:16;
-    RplASItemType m_nodeType:8;
-    int m_flags:5;
-    int m_dataType: 3;
-    const RplSourcePosition* m_position;
-private:
-    static unsigned int m_nextId;
-};
-
-class RplASNode1;
-class RplASCalculable
-{
-public:
-    RplASCalculable();
-public:
-    virtual void calc(RplVMThread& thread) = 0;
-public:
-    RplASClass* clazz() const;
-    void setClass(RplASClass* clazz);
-protected:
-    RplASClass* m_class;
-};
-
-class RplStackFrame;
-class RplASStorable : public RplASCalculable {
-};
-class RplVMThread;
-class RplASConstant : public RplASItem, public RplASCalculable
-{
-public:
-    RplASConstant();
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-public:
-    virtual void dump(RplWriter& writer,int indent);
-    RplASVariant& value();
-private:
-    RplASVariant m_value;
-};
-
-
-class RplASNode1 : public RplASItem
-{
-public:
-    RplASNode1(RplASItemType type);
-    virtual ~RplASNode1();
-public:
-    RplASItem* child() const;
-    void setChild(RplASItem* child);
-public:
-    static void dumpStatements(RplWriter& writer, int indent, RplASItem* statements);
-protected:
-    RplASItem* m_child;
-};
-
-class RplASNode2 : public RplASNode1
-{
-public:
-    RplASNode2(RplASItemType type);
-    virtual ~RplASNode2();
-public:
-    RplASItem* child2() const;
-    void setChild2(RplASItem* child2);
-
-protected:
-    RplASItem* m_child2;
-};
-
-class RplASNode3 : public RplASNode2
-{
-public:
-    RplASNode3(RplASItemType type);
-    virtual ~RplASNode3();
-public:
-    RplASItem* child3() const;
-    void setChild3(RplASItem* child3);
-
-protected:
-    RplASItem* m_child3;
-};
-
-class RplASNode4 : public RplASNode3
-{
-public:
-    RplASNode4(RplASItemType type);
-    virtual ~RplASNode4();
-public:
-    RplASItem* child4() const;
-    void setChild4(RplASItem* child4);
-
-protected:
-    RplASItem* m_child4;
-};
-
-class RplASNode5 : public RplASNode4
-{
-public:
-    RplASNode5(RplASItemType type);
-    virtual ~RplASNode5();
-public:
-    RplASItem*child5() const;
-    void setChild5(RplASItem* child5);
-protected:
-    RplASItem* m_child5;
-};
-class RplASNode6 : public RplASNode5
-{
-public:
-    RplASNode6(RplASItemType type);
-    virtual ~RplASNode6();
-public:
-    RplASItem*child6() const;
-    void setChild6(RplASItem* child5);
-protected:
-    RplASItem* m_child6;
-};
-
-typedef QList<RplASVariant*> RplASListOfVariants;
-typedef QMap<QByteArray, RplASVariant*> RplASMapOfVariants;
-
-class RplASListConstant : public RplASNode1, public RplASCalculable
-{
-public:
-    RplASListConstant();
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-
-public:
-    virtual void dump(RplWriter& writer,int indent);
-    RplASVariant& value();
-    RplASListOfVariants* list();
-private:
-    RplASVariant m_value;
-};
-class RplASMapConstant : public RplASNode1, public RplASCalculable
-{
-public:
-    RplASMapConstant();
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-public:
-    virtual void dump(RplWriter& writer,int indent);
-    RplASVariant& value();
-    RplASMapOfVariants* map();
-private:
-    RplASVariant m_value;
-};
-
-class RplSymbolSpace;
-class RplASNamedValue : public RplASItem, public RplASStorable
-{
-    friend class RplASVarDefinition;
-public:
-    enum Attributes {
-        A_NONE,
-        /// the value cannot be changed.
-        A_CONST         = 1<<1,
-        /// the variable/constant is found in the global namespace, not in a method
-        A_GLOBAL        = 1<<2,
-        /// the variable/constant is found in the module namespace, not in a method
-        A_MODULE_STATIC = 1<<3,
-        /// the evaluation should be lazy
-        A_LAZY          = 1<<4,
-        /// parameter of a method
-        A_PARAM         = 1<<5,
-        /// a automatic variable in counted for loops:
-        A_LOOP          = 1<<6
-    };
-
-public:
-    RplASNamedValue(RplASClass* clazz, RplSymbolSpace* space,
-                    const QByteArray& name, int attributes);
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-public:
-    const QByteArray& name() const;
-    void setSymbolSpace(RplSymbolSpace* space, int variableNo);
-    void dump(RplWriter& writer, int indent);
-    RplSymbolSpace* symbolSpace() const;
-    int variableNo() const;
-    void setVariableNo(int variableNo);
-protected:
-    QByteArray m_name;
-    int m_attributes;
-    RplSymbolSpace* m_symbolSpace;
-    int m_variableNo;
-};
-class RplASConversion : public RplASNode1, public RplASCalculable {
-public:
-    enum Conversion {
-        C_UNDEF,
-        C_INT_TO_FLOAT,
-        C_FLOAT_TO_INT,
-        C_BOOL_TO_INT,
-        C_BOOL_TO_FLOAT
-    };
-
-public:
-    RplASConversion(RplASItem* expression);
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-    virtual void dump(RplWriter& writer,int indent);
-public:
-    static RplASConversion* tryConversion(RplASClass* expected, RplASItem* expr,
-                                          RplParser& parser, bool& isCorrect);
-    static Conversion findConversion(RplASClass* from, RplASClass* to);
-private:
-    Conversion m_conversion;
-};
-
-class RplASIndexedValue : public RplASNode2, public RplASCalculable {
-public:
-    RplASIndexedValue();
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-public:
-    void dump(RplWriter& writer, int indent);
-};
-
-class RplASStatement
-{
-public:
-    RplASStatement();
-public:
-    virtual int execute(RplVMThread& thread) = 0;
-public:
-    static int executeStatementList(RplASItem* list, RplVMThread& thread);
-};
-
-
-class RplASVarDefinition : public RplASNode3, public RplASStatement
-{
-public:
-    RplASVarDefinition();
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-public:
-    void dump(RplWriter& writer, int indent);
-    const QByteArray& name() const;
-    int endOfScope() const;
-    void setEndOfScope(int endOfScope);
-    RplASClass* clazz() const;
-private:
-    /// the column of the blockend containing the definition.
-    /// if 0: end is end of method or end of class
-    /// Note: the source unit is stored in <code>RplASItem::m_sourcePosition</code>
-    int m_endOfScope;
-};
-
-class RplASExprStatement : public RplASNode2, public RplASStatement
-{
-public:
-    RplASExprStatement();
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-public:
-    void dump(RplWriter& writer, int indent);
-};
-
-class RplASUnaryOp : public RplASNode1, RplASCalculable
-{
-public:
-    enum UnaryOp {
-        UOP_UNDEF,
-        UOP_PLUS,
-        UOP_MINUS_INT,
-        UOP_MINUS_FLOAT,
-        UOP_NOT_BOOL,
-        UOP_NOT_INT,
-        UOP_INC,
-        UOP_DEC
-    };
-public:
-    RplASUnaryOp(UnaryOp op, RplASItemType type);
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-public:
-    int getOperator() const;
-    void dump(RplWriter& writer, int indent);
-public:
-    static const char* nameOfOp(UnaryOp op);
-private:
-    UnaryOp m_operator;
-};
-class RplASBinaryOp : public RplASNode2, public RplASCalculable
-{
-public:
-    enum BinOperator {
-        BOP_UNDEF,
-        BOP_ASSIGN,
-        BOP_PLUS_ASSIGN,
-        BOP_MINUS_ASSIGN,
-        BOP_TIMES_ASSIGN,
-        BOP_DIV_ASSIGN,
-        BOP_MOD_ASSIGN,
-        BOP_POWER_ASSIGN,
-        BOP_LOG_OR_ASSIGN,
-        BOP_LOG_AND_ASSIGN,
-        BOP_LOG_XOR_ASSIGN,
-        BOP_BIT_OR_ASSIGN,
-        BOP_BIT_AND_ASSIGN,
-        BOP_BIT_XOR_ASSIGN,
-        BOP_LSHIFT_ASSIGN,
-        BOP_LOG_RSHIFT_ASSIGN,
-        BOP_ARTITH_RSHIFT_ASSIGN,
-        BOP_PLUS,
-        BOP_MINUS,
-        BOP_TIMES,
-        BOP_DIV,
-        BOP_MOD,
-        BOP_POWER,
-        BOP_LOG_OR,
-        BOP_LOG_AND,
-        BOP_LOG_XOR,
-        BOP_BIT_OR,
-        BOP_BIT_AND,
-        BOP_BIT_XOR,
-        BOP_LSHIFT,
-        BOP_LOG_RSHIFT,
-        BOP_ARTITH_RSHIFT,
-        BOP_EQ,
-        BOP_NE,
-        BOP_LE,
-        BOP_LT,
-        BOP_GE,
-        BOP_GT,
-        BOB_COUNT
-    };
-private:
-    inline bool isAssignment() const {
-        return m_operator >= BOP_ASSIGN
-                && m_operator <= BOP_ARTITH_RSHIFT_ASSIGN;
-    }
-public:
-    RplASBinaryOp();
-public:
-    virtual void calc(RplVMThread& thread);
-    virtual bool check(RplParser& parser);
-public:
-    BinOperator getOperator() const;
-    void setOperator(BinOperator op);
-    void dump(RplWriter& writer, int indent);
-private:
-    void assign(RplVMThread& thread);
-public:
-    static const char* nameOfOp(BinOperator op);
-private:
-    BinOperator m_operator;
-};
-
-class RplASIf : public RplASNode4, public RplASStatement
-{
-public:
-    RplASIf();
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-    virtual void dump(RplWriter& writer, int indent);
-};
-
-class RplASForIterated : public RplASNode4, public RplASStatement
-{
-public:
-    RplASForIterated(RplASVarDefinition* variable);
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-    virtual void dump(RplWriter& writer, int indent);
-};
-
-class RplASForCounted : public RplASNode6, public RplASStatement
-{
-public:
-    RplASForCounted(RplASVarDefinition* variable);
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-    virtual void dump(RplWriter& writer, int indent);
-};
-
-class RplASWhile : public RplASNode3, public RplASStatement
-{
-public:
-    RplASWhile();
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-    virtual void dump(RplWriter& writer, int indent);
-};
-
-class RplASRepeat : public RplASNode3, public RplASStatement
-{
-public:
-    RplASRepeat();
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-    virtual void dump(RplWriter& writer, int indent);
-};
-
-class RplASMethod;
-class RplASMethodCall : public RplASNode3, public RplASStatement
-{
-public:
-    RplASMethodCall(const QByteArray& name, RplASItem* parent);
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-public:
-    void dump(RplWriter& writer, int indent);
-
-public:
-    RplASMethod* method() const;
-    void setMethod(RplASMethod* method);
-
-    RplASExprStatement* arg1() const;
-private:
-    QByteArray m_name;
-    RplASMethod* m_method;
-};
-
-class RplParameter : RplASItem
-{
-public:
-    RplParameter();
-    virtual ~RplParameter();
-private:
-    QByteArray m_name;
-    RplASNamedValue* m_default;
-};
-
-class RplASField : public RplASNode1
-{
-public:
-    RplASField(const QByteArray& name);
-public:
-    virtual bool check(RplParser& parser);
-public:
-    void dump(RplWriter& writer, int indent);
-private:
-    QByteArray m_name;
-};
-
-
-class RplASClass;
-class RplSymbolSpace;
-class RplASMethod : public RplASNode2
-{
-public:
-    RplASMethod(const QByteArray& name, RplASTree& tree);
-public:
-    virtual bool check(RplParser& parser);
-    virtual int execute(RplVMThread& thread);
-public:
-    void dump(RplWriter& writer, int indent);
-    RplSymbolSpace* symbols() const;
-    void setSymbols();
-    const QByteArray& name() const;
-    bool equalSignature(RplASMethod& other) const;
-    RplASMethod* sibling() const;
-    void setSibling(RplASMethod* sibling);
-
-private:
-    QByteArray m_name;
-    RplASClass* m_resultType;
-    RplSymbolSpace* m_symbols;
-    // chain over all overloaded methods (same name, other signature):
-    RplASMethod* m_sibling;
-    RplASTree& m_tree;
-};
-
-class RplASClass {
-public:
-    typedef QMap<QByteArray, RplASMethod*> MethodMap;
-public:
-    RplASClass(const QByteArray& name, RplASTree& m_tree);
-    virtual ~RplASClass();
-public:
-    /**
-     * @brief Creates a value object (used in RplASVariant).
-     *
-     * @param source    NULL or a source to copy
-     * @return          a new value object (specific for the class)
-     */
-    virtual void* newValueInstance(void* source = NULL) const = 0;
-    /**
-     * @brief Destroys the given object.
-     *
-     * The object must be created by <code>newValueInstance()</code>.
-     *
-     * @param object    object to destroy
-     */
-    virtual void destroyValueInstance(void* object) const = 0;
-    /**
-     * @brief Returns the boolean value of a class specific value.
-     *
-     * Example: the boolean value of an the empty string is false
-     *
-     * @param object    object to test
-     * @return          false: the object represents the false value<br>
-     *                  true: otherwise
-     */
-    virtual bool boolValueOf(void* object) const = 0;
-    /**
-     * @brief Returns a string representation of an instance.
-     *
-     * @param object    the object to convert
-     * @param maxLength the maximum length of the result (string)
-     * @return          a string describing the <code>object</code>
-     */
-    virtual QByteArray toString(void *object, int maxLength = 80) const = 0;
-public:
-    const QByteArray& name() const;
-    virtual void dump(RplWriter& writer, int indent);
-    void setSymbols();
-protected:
-    QByteArray m_name;
-    RplSymbolSpace* m_symbols;
-    const RplASClass* m_superClass;
-    RplASTree& m_tree;
-};
-
-#include "rplexpr/rplasclasses.hpp"
-
-#include "rplparser.hpp"
-class RplSymbolSpace;
-class RplASTree
-{
-public:
-    enum {
-        DMP_NONE,
-        DMP_GLOBALS     = 1<<1,
-        DMP_MODULES     = 1<<2,
-        DMP_SPACE_STACK = 1<<3,
-        DMP_SPACE_HEAP  = 1<<4,
-        DMP_ALL         = DMP_GLOBALS | DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP,
-        DMP_NO_GLOBALS  = DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP
-    };
-    typedef QMap<QByteArray, RplSymbolSpace*> SymbolSpaceMap;
-    typedef QList<RplSymbolSpace*> SymbolSpaceStack;
-public:
-    RplASTree();
-    ~RplASTree();
-public:
-    bool startModule(RplSourceUnitName name);
-    void finishModule(RplSourceUnitName name);
-    RplSymbolSpace* startClassOrMethod(const QByteArray& name,
-        RplSymbolSpace::SymbolSpaceType type);
-    void finishClassOrMethod(const QByteArray& name);
-    SymbolSpaceStack& symbolSpaces();
-    RplSymbolSpace* currentSpace() const;
-    RplASClass* findClass(const QByteArray& name);
-    void clear();
-    void dump(const char* filename, int flags = DMP_ALL,
-              const char* header = NULL);
-    RplSymbolSpace*findmodule(const QByteArray& name);
-    RplSourcePosition* copyPosition();
-    RplByteStorage& store();
-
-protected:
-    void init();
-    void destroy();
-private:
-    // the mother of all symbol spaces.
-    RplSymbolSpace* m_global;
-    // contains all hit modules
-    SymbolSpaceMap m_modules;
-    // nested modules (import), classes and methods build this stack:
-    SymbolSpaceStack m_symbolSpaces;
-    // top of the stack:
-    RplSymbolSpace* m_currentSpace;
-    // contain all ever built symbol spaces:
-    SymbolSpaceMap m_symbolSpaceHeap;
-    RplByteStorage m_store;
-};
-
-#endif // RPLASTREE_HPP
diff --git a/rplexpr/rplexpr.hpp b/rplexpr/rplexpr.hpp
deleted file mode 100644 (file)
index 7b04db0..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLEXPR_HPP
-#define RPLEXPR_HPP
-
-#include <QStack>
-#include <QRegularExpression>
-#include <QFile>
-#include <QTextStream>
-#include <QDir>
-#include <QtAlgorithms>
-#include <QVariant>
-
-#include "rplexpr/rplsource.hpp"
-#include "rplexpr/rpllexer.hpp"
-#include "rplexpr/rplastree.hpp"
-#include "rplexpr/rplvm.hpp"
-#include "rplexpr/rplparser.hpp"
-#include "rplexpr/rplmfparser.hpp"
-
-#endif // RPLEXPR_HPP
diff --git a/rplexpr/rpllexer.cpp b/rplexpr/rpllexer.cpp
deleted file mode 100644 (file)
index 1366cf8..0000000
+++ /dev/null
@@ -1,1234 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-/** @file
- * @brief Configurable scanner, wich separates syntactic symbols from an input media.
- */
-/** @file rplexpr/rpllexer.hpp
- * @brief Definitions for a configurable lexical analyser.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-
-#define CHAR_INFO_SIZE (int(sizeof m_charInfo / sizeof m_charInfo[0]))
-
-
-/** @class RplToken rpllexer.hpp "rplexpr/rpllexer.hpp"
- *
- * @brief Implements specific exception for the lexer.
- *
- */
-
-/**
- * @brief Constructor.
- *
- * @param position  describes the position of the error/warning
- * @param format    the reason of the exception
- * @param ...       the values for the placeholders in the format.
- */
-RplLexException::RplLexException(const RplSourcePosition& position,
-                                 const char* format, ...) :
-    RplException("")
-{
-    char buffer[64000];
-    m_message = position.toString().toUtf8();
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    m_message += buffer;
-}
-
-/** @class RplToken rpllexer.hpp "rplexpr/rpllexer.hpp"
- *
- * @brief Implements a token which is the smallest unit for a parser.
- *
- */
-/**
- * @brief Constructor.
- * @param type  token type
- */
-RplToken::RplToken(RplTokenType type) :
-    m_tokenType(type),
-    m_string(),
-    m_printableString()
-    // m_value
-{
-    memset(&m_value, 0, sizeof m_value);
-}
-
-/**
- * @brief Destructor.
- */
-RplToken::~RplToken()
-{
-}
-/**
- * @brief Copy constructor.
- *
- * @param source    source to copy
- */
-RplToken::RplToken(const RplToken& source) :
-    m_tokenType(source.m_tokenType),
-    m_string(source.m_string),
-    m_printableString(source.m_printableString),
-    m_value(source.m_value)
-{
-}
-/**
- * @brief Assignment operator.
- *
- * @param source    source to copy
- * @return
- */
-RplToken& RplToken::operator =(const RplToken& source)
-{
-    m_tokenType = source.m_tokenType;
-    m_string = source.m_string;
-    m_value = source.m_value;
-    return *this;
-}
-
-/**
- * @brief Returns the string representation of the instance
- * @return a string representing the instance
- */
-const QByteArray& RplToken::toString()
-{
-    return m_string;
-}
-
-/**
- * @brief Returns the integer value of the token
- *
- * Only relevant if a TOKEN_NUMBER.
- *
- * @return the value of the token as integer
- */
-int RplToken::asInteger() const
-{
-    return (int) m_value.m_integer;
-}
-
-/**
- * @brief Returns the integer value of the token
- *
- * Only relevant if a TOKEN_NUMBER.
- *
- * @return the value of the token as unsigned integer (64 bit)
- */
-quint64 RplToken::asUInt64() const
-{
-    return m_value.m_integer;
-}
-
-/**
- * @brief Returns the floating point value of the token
- *
- * Only relevant if a TOKEN_REAL.
- *
- * @return the value of the token as floating point value
- */
-qreal RplToken::asReal() const
-{
-    return m_value.m_real;
-}
-
-/**
- * @brief Returns the floating point value of the token
- *
- * Only relevant if a TOKEN_NUMBER.
- *
- * @return the value of the token as floating point value
- */
-const QByteArray& RplToken::rawString() const
-{
-    return m_printableString;
-}
-/**
- * @brief Returns the id of the token.
- *
- * Ids are more handy than string, e.g. allowing switch statements.
- *
- * Only relevant for TOKEN_KEYWORD and TOKEN_OPERATOR.
- *
- * @return the id of the token
- */
-int RplToken::id() const
-{
-    return m_value.m_id;
-}
-/**
- * @brief Returns the token type.
- * @return the token type
- */
-RplTokenType RplToken::tokenType() const
-{
-    return m_tokenType;
-}
-
-/**
- * @brief Checks whether the instance has a given token type.
- *
- * @param expected  the token type to compare
- *
- * @return  true: the expected type is the current<br>
- *          false: otherwise
- */
-bool RplToken::isTokenType(RplTokenType expected) const
-{
-    return m_tokenType == expected;
-}
-
-/**
- * @brief Checks whether the instance is a given operator.
- *
- * @param expected      the expected operator
- * @param alternative   0 or a second possibility
- *
- * @return  true: the instance is an operator and the expected or the alternative<br>
- *          false: otherwise
- */
-bool RplToken::isOperator(int expected, int alternative) const
-{
-    return m_tokenType == TOKEN_OPERATOR && (m_value.m_id == expected
-                                             || m_value.m_id == alternative);
-}
-
-/**
- * @brief Checks whether the instance is a given keyword.
- *
- * @param expected      the expected keyword
- * @param alternative   0 or a second possibility
- *
- * @return  true: the instance is a keyword and the expected or the alternative<br>
- *          false: otherwise
- */
-
-bool RplToken::isKeyword(int expected, int alternative) const
-{
-    return m_tokenType == TOKEN_KEYWORD && (m_value.m_id == expected
-                                             || m_value.m_id == alternative);
-}
-
-/**
- * @brief Makes all members undefined.
- */
-void RplToken::clear()
-{
-    m_string.clear();
-    m_printableString.clear();
-    m_tokenType = TOKEN_UNDEF;
-    m_value.m_integer = 0;
-}
-
-/**
- * @brief Returns whether the token is a capitalized id
- *
- * @return  true: the token is an id and the first char is an upper case char<br>
- *          false: otherwise
- */
-bool RplToken::isCapitalizedId() const
-{
-    bool rc = m_tokenType == TOKEN_ID && isupper(m_string.at(0))
-            && (m_string.length() == 1 || islower(m_string.at(1)));
-    return rc;
-}
-
-/**
- * @brief Returns the description of the current token.
- *
- * @return a description of the instance
- */
-QByteArray RplToken::dump() const
-{
-    QByteArray rc;
-    rc = nameOfType(m_tokenType);
-    rc.append(": ").append(this->asUtf8());
-    return rc;
-}
-QByteArray RplToken::asUtf8() const
-{
-    char buffer[4096];
-    buffer[0] = '\0';
-
-    switch(m_tokenType){
-    case TOKEN_UNDEF:
-        break;
-    case TOKEN_STRING:
-        qsnprintf(buffer, sizeof buffer, "'%.*s'", int(sizeof buffer) - 1,
-                 m_printableString.constData());
-        break;
-    case TOKEN_NUMBER:
-        qsnprintf(buffer, sizeof buffer, "%lld", m_value.m_integer);
-        break;
-    case TOKEN_REAL:
-        qsnprintf(buffer, sizeof buffer, "%f", m_value.m_real);
-        break;
-    case TOKEN_KEYWORD:
-    case TOKEN_OPERATOR:
-        qsnprintf(buffer, sizeof buffer, "%lld", (int) m_value.m_id);
-        break;
-    case TOKEN_ID:
-        qsnprintf(buffer, sizeof buffer, "'%.*s'", int(sizeof buffer) - 1,
-                 m_string.constData());
-        break;
-    case TOKEN_COMMENT_REST_OF_LINE:
-    case TOKEN_COMMENT_START:
-    case TOKEN_COMMENT_END:
-    case TOKEN_SPACE:
-    case TOKEN_END_OF_SOURCE:
-    default:
-        break;
-    }
-    return buffer;
-}
-/**
- * @brief Returns then name of a token type.
- * @param   type  the type to convert
- * @return  the token type name
- */
-const char* RplToken::nameOfType(RplTokenType type)
-{
-    const char* rc = "?";
-
-    switch(type){
-    case TOKEN_UNDEF:
-        rc = "undef";
-        break;
-    case TOKEN_STRING:
-        rc = "String";
-        break;
-    case TOKEN_NUMBER:
-        rc = "Number";
-        break;
-    case TOKEN_REAL:
-        rc = "Real";
-        break;
-    case TOKEN_KEYWORD:
-        rc = "Keyword";
-        break;
-    case TOKEN_OPERATOR:
-        rc = "Operator";
-        break;
-    case TOKEN_ID:
-        rc = "Id";
-        break;
-    case TOKEN_COMMENT_REST_OF_LINE:
-        rc = "Comment-1-line";
-        break;
-    case TOKEN_COMMENT_START:
-        rc = "Comment-m-line";
-        break;
-    case TOKEN_COMMENT_END:
-        rc = "end of comment";
-        break;
-    case TOKEN_SPACE:
-        rc = "space";
-        break;
-    case TOKEN_END_OF_SOURCE:
-        rc = "end of source";
-        break;
-    default:
-        break;
-    }
-    return rc;
-}
-
-
-/** @class RplLexer rpllexer.hpp "rplexpr/rpllexer.hpp"
- *
- * @brief Implements a lexical analyser.
- *
- * A lexical analyser reads a text source and separates the tokens for a parser.
- * Tokens are the smallest elements of a parsing process.
- *
- */
-
-static void itemsToVector(const char* items, RplLexer::StringList& vector,
-                         int firstCharFlag, int secondCharFlag,
-                         int thirdCharFlag, int restCharFlag,
-                         int charInfo[])
-{
-    QByteArray array2(items);
-    QList<QByteArray> list = array2.split(' ');
-    QList<QByteArray>::iterator it;
-    int id = 0;
-    for (it = list.begin(); it < list.end(); it++){
-        QByteArray& item2 = *it;
-        QByteArray item(item2);
-        id++;
-        item.append(' ').append(id % 256).append(id / 256);
-        vector.append(item);
-        unsigned char cc = item2.at(0);
-        if (cc < 128)
-            charInfo[cc] |= firstCharFlag;
-        if(item2.size() > 1){
-            cc = item2.at(1);
-            if (cc < 128)
-                charInfo[cc] |= secondCharFlag;
-        }
-        if(item2.size() > 2){
-            cc = item2.at(2);
-            if (cc < 128)
-                charInfo[cc] |= thirdCharFlag;
-        }
-        if(item2.size() > 3){
-            const char* ptr = item2.constData() + 3;
-            while( (cc = *ptr++) != '\0'){
-                if (cc < 128)
-                    charInfo[cc] |= restCharFlag;
-            }
-        }
-    }
-    qSort(vector.begin(), vector.end(), qLess<QByteArray>());
-}
-
-static void charClassToCharInfo(const char* charClass, int flag,
-     int charInfo[])
-{
-    for (int ix = 0; charClass[ix] != '\0'; ix++){
-        unsigned char cc = (unsigned char) charClass[ix];
-        if (cc < 128)
-            charInfo[cc] |= flag;
-        if (charClass[ix+1] == '-'){
-            unsigned char ubound = charClass[ix+2];
-            if (ubound == '\0')
-                charInfo['-'] |= flag;
-            else if (cc >= ubound)
-                throw new RplException("wrong character class range: %c-%c (%s)",
-                         cc, ubound, charClass);
-            else {
-                for (int ii = cc + 1; ii <= ubound; ii++){
-                    charInfo[ii] |= flag;
-                }
-            }
-            ix += 2;
-        }
-    }
-}
-
-/**
- * @brief Constructor.
- *
- * @param source        the input source handler
- * @param keywords      a string with all keywords delimited by " ".
- *                      Example: "if then else fi while do done"
- * @param operators     a string with the operators separated by blank or "\n".
- *                      "\n" separates the operators with the same priority.
- *                      Lower position means lower priority
- * @param rightAssociatives
- *                      the operators which are right associative
- * @param comments      a string with pairs of comment begin and end delimited
- *                      by " ". The comment end can be "\n" for line end.
- *                      Example: "/ * * / // \n" (ignore the blank in "* /")
- * @param firstCharsId  string with the characters which are allowed as first
- *                      characters of an id
- * @param restCharsId   string with the characters which are allowed as non
- *                      first characters of an id
- * @param numericTypes  bit mask of allowed numeric,
- *                      e.g. NUMTYPE_DECIMAL | NUMTYPE_HEXADECIMAL
- * @param stringFeatures bit mask of the string features,
- *                      e.g. SF_QUOTE | SF_TICK
- * @param storageFlags  describes the things which should be stored, e.g.
- *                      S_ORG_STRINGS | S_COMMENTS | S_BLANKS
- */
-RplLexer::RplLexer(RplSource* source,
-        const char* keywords,
-        const char* operators, const char* rightAssociatives,
-        const char* comments,
-        const char* firstCharsId, const char* restCharsId, int numericTypes,
-        int stringFeatures, int storageFlags) :
-    m_source(source),
-    m_keywords(),
-    m_operators(),
-    m_commentStarts(),
-    m_commentEnds(),
-    //m_charInfo()
-    m_idFirstRare(),
-    m_idRestRare(),
-    m_numericTypes(numericTypes),
-    m_idRest2(),
-    m_currentToken(&m_token1),
-    m_waitingToken(NULL),
-    m_waitingToken2(NULL),
-    m_token1(TOKEN_UNDEF),
-    m_token2(TOKEN_UNDEF),
-    m_currentPosition(NULL),
-    m_waitingPosition1(NULL),
-    m_waitingPosition2(NULL),
-    m_maxTokenLength(64),
-    m_input(),
-    m_currentCol(0),
-    m_hasMoreInput(false),
-    m_stringFeatures(stringFeatures),
-    m_storageFlags(storageFlags),
-    // m_prioOfOp
-    // m_assocOfOp
-    #if defined (RPL_LEXER_TRACE)
-    m_trace(true),
-    #endif
-    m_opNames()
-{
-    memset(m_prioOfOp, 0, sizeof m_prioOfOp);
-    memset(m_assocOfOp, 0, sizeof m_assocOfOp);
-
-    memset(m_charInfo, 0, sizeof m_charInfo);
-    itemsToVector(keywords, m_keywords, CC_FIRST_KEYWORD, CC_2nd_KEYWORD,
-                  CC_3rd_KEYWORD, CC_REST_KEYWORD, m_charInfo);
-    prepareOperators(operators, rightAssociatives);
-    charClassToCharInfo(firstCharsId, CC_FIRST_ID, m_charInfo);
-    charClassToCharInfo(restCharsId, CC_REST_ID, m_charInfo);
-    initializeComments(comments);
-    m_input.reserve(m_maxTokenLength*2);
-}
-/**
- * @brief Destructor.
- */
-RplLexer::~RplLexer()
-{
-}
-
-/**
- * @brief Returns the count of blanks in a given range of a string.
- *
- * @param start pointer to the first char to check
- * @param end   pointer to the last char to check
- * @return  the count of blanks
- */
-int countBlanks(const char* start, const char* end){
-    int rc = 0;
-    while(start != end){
-        if (*start++ == ' '){
-            rc++;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Stores the operators in the internal members
- *
- * @param operators     a string with the operators separated by blank or '\n'.
- *                      '\n' separates the operators with the same priority.
- *                      Lower position means lower priority
- */
-void RplLexer::prepareOperators(const char* operators,
-                                const char* rightAssociatives){
-    QByteArray op2(operators);
-    QByteArray rightAssociatives2(" ");
-    rightAssociatives2 += rightAssociatives;
-    op2.replace("\n", " ");
-    itemsToVector(op2.constData(), m_operators, CC_FIRST_OP, CC_2nd_OP,
-                  CC_3rd_OP, CC_REST_OP, m_charInfo);
-    // m_operators is now sorted:
-    // test whether the successor of 1 char operators is starting with this char:
-    // if not this operator will be marked with CC_OP_1_ONLY:
-    for (int ix = 0; ix < m_operators.size() - 1; ix++){
-        // the entries of m_operators end with ' ' and id:
-        if (m_operators.at(ix).size() == 1 + 2
-                && m_operators.at(ix).at(0) != m_operators.at(ix+1).at(0)){
-            int cc = (char) m_operators[ix].at(0);
-            m_charInfo[cc] |= CC_OP_1_ONLY;
-        }
-
-    }
-    m_opNames.reserve(m_operators.size() + 1);
-    op2 = " " + op2;
-    m_opNames = op2.split(' ');
-    QByteArray rAssoc = QByteArray(" ") + rightAssociatives + " ";
-    for (int opId = m_opNames.size() - 1; opId >= 1; opId--){
-        QByteArray item = " " + m_opNames[opId] + " ";
-        if (rAssoc.indexOf(item) >= 0)
-            m_assocOfOp[opId] = true;
-    }
-    const char* start = operators;
-    const char* end;
-    int prio = 0;
-    int endId = 0;
-    int startId = 1;
-    bool again = true;
-    while (again){
-        if ( (end = strchr(start, '\n')) == NULL){
-             end = strchr(start, '\0');
-             again = false;
-        }
-        prio++;
-        endId = startId + countBlanks(start, end) + 1 - 1;
-        while(startId <= endId){
-            m_prioOfOp[startId++] = prio;
-        }
-        start = end + 1;
-    }
-}
-
-void RplLexer::initializeComments(const char* comments)
-{
-    if (comments != NULL)
-    {
-        QByteArray starters;
-        QByteArray comments2(comments);
-        int ix = comments2.indexOf("  ");
-        if (ix >= 0)
-            throw RplException("more than one blank between comment pair(s): col %d %s",
-                               ix + 1, comments + ix);
-        // the index of m_commentEnds is the position number: we need a dummy entry:
-        m_commentEnds.append("");
-
-        QList<QByteArray> items = comments2.split(' ');
-        QList<QByteArray>::iterator it;
-        ix = 0;
-        for (it = items.begin(); it != items.end(); it++, ix++){
-             if (ix % 2 == 0){
-                if (ix > 0)
-                    starters += " ";
-                starters += *it;
-            }else{
-                 m_commentEnds.append(*it);
-            }
-        }
-        if (ix % 2 != 0)
-            throw RplException("not only pairs in the comment list");
-        itemsToVector(starters, m_commentStarts, CC_FIRST_COMMENT_START,
-             CC_2nd_COMMENT_START, CC_3rd_COMMENT_START, CC_REST_COMMENT_START,
-             m_charInfo);
-    }
-}
-/**
- * @brief Searches the prefix of <code>m_input</code> in the vector.
- *
- * @param tokenLength   the length of the prefix in <code>m_input</code>
- * @param vector        the vector to search. Each element contains the id
- *                      as last entry
- * @param id            the id of the entry in the vector. Only set if found
- * @return
- */
-int RplLexer::findInVector(int tokenLength, const StringList& vector)
-{
-    int id = 0;
-    int lbound = 0;
-    int ubound = vector.size() - 1;
-    // binary search over the sorted vector:
-    while(lbound <= ubound){
-        int half = (ubound + lbound) / 2;
-        int compareRc = 0;
-        int ix = 0;
-        const QByteArray& current = vector[half];
-        // vector items end with ' ' and id (2 byte):
-        int currentLength = current.size() - 3;
-        while(ix < tokenLength && compareRc == 0){
-            if (ix >= currentLength)
-                // current is shorter:
-                compareRc = 1;
-            else
-                compareRc = m_input.at(ix) - (int) current.at(ix);
-            ix++;
-        }
-        if (compareRc == 0 && current.at(ix) != ' ')
-            // token.size() < current.size():
-            compareRc = -1;
-        if (compareRc < 0)
-            ubound = half - 1;
-        else if (compareRc > 0)
-            lbound = half + 1;
-        else {
-            id = current[currentLength + 1] + current[currentLength + 2] * 256;
-            break;
-        }
-    }
-    return id;
-}
-/**
- * @brief Reads data until enough data are available for one token.
- *
- * Data will be read from the current source unit.
- * If this unit does not contain more data the next source unit from the stack
- * will be used until the stack is empty.
- *
- * @return  false: no more input is available<br>
- *          true: data are available
- */
-bool RplLexer::fillInput()
-{
-    if (m_hasMoreInput){
-        if (m_input.size() < m_maxTokenLength){
-            m_source->currentReader()->fillBuffer(m_maxTokenLength, m_input,
-                                                  m_hasMoreInput);
-        }
-    }
-
-    while (m_input.size() == 0 && m_source->currentReader() != NULL){
-        if (m_source->currentReader()->nextLine(m_maxTokenLength,
-                                                  m_input, m_hasMoreInput)){
-            m_currentCol = 0;
-        }
-    }
-    return m_input.size() > 0;
-}
-
-/**
- * @brief Finds a token with an id: TOKEN_OP, TOKEN_KEYWORD, ...
- *
- * @post    the token is removed from the input
- *
- * @param tokenType the token type
- * @param flag2     the flag of the 2nd char
- * @param names     the vector with the names, sorted
- * @return          NULL: not found<br>
- *                  otherwise: the token
- */
-RplToken* RplLexer::findTokenWithId(RplTokenType tokenType, int flag2,
-                                   StringList& names)
-{
-    int length = 1;
-    int inputLength = m_input.size();
-    int cc;
-    if (inputLength > 1){
-        cc = m_input[1];
-        if (cc < CHAR_INFO_SIZE && (m_charInfo[cc] & flag2)){
-            length++;
-            if (inputLength > 2){
-                cc = m_input[2];
-                // the 3rd char flag is the "successor" of the 2nd char flag:
-                int flag = (flag2 << 1);
-                if (cc < CHAR_INFO_SIZE && (m_charInfo[cc] & flag)){
-                    length++;
-                    // the rest char flag is the "successor" of the 3nd char flag:
-                    flag <<= 1;
-                    while (length < inputLength){
-                        cc = m_input[length];
-                        if (cc < CHAR_INFO_SIZE && (m_charInfo[cc] & flag))
-                            length++;
-                        else
-                            break;
-                    }
-                }
-            }
-        }
-    }
-    RplToken* rc = NULL;
-    if (! (tokenType == TOKEN_KEYWORD && length < inputLength
-            && (cc = m_input[length]) < CHAR_INFO_SIZE
-            && (m_charInfo[cc] & CC_REST_ID))) {
-        int id;
-        // the length could be too long: the CC_2nd_.. flag could be ambigous
-        while( (id = findInVector(length, names)) <= 0){
-            if (length == 1 || tokenType == TOKEN_KEYWORD){
-                break;
-            }
-            length--;
-        }
-        if (id > 0){
-            rc = m_currentToken;
-            rc->m_tokenType = tokenType;
-            rc->m_value.m_id = id;
-            if (tokenType == TOKEN_COMMENT_START
-                    && (m_storageFlags & STORE_COMMENT) != 0)
-                rc->m_string.append(m_input.mid(0, length));
-            m_input.remove(0, length);
-            m_currentCol += length;
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Converts the number into a token.
- *
- * @return  the token with the number
- */
-RplToken* RplLexer::scanNumber()
-{
-    int inputLength = m_input.size();
-    int cc;
-    int length;
-    quint64 value = 0;
-    if ( (cc = m_input[0]) == '0' && inputLength > 1
-            && (m_numericTypes & NUMTYPE_HEXADECIMAL)
-            && (m_input[1] == 'x' || m_input[1] == 'X')){
-        length = RplString::lengthOfUInt64(m_input.constData() + 2, 16, &value);
-        if (length > 0)
-            length += 2;
-        else
-            throw RplException("invalid hexadecimal number: no digit behind 'x");
-    } else if (cc == '0' && (m_numericTypes & NUMTYPE_OCTAL)
-               && inputLength > 1){
-        length = 1;
-        while (length < inputLength){
-            if ( (cc = m_input[length]) >= '0' && cc <= '7')
-                value = value * 8 + cc - '0';
-            else if (cc >= '8' && cc <= '9')
-                throw RplLexException(*m_currentPosition,
-                                      "invalid octal digit: %c", cc);
-            else
-                break;
-            length++;
-        }
-    } else {
-        length = 1;
-        value = cc - '0';
-        while (length < inputLength){
-            if ( (cc = m_input[length]) >= '0' && cc <= '9')
-                value = value * 10 + cc - '0';
-            else
-                break;
-            length++;
-        }
-    }
-    m_currentToken->m_value.m_integer = value;
-    m_currentToken->m_tokenType = TOKEN_NUMBER;
-    if (length + 1 < inputLength
-            && ((cc = m_input[length]) == '.' || toupper(cc) == 'E')){
-        qreal realValue;
-        int realLength = RplString::lengthOfReal(m_input.constData(), &realValue);
-        if (realLength > length){
-            m_currentToken->m_tokenType = TOKEN_REAL;
-            m_currentToken->m_value.m_real = realValue;
-            length = realLength;
-        }
-    }
-    m_input.remove(0, length);
-    m_currentCol += length;
-    return m_currentToken;
-}
-
-/**
- * @brief Reads a string into the internal data.
- * @return the token with the string
- */
-RplToken*RplLexer::scanString()
-{
-    int delim = m_input[0];
-    int inputLength = m_input.size();
-    int cc;
-    int length = 1;
-    m_currentToken->m_tokenType = TOKEN_STRING;
-    m_currentToken->m_value.m_id = delim;
-    bool again = false;
-    do {
-        while(length < inputLength && (cc = m_input[length]) != delim){
-            length++;
-            if (cc != '\\'
-                || (m_stringFeatures
-                    & (SF_C_ESCAPING | SF_C_HEX_CHARS | SF_C_SPECIAL)) == 0){
-                m_currentToken->m_string.append(QChar(cc));
-            } else {
-                if (length >= inputLength)
-                    throw RplLexException(*m_currentPosition,
-                        "backslash without following character");
-                cc = m_input[length++];
-                if ( (m_stringFeatures & SF_C_HEX_CHARS) && toupper(cc) == 'X'){
-                    if (length >= inputLength)
-                        throw RplLexException(*m_currentPosition,
-                            "missing hexadecimal digit behind \\x");
-                    cc = m_input[length++];
-                    int hexVal = RplQString::valueOfHexDigit(cc);
-                    if (hexVal < 0)
-                        throw RplLexException(*m_currentPosition,
-                            "not a hexadecimal digit behind \\x: %lc",
-                            QChar(cc));
-                    if (length < inputLength){
-                       cc = m_input[length];
-                       int nibble = RplQString::valueOfHexDigit(cc);
-                       if (nibble >= 0){
-                           length++;
-                           hexVal = hexVal * 16 + nibble;
-                       }
-                    }
-                    m_currentToken->m_string.append(QChar(hexVal));
-                } else if ( (m_stringFeatures & SF_C_SPECIAL)){
-                    switch(cc){
-                    case 'r':
-                        cc = '\r';
-                        break;
-                    case 'n':
-                        cc = '\n';
-                        break;
-                    case 't':
-                        cc = '\t';
-                        break;
-                    case 'a':
-                        cc = '\a';
-                        break;
-                    case 'v':
-                        cc = '\v';
-                        break;
-                    case 'f':
-                        cc = '\f';
-                        break;
-                    default:
-                        break;
-                    }
-                    m_currentToken->m_string.append(QChar(cc));
-                } else {
-                   m_currentToken->m_string.append(QChar(cc));
-                }
-            }
-        }
-        if (cc == delim){
-            length++;
-        }
-        if ( (m_stringFeatures & SF_DOUBLE_DELIM) && length < inputLength
-             && m_input[length] == (char) delim){
-            m_currentToken->m_printableString.append(delim);
-            length++;
-            again = true;
-        }
-    }
-    while(again);
-    if (m_storageFlags & STORE_ORG_STRING)
-        m_currentToken->m_printableString.append(m_input.mid(0, length));
-    m_input.remove(0, length);
-    m_currentCol += length;
-    return m_currentToken;
-}
-
-/**
- * @brief Reads a comment into the internal data.
- *
- * precondition: the current token is prepared yet
- */
-void RplLexer::scanComment()
-{
-    int inputLength = m_input.size();
-    int length = 1;
-    QByteArray& commentEnd = m_commentEnds[m_currentToken->id()];
-    int ix;
-    if (commentEnd[0] == '\n'){
-        // single line comment:
-        if (m_storageFlags & STORE_COMMENT)
-            m_currentToken->m_string.append(m_input);
-        length = inputLength;
-    } else {
-        // multiline comment:
-        while( (ix = m_input.indexOf(commentEnd)) < 0){
-            if (m_storageFlags & STORE_COMMENT)
-                m_currentToken->m_string.append(m_input);
-            m_input.clear();
-            if (! fillInput())
-                throw RplLexException(*m_currentPosition,
-                    "comment end not found");
-        }
-        length = ix + commentEnd.size();
-        if (m_storageFlags & STORE_COMMENT)
-            m_currentToken->m_string
-                    .append(m_input.mid(0, length));
-    }
-    m_input.remove(0, length);
-    m_currentCol += length;
-}
-#if defined (RPL_LEXER_TRACE)
-bool RplLexer::trace() const
-{
-    return m_trace;
-}
-
-void RplLexer::setTrace(bool trace)
-{
-    m_trace = trace;
-}
-#endif
-/**
- * @brief Returns the last read token.
- *
- * @return  the current token
- */
-RplToken* RplLexer::currentToken() const
-{
-    return m_currentToken;
-}
-
-/**
- * @brief Returns the current position.
- *
- * @return  the current source code position
- */
-const RplSourcePosition* RplLexer::currentPosition() const
-{
-    return m_currentPosition;
-}
-
-/**
- * @brief Returns the next token.
- *
- * @return the next token
- */
-RplToken* RplLexer::nextToken()
-{
-    RplToken* rc = NULL;
-    int ix;
-    if (m_waitingToken != NULL){
-        rc = m_currentToken = m_waitingToken;
-        m_waitingToken = m_waitingToken2;
-        m_waitingToken2 = NULL;
-        m_currentPosition = m_waitingPosition1;
-        m_waitingPosition1 = m_waitingPosition2;
-        m_waitingPosition2 = NULL;
-    } else {
-        m_currentToken->clear();
-        RplReader* reader = m_source->currentReader();
-        if (reader == NULL)
-            m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE;
-        else {
-            m_waitingPosition2 = m_waitingPosition1;
-            m_waitingPosition1 = m_currentPosition;
-            m_currentPosition = m_source->newPosition(m_currentCol);
-            if (! fillInput()){
-                m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE;
-            } else {
-                int cc = m_input.at(0);
-                if (isspace(cc)){
-                    //waitingPosition = m_currentPosition;
-                    m_currentToken->m_tokenType = TOKEN_SPACE;
-                    ix = 1;
-                    while(ix < m_input.size() && isspace(m_input.at(ix)))
-                        ix++;
-                    if (m_storageFlags & STORE_BLANK){
-                        m_currentToken->m_string.append(m_input.mid(0, ix));
-                    }
-                    m_currentCol += ix;
-                    m_input.remove(0, ix);
-                    rc = m_currentToken;
-                } else if (isdigit(cc)){
-                    rc = scanNumber();
-                } else if ( (cc == '"' && (m_stringFeatures & SF_QUOTE) != 0)
-                           || (cc == '\'' && (m_stringFeatures & SF_TICK) != 0)){
-                    rc = scanString();
-                } else {
-                    if (cc >= CHAR_INFO_SIZE)
-                        throw RplLexException(*m_currentPosition,
-                            "no lexical symbol can start with this char: %lc",
-                            cc);
-                    else
-                    {
-                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_COMMENT_START)){
-                            rc = findTokenWithId(TOKEN_COMMENT_START,
-                                                 CC_2nd_COMMENT_START, m_commentStarts);
-                            if (rc != NULL)
-                                scanComment();
-                            //waitingPosition = m_currentPosition;
-                        }
-
-                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_OP)){
-                            if ( (m_charInfo[cc] & CC_OP_1_ONLY) == 0){
-                                rc = findTokenWithId(TOKEN_OPERATOR,
-                                                 CC_2nd_OP, m_operators);
-                            } else {
-                                rc = m_currentToken;
-                                rc->m_tokenType = TOKEN_OPERATOR;
-                                rc->m_value.m_id = findInVector(1, m_operators);
-                                m_input.remove(0, 1);
-                                m_currentCol += 1;
-                            }
-                        }
-                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_KEYWORD)){
-                            rc = findTokenWithId(TOKEN_KEYWORD,
-                                                 CC_2nd_KEYWORD, m_keywords);
-                        }
-                        if (rc == NULL && (m_charInfo[cc] & CC_FIRST_ID)){
-                            int length = 1;
-                            while(length < m_input.size()
-                                && (cc = m_input[length]) < CHAR_INFO_SIZE
-                                    && (m_charInfo[cc] & CC_REST_ID) != 0)
-                                  length++;
-                            rc = m_currentToken;
-                            rc->m_tokenType = TOKEN_ID;
-                                  rc->m_string.append(m_input.mid(0, length));
-                            m_input.remove(0, length);
-                            m_currentCol += length;
-                        }
-
-                    }
-                }
-            }
-        }
-    }
-    if (rc == NULL || rc->tokenType() == TOKEN_UNDEF){
-        if (m_input.size() == 0){
-            rc = m_currentToken;
-            rc->m_tokenType = TOKEN_END_OF_SOURCE;
-        } else {
-            QByteArray symbol = m_input.mid(0, qMin(20, m_input.size()-1));
-            throw RplLexException(*m_currentPosition,
-                "unknown lexical symbol: %s", symbol.constData());
-        }
-    }
-#if defined (RPL_LEXER_TRACE)
-    if (m_trace){
-        char buffer[256];
-        printf("token: %s pos: %s\n", m_currentToken->dump().constData(),
-               m_currentPosition->utf8(buffer, sizeof buffer));
-        if (strstr(buffer, "0:28") != NULL)
-            buffer[0] = 0;
-    }
-#endif
-    return rc;
-}
-/**
- * @brief Reverses the last <code>nextToken()</code>.
- *
- * Makes that <code>nextToken()</code> returns the current token again.
- */
-void RplLexer::undoLastToken()
-{
-    m_waitingToken = m_currentToken;
-    m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
-    m_waitingPosition1 = m_currentPosition;
-#if defined (RPL_LEXER_TRACE)
-    if (m_trace){
-        char buffer[256];
-        printf("undo last token: waiting-token:  %s pos: %s\n",
-               m_waitingToken->dump().constData(),
-               m_waitingPosition1->utf8(buffer, sizeof buffer));
-        if (strcmp(buffer, "<test>:2:6") == 0)
-            buffer[0] = 0;
-    }
-#endif
-}
-
-/**
- * @brief Reverses the last <code>nextToken()</code>.
- *
- * Makes that <code>nextToken()</code> returns the current token again.
- */
-void RplLexer::undoLastToken2()
-{
-    m_waitingToken2 = m_currentToken;
-    m_waitingToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
-    m_waitingPosition2 = m_waitingPosition1;
-    m_waitingPosition1 = m_currentPosition;
-}
-
-/**
- * @brief Prevents the current token from data loss.
- *
- * Usage:
- * <pre><code>
- * token1 = nextToken();
- * saveLastToken();
- * token2 = nextToken();
- * </code></pre>
- * Then <code>token1</code> and <code>token2</code> contains the wanted content.
- */
-void RplLexer::saveLastToken()
-{
-    if (m_waitingToken == NULL)
-        m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
-}
-
-/**
- * @brief Returns the next relevant token, but the token remains "unread".
- *
- * @return the next token which is not a space/comment
- */
-RplToken*RplLexer::peekNonSpaceToken()
-{
-    RplToken* token = nextNonSpaceToken();
-    undoLastToken();
-    return token;
-}
-/**
- * @brief Returns the maximal length of a token
- * @return  the maximal length of a token
- */
-size_t RplLexer::maxTokenLength() const
-{
-    return m_maxTokenLength;
-}
-
-/**
- * @brief Sets the maximal length of a token
- *
- * @param maxTokenLength    the new maximal length of a token
- */
-void RplLexer::setMaxTokenLength(size_t maxTokenLength)
-{
-    m_maxTokenLength = maxTokenLength;
-}
-
-/**
- * @brief RplLexer::nextNonSpaceToken
- * @return
- */
-RplToken* RplLexer::nextNonSpaceToken()
-{
-    RplToken* rc = NULL;
-    RplTokenType type;
-    do{
-        rc = nextToken();
-    } while( (type = m_currentToken->tokenType()) == TOKEN_SPACE
-             || type == TOKEN_COMMENT_START || type == TOKEN_COMMENT_END
-             || type == TOKEN_COMMENT_REST_OF_LINE);
-    return rc;
-}
-
-/**
- * @brief Prepares a given source unit for reading.
- *
- * Saves the current source position onto the top of stack.
- * Pushes the source unit onto the top of stack.
- *
- * Precondition: the unit must be known by exactly one reader
- *
- * @param unit  the new source unit
- */
-void RplLexer::startUnit(RplSourceUnitName unit)
-{
-    m_source->startUnit(unit, *m_currentPosition);
-}
-/**
- * @brief Returns the source of the instance.
- *
- * @return  the source of the instance
- */
-RplSource* RplLexer::source()
-{
-    return m_source;
-}
-
-/**
- * @brief Returns the priority of a given operator.
- *
- * @param op    the operator
- * @return      the priority of the op
- */
-int RplLexer::prioOfOp(int op) const
-{
-    int rc = op > 0 && (unsigned) op < sizeof m_prioOfOp / sizeof m_prioOfOp[0]
-            ? m_prioOfOp[op] : 0;
-    return rc;
-}
-
-/**
- * @brief Returns the name of an operator.
- *
- * @param op    the operator id
- * @return      the name of the operator
- */
-const QByteArray&RplLexer::nameOfOp(int op) const
-{
-    const QByteArray& rc = m_opNames.at(op);
-    return rc;
-}
-
-/**
- * @brief Returns whether an operator is right associative
- * @param op    op to test
- * @return      true: the operator is right associative<br>
- *              false: otherwise
- */
-bool RplLexer::isRightAssociative(int op) const
-{
-    bool rc = false;
-    if (op >= 0 && (unsigned) op < sizeof m_assocOfOp / sizeof m_assocOfOp[0]){
-        rc = m_assocOfOp[op];
-    }
-    return rc;
-}
-
-
diff --git a/rplexpr/rpllexer.hpp b/rplexpr/rpllexer.hpp
deleted file mode 100644 (file)
index cf27d9b..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLLEXER_HPP
-#define RPLLEXER_HPP
-
-//#define RPL_LEXER_TRACE
-
-enum RplTokenType {
-    TOKEN_UNDEF,
-    TOKEN_STRING,
-    TOKEN_NUMBER,
-    TOKEN_REAL,
-    TOKEN_KEYWORD,
-    TOKEN_OPERATOR,
-    TOKEN_ID,
-    TOKEN_COMMENT_REST_OF_LINE,
-    TOKEN_COMMENT_START,
-    TOKEN_COMMENT_END,
-    TOKEN_SPACE,
-    TOKEN_END_OF_SOURCE,
-    TOKEN_COUNT
-};
-
-class RplLexException : public RplException {
-public:
-    RplLexException(const RplSourcePosition& position, const char* message, ...);
-};
-
-class RplLexer;
-
-class RplToken {
-public:
-    RplToken(RplTokenType type);
-    ~RplToken();
-    RplToken(const RplToken& source);
-    RplToken& operator =(const RplToken& source);
-public:
-    friend class RplLexer;
-    const QByteArray& toString();
-    bool isInteger();
-    int asInteger() const;
-    quint64 asUInt64() const;
-    qreal asReal() const;
-    const QByteArray& rawString() const;
-    int id() const;
-    RplTokenType tokenType() const;
-    bool isTokenType(RplTokenType expected) const;
-    bool isOperator(int expected, int alternative = 0) const;
-    bool isKeyword(int expected, int alternative = 0) const;
-    void clear();
-    bool isCapitalizedId() const;
-    QByteArray dump() const;
-    static const char* nameOfType(RplTokenType type);
-    QByteArray asUtf8() const;
-protected:
-    RplTokenType m_tokenType;
-    QByteArray m_string;
-    // only for TOKEN_STRING: copy from source but with escaped chars like "\\n"
-    QByteArray m_printableString;
-    union {
-        // only for TOKEN_KEYWORD and TOKEN_OPERATOR
-        int m_id;
-        quint64 m_integer;
-        qreal m_real;
-    } m_value;
-};
-
-
-class RplSource;
-class RplLexer
-{
-public:
-    typedef QList<QByteArray> StringList;
-    enum NumericType {
-        NUMTYPE_UNDEF,
-        NUMTYPE_DECIMAL     = 1 << 0,
-        NUMTYPE_OCTAL       = 1 << 1,
-        NUMTYPE_HEXADECIMAL = 1 << 2,
-        NUMTYPE_FLOAT       = 1 << 3,
-        ///
-        NUMTYPE_ALL_INTEGER = NUMTYPE_DECIMAL | NUMTYPE_OCTAL |NUMTYPE_HEXADECIMAL,
-        NUMTYPE_ALL         = NUMTYPE_ALL_INTEGER | NUMTYPE_FLOAT
-    };
-    enum CharClassTag {
-        CC_UNDEF                = 0,
-        /// this char is possible as first char of an id
-        CC_FIRST_ID             = 1 << 0,
-        /// this char is possible as 2nd char of an id
-        CC_2nd_ID               = 1 << 1,
-        /// this char is possible as 3rd char of an id
-        CC_3rd_ID               = 1 << 2,
-        /// this char is possible as 4th... char of an id
-        CC_REST_ID              = 1 << 3,
-        /// this char can start a comment
-        CC_FIRST_COMMENT_START  = 1 << 4,
-        /// this char can be the 2nd char of a comment start
-        CC_2nd_COMMENT_START    = 1 << 5,
-        /// this char can be the 3rd char of a comment start
-        CC_3rd_COMMENT_START    = 1 << 6,
-        /// this char can be the 4th ... of a comment start
-        CC_REST_COMMENT_START   = 1 << 7,
-        /// this char can start a keyword
-        CC_FIRST_KEYWORD        = 1 << 8,
-        /// this char can be the 2nd char of a keyword
-        CC_2nd_KEYWORD          = 1 << 9,
-        /// this char can be the 3rd char of a keyword
-        CC_3rd_KEYWORD          = 1 << 10,
-        /// this char can be the 4th... char of a keyword
-        CC_REST_KEYWORD         = 1 << 11,
-        /// this char can be the 1st char of an operator
-        CC_FIRST_OP             = 1 << 12,
-        /// this char can be the 2nd char of an operator
-        CC_2nd_OP               = 1 << 13,
-        /// this char can be the 3rd char of an operator
-        CC_3rd_OP               = 1 << 14,
-        /// this char can be the 4th... char of an operator
-        CC_REST_OP              = 1 << 15,
-        /// there is an operator with exactly this char
-        /// and there is no other operator starting with this char
-        CC_OP_1_ONLY            = 1 << 16
-    };
-    enum StringFeatures {
-        SF_UNDEF,
-        /// ' can be a string delimiter
-        SF_TICK         = 1 << 1,
-        /// " can be a string delimiter
-        SF_QUOTE        = 1 << 2,
-        /// character escaping like in C: "\x" is "x"
-        SF_C_ESCAPING   = 1 << 3,
-        /// special characters like in C: "\r" "\f" "\n" "\t" "\a"
-        SF_C_SPECIAL    = 1 << 4,
-        /// characters can be written in hexadecimal notation: "\x20" is " "
-        SF_C_HEX_CHARS  = 1 << 5,
-        /// A delimiter inside a string must be doubled (like in Pascal)
-        SF_DOUBLE_DELIM = 1 << 6,
-        // Redefinitions for better reading:
-        SF_LIKE_C       = SF_TICK | SF_QUOTE | SF_C_ESCAPING | SF_C_SPECIAL
-                            | SF_C_HEX_CHARS
-    };
-    enum StorageFlags {
-        S_UNDEF,
-        /// the original string will be stored in m_string too
-        /// (not only m_rawString)
-        STORE_ORG_STRING    = 1 << 1,
-        /// comments will be stored in m_string
-        STORE_COMMENT       = 1 << 2,
-        /// blanks will be stored in m_string
-        STORE_BLANK         = 1 << 3,
-        /// redefinitions for better reading:
-        STORE_NOTHING       = 0,
-        STORE_ALL           = STORE_ORG_STRING | STORE_COMMENT | STORE_BLANK
-    };
-
-public:
-    RplLexer(RplSource* source,
-        const char* keywords,
-        const char* operators,
-        const char* rightAssociatives,
-        const char* comments,
-        const char* firstCharsId = "a-zA-Z_",
-        const char* restCharsId = "a-zA-Z0-9_",
-        int numericTypes = NUMTYPE_DECIMAL | NUMTYPE_HEXADECIMAL | NUMTYPE_FLOAT,
-        int stringFeatures = SF_TICK | SF_QUOTE | SF_C_ESCAPING | SF_C_SPECIAL
-            | SF_C_HEX_CHARS,
-        int storageFlags = STORE_NOTHING);
-    virtual ~RplLexer();
-public:
-    RplToken* nextToken();
-    void undoLastToken();
-    void undoLastToken2();
-    void saveLastToken();
-    RplToken* peekNonSpaceToken();
-    RplToken* nextNonSpaceToken();
-    size_t maxTokenLength() const;
-    void setMaxTokenLength(size_t maxTokenLength);
-    void startUnit(RplSourceUnitName unit);
-    RplSource* source();
-    int prioOfOp(int op) const;
-    const QByteArray& nameOfOp(int op) const;
-    bool isRightAssociative(int op) const;
-    const RplSourcePosition* currentPosition() const;
-    RplToken* currentToken() const;
-#if defined RPL_LEXER_TRACE
-    bool trace() const;
-    void setTrace(bool trace);
-#endif
-private:
-    void prepareOperators(const char* operators, const char* rightAssociatives);
-    void initializeComments(const char* comments);
-    bool fillInput();
-    int findInVector(int tokenLength, const StringList& vector);
-    RplToken* findTokenWithId(RplTokenType tokenType, int flag2,
-                              StringList& names);
-    RplToken* scanNumber();
-    RplToken* scanString();
-    void scanComment();
-protected:
-    RplSource* m_source;
-    /// sorted, string ends with the id of the keyword
-    StringList m_keywords;
-    // sorted, string ends with the id of the operator
-    StringList m_operators;
-    // sorted, each entry ends with the id of the comment start
-    StringList m_commentStarts;
-    // index: id content: comment_end
-    StringList m_commentEnds;
-    // index: ord(char) content: a sum of CharClassTags
-    int m_charInfo[128];
-    // a list of QChars with ord(cc) > 127 and which can be the first char
-    QByteArray m_idFirstRare;
-    // index: ord(char) content: chr(ix) can be the non first char of an id
-    QByteArray m_idRestRare;
-    // a list of QChars with ord(cc) > 127 and which can be the first char
-    int m_numericTypes;
-    QByteArray m_idRest2;
-    RplToken* m_currentToken;
-    RplToken* m_waitingToken;
-    RplToken* m_waitingToken2;
-    RplToken m_token1;
-    RplToken m_token2;
-    const RplSourcePosition* m_currentPosition;
-    const RplSourcePosition* m_waitingPosition1;
-    const RplSourcePosition* m_waitingPosition2;
-    int m_maxTokenLength;
-    QByteArray m_input;
-    int m_currentCol;
-    bool m_hasMoreInput;
-    int m_stringFeatures;
-    int m_storageFlags;
-    /// priority of the operators: index: id of the operator. content: prio
-    char m_prioOfOp[128];
-    char m_assocOfOp[128];
-    QList<QByteArray> m_opNames;
-#if defined (RPL_LEXER_TRACE)
-    bool m_trace;
-#endif
-};
-
-
-#endif // RPLLEXER_HPP
diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp
deleted file mode 100644 (file)
index 9f3f5ec..0000000
+++ /dev/null
@@ -1,1286 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief A parser for the language <b>ML</b>.
- */
-/** @file
- * @brief Definition for a parser for the language <b>ML</b>.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-
-enum MFLocations{
-    L_PARSE_OPERAND_RPARENTH = 2001,
-    L_PARSE_OPERAND_RPARENTH_INFO,
-    L_TERM_WRONG_STRING,
-    L_TERM_WRONG_NUMBER,
-    L_PARSE_OPERAND_WRONG   = 2005,
-    L_DEFINITION_NO_ID,
-    L_DEFINITION_WRONG_ID,
-    L_DEFINITION_UNKNOWN_CLASS,
-    L_DEFINITION_MISSING_ID,
-    L_DEFINITION_NO_OP      = 2010,
-    L_DEFINITION_NO_SEMICOLON,
-    L_PARSE_IF_NO_THEN,
-    L_PARSE_IF_NO_ELSE,
-    L_PARSE_IF_NO_FI,
-    L_PARSE_WHILE_NO_DO     = 2015,
-    L_PARSE_WHILE_NO_OD,
-    L_PARSE_REPEAT_NO_UNTIL,
-    L_PARSE_REPEAT_NO_SEMI,
-    L_PARSE_BODY_WRONG_ITEM,
-    L_PARSE_FOR_NO_TO       = 2020,
-    L_PARSE_LIST_NO_COMMA,
-    L_PARSE_MAP_BOOL,
-    L_PARSE_MAP_NONE,
-    L_PARSE_MAP_NUMERIC,
-    L_PARSE_MAP_EXPR        = 2025,
-    L_PARSE_MAP_EXPR2,
-    L_PARSE_MAP_NO_COLON,
-    L_PARSE_MAP_NO_COMMA,
-    L_PARSE_OPERAND_NOT_OPERAND = 2030,
-    L_PARSE_BODY_NO_START,
-    L_PARSE_OPERAND_NO_BRACKET,
-    L_PARSE_ARGS_NO_COMMA_OR_PARENT,
-    L_PARSE_OPERAND_NO_FIELD2,
-    L_PARSE_OPERAND_NO_BRACKET2 = 2035,
-    L_PARSE_OPERAND_NO_FIELD,
-    L_PARSE_METH_NO_CLASS,
-    L_PARSE_METH_NO_CLASS2,
-    L_PARSE_METH_NO_NAME,
-    L_PARSE_METH_NO_NAME2   = 2040,
-    L_PARSE_METH_NO_LPARENTH,
-    L_PARSE_METH_NO_COLON,
-    L_PARSE_PARAMLIST_NO_PARENTH,
-    L_PARSE_PARAMLIST_NO_PARENTH2,
-    L_PARSE_METH_NO_END     = 2045,
-    L_PARSE_METH_NO_END2,
-    L_PARSE_VAR_DEF_ALREADY_DEFINED,
-    L_PARSE_VAR_DEF_ALREADY_DEFINED2,
-    L_PARSE_CLASS_NO_NAME,
-    L_PARSE_CLASS_LOWERCASE = 2050,
-    L_PARSE_CLASS_ALREADY_DEFINED,
-    L_PARSE_CLASS_ALREADY_DEFINED2
-
-};
-
-/** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
- *
- * @brief Implements a parser for the language MF.
- *
- * MF stands for Mathe Fan or Multiple Faces or ....
- * This is an universal object oriented programming language with extension
- * for matrix operations, simulation and graphics.
- */
-
-RplMFParser::RplMFParser(RplSource& source, RplASTree& abstractSyntaxTree) :
-    RplParser(m_lexer, abstractSyntaxTree),
-    m_lexer(&source,
-            MF_KEYWORDS, MF_OPERATORS, MF_RIGHT_ASSOCIATIVES,
-            "/* */ // \n",
-            "a-zA-Z_", "a-zA-Z0-9_",
-            RplLexer::NUMTYPE_ALL, RplLexer::SF_LIKE_C)
-{
-}
-
-/**
- * @brief Parses an if statement.
- */
-RplASItem* RplMFParser::parseIf()
-{
-    RplASIf* rc = new RplASIf();
-    rc->setPosition(m_lexer.currentPosition());
-
-    RplASItem* condition = parseExpr(0);
-    if (! m_lexer.currentToken()->isKeyword(K_THEN))
-        syntaxError(L_PARSE_IF_NO_THEN, "'then' expected");
-    rc->setChild2(condition);
-    RplASItem* body = parseBody(K_ELSE, K_FI);
-    rc->setChild3(body);
-    if (! m_lexer.currentToken()->isKeyword(K_ELSE, K_FI))
-        syntaxError(L_PARSE_IF_NO_ELSE, "'else' or 'fi' expected");
-    if ( m_lexer.currentToken()->isKeyword(K_ELSE)){
-        RplASItem* body = parseBody(K_FI);
-        rc->setChild4(body);
-    }
-    if (! m_lexer.currentToken()->isKeyword(K_FI))
-        syntaxError(L_PARSE_IF_NO_FI, "'fi' expected");
-    m_lexer.nextNonSpaceToken();
-    return rc;
-}
-/**
- * @brief Parses a while statement.
- */
-
-RplASItem* RplMFParser::parseWhile()
-{
-    RplASWhile* rc = new RplASWhile();
-    rc->setPosition(m_lexer.currentPosition());
-
-    RplASItem* condition = parseExpr(0);
-    if (! m_lexer.currentToken()->isKeyword(K_DO))
-        syntaxError(L_PARSE_WHILE_NO_DO, "'do' expected");
-    rc->setChild2(condition);
-    RplASItem* body = parseBody(K_OD);
-    rc->setChild3(body);
-    if (! m_lexer.currentToken()->isKeyword(K_OD))
-        syntaxError(L_PARSE_WHILE_NO_OD, "'od'  expected");
-    m_lexer.nextNonSpaceToken();
-    return rc;
-}
-
-/**
- * @brief Parses a repeat statement.
- */
-RplASItem* RplMFParser::parseRepeat()
-{
-    RplASRepeat* rc = new RplASRepeat();
-    rc->setPosition(m_lexer.currentPosition());
-
-    RplASItem* body = parseBody(K_UNTIL);
-    rc->setChild3(body);
-    if (! m_lexer.currentToken()->isKeyword(K_UNTIL))
-        syntaxError(L_PARSE_REPEAT_NO_UNTIL, "'until'  expected");
-
-    RplASItem* condition = parseExpr(0);
-    if (! m_lexer.currentToken()->isOperator(O_SEMICOLON))
-        syntaxError(L_PARSE_REPEAT_NO_SEMI, "';' expected");
-    rc->setChild2(condition);
-    m_lexer.nextNonSpaceToken();
-    return rc;
-}
-
-/**
- * @brief Creates a variable definition for a builtin variable.
- * @param var   the basic variable data
- * @return
- */
-RplASVarDefinition* RplMFParser::buildVarDef(RplASNamedValue* var)
-{
-    RplASVarDefinition* rc = new RplASVarDefinition();
-    rc->setPosition(var->position());
-    rc->setChild2(var);
-    RplSymbolSpace* symbols = m_tree.currentSpace();
-    int varNo;
-    symbols->addVariable(rc, varNo);
-    var->setVariableNo(varNo);
-    return rc;
-}
-
-/**
- * @brief Parses a for statement.
- *
- * Syntax:
- * for [ VAR ] [ from START_EXPR ] to END_EXPR [ step STEP_EXPR ] do
- * BODY od
- *
- * for VAR in ITERABLE_EXPR do BODY od
- *
- * @post            the token behind the do is read
- * @return          the abstract syntax tree of the for statement
- */
-RplASItem* RplMFParser::parseFor()
-{
-    int builtinVars = 1;
-    RplASNode2* rc = NULL;
-    const RplSourcePosition* startPosition = m_lexer.currentPosition();
-    RplToken* token = m_lexer.nextNonSpaceToken();
-    RplASNamedValue* var = NULL;
-    if (token->isTokenType(TOKEN_ID)){
-        var = new RplASNamedValue(RplASInteger::m_instance,
-                                  m_tree.currentSpace(), token->toString(),
-                                  RplASNamedValue::A_LOOP);
-        var->setPosition(m_lexer.currentPosition());
-        token = m_lexer.nextNonSpaceToken();
-    }
-    if (token->isKeyword(K_IN)){
-        RplASVarDefinition* varDef = buildVarDef(var);
-        RplASForIterated* node = new RplASForIterated(varDef);
-        rc = node;
-        node->setPosition(startPosition);
-        node->setChild3(var);
-        RplASItem* iterable = parseExpr(0);
-        node->setChild4(iterable);
-    } else {
-        if (var == NULL){
-            char name[32];
-            // Build a unique name inside the scope:
-            qsnprintf(name, sizeof name, "$%d_%d", startPosition->lineNo(),
-                      startPosition->column());
-            var = new RplASNamedValue(RplASInteger::m_instance,
-                                      m_tree.currentSpace(), name,
-                                      RplASNamedValue::A_LOOP);
-            var->setPosition(startPosition);
-        }
-        RplASVarDefinition* varDef = buildVarDef(var);
-        RplASForCounted* node = new RplASForCounted(varDef);
-        rc = node;
-        node->setPosition(startPosition);
-        node->setChild3(var);
-        if (token->isKeyword(K_FROM)){
-            node->setChild4(parseExpr(0));
-        }
-        if (! m_lexer.currentToken()->isKeyword(K_TO)){
-            syntaxError(L_PARSE_FOR_NO_TO, "'to' expected");
-        }
-        node->setChild5(parseExpr(0));
-        if (m_lexer.currentToken()->isKeyword(K_STEP)){
-            node->setChild6(parseExpr(0));
-        }
-    }
-    if (! m_lexer.currentToken()->isKeyword(K_DO))
-        syntaxError(L_PARSE_FOR_NO_TO, "'to' expected");
-    rc->setChild2(parseBody(K_OD, K_UNDEF, builtinVars));
-    m_lexer.nextNonSpaceToken();
-    return rc;
-}
-
-/**
- * @brief Parses a variable definition.
- *
- * Syntax:
- * Variable: { "const" | "lazy" }* TYPE id [ = EXPR ] [ ";" ]
- * Parameter: { "const" | "lazy" }* TYPE id [ = EXPR ] { "," | ")" }
- *
- * @pre             first token of the definition is read
- * @post            token behind the definition is read: ';', ',', ')'
- * @param attribute attribute of the variable: A_PARAM...
- * @return          a variable/parameter definition
- */
-RplASVarDefinition* RplMFParser::parseVarDefinition(
-        RplASNamedValue::Attributes attribute)
-{
-    int attributes = attribute;
-    RplToken* token = m_lexer.currentToken();
-    while(token->isKeyword(K_CONST, K_LAZY)){
-        switch(token->id()){
-        case K_CONST:
-            attributes += RplASNamedValue::A_CONST;
-            break;
-        case K_LAZY:
-            attributes += RplASNamedValue::A_LAZY;
-            break;
-        default:
-            break;
-        }
-        token = m_lexer.nextNonSpaceToken();
-    }
-    if (! token->isTokenType(TOKEN_ID))
-        syntaxError(L_DEFINITION_NO_ID, "class name expected, but no id found");
-    if (! token->isCapitalizedId())
-        syntaxError(L_DEFINITION_WRONG_ID,
-                    "a class name must start with an upper case character");
-    RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString());
-    if (clazz == NULL)
-        syntaxError(L_DEFINITION_UNKNOWN_CLASS, "unknown class");
-    token = m_lexer.nextNonSpaceToken();
-    if (! token->isTokenType(TOKEN_ID))
-        syntaxError(L_DEFINITION_MISSING_ID, "variable name expected");
-    RplSymbolSpace* symbols = m_tree.currentSpace();
-    // freed in the destructor of the nodes:
-    RplASNamedValue* namedValue = new RplASNamedValue(clazz, symbols,
-                                                      token->toString(),
-                                                      attributes);
-    namedValue->setPosition(m_lexer.currentPosition());
-    RplASVarDefinition* rc = new RplASVarDefinition();
-    rc->setPosition(m_lexer.currentPosition());
-    rc->setChild2(namedValue);
-    token = m_lexer.nextNonSpaceToken();
-    if (token->id() == O_ASSIGN){
-        RplASItem* value = parseExpr(0);
-        rc->setChild3(value);
-        token = m_lexer.currentToken();
-    }
-    int varNo = 0;
-    RplASItem* oldSymbol = symbols->addVariable(rc, varNo);
-    if (oldSymbol != NULL)
-        error(L_PARSE_VAR_DEF_ALREADY_DEFINED, oldSymbol->position(),
-              "symbol already defined", "previous definition");
-    namedValue->setVariableNo(varNo);
-    return rc;
-}
-
-/**
- * @brief Reads the current tokens as an formula and returns the variant.
- *
- * @post            the token behind the formula is read
- * @param parent    the parent for the formula: because of the destroying
- *                  the new expression is chained into the parent
- * @return          the variant containing the formula
- */
-RplASVariant* RplMFParser::createFormula(RplASNode1* parent)
-{
-    RplASVariant* variant = NULL;
-    m_lexer.undoLastToken2();
-    RplASExprStatement* expr = dynamic_cast<RplASExprStatement*>
-            (parseExprStatement(false));
-    if (expr != NULL){
-        // chaining per m_child (= next statement) is for freeing while destruction:
-        expr->setChild(parent->child());
-        parent->setChild(expr);
-        // freed in the destructor of varList (~RplASVariant()):
-        variant = new RplASVariant();
-        variant->setObject(expr, RplASFormula::m_instance);
-    }
-    return variant;
-}
-
-/**
- * @brief Converts the current expression into a <code>RplASVariant</code>.
- *
- * If the expression is a constant, the constant value will be the content
- * of the variant. Otherwise a formula will be stored.
- *
- * @pre                 the first token of the variant expression is read
- * @post                the token behind the variant expression is read
- * @param token         the token to convert
- * @param endsWithComma true: the 2nd token is a ','
- * @param parent        the parent node of the expression
- * @return              the variant with the token's content
- */
-RplASVariant* RplMFParser::tokenToVariant(RplToken* token,
-        bool endsWithComma, RplASNode1* parent)
-{
-    RplASVariant* variant = NULL;
-    if (endsWithComma){
-        switch(token->tokenType()){
-        case TOKEN_NUMBER:
-            // freed in the destructor of varList (~RplASVariant()):
-            variant = new RplASVariant();
-            variant->setInt(token->asInteger());
-            break;
-        case TOKEN_STRING:
-            // freed in the destructor of varList (~RplASVariant()):
-            variant = new RplASVariant();
-            variant->setString(token->toString());
-            break;
-        case TOKEN_REAL:
-            // freed in the destructor of varList (~RplASVariant()):
-            variant = new RplASVariant();
-            variant->setFloat(token->asReal());
-            break;
-        case TOKEN_KEYWORD:
-            switch(token->id()){
-            case K_TRUE:
-            case K_FALSE:
-                // freed in the destructor of varList (~RplASVariant()):
-                variant = new RplASVariant();
-                variant->setBool(token->id() == K_TRUE);
-                break;
-            case K_NONE:
-                // freed in the destructor of varList (~RplASVariant()):
-                variant = new RplASVariant();
-                break;
-            default:
-                break;
-            }
-            break;
-        default:
-            break;
-        }
-    }
-    if (variant == NULL)
-        variant = createFormula(parent);
-    return variant;
-}
-
-/**
- * @brief Parses a list.
- *
- * Syntax:<br>
- * '[' [ EXPR_1 [ ',' EXPR_2 ...]] ']'
- *
- * @pre    '[' is the current token
- * @post   the token behind the ']' is read
- * @return a node of the abstract syntax tree
- */
-RplASItem* RplMFParser::parseList()
-{
-    RplASListConstant* rc = new RplASListConstant();
-    RplASVariant& varList = rc->value();
-    RplASListOfVariants* list = static_cast<RplASListOfVariants*>
-            (varList.asObject(NULL));
-    rc->setPosition(m_lexer.currentPosition());
-    RplASVariant* variant;
-    bool again = true;
-    RplToken* token;
-    RplToken* token2;
-    // read the token behind '[':
-    token = m_lexer.nextNonSpaceToken();
-    if (token->isOperator(O_RBRACKET)){
-        // read token behind ']':
-        m_lexer.nextNonSpaceToken();
-    } else{
-        while(again){
-            m_lexer.saveLastToken();
-            token2 = m_lexer.nextNonSpaceToken();
-            variant = tokenToVariant(token, token2->isOperator(O_COMMA), rc);
-            token = m_lexer.currentToken();
-            if (token->isOperator(O_RBRACKET))
-                again = false;
-            else if (! token->isOperator(O_COMMA))
-                syntaxError(L_PARSE_LIST_NO_COMMA, "',' or ']' expected");
-            // read token behind ',' or ']'
-            token = m_lexer.nextNonSpaceToken();
-            if (variant != NULL)
-                list->append(variant);
-        }
-    }
-    return rc;
-}
-
-
-/**
- * @brief Parses a map.
- *
- * Syntax:<br>
- * '{' [ STRING_EXPR_1 ':' EXPR_1 [ ',' STRING_EXPR_2 ': EXPR_2 ...]] '}'
- *
- * @pre    '{' is the current token
- * @post   the token behind the '}' is read
- * @return a node of the abstract syntax tree
- */
-RplASItem* RplMFParser::parseMap()
-{
-    RplASMapConstant* rc = new RplASMapConstant();
-    RplASVariant& varMap = rc->value();
-    RplASMapOfVariants* map = static_cast<RplASMapOfVariants*>
-            (varMap.asObject(NULL));
-    rc->setPosition(m_lexer.currentPosition());
-    RplASVariant* variant;
-    bool again = true;
-    RplToken* token;
-    RplToken* token2;
-    QByteArray key;
-    while(again){
-        token = m_lexer.nextNonSpaceToken();
-        if (token->isOperator(O_RBRACE))
-            again = false;
-        else{
-            key.clear();
-            switch(token->tokenType()){
-            case TOKEN_STRING:
-                // freed in the destructor of varList (~RplASVariant()):
-                key = token->toString();
-                break;
-            case TOKEN_KEYWORD:
-                switch(token->id()){
-                case K_TRUE:
-                case K_FALSE:
-                    syntaxError(L_PARSE_MAP_BOOL,
-                        "boolean value not allowed as key type. Use a string");
-                    break;
-                case K_NONE:
-                    syntaxError(L_PARSE_MAP_NONE,
-                        "'none' is  not allowed as key type. Use a string");
-                    break;
-                default:
-                    syntaxError(L_PARSE_MAP_EXPR,
-                        "a non constant expression is  not allowed as key type. Use a string");
-                    break;
-                }
-                break;
-            case TOKEN_NUMBER:
-            case TOKEN_REAL:
-                syntaxError(L_PARSE_MAP_NUMERIC,
-                    "numeric values not allowed as key type. Use a string");
-                break;
-            default:
-                syntaxError(L_PARSE_MAP_EXPR2,
-                    "a non constant expression is  not allowed as key type. Use a string");
-                break;
-            }
-            token = m_lexer.nextNonSpaceToken();
-            if (! token->isOperator(O_COLON)){
-                syntaxError(L_PARSE_MAP_NO_COLON, "':' expected");
-            } else {
-                token = m_lexer.nextNonSpaceToken();
-                m_lexer.saveLastToken();
-                token2 = m_lexer.nextNonSpaceToken();
-                variant = tokenToVariant(token, token2->isOperator(O_COMMA), rc);
-                (*map)[key] = variant;
-                variant = NULL;
-                token = m_lexer.currentToken();
-                if (token->isOperator(O_RBRACE))
-                    again = false;
-                else if (! token->isOperator(O_COMMA))
-                    syntaxError(L_PARSE_MAP_NO_COMMA, "',' or '}' expected");
-            }
-        }
-    }
-    m_lexer.nextNonSpaceToken();
-    return rc;
-}
-
-/**
- * @brief Builds a node of a variable or a field (as an operand).
- *
- * @param name      name of the variable/field
- * @param position  source position
- * @param parent    NULL: result is a variable
- *
- * @return          a <code>RplASNamedValue</code> or a
- *                  <code>RplASNamedValue</code> instance
- */
-RplASItem* RplMFParser::buildVarOrField(const QByteArray& name,
-    const RplSourcePosition* position, RplASItem* parent)
-{
-    RplASItem* rc = NULL;
-    if (parent == NULL){
-        RplSymbolSpace* space = m_tree.currentSpace();
-        RplASVarDefinition* var = space->findVariable(name);
-        RplASClass* clazz = NULL;
-        if (var != NULL)
-            clazz = var->clazz();
-        RplASNamedValue* var2 = new RplASNamedValue(clazz, space,
-                                                   name, RplASNamedValue::A_NONE);
-        var2->setPosition(position);
-        rc = var2;
-    } else {
-        RplASField* field = new RplASField(name);
-        field->setPosition(position);
-        rc = field;
-        field->setChild(parent);
-    }
-    return rc;
-}
-/**
- * @brief Converts a MF specific unary operator into one of AST.
- *
- * @param op    operator known by MF parser
- *
- * @return      operator known by the abstract syntax tree
- */
-RplASUnaryOp::UnaryOp RplMFParser::convertUnaryOp(int op)
-{
-    RplASUnaryOp::UnaryOp rc;
-    switch(op){
-    case O_PLUS:
-        rc = RplASUnaryOp::UOP_PLUS;
-        break;
-    case O_MINUS:
-        rc = RplASUnaryOp::UOP_MINUS_INT;
-        break;
-    case O_NOT:
-        rc = RplASUnaryOp::UOP_NOT_BOOL;
-        break;
-    case O_BIT_NOT:
-        rc = RplASUnaryOp::UOP_NOT_INT;
-        break;
-    case O_INC:
-        rc = RplASUnaryOp::UOP_INC;
-        break;
-    case O_DEC:
-        rc = RplASUnaryOp::UOP_DEC;
-        break;
-    default:
-        throw RplException("unknown unary operator %d", op);
-        break;
-    }
-    return rc;
-}
-
-/**
- * @brief Parses an operand.
- *
- * An operand is the first and the third part of a binary operation.
- * Examples: constant, variable, method call, an expression in parentheses
- *
- * @post    the token behind the operand is read
- * @return  the node with the operand
- */
-RplASItem* RplMFParser::parseOperand(int level, RplASItem* parent)
-{
-    RplToken* token = m_lexer.nextNonSpaceToken();
-    const RplSourcePosition* startPosition = m_lexer.currentPosition();
-    RplASItem* rc = NULL;
-    bool readNext = true;
-    switch(token->tokenType()){
-    case TOKEN_OPERATOR:
-    {
-        Operator opId = (Operator) token->id();
-        if (parent != NULL && opId != O_LBRACKET)
-            syntaxError(L_PARSE_OPERAND_NO_FIELD,
-                    "field expected (behind a '.')");
-        if (opId == O_LBRACKET){
-            if (parent == NULL){
-                rc = parseList();
-                readNext = false;
-            } else {
-                RplASIndexedValue* value = new RplASIndexedValue();
-                value->setPosition(startPosition);
-                value->setChild(parent);
-                rc = value;
-                value->setChild2(parseExpr(level + 1));
-                if (! m_lexer.currentToken()->isOperator(O_RBRACKET))
-                    syntaxError(L_PARSE_OPERAND_NO_BRACKET2,
-                                "']' expected");
-            }
-        } else if (opId == O_LBRACE){
-            rc = parseMap();
-            readNext = false;
-        } else if (opId == O_LPARENTH){
-            rc = parseExpr(level + 1);
-            token = m_lexer.currentToken();
-            if(! token->isOperator(O_RPARENTH)){
-                // this call never comes back (exception!)
-                syntaxError(L_PARSE_OPERAND_RPARENTH,
-                            "')' expected", "(", startPosition);
-            }
-        } else if (IS_UNARY_OP(opId)){
-            RplASUnaryOp* op = new RplASUnaryOp(convertUnaryOp(token->id()),
-                                                AST_PRE_UNARY_OP);
-            op->setPosition(m_lexer.currentPosition());
-            op->setChild(parseOperand(level));
-            readNext = false;
-            rc = op;
-        } else
-            syntaxError(L_PARSE_OPERAND_NOT_OPERAND,
-                        "operand expected, not an operator");
-        break;
-    }
-    case TOKEN_STRING:
-    case TOKEN_NUMBER:
-    case TOKEN_REAL:
-    {
-        if (parent != NULL)
-            syntaxError(L_PARSE_OPERAND_NO_FIELD2,
-                    "field expected (behind a '.')");
-        RplASConstant* constant = new RplASConstant();
-        constant->setPosition(m_lexer.currentPosition());
-        rc = constant;
-        switch(token->tokenType()){
-        case TOKEN_STRING:
-            constant->value().setString(token->toString());
-            break;
-        case TOKEN_NUMBER:
-            constant->value().setInt(token->asInteger());
-            break;
-        case TOKEN_REAL:
-            constant->value().setFloat(token->asReal());
-            break;
-        default:
-            break;
-        }
-        break;
-    }
-    case TOKEN_ID:
-    {
-        QByteArray name = token->toString();
-        if (name == "a")
-            name = "a";
-        token = m_lexer.nextNonSpaceToken();
-        startPosition = m_lexer.currentPosition();
-        if (token->tokenType() != TOKEN_OPERATOR){
-            rc = buildVarOrField(name, startPosition, parent);
-            readNext = false;
-        } else {
-            if (token->id() == O_LPARENTH){
-                RplASMethodCall* call = new RplASMethodCall(name, parent);
-                call->setPosition(startPosition);
-
-                rc = call;
-                token = m_lexer.nextNonSpaceToken();
-                if (! token->isOperator(O_RPARENTH)){
-                    m_lexer.undoLastToken();
-                    RplASExprStatement* args = parseArguments();
-                    call->setChild2(args);
-                    readNext = false;
-                }
-            } else {
-                rc = buildVarOrField(name, startPosition, parent);
-                if (token->id() == O_LBRACKET){
-                    RplASItem* indexExpr = parseExpr(0);
-                    if (! m_lexer.currentToken()->isOperator(O_RBRACKET))
-                        syntaxError(L_PARSE_OPERAND_NO_BRACKET, "']' expected");
-                    dynamic_cast<RplASNode1*>(rc)->setChild(indexExpr);
-                } else {
-                    if (token->id() == O_INC || token->id() == O_DEC){
-                        RplASUnaryOp* op = new RplASUnaryOp(convertUnaryOp(
-                                                                token->id()),
-                                                            AST_POST_UNARY_OP);
-                        op->setChild(rc);
-                        rc = op;
-                    } else {
-                        readNext = false;
-                    }
-                }
-            }
-        }
-        break;
-    }
-    case TOKEN_END_OF_SOURCE:
-        readNext = false;
-        break;
-    default:
-        // this call never comes back (exception!)
-        syntaxError(L_PARSE_OPERAND_WRONG,
-                    "unexpected symbol detected. Operand expected");
-        break;
-    }
-    if (readNext)
-        m_lexer.nextNonSpaceToken();
-    if (m_lexer.currentToken()->isOperator(O_DOT, O_LBRACKET)){
-        if (m_lexer.currentToken()->asInteger() == O_LBRACKET)
-            m_lexer.undoLastToken();
-        rc = parseOperand(level, rc);
-    }
-    return rc;
-}
-/**
- * @brief Converts a MF specific binary operator into one of AST.
- *
- * @param op    operator known by MF parser
- *
- * @return      operator known by the abstract syntax tree
- */
-RplASBinaryOp::BinOperator RplMFParser::convertBinaryOp(int op){
-    RplASBinaryOp::BinOperator rc;
-    switch(op){
-    case RplMFParser::O_ASSIGN:
-        rc = RplASBinaryOp::BOP_ASSIGN;
-        break;
-    case RplMFParser::O_PLUS_ASSIGN:
-        rc = RplASBinaryOp::BOP_PLUS_ASSIGN;
-        break;
-    case RplMFParser::O_MINUS_ASSIGN:
-        rc = RplASBinaryOp::BOP_MINUS_ASSIGN;
-        break;
-    case RplMFParser::O_DIV_ASSIGN:
-        rc = RplASBinaryOp::BOP_DIV_ASSIGN;
-        break;
-    case RplMFParser::O_TIMES_ASSIGN:
-        rc = RplASBinaryOp::BOP_TIMES_ASSIGN;
-        break;
-    case RplMFParser::O_MOD_ASSIGN:
-        rc = RplASBinaryOp::BOP_MOD_ASSIGN;
-        break;
-    case RplMFParser::O_POWER_ASSIGN:
-        rc = RplASBinaryOp::BOP_POWER_ASSIGN;
-        break;
-    case RplMFParser::O_OR_ASSIGN:
-        rc = RplASBinaryOp::BOP_LOG_OR_ASSIGN;
-        break;
-    case RplMFParser::O_AND_ASSIGN:
-        rc = RplASBinaryOp::BOP_LOG_AND_ASSIGN;
-        break;
-    case RplMFParser::O_LSHIFT_ASSIGN:
-        rc = RplASBinaryOp::BOP_LSHIFT_ASSIGN;
-        break;
-    case RplMFParser::O_RSHIFT_ASSIGN:
-        rc = RplASBinaryOp::BOP_LOG_RSHIFT_ASSIGN;
-        break;
-    case RplMFParser::O_RSHIFT2_ASSIGN:
-        rc = RplASBinaryOp::BOP_ARTITH_RSHIFT_ASSIGN;
-        break;
-    case RplMFParser::O_OR:
-        rc = RplASBinaryOp::BOP_LOG_OR;
-        break;
-    case RplMFParser::O_AND:
-        rc = RplASBinaryOp::BOP_LOG_AND;
-        break;
-    case RplMFParser::O_EQ:
-        rc = RplASBinaryOp::BOP_EQ;
-        break;
-    case RplMFParser::O_NE:
-        rc = RplASBinaryOp::BOP_NE;
-        break;
-    case RplMFParser::O_LT:
-        rc = RplASBinaryOp::BOP_LT;
-        break;
-    case RplMFParser::O_GT:
-        rc = RplASBinaryOp::BOP_GT;
-        break;
-    case RplMFParser::O_LE:
-        rc = RplASBinaryOp::BOP_LE;
-        break;
-    case RplMFParser::O_GE:
-        rc = RplASBinaryOp::BOP_GE;
-        break;
-    case RplMFParser::O_PLUS:
-        rc = RplASBinaryOp::BOP_PLUS;
-        break;
-    case RplMFParser::O_MINUS:
-        rc = RplASBinaryOp::BOP_MINUS;
-        break;
-    case RplMFParser::O_DIV:
-        rc = RplASBinaryOp::BOP_DIV;
-        break;
-    case RplMFParser::O_MOD:
-        rc = RplASBinaryOp::BOP_MOD;
-        break;
-    case RplMFParser::O_TIMES:
-        rc = RplASBinaryOp::BOP_TIMES;
-        break;
-    case RplMFParser::O_POWER:
-        rc = RplASBinaryOp::BOP_POWER;
-        break;
-    case RplMFParser::O_XOR:
-        rc = RplASBinaryOp::BOP_LOG_XOR;
-        break;
-    case RplMFParser::O_BIT_OR:
-        rc = RplASBinaryOp::BOP_BIT_OR;
-        break;
-    case RplMFParser::O_BIT_AND:
-        rc = RplASBinaryOp::BOP_BIT_AND;
-        break;
-    case RplMFParser::O_LSHIFT:
-        rc = RplASBinaryOp::BOP_LSHIFT;
-        break;
-    case RplMFParser::O_RSHIFT:
-        rc = RplASBinaryOp::BOP_LOG_RSHIFT;
-        break;
-    case RplMFParser::O_RSHIFT2:
-        rc = RplASBinaryOp::BOP_ARTITH_RSHIFT;
-        break;
-    default:
-        throw RplException("unknown binary operator %d", op);
-        break;
-    }
-    return rc;
-}
-
-/**
- * @brief Parses an expression.
- *
- * This method parses the part of an expression with the same parenthesis level.
- * The nested parts will be processed recursivly by calling parseOperand which
- * calls <code>parseExpr</code> in the case of inner parentheses.
- *
- * Example: a + (3 * 7 - 2)<br>
- * expr with level 1: 3*7-2<br>
- * expr with level 0: a + expr1<br>
- *
- * @pre         the nextNonSpaceToken() will return the first token of the expr.
- * @post        the token behind the expression is read
- *
- * @param depth the level of the parenthesis
- * @return      the abstract syntax tree representing the parsed expression
- */
-RplASItem* RplMFParser::parseExpr(int depth){
-    RplToken* token;
-    RplASItem* top = parseOperand(depth);
-    if (top != NULL){
-        int lastPrio = INT_MAX;
-        bool again = true;
-        do {
-            token = m_lexer.currentToken();
-            switch(token->tokenType()){
-            case TOKEN_OPERATOR:
-            {
-                Operator opId = (Operator) token->id();
-                if (IS_BINARY_OP(opId)){
-                    RplASBinaryOp* op = new RplASBinaryOp();
-                    op->setPosition(m_lexer.currentPosition());
-                    op->setOperator(convertBinaryOp(opId));
-
-                    int prio = m_lexer.prioOfOp(token->id());
-                    if (prio < lastPrio
-                            || (prio == lastPrio
-                                && ! m_lexer.isRightAssociative(opId))){
-                        op->setChild(top);
-                        top = op;
-                    } else {
-                        // right assoc or higher priority:
-                        RplASBinaryOp* top2 = dynamic_cast<RplASBinaryOp*>(top);
-                        op->setChild(top2->child2());
-                        top2->setChild2(op);
-                    }
-                    lastPrio = prio;
-                    op->setChild2(parseOperand(depth));
-                } else
-                    again = false;
-                break;
-            }
-            case TOKEN_STRING:
-                syntaxError(L_TERM_WRONG_STRING, "Operator expected, not a string");
-                break;
-            case TOKEN_NUMBER:
-            case TOKEN_REAL:
-                syntaxError(L_TERM_WRONG_NUMBER, "Operator expected, not a number");
-                break;
-            case TOKEN_KEYWORD:
-            case TOKEN_ID:
-            case TOKEN_END_OF_SOURCE:
-            default:
-                again = false;
-                break;
-            }
-        } while(again);
-    }
-    return top;
-}
-
-
-/**
- * @brief Parses an expression as a statement.
- *
- * @pre     the nextNonSpaceToken() will return the first token of the expr.<br>
- *          Note: a ';' is part of the expression statement
- * @post    the token behind the expression is read
- * @param   eatSemicolon    true: a trailing ';' will be read
- * @return                  the abstract syntax tree of the expression statement
- */
-RplASItem* RplMFParser::parseExprStatement(bool eatSemicolon)
-{
-    RplASItem* item = parseExpr(0);
-    RplASExprStatement* statement = NULL;
-    if (item != NULL){
-        statement = new RplASExprStatement();
-        statement->setPosition(item->position());
-        statement->setChild2(item);
-    }
-    if (eatSemicolon && m_lexer.currentToken()->isOperator(O_SEMICOLON))
-        m_lexer.nextNonSpaceToken();
-    return statement;
-}
-
-/**
- * @brief Parses a local variable.
- *
- * @return the variable definition
- */
-RplASItem* RplMFParser::parseLocalVar(){
-    RplASItem* rc = parseVarDefinition(RplASNamedValue::A_NONE);
-    return rc;
-}
-
-/**
- * @brief Parses the body.
- *
- * A body is a module, a class region or a method body.
- *
- * @param keywordStop   the first possible keyword which finishes the stm. list
- * @param keywordStop2  the 2nd possible keyword which finishes the statements
- * @param builtinVars   number of variables valid only in this body
- * @return              the first element of the statement list
- */
-RplASItem* RplMFParser::parseBody(Keyword keywordStop, Keyword keywordStop2,
-                                  int builtinVars)
-{
-    RplToken* token = m_lexer.nextNonSpaceToken();
-    RplASItem* item = NULL;
-    RplASItem* body = NULL;
-    RplASNode1* lastStatement = NULL;
-    RplASScope scope;
-    m_tree.currentSpace()->startScope(scope);
-    scope.m_builtInVars = builtinVars;
-    bool again = true;
-    const RplSourcePosition* lastPos = NULL;
-    do {
-        token = m_lexer.currentToken();
-        if (lastPos == m_lexer.currentPosition())
-            syntaxError(L_PARSE_BODY_NO_START, "no statement starts with this symbol");
-        lastPos = m_lexer.currentPosition();
-        // eat a superflous ';'
-        if (token->isOperator(O_SEMICOLON))
-            token = m_lexer.nextNonSpaceToken();
-        try {
-            switch(token->tokenType())
-            {
-            case TOKEN_OPERATOR:
-            case TOKEN_STRING:
-            case TOKEN_NUMBER:
-            case TOKEN_REAL:
-                m_lexer.undoLastToken();
-                item = parseExprStatement();
-                break;
-            case TOKEN_KEYWORD:
-                switch (token->id()){
-                case K_IF:
-                    item = parseIf();
-                    break;
-                case K_WHILE:
-                    item = parseWhile();
-                    break;
-                case K_REPEAT:
-                    item = parseRepeat();
-                    break;
-                case K_FOR:
-                    item = parseFor();
-                    break;
-                case K_CLASS:
-                    parseClass();
-                    item = NULL;
-                    break;
-                case K_FUNCTION:
-                case K_GENERATOR:
-                    parseMethod();
-                    item = NULL;
-                    break;
-                case K_IMPORT:
-                    parseImport();
-                    item = NULL;
-                    break;
-                case K_CONST:
-                case K_LAZY:
-                    item = parseLocalVar();
-                    break;
-                default:
-                    if (token->isKeyword(keywordStop, keywordStop2))
-                        again = false;
-                    break;
-                }
-                break;
-            case TOKEN_ID:
-            {
-                if (token->isCapitalizedId()){
-                    item = parseLocalVar();
-                } else {
-                    m_lexer.undoLastToken();
-                    item = parseExprStatement();
-                }
-                break;
-            }
-            case TOKEN_END_OF_SOURCE:
-                again = false;
-                break;
-            default:
-                break;
-            }
-            if (again && item != NULL){
-                if (body == NULL){
-                    body = item;
-                } else {
-                    lastStatement->setChild(item);
-                }
-                lastStatement = dynamic_cast<RplASNode1*>(item);
-                if (lastStatement == NULL)
-                    error(L_PARSE_BODY_WRONG_ITEM, "wrong item type: %d",
-                          item == NULL ? 0 : item->nodeType());
-                token = m_lexer.currentToken();
-                if (keywordStop != K_UNDEF
-                            && token->isKeyword(keywordStop, keywordStop2))
-                    again = false;
-            }
-        } catch(RplSyntaxError exc){
-            // we look for the end of the statement:
-            token = m_lexer.currentToken();
-            RplTokenType type;
-            Operator op;
-            Keyword key;
-            while( (type = token->tokenType()) != TOKEN_END_OF_SOURCE)
-                if (type == TOKEN_OPERATOR
-                        && ((op = Operator(token->id())) == O_SEMICOLON
-                            || op == O_SEMI_SEMICOLON))
-                    break;
-                else if (type == TOKEN_KEYWORD){
-                    key = Keyword(token->id());
-                    if (key == K_ENDC || key == K_ENDF){
-                        // we need the token again!
-                        m_lexer.undoLastToken();
-                        break;
-                    } else if (key == K_FI || key == K_OD){
-                        break;
-                    } else {
-                        token = m_lexer.nextNonSpaceToken();
-                    }
-                } else {
-                    token = m_lexer.nextNonSpaceToken();
-                }
-        }
-    } while(again);
-
-    if (keywordStop != K_ENDF && keywordStop != K_ENDC
-            && keywordStop != K_UNDEF)
-        m_tree.currentSpace()->finishScope(m_lexer.currentPosition()->lineNo(),
-                                           scope);
-    return body;
-}
-
-/**
- * @brief Parses a parameter list of a method/function.
- *
- * @pre     token behind '(' is read
- * @post    token behind ')' is read
- * @return
- */
-RplASVarDefinition* RplMFParser::parseParameterList(){
-    RplASVarDefinition* rc = NULL;
-    RplASVarDefinition* last = NULL;
-    const RplSourcePosition* startPos = m_lexer.currentPosition();
-    RplASItem* definition = NULL;
-    do {
-        if (definition != NULL)
-            m_lexer.nextNonSpaceToken();
-        RplASVarDefinition* current = parseVarDefinition(RplASNamedValue::A_PARAM);
-        if (rc == NULL){
-            rc = current;
-        } else {
-            last->setChild(current);
-        }
-        last = current;
-    } while(m_lexer.currentToken()->isOperator(O_COMMA));
-    if (! m_lexer.currentToken()->isOperator(O_RPARENTH))
-        syntaxError(L_PARSE_PARAMLIST_NO_PARENTH, ") expected", ")", startPos);
-    m_lexer.nextNonSpaceToken();
-    return rc;
-}
-
-/**
- * @brief Parses a class definition.
- *
- * The method definition will be stored in the symbol space of the parent
- *
- * @pre             token "func" is read
- * @post            token behind "endf" is read
- * @return          NULL
- */
-void RplMFParser::parseMethod()
-{
-    RplASMethod* method = NULL;
-    const RplSourcePosition* startPos = m_lexer.currentPosition();
-    RplToken* token = m_lexer.nextNonSpaceToken();
-    if (! token->isTokenType(TOKEN_ID))
-        syntaxError(L_PARSE_METH_NO_CLASS, "type name expected");
-    QByteArray type = token->toString();
-    if (! isupper(type.at(0)))
-        syntaxError(L_PARSE_METH_NO_CLASS2,
-                    "type name expected (must start with an upper case character)");
-    token = m_lexer.nextNonSpaceToken();
-    if (! token->isTokenType(TOKEN_ID))
-        syntaxError(L_PARSE_METH_NO_NAME, "method name expected");
-    QByteArray name = token->toString();
-    if (! isupper(type.at(0)))
-        syntaxError(L_PARSE_METH_NO_CLASS2,
-                    "method name expected (must start with an lower case character)");
-    token = m_lexer.nextNonSpaceToken();
-    if (! token->isOperator(O_LPARENTH, O_COLON))
-        syntaxError(L_PARSE_METH_NO_LPARENTH, "'(' or ':' expected");
-
-    RplASVarDefinition* parameterList = NULL;
-    method = new RplASMethod(name, m_tree);
-    method->setPosition(startPos);
-    RplSymbolSpace* symbols = m_tree.currentSpace();
-    symbols->addMethod(method);
-    m_tree.startClassOrMethod(name, RplSymbolSpace::SST_METHOD);
-    method->setSymbols();
-    if (token->isOperator(O_LPARENTH)){
-      token = m_lexer.nextNonSpaceToken();
-      if (token->isOperator(O_RPARENTH)){
-          token = m_lexer.nextNonSpaceToken();
-      } else {
-          parameterList = parseParameterList();
-          method->setChild2(parameterList);
-      }
-    }
-    if (! token->isOperator(O_COLON))
-        syntaxError(L_PARSE_METH_NO_COLON, "':' expected");
-
-    method->setChild(parseBody(K_ENDF));
-    if (! m_lexer.currentToken()->isKeyword(K_ENDF))
-        syntaxError(L_PARSE_METH_NO_END, "end of function not found", "endf",
-                    startPos);
-    m_lexer.nextNonSpaceToken();
-    m_tree.finishClassOrMethod(name);
-}
-
-/**
- * @brief Parses a class definition.
- *
- * @pre     "class" is read
- * @post    token behind "endc" is read
- */
-void RplMFParser::parseClass()
-{
-    const RplSourcePosition* startPos = m_lexer.currentPosition();
-    RplToken* token = m_lexer.nextNonSpaceToken();
-    if (! token->isTokenType(TOKEN_ID))
-        syntaxError(L_PARSE_CLASS_NO_NAME, "class name expected");
-    if (! token->isCapitalizedId())
-        syntaxError(L_PARSE_CLASS_LOWERCASE, "class name must start with an uppercase character");
-    QByteArray name = token->toString();
-    RplASUserClass* clazz = new RplASUserClass(name, startPos, m_tree);
-    RplSymbolSpace* parent = m_tree.currentSpace();
-    RplASUserClass* alreadyDefined = parent->addClass(clazz);
-    if (alreadyDefined != NULL){
-        error(L_PARSE_CLASS_ALREADY_DEFINED, alreadyDefined->position(),
-              "class already defined", "previous defined class");
-    }
-    m_tree.startClassOrMethod(name, RplSymbolSpace::SST_CLASS);
-    clazz->setSymbols();
-
-    m_tree.finishClassOrMethod(name);
-}
-
-/**
- * @brief Parses a the import statement
- */
-void RplMFParser::parseImport()
-{
-
-}
-
-/**
- * @brief Parses a module.
- *
- * @pre     the first char of the module is the next char to read.
- * @post    the total module is read
- *
- * @param name  the name of the module (without path)
- */
-RplASItem* RplMFParser::parseModule(RplSourceUnitName name)
-{
-    m_tree.startModule(name);
-    // parse until EOF:
-    RplASItem* body = parseBody(K_UNDEF);
-    m_tree.finishModule(name);
-    return body;
-}
-/**
- * @brief Parse the input given by the source.
- */
-void RplMFParser::parse()
-{
-    RplSource* source = m_lexer.source();
-    RplSourceUnit* mainModule = source->currentReader()->currentSourceUnit();
-    RplSourceUnitName mainModuleName = mainModule->name();
-    try {
-        RplASItem* body = parseModule(mainModuleName);
-        RplSymbolSpace* module = m_tree.findmodule(mainModuleName);
-        if (module != NULL)
-            module->setBody(body);
-    } catch(RplParserStop exc){
-        printf("compiling aborted: %s\n", exc.reason());
-    }
-}
-
-/**
- * @brief Parses an argument list in a method call.
- *
- * @pre     the token '(' is read
- * @post    the token behind the ')' is read
- * @return  the first element of the argument list
- */
-RplASExprStatement* RplMFParser::parseArguments()
-{
-    RplASExprStatement* first = NULL;
-    RplASExprStatement* last = NULL;
-    bool again = false;
-    do {
-        RplASItem* expr = parseExpr(0);
-        if (! m_lexer.currentToken()->isOperator(O_COMMA, O_RPARENTH))
-            syntaxError(L_PARSE_ARGS_NO_COMMA_OR_PARENT, "',' or ')' expected");
-        again = m_lexer.currentToken()->isOperator(O_COMMA);
-        RplASExprStatement* current = new RplASExprStatement();
-        current->setPosition(expr->position());
-        current->setChild2(expr);
-        if (first == NULL)
-            first = last = current;
-        else{
-            last->setChild(current);
-            last = current;
-        }
-    } while (again);
-    // skip ')':
-    m_lexer.nextNonSpaceToken();
-    return first;
-}
-
diff --git a/rplexpr/rplmfparser.hpp b/rplexpr/rplmfparser.hpp
deleted file mode 100644 (file)
index d1d9d61..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLMFPARSER_HPP
-#define RPLMFPARSER_HPP
-
-class RplMFParser : public RplParser
-{
-public:
-    enum Keyword {
-        K_UNDEF, K_IF, K_THEN, K_ELSE, K_FI, K_WHILE, // 5
-        K_DO, K_OD, K_REPEAT, K_UNTIL, K_FOR, // 10
-        K_FROM, K_TO, K_STEP, K_IN, K_CASE, // 15
-        K_OF, K_ESAC, K_LEAVE, K_CONTINUE, K_PASS, // 20
-        K_CLASS, K_ENDC, K_ENDF, K_FUNCTION, K_GENERATOR, // 25
-        K_IMPORT, K_CONST, K_LAZY, K_NONE, K_TRUE, // 30
-        K_FALSE
-        };
-#define MF_KEYWORDS "if then else fi while do od repeat until" \
-    " for from to step in case of esac leave continue pass" \
-    " class endc endf func generator import" \
-    " const lazy none true false"
-    enum Operator {
-        O_UNDEF, O_SEMI_SEMICOLON, O_SEMICOLON, O_COMMA, O_COLON, // 4
-        O_ASSIGN, O_PLUS_ASSIGN, O_MINUS_ASSIGN, O_DIV_ASSIGN, O_TIMES_ASSIGN, // 8
-        O_MOD_ASSIGN, O_POWER_ASSIGN, O_OR_ASSIGN, O_AND_ASSIGN, // 13
-        O_LSHIFT_ASSIGN, O_RSHIFT_ASSIGN, O_RSHIFT2_ASSIGN, // 16
-        O_OR, O_AND, // 18
-        O_EQ, O_NE, // 20
-        O_LT, O_GT, O_LE, O_GE, // 24
-        O_QUESTION, // 25
-        O_PLUS, O_MINUS, // 27
-        O_DIV, O_MOD, O_TIMES, // 30
-        O_POWER, // 31
-        O_XOR, O_BIT_OR, O_BIT_AND, // 34
-        O_LSHIFT, O_RSHIFT, O_RSHIFT2, // 37
-        O_NOT, O_BIT_NOT, // 39
-        O_INC, O_DEC, // 41
-        O_DOT, O_LPARENTH, O_RPARENTH, O_LBRACKET, O_RBRACKET, O_LBRACE, O_RBRACE // 48
-    };
-#define IS_BINARY_OP(op) (Operator(op) >= O_ASSIGN && Operator(op) <= O_DOT)
-#define IS_UNARY_OP(op) (op==O_PLUS || op==O_MINUS || (op>=O_NOT && op<=O_DEC))
-
-/// \n separates the priority classes
-#define MF_OPERATORS ";; ; , :\n" \
-    "= += -= /= *= %= **= |= &= <<= >>= >>>=\n" \
-    "||\n" \
-    "&&\n" \
-    "== !=\n" \
-    "< > <= >=\n" \
-    "?\n" \
-    "+ -\n" \
-    "/ % *\n" \
-    "**\n" \
-    "^ | &\n" \
-    "<< >> >>>\n" \
-    "! ~\n" \
-    "++ --\n" \
-    ". ( ) [ ] { }"
-#define MF_RIGHT_ASSOCIATIVES "= += -= /= *= %= **= |= &= <<= >>= >>>= ** ."
-public:
-    RplMFParser(RplSource& source, RplASTree& ast);
-public:
-    RplASItem* parseIf();
-    RplASItem* parseWhile();
-    RplASItem* parseRepeat();
-    RplASItem* parseFor();
-    RplASVarDefinition* parseVarDefinition(RplASNamedValue::Attributes attribute);
-    RplASItem* parseExpr(int depth);
-    RplASItem* parseBody(Keyword keywordStop, Keyword keywordStop2 = K_UNDEF,
-                         int builtinVars = 0);
-    void parseMethod();
-    void parseClass();
-    void parseImport();
-    RplASItem* parseModule(RplSourceUnitName name);
-    void parse();
-    RplASItem*parseExprStatement(bool eatSemicolon = true);
-    RplASItem*parseList();
-    RplASItem*parseMap();
-protected:
-    RplASExprStatement* parseArguments();
-    RplASItem* parseOperand(int level, RplASItem* parent = NULL);
-    RplASVariant* tokenToVariant(RplToken* token, bool endsWithComma,
-                                 RplASNode1* parent);
-    RplASVariant*createFormula(RplASNode1* parent);
-    RplASItem* buildVarOrField(const QByteArray& name,
-                               const RplSourcePosition* position,
-                               RplASItem* parent);
-    RplASVarDefinition* parseParameterList();
-    RplASItem* parseLocalVar();
-    RplASVarDefinition* buildVarDef(RplASNamedValue* var);
-protected:
-    static RplASBinaryOp::BinOperator convertBinaryOp(int op);
-    static RplASUnaryOp::UnaryOp convertUnaryOp(int op);
-private:
-    ///syntax token builder.
-    /// Note: the super class contains a reference with the same name
-    RplLexer m_lexer;
-};
-
-#endif // RPLMFPARSER_HPP
diff --git a/rplexpr/rplparser.cpp b/rplexpr/rplparser.cpp
deleted file mode 100644 (file)
index de01de5..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- *
- * @brief Generally usable parts of an parser, e.g. error handling.
- */
-/** @file rplexpr/rplparser.hpp
- *
- * @brief Definition of a generally usable parts of an parser.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-
-
-/** @class RplSyntaxError rplparser.hpp "rplexpr/rplparser.hpp"
- *
- * @brief Implements an exception used for jumping out from many nested calls.
- *
- * We don't want to cancel the parse process if an syntax error has been
- * occurred. Therefore we want to recreate after it.
- * A relative simple solution:
- * Ignoring the rest of the statement and start again with the next statement.
- * Often the detection is done deep in an expression and we must jump out.
- * This allows this exception.
- */
-
-/**
- * @brief Constructor.
- * @param reason        the reason of the exception
- * @return
- */
-RplSyntaxError::RplSyntaxError(const char* reason) :
-    m_reason(reason)
-{
-}
-/**
- * @brief Returns the description of the exception.
- *
- * @return  the reason
- */
-const char* RplSyntaxError::reason() const
-{
-    return m_reason;
-}
-
-/** @class RplParserStop rplparser.hpp "rplexpr/rplparser.hpp"
- *
- * @brief Implements an exception used for jumping out from many nested calls.
- *
- * In some situation we want to abort the parsing process.
- * This exception allows this without high costs even the abort position
- * is in a deep nested call.
- */
-
-/**
- * @brief Constructor.
- * @param reason        the reason of the exception
- */
-RplParserStop::RplParserStop(const char* reason) :
-    RplSyntaxError(reason)
-{
-}
-
-/** @class RplParser rplparser.hpp "rplexpr/rplparser.hpp"
- *
- * @brief Implements a base class for parsers.
- *
- * This class offers common things for all parsers, e.g. error handling.
- */
-/**
- * @brief Constructor.
- *
- * @param lexer     the tokenizer
- * @param tree      the abstract syntax tree
- */
-RplParser::RplParser(RplLexer& lexer, RplASTree& tree) :
-    m_lexer(lexer),
-    m_tree(tree),
-    m_messages(),
-    m_errors(0),
-    m_warnings(0),
-    m_maxErrors(20),
-    m_maxWarnings(20)
-{
-}
-
-/**
- * @brief Common actions for the error/warning functions.
- *
- * @param prefix    first char in the message: 'E' (error) or 'W' (warning)
- * @param location  unique id of the error/warning message
- * @param position  position of the error/warning
- * @param message   message with placeholdes like sprintf()
- * @return          false (for chaining)
- */
-bool RplParser::addSimpleMessage(LevelTag prefix, int location,
-                                 const RplSourcePosition* position,
-                                 const char* message){
-    char buffer[2048];
-    QByteArray msg;
-    qsnprintf(buffer, sizeof buffer, "%c%04d %s:%d-%d: ", prefix, location,
-             position->sourceUnit()->name(),
-             position->lineNo(), position->column());
-    int used = strlen(buffer);
-    int length = strlen(message);
-    if (length >= (int) sizeof buffer - used)
-        length = sizeof buffer - used - 1;
-    memcpy(buffer + used, message, length);
-    buffer[used + length] = '\0';
-    m_messages.append(buffer);
-    return false;
-}
-
-/**
- * @brief Common actions for the error/warning functions.
- *
- * @param prefix    first char in the message: 'E' (error) or 'W' (warning)
- * @param location  unique id of the error/warning message
- * @param position  position of the error/warning
- * @param format    message with placeholdes like sprintf()
- * @param varList   the variable argument list
- * @return          false (for chaining)
- */
-bool RplParser::addMessage(LevelTag prefix, int location,
-                           const RplSourcePosition* position,
-                           const char* format, va_list varList){
-    char buffer[2048];
-    qvsnprintf(buffer, sizeof buffer, format, varList);
-    return addSimpleMessage(prefix, location, position, buffer);
-}
-
-/**
- * @brief Adds an error message and throws an exception.
- *
- * The exception will be catched at a position where error recovery can take place.
- *
- * @param location  unique id of the error/warning message
- * @param message   error message
- */
-
-void RplParser::syntaxError(int location, const char* message)
-{
-    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
-    throw RplSyntaxError(message);
-}
-
-/**
- * @brief Adds an error message and throws an exception.
- *
- * This method is used if a closing symbol (e.g. a ')' or 'end') is missed.
- * The message contains a %s as an placeholder for the position of the
- * starting symbol.
- * The exception will be catched at a position where error recovery
- * can take place.
- *
- * @param location  unique id of the error
- * @param message   message describing the error
- * @param symbol    starting symbol corresponding to the missed closing symbol
- * @param position  position of the starting symbol
- */
-
-void RplParser::syntaxError(int location, const char* message,
-                            const char* symbol,
-                            const RplSourcePosition* position)
-{
-    char buffer[256];
-    char buffer2[512];
-    qsnprintf(buffer2, sizeof buffer2,
-            "The starting symbol %s is located here. Missing point: %s",
-            symbol, m_lexer.currentPosition()->utf8(buffer, sizeof buffer));
-
-    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
-    addSimpleMessage(LT_INFO, location + 1, position, buffer2);
-    throw RplSyntaxError(message);
-}
-
-/**
- * @brief Adds an error message.
- *
- * If too much errors an exception will be thrown to stop parsing.
- *
- * @param location  unique id of the error/warning message
- * @param format    message with placeholdes like sprintf()
- * @param ...       optional: the variable argument list
- * @return          false (for chaining)
- */
-bool RplParser::error(int location, const char* format, ...)
-{
-    va_list ap;
-    va_start(ap, format);
-    addMessage(LT_ERROR, location, m_lexer.currentPosition(), format, ap);
-    va_end(ap);
-    if (++m_errors >= m_maxErrors)
-        throw RplParserStop("too many errors");
-    return false;
-}
-/**
- * @brief Adds an error message with an additional info message.
- *
- * If too much errors an exception will be thrown to stop parsing.
- *
- * @param location  unique id of the error/warning message
- * @param position  source position of the additional message
- * @param message   describes the error
- * @param message2  the additional message
- * @param ...       optional: the variable argument list
- * @return          false (for chaining)
- */
-bool RplParser::error(int location, const RplSourcePosition* position,
-                      const char* message, const char* message2)
-{
-    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
-    addSimpleMessage(LT_INFO, location + 1, position, message2);
-    if (++m_errors >= m_maxErrors)
-        throw RplParserStop("too many errors");
-    return false;
-}
-
-/**
- * @brief Adds a warning message.
- *
- * If too much warnings an exception will be thrown to stop parsing.
- *
- * @param location  unique id of the error/warning message
- * @param format    message with placeholdes like sprintf()
- * @param ...       optional: the variable argument list
- */
-void RplParser::warning(int location, const char* format, ...)
-{
-    va_list ap;
-    va_start(ap, format);
-    addMessage(LT_WARNING, location, m_lexer.currentPosition(), format, ap);
-    va_end(ap);
-    if (++m_warnings >= m_maxWarnings)
-        throw RplParserStop("too many warnings");
-}
-/**
- * @brief Return the number of errors.
- *
- * @return the count of errors occurred until now
- */
-int RplParser::errors() const
-{
-    return m_errors;
-}
-/**
- * @brief Return the number of warnings.
- *
- * @return the count of errors occurred until now
- */
-int RplParser::warnings() const
-{
-    return m_warnings;
-}
-
-
diff --git a/rplexpr/rplparser.hpp b/rplexpr/rplparser.hpp
deleted file mode 100644 (file)
index cb21c4c..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLPARSER_HPP
-#define RPLPARSER_HPP
-
-class RplSyntaxError
-{
-public:
-    RplSyntaxError(const char* reason);
-public:
-    const char* reason() const;
-private:
-    const char* m_reason;
-};
-
-class RplParserStop : public RplSyntaxError {
-public:
-    RplParserStop(const char* reason);
-};
-
-class RplParser {
-public:
-    enum LevelTag {
-        LT_ERROR = 'E',
-        LT_WARNING = 'W',
-        LT_INFO = 'I'
-    };
-
-public:
-    typedef QList<QByteArray> MessageList;
-public:
-    RplParser(RplLexer& lexer, RplASTree& ast);
-public:
-    bool addSimpleMessage(LevelTag prefix, int location,
-                          const RplSourcePosition* pos,
-                          const char* message);
-    bool addMessage(LevelTag prefix, int location,
-                    const RplSourcePosition* pos,
-                    const char* format, va_list varList);
-    void syntaxError(int location, const char* message);
-    void syntaxError(int location, const char* message, const char* symbol,
-                     const RplSourcePosition* position);
-    bool error(int location, const char* format, ...);
-    bool error(int location, const RplSourcePosition* position,
-               const char* message, const char* message2);
-    void warning(int location, const char* format, ...);
-    int errors() const;
-    int warnings() const;
-protected:
-    RplLexer& m_lexer;
-    RplASTree& m_tree;
-    MessageList m_messages;
-    int m_errors;
-    int m_warnings;
-    int m_maxErrors;
-    int m_maxWarnings;
-};
-
-#endif // RPLPARSER_HPP
diff --git a/rplexpr/rplsource.cpp b/rplexpr/rplsource.cpp
deleted file mode 100644 (file)
index b10feac..0000000
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Reading from several input media.
- *
- * The abstract base class <code>RplReader</code> and its concrete derivations
- * <code>RplStringReader</code>, <code>RplFileReader</code> are used to read
- * from one medium.
- * The <code>RplSource</code> combines several readers and build an uniquely
- * usable input stream.
- */
-/** @file rplexpr/rplsource.hpp
- *
- * @brief Definitions for reading from several input media.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-
-
-/** @class RplSource rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Stores all source positions.
- *
- */
-
-/** @class RplSourceUnit rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Implements the base class of input source units.
- *
- * A source unit is set of input lines with a name, e.g. a file.
- */
-
-/**
- * @brief Constructor
- * @param name      name of the unit
- * @param reader    the reader which can read the unit
- */
-RplSourceUnit::RplSourceUnit(RplSourceUnitName name, RplReader* reader) :
-    m_name(name),
-    m_lineNo(0),
-    m_reader(reader) {
-}
-
-/**
- * @brief Destructor.
- */
-RplSourceUnit::~RplSourceUnit() {
-}
-
-/**
- * @brief Returns the name.
- * @return  the name
- */
-RplSourceUnitName RplSourceUnit::name() const {
-    return m_name.constData();
-}
-
-/**
- * @brief Returns the line number.
- *
- * @return  the line number
- */
-int RplSourceUnit::lineNo() const {
-    return m_lineNo;
-}
-
-/**
- * @brief Sets the line number.
- *
- * @param lineNo    the new line number
- */
-void RplSourceUnit::setLineNo(int lineNo) {
-    m_lineNo = lineNo;
-}
-/**
- * @brief Returns the reader of the instance.
- *
- * @return  the reader belonging to the instance
- */
-RplReader* RplSourceUnit::reader() const {
-    return m_reader;
-}
-
-/** @class RplSourcePosition rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Stores a precise position in the input source.
- *
- * The input source contains normally a lot of nested source units.
- *
- * Each source unit owns a name and a sequence of lines.
- *
- * The mostly used source unit is a text file.
- *
- * A precice position is the stack of source unit positions.
- */
-
-/**
- * @brief Constructor.
- */
-RplSourcePosition::RplSourcePosition() :
-    m_sourceUnit(NULL),
-    m_lineNo(0),
-    m_column(0),
-    m_caller(NULL)
-{
-}
-
-/**
- * @brief Constructor.
- *
- * @param unit      name of the input source (normally a file)
- * @param lineNo    line number inside the input source
- * @param colNo     distance to the line start
- */
-RplSourcePosition::RplSourcePosition(RplSourceUnit* unit, int lineNo,
-        int colNo) :
-    m_sourceUnit(unit),
-    m_lineNo(lineNo),
-    m_column(colNo),
-    m_caller(NULL)
-{
-    RplReader* reader = dynamic_cast<RplReader*>(unit->reader());
-    m_caller = reader->source().caller();
-}
-/**
- * @brief Destructor
- */
-RplSourcePosition::~ RplSourcePosition(){
-    // That should never occure!
-    assert(false);
-}
-
-/**
- * @brief Placement new operator (for our own memory management).
- *
- * @param cbSize    size of the instance
- * @param buffer    buffer for the instance
- * @return          <code>buffer</code>
- */
-void*RplSourcePosition::operator new(size_t, void* buffer)
-{
-    return buffer;
-}
-
-/**
- * @brief Returns a description of the source position: "<unit>-<lineNo> (<col>):".
- *
- * @return a description of the instance
- */
-QString RplSourcePosition::toString() const
-{
-    char buffer[512];
-    utf8(buffer, sizeof buffer);
-
-    return QString(buffer);
-}
-
-/**
- * @brief Returns the position as a C string.
- *
- * @param buffer        OUT: the target buffer
- * @param bufferSize    the size of the buffer
- * @return              <code>buffer</code>
- */
-char* RplSourcePosition::utf8(char buffer[], size_t bufferSize) const
-{
-    qsnprintf(buffer, bufferSize, "%s:%d:%d",
-             m_sourceUnit == NULL ? "" : m_sourceUnit->name(),
-             m_lineNo, m_column);
-    return buffer;
-}
-
-/**
- * @brief Returns the line number.
- * @return  the line number
- */
-int RplSourcePosition::lineNo() const
-{
-    return m_lineNo;
-}
-
-/**
- * @brief Sets the line number.
- *
- * @param lineNo    the new lineNo
- */
-void RplSourcePosition::setLineNo(int lineNo)
-{
-    m_lineNo = lineNo;
-}
-/**
- * @brief Returns the column.
- *
- * @return  the column of instance.
- */
-int RplSourcePosition::column() const
-{
-    return m_column;
-}
-
-/**
- * @brief Sets the column.
- *
- * @param column    the new column
- */
-void RplSourcePosition::setColumn(int column)
-{
-    m_column = column;
-}
-
-/**
- * @brief Returns the source unit belonging to the instance.
- *
- * @return  the source unit of the instance
- */
-RplSourceUnit* RplSourcePosition::sourceUnit() const
-{
-    return m_sourceUnit;
-}
-
-/**
- * @brief Sets the source unit.
- *
- * @param sourceUnit    the new source unit of the instance
- */
-void RplSourcePosition::setSourceUnit(RplSourceUnit* sourceUnit)
-{
-    m_sourceUnit = sourceUnit;
-    m_lineNo = sourceUnit->lineNo();
-}
-
-
-/** @class RplReader rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Implements a base class for readers of different media.
- */
-
-
-/**
- * @brief Constructor.
- *
- * @param source    the parent
- */
-RplReader::RplReader(RplSource& source) :
-    m_currentSourceUnit(NULL),
-    m_units(),
-    m_source(source) {
-}
-
-/**
- * @brief Destructor.
- */
-RplReader::~RplReader()
-{
-    clear();
-}
-
-/**
- * @brief Frees the resources.
- */
-void RplReader::clear()
-{
-    UnitMap::iterator it;
-    for(it = m_units.begin(); it != m_units.end(); it++) {
-        RplStringSourceUnit* unit = (RplStringSourceUnit*)(*it);
-        delete unit;
-    }
-    m_units.clear();
-    m_currentSourceUnit = NULL;
-}
-
-/**
- * @brief Returns the source of the reader.
- *
- * @return the parent, a source instance
- */
-RplSource&RplReader::source()
-{
-    return m_source;
-}
-/**
- * @brief Returns the current source unit.
- *
- * @return the source unit
- */
-RplSourceUnit* RplReader::currentSourceUnit() const {
-    return m_currentSourceUnit;
-}
-
-/**
- * @brief Sets the current source unit.
- *
- * @param sourceUnit    the name of the new source unit
- * @return              true: source unit exists<br>
- *                      false: source unit not found
- */
-bool RplReader::setCurrentSourceUnit(RplSourceUnitName& sourceUnit) {
-    bool rc = m_units.contains(sourceUnit);
-    if(rc) {
-        m_currentSourceUnit = m_units.value(sourceUnit);
-        m_source.pushSourceUnit(m_currentSourceUnit);
-    }
-    return rc;
-}
-
-/**
- * @brief Removes the "latest" sourceUnit.
- */
-void RplReader::removeSourceUnit() {
-
-    m_currentSourceUnit = m_source.popSourceUnit(this);;
-}
-
-/** @class RplSourcePositionBlock rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Efficient heap of <code>RplSourcePosition</code> instances.
- *
- * The <code>RplSourcePosition</code> heap is only growing. The deletion is
- * done for all entries together.
- * Therefore a simple allocation is possible with blocks.
- */
-RplSourcePositionBlock::RplSourcePositionBlock() :
-    m_successor(NULL)
-    // m_positions
-{
-    memset(m_positions, 0, sizeof m_positions);
-}
-
-/** @class RplSource rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Administrates a set of input sources with different readers.
- *
- * An input stream can be built by some different resources, e.g. files
- * and memory buffers. The RplSource can administrate these resources.
- */
-/**
- * @brief Constructor.
- */
-RplSource::RplSource() :
-    m_sourcePositionStack(),
-    m_sourcePositionBlock(NULL),
-    m_countPositionBlock(RPL_POSITIONS_PER_BLOCK + 1),
-    m_readers(),
-    m_sourceUnits(),
-    m_unitStack(),
-    m_currentReader(NULL)
-{
-    // the stack should never be empty:
-    m_sourcePositionStack.push(NULL);
-}
-
-/**
- * @brief Destructor.
- */
-RplSource::~RplSource() {
-    destroy();
-}
-
-/**
- * @brief Frees the resources of the instance.
- */
-void RplSource::destroy()
-{
-    m_sourcePositionStack.clear();
-    m_readers.clear();
-    m_sourceUnits.clear();
-    m_currentReader = NULL;
-    RplSourcePositionBlock* block = m_sourcePositionBlock;
-    m_sourcePositionBlock = NULL;
-    m_countPositionBlock = RPL_POSITIONS_PER_BLOCK + 1;
-    while(block != NULL){
-        RplSourcePositionBlock* last = block;
-        block = block->m_successor;
-        delete last;
-    }
-}
-
-/**
- * @brief Returns the permanently valid source unit name.
- *
- * If unit names can be local objects (not string constants
- * like __FILE__) then this method must be overridden by
- * a method which builds a permanently valid string.
- *
- * @param unit      unit to find
- * @return          a permanently valid unit name
- */
-RplSourceUnitName RplSource::permanentUnitName(RplSourceUnitName unit) {
-    return unit;
-}
-
-/**
- * @brief Returns the stack with the positions of the open input resources.
- *
- * @return  the stack
- */
-QStack<const RplSourcePosition*> RplSource::sourcePositionStack() const {
-    return m_sourcePositionStack;
-}
-
-/**
- * @brief Returns the source unit stack.
- * @return  the stack of the source units
- */
-QStack<RplSourceUnit*>& RplSource::sourceUnitStack()
-{
-    return m_unitStack;
-}
-
-/**
- * @brief Adds a source reader.
- *
- * @param reader    the new reader. Will be freed in the destructor
- */
-void RplSource::addReader(RplReader* reader) {
-    m_readers.push_back(reader);
-    if (m_currentReader == NULL)
-        m_currentReader = reader;
-}
-
-/**
- * @brief Adds a source unit.
- *
- * @param unit  the new unit. Will be freed in the destructor
- */
-void RplSource::addSourceUnit(RplSourceUnit* unit) {
-    m_sourceUnits.push_back(unit);
-}
-
-/**
- * @brief Starts a new source unit.
- *
- * Saves the current source position onto the top of stack.
- * Pushes the source unit onto the top of stack.
- *
- * @param unit      the source unit
- * @param caller    the position of the include
- *
- */
-bool RplSource::startUnit(RplSourceUnitName unit,
-                          const RplSourcePosition& caller) {
-    m_sourcePositionStack.push_back(&caller);
-    RplReader* reader = NULL;
-    QList<RplReader*>::iterator it;
-    for(it = m_readers.begin();
-            reader == NULL && it != m_readers.end();
-            it++) {
-        RplReader* current = *it;
-        if(current->openSourceUnit(unit)) {
-            reader = current;
-            m_currentReader = current;
-            break;
-        }
-    }
-    return reader != NULL;
-}
-
-/**
- * @brief Pushes a source unit onto the stack.
- *
- * @param unit      the source unit
- */
-void RplSource::pushSourceUnit(RplSourceUnit* unit) {
-    m_unitStack.push(unit);
-}
-
-/**
- * @brief Removes the latest source unit from the stack.
- *
- * @param reader    the current reader
- * @return          NULL: the current reader does not have an open source unit<br>
- *                  otherwise: the last entry from the source unit stack
- */
-RplSourceUnit* RplSource::popSourceUnit(RplReader* reader) {
-    RplSourceUnit* rc = NULL;
-    if(m_unitStack.size() > 0)
-        m_unitStack.pop();
-    m_currentReader = m_unitStack.size() <= 0
-                      ? NULL : m_unitStack.top()->reader();
-    if(m_currentReader == reader)
-        rc = m_unitStack.top();
-    else {
-        for(int ix = m_unitStack.size() - 2; ix >= 0; ix--){
-            if(m_unitStack[ix]->reader() == reader){
-                rc = m_unitStack[ix];
-                break;
-            }
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Returns the reader of the current source unit.
- *
- * @return  NULL: no reader active<br>
- *          otherwise: the current reader
- */
-RplReader* RplSource::currentReader() {
-    return m_currentReader;
-}
-
-/**
- * @brief Returns a new instance of the current source position.
- *
- * The storage is done in a block (efficency).
- *
- * @param colNo     the column in the line
- * @return          a new instance of a source position
- */
-const RplSourcePosition* RplSource::newPosition(int colNo)
-{
-    if (m_countPositionBlock >= RPL_POSITIONS_PER_BLOCK){
-        RplSourcePositionBlock* newBlock = new RplSourcePositionBlock;
-        newBlock->m_successor = m_sourcePositionBlock;
-        m_sourcePositionBlock = newBlock;
-        m_countPositionBlock = 0;
-    }
-    unsigned offset = m_countPositionBlock * sizeof(RplSourcePosition);
-    m_countPositionBlock++;
-    char* posInBlock = &m_sourcePositionBlock->m_positions[offset];
-    RplSourceUnit* unit = dynamic_cast<RplSourceUnit*>(
-                m_currentReader->currentSourceUnit());
-    RplSourcePosition* rc = new (posInBlock) RplSourcePosition(
-                unit, unit->lineNo(), colNo);
-    return rc;
-}
-
-/**
- * @brief Resets all states in the source.
- */
-void RplSource::clear()
-{
-    destroy();
-}
-
-/**
- * @brief Returns the top position of the source unit stack.
- *
- * @return  NULL: stack is empty<br>
- *          the top of the source unit stack
- */
-const RplSourcePosition* RplSource::caller() const
-{
-    return m_sourcePositionStack.size() == 0
-            ? NULL : m_sourcePositionStack.top();
-}
-
-/** @class RplStringSourceUnit rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Stores the state of a string based source unit.
- *
- */
-
-/**
- * @brief Constructor.
- *
- * @param name      name of the unit
- * @param content   content of the unit
- * @param reader    the parent
- */
-RplStringSourceUnit::RplStringSourceUnit(RplSourceUnitName name,
-        const RplSourceUnitContent& content, RplStringReader* reader) :
-    RplSourceUnit(name, reader),
-    m_currentPosition(0),
-    m_content(content) {
-}
-
-/**
- * @brief Destructor.
- */
-RplStringSourceUnit::~RplStringSourceUnit() {
-}
-/**
- * @brief Returns the current read position.
- *
- * @return      the offset (count of QChars) of the end of the last read block
- *              inside m_content
- */
-int RplStringSourceUnit::currentPosition() const {
-    return m_currentPosition;
-}
-
-/**
- * @brief Sets the current read position.
- *
- * @param currentPosition   the offset (count of QChars) of the end of
- *                          the last read block inside <code>m_content</code>
- */
-void RplStringSourceUnit::setCurrentPosition(int currentPosition) {
-    m_currentPosition = currentPosition;
-}
-/**
- * @brief Returns the content of the source unit.
- *
- * @return  the content
- */
-RplSourceUnitContent RplStringSourceUnit::content() const {
-    return m_content.constData();
-}
-
-/** @class RplStringReader rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Implements a source which provides reading from memory based buffers.
- *
- * Examples for usage: interactive input
- */
-
-/**
- * @brief Constructor.
- *
- * @param source    the parent
- */
-RplStringReader::RplStringReader(RplSource& source) :
-    RplReader(source) {
-}
-
-/**
- * @brief Destructor.
- */
-RplStringReader::~RplStringReader() {
-    clear();
-}
-
-/**
- * @brief Opens a new source unit.
- *
- * @param unit  name of the source
- * @return      NULL: unknown source<br>
- *              otherwise: an instance of a sub class of
- *              <code>RplSourceUnit</code>
- */
-RplSourceUnit* RplStringReader::openSourceUnit(RplSourceUnitName unit) {
-    RplSourceUnit* rc = NULL;
-    if(setCurrentSourceUnit(unit)) {
-        rc = m_currentSourceUnit;
-        ((RplStringSourceUnit*) rc)->setCurrentPosition(0);
-    }
-    return rc;
-}
-/**
- * @brief Delivers the next line from the input medium or the first part of it.
- *
- * @param maxSize   if the line length is longer than this value, only the
- *                  first part of the line will be returned
- * @param buffer    OUT: the line will be put here
- * @param hasMore   true: the line was longer than <code>maxSize</code>, only
- *                  the first part of the line is put into the <code>buffer</code>
- * @return          false: no more input available<br>
- *                  true: success
- */
-bool RplStringReader::nextLine(int maxSize, QByteArray& buffer, bool& hasMore) {
-    bool rc = m_currentSourceUnit != NULL;
-    if (rc){
-        m_currentSourceUnit->setLineNo(m_currentSourceUnit->lineNo() + 1);
-        rc = fillBuffer(maxSize, buffer, hasMore);
-    }
-    return rc;
-}
-
-/**
- * @brief Delivers the next part of a long line.
- *
- * @param maxSize   if the remaining line length is longer than this value,
- *                  only the a part of the line will be returned
- * @param buffer    OUT: the part of line will be put here
- * @param hasMore   true: the line was longer than <code>maxSize</code>, only
- *                  the first part of the line is put into the <code>buffer</code>
- * @return          false: no more input available<br>
- *                  true: success
- */
-bool RplStringReader::fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore) {
-    RplStringSourceUnit* unit  = (RplStringSourceUnit*) m_currentSourceUnit;
-    RplSourceUnitContent content = unit->content();
-    int startPos = unit->currentPosition();
-    const char* start = content + startPos;
-    const char* end = strchr(start, '\n');
-    hasMore = false;
-    int size = end == NULL ? strlen(start) : end - start + 1;
-    hasMore = false;
-    if(size > maxSize) {
-        size = maxSize;
-        hasMore = true;
-    }
-    if(size > 0) {
-        buffer.append(start, size);
-        unit->setCurrentPosition(startPos + size);
-    } else {
-        removeSourceUnit();
-    }
-    return size > 0;
-}
-
-/**
- * @brief Adds a source buffer to the reader
- *
- * @param name      name of the medium
- * @param content
- */
-void RplStringReader::addSource(RplSourceUnitName name,
-                                RplSourceUnitContent content) {
-    // Deletion in the destructor of the base class RplReader
-    RplStringSourceUnit* unit = new RplStringSourceUnit(name, content, this);
-    m_units.insert(m_units.begin(), unit->name(), unit);
-    m_currentSourceUnit = unit;
-}
-
-/**
- * @brief Replaces the content of a source unit.
- *
- * @param name      name of the source unit
- * @param content   new content
- */
-void RplStringReader::replaceSource(RplSourceUnitName name,
-                                    RplSourceUnitContent content)
-{
-    if (m_units.contains(name)){
-        RplStringSourceUnit* unit = dynamic_cast<RplStringSourceUnit*>(m_units[name]);
-        unit->m_content = content;
-    }
-}
-
-/** @class RplFileSourceUnit rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Stores the state of a file based source unit.
- *
- * This is the mostly used implementation of the RplSourceUnit/RplReader.
- */
-
-
-RplFileSourceUnit::RplFileSourceUnit(RplSourceUnitName filename,
-                                     RplFileReader* reader) :
-    RplSourceUnit(filename, reader),
-    m_currentPosition(0),
-    m_fp(fopen(filename, "r")),
-    m_textStream(m_fp, QIODevice::ReadOnly),
-    m_line()
-{
-}
-
-
-/**
- * @brief Destructor.
- */
-RplFileSourceUnit::~RplFileSourceUnit()
-{
-    fclose(m_fp);
-}
-
-bool RplFileSourceUnit::isOpen() const
-{
-    return m_fp != NULL;
-}
-/** @class RplFileReader rplsource.hpp "rplexpr/rplsource.hpp"
- *
- * @brief Implements a source which provides reading from memory based buffers.
- *
- * Examples for usage: interactive input
- */
-
-/**
- * @brief Constructor.
- */
-RplFileReader::RplFileReader(RplSource& source) :
-    RplReader(source)
-{
-}
-
-/**
- * @brief Destructor.
- */
-RplFileReader::~RplFileReader() {
-}
-
-/**
- * @brief Opens a new source unit.
- *
- * @param unit  name of the source
- * @return      NULL: unknown source<br>
- *              otherwise: an instance of a sub class of
- *              <code>RplSourceUnit</code>
- */
-RplSourceUnit* RplFileReader::openSourceUnit(RplSourceUnitName unit) {
-    RplSourceUnit* rc = NULL;
-    if(m_units.contains(unit)) {
-        rc = *m_units.find(unit);
-        m_currentSourceUnit = static_cast<RplFileSourceUnit*>(rc);
-    }
-    return rc;
-}
-/**
- * @brief Delivers the next line from the input medium or the first part of it.
- *
- * @param maxSize   if the line length is longer than this value, only the
- *                  first part of the line will be returned
- * @param buffer    OUT: the line will be put here
- * @param hasMore   true: the line was longer than <code>maxSize</code>, only
- *                  the first part of the line is put into the <code>buffer</code>
- * @return          false: no more input available<br>
- *                  true: success
- */
-bool RplFileReader::nextLine(int maxSize, QByteArray& buffer, bool& hasMore) {
-    RplFileSourceUnit* unit  = static_cast<RplFileSourceUnit*>
-            (m_currentSourceUnit);
-    bool rc = ! feof(unit->m_fp);
-    if(! rc) {
-        m_source.popSourceUnit(this);
-    } else {
-        m_currentSourceUnit->setLineNo(m_currentSourceUnit->lineNo() + 1);
-        unit->m_currentPosition = 0;
-        QByteArray& line = unit->m_line;
-        line.reserve(maxSize+1);
-        if (fgets(line.data(), maxSize, unit->m_fp) == NULL)
-            rc = false;
-        else{
-            line[maxSize] = '\0';
-            line.resize(strlen(line.constData()));
-            rc = fillBuffer(maxSize, buffer, hasMore);
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Delivers the next part of a long line.
- *
- * @param maxSize   if the remaining line length is longer than this value,
- *                  only the a part of the line will be returned
- * @param buffer    OUT: the part of line will be put here
- * @param hasMore   true: the line was longer than <code>maxSize</code>, only
- *                  the first part of the line is put into the <code>buffer</code>
- * @return          false: no more input available<br>
- *                  true: success
- */
-bool RplFileReader::fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore) {
-    RplFileSourceUnit* unit  = static_cast<RplFileSourceUnit*>(m_currentSourceUnit);
-    int start = unit->m_currentPosition;
-    QByteArray& content = unit->m_line;
-    int size = content.size() - start;
-    if(size > maxSize)
-        size = maxSize;
-    buffer += content.mid(start, size);
-    unit->m_currentPosition = (start += size);
-    hasMore = start < content.size();
-    return size > 0;
-}
-
-/**
- * @brief Adds a source file to the reader
- *
- * @param filename  the file' name (relative or absolute)
- */
-void RplFileReader::addSource(RplSourceUnitName filename) {
-    // Deleting in ~RplSourceUnit():
-    RplFileSourceUnit* unit = new RplFileSourceUnit(filename, this);
-    m_units.insert(m_units.begin(), unit->name(), unit);
-    m_currentSourceUnit = unit;
-}
-
-
diff --git a/rplexpr/rplsource.hpp b/rplexpr/rplsource.hpp
deleted file mode 100644 (file)
index 40f80b9..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLSOURCE_HPP
-#define RPLSOURCE_HPP
-
-// type of buffer names and filenames. Codec: UTF-8
-typedef const char* RplSourceUnitName;
-
-typedef const char*  RplSourceUnitContent;
-
-class RplSource;
-class RplReader;
-
-class RplSourceUnit {
-public:
-    RplSourceUnit(const char* name, RplReader* reader);
-    virtual ~RplSourceUnit();
-public:
-    const char* name() const;
-    int lineNo() const;
-    void setLineNo(int lineNo);
-    RplReader* reader() const;
-
-protected:
-    QByteArray m_name;
-    int m_lineNo;
-    RplReader* m_reader;
-};
-
-class RplSourcePosition {
-public:
-    RplSourcePosition();
-    RplSourcePosition(RplSourceUnit* unit, int lineNo, int colNo);
-    ~ RplSourcePosition();
-    void* operator new(size_t cbSize, void* buffer);
-private:
-    /// forbid usage of the copy constructor!
-    RplSourcePosition(const RplSourcePosition& source);
-    /// forbid usage of the the assignment!
-    RplSourcePosition& operator=(const RplSourcePosition& source);
-public:
-    QString toString() const;
-    int lineNo() const;
-    void setLineNo(int lineNo);
-
-    int column() const;
-    void setColumn(int column);
-
-    RplSourceUnit* sourceUnit() const;
-    void setSourceUnit(RplSourceUnit* sourceUnit);
-    char*utf8(char buffer[], size_t bufferSize) const;
-private:
-    RplSourceUnit* m_sourceUnit;
-    int m_lineNo;
-    int m_column;
-    const RplSourcePosition* m_caller;
-};
-
-class RplReader {
-public:
-    typedef RplCharPtrMap<RplSourceUnit*> UnitMap;
-public:
-    RplReader(RplSource& source);
-    ~RplReader();
-public:
-    /**
-     * @brief Prepares the reading from a given source unit.
-     *
-     * @param unit  name of the unit
-     * @return      NULL: unit not known<br>
-     *              otherwise: an instance with the state of the reader
-     *              for the source. This is normally a sub class of
-     *              <code>RplSourceUnit</code>
-     */
-    virtual RplSourceUnit* openSourceUnit(const char* unit) = 0;
-    /**
-     * @brief Reads the first part of the next line into a given buffer.
-     *
-     * @param maxSize   the maximum length of the read input.
-     *                  If a line is longer the next part must be read
-     *                  by <code>fillBuffer()</code>
-     * @param buffer    IN/OUT: the read input will be appended here
-     * @param hasMore   OUT: true: the line is longer than maxSize
-     * @return          true: the read was successful<br>
-     *                  false: no more input is available
-     */
-    virtual bool nextLine(int maxSize, QByteArray& buffer, bool& hasMore) = 0;
-    /**
-     * @brief Reads the next part of the current line into a given buffer.
-     *
-     * @param maxSize   the maximum length of the read input.
-     * @param buffer    IN/OUT: the read input will be appended here
-     * @param hasMore   OUT: true: the rest of line is longer than maxSize
-     * @return          true: the read was successful<br>
-     *                  false: no more input is available
-     */
-    virtual bool fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore) = 0;
-public:
-    virtual void clear();
-    RplSource& source();
-    RplSourceUnit* currentSourceUnit() const;
-    bool setCurrentSourceUnit(RplSourceUnitName& currentSourceUnit);
-protected:
-    void removeSourceUnit();
-
-protected:
-    RplSourceUnit* m_currentSourceUnit;
-    /// name -> source
-    UnitMap m_units;
-    RplSource& m_source;
-};
-
-#define RPL_POSITIONS_PER_BLOCK 512
-class RplSourcePositionBlock{
-    friend class RplSource;
-public:
-    RplSourcePositionBlock();
-private:
-    RplSourcePositionBlock* m_successor;
-    char m_positions[RPL_POSITIONS_PER_BLOCK * sizeof(RplSourcePosition)];
-};
-
-class RplSource {
-public:
-    RplSource();
-    virtual ~RplSource();
-public:
-    virtual const char* permanentUnitName(const char* unit);
-    void finishSourceUnit();
-    void addReader(RplReader* reader);
-    void addSourceUnit(RplSourceUnit* unit);
-    QStack<const RplSourcePosition*> sourcePositionStack() const;
-    QStack<RplSourceUnit*>& sourceUnitStack();
-
-    bool startUnit(const char* unit, const RplSourcePosition& caller);
-    void pushSourceUnit(RplSourceUnit* unit);
-    RplSourceUnit* popSourceUnit(RplReader* reader);
-    RplReader* currentReader();
-    const RplSourcePosition* newPosition(int colNo);
-    void clear();
-    const RplSourcePosition* caller() const;
-protected:
-    void destroy();
-protected:
-    // stack of the info about the stacked (open) source units:
-    QStack<const RplSourcePosition*> m_sourcePositionStack;
-    RplSourcePositionBlock* m_sourcePositionBlock;
-    int m_countPositionBlock;
-    QList<RplReader*> m_readers;
-    QList<RplSourceUnit*> m_sourceUnits;
-    // setCurrentSourceUnit() pushes one entry, removeSourceUnit() pops it
-    // (when end of input has been reached).
-    QStack<RplSourceUnit*> m_unitStack;
-    RplReader* m_currentReader;
-};
-
-class RplStringReader;
-
-class RplStringSourceUnit : public RplSourceUnit {
-    friend class RplStringReader;
-public:
-    RplStringSourceUnit(RplSourceUnitName name,
-                        const RplSourceUnitContent& content,
-                        RplStringReader* reader);
-    virtual ~RplStringSourceUnit();
-public:
-    int currentPosition() const;
-    void setCurrentPosition(int currentPosition);
-    RplSourceUnitContent content() const;
-
-private:
-    int m_currentPosition;
-    QByteArray m_content;
-};
-
-class RplStringReader : public RplReader{
-public:
-    RplStringReader(RplSource& source);
-    virtual ~RplStringReader();
-    // RplReader interface
-public:
-    virtual RplSourceUnit* openSourceUnit(RplSourceUnitName unit);
-    virtual bool nextLine(int maxSize, QByteArray& buffer, bool& hasMore);
-    virtual bool fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore);
-public:
-    void addSource(RplSourceUnitName name, RplSourceUnitContent content);
-    void replaceSource(RplSourceUnitName name, RplSourceUnitContent content);
-};
-
-class RplFileReader;
-
-class RplFileSourceUnit : public RplSourceUnit {
-    friend class RplFileReader;
-public:
-    RplFileSourceUnit(RplSourceUnitName filename, RplFileReader* reader);
-    virtual ~RplFileSourceUnit();
-public:
-    bool isOpen() const;
-private:
-    int m_currentPosition;
-    FILE* m_fp;
-    QTextStream m_textStream;
-    QByteArray m_line;
-};
-
-class RplFileReader : public RplReader{
-public:
-    RplFileReader(RplSource& source);
-    virtual ~RplFileReader();
-    // RplReader interface
-public:
-    virtual RplSourceUnit* openSourceUnit(RplSourceUnitName unit);
-    virtual bool nextLine(int maxSize, QByteArray& buffer, bool& hasMore);
-    virtual bool fillBuffer(int maxSize, QByteArray& buffer, bool& hasMore);
-public:
-    void addSource(RplSourceUnitName filename);
-};
-
-
-#endif // RPLSOURCE_HPP
diff --git a/rplexpr/rplvm.cpp b/rplexpr/rplvm.cpp
deleted file mode 100644 (file)
index 9598c23..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- *
- * @brief Implements an interpreter of an abstract syntax tree.
- */
-
-/** @file rplexpr/rplvm.hpp
- *
- * @brief Definitions for an interpreter of an abstract syntax tree.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-
-enum {
-    LOC_VAL_OF_VAR_1 = RPL_FIRST_OF(RPL_MODULE_VM), // 11401
-    LOC_UNOP_1,
-    LOC_UNOP_2,
-    LOC_UNOP_3,
-    LOC_UNOP_4, // 10005
-    LOC_BINOP_1,
-    LOC_COUNT
-};
-
-int RplVMThread::m_nextId = 1;
-
-/** @class RplVmException rplvm.hpp "rplexpr/rplvm.hpp"
- *
- * @brief Implements an exception for the virtual machine.
- *
- */
-/**
- * @brief Constructor
- * @param format    the message with placeholders
- * @param ...       the values for the placeholders
- */
-RplVmException::RplVmException(const char* format, ...) :
-    RplException("")
-{
-    char buffer[16000];
-    va_list ap;
-    va_start(ap, format);
-    qvsnprintf(buffer, sizeof buffer, format, ap);
-    va_end(ap);
-    m_message = buffer;
-}
-
-/** @class RplStackFrame rplvm.hpp "rplexpr/rplvm.hpp"
- *
- * @brief Implements the storage for a symbol space.
- *
- * The owner of a symbol space can be "global", a module, a class, or a method.
- * Some symbol spaces have more than one stack frame, e.g. a recursive called
- * method.
- */
-
-
-/**
- * @brief Constructor.
- *
- * @param symbols   the symbol space belonging to the stack frame
- */
-
-RplStackFrame::RplStackFrame(RplSymbolSpace* symbols) :
-    m_countVariables(symbols->listOfVars().size()),
-    m_variables(NULL),
-    m_symbols(symbols)
-{
-    if (m_countVariables > 0)
-        m_variables = new RplASVariant[m_countVariables];
-}
-
-/**
- * @brief Destructor.
- */
-RplStackFrame::~RplStackFrame()
-{
-    delete[] m_variables;
-    m_variables = NULL;
-}
-
-/**
- * @brief Returns the storage of a variable given by the index.
- *
- * @param index the index of the variable
- *
- * @return      the storage of the variable
- */
-RplASVariant& RplStackFrame::valueOfVariable(int index)
-{
-    if (index < 0 || index >= m_countVariables)
-        throw RplVmException("valueOfVariable(): invalid index: %d", index);
-    return m_variables[index];
-}
-/**
- * @brief Returns the symbol space of the frame.
- *
- * @return  the symbol space
- */
-RplSymbolSpace* RplStackFrame::symbols() const
-{
-    return m_symbols;
-}
-
-/** @class RplVMThread rplvm.hpp "rplexpr/rplvm.hpp"
- *
- * @brief Implements a thread of the virtual machine.
- *
- * The virtual machine can execute many threads at the same time.
- * Each thread has its own stack.
- */
-
-/**
- * @brief Constructor.
- *
- * @param maxStack  the maximal number of nested stack frames
- * @param vm        the parent, the virtual machine
- */
-RplVMThread::RplVMThread(int maxStack, RplVirtualMachine* vm) :
-    m_id(m_nextId++),
-    m_debugMode(false),
-    m_singleStep(false),
-    m_tracing(false),
-    m_maxStack(maxStack),
-    m_frameStack(),
-    // the stack is never empty!
-    m_topOfFrames(0),
-    m_valueStack(),
-    // the stack is never empty!
-    m_topOfValues(0),
-    m_vm(vm),
-    m_logger(new RplLogger())
-{
-    QByteArray prefix = "vm_thread_" + QByteArray::number(m_id);
-    m_logger->buildStandardAppender(prefix);
-    m_frameStack.reserve(maxStack);
-    // the stack is never empty!
-    m_frameStack.append(new RplStackFrame(vm->tree().symbolSpaces()[0]));
-    // the stack is never empty!
-    m_valueStack.append(new RplASVariant);
-}
-
-/**
- * @brief Executes a statement list.
- *
- * @param statements    the first statement of a statement list chained by
- *                      <code>m_child</code>
- * @param space         the current symbol space
- */
-void RplVMThread::execute(RplASNode1* statements, RplSymbolSpace* space)
-{
-    bool debugMode = m_debugMode;
-    RplASNode1 *next;
-    while(statements != NULL){
-        if (debugMode
-                && (m_singleStep
-                    || (statements->flags() & RplASItem::NF_BREAKPOINT) != 0))
-            debug(statements);
-        RplASStatement* statement = dynamic_cast<RplASStatement*>(statements);
-        if (statement != NULL)
-            statement->execute(*this);
-        statements = dynamic_cast<RplASNode1*>(statements->child());
-    }
-}
-
-/**
- * @brief Handles a debugger break.
- *
- * @param statement the current statement (not yet executed)
- */
-void RplVMThread::debug(RplASNode1* statement)
-{
-
-}
-
-/**
- * @brief Returns the logger of the instance.
- *
- * @return  the logger
- */
-RplLogger* RplVMThread::logger() const
-{
-    return m_logger;
-}
-/**
- * @brief Reserves a value in the thread's value stack.
- *
- * @return  the reserved value
- */
-RplASVariant&RplVMThread::reserveValue()
-{
-    RplASVariant* rc;
-    if (++m_topOfValues < m_valueStack.size()){
-        rc = m_valueStack[m_topOfValues];
-        rc->destroyValue();
-    } else {
-        rc = new RplASVariant();
-        m_valueStack.append(rc);
-    }
-    return *rc;
-}
-
-/**
- * @brief Returns the top of the value stack.
- *
- * @return  the top of the value stack
- */
-RplASVariant& RplVMThread::topOfValues()
-{
-    RplASVariant& rc = *m_valueStack[m_topOfValues];
-    return rc;
-}
-
-
-/**
- * @brief Returns the entry under the top of the value stack.
- *
- * @return  the 2nd value the value stack
- */
-RplASVariant& RplVMThread::top2OfValues()
-{
-    RplASVariant& rc = *m_valueStack[m_topOfValues-1];
-    return rc;
-}
-
-/**
- * @brief Returns the top of stack and removes it.
- *
- * @return the old top of stack
- */
-RplASVariant& RplVMThread::popValue()
-{
-    RplASVariant& rc = *m_valueStack[m_topOfValues];
-    if (m_topOfValues > 0)
-        m_topOfValues--;
-    return rc;
-}
-
-/**
- * @brief Copies a variable value to the top of the stack.
- *
- * @param symbolSpace   the symbol space of the variable
- * @param variableNo    the current no of the variable in the symbol space
- */
-void RplVMThread::valueToTop(RplSymbolSpace* symbolSpace, int variableNo)
-{
-    //@ToDo
-}
-
-/**
- * @brief Returns the "left value" (of an assignment).
- * @param item
- * @return
- */
-RplASVariant& RplVMThread::lValue(RplASItem* item)
-{
-    RplASVariant* rc;
-    switch(item->nodeType()){
-    case AST_NAMED_VALUE:
-    {
-        RplASNamedValue* var = dynamic_cast<RplASNamedValue*>(item);
-        rc = &valueOfVariable(var->symbolSpace(), var->variableNo());
-        break;
-    }
-    default:
-        break;
-    }
-    return *rc;
-}
-
-/**
- * @brief Returns the reference of the value of a variable.
- *
- * @param symbolSpace   the symbol space
- * @param variableNo    the current number in the symbol space
- * @return
- */
-RplASVariant& RplVMThread::valueOfVariable(RplSymbolSpace* symbolSpace,
-                                          int variableNo)
-{
-    RplASVariant& rc = *m_valueStack[0];
-    int ix = m_topOfFrames;
-    RplStackFrame* frame = NULL;
-    for(int ix = m_topOfFrames; ix >= 0; ix--){
-        frame = m_frameStack[ix];
-        if (frame->symbols() == symbolSpace){
-            rc = frame->valueOfVariable(variableNo);
-            break;
-        }
-    }
-    if (frame == NULL)
-        m_logger->logv(LOG_ERROR, LOC_VAL_OF_VAR_1, "no frame has symbolspace %s",
-                      symbolSpace->name().constData());
-
-    return rc;
-}
-/**
- * @brief Returns whether each execution step should be dumped.
- * @return  true: tracing is on<br>
- *          false: otherwise
- */
-bool RplVMThread::tracing() const
-{
-    return m_tracing;
-}
-
-/**
- * @brief Sets the tracing flag: if set each execution step is dumped.
- * @param tracing   true: tracing will be done<br>
- *                  false: tracing will not be done
- */
-void RplVMThread::setTracing(bool tracing)
-{
-    m_tracing = tracing;
-}
-
-/**
- * @brief Returns the parent, a virtual machine.
- *
- * @return  the virtual machine
- */
-RplVirtualMachine* RplVMThread::vm() const
-{
-    return m_vm;
-}
-
-/** @class RplVirtualMachine rplvm.hpp "rplexpr/rplvm.hpp"
- *
- * @brief Implements a virtual machine.
- *
- * This is an execution unit which interprets an abstract syntax tree.
- */
-RplVirtualMachine::RplVirtualMachine(RplASTree& tree, RplSource& source,
-                                     int maxStack) :
-    m_maxStack(maxStack),
-    m_threads(),
-    m_flags(VF_UNDEF),
-    m_source(source),
-    m_tree(tree),
-    m_trace()
-{
-    m_threads.reserve(8);
-    m_trace.reserve(1024);
-}
-
-/**
- * @brief Executes the program in a module.
- *
- * @param module    the module's name
- */
-void RplVirtualMachine::executeModule(const char* module)
-{
-    RplSymbolSpace* space = m_tree.findmodule(module);
-    if (space == NULL)
-        throw RplVmException("module not found: %s", module);
-    RplStackFrame frame(space);
-    RplSymbolSpace* mainSpace = NULL;
-    RplASItem* mainStatements = NULL;
-    RplASMethod* method = space->findMethod("main");
-    if (method != NULL){
-        mainStatements = method->child();
-        mainSpace = method->symbols();
-    }
-    addThread(space->body(), space, mainStatements, mainSpace);
-}
-
-/**
- * @brief Adds a thread to the instance.
- *
- * @param initialization        the statements for initialization
- * @param spaceInitialization   the symbol space of the initialization
- * @param statements            the statement list to execute. This is normally
- *                              the body of the main program
- * @param space                 the symbol space of the statements, normally
- *                              the symbol space of the main program
- * @param maxStack  the maximal number of nested stack frames.
- *                  <= 0: use the default
- */
-void RplVirtualMachine::addThread(RplASItem* initialization,
-                                  RplSymbolSpace* spaceInitialization,
-                                  RplASItem* statements,
-                                  RplSymbolSpace* space,
-                                  int maxStack)
-{
-    RplVMThread* thread = new RplVMThread(
-                maxStack <= 0 ? m_maxStack : maxStack, this);
-    m_threads.append(thread);
-    if (initialization != NULL){
-        thread->execute(dynamic_cast<RplASNode1*>(initialization),
-                        spaceInitialization);
-    }
-    if (statements != NULL)
-        thread->execute(dynamic_cast<RplASNode1*>(statements), space);
-}
-/**
- * @brief Tests whether a given flag is set.
- *
- * @param flag      flag to test
- * @return          true: the flag is set<br>
- *                  false: otherwise
- */
-bool RplVirtualMachine::hasFlag(RplVirtualMachine::VMFlag flag) const
-{
-    bool rc = (m_flags & flag) != 0;
-    return rc;
-}
-/**
- * @brief Adds a flag to the current flags.
- *
- * @param flag
- * @return
- */
-void RplVirtualMachine::setFlag(RplVirtualMachine::VMFlag flag)
-{
-    m_flags |= flag;
-}
-
-/**
- * @brief Adds a flag to the current flags.
- *
- * @param flag
- * @return
- */
-void RplVirtualMachine::clearFlag(RplVirtualMachine::VMFlag flag)
-{
-    m_flags &= ~flag;
-}
-
-/**
- * @brief Returns the trace writer.
- * @return  the trace writer
- */
-RplWriter* RplVirtualMachine::traceWriter() const
-{
-    return m_traceWriter;
-}
-
-/**
- * @brief Sets the trace writer.
- *
- * @param traceWriter   the new writer
- */
-void RplVirtualMachine::setTraceWriter(RplWriter* traceWriter)
-{
-    m_traceWriter = traceWriter;
-}
-/**
- * @brief Returns the abstract symbol tree.
- *
- * @return  the abstract symbol tree
- */
-RplASTree& RplVirtualMachine::tree() const
-{
-    return m_tree;
-}
-
diff --git a/rplexpr/rplvm.hpp b/rplexpr/rplvm.hpp
deleted file mode 100644 (file)
index a22d860..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLVM_HPP
-#define RPLVM_HPP
-
-class RplVmException : public RplException {
-public:
-    RplVmException(const char* message, ...);
-};
-class RplStackFrame {
-public:
-    RplStackFrame(RplSymbolSpace* symbols);
-    ~RplStackFrame();
-public:
-    RplASVariant& valueOfVariable(int index);
-    RplSymbolSpace* symbols() const;
-
-private:
-    int m_countVariables;
-    RplASVariant* m_variables;
-    RplSymbolSpace* m_symbols;
-};
-
-class RplVirtualMachine;
-class RplVMThread
-{
-    friend class RplASItem;
-    friend class RplASStatement;
-    friend class RplASCalculable;
-    friend class RplASCondition;
-public:
-    typedef QList<RplStackFrame*> StackFrameList;
-public:
-    RplVMThread(int maxStack, RplVirtualMachine* vm);
-public:
-    void execute(RplASNode1* statements, RplSymbolSpace* space);
-    virtual void debug(RplASNode1* statement);
-    RplWriter* errorWriter() const;
-    void setErrorWriter(RplWriter* errorWriter);
-    RplLogger* logger() const;
-    RplASVariant& reserveValue();
-    RplASVariant& topOfValues();
-    RplASVariant& top2OfValues();
-    RplASVariant& popValue();
-    void valueToTop(RplSymbolSpace* symbolSpace, int variableNo);
-    RplASVariant& lValue(RplASItem* item);
-    RplASVariant& valueOfVariable(RplSymbolSpace* symbolSpace, int variableNo);
-    bool tracing() const;
-    void setTracing(bool tracing);
-    RplVirtualMachine* vm() const;
-
-protected:
-    int m_id;
-    bool m_debugMode;
-    bool m_singleStep;
-    bool m_tracing;
-    int m_maxStack;
-    StackFrameList m_frameStack;
-    int m_topOfFrames;
-    QList<RplASVariant*> m_valueStack;
-    int m_topOfValues;
-    RplVirtualMachine* m_vm;
-    RplLogger* m_logger;
-private:
-    static int m_nextId;
-};
-
-class RplVirtualMachine
-{
-public:
-    enum VMFlag {
-        VF_UNDEF,
-        VF_TRACE_STATEMENTS     = 1<<1,
-        VF_TRACE_LOCALS         = 1<<2,
-        VF_TRACE_AUTO_VARIABLES = 1<<3
-
-    };
-    typedef QList<const char*> LineList;
-public:
-    RplVirtualMachine(RplASTree& tree, RplSource& source, int maxStack = 1024);
-public:
-    void executeModule(const char* module);
-    void addThread(RplASItem* initialization,
-                   RplSymbolSpace* spaceInitialization,
-                   RplASItem* statements, RplSymbolSpace* space,
-                   int maxStack = 0);
-    bool hasFlag(VMFlag flag) const;
-    void setFlag(VMFlag flag);
-    void clearFlag(VMFlag flag);
-    RplWriter* traceWriter() const;
-    void setTraceWriter(RplWriter* traceWriter);
-    RplASTree& tree() const;
-
-private:
-    int m_maxStack;
-    QList<RplVMThread*> m_threads;
-    int m_flags;
-    RplSource& m_source;
-    RplASTree& m_tree;
-    LineList m_trace;
-    RplWriter* m_traceWriter;
-};
-
-#endif // RPLVM_HPP
diff --git a/rplmath/rplenigma.cpp b/rplmath/rplenigma.cpp
deleted file mode 100644 (file)
index eefa89b..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- *
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-/** @file
- *
- * @brief Implements encryption and decryption engines.
- */
-/** @file rplmath/rplenigma.hpp
- *
- * @brief Definitions for encryption and decryption engines.
- */
-
-#include "rplmath/rplmath.hpp"
-
-/** @class RplEnigma::secret_t rplenigma.hpp "rplmath/rplenigma.hpp"
- *
- * @brief Stores the internal structure of a <b>secret</b>.
- *
- * A secret can be a password, a salt, a certificate or simlar
- * which makes an encryption individually.
- */
-/** @class RplEnigma rplenigma.hpp "rplmath/rplenigma.hpp"
- *
- * @brief Implements a portable en/decryption engine.
- *
- * It is used a symetric encryption.
- * Therefore the encrypt methods can be used for decryption too.
- *
- * The encryption can be unique by using certificates.
- * A certificate is a series of bytes affecting the pseudo random sequence.
- *
- * More than one certificate can be used.
- *
- * The encryption is done with an pseudo random generator.
- *
- * The portability (over byte order) is guaranteed if the
- * pseudo random generator is portable (nomalizing big/little endian)
- * and a 64 bit integer arithmetic is available.
- *
- */
-const char* RplEnigma::SET_DECIMALS = "0123456789";
-const char* RplEnigma::SET_HEXDIGITS = "0123456789abcdef";
-const char* RplEnigma::SET_ALPHANUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                      "abcdefghijklmnopqrstuvwxyz_";
-const char* RplEnigma::SET_FILENAME = " !^°$%&=+~#-.0123456789ABCDEFGHIJKLM"
-                                      "NOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
-const char* RplEnigma::SET_32_127 = " !\"#$%&'()*+,-./0123456789:;<=>?@"
-                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f";
-const char* RplEnigma::SET_32_255 = " !\"#$%&'()*+,-./0123456789:;<=>?@"
-                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
-                                    "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-                                    "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-                                    "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-                                    "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
-const char* RplEnigma::SET_PRINTABLE_127 =
-    "\t\r\n !\"#$%&'()*+,-./0123456789:;<=>?@"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f";
-const char* RplEnigma::SET_PRINTABLE_255 =
-    "\t\r\n !\"#$%&'()*+,-./0123456789:;<=>?@"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
-    "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
-    "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
-    "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
-    "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
-
-/**
- * @brief Constructor.
- *
- * @param random    pseudo random generator
- */
-RplEnigma::RplEnigma(RplRandom* random) :
-    m_random(random),
-    m_ownsRandom(false),
-    m_secrets(),
-    m_randomCalls(0),
-    m_randomSource("4711") {
-    m_randomSource.reserve(8096);
-    if(random == NULL) {
-        m_random = new RplRandom();
-        m_ownsRandom = true;
-    }
-}
-/**
- * @brief Destructor.
- */
-RplEnigma::~RplEnigma() {
-    if(m_ownsRandom) {
-        delete m_random;
-        m_random = NULL;
-    }
-}
-
-/**
- * @brief Reads a certificate.
- *
- * @param filename      the name of the certificate
- *
- * @return              empty string: error while reading<br>
- *                      otherwise: the certificate as byte array
- */
-QByteArray RplEnigma::readCertificate(const char* filename) {
-    QByteArray rc = "not implemented: readCertificate(): ";
-    rc += filename;
-    assert(rc.isEmpty());
-    return rc;
-}
-
-inline void buildBooster(QByteArray& booster, const char* charSet) {
-    int size = 257;
-    booster.fill(0, size);
-    int ix = 0;
-    unsigned char cc;
-    while((cc = (unsigned char) *charSet++) != '\0') {
-        booster[cc] = ++ix;
-    }
-    booster[0] = ix;
-}
-
-/**
- * @brief Encodes a string in place with a given character set.
- *
- * If a character of data is not included in the character set
- * it remains unchanged
- *
- * @param data      IN: data to encode<br>
- *                  OUT: data encoded
- * @param size      length of <code>data</code>. If 0
- * @param charSet   a string containing all valid characters
- * @param booster   a performance booster. Once built it can be shared
- *                  between all calls of encodeChar() and decodeChar()
- *                  with the same character set<br>
- *                  IN: "": not initialized otherwise: ready for work
- *                  OUT: ready for work
- */
-void RplEnigma::encode(char* data, int size, const char* charSet,
-                       QByteArray& booster) {
-    if(booster.length() == 0) {
-        buildBooster(booster, charSet);
-    }
-    int lengthOfCharSet = (int)(unsigned char) booster.at(0);
-    for(int ii = 0; ii < size; ii++) {
-        unsigned char cc = (unsigned char) data[ii];
-        int ix = booster.at(cc);
-        if(ix != 0) {
-            int next = nextInt(lengthOfCharSet);
-            int ix2 = (ix - 1 + next) % lengthOfCharSet;
-            data[ii] = charSet[ix2];
-        }
-    }
-}
-
-/**
- * @brief Decodes a string in place with a given character set.
- *
- * If a character of data is not included in the character set
- * it remains unchanged
- *
- * @param data      IN: data to decode<br>
- *                  OUT: data decoded
- * @param size      length of <code>data</code>. If 0
- * @param charSet   a string containing all valid characters
- * @param booster   a performance booster. Once built it can be shared
- *                  between all calls of encodeChar() and decodeChar()
- *                  with the same character set<br>
- *                  IN: "": not initialized otherwise: ready for work
- *                  OUT: ready for work
- */
-void RplEnigma::decode(char* data, int size, const char* charSet,
-                       QByteArray& booster) {
-    if(booster.length() == 0) {
-        buildBooster(booster, charSet);
-    }
-    int lengthOfCharSet = (int)(unsigned char) booster.at(0);
-    for(int ii = 0; ii < size; ii++) {
-        unsigned char cc = (unsigned char) data[ii];
-        int ix = booster.at(cc);
-        if(ix != 0) {
-            int next = nextInt(lengthOfCharSet);
-            int ix2 = (lengthOfCharSet + ix -1 - next) % lengthOfCharSet;
-            data[ii] = charSet[ix2];
-        }
-    }
-}
-/**
- * @brief Encodes or decode a byte array.
- *
- * The encoding method is symetric. Therefore it can encode and decode.
- *
- * @param data      IN: data to encode/decoded<br>
- *                  OUT: data encoded/decoded
- */
-void RplEnigma::change(QByteArray& data) {
-    int randomLength = m_randomSource.length();
-    for(int ix = data.length() - 1; ix >= 0; ix--) {
-        char item = data.at(ix);
-        item = (item ^ nextInt(0xff) ^ m_randomSource.at(ix % randomLength));
-        data[ix] = item;
-    }
-}
-
-/**
- * @brief Adds a random source given by an byte array.
- *
- * A random source can be the binary form of an certificate,
- * a salt, a password or similar.
- *
- * @param byteSecret  a byte sequence which influences the random generation
- */
-void RplEnigma::addByteSecret(QByteArray byteSecret) {
-    // we expand it to a multiple of 64 bit:
-    int oldSize = byteSecret.length();
-    int newSize = (oldSize + 7) / 8 * 8;
-    int ix;
-    if(newSize > oldSize) {
-        byteSecret.resize(newSize);
-        int sum = 0;
-        int start = oldSize > 8 ? oldSize - 8 : 0;
-        for(ix = start; ix < oldSize; ix++) {
-            sum += ix + byteSecret.at(ix);
-        }
-        for(ix = oldSize; ix < newSize; ix++) {
-            sum += ix + 7;
-            byteSecret[ix] = (char)(sum + byteSecret.at(ix-1));
-        }
-    }
-    int count = newSize / 8;
-    secret_t* secret = new secret_t();
-    secret->m_count = count;
-    secret->m_list = new u_int64_t[count];
-    m_secrets.append(secret);
-    for(ix = 0; ix < count; ix++) {
-        u_int64_t value = 0;
-        for(int ix2 = 0; ix2 < 8; ix2++)
-            value = (value << 8) + byteSecret.at(ix * 8 + ix2);
-        secret->m_list[ix] = value;
-    }
-    QByteArray value;
-    QCryptographicHash hash(QCryptographicHash::Md5);
-    RplRandom rand;
-    hash.addData(m_randomSource.constData(), 4);
-    for(ix = 0; ix < byteSecret.length(); ix++) {
-        hash.addData(byteSecret.constData() + ix, 1);
-        QByteArray current = hash.result();
-        int ix2 = rand.nextInt(0, m_randomSource.length() - 1);
-        m_randomSource[ix2] = (m_randomSource.at(ix2) ^ current.at(0));
-        m_randomSource.insert(0, current);
-    }
-}
-
-/**
- * @brief Returns the next random integer
- * @param maxValue
- * @return
- */
-int RplEnigma::nextInt(int maxValue) {
-    u_int64_t seed = 0;
-    QList<secret_t*>::const_iterator it;
-    int ixSecret = m_randomCalls++;
-    int ix = ixSecret;
-    for(it = m_secrets.constBegin(); it != m_secrets.constEnd(); ++it) {
-        secret_t* secret = *it;
-        seed |= ((secret->m_list[ixSecret % secret->m_count]) >> (ix % 8));
-    }
-    m_random->xorSeed(seed);
-    int rc = m_random->nextInt(0, maxValue);
-    return rc;
-}
-
-/**
- * @brief Sets the pseudo random to a define state.
- *
- * @param seed  the initial state
- */
-void RplEnigma::setSeed(u_int64_t seed) {
-    m_random->setSeed(seed);
-    m_randomCalls = 0;
-}
-
-// ------------------
-#if ! defined RPL_TEST
-#define RPL_TEST
-#endif
-#ifdef RPL_TEST
-#include "rplcore/rpltest.hpp"
-/**
- * @brief Unit test for <code>RplEnigma</code>.
- */
-class TestRplEnigma : public RplTest {
-public:
-    TestRplEnigma() : RplTest("RplEnigma") {}
-
-public:
-    void testOneCharset(const char* value, const char* charSet,
-                        const char* expected) {
-        RplEnigma enigma;
-        enigma.addByteSecret(QByteArray("Geheim"));
-        enigma.setSeed(0);
-        QByteArray encoded = value;
-        QByteArray booster;
-        enigma.encode(encoded.data(), encoded.length(), charSet, booster);
-        //printString(encoded.constData());
-        QByteArray decoded = encoded;
-        enigma.setSeed(0);
-        enigma.decode(decoded.data(), decoded.length(), charSet, booster);
-        checkE(value, decoded.constData());
-        checkE(expected, encoded);
-    }
-
-    void printCharSets() {
-        QByteArray value;
-        value.reserve(256);
-        unsigned char cc;
-        for(cc = ' '; cc <= 127; cc++) {
-            if(cc == '"' || cc == '\\')
-                value.append('\\');
-            value.append(cc);
-        }
-        printf("%s\n", value.constData());
-        value.resize(0);
-        for(cc = 128; cc >= 128; cc++) {
-            char buf[10];
-            if(cc % 32 == 0)
-                value.append("\n");
-            sprintf(buf, "\\x%02x", cc);
-            value.append(buf);
-        }
-        printf("%s\n", value.constData());
-    }
-    void printString(const char* value) {
-        QByteArray v;
-        unsigned char cc;
-        while((cc = (unsigned char) *value++) != 0) {
-            if(cc == '\\' || cc == '"') {
-                v.append('\\');
-                v.append(cc);
-            } else if(cc >= 127) {
-                char buffer[10];
-                sprintf(buffer, "\\x%02x", cc);
-                v.append(buffer);
-            } else {
-                v.append(cc);
-            }
-        }
-        printf("%s\n", v.constData());
-    }
-    void testOneBytes(const char* bytes) {
-        RplEnigma enigma;
-        enigma.addByteSecret("Hello World");
-        enigma.setSeed(0x1234);
-
-        QByteArray encoded(bytes);
-        enigma.change(encoded);
-
-        enigma.setSeed(0x1234);
-        QByteArray decoded(encoded);
-        enigma.change(decoded);
-        checkE(bytes, decoded);
-    }
-
-    void testBytes() {
-        testOneBytes("abcdefg");
-        testOneBytes("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
-    }
-
-    void testCharSet() {
-        //testOneCharset("&()[]{}Weiß der Geier/Kuckuck?", RplEnigma::SET_32_255, "2Kc\x9a\xfeQ\xd7\xa84sx)*\xfb\xd2z\xf4\"W\xb0\xee\xb0\xd1\x84\xace\xf8_u*T");
-        testOneCharset("\\Weiß der Geier/Kuckuck?", RplEnigma::SET_32_127,
-                       "(Z?hßaZ_#/QZ+Oi|SI^=<,)A");
-        testOneCharset("01234567890abcdef", RplEnigma::SET_HEXDIGITS,
-                       "c4c25b08735c53a63");
-        testOneCharset("data$1%3.^~", RplEnigma::SET_FILENAME, "^voazo-n%$b");
-        testOneCharset("Weiß der Geier!", RplEnigma::SET_ALPHANUM, "weyß BCk 19NoO!");
-        testOneCharset("12345678901234567890", RplEnigma::SET_DECIMALS,
-                       "97394833084815683977");
-        testOneCharset("000000000000000000000000000", RplEnigma::SET_DECIMALS,
-                       "850592651836811261879625929");
-    }
-
-    virtual void doIt() {
-        testBytes();
-        testCharSet();
-    }
-};
-
-#endif
-void testRplEnigma() {
-#ifdef RPL_TEST
-    TestRplEnigma test;
-    test.run();
-#endif
-}
diff --git a/rplmath/rplenigma.hpp b/rplmath/rplenigma.hpp
deleted file mode 100644 (file)
index e2ed1d3..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef RPLENIGMA_HPP
-#define RPLENIGMA_HPP
-
-class RplEnigma {
-public:
-    ///> '0'..'9'
-    static const char* SET_DECIMALS;
-    ///> '0'..'9' 'a'..'f'
-    static const char* SET_HEXDIGITS;
-    ///> '0'..'9' 'A'..'Z' a'..'z' '_'
-    static const char* SET_ALPHANUM;
-    ///> '0'..'9' 'A'..'Z' z'..'z' '_'
-    static const char* SET_FILENAME;
-    ///> ' ' .. chr(127)
-    static const char* SET_32_127;
-    ///> ' ' .. chr(255)
-    static const char* SET_32_255;
-    ///> TAB, CR, NL, ' '..chr(127)
-    static const char* SET_PRINTABLE_127;
-    ///> TAB, CR, NL, ' '..chr(255)
-    static const char* SET_PRINTABLE_255;
-
-protected:
-    typedef struct {
-        int m_count;
-        u_int64_t* m_list;
-    } secret_t;
-public:
-    RplEnigma(RplRandom* random = NULL);
-    virtual ~RplEnigma();
-private:
-    // No copy constructor: no implementation!
-    RplEnigma(const RplEnigma& source);
-    // Prohibits assignment operator: no implementation!
-    RplEnigma& operator =(const RplEnigma& source);
-public:
-    void encode(char* data, int size, const char* charSet, QByteArray& cache);
-    void decode(char* data, int size, const char* charSet, QByteArray& cache);
-    void change(QByteArray& data);
-    void addByteSecret(QByteArray byteSeed);
-    void setSeed(u_int64_t seed);
-    QByteArray readCertificate(const char* filename);
-protected:
-    int nextInt(int maxValue);
-
-protected:
-    ///> a pseudo random generator
-    RplRandom* m_random;
-    ///> true: m_random must be destroyed (in the destructor).
-    bool m_ownsRandom;
-    ///> This values will be mixed with <code>m_random</code>' seed
-    QList<secret_t*> m_secrets;
-    ///> each call of setSeed sets this value to 0.
-    int m_randomCalls;
-    ///> a byte sequence derived from the secrets
-    QByteArray m_randomSource;
-};
-
-#endif // RPLENIGMA_HPP
diff --git a/rplmath/rplmath.hpp b/rplmath/rplmath.hpp
deleted file mode 100644 (file)
index 81819e9..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLMATH_HPP
-#define RPLMATH_HPP
-
-#ifndef RPLCORE_HPP
-#include "rplcore/rplcore.hpp"
-#endif
-#include "rplmath/rplrandom.hpp"
-#include "rplmath/rplenigma.hpp"
-#include "rplmath/rplmatrix.hpp"
-
-#endif // RPLMATH_HPP
diff --git a/rplmath/rplmatrix.cpp b/rplmath/rplmatrix.cpp
deleted file mode 100644 (file)
index 872af7b..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * RplMatrix.cpp
- *
- *  Created on: 29.05.2014
- *      Author: hm
- */
-
-/** @file
- * @brief Implements 2 dimensional matrices.
- */
-/** @file rplmath/rplmatrix.hpp
- *
- * @brief Definitions for 2 dimensional matrices.
- */
-
-#include "rplmath/rplmath.hpp"
-
-RplMatrixException::RplMatrixException(const RplMatrix& RplMatrix,
-               const char* format, ...) :
-    RplException()
-{
-    if (! RplMatrix.getName().isEmpty())
-        m_message = RplMatrix.getName() + ": ";
-       char buffer[16*1024];
-
-       va_list args;
-       va_start(args, format);
-       qvsnprintf(buffer, sizeof buffer, format, args);
-       va_end(args);
-       m_message += buffer;
-}
-
-/**
- * Constructor.
- */
-RplMatrix::RplMatrix(const char* name) :
-       m_rows(0),
-       m_cols(0),
-       m_values(NULL),
-       m_name(name)
-{
-}
-
-/**
- * Constructor.
- *
- * @param rows         number of rows
- * @param cols         number of columns
- * @param name      the name of the matrix
- */
-RplMatrix::RplMatrix(int rows, int cols, const char* name):
-                       m_rows(rows),
-                       m_cols(cols),
-                       m_values(new MatVal[rows*cols]),
-                       m_name(name)
-{
-}
-/**
- * Destructor.
- */
-RplMatrix::~RplMatrix() {
-       delete m_values;
-       m_values = NULL;
-}
-
-/**
- * Copy constructor.
- *
- * @param source       source to copy
- */
-RplMatrix::RplMatrix(const RplMatrix& source) :
-       m_rows(0),
-    m_cols(0),
-       m_values(NULL),
-    m_name(source.m_name + QByteArray("-copy"))
-{
-       resize(source.m_rows, source.m_cols, source.m_values);
-}
-
-/**
- * Checks the validity of the definition parameters.
- *
- * @param rows         the row number
- * @param cols         the column number
- * @throws RplMatrixException
- */
-void RplMatrix::checkDefinition(int rows, int cols) const
-{
-       if (rows < 0)
-        throw RplMatrixException(*this, "row number negative: %d", rows);
-       if (cols < 0)
-        throw RplMatrixException(*this, "column number negative: %d", cols);
-       if (double(rows) * cols > 1.0*1000*1000)
-        throw RplMatrixException(*this, "too many elements: %d*%d", rows, cols);
-}
-
-/**
- * Checks the validity of the indexes.
- *
- * @param row  the RplMatrix row number: 0..N-1
- * @param col  the RplMatrix column number: 0..M-1
- * @throws RplMatrixException
- */
-void RplMatrix::check(int row, int col) const
-{
-       if (row < 0 || row >= m_rows)
-        throw RplMatrixException(*this, "invalid row: %d not in [0,%d[", row,
-                               m_rows);
-       if (col < 0 || col >= m_cols)
-        throw RplMatrixException(*this, "invalid column: %d not in [0,%d[", col,
-                               m_cols);
-}
-/**
- * Checks whether a given Matrix has the same dimensions.
- *
- * @param operand      Matrix to compare
- * @throws RplMatrixException
- */
-void RplMatrix::checkSameDimension(const RplMatrix& operand) const
-{
-       if (m_rows != operand.getRows())
-        throw RplMatrixException(*this,
-                "%s has a different row count: %d / %d",
-                 operand.getName().constData(), m_rows, operand.getRows());
-       if (m_cols != operand.getCols())
-        throw RplMatrixException(*this,
-                "%s has a different column count: %d / %d",
-                operand.getName().constData(), m_cols, operand.getCols());
-}
-
-/**
- * Assignment operator.
- *
- * @param source       the source to copy
- */
-RplMatrix& RplMatrix::operator =(const RplMatrix& source)
-{
-       resize(source.m_rows, source.m_cols, source.m_values);
-       return *this;
-}
-/**
- * Adds a Matrix to the instance.
- *
- * @param operand      Matrix to add
- * @return                     the instance itself
- */
-RplMatrix& RplMatrix::operator +=(const RplMatrix& operand)
-{
-       checkSameDimension(operand);
-       for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
-               m_values[ix] += operand.m_values[ix];
-       }
-       return *this;
-}
-/**
- * Subtracts a matrix from the instance.
- *
- * @param operand      matrix to subtract
- * @return                     the instance itself
- */
-RplMatrix& RplMatrix::operator -=(const RplMatrix& operand)
-{
-       checkSameDimension(operand);
-       for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
-               m_values[ix] -= operand.m_values[ix];
-       }
-       return *this;
-}
-/**
- * Builds the sum of the instance and a given matrix.
- *
- * @param operand      RplMatrix to add
- * @return                     a new RplMatrix with the sum
- */
-RplMatrix RplMatrix::operator +(const RplMatrix& operand)
-{
-    RplMatrix rc(*this);
-       rc += operand;
-       return rc;
-}
-/**
- * Builds the difference of the instance and a given matrix.
- *
- * @param operand      matrix to subtract
- * @return                     a new matrix with the difference
- */
-RplMatrix RplMatrix::operator -(const RplMatrix& operand)
-{
-    RplMatrix rc(*this);
-       rc -= operand;
-       return rc;
-}
-/**
- * Adds a scalar to the instance.
- *
- * @param scalar       scalar to add
- * @return                     the instance itself
- */
-RplMatrix& RplMatrix::operator +=(MatVal scalar)
-{
-       for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
-               m_values[ix] += scalar;
-       }
-       return *this;
-}
-/**
- * Adds a scalar to the instance.
- *
- * @param scalar       scalar to add
- * @return                     the instance itself
- */
-RplMatrix& RplMatrix::operator -=(MatVal scalar)
-{
-       for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
-               m_values[ix] -= scalar;
-       }
-       return *this;
-}
-/**
- * Builds the sum of the instance and a given scalar.
- *
- * @param scalar       scalar to add
- * @return                     a new matrix with the sum
- */
-RplMatrix RplMatrix::operator +(MatVal scalar)
-{
-    RplMatrix rc(*this);
-       rc += scalar;
-       return rc;
-}
-/**
- * Builds the difference of the instance and a given scalar.
- *
- * @param scalar       scalar to subtract
- * @return                     a new matrix with the sum
- */
-RplMatrix RplMatrix::operator -(MatVal scalar)
-{
-    RplMatrix rc(*this);
-       rc -= scalar;
-       return rc;
-}
-/**
- * Tests the equiness of the instance with a given matrix.
- *
- * @param operand      the matrix to compare
- * @return                     true: the matrices are equal<br>
- *                                     false: otherwise
- */
-bool RplMatrix::operator ==(const RplMatrix& operand) const
-{
-       checkSameDimension(operand);
-       bool rc = true;
-       for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
-               if (m_values[ix] != operand.m_values[ix]){
-                               rc = false;
-                               break;
-                       }
-       }
-       return rc;
-}
-/**
- * Compares the instance with a given scalar.
- *
- * @param scalar       the scalar to compare
- * @return                     true: all elements are equal to the scalar<br>
- *                                     false: otherwise
- */
-bool RplMatrix::operator ==(MatVal scalar) const
-{
-       bool rc = true;
-       for (int ix = m_rows * m_cols - 1; ix >= 0; ix--){
-               if (m_values[ix] != scalar){
-                               rc = false;
-                               break;
-                       }
-       }
-       return rc;
-}
-/**
- * Sets a new row-column pair.
- */
-RplMatrix& RplMatrix::resize(int rows, int cols, const MatVal values[],
-               MatVal defaultValue)
-{
-       checkDefinition(rows, cols);
-       if (rows != m_rows || cols != m_cols){
-               delete m_values;
-               m_values = new MatVal[rows * cols];
-        m_rows = rows;
-        m_cols = cols;
-       }
-       if (values == NULL)
-       {
-        for (int ix = rows*cols - 1; ix >= 0; ix--){
-            m_values[ix] = defaultValue;
-               }
-       } else {
-        for (int ix = rows*cols - 1; ix >= 0; ix--){
-            m_values[ix] = values[ix];
-        }
-       }
-       return *this;
-}
-/**
- * Returns the minimum and the maximum of the instance.
- *
- * @return             a tuple with the minimum and the maximum
- */
-Tuple2 RplMatrix::minMax() const
-{
-#ifndef DBL_MAX
-#define DBL_MAX std::numeric_limits<qreal>::max()
-#define DBL_MIN std::numeric_limits<qreal>::min()
-#endif
-       Tuple2 rc(DBL_MAX, DBL_MIN);
-
-       for (int ix = m_rows*m_cols - 1; ix >= 0; ix--){
-               MatVal x;
-               if ( (x = m_values[ix]) < rc.m_value1)
-                       rc.m_value1 = x;
-               if (x > rc.m_value2)
-                       rc.m_value2 = x;
-       }
-       return rc;
-}
-
-/**
- * Builds a matrix with exchanged rows and cols.
- *
- * @return     the transposed matrix
- */
-RplMatrix RplMatrix::transpose() const
-{
-    RplMatrix rc(m_cols, m_rows);
-
-       for (int row = 0; row < m_rows; row++){
-               for (int col = 0; col < m_cols; col++){
-                       rc.m_values[m_rows*col + row] = m_values[row * m_cols + col];
-               }
-       }
-       return rc;
-}
-QByteArray RplMatrix::toString(const char* prefix, const char* format,
-               const char* rowSeparator, const char* colSeparator) const
-{
-       char buffer[128];
-       Tuple2 minMaxi(minMax());
-    QByteArray rc;
-       qsnprintf(buffer, sizeof buffer, format, minMaxi.m_value1);
-       int length = strlen(buffer);
-       qsnprintf(buffer, sizeof buffer, format, minMaxi.m_value2);
-       int length2 = strlen(buffer);
-       if (length < length2)
-               length = length2;
-       qsnprintf(buffer, sizeof buffer, format,
-                       (minMaxi.m_value1 + minMaxi.m_value2) / 2);
-       length2 = strlen(buffer);
-       if (length < length2)
-               length = length2;
-       if (prefix == NULL)
-               prefix = "";
-       length = m_rows * m_cols * (length + strlen(colSeparator))
-                       + m_rows * strlen(rowSeparator) + strlen(prefix) + 20;
-       rc.reserve(length);
-       rc += prefix;
-       rc += "[";
-       for (int row = 0; row < m_rows; row++){
-        for (int col = 0; col < m_cols; col++){
-                       qsnprintf(buffer, sizeof buffer, format, m_values[m_cols*row + col]);
-                       rc += buffer;
-                       rc += colSeparator;
-               }
-               rc += rowSeparator;
-       }
-       rc += "]";
-       return rc;
-}
-/**
- * Finds the length of a column.
- *
- * @param text         the text to inspect
- * @param separator    the column separator
- * @return                     the count of chars between start and the next separator
- */
-static int lengthOfColumn(const char* text, char separator){
-       const char* ptr = text;
-       while(*ptr == ' ')
-               ptr++;
-       char delimiter = 0;
-       if (*ptr == '"' || *ptr == '\''){
-               delimiter = *ptr++;
-       }
-       while(*ptr){
-               if (*ptr == '\\'){
-                       ptr++;
-                       if (*ptr != '\0')
-                               ptr++;
-               } else if (*ptr == separator)
-                       break;
-               else if (*ptr != delimiter){
-                       ptr++;
-                       while(*ptr && *ptr != separator)
-                               ptr++;
-               }
-       }
-       int rc = ptr - text;
-       return rc;
-}
-/**
- * Skips all columns with a content other than a numeric value.
- *
- * @param line         the text line
- * @param separator    the column separator
- * @return                     the start of a number or ""
- */
-static const char* skipNonNumbers(const char* line, char separator)
-{
-       int len1, len2 = 0;
-
-    while ( (len1 = RplString::lengthOfNumber(line)) == 0
-               && (len2 = lengthOfColumn(line, separator)) > 0)
-               line += len2;
-    if (*line == separator)
-        line++;
-       return line;
-}
-/**
- * Returns the count of numeric numbers in a CSV line.
- *
- * @param line the line from a CSV file
- * @return             0: not only numbers are in the line<br>
- *                             otherwise: the count of numeric columns in the line
- */
-static int countNumbers(const char* line, char separator){
-    line = skipNonNumbers(line, separator);
-       bool again = true;
-       int rc = 0;
-    char cc;
-    while(again && (cc = *line) != '\0' && cc != '\n' && cc != '\r'){
-        int length = RplString::lengthOfNumber(line, true);
-               if (length == 0){
-                       rc = 0;
-                       again = false;
-               } else {
-            line += length;
-                       rc++;
-                       if (*line == separator)
-                               line++;
-               }
-       }
-       return rc;
-}
-/**
- * Reads a file with the CSV (comma separated values) format
- * into the instance.
- */
-void RplMatrix::readFromCvs(const char* filename, int maxLineLength)
-{
-    FILE* fp = fopen(filename, "r");
-    if (fp == NULL)
-        throw RplMatrixException(*this, "Cannot open %s (%d)", filename, errno);
-    char* buffer = new char[maxLineLength + 1];
-    const char* line;
-    char separator = RplString::findCsvSeparator(fp, buffer, maxLineLength);
-    int rows = 0;
-    int cols = 0;
-    int nCols;
-    // find the count of rows and columns:
-    while( (line = fgets(buffer, maxLineLength, fp)) != NULL)
-    {
-         if ( (nCols = countNumbers(line, separator)) > 0){
-            rows++;
-            if (nCols > cols)
-                cols = nCols;
-        }
-    }
-    resize(rows, cols);
-    // find the values
-    fseek(fp, 0, SEEK_SET);
-    int row = -1;
-    while( (line = fgets(buffer, maxLineLength, fp)) != NULL)
-    {
-        int nCols;
-        if ( (nCols = countNumbers(line, separator)) > 0){
-            row++;
-            line = skipNonNumbers(line, separator);
-            int col = -1;
-            int length;
-            const char* ptr;
-            while( (length = RplString::lengthOfNumber(line, true)) > 0){
-                col++;
-                ptr = line;
-                line += length;
-                while(*ptr == ' ')
-                    ptr++;
-                MatVal value = atof(ptr);
-                m_values[m_cols*row + col] = value;
-                if (*line == separator)
-                    line++;
-                else
-                    break;
-            }
-        }
-    }
-
-    fclose(fp);
-    delete buffer;
-}
-void RplMatrix::readFromXml(const char* filename, const char* tagCol,
-               const char* tagRow, const char* tagTable,
-        int maxLineLength)
-{
-    throw RplMatrixException(*this, "readFromXml not implementes: %s %s %s %s %d",
-        filename, tagCol, tagRow, tagTable, maxLineLength);
-}
-
diff --git a/rplmath/rplmatrix.hpp b/rplmath/rplmatrix.hpp
deleted file mode 100644 (file)
index 9082408..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * RplMatrix.hpp
- *
- *  Created on: 29.05.2014
- *      Author: hm
- */
-
-#ifndef RplMatrix_HPP_
-#define RplMatrix_HPP_
-
-
-class RplMatrix;
-/**
- * Implements a RplMatrix specific exception.
- */
-class RplMatrixException : public RplException
-{
-public:
-    RplMatrixException(const RplMatrix& RplMatrix, const char* format, ...);
-};
-
-/**
- * The type of a RplMatrix element.
- */
-typedef qreal MatVal;
-
-class Tuple2 {
-public:
-       Tuple2(MatVal value1, MatVal value2) :
-               m_value1(value1),
-               m_value2(value2)
-       {}
-public:
-       MatVal m_value1;
-       MatVal m_value2;
-};
-/**
- * Implements a RplMatrix with 2 dimensions.
- */
-class RplMatrix {
-public:
-    RplMatrix(const char* name = NULL);
-    RplMatrix(int rows, int cols, const char* name = NULL);
-    virtual ~RplMatrix();
-    RplMatrix(const RplMatrix& source);
-    RplMatrix& operator =(const RplMatrix& source);
-public:
-    RplMatrix& operator +=(const RplMatrix& operand);
-    RplMatrix& operator -=(const RplMatrix& operand);
-    RplMatrix operator +(const RplMatrix& operand);
-    RplMatrix operator -(const RplMatrix& operand);
-    RplMatrix& operator +=(MatVal scalar);
-    RplMatrix& operator -=(MatVal scalar);
-    RplMatrix operator +(MatVal scalar);
-    RplMatrix operator -(MatVal scalar);
-    bool operator ==(const RplMatrix& operand) const;
-       bool operator ==(MatVal scalar) const;
-    inline bool operator !=(const RplMatrix& operand) const
-       { return ! (*this == operand); }
-       inline bool operator !=(MatVal operand)
-       { return ! (*this == operand); }
-public:
-    inline const QByteArray& getName() const
-       { return m_name; }
-       inline MatVal get(int row, int col) const
-       { check(row, col); return m_values[row*m_cols + col]; }
-    inline RplMatrix& set(int row, int col, MatVal value)
-       { check(row, col); m_values[row*m_cols + col] = value; return *this; }
-       inline int getRows() const
-       { return m_rows; }
-       inline int getCols() const
-       { return m_cols; }
-public:
-       void checkDefinition(int rows, int cols) const;
-       void check(int row, int col) const;
-    void checkSameDimension(const RplMatrix& operand) const;
-    RplMatrix& resize(int rows, int cols, const MatVal values[] = NULL,
-                       MatVal defaultValue = 0.0);
-       Tuple2 minMax() const;
-    RplMatrix transpose() const;
-    QByteArray toString(const char* prefix = NULL,
-                       const char* format = "%f",
-                       const char* rowSeparator = "\n",
-                       const char* colSeparator = ",") const;
-       void readFromCvs(const char* filename, int maxLineLength = 1024*1024);
-       void readFromXml(const char* filename, const char* tagCol,
-                       const char* tagRow, const char* tagTable,
-                       int maxLineLength = 1024*1024);
-protected:
-       int m_rows;
-       int m_cols;
-       MatVal* m_values;
-    QByteArray m_name;
-};
-
-#endif /* RplMatrix_HPP_ */
diff --git a/rplmath/rplrandom.cpp b/rplmath/rplrandom.cpp
deleted file mode 100644 (file)
index 5662f0d..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-
-/** @file
- *
- * @brief Implements pseudo random generators.
- */
-/** @file rplmath/rplrandom.hpp
- *
- * @brief Definitions for pseudo random generators.
- */
-#include "rplmath.hpp"
-
-/** @class RplRandom rplrandom.hpp "rplmath/rplrandom.hpp"
- *
- * @brief Implements a portable pseudo random generator.
- *
- */
-
-/**
- * @brief Constructor.
- */
-RplRandom::RplRandom() :
-    m_seed(0) {
-}
-
-/**
- * @brief Destructor.
- */
-RplRandom::~RplRandom() {
-}
-
-/**
- * @brief Returns the next random number as 64 bit unsigned integer.
- *
- * @return the next random number.
- */
-u_int64_t RplRandom::nextInt64() {
-    // Donald Knuth recommands (for 64-Bit):
-    m_seed = m_seed * 6364136223846793005L + 1442695040888963407L;
-    return m_seed;
-}
-/**
- * @brief Sets the random seed.
- *
- * @param seed      the new seed.
- */
-void RplRandom::setSeed(u_int64_t seed) {
-    m_seed = seed;
-}
-/**
- * @brief Modifies the seed.
- *
- * @param seed      the XOR operand.
- */
-void RplRandom::xorSeed(u_int64_t seed) {
-    m_seed ^= seed;
-}
-
-/**
- * @brief nextByte  returns the next random byte.
- *
- * @return          a pseudo random value 0..255
- */
-quint8 RplRandom::nextByte() {
-    u_int64_t value = nextInt64();
-    // forget the last 3 bits:
-    quint8 rc = (quint8)(value >> 3) % 256;
-    return rc;
-}
-
-/**
- * @brief Returns the next pseudo random integer.
- *
- * @param minValue  the minimal result (including)
- * @param maxValue  the maximal result (includeing)
- * @return the next integer
- */
-int RplRandom::nextInt(int minValue, int maxValue) {
-    u_int64_t value = nextInt64();
-    u_int64_t diff = maxValue - minValue;
-    int rc;
-    if(diff <= 0)
-        rc = minValue;
-    else
-        rc = (int)(minValue + value % diff);
-    return rc;
-}
-
-/**
- * @brief Returns a random string.
- *
- * @param length    the length of the result
- * @param minChar   all characters of the result are greater or equal than this value
- * @param maxChar   all characters of the result are lower or equal than this value
- * @return          a random string
- */
-QByteArray RplRandom::nextString(int length, char minChar, char maxChar) {
-    QByteArray rc;
-    rc.resize(length);
-    for(int ii = 0; ii < length; ii++) {
-        rc[ii] = nextInt(minChar, maxChar);
-    }
-    return rc;
-}
-
-/**
- * @brief Returns a random string.
- *
- * @param length    the length of the result
- * @param charSet   a string with all allowed characters
- * @return          a random string with characters from the given set
- */
-QByteArray RplRandom::nextString(int length, char* charSet) {
-    QByteArray rc;
-    rc.resize(length);
-    int ubound = strlen(charSet) - 1;
-    for(int ii = 0; ii < length; ii++) {
-        rc[ii] = charSet[nextInt(0, ubound)];
-    }
-    return rc;
-}
-
diff --git a/rplmath/rplrandom.hpp b/rplmath/rplrandom.hpp
deleted file mode 100644 (file)
index a041fb6..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef RPLRANDOM_HPP
-#define RPLRANDOM_HPP
-
-#include <QtCore>
-class RplRandom {
-public:
-    RplRandom();
-    virtual ~RplRandom();
-private:
-    // No copy constructor: no implementation!
-    RplRandom(const RplRandom& source);
-    // Prohibits assignment operator: no implementation!
-    RplRandom& operator =(const RplRandom& source);
-public:
-    virtual u_int64_t nextInt64();
-    virtual void setSeed(u_int64_t seed);
-    void xorSeed(u_int64_t seed);
-    quint8 nextByte();
-    int nextInt(int minValue, int maxValue);
-    QByteArray nextString(int length = 8, char minChar = ' ', char maxChar = 127);
-    QByteArray nextString(int length, char* charSet);
-protected:
-    u_int64_t m_seed;
-};
-
-
-#endif // RPLRANDOM_HPP
diff --git a/rplmodules.hpp b/rplmodules.hpp
deleted file mode 100644 (file)
index 86ff3b9..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef RPLMODULES_HPP
-#define RPLMODULES_HPP
-
-enum {
-    RPLMODULE_LOGGER = 101,
-    RPLMODULE_CONFIG,
-    RPLMODULE_CONTAINER,
-    RPLMODULE_EXCEPTION,
-    RPLMODULE_TEST, // 105
-    RPLMODULE_TCPSERVER,
-    RPLMODULE_TCPCLIENT,
-    RPLMODULE_TCPPEER,
-    RPLMODULE_TERMINATOR,
-    RPL_MODULE_ASTREE, // 110
-    RPL_MODULE_ASCLASSES,
-    RPL_MODULE_LEXER,
-    RPL_MODULE_SOURCE,
-    RPL_MODULE_VM,
-    RPL_MODULE_MFPARSER, // 115
-    // last element:
-    RPLMODULE_COUNT
-};
-#define RPL_FIRST_OF(moduleNo) (moduleNo*100+1)
-class RplModules{
-public:
-    static int fileToNumber(const char* file);
-    static const char* numberToFile(int location);
-};
-
-
-#endif // RPLMODULES_HPP
diff --git a/rplnet/rplnet.hpp b/rplnet/rplnet.hpp
deleted file mode 100644 (file)
index f9c4731..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLNET_HPP
-#define RPLNET_HPP
-
-#include <QThread>
-#include <QAbstractSocket>
-#include <QTcpSocket>
-#include <QTcpServer>
-#include <QThread>
-#include <QWaitCondition>
-#include <QMutexLocker>
-
-//includes implicite rplcore.hpp:
-#include "../rplmath/rplmath.hpp"
-#include "rpltcppeer.hpp"
-#include "rpltcpserver.hpp"
-#include "rpltcpclient.hpp"
-#include "rplnetconfig.hpp"
-
-#endif // RPLNET_HPP
diff --git a/rplnet/rplnetconfig.cpp b/rplnet/rplnetconfig.cpp
deleted file mode 100644 (file)
index bdb28d5..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#include "rplnetconfig.hpp"
-
-const char* RplNetConfig::IP = "connection.ip";
-const char* RplNetConfig::PORT = "connection.port";
-const char* RplNetConfig::SLEEP_MILLISEC = "connection.sleepmillisec";
diff --git a/rplnet/rplnetconfig.hpp b/rplnet/rplnetconfig.hpp
deleted file mode 100644 (file)
index 4d58ef0..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLNETCONFIG_HPP
-#define RPLNETCONFIG_HPP
-
-class RplNetConfig
-{
-public:
-    static const char* IP;
-    static const char* PORT;
-    static const char* SLEEP_MILLISEC;
-};
-
-#endif // RPLNETCONFIG_HPP
diff --git a/rplnet/rpltcpclient.cpp b/rplnet/rpltcpclient.cpp
deleted file mode 100644 (file)
index 7ae57df..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#include "rplnet.hpp"
-
-enum {
-    LOC_1 = RPL_FIRST_OF(RPLMODULE_TCPCLIENT), // 10701
-    LOC_HANDLE_ERROR_1,
-    LOC_SET_REMOTE_ADDRESS_1,
-};
-
-/** @class RplTcpClient rpltcpclient.hpp "rplnet/rpltcpclient.hpp"
- *
- * @brief Implements a TCP client.
- *
- * Use the protocol defined at <code>RplTcpServer</code>.
- */
-/**
- * @brief Constructor.
- *
- * @param configurator  some parameters will be get from this configurator
- * @param thread        current thread. Used for <code>sleep()</code>
- * @param terminator    NULL or for controlled termination
- * @param logger        a logger
- */
-RplTcpClient::RplTcpClient(RplConfigurator& configurator, QThread* thread,
-                           RplTerminator* terminator,
-                           RplLogger* logger) :
-        m_peer(new RplTcpPeer(configurator, thread, terminator, false, logger)),
-        m_logger(logger),
-        m_configurator(configurator){
-    QByteArray ip = configurator.asString(RplNetConfig::IP, "localhost");
-    int port = configurator.asInt(RplNetConfig::PORT, 12345);
-    if(! ip.isEmpty() && port != 0)
-        setRemoteAddress(ip.constData(), port);
-}
-
-/**
- * @brief Destructor.
- */
-RplTcpClient::~RplTcpClient() {
-    delete m_peer;
-    m_peer = NULL;
-}
-
-/**
- * @brief Defines the remote address for a client.
- * @param ip    NULL or the ip to connect
- * @param port  0 or the port to connect
- */
-void RplTcpClient::setRemoteAddress(const char* ip, int port) {
-    QTcpSocket* socket = (QTcpSocket*) m_peer->getSocket();
-    delete socket;
-    if(ip == NULL || port == 0)
-        m_peer->setSocket(NULL);
-    else {
-        socket = new QTcpSocket();
-        connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
-                this, SLOT(handleError(QAbstractSocket::SocketError)));
-        m_peer->setSocket(socket);
-        m_peer->setAddress(ip, port);
-        m_logger->logv(LOG_INFO, LOC_SET_REMOTE_ADDRESS_1,
-                        "connect with %s:%d", ip, port);
-        socket->connectToHost(QString(ip), port);
-        socket->waitForConnected();
-    }
-}
-
-/**
- * @brief Returns the peer info.
- * @return the peer info
- */
-RplTcpPeer* RplTcpClient::getPeer() const {
-    return m_peer;
-}
-
-/**
- * @brief Handles a network error.
- *
- * @param socketError   the error code
- */
-void RplTcpClient::handleError(QAbstractSocket::SocketError socketError) {
-    if (m_logger != NULL)
-        m_logger->logv(LOG_ERROR, LOC_HANDLE_ERROR_1, "Network error %d",
-                       socketError);
-}
-
-/** @class RplClientThread rpltcpclient.hpp "rplnet/rpltcpclient.hpp"
- *
- * @brief Implements a thread usable for a tcp client.
- *
- * Each <code>RplTcpPeer</code> needs a thread. Therefore this class provides all things
- * needed for a <code>RplTcpClient</code> which uses a <code>RplTcpPeer</code>.
- */
-
-/**
- * @brief Constructor.
- *
- * @param configurator  delivers some connection parameters
- * @param logger        the logger. If NULL a default logger will be used
- */
-RplClientThread::RplClientThread(RplConfigurator& configurator,
-                                 RplLogger* logger) :
-    m_client(NULL),
-    m_logger(logger),
-    m_configurator(configurator),
-    m_ownsLogger(false) {
-    m_client = new RplTcpClient(configurator, this, NULL, logger);
-}
-/**
- * @brief Destructor.
- */
-RplClientThread::~RplClientThread() {
-    delete m_client;
-    m_client = NULL;
-    if(m_ownsLogger) {
-        delete m_logger;
-        m_logger = NULL;
-    }
-}
-/**
- * @brief Returns the peer which can be used for sending and receiving messages.
- *
- * @return the peer
- */
-RplTcpPeer* RplClientThread::getPeer() const {
-    return m_client->getPeer();
-}
-
-/**
- * @brief Returns the logger of the thread.
- * @return the logger
- */
-RplLogger* RplClientThread::getLogger() const {
-    return m_logger;
-}
-
-/**
- * @brief Contains the main method of the thread.
- *
- * Calls <code>doIt()</code> for the real things.
- */
-void RplClientThread::run() {
-    doIt();
-}
diff --git a/rplnet/rpltcpclient.hpp b/rplnet/rpltcpclient.hpp
deleted file mode 100644 (file)
index 7ba45a5..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLTCPCLIENT_HPP
-#define RPLTCPCLIENT_HPP
-
-#ifndef RPLNET_HPP
-#include "rplnet.hpp"
-#endif
-
-class RplTcpPeer;
-
-class RplTcpClient : public QObject {
-    Q_OBJECT
-public:
-    RplTcpClient(RplConfigurator& configurator, QThread* thread,
-                 RplTerminator* terminator,
-                 RplLogger* logger = NULL);
-    virtual ~RplTcpClient();
-private:
-    // No copy constructor: no implementation!
-    RplTcpClient(const RplTcpClient& source);
-    // Prohibits assignment operator: no implementation!
-    RplTcpClient& operator =(const RplTcpClient& source);
-public:
-    RplTcpPeer* getPeer() const;
-private:
-    void setRemoteAddress(const char* ip, int port);
-public slots:
-    void handleError(QAbstractSocket::SocketError socketError);
-private:
-    RplTcpPeer* m_peer;
-    RplLogger* m_logger;
-    RplConfigurator& m_configurator;
-};
-
-class RplClientThread : public QThread {
-public:
-    RplClientThread(RplConfigurator& configurator,
-                    RplLogger* logger = NULL);
-    virtual ~RplClientThread();
-private:
-    // No copy constructor: no implementation!
-    RplClientThread(const RplClientThread& source);
-    // Prohibits the assignment operator. Not implemented!
-    RplClientThread& operator=(const RplClientThread& source);
-public:
-    /**
-     * @brief Does the main task of the thread.
-     *
-     * Will be called from <code>QThread::run()</code>.
-     * The implementations of this abstract method should be call <code>getPeer()</code>
-     * to send and receive messages.
-     */
-    virtual void doIt() = 0;
-    RplTcpPeer* getPeer() const;
-    RplLogger* getLogger() const;
-private:
-    virtual void run();
-protected:
-    RplTcpClient* m_client;
-    RplLogger* m_logger;
-    RplConfigurator& m_configurator;
-private:
-    bool m_ownsLogger;
-};
-
-#endif // RPLTCPCLIENT_HPP
diff --git a/rplnet/rpltcppeer.cpp b/rplnet/rpltcppeer.cpp
deleted file mode 100644 (file)
index d45946f..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#include "rplnet.hpp"
-
-enum {
-    LOC_SEND_1 = RPL_FIRST_OF(RPLMODULE_TCPPEER), // 10801
-    LOC_READ_BYTES_1,
-    LOC_READ_BYTES_2,
-    LOC_READ_BYTES_3,
-    LOC_READ_BYTES_4,
-    LOC_HANDLE_ERROR_1,
-    LOC_SEND_2,
-};
-
-static int s_dummy = 0;
-
-/** @class RplTcpPeer rpltcppeer.hpp "rplnet/rpltcppeer.hpp"
- *
- * @brief Implements the common things for TCP server and client.
- *
- * The communication is done with the following protocol:
- * <ul>
- *  <li>The data is transmitted via TCP.</li>
- *  <li>The data exchange is done with <b>info units</b>.
- *  <li>Each info unit contains a header and the data.</li>
- * </ul>
- * The format of the header:
- *<pre>FLAGS [SALT] COMMAND SIZE
- * </pre>
- * <ul>
- *  <li>FLAGS (1 byte): a XOR sum of the flags defined in <code>rpltcppeer::flag_t</code>.</li>
- *  <li>SALT (4 byte): a random value. Controls the encryption. Only available if <code>FLAG_ENCRYPT</code> is set.</li>
- *  <li>COMMAND (5 byte): define the task to do (client to server) or the answer (server to client).
- *  <li>SIZE (2 or 4 byte): the size of the data behind the header. 4 bytes if <code>FLAG_4_BYTE_SIZE</code> is set.</li>
- * </ul>
- *
- */
-
-/**
- * @brief Creates an instance of a <code>RplTcpPeer</code>.
- *
- * @param configurator  delivers some connection parameters
- * @param thread        the current thread. Used for sleep()
- * @param terminator    NULL or for controlled thread termination
- * @param logger        logger. If Null the global logger will be taken (not thread safe!)
- * @return              an instance of <code>RplTcpPeer</code>
- */
-RplTcpPeer* RplTcpPeer::createPeer(RplConfigurator& configurator,
-                                   QThread* thread,
-                                   RplTerminator* terminator,
-                                   RplLogger* logger) {
-    return new RplTcpPeer(configurator, thread, terminator, logger);
-}
-
-/**
- * @brief Constructor.
- *
- * @param configurator  delivers some connection parameters
- * @param thread        the current thread. Used for sleep()
- * @param terminator    NULL or for controlled thread termination
- * @param isServer      true: the receiving does have a timeout
- * @param logger        logger. If Null the global logger will be taken (not thread safe!)
- */
-RplTcpPeer::RplTcpPeer(RplConfigurator& configurator, QThread* thread,
-                       RplTerminator* terminator,
-                       bool isServer,
-                       RplLogger* logger) :
-        m_socket(NULL),
-        m_logger(logger == NULL ? RplLogger::globalLogger() : logger),
-        m_thread(thread),
-        m_random(),
-        m_timeout(isServer ? 0 : configurator.asInt("connection.timeout", 60)),
-        m_terminator(terminator),
-        m_configurator(configurator),
-        m_isServer(isServer),
-        m_dataLocker(QMutex::NonRecursive),
-        m_waitForData() {
-    // Simulate a true random with time, and addresses from stack and code segment:
-    m_random.setSeed(time(NULL) + ((qint64) this << 8) + ((qint64) &s_dummy << 16)
-                     + ((qint64) &createPeer << 24));
-}
-
-/**
- * @brief Destructor.
- */
-RplTcpPeer::~RplTcpPeer() {
-
-}
-
-/**
- * @brief Sends a message via TCP.
- *
- * @param flags     a sum of FLAGS_... constants
- * @param command   defines the content of the message
- * @param data      NULL or additional data
- * @return          true: success<br>
- *                  false: error occurred
- */
-bool RplTcpPeer::send(qint8 flags, const char* command,
-                      const QByteArray& data) {
-    bool rc = false;
-    QByteArray header;
-    QByteArray data2 = RplString::toCString(data.constData(), 20);
-    m_logger->logv(LOG_INFO, LOC_SEND_1, "send: flags: %x %s %s (%d)",
-        flags, command, data2.constData(), data.length());
-    header.reserve(16);
-    header.append((char) flags);
-    if(flags & FLAG_ENCRYPT) {
-        header.append((char) m_random.nextByte());
-        header.append((char) m_random.nextByte());
-        header.append((char) m_random.nextByte());
-        header.append((char) m_random.nextByte());
-    }
-    unsigned int length = data.length();
-    header.append(char(length % 256));
-    header.append(char((length >> 8) % 256));
-    if(flags & FLAG_4_BYTE_SIZE) {
-        header.append(char((length >> 16) % 256));
-        header.append(char((length >> 24) % 256));
-    }
-    length = strlen(command);
-    header.append(command, length < 5 ? length : 5);
-    while(length++ < 5) {
-        header.append(' ');
-    }
-    qint64 written = m_socket->write(header.constData(), header.length());
-    qint64 written2 = m_socket->write(data);
-    m_socket->flush();
-    int count = 0;
-    if(written != header.length() || written2 != data.length()) {
-        int endTime = time(NULL) + m_timeout;
-        // wait until the data are sent or timeout or external termination:
-        while(m_socket->bytesToWrite() > 0) {
-            m_thread->msleep(1);
-            if(++count % 20 == 0) {
-                if(m_terminator == NULL || m_terminator->isStopped()
-                        || time(NULL) > endTime)
-                    break;
-            }
-        }
-    }
-    if(m_logger->isActive(LOG_DEBUG))
-        m_logger->logv(LOG_DEBUG, LOC_SEND_1, "send %s: %s len=%d loops=%d %s",
-                       m_address.constData(), command, data.length(), count,
-                       RplString::hexDump((const void*) data.constData(), 16, 16).constData());
-    return rc;
-}
-
-/**
- * @brief Reads an amount of bytes with a timeout.
- *
- * @param bytes     count of bytes to read
- * @param maxTime   IN/OUT: last time the read must be ready
- * @param loops     IN/OUT: number of sleeps
- *
- * @return          "": read not successful: timeout or termination or error<br>
- *                  otherwise: the read bytes
- */
-QByteArray RplTcpPeer::readBytes(int bytes, time_t maxTime, int& loops) {
-    QAbstractSocket* socket = getSocket();
-    bool success = true;
-    qint64 available;
-    long msec = m_configurator.asInt(RplNetConfig::SLEEP_MILLISEC, 1);
-    int divider = 1000L / (msec == 0 ? 1 : msec);
-    if (divider < 1)
-        divider = 1;
-    QMutexLocker locker(&m_dataLocker);
-    m_dataLocker.lock();
-
-    while(! m_waitForData.wait(&m_dataLocker, 1000L)){
-          if(loops == 0 && ! m_isServer)
-              maxTime = time(NULL) + m_timeout;
-          if(++loops % divider == 0 && ! m_isServer) {
-              if(time(NULL) > maxTime) {
-                  m_logger->logv(LOG_ERROR, LOC_READ_BYTES_1,
-                                 "receive: timeout (%d)", m_timeout);
-                  success = false;
-                  break;
-              }
-          }
-          if(m_terminator != NULL && m_terminator->isStopped()) {
-              m_logger->log(LOG_ERROR, LOC_READ_BYTES_2, "receive: stopped");
-              success = false;
-              break;
-          }
-    }
-    available = socket->bytesAvailable();
-    m_logger->logv(LOG_DEBUG, LOC_READ_BYTES_4,
-                   "readBytes(): available: %ld/%ld", available, bytes);
-    QByteArray rc;
-    if(success) {
-        rc = socket->read(bytes);
-        if(rc.length() != bytes) {
-            m_logger->logv(LOG_ERROR, LOC_READ_BYTES_3,
-                           "receive: too few bytes: %d of %d",
-                           rc.length(), bytes);
-        }
-    }
-    return rc;
-}
-
-int getInt(const QByteArray& data, int offset, int size) {
-    int rc = ((int)(unsigned char) data.at(offset++));
-    while(--size > 0) {
-        rc = rc * 256 + (unsigned char) data.at(offset++);
-    }
-    return rc;
-}
-
-/**
- * @brief Receives a message via TCP.
- *
- * @param command   OUT: defines the content of the read message
- * @param data      OUT: "" or additional data
- * @return          true: success<br>
- *                  false: error occurred
- */
-bool RplTcpPeer::receive(QByteArray& command, QByteArray& data) {
-    bool rc = true;
-    command.clear();
-    data.clear();
-    QByteArray header;
-    header.reserve(16);
-    int minHeaderSize = 8;
-    int loops = 0;
-    time_t maxTime = 0;
-    quint8 flags = 0;
-    header = readBytes(minHeaderSize, maxTime, loops);
-    if(header.length() > 0) {
-        flags = header.at(0);
-        int headerSize = minHeaderSize;
-        if((flags & FLAG_4_BYTE_SIZE) != 0)
-            headerSize += 2;
-        if((flags & FLAG_ENCRYPT) != 0)
-            headerSize += 4;
-        if(headerSize != minHeaderSize) {
-            QByteArray restHeader = readBytes(headerSize - minHeaderSize,
-                                              maxTime, loops);
-            if(restHeader.length() == 0)
-                header.clear();
-            else
-                header.append(restHeader);
-        }
-    }
-    rc = header.length() > 0;
-    if(rc) {
-        int offset = (flags & FLAG_ENCRYPT) == 0 ? 6 : 8;
-        int size = (flags & FLAG_4_BYTE_SIZE) == 0 ? 4 : 2;
-        int dataLength = getInt(header, offset, size);
-        command = header.mid(offset - 5, 5);
-        data = readBytes(dataLength, maxTime, loops);
-        rc = data.length() == dataLength;
-    }
-    return rc;
-
-}
-
-/**
- * @brief Sends a message and receives an answer message via TCP.
- *
- * @param flags     a sum of FLAGS_... constants
- * @param command       defines the content of the message to send
- * @param data          NULL or additional data
- * @param answer        OUT: the command of the answer
- * @param answerData    OUT: "" or additional data of the answer
- * @return              true: success<br>
- *                      false: error occurred
- */
-bool RplTcpPeer::sendAndReceive(quint8 flags, char command [4],
-        QByteArray* data, QByteArray& answer,
-        QByteArray& answerData) {
-    answer.clear();
-    answerData.clear();
-    bool rc = send(flags, command, data == NULL ? QByteArray("") : *data);
-    if(rc)
-        rc = receive(answer, answerData);
-    return rc;
-}
-
-/**
- * @brief Sets the socket.
- *
- * @param socket    the socket to set
- */
-void RplTcpPeer::setSocket(QAbstractSocket* socket) {
-    m_socket = socket;
-    if (socket != NULL)
-        connect( m_socket, SIGNAL(readyRead()), SLOT(readTcpData()) );
-}
-
-/**
- * @brief Reads the (ready) data from the socket.
- */
-void RplTcpPeer::readTcpData() {
-    m_waitForData.wakeOne();
-}
-
-/**
- * @brief Handles a network error.
- *
- * @param socketError   the error code
- */
-void RplTcpPeer::handleError(QTcpSocket::SocketError socketError) {
-    m_logger->logv(LOG_ERROR, LOC_HANDLE_ERROR_1, "Network error %d",
-                   socketError);
-}
-
-/**
- * @brief Returns a human readable peer address.
- * @return a string with the peer address: e.g. "192.16.2.3:44335"
- */
-QByteArray RplTcpPeer::getPeerAddress() {
-    QByteArray rc;
-    if(m_socket == NULL)
-        rc = "<not connected>";
-    else
-        rc = m_socket->peerAddress().toString().toUtf8();
-    return rc;
-}
-
-/**
- * @brief Returns the socket.
- *
- * @return the socket
- */
-QAbstractSocket* RplTcpPeer::getSocket() const {
-    return m_socket;
-}
-
-/**
- * @brief Returns the port.
- * @return the port of the peer.
- */
-int RplTcpPeer::getPort(){
-    int port = m_configurator.asInt(RplNetConfig::PORT, 12345);
-    return port;
-}
-/**
- * @brief Returns the ip address.
- * @return  "": all addresses (for listening)<br>
- *          otherwise: the address (e.g. 127.0.0.1)
- */
-QByteArray RplTcpPeer::getIp(){
-    QByteArray ip = m_configurator.asString(RplNetConfig::IP, "");
-    return ip;
-}
-/**
- * @brief Sets the address (ip:port).
- * @param ip    the ip address
- * @param port  the port
- */
-void RplTcpPeer::setAddress(const char* ip, int port)
-{
-    m_address = QByteArray(ip) + ":" + QByteArray::number(port);
-}
diff --git a/rplnet/rpltcppeer.hpp b/rplnet/rpltcppeer.hpp
deleted file mode 100644 (file)
index d040496..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLTCPPEER_HPP
-#define RPLTCPPEER_HPP
-
-#ifndef RPLNET_HPP
-#include "rplnet.hpp"
-#endif
-
-class RplTcpPeer : public QObject {
-    Q_OBJECT
-public:
-    enum {
-        ///> standard behaviour
-        FLAG_UNDEF,
-        ///> if set: the size field is 4 byte (max. 4 GByte) instead of 2 byte (64kByte)
-        FLAG_4_BYTE_SIZE = 1,
-        ///> if set the data are compressed by the gzip algorithm
-        FLAG_GZIP = 2,
-        ///> if set the data are encrypted. In front of the size field a 4 byte salt field exists.
-        ///> In this case all data behind the salt field are encrypted.
-        FLAG_ENCRYPT = 4,
-        ///> connection initialization of
-    } flag_t;
-public:
-    static RplTcpPeer* createPeer(RplConfigurator& configurator,
-                                  QThread* thread,
-                                  RplTerminator* terminator,
-                                  RplLogger* logger = NULL);
-public:
-    RplTcpPeer(RplConfigurator& configurator, QThread* thread,
-               RplTerminator* terminator,
-               bool isServer,
-               RplLogger* logger = NULL);
-    virtual ~RplTcpPeer();
-private:
-    // No copy constructor: no implementation!
-    RplTcpPeer(const RplTcpPeer& source);
-    // No assignment operator: no implementation!
-    RplTcpPeer& operator =(const RplTcpPeer& source);
-public:
-    virtual bool send(qint8 flags, const char* command, const QByteArray& data);
-    virtual bool receive(QByteArray& command, QByteArray& data);
-    virtual bool sendAndReceive(quint8 flags, char command [4],
-                                QByteArray* data, QByteArray& answer, QByteArray& answerData);
-    void setSocket(QAbstractSocket* socket);
-    QAbstractSocket* getSocket() const;
-    QByteArray getPeerAddress();
-    void handleError(QTcpSocket::SocketError socketError);
-    int getPort();
-    QByteArray getIp();
-    void setAddress(const char* ip, int port);
-private:
-    QByteArray readBytes(int bytes, time_t maxTime, int& loops);
-
-public slots:
-    void readTcpData();
-
-private:
-    QAbstractSocket* m_socket;
-    // <ip>:<port>
-    QByteArray m_address;
-    RplLogger* m_logger;
-    QByteArray m_received;
-    int m_expected;
-    QThread* m_thread;
-    // Only used for salt generation:
-    RplRandom m_random;
-    ///> maximum allowed time (in seconds) for sending/receiving one info unit
-    int m_timeout;
-    ///> for controlled termination
-    RplTerminator* m_terminator;
-    RplConfigurator& m_configurator;
-    bool m_isServer;
-    QMutex m_dataLocker;
-    QWaitCondition m_waitForData;
-};
-
-#endif // RPLTCPPEER_HPP
diff --git a/rplnet/rpltcpserver.cpp b/rplnet/rpltcpserver.cpp
deleted file mode 100644 (file)
index c9ba87f..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#include "rplnet.hpp"
-
-enum {
-    LOC_RUN_1 = RPL_FIRST_OF(RPLMODULE_TCPSERVER), // 10601
-    LOC_TCP_TREAD_RUN_1,
-    LOC_TCP_TREAD_RUN_2,
-    LOC_TCP_INCOMING_CONNECTION_1,
-};
-
-/** @class RplTcpThread rpltcpserver.hpp "rplcore/rpltcpserver.hpp"
- *
- * @brief Serves one connection of a multihreaded TCP server.
- *
- * Note: The real thing is done by the RplTaskHandler instance.
- */
-
-/**
- * @brief Constructor.
- *
- * @param configurator  delivers some connection parameters
- * @param socketDescriptor  socket of the connection to handle
- * @param threadId          an unique id for the thread
- * @param handler           does the work
- */
-RplTcpThread::RplTcpThread(RplConfigurator& configurator,
-                           qintptr socketDescriptor, int threadId,
-                           RplTaskHandler* handler) :
-    m_threadId(threadId),
-    m_taskHandler(handler),
-    m_socketDescriptor(socketDescriptor),
-    m_configurator(configurator){
-}
-/**
- * @brief Destructor.
- */
-RplTcpThread::~RplTcpThread() {
-
-}
-
-/**
- * @brief Does the proper thread task.
- *
- * Initializes the socket and loops for incoming commands.
- */
-void RplTcpThread::run() {
-    QTcpSocket socket;
-    if(!socket.setSocketDescriptor(getSocketDescriptor())) {
-        emit error(socket.error());
-    } else {
-        RplTcpPeer peer(m_configurator, this, m_taskHandler->getTerminator(),
-                        true, m_taskHandler->getLogger());
-        peer.setSocket(&socket);
-        QByteArray addr = peer.getPeerAddress();
-        m_taskHandler->getLogger()->logv(LOG_DEBUG, LOC_TCP_TREAD_RUN_1,
-                                         "RplTcpThread::run(): start Peer: %s", addr.constData());
-        while(m_taskHandler->handle(&peer)) {
-            // do nothing
-        }
-        socket.disconnectFromHost();
-        socket.waitForDisconnected();
-        m_taskHandler->getLogger()->logv(LOG_DEBUG, LOC_TCP_TREAD_RUN_1,
-                                         "RplTcpThread::run(): end Peer: %s", addr.constData());
-    }
-}
-
-/**
- * @brief Returns the thread id.
- *
- * @return the thread id
- */
-int RplTcpThread::getThreadId() const {
-    return m_threadId;
-}
-/**
- * @brief Returns the task handler.
- *
- * @return the task handler
- */
-RplTaskHandler* RplTcpThread::getTaskHandler() const {
-    return m_taskHandler;
-}
-/**
- * @brief Returns the tcp socket of the served connection.
- *
- * @return the socket
- */
-qintptr RplTcpThread::getSocketDescriptor() const {
-    return m_socketDescriptor;
-}
-
-/** @class RplTcpServer rpltcpserver.hpp "rplcore/rpltcpserver"
- *
- * @brief Implements a multithreaded TCP server.
- */
-
-/**
- * @brief Constructor.
- *
- * @param configurator  some parameters will be get from this configurator
- * @param taskHandler       this handler reads from the tcp and interprets the content
- * @param threadFactory     creates a thread for a new connection
- * @param logger            NULL or logger
- * @param parent            NULL or the parent which deletes the childen
- */
-RplTcpServer::RplTcpServer(RplConfigurator& configurator,
-                           RplTaskHandler* taskHandler,
-                           RplVMThreadFactory& threadFactory,
-                           RplLogger* logger,
-                           QObject* parent) :
-    QTcpServer(parent),
-    m_taskHandler(taskHandler),
-    m_threadId(0),
-    m_threadFactory(threadFactory),
-    m_configurator(configurator){
-}
-
-/**
- * @brief The slot handling a new tcp connection.
- *
- * @param socketDescriptor  the tcp socket
- */
-void RplTcpServer::incomingConnection(qintptr socketDescriptor) {
-    RplTcpThread* thread = m_threadFactory.create(m_configurator,
-                socketDescriptor, ++m_threadId, m_taskHandler);
-    m_taskHandler->getLogger()->log(LOG_DEBUG, LOC_TCP_INCOMING_CONNECTION_1,
-                                    "Connection detected");
-    QTcpServer::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
-    thread->start();
-}
-
-/** @class RplTcpThread rpltcpserver.hpp "rplcore/rpltcpserver.hpp"
- *
- * @brief Defines a function pointer type to create a <code>RplTcpThread</code> instance.
- *
- */
-
-/** @class RplTaskHandler rpltcpserver.hpp "rplcore/rpltcpserver.hpp"
- *
- * @brief An abstract base class for an handler processing  an data unit.
- *
- * The handler knows the stucture of the data unit and can interpret this.
- */
-/**
- * @brief Constructor
- *
- * @param configurator  delivers some connection parameters
- * @param terminator    external controller for thread termination
- * @param logger        the logger
- */
-RplTaskHandler::RplTaskHandler(RplConfigurator& configurator,
-                               RplTerminator* terminator, RplLogger* logger) :
-    m_answerFlags(0),
-    m_logger(logger),
-    m_terminator(terminator),
-    m_configurator(configurator){
-}
-
-/**
- * @brief Destructor.
- */
-RplTaskHandler::~RplTaskHandler() {
-}
-
-/**
- * @brief Reads one data unit, processes it and sends the answer.
- *
- * @param peer      the communication partner
- * @return          false: the application should stop<br>
- *                  true: processing remains
- */
-bool RplTaskHandler::handle(RplTcpPeer* peer) {
-    QByteArray command;
-    QByteArray data;
-    QByteArray answer;
-    QByteArray answerData;
-    bool rc = true;
-    if(peer->receive(command, data)) {
-        rc = process(command, data, answer, answerData);
-        if(answer.length() > 0) {
-            peer->send(m_answerFlags, answer, answerData);
-        }
-    }
-    return rc;
-}
-
-/**
- * @brief Sets the thead id.
- *
- * @param id    the thread id
- */
-void RplTaskHandler::setThreadId(int id) {
-    m_threadId = id;
-}
-
-/**
- * @brief Gets the thread id.
- *
- * @return the thread id
- */
-int RplTaskHandler::getThreadId() const {
-    return m_threadId;
-}
-
-/**
- * @brief Returns the logger.
- *
- * @return  the logger
- */
-RplLogger* RplTaskHandler::getLogger() const {
-    return m_logger;
-}
-
-/**
- * @brief Returns the termination controller.
- *
- * @return the termination controller
- */
-RplTerminator* RplTaskHandler::getTerminator() const {
-    return m_terminator;
-}
-
diff --git a/rplnet/rpltcpserver.hpp b/rplnet/rpltcpserver.hpp
deleted file mode 100644 (file)
index 2683346..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
- */
-#ifndef RPLTCPSERVER_HPP
-#define RPLTCPSERVER_HPP
-
-// the sources generated from QT include this file directly:
-#ifndef RPLNET_HPP
-#include "rplnet.hpp"
-#endif
-
-class RplTcpPeer;
-class RplTaskHandler {
-public:
-    RplTaskHandler(RplConfigurator& configurator,
-                   RplTerminator* terminator,
-                   RplLogger* logger);
-    virtual ~RplTaskHandler();
-public:
-
-    virtual bool handle(RplTcpPeer* peer);
-    /**
-     * @brief Processes one data unit from the socket.
-     *
-     * @param command       defines the meaning of the information unit
-     * @param data          "" or the data of the information unit
-     * @param answer        OUT: "" or the answer to send back
-     * @param answerData    OUT: "" or the answer data to send back
-     * @return              true: the receiving loop should be continued<br>
-     *                      false: the process should be stopped
-     */
-    virtual bool process(const QByteArray& command, const QByteArray& data,
-                         QByteArray& answer, QByteArray& answerData) = 0;
-    void setThreadId(int id);
-    int getThreadId() const;
-    RplLogger* getLogger() const;
-    RplTerminator* getTerminator() const;
-protected:
-    quint8 m_answerFlags;
-private:
-    int m_threadId;
-    RplLogger* m_logger;
-    RplTerminator* m_terminator;
-    RplConfigurator& m_configurator;
-};
-
-class RplTcpThread : public QThread {
-    Q_OBJECT
-public:
-    RplTcpThread(RplConfigurator& m_configurator,
-                 qintptr socketDescriptor, int threadId,
-                 RplTaskHandler* handler);
-    virtual ~RplTcpThread();
-private:
-    // No copy constructor: no implementation!
-    RplTcpThread(const RplTcpThread& source);
-    // No assignment operator: no implementation!
-    RplTcpThread& operator=(const RplTcpThread& source);
-public:
-    void run();
-    int getThreadId() const;
-    RplTaskHandler* getTaskHandler() const;
-    qintptr getSocketDescriptor() const;
-
-signals:
-    void error(QTcpSocket::SocketError socketError);
-
-private:
-    // a unique id for the thread
-    int m_threadId;
-    // this handler interprets the info from the TCP connection
-    RplTaskHandler* m_taskHandler;
-    // the assigned socket
-    qintptr m_socketDescriptor;
-    RplConfigurator& m_configurator;
-};
-class RplThreadFactory {
-public:
-    virtual RplTcpThread* create(RplConfigurator& configurator,
-        qintptr socketDescriptor,
-        int threadId,
-        RplTaskHandler* handler) = 0;
-};
-
-class RplTcpPeer;
-class RplTcpServer : public QTcpServer, public RplTerminator {
-    Q_OBJECT
-public:
-    explicit RplTcpServer(RplConfigurator& configurator,
-            RplTaskHandler* taskHandler,
-            RplThreadFactory& threadFactory,
-            RplLogger* logger = NULL, QObject* parent = 0);
-private:
-    // No copy constructor: no implementation!
-    RplTcpServer(const RplTcpServer& source);
-    // No assignment operator: no implementation!
-    RplTcpServer& operator=(const RplTcpServer& source);
-public:
-    RplTcpPeer* getPeer() const;
-    bool handleTask();
-
-protected slots:
-    void incomingConnection(qintptr socketDescriptor);
-
-private:
-    RplTaskHandler* m_taskHandler;
-    int m_threadId;
-    RplTcpPeer* m_peer;
-    RplThreadFactory& m_threadFactory;
-    RplConfigurator& m_configurator;
-};
-
-#endif // RPLTCPSERVER_HPP
diff --git a/rplstatic/getsrc.pl b/rplstatic/getsrc.pl
deleted file mode 100644 (file)
index 7618a1f..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#! /usr/bin/perl
-
-use strict;
-
-my @rc;
-push @rc, &oneDir("../rplcore/*.hpp");
-push @rc, &oneDir("../rplmath/*.hpp");
-push @rc, &oneDir("../rplnet/*.hpp");
-push @rc, "\n";
-push @rc, &oneDir("../rplcore/*.cpp");
-push @rc, &oneDir("../rplmath/*.cpp");
-push @rc, &oneDir("../rplnet/*.cpp");
-
-print @rc;
-exit 0;
-
-sub oneDir{
-       my $pattern = shift;
-       my @rc;
-       open (my $INP, "ls -1 $pattern|") || die "ls -1 $pattern: $!";
-       while(<$INP>) {
-               if (/(\S+)/){
-                       push(@rc, "    $1 \\\n");
-               }
-       }
-       return @rc;
-}
-
-
diff --git a/rplstatic/rplstatic.pro b/rplstatic/rplstatic.pro
deleted file mode 100644 (file)
index 2263c8d..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#-------------------------------------------------
-#
-# Project created by QtCreator 2014-05-30T21:36:15
-#
-#-------------------------------------------------
-
-QT       += network testlib
-
-QT       -= gui
-
-TARGET = rplstatic
-TEMPLATE = lib
-CONFIG += staticlib
-
-INCLUDEPATH = ..
-
-SOURCES += \
-   ../rplcore/rplconfig.cpp \
-    ../rplcore/rplcontainer.cpp \
-    ../rplcore/rplexception.cpp \
-    ../rplcore/rpllogger.cpp \
-    ../rplcore/rplstring.cpp \
-    ../rplcore/rplterminator.cpp \
-    ../rplcore/rpltest.cpp \
-    ../rplmath/rplenigma.cpp \
-    ../rplmath/rplmatrix.cpp \
-    ../rplmath/rplmatrix_test.cpp \
-    ../rplmath/rplrandom.cpp \
-    ../rplnet/rplnetconfig.cpp \
-    ../rplnet/rpltcpclient.cpp \
-    ../rplnet/rpltcppeer.cpp \
-    ../rplnet/rpltcpserver.cpp \
-    ../rplexpr/rpllexer.cpp \
-    ../rplexpr/rplsource.cpp \
-    ../rplcore/rplqstring.cpp \
-    ../rplexpr/rplastree.cpp \
-    ../rplexpr/rplasclasses.cpp \
-    ../rplexpr/rplmfparser.cpp \
-    ../rplexpr/rplvm.cpp \
-    ../rplexpr/rplparser.cpp \
-    ../rplcore/rplbytestorage.cpp \
-    ../rplcore/rplwriter.cpp \
-    ../rplcore/rplcharptrmap.cpp
-
-HEADERS += ../rplmodules.hpp \
-    ../rplcore/rplconfig.hpp \
-    ../rplcore/rplconfigurator.hpp \
-    ../rplcore/rplcontainer.hpp \
-    ../rplcore/rplcore.hpp \
-    ../rplcore/rplexception.hpp \
-    ../rplcore/rpllogger.hpp \
-    ../rplcore/rplstring.hpp \
-    ../rplcore/rplterminator.hpp \
-    ../rplcore/rpltest.hpp \
-    ../rplmath/rplenigma.hpp \
-    ../rplmath/rplmath.hpp \
-    ../rplmath/rplmatrix.hpp \
-    ../rplmath/rplrandom.hpp \
-    ../rplnet/rplnetconfig.hpp \
-    ../rplnet/rplnet.hpp \
-    ../rplnet/rpltcpclient.hpp \
-    ../rplnet/rpltcppeer.hpp \
-    ../rplnet/rpltcpserver.hpp \
-    ../rplexpr/rpllexer.hpp \
-    ../rplexpr/rplexpr.hpp \
-    ../rplexpr/rplsource.hpp \
-    ../rplcore/rplqstring.hpp \
-    ../rplexpr/rplastree.hpp \
-    ../rplexpr/rplasclasses.hpp \
-    ../rplexpr/rplmfparser.hpp \
-    ../rplexpr/rplvm.hpp \
-    ../rplexpr/rplparser.hpp \
-    ../rplcore/rplbytestorage.hpp \
-    ../rplcore/rplwriter.hpp \
-    ../rplcore/rplcharptrmap.hpp
-
-unix:!symbian {
-    maemo5 {
-        target.path = /opt/usr/lib
-    } else {
-        target.path = /usr/lib
-    }
-    INSTALLS += target
-}
diff --git a/rplstatic/rplstaticlib.cpp b/rplstatic/rplstaticlib.cpp
deleted file mode 100644 (file)
index e4c28bf..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#include "rplstaticlib.hpp"
-
-
-RplStaticLib::RplStaticLib()
-{
-}
diff --git a/rplstatic/rplstaticlib.hpp b/rplstatic/rplstaticlib.hpp
deleted file mode 100644 (file)
index 80a926b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-
-#ifndef RPLSTATICLIB_HPP
-#define RPLSTATICLIB_HPP
-
-
-class RplStaticLib
-{
-
-public:
-    RplStaticLib();
-};
-
-#endif // RPLSTATICLIB_HPP
diff --git a/static/rplstatic.pro b/static/rplstatic.pro
new file mode 100644 (file)
index 0000000..82c9e9b
--- /dev/null
@@ -0,0 +1,83 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2014-05-30T21:36:15
+#
+#-------------------------------------------------
+
+QT       += network testlib
+
+QT       -= gui
+
+TARGET = rplstatic
+TEMPLATE = lib
+CONFIG += staticlib
+
+INCLUDEPATH = .. /usr/include/c++/4.9
+
+SOURCES += \
+   ../base/ReConfig.cpp \
+    ../base/ReContainer.cpp \
+    ../base/ReException.cpp \
+    ../base/ReLogger.cpp \
+    ../base/ReStringUtil.cpp \
+    ../base/ReTerminator.cpp \
+    ../base/ReTest.cpp \
+    ../math/ReEnigma.cpp \
+    ../math/ReMatrix.cpp \
+    ../math/ReRandom.cpp \
+    ../net/ReNetConfig.cpp \
+    ../net/ReTCPClient.cpp \
+    ../net/ReTCPPeer.cpp \
+    ../net/ReTCPServer.cpp \
+    ../expr/ReLexer.cpp \
+    ../expr/ReSource.cpp \
+    ../base/ReQString.cpp \
+    ../expr/ReASTree.cpp \
+    ../expr/ReASClasses.cpp \
+    ../expr/ReMFParser.cpp \
+    ../expr/ReVM.cpp \
+    ../expr/ReParser.cpp \
+    ../base/ReByteStorage.cpp \
+    ../base/ReWriter.cpp \
+    ../base/ReCharPtrMap.cpp
+
+HEADERS += ../remodules.hpp \
+    ../base/ReConfig.hpp \
+    ../base/ReConfigurator.hpp \
+    ../base/ReContainer.hpp \
+    ../base/rebase.hpp \
+    ../base/ReException.hpp \
+    ../base/ReLogger.hpp \
+    ../base/ReStringUtil.hpp \
+    ../base/ReTerminator.hpp \
+    ../base/ReTest.hpp \
+    ../math/ReEnigma.hpp \
+    ../math/remath.hpp \
+    ../math/ReMatrix.hpp \
+    ../math/ReRandom.hpp \
+    ../net/ReNetConfig.hpp \
+    ../net/renet.hpp \
+    ../net/ReTCPClient.hpp \
+    ../net/ReTCPPeer.hpp \
+    ../net/ReTCPServer.hpp \
+    ../expr/ReLexer.hpp \
+    ../expr/reexpr.hpp \
+    ../expr/ReSource.hpp \
+    ../base/ReQString.hpp \
+    ../expr/ReASTree.hpp \
+    ../expr/ReASClasses.hpp \
+    ../expr/ReMFParser.hpp \
+    ../expr/ReVM.hpp \
+    ../expr/ReParser.hpp \
+    ../base/ReByteStorage.hpp \
+    ../base/ReWriter.hpp \
+    ../base/ReCharPtrMap.hpp
+
+unix:!symbian {
+    maemo5 {
+        target.path = /opt/usr/lib
+    } else {
+        target.path = /usr/lib
+    }
+    INSTALLS += target
+}
diff --git a/static/rplstaticlib.cpp b/static/rplstaticlib.cpp
new file mode 100644 (file)
index 0000000..dfb4013
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#include "../static/rplstaticlib.hpp"
+
+
+RplStaticLib::RplStaticLib()
+{
+}
diff --git a/static/rplstaticlib.hpp b/static/rplstaticlib.hpp
new file mode 100644 (file)
index 0000000..80a926b
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+
+
+#ifndef RPLSTATICLIB_HPP
+#define RPLSTATICLIB_HPP
+
+
+class RplStaticLib
+{
+
+public:
+    RplStaticLib();
+};
+
+#endif // RPLSTATICLIB_HPP
diff --git a/unittests/main.cpp b/unittests/main.cpp
deleted file mode 100644 (file)
index 588f9e8..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-#include "../rplcore/rplcore.hpp"
-#include "../rplmath/rplmath.hpp"
-
-#include <QCoreApplication>
-
-void testCore(){
-    extern void testRplString();
-    testRplString();
-
-    extern void testRplCharPtrMap();
-    testRplCharPtrMap();
-
-    extern void testRplWriter();
-    testRplWriter();
-
-    extern void testRplByteStorage();
-    testRplByteStorage();
-
-    extern void testRplQString();
-    testRplQString();
-
-    extern void testRplString();
-    testRplString();
-
-    extern void testRplException();
-    testRplException();
-}
-
-void testExpr(){
-    extern void testRplMFParser();
-    testRplMFParser();
-
-    extern void testRplBenchmark();
-    //testRplBenchmark();
-
-    extern void testRplVM();
-    testRplVM();
-
-    extern void testRplSource();
-    testRplSource();
-
-    extern void testRplLexer();
-    testRplLexer();
-
-    extern void testRplMFParser();
-    testRplMFParser();
-
-    extern void testRplASTree();
-    testRplASTree();
-
-    extern void testRplVM();
-    testRplVM();
-
-}
-
-void testStandard(){
-    testExpr();
-    testCore();
-    extern void testRplMatrix();
-    testRplMatrix();
-
-}
-
-void labor(){
-}
-
-int main(int argc, char *argv[])
-{
-    //labor();
-    if (argc > 1)
-        printf("not used: %s\n", argv[1]);
-
-    testStandard();
-
-}
diff --git a/unittests/rplastree_test.cpp b/unittests/rplastree_test.cpp
deleted file mode 100644 (file)
index 7ace6e3..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Unit test of the abstract syntax tree.
- */
-
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplASTree : public RplTest{
-private:
-    RplSource m_source;
-    RplStringReader m_reader;
-    RplStringSourceUnit m_unit;
-    RplASTree m_tree;
-public:
-    TestRplASTree() :
-        RplTest("RplASTree"),
-        m_source(),
-        m_reader(m_source),
-        m_unit("<main>", "", &m_reader),
-        m_tree()
-    {}
-public:
-    void testRplASException() {
-        try{
-            m_reader.addSource("<main>", "12");
-            m_source.addReader(&m_reader);
-            m_source.addSourceUnit(m_reader.currentSourceUnit());
-            const RplSourcePosition* pos = m_source.newPosition(2);
-            throw RplASException(pos, "simple string: %s", "Hi");
-            checkF(true);
-        } catch (RplASException exc){
-            checkE("<main>:0:2: simple string: Hi", exc.getMessage().constData());
-        }
-    }
-    void testRplASVariant(){
-        RplASVariant val1;
-        val1.setFloat(2.5E-2);
-        checkE(2.5E-2, val1.asFloat());
-        RplASVariant val2(val1);
-        checkE(2.5E-2, val2.asFloat());
-
-        val1.setInt(4321);
-        checkE(4321, val1.asInt());
-        val2 = val1;
-        checkE(4321, val2.asInt());
-
-        val1.setBool(false);
-        checkF(val1.asBool());
-        val2 = val1;
-        checkF(val2.asBool());
-
-        val1.setBool(true);
-        checkT(val1.asBool());
-        val2 = val1;
-        checkT(val2.asBool());
-
-        val1.setString("High noon!");
-        checkE("High noon!", *val1.asString());
-        val2 = val1;
-        val1.setString("Bye");
-        checkE("High noon!", *val2.asString());
-        RplASVariant val3(val1);
-        checkE("Bye", *val3.asString());
-    }
-    void testRplASConstant(){
-        RplASConstant constant;
-        //constant.value().setString("Jonny");
-        RplASVariant value;
-        //constant.calc(value);
-        //checkE("Jonny", *value.asString());
-    }
-    void testRplASNamedValue(){
-        RplASNamedValue value(NULL, m_tree.symbolSpaces()[0], "gugo",
-                RplASNamedValue::A_GLOBAL);
-        checkE("gugo", value.name());
-    }
-    virtual void doIt() {
-        testRplASNamedValue();
-        testRplASConstant();
-        testRplASException();
-        testRplASVariant();
-    }
-};
-void testRplASTree() {
-    TestRplASTree test;
-    test.run();
-}
-
-
-
-
-
-
diff --git a/unittests/rplbench.cpp b/unittests/rplbench.cpp
deleted file mode 100644 (file)
index 86b6674..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Unit test of the abstract syntax tree.
- */
-
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplBenchmark : public RplTest{
-private:
-    const char* m_filename;
-    RplSource m_source;
-    RplFileReader m_reader;
-    RplASTree m_tree;
-public:
-    TestRplBenchmark() :
-        RplTest("RplBenchmark"),
-        m_filename("/home/ws/qt/rplqt/bench/mfbench.mf"),
-        m_source(),
-        m_reader(m_source),
-        m_tree()
-    {
-        m_source.addReader(&m_reader);
-        m_reader.addSource(m_filename);
-    }
-public:
-    void benchmark() {
-        time_t start = time(NULL);
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        time_t end = time(NULL);
-        printf("compilation: %d sec\n", int(end - start));
-    }
-    virtual void doIt() {
-        try{
-            RplFileSourceUnit* unit = dynamic_cast<RplFileSourceUnit*>
-                    (m_reader.currentSourceUnit());
-            if (unit != NULL && ! unit->isOpen())
-                throw RplException("file not found: %s", m_filename);
-            benchmark();
-        } catch(RplException ex){
-            printf("%s\n", ex.getMessage().constData());
-        }
-    }
-};
-void testRplBenchmark() {
-    TestRplBenchmark test;
-    test.run();
-}
-
-
-
diff --git a/unittests/rplbytestorage_test.cpp b/unittests/rplbytestorage_test.cpp
deleted file mode 100644 (file)
index 1245694..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-/** @file
- * @brief Unit test of the byte and C string storage.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplByteStorage : public RplTest{
-public:
-    TestRplByteStorage() :
-        RplTest("RplByteStorage")
-    {}
-private:
-    void testChars(){
-        RplByteStorage store(100);
-        char* s1 = store.allocateChars(4);
-        memcpy((void*) s1, "123", 4);
-        const char* s2 = store.allocateChars("abc");
-        const char* s3 = store.allocateChars("defghij", 3);
-        checkE(s1, "123");
-        checkE(s2, "abc");
-        checkE(s3, "def");
-        const char* ptr = s1 + 4;
-        checkT(ptr == s2);
-        ptr += 4;
-        checkT(ptr == s3);
-    }
-
-    void testBytes(){
-        RplByteStorage store(100);
-        uint8_t* s1 = store.allocateBytes(4);
-        memcpy((void*) s1, "1234", 4);
-        uint8_t* s2 = store.allocateBytes((void*) "abcd", 4);
-        uint8_t* s3 = store.allocateBytes((void*) "efghij", 4);
-        uint8_t* s4 = store.allocateZeros(4);
-
-        checkE("1234abcdefgh", (const char*) s1);
-        uint8_t* ptr = s1 + 4;
-        checkT(ptr == s2);
-        ptr += 4;
-        checkT(ptr == s3);
-        ptr += 4;
-        checkT(ptr == s4);
-        for (int ii = 0; ii < 4; ii++)
-            checkE(0, (int) s4[ii]);
-    }
-    void testBufferChange(){
-        RplByteStorage store(10);
-        char buffer[2];
-        buffer[1] = '\0';
-        for (int ii = 0; ii < 10000; ii++){
-            buffer[1] = 'A' + ii % 26;
-            store.allocateBytes(buffer, 1);
-        }
-        int a = 1;
-    }
-
-public:
-    virtual void doIt() {
-        testBufferChange();
-        testChars();
-        testBytes();
-    }
-};
-void testRplByteStorage() {
-    TestRplByteStorage test;
-    test.run();
-}
-
-
diff --git a/unittests/rplcharptrmap_test.cpp b/unittests/rplcharptrmap_test.cpp
deleted file mode 100644 (file)
index 3600efb..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-#include "rplcore/rplcore.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplCharPtrMap : public RplTest{
-public:
-    TestRplCharPtrMap() :
-        RplTest("RplCharPtrMap")
-    {
-    }
-protected:
-    void testBasic(){
-        RplCharPtrMap<const char*> map;
-        map["x"] = "x1";
-        checkT(map.contains("x"));
-        checkF(map.contains("y"));
-        checkE("x1", map["x"]);
-    }
-
-    virtual void doIt(void) {
-        testBasic();
-    }
-};
-void testRplCharPtrMap() {
-    TestRplCharPtrMap test;
-    test.run();
-}
diff --git a/unittests/rplexception_test.cpp b/unittests/rplexception_test.cpp
deleted file mode 100644 (file)
index 39e124a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-#include "rplcore/rplcore.hpp"
-#include "rplcore/rpltest.hpp"
-/** @file
- * @brief Unit test of the basic exceptions.
- */
-
-class TestRplException : public RplTest{
-public:
-    TestRplException() : RplTest("RplException") {}
-
-public:
-    void testBasic() {
-        try{
-            throw RplException("simple");
-            checkF(true);
-        } catch (RplException exc){
-            checkE("simple", exc.getMessage().constData());
-        }
-        try{
-            throw RplException("String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (RplException exc){
-            checkE("String: Hi and int -333", exc.getMessage().constData());
-        }
-        try{
-            throw RplException(LOG_INFO, 1234, &m_memoryLogger,
-                    "String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (RplException exc){
-            checkT(logContains("^ .*\\(1234\\): String: Hi and int -333"));
-        }
-        log("ok");
-    }
-    virtual void doIt() {
-        testBasic();
-    }
-};
-void testRplException() {
-    TestRplException test;
-    test.run();
-}
-
-
-
diff --git a/unittests/rpllexer_test.cpp b/unittests/rpllexer_test.cpp
deleted file mode 100644 (file)
index 3d9696e..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Unit test of the syntax symbol extractor.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplLexer : public RplTest, public RplToken{
-public:
-    TestRplLexer() :
-        RplTest("RplLexer"),
-        RplToken(TOKEN_ID)
-    {}
-
-public:
-    void testRplToken(){
-        // test constructor values:
-        checkE(TOKEN_ID, tokenType());
-        checkE(0, m_value.m_id);
-        checkT(m_string.isEmpty());
-        checkT(m_printableString.isEmpty());
-
-        m_value.m_id = 7422;
-        checkE(7422, RplToken::id());
-        m_string = "Wow!";
-        checkE("Wow!", RplToken::toString());
-        m_printableString = "GooGoo";
-        checkE("GooGoo", rawString());
-        m_tokenType = TOKEN_NUMBER;
-        checkE(TOKEN_NUMBER, tokenType());
-
-        clear();
-        checkE(TOKEN_UNDEF, tokenType());
-        checkE(0, m_value.m_id);
-        checkT(m_string.isEmpty());
-        checkT(m_printableString.isEmpty());
-
-        m_value.m_integer = 773322;
-        checkE(773322, asInteger());
-        m_value.m_real = 0.25;
-        checkE(0.25, asReal());
-    }
-
-    RplToken* checkToken(RplToken* token, RplTokenType type, int id = 0,
-                    const char* string = NULL){
-        checkE(type, token->tokenType());
-        if (id != 0)
-            checkE(id, token->id());
-        if (string != NULL)
-            checkE(string, token->toString());
-        return token;
-    }
-    enum { KEY_UNDEF, KEY_IF, KEY_THEN, KEY_ELSE, KEY_FI
-         };
-#   define KEYWORDS "if then else fi"
-    enum { OP_UNDEF, OP_PLUS, OP_TIMES, OP_DIV, OP_GT,
-           OP_LT, OP_GE, OP_LE, OP_EQ, OP_ASSIGN, OP_PLUS_ASSIGN, OP_DIV_ASSIGN,
-           OP_TIMES_ASSIGN
-         };
-#   define OPERATORS "+\n* /\n> < >= <= ==\n= += /= *="
-    enum { COMMENT_UNDEF, COMMENT_1, COMMENT_MULTILINE, COMMENT_2
-    };
-#   define COMMENTS "/* */ // \n"
-    void testSpace(){
-        RplSource source;
-        RplStringReader reader(source);
-#       define BLANKS1 "\t\t   \n"
-#       define BLANKS2 " \n"
-        reader.addSource("<main>", BLANKS1 BLANKS2);
-        source.addReader(&reader);
-        RplLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_DECIMAL,
-                 RplLexer::SF_TICK, RplLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS1);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS2);
-    }
-    void testNumeric(){
-        RplSource source;
-        RplStringReader reader(source);
-        const char* blanks = "321 0x73 7.8e+5";
-        reader.addSource("<main>", blanks);
-        source.addReader(&reader);
-        RplLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_TICK, RplLexer::STORE_ALL);
-        RplToken* token = checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkE(321, token->asInteger());
-        token = checkToken(lex.nextNonSpaceToken(), TOKEN_NUMBER);
-        checkE(0x73, token->asInteger());
-        token = checkToken(lex.nextNonSpaceToken(), TOKEN_REAL);
-        checkE(7.8e+5, token->asReal());
-    }
-
-    void testOperators(){
-        RplSource source;
-        RplStringReader reader(source);
-        const char* ops = "<< < <<< <= == = ( ) [ ]";
-        reader.addSource("<main>", ops);
-        source.addReader(&reader);
-        enum { UNDEF, SHIFT, LT, SHIFT2, LE, EQ, ASSIGN,
-               LPARENT, RPARENT, LBRACKET, RBRACKET };
-        RplLexer lex(&source, KEYWORDS, ops, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_TICK, RplLexer::STORE_ALL);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT2);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LE);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, EQ);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, ASSIGN);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
-        reader.addSource("<buffer2>", "(([[");
-        lex.startUnit("<buffer2>");
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
-    }
-
-    void testComments(){
-        RplSource source;
-        RplStringReader reader(source);
-
-        reader.addSource("<main>", "/**/9//\n8/***/7// wow\n/*\n*\n*\n**/");
-        source.addReader(&reader);
-
-        enum { COMMENT_UNDEF, COMMENT_MULTILINE, COMMENT_1
-        };
-        RplLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_LIKE_C, RplLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
-                   "/**/");
-        checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
-                   "//\n");
-        checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
-                   "/***/");
-        checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1,
-                   "// wow\n");
-        checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE,
-                   "/*\n*\n*\n**/");
-    }
-    void testStrings(){
-        RplSource source;
-        RplStringReader reader(source);
-
-        reader.addSource("<main>", "\"abc\\t\\r\\n\\a\\v\"'1\\x9Z\\x21A\\X9'");
-        source.addReader(&reader);
-
-        RplLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_LIKE_C, RplLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_STRING, '"', "abc\t\r\n\a\v");
-        checkToken(lex.nextToken(), TOKEN_STRING, '\'', "1\tZ!A\t");
-    }
-    void testKeywords(){
-        RplSource source;
-        RplStringReader reader(source);
-
-        reader.addSource("<main>", "if\n\tthen else\nfi");
-        source.addReader(&reader);
-
-        RplLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_LIKE_C, RplLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_THEN);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_ELSE);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_FI);
-        checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE);
-    }
-
-    void testIds(){
-        RplSource source;
-        RplStringReader reader(source);
-
-        reader.addSource("<main>", "i\n\tifs\n"
-            "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
-        source.addReader(&reader);
-
-        RplLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_LIKE_C, RplLexer::STORE_ALL);
-        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
-        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
-           "ifs");
-        checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0,
-           "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
-    }
-
-    void testBasic(){
-        RplSource source;
-        RplStringReader reader(source);
-        source.addReader(&reader);
-        reader.addSource("<main>", "if i>1 then i=1+2*_x9 fi");
-        RplLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_LIKE_C, RplLexer::STORE_ALL);
-        RplToken* token;
-        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
-        checkToken(lex.nextToken(), TOKEN_ID, 0, "i");
-        checkToken(lex.nextToken(), TOKEN_OPERATOR, OP_GT);
-        token = checkToken(lex.nextToken(), TOKEN_NUMBER);
-        checkE(1, token->asInteger());
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
-        checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_THEN);
-        checkToken(lex.nextToken(), TOKEN_SPACE, 0);
-
-    }
-    void testPrio(){
-        RplSource source;
-        RplStringReader reader(source);
-        source.addReader(&reader);
-        reader.addSource("x", "");
-        enum { O_UNDEF, O_ASSIGN, O_PLUS, O_MINUS, O_TIMES, O_DIV
-             };
-        RplLexer lex(&source, KEYWORDS,
-                     "=\n+ -\n* /", "=",
-                 COMMENTS,
-                 "A-Za-z_",
-                 "A-Za-z0-9_",
-                 RplLexer::NUMTYPE_ALL,
-                 RplLexer::SF_LIKE_C, RplLexer::STORE_ALL);
-        checkT(lex.prioOfOp(O_ASSIGN) < lex.prioOfOp(O_PLUS));
-        checkE(lex.prioOfOp(O_PLUS), lex.prioOfOp(O_MINUS));
-        checkT(lex.prioOfOp(O_MINUS) < lex.prioOfOp(O_TIMES));
-        checkE(lex.prioOfOp(O_TIMES), lex.prioOfOp(O_DIV));
-    }
-
-    virtual void doIt(void) {
-        testPrio();
-        testBasic();
-        testIds();
-        testKeywords();
-        testComments();
-        testStrings();
-        testOperators();
-        testNumeric();
-        testSpace();
-        testRplToken();
-    }
-};
-void testRplLexer() {
-    TestRplLexer test;
-    test.run();
-}
diff --git a/unittests/rplmatrix_test.cpp b/unittests/rplmatrix_test.cpp
deleted file mode 100644 (file)
index b9a651d..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Matrix_test.cpp
- *
- *  Created on: 29.05.2014
- *      Author: hm
- */
-
-/** @file
- * @brief Unit test of the matrices.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplmath/rplmath.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplMatrix : public RplTest{
-public:
-    TestRplMatrix() : RplTest("RplMatrix") {}
-
-public:
-    void fillMatrix(RplMatrix& mx, MatVal offset = 0){
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                mx.set(row, col, 100.0*row + col + offset);
-            }
-        }
-    }
-    void checkMatrix(const RplMatrix& mx, MatVal offset = 0){
-        int count = 0;
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                checkE(100.0*row + col + offset, mx.get(row, col));
-                count++;
-            }
-        }
-        checkE(mx.getCols()*mx.getRows(), count);
-    }
-    void fillConst(RplMatrix& mx, MatVal value){
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                mx.set(row, col, value);
-            }
-        }
-    }
-    void checkConst(const RplMatrix& mx, MatVal value){
-        int count = 0;
-        for(int row = 0; row < mx.getRows(); row++){
-            for (int col = 0; col < mx.getCols(); col++){
-                checkE(value, mx.get(row, col));
-                count++;
-            }
-        }
-        checkE(mx.getCols()*mx.getRows(), count);
-    }
-
-    void testBasic() {
-        Tuple2 tuple(-2.0, 0.5);
-        checkE(-2.0, tuple.m_value1);
-        checkE(0.5, tuple.m_value2);
-        RplMatrix mat("mx");
-        try{
-            throw RplMatrixException(mat, "String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (RplMatrixException exc){
-            checkE("mx: String: Hi and int -333", exc.getMessage());
-        }
-        RplMatrix mat2;
-        try{
-            throw RplMatrixException(mat2, "String: %s and int %d", "Hi", -333);
-            checkF(true);
-        } catch (RplMatrixException exc){
-            checkE("String: Hi and int -333", exc.getMessage());
-        }
-        checkE("mx", mat.getName());
-        checkE("", mat2.getName());
-
-        RplMatrix m2x3(2, 3, "m2x3");
-        checkE("m2x3", m2x3.getName());
-        checkE(2, m2x3.getRows());
-        checkE(3, m2x3.getCols());
-        fillMatrix(m2x3);
-        checkMatrix(m2x3);
-
-        RplMatrix mxCopy(m2x3);
-        checkE("m2x3-copy", mxCopy.getName());
-        checkE(2, mxCopy.getRows());
-        checkE(3, mxCopy.getCols());
-        checkMatrix(mxCopy);
-
-        RplMatrix mxCopy2("mxCopy2");
-        mxCopy2 = m2x3;
-        checkE("mxCopy2", mxCopy2.getName());
-        checkE(2, mxCopy2.getRows());
-        checkE(3, mxCopy2.getCols());
-        checkMatrix(mxCopy2);
-    }
-    void testAddOperators(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(3, 2, "m2");
-        fillMatrix(m2, 42);
-        checkMatrix(m2, 42);
-        RplMatrix m3(3, 2, "m3");
-        fillMatrix(m3, -42);
-        checkMatrix(m3, -42);
-
-        m1 += 42;
-        checkMatrix(m1, 42);
-
-        checkT(m1 == m2);
-        checkF(m1 == m3);
-
-        m1 -= 42;
-        checkMatrix(m1);
-        m1 -= m1;
-        checkConst(m1, 0);
-
-        fillMatrix(m1);
-        m1 -= m3;
-        checkConst(m1, 42);
-        m1 += m2;
-        checkMatrix(m1, 42*2);
-    }
-    void testCompareOperators(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(3, 2, "m2");
-        fillMatrix(m2);
-
-        checkT(m1 == m2);
-        checkF(m1 != m2);
-        // modify each element, comparism must return false:
-        int row, col;
-        for (row = 0; row < m2.getRows(); row++)
-            for (col = 0; col < m2.getCols(); col++){
-                fillMatrix(m2);
-                m2.set(row, col, -1);
-                checkF(m1 == m2);
-                checkT(m1 != m2);
-            }
-
-        fillConst(m1, 42);
-        checkT(m1 == 42);
-        checkF(m1 == 43);
-        checkT(m1 != 43);
-        for (row = 0; row < m1.getRows(); row++)
-            for (col = 0; col < m1.getCols(); col++){
-                fillMatrix(m1, 42);
-                m1.set(row, col, -1);
-                checkF(m1 == 42);
-                checkT(m1 != 42);
-            }
-    }
-
-    void testCheckDefinition(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(3, 2, "m2");
-        fillMatrix(m2);
-
-        m1.checkDefinition(1, 1);
-        m1.checkDefinition(1000, 1000);
-        m1.checkDefinition(0, 0);
-        try {
-            m1.checkDefinition(-1, 1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: row number negative: -1", exc.getMessage());
-        }
-        try {
-            m1.checkDefinition(1, -1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: column number negative: -1", exc.getMessage());
-        }
-
-    }
-    void testCheck(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-
-        m1.check(0, 0);
-        m1.check(3-1, 2-1);
-        try {
-            m1.check(-1, 1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: invalid row: -1 not in [0,3[", exc.getMessage());
-        }
-        try {
-            m1.check(3, 1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: invalid row: 3 not in [0,3[", exc.getMessage());
-        }
-        try {
-            m1.check(1, -1);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: invalid column: -1 not in [0,2[", exc.getMessage());
-        }
-        try {
-            m1.check(1, 2);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: invalid column: 2 not in [0,2[", exc.getMessage());
-        }
-    }
-    void testCheckSameDimension(){
-        RplMatrix m1(3, 2, "m1");
-        RplMatrix m2(3, 2, "m2");
-
-        m1.checkSameDimension(m2);
-
-        m2.resize(2, 2);
-        try {
-            m1.checkSameDimension(m2);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: m2 has a different row count: 3 / 2", exc.getMessage());
-        }
-        m2.resize(3, 3);
-        try {
-            m1.checkSameDimension(m2);
-            checkT(false);
-        } catch(RplMatrixException exc){
-            checkE("m1: m2 has a different column count: 2 / 3", exc.getMessage());
-        }
-    }
-    void testResize(){
-        RplMatrix m1(3, 2, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        RplMatrix m2(2, 4, "m2");
-        fillConst(m2, 0);
-        checkConst(m2, 0);
-
-        m1.resize(2, 4);
-        checkE(2, m1.getRows());
-        checkE(4, m1.getCols());
-        checkT(m1 == m2);
-    }
-
-    void testMinMax(){
-        RplMatrix m1(4, 5, "m1");
-        fillMatrix(m1);
-        checkMatrix(m1);
-        m1.set(0, 0, -98);
-        m1.set(3, 4, 9999);
-        Tuple2 miniMax = m1.minMax();
-        checkE(-98.0, miniMax.m_value1);
-        checkE(9999.0, miniMax.m_value2);
-
-        fillMatrix(m1);
-        checkMatrix(m1);
-        m1.set(1, 1, 7777);
-        m1.set(3, 4, -987);
-        miniMax = m1.minMax();
-        checkE(-987.0, miniMax.m_value1);
-        checkE(7777.0, miniMax.m_value2);
-    }
-
-    void testTranspose()
-    {
-        RplMatrix m1(1, 5, "m1");
-        fillMatrix(m1);
-        RplMatrix m2(m1.transpose());
-
-        checkE(5, m2.getRows());
-        checkE(1, m2.getCols());
-
-        int row, col;
-        col = 0;
-        for (row = 0; row < 5; row++){
-            checkE(qreal(col*100+row), m2.get(row, 0));
-        }
-
-        m1.resize(35, 73);
-        fillMatrix(m1);
-        m2 = m1.transpose();
-
-        checkE(73, m2.getRows());
-        checkE(35, m2.getCols());
-
-        int count = 0;
-        for (row = 0; row < m2.getRows(); row++){
-            for (col = 0; col < m2.getCols(); col++){
-                checkE(qreal(col*100+row), m2.get(row, col));
-                count++;
-            }
-        }
-        checkE(73*35, count);
-    }
-    void testToString(){
-        RplMatrix m1(1, 1, "m1");
-        m1.set(0, 0, 2.34);
-        checkE("[2.340000,\n]", m1.toString().constData());
-        checkE("jonny[2.34000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
-
-        m1.resize(2, 1);
-        m1.set(0, 0, 2.34);
-        m1.set(1, 0, 55.5);
-
-        checkE("[2.340000,\n55.500000,\n]", m1.toString().constData());
-        checkE("jonny[2.34000 |55.50000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
-        log("");
-    }
-    void testReadCsv(){
-        QByteArray fn = getTempFile("rplmatrixtest.csv");
-        const char* content;
-        RplMatrix m1(1,1,"m1");
-
-        fillMatrix(m1);
-        content = ",Port0,Port1,Port2\n"
-                "element1,5,  -3E-99  , 0.5\n"
-                "element2,7,-22.3,44\n"
-                "\n"
-                "2 Elements, 3, Ports";
-        RplString::write(fn, content);
-        m1.readFromCvs(fn, 256);
-        checkE(2, m1.getRows());
-        checkE(3, m1.getCols());
-
-        checkE(5.0, m1.get(0, 0));
-        checkE(-3.0E-99, m1.get(0, 1));
-        checkE(0.5, m1.get(0, 2));
-
-        checkE(7.0, m1.get(1, 0));
-        checkE(-22.3, m1.get(1, 1));
-        checkE(44.0, m1.get(1, 2));
-
-        fillMatrix(m1);
-        content = "Port0,Port1,Port2\n"
-                "5,  -3E-99  , 0.5\n";
-        RplString::write(fn, content);
-        m1.readFromCvs(fn, 256);
-        checkE(1, m1.getRows());
-        checkE(3, m1.getCols());
-        checkE(5.0, m1.get(0, 0));
-        checkE(-3.0E-99, m1.get(0, 1));
-        checkE(0.5, m1.get(0, 2));
-
-
-/*
-    void readFromCvs(const char* filename, int maxLineLength = 1024*1024);
-    void readFromXml(const char* filename, const char* tagCol,
-            const char* tagRow, const char* tagTable,
-            int maxLineLength = 1024*1024);
-*/
-    }
-    virtual void doIt(void) {
-        testBasic();
-        testAddOperators();
-        testCompareOperators();
-        testCheckDefinition();
-        testCheck();
-        testCheckSameDimension();
-        testResize();
-        testMinMax();
-        testTranspose();
-        testToString();
-        testReadCsv();
-    }
-};
-void testRplMatrix() {
-    TestRplMatrix test;
-    test.run();
-}
diff --git a/unittests/rplmfparser_test.cpp b/unittests/rplmfparser_test.cpp
deleted file mode 100644 (file)
index 6266a48..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-/** @file
- * @brief Unit test of the parser for the language "MF".
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplMFParser : public RplTest{
-private:
-    RplSource m_source;
-    RplASTree m_tree;
-    RplStringReader m_reader;
-    RplFileReader m_fileReader;
-    QByteArray m_currentSource;
-public:
-    TestRplMFParser() :
-        RplTest("RplMFParser"),
-        m_source(),
-        m_tree(),
-        m_reader(m_source),
-        m_fileReader(m_source)
-    {
-        m_source.addReader(&m_reader);
-    }
-protected:
-    void setSource(const char* content){
-        RplASItem::reset();
-        m_currentSource = content;
-        m_tree.clear();
-        m_source.clear();
-        m_reader.clear();
-        m_reader.addSource("<test>", content);
-        m_source.addReader(&m_reader);
-        m_source.addSourceUnit(m_reader.currentSourceUnit());
-    }
-    void setFileSource(const char* filename){
-        RplASItem::reset();
-        m_currentSource = RplString::read(filename);
-        m_tree.clear();
-        m_source.clear();
-        m_fileReader.clear();
-        m_fileReader.addSource(filename);
-        m_source.addReader(&m_fileReader);
-        m_source.addSourceUnit(m_fileReader.currentSourceUnit());
-    }
-
-private:
-    void checkAST(const char* fileExpected, int lineNo){
-        QByteArray fnExpected = "test";
-        fnExpected += QDir::separator().toLatin1();
-        fnExpected += "mfparser";
-        fnExpected += (char) QDir::separator().toLatin1();
-        fnExpected += fileExpected;
-        QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser");
-        m_tree.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS, m_currentSource);
-        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
-                         __FILE__, lineNo);
-    }
-
-public:
-    void fileClassTest(){
-        setFileSource("test/rplmfparser/string1.mf");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("string1.txt", __LINE__);
-    }
-
-    void baseTest(){
-        setSource("2+3*4");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("baseTest.txt", __LINE__);
-    }
-
-    void varDefTest(){
-        setSource("const lazy Str s = 'Hi';\nconst List l;\nInt i = 3;");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("varDefTest.txt", __LINE__);
-    }
-
-    void ifTest(){
-        setSource("Int a;\nInt b;\na = b = 2;\nif 11 < 12\nthen a = 13 * 14\nelse a = 15 / 16\nfi");
-        // setSource("Int a; if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("ifTest1.txt", __LINE__);
-        setSource("Str x;\nif 7 < 6\nthen x = '123';\nfi");
-        parser.parse();
-        checkAST("ifTest2.txt", __LINE__);
-    }
-    void whileTest(){
-        setSource("Int a = 20;\nwhile 3 < 5 do\n a = 7\nod");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("whileTest.txt", __LINE__);
-    }
-
-    void repeatTest(){
-        setSource("Int a;\nrepeat\na++;\nuntil a != 2 * 3;");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("repeatTest.txt", __LINE__);
-    }
-    void forCTest(){
-        setSource("Int a;\nfor b from 10 to 1 step -2 do\na += 1;\nod");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("forC1.txt", __LINE__);
-        setSource("Int a; for to 10 do a += 1 od");
-        parser.parse();
-        checkAST("forC2.txt", __LINE__);
-    }
-    void opTest(){
-        checkE(25, RplMFParser::O_QUESTION);
-        checkE(37, RplMFParser::O_RSHIFT2);
-        checkE(41, RplMFParser::O_DEC);
-        checkE(48, RplMFParser::O_RBRACE);
-        setSource("Int a = 1;\nInt b = 100;\n--a;\nb++;\na--*++b**(8-3);\na=b=(a+(b-2)*3)");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("opTest1.txt", __LINE__);
-    }
-    void forItTest(){
-        setSource("Map a;\nfor x in a do\na += 1;\nod");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("forIt1.txt", __LINE__);
-    }
-    void listTest(){
-        RplMFParser parser(m_source, m_tree);
-        setSource("List b = [];");
-        parser.parse();
-        checkAST("list1.txt", __LINE__);
-        setSource("List a = [2+3, 3.14, 7, 'hi', a]; List b = [];");
-        parser.parse();
-        checkAST("list2.txt", __LINE__);
-    }
-    void mapTest(){
-        setSource("Map a = {};");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("map1.txt", __LINE__);
-        setSource("Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'};\nMap b = {};");
-        parser.parse();
-        checkAST("map2.txt", __LINE__);
-    }
-    void methodCallTest(){
-        //setSource("max(4,3.14);");
-        setSource("rand();\nsin(a);\nmax(1+2*3,4**(5-4));");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("methc1.txt", __LINE__);
-    }
-    void fieldTest(){
-        setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("field1.txt", __LINE__);
-    }
-
-    void methodTest(){
-        setSource("func Float pi: 3.1415; endf func Str delim(): '/' endf;");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("meth1.txt", __LINE__);
-        setSource("func Int fac(const Int n):\n"
-                  "Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi\n"
-                  "rc endf");
-        parser.parse();
-        checkAST("meth2.txt", __LINE__);
-        setSource("func Int max(Int a, Int b):\n Int rc = a;\n"
-                  "if a < b then rc = b; fi\nrc\n"
-                  "endf\n"
-                  "func Int max(const Int a, Int b, Int c):\n"
-                  "max(a, max(b, c))\n"
-                  "endf");
-        parser.parse();
-        checkAST("meth3.txt", __LINE__);
-        setSource("func Int max(const Int a, Int b, Int c):\n"
-                  "func Int max(Int a, Int b):\n Int rc = a;\n"
-                  "if a < b then rc = b; fi\nrc\n"
-                  "endf\n"
-                  "max(a, max(b, c))\n"
-                  "endf");
-        parser.parse();
-        checkAST("meth4.txt", __LINE__);
-    }
-    void mainTest(){
-        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        checkAST("main1.txt", __LINE__);
-    }
-
-    virtual void doIt(void) {
-        mainTest();
-        varDefTest();
-        repeatTest();
-        baseTest();
-        whileTest();
-        methodTest();
-        fieldTest();
-        methodCallTest();
-        mapTest();
-        forItTest();
-        forCTest();
-        listTest();
-        opTest();
-        fileClassTest();
-    }
-};
-void testRplMFParser() {
-    TestRplMFParser test;
-    test.run();
-}
-
-
diff --git a/unittests/rplqstring_test.cpp b/unittests/rplqstring_test.cpp
deleted file mode 100644 (file)
index bdadd09..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-/** @file
- * @brief Unit test of the QString tools.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplQString : public RplTest {
-public:
-    TestRplQString() :
-        RplTest("RplQString")
-    {}
-
-public:
-    void testLengthOfUInt64(){
-        quint64 value = -3;
-        checkE(1, RplQString::lengthOfUInt64(QString("0"), 0, 10, &value));
-        checkE(0LL, value);
-        checkE(3, RplQString::lengthOfUInt64("x432", 1, 10, &value));
-        checkE(432LL, value);
-        checkE(3, RplQString::lengthOfUInt64("x432 x", 1, 10, &value));
-        checkE(432LL, value);
-        checkE(3, RplQString::lengthOfUInt64("x432fabc x", 1, 10, &value));
-        checkE(432LL, value);
-        checkE(16, RplQString::lengthOfUInt64("a1234567890123567", 1, 10, &value));
-        checkE(1234567890123567LL, value);
-        checkE(10, RplQString::lengthOfUInt64("x1234abcdef", 1, 16, &value));
-        checkE(0x1234abcdefLL, value);
-        checkE(3, RplQString::lengthOfUInt64("432", 0, 8, &value));
-        checkE(0432LL, value);
-        checkE(6, RplQString::lengthOfUInt64(" 765432 ", 1, 8, &value));
-        checkE(0765432LL, value);
-
-        checkE(0, RplQString::lengthOfUInt64("1 ", 1, 8, &value));
-        checkE(0, RplQString::lengthOfUInt64("", 1, 8, &value));
-    }
-    void testLengthOfUInt(){
-        uint value = 3;
-        checkE(1, RplQString::lengthOfUInt(QString("0"), 0, 10, &value));
-        checkE(0, value);
-        checkE(3, RplQString::lengthOfUInt("x432", 1, 10, &value));
-        checkE(432, value);
-        checkE(3, RplQString::lengthOfUInt("x432 x", 1, 10, &value));
-        checkE(432, value);
-        checkE(3, RplQString::lengthOfUInt("x432fabc x", 1, 10, &value));
-        checkE(432, value);
-        checkE(3, RplQString::lengthOfUInt("432", 0, 8, &value));
-        checkE(0432, value);
-        checkE(6, RplQString::lengthOfUInt(" 765432 ", 1, 8, &value));
-        checkE(0765432, value);
-
-        checkE(0, RplQString::lengthOfUInt("1 ", 1, 8, &value));
-        checkE(0, RplQString::lengthOfUInt("", 1, 8, &value));
-    }
-    void testLengthOfReal(){
-        qreal value;
-        checkE(4, RplQString::lengthOfReal(QString("0.25"), 0, &value));
-        checkE(0.25, value);
-        checkE(3, RplQString::lengthOfReal(QString("X.25"), 1, &value));
-        checkE(0.25, value);
-        checkE(1, RplQString::lengthOfReal(QString(" 0"), 1, &value));
-        checkE(0.0, value);
-        checkE(17, RplQString::lengthOfReal(QString("X12345678901234567"), 1, &value));
-        checkE(12345678901234567.0, value);
-        checkE(2, RplQString::lengthOfReal(QString(".5"), 0, &value));
-        checkE(0.5, value);
-        checkE(5, RplQString::lengthOfReal(QString("2.5e2x"), 0, &value));
-        checkE(250.0, value);
-        checkE(6, RplQString::lengthOfReal(QString("2.5e+2"), 0, &value));
-        checkE(250.0, value);
-        checkE(7, RplQString::lengthOfReal(QString("2.5E-33"), 0, &value));
-        checkE(2.5e-33, value);
-
-        checkE(3, RplQString::lengthOfReal(QString("2.5E"), 0, &value));
-        checkE(2.5, value);
-        checkE(3, RplQString::lengthOfReal(QString("2.5E+"), 0, &value));
-        checkE(2.5, value);
-        checkE(3, RplQString::lengthOfReal(QString("2.5E-a"), 0, &value));
-        checkE(2.5, value);
-    }
-
-    void testValueOfHexDigit(){
-        checkE(0, RplQString::valueOfHexDigit('0'));
-        checkE(9, RplQString::valueOfHexDigit('9'));
-        checkE(10, RplQString::valueOfHexDigit('a'));
-        checkE(15, RplQString::valueOfHexDigit('f'));
-        checkE(10, RplQString::valueOfHexDigit('A'));
-        checkE(15, RplQString::valueOfHexDigit('F'));
-
-        checkE(-1, RplQString::valueOfHexDigit('0' - 1));
-        checkE(-1, RplQString::valueOfHexDigit('9' + 1));
-        checkE(-1, RplQString::valueOfHexDigit('A' - 1));
-        checkE(-1, RplQString::valueOfHexDigit('F' + 1));
-        checkE(-1, RplQString::valueOfHexDigit('a' - 1));
-        checkE(-1, RplQString::valueOfHexDigit('f' + 1));
-    }
-    void testUtf8(){
-        QString name = "Heinz Müller";
-        char buffer[32];
-        checkE("Heinz Müller", RplQString::utf8(name, buffer, sizeof buffer));
-        memset(buffer, 'x', sizeof buffer);
-        checkE("Heinz", RplQString::utf8(name, buffer, (size_t) (5+1)));
-        checkE(buffer[6], 'x');
-    }
-
-    virtual void doIt(void) {
-        testUtf8();
-        testLengthOfUInt64();
-        testLengthOfUInt();
-        testLengthOfReal();
-        testValueOfHexDigit();
-    }
-};
-void testRplQString() {
-    TestRplQString test;
-    test.run();
-}
-
diff --git a/unittests/rplsource_test.cpp b/unittests/rplsource_test.cpp
deleted file mode 100644 (file)
index 49eeeae..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Unit test of the input media reader.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplSource : public RplTest{
-public:
-    TestRplSource() : RplTest("TestRplSource") {}
-
-private:
-    QByteArray m_content1_1;
-    QByteArray m_content1_2;
-    QByteArray m_content2;
-    RplSource m_source;
-
-protected:
-    void init(){
-        m_content1_1 = "# test\nimport source2\n";
-        m_content1_2 = "a=1;\nveeeeeeeeery looooooooooooooong\n";
-        m_content2 = "x=2";
-    }
-
-    void testRplStringSourceUnit(){
-        RplStringReader reader(m_source);
-        QByteArray content("a=1;\nveeeeeeeeery looooooooooooooong\n");
-        RplStringSourceUnit unit("test", content, &reader);
-        unit.setLineNo(144);
-        checkE(144, unit.lineNo());
-        checkE("test", unit.name());
-    }
-    void checkOne(int maxSize, RplReader& reader){
-        QByteArray total;
-        QByteArray buffer;
-        int lineNo = 0;
-        bool hasMore;
-        checkF(reader.openSourceUnit("unknownSource"));
-        checkT(reader.openSourceUnit("source1"));
-        while(reader.nextLine(maxSize, buffer, hasMore)){
-            lineNo++;
-            total += buffer;
-            buffer.clear();
-            while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
-                total += buffer;
-                buffer.clear();
-            }
-            bool isImport = total.endsWith("source2\n");
-            if (isImport){
-                reader.openSourceUnit("source2");
-                checkE("source2", reader.currentSourceUnit()->name());
-                while(reader.nextLine(maxSize, buffer, hasMore)){
-                    lineNo++;
-                    while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){
-                        total += buffer;
-                        buffer.clear();
-                    }
-                }
-                checkE("source1", reader.currentSourceUnit()->name());
-            }
-        }
-        checkE(5, lineNo);
-        checkE(m_content1_1 + m_content2 + m_content1_2, total);
-
-    }
-
-    void testRplStringReader(){
-        RplStringReader reader(m_source);
-        reader.addSource("source1", m_content1_1 + m_content1_2);
-        reader.addSource("source2", m_content2);
-        RplSourceUnit* unit = reader.openSourceUnit("source1");
-        checkNN(unit);
-        checkE("source1", unit->name());
-        checkE(0, unit->lineNo());
-        checkOne(6, reader);
-        checkOne(100, reader);
-        reader.replaceSource("source2", "content2");
-
-        unit = reader.openSourceUnit("source2");
-        QByteArray buffer;
-        bool hasMore;
-        checkT(reader.nextLine(50, buffer, hasMore));
-        checkE("content2", buffer);
-        checkF(hasMore);
-    }
-
-public:
-    virtual void doIt(void) {
-        init();
-        testRplStringSourceUnit();
-        testRplStringReader();
-    }
-};
-void testRplSource() {
-    TestRplSource test;
-    test.run();
-}
-
-
-
diff --git a/unittests/rplstring_test.cpp b/unittests/rplstring_test.cpp
deleted file mode 100644 (file)
index 8983dc0..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Unit test of the QByteArray tools.
- */
-#include "rplcore/rplcore.hpp"
-#include "rplcore/rpltest.hpp"
-/**
- * @brief Unit test for <code>RplString</code>.
- */
-class TestRplString : public RplTest {
-public:
-    TestRplString() : RplTest("RplString") {}
-
-public:
-    void testCountChar(){
-        checkE(1, RplString::countChar("x", 'x'));
-        checkE(0, RplString::countChar("X", 'x'));
-        checkE(2, RplString::countChar("xbxxbxx", 'b'));
-    }
-
-    void testCount() {
-        checkE(0, RplString::count("abc", " "));
-        checkE(1, RplString::count("abc", "b"));
-        checkE(2, RplString::count("axx", "x"));
-
-        checkE(0, RplString::count("abbc", "bbb"));
-        checkE(1, RplString::count("\n\n", "\n\n"));
-        checkE(2, RplString::count("  a  ", "  "));
-    }
-
-    void testCutString() {
-        QByteArray source("123");
-        QByteArray buffer;
-        checkE(QByteArray("123"), RplString::cutString(source, 4, buffer));
-        checkE(QByteArray("123"), RplString::cutString(source, 3, buffer));
-        checkE(QByteArray("12..."), RplString::cutString(source, 2, buffer));
-        checkE(QByteArray("12"), RplString::cutString(source, 2, buffer, ""));
-    }
-
-    void testHexDump() {
-        QByteArray data("abc123\nxyz");
-        checkE(QByteArray("61 62 63 31  abc1\n"
-                          "32 33 0a 78  23.x\n"
-                          "79 7a        yz\n"),
-               RplString::hexDump((uint8_t*) data.constData(), data.length(), 4));
-        checkE(QByteArray("61 62 63 31 32 33 0a 78 79 7a  abc123.xyz"),
-               RplString::hexDump((uint8_t*) data.constData(), data.length(), 10));
-        checkE(QByteArray("61 62 63 31 32 33 0a 78 79 7a        abc123.xyz"),
-               RplString::hexDump((uint8_t*) data.constData(), data.length(), 12));
-    }
-
-    void testReadWrite() {
-        QByteArray fn = getTempFile("test.dat");
-        const char* content = "Hello world\nLine2\n";
-        checkT(RplString::write(fn, content));
-        checkE(content, RplString::read(fn, false));
-        checkE(content, RplString::read(fn, true) + "\n");
-    }
-
-    void testToArray() {
-        QList<QByteArray> array = RplString::toArray("1 abc 3", " ");
-        checkE(3, array.size());
-        checkE("1", array.at(0));
-        checkE("abc", array.at(1));
-        checkE("3", array.at(2));
-    }
-
-    void testToNumber() {
-        checkE("3", RplString::toNumber(3));
-        checkE("-33", RplString::toNumber(-33));
-        checkE("003", RplString::toNumber(3, "%03d"));
-    }
-
-    void testLengthOfNumber(){
-        checkE(3, RplString::lengthOfNumber("0.3xxx"));
-        checkE(5, RplString::lengthOfNumber(" \t0.3xxx"));
-        checkE(3, RplString::lengthOfNumber("-.3xxx"));
-        checkE(2, RplString::lengthOfNumber(".3exxx"));
-        checkE(2, RplString::lengthOfNumber(".3e+xxx"));
-        checkE(16, RplString::lengthOfNumber("1234567.9012E+77"));
-        checkE(17, RplString::lengthOfNumber("-1234567.9012E+77 "));
-        checkE(18, RplString::lengthOfNumber("-1234567.9012E+77 ", true));
-        checkE(18, RplString::lengthOfNumber("-1234567.9012E+77 x", true));
-        checkE(20, RplString::lengthOfNumber("  -1234567.9012E+77 x", true));
-    }
-
-    void checkCsv(const char* content, char expected){
-        QByteArray fn = getTempFile("testrplstring.csv");
-        RplString::write(fn, content);
-        FILE* fp = fopen(fn, "r");
-        checkNN(fp);
-        char buffer[256];
-        checkE(expected, RplString::findCsvSeparator(fp, buffer, sizeof buffer));
-        fclose(fp);
-    }
-
-    void testFindCsvSeparator(){
-        const char* content = ",,,\t;;;||||";
-        checkCsv(content, '\t');
-
-        content = "col1,col2\n1.5,3,5\n";
-        checkCsv(content, ',');
-
-        content = "col1;col2\n1,50;3.5\n"
-                 "7;8\n10;12\n13;14";
-        checkCsv(content, ';');
-
-        content = "0.3 7.8 8.9\n7.8 9.4 8.3";
-        checkCsv(content, ' ');
-
-        content = "0.3|7.8|8.9\n7.8|         9.4|8.3";
-        checkCsv(content, '|');
-
-        content = "0,3;7.8;8.9";
-        checkCsv(content, ';');
-    }
-    void testLengthOfUInt64(){
-        quint64 value = -3;
-        checkE(1, RplString::lengthOfUInt64("0", 10, &value));
-        checkE(0LL, value);
-        checkE(3, RplString::lengthOfUInt64("432", 10, &value));
-        checkE(432LL, value);
-        checkE(3, RplString::lengthOfUInt64("432 x", 10, &value));
-        checkE(432LL, value);
-        checkE(3, RplString::lengthOfUInt64("432fabc x", 10, &value));
-        checkE(432LL, value);
-        checkE(16, RplString::lengthOfUInt64("1234567890123567", 10, &value));
-        checkE(1234567890123567LL, value);
-        checkE(10, RplString::lengthOfUInt64("1234abcdef", 16, &value));
-        checkE(0x1234abcdefLL, value);
-        checkE(3, RplString::lengthOfUInt64("432", 8, &value));
-        checkE(0432LL, value);
-        checkE(6, RplString::lengthOfUInt64("765432 ", 8, &value));
-        checkE(0765432LL, value);
-
-        checkE(0, RplString::lengthOfUInt64(" ", 8, &value));
-        checkE(0, RplString::lengthOfUInt64("", 8, &value));
-    }
-    void testLengthOfReal(){
-        qreal value;
-        checkE(1, RplString::lengthOfReal("0", &value));
-        checkE(0.0, value);
-        checkE(1, RplString::lengthOfReal("0%", &value));
-        checkE(0.0, value);
-        checkE(4, RplString::lengthOfReal("0.25", &value));
-        checkE(0.25, value);
-        checkE(3, RplString::lengthOfReal(".25", &value));
-        checkE(0.25, value);
-        checkE(17, RplString::lengthOfReal("12345678901234567", &value));
-        checkE(12345678901234567.0, value);
-        checkE(2, RplString::lengthOfReal(".5", &value));
-        checkE(0.5, value);
-        checkE(5, RplString::lengthOfReal("2.5e2x", &value));
-        checkE(250.0, value);
-        checkE(6, RplString::lengthOfReal("2.5e+2", &value));
-        checkE(250.0, value);
-        checkE(7, RplString::lengthOfReal("2.5E-33", &value));
-        checkE(2.5e-33, value);
-
-        checkE(3, RplString::lengthOfReal("2.5E", &value));
-        checkE(2.5, value);
-        checkE(3, RplString::lengthOfReal("2.5E+", &value));
-        checkE(2.5, value);
-        checkE(3, RplString::lengthOfReal("2.5E-a", &value));
-        checkE(2.5, value);
-    }
-
-    virtual void doIt() {
-        testLengthOfReal();
-        testLengthOfUInt64();
-        testCountChar();
-        testCount();
-        testCutString();
-        testToNumber();
-        testToArray();
-        testHexDump();
-        testReadWrite();
-        testLengthOfNumber();
-        testFindCsvSeparator();
-    }
-};
-
-void testRplString() {
-    TestRplString test;
-    test.run();
-}
-
-
-
diff --git a/unittests/rplvm_test.cpp b/unittests/rplvm_test.cpp
deleted file mode 100644 (file)
index 244058e..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-#include "rplcore/rplcore.hpp"
-#include "rplexpr/rplexpr.hpp"
-#include "rplcore/rpltest.hpp"
-
-class TestRplVM : public RplTest{
-private:
-    RplSource m_source;
-    RplASTree m_tree;
-    RplStringReader m_reader;
-    const char* m_currentSource;
-public:
-    TestRplVM() :
-        RplTest("RplVM"),
-        m_source(),
-        m_tree(),
-        m_reader(m_source)
-    {
-        m_source.addReader(&m_reader);
-    }
-protected:
-    void setSource(const char* content){
-        RplASItem::reset();
-        m_currentSource = content;
-        m_tree.clear();
-        m_source.clear();
-        m_reader.clear();
-        m_reader.addSource("<test>", content);
-        m_source.addReader(&m_reader);
-        m_source.addSourceUnit(m_reader.currentSourceUnit());
-    }
-
-private:
-    void checkAST(const char* fileExpected, int lineNo){
-        QByteArray fnExpected = "test";
-        fnExpected += QDir::separator().toLatin1();
-        fnExpected += "rplvm";
-        fnExpected += (char) QDir::separator().toLatin1();
-        fnExpected += fileExpected;
-        QByteArray fnCurrent = getTempFile(fileExpected, "rplvm");
-        RplMFParser parser(m_source, m_tree);
-        parser.parse();
-        RplVirtualMachine vm(m_tree, m_source);
-        vm.setFlag(RplVirtualMachine::VF_TRACE_STATEMENTS);
-        RplFileWriter writer(fnCurrent);
-        vm.setTraceWriter(&writer);
-        writer.write(m_currentSource);
-        vm.executeModule("<test>");
-        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
-                         __FILE__, lineNo);
-    }
-public:
-    void baseTest(){
-        setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf");
-        checkAST("baseTest.txt", __LINE__);
-    }
-    virtual void doIt(void) {
-        baseTest();
-    }
-};
-void testRplVM() {
-    TestRplVM test;
-    test.run();
-}
-
diff --git a/unittests/rplwriter_test.cpp b/unittests/rplwriter_test.cpp
deleted file mode 100644 (file)
index b348982..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
- * Licence:
- * You can use and modify this file without any restriction.
- * There is no warranty.
- * You also can use the licence from http://www.wtfpl.net/.
- * The original sources can be found on https://github.com/republib.
-*/
-
-/** @file
- * @brief Unit test of the output media writers.
- */
-
-#include "rplcore/rplcore.hpp"
-#include "rplcore/rpltest.hpp"
-/**
- * @brief Unit test for <code>RplString</code>.
- */
-class TestRplWriter : public RplTest {
-public:
-    TestRplWriter() : RplTest("RplWriter") {}
-
-private:
-    void testFileWriter(){
-        QByteArray fn = getTempFile("rplwriter.txt");
-        RplFileWriter writer(fn);
-        writer.writeLine("abc");
-        writer.formatLine("%04d", 42);
-        writer.writeIndented(3, "123");
-        writer.indent(2);
-        writer.write("pi");
-        writer.format("%3c%.2f", ':', 3.1415);
-        writer.writeLine();
-        writer.close();
-        QByteArray current = RplString::read(fn, false);
-        checkE("abc\n0042\n\t\t\t123\n\t\tpi  :3.14\n", current);
-    }
-
-public:
-    virtual void doIt(void) {
-        testFileWriter();
-    }
-};
-void testRplWriter() {
-    TestRplWriter test;
-    test.run();
-}
-
-
-
diff --git a/unittests/unittests.pro b/unittests/unittests.pro
deleted file mode 100644 (file)
index 0104a97..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#-------------------------------------------------
-#
-# Project created by QtCreator 2014-05-31T00:01:23
-#
-#-------------------------------------------------
-
-QT       += core network
-
-QT       -= gui
-
-TARGET = unittests
-CONFIG   += console
-CONFIG   -= app_bundle
-
-INCLUDEPATH = ..
-
-TEMPLATE = app
-
-SOURCES += main.cpp \
-    ../rplcore/rpllogger.cpp \
-    ../rplcore/rpltest.cpp \
-    ../rplcore/rplstring.cpp \
-    ../rplcore/rplexception.cpp \
-    ../rplmath/rplmatrix.cpp \
-    ../rplexpr/rplsource.cpp \
-    ../rplexpr/rpllexer.cpp \
-    ../rplexpr/rplastree.cpp \
-    ../rplexpr/rplparser.cpp \
-    ../rplexpr/rplmfparser.cpp \
-    ../rplcore/rplqstring.cpp \
-    ../rplexpr/rplasclasses.cpp \
-    ../rplcore/rplbytestorage.cpp \
-    ../rplexpr/rplvm.cpp \
-    ../rplcore/rplwriter.cpp \
-    rplmatrix_test.cpp \
-    rplexception_test.cpp \
-    rplstring_test.cpp \
-    rplsource_test.cpp \
-    rpllexer_test.cpp \
-    rplqstring_test.cpp \
-    rplastree_test.cpp \
-    rplmfparser_test.cpp \
-    rplvm_test.cpp \
-    rplbytestorage_test.cpp \
-    rplwriter_test.cpp \
-    rplbench.cpp \
-    rplcharptrmap_test.cpp \
-    ../rplcore/rplcharptrmap.cpp
-