]> gitweb.hamatoma.de Git - reqt/commitdiff
dayly work
authorhama <hama@siduction.net>
Fri, 25 Jul 2014 23:02:01 +0000 (01:02 +0200)
committerhama <hama@siduction.net>
Fri, 25 Jul 2014 23:02:01 +0000 (01:02 +0200)
rplexpr/rplastree.cpp
rplexpr/rplastree.hpp
rplexpr/rplmfparser.cpp
rplexpr/rplmfparser.hpp
rplexpr/rplparser.cpp
rplexpr/rplparser.hpp
test/rplmfparser/field1.txt [new file with mode: 0644]
test/rplmfparser/forIt1.txt
test/rplmfparser/methc1.txt
unittests/rplmfparser_test.cpp

index 9f25c5b12ce0f454ac43c4f9b2d5fce28aaf46cb..dffb1deb5e2ed5a1016e40d5e4dde2bad56eabaa 100644 (file)
@@ -744,6 +744,35 @@ void RplASNamedValue::dump(FILE* fp, int indent)
             positionStr(buffer, sizeof buffer));
 }
 
+/** @class RplASIndexedValue rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an indexed values (member of a list)
+ *
+ * <code>m_child</code>: the parent: a list expression
+ * <code>m_child2</code>: the index expression
+ */
+RplASIndexedValue::RplASIndexedValue() :
+    RplASNode2(AST_INDEXED_VALUE)
+{
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp        target file
+ * @param indent    nesting level
+ */
+void RplASIndexedValue::dump(FILE* fp, int indent)
+{
+    DEFINE_TABS(indent);
+    char buffer[256];
+    fprintf(fp, "%sindexedValue id: %d index: %d parent: %d %s\n", tabs,
+            m_id, m_child2->id(), m_child->id(),
+            positionStr(buffer, sizeof buffer));
+    m_child2->dump(fp, indent + 1);
+    m_child->dump(fp, indent + 1);
+}
+
 /** @class RplVarDefinition rplastree.hpp "rplexpr/rplastree.hpp"
  *
  * @brief Implements variable definition for the Abstract Syntax Tree.
@@ -1856,17 +1885,23 @@ void RplASTree::dump(const char* filename, int flags, const char* header)
  *
  * <code>m_child</code>: next statement</br>
  * <code>m_child2</code>: argument list<br>
+ * <code>m_child3</code>: parent (variable, field ...)
  */
 /**
  * @brief Constructor.
+ *
+ * @param name      name of the method/function
+ * @param parent    NULL: it is a function<br>
+ *                  otherwise: the parent (variable, field ...)
  */
-RplASMethodCall::RplASMethodCall(const QString& name) :
-    RplASNode2(AST_METHOD_CALL),
+
+RplASMethodCall::RplASMethodCall(const QString& name, RplASItem* parent) :
+    RplASNode3(AST_METHOD_CALL),
     RplASStatement(),
     m_name(name),
     m_method(NULL)
 {
-
+    m_child3 = parent;
 }
 
 
@@ -1880,13 +1915,16 @@ void RplASMethodCall::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
     char buffer[256];
-    fprintf(fp, "%scall %s Id: %d args: %d succ: %d %s\n", tabs,
+    fprintf(fp, "%scall %s Id: %d args: %d parent: %d succ: %d %s\n", tabs,
             m_name.toUtf8().constData(), m_id,
             m_child2 == NULL ? 0 : m_child2->id(),
+            m_child3 == NULL ? 0 : m_child3->id(),
             m_child == NULL ? 0 : m_child->id(),
             positionStr(buffer, sizeof buffer));
     if (m_child2 != NULL)
         m_child2->dump(fp, indent + 1);
+    if (m_child3 != NULL)
+        m_child3->dump(fp, indent + 1);
 }
 
 /**
@@ -2070,9 +2108,9 @@ void RplASArgument::dump(FILE* fp, int indent)
 
 /** @class RplASField rplastree.hpp "rplexpr/rplastree.hpp"
  *
- * @brief Implements an argument of a method for the Abstract Syntax Tree.
+ * @brief Implements an class field for the Abstract Syntax Tree.
  *
- * <code>m_child</code>: parent (variable, field, method)<br>
+ * <code>m_child</code>: parent (variable, field, method)
  */
 
 /**
@@ -2096,8 +2134,11 @@ void RplASField::dump(FILE* fp, int indent)
 {
     DEFINE_TABS(indent);
     char buffer[256];
-    fprintf(fp, "%sfield %s id: %d expr: %d succ: %s\n", tabs,
+    fprintf(fp, "%sfield %s id: %d parent: %d succ: %s\n", tabs,
             m_name.toUtf8().constData(), m_id,
-            m_child->id(), positionStr(buffer, sizeof buffer));
+            m_child == NULL ? 0 : m_child->id(),
+            positionStr(buffer, sizeof buffer));
     m_child->dump(fp, indent + 1);
 }
+
+
index 72c168f9365c687f39d6ec49be8d920f394df55e..59e20873d6a95074d9b451d02fa2b840e45b75a8 100644 (file)
@@ -18,6 +18,7 @@ enum RplASItemType {
     AST_MAP_CONSTANT,
     AST_MAP_ENTRY,
     AST_NAMED_VALUE,
+    AST_INDEXED_VALUE,
     AST_FIELD,
     AST_VAR_DEFINITION,
     AST_EXPR_STATEMENT,
@@ -306,6 +307,13 @@ protected:
     RplASClass* m_dataType;
 };
 
+class RplASIndexedValue : public RplASNode2 {
+public:
+    RplASIndexedValue();
+public:
+    void dump(FILE* fp, int indent);
+};
+
 class RplASStatement
 {
 public:
@@ -424,10 +432,10 @@ protected:
 };
 
 class RplASMethod;
-class RplASMethodCall : public RplASNode2, public RplASStatement
+class RplASMethodCall : public RplASNode3, public RplASStatement
 {
 public:
-    RplASMethodCall(const QString& name);
+    RplASMethodCall(const QString& name, RplASItem* parent);
 public:
     void dump(FILE* fp, int indent);
     virtual void execute();
index 91ad0079617b0b44df5d2edc744f010faf504890..bbdfebbb054ee498dd348566c7123a0b8a917871 100644 (file)
@@ -12,7 +12,7 @@
 
 enum MFLocations{
     L_PARSE_OPERAND_RPARENTH = 2001,
-    L_PARSE_FREE1,
+    L_PARSE_OPERAND_RPARENTH_INFO,
     L_TERM_WRONG_STRING,
     L_TERM_WRONG_NUMBER,
     L_PARSE_OPERAND_WRONG   = 2005,
@@ -42,7 +42,10 @@ enum MFLocations{
     L_PARSE_OPERAND_NOT_OPERAND = 2030,
     L_PARSE_BODY_NO_START,
     L_PARSE_OPERAND_NO_BRACKET,
-    L_PARSE_ARGS_NO_COMMA_OR_PARENT
+    L_PARSE_ARGS_NO_COMMA_OR_PARENT,
+    L_PARSE_OPERAND_NO_FIELD2,
+    L_PARSE_OPERAND_NO_BRACKET2 = 2035,
+    L_PARSE_OPERAND_NO_FIELD
 };
 
 /** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
@@ -467,6 +470,32 @@ RplASItem* RplMFParser::parseMap()
     return rc;
 }
 
+/**
+ * @brief Builds a node of a variable or a field.
+ *
+ * @param name      name of the variable/field
+ * @param position  source position
+ * @param parent    NULL: result is a variable
+ *
+ * @return          a <code>RplASNamedValue</code> or a
+ *                  <code>RplASNamedValue</code> instance
+ */
+RplASItem* RplMFParser::buildVarOrField(const QString& name,
+    const RplSourcePosition* position, RplASItem* parent)
+{
+    RplASItem* rc = NULL;
+    if (parent == NULL){
+        RplASNamedValue* var = new RplASNamedValue(name);
+        var->setPosition(position);
+        rc = var;
+    } else {
+        RplASField* field = new RplASField(name);
+        field->setPosition(position);
+        rc = field;
+        field->setChild(parent);
+    }
+    return rc;
+}
 /**
  * @brief Parses an operand.
  *
@@ -476,7 +505,7 @@ RplASItem* RplMFParser::parseMap()
  * @post    the token behind the operand is read
  * @return  the node with the operand
  */
-RplASItem* RplMFParser::parseOperand(int level)
+RplASItem* RplMFParser::parseOperand(int level, RplASItem* parent)
 {
     RplToken* token = m_lexer.nextNonSpaceToken();
     const RplSourcePosition* startPosition = m_lexer.currentPosition();
@@ -486,9 +515,23 @@ RplASItem* RplMFParser::parseOperand(int level)
     case TOKEN_OPERATOR:
     {
         Operator opId = (Operator) token->id();
+        if (parent != NULL && opId != O_LBRACKET)
+            syntaxError(L_PARSE_OPERAND_NO_FIELD,
+                    "field expected (behind a '.')");
         if (opId == O_LBRACKET){
-            rc = parseList();
-            readNext = false;
+            if (parent == NULL){
+                rc = parseList();
+                readNext = false;
+            } else {
+                RplASIndexedValue* value = new RplASIndexedValue();
+                value->setPosition(startPosition);
+                value->setChild(parent);
+                rc = value;
+                value->setChild2(parseExpr(level + 1));
+                if (! m_lexer.currentToken()->isOperator(O_RBRACKET))
+                    syntaxError(L_PARSE_OPERAND_NO_BRACKET2,
+                                "']' expected");
+            }
         } else if (opId == O_LBRACE){
             rc = parseMap();
             readNext = false;
@@ -499,8 +542,7 @@ RplASItem* RplMFParser::parseOperand(int level)
                 char buffer[256];
                 // this call never comes back (exception!)
                 syntaxError(L_PARSE_OPERAND_RPARENTH,
-                            "')' expected. '(' is at %s",
-                            startPosition->utf8(buffer, sizeof buffer));
+                            "')' expected", "(", startPosition);
             }
         } else if (IS_UNARY_OP(opId)){
             RplASUnaryOp* op = new RplASUnaryOp(token->id(), AST_PRE_UNARY_OP);
@@ -517,6 +559,9 @@ RplASItem* RplMFParser::parseOperand(int level)
     case TOKEN_NUMBER:
     case TOKEN_REAL:
     {
+        if (parent != NULL)
+            syntaxError(L_PARSE_OPERAND_NO_FIELD2,
+                    "field expected (behind a '.')");
         RplASConstant* constant = new RplASConstant();
         constant->setPosition(m_lexer.currentPosition());
         rc = constant;
@@ -541,12 +586,11 @@ RplASItem* RplMFParser::parseOperand(int level)
         token = m_lexer.nextNonSpaceToken();
         startPosition = m_lexer.currentPosition();
         if (token->tokenType() != TOKEN_OPERATOR){
-            RplASNamedValue* var = new RplASNamedValue(name);
-            rc = var;
+            rc = buildVarOrField(name, startPosition, parent);
             readNext = false;
         } else {
             if (token->id() == O_LPARENTH){
-                RplASMethodCall* call = new RplASMethodCall(name);
+                RplASMethodCall* call = new RplASMethodCall(name, parent);
                 call->setPosition(startPosition);
 
                 rc = call;
@@ -558,19 +602,17 @@ RplASItem* RplMFParser::parseOperand(int level)
                     readNext = false;
                 }
             } else {
-                RplASNamedValue* var = new RplASNamedValue(name);
-                var->setPosition(startPosition);
-                rc = var;
+                rc = buildVarOrField(name, startPosition, parent);
                 if (token->id() == O_LBRACKET){
                     RplASItem* indexExpr = parseExpr(0);
                     if (! m_lexer.currentToken()->isOperator(O_RBRACKET))
                         syntaxError(L_PARSE_OPERAND_NO_BRACKET, "']' expected");
-                    var->setChild(indexExpr);
+                    dynamic_cast<RplASNode1*>(rc)->setChild(indexExpr);
                 } else {
                     if (token->id() == O_INC || token->id() == O_DEC){
                         RplASUnaryOp* op = new RplASUnaryOp(token->id(),
                                                             AST_POST_UNARY_OP);
-                        op->setChild(var);
+                        op->setChild(rc);
                         rc = op;
                     } else {
                         readNext = false;
@@ -591,8 +633,11 @@ RplASItem* RplMFParser::parseOperand(int level)
     }
     if (readNext)
         m_lexer.nextNonSpaceToken();
-//    if (m_lexer.currentToken()->isOperator(O_DOT))
-
+    if (m_lexer.currentToken()->isOperator(O_DOT, O_LBRACKET)){
+        if (m_lexer.currentToken()->asInteger() == O_LBRACKET)
+            m_lexer.undoLastToken();
+        rc = parseOperand(level, rc);
+    }
     return rc;
 }
 
index e0637fad4054d60c543bd60760c5132d7e2249cb..3d581b24750740da982c730906889aa55f040d64 100644 (file)
@@ -87,10 +87,13 @@ public:
     RplASItem*parseMap();
 protected:
     RplASArgument* parseArguments();
-    RplASItem* parseOperand(int level);
+    RplASItem* parseOperand(int level, RplASItem* parent = NULL);
     RplASVariant* tokenToVariant(RplToken* token, bool endsWithComma,
                                  RplASNode1* parent);
     RplASVariant*createFormula(RplASNode1* parent);
+    RplASItem* buildVarOrField(const QString& name,
+                               const RplSourcePosition* position,
+                               RplASItem* parent);
 private:
     ///syntax token builder.
     /// Note: the super class contains a reference with the same name
index a3290a6f728d165b8ba50f9cec2d9e1ac01bafef..c39570cefa59cec6398e22e9ae1cd7fdb43700db 100644 (file)
@@ -88,22 +88,44 @@ RplParser::RplParser(RplLexer& lexer, RplASTree& tree) :
  *
  * @param prefix    first char in the message: 'E' (error) or 'W' (warning)
  * @param location  unique id of the error/warning message
+ * @param position  position of the error/warning
  * @param format    message with placeholdes like sprintf()
  * @param varList   the variable argument list
  */
-void RplParser::addMessage(char prefix, int location, const char* format,
-                           va_list varList){
+void RplParser::addSimpleMessage(LevelTag prefix, int location,
+                                 const RplSourcePosition* position,
+                                 const char* message){
     char buffer[2048];
     QString msg;
-    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());
-    int length = strlen(buffer);
-    vsnprintf(buffer + length, -length + sizeof buffer, format, varList);
+             position->sourceUnit()->name().toUtf8().constData(),
+             position->lineNo(), position->column());
+    int used = strlen(buffer);
+    int length = strlen(message);
+    if (length >= (int) sizeof buffer - used)
+        length = sizeof buffer - used - 1;
+    memcpy(buffer + used, message, length);
+    buffer[used + length] = '\0';
     m_messages.append(buffer);
 }
 
+/**
+ * @brief Common actions for the error/warning functions.
+ *
+ * @param prefix    first char in the message: 'E' (error) or 'W' (warning)
+ * @param location  unique id of the error/warning message
+ * @param position  position of the error/warning
+ * @param format    message with placeholdes like sprintf()
+ * @param varList   the variable argument list
+ */
+void RplParser::addMessage(LevelTag prefix, int location,
+                           const RplSourcePosition* position,
+                           const char* format, va_list varList){
+    char buffer[2048];
+    vsnprintf(buffer, sizeof buffer, format, varList);
+    addSimpleMessage(prefix, location, position, buffer);
+}
+
 /**
  * @brief Adds an error message and throws an exception.
  *
@@ -111,16 +133,42 @@ void RplParser::addMessage(char prefix, int location, const char* format,
  *
  * @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, ...)
+void RplParser::syntaxError(int location, const char* message)
 {
-    va_list ap;
-    va_start(ap, format);
-    addMessage('E', location, format, ap);
-    va_end(ap);
-    throw RplSyntaxError(format);
+    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
+    throw RplSyntaxError(message);
+}
+
+/**
+ * @brief Adds an error message and throws an exception.
+ *
+ * This method is used if a closing symbol (e.g. a ')' or 'end') is missed.
+ * The message contains a %s as an placeholder for the position of the
+ * starting symbol.
+ * The exception will be catched at a position where error recovery
+ * can take place.
+ *
+ * @param location  unique id of the error
+ * @param message   message describing the error
+ * @param symbol    starting symbol corresponding to the missed closing symbol
+ * @param position  position of the starting symbol
+ */
+
+void RplParser::syntaxError(int location, const char* message,
+                            const char* symbol,
+                            const RplSourcePosition* position)
+{
+    char buffer[256];
+    char buffer2[512];
+    snprintf(buffer2, sizeof buffer2,
+            "The starting symbol %s is located here. Missing point: %s",
+            symbol, m_lexer.currentPosition()->utf8(buffer, sizeof buffer));
+
+    addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message);
+    addSimpleMessage(LT_INFO, location + 1, position, buffer2);
+    throw RplSyntaxError(message);
 }
 
 /**
@@ -136,7 +184,7 @@ void RplParser::error(int location, const char* format, ...)
 {
     va_list ap;
     va_start(ap, format);
-    addMessage('E', location, format, ap);
+    addMessage(LT_ERROR, location, m_lexer.currentPosition(), format, ap);
     va_end(ap);
     if (++m_errors >= m_maxErrors)
         throw RplParserStop("too many errors");
@@ -155,7 +203,7 @@ void RplParser::warning(int location, const char* format, ...)
 {
     va_list ap;
     va_start(ap, format);
-    addMessage('W', location, format, ap);
+    addMessage(LT_WARNING, location, m_lexer.currentPosition(), format, ap);
     va_end(ap);
     if (++m_warnings >= m_maxWarnings)
         throw RplParserStop("too many warnings");
index e9334ac707ece9c692560cce79be339c037ed976..5b40149a6f8959153a0bb4d6266888c9d6451e1d 100644 (file)
@@ -26,16 +26,29 @@ public:
 };
 
 class RplParser {
+public:
+    enum LevelTag {
+        LT_ERROR = 'E',
+        LT_WARNING = 'W',
+        LT_INFO = 'I'
+    };
+
 public:
     typedef QList<QString> MessageList;
 public:
     RplParser(RplLexer& lexer, RplASTree& ast);
 public:
-    void syntaxError(int location, const char* format, ...);
+    void addSimpleMessage(LevelTag prefix, int location,
+                          const RplSourcePosition* pos,
+                          const char* message);
+    void addMessage(LevelTag prefix, int location,
+                    const RplSourcePosition* pos,
+                    const char* format, va_list varList);
+    void syntaxError(int location, const char* message);
+    void syntaxError(int location, const char* message, const char* symbol,
+                     const RplSourcePosition* position);
     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;
diff --git a/test/rplmfparser/field1.txt b/test/rplmfparser/field1.txt
new file mode 100644 (file)
index 0000000..b14cd76
--- /dev/null
@@ -0,0 +1,24 @@
+file.find('*.c')[0].name;
+[1,2,3].join(' ');
+3.14.trunc;
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+Expr id: 8 expr: 7 succ: 15 <test>:1:24
+       field name id: 7 parent: 5 succ: <test>:1:24
+               indexedValue id: 5 index: 6 parent: 2 <test>:1:16
+                       const id: 6 value: 0 <test>:1:17
+                       call find Id: 2 args: 4 parent: 1 succ: 0 <test>:1:9
+                               arg 1 id: 4 expr: 3 succ: 0
+                                       const id: 3 value: '*.c' <test>:1:10
+                               namedValue file id: 1 attr: 0x0 <test>:1:4
+Expr id: 15 expr: 12 succ: 18 <test>:2:12
+       call join Id: 12 args: 14 parent: 9 succ: 0 <test>:2:12
+               arg 1 id: 14 expr: 13 succ: 0
+                       const id: 13 value: ' ' <test>:2:13
+               listConst id: 9 <test>:1:26
+                       [1,2,<formula 11>]
+Expr id: 18 expr: 17 succ: 0 <test>:3:10
+       field trunc id: 17 parent: 16 succ: <test>:3:10
+               const id: 16 value: 3.140000 <test>:2:19
index 83e2e953bdae675b490efc6e3b1825b2532e144f..b32a0166338b1bad4ca6bde76f31af0847bfd47a 100644 (file)
@@ -10,7 +10,7 @@ varDef a id: 2 namedValue: 1 value: 0 succ: 4 <test>:1:4
        namedValue a id: 1 attr: 0x0 <test>:1:4
 forIt id: 4 var: 3 set: 5 body: 9 succ: 0 <test>:1:7
        namedValue x id: 3 attr: 0x0 <test>:2:4
-       namedValue a id: 5 attr: 0x0 
+       namedValue a id: 5 attr: 0x0 <test>:2:11
        Expr id: 9 expr: 7 succ: 0 <test>:3:2
                BinOp id: 7 op: += (6) left: 6 right: 8 <test>:3:2
                        namedValue a id: 6 attr: 0x0 <test>:3:2
index 0fe7a1f18fc9087123fce506cb03d8f8bcfb3f6a..bd9866ae12f6aab0be0dd949e2e6b90595204f58 100644 (file)
@@ -6,20 +6,20 @@ max(1+2*3,4**(5-4));
 == Variables:
 == Body:
 Expr id: 2 expr: 1 succ: 6 <test>:1:4
-       call rand Id: 1 args: 0 succ: 0 <test>:1:4
+       call rand Id: 1 args: 0 parent: 0 succ: 0 <test>:1:4
 Expr id: 6 expr: 3 succ: 20 <test>:2:3
-       call sin Id: 3 args: 5 succ: 0 <test>:2:3
-               Arg 1 id: 5 expr: 4 succ: 0
+       call sin Id: 3 args: 5 parent: 0 succ: 0 <test>:2:3
+               arg 1 id: 5 expr: 4 succ: 0
                        namedValue a id: 4 attr: 0x0 <test>:2:5
 Expr id: 20 expr: 7 succ: 0 <test>:3:3
-       call max Id: 7 args: 13 succ: 0 <test>:3:3
-               Arg 1 id: 13 expr: 9 succ: 19
+       call max Id: 7 args: 13 parent: 0 succ: 0 <test>:3:3
+               arg 1 id: 13 expr: 9 succ: 19
                        BinOp id: 9 op: + (26) left: 8 right: 11 <test>:3:5
                                const id: 8 value: 1 <test>:3:4
                                BinOp id: 11 op: * (30) left: 10 right: 12 <test>:3:7
                                        const id: 10 value: 2 <test>:3:6
                                        const id: 12 value: 3 <test>:3:8
-               Arg 2 id: 19 expr: 15 succ: 0
+               arg 2 id: 19 expr: 15 succ: 0
                        BinOp id: 15 op: ** (31) left: 14 right: 17 <test>:3:11
                                const id: 14 value: 4 <test>:3:10
                                BinOp id: 17 op: - (27) left: 16 right: 18 <test>:3:15
index 94d26f79c7360139b662b8fc31130aaaf8b46f6b..18abe4dc1508b2a3d375cd72036eb1381292f391 100644 (file)
@@ -138,8 +138,16 @@ public:
         parser.parse();
         checkAST("methc1.txt", __LINE__);
     }
+    void fieldTest(){
+        //setSource("a.trunc;");
+        setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;");
+        RplMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("field1.txt", __LINE__);
+    }
 
     virtual void doIt(void) {
+        fieldTest();
         methodCallTest();
         mapTest();
         forItTest();