]> gitweb.hamatoma.de Git - reqt/commitdiff
day's work
authorhama <hama@siduction.net>
Tue, 1 Jul 2014 23:05:00 +0000 (01:05 +0200)
committerhama <hama@siduction.net>
Tue, 1 Jul 2014 23:05:00 +0000 (01:05 +0200)
rplexpr/rplastree.cpp
rplexpr/rplastree.hpp
rplexpr/rpllexer.cpp
rplexpr/rpllexer.hpp
rplexpr/rplmfparser.cpp
rplexpr/rplmfparser.hpp

index 865f88fef9d08c8cc8e477ba127ae0e6f9f870ff..c280e31fcb109aa12b41515722cd16c6db8b9b48 100644 (file)
@@ -471,13 +471,16 @@ RplASVariant& RplASConstant::value()
 /**
  * @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(const QString& name, int attributes) :
-    RplASItem(AST_NAMED_VALUE),
+RplASNamedValue::RplASNamedValue(RplASClass* type,
+                                 const QString& name, int attributes) :
+    RplASNode1(AST_NAMED_VALUE),
     m_name(name),
-    m_attributes(attributes)
+    m_attributes(attributes),
+    m_type(type)
 {
 }
 /**
index 5e9d91d537615d3125c5b894c648db089fe9add6..d5a265e9986f4d4e715ace95b898628eb9ec1824 100644 (file)
@@ -155,30 +155,6 @@ private:
     RplASVariant m_value;
 };
 
-class RplASNamedValue : public RplASItem, public RplASCalculable
-{
-public:
-    enum Attributes {
-        A_NONE,
-        /// the value cannot be changed.
-        A_CONST         = 1<<1,
-        /// the variable/constant is found in the global namespace, not in a method
-        A_GLOBAL        = 1<<2,
-        /// the variable/constant is found in the module namespace, not in a method
-        A_MODULE_STATIC = 1<<3
-    };
-
-public:
-    RplASNamedValue(const QString& name, int attributes = A_NONE);
-    QString name() const;
-public:
-    virtual void calc(RplASVariant& value);
-    void dump(FILE* fp, int indent);
-private:
-    QString m_name;
-    int m_attributes;
-};
-
 class RplASNode1 : public RplASItem
 {
 public:
@@ -221,6 +197,35 @@ protected:
     RplASItem* m_child4;
 };
 
+class RplASNamedValue : public RplASNode1, public RplASCalculable
+{
+public:
+    enum Attributes {
+        A_NONE,
+        /// the value cannot be changed.
+        A_CONST         = 1<<1,
+        /// the variable/constant is found in the global namespace, not in a method
+        A_GLOBAL        = 1<<2,
+        /// 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
+    };
+
+public:
+    RplASNamedValue(RplASClass* type, const QString& name,
+        int attributes = A_NONE);
+public:
+    QString name() const;
+public:
+    virtual void calc(RplASVariant& value);
+    void dump(FILE* fp, int indent);
+private:
+    QString m_name;
+    int m_attributes;
+    RplASClass* m_type;
+};
+
 class RplASUnaryOp : public RplASNode1
 {
 public:
index 051451e0a4782c90e92856f2a21b08ac5c77101d..a1c492268fe65c0e8c2957649ee6a6884fa0f857 100644 (file)
@@ -169,6 +169,33 @@ RplTokenType RplToken::tokenType() const
     return m_tokenType;
 }
 
+/**
+ * @brief Checks whether the instance has a given token type.
+ *
+ * @param expected  the token type to compare
+ *
+ * @return  true: the expected type is the current<br>
+ *          false: otherwise
+ */
+bool RplToken::isTokenType(RplTokenType expected) const
+{
+    return m_tokenType == expected;
+}
+
+/**
+ * @brief Checks whether the instance is a given operator.
+ *
+ * @param expected  the token type to compare
+ *
+ * @return  true: the instance is an operator and the expected<br>
+ *          false: otherwise
+ */
+bool RplToken::isOperator(int expected, int alternative) const
+{
+    return m_tokenType == TOKEN_OPERATOR && (m_value.m_id == expected
+                                             || m_value.m_id == alternative);
+}
+
 /**
  * @brief Makes all members undefined.
  */
@@ -180,6 +207,19 @@ void RplToken::clear()
     m_value.m_integer = 0;
 }
 
+/**
+ * @brief Returns whether the token is a capitalized id
+ *
+ * @return  true: the token is an id and the first char is an upper case char<br>
+ *          false: otherwise
+ */
+bool RplToken::isCapitalizedId() const
+{
+    bool rc = m_tokenType == TOKEN_ID && m_string.at(0).isUpper()
+            && (m_string.length() == 1 || m_string.at(1).isLower());
+    return rc;
+}
+
 
 /** @class RplLexer rpllexer.hpp "rplexpr/rpllexer.hpp"
  *
@@ -305,10 +345,13 @@ RplLexer::RplLexer(RplSource* source,
     m_currentCol(0),
     m_hasMoreInput(false),
     m_stringFeatures(stringFeatures),
-    m_storageFlags(storageFlags)
+    m_storageFlags(storageFlags),
     // m_prioOfOp
+    // m_assocOfOp
+    m_opNames()
 {
     memset(m_prioOfOp, 0, sizeof m_prioOfOp);
+    memset(m_assocOfOp, 0, sizeof m_assocOfOp);
     m_currentPosition->setSourceUnit(source->currentReader()
         ->currentSourceUnit());
     memset(m_charInfo, 0, sizeof m_charInfo);
@@ -760,6 +803,16 @@ void RplLexer::scanComment()
     m_input.remove(0, length);
     m_currentCol += length;
 }
+/**
+ * @brief Returns the last read token.
+ *
+ * @return  the current token
+ */
+RplToken* RplLexer::currentToken() const
+{
+    return m_currentToken;
+}
+
 /**
  * @brief Returns the current position.
  *
@@ -964,4 +1017,19 @@ int RplLexer::prioOfOp(int op) const
     return rc;
 }
 
+/**
+ * @brief Returns whether an operator is right associative
+ * @param op    op to test
+ * @return      true: the operator is right associative<br>
+ *              false: otherwise
+ */
+bool RplLexer::isRightAssociative(int op) const
+{
+    bool rc = false;
+    if (op >= 0 && (unsigned) op < sizeof m_assocOfOp / sizeof m_assocOfOp[0]){
+        rc = m_assocOfOp[op];
+    }
+    return rc;
+}
+
 
index 5536aad9c4cf00e9ff16d44fd6609406ac1fd3d1..c624986c681cc174267b6e8e05eb5fbaace2aa41 100644 (file)
@@ -50,7 +50,10 @@ public:
     const QString& rawString() const;
     int id() const;
     RplTokenType tokenType() const;
+    bool isTokenType(RplTokenType expected) const;
+    bool isOperator(int expected, int alternative = 0) const;
     void clear();
+    bool isCapitalizedId() const;
 protected:
     RplTokenType m_tokenType;
     QString m_string;
@@ -176,6 +179,7 @@ public:
     const QByteArray& nameOfOp(int op) const;
     bool isRightAssociative(int op) const;
     RplSourcePosition* currentPosition() const;
+    RplToken* currentToken() const;
 
 private:
     void prepareOperators(const char* operators, const char* rightAssociatives);
index e88a2dbde89b86ff025d6cc8843f68c95a1ed00a..8306aae6d5e09f5014a226523c4d7f5f17eb366e 100644 (file)
 #include "rplexpr/rplexpr.hpp"
 
 enum MFLocations{
-    L_PARSE_OPERAND_RPARENTH = 2000,
+    L_PARSE_OPERAND_RPARENTH = 2001,
     L_PARSE_OPERAND_RPARENTH_FUNC,
-    L_PARSE_OPERAND_WRONG,
-    L_TERM_NO_OP,
-    L_TERM_NO_OP2,
-    L_TERM_WRONG_KEYWORD,
-    L_TERM_WRONG_ID
+    L_TERM_WRONG_STRING,
+    L_TERM_WRONG_NUMBER,
+    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
 
 };
 
@@ -87,12 +90,57 @@ RplASItem* RplMFParser::parseFor()
 /**
  * @brief Parses a variable definition.
  *
+ * Syntax:
+ * 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
  */
-RplASItem* RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute)
+RplASItem* RplMFParser::parseDefinition(Keyword attribute)
 {
-    RplASItem*rc = NULL;
+    RplASNamedValue::Attributes attr = RplASNamedValue::A_NONE;
+    RplToken* token;
+    while(attribute == K_CONST || attribute == K_LAZY){
+        switch(attribute){
+        case K_CONST:
+            attr = RplASNamedValue::A_CONST;
+            break;
+        case K_LAZY:
+            attr = 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");
+    if (! token->isCapitalizedId())
+        syntaxError(L_DEFINITION_WRONG_ID,
+                    "a class name must start with an upper case character");
+    RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString());
+    if (clazz == NULL)
+        syntaxError(L_DEFINITION_UNKNOWN_CLASS, "unknown class");
+    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);
+    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();
+        rc->setChild(value);
+        token = m_lexer.currentToken();
+    }
+    if (token->isOperator(O_SEMICOLON)){
+        syntaxError(L_DEFINITION_NO_OP, "';' expected");
+    }
     return rc;
 }
 
@@ -199,20 +247,16 @@ RplASItem* RplMFParser::parseOperand(int level)
  * second term: a + term1<br>
  *
  * @param depth     the level of the parenthesis
- * @return
+ * @return          the abstract syntax tree representing the parsed expression
  */
 RplASItem* RplMFParser::parseTerm(int depth){
     RplToken* token;
-    RplSourcePosition* start = m_lexer.currentPosition();
-    RplASItem* top = NULL;
-    RplASItem* item = NULL;
-    int lastPrio = -1;
+    RplASItem* top = parseOperand(depth);
+    int lastPrio = INT_MAX;
     bool again = true;
     do {
-        item = parseOperand(depth);
         token = m_lexer.nextNonSpaceToken();
         RplTokenType tokenType = token->tokenType();
-        int tokenId;
         switch(tokenType){
         case TOKEN_OPERATOR:
         {
@@ -220,43 +264,36 @@ RplASItem* RplMFParser::parseTerm(int depth){
                 RplASBinaryOp* op = new RplASBinaryOp();
                 int opId = token->id();
                 op->setOperator(opId);
+                op->setPosition(m_lexer.currentPosition());
+
                 int prio = m_lexer.prioOfOp(token->id());
                 if (prio < lastPrio
-                        || prio == lastPrio && m_lexer.isRightAssociative(opId)){
-                    op->setChild(item);
-                    op->setPosition(m_lexer.currentPosition());
-                    op->setChild2(parseOperand(depth));
-                } else {
-                    op->setChild(item);
-                    op->setPosition(m_lexer.currentPosition());
-                    op->setChild2(parseOperand(depth));
+                        || (prio == lastPrio
+                            && ! m_lexer.isRightAssociative(opId))){
+                    op->setChild(top);
+                    top = op;
+                } else{
+                    RplASBinaryOp* top2 = dynamic_cast<RplASBinaryOp*>(op);
+                    op->setChild(top2->child2());
+                    top2->setChild2(op);
                 }
-            } else if ( (tokenId = token->id()) == O_RPARENT
-                        || IS_OP_BEHIND_EXPR(tokenId))
+                op->setChild2(parseOperand(depth));
+            } else
                 again = false;
-            else
-                syntaxError(L_TERM_NO_OP, "Operator expected");
             break;
         }
         case TOKEN_STRING:
+            syntaxError(L_TERM_WRONG_STRING, "Operator expected, not a string");
+            break;
         case TOKEN_NUMBER:
         case TOKEN_REAL:
-            syntaxError(L_TERM_NO_OP2, "Operator expected");
+            syntaxError(L_TERM_WRONG_NUMBER, "Operator expected, not a number");
             break;
         case TOKEN_KEYWORD:
-            tokenId = token->id();
-            if (IS_KEYWORD_BEHIND_EXPR(tokenId))
-                again = false;
-            else
-                syntaxError(L_TERM_WRONG_KEYWORD, "unexpected keyword found");
-            break;
         case TOKEN_ID:
-            syntaxError(L_TERM_WRONG_ID, "unexpected id found");
-            break;
         case TOKEN_END_OF_SOURCE:
-            again = false;
-            break;
         default:
+            again = false;
             break;
         }
     } while(again);
@@ -327,12 +364,6 @@ RplASItem* RplMFParser::parseBody()
             case K_LAZY:
                 item = parseDefinition(NULL, (Keyword) token->id());
                 break;
-            case K_INT:
-                item = parseDefinition(&RplASInteger::m_instance, K_UNDEF);
-                break;
-            case K_FLOAT:
-                parseDefinition(&RplASFloat::m_instance, K_UNDEF);
-                break;
             case K_BOOL:
                 parseDefinition(&RplASBoolean::m_instance, K_UNDEF);
                 break;
@@ -342,9 +373,8 @@ RplASItem* RplMFParser::parseBody()
             break;
         case TOKEN_ID:
         {
-            RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString());
-            if (clazz != NULL){
-                 item = parseDefinition(clazz, K_UNDEF);
+            if (token->isCapitalizedId()){
+                item = parseDefinition(K_UNDEF);
             } else {
                 m_lexer.undoLastToken();
                 item = parseExpr();
index f17d6e2cd832863bc286e4db677fdab64aef9f63..d2fa98c28d9bbe54342ba0276e72e3f47ff55038 100644 (file)
@@ -44,7 +44,7 @@ public:
         O_INC, O_DEC,
         O_LPARENTH, O_RPARENT, O_LBRACKET, O_RBRACKET, O_LBRACE, O_RBRACE
     };
-#define IS_BINARY_OP(op) ((op) >= O_ASSIGN && op <= O_DOT)
+#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)
@@ -74,7 +74,7 @@ public:
     RplASItem* parseWhile();
     RplASItem* parseRepeat();
     RplASItem* parseFor();
-    RplASItem* parseDefinition(RplASClass* clazz, Keyword attribute);
+    RplASItem* parseDefinition(Keyword attribute);
     RplASItem* parseExpr();
     RplASItem* parseBody();
     RplASItem* parseMethodDefinition();