From 9ecb587d6799b893920dc2513e12ba1bf7a6de6f Mon Sep 17 00:00:00 2001 From: hama Date: Fri, 4 Jul 2014 00:11:27 +0200 Subject: [PATCH] day's work --- rplexpr/rplastree.cpp | 347 ++++++++++++++++++++++++++++++++++++++-- rplexpr/rplastree.hpp | 56 ++++++- rplexpr/rpllexer.cpp | 21 ++- rplexpr/rpllexer.hpp | 1 + rplexpr/rplmfparser.cpp | 52 +++++- 5 files changed, 457 insertions(+), 20 deletions(-) diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index 4972460..bef3477 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -614,7 +614,6 @@ void RplASExprStatement::execute() */ void RplASExprStatement::calc(RplASVariant& value) { - } /** @@ -730,6 +729,26 @@ RplASNode3::~RplASNode3() delete m_child3; m_child3 = NULL; } +/** + * @brief Returns the child3. + * + * @return the child 3 + */ +RplASItem* RplASNode3::child3() const +{ + return m_child3; +} + +/** + * @brief Sets the child3. + * + * @param child3 the new child3 + */ +void RplASNode3::setChild3(RplASItem* child3) +{ + m_child3 = child3; +} + /** @class RplASNode4 rplastree.hpp "rplexpr/rplastree.hpp" * @@ -757,6 +776,73 @@ RplASNode4::~RplASNode4() m_child4 = NULL; } +/** + * @brief Returns the child4. + * + * @return the child 4 + */ +RplASItem* RplASNode4::child4() const +{ + return m_child4; +} + +/** + * @brief Sets the child4. + * + * @param child4 the new child3 + */ +void RplASNode4::setChild4(RplASItem* child4) +{ + m_child4 = child4; +} + + +/** @class RplASNode5 rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements a inner node of the abstract syntax tree with 4 childs. + * + * This class is an abstract class. + */ + +/** + * @brief RplASNode5::RplASNode5 + * @param type + */ +RplASNode5::RplASNode5(RplASItemType type) : + RplASNode4(type), + m_child5(NULL) +{ +} + +/** + * @brief Destructor. + */ +RplASNode5::~RplASNode5() +{ + delete m_child5; + m_child5 = NULL; +} + +/** + * @brief Returns the child5. + * + * @return the child 5 + */ +RplASItem* RplASNode5::child5() const +{ + return m_child5; +} + +/** + * @brief Sets the child5. + * + * @param child5 the new child3 + */ +void RplASNode5::setChild5(RplASItem* child5) +{ + m_child5 = child5; +} + /** @class RplASUnaryOp rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a unary operation. @@ -909,6 +995,67 @@ void RplASCondition::dump(FILE* fp, int indent) m_child->dump(fp, indent); } +/** @class RplASIf rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements an if statement. + * + * The if statement has a condition, a then-part and an optional else-part. + * If the condition is evaluated to true, the then-part will be executed. + * Otherwise the else-part if it exists. + */ + +RplASIf::RplASIf() : + RplASNode3(AST_IF) +{ +} + +/** + * @brief Executes the statement. + * + * Meaning of the childs: + * m_child: condition + * m_child2: if-part + * m_child3: else-part + */ +void RplASIf::execute() +{ + RplASCondition* condition = dynamic_cast(m_child); + if (condition == NULL) + throw RplASException(m_child == NULL ? m_position : m_child->position(), + "if statement: not a condition"); + RplASStatement* body = NULL; + if(condition->calcAsBool()){ + body = dynamic_cast(m_child2); + if (body == NULL) + throw RplASException(m_child2 == NULL ? m_position : m_child2->position(), + "if statement: then-part is not a statement"); + } else if (m_child2 != NULL){ + body = dynamic_cast(m_child3); + if (body == NULL) + throw RplASException(m_child3->position(), + "if statement: else-part is not a statement"); + } + body->execute(); +} + +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASIf::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sIf id: %d condition: %d then: %d else: %d\n", tabs, + m_id, m_child->id(), m_child2->id(), + m_child3 == NULL ? 0 : m_child3->id()); + m_child->dump(fp, indent + 1); + m_child2->dump(fp, indent + 1); + if (m_child3 != NULL) + m_child3->dump(fp, indent + 1); +} + /** @class RplASFor rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a for statement. @@ -928,12 +1075,6 @@ RplASFor::RplASFor() : RplASStatement() { } -/** - * @brief Destructor. - */ -RplASFor::~RplASFor() -{ -} /** * @brief Executes the statement. @@ -965,6 +1106,100 @@ void RplASFor::execute() } } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASFor::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sfor id: %d condition: %d then: %d else: %d\n", tabs, + m_id, m_child->id(), m_child2->id(), + m_child3 == NULL ? 0 : m_child3->id()); + m_child->dump(fp, indent + 1); + m_child2->dump(fp, indent + 1); + if (m_child3 != NULL) + m_child3->dump(fp, indent + 1); +} + +/** @class RplASForCounted rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements a for statement. + * + * The for statement has an optional variable, an optional start value, + * an end value, an optional step and a body. + * + * The start and end value will be calculated. + * The body will be executed so many times given by the start and end value. + */ + +/** + * @brief Constructor. + */ +RplASForCounted::RplASForCounted() : + RplASNode5(AST_FOR), + RplASStatement() +{ +} + +/** + * @brief Executes the statement. + * + * Meaning of the childs: + * m_child: body + * m_child2: variable + * m_child3: start value + * m_child4: end value + * m_child5: step value + */ +void RplASForCounted::execute() +{ + RplASStatement* body = dynamic_cast(m_child); + if (body == NULL) + throw RplASException(m_child == NULL ? m_position : m_child->position(), + "forc statement: body is not a statement"); + int start = 1; + int step = 1; + int end = 0; + RplASNamedValue* var = NULL; + if (m_child2 != NULL){ + var = dynamic_cast(m_child2); + } + for(int ii = start; ii <= end; ii++){ + body->execute(); + } +} + +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASForCounted::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sforc id: %d var: %d from: %d to: %d step: %d body: %d\n", + tabs, m_id, + m_child2 == NULL ? 0 : m_child2->id(), + m_child3 == NULL ? 0 : m_child3->id(), + m_child4 == NULL ? 0 : m_child4->id(), + m_child5 == NULL ? 0 : m_child5->id(), + m_child == NULL ? 0 : m_child->id()); + if (m_child2 != NULL) + m_child2->dump(fp, indent + 1); + if (m_child3 != NULL) + m_child3->dump(fp, indent + 1); + if (m_child4 != NULL) + m_child4->dump(fp, indent + 1); + if (m_child5 != NULL) + m_child5->dump(fp, indent + 1); + if (m_child != NULL) + m_child->dump(fp, indent + 1); +} + /** @class RplASWhile rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a while statement. @@ -978,12 +1213,101 @@ RplASWhile::RplASWhile() : RplASStatement() { } + /** - * @brief Destructor. + * @brief Executes the statement. + * + * Meaning of the childs: + * m_child: body + * m_child2: condition + */ +void RplASWhile::execute() +{ + RplASStatement* body = dynamic_cast(m_child); + if (body == NULL) + throw RplASException(m_child == NULL ? m_position : m_child->position(), + "while statement: body is not a statement"); + RplASCondition* condition = dynamic_cast(m_child2); + if (condition == NULL) + throw RplASException(m_child2 == NULL ? m_position : m_child2->position(), + "for statement: not a condition"); + while(condition->calcAsBool()){ + body->execute(); + } +} + +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASWhile::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%swhile id: %d condition: %d body: %d\n", tabs, m_id, + m_child2 == NULL ? 0 : m_child2->id(), + m_child == NULL ? 0 : m_child->id()); + if (m_child2 != NULL) + m_child2->dump(fp, indent + 1); + if (m_child != NULL) + m_child->dump(fp, indent + 1); +} + +/** @class RplASRepeat rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements a while statement. + * + * The while statement has an a condition and a body. + * The body will be executed while the condition returns true. + */ + +RplASRepeat::RplASRepeat() : + RplASNode2(AST_REPEAT), + RplASStatement() +{ +} + +/** + * @brief Executes the statement. + * + * Meaning of the childs: + * m_child: body + * m_child2: condition + */ +void RplASRepeat::execute() +{ + RplASStatement* body = dynamic_cast(m_child); + if (body == NULL) + throw RplASException(m_child == NULL ? m_position : m_child->position(), + "while statement: body is not a statement"); + RplASCondition* condition = dynamic_cast(m_child2); + if (condition == NULL) + throw RplASException(m_child2 == NULL ? m_position : m_child2->position(), + "for statement: not a condition"); + do { + body->execute(); + } while(condition->calcAsBool()); +} + +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level */ -RplASWhile::~RplASWhile() +void RplASRepeat::dump(FILE* fp, int indent) { + DEFINE_TABS(indent); + fprintf(fp, "%srepeat id: %d condition: %d body: %d\n", tabs, m_id, + m_child2 == NULL ? 0 : m_child2->id(), + m_child == NULL ? 0 : m_child->id()); + if (m_child2 != NULL) + m_child2->dump(fp, indent + 1); + if (m_child != NULL) + m_child->dump(fp, indent + 1); } + /** @class RplASClass rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements the base class of a Abstract Syntax Tree class. @@ -1404,8 +1728,9 @@ void RplASMethod::dump(FILE* fp, int indent) * @brief constructor */ RplASArgument::RplASArgument() : - RplASNode2(AST_ARGUMENT), - RplASStatement() + RplASNode2(AST_ARGUMENT) { } + + diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index 7c64dcc..d8b6f9c 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -24,6 +24,7 @@ enum RplASItemType { AST_BINARY_OP, AST_METHOD_CALL, AST_WHILE, + AST_REPEAT, AST_IF, AST_CONDITION, AST_FOR, @@ -187,6 +188,10 @@ class RplASNode3 : public RplASNode2 public: RplASNode3(RplASItemType type); virtual ~RplASNode3(); +public: + RplASItem* child3() const; + void setChild3(RplASItem* child3); + protected: RplASItem* m_child3; }; @@ -196,10 +201,26 @@ class RplASNode4 : public RplASNode3 public: RplASNode4(RplASItemType type); virtual ~RplASNode4(); +public: + RplASItem* child4() const; + void setChild4(RplASItem* child4); + protected: RplASItem* m_child4; }; +class RplASNode5 : public RplASNode4 +{ +public: + RplASNode5(RplASItemType type); + virtual ~RplASNode5(); +public: + RplASItem*child5() const; + void setChild5(RplASItem* child5); +protected: + RplASItem* m_child5; +}; + class RplASNamedValue : public RplASNode1, public RplASCalculable { public: @@ -298,23 +319,52 @@ public: void dump(FILE* fp, int indent); }; +class RplASIf : public RplASNode3, public RplASStatement +{ +public: + RplASIf(); +public: + virtual void execute(); + virtual void dump(FILE* fp, int indent); +}; + class RplASFor : public RplASNode4, public RplASStatement { public: RplASFor(); - virtual ~RplASFor(); public: virtual void execute(); + virtual void dump(FILE* fp, int indent); +}; + +class RplASForCounted : public RplASNode5, public RplASStatement +{ +public: + RplASForCounted(); +public: + virtual void execute(); + virtual void dump(FILE* fp, int indent); }; class RplASWhile : public RplASNode2, public RplASStatement { public: RplASWhile(); - virtual ~RplASWhile(); +public: + virtual void execute(); + virtual void dump(FILE* fp, int indent); +}; + +class RplASRepeat : public RplASNode2, public RplASStatement +{ +public: + RplASRepeat(); +public: + virtual void execute(); + virtual void dump(FILE* fp, int indent); }; -class RplASArgument : public RplASNode2, public RplASStatement +class RplASArgument : public RplASNode2 { public: RplASArgument(); diff --git a/rplexpr/rpllexer.cpp b/rplexpr/rpllexer.cpp index a13b011..1ab955e 100644 --- a/rplexpr/rpllexer.cpp +++ b/rplexpr/rpllexer.cpp @@ -187,9 +187,10 @@ bool RplToken::isTokenType(RplTokenType expected) const /** * @brief Checks whether the instance is a given operator. * - * @param expected the token type to compare + * @param expected the expected operator + * @param alternative 0 or a second possibility * - * @return true: the instance is an operator and the expected
+ * @return true: the instance is an operator and the expected or the alternative
* false: otherwise */ bool RplToken::isOperator(int expected, int alternative) const @@ -198,6 +199,22 @@ bool RplToken::isOperator(int expected, int alternative) const || m_value.m_id == alternative); } +/** + * @brief Checks whether the instance is a given keyword. + * + * @param expected the expected keyword + * @param alternative 0 or a second possibility + * + * @return true: the instance is a keyword and the expected or the alternative
+ * false: otherwise + */ + +bool RplToken::isKeyword(int expected, int alternative) const +{ + return m_tokenType == TOKEN_KEYWORD && (m_value.m_id == expected + || m_value.m_id == alternative); +} + /** * @brief Makes all members undefined. */ diff --git a/rplexpr/rpllexer.hpp b/rplexpr/rpllexer.hpp index d11720b..20e24ab 100644 --- a/rplexpr/rpllexer.hpp +++ b/rplexpr/rpllexer.hpp @@ -52,6 +52,7 @@ public: RplTokenType tokenType() const; bool isTokenType(RplTokenType expected) const; bool isOperator(int expected, int alternative = 0) const; + bool isKeyword(int expected, int alternative = 0) const; void clear(); bool isCapitalizedId() const; protected: diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp index bf2268d..b179fa2 100644 --- a/rplexpr/rplmfparser.cpp +++ b/rplexpr/rplmfparser.cpp @@ -21,7 +21,14 @@ enum MFLocations{ L_DEFINITION_UNKNOWN_CLASS, L_DEFINITION_MISSING_ID, L_DEFINITION_NO_OP = 2010, - L_DEFINITION_NO_SEMICOLON + L_DEFINITION_NO_SEMICOLON, + L_PARSE_IF_NO_THEN, + L_PARSE_IF_NO_ELSE, + L_PARSE_IF_NO_FI, + L_PARSE_WHILE_NO_DO = 2015, + L_PARSE_WHILE_NO_OD, + L_PARSE_REPEAT_NO_UNTIL, + L_PARSE_REPEAT_NO_SEMI }; @@ -57,7 +64,23 @@ RplASItem* RplMFParser::parseFunc() */ RplASItem* RplMFParser::parseIf() { - RplASItem*rc = NULL; + RplASIf* rc = new RplASIf(); + rc->setPosition(m_lexer.currentPosition()); + + RplASItem* condition = parseExpr(); + if (! m_lexer.currentToken()->isKeyword(K_THEN)) + syntaxError(L_PARSE_IF_NO_THEN, "'then' expected"); + rc->setChild(condition); + RplASItem* body = parseBody(); + rc->setChild2(body); + if (! m_lexer.currentToken()->isKeyword(K_ELSE, K_FI)) + syntaxError(L_PARSE_IF_NO_ELSE, "'else' or 'fi' expected"); + if ( m_lexer.currentToken()->isKeyword(K_ELSE)){ + RplASItem* body = parseBody(); + rc->setChild3(body); + } + if (! m_lexer.currentToken()->isKeyword(K_FI)) + syntaxError(L_PARSE_IF_NO_FI, "'fi' expected"); return rc; } /** @@ -66,7 +89,17 @@ RplASItem* RplMFParser::parseIf() RplASItem* RplMFParser::parseWhile() { - RplASItem*rc = NULL; + RplASWhile* rc = new RplASWhile(); + rc->setPosition(m_lexer.currentPosition()); + + RplASItem* condition = parseExpr(); + if (! m_lexer.currentToken()->isKeyword(K_DO)) + syntaxError(L_PARSE_WHILE_NO_DO, "'do' expected"); + rc->setChild2(condition); + RplASItem* body = parseBody(); + rc->setChild(body); + if (! m_lexer.currentToken()->isKeyword(K_OD)) + syntaxError(L_PARSE_WHILE_NO_OD, "'od' expected"); return rc; } @@ -75,7 +108,18 @@ RplASItem* RplMFParser::parseWhile() */ RplASItem* RplMFParser::parseRepeat() { - RplASItem*rc = NULL; + RplASRepeat* rc = new RplASRepeat(); + rc->setPosition(m_lexer.currentPosition()); + + RplASItem* body = parseBody(); + rc->setChild(body); + if (! m_lexer.currentToken()->isKeyword(K_UNTIL)) + syntaxError(L_PARSE_REPEAT_NO_UNTIL, "'until' expected"); + + RplASItem* condition = parseExpr(); + if (! m_lexer.currentToken()->isOperator(O_SEMICOLON)) + syntaxError(L_PARSE_REPEAT_NO_SEMI, "';' expected"); + rc->setChild2(condition); return rc; } -- 2.39.5