Subversion Repositories Scribus

Rev

Rev 638 | Rev 4430 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
638 fschmid 1
//==============================
4078 fschmid 2
// Function parser v2.8 by Warp
638 fschmid 3
//==============================
137 Franz 4
 
5
#include "fparser.h"
4078 fschmid 6
#include "fpconfig.h"
7
#include "fptypes.h"
8
using namespace FUNCTIONPARSERTYPES;
137 Franz 9
 
10
#include <cstdlib>
11
#include <cstring>
12
#include <cctype>
13
#include <cmath>
14
 
15
using namespace std;
16
 
17
#ifndef M_PI
18
#define M_PI 3.1415926535897932384626433832795
19
#endif
20
 
21
namespace
22
{
23
    const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]);
24
 
25
 
26
    // BCB4 does not implement the standard lower_bound function.
27
    // This is used instead:
28
    const FuncDefinition* fp_lower_bound(const FuncDefinition* first,
29
                                         const FuncDefinition* last,
30
                                         const FuncDefinition& value)
31
    {
32
        while(first < last)
33
        {
34
            const FuncDefinition* middle = first+(last-first)/2;
35
            if(*middle < value) first = middle+1;
36
            else last = middle;
37
        }
38
        return last;
39
    }
40
 
41
 
42
    // Returns a pointer to the FuncDefinition instance which 'name' is
43
    // the same as the one given by 'F'. If no such function name exists,
44
    // returns 0.
45
    inline const FuncDefinition* FindFunction(const char* F)
46
    {
47
        FuncDefinition func = { F, 0, 0, 0 };
48
        while(isalnum(F[func.nameLength])) ++func.nameLength;
49
        if(func.nameLength)
50
        {
51
            const FuncDefinition* found =
52
                fp_lower_bound(Functions, Functions+FUNC_AMOUNT, func);
53
            if(found == Functions+FUNC_AMOUNT || func < *found)
54
                return 0;
55
            return found;
56
        }
57
        return 0;
58
    }
4078 fschmid 59
}
137 Franz 60
 
61
 
62
//---------------------------------------------------------------------------
63
// Copy-on-write method
64
//---------------------------------------------------------------------------
4078 fschmid 65
void FunctionParser::copyOnWrite()
137 Franz 66
{
67
    if(data->referenceCounter > 1)
68
    {
69
        Data* oldData = data;
70
        data = new Data(*oldData);
71
        --(oldData->referenceCounter);
72
        data->referenceCounter = 1;
73
    }
74
}
75
 
76
 
77
//---------------------------------------------------------------------------
78
// Constructors and destructors
79
//---------------------------------------------------------------------------
80
//===========================================================================
81
FunctionParser::FunctionParser():
82
    parseErrorType(FP_NO_ERROR), evalErrorType(0),
4078 fschmid 83
    data(new Data),
84
    evalRecursionLevel(0)
137 Franz 85
{
86
    data->referenceCounter = 1;
87
}
88
 
89
FunctionParser::~FunctionParser()
90
{
91
    if(--(data->referenceCounter) == 0)
92
    {
93
        delete data;
94
    }
95
}
96
 
97
FunctionParser::FunctionParser(const FunctionParser& cpy):
98
    parseErrorType(cpy.parseErrorType),
99
    evalErrorType(cpy.evalErrorType),
4078 fschmid 100
    data(cpy.data),
101
    evalRecursionLevel(0)
137 Franz 102
{
103
    ++(data->referenceCounter);
104
}
105
 
106
FunctionParser& FunctionParser::operator=(const FunctionParser& cpy)
107
{
108
    if(data != cpy.data)
109
    {
638 fschmid 110
        if(--(data->referenceCounter) == 0) delete data;
137 Franz 111
 
112
        parseErrorType = cpy.parseErrorType;
113
        evalErrorType = cpy.evalErrorType;
114
        data = cpy.data;
4078 fschmid 115
        evalRecursionLevel = cpy.evalRecursionLevel;
137 Franz 116
 
117
        ++(data->referenceCounter);
118
    }
119
 
120
    return *this;
121
}
122
 
123
 
124
FunctionParser::Data::Data():
125
    useDegreeConversion(false),
126
    ByteCode(0), ByteCodeSize(0),
127
    Immed(0), ImmedSize(0),
128
    Stack(0), StackSize(0)
129
{}
130
 
131
FunctionParser::Data::~Data()
132
{
133
    if(ByteCode) { delete[] ByteCode; ByteCode=0; }
134
    if(Immed) { delete[] Immed; Immed=0; }
135
    if(Stack) { delete[] Stack; Stack=0; }
136
}
137
 
138
// Makes a deep-copy of Data:
139
FunctionParser::Data::Data(const Data& cpy):
140
    varAmount(cpy.varAmount), useDegreeConversion(cpy.useDegreeConversion),
141
    Variables(cpy.Variables), Constants(cpy.Constants),
142
    FuncPtrNames(cpy.FuncPtrNames), FuncPtrs(cpy.FuncPtrs),
143
    FuncParserNames(cpy.FuncParserNames), FuncParsers(cpy.FuncParsers),
144
    ByteCode(0), ByteCodeSize(cpy.ByteCodeSize),
145
    Immed(0), ImmedSize(cpy.ImmedSize),
146
    Stack(0), StackSize(cpy.StackSize)
147
{
148
    if(ByteCodeSize) ByteCode = new unsigned[ByteCodeSize];
149
    if(ImmedSize) Immed = new double[ImmedSize];
150
    if(StackSize) Stack = new double[StackSize];
151
 
152
    for(unsigned i=0; i<ByteCodeSize; ++i) ByteCode[i] = cpy.ByteCode[i];
153
    for(unsigned i=0; i<ImmedSize; ++i) Immed[i] = cpy.Immed[i];
154
 
155
    // No need to copy the stack contents because it's obsolete outside Eval()
156
}
157
 
158
 
159
//---------------------------------------------------------------------------
160
// Function parsing
161
//---------------------------------------------------------------------------
162
//===========================================================================
163
namespace
164
{
165
    // Error messages returned by ErrorMsg():
166
    const char* ParseErrorMessage[]=
167
    {
168
        "Syntax error",                             // 0
169
        "Mismatched parenthesis",                   // 1
170
        "Missing ')'",                              // 2
171
        "Empty parentheses",                        // 3
172
        "Syntax error: Operator expected",          // 4
173
        "Not enough memory",                        // 5
4078 fschmid 174
        "An unexpected error occurred. Please make a full bug report "
175
        "to the author",                            // 6
137 Franz 176
        "Syntax error in parameter 'Vars' given to "
177
        "FunctionParser::Parse()",                  // 7
178
        "Illegal number of parameters to function", // 8
179
        "Syntax error: Premature end of string",    // 9
180
        "Syntax error: Expecting ( after function", // 10
181
        ""
182
    };
183
 
184
 
185
    // Parse variables
186
    bool ParseVars(const string& Vars, map<string, unsigned>& dest)
187
    {
188
        unsigned varNumber = VarBegin;
189
        unsigned ind1 = 0, ind2;
190
 
191
        while(ind1 < Vars.size())
192
        {
193
            if(!isalpha(Vars[ind1]) && Vars[ind1]!='_') return false;
194
            for(ind2=ind1+1; ind2<Vars.size() && Vars[ind2]!=','; ++ind2)
195
                if(!isalnum(Vars[ind2]) && Vars[ind2]!='_') return false;
196
            const string varName = Vars.substr(ind1, ind2-ind1);
197
 
198
            if(dest.insert(make_pair(varName, varNumber++)).second == false)
199
                return false;
200
 
201
            ind1 = ind2+1;
202
        }
203
        return true;
204
    }
4078 fschmid 205
}
137 Franz 206
 
207
bool FunctionParser::isValidName(const std::string& name) const
208
{
209
    if(name.empty() || (!isalpha(name[0]) && name[0] != '_')) return false;
210
    for(unsigned i=0; i<name.size(); ++i)
211
        if(!isalnum(name[i]) && name[i] != '_') return false;
212
 
213
    if(FindFunction(name.c_str())) return false;
214
 
215
    return true;
216
}
217
 
218
 
219
// Constants:
220
bool FunctionParser::AddConstant(const string& name, double value)
221
{
222
    if(isValidName(name))
223
    {
224
        const char* n = name.c_str();
225
        if(FindVariable(n, data->FuncParserNames) !=
226
           data->FuncParserNames.end() ||
227
           FindVariable(n, data->FuncPtrNames) !=
228
           data->FuncPtrNames.end())
229
            return false;
230
 
231
        copyOnWrite();
232
 
233
        data->Constants[name] = value;
234
        return true;
235
    }
236
    return false;
237
}
238
 
239
// Function pointers
240
bool FunctionParser::AddFunction(const std::string& name,
241
                                 FunctionPtr func, unsigned paramsAmount)
242
{
243
    if(isValidName(name))
244
    {
245
        const char* n = name.c_str();
246
        if(FindVariable(n, data->FuncParserNames) !=
247
           data->FuncParserNames.end() ||
248
           FindConstant(n) != data->Constants.end())
249
            return false;
250
 
251
        copyOnWrite();
252
 
253
        data->FuncPtrNames[name] = data->FuncPtrs.size();
254
        data->FuncPtrs.push_back(Data::FuncPtrData(func, paramsAmount));
255
        return true;
256
    }
257
    return false;
258
}
259
 
260
bool FunctionParser::checkRecursiveLinking(const FunctionParser* fp) const
261
{
262
    if(fp == this) return true;
263
    for(unsigned i=0; i<fp->data->FuncParsers.size(); ++i)
264
        if(checkRecursiveLinking(fp->data->FuncParsers[i])) return true;
265
    return false;
266
}
267
 
268
bool FunctionParser::AddFunction(const std::string& name,
269
                                 FunctionParser& parser)
270
{
271
    if(isValidName(name))
272
    {
273
        const char* n = name.c_str();
274
        if(FindVariable(n, data->FuncPtrNames) != data->FuncPtrNames.end() ||
275
           FindConstant(n) != data->Constants.end())
276
            return false;
277
 
278
        if(checkRecursiveLinking(&parser)) return false;
279
 
280
        copyOnWrite();
281
 
282
        data->FuncParserNames[name] = data->FuncParsers.size();
283
        data->FuncParsers.push_back(&parser);
284
        return true;
285
    }
286
    return false;
287
}
288
 
289
 
290
 
291
// Main parsing function
292
// ---------------------
293
int FunctionParser::Parse(const std::string& Function,
294
                          const std::string& Vars,
295
                          bool useDegrees)
296
{
297
    copyOnWrite();
298
 
299
    data->Variables.clear();
300
 
301
    if(!ParseVars(Vars, data->Variables))
302
    {
303
        parseErrorType = INVALID_VARS;
304
        return Function.size();
305
    }
306
    data->varAmount = data->Variables.size(); // this is for Eval()
307
 
308
    const char* Func = Function.c_str();
309
 
310
    parseErrorType = FP_NO_ERROR;
311
 
312
    int Result = CheckSyntax(Func);
313
    if(Result>=0) return Result;
314
 
315
    data->useDegreeConversion = useDegrees;
316
    if(!Compile(Func)) return Function.size();
317
 
318
    data->Variables.clear();
319
 
320
    parseErrorType = FP_NO_ERROR;
321
    return -1;
322
}
323
 
324
namespace
325
{
4078 fschmid 326
    const char* const fpOperators[] =
327
    {
328
        "+", "-", "*", "/", "%", "^",
329
        "=", "!=", "<=", "<", ">=", ">", "&", "|",
330
 
331
    };
332
 
137 Franz 333
    // Is given char an operator?
4078 fschmid 334
    // (Returns 0 if not, else the size of the operator)
335
    inline int IsOperator(const char* F)
137 Franz 336
    {
4078 fschmid 337
        for(unsigned opInd = 0; fpOperators[opInd]; ++opInd)
338
        {
339
            const char* op = fpOperators[opInd];
340
            for(unsigned n = 0; F[n] == *op; ++n)
341
            {
342
                ++op;
343
                if(*op == 0) return op-fpOperators[opInd];
344
            }
345
        }
346
        return 0;
137 Franz 347
    }
348
 
349
    // skip whitespace
350
    inline void sws(const char* F, int& Ind)
351
    {
352
        while(F[Ind] && isspace(F[Ind])) ++Ind;
353
    }
4078 fschmid 354
}
137 Franz 355
 
356
// Returns an iterator to the variable with the same name as 'F', or to
357
// Variables.end() if no such variable exists:
358
inline FunctionParser::Data::VarMap_t::const_iterator
359
FunctionParser::FindVariable(const char* F, const Data::VarMap_t& vars) const
360
{
361
    if(vars.size())
362
    {
363
        unsigned ind = 0;
364
        while(isalnum(F[ind]) || F[ind] == '_') ++ind;
365
        if(ind)
366
        {
367
            string name(F, ind);
368
            return vars.find(name);
369
        }
370
    }
371
    return vars.end();
372
}
373
 
374
inline FunctionParser::Data::ConstMap_t::const_iterator
375
FunctionParser::FindConstant(const char* F) const
376
{
377
    if(data->Constants.size())
378
    {
379
        unsigned ind = 0;
380
        while(isalnum(F[ind]) || F[ind] == '_') ++ind;
381
        if(ind)
382
        {
383
            string name(F, ind);
384
            return data->Constants.find(name);
385
        }
386
    }
387
    return data->Constants.end();
388
}
389
 
390
//---------------------------------------------------------------------------
391
// Check function string syntax
392
// ----------------------------
393
int FunctionParser::CheckSyntax(const char* Function)
394
{
395
    const Data::VarMap_t& Variables = data->Variables;
396
    const Data::ConstMap_t& Constants = data->Constants;
397
    const Data::VarMap_t& FuncPtrNames = data->FuncPtrNames;
398
    const Data::VarMap_t& FuncParserNames = data->FuncParserNames;
399
 
400
    vector<int> functionParenthDepth;
401
 
402
    int Ind=0, ParenthCnt=0, c;
403
    char* Ptr;
404
 
405
    while(true)
406
    {
407
        sws(Function, Ind);
408
        c=Function[Ind];
409
 
410
// Check for valid operand (must appear)
411
 
4078 fschmid 412
        // Check for leading - or !
413
        if(c=='-' || c=='!') { sws(Function, ++Ind); c=Function[Ind]; }
137 Franz 414
        if(c==0) { parseErrorType=PREMATURE_EOS; return Ind; }
415
 
416
        // Check for math function
417
        bool foundFunc = false;
418
        const FuncDefinition* fptr = FindFunction(&Function[Ind]);
419
        if(fptr)
420
        {
421
            Ind += fptr->nameLength;
422
            foundFunc = true;
423
        }
424
        else
425
        {
426
            // Check for user-defined function
427
            Data::VarMap_t::const_iterator fIter =
428
                FindVariable(&Function[Ind], FuncPtrNames);
429
            if(fIter != FuncPtrNames.end())
430
            {
431
                Ind += fIter->first.size();
432
                foundFunc = true;
433
            }
434
            else
435
            {
436
                Data::VarMap_t::const_iterator pIter =
437
                    FindVariable(&Function[Ind], FuncParserNames);
438
                if(pIter != FuncParserNames.end())
439
                {
440
                    Ind += pIter->first.size();
441
                    foundFunc = true;
442
                }
443
            }
444
        }
445
 
446
        if(foundFunc)
447
        {
448
            sws(Function, Ind);
449
            c = Function[Ind];
450
            if(c!='(') { parseErrorType=EXPECT_PARENTH_FUNC; return Ind; }
4078 fschmid 451
 
452
            int Ind2 = Ind+1;
453
            sws(Function, Ind2);
454
            if(Function[Ind2] == ')')
455
            {
456
                Ind = Ind2+1;
457
                sws(Function, Ind);
458
                c = Function[Ind];
459
                // Ugly, but other methods would just be uglier...
460
                goto CheckOperator;
461
            }
462
 
137 Franz 463
            functionParenthDepth.push_back(ParenthCnt+1);
464
        }
465
 
466
        // Check for opening parenthesis
467
        if(c=='(')
468
        {
469
            ++ParenthCnt;
470
            sws(Function, ++Ind);
471
            if(Function[Ind]==')') { parseErrorType=EMPTY_PARENTH; return Ind;}
472
            continue;
473
        }
474
 
475
        // Check for number
476
        if(isdigit(c) || (c=='.' && isdigit(Function[Ind+1])))
477
        {
478
            strtod(&Function[Ind], &Ptr);
479
            Ind += int(Ptr-&Function[Ind]);
480
            sws(Function, Ind);
481
            c = Function[Ind];
482
        }
483
        else
484
        { // Check for variable
485
            Data::VarMap_t::const_iterator vIter =
486
                FindVariable(&Function[Ind], Variables);
487
            if(vIter != Variables.end())
488
                Ind += vIter->first.size();
489
            else
490
            {
491
                // Check for constant
492
                Data::ConstMap_t::const_iterator cIter =
493
                    FindConstant(&Function[Ind]);
494
                if(cIter != Constants.end())
495
                    Ind += cIter->first.size();
496
                else
497
                { parseErrorType=SYNTAX_ERROR; return Ind; }
498
            }
499
            sws(Function, Ind);
500
            c = Function[Ind];
501
        }
502
 
503
        // Check for closing parenthesis
504
        while(c==')')
505
        {
506
            if(functionParenthDepth.size() &&
507
               functionParenthDepth.back() == ParenthCnt)
508
                functionParenthDepth.pop_back();
509
            if((--ParenthCnt)<0) { parseErrorType=MISM_PARENTH; return Ind; }
510
            sws(Function, ++Ind);
511
            c=Function[Ind];
512
        }
513
 
514
// If we get here, we have a legal operand and now a legal operator or
515
// end of string must follow
516
 
4078 fschmid 517
    CheckOperator:
137 Franz 518
        // Check for EOS
519
        if(c==0) break; // The only way to end the checking loop without error
4078 fschmid 520
 
137 Franz 521
        // Check for operator
4078 fschmid 522
        int opSize = 0;
523
        if(c == ',' && !functionParenthDepth.empty() &&
524
           functionParenthDepth.back() == ParenthCnt)
525
            opSize = 1;
526
        else
527
            opSize = IsOperator(Function+Ind);
528
        if(opSize == 0)
137 Franz 529
        { parseErrorType=EXPECT_OPERATOR; return Ind; }
530
 
531
// If we get here, we have an operand and an operator; the next loop will
532
// check for another operand (must appear)
4078 fschmid 533
        Ind += opSize;
137 Franz 534
    } // while
535
 
536
    // Check that all opened parentheses are also closed
537
    if(ParenthCnt>0) { parseErrorType=MISSING_PARENTH; return Ind; }
538
 
539
// The string is ok
540
    parseErrorType=FP_NO_ERROR;
541
    return -1;
542
}
543
 
544
 
545
// Compile function string to bytecode
546
// -----------------------------------
547
bool FunctionParser::Compile(const char* Function)
548
{
549
    if(data->ByteCode) { delete[] data->ByteCode; data->ByteCode=0; }
550
    if(data->Immed) { delete[] data->Immed; data->Immed=0; }
551
    if(data->Stack) { delete[] data->Stack; data->Stack=0; }
552
 
553
    vector<unsigned> byteCode; byteCode.reserve(1024);
554
    tempByteCode = &byteCode;
555
 
556
    vector<double> immed; immed.reserve(1024);
557
    tempImmed = &immed;
558
 
559
    data->StackSize = StackPtr = 0;
560
 
561
    CompileExpression(Function, 0);
562
    if(parseErrorType != FP_NO_ERROR) return false;
563
 
564
    data->ByteCodeSize = byteCode.size();
565
    data->ImmedSize = immed.size();
566
 
567
    if(data->ByteCodeSize)
568
    {
569
        data->ByteCode = new unsigned[data->ByteCodeSize];
570
        memcpy(data->ByteCode, &byteCode[0],
571
               sizeof(unsigned)*data->ByteCodeSize);
572
    }
573
    if(data->ImmedSize)
574
    {
575
        data->Immed = new double[data->ImmedSize];
576
        memcpy(data->Immed, &immed[0],
577
               sizeof(double)*data->ImmedSize);
578
    }
579
    if(data->StackSize)
580
        data->Stack = new double[data->StackSize];
581
 
582
    return true;
583
}
584
 
585
 
586
inline void FunctionParser::AddCompiledByte(unsigned c)
587
{
588
    tempByteCode->push_back(c);
589
}
590
 
591
inline void FunctionParser::AddImmediate(double i)
592
{
593
    tempImmed->push_back(i);
594
}
595
 
596
inline void FunctionParser::AddFunctionOpcode(unsigned opcode)
597
{
598
    if(data->useDegreeConversion)
599
        switch(opcode)
600
        {
601
          case cCos:
602
          case cCosh:
603
          case cCot:
604
          case cCsc:
605
          case cSec:
606
          case cSin:
607
          case cSinh:
608
          case cTan:
609
          case cTanh:
610
              AddCompiledByte(cRad);
611
        }
612
 
613
    AddCompiledByte(opcode);
614
 
615
    if(data->useDegreeConversion)
616
        switch(opcode)
617
        {
618
          case cAcos:
619
#ifndef NO_ASINH
620
          case cAcosh:
621
          case cAsinh:
622
          case cAtanh:
623
#endif
624
          case cAsin:
625
          case cAtan:
626
          case cAtan2:
627
              AddCompiledByte(cDeg);
628
        }
629
}
630
 
631
inline void FunctionParser::incStackPtr()
632
{
633
    if(++StackPtr > data->StackSize) ++(data->StackSize);
634
}
635
 
636
 
637
// Compile if()
638
int FunctionParser::CompileIf(const char* F, int ind)
639
{
640
    int ind2 = CompileExpression(F, ind, true); // condition
641
    sws(F, ind2);
642
    if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
643
    AddCompiledByte(cIf);
644
    unsigned curByteCodeSize = tempByteCode->size();
645
    AddCompiledByte(0); // Jump index; to be set later
646
    AddCompiledByte(0); // Immed jump index; to be set later
647
 
648
    --StackPtr;
649
 
650
    ind2 = CompileExpression(F, ind2+1, true); // then
651
    sws(F, ind2);
652
    if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
653
    AddCompiledByte(cJump);
654
    unsigned curByteCodeSize2 = tempByteCode->size();
655
    unsigned curImmedSize2 = tempImmed->size();
656
    AddCompiledByte(0); // Jump index; to be set later
657
    AddCompiledByte(0); // Immed jump index; to be set later
658
 
659
    --StackPtr;
660
 
661
    ind2 = CompileExpression(F, ind2+1, true); // else
662
    sws(F, ind2);
663
    if(F[ind2] != ')') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
664
 
665
    // Set jump indices
666
    (*tempByteCode)[curByteCodeSize] = curByteCodeSize2+1;
667
    (*tempByteCode)[curByteCodeSize+1] = curImmedSize2;
668
    (*tempByteCode)[curByteCodeSize2] = tempByteCode->size()-1;
669
    (*tempByteCode)[curByteCodeSize2+1] = tempImmed->size();
670
 
671
    return ind2+1;
672
}
673
 
674
int FunctionParser::CompileFunctionParams(const char* F, int ind,
675
                                          unsigned requiredParams)
676
{
4078 fschmid 677
    int ind2 = ind;
678
    if(requiredParams > 0)
679
    {
680
        unsigned curStackPtr = StackPtr;
681
        ind2 = CompileExpression(F, ind);
137 Franz 682
 
4078 fschmid 683
        if(StackPtr != curStackPtr+requiredParams)
684
        { parseErrorType=ILL_PARAMS_AMOUNT; return ind; }
137 Franz 685
 
4078 fschmid 686
        StackPtr -= requiredParams - 1;
687
    }
688
    else
689
    {
690
        incStackPtr();
691
    }
692
 
137 Franz 693
    sws(F, ind2);
694
    return ind2+1; // F[ind2] is ')'
695
}
696
 
697
// Compiles element
698
int FunctionParser::CompileElement(const char* F, int ind)
699
{
700
    sws(F, ind);
701
    char c = F[ind];
702
 
703
    if(c == '(')
704
    {
705
        ind = CompileExpression(F, ind+1);
706
        sws(F, ind);
707
        return ind+1; // F[ind] is ')'
708
    }
709
 
638 fschmid 710
    if(isdigit(c) || c=='.' /*|| c=='-'*/) // Number
137 Franz 711
    {
712
        const char* startPtr = &F[ind];
713
        char* endPtr;
714
        double val = strtod(startPtr, &endPtr);
715
        AddImmediate(val);
716
        AddCompiledByte(cImmed);
717
        incStackPtr();
718
        return ind+(endPtr-startPtr);
719
    }
720
 
721
    if(isalpha(c) || c == '_') // Function, variable or constant
722
    {
723
        const FuncDefinition* func = FindFunction(F+ind);
724
        if(func) // is function
725
        {
726
            int ind2 = ind + func->nameLength;
727
            sws(F, ind2); // F[ind2] is '('
728
            if(strcmp(func->name, "if") == 0) // "if" is a special case
729
            {
730
                return CompileIf(F, ind2+1);
731
            }
732
 
733
#ifndef DISABLE_EVAL
734
            unsigned requiredParams =
735
                strcmp(func->name, "eval") == 0 ?
736
                data->Variables.size() : func->params;
737
#else
738
            unsigned requiredParams = func->params;
739
#endif
740
            ind2 = CompileFunctionParams(F, ind2+1, requiredParams);
741
            AddFunctionOpcode(func->opcode);
742
            return ind2; // F[ind2-1] is ')'
743
        }
744
 
745
        Data::VarMap_t::const_iterator vIter =
746
            FindVariable(F+ind, data->Variables);
747
        if(vIter != data->Variables.end()) // is variable
748
        {
749
            AddCompiledByte(vIter->second);
750
            incStackPtr();
751
            return ind + vIter->first.size();
752
        }
753
 
754
        Data::ConstMap_t::const_iterator cIter = FindConstant(F+ind);
755
        if(cIter != data->Constants.end()) // is constant
756
        {
757
            AddImmediate(cIter->second);
758
            AddCompiledByte(cImmed);
759
            incStackPtr();
760
            return ind + cIter->first.size();
761
        }
762
 
763
        Data::VarMap_t::const_iterator fIter =
764
            FindVariable(F+ind, data->FuncPtrNames);
765
        if(fIter != data->FuncPtrNames.end()) // is user-defined func pointer
766
        {
767
            unsigned index = fIter->second;
768
 
769
            int ind2 = ind + fIter->first.length();
770
            sws(F, ind2); // F[ind2] is '('
771
 
772
            ind2 = CompileFunctionParams(F, ind2+1,
773
                                         data->FuncPtrs[index].params);
774
 
775
            AddCompiledByte(cFCall);
776
            AddCompiledByte(index);
777
            return ind2;
778
        }
779
 
780
        Data::VarMap_t::const_iterator pIter =
781
            FindVariable(F+ind, data->FuncParserNames);
782
        if(pIter != data->FuncParserNames.end()) // is user-defined func parser
783
        {
784
            unsigned index = pIter->second;
785
 
786
            int ind2 = ind + pIter->first.length();
787
            sws(F, ind2); // F[ind2] is '('
788
 
789
            ind2 = CompileFunctionParams
790
                (F, ind2+1, data->FuncParsers[index]->data->varAmount);
791
 
792
            AddCompiledByte(cPCall);
793
            AddCompiledByte(index);
794
            return ind2;
795
        }
796
    }
797
 
798
    parseErrorType = UNEXPECTED_ERROR;
799
    return ind;
800
}
801
 
802
// Compiles '^'
803
int FunctionParser::CompilePow(const char* F, int ind)
804
{
805
    int ind2 = CompileElement(F, ind);
806
    sws(F, ind2);
807
 
808
    while(F[ind2] == '^')
809
    {
638 fschmid 810
        ind2 = CompileUnaryMinus(F, ind2+1);
137 Franz 811
        sws(F, ind2);
812
        AddCompiledByte(cPow);
813
        --StackPtr;
814
    }
815
 
816
    return ind2;
817
}
818
 
638 fschmid 819
// Compiles unary '-'
820
int FunctionParser::CompileUnaryMinus(const char* F, int ind)
821
{
822
    sws(F, ind);
4078 fschmid 823
    if(F[ind] == '-' || F[ind] == '!')
638 fschmid 824
    {
825
        int ind2 = ind+1;
826
        sws(F, ind2);
827
        ind2 = CompilePow(F, ind2);
828
        sws(F, ind2);
829
 
830
        // if we are negating a constant, negate the constant itself:
4078 fschmid 831
        if(F[ind] == '-' && tempByteCode->back() == cImmed)
638 fschmid 832
            tempImmed->back() = -tempImmed->back();
833
 
834
        // if we are negating a negation, we can remove both:
4078 fschmid 835
        else if((F[ind] == '-' && tempByteCode->back() == cNeg))
638 fschmid 836
            tempByteCode->pop_back();
837
 
838
        else
4078 fschmid 839
            AddCompiledByte(F[ind] == '-' ? cNeg : cNot);
638 fschmid 840
 
841
        return ind2;
842
    }
843
 
844
    int ind2 = CompilePow(F, ind);
845
    sws(F, ind2);
846
    return ind2;
847
}
848
 
137 Franz 849
// Compiles '*', '/' and '%'
850
int FunctionParser::CompileMult(const char* F, int ind)
851
{
638 fschmid 852
    int ind2 = CompileUnaryMinus(F, ind);
137 Franz 853
    sws(F, ind2);
854
    char op;
855
 
856
    while((op = F[ind2]) == '*' || op == '/' || op == '%')
857
    {
638 fschmid 858
        ind2 = CompileUnaryMinus(F, ind2+1);
137 Franz 859
        sws(F, ind2);
860
        switch(op)
861
        {
862
          case '*': AddCompiledByte(cMul); break;
863
          case '/': AddCompiledByte(cDiv); break;
864
          case '%': AddCompiledByte(cMod); break;
865
        }
866
        --StackPtr;
867
    }
868
 
869
    return ind2;
870
}
871
 
872
// Compiles '+' and '-'
873
int FunctionParser::CompileAddition(const char* F, int ind)
874
{
875
    int ind2 = CompileMult(F, ind);
876
    sws(F, ind2);
877
    char op;
878
 
879
    while((op = F[ind2]) == '+' || op == '-')
880
    {
881
        ind2 = CompileMult(F, ind2+1);
882
        sws(F, ind2);
883
        AddCompiledByte(op=='+' ? cAdd : cSub);
884
        --StackPtr;
885
    }
886
 
887
    return ind2;
888
}
889
 
890
// Compiles '=', '<' and '>'
891
int FunctionParser::CompileComparison(const char* F, int ind)
892
{
893
    int ind2 = CompileAddition(F, ind);
894
    sws(F, ind2);
895
    char op;
896
 
4078 fschmid 897
    while((op = F[ind2]) == '=' || op == '<' || op == '>' || op == '!')
137 Franz 898
    {
4078 fschmid 899
        int opSize = (F[ind2+1] == '=' ? 2 : 1);
900
        ind2 = CompileAddition(F, ind2+opSize);
137 Franz 901
        sws(F, ind2);
902
        switch(op)
903
        {
4078 fschmid 904
          case '=':
905
              AddCompiledByte(cEqual); break;
906
          case '<':
907
              AddCompiledByte(opSize == 1 ? cLess : cLessOrEq); break;
908
          case '>':
909
              AddCompiledByte(opSize == 1 ? cGreater : cGreaterOrEq); break;
910
          case '!':
911
              AddCompiledByte(cNEqual); break;
137 Franz 912
        }
913
        --StackPtr;
914
    }
915
 
916
    return ind2;
917
}
918
 
919
// Compiles '&'
920
int FunctionParser::CompileAnd(const char* F, int ind)
921
{
922
    int ind2 = CompileComparison(F, ind);
923
    sws(F, ind2);
924
 
925
    while(F[ind2] == '&')
926
    {
927
        ind2 = CompileComparison(F, ind2+1);
928
        sws(F, ind2);
929
        AddCompiledByte(cAnd);
930
        --StackPtr;
931
    }
932
 
933
    return ind2;
934
}
935
 
936
// Compiles '|'
937
int FunctionParser::CompileOr(const char* F, int ind)
938
{
939
    int ind2 = CompileAnd(F, ind);
940
    sws(F, ind2);
941
 
942
    while(F[ind2] == '|')
943
    {
944
        ind2 = CompileAnd(F, ind2+1);
945
        sws(F, ind2);
946
        AddCompiledByte(cOr);
947
        --StackPtr;
948
    }
949
 
950
    return ind2;
951
}
952
 
953
// Compiles ','
954
int FunctionParser::CompileExpression(const char* F, int ind, bool stopAtComma)
955
{
956
    int ind2 = CompileOr(F, ind);
957
    sws(F, ind2);
958
 
959
    if(stopAtComma) return ind2;
960
 
961
    while(F[ind2] == ',')
962
    {
963
        ind2 = CompileOr(F, ind2+1);
964
        sws(F, ind2);
965
    }
966
 
967
    return ind2;
968
}
969
 
970
 
971
// Return parse error message
972
// --------------------------
973
const char* FunctionParser::ErrorMsg() const
974
{
975
    if(parseErrorType != FP_NO_ERROR) return ParseErrorMessage[parseErrorType];
976
    return 0;
977
}
978
 
979
//---------------------------------------------------------------------------
980
// Function evaluation
981
//---------------------------------------------------------------------------
982
//===========================================================================
983
namespace
984
{
985
    inline int doubleToInt(double d)
986
    {
987
        return d<0 ? -int((-d)+.5) : int(d+.5);
988
    }
989
 
990
    inline double Min(double d1, double d2)
991
    {
992
        return d1<d2 ? d1 : d2;
993
    }
994
    inline double Max(double d1, double d2)
995
    {
996
        return d1>d2 ? d1 : d2;
997
    }
998
 
999
 
1000
    inline double DegreesToRadians(double degrees)
1001
    {
1002
        return degrees*(M_PI/180.0);
1003
    }
1004
    inline double RadiansToDegrees(double radians)
1005
    {
1006
        return radians*(180.0/M_PI);
1007
    }
1008
}
1009
 
1010
double FunctionParser::Eval(const double* Vars)
1011
{
1012
    const unsigned* const ByteCode = data->ByteCode;
1013
    const double* const Immed = data->Immed;
1014
    double* const Stack = data->Stack;
1015
    const unsigned ByteCodeSize = data->ByteCodeSize;
1016
    unsigned IP, DP=0;
1017
    int SP=-1;
1018
 
1019
    for(IP=0; IP<ByteCodeSize; ++IP)
1020
    {
1021
        switch(ByteCode[IP])
1022
        {
1023
// Functions:
1024
          case   cAbs: Stack[SP] = fabs(Stack[SP]); break;
1025
          case  cAcos: if(Stack[SP] < -1 || Stack[SP] > 1)
1026
                       { evalErrorType=4; return 0; }
1027
                       Stack[SP] = acos(Stack[SP]); break;
1028
#ifndef NO_ASINH
1029
          case cAcosh: Stack[SP] = acosh(Stack[SP]); break;
1030
#endif
1031
          case  cAsin: if(Stack[SP] < -1 || Stack[SP] > 1)
1032
                       { evalErrorType=4; return 0; }
1033
                       Stack[SP] = asin(Stack[SP]); break;
1034
#ifndef NO_ASINH
1035
          case cAsinh: Stack[SP] = asinh(Stack[SP]); break;
1036
#endif
1037
          case  cAtan: Stack[SP] = atan(Stack[SP]); break;
1038
          case cAtan2: Stack[SP-1] = atan2(Stack[SP-1], Stack[SP]);
1039
                       --SP; break;
1040
#ifndef NO_ASINH
1041
          case cAtanh: Stack[SP] = atanh(Stack[SP]); break;
1042
#endif
1043
          case  cCeil: Stack[SP] = ceil(Stack[SP]); break;
1044
          case   cCos: Stack[SP] = cos(Stack[SP]); break;
1045
          case  cCosh: Stack[SP] = cosh(Stack[SP]); break;
1046
 
1047
          case   cCot:
1048
              {
1049
                  double t = tan(Stack[SP]);
1050
                  if(t == 0) { evalErrorType=1; return 0; }
1051
                  Stack[SP] = 1/t; break;
1052
              }
1053
          case   cCsc:
1054
              {
1055
                  double s = sin(Stack[SP]);
1056
                  if(s == 0) { evalErrorType=1; return 0; }
1057
                  Stack[SP] = 1/s; break;
1058
              }
1059
 
1060
 
1061
#ifndef DISABLE_EVAL
1062
          case  cEval:
1063
              {
4078 fschmid 1064
                  double retVal = 0;
1065
                  if(evalRecursionLevel == EVAL_MAX_REC_LEVEL)
1066
                  {
1067
                      evalErrorType = 5;
1068
                  }
1069
                  else
1070
                  {
1071
                      data->Stack = new double[data->StackSize];
1072
                      ++evalRecursionLevel;
1073
                      retVal = Eval(&Stack[SP-data->varAmount+1]);
1074
                      --evalRecursionLevel;
1075
                      delete[] data->Stack;
1076
                      data->Stack = Stack;
1077
                  }
137 Franz 1078
                  SP -= data->varAmount-1;
1079
                  Stack[SP] = retVal;
1080
                  break;
1081
              }
1082
#endif
1083
 
1084
          case   cExp: Stack[SP] = exp(Stack[SP]); break;
1085
          case cFloor: Stack[SP] = floor(Stack[SP]); break;
1086
 
1087
          case    cIf:
1088
              {
1089
                  unsigned jumpAddr = ByteCode[++IP];
1090
                  unsigned immedAddr = ByteCode[++IP];
1091
                  if(doubleToInt(Stack[SP]) == 0)
1092
                  {
1093
                      IP = jumpAddr;
1094
                      DP = immedAddr;
1095
                  }
1096
                  --SP; break;
1097
              }
1098
 
1099
          case   cInt: Stack[SP] = floor(Stack[SP]+.5); break;
1100
          case   cLog: if(Stack[SP] <= 0) { evalErrorType=3; return 0; }
1101
                       Stack[SP] = log(Stack[SP]); break;
1102
          case cLog10: if(Stack[SP] <= 0) { evalErrorType=3; return 0; }
1103
                       Stack[SP] = log10(Stack[SP]); break;
1104
          case   cMax: Stack[SP-1] = Max(Stack[SP-1], Stack[SP]);
1105
                       --SP; break;
1106
          case   cMin: Stack[SP-1] = Min(Stack[SP-1], Stack[SP]);
1107
                       --SP; break;
1108
          case   cSec:
1109
              {
1110
                  double c = cos(Stack[SP]);
1111
                  if(c == 0) { evalErrorType=1; return 0; }
1112
                  Stack[SP] = 1/c; break;
1113
              }
1114
          case   cSin: Stack[SP] = sin(Stack[SP]); break;
1115
          case  cSinh: Stack[SP] = sinh(Stack[SP]); break;
1116
          case  cSqrt: if(Stack[SP] < 0) { evalErrorType=2; return 0; }
1117
                       Stack[SP] = sqrt(Stack[SP]); break;
1118
          case   cTan: Stack[SP] = tan(Stack[SP]); break;
1119
          case  cTanh: Stack[SP] = tanh(Stack[SP]); break;
1120
 
1121
 
1122
// Misc:
1123
          case cImmed: Stack[++SP] = Immed[DP++]; break;
1124
          case  cJump: DP = ByteCode[IP+2];
1125
                       IP = ByteCode[IP+1];
1126
                       break;
1127
 
1128
// Operators:
1129
          case   cNeg: Stack[SP] = -Stack[SP]; break;
1130
          case   cAdd: Stack[SP-1] += Stack[SP]; --SP; break;
1131
          case   cSub: Stack[SP-1] -= Stack[SP]; --SP; break;
1132
          case   cMul: Stack[SP-1] *= Stack[SP]; --SP; break;
1133
          case   cDiv: if(Stack[SP] == 0) { evalErrorType=1; return 0; }
1134
                       Stack[SP-1] /= Stack[SP]; --SP; break;
1135
          case   cMod: if(Stack[SP] == 0) { evalErrorType=1; return 0; }
1136
                       Stack[SP-1] = fmod(Stack[SP-1], Stack[SP]);
1137
                       --SP; break;
1138
          case   cPow: Stack[SP-1] = pow(Stack[SP-1], Stack[SP]);
1139
                       --SP; break;
1140
 
4078 fschmid 1141
#ifdef FP_EPSILON
1142
          case cEqual: Stack[SP-1] =
1143
                           (fabs(Stack[SP-1]-Stack[SP]) <= FP_EPSILON);
1144
                       --SP; break;
1145
          case cNEqual: Stack[SP-1] =
1146
                            (fabs(Stack[SP-1] - Stack[SP]) >= FP_EPSILON);
1147
                       --SP; break;
1148
          case  cLess: Stack[SP-1] = (Stack[SP-1] < Stack[SP]-FP_EPSILON);
1149
                       --SP; break;
1150
          case  cLessOrEq: Stack[SP-1] = (Stack[SP-1] <= Stack[SP]+FP_EPSILON);
1151
                       --SP; break;
1152
          case cGreater: Stack[SP-1] = (Stack[SP-1]-FP_EPSILON > Stack[SP]);
1153
                         --SP; break;
1154
          case cGreaterOrEq: Stack[SP-1] =
1155
                                 (Stack[SP-1]+FP_EPSILON >= Stack[SP]);
1156
                         --SP; break;
1157
#else
137 Franz 1158
          case cEqual: Stack[SP-1] = (Stack[SP-1] == Stack[SP]);
1159
                       --SP; break;
4078 fschmid 1160
          case cNEqual: Stack[SP-1] = (Stack[SP-1] != Stack[SP]);
1161
                       --SP; break;
137 Franz 1162
          case  cLess: Stack[SP-1] = (Stack[SP-1] < Stack[SP]);
1163
                       --SP; break;
4078 fschmid 1164
          case  cLessOrEq: Stack[SP-1] = (Stack[SP-1] <= Stack[SP]);
1165
                       --SP; break;
137 Franz 1166
          case cGreater: Stack[SP-1] = (Stack[SP-1] > Stack[SP]);
1167
                         --SP; break;
4078 fschmid 1168
          case cGreaterOrEq: Stack[SP-1] = (Stack[SP-1] >= Stack[SP]);
1169
                         --SP; break;
1170
#endif
1171
 
137 Franz 1172
          case   cAnd: Stack[SP-1] =
1173
                           (doubleToInt(Stack[SP-1]) &&
1174
                            doubleToInt(Stack[SP]));
1175
                       --SP; break;
1176
          case    cOr: Stack[SP-1] =
1177
                           (doubleToInt(Stack[SP-1]) ||
1178
                            doubleToInt(Stack[SP]));
1179
                       --SP; break;
4078 fschmid 1180
          case   cNot: Stack[SP] = !doubleToInt(Stack[SP]); break;
137 Franz 1181
 
1182
// Degrees-radians conversion:
1183
          case   cDeg: Stack[SP] = RadiansToDegrees(Stack[SP]); break;
1184
          case   cRad: Stack[SP] = DegreesToRadians(Stack[SP]); break;
1185
 
1186
// User-defined function calls:
1187
          case cFCall:
1188
              {
1189
                  unsigned index = ByteCode[++IP];
1190
                  unsigned params = data->FuncPtrs[index].params;
1191
                  double retVal =
1192
                      data->FuncPtrs[index].ptr(&Stack[SP-params+1]);
4078 fschmid 1193
                  SP -= int(params)-1;
137 Franz 1194
                  Stack[SP] = retVal;
1195
                  break;
1196
              }
1197
 
1198
          case cPCall:
1199
              {
1200
                  unsigned index = ByteCode[++IP];
1201
                  unsigned params = data->FuncParsers[index]->data->varAmount;
1202
                  double retVal =
1203
                      data->FuncParsers[index]->Eval(&Stack[SP-params+1]);
4078 fschmid 1204
                  SP -= int(params)-1;
137 Franz 1205
                  Stack[SP] = retVal;
1206
                  break;
1207
              }
1208
 
1209
 
1210
#ifdef SUPPORT_OPTIMIZER
1211
          case   cVar: break; // Paranoia. These should never exist
1212
          case   cDup: Stack[SP+1] = Stack[SP]; ++SP; break;
1213
          case   cInv:
1214
              if(Stack[SP] == 0.0) { evalErrorType=1; return 0; }
1215
              Stack[SP] = 1.0/Stack[SP];
1216
              break;
1217
#endif
1218
 
1219
// Variables:
1220
          default:
1221
              Stack[++SP] = Vars[ByteCode[IP]-VarBegin];
1222
        }
1223
    }
1224
 
1225
    evalErrorType=0;
1226
    return Stack[SP];
1227
}
1228
 
1229
 
638 fschmid 1230
#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT
137 Franz 1231
namespace
1232
{
1233
    inline void printHex(std::ostream& dest, unsigned n)
1234
    {
1235
        dest.width(8); dest.fill('0'); hex(dest); //uppercase(dest);
1236
        dest << n;
1237
    }
1238
}
1239
 
1240
void FunctionParser::PrintByteCode(std::ostream& dest) const
1241
{
1242
    const unsigned* const ByteCode = data->ByteCode;
1243
    const double* const Immed = data->Immed;
1244
 
1245
    for(unsigned IP=0, DP=0; IP<data->ByteCodeSize; ++IP)
1246
    {
1247
        printHex(dest, IP);
1248
        dest << ": ";
1249
 
1250
        unsigned opcode = ByteCode[IP];
1251
 
1252
        switch(opcode)
1253
        {
1254
          case cIf:
1255
              dest << "jz\t";
1256
              printHex(dest, ByteCode[IP+1]+1);
1257
              dest << endl;
1258
              IP += 2;
1259
              break;
1260
 
1261
          case cJump:
1262
              dest << "jump\t";
1263
              printHex(dest, ByteCode[IP+1]+1);
1264
              dest << endl;
1265
              IP += 2;
1266
              break;
1267
          case cImmed:
1268
              dest.precision(10);
1269
              dest << "push\t" << Immed[DP++] << endl;
1270
              break;
1271
 
1272
          case cFCall:
1273
              {
1274
                  unsigned index = ByteCode[++IP];
1275
                  Data::VarMap_t::const_iterator iter =
1276
                      data->FuncPtrNames.begin();
1277
                  while(iter->second != index) ++iter;
4078 fschmid 1278
                  dest << "fcall\t" << iter->first
1279
                       << " (" << data->FuncPtrs[index].params << ")" << endl;
137 Franz 1280
                  break;
1281
              }
1282
 
1283
          case cPCall:
1284
              {
1285
                  unsigned index = ByteCode[++IP];
1286
                  Data::VarMap_t::const_iterator iter =
1287
                      data->FuncParserNames.begin();
1288
                  while(iter->second != index) ++iter;
4078 fschmid 1289
                  dest << "pcall\t" << iter->first
1290
                       << " (" << data->FuncParsers[index]->data->varAmount
1291
                       << ")" << endl;
137 Franz 1292
                  break;
1293
              }
1294
 
1295
          default:
1296
              if(opcode < VarBegin)
1297
              {
1298
                  string n;
4078 fschmid 1299
                  unsigned params = 1;
137 Franz 1300
                  switch(opcode)
1301
                  {
1302
                    case cNeg: n = "neg"; break;
1303
                    case cAdd: n = "add"; break;
1304
                    case cSub: n = "sub"; break;
1305
                    case cMul: n = "mul"; break;
1306
                    case cDiv: n = "div"; break;
1307
                    case cMod: n = "mod"; break;
1308
                    case cPow: n = "pow"; break;
1309
                    case cEqual: n = "eq"; break;
4078 fschmid 1310
                    case cNEqual: n = "neq"; break;
137 Franz 1311
                    case cLess: n = "lt"; break;
4078 fschmid 1312
                    case cLessOrEq: n = "le"; break;
137 Franz 1313
                    case cGreater: n = "gt"; break;
4078 fschmid 1314
                    case cGreaterOrEq: n = "ge"; break;
137 Franz 1315
                    case cAnd: n = "and"; break;
1316
                    case cOr: n = "or"; break;
4078 fschmid 1317
                    case cNot: n = "not"; break;
137 Franz 1318
                    case cDeg: n = "deg"; break;
1319
                    case cRad: n = "rad"; break;
1320
 
1321
#ifndef DISABLE_EVAL
1322
                    case cEval: n = "call\t0"; break;
1323
#endif
1324
 
1325
#ifdef SUPPORT_OPTIMIZER
1326
                    case cVar: n = "(var)"; break;
1327
                    case cDup: n = "dup"; break;
1328
                    case cInv: n = "inv"; break;
1329
#endif
1330
 
4078 fschmid 1331
                    default:
1332
                        n = Functions[opcode-cAbs].name;
1333
                        params = Functions[opcode-cAbs].params;
137 Franz 1334
                  }
4078 fschmid 1335
                  dest << n;
1336
                  if(params != 1) dest << " (" << params << ")";
1337
                  dest << endl;
137 Franz 1338
              }
1339
              else
1340
              {
1341
                  dest << "push\tVar" << opcode-VarBegin << endl;
1342
              }
1343
        }
1344
    }
1345
}
638 fschmid 1346
#endif
137 Franz 1347
 
1348
 
1349
 
1350
 
4078 fschmid 1351
#ifndef SUPPORT_OPTIMIZER
1352
void FunctionParser::MakeTree(void *) const {}
137 Franz 1353
void FunctionParser::Optimize()
1354
{
1355
    // Do nothing if no optimizations are supported.
1356
}
1357
#endif