]> gitweb.hamatoma.de Git - reqt/commitdiff
day's work
authorhama <hama@siduction.net>
Sat, 5 Jul 2014 15:22:22 +0000 (17:22 +0200)
committerhama <hama@siduction.net>
Sat, 5 Jul 2014 15:22:22 +0000 (17:22 +0200)
17 files changed:
rplcore/rplqstring.cpp
rplcore/rplqstring.hpp
rplexpr/rplasclasses.cpp
rplexpr/rplastree.cpp
rplexpr/rplastree.hpp
rplexpr/rpllexer.cpp
rplexpr/rpllexer.hpp
rplexpr/rplmfparser.cpp
rplexpr/rplmfparser.hpp
rplexpr/rplparser.cpp
rplexpr/rplsource.cpp
rplexpr/rplsource.hpp
test/rplmfparser/ifTest1.txt [new file with mode: 0644]
test/rplmfparser/ifTest2.txt [new file with mode: 0644]
test/rplmfparser/whileTest.txt [new file with mode: 0644]
unittests/rplmfparser_test.cpp
unittests/rplqstring_test.cpp

index f685ddbbc68815bbaa99dc559aa5087a66dd347e..90c156d7bc6351a63e909d6e703303c296762b01 100644 (file)
@@ -153,3 +153,24 @@ int RplQString::lengthOfReal(const QString& text, int start, qreal* pValue)
         *pValue = value;
     return found ? ix - start : 0;
 }
+
+/**
+ * @brief Converts a QString into a 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;
+}
index 53c8d41a533332d9ef0f33518c24383b6b21f9ac..780ef2444ad972f17cae4d4b5156e5b0edfcaf4e 100644 (file)
@@ -31,6 +31,7 @@ public:
                 : 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
index 3f24a0da63a7faf3af7d9454bdb63f09335a6e10..25f29e9caad36e99fca6b63f966f25ff352e1f5d 100644 (file)
@@ -740,10 +740,9 @@ void*RplASVoid::newValueInstance(void*) const
  *
  * In this case we do nothing.
  *
- * @param object    object to
- * @return
+ * @param object    not used
  */
-void RplASVoid::destroyValueInstance(void* object) const
+void RplASVoid::destroyValueInstance(void*) const
 {
 }
 
index bef3477af4d50281cdfe2cb2838b32e062f237ab..bd6e7ef004ef5d3ffc866b218867ffa4c6fc880a 100644 (file)
@@ -358,7 +358,6 @@ RplASItem::RplASItem(RplASItemType type) :
     m_flags(0),
     m_position(NULL)
 {
-
 }
 /**
  * @brief Destructor.
@@ -443,8 +442,10 @@ void RplASConstant::calc(RplASVariant& value)
 void RplASConstant::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sconst id: %d value: %s\n", tabs, m_id,
-            m_value.toString().toUtf8().constData());
+    char buffer[256];
+    fprintf(fp, "%sconst id: %d value: %s %s\n", tabs, m_id,
+            m_value.toString().toUtf8().constData(),
+            m_position->utf8(buffer, sizeof buffer));
 }
 
 /**
@@ -525,8 +526,10 @@ void RplASNamedValue::calc(RplASVariant& value)
 void RplASNamedValue::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%snamedValue id: %d attr: 0x%x\n", tabs,
-            m_id, m_attributes);
+    char buffer[256];
+    fprintf(fp, "%snamedValue %s id: %d attr: 0x%x %s\n", tabs,
+            m_name.toUtf8().constData(), m_id, m_attributes,
+            m_position->utf8(buffer, sizeof buffer));
 }
 
 /** @class RplVarDefinition rplastree.hpp "rplexpr/rplastree.hpp"
@@ -559,9 +562,11 @@ void RplASVarDefinition::dump(FILE* fp, int indent)
     DEFINE_TABS(indent);
     QByteArray name = m_name.toUtf8();
     QByteArray className = m_dataType == NULL ? "?" : m_dataType->name().toUtf8();
-    fprintf(fp, "%svarDef %s (%s) id: %d succ: %d attr: 0x%x\n",
+    char buffer[256];
+    fprintf(fp, "%svarDef %s (%s) id: %d succ: %d attr: 0x%x %s\n",
             tabs, name.constData(), className.constData(),
-            m_id, m_successor == NULL ? 0 : m_successor->id(), m_attributes);
+            m_id, m_successor == NULL ? 0 : m_successor->id(), m_attributes,
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child != NULL)
         m_child->dump(fp, indent + 1);
     if (m_successor != NULL)
@@ -626,9 +631,11 @@ void RplASExprStatement::calc(RplASVariant& value)
 void RplASExprStatement::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sExpr id: %d succ: %d expr: %d\n", tabs, m_id,
+    char buffer[256];
+    fprintf(fp, "%sExpr id: %d succ: %d expr: %d %s\n", tabs, m_id,
             m_successor == NULL ? 0 : m_successor->id(),
-            m_child == NULL ? 0 : m_child->id() );
+            m_child == NULL ? 0 : m_child->id(),
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child != NULL)
         m_child->dump(fp, indent + 1);
     if (m_successor != NULL)
@@ -878,8 +885,10 @@ int RplASUnaryOp::getOperator() const
 void RplASUnaryOp::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sUnary %d op: %d Child: %d\n", tabs, m_id, m_operator,
-            m_child == NULL ? 0 : m_child->id() );
+    char buffer[256];
+    fprintf(fp, "%sUnary %d op: %d Child: %d %s\n", tabs, m_id, m_operator,
+            m_child == NULL ? 0 : m_child->id(),
+            m_position->utf8(buffer, sizeof buffer) );
     if (m_child != NULL)
         m_child->dump(fp, indent);
 }
@@ -989,8 +998,10 @@ bool RplASCondition::calcAsBool()
 void RplASCondition::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sCondition %d Child: %d\n", tabs, m_id,
-            m_child == NULL ? 0 : m_child->id() );
+    char buffer[256];
+    fprintf(fp, "%sCondition %d Child: %d %s\n", tabs, m_id,
+            m_child == NULL ? 0 : m_child->id(),
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child != NULL)
         m_child->dump(fp, indent);
 }
@@ -1047,9 +1058,11 @@ void RplASIf::execute()
 void RplASIf::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sIf id: %d condition: %d then: %d else: %d\n", tabs,
+    char buffer[256];
+    fprintf(fp, "%sIf id: %d condition: %d then: %d else: %d %s\n", tabs,
             m_id, m_child->id(), m_child2->id(),
-            m_child3 == NULL ? 0 : m_child3->id());
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_position->utf8(buffer, sizeof buffer));
     m_child->dump(fp, indent + 1);
     m_child2->dump(fp, indent + 1);
     if (m_child3 != NULL)
@@ -1115,9 +1128,11 @@ void RplASFor::execute()
 void RplASFor::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sfor id: %d condition: %d then: %d else: %d\n", tabs,
+    char buffer[256];
+    fprintf(fp, "%sfor id: %d condition: %d then: %d else: %d %s\n", tabs,
             m_id, m_child->id(), m_child2->id(),
-            m_child3 == NULL ? 0 : m_child3->id());
+            m_child3 == NULL ? 0 : m_child3->id(),
+            m_position->utf8(buffer, sizeof buffer));
     m_child->dump(fp, indent + 1);
     m_child2->dump(fp, indent + 1);
     if (m_child3 != NULL)
@@ -1181,13 +1196,15 @@ void RplASForCounted::execute()
 void RplASForCounted::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sforc id: %d var: %d from: %d to: %d step: %d body: %d\n",
+    char buffer[256];
+    fprintf(fp, "%sforc id: %d var: %d from: %d to: %d step: %d body: %d %s\n",
             tabs, m_id,
             m_child2 == NULL ? 0 : m_child2->id(),
             m_child3 == NULL ? 0 : m_child3->id(),
             m_child4 == NULL ? 0 : m_child4->id(),
             m_child5 == NULL ? 0 : m_child5->id(),
-            m_child == NULL ? 0 : m_child->id());
+            m_child == NULL ? 0 : m_child->id(),
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child2 != NULL)
         m_child2->dump(fp, indent + 1);
     if (m_child3 != NULL)
@@ -1245,9 +1262,11 @@ void RplASWhile::execute()
 void RplASWhile::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%swhile id: %d condition: %d body: %d\n", tabs, m_id,
+    char buffer[256];
+    fprintf(fp, "%swhile id: %d condition: %d body: %d %s\n", tabs, m_id,
             m_child2 == NULL ? 0 : m_child2->id(),
-            m_child == NULL ? 0 : m_child->id());
+            m_child == NULL ? 0 : m_child->id(),
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child2 != NULL)
         m_child2->dump(fp, indent + 1);
     if (m_child != NULL)
@@ -1299,9 +1318,11 @@ void RplASRepeat::execute()
 void RplASRepeat::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%srepeat id: %d condition: %d body: %d\n", tabs, m_id,
+    char buffer[256];
+    fprintf(fp, "%srepeat id: %d condition: %d body: %d %s\n", tabs, m_id,
             m_child2 == NULL ? 0 : m_child2->id(),
-            m_child == NULL ? 0 : m_child->id());
+            m_child == NULL ? 0 : m_child->id(),
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child2 != NULL)
         m_child2->dump(fp, indent + 1);
     if (m_child != NULL)
@@ -1533,11 +1554,14 @@ void RplASTree::clear()
  *
  * @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)
+void RplASTree::dump(const char* filename, int flags, const char* header)
 {
     FILE* fp = fopen(filename, "w");
     if (fp != NULL){
+        if (header != NULL)
+            fprintf(fp, "%s\n", header);
         if (flags & DMP_GLOBALS){
             m_global->dump(fp, 0, "=== Globals:");
         }
@@ -1552,7 +1576,7 @@ void RplASTree::dump(const char* filename, int flags)
             QList<QString>::iterator it2;
             for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
                 RplSymbolSpace* space = m_modules[*it2];
-                space->dump(fp, 1);
+                space->dump(fp, 0);
             }
         }
         fclose(fp);
@@ -1583,9 +1607,11 @@ RplASMethodCall::~RplASMethodCall()
 void RplASMethodCall::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sCall %d instance: %d args: %d\n", tabs, m_id,
+    char buffer[256];
+    fprintf(fp, "%sCall %d instance: %d args: %d %s\n", tabs, m_id,
             m_child == NULL ? 0 : m_child->id(),
-            m_child2 == NULL ? 0 : m_child2->id());
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child != NULL)
         m_child->dump(fp, indent + 1);
     if (m_child2 != NULL)
@@ -1675,10 +1701,12 @@ void RplASBinaryOp::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
     const QByteArray& opName = RplLexer::m_active->nameOfOp(m_operator);
-    fprintf(fp, "%sBinOp %d op: %s (%d) left: %d right: %d\n", tabs, m_id,
+    char buffer[256];
+    fprintf(fp, "%sBinOp %d op: %s (%d) left: %d right: %d %s\n", tabs, m_id,
             opName.constData(), m_operator,
             m_child == NULL ? 0 : m_child->id(),
-            m_child2 == NULL ? 0 : m_child2->id());
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_position->utf8(buffer, sizeof buffer));
     if (m_child != NULL)
         m_child->dump(fp, indent + 1);
     if (m_child2 != NULL)
@@ -1713,11 +1741,13 @@ RplASMethod::RplASMethod(const QString& name, RplASClass* type) :
 void RplASMethod::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
+    char buffer[256];
     fprintf(fp, "%sMethod %d %s %s(", tabs, m_id,
             m_nodeType == NULL ? "<NoneType>" : m_nodeType->name().toUtf8().constData(),
             m_name.toUtf8().constData());
-    fprintf(fp, ") body: %d args: %d\n", m_child == NULL ? 0 : m_child->id(),
-            m_child2 == NULL ? 0 : m_child2->id());
+    fprintf(fp, ") body: %d args: %d %s\n", m_child == NULL ? 0 : m_child->id(),
+            m_child2 == NULL ? 0 : m_child2->id(),
+            m_position->utf8(buffer, sizeof buffer));
 }
 
 /** @class RplASArgument rplastree.hpp "rplexpr/rplastree.hpp"
index d8b6f9c8e3b1b4ca60159b91c0f84dea4037dc96..2401042e7b5378f1ad8437fe70a2eb2da7dbf549 100644 (file)
@@ -476,8 +476,8 @@ public:
         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_ALL         = DMP_GLOBALS | DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP,
+        DMP_NO_GLOBALS  = DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP
     };
     typedef QMap<QString, RplSymbolSpace*> SymbolSpaceMap;
     typedef QList<RplSymbolSpace*> SymbolSpaceStack;
@@ -494,8 +494,10 @@ public:
     RplSymbolSpace* currentSpace() const;
     RplASClass* findClass(const QString& name);
     void clear();
-    void dump(const char* filename, int flags = DMP_ALL);
+    void dump(const char* filename, int flags = DMP_ALL,
+              const char* header = NULL);
     RplSymbolSpace*findmodule(const QString& name);
+    RplSourcePosition* copyPosition();
 protected:
     void init();
     void destroy();
index 1ab955e3cda9d7d43452f450abe1726965c8af39..edd7e3c0feb8b37822399d5cd3469b4034afee2e 100644 (file)
@@ -30,7 +30,7 @@ RplLexer* RplLexer::m_active = NULL;
  * @param format    the reason of the exception
  * @param ...       the values for the placeholders in the format.
  */
-RplLexException::RplLexException(RplSourcePosition& position,
+RplLexException::RplLexException(const RplSourcePosition& position,
                                  const char* format, ...) :
     RplException("")
 {
@@ -356,9 +356,7 @@ RplLexer::RplLexer(RplSource* source,
     m_waitingToken(NULL),
     m_token1(TOKEN_UNDEF),
     m_token2(TOKEN_UNDEF),
-    m_currentPosition(&m_position1),
-    m_position1(RplSourcePosition()),
-    m_position2(RplSourcePosition()),
+    m_currentPosition(NULL),
     m_maxTokenLength(64),
     m_input(),
     m_currentCol(0),
@@ -371,8 +369,7 @@ RplLexer::RplLexer(RplSource* source,
 {
     memset(m_prioOfOp, 0, sizeof m_prioOfOp);
     memset(m_assocOfOp, 0, sizeof m_assocOfOp);
-    m_currentPosition->setSourceUnit(source->currentReader()
-        ->currentSourceUnit());
+
     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);
@@ -841,7 +838,7 @@ RplToken* RplLexer::currentToken() const
  *
  * @return  the current source code position
  */
-RplSourcePosition* RplLexer::currentPosition() const
+const RplSourcePosition* RplLexer::currentPosition() const
 {
     return m_currentPosition;
 }
@@ -854,26 +851,33 @@ RplSourcePosition* RplLexer::currentPosition() const
 RplToken* RplLexer::nextToken()
 {
     RplToken* rc = NULL;
+    const RplSourcePosition* waitingPosition = NULL;
     int ix;
     if (m_waitingToken != NULL){
-        rc = m_waitingToken;
+        rc = m_currentToken = m_waitingToken;
         m_waitingToken = NULL;
-        m_currentPosition = m_currentPosition == &m_position1
-                ? &m_position2 : &m_position1;
     } else {
         m_currentToken->clear();
         RplReader* reader = m_source->currentReader();
         if (reader == NULL)
             m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE;
         else {
-            m_currentPosition->setLineNo(reader->currentSourceUnit()->lineNo());
-            m_currentPosition->setColumn(m_currentCol);
+            if (waitingPosition == NULL)
+                m_currentPosition = m_source->newPosition(m_currentCol);
+            else {
+                m_currentPosition = waitingPosition;
+                ((RplSourcePosition*)waitingPosition)->setSourceUnit(
+                            m_source->currentReader()->currentSourceUnit());
+                ((RplSourcePosition*)waitingPosition)->setColumn(m_currentCol);
+                waitingPosition = NULL;
+            }
             if (! fillInput()){
                 m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE;
             } else {
                 QChar cc = m_input.at(0);
                 int cc2 = cc.unicode();
                 if (cc.isSpace()){
+                    waitingPosition = m_currentPosition;
                     m_currentToken->m_tokenType = TOKEN_SPACE;
                     ix = 1;
                     while(ix < m_input.size() && m_input.at(ix).isSpace())
@@ -901,6 +905,7 @@ RplToken* RplLexer::nextToken()
                                                  CC_2nd_COMMENT_START, m_commentStarts);
                             if (rc != NULL)
                                 scanComment();
+                            waitingPosition = m_currentPosition;
                         }
 
                         if (rc == NULL && (m_charInfo[cc2] & CC_FIRST_OP)){
@@ -956,9 +961,6 @@ void RplLexer::undoLastToken()
 {
     m_waitingToken = m_currentToken;
     m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
-    m_currentPosition = m_currentPosition == &m_position1
-            ? &m_position2 : &m_position1;
-
 }
 
 /**
index 20e24ab31458902cdb6be67e7361e5103c92dff6..89d6cbf0570c276770d38119c2dd6c1f2ea38192 100644 (file)
@@ -29,7 +29,7 @@ enum RplTokenType {
 
 class RplLexException : public RplException {
 public:
-    RplLexException(RplSourcePosition& position, const char* message, ...);
+    RplLexException(const RplSourcePosition& position, const char* message, ...);
 };
 
 class RplLexer;
@@ -179,7 +179,7 @@ public:
     int prioOfOp(int op) const;
     const QByteArray& nameOfOp(int op) const;
     bool isRightAssociative(int op) const;
-    RplSourcePosition* currentPosition() const;
+    const RplSourcePosition* currentPosition() const;
     RplToken* currentToken() const;
 
 private:
@@ -216,9 +216,7 @@ protected:
     RplToken* m_waitingToken;
     RplToken m_token1;
     RplToken m_token2;
-    RplSourcePosition* m_currentPosition;
-    RplSourcePosition m_position1;
-    RplSourcePosition m_position2;
+    const RplSourcePosition* m_currentPosition;
     int m_maxTokenLength;
     QString m_input;
     int m_currentCol;
index b179fa2c2d857079c754ef6280652baca4bdc1aa..50950fcbb9d53f07f4cc8f526a6d0488b8dd5b39 100644 (file)
@@ -71,12 +71,12 @@ RplASItem* RplMFParser::parseIf()
     if (! m_lexer.currentToken()->isKeyword(K_THEN))
         syntaxError(L_PARSE_IF_NO_THEN, "'then' expected");
     rc->setChild(condition);
-    RplASItem* body = parseBody();
+    RplASItem* body = parseBody(K_ELSE, K_FI);
     rc->setChild2(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();
+        RplASItem* body = parseBody(K_FI);
         rc->setChild3(body);
     }
     if (! m_lexer.currentToken()->isKeyword(K_FI))
@@ -96,7 +96,7 @@ RplASItem* RplMFParser::parseWhile()
     if (! m_lexer.currentToken()->isKeyword(K_DO))
         syntaxError(L_PARSE_WHILE_NO_DO, "'do' expected");
     rc->setChild2(condition);
-    RplASItem* body = parseBody();
+    RplASItem* body = parseBody(K_OD);
     rc->setChild(body);
     if (! m_lexer.currentToken()->isKeyword(K_OD))
         syntaxError(L_PARSE_WHILE_NO_OD, "'od'  expected");
@@ -111,7 +111,7 @@ RplASItem* RplMFParser::parseRepeat()
     RplASRepeat* rc = new RplASRepeat();
     rc->setPosition(m_lexer.currentPosition());
 
-    RplASItem* body = parseBody();
+    RplASItem* body = parseBody(K_UNTIL);
     rc->setChild(body);
     if (! m_lexer.currentToken()->isKeyword(K_UNTIL))
         syntaxError(L_PARSE_REPEAT_NO_UNTIL, "'until'  expected");
@@ -200,7 +200,7 @@ RplASItem* RplMFParser::parseVarDefinition(Keyword attribute)
 RplASItem* RplMFParser::parseOperand(int level)
 {
     RplToken* token = m_lexer.nextNonSpaceToken();
-    RplSourcePosition* startPosition = m_lexer.currentPosition();
+    const RplSourcePosition* startPosition = m_lexer.currentPosition();
     RplASItem* rc = NULL;
     switch(token->tokenType()){
     case TOKEN_OPERATOR:
@@ -269,9 +269,18 @@ RplASItem* RplMFParser::parseOperand(int level)
                 }
             } else if (token->id() == O_LBRACKET){
 
-            } else if (token->id() == O_INC || token->id() == O_DEC){
+            } else {
                 RplASNamedValue* var = new RplASNamedValue(name);
+                var->setPosition(startPosition);
                 rc = var;
+                if (token->id() == O_INC || token->id() == O_DEC){
+                    RplASUnaryOp* op = new RplASUnaryOp(token->id(),
+                                                        AST_POST_UNARY_OP);
+                    op->setChild(var);
+                    rc = op;
+                } else {
+                    m_lexer.undoLastToken();
+                }
             }
         }
         break;
@@ -369,10 +378,9 @@ RplASItem* RplMFParser::parseExpr()
  */
 RplASItem* RplMFParser::parseExprStatement()
 {
-    RplSourcePosition *pos = m_lexer.currentPosition();
     RplASItem* item = parseExpr();
     RplASExprStatement* statement = new RplASExprStatement();
-    statement->setPosition(pos);
+    statement->setPosition(item->position());
     statement->setChild(item);
     return statement;
 }
@@ -381,8 +389,15 @@ RplASItem* RplMFParser::parseExprStatement()
  * @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 opStop        the first possible delimiting operator
+ * @param opStop2       the 2nd possible delimiting operator
+ * @return              the first element of the statement list
  */
-RplASItem* RplMFParser::parseBody()
+RplASItem* RplMFParser::parseBody(Keyword keywordStop, Keyword keywordStop2,
+        Operator opStop, Operator opStop2)
 {
     RplToken* token = m_lexer.nextNonSpaceToken();
     RplASItem* item = NULL;
@@ -391,13 +406,21 @@ RplASItem* RplMFParser::parseBody()
     bool again = true;
     while(again) {
         token = m_lexer.currentToken();
+        // eat a superflous ';'
+        if (token->isOperator(O_SEMICOLON))
+            token = m_lexer.nextNonSpaceToken();
         try {
             switch(token->tokenType())
             {
+            case TOKEN_OPERATOR:
+                if (opStop != O_UNDEF && token->isOperator(opStop, opStop2)){
+                    again = false;
+                    break;
+                }
+                // fall through
             case TOKEN_STRING:
             case TOKEN_NUMBER:
             case TOKEN_REAL:
-            case TOKEN_OPERATOR:
                 m_lexer.undoLastToken();
                 item = parseExprStatement();
                 break;
@@ -430,6 +453,8 @@ RplASItem* RplMFParser::parseBody()
                     item = parseVarDefinition((Keyword) token->id());
                     break;
                 default:
+                    if (token->isKeyword(keywordStop, keywordStop2))
+                        again = false;
                     break;
                 }
                 break;
@@ -449,7 +474,7 @@ RplASItem* RplMFParser::parseBody()
             default:
                 break;
             }
-            if (! token->isTokenType(TOKEN_END_OF_SOURCE)){
+            if (again){
                 if (body == NULL){
                     body = item;
                 } else {
@@ -458,7 +483,14 @@ RplASItem* RplMFParser::parseBody()
                 lastStatement = dynamic_cast<RplASStatement*>(item);
                 if (lastStatement == NULL)
                     assert("wrong item type" == NULL);
-                token = m_lexer.nextNonSpaceToken();
+                token = m_lexer.currentToken();
+                if ((keywordStop != K_UNDEF
+                            && token->isKeyword(keywordStop, keywordStop2))
+                        || (opStop != O_UNDEF
+                            && token->isOperator(opStop, opStop2)))
+                    again = false;
+                else
+                    token = m_lexer.nextNonSpaceToken();
             }
         } catch(RplSyntaxError exc){
             // we look for the end of the statement:
@@ -529,7 +561,8 @@ void RplMFParser::parseImport()
 RplASItem* RplMFParser::parseModule(const QString& name)
 {
     m_tree.startModule(name);
-    RplASItem* body = parseBody();
+    // parse until EOF:
+    RplASItem* body = parseBody(K_UNDEF);
     m_tree.finishModule(name);
     return body;
 }
@@ -541,9 +574,8 @@ void RplMFParser::parse()
     RplSource* source = m_lexer.source();
     RplSourceUnit* mainModule = source->currentReader()->currentSourceUnit();
     QString mainModuleName = mainModule->name();
-    m_tree.startModule(mainModuleName);
     try {
-        RplASItem* body = parseBody();
+        RplASItem* body = parseModule(mainModuleName);
         RplSymbolSpace* module = m_tree.findmodule(mainModuleName);
         if (module != NULL)
             module->setBody(body);
index d0d7daa1d63be99bc9bad0e78a54f5575f68c9fd..2cda2a5a12d7b27e1ec9917142ec81bc6c56310c 100644 (file)
@@ -74,7 +74,8 @@ public:
     RplASItem* parseFor();
     RplASItem* parseVarDefinition(Keyword attribute);
     RplASItem* parseExpr();
-    RplASItem* parseBody();
+    RplASItem* parseBody(Keyword keywordStop, Keyword keywordStop2 = K_UNDEF,
+                         Operator opStop = O_UNDEF, Operator opStop2 = O_UNDEF);
     RplASItem* parseMethodDefinition();
     RplASItem* parseClass();
     void parseImport();
index 52b389a8116e0fddcdd474cc0dbf3fa0034bee86..a3290a6f728d165b8ba50f9cec2d9e1ac01bafef 100644 (file)
@@ -95,7 +95,7 @@ void RplParser::addMessage(char prefix, int location, const char* format,
                            va_list varList){
     char buffer[2048];
     QString msg;
-    RplSourcePosition* pos = m_lexer.currentPosition();
+    const RplSourcePosition* pos = m_lexer.currentPosition();
     snprintf(buffer, sizeof buffer, "%c%04d %s:%d-%d: ", prefix, location,
              pos->sourceUnit()->name().toUtf8().constData(),
              pos->lineNo(), pos->column());
index f7837dec74802be477488690309a1080e215c6ae..f694219ee41f1e9bb15a1130d84406ab68e6a24d 100644 (file)
@@ -110,42 +110,31 @@ RplSourcePosition::RplSourcePosition(RplSourceUnit* unit, int lineNo,
     m_sourceUnit(unit),
     m_lineNo(lineNo),
     m_column(colNo),
-    m_caller(unit->reader()->source().sourcePositionStack().top())
+    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 Copy constructor.
+ * @brief Placement new operator (for our own memory management).
  *
- * @param source    instance to copy
+ * @param cbSize    size of the instance
+ * @param buffer    buffer for the instance
+ * @return          <code>buffer</code>
  */
-RplSourcePosition::RplSourcePosition(const RplSourcePosition& source) :
-    m_sourceUnit(source.m_sourceUnit),
-    m_lineNo(source.m_lineNo),
-    m_column(source.m_column),
-    m_caller(source.m_caller)
+void*RplSourcePosition::operator new(size_t, void* buffer)
 {
+    return buffer;
 }
 
-/**
- * @brief Assignment operator.
- *
- * @param source    instance to copy
- * @return          the instance itself
- */
-RplSourcePosition&RplSourcePosition::operator=(const RplSourcePosition& source)
-{
-    m_sourceUnit = source.m_sourceUnit;
-    m_lineNo = source.m_lineNo;
-    m_column = source.m_column;
-    m_caller = source.m_caller;
-    return *this;
-}
 /**
  * @brief Returns a description of the source position: "<unit>-<lineNo> (<col>):".
  *
@@ -157,10 +146,25 @@ QString RplSourcePosition::toString() const
     if (m_sourceUnit != NULL)
         rc = m_sourceUnit->name();
     QTextStream stream(&rc);
-    stream << "-" << m_lineNo << " (" << m_column << "): ";
+    stream << ":" << m_lineNo << ":" << m_column << ": ";
     return rc;
 }
 
+/**
+ * @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
+{
+    QByteArray module = m_sourceUnit->name().toUtf8();
+    snprintf(buffer, bufferSize, "%s:%d:%d", module.constData(),
+             m_lineNo, m_column);
+    return buffer;
+}
+
 /**
  * @brief Returns the line number.
  * @return  the line number
@@ -217,6 +221,7 @@ RplSourceUnit* RplSourcePosition::sourceUnit() const
 void RplSourcePosition::setSourceUnit(RplSourceUnit* sourceUnit)
 {
     m_sourceUnit = sourceUnit;
+    m_lineNo = sourceUnit->lineNo();
 }
 
 
@@ -299,6 +304,20 @@ 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"
  *
@@ -312,7 +331,8 @@ void RplReader::removeSourceUnit() {
  */
 RplSource::RplSource() :
     m_sourcePositionStack(),
-    m_sourcePositions(),
+    m_sourcePositionBlock(NULL),
+    m_countPositionBlock(RPL_POSITIONS_PER_BLOCK + 1),
     m_readers(),
     m_sourceUnits(),
     m_unitStack(),
@@ -335,10 +355,17 @@ RplSource::~RplSource() {
 void RplSource::destroy()
 {
     m_sourcePositionStack.clear();
-    m_sourcePositions.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;
+    }
 }
 
 /**
@@ -405,9 +432,7 @@ void RplSource::addSourceUnit(RplSourceUnit* unit) {
  */
 bool RplSource::startUnit(const QString& unit,
                           const RplSourcePosition& caller) {
-    RplSourcePosition* position = new RplSourcePosition(caller);
-    m_sourcePositions.append(position);
-    m_sourcePositionStack.push_back(position);
+    m_sourcePositionStack.push_back(&caller);
     RplReader* reader = NULL;
     QList<RplReader*>::iterator it;
     for(it = m_readers.begin();
@@ -468,6 +493,32 @@ 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.
  */
@@ -476,6 +527,18 @@ 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.
@@ -774,3 +837,5 @@ void RplFileReader::addSource(const QDir& dirEntry) {
     RplFileSourceUnit* unit = new RplFileSourceUnit(dirEntry, this);
     m_units.insert(m_units.begin(), name, unit);
 }
+
+
index b9684b380b4ad1dccbb404129bcdcc87b029adf5..8284b2d94f373f02a22eb829f6ed5a9c68134c03 100644 (file)
@@ -34,7 +34,11 @@ 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;
@@ -46,7 +50,7 @@ public:
 
     RplSourceUnit* sourceUnit() const;
     void setSourceUnit(RplSourceUnit* sourceUnit);
-
+    char*utf8(char buffer[], size_t bufferSize) const;
 private:
     RplSourceUnit* m_sourceUnit;
     int m_lineNo;
@@ -106,6 +110,15 @@ protected:
     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:
@@ -123,13 +136,16 @@ public:
     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;
-    QList<const RplSourcePosition*> m_sourcePositions;
+    RplSourcePositionBlock* m_sourcePositionBlock;
+    int m_countPositionBlock;
     QList<RplReader*> m_readers;
     QList<RplSourceUnit*> m_sourceUnits;
     // setCurrentSourceUnit() pushes one entry, removeSourceUnit() pops it
diff --git a/test/rplmfparser/ifTest1.txt b/test/rplmfparser/ifTest1.txt
new file mode 100644 (file)
index 0000000..05afd0c
--- /dev/null
@@ -0,0 +1,29 @@
+Int a;
+Int b;
+a = b = 2;
+if 11 < 12
+then a = 13 * 14
+else a = 15 / 16
+fi
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+varDef a (Int) id: 1 succ: 2 attr: 0x0 <test>:1:4
+varDef b (Int) id: 2 succ: 8 attr: 0x0 <test>:2:4
+Expr id: 8 succ: 9 expr: 4 <test>:3:2
+       BinOp 4 op: = (5) left: 3 right: 5 <test>:3:2
+               namedValue a id: 3 attr: 0x0 <test>:3:2
+               namedValue b id: 5 attr: 0x0 <test>:3:6
+If id: 9 condition: 11 then: 18 else: 24 <test>:3:11
+       BinOp 11 op: < (21) left: 10 right: 12 <test>:4:6
+               const id: 10 value: 11 <test>:4:3
+               const id: 12 value: 12 <test>:4:8
+       Expr id: 18 succ: 0 expr: 14 <test>:5:7
+               BinOp 14 op: = (5) left: 13 right: 15 <test>:5:7
+                       namedValue a id: 13 attr: 0x0 <test>:5:7
+                       const id: 15 value: 13 <test>:5:9
+       Expr id: 24 succ: 0 expr: 20 <test>:6:7
+               BinOp 20 op: = (5) left: 19 right: 21 <test>:6:7
+                       namedValue a id: 19 attr: 0x0 <test>:6:7
+                       const id: 21 value: 15 <test>:6:9
diff --git a/test/rplmfparser/ifTest2.txt b/test/rplmfparser/ifTest2.txt
new file mode 100644 (file)
index 0000000..509fbe2
--- /dev/null
@@ -0,0 +1,14 @@
+Str x; if 7 < 6 then x = '123'; fi
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+varDef x (Str) id: 25 succ: 26 attr: 0x0 <test>:1:4
+If id: 26 condition: 28 then: 33 else: 0 <test>:1:7
+       BinOp 28 op: < (21) left: 27 right: 29 <test>:1:12
+               const id: 27 value: 7 <test>:1:10
+               const id: 29 value: 6 <test>:1:14
+       Expr id: 33 succ: 0 expr: 31 <test>:1:23
+               BinOp 31 op: = (5) left: 30 right: 32 <test>:1:23
+                       namedValue x id: 30 attr: 0x0 <test>:1:23
+                       const id: 32 value: '123' <test>:1:25
diff --git a/test/rplmfparser/whileTest.txt b/test/rplmfparser/whileTest.txt
new file mode 100644 (file)
index 0000000..d5744d3
--- /dev/null
@@ -0,0 +1,13 @@
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+varDef a (Int) id: 1 succ: 3 attr: 0x0
+       const id: 2 value: 20
+while id: 3 condition: 5 body: 9
+       BinOp 5 op: < (21) left: 4 right: 6
+               const id: 4 value: 3
+               const id: 6 value: 5
+       Expr id: 9 succ: 0 expr: 7
+               BinOp 7 op: = (5) left: 0 right: 8
+                       const id: 8 value: 7
index 011652a65847b5934d926326bde55129bf8eff66..244a0f05feca92168b3db3d3f45274d792152e6e 100644 (file)
@@ -15,6 +15,7 @@ private:
     RplSource m_source;
     RplASTree m_tree;
     RplStringReader m_reader;
+    const char* m_currentSource;
 public:
     TestRplMFParser() :
         RplTest("RplMFParser"),
@@ -26,6 +27,7 @@ public:
     }
 protected:
     void setSource(const char* content){
+        m_currentSource = content;
         m_tree.clear();
         m_source.clear();
         m_reader.clear();
@@ -42,7 +44,7 @@ private:
         fnExpected += (char) QDir::separator().toLatin1();
         fnExpected += fileExpected;
         QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser");
-        m_tree.dump(fnCurrent);
+        m_tree.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS, m_currentSource);
         assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
                          __FILE__, lineNo);
     }
@@ -62,7 +64,44 @@ public:
         checkAST("defTest.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; if 7 < 6 then x = '123'; fi");
+        parser.parse();
+        checkAST("ifTest2.txt", __LINE__);
+    }
+    void whileTest(){
+        setSource("Int a = 20; while 3 < 5 do a = 7 od");
+        RplMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("whileTest.txt", __LINE__);
+    }
+
+    void repeatTest(){
+        setSource("Int a; repeat a++; until a != 2 * 3;");
+        RplMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("repeatTest.txt", __LINE__);
+    }
+    void forCTest(){
+        setSource("Int a; for b from 1 to 10 step 2 do a += 1; od");
+        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__);
+    }
+
     virtual void doIt(void) {
+        ifTest();
+        whileTest();
+        repeatTest();
+        forCTest();
         defTest();
         baseTest();
     }
index c2f7698684c68f57bb159d874c7c8d2e75e77115..a048ab7d8a636cb42d0d0d88507b10f9f835e34d 100644 (file)
@@ -97,8 +97,17 @@ public:
         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();