views:

120

answers:

1

I'm not sure what Bjarne meant with this exercise:

"Convert the desk calculator to use a symbol structure instead of using the static variables number_value and string_value."

Did he mean puting those 2 variables inside a structure and then using them through a structure?

Edit: also one exercise related to the clculator and it says: "Allow a user to define functions in the claculator. Hint: Define a function as a sequence of operations just as a user would ave typed them. Such a sequence can be stored either as a char string or as a list of tokens. Then read and execute those operations when the function is called. If you want a user-defined function to take args, you'll have to invent a notation for that."

Could anyone give ma an example of what it means? What sort of functions should user define, i dont get it. Ability to define for example function that returns a ^2 value from its argument for example?

Here's the code.

#include <iostream>
#include <map>

using namespace std;

double term(bool);
double expr(bool);
double prim(bool);
double error(const string&);

double number_value;
string string_value;

int no_of_errors;
map<string, double> table;

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

Token_value curr_tok = PRINT;
Token_value get_token();

double expr(bool get)
{
       double left = term(get);

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

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

       for(;;) 
           switch(curr_tok) {
              case MUL:
                   left *= prim(true);
                   break;
              case DIV:
                   if(double d = prim(true)) {
                       left /= d;
                       break;
                   }
                   return error("divide by zero");
              default:
                      return left;
           }
}

double prim(bool get)
{
       if(get)
          get_token();

       switch(curr_tok) {
           case NUMBER: {
                double v = number_value;
                get_token();
                return v;
           }
           case NAME: {
                double &v = table[string_value];
                if(get_token() == ASSIGN)
                   v = expr(true);
                return v;
           }
           case MINUS:
                return -prim(true);
           case LP: {
                double e = expr(true);
                if(curr_tok != RP)
                  return error(") expected");
                get_token();
                return e;
           }
           default:
                   return error("primary expected");
       }
}

Token_value get_token()
{
       char ch = 0;
       do {
           if(!cin.get(ch)) 
              return curr_tok = END;
       } while(ch != '\n' && isspace(ch));

       switch(ch) {
           case 0:
                return curr_tok = END;
           case ';':
           case '\n':
                return curr_tok = PRINT;
           case '+':
           case '-':
           case '/':
           case '*':
           case '(':
           case ')':
           case '=':
                return curr_tok = Token_value(ch);
           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 >> number_value;
                return curr_tok = NUMBER;
           default:
                   if(isalpha(ch)) {
                       string_value = ch;
                       while(cin.get(ch) && isalnum(ch))
                          string_value.push_back(ch);
                       cin.putback(ch);
                       return curr_tok = NAME;
                   }
                   error("bad token");
                   return curr_tok = PRINT;
       }
}

double error(const string &s)
{
       no_of_errors++;
       cerr << "error: " << s << '\n';
       return 1;
}

int main()
{
      table["pi"] = 3.14;
      table["e"] = 2.71;

      while(cin) {
          get_token();
          if(curr_tok == END)
             break;
          if(curr_tok == PRINT)
             continue;
          cout << expr(false) << endl;
      }
      return no_of_errors;
}
+1  A: 

That's exactly what he means, in my opinion. Also the structure shouldn't be global either, it should be passed as a parameter (by value or reference appropriately).

Ben Voigt
Why does he say the variable are "static"? They are global, not static? Or are global variables also automatically static?
Tool
There's no such thing as a "global" variable per se, just a static variable in the global namespace.
GMan
And what about user defining functions?Any suggestions in what should i do about it? I tought of implementing something like define func(x) x * x; (sort of macro - style) - then when lexer finds "define" keyword it stores the function definition/arguments inside an appropriate structure?
Tool
`static` refers to lifetime, `global` refers to visibility
Ben Voigt