[HELP] Parsing string to recognize Trigo Functions

Hi guys,

I need your help badly.

how do I create a function that can understand trigonometric functions?

Examples:

if I am to input: x^2 + sin(x)

The program will understand the the value between parenthesis preceded by a string
"sin" will be computed as the sine of x. of any function in case.

I have the program here.

Can you help me improve this one? I only have basic knowledge in C++.

Thanks guys.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
//************************************
// C++ BEGINNER PARSER CLASS TUTORIAL
//************************************
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cstring>
using namespace std;

enum types { DELIMITER = 1, VARIABLE, NUMBER };    //DEL = 1; VAR = 2; NUM = 3.

class analyzer
{
    private:
    char *pExpresion;		// Points to the exp<b></b>ression.
    char token[80];		// Holds current token.
    char tokenType;		// Holds token's type.

    void recursive1( double &culmination );
    void recursive2( double &culmination );
    void recursive3( double &culmination );
    void recursive4( double &culmination );
    void recursive5( double &culmination );
    void bomb( double &culmination );
    void nextToken();
    void serror( int error );
    int isdelim( char c );

    public:
    analyzer();					   // analyzer constructor.
    double sniff( char *exp );			// analyzer entry point.
    ~analyzer();						// analyzer destructor.
};

//************************************
// 13 analyzer constructor.
//************************************
analyzer::analyzer()
{

    pExpresion = NULL;

}


double analyzer::sniff( char *exp )
{

    double culmination;

    pExpresion = exp;

    nextToken();
    if( !*token )
    {
        serror( 2 );						// No exp<b></b>ression present.
        return 0.0;
    }
    recursive1( culmination );
    if( *token ) serror( 0 );			// Last token must be null.
    return culmination;
}

//************************************
// 4 Add or subtract two terms.
//************************************
void analyzer::recursive1( double &culmination )
{

    register char beer;
    double bucket;

    recursive2( culmination );
    while( ( beer = *token ) == '+' || beer == '-' )
    {
        nextToken();
        recursive2( bucket );
        switch( beer )
        {
            case '-':
                culmination = culmination - bucket;
                break;
            case '+':
                culmination = culmination + bucket;
                break;
        }
    }
}

//************************************
// 5 Multiply or divide two factors.
//************************************
void analyzer::recursive2( double &culmination )
{

    register char beer;
    double bucket;

    recursive3( culmination );
    while( ( beer = *token ) == '*' || beer == '/' || beer == '%' )
    {
        nextToken();
        recursive3( bucket );
        switch( beer )
        {
            case '*':
                culmination = culmination * bucket;
                break;
            case '/':
                culmination = culmination / bucket;
                break;
            case '%':
                culmination = ( int )culmination % ( int )bucket;
                break;
        }
    }
}


void analyzer::recursive3( double &culmination )
{

    double bucket, ex;
    register int t;

    recursive4( culmination );
    if( *token == '^' )
    {
        nextToken();
        recursive3( bucket );
        ex = culmination;
        if( bucket == 0.0 )
        {
            culmination = 1.0;
            return;
        }
        for( t = ( int )bucket - 1; t>0; --t ) culmination = culmination * ( double )ex;
    }
}

//************************************
// 7 Evaluate a unary + or -.
//************************************
void analyzer::recursive4( double &culmination )
{
    register char  beer;

    beer = 0;
    // if( ( tokenType == DELIMITER ) && *token == '+' || *token == '-' ) // ****
    if( ( tokenType == DELIMITER ) && ( *token == '+' || *token == '-' ) ) // for clarity
    {
        beer = *token;
        nextToken();
    }
    recursive5( culmination );
    if( beer == '-' ) culmination = -culmination;
}


void analyzer::recursive5( double &culmination )
{

    if( ( *token == '(' ) )
    {
        nextToken();
        recursive1( culmination );
        if( *token != ')' )
            serror( 1 );
        nextToken();
    }
    else bomb( culmination );
}

void analyzer::bomb( double &culmination )
{

    switch( tokenType )
    {
        case NUMBER:
            culmination = atof( token );
            nextToken();
            return;

        case VARIABLE:
        {
            std::cout << "looking up value of variable '" << token << "' => assuming result == 999\n" ;
            culmination = 999 ; // *** hard-coded *** TODO: look up symbol table, get the actual value
            nextToken();
            return ;
        }
        default:
            serror( 0 );
    }
}


void analyzer::serror( int error )
{

    // static char *e[] = // ****
    static const char *e[] = // literal strings are arrays of const char
    {
        "Syntax Error",
        "Unbalanced Parentheses",
        "No exp<b></b>ression Present"
    };

    cout << e[error] << endl;
}

//************************************
// 10 Obtain the next token.
//************************************
void analyzer::nextToken()
{

    register char *bucket;

    tokenType = 0;
    bucket = token;
    *bucket = '\0';

    if( !*pExpresion ) return; // At end of exp<b></b>ression.

    while( isspace( *pExpresion ) ) ++pExpresion; // Skip over white space.

    if( strchr( "+-*/%^=()", *pExpresion ) )
    {
        tokenType = DELIMITER;
        // Advance to next char.
        *bucket++ = *pExpresion++;
    }
    else if( isalpha( *pExpresion ) )
    {
        while( !isdelim( *pExpresion ) ) *bucket++ = *pExpresion++;
        tokenType = VARIABLE;
    }
    else if( isdigit( *pExpresion ) )
    {
        while( !isdelim( *pExpresion ) ) *bucket++ = *pExpresion++;
        tokenType = NUMBER;
    }

    *bucket = '\0';
}


int analyzer::isdelim( char c )
{

    //if( strchr( " +-/*%^=()x", c ) || c == 9 || c == '\r' || c == 0 )
    if( strchr( " +-/*%^=()", c ) || c == 9 || c == '\r' || c == 0 )
        return 1;
    return 0;
}


analyzer::~analyzer()
{

}


int main( /*int argc, char* argv[]*/ )
{
    char expstr[80];

    // analyzer equation; // *** moved into the loop // Instantiates equation as an object of type analyzer.

    //for( ;; )	// Creates an infinite loop.
    {
        analyzer equation; // *** moved into the loop // Instantiates equation as an object of type analyzer.
        /*
        cout << endl << endl << endl;
        cout << "  To stop the program" << endl << endl;
        cout << "  enter a period then press return." << endl << endl;
        cout << "  To run the program" << endl << endl;
        cout << "  enter an algebraic express; for example, (12+5)*6 " << endl << endl;
        cout << "  then press return ==>\n";
        */

        cin.getline( expstr, 79 );
        std::cout << "expression: '" << expstr << "'\n\n" ;

        if( *expstr == '.' )
        {
            // equation.~analyzer(); // *** avoid this
            // instead, move the definition of equation into the loop
            // a new analyser object will be created each time through the loop 

            // break; // ****		// Infinite loop exited by typing a period.
            return 0 ; // since we have commented out the loop
        }

        cout << endl << endl << "  Answer is: " << equation.sniff( expstr ) << "\n\n";

        cout << endl << endl << endl;
        cout << "  ";
        // system( "PAUSE" );

        // system( "CLS" );

    };

    cout << endl << endl << endl;
    cout << "  ";
    //system( "PAUSE" );

    return 0;
}

//************************************  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// .... 

/////////////////////// added ///////////////////////////////
#include <string>
#include <map>
#include <math.h>
////////////////////////////////////////////////////////////////
using namespace std;

/////////////////////// added ///////////////////////////////
const std::map< std::string, double(*)(double) > unary_functions =
{ { "sin", ::sin }, { "sqrt", ::sqrt }, { "ceil", ::ceil } /* , ... */ } ;
////////////////////////////////////////////////////////////////


/////////////////////// modified ///////////////////////////////
enum types { DELIMITER = 1, VARIABLE, NUMBER, UNARY_FUNCTION };    // **************

class analyzer
{
    // ...

    /////////////////////// added ///////////////////////////////
    void expect( std::string expected ) { if( token != expected ) serror(0) ; }
    void consume( std::string expected ) { nextToken() ; expect(expected) ; }
    //////////////////////////////////////////////////////

    // ...

};

// ...

void analyzer::bomb( double &culmination )
{

    switch( tokenType )
    {
        case NUMBER:
            culmination = atof( token );
            nextToken();
            return;

        case VARIABLE:
        {
            std::cout << "looking up value of variable '" << token << "' => assuming result == 999\n" ;
            culmination = 999 ; // *** hard-coded *** TODO: look up symbol table, get the actual value
            nextToken();
            return ;
        }

        /////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////// added ///////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        case UNARY_FUNCTION:
        {
            std::cout << "evaluating unary function '" << token << "'\n" ;
            auto fn = unary_functions.find(token)->second ;

            consume( "(" ) ;

            nextToken() ;
            double arg ;
            recursive1(arg) ;

            culmination = fn(arg) ;

            expect( ")" ) ;

            nextToken() ;
            return ;
        }
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////

        default:
            serror( 0 );
    }
}

// ...

void analyzer::nextToken()
{

    /*register*/ char* bucket; // *** register is deprecated **********************************

    tokenType = 0;
    bucket = token;
    *bucket = '\0';

    if( !*pExpresion ) return; // At end of exp<b></b>ression.

    while( isspace( *pExpresion ) ) ++pExpresion; // Skip over white space.

    if( strchr( "+-*/%^=()", *pExpresion ) )
    {
        tokenType = DELIMITER;
        // Advance to next char.
        *bucket++ = *pExpresion++;
    }
    else if( isalpha( *pExpresion ) )
    {
        while( !isdelim( *pExpresion ) ) *bucket++ = *pExpresion++;
        tokenType = VARIABLE;
    }
    else if( isdigit( *pExpresion ) )
    {
        while( !isdelim( *pExpresion ) ) *bucket++ = *pExpresion++;
        tokenType = NUMBER;
    }

    *bucket = '\0';

    /////////////////////// added /////////////////////////////////////////////////////////
    if( unary_functions.find(token) != unary_functions.end() ) tokenType = UNARY_FUNCTION ;
    ///////////////////////////////////////////////////////////////////////////////////////
}

// ... 

Full code: http://coliru.stacked-crooked.com/a/80abc462b8f954ab
Oh. That looks cool. :)
Thanks for the reply JLBorges..
But every time I encode, I get an error.

It says "unary_functions' must be initialized by a constructor, not by {...}

ISO forbids declaration of 'fn' with no type.

here's my headers actually

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#include <iostream>
#include <cstdlib>
#include <cctype>   
#include <cstring>	//string parser
#include <math.h>	//trigo
#include <cmath>	//sinh(x)
#include <conio.h>  // getch()
#include <iomanip>  // setprecision
#include <string>
#include <map>

using namespace std;

#define pause getch();                       //For DEV C++ program, 
#define clrscr() system("CLS");				 //Remove at C4droid
const double e = sinh(1)+cosh(1);
const double pi = acos(0)*2.0;
enum types { DELIMITER = 1, VARIABLE, NUMBER,UNARY_FUNCTION, NEWTON, ILLINOIS, SECANT }; 

const std::map < std::string, double(*)(double) > unary_functions =  {  "sin", ::sin , "sqrt", ::sqrt /* , ... */ };

class analyzer
{
    private:
    char *pExpresion;	
    char token[80];		
    char tokenType;
	void expect( std::string expected ) { if( token != expected ) serror(0) ; }
    void consume( std::string expected ) { nextToken() ; expect(expected) ; }		
    void recursive1( double &culmination, double guess );
    void recursive2( double &culmination, double guess );
    void recursive3( double &culmination, double guess );
    void recursive4( double &culmination, double guess );
    void recursive5( double &culmination, double guess );
    void bomb( double &culmination, double guess );
    void nextToken();
    void serror( int error );
    int isdelim( char c );

    public:
    analyzer();					   
    double sniff( char *exp, double guess );			
    ~analyzer();						
};

analyzer::analyzer()
	{
	    pExpresion = NULL;
	}

double analyzer::sniff( char *exp, double guess )
	{
	    double culmination;
	    pExpresion = exp;
	    nextToken();
	    if( !*token )
	    {
	        serror( 2 );						
	        return 0.0;
	    }
	    recursive1( culmination, guess );
	    if( *token ) serror( 0 );			
	    return culmination;
	}

void analyzer::recursive1( double &culmination, double guess )
	{
	    char beer;
	    double bucket;
	    recursive2( culmination, guess );
	    while( ( beer = *token ) == '+' || beer == '-' )
	    {
	        nextToken();
	        recursive2( bucket, guess );
	        switch( beer )
	        {
	            case '-':
	                culmination = culmination - bucket;
	                break;
	            case '+':
	                culmination = culmination + bucket;
	                break;
	        }
	    }
	}

void analyzer::recursive2( double &culmination, double guess )
	{
	    char beer;
	    double bucket;
	    recursive3( culmination, guess );
	    while( ( beer = *token ) == '*' || beer == '/' || beer == '%' )
	    {
	        nextToken();
	        recursive3( bucket, guess );
	        switch( beer )
	        {
	            case '*':
	                culmination = culmination * bucket;
	                break;
	            case '/':
	                culmination = culmination / bucket;
	                break;
	            case '%':
	                culmination = ( int )culmination % ( int )bucket;
	                break;
	        }
	    }
	}

void analyzer::recursive3( double &culmination, double guess )
	{
	    double bucket, bucket1;
	    int t;
	    int counter = 0;
	    recursive4( culmination, guess );
	    if( *token == '^' )
	    {
	        nextToken();
	        recursive3( bucket, guess );
	        if( bucket == 0.0 )
		        {
		        	culmination = 1.0;
		            return;
		        }
		    culmination = pow (culmination, bucket);  
	    }
	}

void analyzer::recursive4( double &culmination, double guess )
	{
	    char beer;
	    beer = 0;
	    if( ( tokenType == DELIMITER ) && ( *token == '+' || *token == '-' ) ) 
	    {
	        beer = *token;
	        nextToken();
	    }
	    recursive5( culmination, guess );
	    if( beer == '-' ) culmination = -culmination;
	}

void analyzer::recursive5( double &culmination,  double guess )
	{
	    if( ( *token == '(' ) )
	    {
	        nextToken();
	        recursive1( culmination, guess );
	        if( *token != ')' )
	            serror( 1 );
	        nextToken();
	    }
	    else bomb( culmination, guess );
	}

void analyzer::bomb( double &culmination, double guess )
	{
	    float valueX;
	    switch( tokenType )
	    {
	        case NUMBER:
			{
	            culmination = atof( token );
	            nextToken();
	            return;
			}
	        case VARIABLE:
	        {	
				if (*token == 'x' || *token == 'X')
				{  
				    culmination = guess;	   
				}
				else if (*token == 'e' || *token == 'E')
				{
	                culmination = e;
	 	   		}
	 	   		nextToken();
	            return ;
	        }
	        case UNARY_FUNCTION:
		 	{
	 	        auto fn = unary_functions.find(token)->second ;

	            consume( "(" ) ;
	
	            nextToken() ;
	            double arg ;
	            recursive1(arg) ;
	
	            culmination = fn(arg) ;
	
	            expect( ")" ) ;
	
	            nextToken() ;
	            return ;
	 	 	}
	        default:
	            serror( 0 );
	    }
	}

void analyzer::serror( int error )
	{
	    static const char *e[] = 
	    {
	        "Syntax Error",
	        "Unbalanced Parentheses",
	        "No exp<b></b>ression Present"
	    };
	    cout << e[error] << endl;
	}

void analyzer::nextToken()
	{
	    char *bucket;
	    tokenType = 0;
	    bucket = token;
	    *bucket = '\0';
	    if( !*pExpresion ) return;
	    while( isspace( *pExpresion ) ) ++pExpresion;
	    if( strchr( "+-*/%^=()", *pExpresion ) )
	    {
	        tokenType = DELIMITER;
	        *bucket++ = *pExpresion++;
	    }
	    else if( isalpha( *pExpresion ) )
	    {
	        while( !isdelim( *pExpresion ) ) *bucket++ = *pExpresion++;
	        tokenType = VARIABLE;
	    }
	    else if( isdigit( *pExpresion ) )
	    {
	        while( !isdelim( *pExpresion ) ) *bucket++ = *pExpresion++;
	        tokenType = NUMBER;
	    }
	    *bucket = '\0';
	    if( unary_functions.find(token) != unary_functions.end() ) tokenType = UNARY_FUNCTION ;
	}

int analyzer::isdelim( char c )
	{
	    if( strchr( " +-/*%^=()", c ) || c == 9 || c == '\r' || c == 0 )
	        return 1;
	    return 0;
	}	

analyzer::~analyzer()
	{
    }
Last edited on
Sorry, haven't edited my post for a while.
I have changed some contents to evaluate my needs.

May I ask,
Line 222 of the code will not contain any value. (Am i right?)
Why do you have that one there? :)
Last edited on
> It says "unary_functions' must be initialized by a constructor, not by {...}

Compile with -std=c++11 or -std=c++14


> //For DEV C++ program

Hopefully, a current version of Dev-C++ (like Orwell Dev-C++)
Does that have something to do with my recursives (with added
double guess?

Downloaded the Orwell C++. :)
Thanks a lot JLborges
Last edited on
> Line 222 of the code will not contain any value. (Am i right?)

Line 222: recursive1(arg) ;
evaluates the argument to be passed to the function and places it in the local variable arg.

> Why do you have that one there? :)

To evaluate the function, the sub-expression which forms its argument has to be evaluated.
For instance, say, we want to evaluate: sqrt( 45.78 * 62.45 + 67.82 / 45.3 )

To evaluate 45.78 * 62.45 + 67.82 / 45.3

a. we verify and discard the leading parenthesis with consume( "(" ) ;

b. we (the parser) ask the parser (itself) to evaluate 45.78 * 62.45 + 67.82 / 45.3 and place the result in arg with recursive1(arg) ;

c. we call the function with the evaluated argument and place the value returned by the function into culmination with culmination = fn(arg) ;

d. we verify that after the evaluation, the next token is a closing parenthesis with expect( ")" ) ;
Last edited on
here's the output

<a target="_blank" href="http://imageshack.com/f/p2G72K0Gp"><img src="http://imagizer.imageshack.us/v2/150x100q90/902/G72K0G.png" border="0"></a>
closed account (10X9216C)
You could use boost spirit v2 for parser, it provides a way to define a set of rules similar to EBNF if you are familiar with it. Really quick simply calculator i wrote a while back.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#include <iostream>
#include <tuple>
#include <algorithm>
#include <list>
#include <string>
#include <unordered_map>
#include <vector>
#include <cassert>
#include <string>
#include <sstream>
#include <iomanip>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

namespace phx = boost::phoenix;
namespace ascii = boost::spirit::qi::ascii;
namespace qi = boost::spirit::qi;

template<typename T>
std::string ToString(const T& v)
{
    std::ostringstream stream;
    stream << v;
    return stream.str();
}

enum class Opcode
{
    Function,
    Load,
    Add,
    Sub,
    Multiply,
    Divide,
};

struct Function
{
    std::string name;
    int args;
};

struct Compile
{
    template <typename A, typename B>
    struct result { typedef void type; };

    Compile(std::list<Function>& f, std::list<Opcode>& o, std::list<double>& v) : f(f), o(o), v(v)
    {
    }

    void operator()(std::vector<char>& v, int num) const
    {
        f.push_back({ std::string(v.begin(), v.end()), num });
        o.push_back(Opcode::Function);
    }
    void operator()(Opcode c) const { o.push_back(c); }
    void operator()(Opcode c, double value) const { o.push_back(c); v.push_back(value); }

    std::list<Function>& f;
    std::list<Opcode>& o;
    std::list<double>& v;
};

template<typename Iterator>
struct Grammar : boost::spirit::qi::grammar<Iterator, ascii::space_type>
{

    Grammar() : Grammar::base_type(expr), compile(Compile(functions, operations, values))
    {
        using phx::push_back;
        using phx::push_front;

        expr = addExpr.alias();

        funcExpr = (qi::lexeme[+qi::alpha] > '(' > -(expr[qi::_a++] % ',') > ')')[compile(qi::_1, qi::_a)];

        addExpr = multiplyExpr >> *(        ('+' > multiplyExpr[compile(Opcode::Add)])
                                        |   ('-' > multiplyExpr[compile(Opcode::Sub)])
                                   );

        multiplyExpr = mainExpr >> *(       ('*' > mainExpr[compile(Opcode::Multiply)])
                                        |   ('/' > mainExpr[compile(Opcode::Divide)])
                                    );

        mainExpr = funcExpr | varExpr | '(' > expr > ')';

        varExpr = qi::double_[compile(Opcode::Load, qi::_1)];

        qi::on_error<qi::fail>(expr, std::cout << phx::val("Error! Expecting ") << qi::_4 << phx::val(" here: \"")
                                               << phx::construct<std::string>(qi::_3, qi::_2) << phx::val("\"\n"));
    }


    std::list<Function> functions;
    std::list<Opcode> operations;
    std::list<double> values;

    phx::function<Compile> compile;

    qi::rule<Iterator, ascii::space_type, qi::locals<int>> funcExpr;
    qi::rule<Iterator, ascii::space_type> expr, addExpr, multiplyExpr, mainExpr, varExpr;


};

template<typename T>
T pop(std::list<T>& c)
{
    T v = c.back();
    c.pop_back();
    return v;
}

struct FunctionCallerBase
{
    int argCount;
    std::function<double(const std::vector<double>&)> function;
};

template<int N, int C, typename T, typename... Args> struct FuncRef                   { using Type = typename FuncRef<N, C + 1, T, T, Args...>::Type; };
template<int N, typename T, typename... Args>        struct FuncRef<N, N, T, Args...> { using Type = T(*)(Args...); };

template<int N, int C, typename T, int... I> struct Invoker
{
    static T Func(typename FuncRef<N, 0, T>::Type f, const std::vector<T>& args)
    {
        return Invoker<N, C + 1, T, I..., C>::Func(f, args);
    }
};

template<int N, typename T, int... I> struct Invoker<N, N, T, I...>
{
    static T Func(typename FuncRef<N, 0, T>::Type f, const std::vector<T>& args)
    {
        assert(args.size() == N);
        return f(args[I]...);
    }
};

template<int N> struct DoubleFunction
{
    using Ref = typename FuncRef<N, 0, double>::Type;

    static double Invoke(Ref f, const std::vector<double>& args)
    {
        return Invoker<N, 0, double>::Func(f, args);
    }
};

template<int N>
FunctionCallerBase MakeBase(typename DoubleFunction<N>::Ref f)
{
    return{ N, std::bind(DoubleFunction<N>::Invoke, f, std::placeholders::_1) };
}

double div(double a, double b) { return a / b; }
double pi() { return 3.14; }

int main()
{
    try
    {
        std::unordered_map<std::string, FunctionCallerBase> funcTable =
        {
            { "pi", MakeBase<0>(pi) },
            { "sin", MakeBase<1>(std::sin) },
            { "cos", MakeBase<1>(std::cos) },
            { "tan", MakeBase<1>(std::tan) },
            { "asin", MakeBase<1>(std::asin) },
            { "acos", MakeBase<1>(std::acos) },
            { "atan", MakeBase<1>(std::atan) },
            { "div", MakeBase<2>(div) },
        };


        Grammar<std::string::iterator> g;

        std::string str;

        std::getline(std::cin, str);

        auto begin = str.begin();
        auto end = str.end();

        bool hail = boost::spirit::qi::phrase_parse(begin, end, g, boost::spirit::ascii::space);

        if(!hail || begin != end)
        {
            std::cerr << "parse error" << std::endl;
            return 1;
        }

        std::list<double> stack;

        while(!g.operations.empty())
        {

            double v;
            switch(g.operations.front())
            {
                case Opcode::Function:
                {
                    auto& f = g.functions.front();

                    auto it = funcTable.find(g.functions.front().name);

                    if(it == funcTable.end())
                    {
                        throw std::runtime_error("Unknown function name " + f.name + ".");
                    }

                    if(it->second.argCount != f.args)
                    {
                        throw std::runtime_error("Inapprorpiate argument count " + ToString(f.args) + " instead of " + ToString(it->second.argCount) + " " + f.name);
                    }

                    std::vector<double> params;

                    for(int i = 0; i < f.args; ++i)
                    {
                        params.insert(params.begin(), stack.back());
                        stack.pop_back();
                    }

                    stack.push_back(it->second.function(params));
                    g.functions.pop_front();
                    break;
                }
                case Opcode::Load:
                {
                    stack.push_back(g.values.front());
                    g.values.pop_front();
                    break;
                }
                case Opcode::Add:       v = pop(stack); stack.back() += v; break;
                case Opcode::Sub:       v = pop(stack); stack.back() -= v; break;
                case Opcode::Multiply:  v = pop(stack); stack.back() *= v; break;
                case Opcode::Divide:    v = pop(stack); stack.back() /= v; break;
            }

            g.operations.pop_front();
        }

        assert(stack.size());

        std::cout << stack.back();
    }
    catch(std::exception& ex)
    {
        std::cout << ex.what();
        return 1;
    }

}
Thanks for the reply Spectral..
:) Appreciated your help.

although I'm not that familiar with "deep" C++ functions. Basically, what i know is the basic of the basic functions of C++ only. I have tried programming during some codes way back when I was in 2nd year of college..
I'm a Civil engineer by the way so C++ is something like a luxury to me. :)
Topic archived. No new replies allowed.