]> gitweb.hamatoma.de Git - reqt/commitdiff
day's work
authorhama <hama@siduction.net>
Wed, 2 Jul 2014 15:16:30 +0000 (17:16 +0200)
committerhama <hama@siduction.net>
Wed, 2 Jul 2014 15:16:30 +0000 (17:16 +0200)
16 files changed:
rplcore/rpltest.cpp
rplcore/rpltest.hpp
rplexpr/rplasclasses.cpp
rplexpr/rplasclasses.hpp
rplexpr/rplastree.cpp
rplexpr/rplastree.hpp
rplexpr/rpllexer.cpp
rplexpr/rpllexer.hpp
rplexpr/rplmfparser.cpp
rplexpr/rplmfparser.hpp
rplexpr/rplparser.cpp
rplexpr/rplparser.hpp
test/rplmfparser/baseTest.txt [new file with mode: 0644]
test/rplmfparser/defTest.txt [new file with mode: 0644]
unittests/main.cpp
unittests/rplmfparser_test.cpp

index abb952fe350f685ab0dfa0286e4abae0765536be..d68bfee03858b18893620ad445666681904184bb 100644 (file)
@@ -333,6 +333,38 @@ bool RplTest::assertNotNull(const void* ptr, const char* file, int 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
+ * @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];
+        snprintf(buffer, sizeof buffer, "%s has no content. Does it exist?",
+                 expected);
+        error(buffer);
+    } else if (expectedContent.isEmpty()){
+        char buffer[512];
+        snprintf(buffer, sizeof buffer, "%s has no content. Does it exist?",
+                 current);
+        error(buffer);
+    } else {
+        QList<QByteArray> expLines = expectedContent.split('\n');
+        QList<QByteArray> curLines = expectedContent.split('\n');
+        rc = assertEquals(expLines, curLines, file, lineNo);
+    }
+    return rc;
+}
+
 /**
  * @brief Writes an info.
  *
@@ -437,7 +469,10 @@ QByteArray RplTest::getTempDir(const char* node, const char* parent,
 QByteArray RplTest::getTempFile(const char* node, const char* parent,
                                 bool deleteIfExists) {
     QByteArray dir = getTempDir(parent);
-    QByteArray rc = dir + m_separator + node;
+    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());
index ed7caed8551eee9dc59c46411f495a902f22d037..5c7d3ac33c7a7646a78f613252259975b480b4d8 100644 (file)
@@ -42,6 +42,8 @@ public:
     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,
@@ -67,5 +69,5 @@ protected:
 #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
index 152eba018569d5ed6b859393a66f025fa3793fa9..9edd3408c90d21c9d58a22f9ae6a15d8eb2a597e 100644 (file)
@@ -60,12 +60,11 @@ RplSymbolSpace::RplSymbolSpace(RplSymbolSpace::SymbolSpaceType type,
     if (type == SST_GLOBAL){
         m_classes[RplASInteger::m_instance.name()] = &RplASInteger::m_instance;
         m_classes[RplASBoolean::m_instance.name()] = &RplASBoolean::m_instance;
-        m_classes[RplASFloat::m_instance.name()] = &RplASBoolean::m_instance;
+        m_classes[RplASFloat::m_instance.name()] = &RplASFloat::m_instance;
         m_classes[RplASString::m_instance.name()] = &RplASString::m_instance;
         m_classes[RplASList::m_instance.name()] = &RplASList::m_instance;
         m_classes[RplASMap::m_instance.name()] = &RplASMap::m_instance;
     }
-
 }
 
 /**
@@ -89,9 +88,14 @@ RplSymbolSpace::~RplSymbolSpace()
  * @return      NULL: not found<br>
  *              otherwise: the class
  */
-RplASClass*RplSymbolSpace::findClass(const QString& name) const
+RplASClass* RplSymbolSpace::findClass(const QString& name) const
 {
-    return NULL;
+    RplASClass* rc = NULL;
+    if (m_classes.contains(name))
+        rc = m_classes[name];
+    else if (m_parent != NULL)
+        rc = m_parent->findClass(name);
+    return rc;
 }
 
 /**
@@ -125,7 +129,7 @@ void RplSymbolSpace::dump(FILE* fp, int indent, const char* header)
         clazz->dump(fp, indent + 1);
     }
 
-    fprintf(fp, "== Variables:\n");
+    fprintf(fp, "%s== Variables:\n", tabs);
     sorted.clear();
     sorted.reserve(m_variables.size());
     VariableMap::iterator it3;
@@ -138,8 +142,9 @@ void RplSymbolSpace::dump(FILE* fp, int indent, const char* header)
         RplVariable* var = m_variables[*it4];
         var->dump(fp, indent + 1);
     }
-    fprintf(fp, "== Body:\n");
-    m_body->dump(fp, indent + 1);
+    fprintf(fp, "%s== Body:%s\n", tabs, m_body == NULL ? " <none>" : "");
+    if (m_body != NULL)
+        m_body->dump(fp, indent + 1);
 }
 
 /**
@@ -173,6 +178,27 @@ const char*RplSymbolSpace::spaceTypeName(RplSymbolSpace::SymbolSpaceType type)
     }
     return rc;
 }
+/**
+ * @brief Returns the body (a 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 (a abstract syntax tree) of the symbol space.
+ *
+ * @param body  the new body
+ */
+void RplSymbolSpace::setBody(RplASItem* body)
+{
+    m_body = body;
+}
+
 /**
  * @brief Returns the name of the symbol space.
  *
@@ -194,7 +220,7 @@ QString RplSymbolSpace::name() const
  * @brief Constructor.
  */
 RplASBoolean::RplASBoolean() :
-    RplASClass("Boolean")
+    RplASClass("Bool")
 {
 }
 /**
@@ -255,7 +281,7 @@ QString RplASBoolean::toString(void* object, int) const
  * @brief Constructor.
  */
 RplASFloat::RplASFloat() :
-    RplASClass("Boolean")
+    RplASClass("Float")
 {
 }
 
@@ -324,7 +350,7 @@ QString RplASFloat::toString(void* object, int) const
  * @brief Constructor.
  */
 RplASInteger::RplASInteger() :
-    RplASFloat("Integer")
+    RplASFloat("Int")
 {
 }
 
@@ -365,7 +391,7 @@ QString RplASInteger::toString(void* object, int maxLength) const
  * @brief Constructor.
  */
 RplASString::RplASString() :
-    RplASClass("String")
+    RplASClass("Str")
 {
 }
 /**
index 922189058be08d12bcc7f75d9ee710adf31c66d8..5b6481cc4255f34577935b5ba247c17305700308 100644 (file)
@@ -47,6 +47,9 @@ public:
     RplVariable* findVariable(const QString& name) const;
     RplASClass* findClass(const QString& name) const;
     void dump(FILE* fp, int indent, const char* header = NULL);
+    QString name() const;
+    RplASItem* body() const;
+    void setBody(RplASItem* body);
 public:
     static void initGlobal(RplSymbolSpace& global);
     static const char* spaceTypeName(SymbolSpaceType type);
@@ -59,7 +62,6 @@ private:
     RplASItem* m_body;
 public:
     static RplSymbolSpace m_global;
-    QString name() const;
 };
 
 class RplASBoolean : public RplASClass {
index c280e31fcb109aa12b41515722cd16c6db8b9b48..428304a260482790497016f68cd332b510c184d4 100644 (file)
@@ -317,7 +317,7 @@ QString RplASVariant::toString(int maxLength) const
         rc.sprintf("%d", m_value.m_int);
         break;
     case DT_OBJECT:
-        m_class->toString(m_value.m_object, maxLength);
+        rc = m_class->toString(m_value.m_object, maxLength);
         break;
     default:
     case DT_UNDEF:
@@ -354,7 +354,7 @@ void RplASVariant::setObject(void* object, const RplASClass* clazz)
  */
 RplASItem::RplASItem(RplASItemType type) :
     m_id(m_nextId++),
-    m_type(type),
+    m_nodeType(type),
     m_flags(0),
     m_position(NULL)
 {
@@ -443,7 +443,7 @@ void RplASConstant::calc(RplASVariant& value)
 void RplASConstant::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sConstant %d value: %s\n", tabs, m_id,
+    fprintf(fp, "%sconst id: %d value: %s\n", tabs, m_id,
             m_value.toString().toUtf8().constData());
 }
 
@@ -464,25 +464,40 @@ RplASVariant& RplASConstant::value()
 
 /** @class RplASNamedValue rplastree.hpp "rplexpr/rplastree.hpp"
  *
- * @brief Implements the abstract base class of all named values, e.g. variables.
+ * @brief Implements a named values, a constant or a variable
  *
  */
 
 /**
  * @brief Constructor.
  *
- * @param type      the type of the variable
  * @param name      the name of the instance
- * @param attr      a bitmask of <code>Attribute</code> values, e.g. A_CONST
  */
-RplASNamedValue::RplASNamedValue(RplASClass* type,
-                                 const QString& name, int attributes) :
+RplASNamedValue::RplASNamedValue(const QString& name) :
     RplASNode1(AST_NAMED_VALUE),
     m_name(name),
+    m_attributes(0),
+    m_dataType(NULL)
+{
+}
+
+/**
+ * @brief Constructor.
+ *
+ * @param itemType      the node type, e.g. AST_VAR_DEFINITION
+ * @param dataType      the data type (class)
+ * @param name          the name of the variable
+ * @param attributes    the attributes of the variable
+ */
+RplASNamedValue::RplASNamedValue(RplASItemType itemType, RplASClass* dataType,
+                                  const QString& name, int attributes) :
+    RplASNode1(itemType),
+    m_name(name),
     m_attributes(attributes),
-    m_type(type)
+    m_dataType(dataType)
 {
 }
+
 /**
  * @brief Returns the name.
  *
@@ -510,7 +525,61 @@ void RplASNamedValue::calc(RplASVariant& value)
 void RplASNamedValue::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sNamedValue %d attr: 0x%x\n", tabs, m_id, m_attributes);
+    fprintf(fp, "%snamedValue id: %d attr: 0x%x\n", tabs,
+            m_id, m_attributes);
+}
+
+/** @class RplVarDefinition rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements variable definition for the Abstract Syntax Tree.
+ */
+
+/**
+ * @brief Constructor.
+ *
+ * @param type          the data type
+ * @param name          the name of the variable
+ * @param attributes    the attributes of the variable
+ */
+RplASVarDefinition::RplASVarDefinition(RplASClass* type, const QString& name,
+                                   int attributes) :
+    RplASNamedValue(AST_VAR_DEFINITION, type, name, attributes),
+    RplASStatement()
+{
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp        target file
+ * @param indent    nesting level
+ */
+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",
+            tabs, name.constData(), className.constData(),
+            m_id, m_successor == NULL ? 0 : m_successor->id(), m_attributes);
+    if (m_child != NULL)
+        m_child->dump(fp, indent + 1);
+    if (m_successor != NULL)
+        m_successor->dump(fp, indent);
+}
+
+void RplASVarDefinition::execute()
+{
+    //@ToDo
+}
+
+/**
+ * @brief Calculates the initialation value while interpreting.
+ *
+ * @param value     OUT: ignored
+ */
+void RplASVarDefinition::calc(RplASVariant&)
+{
 }
 
 /** @class RplASNode1 rplastree.hpp "rplexpr/rplastree.hpp"
@@ -896,7 +965,7 @@ const QString& RplASClass::name() const
 void RplASClass::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sClass %s super: %s\n", tabs, m_name.toUtf8().constData(),
+    fprintf(fp, "%sclass %s super: %s\n", tabs, m_name.toUtf8().constData(),
             m_superClass == NULL
                 ? "<none>" : m_superClass->name().toUtf8().constData());
     QList<QString> sorted;
@@ -975,10 +1044,9 @@ bool RplASTree::startModule(const QString& name)
 {
     bool rc = m_modules.contains(name);
     if (! rc){
-        // m_modules[0] is the "global" symbol space.
         // freed in ~RplASTree()
         RplSymbolSpace* space = new RplSymbolSpace(RplSymbolSpace::SST_MODULE,
-            name, m_symbolSpaces[0]);
+            name, m_global);
         m_symbolSpaceHeap[name] = space;
         m_modules[name] = space;
         m_symbolSpaces.append(space);
@@ -986,6 +1054,18 @@ bool RplASTree::startModule(const QString& name)
     }
     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 QString& name)
+{
+    RplSymbolSpace* rc = m_modules.contains(name) ? m_modules[name] : NULL;
+    return rc;
+}
 
 /**
  * @brief Handles the end of a module.
@@ -1213,13 +1293,15 @@ void RplASBinaryOp::setOperator(int op)
 void RplASBinaryOp::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
-    fprintf(fp, "%sBinOp %d op: %d left: %d right: %d\n", tabs, m_id, m_operator,
+    const QByteArray& opName = RplLexer::m_active->nameOfOp(m_operator);
+    fprintf(fp, "%sBinOp %d op: %s (%d) left: %d right: %d\n", tabs, m_id,
+            opName.constData(), m_operator,
             m_child == NULL ? 0 : m_child->id(),
             m_child2 == NULL ? 0 : m_child2->id());
     if (m_child != NULL)
         m_child->dump(fp, indent + 1);
     if (m_child2 != NULL)
-        m_child->dump(fp, indent + 1);
+        m_child2->dump(fp, indent + 1);
 }
 
 /** @class RplASMethod rplastree.hpp "rplexpr/rplastree.hpp"
@@ -1237,7 +1319,7 @@ void RplASBinaryOp::dump(FILE* fp, int indent)
 RplASMethod::RplASMethod(const QString& name, RplASClass* type) :
     RplASNode2(AST_METHOD),
     m_name(name),
-    m_type(type)
+    m_nodeType(type)
 {
 }
 
@@ -1251,7 +1333,7 @@ void RplASMethod::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
     fprintf(fp, "%sMethod %d %s %s(", tabs, m_id,
-            m_type == NULL ? "<NoneType>" : m_type->name().toUtf8().constData(),
+            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());
@@ -1269,3 +1351,4 @@ RplASArgument::RplASArgument() :
     RplASStatement()
 {
 }
+
index d5a265e9986f4d4e715ace95b898628eb9ec1824..63b08a2ac86689b49770016bbea57bb075ad89a2 100644 (file)
@@ -14,6 +14,7 @@ enum RplASItemType {
     AST_UNDEF,
     AST_CONSTANT,
     AST_NAMED_VALUE,
+    AST_VAR_DEFINITION,
     AST_METHOD,
     AST_ARGUMENT,
     AST_INTRINSIC_METHOD,
@@ -126,7 +127,7 @@ public:
     virtual void dump(FILE* fp, int indent) = 0;
 protected:
     unsigned int m_id:16;
-    RplASItemType m_type:8;
+    RplASItemType m_nodeType:8;
     int m_flags:5;
     int m_dataType: 3;
     const RplSourcePosition* m_position;
@@ -213,17 +214,43 @@ public:
     };
 
 public:
-    RplASNamedValue(RplASClass* type, const QString& name,
-        int attributes = A_NONE);
+    RplASNamedValue(const QString& name);
+    RplASNamedValue(RplASItemType itemType, RplASClass* dataType,
+                    const QString& name, int attributes);
 public:
     QString name() const;
 public:
     virtual void calc(RplASVariant& value);
     void dump(FILE* fp, int indent);
-private:
+protected:
     QString m_name;
     int m_attributes;
-    RplASClass* m_type;
+    RplASClass* m_dataType;
+};
+
+class RplASStatement
+{
+public:
+    RplASStatement();
+    virtual ~RplASStatement();
+public:
+    virtual void execute() = 0;
+    RplASItem* successor() const;
+    void setSuccessor(RplASItem* successor);
+protected:
+    RplASItem* m_successor;
+};
+
+
+class RplASVarDefinition : public RplASNamedValue, public RplASStatement
+{
+public:
+    RplASVarDefinition(RplASClass* type, const QString& name,
+        int attributes = A_NONE);
+public:
+    virtual void execute();
+    virtual void calc(RplASVariant& value);
+    void dump(FILE* fp, int indent);
 };
 
 class RplASUnaryOp : public RplASNode1
@@ -249,20 +276,6 @@ private:
     int m_operator;
 };
 
-class RplASStatement
-{
-public:
-    RplASStatement();
-    virtual ~RplASStatement();
-public:
-    virtual void execute() = 0;
-    RplASItem* successor() const;
-    void setSuccessor(RplASItem* successor);
-
-private:
-    RplASItem* m_successor;
-};
-
 class RplASCondition : public RplASNode1, public RplASCalculable
 {
 public:
@@ -338,7 +351,7 @@ public:
     void dump(FILE* fp, int indent);
 private:
     QString m_name;
-    RplASClass* m_type;
+    RplASClass* m_nodeType;
     // body is m_child
     // param1 is m_child2
 };
@@ -420,6 +433,7 @@ public:
     RplASClass* findClass(const QString& name);
     void clear();
     void dump(const char* filename, int flags = DMP_ALL);
+    RplSymbolSpace*findmodule(const QString& name);
 protected:
     void init();
     void destroy();
index a1c492268fe65c0e8c2957649ee6a6884fa0f857..82a0f8aeef1b0591cb79f0ae5e0df746decc1c8e 100644 (file)
@@ -11,6 +11,8 @@
 
 #define CHAR_INFO_SIZE (int(sizeof m_charInfo / sizeof m_charInfo[0]))
 
+RplLexer* RplLexer::m_active = NULL;
+
 /** @class RplToken rpllexer.hpp "rplexpr/rpllexer.hpp"
  *
  * @brief Implements specific exception for the lexer.
@@ -362,12 +364,16 @@ RplLexer::RplLexer(RplSource* source,
     charClassToCharInfo(restCharsId, CC_REST_ID, m_charInfo);
     initializeComments(comments);
     m_input.reserve(m_maxTokenLength*2);
+    if (m_active == NULL)
+        m_active = this;
 }
 /**
  * @brief Destructor.
  */
 RplLexer::~RplLexer()
 {
+    if (m_active == this)
+        m_active = NULL;
 }
 
 /**
@@ -1017,6 +1023,18 @@ int RplLexer::prioOfOp(int op) const
     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
index c624986c681cc174267b6e8e05eb5fbaace2aa41..d11720b71108b411eb59950a92ab93fc957b3355 100644 (file)
@@ -228,6 +228,8 @@ protected:
     char m_prioOfOp[128];
     char m_assocOfOp[128];
     QList<QByteArray> m_opNames;
+public:
+    static RplLexer* m_active;
 };
 
 
index 8306aae6d5e09f5014a226523c4d7f5f17eb366e..f3a4203fc646683fb50ac797d733c3001c8ef371 100644 (file)
@@ -15,12 +15,13 @@ enum MFLocations{
     L_PARSE_OPERAND_RPARENTH_FUNC,
     L_TERM_WRONG_STRING,
     L_TERM_WRONG_NUMBER,
-    L_PARSE_OPERAND_WRONG = 2005,
+    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
+    L_DEFINITION_NO_OP      = 2010,
+    L_DEFINITION_NO_SEMICOLON
 
 };
 
@@ -99,10 +100,10 @@ RplASItem* RplMFParser::parseFor()
  * @param clazz     NULL or the type of the variable
  * @param attribute 0 or attribute of the variable: K_CONST or K_LAZY
  */
-RplASItem* RplMFParser::parseDefinition(Keyword attribute)
+RplASItem* RplMFParser::parseVarDefinition(Keyword attribute)
 {
     RplASNamedValue::Attributes attr = RplASNamedValue::A_NONE;
-    RplToken* token;
+    RplToken* token = m_lexer.currentToken();
     while(attribute == K_CONST || attribute == K_LAZY){
         switch(attribute){
         case K_CONST:
@@ -118,7 +119,7 @@ RplASItem* RplMFParser::parseDefinition(Keyword attribute)
         attribute = token->isTokenType(TOKEN_KEYWORD)
                 ? (Keyword) token->id() : K_UNDEF;
     }
-    if (token->isTokenType(TOKEN_ID))
+    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,
@@ -129,7 +130,8 @@ RplASItem* RplMFParser::parseDefinition(Keyword attribute)
     token = m_lexer.nextNonSpaceToken();
     if (! token->isTokenType(TOKEN_ID))
         syntaxError(L_DEFINITION_MISSING_ID, "variable name expected");
-    RplASNamedValue* rc = new RplASNamedValue(clazz, token->toString(), attr);
+    RplASNamedValue* rc = new RplASVarDefinition(clazz, token->toString(), attr);
+    rc->setPosition(m_lexer.currentPosition());
     token = m_lexer.nextNonSpaceToken();
     if (! token->isOperator(O_ASSIGN, O_SEMICOLON))
         syntaxError(L_DEFINITION_NO_OP, "'=' or ';' expected");
@@ -138,8 +140,8 @@ RplASItem* RplMFParser::parseDefinition(Keyword attribute)
         rc->setChild(value);
         token = m_lexer.currentToken();
     }
-    if (token->isOperator(O_SEMICOLON)){
-        syntaxError(L_DEFINITION_NO_OP, "';' expected");
+    if (token->isOperator(O_SEMICOLON)){
+        syntaxError(L_DEFINITION_NO_SEMICOLON, "';' expected");
     }
     return rc;
 }
@@ -181,6 +183,7 @@ RplASItem* RplMFParser::parseOperand(int level)
     case TOKEN_REAL:
     {
         RplASConstant* constant = new RplASConstant();
+        constant->setPosition(m_lexer.currentPosition());
         rc = constant;
         switch(token->tokenType()){
         case TOKEN_STRING:
@@ -260,11 +263,11 @@ RplASItem* RplMFParser::parseTerm(int depth){
         switch(tokenType){
         case TOKEN_OPERATOR:
         {
-            if (IS_BINARY_OP(tokenType)){
+            Operator opId = (Operator) token->id();
+            if (IS_BINARY_OP(opId)){
                 RplASBinaryOp* op = new RplASBinaryOp();
-                int opId = token->id();
-                op->setOperator(opId);
                 op->setPosition(m_lexer.currentPosition());
+                op->setOperator(opId);
 
                 int prio = m_lexer.prioOfOp(token->id());
                 if (prio < lastPrio
@@ -277,6 +280,7 @@ RplASItem* RplMFParser::parseTerm(int depth){
                     op->setChild(top2->child2());
                     top2->setChild2(op);
                 }
+                lastPrio = prio;
                 op->setChild2(parseOperand(depth));
             } else
                 again = false;
@@ -327,72 +331,102 @@ RplASItem* RplMFParser::parseBody()
     RplASStatement* lastStatement = NULL;
     bool again = true;
     while(again) {
-        switch(token->tokenType())
-        {
-        case TOKEN_STRING:
-        case TOKEN_NUMBER:
-        case TOKEN_REAL:
-        case TOKEN_OPERATOR:
-            m_lexer.undoLastToken();
-            item = parseExpr();
-            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:
-                item = parseClass();
-                break;
-            case K_FUNCTION:
-            case K_GENERATOR:
-                item = parseMethodDefinition();
+        token = m_lexer.currentToken();
+        try {
+            switch(token->tokenType())
+            {
+            case TOKEN_STRING:
+            case TOKEN_NUMBER:
+            case TOKEN_REAL:
+            case TOKEN_OPERATOR:
+                m_lexer.undoLastToken();
+                item = parseExpr();
                 break;
-            case K_IMPORT:
-                parseImport();
+            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:
+                    item = parseClass();
+                    break;
+                case K_FUNCTION:
+                case K_GENERATOR:
+                    item = parseMethodDefinition();
+                    break;
+                case K_IMPORT:
+                    parseImport();
+                    break;
+                case K_CONST:
+                case K_LAZY:
+                    item = parseVarDefinition((Keyword) token->id());
+                    break;
+                default:
+                    break;
+                }
                 break;
-            case K_CONST:
-            case K_LAZY:
-                item = parseDefinition(NULL, (Keyword) token->id());
+            case TOKEN_ID:
+            {
+                if (token->isCapitalizedId()){
+                    item = parseVarDefinition(K_UNDEF);
+                } else {
+                    m_lexer.undoLastToken();
+                    item = parseExpr();
+                }
                 break;
-            case K_BOOL:
-                parseDefinition(&RplASBoolean::m_instance, K_UNDEF);
+            }
+            case TOKEN_END_OF_SOURCE:
+                again = false;
                 break;
             default:
                 break;
             }
-            break;
-        case TOKEN_ID:
-        {
-            if (token->isCapitalizedId()){
-                item = parseDefinition(K_UNDEF);
-            } else {
-                m_lexer.undoLastToken();
-                item = parseExpr();
+            if (! token->isTokenType(TOKEN_END_OF_SOURCE)){
+                if (body == NULL){
+                    body = item;
+                } else {
+                    lastStatement->setSuccessor(item);
+                }
+                lastStatement = dynamic_cast<RplASStatement*>(item);
+                if (lastStatement == NULL)
+                    assert("wrong item type" == NULL);
+                token = m_lexer.nextNonSpaceToken();
             }
-            break;
-        }
-        case TOKEN_END_OF_SOURCE:
-            again = false;
-            break;
-        default:
-            break;
-        }
-        if (body == NULL){
-            body = item;
-        } else {
-            lastStatement->setSuccessor(item);
+        } 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();
+                }
         }
-        lastStatement = dynamic_cast<RplASStatement*>(item);
     }
     return body;
 }
@@ -445,7 +479,18 @@ RplASItem* RplMFParser::parseModule(const QString& name)
  */
 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();
+        RplSymbolSpace* module = m_tree.findmodule(mainModuleName);
+        if (module != NULL)
+            module->setBody(body);
+    } catch(RplParserStop exc){
+        printf("compiling stopped: %s\n", exc.reason());
+    }
 }
 
 /**
index d2fa98c28d9bbe54342ba0276e72e3f47ff55038..c888be05a40677674d289d91da93c6af8747c99e 100644 (file)
@@ -74,7 +74,7 @@ public:
     RplASItem* parseWhile();
     RplASItem* parseRepeat();
     RplASItem* parseFor();
-    RplASItem* parseDefinition(Keyword attribute);
+    RplASItem* parseVarDefinition(Keyword attribute);
     RplASItem* parseExpr();
     RplASItem* parseBody();
     RplASItem* parseMethodDefinition();
@@ -87,6 +87,8 @@ protected:
     RplASItem* parseOperand(int level);
     RplASItem* parseTerm(int depth);
 private:
+    ///syntax token builder.
+    /// Note: the super class contains a reference with the same name
     RplLexer m_lexer;
 };
 
index ff6868220e561de58cd5547eb98d4a0cceacf45f..52b389a8116e0fddcdd474cc0dbf3fa0034bee86 100644 (file)
@@ -31,6 +31,15 @@ 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"
  *
index 333b2b0544c1063f24714dba249850dc6ba6ace6..e9334ac707ece9c692560cce79be339c037ed976 100644 (file)
@@ -14,6 +14,8 @@ class RplSyntaxError
 {
 public:
     RplSyntaxError(const char* reason);
+public:
+    const char* reason() const;
 private:
     const char* m_reason;
 };
@@ -36,7 +38,7 @@ protected:
     void addMessage(char prefix, int location, const char* format, va_list varList);
 
 protected:
-    RplLexer m_lexer;
+    RplLexer& m_lexer;
     RplASTree& m_tree;
     MessageList m_messages;
     int m_errors;
diff --git a/test/rplmfparser/baseTest.txt b/test/rplmfparser/baseTest.txt
new file mode 100644 (file)
index 0000000..0fe593c
--- /dev/null
@@ -0,0 +1,18 @@
+=== Globals:
+= global (global) parent: <none>
+== Classes:
+       class Boolean super: <none>
+       class Boolean super: <none>
+       class Integer super: Float
+       class List super: <none>
+       class Map super: <none>
+       class String super: <none>
+== Variables:
+== Body: <none>
+       = <test> (module) parent: global
+       == Classes:
+       == Variables:
+       == Body:
+               BinOp 2 op: + (26) left: 1 right: 3
+                       Constant 1 value: 2
+                       Constant 3 value: 3
diff --git a/test/rplmfparser/defTest.txt b/test/rplmfparser/defTest.txt
new file mode 100644 (file)
index 0000000..8863957
--- /dev/null
@@ -0,0 +1,20 @@
+=== Globals:
+= global (global) parent: <none>
+== Classes:
+       class Bool super: <none>
+       class Float super: <none>
+       class Int super: Float
+       class List super: <none>
+       class Map super: <none>
+       class Str super: <none>
+== Variables:
+== Body: <none>
+       = <test> (module) parent: global
+       == Classes:
+       == Variables:
+       == Body:
+               varDef i (Int) id: 1 succ: 3 attr: 0x0
+                       const id: 2 value: 3
+               varDef s (Str) id: 3 succ: 5 attr: 0x10
+                       const id: 4 value: 'Hi'
+               varDef l (List) id: 5 succ: 0 attr: 0x2
index 274a93c221b7ec51f76a89649b22072e2abce19b..e9fc42b85e05d624b74f6b7aeee33d333b819dd1 100644 (file)
@@ -22,6 +22,9 @@ void testCore(){
 }
 
 void testExpr(){
+    extern void testRplMFParser();
+    testRplMFParser();
+
     extern void testRplASTree();
     testRplASTree();
     extern void testRplSource();
index 5d7d7cbecbf9427793f70cb170561de5fadc589f..6fe622e88dee11c1d19354ad0ad64a7343492291 100644 (file)
@@ -10,7 +10,7 @@
 #include "rplexpr/rplexpr.hpp"
 #include "rplcore/rpltest.hpp"
 
-class TestRplMFParser : public RplTest, public RplMFParser{
+class TestRplMFParser : public RplTest{
 private:
     RplSource m_source;
     RplASTree m_tree;
@@ -18,7 +18,6 @@ private:
 public:
     TestRplMFParser() :
         RplTest("RplMFParser"),
-        RplMFParser(m_source, m_tree),
         m_source(),
         m_tree(),
         m_reader(m_source)
@@ -31,6 +30,21 @@ protected:
         m_tree.clear();
         m_source.clear();
         m_reader.replaceSource("<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 += "rplmfparser";
+        fnExpected += (char) QDir::separator().toLatin1();
+        fnExpected += fileExpected;
+        QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser");
+        m_tree.dump(fnCurrent);
+        assertEqualFiles(fnExpected.constData(), fnCurrent.constData(),
+                         __FILE__, lineNo);
     }
 
 public:
@@ -38,17 +52,19 @@ public:
         setSource("2+3*4");
         RplMFParser parser(m_source, m_tree);
         parser.parse();
+        checkAST("baseTest.txt", __LINE__);
     }
 
     void defTest(){
-        setSource("int i = 3; Str s = 'Hi; List l = [3, 'v4'];");
+        setSource("Int i = 3; const lazy Str s = 'Hi'; const List l;");
         RplMFParser parser(m_source, m_tree);
         parser.parse();
+        checkAST("defTest.txt", __LINE__);
     }
 
     virtual void doIt(void) {
-        //baseTest();
-        //defTest();
+        defTest();
+        baseTest();
     }
 };
 void testRplMFParser() {