bool read(const char* file);
bool write(const char* file);
void clear();
- const QVector<QByteArray>& getLines() const;
+ const QList<QByteArray>& getLines() const;
virtual bool asBool(const char* key, bool defaultValue) const;
virtual int asInt(const char* key, int defaultValue) const;
void initLogger();
private:
const char* m_file;
- QVector<QByteArray> m_lineList;
+ QList<QByteArray> m_lineList;
bool m_readOnly;
RplLogger* m_logger;
// true: the logger must be destroyed in the destructor
*
* @return the line list
*/
-const QVector<QByteArray>& RplMemoryAppender::getLines() const {
+const QList<QByteArray>& RplMemoryAppender::getLines() const {
return m_lines;
}
public:
virtual void log(RplLoggerLevel level, int location, const char* message,
RplLogger* logger);
- const QVector<QByteArray>& getLines() const;
+ const QList<QByteArray>& getLines() const;
void clear();
private:
- QVector<QByteArray> m_lines;
+ QList<QByteArray> m_lines;
// maximum count of m_lines. If larger the oldest lines will be deleted.
int m_maxLines;
// true: standard prefix (level + datetime) will be stored too.
* @param separator the separator between the items to split
* @return an array with the splitted source
*/
-QVector<QByteArray> RplString::toArray(const char* source,
+QList<QByteArray> RplString::toArray(const char* source,
const char* separator) {
const char* end = source;
- QVector<QByteArray> rc;
+ QList<QByteArray> rc;
rc.reserve(count(source, separator) + 1);
int lengthItem = strlen(separator);
while(*end != '\0') {
static QByteArray replaceNode(const char* source, const char* newNode);
static bool write(const char* file, const char* content = NULL,
const char* mode = "w");
- static QVector<QByteArray> toArray(const char* source, const char* separator);
+ static QList<QByteArray> toArray(const char* source, const char* separator);
static QByteArray toCString(const char* source, int maxLength = -1);
static QByteArray toNumber(int value, const char* format = "%d");
static int lengthOfNumber(const char* text, bool skipTrailingSpaces = false);
bool equal = strcmp(expected, current) == 0;
if(! equal) {
if(strchr(expected, '\n') != NULL || strchr(current, '\n')) {
- QVector<QByteArray> exp = RplString::toArray(expected, "\n");
- QVector<QByteArray> cur = RplString::toArray(current, "\n");
+ QList<QByteArray> exp = RplString::toArray(expected, "\n");
+ QList<QByteArray> cur = RplString::toArray(current, "\n");
equal = assertEquals(exp, cur, file, lineNo);
} else {
int ix = 0;
* @param lineNo the line number containing the test
* @return true: equal
*/
-bool RplTest::assertEquals(const QVector<QByteArray>& expected,
- const QVector<QByteArray>& current, const char* file, int lineNo) {
+bool RplTest::assertEquals(const QList<QByteArray>& expected,
+ const QList<QByteArray>& current, const char* file, int lineNo) {
int nMax = expected.size();
bool rc = true;
if(current.size() < nMax)
*/
bool RplTest::logContains(const char* pattern)
{
- const QVector<QByteArray>& lines = m_memoryAppender.getLines();
+ const QList<QByteArray>& lines = m_memoryAppender.getLines();
QRegularExpression rexpr(pattern);
bool rc = false;
QRegularExpressionMatch match;
const char* file, int lineNo);
bool assertEquals(const char* expected, const QByteArray& current,
const char* file, int lineNo);
- bool assertEquals(const QVector<QByteArray>& expected,
- const QVector<QByteArray>& current, const char* file, int lineNo);
+ bool assertEquals(const QList<QByteArray>& expected,
+ const QList<QByteArray>& current, const char* file, int lineNo);
bool assertTrue(bool condition, const char* file, int lineNo);
bool assertFalse(bool condition, const char* file, int lineNo);
bool assertNull(const void* ptr, const char* file, int lineNo);
#include "rplcore/rplcore.hpp"
#include "rplexpr/rplexpr.hpp"
-/** @class RplASList rplastree.hpp "rplexpr/rplastree.hpp"
+RplASList RplASList::m_instance;
+RplASMap RplASMap::m_instance;
+RplASFloat RplASFloat::m_instance;
+RplASInteger RplASInteger::m_instance;
+RplASString RplASString::m_instance;
+RplASBoolean RplASBoolean::m_instance;
+
+/** @class RplSymbolSpace rplastree.hpp "rplexpr/rplastree.hpp"
*
- * @brief Implements the class of a list.
+ * @brief Implements a symbol space for the parser.
*
- * A list is a container of any values. Values can be selected by the index.
+ * A symbol space is a container of the classes and variables which can be used
+ * at a given moment while compiling.
+ *
+ * A symbol space could have a parent which is a symbol space too and extends
+ * the visible classes / variables.
+ *
+ * If an entry exists more than one time in a symbol space chain only the first
+ * can be seen.
+ *
+ * The "last" parent is named "global" and exists always. It contains the
+ * core classes like String, List and Map and methods like print.
+ *
+ * Each module hit by the compiler builds its own symbol space with global as parent.
+ *
+ * Each class defines a symbol space and takes the symbol space of the superclass
+ * as its parent. If there is no superclass the module's symbol space will be taken.
+ *
+ * Each method defines its own symbol space. The parent may be the symbol space of
+ * the module or of the class.
*/
+
/**
* @brief Constructor.
+ *
+ * @param name the symbol space's name
+ * @param parent the parent of the symbol space
*/
-RplASList::RplASList() :
- RplASClass("List")
+RplSymbolSpace::RplSymbolSpace(RplSymbolSpace::SymbolSpaceType type,
+ const QString &name, RplSymbolSpace *parent) :
+ m_type(type),
+ m_name(name),
+ m_variables(),
+ m_classes(),
+ m_parent(parent),
+ m_body(NULL)
{
+ if (type == SST_GLOBAL){
+ m_classes[RplASInteger::m_instance.name()] = &RplASInteger::m_instance;
+ m_classes[RplASBoolean::m_instance.name()] = &RplASBoolean::m_instance;
+ m_classes[RplASFloat::m_instance.name()] = &RplASBoolean::m_instance;
+ m_classes[RplASString::m_instance.name()] = &RplASString::m_instance;
+ m_classes[RplASList::m_instance.name()] = &RplASList::m_instance;
+ m_classes[RplASMap::m_instance.name()] = &RplASMap::m_instance;
+ }
+
}
+/**
+ * @brief Destructor.
+ */
+RplSymbolSpace::~RplSymbolSpace()
+{
+ QMap<QString, RplVariable*>::iterator it;
+ for (it = m_variables.begin(); it != m_variables.end(); it++){
+ delete it.value();
+ }
+ for (it = m_variables.begin(); it != m_variables.end(); it++){
+ delete it.value();
+ }
+}
+/**
+ * @brief Returns the name of the symbol space.
+ *
+ * @return the name
+ */
+QString RplSymbolSpace::name() const
+{
+ return m_name;
+}
+
+
+/** @class RplASBoolean rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a real value.
+ */
+/**
+ * @brief Constructor.
+ */
+RplASBoolean::RplASBoolean() :
+ RplASClass("Boolean")
+{
+}
/**
* @brief Creates a value object (used in RplASVariant).
*
+ * For Booleans nothing is to do!
+ *
* @param source NULL or a source to copy
- * @return a new value object (specific for the class)
+ * @return NULL
*/
-void* RplASList::newValueInstance(void* source)
+void* RplASBoolean::newValueInstance(void* source) const
{
- QList<RplASVariant*>* rc = new QList<RplASVariant*>();
- if (source != NULL){
- QList* source2 = (QList*) source;
- rc->reserve(source2->size());
- QList<RplASVariant*>::iterator it;
- for (it = source->begin();
- it != source->end();
- it++){
- // deleting in destroyValue():
- rc->append(new RplASValue(*it));
- }
- }
- return (void*) rc;
+ return NULL;
}
/**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
*
- * The object must be created by <code>newValueInstance()</code>.
+ * For Booleans nothing is to do!
*
* @param object object to destroy
*/
-void RplASList::destroyValueInstance(void* object)
+void RplASBoolean::destroyValueInstance(void* object) const
{
- delete (QList*) object;
}
-/** @class RplASMap rplastree.hpp "rplexpr/rplastree.hpp"
+/**
+ * @brief Calculates the boolean value of an class specific object.
*
- * @brief Implements the class of a map.
+ * This method should never be called.
*
- * A map is a container of (key, value) pairs.
- * Values can be selected by the key.
+ * @param object the object to test (with type QList*)
+ * @return false
+ */
+bool RplASBoolean::boolValueOf(void* object) const
+{
+ return false;
+}
+
+/** @class RplASNumber rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a one of the values true and false.
*/
/**
* @brief Constructor.
*/
-RplASMap::RplASMap() :
- RplASClass("Map")
+RplASFloat::RplASFloat() :
+ RplASClass("Boolean")
{
}
+
+RplASFloat::RplASFloat(const QString& name) :
+ RplASClass(name)
+{
+ m_superClass = &RplASFloat::m_instance;
+}
/**
* @brief Creates a value object (used in RplASVariant).
*
+ * For Booleans nothing is to do!
+ *
* @param source NULL or a source to copy
- * @return a new value object (specific for the class)
+ * @return NULL
*/
-void* RplASMap::newValueInstance(void* source)
+void* RplASFloat::newValueInstance(void* source) const
{
- QMap<QString, RplASVariant*>* rc = new QMap<QString, RplASVariant*>();
- if (source != NULL){
- QMap<QString, RplASVariant*>* source2 =
- (QMap<QString, RplASVariant*>*) source;
- rc->reserve(source2->size());
- QMap<QString, RplASVariant*>::iterator it;
- for (it = source->begin();
- it != source->end();
- it++){
- // deleting in destroyValue():
- rc->append(new RplASValue(*it));
- }
- }
- return (void*) rc;
+ return NULL;
}
/**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
*
- * The object must be created by <code>newValueInstance()</code>.
+ * For Booleans nothing is to do!
*
* @param object object to destroy
*/
-void RplASMap::destroyValueInstance(void* object)
+void RplASFloat::destroyValueInstance(void* object) const
+{
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object the object to test
+ * @return false
+ */
+bool RplASFloat::boolValueOf(void* object) const
{
- delete (QMap<QString, RplASVariant*>*) object;
+ return false;
}
+/** @class RplASInteger rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a Boolean.
+ *
+ * A Boolean is a one of the values true and false.
+ */
+/**
+ * @brief Constructor.
+ */
+RplASInteger::RplASInteger() :
+ RplASFloat("Integer")
+{
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object the object to test
+ * @return false
+ */
+bool RplASInteger::boolValueOf(void* object) const
+{
+ return false;
+}
+
+
+
/** @class RplASString rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements the class of a string.
* @param source NULL or a source to copy
* @return a new value object (specific for the class)
*/
-void* RplASString::newValueInstance(void* source)
+void* RplASString::newValueInstance(void* source) const
{
QString* rc = source == NULL ? new QString() : new QString(*(QString*) source);
return (void*) rc;
}
/**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
*
* The object must be created by <code>newValueInstance()</code>.
*
* @param object object to destroy
*/
-void RplASString::destroyValueInstance(void* object)
+void RplASString::destroyValueInstance(void* object) const
{
delete (QString*) object;
}
-/** @class RplASNumber rplastree.hpp "rplexpr/rplastree.hpp"
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * This method should never be called.
+ *
+ * @param object the object to test (a QString* instance)
+ * @return false: the string is empty
+ * true: otherwise
+ */
+bool RplASString::boolValueOf(void* object) const
+{
+ bool rc = false;
+ if (object != NULL){
+ QString* string = static_cast<QString*>(object);
+ if (string == NULL)
+ throw RplException("RplASString.boolValueOf(): not a string");
+ rc = ! string->isEmpty();
+ }
+ return rc;
+}
+
+
+/** @class RplASList rplastree.hpp "rplexpr/rplastree.hpp"
*
- * @brief Implements the class of a Number.
+ * @brief Implements the class of a list.
*
- * A Number is a real value.
+ * A list is a container of any values. Values can be selected by the index.
*/
/**
* @brief Constructor.
*/
-RplASNumber::RplASNumber() :
- RplASClass("Number")
+RplASList::RplASList() :
+ RplASClass("List")
{
}
+
/**
* @brief Creates a value object (used in RplASVariant).
*
* @param source NULL or a source to copy
- * @return NULL
+ * @return a new value object (specific for the class)
+ */
+void* RplASList::newValueInstance(void* source) const
+{
+ ListValueType* rc = new ListValueType();
+ if (source != NULL){
+ ListValueType* source2 = (ListValueType*) source;
+ rc->reserve(source2->size());
+ ListValueType::iterator it;
+ for (it = source2->begin();
+ it != source2->end();
+ it++){
+ // deleting in destroyValue():
+ rc->append(new RplASVariant(*(*it)));
+ }
+ }
+ return (void*) rc;
+}
+
+/**
+ * @brief Destroys the given object.
+ *
+ * The object must be created by <code>newValueInstance()</code>.
+ *
+ * @param object object to destroy
+ */
+void RplASList::destroyValueInstance(void* object) const
+{
+ delete static_cast<ListValueType*>(object);
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * @param object the object to test (with type QList*)
+ * @return false: the list is empty<br>
+ * true: otherwise
+ */
+bool RplASList::boolValueOf(void* object) const
+{
+ bool rc = false;
+ if (object != NULL){
+ ListValueType* list = static_cast<ListValueType*>(object);
+ if (list == NULL)
+ throw RplException("RplASList.boolValueOf(): not a list");
+ rc = ! list->empty();
+ }
+ return rc;
+}
+
+/** @class RplASMap rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the class of a map.
+ *
+ * A map is a container of (key, value) pairs.
+ * Values can be selected by the key.
+ */
+/**
+ * @brief Constructor.
*/
-void* RplASNumber::newValueInstance(void* source)
+RplASMap::RplASMap() :
+ RplASClass("Map")
{
- return null;
+}
+/**
+ * @brief Creates a value object (used in RplASVariant).
+ *
+ * @param source NULL or a source to copy
+ * @return a new value object (specific for the class)
+ */
+void* RplASMap::newValueInstance(void* source) const
+{
+ MapValueType* rc = new MapValueType();
+ if (source != NULL){
+ MapValueType* source2 =
+ static_cast<MapValueType*>(source);
+ // rc->reserve(source2->size());
+ MapValueType::iterator it;
+ for (it = source2->begin(); it != source2->end(); it++){
+ // deleting in destroyValue():
+ const QString& key = it.key();
+ RplASVariant* value = new RplASVariant(*it.value());
+ (*rc)[key] = value;
+ }
+ }
+ return (void*) rc;
}
/**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
*
* The object must be created by <code>newValueInstance()</code>.
*
* @param object object to destroy
*/
-void RplASNumber::destroyValueInstance(void* object)
+void RplASMap::destroyValueInstance(void* object) const
{
+ delete (MapValueType*) object;
+}
+
+/**
+ * @brief Calculates the boolean value of an class specific object.
+ *
+ * @param object the object to test (with type QMap*)
+ * @return
+ */
+bool RplASMap::boolValueOf(void* object) const
+{
+ bool rc = false;
+ if (object != NULL){
+ MapValueType* map = reinterpret_cast<MapValueType*>(object);
+ if (map == NULL)
+ throw RplException("RplASMap.boolValueOf(): not a map");
+ rc = map->empty() > 0;
+ }
+ return rc;
}
#ifndef RPLASCLASSES_HPP
#define RPLASCLASSES_HPP
-class RplASList : public RplASClass {
+class RplSymbolSpace;
+class RplVariable {
public:
- RplASList();
- ~RplASList();
+ RplVariable();
+protected:
+ QString m_name;
+ // NULL for "simple" variables (int, float, bool)
+ RplSymbolSpace* m_namespace;
+ RplASVariant m_value;
+ RplASClass* m_class;
+};
+
+class RplSymbolSpace
+{
+public:
+ enum SymbolSpaceType {
+ SST_UNDEF,
+ SST_GLOBAL,
+ SST_MODULE,
+ SST_CLASS,
+ SST_METHOD
+ };
+
+public:
+ typedef QMap<QString, RplVariable*> VariableMap;
+ typedef QMap<QString, RplASClass*> ClassMap;
+public:
+ RplSymbolSpace(SymbolSpaceType type, const QString& name,
+ RplSymbolSpace* parent);
+ ~RplSymbolSpace();
+public:
+ RplVariable* findVariable(const QString& name) const;
+ RplASClass* findClass(const QString& name) const;
+public:
+ static void initGlobal(RplSymbolSpace& global);
+private:
+ SymbolSpaceType m_type;
+ QString m_name;
+ VariableMap m_variables;
+ ClassMap m_classes;
+ RplSymbolSpace* m_parent;
+ RplASItem* m_body;
public:
- void* newValueInstance(void* source = NULL);
- void destroyValueInstance(void* object);
+ static RplSymbolSpace m_global;
+ QString name() const;
};
-class RplASMap : public RplASClass {
+class RplASBoolean : public RplASClass {
public:
- RplASMap();
- ~RplASMap();
+ RplASBoolean();
+public:
+ void* newValueInstance(void* source = NULL) const;
+ void destroyValueInstance(void* object) const;
+ virtual bool boolValueOf(void* object) const;
public:
- void* newValueInstance(void* source = NULL);
- void destroyValueInstance(void* object);
+ static RplASBoolean m_instance;
};
-class RplASNumber : public RplASClass {
+class RplASFloat : public RplASClass {
+public:
+ RplASFloat();
+ RplASFloat(const QString& name);
+public:
+ void* newValueInstance(void* source = NULL) const;
+ void destroyValueInstance(void* object) const;
+ virtual bool boolValueOf(void* object) const;
+public:
+ static RplASFloat m_instance;
+};
+
+class RplASInteger : public RplASFloat {
+public:
+ RplASInteger();
public:
- RplASNumber();
- ~RplASNumber();
+ virtual bool boolValueOf(void* object) const;
public:
- void* newValueInstance(void* source = NULL);
- void destroyValueInstance(void* object);
+ static RplASInteger m_instance;
};
class RplASString : public RplASClass {
public:
RplASString();
- ~RplASString();
public:
- void* newValueInstance(void* source = NULL);
- void destroyValueInstance(void* object);
+ void* newValueInstance(void* source = NULL) const;
+ void destroyValueInstance(void* object) const;
+ virtual bool boolValueOf(void* object) const;
+public:
+ static RplASString m_instance;
+};
+
+class RplASList : public RplASClass {
+public:
+ typedef QList<RplASVariant*> ListValueType;
+public:
+ RplASList();
+public:
+ void* newValueInstance(void* source = NULL) const;
+ void destroyValueInstance(void* object) const;
+ virtual bool boolValueOf(void* object) const;
+public:
+ static RplASList m_instance;
};
+class RplASMap : public RplASClass {
+public:
+ typedef QMap<QString, RplASVariant*> MapValueType;
+public:
+ RplASMap();
+public:
+ void* newValueInstance(void* source = NULL) const;
+ void destroyValueInstance(void* object) const;
+ virtual bool boolValueOf(void* object) const;
+public:
+ static RplASMap m_instance;
+};
+
+
+
#endif // RPLASCLASSES_HPP
#include "rplcore/rplcore.hpp"
#include "rplexpr/rplexpr.hpp"
+/** @class RplASException rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a specific exception for the Abstract Syntax Tree.
+ */
+
+/**
+ * @brief RplASException::RplASException
+ * @param message
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param position describes the position of the error/warning
+ * @param format the reason of the exception
+ * @param ... the values for the placeholders in the format.
+ */
+RplASException::RplASException(const RplSourcePosition* position,
+ const char* format, ...) :
+ RplException("")
+{
+ char buffer[64000];
+ if (position != NULL)
+ m_message = position->toString().toUtf8();
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof buffer, format, ap);
+ va_end(ap);
+ m_message += buffer;
+}
+
+
/** @class RplASVariant rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements a class which can be one of the basic types.
// m_value
m_class(source.m_class)
{
+ copyValue(source);
+}
+
+/**
+ * @brief Assignment operator.
+ *
+ * @param source the source to copy
+ * @return the instance itself
+ */
+RplASVariant&RplASVariant::operator=(const RplASVariant& source)
+{
+ destroyValue();
+ m_dataType = source.m_dataType;
+ m_class = source.m_class;
+ copyValue(source);
+ return *this;
}
/**
{
switch(source.m_dataType)
{
- case DT_NUMBER:
- m_value.m_number = source.m_value.m_number;
+ case DT_BOOL:
+ m_value.m_bool = source.m_value.m_bool;
break;
- case DT_STRING:
- // deleting in destroyValue():
- m_value.m_string = new QString(source.m_value.m_string);
+ case DT_FLOAT:
+ m_value.m_float = source.m_value.m_float;
break;
- case DT_LIST:
- {
+ case DT_INTEGER:
+ m_value.m_int = source.m_value.m_int;
break;
- }
- case DT_MAP:
- {
- m_value.m_map = new QList<RplASVariant*>();
- m_value.m_map.reserve(source.m_value.m_list.size());
- QList<RplASVariant*>::iterator it;
- for (it = source.m_value.m_list.begin();
- it != source.m_value.m_list.end();
- it++){
- // deleting in destroyValue():
- m_value.m_list.append(new RplASValue(*it));
- }
- break
- }
- case DT_OBJECT:
- // deleting in destroyValue():
- m_value.m_object = m_class->newValueInstance(source.m_value.m_object);
+ case DT_UNDEF:
break;
default:
- break;
+ m_value.m_object = m_class->newValueInstance(source.m_value.m_object);
}
}
*/
void RplASVariant::destroyValue()
{
- switch(source.m_dataType)
+ switch(m_dataType)
{
- case DT_NUMBER:
- break;
- case DT_STRING:
- // deleting in destroyValue():
- m_value.m_string = delete m_value.m_string;
- m_value.m_string = NULL;
- break;
- case DT_LIST:
- delete m_value.m_list;
- m_value.m_list = NULL;
- break;
- case DT_MAP:
- delete m_value.m_map;
- m_value.m_map = NULL;
- break;
- case DT_OBJECT:
- m_map.destroyValueInstance(m_value.m_object);
- m_value.m_object = NULL;
+ case DT_BOOL:
+ case DT_FLOAT:
+ case DT_INTEGER:
+ case DT_UNDEF:
break;
default:
+ m_class->destroyValueInstance(m_value.m_object);
+ m_value.m_object = NULL;
break;
}
}
+/**
+ * @brief Returns the numeric value.
+ *
+ * @return the numeric value
+ * @throw RplException the instance is not a numberic value
+ *
+ */
+qreal RplASVariant::asFloat() const
+{
+ if (m_dataType != DT_FLOAT)
+ throw RplException("RplASVariant::asNumber: not a number: %d",
+ m_dataType);
+ return m_value.m_float;
+}
+/**
+ * @brief Returns the numeric value.
+ *
+ * @return the numeric value
+ * @throw RplException the instance is not a numberic value
+ *
+ */
+int RplASVariant::asInt() const
+{
+ if (m_dataType != DT_INTEGER)
+ throw RplException("RplASVariant::asInt: not an integer: %d",
+ m_dataType);
+ return m_value.m_int;
+}
+
+/**
+ * @brief Returns the boolean value.
+ *
+ * @return the boolean value
+ * @throw RplException the instance is not a boolean value
+ *
+ */
+bool RplASVariant::asBool() const
+{
+ if (m_dataType != DT_BOOL)
+ throw RplException("RplASVariant::asBool: not a boolean: %d",
+ m_dataType);
+ return m_value.m_bool;
+}
+
+/**
+ * @brief Returns the class specific value.
+ *
+ * @param clazz OUT: the class of the instance. May be NULL
+ * @return the class specific value
+ * @throw RplException the instance is not a boolean value
+ *
+ */
+void* RplASVariant::asObject(const RplASClass** clazz) const
+{
+ if (m_dataType != DT_OBJECT)
+ throw RplException("RplASVariant::asObject: not an object: %d",
+ m_dataType);
+ if (clazz != NULL)
+ *clazz = m_class;
+ return m_value.m_object;
+}
+
+/**
+ * @brief Returns the value as string.
+ *
+ * @return the value as string
+ * @throw RplException the instance is not a string value
+ */
+const QString* RplASVariant::asString() const
+{
+ const RplASClass* clazz;
+ const QString* rc = static_cast<const QString*>(asObject(&clazz));
+ if (clazz->name() != "String"){
+ const QString& name = clazz->name();
+ throw RplException("RplASVariant::asString: not an string: %s",
+ name.toUtf8().constData());
+ }
+ return rc;
+}
+
+/**
+ * @brief Make the instance to a numeric value.
+ *
+ * @param number the numeric value.
+ */
+void RplASVariant::setFloat(qreal number)
+{
+ destroyValue();
+ m_dataType = DT_FLOAT;
+ m_value.m_float = number;
+ m_class = &RplASFloat::m_instance;
+}
+
+/**
+ * @brief Make the instance to an integer value.
+ *
+ * @param integer the numeric value.
+ */
+void RplASVariant::setInt(int integer)
+{
+ destroyValue();
+ m_dataType = DT_INTEGER;
+ m_value.m_int = integer;
+ m_class = &RplASInteger::m_instance;
+}
+
+/**
+ * @brief Make the instance to a boolean value.
+ *
+ * @param value the boolean value.
+ */
+void RplASVariant::setBool(bool value)
+{
+ destroyValue();
+ m_dataType = DT_BOOL;
+ m_value.m_bool = value;
+ m_class = &RplASBoolean::m_instance;
+}
+
+/**
+ * @brief Make the instance to a boolean value.
+ *
+ * @param value the string value.
+ */
+void RplASVariant::setString(const QString& string)
+{
+ // deletion in RplASVariant::destroyValue():
+ setObject(new QString(string), &RplASString::m_instance);
+}
+
+/**
+ * @brief Make the instance to an object.
+ *
+ * @param object the class specific value object.
+ */
+void RplASVariant::setObject(void* object, const RplASClass* clazz)
+{
+ destroyValue();
+ m_dataType = DT_OBJECT;
+ m_value.m_object = object;
+ m_class = clazz;
+}
+
+
/** @class RplASItem rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements the abstract base class of all entries of an AST.
{
}
-RplSourcePosition* RplASItem::position() const
+/**
+ * @brief Returns the position of the item in the source code.
+ *
+ * @return the position of the item
+ */
+const RplSourcePosition* RplASItem::position() const
{
return m_position;
}
-void RplASItem::setPosition(RplSourcePosition* position)
+/**
+ * @brief Stores the position in the source code.
+ *
+ * @param position the position to store
+ */
+void RplASItem::setPosition(const RplSourcePosition* position)
{
m_position = position;
}
* @brief Implements the abstract base class of value containing items.
*
*/
-RplASExpr::RplASExpr()
+RplASCalculable::RplASCalculable()
{
}
-/** @class RplASValue rplastree.hpp "rplexpr/rplastree.hpp"
+/** @class RplASConstant rplastree.hpp "rplexpr/rplastree.hpp"
*
- * @brief Implements the abstract base class of all named values, e.g. variables.
+ * @brief Implements a constant for the Abstract Syntax Tree.
*
*/
/**
* @brief Constructor.
*
- * @param type the type of the instance
- * @param name the name of the instance
- * @param isConst true: the value is constant: It is not allowed to change it
*/
-RplASValue::RplASValue(RplASItemType type, const QString& name, boolean isConst) :
- RplASItem(type),
- m_name(name),
- m_isConst(isConst)
+RplASConstant::RplASConstant() :
+ RplASItem(AST_CONSTANT),
+ m_value()
{
}
+
/**
- * @brief Destructor.
+ * @brief Calculates the expression.
+ *
+ * @param value OUT: the calculated value
*/
-RplASValue::~RplASValue()
+void RplASConstant::calc(RplASVariant& value)
{
+ value = m_value;
}
+/**
+ * @brief Returns the value of the constant.
+ *
+ * This method will be used to set the value of the constant:
+ * <pre><code>RplASConstant constant;
+ * constant.value().setString("Jonny");
+ *</code></pre>
+ *
+ * @return the internal value
+ */
+RplASVariant& RplASConstant::value()
+{
+ return m_value;
+}
-/** @class RplASScalar rplastree.hpp "rplexpr/rplastree.hpp"
+/** @class RplASNamedValue rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements the abstract base class of all named values, e.g. variables.
*
- * @brief Implements a variable/constant with exactly one value.
*/
+
/**
- * @brief Constructor
- * @param name
- * @param isConst
+ * @brief Constructor.
+ *
+ * @param name the name of the instance
+ * @param attr a bitmask of <code>Attribute</code> values, e.g. A_CONST
*/
-RplASScalar::RplASScalar(const QString& name, boolean isConst) :
- RplASValue(AST_SCALAR, name, isConst),
- m_value()
+RplASNamedValue::RplASNamedValue(const QString& name, int attributes) :
+ RplASItem(AST_NAMED_VALUE),
+ m_name(name),
+ m_attributes(attributes)
{
}
-
/**
- * @brief Destructor.
+ * @brief Returns the name.
+ *
+ * @return the name
*/
-RplASScalar::~RplASScalar()
+QString RplASNamedValue::name() const
{
+ return m_name;
}
-
/**
- * @brief RplASScalar::calc
- * @return the value of the variable/constant
+ * @brief Calculates the value.
+ *
+ * @param value OUT: the value of the instance
*/
-QVariant RplASScalar::calc()
+void RplASNamedValue::calc(RplASVariant& value)
{
- return m_value;
+
}
/** @class RplASNode1 rplastree.hpp "rplexpr/rplastree.hpp"
delete m_child;
m_child = NULL;
}
+/**
+ * @brief Sets the child.
+ */
+void RplASNode1::setChild(RplASItem* child)
+{
+ m_child = child;
+}
/** @class RplASNode2 rplastree.hpp "rplexpr/rplastree.hpp"
*
m_child3 = NULL;
}
-/** @class RplASBinOp rplastree.hpp "rplexpr/rplastree.hpp"
+/** @class RplASNode4 rplastree.hpp "rplexpr/rplastree.hpp"
*
- * @brief Implements a binary operator.
+ * @brief Implements a inner node of the abstract syntax tree with 3 childs.
+ *
+ * This class is an abstract class.
*/
+
/**
- * @brief Constructor.
- *
- * @param op the operator
+ * @brief RplASNode4::RplASNode4
+ * @param type
*/
-RplASBinOp::RplASBinOp(RplASBinaryOperator op) :
- RplASNode2(type),
- m_op(op)
+RplASNode4::RplASNode4(RplASItemType type) :
+ RplASNode3(type),
+ m_child4(NULL)
{
}
+
/**
* @brief Destructor.
*/
-RplASUnaryOp::~RplASBinOp()
+RplASNode4::~RplASNode4()
{
+ delete m_child4;
+ m_child4 = NULL;
}
/** @class RplASUnaryOp rplastree.hpp "rplexpr/rplastree.hpp"
*
- * @brief Implements a unary operator.
+ * @brief Implements a unary operation.
+ *
+ * This is a operation with one operand, e.g. the boolean not operation.
*/
/**
* @brief Constructor.
- *
- * @param op operator
*/
-RplASUnaryOp::RplASUnaryOp(RplASUnaryOperator op) :
- RplASItem(AST_UNOP),
- m_op(op)
+RplASUnary::RplASUnaryOp(int op) :
+ m_operator(op)
{
}
+
/**
- * @brief Destructor.
+ * @brief Returns the operator of the unary operation.
+ *
+ * @return the operator
*/
-RplASUnaryOp::~RplASUnaryOp()
+int RplASUnary::getOperator() const
{
-
+ return m_operator;
}
+
/** @class RplASStatement rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements a base class for all statements.
m_successor = NULL;
}
+
+/** @class RplASCondition rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a condition.
+ *
+ * The condition is a statement and a RplASExpr and will be used in other
+ * statements like for and while.
+ *
+ */
+/**
+ * @brief Constructor.
+ */
+RplASCondition::RplASCondition() :
+ RplASNode1(AST_CONDITION),
+ RplASCalculable()
+{
+}
+
+void RplASCondition::calc(RplASVariant& value)
+{
+ value.setBool(false);
+ RplASCalculable* node = dynamic_cast<RplASCalculable*>(m_child);
+ if (node == NULL)
+ throw RplASException(m_position, "child of condition is not calculable");
+ node->calc(value);
+}
+/**
+ * @brief Calculates the boolean value and returns it.
+ *
+ * @return the boolean value of the expression
+ */
+bool RplASCondition::calcAsBool()
+{
+ bool rc = false;
+ RplASVariant value;
+ calc(value);
+ switch(value.m_dataType){
+ case RplASVariant::DT_FLOAT:
+ rc = value.m_value.m_float == 0;
+ break;
+ case RplASVariant::DT_BOOL:
+ rc = value.m_value.m_bool;
+ break;
+ case RplASVariant::DT_OBJECT:
+ rc = value.m_class->boolValueOf(value.m_value.m_object);
+ break;
+ default:
+ rc = false;
+ break;
+ }
+ return rc;
+}
+
/** @class RplASFor rplastree.hpp "rplexpr/rplastree.hpp"
*
* @brief Implements a for statement.
* @brief Constructor.
*/
RplASFor::RplASFor() :
- RplASNode3(AST_FOR),
+ RplASNode4(AST_FOR),
RplASStatement()
{
}
{
}
+/**
+ * @brief Executes the statement.
+ *
+ * Meaning of the childs:
+ * m_child: initialization
+ * m_child2: condition
+ * m_child3: forwarding statement
+ * m_child4: body
+ */
void RplASFor::execute()
{
((RplASStatement*) m_child)->execute();
- RplASTerm* condition = (RplASTerm* condition)RplASTerm
+ RplASCondition* condition = dynamic_cast<RplASCondition*>(m_child2);
+ if (condition == NULL)
+ throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
+ "for statement: not a condition");
+ RplASStatement* forwarding = dynamic_cast<RplASStatement*>(m_child3);
+ if (forwarding == NULL)
+ throw RplASException(m_child3 == NULL ? m_position : m_child3->position(),
+ "for statement: forwarding is not a statement");
+ RplASStatement* body = dynamic_cast<RplASStatement*>(m_child4);
+ if (body == NULL)
+ throw RplASException(m_child4 == NULL ? m_position : m_child4->position(),
+ "for statement: body is not a statement");
+ while(condition->calcAsBool()){
+ body->execute();
+ forwarding->execute();
+ }
}
/** @class RplASWhile rplastree.hpp "rplexpr/rplastree.hpp"
{
}
+/**
+ * @brief Return the class name.
+ *
+ * @return the class name
+ */
+const QString& RplASClass::name() const
+{
+ return m_name;
+}
+
+/** @class RplASTree rplastree.hpp "rplexpr/rplastree.hpp"
+ *
+ * @brief Implements a manager for all parts of an Abstract Syntax Tree.
+ *
+ * It contains the global symbol space and maintainance a list of used modules.
+ */
+
+/**
+ * @brief Constructor.
+ */
+RplASTree::RplASTree() :
+ // freed in ~RplASTree()
+ m_global(new RplSymbolSpace(RplSymbolSpace::SST_GLOBAL, "global", NULL)),
+ m_modules(),
+ m_symbolSpaces(),
+ m_currentSpace(m_global)
+{
+ m_symbolSpaces.append(m_global);
+}
+
+/**
+ * @brief Destructor.
+ */
+RplASTree::~RplASTree()
+{
+ SymbolSpaceMap::iterator it;
+ for (it = m_symbolSpaceHeap.begin(); it != m_symbolSpaceHeap.end(); it++){
+ delete it.value();
+ }
+ m_symbolSpaceHeap.clear();
+}
+
+/**
+ * @brief Handles the start of a new module.
+ *
+ * @param name the module's name
+ * @return true: the module is new<br>
+ * false: the module is yet known
+ */
+bool RplASTree::startModule(const QString& name)
+{
+ bool rc = m_modules.contains(name);
+ if (! rc){
+ // m_modules[0] is the "global" symbol space.
+ // freed in ~RplASTree()
+ RplSymbolSpace* space = new RplSymbolSpace(RplSymbolSpace::SST_MODULE,
+ name, m_symbolSpaces[0]);
+ m_symbolSpaceHeap[name] = space;
+ m_modules[name] = space;
+ m_symbolSpaces.append(space);
+ m_currentSpace = space;
+ }
+ return rc;
+}
+
+/**
+ * @brief Handles the end of a module.
+ * @param name the module's name
+ */
+void RplASTree::finishModule(const QString& name)
+{
+ RplSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+ if (top->name() != name)
+ throw RplException("RplASTree::finishModule(): module is not top: %s",
+ name.toUtf8().constData());
+ else {
+ m_symbolSpaces.removeLast();
+ // "global" is always the bottom:
+ m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+ }
+}
+
+/**
+ * @brief Handles the start of a new class definition.
+ * @param name
+ */
+void RplASTree::startClassOrMethod(const QString& name,
+ RplSymbolSpace::SymbolSpaceType type)
+{
+ // the stack m_modules is never empty because of "global" and modules.
+ RplSymbolSpace* parent = m_symbolSpaces[m_symbolSpaces.size() - 1];
+ QString fullName = parent->name() + "." + name;
+ // freed in ~RplASTree()
+ RplSymbolSpace* space = new RplSymbolSpace(type, fullName, parent);
+ m_symbolSpaceHeap[fullName] = space;
+ m_symbolSpaces.append(space);
+ m_currentSpace = space;
+}
+
+/**
+ * @brief Handles the end of a class definition.
+ *
+ * @param name the name of the class (short form)
+ */
+void RplASTree::finishClassOrMethod(const QString& name)
+{
+ RplSymbolSpace* top = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+ if (! top->name().endsWith("." + name))
+ throw RplException("RplASTree::finishModule(): class is not top: %s",
+ name.toUtf8().constData());
+ else {
+ m_symbolSpaces.removeLast();
+ // "global" is the bottom always!
+ m_currentSpace = m_symbolSpaces.at(m_symbolSpaces.size() - 1);
+ }
+}
+
+/**
+ * @brief Returns the stack of the symbol spaces.
+ *
+ * @return the stack with the active symbol spaces
+ */
+RplASTree::SymbolSpaceStack& RplASTree::symbolSpaces()
+{
+ return m_symbolSpaces;
+}
+/**
+ * @brief Returns the current symbol space (top of the stack).
+ *
+ * @return the current symbol space
+ */
+RplSymbolSpace* RplASTree::currentSpace() const
+{
+ return m_currentSpace;
+}
enum RplASItemType {
AST_UNDEF,
- AST_SCALAR,
- AST_MATRIX,
- AST_LIST,
- AST_MAP,
- AST_BINOP,
- AST_UNOP,
- AST_FUNCTION,
- AST_CALL,
+ AST_CONSTANT,
+ AST_NAMED_VALUE,
+ AST_METHOD,
+ AST_INTRINSIC_METHOD,
+ AST_METHOD_CALL,
AST_WHILE,
AST_IF,
+ AST_CONDITION,
AST_FOR,
+ AST_COUNTED_FOR,
AST_SWITCH,
- AST_STATEMENT
-
+ AST_LEAVE,
+ AST_CONTINUE
};
-enum RplASBinaryOperator {
- ASOP_UNDEF,
- ASOP_PLUS,
- ASOP_MINUS,
- ASOP_TIMES,
- ASOP_DIV,
- ASOP_MOD,
- ASOP_OR,
- ASOP_AND,
- ASOP_GT,
- ASOP_LT,
- ASOP_GE,
- ASOP_LE,
- ASOP_EQ,
- ASOP_NE,
- ASOP_ASSIGN,
- ASOP_ASSIGN_PLUS,
- ASOP_ASSIGN_MINUS,
- ASOP_ASSIGN_TIMES,
- ASOP_ASSIGN_DIV,
- ASOP_ASSIGN_MOD
-};
-enum RplASUnaryOperator {
- ASUOP_UNDEF,
- ASUOP_PLUS,
- ASOUP_MINUS,
- ASUOP_POST_DECREMENT,
- ASUOP_PRE_DECREMENT,
- ASUOP_POST_INCREMENT,
- ASUOP_PRE_INCREMENT
+class RplASException : public RplException {
+public:
+ RplASException(const RplSourcePosition* position, const char* message, ...);
};
+
class RplASClass;
+class RplASNamedValue;
+class RplASItem;
+class RplASCondition;
+
class RplASVariant {
public:
enum DataType {
DT_UNDEF,
- DT_NUMBER,
- DT_STRING,
- DT_MAP,
- DT_LIST,
+ DT_FLOAT,
+ DT_INTEGER,
+ DT_BOOL,
DT_OBJECT
};
-
+ friend class RplASCondition;
public:
RplASVariant();
~RplASVariant();
RplASVariant(const RplASVariant& source);
RplASVariant& operator=(const RplASVariant& source);
+ qreal asFloat() const;
+ int asInt() const;
+ bool asBool() const;
+ void* asObject(const RplASClass** clazz) const;
+ const QString* asString() const;
+ void setFloat(qreal number);
+ void setInt(int integer);
+ void setBool(bool value);
+ void setObject(void* object, const RplASClass* clazz);
+ void setString(const QString& string);
protected:
void copyValue(const RplASVariant& source);
void destroyValue();
private:
DataType m_dataType;
union {
- qreal m_number;
- QString* m_string;
- QMap<QString, RplASVariant*> m_map;
- QList<RplAsValue*> m_list;
+ qreal m_float;
+ int m_int;
+ bool m_bool;
void* m_object;
} m_value;
- RplASClass* m_class;
+ const RplASClass* m_class;
};
class RplASTree;
friend class RplASTree;
RplASItem(RplASItemType type);
virtual ~RplASItem();
-
+public:
+ const RplSourcePosition* position() const;
+ void setPosition(const RplSourcePosition* position);
protected:
- RplSourcePosition* m_position;
+ RplASItemType m_type;
+ const RplSourcePosition* m_position;
};
-class RplASExpr
+class RplASCalculable
{
public:
- RplASExpr();
+ RplASCalculable();
public:
- virtual QVariant calc() = 0;
+ virtual void calc(RplASVariant& value) = 0;
};
-class RplASValue : public RplASItem, public RplASExpr
+class RplASConstant : public RplASItem, public RplASCalculable
{
public:
- RplASValue(RplASItemType type, const QString& name,
- boolean isConst);
- virtual ~RplASValue();
+ RplASConstant();
+public:
+ virtual void calc(RplASVariant& value);
+public:
+ RplASVariant& value();
private:
- QString m_name;
- boolean m_isConst;
+ RplASVariant m_value;
};
-class RplASScalar : public RplASValue
+class RplASNamedValue : public RplASItem, public RplASCalculable
{
public:
- RplASScalar(const QString& name, boolean isConst);
- virtual ~RplASScalar();
+ enum Attributes {
+ A_NONE,
+ /// the value cannot be changed.
+ A_CONST = 1<<1,
+ /// the variable/constant is found in the global namespace, not in a method
+ A_GLOBAL = 1<<2,
+ /// the variable/constant is found in the module namespace, not in a method
+ A_MODULE_STATIC = 1<<3
+ };
+
+public:
+ RplASNamedValue(const QString& name, int attributes = A_NONE);
+ QString name() const;
public:
- virtual QVariant calc();
+ virtual void calc(RplASVariant& value);
private:
- QVariant m_value;
+ QString m_name;
+ int m_attributes;
};
class RplASNode1 : public RplASItem
public:
RplASNode1(RplASItemType type);
virtual ~RplASNode1();
+public:
+ void setChild(RplASItem* child);
protected:
RplASItem* m_child;
};
RplASItem* m_child3;
};
-class RplASBinOp : public RplASNode2
+class RplASNode4 : public RplASNode3
{
public:
- RplASBinOp(RplASBinaryOperator op);
- virtual ~RplASBinOp();
-private:
- RplASBinaryOperator m_op;
+ RplASNode4(RplASItemType type);
+ virtual ~RplASNode4();
+protected:
+ RplASItem* m_child4;
};
-class RplASUnaryOp : public RplASNode1
+class RplASUnary : public RplASNode1
+{
+public:
+ RplASUnaryOp(int op);
+public:
+ int getOperator() const;
+
+private:
+ int m_operator;
+};
+class RplASBinaryOp : public RplASNode2
{
public:
- RplASUnaryOp(RplASUnaryOperator op);
- virtual ~RplASUnaryOp();
+ RplASBinaryOp();
private:
- RplASUnaryOperator m_op;
+ int m_operator;
};
class RplASStatement
RplASItem* m_successor;
};
-class RplASFor : public RplASNode3, public RplASStatement
+class RplASCondition : public RplASNode1, public RplASCalculable
+{
+public:
+ RplASCondition();
+public:
+ void calc(RplASVariant& value);
+ bool calcAsBool();
+};
+
+class RplASFor : public RplASNode4, public RplASStatement
{
public:
RplASFor();
virtual ~RplASFor();
public:
virtual void execute();
-private:
- RplASStatement* m_body;
};
class RplASWhile : public RplASNode2, public RplASStatement
virtual ~RplASWhile();
};
-class RplArgument : public RplAsNode2, public RplASStatement
+class RplArgument : public RplASNode2, public RplASStatement
{
public:
RplArgument();
virtual ~RplArgument();
};
+class RplASMethod;
class RplAsMethodCall : public RplASNode2, public RplASStatement
{
public:
- RplArgument();
- virtual ~RplArgument();
+ RplAsMethodCall();
+ virtual ~RplAsMethodCall();
private:
- RplASFunction* m_function;
+ RplASMethod* m_method;
RplArgument* m_arg1;
};
virtual ~RplParameter();
private:
QString m_name;
- RplASValue* m_default;
+ RplASNamedValue* m_default;
};
class RplASClass;
-class RplASMethod : public RplASNode2, public RplASStatement
+class RplASMethod : public RplASNode2
{
public:
RplASMethod();
* @param source NULL or a source to copy
* @return a new value object (specific for the class)
*/
- void* newValueInstance(void* source = NULL) = 0;
+ virtual void* newValueInstance(void* source = NULL) const = 0;
/**
- * @brief Destroyes the given object.
+ * @brief Destroys the given object.
*
* The object must be created by <code>newValueInstance()</code>.
*
* @param object object to destroy
*/
- void destroyValueInstance(void* object) = 0;
+ virtual void destroyValueInstance(void* object) const = 0;
+ /**
+ * @brief Returns the boolean value of a class specific value.
+ *
+ * Example: the boolean value of an the empty string is false
+ *
+ * @param object object to test
+ * @return false: the object represents the false value<br>
+ * true: otherwise
+ */
+ virtual bool boolValueOf(void* object) const = 0;
+public:
+ const QString& name() const;
protected:
QString m_name;
- QMap<String, RplASMethod*> m_methods;
- RplASClass* m_superClass;
+ QMap<QString, RplASMethod*> m_methods;
+ const RplASClass* m_superClass;
};
-
+#include "rplexpr/rplasclasses.hpp"
+class RplSymbolSpace;
class RplASTree
{
+public:
+ typedef QMap<QString, RplSymbolSpace*> SymbolSpaceMap;
+ typedef QList<RplSymbolSpace*> SymbolSpaceStack;
public:
RplASTree();
+ ~RplASTree();
+public:
+ bool startModule(const QString& name);
+ void finishModule(const QString& name);
+ void startClassOrMethod(const QString& name,
+ RplSymbolSpace::SymbolSpaceType type);
+ void finishClassOrMethod(const QString& name);
+ SymbolSpaceStack& symbolSpaces();
+ RplSymbolSpace* currentSpace() const;
+
+private:
+ // the mother of all symbol spaces.
+ RplSymbolSpace* m_global;
+ // contains all hit modules
+ SymbolSpaceMap m_modules;
+ // nested modules (import), classes and methods build this stack:
+ SymbolSpaceStack m_symbolSpaces;
+ // top of the stack:
+ RplSymbolSpace* m_currentSpace;
+ // contain all ever built symbol spaces:
+ SymbolSpaceMap m_symbolSpaceHeap;
};
#endif // RPLASTREE_HPP
#include "rplexpr/rplsource.hpp"
#include "rplexpr/rpllexer.hpp"
#include "rplexpr/rplastree.hpp"
-#include "rplexpr/rplasclasses.hpp"
+#include "rplexpr/rplvm.hpp"
+#include "rplexpr/rplmfparser.hpp"
#endif // RPLEXPR_HPP
#include "rplexpr/rplexpr.hpp"
#define CHAR_INFO_SIZE (int(sizeof m_charInfo / sizeof m_charInfo[0]))
+
/** @class RplToken rpllexer.hpp "rplexpr/rpllexer.hpp"
*
- * @brief Implements a token which is the smallest unit for a parser.
+ * @brief Implements specific exception for the lexer.
*
*/
m_message += buffer;
}
+/** @class RplToken rpllexer.hpp "rplexpr/rpllexer.hpp"
+ *
+ * @brief Implements a token which is the smallest unit for a parser.
+ *
+ */
/**
* @brief Constructor.
* @param type token type
*
*/
-static void itemsToVector(const char* items, QVector<QString>& vector,
+static void itemsToVector(const char* items, RplLexer::StringList& vector,
int firstCharFlag, int secondCharFlag,
int thirdCharFlag, int restCharFlag,
int charInfo[])
* @param id the id of the entry in the vector. Only set if found
* @return
*/
-int RplLexer::findInVector(int tokenLength, const QVector<QString>& vector)
+int RplLexer::findInVector(int tokenLength, const StringList& vector)
{
int id = 0;
int lbound = 0;
* otherwise: the token
*/
RplToken* RplLexer::findTokenWithId(RplTokenType tokenType, int flag2,
- QVector<QString>& names)
+ StringList& names)
{
int length = 1;
int inputLength = m_input.size();
}
return rc;
}
+/**
+ * @brief Makes that nextToken() returns the current token again.
+ */
+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;
+
+}
+
+/**
+ * @brief Returns the next relevant token, but the token remains "unread".
+ *
+ * @return the next token which is not a space/comment
+ */
+RplToken*RplLexer::peekNonSpaceToken()
+{
+ nextNonSpaceToken();
+ undoLastToken();
+}
/**
* @brief Returns the maximal length of a token
* @return the maximal length of a token
class RplLexer
{
public:
+ typedef QList<QString> StringList;
enum NumericType {
NUMTYPE_UNDEF,
NUMTYPE_DECIMAL = 1 << 0,
SF_QUOTE = 1 << 2,
/// character escaping like in C: \<char> is <char>
SF_C_ESCAPING = 1 << 3,
- /// special characters like in C: \r \f \r \t
+ /// special characters like in C: \r \f \n \t \a
SF_C_SPECIAL = 1 << 4,
/// characters can be written in hexadecimal notation: \x20 is ' '
SF_C_HEX_CHARS = 1 << 5,
virtual ~RplLexer();
public:
RplToken* nextToken();
+ void undoLastToken();
RplToken* peekNonSpaceToken();
RplToken* nextNonSpaceToken();
size_t maxTokenLength() const;
void prepareOperators(const char* operators);
void initializeComments(const char* comments);
bool fillInput();
- int findInVector(int tokenLength, const QVector<QString>& vector);
+ int findInVector(int tokenLength, const StringList& vector);
const char* nextText(int& length, bool &isLast);
RplToken* findTokenWithId(RplTokenType tokenType, int flag2,
- QVector<QString>& names);
+ StringList& names);
RplToken* scanNumber();
RplToken* scanString();
void scanComment();
protected:
RplSource* m_source;
/// sorted, string ends with the id of the keyword
- QVector<QString> m_keywords;
+ StringList m_keywords;
// sorted, string ends with the id of the operator
- QVector<QString> m_operators;
+ StringList m_operators;
// sorted, each entry ends with the id of the comment start
- QVector<QString> m_commentStarts;
+ StringList m_commentStarts;
// index: id content: comment_end
- QVector<QString> m_commentEnds;
+ StringList m_commentEnds;
// index: ord(char) content: a sum of CharClassTags
int m_charInfo[128];
// a list of QChars with ord(cc) > 127 and which can be the first char
--- /dev/null
+/*
+ * 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"
+
+/** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
+ *
+ * @brief Implements a parser for the language MF.
+ *
+ * MF stands for Mathe Fan or Multiple Faces or ....
+ * This is an universal object oriented programming language with extension
+ * for matrix operations, simulation and graphics.
+ */
+
+RplMFParser::RplMFParser(RplSource& source) :
+ m_lexer(&source,
+ MF_KEYWORDS, MF_OPERATORS,
+ "/* */ // \n",
+ "a-zA-Z_", "a-zA-Z0-9_",
+ NUMTYPE_ALL, SF_C_ALL
+ )
+{
+}
+
+/**
+ * @brief Parses a function or a generator.
+ */
+void RplMFParser::parseFunc()
+{
+
+}
+/**
+ * @brief Parses an if statement.
+ */
+void RplMFParser::parseIf()
+{
+
+}
+/**
+ * @brief Parses a while statement.
+ */
+
+void RplMFParser::parseWhile()
+{
+
+}
+
+/**
+ * @brief Parses a repeat statement.
+ */
+void RplMFParser::parseRepeat()
+{
+
+}
+
+/**
+ * @brief Parses a for statement.
+ */
+void RplMFParser::parseFor()
+{
+
+}
+
+/**
+ * @brief Parses a variable definition.
+ *
+ * @param clazz NULL or the type of the variable
+ * @param attribute 0 or attribute of the variable: K_CONST or K_LAZY
+ */
+void RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute = K_UNDEF)
+{
+
+}
+
+/**
+ * @brief Parses an operand.
+ * An operand is the first and the third part of an binary operation.
+ * Examples: constant, variable, method call
+ *
+ * @return the node with the operand
+ */
+RplASItem* RplMFParser::parseOperand(int level)
+{
+ RplToken* token = m_lexer->nextNonSpaceToken();
+ RplASItem* rc = NULL;
+ switch(token->tokenType()){
+ case TOKEN_OPERATOR:
+ rc = new RplASUnary(token->id());
+ rc->setChild(parseOperand);
+ break;
+ case TOKEN_STRING:
+ case TOKEN_NUMBER:
+ case TOKEN_REAL:
+ {
+ RplASConstant constant = new RplASConstant();
+ item = constant;
+ switch(token->tokenType()){
+ case TOKEN_STRING:
+ constant.m_value.setString(token->toString());
+ break;
+ case TOKEN_NUMBER:
+ constant.m_value.setInt(token->asInteger());
+ break;
+ case TOKEN_REAL:
+ constant.m_value.setFloat(token->asReal());
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case TOKEN_ID:
+ {
+ QString name = token->toString();
+ token = m_lexer->nextNonSpaceToken();
+ if (token->tokenType() != TOKEN_OPERATOR){
+ RplASNamedValue* var = new RplASNamedValue(name);
+ item = var;
+ m_lexer->undoLastToken();
+ } else {
+ if (token->id() == m_tokenParenthesis){
+ RplASItem* args = parseArguments();
+ RplAsMethodCall =
+ } else if (token->id() == m_tokenDecrement){
+ RplASNamedValue* var = new RplASNamedValue(name);
+ item = var;
+
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return item;
+}
+
+/**
+ * @brief Parses a term.
+ *
+ * A term is a part of an expression with the same parenthesis level.
+ * Example: a + (3 * 7 - 2)<br>
+ * first term: 3*7-2<br>
+ * second term: a + term1<br>
+ *
+ * @param depth the level of the parenthesis
+ * @return
+ */
+RplASItem* RplMFParser::parseTerm(int depth){
+ RplToken* token;
+ RplSourcePosition* start = m_lexer->currentSourcePosition();
+ RplASItem* top = NULL;
+ RplASItem* item;
+ bool again = true;
+ do {
+ item = parseOperand(level);
+ token = m_lexer->nextNonSpaceToken();
+ switch(token->tokenType()){
+ case TOKEN_OPERATOR:
+ break;
+ case TOKEN_STRING:
+ case TOKEN_NUMBER:
+ case TOKEN_REAL:
+ break;
+ case TOKEN_KEYWORD:
+ case TOKEN_OPERATOR:
+ case TOKEN_ID:
+ case TOKEN_END_OF_SOURCE:
+ again = false;
+ break;
+ default:
+ break;
+ }
+ } while(again);
+
+}
+
+/**
+ * @brief Parses an expression.
+ *
+ * @precond the nextNonSpaceToken() will return the first token of the expr.
+ * @postcond all tokens belonging to the expr are read
+ *
+ * @return the token behind the expr
+ */
+RplToken* RplMFParser::parseExpr()
+{
+ RplASItem* item = parseTerm(0);
+}
+
+/**
+ * @brief Parses the body.
+ *
+ * A body is a module, a class region or a method body.
+ */
+void RplMFParser::parseBody()
+{
+ RplToken token = m_lexer->nextNonSpaceToken();
+ switch(token.tokenType())
+ {
+ case TOKEN_STRING:
+ case TOKEN_NUMBER:
+ case TOKEN_REAL:
+ case TOKEN_OPERATOR:
+ m_lexer->undoNextToken();
+ token = parseExpr();
+ break;
+ case TOKEN_KEYWORD:
+ switch (token.id()){
+ case K_IF:
+ parseIf();
+ break;
+ case K_WHILE:
+ parseWhile();
+ break;
+ case K_REPEAT:
+ parseRepeat();
+ break;
+ case K_FOR:
+ parseFor();
+ break;
+ case K_CLASS:
+ parseClass();
+ break;
+ case K_FUNCTION:
+ case K_GENERATOR:
+ parseMethod();
+ break;
+ case K_IMPORT:
+ parseImport();
+ break;
+ case K_CONST:
+ case K_LAZY:
+ parseDefinition(NULL, token.id());
+ break;
+ case K_INT:
+ parseDefinition(&RplASInteger.m_instance);
+ break;
+ case K_FLOAT:
+ parseDefinition(&RplASFloat.m_instance);
+ break;
+ case K_BOOL:
+ parseDefinition(&RplASBoolean.m_instance);
+ break;
+ default:
+ break;
+ }
+ break;
+ case TOKEN_ID:
+ {
+ RplASClass* clazz = m_tree.currentSpace()->findClass();
+ if (clazz != NULL){
+ parseDefinition(clazz);
+ } else {
+ m_lexer->undoNextToken();
+ parseExpr();
+ }
+ break;
+ }
+ case TOKEN_END_OF_SOURCE:
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief Parses a module.
+ *
+ * @precond the first char of the module is the next char to read.
+ * @postcond the total module is read
+ *
+ * @param name the name of the module (without path)
+ */
+void RplMFParser::parseModule(const QString& name)
+{
+ m_tree.startModule(name);
+ parseBody();
+ m_tree.finishModule(name);
+}
+/**
+ * @brief Parse the input given by the source.
+ */
+void RplMFParser::parse()
+{
+
+}
+
--- /dev/null
+/*
+ * 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.
+*/
+
+
+#ifndef RPLMFPARSER_HPP
+#define RPLMFPARSER_HPP
+
+class RplMFParser
+{
+public:
+ enum Keyword {
+ K_UNDEF, K_IF, K_THEN, K_ELSE, K_FI, K_WHILE, K_DO, K_OD, K_REPEAT, K_UNTIL,
+ K_FOR, K_FROM, K_TO, K_STEP, K_CASE, K_OF, K_ESAC, K_LEAVE, K_CONTINUE, K_PASS,
+ K_CLASS, K_END, K_FUNCTION, K_GENERATOR, K_IMPORT,
+ K_CONST, K_LAZY, K_INT, K_FLOAT, K_BOOL, K_NONE, K_TRUE, K_FALSE
+ };
+#define MF_KEYWORDS "if then else fi while do od repeat until" \
+ " for from to step case of esac leave continue pass" \
+ " class end function generator import" \
+ " const lazy int float bool None True False"
+ enum Operator {
+ O_UNDEF, O_SEMI_SEMICOLON, O_SEMICOLON, O_COMMA, O_COLON, O_QUESTION,
+ O_OR, O_AND,
+ O_XOR, O_BIT_OR, O_BIT_AND, O_LSHIFT, O_RSHIFT, O_RSHIFT2,
+ O_LT, O_GT, O_LE, O_GE, O_EQ, O_NE,
+ O_PLUS, O_MINUS, O_DIV, O_MOD, O_TIMES, O_POWER, O_INC, O_DEC,
+ O_DOT
+ };
+
+#define MF_OPERATORS ";; ; , : ?" \
+ " || && " \
+ " ^ | & << >> >>>" \
+ " < > <= >= == !=" \
+ " + - / % * ** ++ --" \
+ " ."
+public:
+ RplMFParser(RplSource& source, RplASTree& ast);
+public:
+ void parseFunc();
+ void parseIf();
+ void parseWhile();
+ void parseRepeat();
+ void parseFor();
+ void parseDefinition(RplASClass* clazz);
+ RplToken* parseExpr();
+ void parseBody();
+ void parseClass();
+ void parseModule(const QString& name);
+ void parse();
+ RplASItem* parseOperand();
+ RplASItem* parseTerm(int depth);
+private:
+ RplLexer m_lexer;
+ RplASTree& m_tree;
+};
+
+#endif // RPLMFPARSER_HPP
*/
QString RplSourcePosition::toString() const
{
- QString rc = m_sourceUnit->name();
+ QString rc;
+ if (m_sourceUnit != NULL)
+ rc = m_sourceUnit->name();
QTextStream stream(&rc);
stream << "-" << m_lineNo << " (" << m_column << "): ";
return rc;
--- /dev/null
+/*
+ * 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"
+
+
--- /dev/null
+/*
+ * 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.
+*/
+
+
+#ifndef RPLVM_HPP
+#define RPLVM_HPP
+
+class RplStackFrame {
+public:
+ RplStackFrame(int countArgs, int countLocals);
+ ~RplStackFrame();
+public:
+private:
+ RplASVariant* m_variables;
+};
+
+class RPLVirtualMachine
+{
+public:
+ RPLVirtualMachine();
+public:
+ void calc();
+private:
+ RplStackFrame m_global;
+ QMap<QString, RplSymbolSpace*> m_modules;
+ QList<RplStackFrame*> m_stack;
+};
+
+#endif // RPLVM_HPP
../rplexpr/rplsource.cpp \
../rplcore/rplqstring.cpp \
../rplexpr/rplastree.cpp \
- ../rplexpr/rplasclasses.cpp
+ ../rplexpr/rplasclasses.cpp \
+ ../rplexpr/rplmfparser.cpp \
+ ../rplexpr/rplvm.cpp
HEADERS += ../rplmodules.hpp \
../rplcore/rplconfig.hpp \
../rplexpr/rplsource.hpp \
../rplcore/rplqstring.hpp \
../rplexpr/rplastree.hpp \
- ../rplexpr/rplasclasses.hpp
+ ../rplexpr/rplasclasses.hpp \
+ ../rplexpr/rplmfparser.hpp \
+ ../rplexpr/rplvm.hpp
unix:!symbian {
maemo5 {
}
void testExpr(){
+ extern void testRplASTree();
+ testRplASTree();
extern void testRplSource();
testRplSource();
-
+ extern void testRplLexer();
+ testRplLexer();
}
void testStandard(){
if (argc > 1)
printf("not used: %s\n", argv[1]);
- extern void testRplLexer();
- testRplLexer();
-
testStandard();
}
--- /dev/null
+/*
+ * 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 TestRplASTree : public RplTest{
+private:
+ RplSource m_source;
+ RplStringReader m_reader;
+ RplStringSourceUnit m_unit;
+public:
+ TestRplASTree() :
+ RplTest("RplASTree"),
+ m_source(),
+ m_reader(m_source),
+ m_unit("<main>", "", &m_reader)
+ {}
+public:
+ void testRplASException() {
+ try{
+ RplSourcePosition pos(&m_unit, 1, 2);
+ throw RplASException(&pos, "simple string: %s", "Hi");
+ checkF(true);
+ } catch (RplASException exc){
+ checkE("<main>-1 (2): simple string: Hi", exc.getMessage().constData());
+ }
+ }
+ void testRplASVariant(){
+ RplASVariant val1;
+ val1.setFloat(2.5E-2);
+ checkE(2.5E-2, val1.asFloat());
+ RplASVariant val2(val1);
+ checkE(2.5E-2, val2.asFloat());
+
+ val1.setInt(4321);
+ checkE(4321, val1.asInt());
+ val2 = val1;
+ checkE(4321, val2.asInt());
+
+ val1.setBool(false);
+ checkF(val1.asBool());
+ val2 = val1;
+ checkF(val2.asBool());
+
+ val1.setBool(true);
+ checkT(val1.asBool());
+ val2 = val1;
+ checkT(val2.asBool());
+
+ val1.setString("High noon!");
+ checkE("High noon!", *val1.asString());
+ val2 = val1;
+ val1.setString("Bye");
+ checkE("High noon!", *val2.asString());
+ RplASVariant val3(val1);
+ checkE("Bye", *val3.asString());
+ }
+ void testRplASConstant(){
+ RplASConstant constant;
+ constant.value().setString("Jonny");
+ RplASVariant value;
+ constant.calc(value);
+ checkE("Jonny", *value.asString());
+ }
+ void testRplASNamedValue(){
+ RplASNamedValue value("gugo");
+ checkE("gugo", value.name());
+ }
+ void testRplASCondition(){
+ RplASCondition cond;
+ RplASConstant* constant = new RplASConstant();
+ constant->value().setString("True");
+ cond.setChild(constant);
+ checkT(cond.calcAsBool());
+ constant->value().setInt(0);
+ checkF(cond.calcAsBool());
+ }
+
+ virtual void doIt() {
+ testRplASCondition();
+ testRplASNamedValue();
+ testRplASConstant();
+ testRplASException();
+ testRplASVariant();
+ }
+};
+void testRplASTree() {
+ TestRplASTree test;
+ test.run();
+}
+
+
+
+
+
+
}
void testToArray() {
- QVector<QByteArray> array = RplString::toArray("1 abc 3", " ");
+ QList<QByteArray> array = RplString::toArray("1 abc 3", " ");
checkE(3, array.size());
checkE("1", array.at(0));
checkE("abc", array.at(1));
rpllexer_test.cpp \
rplqstring_test.cpp \
../rplcore/rplqstring.cpp \
- ../rplexpr/rplasclasses.cpp
+ ../rplexpr/rplasclasses.cpp \
+ rplastree_test.cpp