title: solution to bjarne stroustrup chapter 7 drill 7 sqrt() function plus a inquiry about error for sqrt() func
body: <p>I thought I would post this, because it's relatively tricky for a relative noob and I didn't see any
  specific posts about this drill.</p>
  
  <p>Also, when I enter: 'sqrt x);' I get the proper error message, 
  but when I enter: 'sqrtx);' I get error: 'get: undefined name sqrtx'
  apparently the program thinks it is a declaration of a variable, 
  any suggestions on better error handling???</p>
  
  <p>This is the solution to chapter 7 drill 7, creating sqrt() for user of the calc program:</p>
  
  <pre><code>/*
      calculator08buggy.cpp
  
      This program implements a basic expression calculator.
      Input from cin; output to cout.
  
      The grammar for input is :
  
      Statement:
          Expression
          Print
          Quit
  
      Print: 
          ;
  
      Quit: 
          q
  
      Expression:
          Term
          Expression + Term
          Expression - Term
  
      Term:
          Primary
          Term * Primary
          Term / Primary
          Term % Primary
  
      Secondary:
          primary
          sqrt ( Expression )
  
      Primary:
          Number
          ( Expression )
          -Primary
          +Primary
  
      Number:
          floating point literal
  
      Input comes from cin through the Token_stream called ts.
  
      We have inserted 3 bugs that the compiler will catch and 3 that it won't.
  */
  //------------------------------------------------------------------------------
  #include "std_lib_facilities.h"
  //------------------------------------------------------------------------------
  struct Token {
      char kind;
      double value;
      string name;
      Token() {}//SQRT OVERHAULD CODE HERE!!!
      Token(char ch) :kind(ch), value(0) { }
      Token(char ch, double val) :kind(ch), value(val) { }
      Token(char ch, string n) :kind(ch), name(n) { } //contructor for variable names 
  };
  //------------------------------------------------------------------------------
  class Token_stream {
      bool full;
      Token buffer;
  public:
      Token_stream() :full(0), buffer(0) { }
  
      Token get();
  
      void unget(Token t) { buffer=t; full=true; } 
  
      void ignore(char); //is called by clean_up_mess() and ignores erroneous statement until it reads a ';'
  };
  //------------------------------------------------------------------------------
  const char let = 'L'; //this the t.kind for declartion
  const string declkey = "let"; //this is string used to declar a variable
  const char quit = 'Q';
  const char print = ';';
  const char number = '8'; //this the t.kind for a number
  const char name = 'a'; //this the t.kind for a variable name
  const char square_root = 'S'; //SQRT OVERHAULD CODE HERE!!!
  //------------------------------------------------------------------------------
  Token Token_stream::get()
  {
      if (full) { full=false; return buffer; }
      char ch;
      cin &gt;&gt; ch;
      switch (ch) {
      case '(':
      case ')':
      case '+':
      case '-':
      case '*':
      case '/':
      case '%':
      case ';':
      case '=':
          return Token(ch);
      case '.':
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      {   cin.unget();
          double val;
          cin &gt;&gt; val;
          return Token(number,val);
      }
      default:
          if (isalpha(ch)) {
              string s;
              s += ch;
              while(cin.get(ch) &amp;&amp; (isalpha(ch) || isdigit(ch))) s+=ch;
              cin.unget();
              if (s == "let") return Token(let);  
              if (s == "q") return Token(quit);
              if (s == "sqrt") return Token(square_root); //SQRT OVERHAULD CODE HERE!!!
              return Token(name,s);
          }
          error("Bad token");
      }
  }
  //------------------------------------------------------------------------------
  void Token_stream::ignore(char c)// argument is 'print' or ';'
  {
      if (full &amp;&amp; c==buffer.kind) {
          full = false;
          return;
      }
      full = false;
  
      char ch;
      while (cin&gt;&gt;ch)
          if (ch==c) return;
  }
  //------------------------------------------------------------------------------
  struct Variable {
      string name;
      double value;
      Variable(string n, double v) :name(n), value(v) { }
  };
  //------------------------------------------------------------------------------
  vector&lt;Variable&gt; names; 
  //------------------------------------------------------------------------------
  double get_value(string s) //returns variable value if 's' matches name already in vector 'names'
  {
      for (int i = 0; i&lt;names.size(); ++i)
          if (names[i].name == s) return names[i].value;
      error("get: undefined name ",s);
  }
  //------------------------------------------------------------------------------
  void set_value(string s, double d)//if 's' matches name in 'names' resets value to 'd'
  {
      for (int i = 0; i&lt;=names.size(); ++i)
          if (names[i].name == s) {
              names[i].value = d;
              return;
          }
      error("set: undefined name ",s);
  }
  //------------------------------------------------------------------------------
  bool is_declared(string s)// if 's' is already in 'names' return true/else return false
  {
      for (int i = 0; i&lt;names.size(); ++i)
          if (names[i].name == s) return true;
      return false;
  }
  //------------------------------------------------------------------------------
  void define_name(string name, double val)
  {   
      names.push_back(Variable(name,val));
  }
  
  //------------------------------------------------------------------------------
  Token_stream ts; //declare ts here so following functions can use
  //------------------------------------------------------------------------------
  double expression();//declare here so following primary() &amp; term () can use
  //------------------------------------------------------------------------------
  double primary()
  {
      Token t = ts.get();
      switch (t.kind) {
      case '(':
      {   double d = expression();
          t = ts.get();
          if (t.kind != ')') error("')' expected");
          return d;
      }
      case '-':
          return - primary();
  
      case number:
          return t.value;
  
      case name:
          return get_value(t.name);
  
      case square_root:
           { ts.unget(t);
               return NULL; }                          //SQRT OVERHAULD CODE HERE!!!
  
      default:
          error("primary expected");
      }
  }
  //------------------------------------------------------------------------------
  // deal with 'sqrt()'
  double secondary()                             //SQRT OVERHAULD CODE HERE!!!
  {
      double left = primary(); //is null if sqrt called
      Token t = ts.get();        // get the next token from token stream
      Token t2;
      double d;
  
          while(true) {
  
          switch (t.kind) {
              case square_root:
  
                  t2 = ts.get(); //make sure '(' is next token
                  if (t2.kind != '(') 
                              error("'(' missing in declaration sqrt ");
  
                  d = expression(); 
                  left = sqrt(d);
  
                  cout &lt;&lt; endl &lt;&lt; "new output works: " &lt;&lt; left &lt;&lt; endl;
  
                  t = ts.get();
  
                  if (t.kind != ')') //make sure ')' is last token in call to sqrt
                          error("')' expected");
  
                  t = ts.get();
                  break;
  
             default: 
                  ts.unget(t);    // put t back into the token stream
                  return left;
          }
      }
  }
  //------------------------------------------------------------------------------
  double term()
  {
      double left = secondary();
      while(true) {
          Token t = ts.get();
          switch(t.kind) {
          case '*':
              left *= primary();
              break;
          case '/':
          {   double d = primary();
              if (d == 0) error("divide by zero");
              left /= d;
              break;
          }
          default:
              ts.unget(t);
              return left;
          }
      }
  }
  //------------------------------------------------------------------------------
  double expression()
  {
      double left = term();
      while(true) {
          Token t = ts.get();
          switch(t.kind) {
          case '+':
              left += term();
              break;
          case '-':
              left -= term();
              break;
          default:
              ts.unget(t);
              return left;
          }
      }
  }
  //------------------------------------------------------------------------------
  double declaration()
  {
      Token t = ts.get();
      if (t.kind != 'a') error ("name expected in declaration");
      string name = t.name;
      if (is_declared(name)) error(name, " declared twice");
      Token t2 = ts.get();
      if (t2.kind != '=') error("= missing in declaration of " ,name);
      double d = expression();
      names.push_back(Variable(name,d));
      return d;
  }
  //------------------------------------------------------------------------------
  double statement()
  {
      Token t = ts.get();
      switch(t.kind) {
      case let:
          return declaration();
      default:
          ts.unget(t);
          return expression();
      }
  }
  //------------------------------------------------------------------------------
  void clean_up_mess()
  {
      ts.ignore(print);
  }
  //------------------------------------------------------------------------------
  const string prompt = "&gt; ";
  const string result = "= ";
  //------------------------------------------------------------------------------
  void calculate()
  {
      while(true) try {
          cout &lt;&lt; prompt;
          Token t = ts.get();
          while (t.kind == print) t=ts.get();
          if (t.kind == quit) return;
          ts.unget(t);
          cout &lt;&lt; result &lt;&lt; statement() &lt;&lt; endl;
      }
      catch(runtime_error&amp; e) {
          cerr &lt;&lt; e.what() &lt;&lt; endl;
          clean_up_mess();
      }
  }
  //------------------------------------------------------------------------------
  int main()
  {
      define_name("k", 1000);
  
      try {
  
          calculate();
          return 0;
      }
      catch (exception&amp; e) {
          cerr &lt;&lt; "exception: " &lt;&lt; e.what() &lt;&lt; endl;
          char c;
          while (cin &gt;&gt;c&amp;&amp; c!=';') ;
          return 1;
      }
      catch (...) {
          cerr &lt;&lt; "exception\n";
          char c;
          while (cin&gt;&gt;c &amp;&amp; c!=';');
          return 2;
      }
  }
  //------------------------------------------------------------------------------
  </code></pre>