Project

General

Profile

Statistics
| Branch: | Revision:

root / src / envir / statisticparser.cc @ a3be1d55

History | View | Annotate | Download (19.2 KB)

1
//==========================================================================
2
//  STATISTICPARSER.CC - 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
#include "statisticparser.h"
19
#include "resultfilters.h"    // WarmupFilter, ExpressionFilter
20
#include "resultrecorders.h"  // ExpressionRecorder
21

    
22

    
23
class SignalSourceReference : public Expression::Variable
24
{
25
  private:
26
    SignalSource signalSource;
27
  public:
28
    SignalSourceReference(const SignalSource& src) : signalSource(src) {}
29
    virtual Functor *dup() const {return new SignalSourceReference(signalSource);}
30
    virtual const char *getName() const {return "<signalsource>";}
31
    virtual char getReturnType() const {return Expression::Value::DBL;}
32
    virtual Expression::Value evaluate(Expression::Value args[], int numargs) {throw opp_runtime_error("unsupported");}
33
    const SignalSource& getSignalSource() {return signalSource;}
34
};
35

    
36
class FilterOrRecorderReference : public Expression::Function
37
{
38
  private:
39
    std::string name;
40
    int argcount;
41
  public:
42
    FilterOrRecorderReference(const char *s, int argc) {name = s; argcount = argc;}
43
    virtual Functor *dup() const {return new FilterOrRecorderReference(name.c_str(), argcount);}
44
    virtual const char *getName() const {return name.c_str();}
45
    virtual const char *getArgTypes() const {const char *ddd="DDDDDDDDDD"; Assert(argcount<10); return ddd+strlen(ddd)-argcount;}
46
    virtual int getNumArgs() const {return argcount;}
47
    virtual char getReturnType() const {return Expression::Value::DBL;}
48
    virtual Expression::Value evaluate(Expression::Value args[], int numargs) {throw opp_runtime_error("unsupported");}
49
};
50

    
51

    
52
class SourceExpressionResolver : public Expression::Resolver
53
{
54
  protected:
55
    cComponent *component;
56
    bool needWarmupPeriodFilter;
57

    
58
  public:
59
    SourceExpressionResolver(cComponent *comp, bool needWarmupFilter)
60
    {
61
        component = comp;
62
        needWarmupPeriodFilter = needWarmupFilter;
63
    }
64

    
65
    virtual Expression::Functor *resolveVariable(const char *varname)
66
    {
67
        // interpret varname as signal name
68
        simsignal_t signalID = cComponent::registerSignal(varname);
69
        if (!needWarmupPeriodFilter)
70
            return new SignalSourceReference(SignalSource(component, signalID));
71
        else
72
        {
73
            WarmupPeriodFilter *warmupFilter = new WarmupPeriodFilter();
74
            component->subscribe(signalID, warmupFilter);
75
            return new SignalSourceReference(SignalSource(warmupFilter));
76
        }
77
    }
78

    
79
    virtual Expression::Functor *resolveFunction(const char *funcname, int argcount)
80
    {
81
        if (MathFunction::supports(funcname))
82
            return new MathFunction(funcname);
83
        else if (false)
84
            ; // TODO: recognize and handle custom functions (i.e. NEDFunctions!)
85
        else
86
            return new FilterOrRecorderReference(funcname, argcount);
87
    }
88
};
89

    
90
//---
91

    
92
static int countDepth(const std::vector<Expression::Elem>& v, int root)
93
{
94
    Assert(root >= 0);
95
    int argc = v[root].getNumArgs();
96
    int depth = 1;
97
    for (int i=0; i<argc; i++)
98
        depth += countDepth(v, root-depth);
99
    return depth;
100
}
101

    
102
SignalSource StatisticSourceParser::parse(cComponent *component, const char *statisticName, const char *sourceSpec, bool needWarmupFilter)
103
{
104
    // parse expression
105
    Expression expr;
106
    SourceExpressionResolver resolver(component, needWarmupFilter);
107
    expr.parse(sourceSpec, &resolver);
108

    
109
    int exprLen = expr.getExpressionLength();
110
    const Expression::Elem *elems = expr.getExpression();
111

    
112
    //printf("Source spec expression %s was parsed as:\n", sourceSpec);
113
    //for (int i=0; i<exprLen; i++)
114
    //    printf("  [%d] %s\n", i, elems[i].str().c_str());
115

    
116
    std::vector<Expression::Elem> stack;
117

    
118
    for (int i = 0; i < exprLen; i++)
119
    {
120
       const Expression::Elem& e = elems[i];
121

    
122
       // push it onto the stack
123
       stack.push_back(e);
124

    
125
       // if TOS is a filter: create ExpressionFilter from top n items, install it
126
       // as listener, create and chain the ResultFilter after it, and replace
127
       // expression on the stack (top n items) with a SourceReference.
128
       if (e.getType()==Expression::Elem::FUNCTOR && dynamic_cast<FilterOrRecorderReference*>(e.getFunctor()))
129
       {
130
           // determine how many elements this expression covers on the stack
131
           int len = countDepth(stack, stack.size()-1);
132
           // use top 'len' elements to create an ExpressionFilter,
133
           // install it, and replace top 'len' elements with a SignalSourceReference
134
           // on the stack.
135
           // if top 'len' elements contain more than one signalsource/filterorrecorder elements --> throw error (not supported for now)
136
           FilterOrRecorderReference *filterRef = (FilterOrRecorderReference *) e.getFunctor();
137
           SignalSource signalSource = createFilter(filterRef, stack, len);
138
           stack.erase(stack.end()-len, stack.end());
139
           stack.push_back(Expression::Elem());
140
           stack.back() = new SignalSourceReference(signalSource);
141
       }
142
    }
143

    
144
    // there may be an outer expression, like: source=2*mean(eed); wrap it into an ExpressionFilter
145
    if (stack.size() > 1)
146
    {
147
        // determine how many elements this covers on the stack
148
        int len = countDepth(stack, stack.size()-1);
149
        // use top 'len' elements to create an ExpressionFilter,
150
        // install it, and replace top 'len' elements with a SignalSourceReference
151
        // on the stack.
152
        // if top 'len' elements contain more than one signalsource/filterorrecorder elements --> throw error (not supported for now)
153
        SignalSource signalSource = createFilter(NULL, stack, len);
154
        stack.erase(stack.end()-len, stack.end());
155
        stack.push_back(Expression::Elem());
156
        stack.back() = new SignalSourceReference(signalSource);
157
    }
158

    
159
    // the whole expression must have evaluated to a single SignalSourceReference
160
    // (at least now, when we don't support computing a scalar from multiple signals)
161
    if (stack.size() != 1)
162
        throw opp_runtime_error("malformed expression"); // something wrong
163
    if (stack[0].getType()!=Expression::Elem::FUNCTOR || !dynamic_cast<SignalSourceReference*>(stack[0].getFunctor()))
164
        throw opp_runtime_error("malformed expression"); // something wrong
165
    SignalSourceReference *signalSourceReference = (SignalSourceReference*) stack[0].getFunctor();
166
    return signalSourceReference->getSignalSource();
167
}
168

    
169
SignalSource StatisticSourceParser::createFilter(FilterOrRecorderReference *filterRef, const std::vector<Expression::Elem>& stack, int len)
170
{
171
    Assert(len >= 1);
172
    int stackSize = stack.size();
173

    
174
    int argLen = filterRef ? len-1 : len;  // often we need to ignore the last element on the stack, which is the filter name itself
175

    
176
    // count SignalSourceReferences (nested filter) - there must be exactly one;
177
    // i.e. the expression may refer to exactly one signal only
178
    int numSignalRefs = 0;
179
    SignalSourceReference *signalSourceReference = NULL;
180
    for (int i = stackSize-len; i < stackSize; i++)
181
    {
182
        const Expression::Elem& e = stack[i];
183
        if (e.getType()==Expression::Elem::FUNCTOR)
184
            if (dynamic_cast<SignalSourceReference*>(e.getFunctor()))
185
                {numSignalRefs++; signalSourceReference = (SignalSourceReference*)e.getFunctor();}
186
    }
187

    
188
    if (numSignalRefs != 1)
189
    {
190
        if (numSignalRefs == 0)
191
            throw cRuntimeError("expression inside %s() does not refer to any signal", filterRef->getName());
192
        else
193
            throw cRuntimeError("expression inside %s() may only refer to one signal", filterRef->getName());
194
    }
195

    
196
    // Note: filterRef==NULL is also valid input, need to be prepared for it!
197
    ResultFilter *filter = NULL;
198
    if (filterRef)
199
    {
200
        const char *filterName = filterRef->getName();
201
        filter = ResultFilterDescriptor::get(filterName)->create();
202
    }
203

    
204
    SignalSource result(NULL);
205

    
206
    if (argLen == 1)
207
    {
208
        // a plain signal reference or chained filter -- no ExpressionFilter needed
209
        const SignalSource& signalSource = signalSourceReference->getSignalSource();
210
        if (!filter)
211
            result = signalSource;
212
        else {
213
            signalSource.subscribe(filter);
214
            result = SignalSource(filter);
215
        }
216
    }
217
    else // (argLen > 1)
218
    {
219
        // some expression -- add an ExpressionFilter, and the new filter on top
220
        // replace Expr with SignalSourceReference
221
        ExpressionFilter *exprFilter = new ExpressionFilter();
222

    
223
        Expression::Elem *v = new Expression::Elem[argLen];
224
        for (int i=0; i<argLen; i++)
225
        {
226
            v[i] = stack[stackSize-len+i];
227
            if (v[i].getType()==Expression::Elem::FUNCTOR && dynamic_cast<SignalSourceReference*>(v[i].getFunctor()))
228
                v[i] = exprFilter->makeValueVariable();
229
        }
230

    
231
        exprFilter->getExpression().setExpression(v, argLen);
232

    
233
        // subscribe
234
        const SignalSource& signalSource = signalSourceReference->getSignalSource();
235
        signalSource.subscribe(exprFilter);
236
        if (!filter)
237
            result = SignalSource(exprFilter);
238
        else {
239
            exprFilter->addDelegate(filter);
240
            result = SignalSource(filter);
241
        }
242
    }
243
    return result;
244
}
245

    
246
//---
247

    
248
class RecorderExpressionResolver : public Expression::Resolver
249
{
250
  protected:
251
    SignalSource signalSource;
252

    
253
  public:
254
    RecorderExpressionResolver(const SignalSource& source) : signalSource(source) {}
255

    
256
    virtual Expression::Functor *resolveVariable(const char *varname)
257
    {
258
        // "$source" to mean the source signal; "timeavg" to mean "timeavg($source)"
259
        if (strcmp(varname, "$source")==0)
260
            return new SignalSourceReference(signalSource);
261
        else
262
            // argcount=0 means that it refers to the source spec; so "max" and "max()"
263
            // will translate to the same thing (cf. with resolveFunction())
264
            return new FilterOrRecorderReference(varname, 0);
265
    }
266

    
267
    virtual Expression::Functor *resolveFunction(const char *funcname, int argcount)
268
    {
269
        if (MathFunction::supports(funcname))
270
            return new MathFunction(funcname);
271
        else if (false)
272
            ; // TODO: recognize and handle custom functions (i.e. NEDFunctions!)
273
        else
274
            return new FilterOrRecorderReference(funcname, argcount);
275
    }
276
};
277

    
278
void StatisticRecorderParser::parse(const SignalSource& source, const char *recordingMode, bool scalarsEnabled, bool vectorsEnabled, cComponent *component, const char *statisticName)
279
{
280
    // parse expression
281
    Expression expr;
282
    RecorderExpressionResolver resolver(source);
283
    expr.parse(recordingMode, &resolver);
284

    
285
    int exprLen = expr.getExpressionLength();
286
    const Expression::Elem *elems = expr.getExpression();
287

    
288
    //printf("Recorder expression %s was parsed as:\n", sourceSpec);
289
    //for (int i=0; i<exprLen; i++)
290
    //    printf("  [%d] %s\n", i, elems[i].str().c_str());
291

    
292
    std::vector<Expression::Elem> stack;
293

    
294
    for (int i = 0; i < exprLen; i++)
295
    {
296
       const Expression::Elem& e = elems[i];
297

    
298
       // push it onto the stack
299
       stack.push_back(e);
300

    
301
       // if TOS is a filter: create ExpressionFilter from top n items, install it
302
       // as listener, create and chain the ResultFilter after it, and replace
303
       // expression on the stack (top n items) with a SourceReference.
304
       if (e.getType()==Expression::Elem::FUNCTOR && dynamic_cast<FilterOrRecorderReference*>(e.getFunctor()))
305
       {
306
           // determine how many elements this expression covers on the stack
307
           int len = countDepth(stack, stack.size()-1);
308
           // use top 'len' elements to create an ExpressionFilter,
309
           // install it, and replace top 'len' elements with a SignalSourceReference
310
           // on the stack.
311
           // if top 'len' elements contain more than one signalsource/filterorrecorder elements --> throw error (not supported for now)
312
           FilterOrRecorderReference *filterOrRecorderRef = (FilterOrRecorderReference *) e.getFunctor();
313
           SignalSource signalSource = createFilterOrRecorder(filterOrRecorderRef, i==exprLen-1, stack, len, source, component, statisticName, recordingMode);
314
           stack.erase(stack.end()-len, stack.end());
315
           stack.push_back(Expression::Elem());
316
           stack.back() = new SignalSourceReference(signalSource);
317
       }
318
    }
319

    
320
    // there may be an outer expression, like: source=2*mean(eed); wrap it into an ExpressionRecorder
321
    if (stack.size() > 1)
322
    {
323
        // determine how many elements this covers on the stack
324
        int len = countDepth(stack, stack.size()-1);
325
        // use top 'len' elements to create an ExpressionFilter,
326
        // install it, and replace top 'len' elements with a SignalSourceReference
327
        // on the stack.
328
        // if top 'len' elements contain more than one signalsource/filterorrecorder elements --> throw error (not supported for now)
329
        SignalSource signalSource = createFilterOrRecorder(NULL, true, stack, len, source, component, statisticName, recordingMode);
330
        stack.erase(stack.end()-len, stack.end());
331
        stack.push_back(Expression::Elem());
332
        stack.back() = new SignalSourceReference(signalSource);
333
    }
334

    
335
    // the whole expression must have evaluated to a single SignalSourceReference
336
    // containing a SignalSource(NULL), because the outer element must be a recorder
337
    // that does not support further chaining (see markRecorders())
338
    if (stack.size() != 1)
339
        throw opp_runtime_error("malformed expression"); // something wrong
340
    if (stack[0].getType()!=Expression::Elem::FUNCTOR || !dynamic_cast<SignalSourceReference*>(stack[0].getFunctor()))
341
        throw opp_runtime_error("malformed expression"); // something wrong
342
    if (!((SignalSourceReference*)stack[0].getFunctor())->getSignalSource().isNull())
343
        throw opp_runtime_error("malformed expression"); // something wrong
344
}
345

    
346
//XXX now it appears that StatisticSourceParser::createFilter() is a special case of this -- eliminate it?
347
SignalSource StatisticRecorderParser::createFilterOrRecorder(FilterOrRecorderReference *filterOrRecorderRef, bool makeRecorder, const std::vector<Expression::Elem>& stack, int len, const SignalSource& source, cComponent *component, const char *statisticName, const char *recordingMode)
348
{
349
    Assert(len >= 1);
350
    int stackSize = stack.size();
351

    
352
    int argLen = filterOrRecorderRef ? len-1 : len;  // often we need to ignore the last element on the stack, which is the filter name itself
353

    
354
    // count embedded signal references, unless filter is arg-less (i.e. it has an
355
    // implicit source arg, like "record=timeavg" which means "record=timeavg($source)")
356
    SignalSourceReference *signalSourceReference = NULL;
357
    if (!filterOrRecorderRef || filterOrRecorderRef->getNumArgs()>0)
358
    {
359
        // count SignalSourceReferences (nested filter) - there must be exactly one;
360
        // i.e. the expression may refer to exactly one signal only
361
        int numSignalRefs = 0;
362
        for (int i = stackSize-len; i < stackSize; i++)
363
        {
364
            const Expression::Elem& e = stack[i];
365
            if (e.getType()==Expression::Elem::FUNCTOR)
366
                if (dynamic_cast<SignalSourceReference*>(e.getFunctor()))
367
                    {numSignalRefs++; signalSourceReference = (SignalSourceReference*)e.getFunctor();}
368
        }
369

    
370
        if (numSignalRefs != 1)
371
        {
372
            if (numSignalRefs == 0)
373
                throw cRuntimeError("expression inside %s() does not refer to any signal", filterOrRecorderRef->getName());
374
            else
375
                throw cRuntimeError("expression inside %s() may only refer to one signal", filterOrRecorderRef->getName());
376
        }
377
    }
378

    
379
    // Note: filterOrRecorderRef==NULL is also valid input, need to be prepared for it!
380
    ResultListener *filterOrRecorder = NULL;
381
    if (filterOrRecorderRef)
382
    {
383
        const char *name = filterOrRecorderRef->getName();
384
        if (makeRecorder) {
385
            ResultRecorder *recorder = ResultRecorderDescriptor::get(name)->create();
386
            recorder->init(component, statisticName, recordingMode);
387
            filterOrRecorder = recorder;
388
        }
389
        else
390
            filterOrRecorder = ResultFilterDescriptor::get(name)->create();
391
    }
392

    
393
    SignalSource result(NULL);
394

    
395
    if (argLen <= 1)
396
    {
397
        // a plain signal reference or chained filter -- no ExpressionFilter needed
398
        const SignalSource& signalSource = signalSourceReference ?
399
            signalSourceReference->getSignalSource() : source;
400

    
401
        if (!filterOrRecorder)
402
            result = signalSource;
403
        else {
404
            signalSource.subscribe(filterOrRecorder);
405
            if (!makeRecorder)
406
                result = SignalSource((ResultFilter*)filterOrRecorder);
407
        }
408
    }
409
    else // (argLen > 1)
410
    {
411
        // some expression -- add an ExpressionFilter or Recorder, and chain the
412
        // new filter (if exists) on top of it.
413
        ResultListener *exprListener;
414
        if (!filterOrRecorder && makeRecorder)
415
        {
416
            // expression recorder
417
            ExpressionRecorder *exprRecorder = new ExpressionRecorder();
418
            exprRecorder->init(component, statisticName, recordingMode);
419

    
420
            Expression::Elem *v = new Expression::Elem[argLen];
421
            for (int i=0; i<argLen; i++)
422
            {
423
                v[i] = stack[stackSize-len+i];
424
                if (v[i].getType()==Expression::Elem::FUNCTOR && dynamic_cast<SignalSourceReference*>(v[i].getFunctor()))
425
                    v[i] = exprRecorder->makeValueVariable();
426
            }
427
            exprRecorder->getExpression().setExpression(v, argLen);
428
            exprListener = exprRecorder;
429
        }
430
        else
431
        {
432
            // expression filter
433
            ExpressionFilter *exprFilter = new ExpressionFilter();
434

    
435
            Expression::Elem *v = new Expression::Elem[argLen];
436
            for (int i=0; i<argLen; i++)
437
            {
438
                v[i] = stack[stackSize-len+i];
439
                if (v[i].getType()==Expression::Elem::FUNCTOR && dynamic_cast<SignalSourceReference*>(v[i].getFunctor()))
440
                    v[i] = exprFilter->makeValueVariable();
441
            }
442
            exprFilter->getExpression().setExpression(v, argLen);
443
            exprListener = exprFilter;
444
        }
445

    
446

    
447
        // subscribe
448
        const SignalSource& signalSource = signalSourceReference->getSignalSource();
449
        signalSource.subscribe(exprListener);
450
        if (!filterOrRecorder) {
451
            if (dynamic_cast<ExpressionFilter*>(exprListener))
452
                result = SignalSource((ExpressionFilter*)exprListener);
453
        }
454
        else {
455
            Assert(dynamic_cast<ExpressionFilter*>(exprListener));
456
            ((ExpressionFilter*)exprListener)->addDelegate(filterOrRecorder);
457
            if (!makeRecorder)
458
                result = SignalSource((ResultFilter*)filterOrRecorder);
459
        }
460
    }
461
    return result; // if makeRecorder=true, we return a NULL SignalSource (no chaining possible)
462
}
463