#include <QtMath>
typedef unsigned char uint8_t;
+#define RPL_UNUSED(x) (void)(x)
+
#include "rplmodules.hpp"
#include "rplcore/rpllogger.hpp"
#include "rplcore/rplexception.hpp"
{
return NULL;
}
+
+/**
+ * @brief Writes the content of the instance into a file.
+ *
+ * @param fp the target file
+ * @param indent nesting level: so many tabs will be used as prefix
+ * @param header NULL or the headline
+ */
+void RplSymbolSpace::dump(FILE* fp, int indent, const char* header)
+{
+ char tabs[32];
+ memset(tabs, '\t', sizeof tabs);
+ tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0';
+ if (header != NULL)
+ fprintf(fp, "%s%s\n", tabs, header);
+ fprintf(fp, "%s= %s (%s) parent: %s\n", tabs, m_name.toUtf8().constData(),
+ spaceTypeName(m_type),
+ m_parent == NULL ? "<none>" : m_parent->name().toUtf8().constData());
+ fprintf(fp, "%s== Classes:\n", tabs);
+ QList<QString> sorted;
+ sorted.reserve(m_classes.size());
+ ClassMap::iterator it;
+ for (it = m_classes.begin(); it != m_classes.end(); it++){
+ sorted.append(it.key());
+ }
+ qSort(sorted.begin(), sorted.end(), qLess<QString>());
+ QList<QString>::iterator it2;
+ for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
+ RplASClass* clazz = m_classes[*it2];
+ clazz->dump(fp, indent + 1);
+ }
+
+ fprintf(fp, "== Variables:\n");
+ sorted.clear();
+ sorted.reserve(m_variables.size());
+ VariableMap::iterator it3;
+ for (it3 = m_variables.begin(); it3 != m_variables.end(); it3++){
+ sorted.append(it3.key());
+ }
+ qSort(sorted.begin(), sorted.end(), qLess<QString>());
+ QList<QString>::iterator it4;
+ for (it4 = sorted.begin(); it4 != sorted.end(); it4++){
+ RplVariable* var = m_variables[*it4];
+ var->dump(fp, indent + 1);
+ }
+ fprintf(fp, "== Body:\n");
+ m_body->dump(fp, indent + 1);
+}
+
+/**
+ * @brief Returns the name of a space type.
+ *
+ * @param type type to inspect
+ * @return the name of the type
+ */
+const char*RplSymbolSpace::spaceTypeName(RplSymbolSpace::SymbolSpaceType type)
+{
+ const char* rc = NULL;
+ switch(type){
+ case SST_UNDEF:
+ rc = "undef";
+ break;
+ case SST_GLOBAL:
+ rc = "global";
+ break;
+ case SST_MODULE:
+ rc = "module";
+ break;
+ case SST_CLASS:
+ rc = "class";
+ break;
+ case SST_METHOD:
+ rc = "method";
+ break;
+ default:
+ rc = "?";
+ break;
+ }
+ return rc;
+}
/**
* @brief Returns the name of the symbol space.
*
* @param source NULL or a source to copy
* @return NULL
*/
-void* RplASBoolean::newValueInstance(void* source) const
+void* RplASBoolean::newValueInstance(void*) const
{
return NULL;
}
*
* @param object object to destroy
*/
-void RplASBoolean::destroyValueInstance(void* object) const
+void RplASBoolean::destroyValueInstance(void*) const
{
}
* @param object the object to test (with type QList*)
* @return false
*/
-bool RplASBoolean::boolValueOf(void* object) const
+bool RplASBoolean::boolValueOf(void*) const
{
return false;
}
* @param object the object to convert
* @return a string describing the <code>object</code>
*/
-QString RplASBoolean::toString(void* object, int maxLength) const
+QString RplASBoolean::toString(void* object, int) const
{
return ((RplASVariant*) object)->asBool() ? "True" : "False";
}
* @param source NULL or a source to copy
* @return NULL
*/
-void* RplASFloat::newValueInstance(void* source) const
+void* RplASFloat::newValueInstance(void*) const
{
return NULL;
}
*
* @param object object to destroy
*/
-void RplASFloat::destroyValueInstance(void* object) const
+void RplASFloat::destroyValueInstance(void*) const
{
}
* @param object the object to test
* @return false
*/
-bool RplASFloat::boolValueOf(void* object) const
+bool RplASFloat::boolValueOf(void*) const
{
return false;
}
* @param object the object to convert
* @return a string describing the <code>object</code>
*/
-QString RplASFloat::toString(void* object, int maxLength) const
+QString RplASFloat::toString(void* object, int) const
{
QString rc;
rc.sprintf("%f", ((RplASVariant *) object)->asFloat());
* @param object the object to test
* @return false
*/
-bool RplASInteger::boolValueOf(void* object) const
+bool RplASInteger::boolValueOf(void*) const
{
return false;
}
return rc;
}
+
+/** @class RplVariable rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a variable of a symbol space.
+ */
+
+/**
+ * @brief Constructor.
+ */
+RplVariable::RplVariable(const QString& name) :
+ m_name(name),
+ m_namespace(NULL),
+ m_value(),
+ m_type(NULL)
+{
+
+}
+
+/**
+ * @brief Writes the content of the instance into a file.
+ *
+ * @param fp the target file
+ * @param indent nesting level: so many tabs will be used as prefix
+ * @param header NULL or the headline
+ */
+void RplVariable::dump(FILE* fp, int indent)
+{
+ char tabs[32];
+ memset(tabs, '\t', sizeof tabs);
+ tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0';
+
+ QByteArray name1 = m_type == NULL ? "NoneType" : m_type->name().toUtf8();
+ QByteArray name2 = m_name.toUtf8();
+ QByteArray val = m_value.toString().toUtf8();
+ fprintf(fp, "%s%s %s: value: %s\n", tabs,
+ name1.constData(),
+ name2.constData(), val.constData());
+}
class RplSymbolSpace;
class RplVariable {
public:
- RplVariable();
+ RplVariable(const QString& name);
+public:
+ void dump(FILE* fp, int indent);
+
protected:
QString m_name;
// NULL for "simple" variables (int, float, bool)
RplSymbolSpace* m_namespace;
RplASVariant m_value;
- RplASClass* m_class;
+ RplASClass* m_type;
};
class RplSymbolSpace
public:
RplVariable* findVariable(const QString& name) const;
RplASClass* findClass(const QString& name) const;
+ void dump(FILE* fp, int indent, const char* header = NULL);
public:
static void initGlobal(RplSymbolSpace& global);
+ static const char* spaceTypeName(SymbolSpaceType type);
private:
SymbolSpaceType m_type;
QString m_name;
unsigned int RplASItem::m_nextId = 1;
+#define DEFINE_TABS(indent) \
+ char tabs[32]; \
+ memset(tabs, '\t', sizeof tabs); \
+ tabs[(unsigned) indent < sizeof tabs ? indent : sizeof tabs - 1] = '\0'
+
/** @class RplASException rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements a specific exception for the Abstract Syntax Tree.
m_position = position;
}
+/**
+ * @brief Returns the id of the instance.
+ *
+ * @return the id
+ */
+unsigned int RplASItem::id() const
+{
+ return m_id;
+}
+
+
/** @class RplASExpr rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements the abstract base class of value containing items.
value = m_value;
}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASConstant::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sConstant %d value: %s\n", tabs, m_id,
+ m_value.toString().toUtf8().constData());
+}
+
/**
* @brief Returns the value of the constant.
*
{
}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASNamedValue::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sNamedValue %d attr: 0x%x\n", tabs, m_id, m_attributes);
+}
/** @class RplASNode1 rplastree.hpp "rplexpr/rplastree.hpp"
*
return m_operator;
}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASUnaryOp::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sUnary %d op: %d Child: %d\n", tabs, m_id, m_operator,
+ m_child == NULL ? 0 : m_child->id() );
+ if (m_child != NULL)
+ m_child->dump(fp, indent);
+}
+
/** @class RplASStatement rplastree.hpp "rplexpr/rplastree.hpp"
*
delete m_successor;
m_successor = NULL;
}
+/**
+ * @brief Returns the next statement.
+ * @return the next statement of a statement list
+ */
+RplASItem* RplASStatement::successor() const
+{
+ return m_successor;
+}
+
+/**
+ * @brief Sets the next statement.
+ *
+ * @param successor the successor in the statement list
+ */
+void RplASStatement::setSuccessor(RplASItem* successor)
+{
+ m_successor = successor;
+}
+
/** @class RplASCondition rplastree.hpp "rplexpr/rplastree.hpp"
return rc;
}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASCondition::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sCondition %d Child: %d\n", tabs, m_id,
+ m_child == NULL ? 0 : m_child->id() );
+ if (m_child != NULL)
+ m_child->dump(fp, indent);
+}
+
/** @class RplASFor rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements a for statement.
return m_name;
}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASClass::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sClass %s super: %s\n", tabs, m_name.toUtf8().constData(),
+ m_superClass == NULL
+ ? "<none>" : m_superClass->name().toUtf8().constData());
+ QList<QString> sorted;
+ sorted.reserve(m_methods.size());
+ MethodMap::iterator it;
+ for (it = m_methods.begin(); it != m_methods.end(); it++){
+ sorted.append(it.key());
+ }
+ qSort(sorted.begin(), sorted.end(), qLess<QString>());
+ QList<QString>::iterator it2;
+ for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
+ RplASMethod* current = m_methods[*it2];
+ current->dump(fp, indent + 1);
+ }
+}
+
/** @class RplASTree rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements a manager for all parts of an Abstract Syntax Tree.
m_global(new RplSymbolSpace(RplSymbolSpace::SST_GLOBAL, "global", NULL)),
m_modules(),
m_symbolSpaces(),
- m_currentSpace(m_global)
+ m_currentSpace(NULL)
{
- m_symbolSpaces.append(m_global);
+ init();
}
/**
* @brief Destructor.
*/
RplASTree::~RplASTree()
+{
+ destroy();
+}
+
+/**
+ * @brief Initializes the instance.
+ *
+ * Used in the constructor and in clear.
+ */
+void RplASTree::init()
+{
+ m_symbolSpaces.append(m_global);
+ m_currentSpace = m_global;
+}
+
+/**
+ * @brief Frees the resources of the instance.
+ */
+void RplASTree::destroy()
{
SymbolSpaceMap::iterator it;
for (it = m_symbolSpaceHeap.begin(); it != m_symbolSpaceHeap.end(); it++){
return m_currentSpace;
}
+/**
+ * @brief Removes all content from the abstract syntax tree.
+ */
+void RplASTree::clear()
+{
+ destroy();
+ //m_global->clear();
+ m_modules.clear();
+ m_symbolSpaces.clear();
+ init();
+}
+
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param filename filename
+ * @param flags what to dump: sum of DMP_... flags
+ */
+void RplASTree::dump(const char* filename, int flags)
+{
+ FILE* fp = fopen(filename, "w");
+ if (fp != NULL){
+ if (flags & DMP_GLOBALS){
+ m_global->dump(fp, 0, "=== Globals:");
+ }
+ if (flags & DMP_MODULES){
+ QList<QString> sorted;
+ sorted.reserve(m_modules.size());
+ SymbolSpaceMap::iterator it;
+ for (it = m_modules.begin(); it != m_modules.end(); it++){
+ sorted.append(it.key());
+ }
+ qSort(sorted.begin(), sorted.end(), qLess<QString>());
+ QList<QString>::iterator it2;
+ for (it2 = sorted.begin(); it2 != sorted.end(); it2++){
+ RplSymbolSpace* space = m_modules[*it2];
+ space->dump(fp, 1);
+ }
+ }
+ fclose(fp);
+ }
+}
+
/**
* @brief Constructor.
*/
}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASMethodCall::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sCall %d instance: %d args: %d\n", tabs, m_id,
+ m_child == NULL ? 0 : m_child->id(),
+ m_child2 == NULL ? 0 : m_child2->id());
+ if (m_child != NULL)
+ m_child->dump(fp, indent + 1);
+ if (m_child2 != NULL)
+ m_child->dump(fp, indent + 1);
+}
+
void RplASMethodCall::execute()
{
}
*/
RplASArgument* RplASMethodCall::arg1() const
{
- return m_arg1;
+ return dynamic_cast<RplASArgument*>(m_child2);
}
/**
*/
void RplASMethodCall::setArg1(RplASArgument* arg1)
{
- m_arg1 = arg1;
+ m_child2 = arg1;
}
-
+/** @class RplASBinaryOp rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements binary operator for the Abstract Syntax Tree.
+ */
+/**
+ * @brief Constructor.
+ */
RplASBinaryOp::RplASBinaryOp() :
RplASNode2(AST_BINARY_OP),
m_operator(0)
{
}
+/**
+ * @brief Returns the operator.
+ *
+ * @return the operator
+ */
int RplASBinaryOp::getOperator() const
{
return m_operator;
}
+/**
+ * @brief Sets the operator.
+ *
+ * @param op the operator
+ */
void RplASBinaryOp::setOperator(int op)
{
m_operator = op;
}
+/**
+ * @brief Writes the internals into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASBinaryOp::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sBinOp %d op: %d left: %d right: %d\n", tabs, m_id, m_operator,
+ m_child == NULL ? 0 : m_child->id(),
+ m_child2 == NULL ? 0 : m_child2->id());
+ if (m_child != NULL)
+ m_child->dump(fp, indent + 1);
+ if (m_child2 != NULL)
+ m_child->dump(fp, indent + 1);
+}
+
+/** @class RplASMethod rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a method definition for the Abstract Syntax Tree.
+ *
+ * The special case "function" (a method without class) is included.
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param name the method name
+ * @param type the method result type
+ */
+RplASMethod::RplASMethod(const QString& name, RplASClass* type) :
+ RplASNode2(AST_METHOD),
+ m_name(name),
+ m_type(type)
+{
+}
+
+/**
+ * @brief Writes the internals of the instance into a file.
+ *
+ * @param fp target file
+ * @param indent nesting level
+ */
+void RplASMethod::dump(FILE* fp, int indent)
+{
+ DEFINE_TABS(indent);
+ fprintf(fp, "%sMethod %d %s %s(", tabs, m_id,
+ m_type == NULL ? "<NoneType>" : m_type->name().toUtf8().constData(),
+ m_name.toUtf8().constData());
+ fprintf(fp, ") body: %d args: %d\n", m_child == NULL ? 0 : m_child->id(),
+ m_child2 == NULL ? 0 : m_child2->id());
+}
+
+/** @class RplASArgument rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements an argument of a method for the Abstract Syntax Tree.
+ */
+/**
+ * @brief RplASArgument::RplASArgument
+ */
+RplASArgument::RplASArgument() :
+ RplASNode2(AST_ARGUMENT),
+ RplASStatement()
+{
+}
AST_CONSTANT,
AST_NAMED_VALUE,
AST_METHOD,
+ AST_ARGUMENT,
AST_INTRINSIC_METHOD,
AST_PRE_UNARY_OP,
AST_POST_UNARY_OP,
public:
const RplSourcePosition* position() const;
void setPosition(const RplSourcePosition* position);
+ unsigned int id() const;
+public:
+ /**
+ * @brief Writes the content of the instance into a file.
+ *
+ * @param fp the target file
+ * @param indent nesting level: so many tabs will be used as prefix
+ * @param header NULL or the headline
+ */
+ virtual void dump(FILE* fp, int indent) = 0;
protected:
unsigned int m_id:16;
RplASItemType m_type:8;
public:
virtual void calc(RplASVariant& value);
public:
+ virtual void dump(FILE* fp, int indent);
RplASVariant& value();
private:
RplASVariant m_value;
QString name() const;
public:
virtual void calc(RplASVariant& value);
+ void dump(FILE* fp, int indent);
private:
QString m_name;
int m_attributes;
RplASUnaryOp(int op, RplASItemType type);
public:
int getOperator() const;
+ void dump(FILE* fp, int indent);
private:
int m_operator;
public:
int getOperator() const;
void setOperator(int op);
-
+ void dump(FILE* fp, int indent);
private:
int m_operator;
};
virtual ~RplASStatement();
public:
virtual void execute() = 0;
+ RplASItem* successor() const;
+ void setSuccessor(RplASItem* successor);
+
private:
RplASItem* m_successor;
};
public:
void calc(RplASVariant& value);
bool calcAsBool();
+ void dump(FILE* fp, int indent);
};
class RplASFor : public RplASNode4, public RplASStatement
{
public:
RplASArgument();
- virtual ~RplASArgument();
};
class RplASMethod;
RplASMethodCall();
virtual ~RplASMethodCall();
public:
+ void dump(FILE* fp, int indent);
virtual void execute();
public:
RplASMethod* method() const;
void setMethod(RplASMethod* method);
- RplASArgument* arg1() const;
+ RplASArgument*arg1() const;
void setArg1(RplASArgument* arg1);
-
private:
RplASMethod* m_method;
- RplASArgument* m_arg1;
+ // body is child
+ // arg1 is child2
};
class RplParameter : RplASItem
class RplASMethod : public RplASNode2
{
public:
- RplASMethod();
+ RplASMethod(const QString& name, RplASClass* type);
public:
void execute();
+ void dump(FILE* fp, int indent);
private:
QString m_name;
+ RplASClass* m_type;
+ // body is m_child
+ // param1 is m_child2
};
class RplASClass {
+public:
+ typedef QMap<QString, RplASMethod*> MethodMap;
public:
RplASClass(const QString& name);
public:
virtual QString toString(void *object, int maxLength = 80) const = 0;
public:
const QString& name() const;
+ virtual void dump(FILE* fp, int indent);
protected:
QString m_name;
- QMap<QString, RplASMethod*> m_methods;
+ MethodMap m_methods;
const RplASClass* m_superClass;
};
class RplASTree
{
public:
+ enum {
+ DMP_NONE,
+ DMP_GLOBALS = 1<<1,
+ DMP_MODULES = 1<<2,
+ DMP_SPACE_STACK = 1<<3,
+ DMP_SPACE_HEAP = 1<<4,
+ DMP_ALL = DMP_GLOBALS | DMP_MODULES | DMP_SPACE_STACK | DMP_SPACE_HEAP
+
+ };
typedef QMap<QString, RplSymbolSpace*> SymbolSpaceMap;
typedef QList<RplSymbolSpace*> SymbolSpaceStack;
public:
SymbolSpaceStack& symbolSpaces();
RplSymbolSpace* currentSpace() const;
RplASClass* findClass(const QString& name);
-
+ void clear();
+ void dump(const char* filename, int flags = DMP_ALL);
+protected:
+ void init();
+ void destroy();
private:
// the mother of all symbol spaces.
RplSymbolSpace* m_global;
*/
RplToken*RplLexer::peekNonSpaceToken()
{
- nextNonSpaceToken();
+ RplToken* token = nextNonSpaceToken();
undoLastToken();
+ return token;
}
/**
* @brief Returns the maximal length of a token
*/
int RplLexer::prioOfOp(int op) const
{
- int rc = op > 0 && op < sizeof m_prioOfOp / sizeof m_prioOfOp[0]
+ int rc = op > 0 && (unsigned) op < sizeof m_prioOfOp / sizeof m_prioOfOp[0]
? m_prioOfOp[op] : 0;
return rc;
}
RplToken* token;
RplSourcePosition* start = m_lexer.currentPosition();
RplASItem* top = NULL;
- RplASItem* item;
+ RplASItem* item = NULL;
int lastPrio = -1;
bool again = true;
do {
break;
}
} while(again);
-
+ return top;
}
/**
{
RplToken* token = m_lexer.nextNonSpaceToken();
RplASItem* item = NULL;
- switch(token->tokenType())
- {
- case TOKEN_STRING:
- case TOKEN_NUMBER:
- case TOKEN_REAL:
- case TOKEN_OPERATOR:
- m_lexer.undoLastToken();
- item = parseExpr();
- break;
- case TOKEN_KEYWORD:
- switch (token->id()){
- case K_IF:
- item = parseIf();
- break;
- case K_WHILE:
- item = parseWhile();
- break;
- case K_REPEAT:
- item = parseRepeat();
- break;
- case K_FOR:
- item = parseFor();
- break;
- case K_CLASS:
- item = parseClass();
- break;
- case K_FUNCTION:
- case K_GENERATOR:
- item = parseMethodDefinition();
- break;
- case K_IMPORT:
- parseImport();
- break;
- case K_CONST:
- case K_LAZY:
- item = parseDefinition(NULL, (Keyword) token->id());
+ RplASItem* body = NULL;
+ RplASStatement* lastStatement = NULL;
+ bool again = true;
+ while(again) {
+ switch(token->tokenType())
+ {
+ case TOKEN_STRING:
+ case TOKEN_NUMBER:
+ case TOKEN_REAL:
+ case TOKEN_OPERATOR:
+ m_lexer.undoLastToken();
+ item = parseExpr();
break;
- case K_INT:
- item = parseDefinition(&RplASInteger::m_instance, K_UNDEF);
+ case TOKEN_KEYWORD:
+ switch (token->id()){
+ case K_IF:
+ item = parseIf();
+ break;
+ case K_WHILE:
+ item = parseWhile();
+ break;
+ case K_REPEAT:
+ item = parseRepeat();
+ break;
+ case K_FOR:
+ item = parseFor();
+ break;
+ case K_CLASS:
+ item = parseClass();
+ break;
+ case K_FUNCTION:
+ case K_GENERATOR:
+ item = parseMethodDefinition();
+ break;
+ case K_IMPORT:
+ parseImport();
+ break;
+ case K_CONST:
+ case K_LAZY:
+ item = parseDefinition(NULL, (Keyword) token->id());
+ break;
+ case K_INT:
+ item = parseDefinition(&RplASInteger::m_instance, K_UNDEF);
+ break;
+ case K_FLOAT:
+ parseDefinition(&RplASFloat::m_instance, K_UNDEF);
+ break;
+ case K_BOOL:
+ parseDefinition(&RplASBoolean::m_instance, K_UNDEF);
+ break;
+ default:
+ break;
+ }
break;
- case K_FLOAT:
- parseDefinition(&RplASFloat::m_instance, K_UNDEF);
+ case TOKEN_ID:
+ {
+ RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString());
+ if (clazz != NULL){
+ item = parseDefinition(clazz, K_UNDEF);
+ } else {
+ m_lexer.undoLastToken();
+ item = parseExpr();
+ }
break;
- case K_BOOL:
- parseDefinition(&RplASBoolean::m_instance, K_UNDEF);
+ }
+ case TOKEN_END_OF_SOURCE:
+ again = false;
break;
default:
break;
}
- break;
- case TOKEN_ID:
- {
- RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString());
- if (clazz != NULL){
- item = parseDefinition(clazz, K_UNDEF);
+ if (body == NULL){
+ body = item;
} else {
- m_lexer.undoLastToken();
- item = parseExpr();
+ lastStatement->setSuccessor(item);
}
- break;
+ lastStatement = dynamic_cast<RplASStatement*>(item);
}
- case TOKEN_END_OF_SOURCE:
- break;
- default:
- break;
- }
- //@ToDo: add item to list
- return NULL;
+ return body;
}
/**
RplASItem* RplMFParser::parseModule(const QString& name)
{
m_tree.startModule(name);
- parseBody();
+ RplASItem* body = parseBody();
m_tree.finishModule(name);
+ return body;
}
/**
* @brief Parse the input given by the source.
/**
* @brief Parses an argument list.
+ *
* @return the first element of the argument list
*/
-RplASArgument*RplMFParser::parseArguments()
+RplASArgument* RplMFParser::parseArguments()
{
-
+ return NULL;
}
O_LPARENTH, O_RPARENT, O_LBRACKET, O_RBRACKET
};
#define IS_BINARY_OP(op) ((op) >= O_ASSIGN && op <= O_DOT)
-#define IS_UNARY_OP(op) (op==O_PLUS || op==O_MINUS || op>=O_NOT && op<=O_DEC)
+#define IS_UNARY_OP(op) (op==O_PLUS || op==O_MINUS || (op>=O_NOT && op<=O_DEC))
/// \n separates the priority classes
#define MF_OPERATORS ";; ; , :\n" \
"= += -= /= *= %= **= |= &= <<= >>= >>>=\n" \
* @brief Destructor.
*/
RplSource::~RplSource() {
+ destroy();
+}
+
+/**
+ * @brief Frees the resources of the instance.
+ */
+void RplSource::destroy()
+{
+ m_sourcePositionStack.clear();
+ m_sourcePositions.clear();
+ m_readers.clear();
+ m_sourceUnits.clear();
+ m_currentReader = NULL;
}
/**
return m_currentReader;
}
+/**
+ * @brief Resets all states in the source.
+ */
+void RplSource::clear()
+{
+ destroy();
+}
+
/** @class RplStringSourceUnit rplsource.hpp "rplexpr/rplsource.hpp"
*
* @brief Stores the state of a string based source unit.
m_currentSourceUnit = unit;
}
+/**
+ * @brief Replaces the content of a source unit.
+ *
+ * @param name name of the source unit
+ * @param content new content
+ */
+void RplStringReader::replaceSource(const QString& name, const QString& content)
+{
+ if (m_units.contains(name)){
+ RplStringSourceUnit* unit = dynamic_cast<RplStringSourceUnit*>(m_units[name]);
+ unit->m_content = content;
+ }
+}
+
/** @class RplFileSourceUnit rplsource.hpp "rplexpr/rplsource.hpp"
*
* @brief Stores the state of a file based source unit.
void pushSourceUnit(RplSourceUnit* unit);
RplSourceUnit* popSourceUnit(RplReader* reader);
RplReader* currentReader();
+ void clear();
+protected:
+ void destroy();
protected:
// stack of the info about the stacked (open) source units:
QStack<const RplSourcePosition*> m_sourcePositionStack;
virtual bool fillBuffer(int maxSize, QString& buffer, bool& hasMore);
public:
void addSource(const QString& name, const QString& content);
+ void replaceSource(const QString& name, const QString& content);
};
class RplFileReader;
private:
RplSource m_source;
RplASTree m_tree;
+ RplStringReader m_reader;
public:
TestRplMFParser() :
RplTest("RplMFParser"),
RplMFParser(m_source, m_tree),
m_source(),
- m_tree()
- {}
+ m_tree(),
+ m_reader(m_source)
+ {
+ m_reader.addSource("<test>", "");
+ m_source.addReader(&m_reader);
+ }
+protected:
+ void setSource(const char* content){
+ m_tree.clear();
+ m_source.clear();
+ m_reader.replaceSource("<test>", content);
+ }
public:
void baseTest(){
+ setSource("2+3*4");
+ RplMFParser parser(m_source, m_tree);
+ parser.parse();
+ }
+ void defTest(){
+ setSource("int i = 3; Str s = 'Hi; List l = [3, 'v4'];");
+ RplMFParser parser(m_source, m_tree);
+ parser.parse();
}
virtual void doIt(void) {
- baseTest();
+ //baseTest();
+ //defTest();
}
};
void testRplMFParser() {
checkE(0, unit->lineNo());
checkOne(6, reader);
checkOne(100, reader);
+ reader.replaceSource("source2", "content2");
+
+ unit = reader.openSourceUnit("source2");
+ QString buffer;
+ bool hasMore;
+ checkT(reader.nextLine(50, buffer, hasMore));
+ checkE("content2", buffer);
+ checkF(hasMore);
}
public: