From: hama Date: Fri, 15 Aug 2014 22:34:53 +0000 (+0200) Subject: dayly work X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=f608d91613605cd718547bedbb3df3c4fca49fa8;p=reqt dayly work --- diff --git a/README.md b/README.md index f1c2568..f879c27 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ +doc: +* rpldoc.zip contains a full source code documentation generated by Doxygen usage: * copy (or link) the wanted source directories (e.g. rplcore+rplnet) into your project. -* insert the main include files (e.g. rplcore/rplcore.hpp) into your source +* each of the sublibraries rplcore, rplmath, rplexpr... has a main include file, e.g. rplcore/rplcore.hpp +* include this main include file into your source + diff --git a/rplcore/rplbytestorage.cpp b/rplcore/rplbytestorage.cpp index 4aca921..df1600b 100644 --- a/rplcore/rplbytestorage.cpp +++ b/rplcore/rplbytestorage.cpp @@ -12,7 +12,7 @@ */ /** @file rplcore/rplbytestorage.hpp * - * @brief Definitions for a a very efficient storage for bytes and C strings. + * @brief Definitions for a very efficient storage for bytes and C strings. */ #include "rplcore/rplcore.hpp" @@ -114,7 +114,7 @@ const char* RplByteStorage::allocateChars(const char* source, int size) /** * @brief Duplicates a string into a new allocated block. * - * The unicode string will be converted into a UTF-8 string. + * The unicode string will be converted into an UTF-8 string. * * @param source the source string * @return a copy of the source string. The copy ends always with '\0' diff --git a/rplcore/rpllogger.cpp b/rplcore/rpllogger.cpp index b998d68..f8ac50d 100644 --- a/rplcore/rpllogger.cpp +++ b/rplcore/rpllogger.cpp @@ -49,7 +49,7 @@ void RplLogger::destroyGlobalLogger() { * * @brief Puts the logging info to a medium (e.g. a file). * - * This is a abstract base class. + * This is an abstract base class. */ /** @@ -581,7 +581,7 @@ void RplFileAppender::log(RplLoggerLevel level, int location, /** @class RplMemoryAppender rpllogger.hpp "rplcore/rpllogger.hpp" * - * @brief Puts the logging info to a internal buffer. + * @brief Puts the logging info to an internal buffer. * * This line list can be required: getLines(). */ diff --git a/rplcore/rplqstring.cpp b/rplcore/rplqstring.cpp index b0d64af..2cd8995 100644 --- a/rplcore/rplqstring.cpp +++ b/rplcore/rplqstring.cpp @@ -161,7 +161,7 @@ int RplQString::lengthOfReal(const QString& text, int start, qreal* pValue) } /** - * @brief Converts a QString into a utf-8 string + * @brief Converts a QString into an utf-8 string * * The expression qstring.toUtf8().constData() is not allowed * in a variable argument list like sprintf. This is a thread save workaround. diff --git a/rplcore/rpltest.cpp b/rplcore/rpltest.cpp index 3fd6a3e..249efa6 100644 --- a/rplcore/rpltest.cpp +++ b/rplcore/rpltest.cpp @@ -17,7 +17,7 @@ /** @class RplTest rpltest.hpp "rplcore/repltest" * - * @brief Implements a unit test base class similar JUnit for java. + * @brief Implements an unit test base class similar JUnit for java. * * Example for usage: * @@ -434,7 +434,7 @@ bool RplTest::logContains(const char* pattern) * @param node NULL or the node (name without path) * @param parent NULL or a node of the parent * @param withSeparator true: the result ends with slash/backslash - * @return the name of a existing directory + * @return the name of an existing directory */ QByteArray RplTest::getTempDir(const char* node, const char* parent, bool withSeparator) { diff --git a/rplcore/rplwriter.cpp b/rplcore/rplwriter.cpp index de35350..4ff58d1 100644 --- a/rplcore/rplwriter.cpp +++ b/rplcore/rplwriter.cpp @@ -15,7 +15,7 @@ /** @file rplcore/rplwriter.hpp * * @brief Definitions for a writer to an output media. - + */ #include "rplcore/rplcore.hpp" const char* RplWriter::m_tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; @@ -68,12 +68,10 @@ void RplWriter::indent(int indent) */ void RplWriter::format(const char* format, ...) { - char buffer[64000]; va_list ap; va_start(ap, format); - vsnprintf(buffer, sizeof buffer, format, ap); + write(ap, format); va_end(ap); - write(buffer); } /** * @brief Formats a line and write it to the output medium. @@ -91,6 +89,19 @@ void RplWriter::formatLine(const char* format, ...) writeLine(buffer); } +/** + * @brief Formats a message and writes it to the output medium. + * + * @param ap variable argument list (like in vsprintf) + * @param format format string with placeholders + */ +void RplWriter::write(va_list ap, const char* format) +{ + char buffer[64000]; + vsnprintf(buffer, sizeof buffer, format, ap); + write(buffer); +} + /** * @brief Writes a line with indention to the output medium. * @@ -130,12 +141,15 @@ void RplWriter::formatIndented(int indent, const char* format, ...) /** * @brief Constructor. * - * @param filename the file's name - * @param mode write mode, "w" for write or "a" for append - * @param eoln line end: "\n" or "\r\n" + * @param filename the file's name + * @param mode write mode, "w" for write or "a" for append + * @param additionalStream if not NULL the content will be written to this + * stream too. Normal usage: stdout or + * stderr + * @param eoln line end: "\n" or "\r\n" */ RplFileWriter::RplFileWriter(const char* filename, const char* mode, - const char* eoln) : + FILE* additionalStream, const char* eoln) : m_fp(fopen(filename, mode)), m_name(filename), m_eoln(eoln) @@ -148,9 +162,10 @@ RplFileWriter::RplFileWriter(const char* filename, const char* mode, */ void RplFileWriter::write(const char* message) { - if (m_fp != NULL){ + if (m_fp != NULL) fputs(message, m_fp); - } + if (m_additionalStream != NULL) + fputs(message, m_additionalStream); } /** @@ -164,6 +179,11 @@ void RplFileWriter::writeLine(const char* line) fputs(line, m_fp); fputs(m_eoln, m_fp); } + if (m_additionalStream != NULL){ + if (line != NULL) + fputs(line, m_additionalStream); + fputc('\n', m_additionalStream); + } } /** @@ -175,4 +195,5 @@ void RplFileWriter::close() fclose(m_fp); m_fp = NULL; } + m_additionalStream = NULL; } diff --git a/rplcore/rplwriter.hpp b/rplcore/rplwriter.hpp index d9d5772..7b661e3 100644 --- a/rplcore/rplwriter.hpp +++ b/rplcore/rplwriter.hpp @@ -32,6 +32,7 @@ public: void indent(int indent); void format(const char* format, ...); void formatLine(const char* format, ...); + void write(va_list ap, const char* format); void writeIndented(int indent, const char* line); void formatIndented(int indent, const char* format, ...); protected: @@ -43,7 +44,7 @@ class RplFileWriter : public RplWriter { public: RplFileWriter(const char* filename, const char* mode = "w", - const char* eoln = "\n"); + FILE* additionalStream = NULL, const char* eoln = "\n"); public: virtual void write(const char* line); virtual void writeLine(const char* line = NULL); @@ -52,6 +53,7 @@ protected: FILE* m_fp; QByteArray m_name; QByteArray m_eoln; + FILE* m_additionalStream; }; #endif // RPLWRITER_HPP diff --git a/rpldoc.zip b/rpldoc.zip new file mode 100644 index 0000000..020aa68 Binary files /dev/null and b/rpldoc.zip differ diff --git a/rplexpr/rplasclasses.cpp b/rplexpr/rplasclasses.cpp index 46b3d07..1ecd6a0 100644 --- a/rplexpr/rplasclasses.cpp +++ b/rplexpr/rplasclasses.cpp @@ -288,7 +288,7 @@ RplSymbolSpace* RplSymbolSpace::parent() const } /** - * @brief Returns the body (a abstract syntax tree) of the symbol space. + * @brief Returns the body (an abstract syntax tree) of the symbol space. * * @return NULL: no body available
* othewise: the body of the instance @@ -299,7 +299,7 @@ RplASItem* RplSymbolSpace::body() const } /** - * @brief Sets the body (a abstract syntax tree) of the symbol space. + * @brief Sets the body (an abstract syntax tree) of the symbol space. * * @param body the new body */ @@ -456,7 +456,7 @@ QString RplASBoolean::toString(void* object, int) const * * @brief Implements the class of a Boolean. * - * A Boolean is a one of the values true and false. + * A Boolean is one of the values true and false. */ /** * @brief Constructor. @@ -877,7 +877,7 @@ RplVariable::RplVariable(const QString& name) : } /** - * @brief Writes the content of the instance into a output media. + * @brief Writes the content of the instance into an output media. * * @param writer writes to output * @param indent nesting level: so many tabs will be used as prefix @@ -1014,7 +1014,7 @@ QString RplASFormula::toString(void* object, int) const /** @class RplASUserClass rplastree.hpp "rplexpr/rplastree.hpp" * - * @brief Implements a data type representing a user defined class. + * @brief Implements a data type representing an user defined class. */ @@ -1034,7 +1034,7 @@ RplASUserClass::RplASUserClass(const QString& name, } /** - * @brief Creates an instance of a user defined class. + * @brief Creates an instance of an user defined class. * * @param source the type (user defined class) of the result * @return an instance of an user defined class diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index d4b9d2a..9838f7d 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -19,6 +19,16 @@ #include "rplcore/rplcore.hpp" #include "rplexpr/rplexpr.hpp" +enum { + LOC_VARDEF_EXEC_1 = RPL_FIRST_OF(RPL_MODULE_ASTREE), // 10001 + LOC_UNOP_1, + LOC_UNOP_2, + LOC_UNOP_3, + LOC_UNOP_4, // 10005 + LOC_BINOP_1, + LOC_COUNT +}; + unsigned int RplASItem::m_nextId = 1; #define DEFINE_TABS(indent) \ @@ -203,6 +213,7 @@ void RplASVariant::destroyValue() m_value.m_object = NULL; break; } + m_variantType = VT_UNDEF; } /** * @brief Returns the variantType of the instance. @@ -214,6 +225,33 @@ RplASVariant::VariantType RplASVariant::variantType() const return m_variantType; } +/** + * @brief Return the name of the variant type. + * + * @return the type as string + */ +const char*RplASVariant::nameOfType() const +{ + const char* rc = "?"; + switch(m_variantType){ + case VT_FLOAT: + rc = "Float"; + break; + case VT_INTEGER: + rc = "Int"; + break; + case VT_BOOL: + rc = "Bool"; + break; + case VT_OBJECT: + rc = "Obj"; + break; + default: + break; + } + return rc; +} + /** * @brief Returns the class (data type) of the instance. * @@ -472,6 +510,28 @@ char* RplASItem::positionStr(char buffer[], size_t bufferSize) const return rc; } +/** + * @brief Logs an internal error. + * + * @param logger can write to the output medium + * @param location identifies the error location + * @param format string with placeholders (optional) like sprintf() + * @param ... values for the placeholders + */ +void RplASItem::error(RplLogger* logger, int location, const char* format, ...) +{ + char buffer[1024]; + int halfBufferSize = (sizeof buffer) / 2; + snprintf(buffer, halfBufferSize, "id: %d [%s]:", m_id, + positionStr(buffer + halfBufferSize, halfBufferSize)); + int length = strlen(buffer); + va_list ap; + va_start(ap, format); + vsnprintf(buffer + length, (sizeof buffer) - length, format, ap); + va_end(ap); + logger->log(LOG_ERROR, location, buffer); +} + /** * @brief Resets the static id counter. */ @@ -488,6 +548,99 @@ RplASItemType RplASItem::nodeType() const { return m_nodeType; } + +/** + * @brief Returns the node type as a string. + * + * @return the node type as string + */ +const char*RplASItem::nameOfItemType() const +{ + const char* rc = "?"; + switch(m_nodeType){ + case AST_CONSTANT: + rc = "constant"; + break; + case AST_LIST_CONSTANT: + rc = "list"; + break; + case AST_LIST_ENTRY: + rc = "listEntry"; + break; + case AST_MAP_CONSTANT: + rc = "map"; + break; + case AST_MAP_ENTRY: + rc = "mapEntry"; + break; + case AST_NAMED_VALUE: + rc = "namedValue"; + break; + case AST_INDEXED_VALUE: + rc = "indexedValue"; + break; + case AST_FIELD: + rc = "field"; + break; + case AST_VAR_DEFINITION: + rc = "varDef"; + break; + case AST_EXPR_STATEMENT: + rc = "exprStatement"; + break; + case AST_METHOD: + rc = "method"; + break; + case AST_ARGUMENT: + rc = "arg"; + break; + case AST_INTRINSIC_METHOD: + rc = "intrinsicMethod"; + break; + case AST_PRE_UNARY_OP: + rc = "preUnary"; + break; + case AST_POST_UNARY_OP: + rc = "postUnary"; + break; + case AST_BINARY_OP: + rc = "binOp"; + break; + case AST_METHOD_CALL: + rc = "methodCall"; + break; + case AST_WHILE: + rc = "while"; + break; + case AST_REPEAT: + rc = "repeat"; + break; + case AST_IF: + rc = "if"; + break; + case AST_CONDITION: + rc = "condition"; + break; + case AST_ITERATED_FOR: + rc = "iFor"; + break; + case AST_COUNTED_FOR: + rc = "cFor"; + break; + case AST_SWITCH: + rc = "switch"; + break; + case AST_LEAVE: + rc = "leave"; + break; + case AST_CONTINUE: + rc = "continue"; + break; + default: + break; + } + return rc; +} /** * @brief Returns the flags of the node. * @@ -537,15 +690,14 @@ RplASConstant::RplASConstant() : } /** - * @brief Calculates the expression. + * @brief Copies the const value to the top of value stack. * - * @param value IN/OUT: the calculated value - * @return NULL + * @param thread IN/OUT: the execution unit, a VM thread */ -RplASNode1* RplASConstant::calc(RplASVariant& value) +void RplASConstant::calc(RplVMThread& thread) { - value = m_value; - return NULL; + RplASVariant& value = thread.reserveValue(); + value.copyValue(m_value); } /** @@ -605,15 +757,14 @@ RplASListOfVariants* RplASListConstant::list(){ } /** - * @brief Calculates the expression. + * @brief Copies the list constant to the top of value stack. * - * @param value IN/OUT: the calculated value - * @return NULL + * @param thread IN/OUT: the execution unit, a VM thread */ -RplASNode1* RplASListConstant::calc(RplASVariant& value) +void RplASListConstant::calc(RplVMThread& thread) { - value = m_value; - return NULL; + RplASVariant& value = thread.reserveValue(); + value.copyValue(m_value); } /** @@ -664,16 +815,14 @@ RplASMapConstant::RplASMapConstant() : } /** - * @brief Calculates the value. + * @brief Copies the map constant to the top of value stack. * - * @param value IN/OUT: the value of the instance - * @return NULL + * @param thread IN/OUT: the execution unit, a VM thread */ -RplASNode1* RplASMapConstant::calc(RplASVariant& ) +void RplASMapConstant::calc(RplVMThread& thread) { - // ToDo: copy map: - //value = m_value; - return NULL; + RplASVariant& value = thread.reserveValue(); + value.copyValue(m_value); } /** * @brief Writes the internals into a file. @@ -729,7 +878,9 @@ RplASNamedValue::RplASNamedValue(const QString& name) : RplASNode1(AST_NAMED_VALUE), m_name(name), m_attributes(0), - m_dataType(NULL) + m_dataType(NULL), + m_symbolSpace(NULL), + m_variableNo(0) { } @@ -745,7 +896,9 @@ RplASNamedValue::RplASNamedValue(RplASClass* dataType, RplASNode1(AST_NAMED_VALUE), m_name(name), m_attributes(attributes), - m_dataType(dataType) + m_dataType(dataType), + m_symbolSpace(NULL), + m_variableNo(0) { } @@ -758,16 +911,25 @@ const QString& RplASNamedValue::name() const { return m_name; } + +/** + * @brief Sets the symbol space. + * @param space + * @param variableNo + */ +void RplASNamedValue::setSymbolSpace(RplSymbolSpace* space, int variableNo) +{ + m_symbolSpace = space; + m_variableNo = variableNo; +} /** - * @brief Calculates the value. + * @brief Copies the value of the variable to the top of value stack. * - * @param value In/OUT: the value of the instance - * @param frame not used - * @return NULL + * @param thread IN/OUT: the execution unit, a VM thread */ -RplASNode1* RplASNamedValue::calc(RplASVariant& , RplStackFrame* ) +void RplASNamedValue::calc(RplVMThread& thread) { - return NULL; + thread.valueToTop(m_symbolSpace, m_variableNo); } /** * @brief Writes the internals into a file. @@ -792,6 +954,36 @@ RplASClass* RplASNamedValue::dataType() const return m_dataType; } +/** + * @brief Assigns the top of stack of the thread to the instance. + * + * @param thread the execution unit, a virtual machine thread + */ +void RplASNamedValue::assign(RplVMThread& thread) +{ + +} + +/** + * @brief Returns the symbol space of the variable. + * + * @return the symbol space + */ +RplSymbolSpace*RplASNamedValue::symbolSpace() const +{ + return m_symbolSpace; +} + +/** + * @brief Returns the variable no of the variable. + * + * @return the current number of the variable in the symbol space + */ +int RplASNamedValue::variableNo() const +{ + return m_variableNo; +} + /** @class RplASIndexedValue rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements an indexed values (member of a list) @@ -836,6 +1028,7 @@ RplASVarDefinition::RplASVarDefinition() : RplASNode3(AST_VAR_DEFINITION), RplASStatement() { + m_flags |= NF_STATEMENT; } /** @@ -888,20 +1081,26 @@ RplASClass* RplASVarDefinition::datatype() const /** * @brief Executes the statement. */ -void RplASVarDefinition::execute() +void RplASVarDefinition::execute(RplVMThread& thread) { - //@ToDo -} - -/** - * @brief Calculates the initialation value while interpreting. - * - * @param value IN/OUT: ignored - * @return NULL - */ -RplASNode1* RplASVarDefinition::calc(RplASVariant&) -{ - return NULL; + if (m_child3 != NULL){ + RplASNamedValue* var = dynamic_cast(m_child2); + if (var == NULL) + error(thread.logger(), LOC_VARDEF_EXEC_1, + "Not a named value: id: %d", + m_child2 == NULL ? 0 : m_child2->id()); + else{ + RplASCalculable* expr = dynamic_cast(m_child3); + if (expr == NULL) + error(thread.logger(), LOC_VARDEF_EXEC_1, + "not calculable: id: %d", + m_child3 == NULL ? 0 : m_child2->id()); + else { + expr->calc(thread); + var->assign(thread); + } + } + } } /** @class RplASExprStatement rplastree.hpp "rplexpr/rplastree.hpp" @@ -919,27 +1118,17 @@ RplASExprStatement::RplASExprStatement() : RplASNode2(AST_EXPR_STATEMENT), RplASStatement() { + m_flags |= NF_STATEMENT; } /** * @brief Executes the statement. */ -void RplASExprStatement::execute() +void RplASExprStatement::execute(RplVMThread& thread) { } -/** - * @brief Calculates the value of the expression. - * - * @param value IN/OUT: the calculated value - * @return NULL - */ -RplASNode1* RplASExprStatement::calc(RplASVariant& ) -{ - return NULL; -} - /** * @brief Writes the internals into a file. * @@ -1019,6 +1208,7 @@ void RplASNode1::dumpStatements(RplWriter& writer, int indent, } } + /** @class RplASNode2 rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements an inner node of the abstract syntax tree with two childs. @@ -1242,9 +1432,9 @@ void RplASNode6::setChild6(RplASItem* child6) /** @class RplASUnaryOp rplastree.hpp "rplexpr/rplastree.hpp" * - * @brief Implements a unary operation. + * @brief Implements an unary operation. * - * This is a operation with one operand, e.g. the boolean not operation. + * This is an operation with one operand, e.g. the boolean not operation. */ /** @@ -1259,6 +1449,71 @@ RplASUnaryOp::RplASUnaryOp(int op, RplASItemType type) : { } +/** + * @brief Calculates the value of the unary operator. + * + * @param thread IN/OUT: the execution unit, a VM thread + */ +void RplASUnaryOp::calc(RplVMThread& thread) +{ + RplASVariant& value = thread.topOfValues(); + switch(m_operator){ + case UOP_PLUS: + break; + case UOP_MINUS: + switch (value.variantType()){ + case RplASVariant::VT_FLOAT: + value.setFloat(- value.asFloat()); + break; + case RplASVariant::VT_INTEGER: + value.setInt(- value.asInt()); + break; + case RplASVariant::VT_BOOL: + case RplASVariant::VT_OBJECT: + default: + error(thread.logger(), LOC_UNOP_1, "wrong type %s for '-'", + value.nameOfType()); + break; + } + break; + case UOP_LOGICAL_NOT: + switch (value.variantType()){ + case RplASVariant::VT_FLOAT: + value.setBool(value.asFloat() != 0.0); + break; + case RplASVariant::VT_INTEGER: + value.setBool(value.asInt() != 0); + break; + case RplASVariant::VT_BOOL: + value.setBool(! value.asBool()); + break; + case RplASVariant::VT_OBJECT: + default: + error(thread.logger(), LOC_UNOP_2, "wrong type %s for '!'", + value.nameOfType()); + break; + } + break; + case UOP_BIT_NOT: + switch (value.variantType()){ + case RplASVariant::VT_INTEGER: + value.setInt(~value.asInt()); + break; + case RplASVariant::VT_FLOAT: + case RplASVariant::VT_BOOL: + case RplASVariant::VT_OBJECT: + default: + error(thread.logger(), LOC_UNOP_3, "wrong type %s for '~'", + value.nameOfType()); + break; + } + break; + default: + error(thread.logger(), LOC_UNOP_4, "unknown operator: %d", m_operator); + break; + } +} + /** * @brief Returns the operator of the unary operation. * @@ -1323,26 +1578,24 @@ RplASCondition::RplASCondition() : /** * @brief Calculates the value of the condition - * @param value IN/OUT: the bool value of the condition - * @return NULL + * + * @param thread IN/OUT: the bool value of the condition */ -RplASNode1* RplASCondition::calc(RplASVariant& value) +void RplASCondition::calc(RplVMThread& thread) { - value.setBool(false); RplASCalculable* node = dynamic_cast(m_child); if (node == NULL) throw RplASException(m_position, "child of condition is not calculable"); - node->calc(value); - return NULL; + node->calc(thread); } /** * @brief Calculates the boolean value and returns it. */ -bool RplASCondition::calcAsBool() +bool RplASCondition::calcAsBool(RplVMThread& thread) { bool rc = false; - RplASVariant value; - calc(value); + calc(thread); + RplASVariant& value = thread.topOfValues(); switch(value.m_variantType){ case RplASVariant::VT_FLOAT: rc = value.m_value.m_float == 0; @@ -1393,20 +1646,21 @@ void RplASCondition::dump(RplWriter& writer, int indent) RplASIf::RplASIf() : RplASNode4(AST_IF) { + m_flags |= NF_STATEMENT; } /** * @brief Executes the statement. * */ -void RplASIf::execute() +void RplASIf::execute(RplVMThread& thread) { RplASCondition* condition = dynamic_cast(m_child2); if (condition == NULL) throw RplASException(m_child2 == NULL ? m_position : m_child2->position(), "if statement: not a condition"); RplASStatement* body = NULL; - if(condition->calcAsBool()){ + if(condition->calcAsBool(thread)){ body = dynamic_cast(m_child3); if (body == NULL) throw RplASException(m_child2 == NULL ? m_position : m_child2->position(), @@ -1417,7 +1671,7 @@ void RplASIf::execute() throw RplASException(m_child4->position(), "if statement: else-part is not a statement"); } - body->execute(); + body->execute(thread); } /** @@ -1469,6 +1723,7 @@ RplASForIterated::RplASForIterated(RplASNamedValue* variable) : RplASNode4(AST_ITERATED_FOR), RplASStatement() { + m_flags |= NF_STATEMENT; m_child2 = variable; } @@ -1476,7 +1731,7 @@ RplASForIterated::RplASForIterated(RplASNamedValue* variable) : * @brief Executes the statement. * */ -void RplASForIterated::execute() +void RplASForIterated::execute(RplVMThread& thread) { } @@ -1531,6 +1786,7 @@ RplASForCounted::RplASForCounted(RplASNamedValue* variable) : RplASNode6(AST_ITERATED_FOR), RplASStatement() { + m_flags |= NF_STATEMENT; m_child3 = variable; } @@ -1538,7 +1794,7 @@ RplASForCounted::RplASForCounted(RplASNamedValue* variable) : * @brief Executes the statement. * */ -void RplASForCounted::execute() +void RplASForCounted::execute(RplVMThread& thread) { RplASStatement* body = dynamic_cast(m_child2); if (body == NULL) @@ -1552,7 +1808,7 @@ void RplASForCounted::execute() var = dynamic_cast(m_child3); } for(int ii = start; ii <= end; ii += step){ - body->execute(); + body->execute(thread); } } @@ -1601,6 +1857,7 @@ RplASWhile::RplASWhile() : RplASNode3(AST_WHILE), RplASStatement() { + m_flags |= NF_STATEMENT; } /** @@ -1608,7 +1865,7 @@ RplASWhile::RplASWhile() : * * Meaning of the childs: */ -void RplASWhile::execute() +void RplASWhile::execute(RplVMThread& thread) { RplASStatement* body = dynamic_cast(m_child3); if (body == NULL) @@ -1618,8 +1875,8 @@ void RplASWhile::execute() if (condition == NULL) throw RplASException(m_child2 == NULL ? m_position : m_child2->position(), "for statement: not a condition"); - while(condition->calcAsBool()){ - body->execute(); + while(condition->calcAsBool(thread)){ + body->execute(thread); } } @@ -1660,6 +1917,7 @@ RplASRepeat::RplASRepeat() : RplASNode3(AST_REPEAT), RplASStatement() { + m_flags |= NF_STATEMENT; } /** @@ -1669,7 +1927,7 @@ RplASRepeat::RplASRepeat() : * m_child: body * m_child2: condition */ -void RplASRepeat::execute() +void RplASRepeat::execute(RplVMThread& thread) { RplASStatement* body = dynamic_cast(m_child3); if (body == NULL) @@ -1680,8 +1938,8 @@ void RplASRepeat::execute() throw RplASException(m_child2 == NULL ? m_position : m_child2->position(), "repeat statement: not a condition"); do { - body->execute(); - } while(condition->calcAsBool()); + body->execute(thread); + } while(condition->calcAsBool(thread)); } /** @@ -1706,7 +1964,7 @@ void RplASRepeat::dump(RplWriter& writer, int indent) /** @class RplASClass rplastree.hpp "rplexpr/rplastree.hpp" * - * @brief Implements the base class of a Abstract Syntax Tree class. + * @brief Implements the base class of an Abstract Syntax Tree class. * * This class is abstract. */ @@ -1999,6 +2257,7 @@ RplASMethodCall::RplASMethodCall(const QString& name, RplASItem* parent) : m_name(name), m_method(NULL) { + m_flags |= NF_STATEMENT; m_child3 = parent; } @@ -2027,7 +2286,7 @@ void RplASMethodCall::dump(RplWriter& writer, int indent) /** * @brief Executes the statement. */ -void RplASMethodCall::execute() +void RplASMethodCall::execute(RplVMThread& thread) { } @@ -2072,16 +2331,46 @@ RplASArgument* RplASMethodCall::arg1() const */ RplASBinaryOp::RplASBinaryOp() : RplASNode2(AST_BINARY_OP), - m_operator(0) + m_operator(BOP_UNDEF) { } +/** + * @brief Calculates the binary operation. + * + * @param thread IN/OUT: the bool value of the condition + */ +void RplASBinaryOp::calc(RplVMThread& thread) +{ + if (isAssignment()) + assign(thread); + else{ + switch(m_operator){ + case BOP_PLUS: + case BOP_MINUS: + case BOP_TIMES: + case BOP_DIV: + case BOP_MOD: + case BOP_POWER: + case BOP_LOG_OR: + case BOP_LOG_AND: + case BOP_LOG_XOR: + case BOP_BIT_OR: + case BOP_BIT_AND: + case BOP_BIT_XOR: + break; + default: + break; + } + } +} + /** * @brief Returns the operator. * * @return the operator */ -int RplASBinaryOp::getOperator() const +RplASBinaryOp::BinOperator RplASBinaryOp::getOperator() const { return m_operator; } @@ -2091,7 +2380,7 @@ int RplASBinaryOp::getOperator() const * * @param op the operator */ -void RplASBinaryOp::setOperator(int op) +void RplASBinaryOp::setOperator(BinOperator op) { m_operator = op; } @@ -2118,6 +2407,47 @@ void RplASBinaryOp::dump(RplWriter& writer, int indent) m_child2->dump(writer, indent + 1); } +/** + * @brief Does an assignment. + * + * @param thread + */ +void RplASBinaryOp::assign(RplVMThread& thread) +{ + RplASVariant& rValue = thread.lValue(m_child); + RplASCalculable* expr = dynamic_cast(m_child2); + if (expr == NULL) + error(thread.logger(), LOC_BINOP_1, "not a calulable: id: %d", + m_child2 == NULL ? 0 : m_child2->id()); + else { + RplASVariant& value = thread.popValue(); + switch(m_operator){ + case BOP_ASSIGN: + break; + case BOP_PLUS_ASSIGN: + switch(value.variantType()){ + + } + break; + case BOP_MINUS_ASSIGN: + case BOP_TIMES_ASSIGN: + case BOP_DIV_ASSIGN: + case BOP_MOD_ASSIGN: + case BOP_POWER_ASSIGN: + case BOP_LOG_OR_ASSIGN: + case BOP_LOG_AND_ASSIGN: + case BOP_LOG_XOR_ASSIGN: + case BOP_BIT_OR_ASSIGN: + case BOP_BIT_AND_ASSIGN: + case BOP_BIT_XOR_ASSIGN: + break; + default: + break; + } + rValue.copyValue(value); + } +} + /** @class RplASMethod rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements a method definition for the Abstract Syntax Tree. diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index 742d6be..06e8e8b 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -92,8 +92,8 @@ public: void setString(const QString& string); QString toString(int maxLength = 80) const; VariantType variantType() const; + const char* nameOfType() const; const RplASClass* getClass() const; -protected: void copyValue(const RplASVariant& source); void destroyValue(); private: @@ -117,8 +117,10 @@ public: NF_UNDEF, /// the node calculates a value: NF_CALCULABLE = 1 << 1, + /// the node calculates a value: + NF_STATEMENT = 1 << 2, /// the tree under this node is complete checked for data type correctness - NF_TYPECHECK_COMPLETE = 1 << 2, + NF_TYPECHECK_COMPLETE = 1 << 3, /// debugger: this node is a breakpoint NF_BREAKPOINT = 1 << 5 }; @@ -132,6 +134,7 @@ public: void setPosition(const RplSourcePosition* position); unsigned int id() const; char* positionStr(char buffer[], size_t bufferSize) const; + void error(RplLogger* logger, int location, const char* format, ...); public: /** * @brief Writes the content of the instance into an output medium. @@ -143,6 +146,7 @@ public: public: static void reset(); RplASItemType nodeType() const; + const char* nameOfItemType() const; int flags() const; void setFlags(int flags); @@ -158,24 +162,23 @@ private: }; class RplASNode1; +class RplVMThread; class RplASCalculable { public: - virtual RplASNode1* calc(RplASVariant& value) = 0; + virtual void calc(RplVMThread& thread) = 0; }; class RplStackFrame; -class RplASStorable{ -public: - virtual RplASNode1* calc(RplASVariant& value, RplStackFrame* frame) = 0; +class RplASStorable : RplASCalculable { }; - +class RplVMThread; class RplASConstant : public RplASItem, public RplASCalculable { public: RplASConstant(); public: - virtual RplASNode1* calc(RplASVariant& value); + virtual void calc(RplVMThread& thread); public: virtual void dump(RplWriter& writer,int indent); RplASVariant& value(); @@ -268,7 +271,7 @@ class RplASListConstant : public RplASNode1, public RplASCalculable public: RplASListConstant(); public: - virtual RplASNode1* calc(RplASVariant& value); + virtual void calc(RplVMThread& thread); public: virtual void dump(RplWriter& writer,int indent); RplASVariant& value(); @@ -281,7 +284,7 @@ class RplASMapConstant : public RplASNode1, public RplASCalculable public: RplASMapConstant(); public: - virtual RplASNode1* calc(RplASVariant& value); + virtual void calc(RplVMThread& thread); public: virtual void dump(RplWriter& writer,int indent); RplASVariant& value(); @@ -290,6 +293,7 @@ private: RplASVariant m_value; }; +class RplSymbolSpace; class RplASNamedValue : public RplASNode1, public RplASStorable { public: @@ -313,15 +317,19 @@ public: const QString& name, int attributes); public: const QString& name() const; -public: - virtual RplASNode1* calc(RplASVariant& value, RplStackFrame* frame); + void setSymbolSpace(RplSymbolSpace* space, int variableNo); + virtual void calc(RplVMThread& thread); void dump(RplWriter& writer, int indent); RplASClass* dataType() const; - + void assign(RplVMThread& thread); + RplSymbolSpace* symbolSpace() const; + int variableNo() const; protected: QString m_name; int m_attributes; RplASClass* m_dataType; + RplSymbolSpace* m_symbolSpace; + int m_variableNo; }; class RplASIndexedValue : public RplASNode2 { @@ -336,7 +344,7 @@ class RplASStatement public: RplASStatement(); public: - virtual void execute() = 0; + virtual void execute(RplVMThread& thread) = 0; }; @@ -345,8 +353,7 @@ class RplASVarDefinition : public RplASNode3, public RplASStatement public: RplASVarDefinition(); public: - virtual void execute(); - virtual RplASNode1* calc(RplASVariant& value); + virtual void execute(RplVMThread& thread); void dump(RplWriter& writer, int indent); const QString& name() const; RplASClass* datatype() const; @@ -357,32 +364,90 @@ class RplASExprStatement : public RplASNode2, public RplASStatement public: RplASExprStatement(); public: - virtual void execute(); - virtual RplASNode1* calc(RplASVariant& value); + virtual void execute(RplVMThread& thread); void dump(RplWriter& writer, int indent); }; -class RplASUnaryOp : public RplASNode1 +class RplASUnaryOp : public RplASNode1, RplASCalculable { +public: + enum { + UOP_UNDEF, + UOP_PLUS, + UOP_MINUS, + UOP_LOGICAL_NOT, + UOP_BIT_NOT + }; public: RplASUnaryOp(int op, RplASItemType type); public: + virtual void calc(RplVMThread& thread); int getOperator() const; void dump(RplWriter& writer, int indent); private: int m_operator; }; -class RplASBinaryOp : public RplASNode2 +class RplASBinaryOp : public RplASNode2, public RplASCalculable { +public: + enum BinOperator { + BOP_UNDEF, + BOP_ASSIGN, + BOP_PLUS_ASSIGN, + BOP_MINUS_ASSIGN, + BOP_TIMES_ASSIGN, + BOP_DIV_ASSIGN, + BOP_MOD_ASSIGN, + BOP_POWER_ASSIGN, + BOP_LOG_OR_ASSIGN, + BOP_LOG_AND_ASSIGN, + BOP_LOG_XOR_ASSIGN, + BOP_BIT_OR_ASSIGN, + BOP_BIT_AND_ASSIGN, + BOP_BIT_XOR_ASSIGN, + BOP_LSHIFT_ASSIGN, + BOP_LOG_RSHIFT_ASSIGN, + BOP_ARTITH_RSHIFT_ASSIGN, + BOP_PLUS, + BOP_MINUS, + BOP_TIMES, + BOP_DIV, + BOP_MOD, + BOP_POWER, + BOP_LOG_OR, + BOP_LOG_AND, + BOP_LOG_XOR, + BOP_BIT_OR, + BOP_BIT_AND, + BOP_BIT_XOR, + BOP_LSHIFT, + BOP_LOG_RSHIFT, + BOP_ARTITH_RSHIFT, + BOP_EQ, + BOP_NE, + BOP_LE, + BOP_LT, + BOP_GE, + BOP_GT, + BOB_COUNT + }; +private: + inline bool isAssignment() const { + return m_operator >= BOP_ASSIGN + && m_operator <= BOP_ARTITH_RSHIFT_ASSIGN; + } public: RplASBinaryOp(); public: - int getOperator() const; - void setOperator(int op); + void calc(RplVMThread& thread); + BinOperator getOperator() const; + void setOperator(BinOperator op); void dump(RplWriter& writer, int indent); private: - int m_operator; + void assign(RplVMThread& thread); +private: + BinOperator m_operator; }; class RplASCondition : public RplASNode1, public RplASCalculable @@ -390,8 +455,8 @@ class RplASCondition : public RplASNode1, public RplASCalculable public: RplASCondition(); public: - RplASNode1* calc(RplASVariant& value); - bool calcAsBool(); + void calc(RplVMThread& thread); + bool calcAsBool(RplVMThread& thread); void dump(RplWriter& writer, int indent); }; @@ -400,7 +465,7 @@ class RplASIf : public RplASNode4, public RplASStatement public: RplASIf(); public: - virtual void execute(); + virtual void execute(RplVMThread& thread); virtual void dump(RplWriter& writer, int indent); }; @@ -409,7 +474,7 @@ class RplASForIterated : public RplASNode4, public RplASStatement public: RplASForIterated(RplASNamedValue* variable); public: - virtual void execute(); + virtual void execute(RplVMThread& thread); virtual void dump(RplWriter& writer, int indent); }; @@ -418,7 +483,7 @@ class RplASForCounted : public RplASNode6, public RplASStatement public: RplASForCounted(RplASNamedValue* variable); public: - virtual void execute(); + virtual void execute(RplVMThread& thread); virtual void dump(RplWriter& writer, int indent); }; @@ -427,7 +492,7 @@ class RplASWhile : public RplASNode3, public RplASStatement public: RplASWhile(); public: - virtual void execute(); + virtual void execute(RplVMThread& thread); virtual void dump(RplWriter& writer, int indent); }; @@ -436,7 +501,7 @@ class RplASRepeat : public RplASNode3, public RplASStatement public: RplASRepeat(); public: - virtual void execute(); + virtual void execute(RplVMThread& thread); virtual void dump(RplWriter& writer, int indent); }; @@ -457,7 +522,7 @@ public: RplASMethodCall(const QString& name, RplASItem* parent); public: void dump(RplWriter& writer, int indent); - virtual void execute(); + virtual void execute(RplVMThread& thread); public: RplASMethod* method() const; @@ -497,7 +562,7 @@ class RplASMethod : public RplASNode2 public: RplASMethod(const QString& name, RplASTree& tree); public: - void execute(); + void execute(RplVMThread& thread); void dump(RplWriter& writer, int indent); RplSymbolSpace* symbols() const; void setSymbols(); diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp index 31d4a37..5fadeca 100644 --- a/rplexpr/rplmfparser.cpp +++ b/rplexpr/rplmfparser.cpp @@ -651,6 +651,110 @@ RplASItem* RplMFParser::parseOperand(int level, RplASItem* parent) } return rc; } +RplASBinaryOp::BinOperator encodeBinOp(int op){ + RplASBinaryOp::BinOperator rc = RplASBinaryOp::BOP_UNDEF; + switch(op){ + case RplMFParser::O_ASSIGN: + rc = RplASBinaryOp::BOP_ASSIGN; + break; + case RplMFParser::O_PLUS_ASSIGN: + rc = RplASBinaryOp::BOP_PLUS_ASSIGN; + break; + case RplMFParser::O_MINUS_ASSIGN: + rc = RplASBinaryOp::BOP_MINUS_ASSIGN; + break; + case RplMFParser::O_DIV_ASSIGN: + rc = RplASBinaryOp::BOP_DIV_ASSIGN; + break; + case RplMFParser::O_TIMES_ASSIGN: + rc = RplASBinaryOp::BOP_TIMES_ASSIGN; + break; + case RplMFParser::O_MOD_ASSIGN: + rc = RplASBinaryOp::BOP_MOD_ASSIGN; + break; + case RplMFParser::O_POWER_ASSIGN: + rc = RplASBinaryOp::BOP_POWER_ASSIGN; + break; + case RplMFParser::O_OR_ASSIGN: + rc = RplASBinaryOp::BOP_LOG_OR_ASSIGN; + break; + case RplMFParser::O_AND_ASSIGN: + rc = RplASBinaryOp::BOP_LOG_AND_ASSIGN; + break; + case RplMFParser::O_LSHIFT_ASSIGN: + rc = RplASBinaryOp::BOP_LSHIFT_ASSIGN; + break; + case RplMFParser::O_RSHIFT_ASSIGN: + rc = RplASBinaryOp::BOP_LOG_RSHIFT_ASSIGN; + break; + case RplMFParser::O_RSHIFT2_ASSIGN: + rc = RplASBinaryOp::BOP_ARTITH_RSHIFT_ASSIGN; + break; + case RplMFParser::O_OR: + rc = RplASBinaryOp::BOP_LOG_OR; + break; + case RplMFParser::O_AND: + rc = RplASBinaryOp::BOP_LOG_AND; + break; + case RplMFParser::O_EQ: + rc = RplASBinaryOp::BOP_EQ; + break; + case RplMFParser::O_NE: + rc = RplASBinaryOp::BOP_NE; + break; + case RplMFParser::O_LT: + rc = RplASBinaryOp::BOP_LT; + break; + case RplMFParser::O_GT: + rc = RplASBinaryOp::BOP_GT; + break; + case RplMFParser::O_LE: + rc = RplASBinaryOp::BOP_LE; + break; + case RplMFParser::O_GE: + rc = RplASBinaryOp::BOP_GE; + break; + case RplMFParser::O_PLUS: + rc = RplASBinaryOp::BOP_PLUS; + break; + case RplMFParser::O_MINUS: + rc = RplASBinaryOp::BOP_MINUS; + break; + case RplMFParser::O_DIV: + rc = RplASBinaryOp::BOP_DIV; + break; + case RplMFParser::O_MOD: + rc = RplASBinaryOp::BOP_MOD; + break; + case RplMFParser::O_TIMES: + rc = RplASBinaryOp::BOP_TIMES; + break; + case RplMFParser::O_POWER: + rc = RplASBinaryOp::BOP_POWER; + break; + case RplMFParser::O_XOR: + rc = RplASBinaryOp::BOP_LOG_XOR; + break; + case RplMFParser::O_BIT_OR: + rc = RplASBinaryOp::BOP_BIT_OR; + break; + case RplMFParser::O_BIT_AND: + rc = RplASBinaryOp::BOP_BIT_AND; + break; + case RplMFParser::O_LSHIFT: + rc = RplASBinaryOp::BOP_LSHIFT; + break; + case RplMFParser::O_RSHIFT: + rc = RplASBinaryOp::BOP_LOG_RSHIFT; + break; + case RplMFParser::O_RSHIFT2: + rc = RplASBinaryOp::BOP_ARTITH_RSHIFT; + break; + default: + break; + } + return rc; +} /** * @brief Parses an expression. @@ -684,7 +788,7 @@ RplASItem* RplMFParser::parseExpr(int depth){ if (IS_BINARY_OP(opId)){ RplASBinaryOp* op = new RplASBinaryOp(); op->setPosition(m_lexer.currentPosition()); - op->setOperator(opId); + op->setOperator(encodeBinOp(opId)); int prio = m_lexer.prioOfOp(token->id()); if (prio < lastPrio diff --git a/rplexpr/rplsource.cpp b/rplexpr/rplsource.cpp index 65153f3..a542bea 100644 --- a/rplexpr/rplsource.cpp +++ b/rplexpr/rplsource.cpp @@ -12,7 +12,7 @@ * The abstract base class RplReader and its concrete derivations * RplStringReader, RplFileReader are used to read * from one medium. - * The RplSource combines several readers and build a uniquely + * The RplSource combines several readers and build an uniquely * usable input stream. */ /** @file rplexpr/rplsource.hpp diff --git a/rplexpr/rplvm.cpp b/rplexpr/rplvm.cpp index 91c1518..d3eb63b 100644 --- a/rplexpr/rplvm.cpp +++ b/rplexpr/rplvm.cpp @@ -10,6 +10,7 @@ * * @brief Implements an interpreter of an abstract syntax tree. */ + /** @file rplexpr/rplvm.hpp * * @brief Definitions for an interpreter of an abstract syntax tree. @@ -18,6 +19,8 @@ #include "rplcore/rplcore.hpp" #include "rplexpr/rplexpr.hpp" +int RplVMThread::m_nextId = 1; + /** @class RplVmException rplvm.hpp "rplexpr/rplvm.hpp" * * @brief Implements an exception for the virtual machine. @@ -102,14 +105,22 @@ RplASVariant& RplStackFrame::valueOfVariable(int index) * @param vm the parent, the virtual machine */ RplVMThread::RplVMThread(int maxStack, RplVirtualMachine* vm) : + m_id(m_nextId++), m_singleStep(false), m_debugMode(false), m_maxStack(maxStack), m_stack(), - m_currentValue(), - m_vm(vm) + m_valueStack(), + // the stack is never empty! + m_topOfValues(1), + m_vm(vm), + m_logger(new RplLogger()) { + QByteArray prefix = "vm_thread_" + QByteArray::number(m_id); + m_logger->buildStandardAppender(prefix); m_stack.reserve(maxStack); + // the stack is never empty! + m_valueStack.append(new RplASVariant); } /** @@ -122,13 +133,16 @@ RplVMThread::RplVMThread(int maxStack, RplVirtualMachine* vm) : void RplVMThread::execute(RplASNode1* statements, RplSymbolSpace* space) { bool debugMode = m_debugMode; + RplASNode1 *next; while(statements != NULL){ if (debugMode && (m_singleStep || (statements->flags() & RplASItem::NF_BREAKPOINT) != 0)) debug(statements); - RplASCalculable* statement = dynamic_cast(statements); - statement->calc(m_currentValue); + RplASStatement* statement = dynamic_cast(statements); + if (statement != NULL) + statement->execute(*this); + statements = dynamic_cast(statements->child()); } } @@ -142,11 +156,109 @@ void RplVMThread::debug(RplASNode1* statement) } +/** + * @brief Returns the logger of the instance. + * + * @return the logger + */ +RplLogger* RplVMThread::logger() const +{ + return m_logger; +} +/** + * @brief Reserves a value in the thread's value stack. + * + * @return the reserved value + */ +RplASVariant&RplVMThread::reserveValue() +{ + RplASVariant* rc; + if (++m_topOfValues < m_valueStack.size()){ + rc = m_valueStack[m_topOfValues]; + rc->destroyValue(); + } else { + rc = new RplASVariant(); + m_valueStack.append(rc); + } + return *rc; +} + +/** + * @brief Returns the top of the value stack. + * + * @return the top of the value stack + */ +RplASVariant& RplVMThread::topOfValues() +{ + RplASVariant& rc = *m_valueStack[m_topOfValues]; + return rc; +} + +/** + * @brief Returns the top of stack and removes it. + * + * @return the old top of stack + */ +RplASVariant& RplVMThread::popValue() +{ + RplASVariant& rc = *m_valueStack[m_topOfValues]; + if (m_topOfValues > 0) + m_topOfValues--; + return rc; +} + +/** + * @brief Copies a variable value to the top of the stack. + * + * @param symbolSpace the symbol space of the variable + * @param variableNo the current no of the variable in the symbol space + */ +void RplVMThread::valueToTop(RplSymbolSpace* symbolSpace, int variableNo) +{ + //@ToDo +} + +/** + * @brief Returns the "left value" (of an assignment). + * @param item + * @return + */ +RplASVariant& RplVMThread::lValue(RplASItem* item) +{ + RplASVariant* rc; + switch(item->nodeType()){ + case AST_NAMED_VALUE: + { + RplASNamedValue* var = dynamic_cast(item); + rc = &valueOfVariable(var->symbolSpace(), var->variableNo()); + break; + } + default: + break; + } + return *rc; +} + +/** + * @brief Returns the reference of the value of a variable. + * + * @param symbolSpace the symbol space + * @param variableNo the current number in the symbol space + * @return + */ +RplASVariant& RplVMThread::valueOfVariable(RplSymbolSpace* symbolSpace, + int variableNo) +{ + RplASVariant& rc = *m_valueStack[0]; + + return rc; +} + /** @class RplVirtualMachine rplvm.hpp "rplexpr/rplvm.hpp" * * @brief Implements a virtual machine. * - * This is a execution unit which interprets an abstract syntax tree. + * This is an execution unit which interprets an abstract syntax tree. */ RplVirtualMachine::RplVirtualMachine(RplASTree& tree, RplSource& source, int maxStack) : @@ -243,3 +355,14 @@ void RplVirtualMachine::clearFlag(RplVirtualMachine::VMFlag flag) { m_flags &= ~flag; } + +/** + * @brief Sets the trace writer. + * + * @param traceWriter the new writer + */ +void RplVirtualMachine::setTraceWriter(RplWriter* traceWriter) +{ + m_traceWriter = traceWriter; +} + diff --git a/rplexpr/rplvm.hpp b/rplexpr/rplvm.hpp index 4134935..c9c9d84 100644 --- a/rplexpr/rplvm.hpp +++ b/rplexpr/rplvm.hpp @@ -29,6 +29,10 @@ private: class RplVirtualMachine; class RplVMThread { + friend class RplASItem; + friend class RplASStatement; + friend class RplASCalculable; + friend class RplASCondition; public: typedef QList StackFrameList; public: @@ -36,13 +40,27 @@ public: public: void execute(RplASNode1* statements, RplSymbolSpace* space); virtual void debug(RplASNode1* statement); + RplWriter* errorWriter() const; + void setErrorWriter(RplWriter* errorWriter); + RplLogger* logger() const; + RplASVariant& reserveValue(); + RplASVariant& topOfValues(); + RplASVariant& popValue(); + void valueToTop(RplSymbolSpace* symbolSpace, int variableNo); + RplASVariant& lValue(RplASItem* item); + RplASVariant& valueOfVariable(RplSymbolSpace* symbolSpace, int variableNo); protected: + int m_id; bool m_debugMode; bool m_singleStep; int m_maxStack; StackFrameList m_stack; - RplASVariant m_currentValue; + QList m_valueStack; + int m_topOfValues; RplVirtualMachine* m_vm; + RplLogger* m_logger; +private: + static int m_nextId; }; class RplVirtualMachine @@ -67,6 +85,8 @@ public: bool hasFlag(VMFlag flag) const; void setFlag(VMFlag flag); void clearFlag(VMFlag flag); + void setTraceWriter(RplWriter* traceWriter); + private: int m_maxStack; QList m_threads; @@ -74,6 +94,7 @@ private: RplSource& m_source; RplASTree& m_tree; LineList m_trace; + RplWriter* m_traceWriter; }; #endif // RPLVM_HPP diff --git a/rplexpr/rplvm_test.cpp b/rplexpr/rplvm_test.cpp deleted file mode 100644 index 05acac0..0000000 --- a/rplexpr/rplvm_test.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licence: - * You can use and modify this file without any restriction. - * There is no warranty. - * You also can use the licence from http://www.wtfpl.net/. - * The original sources can be found on https://github.com/republib. -*/ - -#include "rplcore/rplcore.hpp" -#include "rplexpr/rplexpr.hpp" -#include "rplcore/rpltest.hpp" - -class TestRplVM : public RplTest{ -private: - RplSource m_source; - RplASTree m_tree; - RplStringReader m_reader; - const char* m_currentSource; -public: - TestRplVM() : - RplTest("RplVM"), - m_source(), - m_tree(), - m_reader(m_source) - { - m_source.addReader(&m_reader); - } -protected: - void setSource(const char* content){ - RplASItem::reset(); - m_currentSource = content; - m_tree.clear(); - m_source.clear(); - m_reader.clear(); - m_reader.addSource("", content); - m_source.addReader(&m_reader); - m_source.addSourceUnit(m_reader.currentSourceUnit()); - } - -private: - void checkAST(RplVirtualMachine& vm, const char* fileExpected, int lineNo){ - QByteArray fnExpected = "test"; - fnExpected += QDir::separator().toLatin1(); - fnExpected += "rplvm"; - fnExpected += (char) QDir::separator().toLatin1(); - fnExpected += fileExpected; - QByteArray fnCurrent = getTempFile(fileExpected, "rplvm"); - vm.setFlag(RplVirtualMachine::VF_TRACE_STATEMENTS); - vm.executeModule(""); - //vm.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS); - assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), - __FILE__, lineNo); - } -public: - void baseTest(){ - setSource("Int a=2+3*4"); - RplMFParser parser(m_source, m_tree); - parser.parse(); - RplVirtualMachine vm(m_tree, m_source); - checkAST(vm, "baseTest.txt", __LINE__); - } - virtual void doIt(void) { - baseTest(); - } -}; -void testRplVM() { - TestRplVM test; - test.run(); -} - diff --git a/rplmodules.hpp b/rplmodules.hpp index 998e0c0..9bfcb7e 100644 --- a/rplmodules.hpp +++ b/rplmodules.hpp @@ -11,7 +11,12 @@ enum { RPLMODULE_TCPCLIENT, RPLMODULE_TCPPEER, RPLMODULE_TERMINATOR, - + RPL_MODULE_ASTREE, // 10 + RPL_MODULE_ASCLASSES, + RPL_MODULE_LEXER, + RPL_MODULE_SOURCE, + RPL_MODULE_ASVM, + RPL_MODULE_MFPARSER, // 15 // last element: RPLMODULE_COUNT }; diff --git a/rplnet/rpltcppeer.cpp b/rplnet/rpltcppeer.cpp index 207c36b..743de31 100644 --- a/rplnet/rpltcppeer.cpp +++ b/rplnet/rpltcppeer.cpp @@ -48,7 +48,7 @@ static int s_dummy = 0; * @param thread the current thread. Used for sleep() * @param terminator NULL or for controlled thread termination * @param logger logger. If Null the global logger will be taken (not thread safe!) - * @return a instance of RplTcpPeer + * @return an instance of RplTcpPeer */ RplTcpPeer* RplTcpPeer::createPeer(RplConfigurator& configurator, QThread* thread, diff --git a/rplnet/rpltcpserver.cpp b/rplnet/rpltcpserver.cpp index d6ab519..25cc44e 100644 --- a/rplnet/rpltcpserver.cpp +++ b/rplnet/rpltcpserver.cpp @@ -111,7 +111,7 @@ qintptr RplTcpThread::getSocketDescriptor() const { */ RplTcpServer::RplTcpServer(RplConfigurator& configurator, RplTaskHandler* taskHandler, - RplThreadFactory& threadFactory, + RplVMThreadFactory& threadFactory, RplLogger* logger, QObject* parent) : QTcpServer(parent), diff --git a/unittests/rplastree_test.cpp b/unittests/rplastree_test.cpp index 7786ab4..e660b3f 100644 --- a/unittests/rplastree_test.cpp +++ b/unittests/rplastree_test.cpp @@ -72,10 +72,10 @@ public: } void testRplASConstant(){ RplASConstant constant; - constant.value().setString("Jonny"); + //constant.value().setString("Jonny"); RplASVariant value; - constant.calc(value); - checkE("Jonny", *value.asString()); + //constant.calc(value); + //checkE("Jonny", *value.asString()); } void testRplASNamedValue(){ RplASNamedValue value("gugo"); @@ -86,9 +86,9 @@ public: RplASConstant* constant = new RplASConstant(); constant->value().setString("True"); cond.setChild(constant); - checkT(cond.calcAsBool()); + //checkT(cond.calcAsBool()); constant->value().setInt(0); - checkF(cond.calcAsBool()); + //checkF(cond.calcAsBool()); } virtual void doIt() { diff --git a/unittests/rplexception_test.cpp b/unittests/rplexception_test.cpp index b39f308..39e124a 100644 --- a/unittests/rplexception_test.cpp +++ b/unittests/rplexception_test.cpp @@ -7,6 +7,9 @@ */ #include "rplcore/rplcore.hpp" #include "rplcore/rpltest.hpp" +/** @file + * @brief Unit test of the basic exceptions. + */ class TestRplException : public RplTest{ public: diff --git a/unittests/rplmfparser_test.cpp b/unittests/rplmfparser_test.cpp index 74d0300..c2841b8 100644 --- a/unittests/rplmfparser_test.cpp +++ b/unittests/rplmfparser_test.cpp @@ -13,14 +13,14 @@ #include "rplexpr/rplexpr.hpp" #include "rplcore/rpltest.hpp" -class TestRplVM : public RplTest{ +class TestRplMFParser : public RplTest{ private: RplSource m_source; RplASTree m_tree; RplStringReader m_reader; const char* m_currentSource; public: - TestRplVM() : + TestRplMFParser() : RplTest("RplMFParser"), m_source(), m_tree(), @@ -192,7 +192,7 @@ public: } }; void testRplMFParser() { - TestRplVM test; + TestRplMFParser test; test.run(); } diff --git a/unittests/rplvm_test.cpp b/unittests/rplvm_test.cpp new file mode 100644 index 0000000..16767fa --- /dev/null +++ b/unittests/rplvm_test.cpp @@ -0,0 +1,71 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + +#include "rplcore/rplcore.hpp" +#include "rplexpr/rplexpr.hpp" +#include "rplcore/rpltest.hpp" + +class TestRplVM : public RplTest{ +private: + RplSource m_source; + RplASTree m_tree; + RplStringReader m_reader; + const char* m_currentSource; +public: + TestRplVM() : + RplTest("RplVM"), + m_source(), + m_tree(), + m_reader(m_source) + { + m_source.addReader(&m_reader); + } +protected: + void setSource(const char* content){ + RplASItem::reset(); + m_currentSource = content; + m_tree.clear(); + m_source.clear(); + m_reader.clear(); + m_reader.addSource("", content); + m_source.addReader(&m_reader); + m_source.addSourceUnit(m_reader.currentSourceUnit()); + } + +private: + void checkAST(const char* fileExpected, int lineNo){ + QByteArray fnExpected = "test"; + fnExpected += QDir::separator().toLatin1(); + fnExpected += "rplvm"; + fnExpected += (char) QDir::separator().toLatin1(); + fnExpected += fileExpected; + QByteArray fnCurrent = getTempFile(fileExpected, "rplvm"); + RplMFParser parser(m_source, m_tree); + parser.parse(); + RplVirtualMachine vm(m_tree, m_source); + vm.setFlag(RplVirtualMachine::VF_TRACE_STATEMENTS); + RplFileWriter writer(fnCurrent); + vm.setTraceWriter(&writer); + vm.executeModule(""); + assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), + __FILE__, lineNo); + } +public: + void baseTest(){ + setSource("Int a=2+3*4"); + checkAST("baseTest.txt", __LINE__); + } + virtual void doIt(void) { + baseTest(); + } +}; +void testRplVM() { + TestRplVM test; + test.run(); +} + diff --git a/unittests/unittests.pro b/unittests/unittests.pro index 18dec12..285f0e1 100644 --- a/unittests/unittests.pro +++ b/unittests/unittests.pro @@ -17,7 +17,6 @@ INCLUDEPATH = .. TEMPLATE = app SOURCES += main.cpp \ - rplmatrix_test.cpp \ ../rplcore/rpllogger.cpp \ ../rplcore/rpltest.cpp \ ../rplcore/rplstring.cpp \ @@ -28,19 +27,20 @@ SOURCES += main.cpp \ ../rplexpr/rplastree.cpp \ ../rplexpr/rplparser.cpp \ ../rplexpr/rplmfparser.cpp \ + ../rplcore/rplqstring.cpp \ + ../rplexpr/rplasclasses.cpp \ + ../rplcore/rplbytestorage.cpp \ + ../rplexpr/rplvm.cpp \ + ../rplcore/rplwriter.cpp \ + rplmatrix_test.cpp \ rplexception_test.cpp \ rplstring_test.cpp \ rplsource_test.cpp \ rpllexer_test.cpp \ rplqstring_test.cpp \ - ../rplcore/rplqstring.cpp \ - ../rplexpr/rplasclasses.cpp \ rplastree_test.cpp \ rplmfparser_test.cpp \ - ../rplexpr/rplvm_test.cpp \ + rplvm_test.cpp \ rplbytestorage_test.cpp \ - ../rplcore/rplbytestorage.cpp \ - ../rplexpr/rplvm.cpp \ - rplwriter_test.cpp \ - ../rplcore/rplwriter.cpp + rplwriter_test.cpp