From 533122de7a6e48191f7785fc2d167125eeb342dd Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Wed, 25 Jul 2012 22:19:42 +0200 Subject: [PATCH] make it shared, properly export symbols --- include/AnyType | 2 + include/BinaryOperator | 2 + include/BoolEngine | 2 + include/CharacterClassSettings | 2 + include/Engine | 2 + include/Exception | 2 + include/Expression | 2 + include/FloatEngine | 2 + include/IntEngine | 2 + include/IntFloatEngine | 2 + include/Position | 2 + include/StringEngine | 2 + include/Token | 2 + include/UnaryOperator | 2 + include/elam.h | 29 +++++ include/elambinary.h | 86 +++++++++++++ include/elamboolengine.h | 32 +++++ include/elamcharclass.h | 162 +++++++++++++++++++++++++ include/elamengine.h | 262 ++++++++++++++++++++++++++++++++++++++++ include/elamexpression.h | 176 +++++++++++++++++++++++++++ include/elamfloatengine.h | 45 +++++++ include/elamglobal.h | 18 +++ include/elamintengine.h | 29 +++++ include/elamstringengine.h | 29 +++++ include/elamunary.h | 89 ++++++++++++++ include/elamvalue.h | 152 +++++++++++++++++++++++ src/elam.h | 31 ----- src/elam.pro | 9 +- src/elambinary.h | 85 ------------- src/elamboolengine.h | 32 ----- src/elamcharclass.h | 162 ------------------------- src/elamengine.cpp | 2 + src/elamengine.h | 260 --------------------------------------- src/elamexpression.h | 176 --------------------------- src/elamfloatengine.h | 45 ------- src/elamintengine.h | 29 ----- src/elamstringengine.h | 29 ----- src/elamunary.h | 89 -------------- src/elamvalue.h | 150 ----------------------- 39 files changed, 1144 insertions(+), 1092 deletions(-) create mode 100644 include/AnyType create mode 100644 include/BinaryOperator create mode 100644 include/BoolEngine create mode 100644 include/CharacterClassSettings create mode 100644 include/Engine create mode 100644 include/Exception create mode 100644 include/Expression create mode 100644 include/FloatEngine create mode 100644 include/IntEngine create mode 100644 include/IntFloatEngine create mode 100644 include/Position create mode 100644 include/StringEngine create mode 100644 include/Token create mode 100644 include/UnaryOperator create mode 100644 include/elam.h create mode 100644 include/elambinary.h create mode 100644 include/elamboolengine.h create mode 100644 include/elamcharclass.h create mode 100644 include/elamengine.h create mode 100644 include/elamexpression.h create mode 100644 include/elamfloatengine.h create mode 100644 include/elamglobal.h create mode 100644 include/elamintengine.h create mode 100644 include/elamstringengine.h create mode 100644 include/elamunary.h create mode 100644 include/elamvalue.h delete mode 100644 src/elam.h delete mode 100644 src/elambinary.h delete mode 100644 src/elamboolengine.h delete mode 100644 src/elamcharclass.h delete mode 100644 src/elamengine.h delete mode 100644 src/elamexpression.h delete mode 100644 src/elamfloatengine.h delete mode 100644 src/elamintengine.h delete mode 100644 src/elamstringengine.h delete mode 100644 src/elamunary.h delete mode 100644 src/elamvalue.h diff --git a/include/AnyType b/include/AnyType new file mode 100644 index 0000000..5fcdb6e --- /dev/null +++ b/include/AnyType @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamvalue.h" diff --git a/include/BinaryOperator b/include/BinaryOperator new file mode 100644 index 0000000..9105013 --- /dev/null +++ b/include/BinaryOperator @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elambinary.h" diff --git a/include/BoolEngine b/include/BoolEngine new file mode 100644 index 0000000..cc9401d --- /dev/null +++ b/include/BoolEngine @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamboolengine.h" diff --git a/include/CharacterClassSettings b/include/CharacterClassSettings new file mode 100644 index 0000000..4d4b633 --- /dev/null +++ b/include/CharacterClassSettings @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamcharclass.h" diff --git a/include/Engine b/include/Engine new file mode 100644 index 0000000..bea5477 --- /dev/null +++ b/include/Engine @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamengine.h" diff --git a/include/Exception b/include/Exception new file mode 100644 index 0000000..5fcdb6e --- /dev/null +++ b/include/Exception @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamvalue.h" diff --git a/include/Expression b/include/Expression new file mode 100644 index 0000000..c46a659 --- /dev/null +++ b/include/Expression @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamexpression.h" diff --git a/include/FloatEngine b/include/FloatEngine new file mode 100644 index 0000000..0e25e64 --- /dev/null +++ b/include/FloatEngine @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamfloatengine.h" diff --git a/include/IntEngine b/include/IntEngine new file mode 100644 index 0000000..147f580 --- /dev/null +++ b/include/IntEngine @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamintengine.h" diff --git a/include/IntFloatEngine b/include/IntFloatEngine new file mode 100644 index 0000000..0e25e64 --- /dev/null +++ b/include/IntFloatEngine @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamfloatengine.h" diff --git a/include/Position b/include/Position new file mode 100644 index 0000000..5fcdb6e --- /dev/null +++ b/include/Position @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamvalue.h" diff --git a/include/StringEngine b/include/StringEngine new file mode 100644 index 0000000..fceaf33 --- /dev/null +++ b/include/StringEngine @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamstringengine.h" diff --git a/include/Token b/include/Token new file mode 100644 index 0000000..c46a659 --- /dev/null +++ b/include/Token @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamexpression.h" diff --git a/include/UnaryOperator b/include/UnaryOperator new file mode 100644 index 0000000..dcdf78b --- /dev/null +++ b/include/UnaryOperator @@ -0,0 +1,2 @@ +//auto-generated code, do not change +#include "elamunary.h" diff --git a/include/elam.h b/include/elam.h new file mode 100644 index 0000000..b1017c9 --- /dev/null +++ b/include/elam.h @@ -0,0 +1,29 @@ +//ELAM main header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_LIB_H +#define ELAM_LIB_H + +#include "elamengine.h" +#include "elamintengine.h" +#include "elamfloatengine.h" +#include "elamboolengine.h" +#include "elamstringengine.h" + +/** \mainpage ELAM - Elementary Logic and Arithmetic Machine + +Please see the main docu for build instructions and a tutorial on how to use ELAM.

+ +See the ELAM namespace for member documentation. + +*/ + + +namespace ELAM { + + +}; + +#endif diff --git a/include/elambinary.h b/include/elambinary.h new file mode 100644 index 0000000..f18124c --- /dev/null +++ b/include/elambinary.h @@ -0,0 +1,86 @@ +// main header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_ENGINE_BINARY_H +#define ELAM_ENGINE_BINARY_H + +#include +#include +#include + +#include "../dptr/dptr_base.h" +#include "elamglobal.h" + +#include + +namespace ELAM { +class Engine; + +/** \brief pointer to a function wrapping a binary operator +\param op1 the left operand +\param op2 the right operand +\param engine the engine calling the operator +\returns the result of the operation*/ +typedef std::functionBinaryOperatorCall; + +/** Helper type to select the correct overload from several variants. +If your compiler complains that it cannot resolve an overloaded pointer when calling BinaryOperator::setCallback then cast to this type to help the compiler: +\code +myBinaryOp.setCallback(BinaryOperatorCall_FP(myFunction),type1,type2); +\endcode +*/ +typedef QVariant(*BinaryOperatorCall_FP)(const QVariant&op1,const QVariant&op2,Engine&engine); + +/** \brief Wraps a particular binary operator. + +You can use the methods of this class to change the routines that handle the operator and the types on which it operates. Instances of this class are implicitly shared - meaning calls on a copy of an instance are also visible on the original and all other copies. +*/ +class ELAM_EXPORT BinaryOperator +{ + DECLARE_SHARED_DPTR(d); + public: + BinaryOperator(const BinaryOperator&); + BinaryOperator(); + ~BinaryOperator(); + /**the operator becomes a shared copy of op and abandones its old link*/ + BinaryOperator& operator=(const BinaryOperator&op); + + /**sets a callback function for the operator and a specific typ + \param callback the function to call, if it is null the type is deleted from this operators type list + \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced + */ + void setCallback(BinaryOperatorCall callback,QString type1,QString type2); + /**sets a callback function for the operator and a specific typ + \param callback the function to call, if it is null the type is deleted from this operators type list + \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced + */ + void setCallback(BinaryOperatorCall callback,int type1,int type2); + + /**returns the callback function attached to the type or NULL if there is none*/ + BinaryOperatorCall getCallback(QString type1,QString type2)const; + /**returns the callback function attached to the type or NULL if there is none*/ + BinaryOperatorCall getCallback(int type1,int type2)const; + + ///removes the type from this operators list + void removeCallback(QString,QString); + ///removes the type from this operators list + void removeCallback(int,int); + + ///returns all combinations of type names that have a valid callback in this operator + QList > getTypeNames()const; + ///returns all combinations of type IDs that have a valid callback in this operator + QList > getTypeIds()const; + + ///calls the callback function associated with the type of the argument, throws an exception if there is no callback + QVariant execute(const QVariant&,const QVariant&,Engine&)const; + + ///true if this operator has no callbacks + bool isNull()const; +}; + +//end of namespace +}; + +#endif diff --git a/include/elamboolengine.h b/include/elamboolengine.h new file mode 100644 index 0000000..d74fc21 --- /dev/null +++ b/include/elamboolengine.h @@ -0,0 +1,32 @@ +//ELAM integer engine header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_BOOLENGINE_H +#define ELAM_BOOLENGINE_H + +#include "elamengine.h" + +namespace ELAM { + +/**A boolean and logic math enabled engine. + +This engine type plays nicely with ELAM::IntEngine +*/ +class ELAM_EXPORT BoolEngine:public Engine +{ + public: + ///instantiates a pre-configured engine + BoolEngine(); + + ///configures any engine to support basic boolean math + static void configureBoolEngine(Engine&); + + ///configures any engine to support logic functions + static void configureLogicEngine(Engine&); +}; + +}; + +#endif diff --git a/include/elamcharclass.h b/include/elamcharclass.h new file mode 100644 index 0000000..c08bcd5 --- /dev/null +++ b/include/elamcharclass.h @@ -0,0 +1,162 @@ +// main header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_ENGINE_CCLASS_H +#define ELAM_ENGINE_CCLASS_H + +#include +#include +#include + +#include "elamexpression.h" + +#include "../dptr/dptr_base.h" + +namespace ELAM { + +/** \brief This class holds the character classes used by an Engine. + +\see Engine::characterClasses() + +There are three major classes of chracters: + - names + - names can be variables, constants, functions + - the names class has two sub-classes + - start-of-names is characters that may start a name, usually letters and underscores + - all-of-names is characters that may be contained anywhere in names, this class must include the complete start of names class + - operators + - any sequence of these characters is interpreted as unary or binary operator + - whitespace + - whitespace can separate other tokens, but is ignored itself + +None of these three classes may overlap. There are several more minor classes: + - literals + - the character class actually only contains characters that can start a literal, the continuation and end of literals is determines by a callback routine + - characters in this class may overlap with names, but must not overlap with operators, whitespace and start-of-names + - parentheses + - are two distinct characters that group expressions, none of them must be contained in any other class + - comma + - a single character separating arguments in functions, the comma character must not be contained in any other class + - assignment + - one or two characters that denote an assignment + - both are optional, both must be contained in operators + - one of the characters, if it exists, is the first character of an assignment + - the other of the characters, if it exists, is the last character of an assignment + - just those two characters are the simple assignment operator + - both surrounding another operator combine the operation with assignment (e.g. a+=b is equivalent to a=a+b) + +*/ +class ELAM_EXPORT CharacterClassSettings +{ + DECLARE_SHARED_DPTR(d) + public: + ///class of operator characters + QString operatorClass()const; + ///sets the class of operator characters + void setOperatorClass(QString); + + /**returns the two name sub-classes + nameClass().first refers to start characters, + nameClass().second refers to all characters that can turn up anywhere in names*/ + QPair nameClass()const; + /**sets the two sub-classes of names + \param startchars are characters that can start a name + \param allchars are characters that can turn up anywhere in names, allchars must include all characters from startchars*/ + void setNameClass(QString startchars,QString allchars); + /**convenience overload: sets the two sub-classes of names + \param chars.first are characters that can start a name + \param chars.second are characters that can turn up anywhere in names, second must include all characters from first*/ + void setNameClass(const QPair&chars) + {setNameClass(chars.first,chars.second);} + + ///returns all characters that are regarded as whitespace + QString whitespaceClass()const; + ///sets all characters that are regarded as whitespace + void setWhitespaceClass(QString); + + ///returns all characters that start a literal, normally digits ' and " + QString literalStartClass()const; + ///sets characters that can start a literal + void setLiteralStartClass(QString); + + ///returns the opening (first) and closing (second) character of parentheses + QPair parenthesesChars()const; + /**sets the characters used for parentheses + \param open the character that opens/begins a parentheses structure, normally "(" + \param close the character that closes/ends a parentheses structure, normally ")" + + The parentheses characters must not be included in any other class.*/ + void setParentheses(QChar open,QChar close); + + /** \brief returns the characters that designate an assignment + + - assignmentChars().first is the character that starts an assignment operator, + - assignmentChars().second is the character that ends it.*/ + QPair assignmentChars()const; + + /** sets the characters used for assignment operators + \param start if not '\0' the character that marks the start of an assignment + \param end if not '\0' the character that marks the end of an assignment + + The combination of both characters along (without whitespace) is the direct assignment operator. In automatic assignment operator mode any operator that starts with the start character and ends with end character is regarded as an implicit assignment. + + In the default configuration the start character is not set ('\0') and the end character is '=', so "a=1" will assign the value "1" to the variable "a" and "a += 1" is equivalent to "a = a + 1". + + You can turn this automatism around by defining a start character only (e.g. start='=' and end='\0'). Then the assignment would still be "a = 1", but the combination of assignment and "+" would become "a =+ 1". + + If you define both characters then both must be present in assignments. For example with start=':' and end='=' then assignment becomes "a:=1" and assignment with "+" becomes "a :+= 1". + + If set, both characters must be part of the operator class. + + If both start and end are '\0' it will be impossible to make assignments*/ + void setAssignmentChars(QChar start,QChar end); + + ///returns the character used as a comma (separator of function arguments) + QChar commaChar()const; + /**sets the character used as comma + + The character must not be part of any other class.*/ + void setCommaChar(QChar); + + /**true if the settings are internally consistent + + The character class settings are consistent if all constraints of class inclusion and exclusion are fullfilled.*/ + bool isConsistent()const; + + /**returns the type of token the character belongs to + \param ch the character to be checked + \param oldtype the type the previous character belongs to (set to Invalid if this is the first character) + + Compares the character with the known settings for character classes and returns its probable token type. The old type of the previous character is necessary to check for context sensitive rules. + + \returns the type of this character: + - Invalid is returned if the character does not match any class, parsing should stop here + - If Literal is returned the calling engine must use specialized literal checking functions to find the end of the literal, the next character checke with this routine should be the first one behind the end of the literal + - Assignment characters are returned as Operator class + - Whitespace class characters should be ignored + - Special character types (Par*, Comma) must be tokenized separately + - Any other type (Name, Operator) must be concatenated until the return type changes + */ + Token::Type charType(QChar ch,Token::Type oldtype)const; + + ///returns true if the string contains any assignment operator + bool isAssignment(QString)const; + ///returns true if the string contains exactly the simple assignment operator + bool isSimpleAssignment(QString)const; + + ///returns true if the string can be interpreted as name + bool isName(QString)const; + + ///returns true if the string can be interpreted as operator + bool isOperator(QString)const; + + ///removes assignment chars from the token and returns the pure operator or an empty string if it was a pure assignment + QString toOperator(QString)const; +}; + +//end of namespace +}; + +#endif diff --git a/include/elamengine.h b/include/elamengine.h new file mode 100644 index 0000000..1dab137 --- /dev/null +++ b/include/elamengine.h @@ -0,0 +1,262 @@ +// main header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_ENGINE_H +#define ELAM_ENGINE_H + +#include +#include +#include + +#include "elamexpression.h" +#include "elamunary.h" +#include "elambinary.h" +#include "elamcharclass.h" + +#include "../dptr/dptr_base.h" + +#include + +namespace ELAM { + +///returns version information about ELAM +ELAM_EXPORT QString versionInfo(); + +class Engine; + +/**pointer to a function wrapping a mathematical function +\param args the list of arguments +\returns the result of the function or ELAM::Exception in case or errors + +Functions must check their arguments for validity before they start calculating. On error a function should returns an ELAM::Exception. + +\param args the list of arguments that was given to the function, the implementation must check for length and type of the arguments +\param engine the engine calling the function +*/ +typedef std::function&args,Engine&engine)>Function; + +/** Helper type to select the correct overload from several variants. +If your compiler complains that it cannot resolve an overloaded pointer when calling Engine::setFunction then cast to this type to help the compiler: +\code +myEngine.setFunction("hellofunc",Function_FP(myFunction)); +\endcode +*/ +typedef QVariant(*Function_FP)(const QList&args,Engine&engine); + + +/**wraps the parser routine for a literal +\param expr the original expression string +\param engine the engine that is calling this parser +\param start the character (index of expr) at which the literal starts +\returns the parsed literal (first=string representation, second=value represented by it + +The string representation of the literal must be verbatim from expr, so that the calling engine can determine where to continue parsing in expr. + +If the parser does not find a valid literal according to its rules it must return an empty string. +*/ +typedef std::function(const QString&expr,Engine&engine,int start)>LiteralParser; + +/** Helper type to select the correct overload from several variants. +If your compiler complains that it cannot resolve an overloaded pointer when calling Engine::setLiteralParser then cast to this type to help the compiler: +\code +myEngine.setLiteralParser(Function_FP(myDecimal),"123456789"); +\endcode +*/ +typedef QPair(*LiteralParser_FP)(const QString&expr,Engine&engine,int start); + +/**Wraps a cast function to convert various types into another type. +\param orig the original value of any type +\param engine the engine calling the cast +\returns the converted value that conforms to the expected type*/ +typedef std::functionTypeCast; + +/** Helper type to select the correct overload from several variants. +If your compiler complains that it cannot resolve an overloaded pointer when calling Engine::setAutoCast then cast to this type to help the compiler: +\code +myEngine.setAutoCast(targetType,QList()<0 if the parser is registered successfully, or 0 if: + - the parser is null + - the start characters are empty + - the priority is outside the allowed range (0<=prio<=100) + + A return value >0 can be used as an ID to remove the parser again with removeLiteralParser(int) . + + If a parser function is registered a second time the new registration overwrites the old registration. + */ + int setLiteralParser(LiteralParser parser,QString startchars,int prio=50); + ///removes a parser function + void removeLiteralParser(int parserid); + + ///sets/overrides the priority of an operator, creating the operator if it does not exist yet + void setBinaryOperatorPrio(QString name,int prio); + + /**registers a type as primary, this means it is not cast into another type when encountered + \param typeId the QVariant ID of the type to register*/ + void registerType(int typeId); + /**Registers an automatic cast function. + + Automatic cast functions must succeed in converting, if the result is uncertain (e.g. as in converting a string to a number) use an explicit function. + + \param target the target of the cast function, the target is automatically registered as primary type (see registerType) + \param origin type IDs that are automatically converted using this function, origins that are also primary types are ignored + \param castfunc the function that converts these types + \param prio the priority of the cast, if a cast function for the same origin, but a higher priority exists the one with the higher priority is used; the priority must be a positive value*/ + void setAutoCast(int target,QListorigin,TypeCast castfunc,int prio=50); + + ///simply parses an expression string into an object + Expression expression(QString); + ///simply parses an expression string into an object + Expression expression(QList); + ///simply parses an expression string into a list of tokens + QList tokenize(QString); + ///parses and evaluates an expression string into a final value + QVariant evaluate(QString); + ///evaluates a parsed expression into a final value + QVariant evaluate(Expression); + ///gives access to the character classes settings + CharacterClassSettings characterClasses(); + private: + ///parse a literal + QPairparseLiteral(QString,int); +}; + +//end of namespace +}; + +#endif diff --git a/include/elamexpression.h b/include/elamexpression.h new file mode 100644 index 0000000..2311fbf --- /dev/null +++ b/include/elamexpression.h @@ -0,0 +1,176 @@ +//ELAM main header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_EXPRESSION_H +#define ELAM_EXPRESSION_H + +#include "elamvalue.h" +#include "../dptr/dptr_base.h" + +namespace ELAM { + +/**Represents a single token in a parsed expression. + +Tokens are pretty stupid themselves - they just know their type, position, their original piece of text and an optional value (literals). They are used by the engine and expressions to transform text into executable expressions.*/ +class ELAM_EXPORT Token +{ + DECLARE_SHARED_DPTR(d) + public: + ///The type of token + enum Type { + ///invalid token + Invalid=0, + ///the token represents a function call + Function = 1, + ///the token represents a constant + Constant = 2, + ///the token represents a variable + Variable = 4, + ///a name: function, variable, or constant + Name=0xff, + ///mask for name tokens + NameMask=Name, + + ///the token represents an unary operator + UnaryOp = 0x100, + ///the token represents a binary operator + BinaryOp = 0x200, + ///the token represents an assignment (with optional implicit binary op) + AssignmentOp = 0x400, + ///an operator (unary or binary) + Operator=0xff00, + ///mask for operator tokens + OperatorMask=Operator, + + ///mask for special class tokens that have a syntactic function (parentheses, comma, ...) + SpecialCharMask=0xff0000, + ///mask for parentheses + ParenthesesMask=0xf0000, + ///meta-type used for parsed sub-tokens + Parentheses=0x10000, + ///opening parenthese + ParOpen=0x20000, + ///closing parenthese + ParClose=0x40000, + ///a comma - separating expressions in function calls + Comma=0x100000, + + ///a literal value + Literal=0x1000000, + ///mask for literal values + LiteralMask=Literal, + + ///mask for tokens that are functional (non-ignored) + FunctionalMask=NameMask|OperatorMask|SpecialCharMask, + + ///white space chars, this is actually not used for tokens, but for parsing + Whitespace=0x10000000, + ///mask for ignored tokens + IgnoredTokenMask=0xf0000000, + }; + ///creates an empty/invalid token + explicit Token(Position pos=Position(-1,-1)); + ///creates a token from a parsed piece of string, only generic types can be used + Token(QString,Type,Position pos=Position(-1,-1)); + ///creates a literal token + Token(QString,QVariant,Position pos=Position(-1,-1)); + ///returns the string content of the token + QString content()const; + ///returns the type of token this is + Type type()const; + ///for literals: returns the value + QVariant literalValue()const; + ///returns the original position of the token + Position position()const; + ///when the token is hierarchised (Parentheses, Function) this returns the subordinate tokens + QListsubTokens()const; + + ///true if the token is functional (not ignored) + inline bool isFunctional()const{return type()&FunctionalMask;} + ///true if the token represents an operator + inline bool isOperator()const{return type()&OperatorMask;} + ///true if the token can be ignored + inline bool isIgnored()const{return type()&IgnoredTokenMask;} + ///true if the token represents a name + inline bool isName()const{return type()&NameMask;} + ///true if the token is a literal + inline bool isLiteral()const{return type()&LiteralMask;} + protected: + friend class Expression; + ///makes the tokens type more specialized + void setSubType(Type); + ///adds a token to the sub-token list + void addSubToken(const Token&); + ///overrides the list of sub-tokens + void setSubTokens(const QList&); +}; + +///makes tokens accessable to qDebug() +ELAM_EXPORT QDebug& operator<<(QDebug,const Token&); +///makes tokens accessable to qDebug() +ELAM_EXPORT QDebug& operator<<(QDebug,const QList&); + +class Engine; +/**Represents an expression in the context of its engine. + +An expression always has an engine as context and stores a hierarchy of operations (also expressions) to perform when called to evaluate. Expressions may become invalid if constants, functions, or operators change between the time they are created and the time they are evaluated. +*/ +class ELAM_EXPORT Expression +{ + DECLARE_SHARED_DPTR(d) + public: + enum Type { + Literal=Token::Literal, + Variable=Token::Variable, + Constant=Token::Constant, + Function=Token::Function, + Parentheses=Token::Parentheses, + UnaryOp=Token::UnaryOp, + BinaryOp=Token::BinaryOp, + AssignmentOp=Token::AssignmentOp, + Exception=Token::IgnoredTokenMask, + }; + ///creates and invalid expression, that always evaluates to an exception + Expression(); + ///creates an expression by its context engine and its tokens + Expression(Engine*parent,const QList&tokens); + + ///evaluates the expression and returns the result of the evaluation + QVariant evaluate(); + + ///returns the position of the main element of this expression + Position position()const; + private: + friend QDebug& operator<<(QDebug,const Expression&); + ///helper for qDebug() + static void printExpression(QDebug&,const Expression&,int); + ///scan tokens and decide what specific sub-type they are + QListclassifyTokens(QList toks); + /**pushes parentheses and function arguments into the sub-tokens of their parents; + the result is a list of tokens that are on the same level*/ + QListreduceTokens(QList toks); + ///scan tokens for errors, returns Exception::NoError if none are found + ELAM::Exception scanForError(const QList< Token >& toks); + ///reduce surrounding parentheses and whitespace + QListsimplifyTokens(QList toks); + ///parses tokens and splits them by comma + void functionInit(); + ///helper for evaluate - evaluates a function + QVariant evalFunction(); + ///helper for evaluate - evaluates an unary operator + QVariant evalUnary(); + ///helper for evaluate - evaluates an binary operator + QVariant evalBinary(); + ///helper for evaluate - evaluates an assignment and an optional binary operator + QVariant evalAssign(); +}; + +///makes expressions accessable to qDebug() +ELAM_EXPORT QDebug& operator<<(QDebug,const Expression&); + +//end of namespace +}; + +#endif diff --git a/include/elamfloatengine.h b/include/elamfloatengine.h new file mode 100644 index 0000000..0a5c133 --- /dev/null +++ b/include/elamfloatengine.h @@ -0,0 +1,45 @@ +//ELAM floating point engine header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_FLOATENGINE_H +#define ELAM_FLOATENGINE_H + +#include "elamengine.h" + +namespace ELAM { + +/**an engine that has floating point (double) numbers implemented + +This engine type plays nice with the IntEngine functions by supplemening its operators to be able to mix float and int in operations. + +Per default only the float versions are pre-installed. Use IntEngine::configureIntEngine or IntFloatEngine to have both. +*/ +class ELAM_EXPORT FloatEngine:public Engine +{ + public: + ///instantiates a pre-initialized engine + FloatEngine(); + + ///configures any engine to support float + static void configureFloatEngine(Engine&); + + ///returns the high priority for float literal parsers, this applies to floats that are definitely not int + static int floatHighParserPrio(); + ///returns the low priority for float literal parsers, this applies to floats that would be interpreted as int if an int engine is present + static int floatLowParserPrio(); +}; + +///an engine with integer and float math pre-installed, see IntEngine and FloatEngine +class ELAM_EXPORT IntFloatEngine:public Engine +{ + public: + ///instantiates a pre-installed engine + IntFloatEngine(); +}; + +//end of namespace +}; + +#endif diff --git a/include/elamglobal.h b/include/elamglobal.h new file mode 100644 index 0000000..0f7f4d4 --- /dev/null +++ b/include/elamglobal.h @@ -0,0 +1,18 @@ +//ELAM global definitions header +// +// (c) Konrad Rosenbaum, 2012 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_GLOBAL_H +#define ELAM_GLOBAL_H + +//export for DLL +#include + +#if defined(ELAM_LIBRARY_BUILD) +# define ELAM_EXPORT Q_DECL_EXPORT +#else +# define ELAM_EXPORT Q_DECL_IMPORT +#endif + +#endif diff --git a/include/elamintengine.h b/include/elamintengine.h new file mode 100644 index 0000000..5f7acc4 --- /dev/null +++ b/include/elamintengine.h @@ -0,0 +1,29 @@ +//ELAM integer engine header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_INTENGINE_H +#define ELAM_INTENGINE_H + +#include "elamengine.h" + +namespace ELAM { + +///integer math enabled engine +class ELAM_EXPORT IntEngine:public Engine +{ + public: + ///instantiates a pre-configured engine + IntEngine(); + + ///configures any engine to support basic int math + static void configureIntEngine(Engine&); + + ///returns the default priority of the int literal parser + static int intParserPrio(); +}; + +}; + +#endif diff --git a/include/elamstringengine.h b/include/elamstringengine.h new file mode 100644 index 0000000..931cf39 --- /dev/null +++ b/include/elamstringengine.h @@ -0,0 +1,29 @@ +//ELAM string engine header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_STRENGINE_H +#define ELAM_STRENGINE_H + +#include "elamengine.h" + +namespace ELAM { + +///integer math enabled engine +class ELAM_EXPORT StringEngine:public Engine +{ + public: + ///instantiates a pre-configured engine + StringEngine(); + + ///configures any engine to support basic int math + static void configureStringEngine(Engine&); + + ///returns the default priority of the int literal parser + static int stringParserPrio(); +}; + +}; + +#endif diff --git a/include/elamunary.h b/include/elamunary.h new file mode 100644 index 0000000..79561d7 --- /dev/null +++ b/include/elamunary.h @@ -0,0 +1,89 @@ +// main header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_ENGINE_UNARY_H +#define ELAM_ENGINE_UNARY_H + +#include +#include +#include + +#include "../dptr/dptr_base.h" + +#include + +namespace ELAM { +class Engine; + +/** \brief pointer to a function wrapping an unary operator +\param op the operand to be worked on +\param engine the engine calling the operator +\returns the result of the operation*/ +typedef std::functionUnaryOperatorCall; + +/** Helper type to select the correct overload from several variants. +If your compiler complains that it cannot resolve an overloaded pointer when calling UnaryOperator::setCallback then cast to this type to help the compiler: +\code +myUnaryOp.setCallback(UnaryOperatorCall_FP(myFunction),type); +\endcode +*/ +typedef QVariant(*UnaryOperatorCall_FP)(const QVariant&op,Engine&engine); + +/** \brief Wraps a particular unary operator. + +You can use the methods of this class to change the routines that handle the operator and the types on which it operates. Instances of this class are implicitly shared - meaning calls on a copy of an instance are also visible on the original and all other copies. +*/ +class ELAM_EXPORT UnaryOperator +{ + DECLARE_SHARED_DPTR(d); + public: + /**copy constructor, + the instance will access the exact same operator as the original, any setting that is done in the copy is also done in the original and all other copies.*/ + UnaryOperator(const UnaryOperator&); + ///instantiates an empty operator + UnaryOperator(); + ///deletes and operator + ~UnaryOperator(); + + /**the operator becomes a shared copy of op and abandones its old link*/ + UnaryOperator& operator=(const UnaryOperator&op); + + /**sets a callback function for the operator and a specific typ + \param callback the function to call, if it is null the type is deleted from this operators type list + \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced + */ + void setCallback(UnaryOperatorCall callback,QString type); + /**sets a callback function for the operator and a specific typ + \param callback the function to call, if it is null the type is deleted from this operators type list + \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced + */ + void setCallback(UnaryOperatorCall callback,int type); + + /**returns the callback function attached to the type or NULL if there is none*/ + UnaryOperatorCall getCallback(QString type)const; + /**returns the callback function attached to the type or NULL if there is none*/ + UnaryOperatorCall getCallback(int type)const; + + ///removes the type from this operators list + void removeCallback(QString); + ///removes the type from this operators list + void removeCallback(int); + + ///returns all type names that have a valid callback in this operator + QStringList getTypeNames()const; + ///returns all type IDs that have a valid callback in this operator + QList getTypeIds()const; + + ///calls the callback function associated with the type of the argument, throws an exception if there is no callback + QVariant execute(const QVariant&,Engine&)const; + + ///true if this operator has no callbacks + bool isNull()const; +}; + +//end of namespace +}; + +#endif diff --git a/include/elamvalue.h b/include/elamvalue.h new file mode 100644 index 0000000..7ebcc94 --- /dev/null +++ b/include/elamvalue.h @@ -0,0 +1,152 @@ +//ELAM value definition header +// +// (c) Konrad Rosenbaum, 2010 +// protected under the GNU LGPL v3 or at your option any newer + +#ifndef ELAM_VALUE_H +#define ELAM_VALUE_H + +#include +#include +#include +#include + +#include "elamglobal.h" + +namespace ELAM { + +/** \brief A character position inside a text/string that is being evaluated. + +A position consists of line and column. The top left position in a text is assumed to be line 1 column 1. Any position with line and/or column less than zero is considered invalid. + +This class is completely inline and as such should be quite fast.*/ +class ELAM_EXPORT Position +{ + public: + ///converts a pair of ints to a position + inline Position(const QPair&p){mline=p.first;mcol=p.second;} + ///converts a QPoint to a position - x is interpreted as column, y as line + inline Position(const QPoint &p){mline=p.y();mcol=p.x();} + ///instantiates a position from line and column + inline Position(int line,int col){mline=line;mcol=col;} + ///instantiates a position from column only, line is assumed to be "1" + inline Position(int col){mline=1;mcol=col;} + ///instantiates an invalid position + inline Position(){mline=mcol=-1;} + ///copy constructor + inline Position(const Position&p){mline=p.mline;mcol=p.mcol;} + + ///copies a position + inline Position& operator=(const Position&p){mline=p.mline;mcol=p.mcol;return *this;} + + ///returns the line of this position or -1 if the position is invalid + inline int line()const{if(mcol>=0)return mline;else return -1;} + ///returns the column of this position or -1 if the position is invalid + inline int column()const{if(mline>=0)return mcol;else return -1;} + + ///true if this position is valid + inline bool isValid()const{return mline>=0 && mcol >=0;} + + ///transparently converts to a pair of ints + inline operator QPair()const{return QPair(mline,mcol);} + ///transparently converts to a QPoint, with x=column and y=line + inline operator QPoint()const{return QPoint(mcol,mline);} + ///converts to a human readable QString + explicit inline operator QString()const + {return QString("line=%1, column=%2").arg(mline).arg(mcol);} + private: + int mline,mcol; +}; +ELAM_EXPORT QDebug&operator<<(QDebug,const Position&); + +/**Objects of this class represent an exception in the evaluation of an ELAM expression.*/ +class ELAM_EXPORT Exception +{ + public: + ///Type of Exception + enum ErrorType{ + ///not an exception + NoError=0, + ///error while parsing the expression + ParserError, + ///the operator is not known + UnknownOperatorError, + ///the function is not known + UnknownFunctionError, + ///unknown variable or constant + UnknownValueError, + ///the operator or function is known, but the type of one of the arguments is not supported + TypeMismatchError, + ///the amount of arguments to a function is wrong or the syntax of arguments + ArgumentListError, + ///the operation itself failed, e.g. division by zero + OperationError, + }; + + ///instantiates a copy of an exception + Exception(const Exception&); + ///instantiate a copy from a matching variant + Exception(const QVariant&); + /**instantiates an exception + \param type the type of exception + \param errorText some human readable text describing the problem + \param pos the position in the original expression string where the problem occurred*/ + Exception(ErrorType type=NoError,QString errorText=QString(),Position pos=Position()); + /**instantiates an exception + \param type the type of exception + \param errorText some human readable text describing the problem + \param pos the position in the original expression string where the problem occurred*/ + Exception(ErrorType type,Position pos,QString errorText=QString()); + + ///copies an exception + Exception& operator=(const Exception&); + + ///returns the describing text of the exception (if existing) + QString errorText()const{return merr;} + ///type of error represented by the exception + ErrorType errorType()const{return mtype;} + ///returns a human readable error type name of this exception + QString errorTypeName()const; + ///the position in the original expression where the error originated + Position errorPos()const{return mpos;} + ///the position in the original expression where the error originated + Position position()const{return mpos;} + ///the line in the original expression where the error originated + int errorLine()const{return mpos.line();} + ///the column in the original expression where the error originated + int errorColumn()const{return mpos.column();} + + ///overrides the exceptions position + void setPosition(Position p){mpos=p;} + + ///converts the exception to a variant + operator QVariant()const{return QVariant::fromValue(*this);} + + ///the meta type ID (used with QVariant) of the exception type + static int metaTypeId(); + + private: + ErrorType mtype; + QString merr; + Position mpos; +}; + +ELAM_EXPORT QDebug&operator<<(QDebug,const Exception&); + +/**this type is not actually used, its ID is used as a fallback to tell operators, functions and engines that any supported type can be used*/ +class ELAM_EXPORT AnyType +{ + public: + ///returns the meta type ID of the ANY type + static int metaTypeId(); +}; +QDebug&operator<<(QDebug,const AnyType&); + +//end of namespace +}; + + +Q_DECLARE_METATYPE(ELAM::Exception); +Q_DECLARE_METATYPE(ELAM::AnyType); + +#endif diff --git a/src/elam.h b/src/elam.h deleted file mode 100644 index d3806f9..0000000 --- a/src/elam.h +++ /dev/null @@ -1,31 +0,0 @@ -//ELAM main header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_LIB_H -#define ELAM_LIB_H - -#include "elamengine.h" -#include "elamintengine.h" -#include "elamfloatengine.h" -#include "elamboolengine.h" -#include "elamstringengine.h" - -/** \mainpage ELAM - Elementary Logic and Arithmetic Machine - -Please see the main docu for build instructions and a tutorial on how to use ELAM.

- -See the ELAM namespace for member documentation. - -*/ - - -namespace ELAM { - -///returns version information about ELAM -inline QString versionInfo(){return "0.2 alpha";} - -}; - -#endif diff --git a/src/elam.pro b/src/elam.pro index 982c04b..adf6142 100644 --- a/src/elam.pro +++ b/src/elam.pro @@ -1,12 +1,13 @@ TEMPLATE = lib TARGET = elam DESTDIR = .. -CONFIG += staticlib create_prl +CONFIG += dll create_prl QT -= gui OBJECTS_DIR = .ctmp MOC_DIR = .ctmp RCC_DIR = .ctmp - +DEFINES += ELAM_LIBRARY_BUILD +VERSION = 0.3.0 HEADERS += \ elam.h \ @@ -33,7 +34,7 @@ SOURCES += \ elamboolengine.cpp \ elamstringengine.cpp -INCLUDEPATH += . -DEPENDPATH += . +INCLUDEPATH += . ../include +DEPENDPATH += . ../include ../dptr QMAKE_CXXFLAGS+=-std=gnu++0x \ No newline at end of file diff --git a/src/elambinary.h b/src/elambinary.h deleted file mode 100644 index f0972bc..0000000 --- a/src/elambinary.h +++ /dev/null @@ -1,85 +0,0 @@ -// main header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_ENGINE_BINARY_H -#define ELAM_ENGINE_BINARY_H - -#include -#include -#include - -#include "../dptr/dptr_base.h" - -#include - -namespace ELAM { -class Engine; - -/** \brief pointer to a function wrapping a binary operator -\param op1 the left operand -\param op2 the right operand -\param engine the engine calling the operator -\returns the result of the operation*/ -typedef std::functionBinaryOperatorCall; - -/** Helper type to select the correct overload from several variants. -If your compiler complains that it cannot resolve an overloaded pointer when calling BinaryOperator::setCallback then cast to this type to help the compiler: -\code -myBinaryOp.setCallback(BinaryOperatorCall_FP(myFunction),type1,type2); -\endcode -*/ -typedef QVariant(*BinaryOperatorCall_FP)(const QVariant&op1,const QVariant&op2,Engine&engine); - -/** \brief Wraps a particular binary operator. - -You can use the methods of this class to change the routines that handle the operator and the types on which it operates. Instances of this class are implicitly shared - meaning calls on a copy of an instance are also visible on the original and all other copies. -*/ -class BinaryOperator -{ - DECLARE_SHARED_DPTR(d); - public: - BinaryOperator(const BinaryOperator&); - BinaryOperator(); - ~BinaryOperator(); - /**the operator becomes a shared copy of op and abandones its old link*/ - BinaryOperator& operator=(const BinaryOperator&op); - - /**sets a callback function for the operator and a specific typ - \param callback the function to call, if it is null the type is deleted from this operators type list - \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced - */ - void setCallback(BinaryOperatorCall callback,QString type1,QString type2); - /**sets a callback function for the operator and a specific typ - \param callback the function to call, if it is null the type is deleted from this operators type list - \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced - */ - void setCallback(BinaryOperatorCall callback,int type1,int type2); - - /**returns the callback function attached to the type or NULL if there is none*/ - BinaryOperatorCall getCallback(QString type1,QString type2)const; - /**returns the callback function attached to the type or NULL if there is none*/ - BinaryOperatorCall getCallback(int type1,int type2)const; - - ///removes the type from this operators list - void removeCallback(QString,QString); - ///removes the type from this operators list - void removeCallback(int,int); - - ///returns all combinations of type names that have a valid callback in this operator - QList > getTypeNames()const; - ///returns all combinations of type IDs that have a valid callback in this operator - QList > getTypeIds()const; - - ///calls the callback function associated with the type of the argument, throws an exception if there is no callback - QVariant execute(const QVariant&,const QVariant&,Engine&)const; - - ///true if this operator has no callbacks - bool isNull()const; -}; - -//end of namespace -}; - -#endif diff --git a/src/elamboolengine.h b/src/elamboolengine.h deleted file mode 100644 index 379bb32..0000000 --- a/src/elamboolengine.h +++ /dev/null @@ -1,32 +0,0 @@ -//ELAM integer engine header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_BOOLENGINE_H -#define ELAM_BOOLENGINE_H - -#include "elamengine.h" - -namespace ELAM { - -/**A boolean and logic math enabled engine. - -This engine type plays nicely with ELAM::IntEngine -*/ -class BoolEngine:public Engine -{ - public: - ///instantiates a pre-configured engine - BoolEngine(); - - ///configures any engine to support basic boolean math - static void configureBoolEngine(Engine&); - - ///configures any engine to support logic functions - static void configureLogicEngine(Engine&); -}; - -}; - -#endif diff --git a/src/elamcharclass.h b/src/elamcharclass.h deleted file mode 100644 index a3c32e8..0000000 --- a/src/elamcharclass.h +++ /dev/null @@ -1,162 +0,0 @@ -// main header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_ENGINE_CCLASS_H -#define ELAM_ENGINE_CCLASS_H - -#include -#include -#include - -#include "elamexpression.h" - -#include "../dptr/dptr_base.h" - -namespace ELAM { - -/** \brief This class holds the character classes used by an Engine. - -\see Engine::characterClasses() - -There are three major classes of chracters: - - names - - names can be variables, constants, functions - - the names class has two sub-classes - - start-of-names is characters that may start a name, usually letters and underscores - - all-of-names is characters that may be contained anywhere in names, this class must include the complete start of names class - - operators - - any sequence of these characters is interpreted as unary or binary operator - - whitespace - - whitespace can separate other tokens, but is ignored itself - -None of these three classes may overlap. There are several more minor classes: - - literals - - the character class actually only contains characters that can start a literal, the continuation and end of literals is determines by a callback routine - - characters in this class may overlap with names, but must not overlap with operators, whitespace and start-of-names - - parentheses - - are two distinct characters that group expressions, none of them must be contained in any other class - - comma - - a single character separating arguments in functions, the comma character must not be contained in any other class - - assignment - - one or two characters that denote an assignment - - both are optional, both must be contained in operators - - one of the characters, if it exists, is the first character of an assignment - - the other of the characters, if it exists, is the last character of an assignment - - just those two characters are the simple assignment operator - - both surrounding another operator combine the operation with assignment (e.g. a+=b is equivalent to a=a+b) - -*/ -class CharacterClassSettings -{ - DECLARE_SHARED_DPTR(d) - public: - ///class of operator characters - QString operatorClass()const; - ///sets the class of operator characters - void setOperatorClass(QString); - - /**returns the two name sub-classes - nameClass().first refers to start characters, - nameClass().second refers to all characters that can turn up anywhere in names*/ - QPair nameClass()const; - /**sets the two sub-classes of names - \param startchars are characters that can start a name - \param allchars are characters that can turn up anywhere in names, allchars must include all characters from startchars*/ - void setNameClass(QString startchars,QString allchars); - /**convenience overload: sets the two sub-classes of names - \param chars.first are characters that can start a name - \param chars.second are characters that can turn up anywhere in names, second must include all characters from first*/ - void setNameClass(const QPair&chars) - {setNameClass(chars.first,chars.second);} - - ///returns all characters that are regarded as whitespace - QString whitespaceClass()const; - ///sets all characters that are regarded as whitespace - void setWhitespaceClass(QString); - - ///returns all characters that start a literal, normally digits ' and " - QString literalStartClass()const; - ///sets characters that can start a literal - void setLiteralStartClass(QString); - - ///returns the opening (first) and closing (second) character of parentheses - QPair parenthesesChars()const; - /**sets the characters used for parentheses - \param open the character that opens/begins a parentheses structure, normally "(" - \param close the character that closes/ends a parentheses structure, normally ")" - - The parentheses characters must not be included in any other class.*/ - void setParentheses(QChar open,QChar close); - - /** \brief returns the characters that designate an assignment - - - assignmentChars().first is the character that starts an assignment operator, - - assignmentChars().second is the character that ends it.*/ - QPair assignmentChars()const; - - /** sets the characters used for assignment operators - \param start if not '\0' the character that marks the start of an assignment - \param end if not '\0' the character that marks the end of an assignment - - The combination of both characters along (without whitespace) is the direct assignment operator. In automatic assignment operator mode any operator that starts with the start character and ends with end character is regarded as an implicit assignment. - - In the default configuration the start character is not set ('\0') and the end character is '=', so "a=1" will assign the value "1" to the variable "a" and "a += 1" is equivalent to "a = a + 1". - - You can turn this automatism around by defining a start character only (e.g. start='=' and end='\0'). Then the assignment would still be "a = 1", but the combination of assignment and "+" would become "a =+ 1". - - If you define both characters then both must be present in assignments. For example with start=':' and end='=' then assignment becomes "a:=1" and assignment with "+" becomes "a :+= 1". - - If set, both characters must be part of the operator class. - - If both start and end are '\0' it will be impossible to make assignments*/ - void setAssignmentChars(QChar start,QChar end); - - ///returns the character used as a comma (separator of function arguments) - QChar commaChar()const; - /**sets the character used as comma - - The character must not be part of any other class.*/ - void setCommaChar(QChar); - - /**true if the settings are internally consistent - - The character class settings are consistent if all constraints of class inclusion and exclusion are fullfilled.*/ - bool isConsistent()const; - - /**returns the type of token the character belongs to - \param ch the character to be checked - \param oldtype the type the previous character belongs to (set to Invalid if this is the first character) - - Compares the character with the known settings for character classes and returns its probable token type. The old type of the previous character is necessary to check for context sensitive rules. - - \returns the type of this character: - - Invalid is returned if the character does not match any class, parsing should stop here - - If Literal is returned the calling engine must use specialized literal checking functions to find the end of the literal, the next character checke with this routine should be the first one behind the end of the literal - - Assignment characters are returned as Operator class - - Whitespace class characters should be ignored - - Special character types (Par*, Comma) must be tokenized separately - - Any other type (Name, Operator) must be concatenated until the return type changes - */ - Token::Type charType(QChar ch,Token::Type oldtype)const; - - ///returns true if the string contains any assignment operator - bool isAssignment(QString)const; - ///returns true if the string contains exactly the simple assignment operator - bool isSimpleAssignment(QString)const; - - ///returns true if the string can be interpreted as name - bool isName(QString)const; - - ///returns true if the string can be interpreted as operator - bool isOperator(QString)const; - - ///removes assignment chars from the token and returns the pure operator or an empty string if it was a pure assignment - QString toOperator(QString)const; -}; - -//end of namespace -}; - -#endif diff --git a/src/elamengine.cpp b/src/elamengine.cpp index 569248e..9b5a7d4 100644 --- a/src/elamengine.cpp +++ b/src/elamengine.cpp @@ -10,6 +10,8 @@ #include "../dptr/dptr.h" namespace ELAM { + +ELAM_EXPORT QString versionInfo(){return "0.3 alpha";} /////////////////////////////////////////////////////////////////////////////// // Engine diff --git a/src/elamengine.h b/src/elamengine.h deleted file mode 100644 index 0912bb2..0000000 --- a/src/elamengine.h +++ /dev/null @@ -1,260 +0,0 @@ -// main header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_ENGINE_H -#define ELAM_ENGINE_H - -#include -#include -#include - -#include "elamexpression.h" -#include "elamunary.h" -#include "elambinary.h" -#include "elamcharclass.h" - -#include "../dptr/dptr_base.h" - -#include - -namespace ELAM { - - -class Engine; - -/**pointer to a function wrapping a mathematical function -\param args the list of arguments -\returns the result of the function or ELAM::Exception in case or errors - -Functions must check their arguments for validity before they start calculating. On error a function should returns an ELAM::Exception. - -\param args the list of arguments that was given to the function, the implementation must check for length and type of the arguments -\param engine the engine calling the function -*/ -typedef std::function&args,Engine&engine)>Function; - -/** Helper type to select the correct overload from several variants. -If your compiler complains that it cannot resolve an overloaded pointer when calling Engine::setFunction then cast to this type to help the compiler: -\code -myEngine.setFunction("hellofunc",Function_FP(myFunction)); -\endcode -*/ -typedef QVariant(*Function_FP)(const QList&args,Engine&engine); - - -/**wraps the parser routine for a literal -\param expr the original expression string -\param engine the engine that is calling this parser -\param start the character (index of expr) at which the literal starts -\returns the parsed literal (first=string representation, second=value represented by it - -The string representation of the literal must be verbatim from expr, so that the calling engine can determine where to continue parsing in expr. - -If the parser does not find a valid literal according to its rules it must return an empty string. -*/ -typedef std::function(const QString&expr,Engine&engine,int start)>LiteralParser; - -/** Helper type to select the correct overload from several variants. -If your compiler complains that it cannot resolve an overloaded pointer when calling Engine::setLiteralParser then cast to this type to help the compiler: -\code -myEngine.setLiteralParser(Function_FP(myDecimal),"123456789"); -\endcode -*/ -typedef QPair(*LiteralParser_FP)(const QString&expr,Engine&engine,int start); - -/**Wraps a cast function to convert various types into another type. -\param orig the original value of any type -\param engine the engine calling the cast -\returns the converted value that conforms to the expected type*/ -typedef std::functionTypeCast; - -/** Helper type to select the correct overload from several variants. -If your compiler complains that it cannot resolve an overloaded pointer when calling Engine::setAutoCast then cast to this type to help the compiler: -\code -myEngine.setAutoCast(targetType,QList()<0 if the parser is registered successfully, or 0 if: - - the parser is null - - the start characters are empty - - the priority is outside the allowed range (0<=prio<=100) - - A return value >0 can be used as an ID to remove the parser again with removeLiteralParser(int) . - - If a parser function is registered a second time the new registration overwrites the old registration. - */ - int setLiteralParser(LiteralParser parser,QString startchars,int prio=50); - ///removes a parser function - void removeLiteralParser(int parserid); - - ///sets/overrides the priority of an operator, creating the operator if it does not exist yet - void setBinaryOperatorPrio(QString name,int prio); - - /**registers a type as primary, this means it is not cast into another type when encountered - \param typeId the QVariant ID of the type to register*/ - void registerType(int typeId); - /**Registers an automatic cast function. - - Automatic cast functions must succeed in converting, if the result is uncertain (e.g. as in converting a string to a number) use an explicit function. - - \param target the target of the cast function, the target is automatically registered as primary type (see registerType) - \param origin type IDs that are automatically converted using this function, origins that are also primary types are ignored - \param castfunc the function that converts these types - \param prio the priority of the cast, if a cast function for the same origin, but a higher priority exists the one with the higher priority is used; the priority must be a positive value*/ - void setAutoCast(int target,QListorigin,TypeCast castfunc,int prio=50); - - ///simply parses an expression string into an object - Expression expression(QString); - ///simply parses an expression string into an object - Expression expression(QList); - ///simply parses an expression string into a list of tokens - QList tokenize(QString); - ///parses and evaluates an expression string into a final value - QVariant evaluate(QString); - ///evaluates a parsed expression into a final value - QVariant evaluate(Expression); - ///gives access to the character classes settings - CharacterClassSettings characterClasses(); - private: - ///parse a literal - QPairparseLiteral(QString,int); -}; - -//end of namespace -}; - -#endif diff --git a/src/elamexpression.h b/src/elamexpression.h deleted file mode 100644 index b804a05..0000000 --- a/src/elamexpression.h +++ /dev/null @@ -1,176 +0,0 @@ -//ELAM main header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_EXPRESSION_H -#define ELAM_EXPRESSION_H - -#include "elamvalue.h" -#include "../dptr/dptr_base.h" - -namespace ELAM { - -/**Represents a single token in a parsed expression. - -Tokens are pretty stupid themselves - they just know their type, position, their original piece of text and an optional value (literals). They are used by the engine and expressions to transform text into executable expressions.*/ -class Token -{ - DECLARE_SHARED_DPTR(d) - public: - ///The type of token - enum Type { - ///invalid token - Invalid=0, - ///the token represents a function call - Function = 1, - ///the token represents a constant - Constant = 2, - ///the token represents a variable - Variable = 4, - ///a name: function, variable, or constant - Name=0xff, - ///mask for name tokens - NameMask=Name, - - ///the token represents an unary operator - UnaryOp = 0x100, - ///the token represents a binary operator - BinaryOp = 0x200, - ///the token represents an assignment (with optional implicit binary op) - AssignmentOp = 0x400, - ///an operator (unary or binary) - Operator=0xff00, - ///mask for operator tokens - OperatorMask=Operator, - - ///mask for special class tokens that have a syntactic function (parentheses, comma, ...) - SpecialCharMask=0xff0000, - ///mask for parentheses - ParenthesesMask=0xf0000, - ///meta-type used for parsed sub-tokens - Parentheses=0x10000, - ///opening parenthese - ParOpen=0x20000, - ///closing parenthese - ParClose=0x40000, - ///a comma - separating expressions in function calls - Comma=0x100000, - - ///a literal value - Literal=0x1000000, - ///mask for literal values - LiteralMask=Literal, - - ///mask for tokens that are functional (non-ignored) - FunctionalMask=NameMask|OperatorMask|SpecialCharMask, - - ///white space chars, this is actually not used for tokens, but for parsing - Whitespace=0x10000000, - ///mask for ignored tokens - IgnoredTokenMask=0xf0000000, - }; - ///creates an empty/invalid token - explicit Token(Position pos=Position(-1,-1)); - ///creates a token from a parsed piece of string, only generic types can be used - Token(QString,Type,Position pos=Position(-1,-1)); - ///creates a literal token - Token(QString,QVariant,Position pos=Position(-1,-1)); - ///returns the string content of the token - QString content()const; - ///returns the type of token this is - Type type()const; - ///for literals: returns the value - QVariant literalValue()const; - ///returns the original position of the token - Position position()const; - ///when the token is hierarchised (Parentheses, Function) this returns the subordinate tokens - QListsubTokens()const; - - ///true if the token is functional (not ignored) - inline bool isFunctional()const{return type()&FunctionalMask;} - ///true if the token represents an operator - inline bool isOperator()const{return type()&OperatorMask;} - ///true if the token can be ignored - inline bool isIgnored()const{return type()&IgnoredTokenMask;} - ///true if the token represents a name - inline bool isName()const{return type()&NameMask;} - ///true if the token is a literal - inline bool isLiteral()const{return type()&LiteralMask;} - protected: - friend class Expression; - ///makes the tokens type more specialized - void setSubType(Type); - ///adds a token to the sub-token list - void addSubToken(const Token&); - ///overrides the list of sub-tokens - void setSubTokens(const QList&); -}; - -///makes tokens accessable to qDebug() -QDebug& operator<<(QDebug,const Token&); -///makes tokens accessable to qDebug() -QDebug& operator<<(QDebug,const QList&); - -class Engine; -/**Represents an expression in the context of its engine. - -An expression always has an engine as context and stores a hierarchy of operations (also expressions) to perform when called to evaluate. Expressions may become invalid if constants, functions, or operators change between the time they are created and the time they are evaluated. -*/ -class Expression -{ - DECLARE_SHARED_DPTR(d) - public: - enum Type { - Literal=Token::Literal, - Variable=Token::Variable, - Constant=Token::Constant, - Function=Token::Function, - Parentheses=Token::Parentheses, - UnaryOp=Token::UnaryOp, - BinaryOp=Token::BinaryOp, - AssignmentOp=Token::AssignmentOp, - Exception=Token::IgnoredTokenMask, - }; - ///creates and invalid expression, that always evaluates to an exception - Expression(); - ///creates an expression by its context engine and its tokens - Expression(Engine*parent,const QList&tokens); - - ///evaluates the expression and returns the result of the evaluation - QVariant evaluate(); - - ///returns the position of the main element of this expression - Position position()const; - private: - friend QDebug& operator<<(QDebug,const Expression&); - ///helper for qDebug() - static void printExpression(QDebug&,const Expression&,int); - ///scan tokens and decide what specific sub-type they are - QListclassifyTokens(QList toks); - /**pushes parentheses and function arguments into the sub-tokens of their parents; - the result is a list of tokens that are on the same level*/ - QListreduceTokens(QList toks); - ///scan tokens for errors, returns Exception::NoError if none are found - ELAM::Exception scanForError(const QList< Token >& toks); - ///reduce surrounding parentheses and whitespace - QListsimplifyTokens(QList toks); - ///parses tokens and splits them by comma - void functionInit(); - ///helper for evaluate - evaluates a function - QVariant evalFunction(); - ///helper for evaluate - evaluates an unary operator - QVariant evalUnary(); - ///helper for evaluate - evaluates an binary operator - QVariant evalBinary(); - ///helper for evaluate - evaluates an assignment and an optional binary operator - QVariant evalAssign(); -}; - -///makes expressions accessable to qDebug() -QDebug& operator<<(QDebug,const Expression&); - -//end of namespace -}; - -#endif diff --git a/src/elamfloatengine.h b/src/elamfloatengine.h deleted file mode 100644 index b850789..0000000 --- a/src/elamfloatengine.h +++ /dev/null @@ -1,45 +0,0 @@ -//ELAM floating point engine header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_FLOATENGINE_H -#define ELAM_FLOATENGINE_H - -#include "elamengine.h" - -namespace ELAM { - -/**an engine that has floating point (double) numbers implemented - -This engine type plays nice with the IntEngine functions by supplemening its operators to be able to mix float and int in operations. - -Per default only the float versions are pre-installed. Use IntEngine::configureIntEngine or IntFloatEngine to have both. -*/ -class FloatEngine:public Engine -{ - public: - ///instantiates a pre-initialized engine - FloatEngine(); - - ///configures any engine to support float - static void configureFloatEngine(Engine&); - - ///returns the high priority for float literal parsers, this applies to floats that are definitely not int - static int floatHighParserPrio(); - ///returns the low priority for float literal parsers, this applies to floats that would be interpreted as int if an int engine is present - static int floatLowParserPrio(); -}; - -///an engine with integer and float math pre-installed, see IntEngine and FloatEngine -class IntFloatEngine:public Engine -{ - public: - ///instantiates a pre-installed engine - IntFloatEngine(); -}; - -//end of namespace -}; - -#endif diff --git a/src/elamintengine.h b/src/elamintengine.h deleted file mode 100644 index 71ae4ec..0000000 --- a/src/elamintengine.h +++ /dev/null @@ -1,29 +0,0 @@ -//ELAM integer engine header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_INTENGINE_H -#define ELAM_INTENGINE_H - -#include "elamengine.h" - -namespace ELAM { - -///integer math enabled engine -class IntEngine:public Engine -{ - public: - ///instantiates a pre-configured engine - IntEngine(); - - ///configures any engine to support basic int math - static void configureIntEngine(Engine&); - - ///returns the default priority of the int literal parser - static int intParserPrio(); -}; - -}; - -#endif diff --git a/src/elamstringengine.h b/src/elamstringengine.h deleted file mode 100644 index de35cd9..0000000 --- a/src/elamstringengine.h +++ /dev/null @@ -1,29 +0,0 @@ -//ELAM string engine header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_STRENGINE_H -#define ELAM_STRENGINE_H - -#include "elamengine.h" - -namespace ELAM { - -///integer math enabled engine -class StringEngine:public Engine -{ - public: - ///instantiates a pre-configured engine - StringEngine(); - - ///configures any engine to support basic int math - static void configureStringEngine(Engine&); - - ///returns the default priority of the int literal parser - static int stringParserPrio(); -}; - -}; - -#endif diff --git a/src/elamunary.h b/src/elamunary.h deleted file mode 100644 index f79af2c..0000000 --- a/src/elamunary.h +++ /dev/null @@ -1,89 +0,0 @@ -// main header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_ENGINE_UNARY_H -#define ELAM_ENGINE_UNARY_H - -#include -#include -#include - -#include "../dptr/dptr_base.h" - -#include - -namespace ELAM { -class Engine; - -/** \brief pointer to a function wrapping an unary operator -\param op the operand to be worked on -\param engine the engine calling the operator -\returns the result of the operation*/ -typedef std::functionUnaryOperatorCall; - -/** Helper type to select the correct overload from several variants. -If your compiler complains that it cannot resolve an overloaded pointer when calling UnaryOperator::setCallback then cast to this type to help the compiler: -\code -myUnaryOp.setCallback(UnaryOperatorCall_FP(myFunction),type); -\endcode -*/ -typedef QVariant(*UnaryOperatorCall_FP)(const QVariant&op,Engine&engine); - -/** \brief Wraps a particular unary operator. - -You can use the methods of this class to change the routines that handle the operator and the types on which it operates. Instances of this class are implicitly shared - meaning calls on a copy of an instance are also visible on the original and all other copies. -*/ -class UnaryOperator -{ - DECLARE_SHARED_DPTR(d); - public: - /**copy constructor, - the instance will access the exact same operator as the original, any setting that is done in the copy is also done in the original and all other copies.*/ - UnaryOperator(const UnaryOperator&); - ///instantiates an empty operator - UnaryOperator(); - ///deletes and operator - ~UnaryOperator(); - - /**the operator becomes a shared copy of op and abandones its old link*/ - UnaryOperator& operator=(const UnaryOperator&op); - - /**sets a callback function for the operator and a specific typ - \param callback the function to call, if it is null the type is deleted from this operators type list - \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced - */ - void setCallback(UnaryOperatorCall callback,QString type); - /**sets a callback function for the operator and a specific typ - \param callback the function to call, if it is null the type is deleted from this operators type list - \param type the type of variable to work on, this must be a type registered with QVariant, if this type is already known to the operator its callback is replaced - */ - void setCallback(UnaryOperatorCall callback,int type); - - /**returns the callback function attached to the type or NULL if there is none*/ - UnaryOperatorCall getCallback(QString type)const; - /**returns the callback function attached to the type or NULL if there is none*/ - UnaryOperatorCall getCallback(int type)const; - - ///removes the type from this operators list - void removeCallback(QString); - ///removes the type from this operators list - void removeCallback(int); - - ///returns all type names that have a valid callback in this operator - QStringList getTypeNames()const; - ///returns all type IDs that have a valid callback in this operator - QList getTypeIds()const; - - ///calls the callback function associated with the type of the argument, throws an exception if there is no callback - QVariant execute(const QVariant&,Engine&)const; - - ///true if this operator has no callbacks - bool isNull()const; -}; - -//end of namespace -}; - -#endif diff --git a/src/elamvalue.h b/src/elamvalue.h deleted file mode 100644 index 4a8ccfc..0000000 --- a/src/elamvalue.h +++ /dev/null @@ -1,150 +0,0 @@ -//ELAM value definition header -// -// (c) Konrad Rosenbaum, 2010 -// protected under the GNU LGPL v3 or at your option any newer - -#ifndef ELAM_VALUE_H -#define ELAM_VALUE_H - -#include -#include -#include -#include - -namespace ELAM { - -/** \brief A character position inside a text/string that is being evaluated. - -A position consists of line and column. The top left position in a text is assumed to be line 1 column 1. Any position with line and/or column less than zero is considered invalid. - -This class is completely inline and as such should be quite fast.*/ -class Position -{ - public: - ///converts a pair of ints to a position - inline Position(const QPair&p){mline=p.first;mcol=p.second;} - ///converts a QPoint to a position - x is interpreted as column, y as line - inline Position(const QPoint &p){mline=p.y();mcol=p.x();} - ///instantiates a position from line and column - inline Position(int line,int col){mline=line;mcol=col;} - ///instantiates a position from column only, line is assumed to be "1" - inline Position(int col){mline=1;mcol=col;} - ///instantiates an invalid position - inline Position(){mline=mcol=-1;} - ///copy constructor - inline Position(const Position&p){mline=p.mline;mcol=p.mcol;} - - ///copies a position - inline Position& operator=(const Position&p){mline=p.mline;mcol=p.mcol;return *this;} - - ///returns the line of this position or -1 if the position is invalid - inline int line()const{if(mcol>=0)return mline;else return -1;} - ///returns the column of this position or -1 if the position is invalid - inline int column()const{if(mline>=0)return mcol;else return -1;} - - ///true if this position is valid - inline bool isValid()const{return mline>=0 && mcol >=0;} - - ///transparently converts to a pair of ints - inline operator QPair()const{return QPair(mline,mcol);} - ///transparently converts to a QPoint, with x=column and y=line - inline operator QPoint()const{return QPoint(mcol,mline);} - ///converts to a human readable QString - explicit inline operator QString()const - {return QString("line=%1, column=%2").arg(mline).arg(mcol);} - private: - int mline,mcol; -}; -QDebug&operator<<(QDebug,const Position&); - -/**Objects of this class represent an exception in the evaluation of an ELAM expression.*/ -class Exception -{ - public: - ///Type of Exception - enum ErrorType{ - ///not an exception - NoError=0, - ///error while parsing the expression - ParserError, - ///the operator is not known - UnknownOperatorError, - ///the function is not known - UnknownFunctionError, - ///unknown variable or constant - UnknownValueError, - ///the operator or function is known, but the type of one of the arguments is not supported - TypeMismatchError, - ///the amount of arguments to a function is wrong or the syntax of arguments - ArgumentListError, - ///the operation itself failed, e.g. division by zero - OperationError, - }; - - ///instantiates a copy of an exception - Exception(const Exception&); - ///instantiate a copy from a matching variant - Exception(const QVariant&); - /**instantiates an exception - \param type the type of exception - \param errorText some human readable text describing the problem - \param pos the position in the original expression string where the problem occurred*/ - Exception(ErrorType type=NoError,QString errorText=QString(),Position pos=Position()); - /**instantiates an exception - \param type the type of exception - \param errorText some human readable text describing the problem - \param pos the position in the original expression string where the problem occurred*/ - Exception(ErrorType type,Position pos,QString errorText=QString()); - - ///copies an exception - Exception& operator=(const Exception&); - - ///returns the describing text of the exception (if existing) - QString errorText()const{return merr;} - ///type of error represented by the exception - ErrorType errorType()const{return mtype;} - ///returns a human readable error type name of this exception - QString errorTypeName()const; - ///the position in the original expression where the error originated - Position errorPos()const{return mpos;} - ///the position in the original expression where the error originated - Position position()const{return mpos;} - ///the line in the original expression where the error originated - int errorLine()const{return mpos.line();} - ///the column in the original expression where the error originated - int errorColumn()const{return mpos.column();} - - ///overrides the exceptions position - void setPosition(Position p){mpos=p;} - - ///converts the exception to a variant - operator QVariant()const{return QVariant::fromValue(*this);} - - ///the meta type ID (used with QVariant) of the exception type - static int metaTypeId(); - - private: - ErrorType mtype; - QString merr; - Position mpos; -}; - -QDebug&operator<<(QDebug,const Exception&); - -/**this type is not actually used, its ID is used as a fallback to tell operators, functions and engines that any supported type can be used*/ -class AnyType -{ - public: - ///returns the meta type ID of the ANY type - static int metaTypeId(); -}; -QDebug&operator<<(QDebug,const AnyType&); - -//end of namespace -}; - - -Q_DECLARE_METATYPE(ELAM::Exception); -Q_DECLARE_METATYPE(ELAM::AnyType); - -#endif -- 1.7.2.5