From: hama Date: Sat, 5 Jul 2014 15:22:22 +0000 (+0200) Subject: day's work X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=b28829aec2eef01ef39593e1c88668a71b1e048c;p=reqt day's work --- diff --git a/rplcore/rplqstring.cpp b/rplcore/rplqstring.cpp index f685ddb..90c156d 100644 --- a/rplcore/rplqstring.cpp +++ b/rplcore/rplqstring.cpp @@ -153,3 +153,24 @@ int RplQString::lengthOfReal(const QString& text, int start, qreal* pValue) *pValue = value; return found ? ix - start : 0; } + +/** + * @brief Converts a QString into a utf-8 string + * + * The expression qstring.toUtf8().constData() is not allowed + * in a variable argument list like sprintf. This is a thread save workaround. + * + * @param source string to convert + * @param buffer OUT: target buffer + * @param bufferSize size of the target buffer + * @return buffer + */ +char*RplQString::utf8(const QString& source, char buffer[], size_t bufferSize) +{ + QByteArray val = source.toUtf8(); + if (val.length() < (int) bufferSize) + bufferSize = val.length() + 1; + memcpy(buffer, val.constData(), bufferSize - 1); + buffer[bufferSize - 1] = '\0'; + return buffer; +} diff --git a/rplcore/rplqstring.hpp b/rplcore/rplqstring.hpp index 53c8d41..780ef24 100644 --- a/rplcore/rplqstring.hpp +++ b/rplcore/rplqstring.hpp @@ -31,6 +31,7 @@ public: : digit >= 'A' && digit <= 'F' ? digit - 'A' + 10 : digit >= 'a' && digit <= 'f' ? digit - 'a' + 10 : -1; } + static char* utf8(const QString& source, char buffer[], size_t bufferSize); }; #endif // RPLQSTRING_HPP diff --git a/rplexpr/rplasclasses.cpp b/rplexpr/rplasclasses.cpp index 3f24a0d..25f29e9 100644 --- a/rplexpr/rplasclasses.cpp +++ b/rplexpr/rplasclasses.cpp @@ -740,10 +740,9 @@ void*RplASVoid::newValueInstance(void*) const * * In this case we do nothing. * - * @param object object to - * @return + * @param object not used */ -void RplASVoid::destroyValueInstance(void* object) const +void RplASVoid::destroyValueInstance(void*) const { } diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index bef3477..bd6e7ef 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -358,7 +358,6 @@ RplASItem::RplASItem(RplASItemType type) : m_flags(0), m_position(NULL) { - } /** * @brief Destructor. @@ -443,8 +442,10 @@ void RplASConstant::calc(RplASVariant& value) void RplASConstant::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%sconst id: %d value: %s\n", tabs, m_id, - m_value.toString().toUtf8().constData()); + char buffer[256]; + fprintf(fp, "%sconst id: %d value: %s %s\n", tabs, m_id, + m_value.toString().toUtf8().constData(), + m_position->utf8(buffer, sizeof buffer)); } /** @@ -525,8 +526,10 @@ void RplASNamedValue::calc(RplASVariant& value) void RplASNamedValue::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%snamedValue id: %d attr: 0x%x\n", tabs, - m_id, m_attributes); + char buffer[256]; + fprintf(fp, "%snamedValue %s id: %d attr: 0x%x %s\n", tabs, + m_name.toUtf8().constData(), m_id, m_attributes, + m_position->utf8(buffer, sizeof buffer)); } /** @class RplVarDefinition rplastree.hpp "rplexpr/rplastree.hpp" @@ -559,9 +562,11 @@ void RplASVarDefinition::dump(FILE* fp, int indent) DEFINE_TABS(indent); QByteArray name = m_name.toUtf8(); QByteArray className = m_dataType == NULL ? "?" : m_dataType->name().toUtf8(); - fprintf(fp, "%svarDef %s (%s) id: %d succ: %d attr: 0x%x\n", + char buffer[256]; + fprintf(fp, "%svarDef %s (%s) id: %d succ: %d attr: 0x%x %s\n", tabs, name.constData(), className.constData(), - m_id, m_successor == NULL ? 0 : m_successor->id(), m_attributes); + m_id, m_successor == NULL ? 0 : m_successor->id(), m_attributes, + m_position->utf8(buffer, sizeof buffer)); if (m_child != NULL) m_child->dump(fp, indent + 1); if (m_successor != NULL) @@ -626,9 +631,11 @@ void RplASExprStatement::calc(RplASVariant& value) void RplASExprStatement::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%sExpr id: %d succ: %d expr: %d\n", tabs, m_id, + char buffer[256]; + fprintf(fp, "%sExpr id: %d succ: %d expr: %d %s\n", tabs, m_id, m_successor == NULL ? 0 : m_successor->id(), - m_child == NULL ? 0 : m_child->id() ); + m_child == NULL ? 0 : m_child->id(), + m_position->utf8(buffer, sizeof buffer)); if (m_child != NULL) m_child->dump(fp, indent + 1); if (m_successor != NULL) @@ -878,8 +885,10 @@ int RplASUnaryOp::getOperator() const 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() ); + char buffer[256]; + fprintf(fp, "%sUnary %d op: %d Child: %d %s\n", tabs, m_id, m_operator, + m_child == NULL ? 0 : m_child->id(), + m_position->utf8(buffer, sizeof buffer) ); if (m_child != NULL) m_child->dump(fp, indent); } @@ -989,8 +998,10 @@ bool RplASCondition::calcAsBool() 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() ); + char buffer[256]; + fprintf(fp, "%sCondition %d Child: %d %s\n", tabs, m_id, + m_child == NULL ? 0 : m_child->id(), + m_position->utf8(buffer, sizeof buffer)); if (m_child != NULL) m_child->dump(fp, indent); } @@ -1047,9 +1058,11 @@ void RplASIf::execute() void RplASIf::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%sIf id: %d condition: %d then: %d else: %d\n", tabs, + char buffer[256]; + fprintf(fp, "%sIf id: %d condition: %d then: %d else: %d %s\n", tabs, m_id, m_child->id(), m_child2->id(), - m_child3 == NULL ? 0 : m_child3->id()); + m_child3 == NULL ? 0 : m_child3->id(), + m_position->utf8(buffer, sizeof buffer)); m_child->dump(fp, indent + 1); m_child2->dump(fp, indent + 1); if (m_child3 != NULL) @@ -1115,9 +1128,11 @@ void RplASFor::execute() void RplASFor::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%sfor id: %d condition: %d then: %d else: %d\n", tabs, + char buffer[256]; + fprintf(fp, "%sfor id: %d condition: %d then: %d else: %d %s\n", tabs, m_id, m_child->id(), m_child2->id(), - m_child3 == NULL ? 0 : m_child3->id()); + m_child3 == NULL ? 0 : m_child3->id(), + m_position->utf8(buffer, sizeof buffer)); m_child->dump(fp, indent + 1); m_child2->dump(fp, indent + 1); if (m_child3 != NULL) @@ -1181,13 +1196,15 @@ void RplASForCounted::execute() 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", + char buffer[256]; + fprintf(fp, "%sforc id: %d var: %d from: %d to: %d step: %d body: %d %s\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()); + m_child == NULL ? 0 : m_child->id(), + m_position->utf8(buffer, sizeof buffer)); if (m_child2 != NULL) m_child2->dump(fp, indent + 1); if (m_child3 != NULL) @@ -1245,9 +1262,11 @@ void RplASWhile::execute() void RplASWhile::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%swhile id: %d condition: %d body: %d\n", tabs, m_id, + char buffer[256]; + fprintf(fp, "%swhile id: %d condition: %d body: %d %s\n", tabs, m_id, m_child2 == NULL ? 0 : m_child2->id(), - m_child == NULL ? 0 : m_child->id()); + m_child == NULL ? 0 : m_child->id(), + m_position->utf8(buffer, sizeof buffer)); if (m_child2 != NULL) m_child2->dump(fp, indent + 1); if (m_child != NULL) @@ -1299,9 +1318,11 @@ void RplASRepeat::execute() void RplASRepeat::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%srepeat id: %d condition: %d body: %d\n", tabs, m_id, + char buffer[256]; + fprintf(fp, "%srepeat id: %d condition: %d body: %d %s\n", tabs, m_id, m_child2 == NULL ? 0 : m_child2->id(), - m_child == NULL ? 0 : m_child->id()); + m_child == NULL ? 0 : m_child->id(), + m_position->utf8(buffer, sizeof buffer)); if (m_child2 != NULL) m_child2->dump(fp, indent + 1); if (m_child != NULL) @@ -1533,11 +1554,14 @@ void RplASTree::clear() * * @param filename filename * @param flags what to dump: sum of DMP_... flags + * @param header NULL or a text put on the top */ -void RplASTree::dump(const char* filename, int flags) +void RplASTree::dump(const char* filename, int flags, const char* header) { FILE* fp = fopen(filename, "w"); if (fp != NULL){ + if (header != NULL) + fprintf(fp, "%s\n", header); if (flags & DMP_GLOBALS){ m_global->dump(fp, 0, "=== Globals:"); } @@ -1552,7 +1576,7 @@ void RplASTree::dump(const char* filename, int flags) QList::iterator it2; for (it2 = sorted.begin(); it2 != sorted.end(); it2++){ RplSymbolSpace* space = m_modules[*it2]; - space->dump(fp, 1); + space->dump(fp, 0); } } fclose(fp); @@ -1583,9 +1607,11 @@ RplASMethodCall::~RplASMethodCall() void RplASMethodCall::dump(FILE* fp, int indent) { DEFINE_TABS(indent); - fprintf(fp, "%sCall %d instance: %d args: %d\n", tabs, m_id, + char buffer[256]; + fprintf(fp, "%sCall %d instance: %d args: %d %s\n", tabs, m_id, m_child == NULL ? 0 : m_child->id(), - m_child2 == NULL ? 0 : m_child2->id()); + m_child2 == NULL ? 0 : m_child2->id(), + m_position->utf8(buffer, sizeof buffer)); if (m_child != NULL) m_child->dump(fp, indent + 1); if (m_child2 != NULL) @@ -1675,10 +1701,12 @@ void RplASBinaryOp::dump(FILE* fp, int indent) { DEFINE_TABS(indent); const QByteArray& opName = RplLexer::m_active->nameOfOp(m_operator); - fprintf(fp, "%sBinOp %d op: %s (%d) left: %d right: %d\n", tabs, m_id, + char buffer[256]; + fprintf(fp, "%sBinOp %d op: %s (%d) left: %d right: %d %s\n", tabs, m_id, opName.constData(), m_operator, m_child == NULL ? 0 : m_child->id(), - m_child2 == NULL ? 0 : m_child2->id()); + m_child2 == NULL ? 0 : m_child2->id(), + m_position->utf8(buffer, sizeof buffer)); if (m_child != NULL) m_child->dump(fp, indent + 1); if (m_child2 != NULL) @@ -1713,11 +1741,13 @@ RplASMethod::RplASMethod(const QString& name, RplASClass* type) : void RplASMethod::dump(FILE* fp, int indent) { DEFINE_TABS(indent); + char buffer[256]; fprintf(fp, "%sMethod %d %s %s(", tabs, m_id, m_nodeType == NULL ? "" : m_nodeType->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()); + fprintf(fp, ") body: %d args: %d %s\n", m_child == NULL ? 0 : m_child->id(), + m_child2 == NULL ? 0 : m_child2->id(), + m_position->utf8(buffer, sizeof buffer)); } /** @class RplASArgument rplastree.hpp "rplexpr/rplastree.hpp" diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index d8b6f9c..2401042 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -476,8 +476,8 @@ public: 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 - + DMP_ALL = DMP_GLOBALS | DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP, + DMP_NO_GLOBALS = DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP }; typedef QMap SymbolSpaceMap; typedef QList SymbolSpaceStack; @@ -494,8 +494,10 @@ public: RplSymbolSpace* currentSpace() const; RplASClass* findClass(const QString& name); void clear(); - void dump(const char* filename, int flags = DMP_ALL); + void dump(const char* filename, int flags = DMP_ALL, + const char* header = NULL); RplSymbolSpace*findmodule(const QString& name); + RplSourcePosition* copyPosition(); protected: void init(); void destroy(); diff --git a/rplexpr/rpllexer.cpp b/rplexpr/rpllexer.cpp index 1ab955e..edd7e3c 100644 --- a/rplexpr/rpllexer.cpp +++ b/rplexpr/rpllexer.cpp @@ -30,7 +30,7 @@ RplLexer* RplLexer::m_active = NULL; * @param format the reason of the exception * @param ... the values for the placeholders in the format. */ -RplLexException::RplLexException(RplSourcePosition& position, +RplLexException::RplLexException(const RplSourcePosition& position, const char* format, ...) : RplException("") { @@ -356,9 +356,7 @@ RplLexer::RplLexer(RplSource* source, m_waitingToken(NULL), m_token1(TOKEN_UNDEF), m_token2(TOKEN_UNDEF), - m_currentPosition(&m_position1), - m_position1(RplSourcePosition()), - m_position2(RplSourcePosition()), + m_currentPosition(NULL), m_maxTokenLength(64), m_input(), m_currentCol(0), @@ -371,8 +369,7 @@ RplLexer::RplLexer(RplSource* source, { memset(m_prioOfOp, 0, sizeof m_prioOfOp); memset(m_assocOfOp, 0, sizeof m_assocOfOp); - m_currentPosition->setSourceUnit(source->currentReader() - ->currentSourceUnit()); + memset(m_charInfo, 0, sizeof m_charInfo); itemsToVector(keywords, m_keywords, CC_FIRST_KEYWORD, CC_2nd_KEYWORD, CC_3rd_KEYWORD, CC_REST_KEYWORD, m_charInfo); @@ -841,7 +838,7 @@ RplToken* RplLexer::currentToken() const * * @return the current source code position */ -RplSourcePosition* RplLexer::currentPosition() const +const RplSourcePosition* RplLexer::currentPosition() const { return m_currentPosition; } @@ -854,26 +851,33 @@ RplSourcePosition* RplLexer::currentPosition() const RplToken* RplLexer::nextToken() { RplToken* rc = NULL; + const RplSourcePosition* waitingPosition = NULL; int ix; if (m_waitingToken != NULL){ - rc = m_waitingToken; + rc = m_currentToken = m_waitingToken; m_waitingToken = NULL; - m_currentPosition = m_currentPosition == &m_position1 - ? &m_position2 : &m_position1; } else { m_currentToken->clear(); RplReader* reader = m_source->currentReader(); if (reader == NULL) m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE; else { - m_currentPosition->setLineNo(reader->currentSourceUnit()->lineNo()); - m_currentPosition->setColumn(m_currentCol); + if (waitingPosition == NULL) + m_currentPosition = m_source->newPosition(m_currentCol); + else { + m_currentPosition = waitingPosition; + ((RplSourcePosition*)waitingPosition)->setSourceUnit( + m_source->currentReader()->currentSourceUnit()); + ((RplSourcePosition*)waitingPosition)->setColumn(m_currentCol); + waitingPosition = NULL; + } if (! fillInput()){ m_currentToken->m_tokenType = TOKEN_END_OF_SOURCE; } else { QChar cc = m_input.at(0); int cc2 = cc.unicode(); if (cc.isSpace()){ + waitingPosition = m_currentPosition; m_currentToken->m_tokenType = TOKEN_SPACE; ix = 1; while(ix < m_input.size() && m_input.at(ix).isSpace()) @@ -901,6 +905,7 @@ RplToken* RplLexer::nextToken() CC_2nd_COMMENT_START, m_commentStarts); if (rc != NULL) scanComment(); + waitingPosition = m_currentPosition; } if (rc == NULL && (m_charInfo[cc2] & CC_FIRST_OP)){ @@ -956,9 +961,6 @@ void RplLexer::undoLastToken() { m_waitingToken = m_currentToken; m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1; - m_currentPosition = m_currentPosition == &m_position1 - ? &m_position2 : &m_position1; - } /** diff --git a/rplexpr/rpllexer.hpp b/rplexpr/rpllexer.hpp index 20e24ab..89d6cbf 100644 --- a/rplexpr/rpllexer.hpp +++ b/rplexpr/rpllexer.hpp @@ -29,7 +29,7 @@ enum RplTokenType { class RplLexException : public RplException { public: - RplLexException(RplSourcePosition& position, const char* message, ...); + RplLexException(const RplSourcePosition& position, const char* message, ...); }; class RplLexer; @@ -179,7 +179,7 @@ public: int prioOfOp(int op) const; const QByteArray& nameOfOp(int op) const; bool isRightAssociative(int op) const; - RplSourcePosition* currentPosition() const; + const RplSourcePosition* currentPosition() const; RplToken* currentToken() const; private: @@ -216,9 +216,7 @@ protected: RplToken* m_waitingToken; RplToken m_token1; RplToken m_token2; - RplSourcePosition* m_currentPosition; - RplSourcePosition m_position1; - RplSourcePosition m_position2; + const RplSourcePosition* m_currentPosition; int m_maxTokenLength; QString m_input; int m_currentCol; diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp index b179fa2..50950fc 100644 --- a/rplexpr/rplmfparser.cpp +++ b/rplexpr/rplmfparser.cpp @@ -71,12 +71,12 @@ RplASItem* RplMFParser::parseIf() if (! m_lexer.currentToken()->isKeyword(K_THEN)) syntaxError(L_PARSE_IF_NO_THEN, "'then' expected"); rc->setChild(condition); - RplASItem* body = parseBody(); + RplASItem* body = parseBody(K_ELSE, K_FI); 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(); + RplASItem* body = parseBody(K_FI); rc->setChild3(body); } if (! m_lexer.currentToken()->isKeyword(K_FI)) @@ -96,7 +96,7 @@ RplASItem* RplMFParser::parseWhile() if (! m_lexer.currentToken()->isKeyword(K_DO)) syntaxError(L_PARSE_WHILE_NO_DO, "'do' expected"); rc->setChild2(condition); - RplASItem* body = parseBody(); + RplASItem* body = parseBody(K_OD); rc->setChild(body); if (! m_lexer.currentToken()->isKeyword(K_OD)) syntaxError(L_PARSE_WHILE_NO_OD, "'od' expected"); @@ -111,7 +111,7 @@ RplASItem* RplMFParser::parseRepeat() RplASRepeat* rc = new RplASRepeat(); rc->setPosition(m_lexer.currentPosition()); - RplASItem* body = parseBody(); + RplASItem* body = parseBody(K_UNTIL); rc->setChild(body); if (! m_lexer.currentToken()->isKeyword(K_UNTIL)) syntaxError(L_PARSE_REPEAT_NO_UNTIL, "'until' expected"); @@ -200,7 +200,7 @@ RplASItem* RplMFParser::parseVarDefinition(Keyword attribute) RplASItem* RplMFParser::parseOperand(int level) { RplToken* token = m_lexer.nextNonSpaceToken(); - RplSourcePosition* startPosition = m_lexer.currentPosition(); + const RplSourcePosition* startPosition = m_lexer.currentPosition(); RplASItem* rc = NULL; switch(token->tokenType()){ case TOKEN_OPERATOR: @@ -269,9 +269,18 @@ RplASItem* RplMFParser::parseOperand(int level) } } else if (token->id() == O_LBRACKET){ - } else if (token->id() == O_INC || token->id() == O_DEC){ + } else { RplASNamedValue* var = new RplASNamedValue(name); + var->setPosition(startPosition); rc = var; + if (token->id() == O_INC || token->id() == O_DEC){ + RplASUnaryOp* op = new RplASUnaryOp(token->id(), + AST_POST_UNARY_OP); + op->setChild(var); + rc = op; + } else { + m_lexer.undoLastToken(); + } } } break; @@ -369,10 +378,9 @@ RplASItem* RplMFParser::parseExpr() */ RplASItem* RplMFParser::parseExprStatement() { - RplSourcePosition *pos = m_lexer.currentPosition(); RplASItem* item = parseExpr(); RplASExprStatement* statement = new RplASExprStatement(); - statement->setPosition(pos); + statement->setPosition(item->position()); statement->setChild(item); return statement; } @@ -381,8 +389,15 @@ RplASItem* RplMFParser::parseExprStatement() * @brief Parses the body. * * A body is a module, a class region or a method body. + * + * @param keywordStop the first possible keyword which finishes the stm. list + * @param keywordStop2 the 2nd possible keyword which finishes the statements + * @param opStop the first possible delimiting operator + * @param opStop2 the 2nd possible delimiting operator + * @return the first element of the statement list */ -RplASItem* RplMFParser::parseBody() +RplASItem* RplMFParser::parseBody(Keyword keywordStop, Keyword keywordStop2, + Operator opStop, Operator opStop2) { RplToken* token = m_lexer.nextNonSpaceToken(); RplASItem* item = NULL; @@ -391,13 +406,21 @@ RplASItem* RplMFParser::parseBody() bool again = true; while(again) { token = m_lexer.currentToken(); + // eat a superflous ';' + if (token->isOperator(O_SEMICOLON)) + token = m_lexer.nextNonSpaceToken(); try { switch(token->tokenType()) { + case TOKEN_OPERATOR: + if (opStop != O_UNDEF && token->isOperator(opStop, opStop2)){ + again = false; + break; + } + // fall through case TOKEN_STRING: case TOKEN_NUMBER: case TOKEN_REAL: - case TOKEN_OPERATOR: m_lexer.undoLastToken(); item = parseExprStatement(); break; @@ -430,6 +453,8 @@ RplASItem* RplMFParser::parseBody() item = parseVarDefinition((Keyword) token->id()); break; default: + if (token->isKeyword(keywordStop, keywordStop2)) + again = false; break; } break; @@ -449,7 +474,7 @@ RplASItem* RplMFParser::parseBody() default: break; } - if (! token->isTokenType(TOKEN_END_OF_SOURCE)){ + if (again){ if (body == NULL){ body = item; } else { @@ -458,7 +483,14 @@ RplASItem* RplMFParser::parseBody() lastStatement = dynamic_cast(item); if (lastStatement == NULL) assert("wrong item type" == NULL); - token = m_lexer.nextNonSpaceToken(); + token = m_lexer.currentToken(); + if ((keywordStop != K_UNDEF + && token->isKeyword(keywordStop, keywordStop2)) + || (opStop != O_UNDEF + && token->isOperator(opStop, opStop2))) + again = false; + else + token = m_lexer.nextNonSpaceToken(); } } catch(RplSyntaxError exc){ // we look for the end of the statement: @@ -529,7 +561,8 @@ void RplMFParser::parseImport() RplASItem* RplMFParser::parseModule(const QString& name) { m_tree.startModule(name); - RplASItem* body = parseBody(); + // parse until EOF: + RplASItem* body = parseBody(K_UNDEF); m_tree.finishModule(name); return body; } @@ -541,9 +574,8 @@ void RplMFParser::parse() RplSource* source = m_lexer.source(); RplSourceUnit* mainModule = source->currentReader()->currentSourceUnit(); QString mainModuleName = mainModule->name(); - m_tree.startModule(mainModuleName); try { - RplASItem* body = parseBody(); + RplASItem* body = parseModule(mainModuleName); RplSymbolSpace* module = m_tree.findmodule(mainModuleName); if (module != NULL) module->setBody(body); diff --git a/rplexpr/rplmfparser.hpp b/rplexpr/rplmfparser.hpp index d0d7daa..2cda2a5 100644 --- a/rplexpr/rplmfparser.hpp +++ b/rplexpr/rplmfparser.hpp @@ -74,7 +74,8 @@ public: RplASItem* parseFor(); RplASItem* parseVarDefinition(Keyword attribute); RplASItem* parseExpr(); - RplASItem* parseBody(); + RplASItem* parseBody(Keyword keywordStop, Keyword keywordStop2 = K_UNDEF, + Operator opStop = O_UNDEF, Operator opStop2 = O_UNDEF); RplASItem* parseMethodDefinition(); RplASItem* parseClass(); void parseImport(); diff --git a/rplexpr/rplparser.cpp b/rplexpr/rplparser.cpp index 52b389a..a3290a6 100644 --- a/rplexpr/rplparser.cpp +++ b/rplexpr/rplparser.cpp @@ -95,7 +95,7 @@ void RplParser::addMessage(char prefix, int location, const char* format, va_list varList){ char buffer[2048]; QString msg; - RplSourcePosition* pos = m_lexer.currentPosition(); + const RplSourcePosition* pos = m_lexer.currentPosition(); snprintf(buffer, sizeof buffer, "%c%04d %s:%d-%d: ", prefix, location, pos->sourceUnit()->name().toUtf8().constData(), pos->lineNo(), pos->column()); diff --git a/rplexpr/rplsource.cpp b/rplexpr/rplsource.cpp index f7837de..f694219 100644 --- a/rplexpr/rplsource.cpp +++ b/rplexpr/rplsource.cpp @@ -110,42 +110,31 @@ RplSourcePosition::RplSourcePosition(RplSourceUnit* unit, int lineNo, m_sourceUnit(unit), m_lineNo(lineNo), m_column(colNo), - m_caller(unit->reader()->source().sourcePositionStack().top()) + m_caller(NULL) { + RplReader* reader = dynamic_cast(unit->reader()); + m_caller = reader->source().caller(); } /** * @brief Destructor */ RplSourcePosition::~ RplSourcePosition(){ + // That should never occure! + assert(false); } /** - * @brief Copy constructor. + * @brief Placement new operator (for our own memory management). * - * @param source instance to copy + * @param cbSize size of the instance + * @param buffer buffer for the instance + * @return buffer */ -RplSourcePosition::RplSourcePosition(const RplSourcePosition& source) : - m_sourceUnit(source.m_sourceUnit), - m_lineNo(source.m_lineNo), - m_column(source.m_column), - m_caller(source.m_caller) +void*RplSourcePosition::operator new(size_t, void* buffer) { + return buffer; } -/** - * @brief Assignment operator. - * - * @param source instance to copy - * @return the instance itself - */ -RplSourcePosition&RplSourcePosition::operator=(const RplSourcePosition& source) -{ - m_sourceUnit = source.m_sourceUnit; - m_lineNo = source.m_lineNo; - m_column = source.m_column; - m_caller = source.m_caller; - return *this; -} /** * @brief Returns a description of the source position: "- ():". * @@ -157,10 +146,25 @@ QString RplSourcePosition::toString() const if (m_sourceUnit != NULL) rc = m_sourceUnit->name(); QTextStream stream(&rc); - stream << "-" << m_lineNo << " (" << m_column << "): "; + stream << ":" << m_lineNo << ":" << m_column << ": "; return rc; } +/** + * @brief Returns the position as a C string. + * + * @param buffer OUT: the target buffer + * @param bufferSize the size of the buffer + * @return buffer + */ +char* RplSourcePosition::utf8(char buffer[], size_t bufferSize) const +{ + QByteArray module = m_sourceUnit->name().toUtf8(); + snprintf(buffer, bufferSize, "%s:%d:%d", module.constData(), + m_lineNo, m_column); + return buffer; +} + /** * @brief Returns the line number. * @return the line number @@ -217,6 +221,7 @@ RplSourceUnit* RplSourcePosition::sourceUnit() const void RplSourcePosition::setSourceUnit(RplSourceUnit* sourceUnit) { m_sourceUnit = sourceUnit; + m_lineNo = sourceUnit->lineNo(); } @@ -299,6 +304,20 @@ void RplReader::removeSourceUnit() { m_currentSourceUnit = m_source.popSourceUnit(this);; } +/** @class RplSourcePositionBlock rplsource.hpp "rplexpr/rplsource.hpp" + * + * @brief Efficient heap of RplSourcePosition instances. + * + * The RplSourcePosition heap is only growing. The deletion is + * done for all entries together. + * Therefore a simple allocation is possible with blocks. + */ +RplSourcePositionBlock::RplSourcePositionBlock() : + m_successor(NULL) + // m_positions +{ + memset(m_positions, 0, sizeof m_positions); +} /** @class RplSource rplsource.hpp "rplexpr/rplsource.hpp" * @@ -312,7 +331,8 @@ void RplReader::removeSourceUnit() { */ RplSource::RplSource() : m_sourcePositionStack(), - m_sourcePositions(), + m_sourcePositionBlock(NULL), + m_countPositionBlock(RPL_POSITIONS_PER_BLOCK + 1), m_readers(), m_sourceUnits(), m_unitStack(), @@ -335,10 +355,17 @@ RplSource::~RplSource() { void RplSource::destroy() { m_sourcePositionStack.clear(); - m_sourcePositions.clear(); m_readers.clear(); m_sourceUnits.clear(); m_currentReader = NULL; + RplSourcePositionBlock* block = m_sourcePositionBlock; + m_sourcePositionBlock = NULL; + m_countPositionBlock = RPL_POSITIONS_PER_BLOCK + 1; + while(block != NULL){ + RplSourcePositionBlock* last = block; + block = block->m_successor; + delete last; + } } /** @@ -405,9 +432,7 @@ void RplSource::addSourceUnit(RplSourceUnit* unit) { */ bool RplSource::startUnit(const QString& unit, const RplSourcePosition& caller) { - RplSourcePosition* position = new RplSourcePosition(caller); - m_sourcePositions.append(position); - m_sourcePositionStack.push_back(position); + m_sourcePositionStack.push_back(&caller); RplReader* reader = NULL; QList::iterator it; for(it = m_readers.begin(); @@ -468,6 +493,32 @@ RplReader* RplSource::currentReader() { return m_currentReader; } +/** + * @brief Returns a new instance of the current source position. + * + * The storage is done in a block (efficency). + * + * @param colNo the column in the line + * @return a new instance of a source position + */ +const RplSourcePosition* RplSource::newPosition(int colNo) +{ + if (m_countPositionBlock >= RPL_POSITIONS_PER_BLOCK){ + RplSourcePositionBlock* newBlock = new RplSourcePositionBlock; + newBlock->m_successor = m_sourcePositionBlock; + m_sourcePositionBlock = newBlock; + m_countPositionBlock = 0; + } + unsigned offset = m_countPositionBlock * sizeof(RplSourcePosition); + m_countPositionBlock++; + char* posInBlock = &m_sourcePositionBlock->m_positions[offset]; + RplSourceUnit* unit = dynamic_cast( + m_currentReader->currentSourceUnit()); + RplSourcePosition* rc = new (posInBlock) RplSourcePosition( + unit, unit->lineNo(), colNo); + return rc; +} + /** * @brief Resets all states in the source. */ @@ -476,6 +527,18 @@ void RplSource::clear() destroy(); } +/** + * @brief Returns the top position of the source unit stack. + * + * @return NULL: stack is empty
+ * the top of the source unit stack + */ +const RplSourcePosition* RplSource::caller() const +{ + return m_sourcePositionStack.size() == 0 + ? NULL : m_sourcePositionStack.top(); +} + /** @class RplStringSourceUnit rplsource.hpp "rplexpr/rplsource.hpp" * * @brief Stores the state of a string based source unit. @@ -774,3 +837,5 @@ void RplFileReader::addSource(const QDir& dirEntry) { RplFileSourceUnit* unit = new RplFileSourceUnit(dirEntry, this); m_units.insert(m_units.begin(), name, unit); } + + diff --git a/rplexpr/rplsource.hpp b/rplexpr/rplsource.hpp index b9684b3..8284b2d 100644 --- a/rplexpr/rplsource.hpp +++ b/rplexpr/rplsource.hpp @@ -34,7 +34,11 @@ public: RplSourcePosition(); RplSourcePosition(RplSourceUnit* unit, int lineNo, int colNo); ~ RplSourcePosition(); + void* operator new(size_t cbSize, void* buffer); +private: + /// forbid usage of the copy constructor! RplSourcePosition(const RplSourcePosition& source); + /// forbid usage of the the assignment! RplSourcePosition& operator=(const RplSourcePosition& source); public: QString toString() const; @@ -46,7 +50,7 @@ public: RplSourceUnit* sourceUnit() const; void setSourceUnit(RplSourceUnit* sourceUnit); - + char*utf8(char buffer[], size_t bufferSize) const; private: RplSourceUnit* m_sourceUnit; int m_lineNo; @@ -106,6 +110,15 @@ protected: RplSource& m_source; }; +#define RPL_POSITIONS_PER_BLOCK 512 +class RplSourcePositionBlock{ + friend class RplSource; +public: + RplSourcePositionBlock(); +private: + RplSourcePositionBlock* m_successor; + char m_positions[RPL_POSITIONS_PER_BLOCK * sizeof(RplSourcePosition)]; +}; class RplSource { public: @@ -123,13 +136,16 @@ public: void pushSourceUnit(RplSourceUnit* unit); RplSourceUnit* popSourceUnit(RplReader* reader); RplReader* currentReader(); + const RplSourcePosition* newPosition(int colNo); void clear(); + const RplSourcePosition* caller() const; protected: void destroy(); protected: // stack of the info about the stacked (open) source units: QStack m_sourcePositionStack; - QList m_sourcePositions; + RplSourcePositionBlock* m_sourcePositionBlock; + int m_countPositionBlock; QList m_readers; QList m_sourceUnits; // setCurrentSourceUnit() pushes one entry, removeSourceUnit() pops it diff --git a/test/rplmfparser/ifTest1.txt b/test/rplmfparser/ifTest1.txt new file mode 100644 index 0000000..05afd0c --- /dev/null +++ b/test/rplmfparser/ifTest1.txt @@ -0,0 +1,29 @@ +Int a; +Int b; +a = b = 2; +if 11 < 12 +then a = 13 * 14 +else a = 15 / 16 +fi += (module) parent: global +== Classes: +== Variables: +== Body: +varDef a (Int) id: 1 succ: 2 attr: 0x0 :1:4 +varDef b (Int) id: 2 succ: 8 attr: 0x0 :2:4 +Expr id: 8 succ: 9 expr: 4 :3:2 + BinOp 4 op: = (5) left: 3 right: 5 :3:2 + namedValue a id: 3 attr: 0x0 :3:2 + namedValue b id: 5 attr: 0x0 :3:6 +If id: 9 condition: 11 then: 18 else: 24 :3:11 + BinOp 11 op: < (21) left: 10 right: 12 :4:6 + const id: 10 value: 11 :4:3 + const id: 12 value: 12 :4:8 + Expr id: 18 succ: 0 expr: 14 :5:7 + BinOp 14 op: = (5) left: 13 right: 15 :5:7 + namedValue a id: 13 attr: 0x0 :5:7 + const id: 15 value: 13 :5:9 + Expr id: 24 succ: 0 expr: 20 :6:7 + BinOp 20 op: = (5) left: 19 right: 21 :6:7 + namedValue a id: 19 attr: 0x0 :6:7 + const id: 21 value: 15 :6:9 diff --git a/test/rplmfparser/ifTest2.txt b/test/rplmfparser/ifTest2.txt new file mode 100644 index 0000000..509fbe2 --- /dev/null +++ b/test/rplmfparser/ifTest2.txt @@ -0,0 +1,14 @@ +Str x; if 7 < 6 then x = '123'; fi += (module) parent: global +== Classes: +== Variables: +== Body: +varDef x (Str) id: 25 succ: 26 attr: 0x0 :1:4 +If id: 26 condition: 28 then: 33 else: 0 :1:7 + BinOp 28 op: < (21) left: 27 right: 29 :1:12 + const id: 27 value: 7 :1:10 + const id: 29 value: 6 :1:14 + Expr id: 33 succ: 0 expr: 31 :1:23 + BinOp 31 op: = (5) left: 30 right: 32 :1:23 + namedValue x id: 30 attr: 0x0 :1:23 + const id: 32 value: '123' :1:25 diff --git a/test/rplmfparser/whileTest.txt b/test/rplmfparser/whileTest.txt new file mode 100644 index 0000000..d5744d3 --- /dev/null +++ b/test/rplmfparser/whileTest.txt @@ -0,0 +1,13 @@ += (module) parent: global +== Classes: +== Variables: +== Body: +varDef a (Int) id: 1 succ: 3 attr: 0x0 + const id: 2 value: 20 +while id: 3 condition: 5 body: 9 + BinOp 5 op: < (21) left: 4 right: 6 + const id: 4 value: 3 + const id: 6 value: 5 + Expr id: 9 succ: 0 expr: 7 + BinOp 7 op: = (5) left: 0 right: 8 + const id: 8 value: 7 diff --git a/unittests/rplmfparser_test.cpp b/unittests/rplmfparser_test.cpp index 011652a..244a0f0 100644 --- a/unittests/rplmfparser_test.cpp +++ b/unittests/rplmfparser_test.cpp @@ -15,6 +15,7 @@ private: RplSource m_source; RplASTree m_tree; RplStringReader m_reader; + const char* m_currentSource; public: TestRplMFParser() : RplTest("RplMFParser"), @@ -26,6 +27,7 @@ public: } protected: void setSource(const char* content){ + m_currentSource = content; m_tree.clear(); m_source.clear(); m_reader.clear(); @@ -42,7 +44,7 @@ private: fnExpected += (char) QDir::separator().toLatin1(); fnExpected += fileExpected; QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser"); - m_tree.dump(fnCurrent); + m_tree.dump(fnCurrent, RplASTree::DMP_NO_GLOBALS, m_currentSource); assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), __FILE__, lineNo); } @@ -62,7 +64,44 @@ public: checkAST("defTest.txt", __LINE__); } + void ifTest(){ + setSource("Int a;\nInt b;\na = b = 2;\nif 11 < 12\nthen a = 13 * 14\nelse a = 15 / 16\nfi"); + // setSource("Int a; if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi"); + RplMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("ifTest1.txt", __LINE__); + setSource("Str x; if 7 < 6 then x = '123'; fi"); + parser.parse(); + checkAST("ifTest2.txt", __LINE__); + } + void whileTest(){ + setSource("Int a = 20; while 3 < 5 do a = 7 od"); + RplMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("whileTest.txt", __LINE__); + } + + void repeatTest(){ + setSource("Int a; repeat a++; until a != 2 * 3;"); + RplMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("repeatTest.txt", __LINE__); + } + void forCTest(){ + setSource("Int a; for b from 1 to 10 step 2 do a += 1; od"); + RplMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("forC1.txt", __LINE__); + setSource("Int a; for to 10 do a += 1 od"); + parser.parse(); + checkAST("forC2.txt", __LINE__); + } + virtual void doIt(void) { + ifTest(); + whileTest(); + repeatTest(); + forCTest(); defTest(); baseTest(); } diff --git a/unittests/rplqstring_test.cpp b/unittests/rplqstring_test.cpp index c2f7698..a048ab7 100644 --- a/unittests/rplqstring_test.cpp +++ b/unittests/rplqstring_test.cpp @@ -97,8 +97,17 @@ public: checkE(-1, RplQString::valueOfHexDigit('a' - 1)); checkE(-1, RplQString::valueOfHexDigit('f' + 1)); } + void testUtf8(){ + QString name = "Heinz Müller"; + char buffer[32]; + checkE("Heinz Müller", RplQString::utf8(name, buffer, sizeof buffer)); + memset(buffer, 'x', sizeof buffer); + checkE("Heinz", RplQString::utf8(name, buffer, (size_t) (5+1))); + checkE(buffer[6], 'x'); + } virtual void doIt(void) { + testUtf8(); testLengthOfUInt64(); testLengthOfUInt(); testLengthOfReal();