From: hama Date: Tue, 1 Jul 2014 23:05:00 +0000 (+0200) Subject: day's work X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=c4526a29e0bee2a3108a488996cad1ab691e26ac;p=reqt day's work --- diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index 865f88f..c280e31 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -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 Attribute 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) { } /** diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index 5e9d91d..d5a265e 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -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: diff --git a/rplexpr/rpllexer.cpp b/rplexpr/rpllexer.cpp index 051451e..a1c4922 100644 --- a/rplexpr/rpllexer.cpp +++ b/rplexpr/rpllexer.cpp @@ -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
+ * 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
+ * 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
+ * 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
+ * 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; +} + diff --git a/rplexpr/rpllexer.hpp b/rplexpr/rpllexer.hpp index 5536aad..c624986 100644 --- a/rplexpr/rpllexer.hpp +++ b/rplexpr/rpllexer.hpp @@ -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); diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp index e88a2db..8306aae 100644 --- a/rplexpr/rplmfparser.cpp +++ b/rplexpr/rplmfparser.cpp @@ -11,13 +11,16 @@ #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" }* id [ = ] ";" + * Parameter: { "const" | "lazy" }* id [ = ] { "," | ")" } + * + * 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
* * @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(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(); diff --git a/rplexpr/rplmfparser.hpp b/rplexpr/rplmfparser.hpp index f17d6e2..d2fa98c 100644 --- a/rplexpr/rplmfparser.hpp +++ b/rplexpr/rplmfparser.hpp @@ -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();