The program crashes

Pages: 12
closed account (z05DSL3A)
Please don't take this the wrong way, but the code is a bit of a mess. I can't follow it properly without spending a lot of time on it.

TrigSqrt() is never called.

you need to include cmath..
1
2
3
4
5
6
7
8
9
#include <iostream>
#include <cmath>
using namespace std;

// Not Needed useing cmath header
//double cos (double x );
//double sin (double x );
//double tan (double x );
//double sqrt (double x ); 


I would sugest that you try restructuring your code.

Sorry.
Last edited on
I rewrote some of it to begin again, but it doesn't work, I'm not that god at this really.
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
#include <iostream>
using namespace std;

enum TOKEN
{
  PARBEG, PAREND, PLUS, TIMES, SIN
}

typedef int Iterator;
int begin, end, oper;
double rakna(Iterator begin, Iterator end);
{
  double res;
  int has_type;
  if(begin != end && begin+1!=end && *begin==TOKEN_PARBEG && *(end-1)==TOKEN_PAREND)
  {
    return rakna(begin+1,end-1,0);
  }
  if(oper==0)
  {
    Iterator next=begin, last=next;
    res=0.0;
    while(last!=end)
    {
      ++last;
      next=find_if(next,end,has_type(TOKEN_PLUS));
      res+=rakna(last, next, 1);
    }
  }
  else if(oper==1)
  {
    Iterator next=begin,last=next;
    res=1.0;
    while(last!=end)
    {
      ++last;
      next=find_if(next,end,has_type(TOKEN_TIMES));
      res*=rakna(last,next,2);
    }
  }
  else if(oper==2)
  {
    if(begin->type==TOKEN_SIN)
    {
      res=sin(rakna(begin+1,end,3));
    }
  }
  else
  {
    assert(begin+1==end);
    assert(begin->has_value());
    res=begin->value;
  }
  return res;
}
closed account (z05DSL3A)
Here is some code put together from Stroustrups book, compare it to your previous code.

The Grammar for the language accepted by this calculator is
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
program:
    END
    expr_list END

expr_list:
    expression PRINT
    expression PRINT expr_list

expression:
    term + expression
    term - expression
    term

term:
    primary / term
    primary * term
    primary

primary:
    NUMBER
    NAME
    NAME = expression
    - primary
    ( expression )


When you have your head around that, look at modifying the grammar to incorporate sin, cos... that should help you get you calls to the relevant functions in the right place.

Hope this helps.

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
#include <iostream>
#include <string>
#include <map>

using std::string;
using std::cin;
using std::cerr;
using std::endl;

/*****************************************************************************/
namespace Lexer
{
    enum Token{
        NAME, NUMBER, END, PLUS='+', MINUS='-', MUL='*', DIV='/',
        PRINT=';', ASSIGN='=', LP='(', RP=')'
    };

    Token currToken;
    double numberValue;
    string stringValue;
    
    Token getToken();
}

/*****************************************************************************/
namespace Parser
{
    double prim(bool);
    double term(bool);
    double expr(bool);

    std::map<string,double> table;
    int noOfErrors;
    double error(const string& s);

    using Lexer::getToken;
    using Lexer::currToken;
    using Lexer::numberValue;
    using Lexer::stringValue;
}

/***************************************************************************/
/*
program:
    END
    expr_list END

expr_list:
    expression PRINT
    expression PRINT expr_list

expression:
    term + expression
    term - expression
    term

term:
    primary / term
    primary * term
    primary

primary:
    NUMBER
    NAME
    NAME = expression
    - primary
    ( expression )
*/
int main(int argc, char* argv[])
{
    while(cin)
    {
        //Put the first token
        Lexer::getToken(); 
        //
        // break out of while if the end token
        if(Lexer::currToken == Lexer::END) break;
        //
        // if current token is PRINT 
        if(Lexer::currToken == Lexer::PRINT) continue;
        //
        // call expr() without geting the next token to evaluate the expresion
        std::cout << Parser::expr(false) << std::endl;
    }
    return 0;
}

/*****************************************************************************/
// Lexer::getToken()
// The parser uses getToken() to get its input. The most recent call to 
// getToken is stored in the global variable currToken.
Lexer::Token Lexer::getToken()
{
    char ch =0;
    
    do
    {// skip white spaces except '\n'
        //
        // if hit the end of the stream return END token
        if(!cin.get(ch)) return currToken = END;

    }while(ch !='\n' && isspace(ch) );
    
    switch (ch)
    {
        // PRINT token: thismarkse the end of an expr_list
        case ';':
        case '\n':
            return currToken = PRINT;

        // Parentheses and operators are handled by returning 
        // their values.
        case '*': case '/': case '+': case '-':
        case '(': case ')': case '=':
            return currToken = Token(ch);

        // if the char represents the start of a number, push
        // it back into the stream and read the number into numberValue
        // and return NUMBER token
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
        case '.':
            cin.putback(ch);
            cin >> numberValue;
            return currToken = NUMBER;
        
        default: // NAME, Name =, or eror
            if (isalpha(ch))
            {
                // This allows you to store and retreave named values
                // eg enter pi = 3.1415926; and then you can use pi as
                // a value like pi * 2; willgive the answer 6.2831852 
                stringValue = ch;
                while (cin.get(ch) && isalnum(ch)) 
                    stringValue.push_back(ch); //build up the string
                
                // the char is not an alpha/numeric so push it back
                // for next time.
                cin.putback(ch);
                return currToken = NAME;
            }
            // if you are here you don't have a valid token
            // show an error and mark the end of the expr_list with PRINT
            error("Bad token");
            return currToken = PRINT;
    }
}

/*****************************************************************************/
// Parser::prim(bool get)
//
double Parser::prim(bool get)
{
     if (get) getToken();

     switch (currToken)
     {
        case Lexer::NUMBER:
        {
            double v = Lexer::numberValue;
            getToken();
            return v;
        }
        case Lexer::NAME:
        {
            double& v = table[stringValue];
            if(getToken() == Lexer::ASSIGN) 
                v = expr(true);
            return v;
        }
        case Lexer::MINUS:
            {
                return -prim(true);
            }
        case Lexer::LP:
            {
                double e = expr(true);
                if (currToken != Lexer::RP)
                    return error(") expected");
                getToken();
                return e;
            }
        default:
            return error("primary expected.");
     }
}

double Parser::term(bool get)
{
    double left = prim(get);

    for(;;)
    {
        switch (currToken)
        {
        case  Lexer::MUL:
            left *= prim(true);
            break;
        case Lexer::DIV:
            if (double d = prim(true))
            {
                left /= d;
                break;
            }
            return error("Divide by 0");
        default:
            return left;
        }
    }
}

///////////////////////////////////////
// Parser::expr(bool get)
// Input: bool get; Indicates whether the function
//                  needs to get the next token.
// The function handles the Addition and Subtraction
double Parser::expr(bool get)
{
    double left = term(get); 

    for(;;) //forever
    {
        switch (currToken)
        {
            case Lexer::PLUS:
                left += term(true);
                break;
            case Lexer::MINUS:
                left -= term(true);
                break;
            default:
                return left;
        }
    }
}

double Parser::error(const string& s)
{
    noOfErrors++;
    cerr << "Error: " << s << endl;
    return 1;
}

Last edited on
Thank you very much, do you think you could add some commentaries please, so I know what I'm doing.
closed account (z05DSL3A)
I have started putting coments in the code above. Keep an eye on it, I'll try to do more soon.
Feel free to ask questions.
And if you have time, could you add some pseudocode, it would be nice of you, and helpful for me :)

Thanks for your help
closed account (z05DSL3A)
It is basically a "Recursive descent parser", if you Google it you will probably find better explanations of it than I have time to do. I will try to finish commenting it in the next few days though.
Topic archived. No new replies allowed.
Pages: 12