]> gitweb.hamatoma.de Git - reqt/commitdiff
day's work
authorhama <hama@siduction.net>
Sat, 28 Jun 2014 22:21:49 +0000 (00:21 +0200)
committerhama <hama@siduction.net>
Sat, 28 Jun 2014 22:21:49 +0000 (00:21 +0200)
14 files changed:
rplexpr/rplasclasses.cpp
rplexpr/rplastree.cpp
rplexpr/rplastree.hpp
rplexpr/rplexpr.hpp
rplexpr/rpllexer.cpp
rplexpr/rpllexer.hpp
rplexpr/rplmfparser.cpp
rplexpr/rplmfparser.hpp
rplexpr/rplparser.cpp [new file with mode: 0644]
rplexpr/rplparser.hpp [new file with mode: 0644]
rplexpr/rplsource.cpp
rplstatic/rplstatic.pro
unittests/rplmfparser_test.cpp
unittests/unittests.pro

index ab2ffa126226656fada93002cd6f7f87a0e1a859..4d0818019371d14f457358b14fa55dec3f665248 100644 (file)
@@ -81,6 +81,18 @@ RplSymbolSpace::~RplSymbolSpace()
         delete it.value();
     }
 }
+
+/**
+ * @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 QString& name) const
+{
+    return NULL;
+}
 /**
  * @brief Returns the name of the symbol space.
  *
index 0280713bdc57bd212bbba6d50e4e732b9afa4f0a..c17a38cefa62f261580b9b2d2bbfc2307d8f068d 100644 (file)
@@ -20,6 +20,25 @@ unsigned int RplASItem::m_nextId = 1;
  * @brief RplASException::RplASException
  * @param message
  */
+
+
+/**
+ * @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();
+    vsnprintf(buffer, sizeof buffer, format, varList);
+    m_message += buffer;
+}
+
 /**
  * @brief Constructor.
  *
@@ -31,16 +50,23 @@ RplASException::RplASException(const RplSourcePosition* position,
                                  const char* format, ...) :
     RplException("")
 {
-    char buffer[64000];
-    if (position != NULL)
-        m_message = position->toString().toUtf8();
     va_list ap;
     va_start(ap, format);
-    vsnprintf(buffer, sizeof buffer, format, ap);
+    build(position, format, ap);
     va_end(ap);
-    m_message += buffer;
 }
 
+/**
+ * @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.
+ */
+RplASException::RplASException() :
+    RplException("")
+{
+}
 
 /** @class RplASVariant rplastree.hpp "rplexpr/rplastree.hpp"
  *
@@ -283,7 +309,7 @@ QString RplASVariant::toString(int maxLength) const
         rc.sprintf("%f", m_value.m_float);
         break;
     case DT_INTEGER:
-        rc.sprintf("%d", m_value.m_float);
+        rc.sprintf("%d", m_value.m_int);
         break;
     case DT_OBJECT:
         m_class->toString(m_value.m_object, maxLength);
@@ -502,6 +528,16 @@ 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"
  *
@@ -886,11 +922,25 @@ RplSymbolSpace* RplASTree::currentSpace() const
 }
 
 /**
- * @brief Returns the method.
- *
- * @return the method
+ * @brief Constructor.
  */
-RplASMethod* RplAsMethodCall::method() const
+RplASMethodCall::RplASMethodCall() :
+    RplASNode2(AST_METHOD_CALL),
+    RplASStatement()
+{
+
+}
+
+RplASMethodCall::~RplASMethodCall()
+{
+
+}
+
+void RplASMethodCall::execute()
+{
+}
+
+RplASMethod* RplASMethodCall::method() const
 {
     return m_method;
 }
@@ -899,7 +949,7 @@ RplASMethod* RplAsMethodCall::method() const
  * @brief Sets the method.
  * @param method    method to set
  */
-void RplAsMethodCall::setMethod(RplASMethod* method)
+void RplASMethodCall::setMethod(RplASMethod* method)
 {
     m_method = method;
 }
@@ -909,7 +959,7 @@ void RplAsMethodCall::setMethod(RplASMethod* method)
  *
  * @return  the first element of an argument list
  */
-RplArgument* RplAsMethodCall::arg1() const
+RplASArgument* RplASMethodCall::arg1() const
 {
     return m_arg1;
 }
@@ -919,8 +969,24 @@ RplArgument* RplAsMethodCall::arg1() const
  *
  * @param arg1  NULL or the first element of the argument list
  */
-void RplAsMethodCall::setArg1(RplArgument* arg1)
+void RplASMethodCall::setArg1(RplASArgument* arg1)
 {
     m_arg1 = arg1;
 }
 
+
+RplASBinaryOp::RplASBinaryOp() :
+    RplASNode2(AST_BINARY_OP),
+    m_operator(0)
+{
+}
+
+int RplASBinaryOp::getOperator() const
+{
+    return m_operator;
+}
+
+void RplASBinaryOp::setOperator(int op)
+{
+    m_operator = op;
+}
index 76ef53b36aaa12d5cb1c59e17a8e2227cb8c8331..f31fab165f3c8458fea98b54e85642afb0b377df 100644 (file)
@@ -32,7 +32,10 @@ enum RplASItemType {
 
 class RplASException : public RplException {
 public:
+    RplASException();
     RplASException(const RplSourcePosition* position, const char* message, ...);
+protected:
+    void build(const RplSourcePosition* position, const char* format, va_list varList);
 };
 
 class RplASClass;
@@ -179,6 +182,10 @@ class RplASNode2 : public RplASNode1
 public:
     RplASNode2(RplASItemType type);
     virtual ~RplASNode2();
+public:
+    RplASItem* child2() const;
+    void setChild2(RplASItem* child2);
+
 protected:
     RplASItem* m_child2;
 };
@@ -215,6 +222,10 @@ class RplASBinaryOp : public RplASNode2
 {
 public:
     RplASBinaryOp();
+public:
+    int getOperator() const;
+    void setOperator(int op);
+
 private:
     int m_operator;
 };
@@ -255,29 +266,32 @@ public:
     virtual ~RplASWhile();
 };
 
-class RplArgument : public RplASNode2, public RplASStatement
+class RplASArgument : public RplASNode2, public RplASStatement
 {
 public:
-    RplArgument();
-    virtual ~RplArgument();
+    RplASArgument();
+    virtual ~RplASArgument();
 };
 
 class RplASMethod;
-class RplAsMethodCall : public RplASNode2, public RplASStatement
+class RplASMethodCall : public RplASNode2, public RplASStatement
 {
 public:
-    RplAsMethodCall();
-    virtual ~RplAsMethodCall();
+    RplASMethodCall();
+    virtual ~RplASMethodCall();
+public:
+    virtual void execute();
+
 public:
     RplASMethod* method() const;
     void setMethod(RplASMethod* method);
 
-    RplArgument* arg1() const;
-    void setArg1(RplArgument* arg1);
+    RplASArgument* arg1() const;
+    void setArg1(RplASArgument* arg1);
 
 private:
     RplASMethod* m_method;
-    RplArgument* m_arg1;
+    RplASArgument* m_arg1;
 };
 
 class RplParameter : RplASItem
@@ -364,6 +378,7 @@ public:
     void finishClassOrMethod(const QString& name);
     SymbolSpaceStack& symbolSpaces();
     RplSymbolSpace* currentSpace() const;
+    RplASClass* findClass(const QString& name);
 
 private:
     // the mother of all symbol spaces.
index 18a9cf6bfd47c21425f405957cb6cd2424b45a40..7b04db064eb53ba273e29dc904a34b6c5f2ceeec 100644 (file)
@@ -22,6 +22,7 @@
 #include "rplexpr/rpllexer.hpp"
 #include "rplexpr/rplastree.hpp"
 #include "rplexpr/rplvm.hpp"
+#include "rplexpr/rplparser.hpp"
 #include "rplexpr/rplmfparser.hpp"
 
 #endif // RPLEXPR_HPP
index d7ad9a2419c352f66a041d3f2f39a65d4980da13..c74795f86f9a7bba7eaa436482f0899504f4e0af 100644 (file)
@@ -745,6 +745,15 @@ void RplLexer::scanComment()
     m_input.remove(0, length);
     m_currentCol += length;
 }
+/**
+ * @brief Returns the current position.
+ *
+ * @return  the current source code position
+ */
+RplSourcePosition* RplLexer::currentPosition() const
+{
+    return m_currentPosition;
+}
 
 /**
  * @brief Returns the next token.
index 49a11e6b236fbf999f4478134ed5a207e92fe533..f761affa63d1aefc03a1949b4b8a8dfac7070ea2 100644 (file)
@@ -171,6 +171,8 @@ public:
     void startUnit(const QString& unit);
     RplSource* source();
     int prioOfOp(int op) const;
+    RplSourcePosition* currentPosition() const;
+
 private:
     void prepareOperators(const char* operators);
     void initializeComments(const char* comments);
index 69b56edec0b79933980558c51ed1fcf627212f2a..78b5992170d1180af9713b182452c4bdfcfaa3b1 100644 (file)
 #include "rplcore/rplcore.hpp"
 #include "rplexpr/rplexpr.hpp"
 
+enum MFLocations{
+    L_PARSE_OPERAND_RPARENTH = 2000,
+    L_PARSE_OPERAND_RPARENTH_FUNC,
+    L_PARSE_OPERAND_WRONG
+
+};
+
 /** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
  *
  * @brief Implements a parser for the language MF.
  */
 
 RplMFParser::RplMFParser(RplSource& source, RplASTree& abstractSyntaxTree) :
+    RplParser(m_lexer, abstractSyntaxTree),
     m_lexer(&source,
             MF_KEYWORDS, MF_OPERATORS,
             "/* */ // \n",
             "a-zA-Z_", "a-zA-Z0-9_",
-            RplLexer::NUMTYPE_ALL, RplLexer::SF_LIKE_C),
-    m_tree(abstractSyntaxTree)
+            RplLexer::NUMTYPE_ALL, RplLexer::SF_LIKE_C)
 {
 }
 
 /**
  * @brief Parses a function or a generator.
  */
-void RplMFParser::parseFunc()
+RplASItem* RplMFParser::parseFunc()
 {
-
+   RplASItem*rc = NULL;
+   return rc;
 }
 /**
  * @brief Parses an if statement.
  */
-void RplMFParser::parseIf()
+RplASItem* RplMFParser::parseIf()
 {
-
+    RplASItem*rc = NULL;
+    return rc;
 }
 /**
  * @brief Parses a while statement.
  */
 
-void RplMFParser::parseWhile()
+RplASItem* RplMFParser::parseWhile()
 {
-
+    RplASItem*rc = NULL;
+    return rc;
 }
 
 /**
  * @brief Parses a repeat statement.
  */
-void RplMFParser::parseRepeat()
+RplASItem* RplMFParser::parseRepeat()
 {
-
+    RplASItem*rc = NULL;
+    return rc;
 }
 
 /**
  * @brief Parses a for statement.
  */
-void RplMFParser::parseFor()
+RplASItem* RplMFParser::parseFor()
 {
-
+    RplASItem*rc = NULL;
+    return rc;
 }
 
 /**
@@ -74,9 +86,10 @@ void RplMFParser::parseFor()
  * @param clazz     NULL or the type of the variable
  * @param attribute 0 or attribute of the variable: K_CONST or K_LAZY
  */
-void RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute)
+RplASItem* RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute)
 {
-
+    RplASItem*rc = NULL;
+    return rc;
 }
 
 /**
@@ -89,27 +102,43 @@ void RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute)
 RplASItem* RplMFParser::parseOperand(int level)
 {
     RplToken* token = m_lexer.nextNonSpaceToken();
+    RplSourcePosition* startPosition = m_lexer.currentPosition();
     RplASItem* rc = NULL;
     switch(token->tokenType()){
     case TOKEN_OPERATOR:
-        rc = new RplASUnary(token->id());
-        rc->setChild(parseOperand);
+    {
+        Operator op = (Operator) token->id();
+        if (op == O_LPARENTH){
+            rc = parseTerm(level + 1);
+        } else if (IS_UNARY_OP(op)){
+            RplASUnaryOp* node = new RplASUnaryOp(token->id(), AST_PRE_UNARY_OP);
+            rc = node;
+            node->setChild(parseOperand(level));
+            token = m_lexer.nextNonSpaceToken();
+            if(token->tokenType() != TOKEN_OPERATOR || token->id() != O_RPARENT){
+                QByteArray pos = startPosition->toString().toUtf8();
+                // this call never comes back (exception!)
+                syntaxError(L_PARSE_OPERAND_RPARENTH,
+                            "')' expected. '(' is at %s", pos.constData());
+            }
+        }
         break;
+    }
     case TOKEN_STRING:
     case TOKEN_NUMBER:
     case TOKEN_REAL:
     {
-        RplASConstant constant = new RplASConstant();
-        item = constant;
+        RplASConstant* constant = new RplASConstant();
+        rc = constant;
         switch(token->tokenType()){
         case TOKEN_STRING:
-            constant.m_value.setString(token->toString());
+            constant->value().setString(token->toString());
             break;
         case TOKEN_NUMBER:
-            constant.m_value.setInt(token->asInteger());
+            constant->value().setInt(token->asInteger());
             break;
         case TOKEN_REAL:
-            constant.m_value.setFloat(token->asReal());
+            constant->value().setFloat(token->asReal());
             break;
         default:
             break;
@@ -120,26 +149,41 @@ RplASItem* RplMFParser::parseOperand(int level)
     {
         QString name = token->toString();
         token = m_lexer.nextNonSpaceToken();
+        startPosition = m_lexer.currentPosition();
         if (token->tokenType() != TOKEN_OPERATOR){
             RplASNamedValue* var = new RplASNamedValue(name);
-            item = var;
+            rc = var;
             m_lexer.undoLastToken();
         } else {
             if (token->id() == O_LPARENTH){
-                RplASItem* args = parseArguments();
-                RplAsMethodCall node = new RplAsMethodCall();
-                node.setArg1(args);
+                RplASArgument* args = parseArguments();
+                RplASMethodCall* call = new RplASMethodCall();
+                rc = call;
+                call->setArg1(args);
+                token = m_lexer.nextNonSpaceToken();
+                if (token->tokenType() != TOKEN_OPERATOR
+                        || token->id() != O_RPARENT){
+                    QByteArray pos = startPosition->toString().toUtf8();
+                    // this call never comes back (exception!)
+                    syntaxError(L_PARSE_OPERAND_RPARENTH_FUNC,
+                                "')' expected. '(' is at %s", pos.constData());
+                }
+            } else if (token->id() == O_LBRACKET){
+
             } else if (token->id() == O_INC || token->id() == O_DEC){
                 RplASNamedValue* var = new RplASNamedValue(name);
-                item = var;
+                rc = var;
             }
         }
         break;
     }
     default:
+        // this call never comes back (exception!)
+        syntaxError(L_PARSE_OPERAND_WRONG,
+                    "unexpected symbol detected. Operand expected");
         break;
     }
-    return item;
+    return rc;
 }
 
 /**
@@ -155,13 +199,13 @@ RplASItem* RplMFParser::parseOperand(int level)
  */
 RplASItem* RplMFParser::parseTerm(int depth){
     RplToken* token;
-    RplSourcePosition* start = m_lexer.currentSourcePosition();
+    RplSourcePosition* start = m_lexer.currentPosition();
     RplASItem* top = NULL;
     RplASItem* item;
     int lastPrio = -1;
     bool again = true;
     do {
-        item = parseOperand(level);
+        item = parseOperand(depth);
         token = m_lexer.nextNonSpaceToken();
         RplTokenType tokenType = token->tokenType();
         switch(tokenType){
@@ -169,12 +213,12 @@ RplASItem* RplMFParser::parseTerm(int depth){
         {
             if (IS_BINARY_OP(tokenType)){
                 RplASBinaryOp* op = new RplASBinaryOp();
-                op->setOp(token->id());
+                op->setOperator(token->id());
                 int prio = m_lexer.prioOfOp(token->id());
                 op->setChild(item);
                 op->setPosition(m_lexer.currentPosition());
-                op->setChild2(parseOperand(level));
-                if
+                op->setChild2(parseOperand(depth));
+
             }
             break;
         }
@@ -183,7 +227,6 @@ RplASItem* RplMFParser::parseTerm(int depth){
         case TOKEN_REAL:
             break;
         case TOKEN_KEYWORD:
-        case TOKEN_OPERATOR:
         case TOKEN_ID:
         case TOKEN_END_OF_SOURCE:
             again = false;
@@ -199,13 +242,14 @@ RplASItem* RplMFParser::parseTerm(int depth){
  * @brief Parses an expression.
  *
  * @precond     the nextNonSpaceToken() will return the first token of the expr.
- * @postcond    all tokens belonging to the expr are read
+ * @postcond    all tokens belonging to the expr are read (not more!)
  *
- * @return      the token behind the expr
+ * @return      the tree of the expression
  */
-RplToken* RplMFParser::parseExpr()
+RplASItem* RplMFParser::parseExpr()
 {
-    RplASItem* item = parseTerm(0);
+    RplASItem* rc = parseTerm(0);
+    return rc;
 }
 
 /**
@@ -213,54 +257,55 @@ RplToken* RplMFParser::parseExpr()
  *
  * A body is a module, a class region or a method body.
  */
-void RplMFParser::parseBody()
+RplASItem* RplMFParser::parseBody()
 {
-    RplToken token = m_lexer.nextNonSpaceToken();
-    switch(token.tokenType())
+    RplToken* token = m_lexer.nextNonSpaceToken();
+    RplASItem* item = NULL;
+    switch(token->tokenType())
     {
     case TOKEN_STRING:
     case TOKEN_NUMBER:
     case TOKEN_REAL:
     case TOKEN_OPERATOR:
-        m_lexer.undoNextToken();
-        token = parseExpr();
+        m_lexer.undoLastToken();
+        item = parseExpr();
         break;
     case TOKEN_KEYWORD:
-        switch (token.id()){
+        switch (token->id()){
         case K_IF:
-            parseIf();
+            item = parseIf();
             break;
         case K_WHILE:
-            parseWhile();
+            item = parseWhile();
             break;
         case K_REPEAT:
-            parseRepeat();
+            item = parseRepeat();
             break;
         case K_FOR:
-            parseFor();
+            item = parseFor();
             break;
         case K_CLASS:
-            parseClass();
+            item = parseClass();
             break;
         case K_FUNCTION:
         case K_GENERATOR:
-            parseMethod();
+            item = parseMethodDefinition();
             break;
         case K_IMPORT:
             parseImport();
             break;
         case K_CONST:
         case K_LAZY:
-            parseDefinition(NULL, token.id());
+            item = parseDefinition(NULL, (Keyword) token->id());
             break;
         case K_INT:
-            parseDefinition(&RplASInteger.m_instance);
+            item = parseDefinition(&RplASInteger::m_instance, K_UNDEF);
             break;
         case K_FLOAT:
-            parseDefinition(&RplASFloat.m_instance);
+            parseDefinition(&RplASFloat::m_instance, K_UNDEF);
             break;
         case K_BOOL:
-            parseDefinition(&RplASBoolean.m_instance);
+            parseDefinition(&RplASBoolean::m_instance, K_UNDEF);
             break;
         default:
             break;
@@ -268,12 +313,12 @@ void RplMFParser::parseBody()
         break;
     case TOKEN_ID:
     {
-        RplASClass* clazz = m_tree.currentSpace()->findClass();
+        RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString());
         if (clazz != NULL){
-             parseDefinition(clazz);
+             item = parseDefinition(clazz, K_UNDEF);
         } else {
-            m_lexer.undoNextToken();
-            parseExpr();
+            m_lexer.undoLastToken();
+            item = parseExpr();
         }
         break;
     }
@@ -282,6 +327,36 @@ void RplMFParser::parseBody()
     default:
         break;
     }
+    //@ToDo: add item to list
+    return NULL;
+}
+
+/**
+ * @brief Parses a class definition.
+ * @return  the node in an abstract syntax tree
+ */
+RplASItem*RplMFParser::parseMethodDefinition()
+{
+    RplASItem* rc = NULL;
+    return rc;
+}
+
+/**
+ * @brief Parses a class definition.
+ * @return  the node in an abstract syntax tree
+ */
+RplASItem*RplMFParser::parseClass()
+{
+    RplASItem* rc = NULL;
+    return rc;
+}
+
+/**
+ * @brief Parses a the import statement
+ */
+void RplMFParser::parseImport()
+{
+
 }
 
 /**
@@ -292,7 +367,7 @@ void RplMFParser::parseBody()
  *
  * @param name  the name of the module (without path)
  */
-void RplMFParser::parseModule(const QString& name)
+RplASItem* RplMFParser::parseModule(const QString& name)
 {
     m_tree.startModule(name);
     parseBody();
@@ -306,3 +381,12 @@ void RplMFParser::parse()
 
 }
 
+/**
+ * @brief Parses an argument list.
+ * @return the first element of the argument list
+ */
+RplASArgument*RplMFParser::parseArguments()
+{
+
+}
+
index fbe938df0e2b8304b379c6f668193dd08f2dcd12..3e5770abd923e11090fd0edb321ed6e7394be9df 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef RPLMFPARSER_HPP
 #define RPLMFPARSER_HPP
 
-class RplMFParser
+class RplMFParser : public RplParser
 {
 public:
     enum Keyword {
@@ -64,22 +64,25 @@ public:
 public:
     RplMFParser(RplSource& source, RplASTree& ast);
 public:
-    void parseFunc();
-    void parseIf();
-    void parseWhile();
-    void parseRepeat();
-    void parseFor();
-    void parseDefinition(RplASClass* clazz, Keyword attribute);
-    RplToken* parseExpr();
-    void parseBody();
-    void parseClass();
-    void parseModule(const QString& name);
+    RplASItem* parseFunc();
+    RplASItem* parseIf();
+    RplASItem* parseWhile();
+    RplASItem* parseRepeat();
+    RplASItem* parseFor();
+    RplASItem* parseDefinition(RplASClass* clazz, Keyword attribute);
+    RplASItem* parseExpr();
+    RplASItem* parseBody();
+    RplASItem* parseMethodDefinition();
+    RplASItem* parseClass();
+    void parseImport();
+    RplASItem* parseModule(const QString& name);
     void parse();
+protected:
+    RplASArgument* parseArguments();
     RplASItem* parseOperand(int level);
     RplASItem* parseTerm(int depth);
 private:
     RplLexer m_lexer;
-    RplASTree& m_tree;
 };
 
 #endif // RPLMFPARSER_HPP
diff --git a/rplexpr/rplparser.cpp b/rplexpr/rplparser.cpp
new file mode 100644 (file)
index 0000000..ff68682
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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"
+
+
+/** @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)
+{
+}
+
+/** @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
+ * @return
+ */
+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 format    message with placeholdes like sprintf()
+ * @param varList   the variable argument list
+ */
+void RplParser::addMessage(char prefix, int location, const char* format,
+                           va_list varList){
+    char buffer[2048];
+    QString msg;
+    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());
+    int length = strlen(buffer);
+    vsnprintf(buffer + length, -length + sizeof buffer, format, varList);
+    m_messages.append(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 format    message with placeholdes like sprintf()
+ * @param ...       optional: the variable argument list
+ */
+
+void RplParser::syntaxError(int location, const char* format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    addMessage('E', location, format, ap);
+    va_end(ap);
+    throw RplSyntaxError(format);
+}
+
+/**
+ * @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
+ */
+void RplParser::error(int location, const char* format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    addMessage('E', location, format, ap);
+    va_end(ap);
+    if (++m_errors >= m_maxErrors)
+        throw RplParserStop("too many errors");
+}
+
+/**
+ * @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('W', location, format, ap);
+    va_end(ap);
+    if (++m_warnings >= m_maxWarnings)
+        throw RplParserStop("too many warnings");
+}
+
+
diff --git a/rplexpr/rplparser.hpp b/rplexpr/rplparser.hpp
new file mode 100644 (file)
index 0000000..333b2b0
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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);
+private:
+    const char* m_reason;
+};
+
+class RplParserStop : public RplSyntaxError {
+public:
+    RplParserStop(const char* reason);
+};
+
+class RplParser {
+public:
+    typedef QList<QString> MessageList;
+public:
+    RplParser(RplLexer& lexer, RplASTree& ast);
+public:
+    void syntaxError(int location, const char* format, ...);
+    void error(int location, const char* format, ...);
+    void warning(int location, const char* format, ...);
+protected:
+    void addMessage(char prefix, int location, const char* format, va_list varList);
+
+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
index 5e147ff6ac8642d14a67812e371dd3c1dc9db108..3b3b316fc2d3432ad7b80190bce9af683bc34708 100644 (file)
@@ -161,6 +161,15 @@ QString RplSourcePosition::toString() const
     return rc;
 }
 
+/**
+ * @brief Returns the line number.
+ * @return  the line number
+ */
+int RplSourcePosition::lineNo() const
+{
+    return m_lineNo;
+}
+
 /**
  * @brief Sets the line number.
  *
index 78d1cd826fb5656e5b4fdccb79529cec7c1efe49..19d3f14f9347b433503e6c1051e9b3385bf4cc8b 100644 (file)
@@ -36,7 +36,8 @@ SOURCES += \
     ../rplexpr/rplastree.cpp \
     ../rplexpr/rplasclasses.cpp \
     ../rplexpr/rplmfparser.cpp \
-    ../rplexpr/rplvm.cpp
+    ../rplexpr/rplvm.cpp \
+    ../rplexpr/rplparser.cpp
 
 HEADERS += ../rplmodules.hpp \
     ../rplcore/rplconfig.hpp \
@@ -64,7 +65,8 @@ HEADERS += ../rplmodules.hpp \
     ../rplexpr/rplastree.hpp \
     ../rplexpr/rplasclasses.hpp \
     ../rplexpr/rplmfparser.hpp \
-    ../rplexpr/rplvm.hpp
+    ../rplexpr/rplvm.hpp \
+    ../rplexpr/rplparser.hpp
 
 unix:!symbian {
     maemo5 {
index 5a635d005410b0e6711d0b956e509892e793620c..e5a188fe36027328f28e84e2e0263b1df22809fb 100644 (file)
@@ -28,6 +28,7 @@ public:
     }
 
     virtual void doIt(void) {
+        baseTest();
     }
 };
 void testRplMFParser() {
index 29e0bce3d19fa74e275fa3fd0341c5a641468f36..4ce578f88b7e5640accf4b8bc7f853b9203df230 100644 (file)
@@ -26,6 +26,7 @@ SOURCES += main.cpp \
     ../rplexpr/rplsource.cpp \
     ../rplexpr/rpllexer.cpp \
     ../rplexpr/rplastree.cpp \
+    ../rplexpr/rplparser.cpp \
     ../rplexpr/rplmfparser.cpp \
     rplexception_test.cpp \
     rplstring_test.cpp \