views:

154

answers:

3

I've got a fairly complex calculator that prints output when the user inputs ";" (and hits enter.) What I'm trying to do now is allow the user to print output when they hit enter, (without use of semicolon.) I need to know how I can implement this.

Side note: The calculator uses tokenization to read user input

This is part of the calculator's source, and the only part that needs to be changed. It is a member function of Token_stream that is called when various other functions of the calculator call to get the next token.

const char let = '#';
const char quit = 'Q';
const char print = ';';
const char number = '8';
const char name = 'a';
const char sq_rt = '@';
const char power = '^';
const char constant = '~';

Token Token_stream::get()
{
    if (full) { full=false; return buffer; }
    char ch;
    cin >> ch;
    switch (ch) {
    case '(':
    case ')':
    case '+':
    case '-':
    case '*':
    case '/':
    case '%':
    case ';':
    case '=':
    case ',':
    case constant:
    case power:
    case sq_rt:
    case let:
    case quit:
    case name:
     return Token(ch);   // let each character represent itself
    case '.':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    { cin.unget();       // equivalent of putback
     double val;
     cin >> val;
     return Token(number,val);
    }
    default:
     if (isalpha(ch)) {       // in order to create variable names
      string s;
      s += ch;
      while(cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_')) s += ch;
      cin.unget();
      if (s == "const") return Token(constant);
      if (s == "quit") return Token(quit);
      if (s == "pow") return Token(power);
      if (s == "sqrt") return Token(sq_rt);
      if (s == "let") return Token(let); 
      if (s == "name") return Token(name);
      return Token(name,s);
             }
       else if (isspace(ch)) {    // my attempt at allowing enter to produce output
            string s;
            cin.get(ch);
            s += ch;
            if(s == "\n") return Token(print);
            }

            }
     error("Bad token");
    }

So far if the user enters 5*5 and hits space then enter..nothing happens. However if they hit space, then enter a random character (any character, not just ;) then hit enter, it ouputs the answer. After this, the user can use enter to produce output, but it saves the extra token that the user input after they hit space, so the order of operations gets all screwy.

In short, I need to know how to allow the user initially to hit space then enter (or even just enter, but working with space and enter for now) to produce output - without any additional characters.

If you'd like to see more source or have any questions regarding the calculator itself in order to solve the problem I'd be happy to post more.

P.S. The original program is from a book I'm learning C++ from. I've just been doing exercises that change it and add features to it.

+3  A: 

I would read the line into a string first, and pass that to your 'Token' class.

Something like:

#include <iostream>
#include <string>

...

{
    std::string in;
    getline( std::cin, in );
    Token t( in );
    // Do whatever you need to with 't'
    std::cout << in << " = " << t.Result() << std::endl;
}
kitchen
A: 

Exapnding on 'kitchen'

Assuming you create your token stream class like this:

int main()
{
     Token_stream    stream(std::cin);

     // Do Stuff.
};

You could change this too:

int main()
{
    MyApplicationState   stateInfo;
    std::string          line;

    while(std::getline(std::cin,line))
    {
        std::stringstream s(line);
        Token_stream      stream(stateInfo,s);

        // Do stuff
    }
}

Now each line is its own stream.
This assumes that each line contains all the information required for an expression and that you can store state information in an object MyApplicationState.

Martin York
A: 

Another idea to expand on the above stated solutions:

In the case that one line does not contain all the information, i.e if there is a need to 'space' the input over multiple line set a standard delimitation character(s). For example two newlines (two enter presses in a row) would mark the end of the stream.

Then just read the whole thing into one buffer (like suggested in answers before) and parse that buffer.

An end of line on Windows is usually or in hex 0X0D 0X0A sequence.

Roman M