From 1030a317b4b1a5a9204843395232e953c19564d1 Mon Sep 17 00:00:00 2001 From: hama Date: Mon, 30 Jun 2014 00:43:51 +0200 Subject: [PATCH] day's work --- rplcore/rplcore.hpp | 2 + rplexpr/rplasclasses.cpp | 136 ++++++++++++++-- rplexpr/rplasclasses.hpp | 9 +- rplexpr/rplastree.cpp | 286 ++++++++++++++++++++++++++++++++- rplexpr/rplastree.hpp | 54 ++++++- rplexpr/rpllexer.cpp | 5 +- rplexpr/rplmfparser.cpp | 139 ++++++++-------- rplexpr/rplmfparser.hpp | 2 +- rplexpr/rplsource.cpp | 35 ++++ rplexpr/rplsource.hpp | 4 + unittests/rplmfparser_test.cpp | 26 ++- unittests/rplsource_test.cpp | 8 + 12 files changed, 613 insertions(+), 93 deletions(-) diff --git a/rplcore/rplcore.hpp b/rplcore/rplcore.hpp index 515e442..168232c 100644 --- a/rplcore/rplcore.hpp +++ b/rplcore/rplcore.hpp @@ -31,6 +31,8 @@ #include typedef unsigned char uint8_t; +#define RPL_UNUSED(x) (void)(x) + #include "rplmodules.hpp" #include "rplcore/rpllogger.hpp" #include "rplcore/rplexception.hpp" diff --git a/rplexpr/rplasclasses.cpp b/rplexpr/rplasclasses.cpp index 4d08180..152eba0 100644 --- a/rplexpr/rplasclasses.cpp +++ b/rplexpr/rplasclasses.cpp @@ -93,6 +93,86 @@ RplASClass*RplSymbolSpace::findClass(const QString& name) const { return NULL; } + +/** + * @brief Writes the content of the instance into a file. + * + * @param fp the target file + * @param indent nesting level: so many tabs will be used as prefix + * @param header NULL or the headline + */ +void RplSymbolSpace::dump(FILE* fp, int indent, const char* header) +{ + char tabs[32]; + memset(tabs, '\t', sizeof tabs); + tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0'; + if (header != NULL) + fprintf(fp, "%s%s\n", tabs, header); + fprintf(fp, "%s= %s (%s) parent: %s\n", tabs, m_name.toUtf8().constData(), + spaceTypeName(m_type), + m_parent == NULL ? "" : m_parent->name().toUtf8().constData()); + fprintf(fp, "%s== Classes:\n", tabs); + QList sorted; + sorted.reserve(m_classes.size()); + ClassMap::iterator it; + for (it = m_classes.begin(); it != m_classes.end(); it++){ + sorted.append(it.key()); + } + qSort(sorted.begin(), sorted.end(), qLess()); + QList::iterator it2; + for (it2 = sorted.begin(); it2 != sorted.end(); it2++){ + RplASClass* clazz = m_classes[*it2]; + clazz->dump(fp, indent + 1); + } + + fprintf(fp, "== Variables:\n"); + sorted.clear(); + sorted.reserve(m_variables.size()); + VariableMap::iterator it3; + for (it3 = m_variables.begin(); it3 != m_variables.end(); it3++){ + sorted.append(it3.key()); + } + qSort(sorted.begin(), sorted.end(), qLess()); + QList::iterator it4; + for (it4 = sorted.begin(); it4 != sorted.end(); it4++){ + RplVariable* var = m_variables[*it4]; + var->dump(fp, indent + 1); + } + fprintf(fp, "== Body:\n"); + m_body->dump(fp, indent + 1); +} + +/** + * @brief Returns the name of a space type. + * + * @param type type to inspect + * @return the name of the type + */ +const char*RplSymbolSpace::spaceTypeName(RplSymbolSpace::SymbolSpaceType type) +{ + const char* rc = NULL; + switch(type){ + case SST_UNDEF: + rc = "undef"; + break; + case SST_GLOBAL: + rc = "global"; + break; + case SST_MODULE: + rc = "module"; + break; + case SST_CLASS: + rc = "class"; + break; + case SST_METHOD: + rc = "method"; + break; + default: + rc = "?"; + break; + } + return rc; +} /** * @brief Returns the name of the symbol space. * @@ -125,7 +205,7 @@ RplASBoolean::RplASBoolean() : * @param source NULL or a source to copy * @return NULL */ -void* RplASBoolean::newValueInstance(void* source) const +void* RplASBoolean::newValueInstance(void*) const { return NULL; } @@ -137,7 +217,7 @@ void* RplASBoolean::newValueInstance(void* source) const * * @param object object to destroy */ -void RplASBoolean::destroyValueInstance(void* object) const +void RplASBoolean::destroyValueInstance(void*) const { } @@ -149,7 +229,7 @@ void RplASBoolean::destroyValueInstance(void* object) const * @param object the object to test (with type QList*) * @return false */ -bool RplASBoolean::boolValueOf(void* object) const +bool RplASBoolean::boolValueOf(void*) const { return false; } @@ -160,7 +240,7 @@ bool RplASBoolean::boolValueOf(void* object) const * @param object the object to convert * @return a string describing the object */ -QString RplASBoolean::toString(void* object, int maxLength) const +QString RplASBoolean::toString(void* object, int) const { return ((RplASVariant*) object)->asBool() ? "True" : "False"; } @@ -192,7 +272,7 @@ RplASFloat::RplASFloat(const QString& name) : * @param source NULL or a source to copy * @return NULL */ -void* RplASFloat::newValueInstance(void* source) const +void* RplASFloat::newValueInstance(void*) const { return NULL; } @@ -204,7 +284,7 @@ void* RplASFloat::newValueInstance(void* source) const * * @param object object to destroy */ -void RplASFloat::destroyValueInstance(void* object) const +void RplASFloat::destroyValueInstance(void*) const { } @@ -216,7 +296,7 @@ void RplASFloat::destroyValueInstance(void* object) const * @param object the object to test * @return false */ -bool RplASFloat::boolValueOf(void* object) const +bool RplASFloat::boolValueOf(void*) const { return false; } @@ -227,7 +307,7 @@ bool RplASFloat::boolValueOf(void* object) const * @param object the object to convert * @return a string describing the object */ -QString RplASFloat::toString(void* object, int maxLength) const +QString RplASFloat::toString(void* object, int) const { QString rc; rc.sprintf("%f", ((RplASVariant *) object)->asFloat()); @@ -256,7 +336,7 @@ RplASInteger::RplASInteger() : * @param object the object to test * @return false */ -bool RplASInteger::boolValueOf(void* object) const +bool RplASInteger::boolValueOf(void*) const { return false; } @@ -566,3 +646,41 @@ QString RplASMap::toString(void* object, int maxLength) const return rc; } + +/** @class RplVariable rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements a variable of a symbol space. + */ + +/** + * @brief Constructor. + */ +RplVariable::RplVariable(const QString& name) : + m_name(name), + m_namespace(NULL), + m_value(), + m_type(NULL) +{ + +} + +/** + * @brief Writes the content of the instance into a file. + * + * @param fp the target file + * @param indent nesting level: so many tabs will be used as prefix + * @param header NULL or the headline + */ +void RplVariable::dump(FILE* fp, int indent) +{ + char tabs[32]; + memset(tabs, '\t', sizeof tabs); + tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0'; + + QByteArray name1 = m_type == NULL ? "NoneType" : m_type->name().toUtf8(); + QByteArray name2 = m_name.toUtf8(); + QByteArray val = m_value.toString().toUtf8(); + fprintf(fp, "%s%s %s: value: %s\n", tabs, + name1.constData(), + name2.constData(), val.constData()); +} diff --git a/rplexpr/rplasclasses.hpp b/rplexpr/rplasclasses.hpp index e4d3885..9221890 100644 --- a/rplexpr/rplasclasses.hpp +++ b/rplexpr/rplasclasses.hpp @@ -13,13 +13,16 @@ class RplSymbolSpace; class RplVariable { public: - RplVariable(); + RplVariable(const QString& name); +public: + void dump(FILE* fp, int indent); + protected: QString m_name; // NULL for "simple" variables (int, float, bool) RplSymbolSpace* m_namespace; RplASVariant m_value; - RplASClass* m_class; + RplASClass* m_type; }; class RplSymbolSpace @@ -43,8 +46,10 @@ public: public: RplVariable* findVariable(const QString& name) const; RplASClass* findClass(const QString& name) const; + void dump(FILE* fp, int indent, const char* header = NULL); public: static void initGlobal(RplSymbolSpace& global); + static const char* spaceTypeName(SymbolSpaceType type); private: SymbolSpaceType m_type; QString m_name; diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index c17a38c..865f88f 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -11,6 +11,11 @@ unsigned int RplASItem::m_nextId = 1; +#define DEFINE_TABS(indent) \ + char tabs[32]; \ + memset(tabs, '\t', sizeof tabs); \ + tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0' + /** @class RplASException rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a specific exception for the Abstract Syntax Tree. @@ -383,6 +388,17 @@ void RplASItem::setPosition(const RplSourcePosition* position) m_position = position; } +/** + * @brief Returns the id of the instance. + * + * @return the id + */ +unsigned int RplASItem::id() const +{ + return m_id; +} + + /** @class RplASExpr rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements the abstract base class of value containing items. @@ -418,6 +434,19 @@ void RplASConstant::calc(RplASVariant& value) value = m_value; } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASConstant::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sConstant %d value: %s\n", tabs, m_id, + m_value.toString().toUtf8().constData()); +} + /** * @brief Returns the value of the constant. * @@ -469,6 +498,17 @@ void RplASNamedValue::calc(RplASVariant& value) { } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASNamedValue::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sNamedValue %d attr: 0x%x\n", tabs, m_id, m_attributes); +} /** @class RplASNode1 rplastree.hpp "rplexpr/rplastree.hpp" * @@ -617,6 +657,21 @@ int RplASUnaryOp::getOperator() const return m_operator; } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASUnaryOp::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sUnary %d op: %d Child: %d\n", tabs, m_id, m_operator, + m_child == NULL ? 0 : m_child->id() ); + if (m_child != NULL) + m_child->dump(fp, indent); +} + /** @class RplASStatement rplastree.hpp "rplexpr/rplastree.hpp" * @@ -640,6 +695,25 @@ RplASStatement::~RplASStatement() delete m_successor; m_successor = NULL; } +/** + * @brief Returns the next statement. + * @return the next statement of a statement list + */ +RplASItem* RplASStatement::successor() const +{ + return m_successor; +} + +/** + * @brief Sets the next statement. + * + * @param successor the successor in the statement list + */ +void RplASStatement::setSuccessor(RplASItem* successor) +{ + m_successor = successor; +} + /** @class RplASCondition rplastree.hpp "rplexpr/rplastree.hpp" @@ -694,6 +768,21 @@ bool RplASCondition::calcAsBool() return rc; } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASCondition::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sCondition %d Child: %d\n", tabs, m_id, + m_child == NULL ? 0 : m_child->id() ); + if (m_child != NULL) + m_child->dump(fp, indent); +} + /** @class RplASFor rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a for statement. @@ -795,6 +884,32 @@ const QString& RplASClass::name() const return m_name; } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASClass::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sClass %s super: %s\n", tabs, m_name.toUtf8().constData(), + m_superClass == NULL + ? "" : m_superClass->name().toUtf8().constData()); + QList sorted; + sorted.reserve(m_methods.size()); + MethodMap::iterator it; + for (it = m_methods.begin(); it != m_methods.end(); it++){ + sorted.append(it.key()); + } + qSort(sorted.begin(), sorted.end(), qLess()); + QList::iterator it2; + for (it2 = sorted.begin(); it2 != sorted.end(); it2++){ + RplASMethod* current = m_methods[*it2]; + current->dump(fp, indent + 1); + } +} + /** @class RplASTree rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a manager for all parts of an Abstract Syntax Tree. @@ -810,15 +925,34 @@ RplASTree::RplASTree() : m_global(new RplSymbolSpace(RplSymbolSpace::SST_GLOBAL, "global", NULL)), m_modules(), m_symbolSpaces(), - m_currentSpace(m_global) + m_currentSpace(NULL) { - m_symbolSpaces.append(m_global); + init(); } /** * @brief Destructor. */ RplASTree::~RplASTree() +{ + destroy(); +} + +/** + * @brief Initializes the instance. + * + * Used in the constructor and in clear. + */ +void RplASTree::init() +{ + m_symbolSpaces.append(m_global); + m_currentSpace = m_global; +} + +/** + * @brief Frees the resources of the instance. + */ +void RplASTree::destroy() { SymbolSpaceMap::iterator it; for (it = m_symbolSpaceHeap.begin(); it != m_symbolSpaceHeap.end(); it++){ @@ -921,6 +1055,49 @@ RplSymbolSpace* RplASTree::currentSpace() const return m_currentSpace; } +/** + * @brief Removes all content from the abstract syntax tree. + */ +void RplASTree::clear() +{ + destroy(); + //m_global->clear(); + m_modules.clear(); + m_symbolSpaces.clear(); + init(); +} + +/** + * @brief Writes the internals into a file. + * + * @param filename filename + * @param flags what to dump: sum of DMP_... flags + */ +void RplASTree::dump(const char* filename, int flags) +{ + FILE* fp = fopen(filename, "w"); + if (fp != NULL){ + if (flags & DMP_GLOBALS){ + m_global->dump(fp, 0, "=== Globals:"); + } + if (flags & DMP_MODULES){ + QList sorted; + sorted.reserve(m_modules.size()); + SymbolSpaceMap::iterator it; + for (it = m_modules.begin(); it != m_modules.end(); it++){ + sorted.append(it.key()); + } + qSort(sorted.begin(), sorted.end(), qLess()); + QList::iterator it2; + for (it2 = sorted.begin(); it2 != sorted.end(); it2++){ + RplSymbolSpace* space = m_modules[*it2]; + space->dump(fp, 1); + } + } + fclose(fp); + } +} + /** * @brief Constructor. */ @@ -936,6 +1113,24 @@ RplASMethodCall::~RplASMethodCall() } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASMethodCall::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sCall %d instance: %d args: %d\n", tabs, m_id, + m_child == NULL ? 0 : m_child->id(), + m_child2 == NULL ? 0 : m_child2->id()); + if (m_child != NULL) + m_child->dump(fp, indent + 1); + if (m_child2 != NULL) + m_child->dump(fp, indent + 1); +} + void RplASMethodCall::execute() { } @@ -961,7 +1156,7 @@ void RplASMethodCall::setMethod(RplASMethod* method) */ RplASArgument* RplASMethodCall::arg1() const { - return m_arg1; + return dynamic_cast(m_child2); } /** @@ -971,22 +1166,103 @@ RplASArgument* RplASMethodCall::arg1() const */ void RplASMethodCall::setArg1(RplASArgument* arg1) { - m_arg1 = arg1; + m_child2 = arg1; } - +/** @class RplASBinaryOp rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements binary operator for the Abstract Syntax Tree. + */ +/** + * @brief Constructor. + */ RplASBinaryOp::RplASBinaryOp() : RplASNode2(AST_BINARY_OP), m_operator(0) { } +/** + * @brief Returns the operator. + * + * @return the operator + */ int RplASBinaryOp::getOperator() const { return m_operator; } +/** + * @brief Sets the operator. + * + * @param op the operator + */ void RplASBinaryOp::setOperator(int op) { m_operator = op; } +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASBinaryOp::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sBinOp %d op: %d left: %d right: %d\n", tabs, m_id, m_operator, + m_child == NULL ? 0 : m_child->id(), + m_child2 == NULL ? 0 : m_child2->id()); + if (m_child != NULL) + m_child->dump(fp, indent + 1); + if (m_child2 != NULL) + m_child->dump(fp, indent + 1); +} + +/** @class RplASMethod rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements a method definition for the Abstract Syntax Tree. + * + * The special case "function" (a method without class) is included. + */ +/** + * @brief Constructor. + * + * @param name the method name + * @param type the method result type + */ +RplASMethod::RplASMethod(const QString& name, RplASClass* type) : + RplASNode2(AST_METHOD), + m_name(name), + m_type(type) +{ +} + +/** + * @brief Writes the internals of the instance into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASMethod::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + fprintf(fp, "%sMethod %d %s %s(", tabs, m_id, + m_type == NULL ? "" : m_type->name().toUtf8().constData(), + m_name.toUtf8().constData()); + fprintf(fp, ") body: %d args: %d\n", m_child == NULL ? 0 : m_child->id(), + m_child2 == NULL ? 0 : m_child2->id()); +} + +/** @class RplASArgument rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements an argument of a method for the Abstract Syntax Tree. + */ +/** + * @brief RplASArgument::RplASArgument + */ +RplASArgument::RplASArgument() : + RplASNode2(AST_ARGUMENT), + RplASStatement() +{ +} diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index f31fab1..5e9d91d 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -15,6 +15,7 @@ enum RplASItemType { AST_CONSTANT, AST_NAMED_VALUE, AST_METHOD, + AST_ARGUMENT, AST_INTRINSIC_METHOD, AST_PRE_UNARY_OP, AST_POST_UNARY_OP, @@ -113,6 +114,16 @@ public: public: const RplSourcePosition* position() const; void setPosition(const RplSourcePosition* position); + unsigned int id() const; +public: + /** + * @brief Writes the content of the instance into a file. + * + * @param fp the target file + * @param indent nesting level: so many tabs will be used as prefix + * @param header NULL or the headline + */ + virtual void dump(FILE* fp, int indent) = 0; protected: unsigned int m_id:16; RplASItemType m_type:8; @@ -138,6 +149,7 @@ public: public: virtual void calc(RplASVariant& value); public: + virtual void dump(FILE* fp, int indent); RplASVariant& value(); private: RplASVariant m_value; @@ -161,6 +173,7 @@ public: QString name() const; public: virtual void calc(RplASVariant& value); + void dump(FILE* fp, int indent); private: QString m_name; int m_attributes; @@ -214,6 +227,7 @@ public: RplASUnaryOp(int op, RplASItemType type); public: int getOperator() const; + void dump(FILE* fp, int indent); private: int m_operator; @@ -225,7 +239,7 @@ public: public: int getOperator() const; void setOperator(int op); - + void dump(FILE* fp, int indent); private: int m_operator; }; @@ -237,6 +251,9 @@ public: virtual ~RplASStatement(); public: virtual void execute() = 0; + RplASItem* successor() const; + void setSuccessor(RplASItem* successor); + private: RplASItem* m_successor; }; @@ -248,6 +265,7 @@ public: public: void calc(RplASVariant& value); bool calcAsBool(); + void dump(FILE* fp, int indent); }; class RplASFor : public RplASNode4, public RplASStatement @@ -270,7 +288,6 @@ class RplASArgument : public RplASNode2, public RplASStatement { public: RplASArgument(); - virtual ~RplASArgument(); }; class RplASMethod; @@ -280,18 +297,19 @@ public: RplASMethodCall(); virtual ~RplASMethodCall(); public: + void dump(FILE* fp, int indent); virtual void execute(); public: RplASMethod* method() const; void setMethod(RplASMethod* method); - RplASArgument* arg1() const; + RplASArgument*arg1() const; void setArg1(RplASArgument* arg1); - private: RplASMethod* m_method; - RplASArgument* m_arg1; + // body is child + // arg1 is child2 }; class RplParameter : RplASItem @@ -309,14 +327,20 @@ class RplASClass; class RplASMethod : public RplASNode2 { public: - RplASMethod(); + RplASMethod(const QString& name, RplASClass* type); public: void execute(); + void dump(FILE* fp, int indent); private: QString m_name; + RplASClass* m_type; + // body is m_child + // param1 is m_child2 }; class RplASClass { +public: + typedef QMap MethodMap; public: RplASClass(const QString& name); public: @@ -354,9 +378,10 @@ public: virtual QString toString(void *object, int maxLength = 80) const = 0; public: const QString& name() const; + virtual void dump(FILE* fp, int indent); protected: QString m_name; - QMap m_methods; + MethodMap m_methods; const RplASClass* m_superClass; }; @@ -365,6 +390,15 @@ class RplSymbolSpace; class RplASTree { public: + enum { + DMP_NONE, + DMP_GLOBALS = 1<<1, + DMP_MODULES = 1<<2, + DMP_SPACE_STACK = 1<<3, + DMP_SPACE_HEAP = 1<<4, + DMP_ALL = DMP_GLOBALS | DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP + + }; typedef QMap SymbolSpaceMap; typedef QList SymbolSpaceStack; public: @@ -379,7 +413,11 @@ public: SymbolSpaceStack& symbolSpaces(); RplSymbolSpace* currentSpace() const; RplASClass* findClass(const QString& name); - + void clear(); + void dump(const char* filename, int flags = DMP_ALL); +protected: + void init(); + void destroy(); private: // the mother of all symbol spaces. RplSymbolSpace* m_global; diff --git a/rplexpr/rpllexer.cpp b/rplexpr/rpllexer.cpp index c74795f..89c3dbf 100644 --- a/rplexpr/rpllexer.cpp +++ b/rplexpr/rpllexer.cpp @@ -873,8 +873,9 @@ void RplLexer::undoLastToken() */ RplToken*RplLexer::peekNonSpaceToken() { - nextNonSpaceToken(); + RplToken* token = nextNonSpaceToken(); undoLastToken(); + return token; } /** * @brief Returns the maximal length of a token @@ -943,7 +944,7 @@ RplSource* RplLexer::source() */ int RplLexer::prioOfOp(int op) const { - int rc = op > 0 && op < sizeof m_prioOfOp / sizeof m_prioOfOp[0] + int rc = op > 0 && (unsigned) op < sizeof m_prioOfOp / sizeof m_prioOfOp[0] ? m_prioOfOp[op] : 0; return rc; } diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp index 78b5992..2776249 100644 --- a/rplexpr/rplmfparser.cpp +++ b/rplexpr/rplmfparser.cpp @@ -201,7 +201,7 @@ RplASItem* RplMFParser::parseTerm(int depth){ RplToken* token; RplSourcePosition* start = m_lexer.currentPosition(); RplASItem* top = NULL; - RplASItem* item; + RplASItem* item = NULL; int lastPrio = -1; bool again = true; do { @@ -235,7 +235,7 @@ RplASItem* RplMFParser::parseTerm(int depth){ break; } } while(again); - + return top; } /** @@ -261,74 +261,85 @@ RplASItem* RplMFParser::parseBody() { RplToken* token = m_lexer.nextNonSpaceToken(); RplASItem* item = NULL; - switch(token->tokenType()) - { - case TOKEN_STRING: - case TOKEN_NUMBER: - case TOKEN_REAL: - case TOKEN_OPERATOR: - m_lexer.undoLastToken(); - item = parseExpr(); - break; - case TOKEN_KEYWORD: - switch (token->id()){ - case K_IF: - item = parseIf(); - break; - case K_WHILE: - item = parseWhile(); - break; - case K_REPEAT: - item = parseRepeat(); - break; - case K_FOR: - item = parseFor(); - break; - case K_CLASS: - item = parseClass(); - break; - case K_FUNCTION: - case K_GENERATOR: - item = parseMethodDefinition(); - break; - case K_IMPORT: - parseImport(); - break; - case K_CONST: - case K_LAZY: - item = parseDefinition(NULL, (Keyword) token->id()); + RplASItem* body = NULL; + RplASStatement* lastStatement = NULL; + bool again = true; + while(again) { + switch(token->tokenType()) + { + case TOKEN_STRING: + case TOKEN_NUMBER: + case TOKEN_REAL: + case TOKEN_OPERATOR: + m_lexer.undoLastToken(); + item = parseExpr(); break; - case K_INT: - item = parseDefinition(&RplASInteger::m_instance, K_UNDEF); + case TOKEN_KEYWORD: + switch (token->id()){ + case K_IF: + item = parseIf(); + break; + case K_WHILE: + item = parseWhile(); + break; + case K_REPEAT: + item = parseRepeat(); + break; + case K_FOR: + item = parseFor(); + break; + case K_CLASS: + item = parseClass(); + break; + case K_FUNCTION: + case K_GENERATOR: + item = parseMethodDefinition(); + break; + case K_IMPORT: + parseImport(); + break; + case K_CONST: + 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; + default: + break; + } break; - case K_FLOAT: - parseDefinition(&RplASFloat::m_instance, K_UNDEF); + case TOKEN_ID: + { + RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString()); + if (clazz != NULL){ + item = parseDefinition(clazz, K_UNDEF); + } else { + m_lexer.undoLastToken(); + item = parseExpr(); + } break; - case K_BOOL: - parseDefinition(&RplASBoolean::m_instance, K_UNDEF); + } + case TOKEN_END_OF_SOURCE: + again = false; break; default: break; } - break; - case TOKEN_ID: - { - RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString()); - if (clazz != NULL){ - item = parseDefinition(clazz, K_UNDEF); + if (body == NULL){ + body = item; } else { - m_lexer.undoLastToken(); - item = parseExpr(); + lastStatement->setSuccessor(item); } - break; + lastStatement = dynamic_cast(item); } - case TOKEN_END_OF_SOURCE: - break; - default: - break; - } - //@ToDo: add item to list - return NULL; + return body; } /** @@ -370,8 +381,9 @@ void RplMFParser::parseImport() RplASItem* RplMFParser::parseModule(const QString& name) { m_tree.startModule(name); - parseBody(); + RplASItem* body = parseBody(); m_tree.finishModule(name); + return body; } /** * @brief Parse the input given by the source. @@ -383,10 +395,11 @@ void RplMFParser::parse() /** * @brief Parses an argument list. + * * @return the first element of the argument list */ -RplASArgument*RplMFParser::parseArguments() +RplASArgument* RplMFParser::parseArguments() { - + return NULL; } diff --git a/rplexpr/rplmfparser.hpp b/rplexpr/rplmfparser.hpp index 3e5770a..8ebe9b3 100644 --- a/rplexpr/rplmfparser.hpp +++ b/rplexpr/rplmfparser.hpp @@ -43,7 +43,7 @@ public: O_LPARENTH, O_RPARENT, O_LBRACKET, O_RBRACKET }; #define IS_BINARY_OP(op) ((op) >= O_ASSIGN && op <= O_DOT) -#define IS_UNARY_OP(op) (op==O_PLUS || op==O_MINUS || op>=O_NOT && op<=O_DEC) +#define IS_UNARY_OP(op) (op==O_PLUS || op==O_MINUS || (op>=O_NOT && op<=O_DEC)) /// \n separates the priority classes #define MF_OPERATORS ";; ; , :\n" \ "= += -= /= *= %= **= |= &= <<= >>= >>>=\n" \ diff --git a/rplexpr/rplsource.cpp b/rplexpr/rplsource.cpp index 3b3b316..850c63c 100644 --- a/rplexpr/rplsource.cpp +++ b/rplexpr/rplsource.cpp @@ -315,6 +315,19 @@ RplSource::RplSource() : * @brief Destructor. */ RplSource::~RplSource() { + destroy(); +} + +/** + * @brief Frees the resources of the instance. + */ +void RplSource::destroy() +{ + m_sourcePositionStack.clear(); + m_sourcePositions.clear(); + m_readers.clear(); + m_sourceUnits.clear(); + m_currentReader = NULL; } /** @@ -444,6 +457,14 @@ RplReader* RplSource::currentReader() { return m_currentReader; } +/** + * @brief Resets all states in the source. + */ +void RplSource::clear() +{ + destroy(); +} + /** @class RplStringSourceUnit rplsource.hpp "rplexpr/rplsource.hpp" * * @brief Stores the state of a string based source unit. @@ -603,6 +624,20 @@ void RplStringReader::addSource(const QString& name, m_currentSourceUnit = unit; } +/** + * @brief Replaces the content of a source unit. + * + * @param name name of the source unit + * @param content new content + */ +void RplStringReader::replaceSource(const QString& name, const QString& content) +{ + if (m_units.contains(name)){ + RplStringSourceUnit* unit = dynamic_cast(m_units[name]); + unit->m_content = content; + } +} + /** @class RplFileSourceUnit rplsource.hpp "rplexpr/rplsource.hpp" * * @brief Stores the state of a file based source unit. diff --git a/rplexpr/rplsource.hpp b/rplexpr/rplsource.hpp index 1672711..e341f44 100644 --- a/rplexpr/rplsource.hpp +++ b/rplexpr/rplsource.hpp @@ -122,6 +122,9 @@ public: void pushSourceUnit(RplSourceUnit* unit); RplSourceUnit* popSourceUnit(RplReader* reader); RplReader* currentReader(); + void clear(); +protected: + void destroy(); protected: // stack of the info about the stacked (open) source units: QStack m_sourcePositionStack; @@ -163,6 +166,7 @@ public: virtual bool fillBuffer(int maxSize, QString& buffer, bool& hasMore); public: void addSource(const QString& name, const QString& content); + void replaceSource(const QString& name, const QString& content); }; class RplFileReader; diff --git a/unittests/rplmfparser_test.cpp b/unittests/rplmfparser_test.cpp index e5a188f..5d7d7cb 100644 --- a/unittests/rplmfparser_test.cpp +++ b/unittests/rplmfparser_test.cpp @@ -14,21 +14,41 @@ class TestRplMFParser : public RplTest, public RplMFParser{ private: RplSource m_source; RplASTree m_tree; + RplStringReader m_reader; public: TestRplMFParser() : RplTest("RplMFParser"), RplMFParser(m_source, m_tree), m_source(), - m_tree() - {} + m_tree(), + m_reader(m_source) + { + m_reader.addSource("", ""); + m_source.addReader(&m_reader); + } +protected: + void setSource(const char* content){ + m_tree.clear(); + m_source.clear(); + m_reader.replaceSource("", content); + } public: void baseTest(){ + setSource("2+3*4"); + RplMFParser parser(m_source, m_tree); + parser.parse(); + } + void defTest(){ + setSource("int i = 3; Str s = 'Hi; List l = [3, 'v4'];"); + RplMFParser parser(m_source, m_tree); + parser.parse(); } virtual void doIt(void) { - baseTest(); + //baseTest(); + //defTest(); } }; void testRplMFParser() { diff --git a/unittests/rplsource_test.cpp b/unittests/rplsource_test.cpp index cc323e6..9d0a6cd 100644 --- a/unittests/rplsource_test.cpp +++ b/unittests/rplsource_test.cpp @@ -78,6 +78,14 @@ protected: checkE(0, unit->lineNo()); checkOne(6, reader); checkOne(100, reader); + reader.replaceSource("source2", "content2"); + + unit = reader.openSourceUnit("source2"); + QString buffer; + bool hasMore; + checkT(reader.nextLine(50, buffer, hasMore)); + checkE("content2", buffer); + checkF(hasMore); } public: -- 2.39.5