]> gitweb.hamatoma.de Git - reqt/commitdiff
dayly work
authorhama <hama@siduction.net>
Sat, 26 Jul 2014 11:13:58 +0000 (13:13 +0200)
committerhama <hama@siduction.net>
Sat, 26 Jul 2014 11:13:58 +0000 (13:13 +0200)
rplexpr/rplastree.cpp
rplexpr/rplastree.hpp
rplexpr/rplmfparser.cpp
rplexpr/rplmfparser.hpp
rplexpr/rplparser.cpp
test/rplmfparser/defTest.txt
test/rplmfparser/meth1.txt [new file with mode: 0644]
test/rplmfparser/meth2.txt [new file with mode: 0644]
unittests/rplmfparser_test.cpp

index dffb1deb5e2ed5a1016e40d5e4dde2bad56eabaa..2df3291124b2381cbbc7ebc8123fc673a9228ddc 100644 (file)
@@ -2026,6 +2026,9 @@ void RplASBinaryOp::dump(FILE* fp, int indent)
  * @brief Implements a method definition for the Abstract Syntax Tree.
  *
  * The special case "function" (a method without class) is included.
+ *
+ * <code>m_child</code>: body</br>
+ * <code>m_child2</code>: parameter list (or NULL)
  */
 /**
  * @brief Constructor.
@@ -2033,10 +2036,11 @@ void RplASBinaryOp::dump(FILE* fp, int indent)
  * @param name      the method name
  * @param type      the method result type
  */
-RplASMethod::RplASMethod(const QString& name, RplASClass* type) :
+RplASMethod::RplASMethod(const QString& name) :
     RplASNode2(AST_METHOD),
     m_name(name),
-    m_nodeType(type)
+    m_resultType(NULL),
+    m_parent(NULL)
 {
 }
 
@@ -2050,13 +2054,37 @@ 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(),
+    fprintf(fp, "%sMethod %s %s(", tabs,
+            m_resultType == NULL ? "<NoneType>" : m_resultType->name().toUtf8().constData(),
             m_name.toUtf8().constData());
-    fprintf(fp, ") body: %d args: %d %s\n", m_child == NULL ? 0 : m_child->id(),
+    fprintf(fp, ") id: %d parent: %d args: %d body: %d %s\n", m_id,
+            m_parent == NULL ? 0 : m_parent->id(),
             m_child2 == NULL ? 0 : m_child2->id(),
+            m_child->id(),
             positionStr(buffer, sizeof buffer));
+    if (m_child2 != NULL)
+        m_child2->dump(fp, indent + 1);
+    m_child->dump(fp, indent + 1);
+}
+/**
+ * @brief Returns the parent of the method: a class or a method.
+ * @return  NULL: this is a function, not a method<br>
+ *          otherwise: the parent: a class or a method/func
+ */
+RplASItem* RplASMethod::parent() const
+{
+    return m_parent;
 }
+/**
+ * @brief Sets the parent of the method.
+ *
+ * @param parent    the parent: NULL or a class or a method
+ */
+void RplASMethod::setParent(RplASItem* parent)
+{
+    m_parent = parent;
+}
+
 
 /** @class RplASArgument rplastree.hpp "rplexpr/rplastree.hpp"
  *
index 59e20873d6a95074d9b451d02fa2b840e45b75a8..fbb8cc5f5b8baa260b2f32ec341e0df59ebce09e 100644 (file)
@@ -289,7 +289,9 @@ public:
         /// the variable/constant is found in the module namespace, not in a method
         A_MODULE_STATIC = 1<<3,
         /// the evaluation should be lazy
-        A_LAZY          = 1<<4
+        A_LAZY          = 1<<4,
+        /// parameter of a method
+        A_PARAM         = 1<<5
     };
 
 public:
@@ -475,15 +477,17 @@ class RplASClass;
 class RplASMethod : public RplASNode2
 {
 public:
-    RplASMethod(const QString& name, RplASClass* type);
+    RplASMethod(const QString& name);
 public:
     void execute();
     void dump(FILE* fp, int indent);
+    RplASItem* parent() const;
+    void setParent(RplASItem* parent);
+
 private:
     QString m_name;
-    RplASClass* m_nodeType;
-    // body is m_child
-    // param1 is m_child2
+    RplASClass* m_resultType;
+    RplASItem* m_parent;
 };
 
 class RplASClass {
index bbdfebbb054ee498dd348566c7123a0b8a917871..e15e695e5ceba15a1851b0deae0fcd919d130881 100644 (file)
@@ -45,7 +45,17 @@ enum MFLocations{
     L_PARSE_ARGS_NO_COMMA_OR_PARENT,
     L_PARSE_OPERAND_NO_FIELD2,
     L_PARSE_OPERAND_NO_BRACKET2 = 2035,
-    L_PARSE_OPERAND_NO_FIELD
+    L_PARSE_OPERAND_NO_FIELD,
+    L_PARSE_METH_NO_CLASS,
+    L_PARSE_METH_NO_CLASS2,
+    L_PARSE_METH_NO_NAME,
+    L_PARSE_METH_NO_NAME2   = 2040,
+    L_PARSE_METH_NO_LPARENTH,
+    L_PARSE_METH_NO_COLON,
+    L_PARSE_PARAMLIST_NO_PARENTH,
+    L_PARSE_PARAMLIST_NO_PARENTH2,
+    L_PARSE_METH_NO_END     = 2045,
+    L_PARSE_METH_NO_END2
 };
 
 /** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
@@ -67,14 +77,6 @@ RplMFParser::RplMFParser(RplSource& source, RplASTree& abstractSyntaxTree) :
 {
 }
 
-/**
- * @brief Parses a function or a generator.
- */
-RplASItem* RplMFParser::parseFunc()
-{
-   RplASItem*rc = NULL;
-   return rc;
-}
 /**
  * @brief Parses an if statement.
  */
@@ -199,32 +201,29 @@ RplASItem* RplMFParser::parseFor()
  * @brief Parses a variable definition.
  *
  * Syntax:
- * Variable: { "const" | "lazy" }* <type> id [ = <expr> ] ";"
+ * Variable: { "const" | "lazy" }* <type> id [ = <expr> ] [ ";" ]
  * Parameter: { "const" | "lazy" }* <type> id [ = <expr> ] { "," | ")" }
  *
- * AST: RplASNamedValue
- *
- * @param clazz     NULL or the type of the variable
- * @param attribute 0 or attribute of the variable: K_CONST or K_LAZY
+ * @pre             first token of the definition is read
+ * @post            token behind the definition is read: ';', ',', ')'
+ * @param attribute attribute of the variable: A_PARAM...
  */
-RplASItem* RplMFParser::parseVarDefinition(Keyword attribute)
+RplASItem* RplMFParser::parseVarDefinition(RplASNamedValue::Attributes attribute)
 {
-    RplASNamedValue::Attributes attr = RplASNamedValue::A_NONE;
+    int attributes = attribute;
     RplToken* token = m_lexer.currentToken();
-    while(attribute == K_CONST || attribute == K_LAZY){
-        switch(attribute){
+    while(token->isKeyword(K_CONST, K_LAZY)){
+        switch(token->id()){
         case K_CONST:
-            attr = RplASNamedValue::A_CONST;
+            attributes += RplASNamedValue::A_CONST;
             break;
         case K_LAZY:
-            attr = RplASNamedValue::A_LAZY;
+            attributes += RplASNamedValue::A_LAZY;
             break;
         default:
             break;
         }
         token = m_lexer.nextNonSpaceToken();
-        attribute = token->isTokenType(TOKEN_KEYWORD)
-                ? (Keyword) token->id() : K_UNDEF;
     }
     if (! token->isTokenType(TOKEN_ID))
         syntaxError(L_DEFINITION_NO_ID, "class name expected, but no id found");
@@ -238,23 +237,18 @@ RplASItem* RplMFParser::parseVarDefinition(Keyword attribute)
     if (! token->isTokenType(TOKEN_ID))
         syntaxError(L_DEFINITION_MISSING_ID, "variable name expected");
     // freed in the destructor of the nodes:
-    RplASNamedValue* namedValue = new RplASNamedValue(clazz, token->toString(), attr);
+    RplASNamedValue* namedValue = new RplASNamedValue(clazz, token->toString(),
+                                                      attributes);
     namedValue->setPosition(m_lexer.currentPosition());
     RplASVarDefinition* rc = new RplASVarDefinition();
     rc->setPosition(m_lexer.currentPosition());
     rc->setChild2(namedValue);
     token = m_lexer.nextNonSpaceToken();
-    if (! token->isOperator(O_ASSIGN, O_SEMICOLON))
-        syntaxError(L_DEFINITION_NO_OP, "'=' or ';' expected");
     if (token->id() == O_ASSIGN){
         RplASItem* value = parseExpr(0);
         rc->setChild3(value);
         token = m_lexer.currentToken();
     }
-    if (! token->isOperator(O_SEMICOLON)){
-        syntaxError(L_DEFINITION_NO_SEMICOLON, "';' expected");
-    }
-    m_lexer.nextNonSpaceToken();
     return rc;
 }
 
@@ -539,7 +533,6 @@ RplASItem* RplMFParser::parseOperand(int level, RplASItem* parent)
             rc = parseExpr(level + 1);
             token = m_lexer.currentToken();
             if(! token->isOperator(O_RPARENT)){
-                char buffer[256];
                 // this call never comes back (exception!)
                 syntaxError(L_PARSE_OPERAND_RPARENTH,
                             "')' expected", "(", startPosition);
@@ -736,6 +729,11 @@ RplASItem* RplMFParser::parseExprStatement(bool eatSemicolon)
     return statement;
 }
 
+RplASItem* RplMFParser::parseLocalVar(){
+    RplASItem* rc = parseVarDefinition(RplASNamedValue::A_NONE);
+    return rc;
+}
+
 /**
  * @brief Parses the body.
  *
@@ -798,14 +796,14 @@ RplASItem* RplMFParser::parseBody(Keyword keywordStop, Keyword keywordStop2,
                     break;
                 case K_FUNCTION:
                 case K_GENERATOR:
-                    item = parseMethodDefinition();
+                    item = parseMethodDefinition(NULL);
                     break;
                 case K_IMPORT:
                     parseImport();
                     break;
                 case K_CONST:
                 case K_LAZY:
-                    item = parseVarDefinition((Keyword) token->id());
+                    item = parseLocalVar();
                     break;
                 default:
                     if (token->isKeyword(keywordStop, keywordStop2))
@@ -816,7 +814,7 @@ RplASItem* RplMFParser::parseBody(Keyword keywordStop, Keyword keywordStop2,
             case TOKEN_ID:
             {
                 if (token->isCapitalizedId()){
-                    item = parseVarDefinition(K_UNDEF);
+                    item = parseLocalVar();
                 } else {
                     m_lexer.undoLastToken();
                     item = parseExprStatement();
@@ -876,13 +874,84 @@ RplASItem* RplMFParser::parseBody(Keyword keywordStop, Keyword keywordStop2,
     return body;
 }
 
+/**
+ * @brief Parses a parameter list of a method/function.
+ *
+ * @pre     token behind '(' is read
+ * @post    token behind ')' is read
+ * @return
+ */
+RplASExprStatement* RplMFParser::parseParameterList(){
+    RplASExprStatement* rc = NULL;
+    RplASExprStatement* last = NULL;
+    const RplSourcePosition* startPos = m_lexer.currentPosition();
+    RplASItem* definition;
+    do {
+        definition = parseVarDefinition(RplASNamedValue::A_PARAM);
+        RplASExprStatement *current = new RplASExprStatement();
+        current->setChild2(definition);
+        if (rc == NULL){
+            rc = current;
+        } else {
+            current->setChild(last);
+            last->setChild(current);
+        }
+        last = current;
+    } while(m_lexer.currentToken()->isOperator(O_COMMA));
+    if (! m_lexer.currentToken()->isOperator(O_RPARENT))
+        syntaxError(L_PARSE_PARAMLIST_NO_PARENTH, ") expected", ")", startPos);
+    m_lexer.nextNonSpaceToken();
+    return rc;
+}
+
 /**
  * @brief Parses a class definition.
+ *
+ * @pre     token "func" is read
+ * @post    token behind "endf" is read
  * @return  the node in an abstract syntax tree
  */
-RplASItem*RplMFParser::parseMethodDefinition()
+RplASMethod*RplMFParser::parseMethodDefinition(RplASItem* parent)
 {
-    RplASItem* rc = NULL;
+    RplASMethod* rc = NULL;
+    const RplSourcePosition* startPos = m_lexer.currentPosition();
+    RplToken* token = m_lexer.nextNonSpaceToken();
+    if (! token->isTokenType(TOKEN_ID))
+        syntaxError(L_PARSE_METH_NO_CLASS, "type name expected");
+    QString type = token->toString();
+    if (! type.at(0).isUpper())
+        syntaxError(L_PARSE_METH_NO_CLASS2,
+                    "type name expected (must start with an upper case character)");
+    token = m_lexer.nextNonSpaceToken();
+    if (! token->isTokenType(TOKEN_ID))
+        syntaxError(L_PARSE_METH_NO_NAME, "method name expected");
+    QString name = token->toString();
+    if (! type.at(0).isUpper())
+        syntaxError(L_PARSE_METH_NO_CLASS2,
+                    "method name expected (must start with an lower case character)");
+    token = m_lexer.nextNonSpaceToken();
+    if (! token->isOperator(O_LPARENTH, O_COLON))
+        syntaxError(L_PARSE_METH_NO_LPARENTH, "'(' or ':' expected");
+    RplASExprStatement* parameterList;
+    if (token->isOperator(O_LPARENTH)){
+      token = m_lexer.nextNonSpaceToken();
+      if (token->isOperator(O_RPARENT)){
+          token = m_lexer.nextNonSpaceToken();
+      } else {
+          parameterList = parseParameterList();
+      }
+    }
+    if (! token->isOperator(O_COLON))
+        syntaxError(L_PARSE_METH_NO_COLON, "':' expected");
+    rc = new RplASMethod(name);
+    rc->setParent(parent);
+    rc->setPosition(startPos);
+    rc->setChild2(parameterList);
+    rc->setChild(parseBody(K_ENDF));
+    if (! m_lexer.currentToken()->isKeyword(K_ENDF))
+        syntaxError(L_PARSE_METH_NO_END, "end of function not found", "endf",
+                    startPos);
+    m_lexer.nextNonSpaceToken();
     return rc;
 }
 
index 3d581b24750740da982c730906889aa55f040d64..dcee6ec6847efb71fda9d0bd4aa13159200f7b94 100644 (file)
@@ -46,8 +46,7 @@ public:
     };
 #define IS_BINARY_OP(op) (Operator(op) >= O_ASSIGN && Operator(op) <= O_DOT)
 #define IS_UNARY_OP(op) (op==O_PLUS || op==O_MINUS || (op>=O_NOT && op<=O_DEC))
-#define IS_OP_BEHIND_EXPR(o) (o==O_RBRACKET||o==O_RBRACE||o==O_SEMICOLON \
-    ||o==O_COMMA||o==O_SEMI_SEMICOLON||o==O_QUESTION)
+
 /// \n separates the priority classes
 #define MF_OPERATORS ";; ; , :\n" \
     "= += -= /= *= %= **= |= &= <<= >>= >>>=\n" \
@@ -68,16 +67,15 @@ public:
 public:
     RplMFParser(RplSource& source, RplASTree& ast);
 public:
-    RplASItem* parseFunc();
     RplASItem* parseIf();
     RplASItem* parseWhile();
     RplASItem* parseRepeat();
     RplASItem* parseFor();
-    RplASItem* parseVarDefinition(Keyword attribute);
+    RplASItem* parseVarDefinition(RplASNamedValue::Attributes attribute);
     RplASItem* parseExpr(int depth);
     RplASItem* parseBody(Keyword keywordStop, Keyword keywordStop2 = K_UNDEF,
                          Operator opStop = O_UNDEF, Operator opStop2 = O_UNDEF);
-    RplASItem* parseMethodDefinition();
+    RplASMethod*parseMethodDefinition(RplASItem* parent);
     RplASItem* parseClass();
     void parseImport();
     RplASItem* parseModule(const QString& name);
@@ -94,6 +92,8 @@ protected:
     RplASItem* buildVarOrField(const QString& name,
                                const RplSourcePosition* position,
                                RplASItem* parent);
+    RplASExprStatement*parseParameterList();
+    RplASItem* parseLocalVar();
 private:
     ///syntax token builder.
     /// Note: the super class contains a reference with the same name
index c39570cefa59cec6398e22e9ae1cd7fdb43700db..bc9bcd68119375d3f86c03acd1ef09841c9e01fc 100644 (file)
@@ -53,7 +53,6 @@ const char* RplSyntaxError::reason() const
 /**
  * @brief Constructor.
  * @param reason        the reason of the exception
- * @return
  */
 RplParserStop::RplParserStop(const char* reason) :
     RplSyntaxError(reason)
index b76645298522196929a2eddef1e68d8bd7879caf..8d941fa75829f53b4d0e4032d3350649ad10416d 100644 (file)
@@ -7,7 +7,7 @@ varDef i id: 2 namedValue: 1 value: 3 succ: 5 <test>:1:4
        namedValue i id: 1 attr: 0x0 <test>:1:4
        const id: 3 value: 3 <test>:1:8
 varDef s id: 5 namedValue: 4 value: 6 succ: 8 <test>:1:26
-       namedValue s id: 4 attr: 0x10 <test>:1:26
+       namedValue s id: 4 attr: 0x12 <test>:1:26
        const id: 6 value: 'Hi' <test>:1:30
 varDef l id: 8 namedValue: 7 value: 0 succ: 0 <test>:1:47
        namedValue l id: 7 attr: 0x2 <test>:1:47
diff --git a/test/rplmfparser/meth1.txt b/test/rplmfparser/meth1.txt
new file mode 100644 (file)
index 0000000..70435a3
--- /dev/null
@@ -0,0 +1,7 @@
+func Float pi: 3.1415; endf func Str delim(): '/' endf;
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+Method 1 <NoneType> pi() body: 4 args: 36816 <test>:0:0
+Method 4 <NoneType> delim() body: 0 args: 36816 <test>:1:28
diff --git a/test/rplmfparser/meth2.txt b/test/rplmfparser/meth2.txt
new file mode 100644 (file)
index 0000000..ef65275
--- /dev/null
@@ -0,0 +1,8 @@
+func Int fac(const Int n):
+Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi
+rc endf
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+Method 4 <NoneType> fac() body: 0 args: 3 <test>:0:55
index 18abe4dc1508b2a3d375cd72036eb1381292f391..8b2424d839edf492171d49093997fb8d66f572bd 100644 (file)
@@ -139,14 +139,25 @@ public:
         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__);
     }
 
+    void methodTest(){
+        setSource("func Float pi: 3.1415; endf func Str delim(): '/' endf;");
+        RplMFParser parser(m_source, m_tree);
+        parser.parse();
+        checkAST("meth1.txt", __LINE__);
+        setSource("func Int fac(const Int n):\n"
+                  "Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi\n"
+                  "rc endf");
+        parser.parse();
+        checkAST("meth2.txt", __LINE__);
+    }
     virtual void doIt(void) {
+        methodTest();
         fieldTest();
         methodCallTest();
         mapTest();