*pValue = value;
return found ? ix - start : 0;
}
+
+/**
+ * @brief Converts a QString into a utf-8 string
+ *
+ * The expression <code>qstring.toUtf8().constData()</code> 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 <code>buffer</code>
+ */
+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;
+}
: 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
*
* 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
{
}
m_flags(0),
m_position(NULL)
{
-
}
/**
* @brief Destructor.
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));
}
/**
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"
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)
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)
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);
}
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);
}
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)
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)
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)
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)
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)
*
* @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:");
}
QList<QString>::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);
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)
{
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)
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 ? "<NoneType>" : 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"
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<QString, RplSymbolSpace*> SymbolSpaceMap;
typedef QList<RplSymbolSpace*> SymbolSpaceStack;
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();
* @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("")
{
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),
{
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);
*
* @return the current source code position
*/
-RplSourcePosition* RplLexer::currentPosition() const
+const RplSourcePosition* RplLexer::currentPosition() const
{
return m_currentPosition;
}
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())
CC_2nd_COMMENT_START, m_commentStarts);
if (rc != NULL)
scanComment();
+ waitingPosition = m_currentPosition;
}
if (rc == NULL && (m_charInfo[cc2] & CC_FIRST_OP)){
{
m_waitingToken = m_currentToken;
m_currentToken = m_currentToken == &m_token1 ? &m_token2 : &m_token1;
- m_currentPosition = m_currentPosition == &m_position1
- ? &m_position2 : &m_position1;
-
}
/**
class RplLexException : public RplException {
public:
- RplLexException(RplSourcePosition& position, const char* message, ...);
+ RplLexException(const RplSourcePosition& position, const char* message, ...);
};
class RplLexer;
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:
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;
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))
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");
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");
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:
}
} 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;
*/
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;
}
* @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;
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;
item = parseVarDefinition((Keyword) token->id());
break;
default:
+ if (token->isKeyword(keywordStop, keywordStop2))
+ again = false;
break;
}
break;
default:
break;
}
- if (! token->isTokenType(TOKEN_END_OF_SOURCE)){
+ if (again){
if (body == NULL){
body = item;
} else {
lastStatement = dynamic_cast<RplASStatement*>(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:
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;
}
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);
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();
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());
m_sourceUnit(unit),
m_lineNo(lineNo),
m_column(colNo),
- m_caller(unit->reader()->source().sourcePositionStack().top())
+ m_caller(NULL)
{
+ RplReader* reader = dynamic_cast<RplReader*>(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 <code>buffer</code>
*/
-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: "<unit>-<lineNo> (<col>):".
*
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 <code>buffer</code>
+ */
+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
void RplSourcePosition::setSourceUnit(RplSourceUnit* sourceUnit)
{
m_sourceUnit = sourceUnit;
+ m_lineNo = sourceUnit->lineNo();
}
m_currentSourceUnit = m_source.popSourceUnit(this);;
}
+/** @class RplSourcePositionBlock rplsource.hpp "rplexpr/rplsource.hpp"
+ *
+ * @brief Efficient heap of <code>RplSourcePosition</code> instances.
+ *
+ * The <code>RplSourcePosition</code> 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"
*
*/
RplSource::RplSource() :
m_sourcePositionStack(),
- m_sourcePositions(),
+ m_sourcePositionBlock(NULL),
+ m_countPositionBlock(RPL_POSITIONS_PER_BLOCK + 1),
m_readers(),
m_sourceUnits(),
m_unitStack(),
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;
+ }
}
/**
*/
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<RplReader*>::iterator it;
for(it = m_readers.begin();
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<RplSourceUnit*>(
+ m_currentReader->currentSourceUnit());
+ RplSourcePosition* rc = new (posInBlock) RplSourcePosition(
+ unit, unit->lineNo(), colNo);
+ return rc;
+}
+
/**
* @brief Resets all states in the source.
*/
destroy();
}
+/**
+ * @brief Returns the top position of the source unit stack.
+ *
+ * @return NULL: stack is empty<br>
+ * 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.
RplFileSourceUnit* unit = new RplFileSourceUnit(dirEntry, this);
m_units.insert(m_units.begin(), name, unit);
}
+
+
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;
RplSourceUnit* sourceUnit() const;
void setSourceUnit(RplSourceUnit* sourceUnit);
-
+ char*utf8(char buffer[], size_t bufferSize) const;
private:
RplSourceUnit* m_sourceUnit;
int m_lineNo;
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:
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<const RplSourcePosition*> m_sourcePositionStack;
- QList<const RplSourcePosition*> m_sourcePositions;
+ RplSourcePositionBlock* m_sourcePositionBlock;
+ int m_countPositionBlock;
QList<RplReader*> m_readers;
QList<RplSourceUnit*> m_sourceUnits;
// setCurrentSourceUnit() pushes one entry, removeSourceUnit() pops it
--- /dev/null
+Int a;
+Int b;
+a = b = 2;
+if 11 < 12
+then a = 13 * 14
+else a = 15 / 16
+fi
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+varDef a (Int) id: 1 succ: 2 attr: 0x0 <test>:1:4
+varDef b (Int) id: 2 succ: 8 attr: 0x0 <test>:2:4
+Expr id: 8 succ: 9 expr: 4 <test>:3:2
+ BinOp 4 op: = (5) left: 3 right: 5 <test>:3:2
+ namedValue a id: 3 attr: 0x0 <test>:3:2
+ namedValue b id: 5 attr: 0x0 <test>:3:6
+If id: 9 condition: 11 then: 18 else: 24 <test>:3:11
+ BinOp 11 op: < (21) left: 10 right: 12 <test>:4:6
+ const id: 10 value: 11 <test>:4:3
+ const id: 12 value: 12 <test>:4:8
+ Expr id: 18 succ: 0 expr: 14 <test>:5:7
+ BinOp 14 op: = (5) left: 13 right: 15 <test>:5:7
+ namedValue a id: 13 attr: 0x0 <test>:5:7
+ const id: 15 value: 13 <test>:5:9
+ Expr id: 24 succ: 0 expr: 20 <test>:6:7
+ BinOp 20 op: = (5) left: 19 right: 21 <test>:6:7
+ namedValue a id: 19 attr: 0x0 <test>:6:7
+ const id: 21 value: 15 <test>:6:9
--- /dev/null
+Str x; if 7 < 6 then x = '123'; fi
+= <test> (module) parent: global
+== Classes:
+== Variables:
+== Body:
+varDef x (Str) id: 25 succ: 26 attr: 0x0 <test>:1:4
+If id: 26 condition: 28 then: 33 else: 0 <test>:1:7
+ BinOp 28 op: < (21) left: 27 right: 29 <test>:1:12
+ const id: 27 value: 7 <test>:1:10
+ const id: 29 value: 6 <test>:1:14
+ Expr id: 33 succ: 0 expr: 31 <test>:1:23
+ BinOp 31 op: = (5) left: 30 right: 32 <test>:1:23
+ namedValue x id: 30 attr: 0x0 <test>:1:23
+ const id: 32 value: '123' <test>:1:25
--- /dev/null
+= <test> (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
RplSource m_source;
RplASTree m_tree;
RplStringReader m_reader;
+ const char* m_currentSource;
public:
TestRplMFParser() :
RplTest("RplMFParser"),
}
protected:
void setSource(const char* content){
+ m_currentSource = content;
m_tree.clear();
m_source.clear();
m_reader.clear();
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);
}
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();
}
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();