Statistics
| Branch: | Revision:

root / include / cdynamicexpression.h @ master

History | View | Annotate | Download (12.1 KB)

1
//==========================================================================
2
//   CDYNAMICEXPRESSION.H  - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//  Author: Andras Varga
7
//
8
//==========================================================================
9

    
10
/*--------------------------------------------------------------*
11
  Copyright (C) 1992-2008 Andras Varga
12
  Copyright (C) 2006-2008 OpenSim Ltd.
13

14
  This file is distributed WITHOUT ANY WARRANTY. See the file
15
  `license' for details on this and other legal matters.
16
*--------------------------------------------------------------*/
17

    
18
#ifndef __CDYNAMICEXPRESSION_H
19
#define __CDYNAMICEXPRESSION_H
20

    
21
#include "cexpression.h"
22
#include "cdummystringpool.h"
23

    
24
NAMESPACE_BEGIN
25

    
26
class cXMLElement;
27
class cPar;
28
class cMathFunction;
29
class cNEDFunction;
30

    
31
/**
32
 * A stack-based expression evaluator class, for dynamically created
33
 * expressions.
34
 *
35
 * NOTE: Experimental class -- API is subject to change.
36
 *
37
 * @ingroup SimCore
38
 */
39
class SIM_API cDynamicExpression : public cExpression
40
{
41
  public:
42
    /**
43
     * Operations supported by this class:
44
     *  - add, subtract, multiply, divide ("+" is also string concatenation)
45
     *  - modulo, power of, negation (-1)
46
     *  - equal, not equal, greater, greater or equal, less, less or equal
47
     *  - inline if (the C/C++ ?: operator)
48
     *  - logical and, or, xor, not
49
     *  - bitwise and, or, xor, not (1's complement)
50
     *  - left shift, right shift
51
     */
52
    enum OpType {
53
        ADD, SUB, MUL, DIV, MOD, POW, NEG,
54
        EQ, NE, GT, GE, LT, LE, IIF, AND, OR, XOR, NOT,
55
        BIN_AND, BIN_OR, BIN_XOR, BIN_NOT, LSHIFT, RSHIFT
56
    };
57

    
58
    class Functor; // forward decl
59

    
60
    /**
61
     * One element in a (reverse Polish) expression
62
     */
63
    class SIM_API Elem
64
    {
65
      friend class cDynamicExpression;
66
      private:
67
        // Types:
68
        //  - bool
69
        //  - double (there is no long -- we calculate everything in double)
70
        //  - string
71
        //  - pointer to an "external" cXMLElement
72
        //  - cMathFunction: function with 0/1/2/3/4 double arguments
73
        //  - cNEDFunction: function taking/returning Value (NEDFunction)
74
        //  - functor
75
        //  - math operator (+-*/%^...)
76
        //  - constant subexpression
77
        //
78
        enum Type {UNDEF, BOOL, DBL, STR, XML, MATHFUNC, NEDFUNC, FUNCTOR, OP, CONSTSUBEXPR} type;
79
        static cDummyStringPool stringPool;
80
        union {
81
            bool b;
82
            struct {double d; const char *unit;} d;
83
            const char *s; // points into stringPool
84
            cXMLElement *x;
85
            cMathFunction *f;
86
            struct {cNEDFunction *f; int argc;} nf;
87
            Functor *fu;
88
            OpType op;
89
            cExpression *constExpr;
90
        };
91

    
92
      private:
93
        void deleteOld();
94

    
95
      public:
96
        Elem()  {type=UNDEF;}
97
        Elem(const Elem& other)  {type=UNDEF; operator=(other);}
98
        ~Elem();
99

    
100
        /**
101
         * Assignment operator -- we need to copy Elem at a hundred places
102
         */
103
        void operator=(const Elem& other);
104

    
105
        /**
106
         * Effect during evaluation of the expression: pushes the given boolean
107
         * constant to the evaluation stack.
108
         */
109
        void operator=(bool _b)  {type=BOOL; b=_b;}
110

    
111
        /**
112
         * Effect during evaluation of the expression: pushes the given number
113
         * (which is converted to double) to the evaluation stack.
114
         */
115
        void operator=(int _i)  {type=DBL; d.d=_i; d.unit=NULL;}
116

    
117
        /**
118
         * Effect during evaluation of the expression: pushes the given number
119
         * (which is converted to double) to the evaluation stack.
120
         */
121
        void operator=(short _i)  {type=DBL; d.d=_i; d.unit=NULL;}
122

    
123
        /**
124
         * Effect during evaluation of the expression: pushes the given number
125
         * (which is converted to double) to the evaluation stack.
126
         */
127
        void operator=(long _l)  {type=DBL; d.d=_l; d.unit=NULL;}
128

    
129
        /**
130
         * Effect during evaluation of the expression: pushes the given number
131
         * to the evaluation stack.
132
         */
133
        void operator=(double _d)  {type=DBL; d.d=_d; d.unit=NULL;}
134

    
135
        /**
136
         * Sets the unit of an Elem previously set to a double value.
137
         * The type must already be DBL, or an error gets thrown.
138
         */
139
        void setUnit(const char *s)  {ASSERT(type==DBL); d.unit = stringPool.get(s);}
140

    
141
        /**
142
         * Effect during evaluation of the expression: pushes the given string
143
         * to the evaluation stack.
144
         */
145
        void operator=(const char *_s)  {type=STR; s = stringPool.get(_s);}
146

    
147
        /**
148
         * Effect during evaluation of the expression: pushes the given
149
         * cXMLElement pointer to the evaluation stack.
150
         */
151
        void operator=(cXMLElement *_x)  {type=XML; x=_x;}
152

    
153
        /**
154
         * Effect during evaluation of the expression: Call a function
155
         * taking 0..4 doubles and returning a double.
156
         */
157
        void operator=(cMathFunction *_f)  {type=MATHFUNC; ASSERT(_f); f=_f;}
158

    
159
        /**
160
         * Effect during evaluation of the expression: call a function
161
         * that function takes an array of Values and returns a Value.
162
         */
163
        void set(cNEDFunction *f, int argc)  {type=NEDFUNC; ASSERT(f); nf.f=f; nf.argc=argc;}
164

    
165
        /**
166
         * Function object, with an interface not unlike cNEDFunction.
167
         * This object will be deleted by expression's destructor.
168
         */
169
        void operator=(Functor *f)  {type=FUNCTOR; ASSERT(f); fu=f;}
170

    
171
        /**
172
         * Unary, binary or tertiary (?:) operations.
173
         */
174
        void operator=(OpType _op)  {type=OP; op=_op;}
175

    
176
        /**
177
         * Constant subexpression.
178
         */
179
        void operator=(cExpression *_expr)  {type=CONSTSUBEXPR; constExpr=_expr;}
180

    
181
        /**
182
         * For cDynamicExpression::compare()
183
         */
184
        int compare(const Elem& other) const;
185
    };
186

    
187
    /**
188
     * The dynamic expression evaluator calculates in Values.
189
     *
190
     * Note: There is no <tt>long</tt> field in it: all numeric calculations are
191
     * performed in floating point (<tt>double</tt>). While this is fine on 32-bit
192
     * architectures, on 64-bit architectures some precision will be lost
193
     * because IEEE <tt>double</tt>'s mantissa is only 53 bits.
194
     *
195
     * NOTE: Experimental class -- API is subject to change.
196
     */
197
    struct SIM_API Value
198
    {
199
        // Note: char codes need to be present and be consistent with cNEDFunction::getArgTypes()
200
        enum {UNDEF=0, BOOL='B', DBL='D', STR='S', XML='X'} type;
201
        bool bl;
202
        double dbl;
203
        const char *dblunit; // stringpooled, may be NULL
204
        std::string s;
205
        cXMLElement *xml;
206

    
207
        Value()  {type=UNDEF;}
208
        Value(bool b)  {*this=b;}
209
        Value(long l)  {*this=l;}
210
        Value(double d)  {*this=d;}
211
        Value(double d, const char *unit)  {set(d,unit);}
212
        Value(const char *s)  {*this=s;}
213
        Value(const std::string& s)  {*this=s;}
214
        Value(cXMLElement *x)  {*this=x;}
215
        Value(const cPar& par) {*this=par;}
216
        void operator=(bool b)  {type=BOOL; bl=b;}
217
        void operator=(long l)  {type=DBL; dbl=l; dblunit=NULL;}
218
        void operator=(double d)  {type=DBL; dbl=d; dblunit=NULL;}
219
        void set(double d, const char *unit) {type=DBL; dbl=d; dblunit=unit;}
220
        void operator=(const char *s)  {type=STR; this->s=s?s:"";}
221
        void operator=(const std::string& s)  {type=STR; this->s=s;}
222
        void operator=(cXMLElement *x)  {type=XML; xml=x;}
223
        void operator=(const cPar& par);
224
        std::string str() const;
225
        Value& convertTo(const char *unit) {dbl=convertUnit(dbl, dblunit, unit); dblunit=unit; return *this;}
226
    };
227

    
228
    /**
229
     * Function object base class. We use function objects to handle NED parameter
230
     * references, "index" and "sizeof" operators, and references to NED "for" loop
231
     * variables.
232
     */
233
    class SIM_API Functor : public cObject
234
    {
235
      public:
236
        virtual const char *getArgTypes() const = 0;
237
        virtual int getNumArgs() const {return strlen(getArgTypes());}
238
        virtual char getReturnType() const = 0;
239
        virtual Value evaluate(cComponent *context, Value args[], int numargs) = 0;
240
        virtual std::string str(std::string args[], int numargs) = 0;
241
    };
242

    
243
  protected:
244
    Elem *elems;
245
    int size;
246

    
247
  public:
248
    /** @name Constructors, destructor, assignment. */
249
    //@{
250

    
251
    /**
252
     * Constructor.
253
     */
254
    explicit cDynamicExpression();
255

    
256
    /**
257
     * Copy constructor.
258
     */
259
    cDynamicExpression(const cDynamicExpression& other) {elems=NULL; operator=(other);}
260

    
261
    /**
262
     * Destructor.
263
     */
264
    virtual ~cDynamicExpression();
265

    
266
    /**
267
     * Assignment operator.
268
     */
269
    cDynamicExpression& operator=(const cDynamicExpression& other);
270
    //@}
271

    
272
    /** @name Redefined cObject functions */
273
    //@{
274

    
275
    /**
276
     * Creates and returns an exact copy of this object.
277
     */
278
    virtual cDynamicExpression *dup() const  {return new cDynamicExpression(*this);}
279

    
280
    /**
281
     * Produces a one-line description of the object's contents.
282
     * See cObject for more details.
283
     */
284
    virtual std::string info() const;
285

    
286
    // Note: parsimPack()/parsimUnpack() de-inherited in cExpression.
287
    //@}
288

    
289
    /** @name Setter and evaluator methods. */
290
    //@{
291
    /**
292
     * Sets the Reverse Polish expression to evaluate. The array must be a
293
     * dynamically allocated one, and will be deleted by this object.
294
     * No verification is performed on the expression at this time.
295
     */
296
    virtual void setExpression(Elem e[], int size);
297

    
298
    /**
299
     * Evaluate the expression, and return the results as a Value.
300
     * Throws an error if the expression has some problem (i.e. stack
301
     * overflow/underflow, "cannot cast", "function not found", etc.)
302
     */
303
    virtual Value evaluate(cComponent *context) const;
304

    
305
    /**
306
     * Evaluate the expression and convert the result to bool if possible;
307
     * throw an error if conversion from that type is not supported.
308
     */
309
    virtual bool boolValue(cComponent *context);
310

    
311
    /**
312
     * Evaluate the expression and convert the result to long if possible;
313
     * throw an error if conversion from that type is not supported.
314
     */
315
    virtual long longValue(cComponent *context, const char *expectedUnit=NULL);
316

    
317
    /**
318
     * Evaluate the expression and convert the result to double if possible;
319
     * throw an error if conversion from that type is not supported.
320
     */
321
    virtual double doubleValue(cComponent *context, const char *expectedUnit=NULL);
322

    
323
    /**
324
     * Evaluate the expression and convert the result to string if possible;
325
     * throw an error if conversion from that type is not supported.
326
     */
327
    virtual std::string stringValue(cComponent *context);
328

    
329
    /**
330
     * Evaluate the expression and convert the result to an XML tree if possible;
331
     * throw an error if conversion from that type is not supported.
332
     */
333
    virtual cXMLElement *xmlValue(cComponent *context);
334
    //@}
335

    
336
    /** @name Miscellaneous utility functions. */
337
    //@{
338
    /**
339
     * Converts the expression to string.
340
     */
341
    virtual std::string str() const;
342

    
343
    /**
344
     * Interprets the string as an expression, and stores it.
345
     */
346
    virtual void parse(const char *text);
347

    
348
    /**
349
     * Compares two expressions.
350
     */
351
    virtual int compare(const cExpression *other) const;
352

    
353
    /**
354
     * Returns true if the expression is just a literal (or equivalent to one,
355
     * like "2+2").
356
     */
357
    virtual bool isAConstant() const;
358

    
359
    /**
360
     * Returns true if this expression contains const subexpressions.
361
     */
362
    virtual bool containsConstSubexpressions() const;
363

    
364
    /**
365
     * Evaluates const subexpressions, and replaces them with their values.
366
     * See cDynamicExpression::Elem::CONSTSUBEXPR.
367
     */
368
    virtual void evaluateConstSubexpressions(cComponent *context);
369

    
370
    /**
371
     * Convert the given number into the target unit (e.g. milliwatt to watt).
372
     * Throws an exception if conversion is not possible (unknown/unrelated units).
373
     */
374
    static double convertUnit(double d, const char *unit, const char *targetUnit);
375

    
376
    //@}
377
};
378

    
379
NAMESPACE_END
380

    
381

    
382
#endif
383

    
384